./m23.lua

  1.   
  2. --[[ 
  3. 	m23.lua 
  4. 	SR3 Mission Script 
  5. 	DATE: 09/14/10 
  6. 	AUTHOR:	matt.gawalek 
  7. ]]-- 
  8.  
  9.  
  10. -- Debug flags -- 
  11.  
  12. -- Tweakable Parameters -- 
  13. 	M23_tweak_values = { 
  14. 		boss_battle_self_descruct_time_limit = 5 * 60 * 1000, -- 5 minutes, in milliseconds 
  15. 		escape_time_limit = 45000, -- milliseconds 
  16. 		fight_looping_cam_shake_amount = 0.2, 
  17. 		escape_looping_cam_shake_amount = 2.0, 
  18. 		taunt_idx_max = 3 
  19. 	} 
  20. 	 
  21. 	-- Checkpoints -- 
  22. 	M23_checkpoints = { 
  23. 		start = { 
  24. 			name = MISSION_START_CHECKPOINT,			-- defined in ug_lib.lua 
  25. 			player_starts = { "nav_player_start_chk_01_ 001", "nav_player_start_chk_01_ 002" }, 
  26. 		}, 
  27. 		saints_hq = { 
  28. 			name = "m23_checkpoint_saints_hq", 
  29. 			player_starts = { "nav_player_start_chk_01b 001", "nav_player_start_chk_01b 002" }, 
  30. 		}, 
  31. 		landing_deck = { 
  32. 			name = "m23_checkpoint_landing_deck", 
  33. 			player_starts = { "nav_player_start_chk_02_ 001", "nav_player_start_chk_02_ 002" }, 
  34. 		}, 
  35. 		bridge = { 
  36. 			name = "m23_checkpoint_bridge", 
  37. 			player_starts = { "nav_player_start_chk_03_ 001", "nav_player_start_chk_03_ 002" }, 
  38. 		}, 
  39. 		escape = { 
  40. 			name = "m23_checkpoint_escape", 
  41. 			player_starts = { "nav_player_start_chk_04_ 001", "nav_player_start_chk_04_ 002" }, 
  42. 		}, 
  43. 	} 
  44. 	 
  45. 	M23_cyrus_boss_ai = { 
  46. 		start_path_1 = "path_cyrus_boss_start 001", 
  47. 		start_path_2 = "path_cyrus_boss_start 002", 
  48. 		 
  49. 		-- Define Cyrus's various strafe attacks 
  50. 		strafe_attacks = { 
  51. 			{ 
  52. 				paths = { 
  53. 					left_to_right = { 
  54. 						intro = "path_cyrus_strafe_lr_intro 001", 
  55. 						middle = "path_cyrus_strafe_lr_middle 001", 
  56. 						outro = "path_cyrus_strafe_lr_outro 001", 
  57. 					}, 
  58. 					right_to_left = { 
  59. 						intro = "path_cyrus_strafe_rl_intro 001", 
  60. 						middle = "path_cyrus_strafe_rl_middle 001", 
  61. 						outro = "path_cyrus_strafe_rl_outro 001", 
  62. 					}, 
  63. 				}, 
  64. 				vtol_speed = 35, 
  65. 				refire_delay = 5.0, 
  66. 				error_radius = 1.5, 
  67. 			}, 
  68. 		}, 
  69. 		 
  70. 		-- Define Cyrus's varius sweep attacks 
  71. 		sweep_attacks = { 
  72. 			{ 
  73. 				paths = { 
  74. 					left_to_right = { 
  75. 						intro = "path_cyrus_sweep_lr_intro 001", 
  76. 						middle = "path_cyrus_sweep_lr_middle 001", 
  77. 						outro = "path_cyrus_sweep_lr_outro 001", 
  78. 					}, 
  79. 					right_to_left = { 
  80. 						intro = "path_cyrus_sweep_rl_intro 001", 
  81. 						middle = "path_cyrus_sweep_rl_middle 001", 
  82. 						outro = "path_cyrus_sweep_rl_outro 001", 
  83. 					}, 
  84. 				}, 
  85. 				refire_delay = 0.0, 
  86. 				vtol_speed = 30, 
  87. 			}, 
  88. 		}, 
  89. 		 
  90. 		chase_attacks = { 
  91. 			{ 
  92. 				paths = { 
  93. 					intro = "path_cyrus_sweep_intro 001", 
  94. 					outro = "path_cyrus_sweep_outro 001", 
  95. 				}, 
  96. 				duration = 20.0, 
  97. 			}, 
  98. 		}, 
  99. 		 
  100. 		reinforcement_attacks = { 
  101. 			{ 
  102. 				cyrus_paths = { 
  103. 					left_to_right = "path_cyrus_reinforcement_lr 001", 
  104. 					right_to_left = "path_cyrus_reinforcement_rl 001", 
  105. 				}, 
  106. 				transport_paths = { 
  107. 					{ 
  108. 						approach_path = "path_cyrus_transport 001", 
  109. 						exit_path = "path_cyrus_trans_exit 001", 
  110. 					}, 
  111. 					{ 
  112. 						approach_path = "path_cyrus_transport 002", 
  113. 						exit_path = "path_cyrus_trans_exit 002", 
  114. 					}, 
  115. 					{ 
  116. 						approach_path = "path_cyrus_transport 003", 
  117. 						exit_path = "path_cyrus_trans_exit 003", 
  118. 					}, 
  119. 				}, 
  120. 			}, 
  121. 		}, 
  122. 		 
  123. 		reinforce_threads = { 
  124. 			{ 
  125. 				func = "m23_cyrus_boss_ai_reinforcement_thread" 
  126. 			}, 
  127. 		}, 
  128. 		 
  129. 		attack_threads = { 
  130. 			--[[ 
  131. 			{ 
  132. 				func = "m23_cyrus_boss_ai_chase_thread", 
  133. 			}, 
  134. 			--]] 
  135. 			{ 
  136. 				func = "m23_cyrus_boss_ai_strafe_thread", 
  137. 			}, 
  138. 			{ 
  139. 				func = "m23_cyrus_boss_ai_sweep_thread", 
  140. 			}, 
  141. 		}, 
  142. 	} 
  143.  
  144. -- Groups -- 
  145. 	M23_groups = { 
  146. 		mission_start = { 
  147. 			name = "Group_mission_start 001", 
  148. 			courtesy_cars = { "veh_courtesy_car 001", "veh_courtesy_car 002" }, 
  149. 		}, 
  150. 		 
  151. 		courtesy_helis = { 
  152. 			name = "group_courtesy_helis", 
  153. 			vehicles = { "veh_courtesy_heli 001", "veh_courtesy_heli 002" }, 
  154. 		}, 
  155. 		 
  156. 		daedalus_vtols_01 = { 
  157. 			name = "Group_daedalus_vtols 001", 
  158. 			vtols = { "veh_daedalus_vtol 001", "veh_daedalus_vtol 002", "veh_daedalus_vtol 004", "veh_daedalus_vtol 005", "veh_daedalus_vtol 006" }, 
  159. 		}, 
  160. 		 
  161. 		daedalus_escape_vtols = { 
  162. 			name = "Group_daedalus_vtols 002", 
  163. 			vtols = { "veh_daedalus_vtol 007", "veh_daedalus_vtol 008" }, 
  164. 		},	 
  165. 		 
  166. 		daedalus_tanks_01 = { 
  167. 			name = "Group_daedalus_tanks 001", 
  168. 			tanks = { 
  169. 				{ 
  170. 					vehicle = "veh_daedalus_tank_01_ 001", 
  171. 					chars = { "char_tank_driver_01_ 001", "char_tank_gunner_01_ 001" }, 
  172. 				}, 
  173. 				{ 
  174. 					vehicle = "veh_daedalus_tank_01_ 002", 
  175. 					chars = { "char_tank_driver_01_ 002", "char_tank_gunner_01_ 002" }, 
  176. 				}, 
  177. 				{ 
  178. 					vehicle = "veh_daedalus_tank_01_ 003", 
  179. 					chars = { "char_tank_driver_01_ 003", "char_tank_gunner_01_ 003" }, 
  180. 				}, 
  181. 			}, 
  182. 		}, 
  183. 		 
  184. 		daedalus_tanks_02 = { 
  185. 			name = "Group_daedalus_tanks 002", 
  186. 			tanks = { 
  187. 				{ 
  188. 					vehicle = "veh_daedalus_tank_02_ 001", 
  189. 					chars = { "char_tank_gunner_02_ 001"--[[, "char_tank_driver_02_ 001"--]] }, 
  190. 					thread_ids = { --[[-1,--]] -1 }, 
  191. 				}, 
  192. 				{ 
  193. 					vehicle = "veh_daedalus_tank_02_ 002", 
  194. 					chars = { "char_tank_gunner_02_ 002"--[[, ""char_tank_driver_02_ 002"--]] }, 
  195. 					thread_ids = { --[[-1,--]] -1 }, 
  196. 				}, 
  197. 				{ 
  198. 					vehicle = "veh_daedalus_tank_02_ 003", 
  199. 					chars = { "char_tank_gunner_02_ 003"--[[, ""char_tank_driver_02_ 003"--]] }, 
  200. 					thread_ids = { --[[-1,--]] -1 }, 
  201. 				}, 
  202. 				{ 
  203. 					vehicle = "veh_daedalus_tank_02_ 004", 
  204. 					chars = { "char_tank_gunner_02_ 004"--[[, ""char_tank_driver_02_ 004"--]] }, 
  205. 					thread_ids = { --[[-1,--]] -1 }, 
  206. 				}, 
  207. 			}, 
  208. 		}, 
  209. 		 
  210. 		daedalus_apc_01 = { 
  211. 			name = "group_daedalus_apc 001", 
  212. 		}, 
  213. 		 
  214. 		--[[ 
  215. 		attack_vtols_01 = { 
  216. 			name = "Group_attack_vtols 001", 
  217. 			vtols = { 
  218. 				{ 
  219. 					vehicle = "veh_attack_vtol 001", 
  220. 					chars = { "char_attack_vtol_pilot 001" }, 
  221. 					lift_off_pos = "nav_attack_vtol_takeoff 001", 
  222. 					delay = 0.0, 
  223. 					thread_id = -1, 
  224. 				}, 
  225. 				{ 
  226. 					vehicle = "veh_attack_vtol 002", 
  227. 					chars = { "char_attack_vtol_pilot 002" }, 
  228. 					lift_off_pos = "nav_attack_vtol_takeoff 002", 
  229. 					delay = 6.0, 
  230. 					thread_id = -1, 
  231. 				}, 
  232. 			}, 
  233. 		}, 
  234. 		--]] 
  235. 		 
  236. 		dog_fight_01 = { 
  237. 			name = "Group_dog_fight 001", 
  238. 			lead_group = { 
  239. 				vehicle = "veh_saint_dog_fight_01_ 001", 
  240. 				chars = { "char_saint_dog_fight_01_ 001" }, 
  241. 				path = "path_dog_fight_01_ 001", 
  242. 			}, 
  243. 			chase_groups = { 
  244. 				{ 
  245. 					vehicle = "veh_stag_dog_fight_01_ 001", 
  246. 					chars = { "char_stag_dog_fight_01_ 001" }, 
  247. 					follow_dist = 40.0 
  248. 				}, 
  249. 			}, 
  250. 			thread_id = -1, 
  251. 		}, 
  252. 		 
  253. 		dog_fight_02 = { 
  254. 			name = "Group_dog_fight 002", 
  255. 			lead_group = { 
  256. 				vehicle = "veh_stag_dog_fight_02_ 001", 
  257. 				chars = { "char_stag_dog_fight_02_ 001" }, 
  258. 				path = "path_dog_fight_02_ 001", 
  259. 			}, 
  260. 			chase_groups = { 
  261. 				{ 
  262. 					vehicle = "veh_saint_dog_fight_02_ 001", 
  263. 					chars = { "char_saint_dog_fight_02_ 001" }, 
  264. 					follow_dist = 40.0 
  265. 				}, 
  266. 				--[[ 
  267. 				{ 
  268. 					vehicle = "veh_saint_dog_fight_02_ 002", 
  269. 					chars = { "char_saint_dog_fight_02_ 002" }, 
  270. 					follow_dist = 40.0 
  271. 				} 
  272. 				--]] 
  273. 			}, 
  274. 			thread_id = -1, 
  275. 		}, 
  276. 		 
  277. 		saints_landing_deck_reinforcements = { 
  278. 			name = "group_saints_ld_reinforce", 
  279. 			groups = { 
  280. 				{ 
  281. 					vehicle = "veh_saints_reinforce 001", 
  282. 					chars = { "char_saints_reinforce 001", "char_saints_reinforce 002" }, 
  283. 					path = "path_saints_reinforce 001", 
  284. 					landing_nav = "nav_saints_reinforce_land 001", 
  285. 					thread_id = -1, 
  286. 				}, 
  287. 				{ 
  288. 					vehicle = "veh_saints_reinforce 002", 
  289. 					chars = { "char_saints_reinforce 003", "char_saints_reinforce 004" }, 
  290. 					path = "path_saints_reinforce 002", 
  291. 					landing_nav = "nav_saints_reinforce_land 002", 
  292. 					thread_id = -1, 
  293. 				}, 
  294. 			}, 
  295. 		}, 
  296. 		 
  297. 		bomb_spawn_01 = { 
  298. 			name = "group_bomb_spawn 001", 
  299. 		}, 
  300. 		 
  301. 		bomb_spawn_02 = { 
  302. 			name = "group_bomb_spawn 002", 
  303. 		}, 
  304. 		 
  305. 		bomb_spawn_03 = { 
  306. 			name = "group_bomb_spawn 003", 
  307. 		}, 
  308. 		 
  309. 		amb_spawn_01 = { 
  310. 			name = "group_stag_amb 001", 
  311. 		}, 
  312. 				 
  313. 		ammo_stash_02 = { 
  314. 			name = "Group_ammo_stash 002", 
  315. 			miniguns = { "itm_weapon_minigun 001", "itm_weapon_minigun 002" }, 
  316. 		}, 
  317. 		 
  318. 		cyrus_vtol = { 
  319. 			name = "Group_cryrus_vtol 001", 
  320. 			cyrus = "char_cyrus 001", 
  321. 			vtol = "veh_cyrus_vtol 001", 
  322. 		}, 
  323. 		 
  324. 		transport_vtol_01 = { 
  325. 			name = "Group_transport_vtol 001", 
  326. 			vtol = "veh_transport_vtol_01_ 001", 
  327. 			pilots = { "char_transport_vtol_01_pilot" }, 
  328. 			soldiers = { "char_transport_vtol_01_ 002", "char_transport_vtol_01_ 003", "char_transport_vtol_01_ 004", "char_transport_vtol_01_ 005", "char_transport_vtol_01_ 006" }, 
  329. 		}, 
  330. 	} 
  331. 	 
  332. -- Navpoints -- 
  333. 	M23_navpoints = { 
  334. 		saints_hq_gps = "nav_saints_hq_gps 001", 
  335. 		saints_hq_elevator = "nav_saints_hq_elevator 001", 
  336. 		daedalus_landing_pos = "nav_landing_pos 001", 
  337. 		daedalus_self_destruct_audio_pos = "nav_self_destruct_audio", 
  338. 		mission_end = { "nav_local_end 001", "nav_remote_end 001" }, 
  339. 	} 
  340. 	 
  341. -- Triggers -- 
  342. 	M23_triggers = { 
  343. 		saints_hq_activate_helis = "tgr_activate_helis", 
  344. 		awesome_daedalus = "tgr_awesome_daedalus", 
  345. 		saints_hq_elev_up = "tgr_saints_hq_elev_up 001", 
  346. 		saints_hq_elev_down = "tgr_saints_hq_elev_down 001", 
  347. 		saints_hq_gps = "tgr_saints_hq_gps 001",  
  348. 		saints_hq_entry = "tgr_saints_hq_entry", 
  349. 		daedalus_airspace = "tgr_daedalus_airspace 001", 
  350. 		daedalus_gunfire = "tgr_daedalus_gunfire", 
  351. 		daedalus_defensive_area = "tgr_daedalus_defenses 001", 
  352. 		daedalus_landing_zone = "tgr_daedalus_landing_zone 001", 
  353. 		rear_deck = "tgr_rear_deck", 
  354. 		cyrus_combat = "tgr_cyrus_combat 001", 
  355. 		flee_region = "tgr_flee_region 001", 
  356. 		daedalus_blast_radius = "tgr_daedalus_blast_radius 001", 
  357. 	} 
  358. 	 
  359. -- Kill Regions -- 
  360. 	M23_kill_regions = {	"tgr_daed_eng_kill 001", "tgr_daed_eng_kill 002", "tgr_daed_eng_kill 003", "tgr_daed_eng_kill 004", 
  361. 								"tgr_daed_eng_kill 005", "tgr_daed_eng_kill 006", "tgr_daed_eng_kill 007", "tgr_daed_eng_kill 008", 
  362. 								"tgr_daed_eng_kill 009", "tgr_daed_eng_kill 010", "tgr_daed_eng_kill 011", "tgr_daed_eng_kill 012", 
  363. 								"tgr_daed_eng_kill 013", "tgr_daed_eng_kill 014", "tgr_daed_eng_kill 015", "tgr_daed_eng_kill 016", 
  364. 	} 
  365. 			 
  366.  
  367. -- Characters -- 
  368.  
  369. -- Vehicles -- 
  370.  
  371. -- Continuous Spawn Groups -- 
  372. 	M23_spawn_groups = { 
  373. 		defensive_01 = "Group_stag_cs_defense 001", 
  374. 		defensive_02 = "Group_stag_cs_defense 002", 
  375. 		offensive_01 = "Group_stag_cs_offense 001", 
  376. 		offensive_02 = "Group_stag_cs_offense 002", 
  377. 		riotshield_01 = "Group_stag_cs_riotshield 001", 
  378. 		-- sniper_01 = "Group_stag_cs_sniper 001", 
  379. 	} 
  380. 	 
  381. -- Spawn Regions -- 
  382. 	M23_spawn_regions = { 
  383. 		landing_deck = { 	"spr_landing_deck 001", "spr_landing_deck 002", "spr_landing_deck 003", "spr_landing_deck 004", 
  384. 								"spr_landing_deck 005", "spr_landing_deck 006", "spr_landing_deck 007", "spr_landing_deck 008", 
  385. 								"spr_landing_deck 009", "spr_landing_deck 010", "spr_landing_deck 011" }, 
  386. 		cyrus_deck = { "spr_deck_reinforce 001", "spr_deck_reinforce 002", "spr_deck_reinforce 003", 
  387. 						"spr_deck_reinforce 004", "spr_deck_reinforce 005" }, 
  388. 	} 
  389. 	 
  390. -- Movers -- 
  391. 	M23_movers = { 
  392. 		hangar_door = "mvr_daed_door 001", 
  393. 		daedalus_guns = { 
  394. 			{ 
  395. 				mover_name = "daedalus_gun_1", 
  396. 				effect_nav = "daed_muzzle_vfx_1", 
  397. 				death_vfx = "daed_death_vfx 001", 
  398. 				firing_thread = INVALID_THREAD_HANDLE, 
  399. 			}, 
  400. 			{ 
  401. 				mover_name = "daedalus_gun_2", 
  402. 				effect_nav = "daed_muzzle_vfx_2", 
  403. 				death_vfx = "daed_death_vfx 002", 
  404. 				firing_thread = INVALID_THREAD_HANDLE, 
  405. 			}, 
  406. 			{ 
  407. 				mover_name = "daedalus_gun_3", 
  408. 				effect_nav = "daed_muzzle_vfx_3", 
  409. 				death_vfx = "daed_death_vfx 003", 
  410. 				firing_thread = INVALID_THREAD_HANDLE, 
  411. 			}, 
  412. 			{ 
  413. 				mover_name = "daedalus_gun_4", 
  414. 				effect_nav = "daed_muzzle_vfx_4", 
  415. 				death_vfx = "daed_death_vfx 004", 
  416. 				firing_thread = INVALID_THREAD_HANDLE, 
  417. 			}, 
  418. 		}, 
  419. 	} 
  420.  
  421. -- Cutscenes -- 
  422. 	M23_cutscenes = { 
  423. 		intro = "23_in", 
  424. 		cyrus_death = "23_z01", 
  425. 		outro = "23_out", 
  426. 	} 
  427. 	 
  428. -- Text -- 
  429. 	M23_objectives = { 
  430. 		get_helicopter = { 
  431. 			tag = "M23_OBJ_GET_HELICOPTER", 
  432. 			icon = OI_ASSET_LOCATION, 
  433. 		}, 
  434. 		go_to_daedalus = { 
  435. 			tag = "M23_OBJ_GO_TO_DAEDALUS", 
  436. 			icon = OI_ASSET_LOCATION, 
  437. 		}, 
  438. 		land_on_daedalus = { 
  439. 			tag = "M23_OBJ_LAND_ON_DAEDALUS", 
  440. 			icon = OI_ASSET_LOCATION, 
  441. 		}, 
  442. 		destroy_guns = { 
  443. 			tag = "M23_OBJ_DESTROY_GUNS", 
  444. 			icon = OI_ASSET_KILL, 
  445. 		}, 
  446. 		destroy_defenses = { 
  447. 			tag = "M23_OBJ_DESTROY_DEFENSES", 
  448. 			icon = OI_ASSET_KILL, 
  449. 		}, 
  450. 		plant_bombs = { 
  451. 			tag = "M23_OBJ_PLANT_BOMB", 
  452. 			icon = OI_ASSET_USE, 
  453. 		}, 
  454. 		fly_to_side_deck = { 
  455. 			tag = "M23_OBJ_FLY_TO_SIDE_DECK", 
  456. 			icon = OI_ASSET_LOCATION, 
  457. 		}, 
  458. 		fly_to_rear_deck = { 
  459. 			tag = "M23_OBJ_FLY_TO_REAR_DECK", 
  460. 			icon = OI_ASSET_LOCATION, 
  461. 		}, 
  462. 		kill_cyrus = { 
  463. 			tag = "M23_OBJ_KILL_CYRUS", 
  464. 			icon = OI_ASSET_KILL, 
  465. 		}, 
  466. 		escape = { 
  467. 			tag = "M23_OBJ_ESCAPE", 
  468. 			icon = OI_ASSET_LOCATION, 
  469. 		}, 
  470. 	} 
  471. 	 
  472. 	-- Threads -- 
  473. 	M23_threads = { 
  474. 		mission_start_vo = -1, 
  475. 		wait_for_heli_takeoff = -1, 
  476. 		cyrus_attack_bridge = -1, 
  477. 		cyrus_boss_ai = -1, 
  478. 		cyrus_boss_action = -1, 
  479. 		cyrus_fire_weapon_thread = -1, 
  480. 		cyrus_transport_thread = -1, 
  481. 		cyrus_destroy_player_helis = -1, 
  482. 		explosions = -1, 
  483. 		async_delay_thread = -1, 
  484. 		daedalus_guns_thread = -1, 
  485. 	} 
  486. 	 
  487. 	M23_music = { 
  488. 		mission_start = "M23_music_mission_start",-- 
  489. 		mission_start_end = "M23_music_mission_start_end",-- 
  490. 		daedalus_battle = "M23_music_daedalus_battle",-- 
  491. 		daedalus_battle_end = "M23_music_daedalus_battle_end",-- 
  492. 		cyrus_fight = "M23_music_cyrus_boss_fight",-- 
  493. 		cyrus_fight_end = "M23_music_cyrus_boss_fight_end",-- 
  494. 		checkpoint_saints_hq = "M23_music_mission_start_checkpoint",-- 
  495. 		checkpoint_daedalus = "M23_music_daedalus_checkpoint",-- 
  496. 		checkpoint_cyrus_fight = "M23_music_cyrus_fight_checkpoint", 
  497. 		stop_all = "M23_music_stop", 
  498. 	} 
  499. 	 
  500. 	M23_personas = { 
  501. 		pierce = { 
  502. 			name = "Pierce", 
  503. 			persona_id = -1, 
  504. 		}, 
  505. 		oleg = { 
  506. 			name = "Oleg", 
  507. 			persona_id = -1, 
  508. 		}, 
  509. 		kinzie = { 
  510. 			name = "Kinzie", 
  511. 			persona_id = -1, 
  512. 		}, 
  513. 		angel = { 
  514. 			name = "Angel", 
  515. 			persona_id = -1, 
  516. 		}, 
  517. 		cyrus = { 
  518. 			name = "Cyrus", 
  519. 			persona_id = -1, 
  520. 		}, 
  521. 		interrogation = { 
  522. 			name = "Interrogation", 
  523. 			persona_id = -1, 
  524. 		}, 
  525. 	} 
  526. 	 
  527. 	M23_conversations = { 
  528. 		mission_start = { 
  529. 			name = "M23_Mission_Start", 
  530. 			handle = INVALID_CONVERSATION_HANDLE, 
  531. 		}, 
  532. 		awesome_daedalus = { 
  533. 			name = "M23_Awesome_Daedalus", 
  534. 			handle = INVALID_CONVERSATION_HANDLE, 
  535. 		}, 
  536. 		not_making_a_dent = { 
  537. 			name = "M23_Not_Making_A_Dent", 
  538. 			handle = INVALID_CONVERSATION_HANDLE, 
  539. 		}, 
  540. 		cyrus_start = { 
  541. 			name = "M23_Cyrus_Start", 
  542. 			handle = INVALID_CONVERSATION_HANDLE, 
  543. 		}, 
  544. 		fireworks_started = { 
  545. 			name = "M23_Cyrus_Low_Health", 
  546. 			handle = INVALID_CONVERSATION_HANDLE, 
  547. 		}, 
  548. 		times_up = { 
  549. 			name = "M23_Time_Running_Out_2", 
  550. 			handle = INVALID_CONVERSATION_HANDLE, 
  551. 		}, 
  552. 	} 
  553. 	 
  554. 	M23_dialog_lines = { 
  555. 		oleg_phone_call = "M23_Oleg_Update_Call", 
  556. 		kinzie_phone_call = "M23_Kinzie_Update_Call", 
  557. 		angel_phone_call = "M23_Angel_Update_Call", 
  558. 		take_out_turrets = "M23_Take_Out_Turrets", 
  559. 		turrets_down = "M23_Turrets_Down", 
  560. 		first_bomb = "M23_Plant_First_Bomb", 
  561. 		second_bomb = "M23_Plant_Second_Bomb", 
  562. 		third_bomb = "M23_Plant_Third_Bomb", 
  563. 		fourth_bomb = "M23_Plant_Fourth_Bomb", 
  564. 		callout_weapons = "M23_Call_Out_Weapons_On_Deck", 
  565. 		-- clear_the_deck = "M23_Clear_the_Deck", 
  566. 		-- get_to_bridge = "M23_Get_to_Bridge", 
  567. 		-- armory = "M23_Armory", 
  568. 		find_cyrus = "M23_Cyrus_Finds_You_On_Deck", 
  569. 		self_destruct = "M23_Self_Destruct_Start", 
  570. 		cyrus_call_backup = "M23_Call_Backup", 
  571. 		cyrus_taunts = { "M23_Cyrus_Taunt_01", "M23_Cyrus_Taunt_02", "M23_Cyrus_Taunt_03" }, 
  572. 		abandon_ship = "M23_Time_Running_Out_01", 
  573. 		escape = "M23_Escape", 
  574. 	} 
  575. 		 
  576. -- Other -- 
  577. 	M23_vfx = { 
  578. 		daedalus_explosoin = "vfx_daedalus_explosion 001", 
  579. 	} 
  580. 	 
  581. 	M23_missile_racks = { 
  582. 		{ 
  583. 			thread = INVALID_THREAD_HANDLE, 
  584. 			cur_rack = 1, 
  585. 			target = "rack_target", 
  586. 			racks = { 
  587. 				-- Racks will be chosen in sequence and a missile will fire from each nav point in that rack in sequence. 
  588. 				{ 
  589. 					"rack<005>", "rack<004>", "rack<001>", 
  590. 				}, 
  591. 				{ 
  592. 					"rack<006>", "rack<003>", "rack<002>", 
  593. 				}, 
  594. 				{ 
  595. 					"rack<009>", "rack<008>", "rack<007>", 
  596. 				}, 
  597. 				{ 
  598. 					"rack<012>", "rack<011>", "rack<010>", 
  599. 				}, 
  600. 				{ 
  601. 					"rack<013>", "rack<014>", "rack<015>", 
  602. 				}, 
  603. 				{ 
  604. 					"rack<016>", "rack<017>", "rack<018>", 
  605. 				}, 
  606. 			}, 
  607. 		}, 
  608. 		{ 
  609. 			thread = INVALID_THREAD_HANDLE, 
  610. 			cur_rack = 1, 
  611. 			target = "rack_target2", 
  612. 			racks = { 
  613. 				-- Racks will be chosen in sequence and a missile will fire from each nav point in that rack in sequence. 
  614. 				{ 
  615. 					"rack2<005>", "rack2<004>", "rack2<001>", 
  616. 				}, 
  617. 				{ 
  618. 					"rack2<006>", "rack2<003>", "rack2<002>", 
  619. 				}, 
  620. 				{ 
  621. 					"rack2<009>", "rack2<008>", "rack2<007>", 
  622. 				}, 
  623. 				{ 
  624. 					"rack2<012>", "rack2<011>", "rack2<010>", 
  625. 				}, 
  626. 				{ 
  627. 					"rack2<013>", "rack2<014>", "rack2<015>", 
  628. 				}, 
  629. 				{ 
  630. 					"rack2<016>", "rack2<017>", "rack2<018>", 
  631. 				}, 
  632. 			}, 
  633. 		}, 
  634. 	} 
  635. 	 
  636. 	M23_daedalus_guns = { 
  637. 		effects = { 
  638. 			"Vfx Daedalus Gun 01<001>", "Vfx Daedalus Gun 01<002>", "Vfx Daedalus Gun 01<003>", "Vfx Daedalus Gun 01<004>", "Vfx Daedalus Gun 01<005>", "Vfx Daedalus Gun 01<006>",  
  639. 			"Vfx Daedalus Gun 01<007>", "Vfx Daedalus Gun 01<008>", "Vfx Daedalus Gun 01<009>", "Vfx Daedalus Gun 01<010>", "Vfx Daedalus Gun 01<011>", "Vfx Daedalus Gun 01<012>",  
  640. 			 
  641. 			"Vfx Daedalus Gun 02<001>", "Vfx Daedalus Gun 02<002>", "Vfx Daedalus Gun 02<003>", "Vfx Daedalus Gun 02<004>", "Vfx Daedalus Gun 02<005>", "Vfx Daedalus Gun 02<006>",  
  642. 			"Vfx Daedalus Gun 02<007>", "Vfx Daedalus Gun 02<008>", "Vfx Daedalus Gun 02<009>", "Vfx Daedalus Gun 02<010>", "Vfx Daedalus Gun 02<011>", "Vfx Daedalus Gun 02<012>",  
  643. 			 
  644. 			"Vfx Daedalus Gun 03<001>", "Vfx Daedalus Gun 03<002>", "Vfx Daedalus Gun 03<003>", "Vfx Daedalus Gun 03<004>", "Vfx Daedalus Gun 03<005>", "Vfx Daedalus Gun 03<006>",  
  645. 			"Vfx Daedalus Gun 03<007>", "Vfx Daedalus Gun 03<008>", "Vfx Daedalus Gun 03<009>", "Vfx Daedalus Gun 03<010>", "Vfx Daedalus Gun 03<011>", "Vfx Daedalus Gun 03<012>",  
  646. 			"Vfx Daedalus Gun 03<013>", "Vfx Daedalus Gun 03<014>", "Vfx Daedalus Gun 03<015>", "Vfx Daedalus Gun 03<016>", "Vfx Daedalus Gun 03<017>", "Vfx Daedalus Gun 03<018>",  
  647. 			"Vfx Daedalus Gun 03<019>", "Vfx Daedalus Gun 03<020>",  
  648. 			 
  649. 			"Vfx Daedalus Gun 04<001>", "Vfx Daedalus Gun 04<002>",  
  650. 		}, 
  651. 		 
  652. 		threads = { 
  653. 			[1] = INVALID_THREAD_HANDLE, 
  654. 			[2] = INVALID_THREAD_HANDLE, 
  655. 			[3] = INVALID_THREAD_HANDLE, 
  656. 			[4] = INVALID_THREAD_HANDLE, 
  657. 			[5] = INVALID_THREAD_HANDLE, 
  658. 			[6] = INVALID_THREAD_HANDLE, 
  659. 			[7] = INVALID_THREAD_HANDLE, 
  660. 			[8] = INVALID_THREAD_HANDLE, 
  661. 			[9] = INVALID_THREAD_HANDLE, 
  662. 			[10] = INVALID_THREAD_HANDLE, 
  663. 		}, 
  664. 		 
  665. 		active_effect_handles = { 
  666. 			[1] = -1, 
  667. 			[2] = -1, 
  668. 			[3] = -1, 
  669. 			[4] = -1, 
  670. 			[5] = -1, 
  671. 			[6] = -1, 
  672. 			[7] = -1, 
  673. 			[8] = -1, 
  674. 			[9] = -1, 
  675. 			[10] = -1, 
  676. 		}, 
  677. 		 
  678. 		active_audio_loops = { 
  679. 			[1] = -1, 
  680. 			[2] = -1, 
  681. 			[3] = -1, 
  682. 			[4] = -1, 
  683. 			[5] = -1, 
  684. 			[6] = -1, 
  685. 			[7] = -1, 
  686. 			[8] = -1, 
  687. 			[9] = -1, 
  688. 			[10] = -1, 
  689. 		}, 
  690. 	} 
  691. 	 
  692. 	M23_explosions = { 
  693. 		effect = "VTOL_M_Exp-NPC", 
  694. 		 
  695. 		self_destruct_begin_explosions = { "warning_splosion <001>", "warning_splosion <002>", "warning_splosion <003>" }, 
  696.  
  697. 		self_destruct_explosions = {	"self_destruct_splosion <001>", "self_destruct_splosion <002>", "self_destruct_splosion <003>", 
  698. 										"self_destruct_splosion <004>", "self_destruct_splosion <005>", "self_destruct_splosion <006>", 
  699. 										"self_destruct_splosion <007>", "self_destruct_splosion <008>", "self_destruct_splosion <009>", 
  700. 										"self_destruct_splosion <010>", "self_destruct_splosion <011>", "self_destruct_splosion <012>", 
  701. 										"self_destruct_splosion <013>", "self_destruct_splosion <014>", "self_destruct_splosion <015>", 
  702. 										"self_destruct_splosion <016>", "self_destruct_splosion <017>", "self_destruct_splosion <018>", 
  703. 										"self_destruct_splosion <019>", "self_destruct_splosion <020>", "self_destruct_splosion <021>", 
  704. 										"self_destruct_splosion <022>" }, 
  705. 										 
  706. 		vtol_escape_explosions = {	"self_destruct_splosion <023>", "self_destruct_splosion <024>", "self_destruct_splosion <025>", 
  707. 										"self_destruct_splosion <026>", "self_destruct_splosion <027>", "self_destruct_splosion <028>", 
  708. 										"self_destruct_splosion <029>", }, 
  709. 	} 
  710. 	 
  711. 	M23_smoke = { 
  712. 		city_carnage = { "vfx_smoke_city 001", "vfx_smoke_city 002", "vfx_smoke_city 003", "vfx_smoke_city 004", "vfx_smoke_city 005" }, 
  713. 		daedalus_rear = { "vfx_smoke_rear 001", "vfx_smoke_rear 002", "vfx_smoke_rear 003", "vfx_smoke_rear 004" }, 
  714. 		daedalus_fore = { "vfx_smoke_fore 001", "vfx_smoke_fore 002", "vfx_smoke_fore 003" }, 
  715. 	} 
  716. 	 
  717.  
  718. 	M23_flags = { 
  719. 		showed_courtesy_helis = false, 
  720. 		player_entered_saints_hq = false, 
  721. 		player_got_heli = { false, false }, 
  722. 		daedalus_airspace_entered = false, 
  723. 		daedalus_defensive_area_entered = false, 
  724. 		daedalus_landing_complete = false, 
  725. 		destruct_start = false, 
  726. 		cyrus_vtol_destroyed = false, 
  727. 		escape_timer_expired = false, 
  728. 		do_cyrus_reinforcements = false, 
  729. 		cyrus_final_phase = false, 
  730. 		cyrus_fly_left_to_right = true, 
  731. 		local_player_escaped = false, 
  732. 		remote_player_escaped = false, 
  733. 		daedalus_main_cannons_firing = false, 
  734. 		play_kinzie_call_on_next_vehicle_enter = false, 
  735. 		daedalus_gunfire_enabled_local = false, 
  736. 		daedalus_gunfire_enabled_remote = false, 
  737. 		leaving_daedalus_fails_mission = false, 
  738. 	} 
  739. 	 
  740. 	M23_runtime = { 
  741. 		daedalus_guns_alive = 0, 
  742. 		daedalus_surface_tanks_alive = 0, 
  743. 		cyrus_taunt_idx = 0, 
  744. 		local_player_last_vehicle = nil, 
  745. 		remote_player_last_vehicle = nil, 
  746. 		cur_bomb_planted = false, 
  747. 		cur_cell_call = "", 
  748. 		ambush_groups = { }, 
  749. 	} 
  750. 	 
  751. 	M23_bomb_triggers = { 
  752. 		landing_deck_bomb_1 = { 
  753. 			trigger_name = "tgr_plant_bomb_1", 
  754. 			minimap_icon = MINIMAP_ICON_USE,  
  755. 			ingame_effect = INGAME_EFFECT_LOCATION,  
  756. 			oi_asset = OI_ASSET_USE,  
  757. 			oi_flags = OI_FLAGS_LOCATION, 
  758. 			objective = M23_objectives.plant_bombs, 
  759. 			play_bomb_anim = true, 
  760. 			anim_nav = "bomb_1_anim_orient", 
  761. 		}, 
  762. 		landing_deck_bomb_2 = { 
  763. 			trigger_name = "tgr_plant_bomb_2", 
  764. 			minimap_icon = MINIMAP_ICON_USE,  
  765. 			ingame_effect = INGAME_EFFECT_LOCATION,  
  766. 			oi_asset = OI_ASSET_USE,  
  767. 			oi_flags = OI_FLAGS_LOCATION, 
  768. 			objective = M23_objectives.plant_bombs, 
  769. 			play_bomb_anim = true, 
  770. 			anim_nav = "bomb_2_anim_orient", 
  771. 		}, 
  772. 		fly_to_side = { 
  773. 			trigger_name = "tgr_fly_to_side", 
  774. 			minimap_icon = MINIMAP_ICON_LOCATION,  
  775. 			ingame_effect = INGAME_EFFECT_LOCATION,  
  776. 			oi_asset = OI_ASSET_LOCATION,  
  777. 			oi_flags = OI_FLAGS_LOCATION, 
  778. 			objective = M23_objectives.fly_to_rear_deck, 
  779. 			play_bomb_anim = false, 
  780. 		}, 
  781. 		side_deck_bomb = { 
  782. 			trigger_name = "tgr_plant_bomb_3", 
  783. 			minimap_icon = MINIMAP_ICON_USE,  
  784. 			ingame_effect = INGAME_EFFECT_LOCATION,  
  785. 			oi_asset = OI_ASSET_USE,  
  786. 			oi_flags = OI_FLAGS_LOCATION, 
  787. 			objective = M23_objectives.plant_bombs, 
  788. 			play_bomb_anim = true, 
  789. 			anim_nav = "bomb_3_anim_orient", 
  790. 		}, 
  791. 		fly_to_rear = { 
  792. 			trigger_name = "tgr_fly_to_rear", 
  793. 			minimap_icon = MINIMAP_ICON_LOCATION,  
  794. 			ingame_effect = INGAME_EFFECT_LOCATION,  
  795. 			oi_asset = OI_ASSET_LOCATION,  
  796. 			oi_flags = OI_FLAGS_LOCATION, 
  797. 			objective = M23_objectives.fly_to_rear_deck, 
  798. 			play_bomb_anim = false, 
  799. 		}, 
  800. 		rear_deck_bomb = { 
  801. 			trigger_name = "tgr_plant_bomb_4", 
  802. 			minimap_icon = MINIMAP_ICON_USE,  
  803. 			ingame_effect = INGAME_EFFECT_LOCATION,  
  804. 			oi_asset = OI_ASSET_USE,  
  805. 			oi_flags = OI_FLAGS_LOCATION, 
  806. 			objective = M23_objectives.plant_bombs, 
  807. 			play_bomb_anim = true, 
  808. 			anim_nav = "bomb_4_anim_orient", 
  809. 		}, 
  810. 	} 
  811. 	 
  812. 	M23_audio_emitters = { 
  813. 		daedalus_alarm = "M23_alarm", 
  814. 	} 
  815.  
  816.  
  817. -- ************************* 
  818. -- 
  819. -- Standard functions 
  820. -- 
  821. -- ************************* 
  822.  
  823. -- This is the primary entry point for the mission, and is responsible for starting up the mission 
  824. -- at the specified checkpoint. 
  825. -- CALLED FROM CODE 
  826. -- 
  827. -- m23_checkpoint:	The checkpoint the mission should begin at 
  828. -- is_restart:					TRUE if the mission is restarting, FALSE otherwise 
  829. -- 
  830. function m23_start(m23_checkpoint, is_restart) 
  831. 	 
  832. 	-- Check if this mission starting from the beginning 
  833. 	if (m23_checkpoint == M23_checkpoints.start.name) then 
  834. 		if (is_restart == false) then 
  835. 			-- First time playing mission 
  836. 			 
  837. 			-- Play an intro cutscene??? 
  838. 			if (M23_cutscenes.intro ~= "") then 
  839. 				cutscene_play(M23_cutscenes.intro, nil, {M23_checkpoints.start.player_starts[1], M23_checkpoints.start.player_starts[2]}, false) 
  840. 			end 
  841. 		end 
  842. 	end 
  843.  
  844. 	-- Handle mission initialization for the current checkpoint 
  845. 	m23_initialize(m23_checkpoint, is_restart) 
  846.  
  847. 	-- Run the mission from the current checkpoint 
  848. 	m23_run(m23_checkpoint) 
  849. 	 
  850. end 
  851.  
  852. -- This is the primary function responsible for running the entire mission from start to finish. 
  853. -- 
  854. -- first_checkpoint:	The first checkpoint to begin running the mission at 
  855. -- 
  856. function m23_run(first_checkpoint) 
  857. 	local current_checkpoint = first_checkpoint 
  858. 	 
  859. 	mission_set_cancel_warp_location(M23_checkpoints.start.player_starts[1], M23_checkpoints.start.player_starts[2]) 
  860.  
  861. 	-- Run the mission from the beginning 
  862. 	if (current_checkpoint == M23_checkpoints.start.name) then 
  863. 		m23_get_to_saints_hq() 
  864. 		 
  865. 		-- Set the checkpoint 
  866. 		current_checkpoint = M23_checkpoints.saints_hq.name 
  867. 		mission_set_checkpoint(M23_checkpoints.saints_hq.name, true) 
  868. 	end 
  869. 	 
  870. 	mission_set_cancel_warp_location(M23_checkpoints.saints_hq.player_starts[1], M23_checkpoints.saints_hq.player_starts[2]) 
  871. 	 
  872. 	if (current_checkpoint == M23_checkpoints.saints_hq.name) then 
  873. 		m23_aquire_helicopter() 
  874. 		 
  875. 		m23_get_to_daedalus() 
  876. 		 
  877. 		--m23_approach_daedalus_landing_area() 
  878. 		m23_daedalus_destroy_guns() 
  879. 		-- m23_daedalus_destroy_tanks() 
  880. 		m23_land_on_the_daedalus() 
  881. 		 
  882. 		-- Set the checkpoint 
  883. 		current_checkpoint = M23_checkpoints.landing_deck.name 
  884. 		mission_set_checkpoint(M23_checkpoints.landing_deck.name, true) 
  885. 	end 
  886. 		 
  887. 	-- At this point, if a player leaves the Daedalus, they fail the mission. 
  888. 	M23_flags.leaving_daedalus_fails_mission = true 
  889. 	 
  890. 	if (current_checkpoint == M23_checkpoints.landing_deck.name) then		 
  891. 		character_ragdoll_set_last_resort_position(M23_checkpoints.landing_deck.player_starts[1]) 
  892. 		 
  893. 		audio_ambient_emitter_start(M23_audio_emitters.daedalus_alarm) 
  894. 	 
  895. 		m23_plant_bombs() 
  896. 		 
  897. 		audio_ambient_emitter_stop(M23_audio_emitters.daedalus_alarm) 
  898. 		 
  899. 		-- Set the checkpoint 
  900. 		current_checkpoint = M23_checkpoints.bridge.name 
  901. 		mission_set_checkpoint(M23_checkpoints.bridge.name, true) 
  902. 	end 
  903. 	 
  904. 	if (current_checkpoint == M23_checkpoints.bridge.name) then 
  905. 		character_ragdoll_set_last_resort_position(M23_checkpoints.bridge.player_starts[1]) 
  906. 		 
  907. 		m23_cyrus_fly_by() 
  908. 	 
  909. 		-- Progress music. 
  910. 		m23_post_music_event(M23_music.cyrus_fight) 
  911. 		 
  912. 		m23_kill_cyrus() 
  913. 		m23_play_cyrus_death_scene() 
  914. 		 
  915. 		-- Set the checkpoint 
  916. 		current_checkpoint = M23_checkpoints.escape.name 
  917. 		mission_set_checkpoint(M23_checkpoints.escape.name, true) 
  918. 	end 
  919. 	 
  920. 	-- At this point, the players no longer fail for leaving the Daedalus. 
  921. 	M23_flags.leaving_daedalus_fails_mission = false 
  922. 	 
  923. 	if (current_checkpoint == M23_checkpoints.escape.name) then 
  924. 		character_ragdoll_set_last_resort_position(M23_checkpoints.escape.player_starts[1]) 
  925. 		 
  926. 		m23_escape_from_daedalus() 
  927. 	end 
  928. 	 
  929. 	--m23_success() -- Called from C after mission_end_success 
  930. 	 
  931. 	fade_out(0.5) 
  932. 	fade_out_block() 
  933. 	 
  934. 	city_zone_swap("daedext1", DISABLE) -- remove daedalus exterior 
  935. 	 
  936. 	delay(1.0) 
  937. 	 
  938. 	-- Call mission success?? 
  939. 	mission_end_success("m23", M23_cutscenes.outro, M23_navpoints.mission_end) 
  940. end 
  941.  
  942. -- This is the primary function responsible for cleaning up the entire mission 
  943. -- CALLED FROM CODE (+++MUST RETURN IMMEDIATLY+++) 
  944. -- 
  945. function m23_cleanup() 
  946. 	-- Call all of the clean-up functions for each section of this mission 
  947. 	m23_cleanup_aquire_heli() 
  948. 	m23_cleanup_get_to_daedalus() 
  949. 	--m23_cleanup_approach_daedalus_landing_area() 
  950. 	--m23_cleanup_daedalus_destroy_tanks() 
  951. 	m23_cleanup_daedalus_destroy_guns() 
  952. 	m23_cleanup_land_on_the_daedalus() 
  953. 	m23_cleanup_plant_bombs() 
  954. 	m23_cleanup_cyrus_fly_by() 
  955. 	m23_cleanup_kill_cyrus() 
  956. 	m23_cleanup_escape_from_daedalus() 
  957. 	m23_cleanup_cyrus_death_scene() 
  958. 	m23_exited_daedalus_gunfire(nil, nil, nil, true) 
  959. 	 
  960. 	-- Destroy any active continous spawn groups 
  961. 	m23_cleanup_landing_deck_cont_spawn(true) 
  962. 	 
  963. 	-- Clear the any notoriety 
  964. 	notoriety_reset("police") 
  965. 	-- notoriety_set_desired_vehicle_count("police", -1) 
  966. 	m23_set_notoriety_aircraft_enabled(true) 
  967. 	-- set_stag_active(false) -- Commented this out because we are setting it now only with mission success because of critical path -JB 
  968. 	 
  969. 	-- Clear all the peds fleeing, and stop the continuous explosion 
  970. 	set_civilians_flee(false) 
  971. 	continuous_explosion_stop() 
  972. 	 
  973. 	-- Make sure any triggers have been disabled 
  974. 	for i, trigger in pairs(M23_triggers) do 
  975. 		on_trigger("", trigger) 
  976. 		on_trigger_exit("", trigger) 
  977. 		trigger_enable(trigger, false) 
  978. 		marker_remove_trigger(trigger) 
  979. 	end 
  980. 	 
  981. 	-- Cleanup kill regions 
  982. 	for i, region in pairs(M23_kill_regions) do 
  983. 		trigger_enable(region, false) 
  984. 		on_trigger("", region) 
  985. 		marker_remove_trigger(region) 
  986. 	end 
  987. 	 
  988. 	-- Make sure all groups have been destroyed 
  989. 	for i, group in pairs(M23_groups) do 
  990. 		if (group_is_loaded(group.name) == true) then 
  991. 			group_destroy(group.name) 
  992. 		end 
  993. 	end 
  994. 	 
  995. 	-- Make sure all threads are inactive 
  996. 	for i, thread in pairs(M23_threads) do 
  997. 		if (thread ~= -1 and thread_check_done(thread) == false) then 
  998. 			thread_kill(thread) 
  999. 		end 
  1000. 	end 
  1001. 	 
  1002. 	-- Make sure all the threads processing the dog-fights are cleaned up 
  1003. 	if (M23_groups.dog_fight_01.thread_id ~= -1 and thread_check_done(M23_groups.dog_fight_01.thread_id) == false) then 
  1004. 		thread_kill(M23_groups.dog_fight_01.thread_id) 
  1005. 	end 
  1006. 	if (M23_groups.dog_fight_02.thread_id ~= -1 and thread_check_done(M23_groups.dog_fight_02.thread_id) == false) then 
  1007. 		thread_kill(M23_groups.dog_fight_02.thread_id) 
  1008. 	end	 
  1009. 	 
  1010. 	--[[ 
  1011. 	-- Make sure all the threads processing the VTOLs taking off are cleaned up 
  1012. 	for i, vtol in pairs(M23_groups.attack_vtols_01.vtols) do 
  1013. 		if (vtol.thread_id ~= -1 and thread_check_done(vtol.thread_id) == false) then 
  1014. 			thread_kill(vtol.thread_id) 
  1015. 		end 
  1016. 	end 
  1017. 	--]] 
  1018. 	 
  1019. 	-- Make sure all the threads processing the guys running to their tanks are cleaned up 
  1020. 	for i, tank in pairs(M23_groups.daedalus_tanks_02.tanks) do 
  1021. 		for j, char in pairs(tank.chars) do 
  1022. 			if (tank.thread_ids[j] ~= -1 and thread_check_done(tank.thread_ids[j]) == false) then 
  1023. 				thread_kill(tank.thread_ids[j]) 
  1024. 			end 
  1025. 		end 
  1026. 	end 
  1027. 	 
  1028. 	-- Unload off-screen personas 
  1029. 	for i, persona in pairs(M23_personas) do 
  1030. 		if (persona.persona_id ~= -1) then 
  1031. 			audio_persona_remove_2d(persona.persona_id) 
  1032. 			persona.persona_id = -1 
  1033. 		end 
  1034. 	end 
  1035. 	 
  1036. 	-- Clean-up any conversations 
  1037. 	for i, convo in pairs(M23_conversations) do 
  1038. 		if (convo.handle ~= INVALID_CONVERSATION_HANDLE) then 
  1039. 			audio_conversation_end(convo.handle) 
  1040. 		end 
  1041. 	end 
  1042. 	 
  1043. 	-- Stop the explosions thread 
  1044. 	if (M23_threads.explosions ~= INVALID_THREAD_HANDLE) then 
  1045. 		thread_kill(M23_threads.explosions) 
  1046. 		M23_threads.explosions = INVALID_THREAD_HANDLE 
  1047. 	end 
  1048. 	 
  1049. 	-- Make sure the thread processing the Saints' landing deck reinforcements is killed. 
  1050. 	for i, group in pairs(M23_groups.saints_landing_deck_reinforcements.groups) do 
  1051. 		if (group.thread_id ~= -1 and thread_check_done(group.thread_id) == false) then 
  1052. 			thread_kill(group.thread_id) 
  1053. 			group.thread_id = -1 
  1054. 		end 
  1055. 	end 
  1056. 	 
  1057. 	m23_end_ambient_explosion_audio() 
  1058. 	m23_disable_mission_ambient_emitters() 
  1059. 	 
  1060. 	-- Clean up zone swaps. 
  1061. 	city_zone_swap("daedext1", DISABLE) -- remove daedalus exterior 
  1062. 	 
  1063. 	-- Tell audio to stop everything that's going on. 
  1064. 	audio_object_post_event("M23_unload") 
  1065. 	 
  1066. 	-- Stop any cell calls. 
  1067. 	audio_remove_mission_cellphone(M23_runtime.cur_cell_call) 
  1068. 	 
  1069. 	-- Stop using the mission specified ragdoll get up last resort. 
  1070. 	character_ragdoll_clear_last_resort_position() 
  1071. end 
  1072.  
  1073. -- Called when the mission has ended with success 
  1074. -- CALLED FROM CODE (+++MUST RETURN IMMEDIATLY+++) 
  1075. -- 
  1076. function m23_success() 
  1077. 	--[[ INSERT ANY MISSION SPECIFIC SUCCESS STUFF ]]-- 
  1078. 	-- if (M23_cutscenes.outro ~= "") then 
  1079. 	-- 	bink_play(M23_cutscenes.outro) 
  1080. 	-- end 
  1081. 	 
  1082. 	--'Win the Game' World State Changes  
  1083. 	local skip_teleport = true	 
  1084. 	m23_m24_coop_skip(skip_teleport) -- do the stuff we'd do in the skip case 
  1085.  
  1086. 	-- Stop music. 
  1087. 	m23_post_music_event(M23_music.stop_all) 
  1088. end 
  1089.  
  1090.  
  1091. -- ************************* 
  1092. -- 
  1093. -- Local functions 
  1094. -- 
  1095. -- ************************* 
  1096.  
  1097. -- Initialize the mission for the specified checkpoint 
  1098. -- 
  1099. -- checkpoint:		Checkpoint to initialize the mission to 
  1100. -- is_restart:      Whether or not the mission is being restarted. 
  1101. -- 
  1102. function m23_initialize(checkpoint, is_restart) 
  1103. 	-- Make sure the screen is completly faded out 
  1104. 	mission_start_fade_out(0.0) 
  1105.  
  1106. 	-- Set the mission author 
  1107. 	set_mission_author("matt.gawalek") 
  1108.  
  1109. 	-- Common initialization 
  1110. 	m23_initialize_common() 
  1111.  
  1112. 	-- Checkpoint specific initialization 
  1113. 	m23_initialize_checkpoint(checkpoint, is_restart) 
  1114.  
  1115. 	-- Start fading in  
  1116. 	mission_start_fade_in() 
  1117.  
  1118. end 
  1119.  
  1120. -- *************************************************** 
  1121. -- m23_initialize Helper Functions 
  1122. -- *************************************************** 
  1123.  
  1124. -- Handle any common initialization 
  1125. -- 
  1126. function m23_initialize_common()	 
  1127. 	-- Perform zone swaps 
  1128. 	city_zone_swap("daedext1", true) -- swap in the daedalus exterior 
  1129. 	 
  1130. 	-- Begin constant rumble-booms in the background. 
  1131. 	m23_begin_ambient_explosion_audio() 
  1132. 		 
  1133. 	-- Set up kill regions 
  1134. 	for i, region in pairs(M23_kill_regions) do 
  1135. 		trigger_enable(region, true) 
  1136. 		on_trigger("m23_engine_death_cb", region) 
  1137. 	end 
  1138. 	 
  1139. 	-- Turn on notoriety, but only spawn air units 
  1140. 	notoriety_spawn_only_air(true) 
  1141. 	set_stag_active(true) 
  1142. 	notoriety_set("police", 5) 
  1143. 	notoriety_set_can_decay(false) 
  1144. 		 
  1145. 	-- Spawn the initial script objects for the Daedalus 
  1146. 	group_create(M23_groups.ammo_stash_02.name, true) 
  1147. 	 
  1148. 	-- Create the second group of tanks, and hide all the characters 
  1149. 	group_create(M23_groups.daedalus_tanks_02.name, true) 
  1150. 	for i, tank in pairs(M23_groups.daedalus_tanks_02.tanks) do 
  1151. 		for j, char in pairs(tank.chars) do 
  1152. 			character_hide(char) 
  1153. 		end 
  1154. 	end 
  1155. 	 
  1156. 	group_create(M23_groups.daedalus_apc_01.name, true) 
  1157. 			 
  1158. 	-- Load off-screen personas 
  1159. 	for i, persona in pairs(M23_personas) do 
  1160. 		persona.persona_id = audio_persona_load_2d(persona.name) 
  1161. 	end 
  1162. 		 
  1163. 	M23_runtime.local_player_last_vehicle = nil 
  1164. 	M23_runtime.remote_player_last_vehicle = nil 
  1165. 	 
  1166. 	-- Activate the trigger to begin gunfire around the Daedalus. 
  1167. 	trigger_enable(M23_triggers.daedalus_gunfire, true) 
  1168. 	on_trigger("m23_entered_daedalus_gunfire", M23_triggers.daedalus_gunfire) 
  1169. 	on_trigger_exit("m23_exited_daedalus_gunfire", M23_triggers.daedalus_gunfire) 
  1170. end 
  1171.  
  1172. -- Begins the constant background explosion audio for the player. 
  1173. -- 
  1174. function m23_begin_ambient_explosion_audio() 
  1175. 	audio_object_post_event("M23_AMB_CITY_BOMBARDMENT", nil, nil, LOCAL_PLAYER) 
  1176. 	if coop_is_active() == true then 
  1177. 		audio_object_post_event("M23_AMB_CITY_BOMBARDMENT", nil, nil, REMOTE_PLAYER) 
  1178. 	end 
  1179. end 
  1180.  
  1181. -- Ends the constant background explosion audio for the player. 
  1182. -- 
  1183. function m23_end_ambient_explosion_audio() 
  1184. 	audio_object_post_event("M23_AMB_CITY_BOMBARDMENT_STOP", nil, nil, LOCAL_PLAYER) 
  1185. 	if coop_is_active() == true then 
  1186. 		audio_object_post_event("M23_AMB_CITY_BOMBARDMENT_STOP", nil, nil, REMOTE_PLAYER) 
  1187. 	end 
  1188. end 
  1189.  
  1190. -- Disables ambient emitters for this mission. 
  1191. -- 
  1192. function m23_disable_mission_ambient_emitters() 
  1193. 	for i, emitter in pairs(M23_audio_emitters) do 
  1194. 		audio_ambient_emitter_stop(emitter) 
  1195. 	end 
  1196. end 
  1197.  
  1198. -- Creates the group of VTOLs on the landing deck. 
  1199. function m23_create_landing_deck_vtols() 
  1200. 	group_create(M23_groups.daedalus_vtols_01.name, true) 
  1201. 	turn_invulnerable(M23_groups.daedalus_vtols_01.vtols[1]) 
  1202. 	on_vehicle_enter("m23_invuln_vtol_enter", M23_groups.daedalus_vtols_01.vtols[1]) 
  1203. end 
  1204.  
  1205. -- Detonates and then shortly destroys the landing deck VTOL group.  We need 
  1206. -- to do this to free up more high component vehicles. 
  1207. function m23_obliterate_landing_deck_vtols() 
  1208. 	if group_is_loaded(M23_groups.daedalus_vtols_01.name) then 
  1209. 		for i, vtol in pairs(M23_groups.daedalus_vtols_01.vtols) do 
  1210. 			vehicle_detonate(vtol) 
  1211. 		end 
  1212. 	end 
  1213. 	 
  1214. 	-- Delay regardless to keep timing consistent 
  1215. 	delay(3.0) 
  1216. 	 
  1217. 	if group_is_loaded(M23_groups.daedalus_vtols_01.name) then 
  1218. 		group_destroy(M23_groups.daedalus_vtols_01.name) 
  1219. 	end 
  1220. end 
  1221.  
  1222. -- Lights a character on fire, explodes them, and kills them. 
  1223. -- Basically it ruins their day. 
  1224. -- 
  1225. -- character:     (string) name of the character to kill 
  1226. -- light_on_fire: (bool, optional; default = false) whether or not we should light the character on fire 
  1227. -- explode:       (bool, optional; default = false) whether or not the character should explode 
  1228. -- allow_revive:  (bool, optional; default = true) whether or not the player should be revivable. 
  1229. -- 
  1230. function m23_insta_kill_character(character, light_on_fire, explode, allow_revive) 
  1231. 	if light_on_fire == true then 
  1232. 		character_ignite(character) 
  1233. 	end 
  1234. 	 
  1235. 	if explode == true then 
  1236. 		explosion_create("VTOL_M_Exp-NPC", character) 
  1237. 	end 
  1238. 	 
  1239. 	if allow_revive == nil then 
  1240. 		allow_revive = true 
  1241. 	end 
  1242. 	 
  1243. 	character_kill(character, true, nil, allow_revive) 
  1244. end 
  1245.  
  1246. -- Begins firing missiles from the Daedalus missile racks and the main cannons and starts up ambient emitters. 
  1247. function m23_entered_daedalus_gunfire(character, trigger) 
  1248. 	-- Make sure this is one of the players and if it is flag them as enabled for playing gunfire effects. 
  1249. 	if character == LOCAL_PLAYER then 
  1250. 		M23_flags.daedalus_gunfire_enabled_local = true 
  1251. 	elseif character == REMOTE_PLAYER then 
  1252. 		M23_flags.daedalus_gunfire_enabled_remote = true 
  1253. 	else 
  1254. 		-- Not a player. 
  1255. 		return 
  1256. 	end 
  1257.  
  1258. 	-- Only enable the missile racks if both players are in range. 
  1259. 	local missiles_enabled = true 
  1260. 	if coop_is_active() then 
  1261. 		-- Check both players. 
  1262. 		missiles_enabled = M23_flags.daedalus_gunfire_enabled_local and M23_flags.daedalus_gunfire_enabled_remote 
  1263. 	else 
  1264. 		-- Only need to check the local player. 
  1265. 		missiles_enabled = M23_flags.daedalus_gunfire_enabled_local 
  1266. 	end 
  1267. 	 
  1268. 	if missiles_enabled then 
  1269. 		for i, rack in pairs(M23_missile_racks) do 
  1270. 			rack.thread = thread_new("m23_missile_rack_thread", rack) 
  1271. 		end 
  1272. 	end 
  1273. 	 
  1274. 	-- Start up a gunfire thread if we don't have one running yet. 
  1275. 	if M23_threads.daedalus_guns_thread == INVALID_THREAD_HANDLE then 
  1276. 		M23_threads.daedalus_guns_thread = thread_new("m23_daedalus_guns_thread") 
  1277. 	end 
  1278. 	 
  1279. 	M23_flags.daedalus_main_cannons_firing = true 
  1280. end 
  1281.  
  1282. -- Stops any threads firing missiles from the Daedalus missile racks and stops ambient emitters. 
  1283. -- 
  1284. -- register_callback:  (bool) if true, we'll register a trigger callback to start 
  1285. --                        up the missiles firing again if the player gets close to 
  1286. --                        the Daedalus again. 
  1287. -- shut_it_all_down:   (bool, optional) if true, we shut everything down for both players, used during cleanup. 
  1288. -- 
  1289. function m23_exited_daedalus_gunfire(character, trigger, register_callback, shut_it_all_down) 
  1290. 	-- Make sure this is one of the players and if it is flag them as disabled for playing gunfire effects. 
  1291. 	if shut_it_all_down == true then 
  1292. 		-- Clean everything up. 
  1293. 		M23_flags.daedalus_gunfire_enabled_local = false 
  1294. 		M23_flags.daedalus_gunfire_enabled_remote = false 
  1295. 	else		 
  1296. 		if character == LOCAL_PLAYER then 
  1297. 			M23_flags.daedalus_gunfire_enabled_local = false 
  1298. 		elseif character == REMOTE_PLAYER then 
  1299. 			M23_flags.daedalus_gunfire_enabled_remote = false 
  1300. 		else 
  1301. 			-- Not a player. 
  1302. 			return 
  1303. 		end 
  1304. 	end 
  1305. 	 
  1306. 	-- If either player left the area, stop the missile racks.  Explosions tend 
  1307. 	-- to queue up and all go at once if they're created in an unloaded zone. 
  1308. 	for i, rack in pairs(M23_missile_racks) do 
  1309. 		if rack.thread ~= INVALID_THREAD_HANDLE then 
  1310. 			thread_kill(rack.thread) 
  1311. 			rack.thread = INVALID_THREAD_HANDLE 
  1312. 		end 
  1313. 	end	 
  1314. 	 
  1315. 	-- If both players left the area, stop the gunfire thread. 
  1316. 	if M23_flags.daedalus_gunfire_enabled_local == false and M23_flags.daedalus_gunfire_enabled_remote == false then 
  1317. 		M23_daedalus_guns.threads = cleanup_threads(M23_daedalus_guns.threads) 
  1318. 		M23_threads.daedalus_guns_thread = cleanup_threads(M23_threads.daedalus_guns_thread) 
  1319. 		m23_stop_all_daedalus_gun_effects() 
  1320. 	end 
  1321. 	 
  1322. 	M23_flags.daedalus_main_cannons_firing = false 
  1323. 	 
  1324. 	-- If a player exits this trigger after they've landed on the Daedalus, this is now a 
  1325. 	-- failure condition since we have to disable the crib garage. 
  1326. 	if M23_flags.leaving_daedalus_fails_mission == true then 
  1327. 		mission_end_failure("m23", "m23_failure_cyrus_escaped") 
  1328. 	end 
  1329. end 
  1330.  
  1331. -- Callback function for when the player enters the invulnerable VTOL. 
  1332. function m23_invuln_vtol_enter(player, vehicle, seat) 
  1333. 	turn_vulnerable(vehicle) 
  1334. 	on_vehicle_enter("", vehicle) 
  1335. end 
  1336.  
  1337. -- Callback function for when the player flies a vehicle/lands in the engines 
  1338. function m23_engine_death_cb(char, trigger) 
  1339. 	if character_is_in_vehicle(char) then 
  1340. 		vehicle_detonate(get_char_vehicle_name(char)) 
  1341. 	end 
  1342. 	 
  1343. 	delay(1.0) 
  1344. 	m23_insta_kill_character(char, true) 
  1345. end 
  1346.  
  1347. -- Helper function that spawns and sets up the initial stuff for 
  1348. -- the mission.  Used by the first two checkpoints. 
  1349. -- 
  1350. function m23_initialize_start_common()		 
  1351. 	-- Create all the mission start script objects 
  1352. 	group_create(M23_groups.mission_start.name, true) 
  1353. 	 
  1354. 	-- Setup the courtesy helicopters (invulnerable + infinite mass) 
  1355. 	for i, heli in pairs(M23_groups.courtesy_helis.vehicles) do 
  1356. 		turn_invulnerable(heli) 
  1357. 		vehicle_infinite_mass(heli, true) 
  1358. 	end 
  1359. 	 
  1360. 	-- Set all the peds fleeing from the Daedalus and start a continuous explosion 
  1361. 	set_ped_density(1.0) 
  1362. 	set_traffic_density(1.0) 
  1363. 	set_civilians_flee(true, false) 
  1364. 	continuous_explosion_start("Daedalus", M23_navpoints.daedalus_landing_pos) 
  1365. 	continuous_explosion_follow_target_add(LOCAL_PLAYER) 
  1366. 	continuous_explosion_avoid_object_add(LOCAL_PLAYER) 
  1367. 	if (coop_is_active() == true) then 
  1368. 		continuous_explosion_follow_target_add(REMOTE_PLAYER) 
  1369. 		continuous_explosion_avoid_object_add(REMOTE_PLAYER) 
  1370. 	end 
  1371. 	 
  1372. 	for i, vfx in pairs(M23_smoke.city_carnage) do 
  1373. 		effect_play(vfx, true) 
  1374. 	end 
  1375.  
  1376. 	-- Add the courtesy vehicles to the continuous explosion avoid list 
  1377. 	continuous_explosion_avoid_object_add(M23_groups.mission_start.courtesy_cars[1]) 
  1378. 	if (coop_is_active() == true) then 
  1379. 		continuous_explosion_avoid_object_add(M23_groups.mission_start.courtesy_cars[2]) 
  1380. 	else  
  1381. 		-- If coop isn't active, then hide the second courtesy vehicles 
  1382. 		vehicle_hide(M23_groups.mission_start.courtesy_cars[2]) 
  1383. 	end 
  1384. 	 
  1385. 	for i, heli in pairs(M23_groups.courtesy_helis.vehicles) do 
  1386. 		continuous_explosion_avoid_object_add(heli) 
  1387. 	end 
  1388. 	 
  1389. 	-- Create the script group for the daedalus tanks 
  1390. 	group_create(M23_groups.daedalus_tanks_01.name, true) 
  1391. 	for i, tank in pairs(M23_groups.daedalus_tanks_01.tanks) do 
  1392. 		vehicle_suppress_npc_exit(tank.vehicle, true) 
  1393. 		 
  1394. 		vehicle_enter_group_teleport(tank.chars, tank.vehicle) 
  1395. 		--vehicle_enter_teleport(tank.chars[1], tank.vehicle, 1) 
  1396. 		--vehicle_enter_teleport(tank.chars[2], tank.vehicle, 2) 
  1397. 		 
  1398. 		-- Make the tank stationary 
  1399. 		vehicle_disable_chase(tank.vehicle, true) 
  1400. 		vehicle_disable_flee(tank.vehicle, true) 
  1401. 	end 
  1402. 	 
  1403. 	--[[ 
  1404. 	-- Create the script group for the attack VTOLs 
  1405. 	group_create(M23_groups.attack_vtols_01.name, true) 
  1406. 	for i, vtol in pairs(M23_groups.attack_vtols_01.vtols) do 
  1407. 		for j, char in pairs(vtol.chars) do 
  1408. 			vehicle_enter_teleport(char, vtol.vehicle, (j - 1)) 
  1409. 		end 
  1410. 	end 
  1411. 	--]] 
  1412. end 
  1413.  
  1414. -- Checkpoint specific initialization 
  1415. -- 
  1416. -- checkpoint:		The checkpoint to be initialized 
  1417. -- is_restart:      Whether or not the mission is being restarted. 
  1418. -- 
  1419. function m23_initialize_checkpoint(checkpoint, is_restart) 
  1420. 	if (checkpoint == M23_checkpoints.start.name) then 
  1421. 		if is_restart then 
  1422. 			-- Teleport the players into position if we're restarting.  Otherwise the cutscene will do this. 
  1423. 			teleport_coop(M23_checkpoints.start.player_starts[1], M23_checkpoints.start.player_starts[2]) 
  1424. 		end 
  1425. 		 
  1426. 		-- Create the courtesy helicopters hidden, and unhide them when the player gets closer. 
  1427. 		group_create_hidden(M23_groups.courtesy_helis.name, true) 
  1428. 		trigger_enable(M23_triggers.saints_hq_activate_helis, true) 
  1429. 		on_trigger("m23_saints_hq_activate_helis_cb", M23_triggers.saints_hq_activate_helis) 
  1430. 		 
  1431. 		m23_initialize_start_common() 
  1432. 		m23_create_landing_deck_vtols() 
  1433. 		 
  1434. 		--[[ TODO: This should be unnecessary once the saints HQ crib is up and running ]]-- 
  1435. 		-- Setup the trigger for the Saint's HQ 
  1436. 		--trigger_enable(M23_triggers.saints_hq_elev_up, true) 
  1437. 		trigger_enable(M23_triggers.saints_hq_elev_down, true) 
  1438. 		trigger_enable(M23_triggers.saints_hq_gps, true) 
  1439. 		on_trigger("", M23_triggers.saints_hq_elev_up) 
  1440. 		on_trigger("m23_saints_hq_elev_down_cb", M23_triggers.saints_hq_elev_down) 
  1441. 		on_trigger("m23_saints_hq_gps_cb", M23_triggers.saints_hq_gps) 
  1442. 		--[[ END TODO ]]-- 
  1443. 		 
  1444. 		m23_post_music_event(M23_music.mission_start) 
  1445. 	end 
  1446. 	 
  1447. 	if (checkpoint == M23_checkpoints.saints_hq.name) then 
  1448. 		-- Teleport the players into position 
  1449. 		teleport_coop(M23_checkpoints.saints_hq.player_starts[1], M23_checkpoints.saints_hq.player_starts[2]) 
  1450. 		 
  1451. 		group_create(M23_groups.courtesy_helis.name, true) 
  1452. 		m23_initialize_start_common() 
  1453. 		m23_create_landing_deck_vtols() 
  1454. 		 
  1455. 		m23_post_music_event(M23_music.checkpoint_saints_hq) 
  1456. 	end 
  1457. 	 
  1458. 	if (checkpoint == M23_checkpoints.landing_deck.name) then		 
  1459. 		-- Teleport the players into position 
  1460. 		teleport_coop(M23_checkpoints.landing_deck.player_starts[1], M23_checkpoints.landing_deck.player_starts[2]) 
  1461. 		 
  1462. 		m23_set_notoriety_aircraft_enabled(false) 
  1463. 	 
  1464. 		m23_entered_daedalus_gunfire(LOCAL_PLAYER) 
  1465. 		if coop_is_active() then 
  1466. 			m23_entered_daedalus_gunfire(REMOTE_PLAYER) 
  1467. 		end 
  1468. 		 
  1469. 		-- Start the continious spawn on the landing deck 
  1470. 		m23_setup_landing_deck_cont_spawn() 
  1471. 		m23_create_landing_deck_vtols() 
  1472. 		 
  1473. 		m23_post_music_event(M23_music.checkpoint_daedalus) 
  1474. 	end 
  1475. 	 
  1476. 	if (checkpoint == M23_checkpoints.bridge.name) then 
  1477. 		-- Teleport the players into position 
  1478. 		teleport_coop(M23_checkpoints.bridge.player_starts[1], M23_checkpoints.bridge.player_starts[2]) 
  1479. 		 
  1480. 		m23_set_notoriety_aircraft_enabled(false) 
  1481. 	 
  1482. 		m23_entered_daedalus_gunfire(LOCAL_PLAYER) 
  1483. 		if coop_is_active() then 
  1484. 			m23_entered_daedalus_gunfire(REMOTE_PLAYER) 
  1485. 		end 
  1486. 	end 
  1487. 	 
  1488. 	if (checkpoint == M23_checkpoints.escape.name) then 
  1489. 		-- Teleport the players into position 
  1490. 		teleport_coop(M23_checkpoints.escape.player_starts[1], M23_checkpoints.escape.player_starts[2]) 
  1491. 		 
  1492. 		m23_post_music_event(M23_music.checkpoint_cyrus_fight) 
  1493. 		 
  1494. 		audio_object_post_event("M23_SFX_DAEDALUS_SELF_DESTRUCT", nil, nil, M23_navpoints.daedalus_self_destruct_audio_pos) 
  1495. 		 
  1496. 		m23_set_notoriety_aircraft_enabled(false) 
  1497. 	end 
  1498. end 
  1499.  
  1500.  
  1501. -- *************************************************** 
  1502. -- m23_run Helper Functions 
  1503. -- *************************************************** 
  1504.  
  1505. -- Returns which player(s) are in range to see the gunfire effects on the Daedalus. 
  1506. -- 
  1507. function m23_get_daedalus_gunfire_sync_flags() 
  1508. 	local sync_flags = SYNC_ALL 
  1509. 	if M23_flags.daedalus_gunfire_enabled_local ~= true then 
  1510. 		sync_flags = SYNC_REMOTE 
  1511. 	end 
  1512. 	if M23_flags.daedalus_gunfire_enabled_remote ~= true then 
  1513. 		if sync_flags ~= SYNC_ALL then 
  1514. 			return -1 
  1515. 		end 
  1516. 		 
  1517. 		sync_flags = SYNC_LOCAL 
  1518. 	end 
  1519. 	 
  1520. 	return sync_flags 
  1521. end 
  1522.  
  1523. -- Posts a music audio event. 
  1524. function m23_post_music_event(event_name) 
  1525. 	audio_object_post_event(event_name, nil, nil, LOCAL_PLAYER) 
  1526. end 
  1527.  
  1528. function m23_cell_convo_finished() 
  1529. 	M23_runtime.cur_cell_call = "" 
  1530. end 
  1531.  
  1532. function m23_play_cell_convo(conv_name, receiving_call, persona_override_id) 
  1533. 	while M23_runtime.cur_cell_call ~= "" do 
  1534. 		thread_yield() 
  1535. 	end 
  1536. 	M23_runtime.cur_cell_call = conv_name 
  1537. 	audio_play_for_mission_cellphone(conv_name, receiving_call, true, "", "m23_cell_convo_finished", persona_override_id) 
  1538. 	while M23_runtime.cur_cell_call ~= "" do 
  1539. 		thread_yield() 
  1540. 	end 
  1541. end 
  1542.  
  1543. -- Stops all the gun effects from the Daedalus. 
  1544. -- 
  1545. function m23_stop_all_daedalus_gun_effects() 
  1546. 	for i in pairs(M23_daedalus_guns.active_effect_handles) do 
  1547. 		if M23_daedalus_guns.active_effect_handles[i] ~= -1 then 
  1548. 			-- Stop the effect. 
  1549. 			effect_stop(M23_daedalus_guns.active_effect_handles[i]) 
  1550. 			M23_daedalus_guns.active_effect_handles[i] = -1 
  1551. 		end 
  1552. 	end 
  1553. 		 
  1554. 	for i in pairs(M23_daedalus_guns.active_audio_loops) do 
  1555. 		if M23_daedalus_guns.active_audio_loops[i] > 0 then 
  1556. 			-- Stop the audio. 
  1557. 			audio_stop(M23_daedalus_guns.active_audio_loops[i]) 
  1558. 			M23_daedalus_guns.active_audio_loops[i] = -1 
  1559. 		end 
  1560. 	end 
  1561. end 
  1562.  
  1563. -- Have Cyrus fly a path for the boss battle. 
  1564. function m23_cyrus_pathfind(left_to_right_path, right_to_left_path, speed) 
  1565. 	local path_name = "" 
  1566. 	if M23_flags.cyrus_fly_left_to_right == true then 
  1567. 		path_name = left_to_right_path 
  1568. 	else 
  1569. 		path_name = right_to_left_path 
  1570. 	end 
  1571. 	if (helicopter_fly_to_direct_dont_stop(M23_groups.cyrus_vtol.vtol, speed, path_name) == false) then 
  1572. 		--message("Failed path: " .. path_name, 4.0) 
  1573. 	end 
  1574. end 
  1575.  
  1576. -- Get to the Saints HQ 
  1577. function m23_get_to_saints_hq() 
  1578. 	-- Set the objective text 
  1579. 	objective_text(0, M23_objectives.get_helicopter.tag, nil, nil, SYNC_ALL, M23_objectives.get_helicopter.icon) 
  1580.  
  1581. 	-- Add a waypoint to the Saint's HQ 
  1582. 	mission_waypoint_add(M23_navpoints.saints_hq_gps, SYNC_ALL) 
  1583. 	--marker_add_trigger(M23_triggers.saints_hq_gps, MINIMAP_ICON_LOCATION, INGAME_EFFECT_LOCATION, OI_ASSET_LOCATION, OI_FLAGS_LOCATION, SYNC_ALL) 
  1584. 	marker_add_trigger(M23_triggers.saints_hq_elev_up, MINIMAP_ICON_LOCATION, INGAME_EFFECT_LOCATION, OI_ASSET_LOCATION, OI_FLAGS_LOCATION, SYNC_ALL) 
  1585. 	 
  1586. 	-- Kick off a thread to process the VO for the mission start 
  1587. 	M23_threads.mission_start_vo = thread_new("m23_thread_process_mission_start_vo") 
  1588. 	 
  1589. 	-- Set up the trigger at the top of the elevator. 
  1590. 	trigger_enable(M23_triggers.saints_hq_entry, true) 
  1591. 	on_trigger("m23_saints_hq_entry_cb", M23_triggers.saints_hq_entry) 
  1592.  
  1593. 	-- Register a callback for when a player enters a vehicle 
  1594. 	on_vehicle_enter("m23_player_entered_vehicle_cb", LOCAL_PLAYER) 
  1595. 	if (coop_is_active() == true) then 
  1596. 		on_vehicle_enter("m23_player_entered_vehicle_cb", REMOTE_PLAYER) 
  1597. 	end 
  1598. 	 
  1599. 	-- Wait for a player to enter the Saints HQ or get a heli elsewhere 
  1600. 	while (M23_flags.player_entered_saints_hq == false and M23_flags.player_got_heli[1] == false and M23_flags.player_got_heli[2] == false) do 
  1601. 		thread_yield() 
  1602. 	end 
  1603. 	 
  1604. 	m23_cleanup_get_to_saints_hq() 
  1605. end 
  1606.  
  1607. -- Thread to process the series of phone call to the player from the Saints 
  1608. function m23_thread_process_mission_start_vo() 
  1609. 	M23_conversations.mission_start.handle = audio_conversation_load(M23_conversations.mission_start.name) 
  1610. 	audio_conversation_play(M23_conversations.mission_start.handle) 
  1611. 	audio_conversation_wait_for_end(M23_conversations.mission_start.handle) 
  1612. 	 
  1613. 	delay(6.0) 
  1614.  
  1615. 	m23_play_cell_convo(M23_dialog_lines.oleg_phone_call, true, M23_personas.oleg.persona_id) 
  1616. 	 
  1617. 	delay(6.0) 
  1618. 	local audio_id = audio_play_persona_line_2d(M23_personas.kinzie.persona_id, M23_dialog_lines.kinzie_phone_call) 
  1619. 	while(audio_is_playing(audio_id) == true) do 
  1620. 		thread_yield() 
  1621. 	end 
  1622. 	 
  1623. 	delay(8.0) 
  1624. 	audio_id = audio_play_persona_line_2d(M23_personas.angel.persona_id, M23_dialog_lines.angel_phone_call) 
  1625. 	while(audio_is_playing(audio_id) == true) do 
  1626. 		thread_yield() 
  1627. 	end 
  1628. end 
  1629.  
  1630. -- Cleanup for the "Get to Saints HQ" objective. 
  1631. -- 
  1632. function m23_cleanup_get_to_saints_hq() 
  1633. 	trigger_enable(M23_triggers.saints_hq_entry, false) 
  1634. 	on_trigger("", M23_triggers.saints_hq_entry) 
  1635. 	 
  1636. 	-- Register a callback for when a player enters a vehicle 
  1637. 	on_vehicle_enter("", LOCAL_PLAYER) 
  1638. 	if (coop_is_active() == true) then 
  1639. 		on_vehicle_enter("", REMOTE_PLAYER) 
  1640. 	end 
  1641. end 
  1642.  
  1643. -- Callback for when a player enters the Saints HQ 
  1644. -- 
  1645. function m23_saints_hq_entry_cb() 
  1646. 	M23_flags.player_entered_saints_hq = true 
  1647. end 
  1648.  
  1649. -- Wait until at least one player aquires a helicopter 
  1650. function m23_aquire_helicopter() 
  1651. 	-- Set the objective text 
  1652. 	objective_text(0, M23_objectives.get_helicopter.tag, nil, nil, SYNC_ALL, M23_objectives.get_helicopter.icon) 
  1653. 	 
  1654. 	-- If none of the player's have a heli yet, then highlight the courtesy helicopters 
  1655. 	if (M23_flags.showed_courtesy_helis == false) then 
  1656. 		if (M23_flags.player_got_heli[1] == false and M23_flags.player_got_heli[2] == false) then 
  1657. 			for i, heli in pairs(M23_groups.courtesy_helis.vehicles) do 
  1658. 				marker_add(heli, MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION, OI_FLAGS_LOCATION, SYNC_ALL) 
  1659. 				on_vehicle_destroyed("m23_courtesy_heli_destroyed_cb", heli) 
  1660. 			end 
  1661. 			 
  1662. 			M23_flags.showed_courtesy_helis = true 
  1663. 		end 
  1664. 	end 
  1665.  
  1666. 	-- Register a callback for when a player enters a vehicle 
  1667. 	on_vehicle_enter("m23_player_entered_vehicle_cb", LOCAL_PLAYER) 
  1668. 	if (coop_is_active() == true) then 
  1669. 		on_vehicle_enter("m23_player_entered_vehicle_cb", REMOTE_PLAYER) 
  1670. 	end 
  1671.  
  1672. 	-- Wait until at least one player has aquired a helicopter 
  1673. 	local player_has_heli = false 
  1674. 	while(M23_flags.player_got_heli[1] == false and M23_flags.player_got_heli[2] == false) do 
  1675. 		thread_yield() 
  1676. 	end 
  1677. 	 
  1678. 	m23_cleanup_aquire_heli() 
  1679. end 
  1680.  
  1681. -- Cleanup for the aquire heli objective 
  1682. function m23_cleanup_aquire_heli() 
  1683. 	for i, heli in pairs(M23_groups.courtesy_helis.vehicles) do 
  1684. 		marker_remove(heli) 
  1685. 		on_vehicle_destroyed("", heli) 
  1686. 	end 
  1687. 	 
  1688. 	marker_remove_trigger(M23_triggers.saints_hq_elev_up) 
  1689. 	 
  1690. 	-- Register a callback for when a player enters a vehicle 
  1691. 	on_vehicle_enter("", LOCAL_PLAYER) 
  1692. 	if (coop_is_active() == true) then 
  1693. 		on_vehicle_enter("", REMOTE_PLAYER) 
  1694. 	end 
  1695. end 
  1696.  
  1697. -- Callback when a player enters any vehicle  
  1698. -- 
  1699. -- player:		Player that entered a vehicle 
  1700. -- vehicle:		Vehicle that the player entered 
  1701. -- seat:		Seat index 
  1702. function m23_track_player_enter_vehicle_cb(player, vehicle, seat) 
  1703. 	if player == LOCAL_PLAYER then 
  1704. 		if seat == 0 then 
  1705. 			M23_runtime.local_player_last_vehicle = vehicle 
  1706. 		else 
  1707. 			-- Player is riding as a passenger, don't track this vehicle. 
  1708. 			M23_runtime.local_player_last_vehicle = nil 
  1709. 		end 
  1710. 	elseif player == REMOTE_PLAYER then 
  1711. 		if seat == 0 then 
  1712. 			M23_runtime.remote_player_last_vehicle = vehicle 
  1713. 		else 
  1714. 			-- Player is riding as a passenger, don't track this vehicle. 
  1715. 			M23_runtime.remote_player_last_vehicle = nil 
  1716. 		end 
  1717. 	end 
  1718. 	 
  1719. 	if M23_flags.play_kinzie_call_on_next_vehicle_enter then 
  1720. 		M23_flags.play_kinzie_call_on_next_vehicle_enter = false 
  1721. 		m23_play_cell_convo(M23_conversations.awesome_daedalus.name, false) 
  1722. 	end 
  1723. end 
  1724.  
  1725. -- player:		Player that entered a vehicle 
  1726. -- vehicle:		Vehicle that the player entered 
  1727. -- seat:		Seat index 
  1728. function m23_player_entered_vehicle_cb(player, vehicle, seat) 
  1729. 	local vehicle_type = get_char_vehicle_type(player) 
  1730. 	if (vehicle_type == VT_AIRPLANE or vehicle_type == VT_HELICOPTER or vehicle_type == VT_VTOL) then 
  1731. 		-- Update which player's are in a heli 
  1732. 		if (player == LOCAL_PLAYER) then 
  1733. 			M23_flags.player_got_heli[1] = true 
  1734. 		else 
  1735. 			M23_flags.player_got_heli[2] = true 
  1736. 		end 
  1737. 		 
  1738. 		if (coop_is_active() == true) then 
  1739. 			if (M23_flags.player_got_heli[1] == false or M23_flags.player_got_heli[2] == false) then 
  1740. 				if (vehicle == M23_groups.courtesy_helis.vehicles[1] or vehicle == M23_groups.courtesy_helis.vehicles[2]) then 
  1741. 					M23_threads.wait_for_heli_takeoff = thread_new("m23_wait_for_heli_takeoff_thread", vehicle) 
  1742. 				end 
  1743. 			else 
  1744. 				marker_remove(M23_groups.courtesy_helis.vehicles[1], SYNC_ALL) 
  1745. 				marker_remove(M23_groups.courtesy_helis.vehicles[2], SYNC_ALL) 
  1746. 			end 
  1747. 		end 
  1748. 		 
  1749. 		-- Check if this was one of the courtesy helicopters 
  1750. 		for i, heli in pairs(M23_groups.courtesy_helis.vehicles) do 
  1751. 			if (vehicle == heli) then 
  1752. 				turn_vulnerable(heli) 
  1753. 				vehicle_infinite_mass(heli, false) 
  1754. 				on_vehicle_destroyed("", heli) 
  1755. 			end 
  1756. 		end 
  1757. 	end 
  1758. end 
  1759.  
  1760. -- Function for when a heli is destroyed before it's made vulnerable 
  1761. function m23_courtesy_heli_destroyed_cb(heli) 
  1762. 	marker_remove(heli, SYNC_ALL) 
  1763. 	on_vehicle_destroyed("", heli) 
  1764. end 
  1765.  
  1766.  
  1767. --[[ 
  1768. 	OBJECTIVE: Get to the Daedalus 
  1769. 	]]-- 
  1770.  
  1771. -- Fly to the Daedalus's airspace 
  1772. function m23_get_to_daedalus() 
  1773. 	objective_text(0, M23_objectives.go_to_daedalus.tag, nil, nil, SYNC_ALL, M23_objectives.go_to_daedalus.icon) 
  1774. 	 
  1775. 	-- Make sure the waypoint to the Saint's HQ has been removed 
  1776. 	mission_waypoint_remove() 
  1777. 	 
  1778. 	--[[ 
  1779. 	-- Play the newsbreak for the result of M22. 
  1780. 	radio_newsbreak("M22_Kill_Killbane") 
  1781. 	--]] 
  1782.  
  1783. 	-- Remove the courtesy helicopter markers for any player in a heli 
  1784. 	if (M23_flags.player_got_heli[1] == true) then 
  1785. 		marker_remove(M23_groups.courtesy_helis.vehicles[1], SYNC_LOCAL) 
  1786. 		marker_remove(M23_groups.courtesy_helis.vehicles[2], SYNC_LOCAL) 
  1787. 	end 
  1788. 	if (M23_flags.player_got_heli[2] == true) then 
  1789. 		marker_remove(M23_groups.courtesy_helis.vehicles[1], SYNC_REMOTE) 
  1790. 		marker_remove(M23_groups.courtesy_helis.vehicles[2], SYNC_REMOTE) 
  1791. 	end 
  1792. 	 
  1793. 	-- Make the courtesy helis vulnerable, normally massive again. 
  1794. 	for i, heli in pairs(M23_groups.courtesy_helis.vehicles) do 
  1795. 		turn_vulnerable(heli) 
  1796. 		vehicle_infinite_mass(heli, false) 
  1797. 		on_vehicle_destroyed("", heli) 
  1798. 	end 
  1799. 	 
  1800. 	marker_add(M23_navpoints.daedalus_landing_pos, MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION, OI_FLAGS_LOCATION, SYNC_ALL) 
  1801. 	 
  1802. 	--[[ 
  1803. 	-- Set up the trigger to play the "whoa, the Daedalus is neato!" conversation. 
  1804. 	trigger_enable(M23_triggers.awesome_daedalus, true) 
  1805. 	on_trigger("m23_awesome_daedalus_convo_cb", M23_triggers.awesome_daedalus) 
  1806. 	--]] 
  1807. 	 
  1808. 	-- Activate the trigger for the Daedalus's airspace (to update the mission objective) 
  1809. 	trigger_enable(M23_triggers.daedalus_airspace, true) 
  1810. 	on_trigger("m23_daedalus_airspace_entered_cb", M23_triggers.daedalus_airspace) 
  1811. 	M23_flags.daedalus_airspace_entered = false 
  1812. 	 
  1813. 	-- Wait until the player enter's the Daedalus's airspace 
  1814. 	while(M23_flags.daedalus_airspace_entered == false) do 
  1815. 		thread_yield() 
  1816. 	end 
  1817. 	 
  1818. 	m23_cleanup_get_to_daedalus() 
  1819. end 
  1820.  
  1821. -- Cleanup function for the objective to get to the Daedalus 
  1822. function m23_cleanup_get_to_daedalus() 
  1823. 	-- Remove landing marker 
  1824. 	marker_remove(M23_navpoints.daedalus_landing_pos, SYNC_ALL) 
  1825. 	 
  1826. 	on_trigger("", M23_triggers.daedalus_airspace) 
  1827. 	on_trigger_exit("", M23_triggers.daedalus_airspace) 
  1828. 	trigger_enable(M23_triggers.daedalus_airspace, false) 
  1829. end 
  1830.  
  1831. -- Callback for when a player enters the trigger to play the "awesome Daedalus" convo. 
  1832. -- 
  1833. function m23_awesome_daedalus_convo_cb(player, trigger) 
  1834. 	m23_play_cell_convo(M23_conversations.awesome_daedalus.name, false) 
  1835. 	on_trigger("", trigger) 
  1836. 	trigger_enable(trigger, false) 
  1837. end 
  1838.  
  1839. -- Callback for when a player enters the Daedalus's airspace 
  1840. --  
  1841. -- player:		Player that triggered the trigger region 
  1842. -- trigger:		Trigger region that got triggered 
  1843. function m23_daedalus_airspace_entered_cb(player, trigger) 
  1844. 	M23_flags.daedalus_airspace_entered = true 
  1845. end 
  1846.  
  1847.  
  1848. --[[ 
  1849. 	OBJECTIVE: Approach landing area 
  1850. 	--]] 
  1851. 	 
  1852. --[[ 
  1853.  
  1854. -- Update the obejctive for the player to land on the Daedalus, until they get within the defensive range of the Daedalus 
  1855. function m23_approach_daedalus_landing_area() 
  1856. 	-- Update the obective text 
  1857. 	objective_text(0, M23_objectives.land_on_daedalus.tag, nil, nil, SYNC_ALL, M23_objectives.land_on_daedalus.icon) 
  1858. 	 
  1859. 	-- notoriety_set_desired_vehicle_count("police", 0) 
  1860. 	notoriety_force_no_spawn("STAG", true) 
  1861. 	 
  1862. 	-- Kick off the threads to process the dog-fights going on around the Daedalus 
  1863. 	M23_groups.dog_fight_01.thread_id = thread_new("m23_process_dog_fight", M23_groups.dog_fight_01) 
  1864. 	M23_groups.dog_fight_02.thread_id = thread_new("m23_process_dog_fight", M23_groups.dog_fight_02) 
  1865.  
  1866. 	-- Give the attack VTOLs orders to attack the players 
  1867. 	for i, vtol in pairs(M23_groups.attack_vtols_01.vtols) do 
  1868. 		vtol.thread_id = thread_new("m23_process_attack_vtol_take_off", vtol.vehicle, vtol.chars[1], vtol.lift_off_pos, vtol.delay) 
  1869. 	end 
  1870. 	 
  1871. 	-- Enable the trigger for the Daedalus's defenses 
  1872. 	trigger_enable(M23_triggers.daedalus_defensive_area, true) 
  1873. 	on_trigger("m23_daedalus_defensive_area_enetered_cb", M23_triggers.daedalus_defensive_area) 
  1874. 	M23_flags.daedalus_defensive_area_entered = false 
  1875. 	 
  1876. 	-- Wait until the player gets within the Daedalus's defensive range 
  1877. 	while(M23_flags.daedalus_defensive_area_entered == false) do 
  1878. 		thread_yield() 
  1879. 	end 
  1880. 	 
  1881. 	m23_cleanup_approach_daedalus_landing_area() 
  1882. end 
  1883.  
  1884. -- Cleanup for the land on the Daedalus obejctive 
  1885. function m23_cleanup_approach_daedalus_landing_area() 
  1886. 	trigger_enable(M23_triggers.daedalus_defensive_area, false) 
  1887. 	on_trigger("", M23_triggers.daedalus_defensive_area) 
  1888. end 
  1889.  
  1890. -- Callback for when a player enters the Daedalus's defensive area 
  1891. --  
  1892. -- player:		Player that triggered the trigger region 
  1893. -- trigger:		Trigger region that got triggered 
  1894. function m23_daedalus_defensive_area_enetered_cb() 
  1895. 	M23_flags.daedalus_defensive_area_entered = true 
  1896. end 
  1897.  
  1898. --]] 
  1899.  
  1900. --[[ 
  1901. 	OBJECTIVE: Take out the Daedalus' guns 
  1902. 	--]] 
  1903. 	 
  1904. -- Process the guns on the Daedalus the player is instructed to destroy 
  1905. function m23_daedalus_destroy_guns() 
  1906. 	m23_set_notoriety_aircraft_enabled(false) 
  1907. 	 
  1908. 	-- Play some dialog 
  1909. 	audio_play_persona_line(LOCAL_PLAYER, M23_dialog_lines.take_out_turrets) 
  1910. 	 
  1911. 	-- Get all the guns we need to destroy 
  1912. 	M23_runtime.daedalus_guns_alive = 0 
  1913. 	for i, gun in pairs(M23_movers.daedalus_guns) do 
  1914. 		if (mesh_mover_destroyed(gun.mover_name) == false) then 
  1915. 			-- Register a callback for when this gun is destroyed. 
  1916. 			on_mover_destroyed("m23_callback_daedalus_gun_destroyed_cb", gun.mover_name) 
  1917. 			 
  1918. 			-- Start up a thread to fire the cannon periodically. 
  1919. 			gun.firing_thread = thread_new("m23_daedalus_cannon_firing_thread", gun.effect_nav, 1.0, 3.0) 
  1920. 			 
  1921. 			-- Add a marker for this gun. 
  1922. 			marker_add(gun.mover_name, MINIMAP_ICON_KILL, OI_ASSET_KILL_FULL, OI_FLAGS_FULL) 
  1923. 			 
  1924. 			-- Update our gun count. 
  1925. 			M23_runtime.daedalus_guns_alive = M23_runtime.daedalus_guns_alive + 1 
  1926. 		end 
  1927. 	end 
  1928. 	 
  1929. 	-- Kick off the threads to process the dog-fights going on around the Daedalus 
  1930. 	M23_groups.dog_fight_01.thread_id = thread_new("m23_process_dog_fight", M23_groups.dog_fight_01) 
  1931. 	M23_groups.dog_fight_02.thread_id = thread_new("m23_process_dog_fight", M23_groups.dog_fight_02) 
  1932. 	 
  1933. 	--[[ 
  1934. 	-- Give the attack VTOLs orders to attack the players 
  1935. 	for i, vtol in pairs(M23_groups.attack_vtols_01.vtols) do 
  1936. 		vtol.thread_id = thread_new("m23_process_attack_vtol_take_off", vtol.vehicle, vtol.chars[1], vtol.lift_off_pos, vtol.delay) 
  1937. 	end 
  1938. 	--]] 
  1939. 	 
  1940. 	group_create(M23_groups.bomb_spawn_01) 
  1941. 	group_create(M23_groups.bomb_spawn_02) 
  1942. 	group_create(M23_groups.bomb_spawn_03) 
  1943. 	group_create(M23_groups.amb_spawn_01) 
  1944. 	 
  1945. 	-- If there is at least one gun alive, then display the destroy defenses objective. 
  1946. 	if (M23_runtime.daedalus_guns_alive > 0) then 
  1947. 		objective_text(0, M23_objectives.destroy_guns.tag, nil, nil, SYNC_ALL, M23_objectives.destroy_guns.icon) 
  1948. 	end 
  1949. 		 
  1950. 	-- Progress music. 
  1951. 	m23_post_music_event(M23_music.mission_start_end) 
  1952. 	 
  1953. 	delay(9.0) 
  1954. 	 
  1955. 	-- Progress music. 
  1956. 	m23_post_music_event(M23_music.daedalus_battle) 
  1957. 	 
  1958. 	-- Wait until all the guns have been destroyed. 
  1959. 	while (M23_runtime.daedalus_guns_alive > 0) do 
  1960. 		thread_yield() 
  1961. 	end 
  1962. 	 
  1963. 	m23_end_ambient_explosion_audio() 
  1964. 	 
  1965. 	-- Play some dialog 
  1966. 	audio_play_persona_line(LOCAL_PLAYER, M23_dialog_lines.turrets_down) 
  1967. 	 
  1968. 	m23_cleanup_daedalus_destroy_guns() 
  1969. 	 
  1970. 	delay(1.0) 
  1971. 	 
  1972. 	m23_play_cell_convo(M23_conversations.not_making_a_dent.name, false) 
  1973. end 
  1974.  
  1975. -- Cleanup for the objective to destroy the Daedalus guns. 
  1976. function m23_cleanup_daedalus_destroy_guns() 
  1977. 	for i, gun in pairs(M23_movers.daedalus_guns) do 
  1978. 		on_mover_destroyed("", gun.mover_name) 
  1979. 		marker_remove(gun.mover_name) 
  1980. 		thread_kill(gun.firing_thread) 
  1981. 		gun.firing_thread = INVALID_THREAD_HANDLE 
  1982. 	end 
  1983. end 
  1984.  
  1985. -- Callback for when a gun on the Daedalus gets destroyed. 
  1986. function m23_callback_daedalus_gun_destroyed_cb(gun_mover_name) 
  1987. 	-- Find the gun in question. 
  1988. 	local found_gun = nil 
  1989. 	for i, cur_gun in pairs(M23_movers.daedalus_guns) do 
  1990. 		if cur_gun.mover_name == gun_mover_name then 
  1991. 			found_gun = cur_gun 
  1992. 			break 
  1993. 		end 
  1994. 	end 
  1995.  
  1996. 	on_mover_destroyed("", found_gun.mover_name) 
  1997. 	marker_remove(found_gun.mover_name) 
  1998. 	explosion_create("M23_daedalus_cannon_exp", found_gun.death_vfx) 
  1999. 	 
  2000. 	-- Stop the thread that's firing the cannon. 
  2001. 	thread_kill(found_gun.firing_thread) 
  2002. 	found_gun.firing_thread = INVALID_THREAD_HANDLE 
  2003. 	 
  2004. 	M23_runtime.daedalus_guns_alive = M23_runtime.daedalus_guns_alive - 1 
  2005. end 
  2006.  
  2007.  
  2008. --[[ 
  2009. 	OBJECTIVE: Take out the surface defenses 
  2010. 	--]] 
  2011. 	 
  2012. -- Process the tanks on the Daedalus the player is instructed to destroy 
  2013. function m23_daedalus_destroy_tanks() 
  2014. 	-- Start the continious spawn on the landing deck 
  2015. 	m23_setup_landing_deck_cont_spawn() 
  2016. 	 
  2017. 	-- Play some dialog 
  2018. 	audio_play_persona_line(LOCAL_PLAYER, M23_dialog_lines.clear_the_deck) 
  2019. 	 
  2020. 	-- Check if any tanks are alive 
  2021. 	M23_runtime.daedalus_surface_tanks_alive = 0 
  2022. 	for i, tank in pairs(M23_groups.daedalus_tanks_01.tanks) do 
  2023. 		if (vehicle_is_destroyed(tank.vehicle) == false) then 
  2024. 			-- Make the tank fire at the closest player 
  2025. 			--force_fire_object_position(tank.chars[1], CLOSEST_PLAYER, true) 
  2026. 			 
  2027. 			-- Add a marker and register a callback so we know when it's destroyed 
  2028. 			on_vehicle_destroyed("m23_callback_daedalus_tank_destroyed_cb", tank.vehicle) 
  2029. 			marker_add(tank.vehicle, MINIMAP_ICON_KILL, OI_ASSET_KILL_FULL) 
  2030. 			 
  2031. 			-- Update our count of tanks that are alive 
  2032. 			M23_runtime.daedalus_surface_tanks_alive = M23_runtime.daedalus_surface_tanks_alive + 1 
  2033. 		end 
  2034. 	end 
  2035. 	 
  2036. 	-- If there is at least one tank alive, then display the destroy defenses objective 
  2037. 	if (M23_runtime.daedalus_surface_tanks_alive > 0) then 
  2038. 		objective_text(0, M23_objectives.destroy_defenses.tag, nil, nil, SYNC_ALL, M23_objectives.destroy_defenses.icon) 
  2039. 	end 
  2040. 	 
  2041. 	-- Wait until all the tanks have been destroyed 
  2042. 	while (M23_runtime.daedalus_surface_tanks_alive > 0) do 
  2043. 		thread_yield() 
  2044. 	end 
  2045. 	 
  2046. 	m23_cleanup_daedalus_destroy_tanks() 
  2047. end 
  2048.  
  2049. -- Cleanup for the objective to destroy the Daedalus tanks 
  2050. function m23_cleanup_daedalus_destroy_tanks() 
  2051. 	for i, tank in pairs(M23_groups.daedalus_tanks_01.tanks) do 
  2052. 		on_vehicle_destroyed("", tank.vehicle) 
  2053. 		marker_remove(tank.vehicle) 
  2054. 	end 
  2055. end 
  2056.  
  2057. -- Callback for when a tank on the Daedalus gets destroyed 
  2058. function m23_callback_daedalus_tank_destroyed_cb(vehicle) 
  2059. 	on_vehicle_destroyed("", vehicle) 
  2060. 	marker_remove(vehicle) 
  2061. 	 
  2062. 	M23_runtime.daedalus_surface_tanks_alive = M23_runtime.daedalus_surface_tanks_alive - 1 
  2063. end 
  2064.  
  2065.  
  2066. --[[  
  2067. 	OBJECT: Land on the Daedalus 
  2068. 	--]] 
  2069. 	 
  2070. -- Process the player landing on the Daedalus 
  2071. function m23_land_on_the_daedalus() 
  2072. 	-- Start the continious spawn on the landing deck 
  2073. 	m23_setup_landing_deck_cont_spawn() 
  2074. 	 
  2075. 	-- Enable the trigger for the Daedalus's landing zone, and add a marker at the landing area 
  2076. 	trigger_enable(M23_triggers.daedalus_landing_zone, true) 
  2077. 	on_trigger("m23_daedalus_landing_zone_entered_cb", M23_triggers.daedalus_landing_zone) 
  2078. 	M23_flags.daedalus_landing_complete = false 
  2079. 	 
  2080. 	-- The player can exit a vehicle inside the trigger without "entering" the trigger. 
  2081. 	on_vehicle_exit("m23_daedalus_landing_player_exited_vehicle", LOCAL_PLAYER) 
  2082. 	if coop_is_active() == true then 
  2083. 		on_vehicle_exit("m23_daedalus_landing_player_exited_vehicle", REMOTE_PLAYER) 
  2084. 	end 
  2085. 	 
  2086. 	-- Show the "land on the daedalus" objective 
  2087. 	objective_text(0, M23_objectives.land_on_daedalus.tag, nil, nil, SYNC_ALL, M23_objectives.land_on_daedalus.icon) 
  2088. 	marker_add(M23_navpoints.daedalus_landing_pos, MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION, OI_FLAGS_LOCATION, SYNC_ALL) 
  2089. 	 
  2090. 	-- Wait until they have landed 
  2091. 	while(M23_flags.daedalus_landing_complete == false) do 
  2092. 		thread_yield() 
  2093. 	end 
  2094. 	 
  2095. 	m23_cleanup_land_on_the_daedalus() 
  2096. end 
  2097.  
  2098. -- Cleanup function for landing on the Daedalus 
  2099. function m23_cleanup_land_on_the_daedalus() 
  2100. 	trigger_enable(M23_triggers.daedalus_landing_zone, false) 
  2101. 	on_trigger("", M23_triggers.daedalus_landing_zone) 
  2102. 	 
  2103. 	on_vehicle_exit("", LOCAL_PLAYER) 
  2104. 	if coop_is_active() == true then 
  2105. 		on_vehicle_exit("", REMOTE_PLAYER) 
  2106. 	end 
  2107. 	 
  2108. 	marker_remove(M23_navpoints.daedalus_landing_pos) 
  2109. 	 
  2110. 	continuous_explosion_stop() 
  2111. end 
  2112.  
  2113. -- The player can exit a vehicle inside the trigger without "entering" the trigger, 
  2114. -- so do a manual check. 
  2115. -- 
  2116. -- character:   (string) the name of the character that exited a vehicle. 
  2117. -- 
  2118. function m23_daedalus_landing_player_exited_vehicle(character) 
  2119. 	if object_is_in_trigger(M23_triggers.daedalus_landing_zone, character) then 
  2120. 		M23_flags.daedalus_landing_complete = true 
  2121. 	end 
  2122. end 
  2123.  
  2124. -- Callback for when a player enters the trigger on the Daedalus's landing zone 
  2125. --  
  2126. -- player:		Player that triggered the trigger region 
  2127. -- trigger:		Trigger region that got triggered 
  2128. function m23_daedalus_landing_zone_entered_cb(player, trigger) 
  2129. 	M23_flags.daedalus_landing_complete = true 
  2130. end 
  2131.  
  2132.  
  2133. -- Thread function to land Saints reinforcements on the landing deck area. 
  2134. function m23_do_landing_deck_saints_reinforcements_thread(group)	 
  2135. 	-- Put the guys we spawned in their helicopters. 
  2136. 	vehicle_enter_group_teleport(group.chars, group.vehicle) 
  2137. 	 
  2138. 	for i, dude in pairs(group.chars) do 
  2139. 		turn_invulnerable(dude) 
  2140. 	end 
  2141. 	turn_invulnerable(group.vehicle) 
  2142. 	 
  2143. 	-- Path to the landing zone 
  2144. 	-- direct call to helicopter_fly_to_do because we don't want to wait for completion 
  2145. 	helicopter_fly_to_do(group.vehicle, -1, true, "", false, group.path, 1.0) 
  2146. 	 
  2147. 	while (get_char_vehicle_is_in_air(group.chars[1]) == true) do 
  2148. 		thread_yield() 
  2149. 	end 
  2150. 	 
  2151. 	helicopter_fly_to_stop(group.vehicle) 
  2152. 	vehicle_stop(group.vehicle, true) 
  2153. 	 
  2154. 	-- Have the dudes get out and make the helicopter unenterable. 
  2155. 	for i, dude in pairs(group.chars) do 
  2156. 		vehicle_exit(dude, true) 
  2157. 	end 
  2158. 	 
  2159. 	delay(10.0) 
  2160. 	 
  2161. 	for i, dude in pairs(group.chars) do 
  2162. 		turn_vulnerable(dude) 
  2163. 	end 
  2164. 	turn_vulnerable(group.vehicle) 
  2165. end 
  2166.  
  2167.  
  2168. --[[ 
  2169. 	OBJECTIVE: Plant bombs on the Daedalus. 
  2170. 	--]] 
  2171. 	 
  2172. -- The player has to plant bombs at various places around the Daedalus. 
  2173. -- 
  2174. function m23_plant_bombs() 
  2175. 	-- Register callbacks to track the players' vehicles so we can blow them up before 
  2176. 	-- the Cyrus boss fight. 
  2177. 	on_vehicle_enter("m23_track_player_enter_vehicle_cb", LOCAL_PLAYER) 
  2178. 	if (coop_is_active() == true) then 
  2179. 		on_vehicle_enter("m23_track_player_enter_vehicle_cb", REMOTE_PLAYER) 
  2180. 	end 
  2181.  
  2182. 	-- Set bombs and fly to places. 
  2183. 	m23_set_bomb_or_fly_to(M23_bomb_triggers.landing_deck_bomb_1) 
  2184. 	audio_play_persona_line(LOCAL_PLAYER, M23_dialog_lines.first_bomb) 
  2185. 	m23_set_bomb_or_fly_to(M23_bomb_triggers.landing_deck_bomb_2) 
  2186. 	audio_play_persona_line(LOCAL_PLAYER, M23_dialog_lines.second_bomb) 
  2187. 	M23_flags.play_kinzie_call_on_next_vehicle_enter = true 
  2188. 	m23_set_bomb_or_fly_to(M23_bomb_triggers.fly_to_side) 
  2189. 	m23_set_bomb_or_fly_to(M23_bomb_triggers.side_deck_bomb) 
  2190. 	audio_play_persona_line(LOCAL_PLAYER, M23_dialog_lines.third_bomb)	 
  2191. 	--m23_set_bomb_or_fly_to(M23_bomb_triggers.fly_to_rear) 
  2192. 	m23_set_bomb_or_fly_to(M23_bomb_triggers.rear_deck_bomb) 
  2193. 	 
  2194. 	-- Progress music. 
  2195. 	m23_post_music_event(M23_music.daedalus_battle_end) 
  2196. 	 
  2197. 	audio_play_persona_line(LOCAL_PLAYER, M23_dialog_lines.fourth_bomb) 
  2198. 	 
  2199. 	objective_text_clear(0) 
  2200. 	 
  2201. 	m23_cleanup_plant_bombs() 
  2202. end 
  2203.  
  2204. -- Enables a trigger and sets a marker for either a bomb or a "fly to" location 
  2205. -- and waits for the player to finish doing that. 
  2206. -- 
  2207. function m23_set_bomb_or_fly_to(trigger) 
  2208. 	M23_runtime.cur_bomb_planted = false 
  2209. 	trigger_enable(trigger.trigger_name) 
  2210. 	on_trigger("m23_bomb_planted_or_flown_to_cb", trigger.trigger_name) 
  2211. 	marker_add_trigger(trigger.trigger_name, trigger.minimap_icon, trigger.ingame_effect, trigger.oi_asset, trigger.oi_flags, SYNC_ALL) 
  2212. 	 
  2213. 	objective_text(0, trigger.objective.tag, nil, nil, SYNC_ALL, trigger.objective.icon) 
  2214. 	 
  2215. 	-- Wait for the player to plant the bomb or fly to the destination. 
  2216. 	while M23_runtime.cur_bomb_planted == false do 
  2217. 		thread_yield() 
  2218. 	end 
  2219. end 
  2220.  
  2221. -- Cleans up a bomb or "fly to" trigger. 
  2222. -- 
  2223. function m23_cleanup_bomb_trigger(trigger) 
  2224. 	trigger_enable(trigger.trigger_name, false) 
  2225. 	on_trigger("", trigger.trigger_name) 
  2226. 	marker_remove_trigger(trigger.trigger_name) 
  2227. end 
  2228.  
  2229. -- Called when the player plants a bomb or makes it to a "fly to" trigger. 
  2230. -- 
  2231. function m23_bomb_planted_or_flown_to_cb(character, trigger)	 
  2232. 	-- Find the trigger we just hit. 
  2233. 	local found_trigger = nil 
  2234. 	for i, cur_trigger in pairs(M23_bomb_triggers) do 
  2235. 		if cur_trigger.trigger_name == trigger then 
  2236. 			found_trigger = cur_trigger 
  2237. 			break 
  2238. 		end 
  2239. 	end 
  2240. 	 
  2241. 	-- Clean up the trigger before we do anything else. 
  2242. 	m23_cleanup_bomb_trigger(found_trigger) 
  2243. 	 
  2244. 	if found_trigger.play_bomb_anim == true then 
  2245. 		-- Set up the character for the animation. 
  2246. 		character_prevent_explosion_fling(character, true) 
  2247. 		character_allow_ragdoll(character, false) 
  2248. 		character_prevent_flinching(character, true) 
  2249. 		--player_controls_disable(character) 
  2250. 		 
  2251. 		-- Play the intro animation and align the player to the orientation nav point. 
  2252. 		action_play(character, "plant explosive enter", "plant explosive enter", false, 0.8, false, false, found_trigger.anim_nav) 
  2253. 		 
  2254. 		-- Play the middle section of the animation. 
  2255. 		set_animation_state(character, "plant explosive idle") 
  2256. 		if character_is_dead(character) == false then 
  2257. 			delay(3.0) 
  2258. 		end 
  2259. 		clear_animation_state(character) 
  2260. 		 
  2261. 		-- Play the outro animation. 
  2262. 		action_play(character, "plant explosive exit") 
  2263. 		 
  2264. 		-- Clean up any settings we applied for the animation. 
  2265. 		player_controls_enable(character) 
  2266. 		character_prevent_flinching(character, false) 
  2267. 		character_allow_ragdoll(character, true) 
  2268. 		character_prevent_explosion_fling(character, false) 
  2269. 	end 
  2270. 	 
  2271. 	M23_runtime.cur_bomb_planted = true 
  2272. end 
  2273.  
  2274. -- Clean up anything for the plant bombs objective. 
  2275. -- 
  2276. function m23_cleanup_plant_bombs() 
  2277. 	-- Clean up bomb triggers. 
  2278. 	M23_runtime.cur_bomb_planted = false 
  2279. 	for i, trigger in pairs(M23_bomb_triggers) do 
  2280. 		m23_cleanup_bomb_trigger(trigger) 
  2281. 	end 
  2282. 	 
  2283. 	-- Clean up vehicle callbacks. 
  2284. 	on_vehicle_enter("", LOCAL_PLAYER) 
  2285. 	if (coop_is_active() == true) then 
  2286. 		on_vehicle_enter("", REMOTE_PLAYER) 
  2287. 	end 
  2288. end 
  2289.  
  2290. --[[ 
  2291. 	OBJECTIVE: Kill Cyrus (boss battle) 
  2292. 	--]] 
  2293.  
  2294. -- Cyrus flies over the rear deck and destroys the players' helicopter(s) 
  2295. -- 
  2296. function m23_cyrus_fly_by() 
  2297. 	-- Prevent the players from getting back in their helicopters. 
  2298. 	if M23_runtime.local_player_last_vehicle ~= "" and M23_runtime.local_player_last_vehicle ~= nil and M23_runtime.local_player_last_vehicle ~= LOCAL_PLAYER then 
  2299. 		set_unjackable_flag(M23_runtime.local_player_last_vehicle) 
  2300. 	end 
  2301. 	if M23_runtime.remote_player_last_vehicle ~= "" and M23_runtime.remote_player_last_vehicle ~= nil and M23_runtime.remote_player_last_vehicle ~= REMOTE_PLAYER then 
  2302. 		set_unjackable_flag(M23_runtime.remote_player_last_vehicle) 
  2303. 	end 
  2304.  
  2305. 	-- Create Cyrus and his vtol, and put Cyrus in the driver's seat 
  2306. 	group_create_hidden(M23_groups.cyrus_vtol.name, true) 
  2307. 	vehicle_enter_teleport(M23_groups.cyrus_vtol.cyrus, M23_groups.cyrus_vtol.vtol) 
  2308. 	vehicle_max_speed(M23_groups.cyrus_vtol.vtol, 150.0) 
  2309. 	turn_invulnerable(M23_groups.cyrus_vtol.vtol) 
  2310. 	turn_invulnerable(M23_groups.cyrus_vtol.cyrus) -- Cyrus himself is invulnerable until his VTOL hits 25% health. 
  2311. 	vehicle_prevent_explosion_fling(M23_groups.cyrus_vtol.vtol, true) 
  2312. 	vehicle_infinite_mass(M23_groups.cyrus_vtol.vtol, true)  -- Don't allow ramming Cyrus with another heli to knock him off his path. 
  2313. 	helicopter_set_dont_death_spiral(M23_groups.cyrus_vtol.vtol, true)  -- Don't allow ramming Cyrus with another heli to death spiral him. 
  2314. 	set_dont_attack_me_on_sight_flag(M23_groups.cyrus_vtol.cyrus, true) -- We don't want the dogfighting Saints to attack Cyrus. 
  2315. 	set_unjackable_flag(M23_groups.cyrus_vtol.vtol, true) -- Don't allow the player to RC Cyrus. 
  2316. 	 
  2317. 	-- Register the players as targets. 
  2318. 	ai_add_enemy_target(M23_groups.cyrus_vtol.cyrus, LOCAL_PLAYER, ATTACK_ON_SIGHT, true) 
  2319. 	if (coop_is_active() == true) then 
  2320. 		ai_add_enemy_target(M23_groups.cyrus_vtol.cyrus, REMOTE_PLAYER, ATTACK_ON_SIGHT, true) 
  2321. 	end 
  2322. 	 
  2323. 	set_perfect_aim(M23_groups.cyrus_vtol.cyrus, true) 
  2324. 	--set_ignore_ai_flag(M23_groups.cyrus_vtol.cyrus, true) 
  2325. 	 
  2326. 	-- Start a thread to blow up the players' helicopter(s) 
  2327. 	M23_threads.cyrus_destroy_player_helis = thread_new("m23_cyrus_destroy_player_helis_thread") 
  2328. 	 
  2329. 	-- Play some dialog 
  2330. 	audio_play_persona_line(LOCAL_PLAYER, M23_dialog_lines.find_cyrus) 
  2331. 	 
  2332. 	-- Update the objective text with the new objective 
  2333. 	-- objective_text(0, M23_objectives.kill_cyrus.tag, nil, nil, SYNC_ALL, M23_objectives.kill_cyrus.icon) 
  2334. 	-- marker_add(M23_groups.cyrus_vtol.vtol, MINIMAP_ICON_KILL, OI_ASSET_KILL_FULL, OI_FLAGS_FULL) 
  2335. 	 
  2336. 	-- Fly the intro flyover path. 
  2337. 	group_show(M23_groups.cyrus_vtol) 
  2338. 	helicopter_fly_to_direct_dont_stop(M23_groups.cyrus_vtol.vtol, 30, M23_cyrus_boss_ai.start_path_1) 
  2339. 	 
  2340. 	-- Update the objective text with the new objective 
  2341. 	M23_conversations.cyrus_start.handle = audio_conversation_load(M23_conversations.cyrus_start.name) 
  2342. 	audio_conversation_play(M23_conversations.cyrus_start.handle) 
  2343. 	objective_text(0, M23_objectives.kill_cyrus.tag, nil, nil, SYNC_ALL, M23_objectives.kill_cyrus.icon) 
  2344. 	marker_add(M23_groups.cyrus_vtol.vtol, MINIMAP_ICON_KILL, OI_ASSET_KILL_FULL, OI_FLAGS_FULL) 
  2345. 	 
  2346. 	-- Fly the outro flyover path. 
  2347. 	helicopter_fly_to_direct_dont_stop(M23_groups.cyrus_vtol.vtol, 75, M23_cyrus_boss_ai.start_path_2) 
  2348. 	 
  2349. 	set_perfect_aim(M23_groups.cyrus_vtol.cyrus, false) 
  2350. 	--set_ignore_ai_flag(M23_groups.cyrus_vtol.cyrus, false) 
  2351. 	 
  2352. 	m23_cleanup_cyrus_fly_by() 
  2353. end 
  2354.  
  2355. -- Thread function to process Cyrus firing at and destroying the players' helicopters. 
  2356. -- 
  2357. function m23_cyrus_destroy_player_helis_thread()	 
  2358. 	-- Blow up the players' helicopter(s). 
  2359. 	-- Note: the player's vehicle name is set to LOCAL_PLAYER if it is a non-scripted vehicle I guess. 
  2360. 	 
  2361. 	delay(3.0) 
  2362. 	 
  2363. 	-- Destroy the nearest player helicopter first. 
  2364. 	local first_heli = nil 
  2365. 	local second_heli = nil 
  2366. 	local local_dist = nil 
  2367. 	local remote_dist = nil 
  2368. 	 
  2369. 	if M23_runtime.local_player_last_vehicle ~= "" and M23_runtime.local_player_last_vehicle ~= nil and M23_runtime.local_player_last_vehicle ~= LOCAL_PLAYER then 
  2370. 		if object_is_in_trigger(M23_triggers.rear_deck, M23_runtime.local_player_last_vehicle ) then 
  2371. 			local_dist = get_dist(M23_groups.cyrus_vtol.vtol, M23_runtime.local_player_last_vehicle) 
  2372. 		end 
  2373. 	end 
  2374. 	 
  2375. 	if M23_runtime.remote_player_last_vehicle ~= "" and M23_runtime.remote_player_last_vehicle ~= nil and M23_runtime.remote_player_last_vehicle ~= REMOTE_PLAYER then 
  2376. 		if object_is_in_trigger(M23_triggers.rear_deck, M23_runtime.remote_player_last_vehicle ) then 
  2377. 			remote_dist = get_dist(M23_groups.cyrus_vtol.vtol, M23_runtime.remote_player_last_vehicle) 
  2378. 		end 
  2379. 	end 
  2380. 	 
  2381. 	if local_dist ~= nil and remote_dist ~= nil then 
  2382. 		if local_dist < remote_dist then 
  2383. 			first_heli = M23_runtime.local_player_last_vehicle 
  2384. 			second_heli = M23_runtime.remote_player_last_vehicle 
  2385. 		else 
  2386. 			first_heli = M23_runtime.remote_player_last_vehicle 
  2387. 			second_heli = M23_runtime.local_player_last_vehicle 
  2388. 		end 
  2389. 	else 
  2390. 		if local_dist ~= nil then 
  2391. 			first_heli = M23_runtime.local_player_last_vehicle 
  2392. 		elseif remote_dist ~= nil then 
  2393. 			first_heli = M23_runtime.remote_player_last_vehicle 
  2394. 		end 
  2395. 	end 
  2396. 	 
  2397. 	-- Attack and destroy the first heli. 
  2398. 	if first_heli ~= nil then 
  2399. 		M23_threads.async_delay_thread = thread_new("delay", 6.0) 
  2400. 		 
  2401. 		-- Fire at the heli for a while or until it blows up. 
  2402. 		while thread_check_done(M23_threads.async_delay_thread) == false do 
  2403. 			helicopter_shoot_vehicle(M23_groups.cyrus_vtol.vtol, first_heli, true, 1.0, false) 
  2404. 			thread_yield() 
  2405. 			if vehicle_is_destroyed(first_heli) == true then 
  2406. 				thread_kill(M23_threads.async_delay_thread) 
  2407. 				break 
  2408. 			end 
  2409. 		end 
  2410.  
  2411. 		-- Force it to blow up. 
  2412. 		if vehicle_is_destroyed(first_heli) == false then 
  2413. 			vehicle_detonate(first_heli) 
  2414. 		end 
  2415. 	end 
  2416. 	 
  2417. 	-- Attack and destroy the second heli. 
  2418. 	if second_heli ~= nil then 
  2419. 		M23_threads.async_delay_thread = thread_new("delay", 6.0) 
  2420. 		 
  2421. 		-- Fire at the heli for a while or until it blows up. 
  2422. 		while thread_check_done(M23_threads.async_delay_thread) == false do 
  2423. 			helicopter_shoot_vehicle(M23_groups.cyrus_vtol.vtol, second_heli, true, 1.0, false) 
  2424. 			thread_yield() 
  2425. 		end 
  2426. 	 
  2427. 		-- Force it to blow up. 
  2428. 		if vehicle_is_destroyed(second_heli) == false then 
  2429. 			vehicle_detonate(second_heli) 
  2430. 		end 
  2431. 	end 
  2432. end 
  2433.  
  2434. -- Clean up anything for the fly by function. 
  2435. -- 
  2436. function m23_cleanup_cyrus_fly_by() 
  2437. 	thread_kill(M23_threads.cyrus_destroy_player_helis) 
  2438. 	M23_threads.cyrus_destroy_player_helis = -1 
  2439. 	thread_kill(M23_threads.async_delay_thread) 
  2440. 	M23_threads.async_delay_thread = -1 
  2441. end 
  2442.  
  2443. -- Process the Cyrus boss battle	 
  2444. function m23_kill_cyrus() 
  2445. 	-- Update the objective text with the new objective 
  2446. 	-- objective_text(0, M23_objectives.kill_cyrus.tag, nil, nil, SYNC_ALL, M23_objectives.kill_cyrus.icon) 
  2447. 		 
  2448. 	-- Start up the dog fight threads again if they've stopped. 
  2449. 	if (M23_groups.dog_fight_01.thread_id == -1 or thread_check_done(M23_groups.dog_fight_01.thread_id) == true) then 
  2450. 		M23_groups.dog_fight_01.thread_id = thread_new("m23_process_dog_fight", M23_groups.dog_fight_01) 
  2451. 	end 
  2452. 	if (M23_groups.dog_fight_02.thread_id == -1 or thread_check_done(M23_groups.dog_fight_02.thread_id) == true) then 
  2453. 		M23_groups.dog_fight_02.thread_id = thread_new("m23_process_dog_fight", M23_groups.dog_fight_02) 
  2454. 	end 
  2455. 	 
  2456. 	-- Setup Cyrus's VTOL 
  2457. 	M23_flags.cyrus_vtol_destroyed = false 
  2458. 	on_vehicle_destroyed("m23_cyrus_vtol_destroyed_cb", M23_groups.cyrus_vtol.vtol) 
  2459. 	turn_vulnerable(M23_groups.cyrus_vtol.vtol) 
  2460. 	turn_invulnerable(M23_groups.cyrus_vtol.cyrus) -- Cyrus himself is invulnerable until his VTOL hits 25% health. 
  2461. 	trigger_enable(M23_triggers.cyrus_combat, true) 
  2462. 	on_trigger_exit("m23_failure_leave_cb", M23_triggers.cyrus_combat) 
  2463. 	-- marker_add(M23_groups.cyrus_vtol.vtol, MINIMAP_ICON_KILL, OI_ASSET_KILL_FULL, OI_FLAGS_FULL) 
  2464. 	 
  2465. 	-- Enable spawn regions on the deck for reinforcements to arrive from. 
  2466. 	continuous_spawn_regions_enable(M23_spawn_regions.cyrus_deck, true) 
  2467. 	 
  2468. 	-- Setup callbacks for when Cyrus' health gets to certain levels. 
  2469. 	on_damage("m23_cyrus_health_75", M23_groups.cyrus_vtol.vtol, 0.75) 
  2470. 	 
  2471. 	-- Prevent Cyrus from falling below 75% health. 
  2472. 	local new_min = get_max_hit_points(M23_groups.cyrus_vtol.vtol) * 0.75 
  2473. 	set_min_hit_points(M23_groups.cyrus_vtol.vtol, new_min) 
  2474. 	 
  2475. 	-- Start the continuous spawn 
  2476. 	-- m23_setup_bridge_stairs_cont_spawn() 
  2477. 	 
  2478. 	-- Create a new thread to process Cyrus's boss AI 
  2479. 	M23_threads.cyrus_boss_ai = thread_new("m23_process_cyrus_boss_ai_thread") 
  2480. 	 
  2481. 	while audio_conversation_playing(M23_conversations.cyrus_start.handle) do 
  2482. 		thread_yield() 
  2483. 	end 
  2484. 	 
  2485. 	-- Make the miniguns obvious 
  2486. 	if coop_is_active() then 
  2487. 		for i, gun in pairs(M23_groups.ammo_stash_02.miniguns) do 
  2488. 			if ((not inv_has_item("brute_minigun", LOCAL_PLAYER)) or (not inv_has_item("brute_minigun", REMOTE_PLAYER))) then 
  2489. 				marker_add(gun, MINIMAP_ICON_USE, OI_ASSET_USE, OI_FLAGS_DEFAULT, SYNC_ALL) 
  2490. 				on_pickup("m23_minigun_cb", gun) 
  2491. 			end 
  2492. 		end 
  2493. 	else 
  2494. 		for i, gun in pairs(M23_groups.ammo_stash_02.miniguns) do 
  2495. 			if (not inv_has_item("brute_minigun")) then 
  2496. 				marker_add(gun, MINIMAP_ICON_USE, OI_ASSET_USE, OI_FLAGS_DEFAULT, SYNC_ALL) 
  2497. 				on_pickup("m23_minigun_cb", gun) 
  2498. 			end 
  2499. 		end 
  2500. 	end 
  2501. 	audio_play_persona_line(LOCAL_PLAYER, M23_dialog_lines.callout_weapons) 
  2502. 	 
  2503. 	-- Prep the Cyrus death cutscene. 
  2504. 	zscene_prep(M23_cutscenes.cyrus_death) 
  2505.  
  2506. 	-- Wait until Cyrus's VTOL is destroyed or the self desctruct timer runs out. 
  2507. 	while(M23_flags.cyrus_vtol_destroyed == false and M23_flags.escape_timer_expired == false) do 
  2508. 		thread_yield() 
  2509. 	end 
  2510. 	 
  2511. 	if M23_flags.escape_timer_expired == true then 
  2512. 		-- The self destruct timer expired.  Things go boom. 
  2513. 		m23_do_boss_battle_self_destruct() 
  2514. 	end 
  2515. 	 
  2516. 	m23_cleanup_kill_cyrus() 
  2517. end 
  2518.  
  2519. -- The player picked up a minigun 
  2520. function m23_minigun_cb() 
  2521. 	for i, gun in pairs(M23_groups.ammo_stash_02.miniguns) do 
  2522. 		marker_remove(gun, SYNC_ALL) 
  2523. 		on_pickup("", gun) 
  2524. 	end 
  2525. end 
  2526.  
  2527. -- Cleanup the Cyrus boss battle 
  2528. function m23_cleanup_kill_cyrus() 
  2529. 	on_vehicle_destroyed("", M23_groups.cyrus_vtol.vtol) 
  2530. 	on_damage("", M23_groups.cyrus_vtol.vtol, 1.0) 
  2531. 	marker_remove(M23_groups.cyrus_vtol.vtol, SYNC_ALL) 
  2532. 	thread_kill(M23_threads.cyrus_boss_ai) 
  2533. 	on_trigger_exit("", M23_triggers.cyrus_combat) 
  2534. 	trigger_enable(M23_triggers.cyrus_combat, false) 
  2535. 	 
  2536. 	-- End camera shake 
  2537. 	camera_shake_stop() 
  2538. 	 
  2539. 	-- Disable the spawn regions on the deck. 
  2540. 	continuous_spawn_regions_enable(M23_spawn_regions.cyrus_deck, false) 
  2541. 	continuous_spawn_stop(M23_spawn_groups.offensive_01) 
  2542. 	continuous_spawn_stop(M23_spawn_groups.offensive_02) 
  2543. 	 
  2544. 	-- Cleanup miniguns 
  2545. 	for i, gun in pairs(M23_groups.ammo_stash_02.miniguns) do 
  2546. 		marker_remove(gun, SYNC_ALL) 
  2547. 		on_pickup("", gun) 
  2548. 	end 
  2549. end 
  2550.  
  2551. -- Callback for when Cyrus's VTOL has been destroyed 
  2552. function m23_cyrus_vtol_destroyed_cb() 
  2553. 	M23_flags.cyrus_vtol_destroyed = true 
  2554. end 
  2555.  
  2556. -- Callback for when Cyrus's VTOL reaches 75% health. 
  2557. -- 
  2558. -- vehicle:		(string) name of the vehicle damaged 
  2559. -- attacker:	(string) name of person causing the damage 
  2560. function m23_cyrus_health_75(vehicle, attacker) 
  2561. 	--message("75 health") 
  2562. 	M23_flags.do_cyrus_reinforcements = true 
  2563. 	M23_flags.destruct_start = true 
  2564. 	M23_tweak_values.taunt_idx_max = 4 
  2565. 	 
  2566. 	-- Keep Cyrus at 75% health until the reinforcement action finishes. 
  2567. 	vehicle_set_invulnerable(M23_groups.cyrus_vtol.vtol) 
  2568. 	 
  2569. 	-- Prevent Cyrus from falling below 50% health for the next stage. 
  2570. 	local new_min = get_max_hit_points(M23_groups.cyrus_vtol.vtol) * 0.50 
  2571. 	set_min_hit_points(M23_groups.cyrus_vtol.vtol, new_min) 
  2572. 	 
  2573. 	on_damage("m23_cyrus_health_50", M23_groups.cyrus_vtol.vtol, 0.50) 
  2574. 	 
  2575. 	-- Start the self destruct countdown timer. 
  2576. 	delay(rand_float(1.0, 5.0)) 
  2577. 	m23_boss_battle_self_destruct_timer_start() 
  2578. end 
  2579.  
  2580. -- Callback for when Cyrus's VTOL reaches 50% health. 
  2581. -- 
  2582. -- vehicle:		(string) name of the vehicle damaged 
  2583. -- attacker:	(string) name of person causing the damage 
  2584. function m23_cyrus_health_50(vehicle, attacker) 
  2585. 	--message("50 health") 
  2586. 	M23_flags.do_cyrus_reinforcements = true 
  2587. 	 
  2588. 	-- Stumble the players (can't call non-blocking because it will never give control back to the player) 
  2589. 	thread_new("m23_stumble", LOCAL_PLAYER) 
  2590. 	if (coop_is_active() == true) then 
  2591. 		thread_new("m23_stumble", REMOTE_PLAYER) 
  2592. 	end 
  2593. 	 
  2594. 	-- Play some audio. 
  2595. 	audio_object_post_event("m23_sfx_daedalus_shudders") 
  2596. 	 
  2597. 	-- Keep Cyrus at 50% health until the reinforcement action finishes. 
  2598. 	vehicle_set_invulnerable(M23_groups.cyrus_vtol.vtol) 
  2599. 	 
  2600. 	-- Prevent Cyrus from falling below 25% health for the next stage. 
  2601. 	local new_min = get_max_hit_points(M23_groups.cyrus_vtol.vtol) * 0.25 
  2602. 	set_min_hit_points(M23_groups.cyrus_vtol.vtol, new_min) 
  2603. 	 
  2604. 	on_damage("m23_cyrus_health_25", M23_groups.cyrus_vtol.vtol, 0.25) 
  2605. end 
  2606.  
  2607. -- Callback for when Cyrus's VTOL reaches 25% health. 
  2608. -- 
  2609. -- vehicle:		(string) name of the vehicle damaged 
  2610. -- attacker:	(string) name of person causing the damage 
  2611. function m23_cyrus_health_25(vehicle, attacker) 
  2612. 	--message("25% health") 
  2613. 	M23_flags.do_cyrus_reinforcements = true 
  2614. 	M23_flags.cyrus_final_phase = true 
  2615. 	 
  2616. 	-- Keep Cyrus at 25% health until the reinforcement action finishes. 
  2617. 	vehicle_set_invulnerable(M23_groups.cyrus_vtol.vtol) 
  2618. 	M23_conversations.times_up.handle = audio_conversation_load(M23_conversations.times_up.name) 
  2619. 	audio_conversation_play(M23_conversations.times_up.handle) 
  2620. 	 
  2621. 	-- Prevent Cyrus from falling below 10% health so that he doesn't blow up 
  2622. 	-- before we can hide him and play the z-scene of him crashing. 
  2623. 	local new_min = get_max_hit_points(M23_groups.cyrus_vtol.vtol) * 0.10 
  2624. 	set_min_hit_points(M23_groups.cyrus_vtol.vtol, new_min) 
  2625. 	 
  2626. 	on_damage("m23_cyrus_health_15", M23_groups.cyrus_vtol.vtol, 0.15) 
  2627. end 
  2628.  
  2629. -- Callback for when Cyrus's VTOL reaches 15% health.  This 
  2630. -- is when the engine will catch fire, and we should consider Cyrus 
  2631. -- dead. 
  2632. -- 
  2633. -- vehicle:		(string) name of the vehicle damaged 
  2634. -- attacker:	(string) name of person causing the damage 
  2635. function m23_cyrus_health_15(vehicle, attacker) 
  2636. 	--message("15 health") 
  2637. 	 
  2638. 	-- Keep Cyrus from blowing up so that we don't see debris falling from the sky 
  2639. 	-- after the z-scene. 
  2640. 	local max_hp = get_max_hit_points(M23_groups.cyrus_vtol.vtol) 
  2641. 	local target_hp = max_hp * 0.20 -- above "on fire" threshold 
  2642. 	set_current_hit_points(M23_groups.cyrus_vtol.vtol, target_hp) 
  2643. 	vehicle_set_smoke_and_fire_state(M23_groups.cyrus_vtol.vtol, false, false) 
  2644. 	vehicle_set_invulnerable(M23_groups.cyrus_vtol.vtol) 
  2645. 	 
  2646. 	-- Consider Cyrus dead at this point, since the z-scene shows him crashing into the deck (we don't want him to blow up twice). 
  2647. 	M23_flags.cyrus_vtol_destroyed = true 
  2648. 	 
  2649. 	on_damage("", M23_groups.cyrus_vtol.vtol, 1.0) 
  2650. end 
  2651.  
  2652. -- Start a timer for the self destruct, do some explosions, and make dudes stumble. 
  2653. function m23_boss_battle_self_destruct_timer_start() 
  2654. 	-- Make something explode. 
  2655. 	for i, explosion in pairs(M23_explosions.self_destruct_begin_explosions) do 
  2656. 		explosion_create(M23_explosions.effect, explosion) 
  2657. 		delay(0.1) 
  2658. 	end 
  2659. 	 
  2660. 	for i, vfx in pairs(M23_smoke.daedalus_rear) do 
  2661. 		effect_play(vfx, true) 
  2662. 	end 
  2663. 	 
  2664. 	M23_daedalus_guns.threads = cleanup_threads(M23_daedalus_guns.threads) 
  2665. 	M23_threads.daedalus_guns_thread = cleanup_threads(M23_threads.daedalus_guns_thread) 
  2666. 	m23_stop_all_daedalus_gun_effects() 
  2667. 	 
  2668. 	-- Stumble the players (can't call non-blocking because it will never give control back to the player) 
  2669. 	thread_new("m23_stumble", LOCAL_PLAYER) 
  2670. 	if (coop_is_active() == true) then 
  2671. 		thread_new("m23_stumble", REMOTE_PLAYER) 
  2672. 	end 
  2673. 	 
  2674. 	-- Play some audio. 
  2675. 	audio_object_post_event("m23_sfx_daedalus_shudders") 
  2676. 	 
  2677. 	-- Start a camera shake 
  2678. 	camera_shake_play_looping("cargo_plane_interior", M23_tweak_values.fight_looping_cam_shake_amount) 
  2679. 		 
  2680. 	m23_obliterate_landing_deck_vtols() 
  2681. 	 
  2682. 	delay(1.0) 
  2683. 	 
  2684. 	-- Start the timer. 
  2685. 	hud_timer_set(1, M23_tweak_values.boss_battle_self_descruct_time_limit, "m23_cb_boss_battle_self_destruct_time_expired") 
  2686. 	m23_play_cell_convo(M23_conversations.fireworks_started.name, false) 
  2687. 	M23_flags.escape_timer_expired = false 
  2688. 	 
  2689. 	delay(1.0) 
  2690. 	 
  2691. 	audio_object_post_event("M23_SFX_DAEDALUS_SELF_DESTRUCT_ALARM", nil, nil, M23_navpoints.daedalus_self_destruct_audio_pos) 
  2692. end 
  2693.  
  2694. -- Plays a stumble on the player. 
  2695. function m23_stumble(player) 
  2696. 	player_release_human_shield(player, true) 
  2697. 	if (character_is_in_vehicle(player) == false and character_is_ready(player) and (not character_is_jumping(player))) then 
  2698. 		action_play(player, "Plane Stumble Right") 
  2699. 	end 
  2700. end 
  2701.  
  2702. -- Callback for when the self-destruct timer expires during the Cyrus fight 
  2703. function m23_cb_boss_battle_self_destruct_time_expired() 
  2704. 	M23_flags.escape_timer_expired = true 
  2705. 	hud_timer_stop(1) 
  2706. end 
  2707.  
  2708. -- Triggers a bunch of explosions and then forcibly kills the players 
  2709. function m23_do_boss_battle_self_destruct() 
  2710. 	-- Start a thread to create random explosions 
  2711. 	M23_threads.explosions = thread_new("m23_self_destruct_explosions_thread") 
  2712. 	 
  2713. 	-- Let stuff blow up for a while. 
  2714. 	delay(5) 
  2715. 	 
  2716. 	-- Kill the player(s) 
  2717. 	m23_insta_kill_character(LOCAL_PLAYER, true, true) 
  2718. 	if coop_is_active() then 
  2719. 		m23_insta_kill_character(REMOTE_PLAYER, true, true) 
  2720. 	end 
  2721. 	 
  2722. 	while (true) do 
  2723. 		thread_yield() 
  2724. 	end 
  2725. end 
  2726.  
  2727. -- Genarate random explosions 
  2728. function m23_self_destruct_explosions_thread() 
  2729. 	while(true) do 
  2730. 		-- Delay a random time and explode a random navpoint 
  2731. 		delay(rand_float(0.2, 0.35)) 
  2732. 		explosion_create(M23_explosions.effect, get_random_table_entry(M23_explosions.self_destruct_explosions)) 
  2733. 	end 
  2734. end 
  2735.  
  2736. -- Genarate less random explosions 
  2737. function m23_vtol_escape_explosions_thread() 
  2738. 	while(true) do 
  2739. 		-- Delay a random time and explode a random navpoint 
  2740. 		delay(rand_float(0.2, 0.35)) 
  2741. 		explosion_create(M23_explosions.effect, get_random_table_entry(M23_explosions.vtol_escape_explosions)) 
  2742. 	end 
  2743. end 
  2744.  
  2745.  
  2746. --[[ 
  2747. 	Z-SCENE: Cyrus Dies! 
  2748. 	--]] 
  2749. 	 
  2750. function m23_play_cyrus_death_scene() 
  2751. 	cutscene_play(M23_cutscenes.cyrus_death, nil, M23_checkpoints.escape.player_starts) 
  2752. 	 
  2753. 	-- Make Cyrus go bye-bye 
  2754. 	group_destroy(M23_groups.cyrus_vtol.name) 
  2755. end 
  2756.  
  2757. function m23_cleanup_cyrus_death_scene() 
  2758. 	--[[ NOTHING TO DO ]]-- 
  2759. end 
  2760.  
  2761.  
  2762. --[[ 
  2763. 	OBJECTIVE: Escape!!! 
  2764. 	--]] 
  2765. 	 
  2766. function m23_escape_from_daedalus() 
  2767. 	-- Update the objective text with the new objective 
  2768. 	objective_text(0, M23_objectives.escape.tag, nil, nil, SYNC_ALL, M23_objectives.escape.icon) 
  2769. 	 
  2770. 	-- Start a camera shake 
  2771. 	camera_shake_play_looping("cargo_plane_interior", M23_tweak_values.escape_looping_cam_shake_amount) 
  2772. 	mesh_mover_hide(M23_movers.hangar_door) 
  2773. 	 
  2774. 	M23_threads.explosions = thread_new("m23_self_destruct_explosions_thread") 
  2775. 	M23_threads.explosions = thread_new("m23_vtol_escape_explosions_thread") 
  2776. 	 
  2777. 	for i, vfx in pairs(M23_smoke.daedalus_rear) do 
  2778. 		effect_play(vfx, true) 
  2779. 	end 
  2780. 	for i, vfx in pairs(M23_smoke.daedalus_fore) do 
  2781. 		effect_play(vfx, true) 
  2782. 	end 
  2783. 	 
  2784. 	delay(0.5) 
  2785. 	-- Stumble the players (can't call non-blocking because it will never give control back to the player) 
  2786. 	thread_new("m23_stumble", LOCAL_PLAYER) 
  2787. 	if (coop_is_active() == true) then 
  2788. 		thread_new("m23_stumble", REMOTE_PLAYER) 
  2789. 	end 
  2790. 	 
  2791. 	-- Play some VO 
  2792. 	audio_play_persona_line(LOCAL_PLAYER, M23_dialog_lines.escape) 
  2793. 	 
  2794. 	-- Set up callbacks for the players exiting the blast radius trigger. 
  2795. 	trigger_enable(M23_triggers.daedalus_blast_radius, true) 
  2796. 	on_trigger_exit("m23_cb_player_escaped", M23_triggers.daedalus_blast_radius) 
  2797. 	on_trigger("m23_cb_player_unescaped", M23_triggers.daedalus_blast_radius) 
  2798. 	 
  2799. 	-- Set up callbacks for trying to flee the Daedalus without taking a VTOL 
  2800. 	trigger_enable(M23_triggers.flee_region, true) 
  2801. 	on_trigger_exit("m23_cb_fleeing_check", M23_triggers.flee_region) 
  2802. 	 
  2803. 	M23_flags.local_player_escaped = (object_is_in_trigger(M23_triggers.daedalus_blast_radius, LOCAL_PLAYER) == false) 
  2804. 	M23_flags.remote_player_escaped = true 
  2805. 	if (coop_is_active()) then 
  2806. 		M23_flags.remote_player_escaped = (object_is_in_trigger(M23_triggers.daedalus_blast_radius, REMOTE_PLAYER) == false) 
  2807. 	end 
  2808. 	 
  2809. 	-- Setup the escape VTOLS 
  2810. 	group_create_hidden(M23_groups.daedalus_escape_vtols.name, true) 
  2811. 	vehicle_show(M23_groups.daedalus_escape_vtols.vtols[1]) 
  2812. 	on_vehicle_enter("m23_entered_escape_vtol", M23_groups.daedalus_escape_vtols.vtols[1]) 
  2813. 	marker_add(M23_groups.daedalus_escape_vtols.vtols[1], MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION, OI_FLAGS_LOCATION, SYNC_ALL) 
  2814. 	vehicle_set_invulnerable(M23_groups.daedalus_escape_vtols.vtols[1]) 
  2815. 	 
  2816. 	if coop_is_active() then 
  2817. 		vehicle_show(M23_groups.daedalus_escape_vtols.vtols[2]) 
  2818. 		on_vehicle_enter("m23_entered_escape_vtol", M23_groups.daedalus_escape_vtols.vtols[2]) 
  2819. 		marker_add(M23_groups.daedalus_escape_vtols.vtols[2], MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION, OI_FLAGS_LOCATION, SYNC_ALL) 
  2820. 		vehicle_set_invulnerable(M23_groups.daedalus_escape_vtols.vtols[2]) 
  2821. 	end 
  2822. 	 
  2823. 	-- Set the HUD timer, and wait for it to expire 
  2824. 	hud_timer_set(1, M23_tweak_values.escape_time_limit, "m23_cb_escape_time_expired") 
  2825. 	M23_flags.escape_timer_expired = false 
  2826. 	while(M23_flags.escape_timer_expired == false and (M23_flags.local_player_escaped == false or M23_flags.remote_player_escaped == false)) do 
  2827. 		thread_yield() 
  2828. 	end 
  2829. 	 
  2830. 	if M23_flags.local_player_escaped or M23_flags.remote_player_escaped then	 
  2831. 		-- Progress music if a player escaped. 
  2832. 		m23_post_music_event(M23_music.cyrus_fight_end) 
  2833. 	end 
  2834. 	 
  2835. 	-- Stop the HUD timer in case the players escaped early. 
  2836. 	hud_timer_stop(1) 
  2837. 	 
  2838. 	effect_play(M23_vfx.daedalus_explosoin) 
  2839. 	 
  2840. 	-- Kill any players caught in the explosion radius 
  2841. 	if (M23_flags.local_player_escaped == false) then 
  2842. 		local vehicle_name = get_char_vehicle_name(LOCAL_PLAYER) 
  2843. 		if (vehicle_name ~= nil and vehicle_name ~= "") then 
  2844. 			vehicle_detonate(vehicle_name) 
  2845. 		end 
  2846. 		 
  2847. 		m23_insta_kill_character(LOCAL_PLAYER, true, true, false) 
  2848. 	end 
  2849. 	if (M23_flags.remote_player_escaped == false) then 
  2850. 		local vehicle_name = get_char_vehicle_name(REMOTE_PLAYER) 
  2851. 		if (vehicle_name ~= nil and vehicle_name ~= "") then 
  2852. 			vehicle_detonate(vehicle_name) 
  2853. 		end 
  2854. 		 
  2855. 		m23_insta_kill_character(REMOTE_PLAYER, true, true, false) 
  2856. 	end 
  2857. 	 
  2858. 	-- If either player died, delay and allow the mission to fail for their death. 
  2859. 	if M23_flags.remote_player_escaped == false or M23_flags.local_player_escaped == false then 
  2860. 		delay(20.0) 
  2861. 	end 
  2862.  
  2863. 	m23_cleanup_escape_from_daedalus() 
  2864. end 
  2865.  
  2866. function m23_cleanup_escape_from_daedalus() 
  2867. 	-- Cleanup the escape VTOLS 
  2868. 	for i, vtol in pairs(M23_groups.daedalus_escape_vtols.vtols) do 
  2869. 		on_vehicle_enter("", vtol) 
  2870. 		marker_remove(vtol) 
  2871. 	end 
  2872. 	 
  2873. 	on_vehicle_enter("", M23_groups.daedalus_vtols_01.vtols[1]) 
  2874. 	 
  2875. 	-- Clear triggers. 
  2876. 	on_trigger_exit("", M23_triggers.daedalus_blast_radius) 
  2877. 	trigger_enable(M23_triggers.daedalus_blast_radius, false) 
  2878. 	 
  2879. 	on_trigger("", M23_triggers.daedalus_blast_radius) 
  2880. 	on_trigger_exit("", M23_triggers.flee_region) 
  2881. 	trigger_enable(M23_triggers.flee_region, false) 
  2882. 	 
  2883. 	-- End camera shake 
  2884. 	camera_shake_stop() 
  2885. 	 
  2886. 	-- Stop the timer 
  2887. 	hud_timer_stop(1) 
  2888. end	 
  2889.  
  2890. -- Callback for when the player enters one of the courtesy escape vehicles 
  2891. function m23_entered_escape_vtol(player, vtol, seat) 
  2892. 	-- Just remove the marker 
  2893. 	if coop_is_active() then 
  2894. 		marker_remove(vtol) 
  2895. 		on_vehicle_enter("", vtol) 
  2896. 	else 
  2897. 		for i, vehicle in pairs(M23_groups.daedalus_escape_vtols.vtols) do 
  2898. 			marker_remove(vehicle) 
  2899. 			on_vehicle_enter("", vehicle) 
  2900. 		end 
  2901. 	end 
  2902. end 
  2903.  
  2904. -- Callback for when the escape time expires 
  2905. function m23_cb_escape_time_expired() 
  2906. 	M23_flags.escape_timer_expired = true 
  2907. 	hud_timer_stop(1) 
  2908. end 
  2909.  
  2910. -- Callback for when a player exits the blast radius 
  2911. function m23_cb_player_escaped(human, trigger) 
  2912. 	if human == LOCAL_PLAYER then 
  2913. 		M23_flags.local_player_escaped = true 
  2914. 	elseif human == REMOTE_PLAYER then 
  2915. 		M23_flags.remote_player_escaped = true 
  2916. 	end 
  2917. end 
  2918.  
  2919. -- Callback for when a player enters the blast radius 
  2920. function m23_cb_player_unescaped(human, trigger) 
  2921. 	if human == LOCAL_PLAYER then 
  2922. 		M23_flags.local_player_escaped = false 
  2923. 	elseif human == REMOTE_PLAYER then 
  2924. 		M23_flags.remote_player_escaped = false 
  2925. 	end 
  2926. end 
  2927.  
  2928. -- Callback for when the player tries to flee to see if they're in a VTOL 
  2929. function m23_cb_fleeing_check(human, trigger) 
  2930. 	if character_is_in_vehicle(human) then 
  2931. 		trigger_enable(M23_triggers.flee_region, false) 
  2932. 		on_trigger_exit("", M23_triggers.flee_region) 
  2933. 	else 
  2934. 		explosion_create("VTOL_M_Exp-NPC", human) 
  2935. 		delay(0.5) 
  2936. 		m23_insta_kill_character(human, true, true) 
  2937. 	end 
  2938. end 
  2939.  
  2940.  
  2941. -- *************************************************** 
  2942. -- Miscellaneous m23 Helper Funcrtions 
  2943. -- *************************************************** 
  2944.  
  2945. -- Sets notoriety aircraft spawn groups as enabled or disabled 
  2946. function m23_set_notoriety_aircraft_enabled(enabled) 
  2947. 	notoriety_force_no_spawn_group("stag_attack_heli", not enabled) 
  2948. 	notoriety_force_no_spawn_group("stag_heli", not enabled) 
  2949. 	notoriety_force_no_spawn_group("police_heli", not enabled) 
  2950. 	notoriety_force_no_spawn_group("police_blackhawk", not enabled) 
  2951. 	notoriety_force_no_spawn_group("police_attack_heli", not enabled) 
  2952. end 
  2953.  
  2954. -- Setup and start the continuous spawn for the landing deck of the Daedalus 
  2955. function m23_setup_landing_deck_cont_spawn() 
  2956. 	-- Start the continuous spawn 
  2957. 	spawn_region_max_spawn_dist(150.0) 
  2958. 	continuous_spawn_regions_enable(M23_spawn_regions.landing_deck, true) 
  2959. 	continuous_spawn_start(M23_spawn_groups.defensive_01, 0, 5) 
  2960. 	continuous_spawn_start(M23_spawn_groups.defensive_02, 0, 5) 
  2961. 	continuous_spawn_start(M23_spawn_groups.offensive_01, 0, 5) 
  2962. 	continuous_spawn_start(M23_spawn_groups.riotshield_01, 0, 5) 
  2963. end 
  2964.  
  2965. -- Stop the landing deck continuous spawn 
  2966. --  
  2967. -- immediate:	True to immediately destroy any active obejcts, false if they should be passed to the ambient system 
  2968. function m23_cleanup_landing_deck_cont_spawn(immediate) 
  2969. 	spawn_region_max_spawn_dist_reset() 
  2970. 	continuous_spawn_regions_enable(M23_spawn_regions.landing_deck, false) 
  2971.  
  2972. 	continuous_spawn_stop(M23_spawn_groups.defensive_01) 
  2973. 	continuous_spawn_stop(M23_spawn_groups.defensive_02) 
  2974. 	continuous_spawn_stop(M23_spawn_groups.offensive_01) 
  2975. 	continuous_spawn_stop(M23_spawn_groups.riotshield_01) 
  2976. end 
  2977.  
  2978. -- Setup an ambush group 
  2979. -- 
  2980. -- group_table:		Lua table defining the ambush group 
  2981. function m23_helper_setup_ambush_group(group_table) 
  2982. 	-- Register this ambush group 
  2983. 	M23_runtime.ambush_groups[#M23_runtime.ambush_groups + 1] = group_table 
  2984.  
  2985. 	-- Enable the trigger(s) 
  2986. 	for i, trigger in pairs(group_table.triggers) do 
  2987. 		trigger_enable(trigger, true) 
  2988. 		on_trigger("m23_ambush_triggered_cb", trigger) 
  2989. 	end 
  2990. end 
  2991.  
  2992. -- Cleanup an ambush group 
  2993. function m23_helper_cleanup_ambush_group(group_table, destroy) 
  2994. 	-- Find and un-register this ambush group 
  2995. 	for i, group in pairs(M23_runtime.ambush_groups) do 
  2996. 		if (M23_runtime.ambush_groups[i].name == group_table.name) then 
  2997. 			M23_runtime.ambush_groups[i] = M23_runtime.ambush_groups[#M23_runtime.ambush_groups] 
  2998. 			M23_runtime.ambush_groups[#M23_runtime.ambush_groups] = nil 
  2999. 			break 
  3000. 		end 
  3001. 	end 
  3002. 	 
  3003. 	-- Disabled the trigger(s) 
  3004. 	for i, trigger in pairs(group_table.triggers) do  
  3005. 		trigger_enable(trigger, false) 
  3006. 		on_trigger("", trigger) 
  3007. 	end 
  3008. end 
  3009.  
  3010. -- Callback when the player enters an ambush trigger 
  3011. -- 
  3012. -- triggerer:		Play that entered the trigger 
  3013. -- trigger:			Name of the trigger that was entered 
  3014. function m23_ambush_triggered_cb(triggerer, trigger) 
  3015. 	-- Look-up the script group for this trigger volume 
  3016. 	local group_table = nil 
  3017. 	for i, ambush_group in pairs(M23_runtime.ambush_groups) do 
  3018. 		for j, ambush_trigger in pairs(ambush_group.triggers) do 
  3019. 			if (ambush_trigger == trigger) then 
  3020. 				group_table = ambush_group 
  3021. 			end 
  3022. 		end 
  3023. 	end 
  3024. 	 
  3025. 	if (group_table ~= nil) then 
  3026. 		for i, char in pairs(group_table.chars) do 
  3027. 			if (char.behavior == "advance") then 
  3028. 				npc_leash_remove(char.name) 
  3029. 				ai_add_enemy_target(char.name, CLOSEST_PLAYER, ATTACK_ON_SIGHT, false) 
  3030. 				ai_do_scripted_move(char.name, char.nav, true, false) 
  3031. 			elseif (char.behavior == "attack_region") then 
  3032. 				npc_leash_remove(char.name) 
  3033. 				ai_add_enemy_target(char.name, CLOSEST_PLAYER, ATTACK_ON_SIGHT, false) 
  3034. 				ai_attack_region(char.name, char.nav, char.radius) 
  3035. 			elseif (char.behavior == "take_cover") then 
  3036. 				npc_leash_remove(char.name) 
  3037. 				ai_add_enemy_target(char.name, CLOSEST_PLAYER, ATTACK_ON_SIGHT, false) 
  3038. 				ai_do_scripted_take_cover(char.name) 
  3039. 			end 
  3040. 		end		 
  3041. 	end 
  3042. end 
  3043.  
  3044. -- ************************* 
  3045. -- 
  3046. -- Callback functions 
  3047. -- 
  3048. -- ************************* 
  3049.  
  3050. -- Callback to unhide/activate the courtesy helis at the Saints HQ 
  3051. -- 
  3052. -- player:		Player that triggered the trigger region 
  3053. -- trigger:		Trigger region that got triggered 
  3054. function m23_saints_hq_activate_helis_cb(player, trigger) 
  3055. 	-- Clear the trigger. 
  3056. 	trigger_enable(M23_triggers.saints_hq_activate_helis, false) 
  3057. 	on_trigger("", M23_triggers.saints_hq_activate_helis) 
  3058. 	 
  3059. 	-- Unhide the helis. 
  3060. 	group_show(M23_groups.courtesy_helis.name) 
  3061. end 
  3062.  
  3063. -- Callback when a player triggers the elevator up at the Saints HQ 
  3064. --  
  3065. -- player:		Player that triggered the trigger region 
  3066. -- trigger:		Trigger region that got triggered 
  3067. function m23_saints_hq_elev_up_cb(player, trigger) 
  3068.  
  3069. end 
  3070.  
  3071. -- Callback when a player enters the triggers the elevator down at the Saints HQ 
  3072. --  
  3073. -- player:		Player that triggered the trigger region 
  3074. -- trigger:		Trigger region that got triggered 
  3075. function m23_saints_hq_elev_down_cb(player, trigger) 
  3076. 	marker_remove_trigger(M23_triggers.saints_hq_elev_up) 
  3077. 	mission_waypoint_remove() 
  3078. 	m23_saints_hq_entry_cb() 
  3079. end 
  3080.  
  3081. -- Callback when a player gets to the base of the Saints HQ 
  3082. -- 
  3083. -- player:		Player that triggered the trigger region 
  3084. -- trigger:		Trigger region that got triggered 
  3085. function m23_saints_hq_gps_cb(player, trigger) 
  3086. 	waypoint_remove() 
  3087. 	--marker_remove_trigger(M23_triggers.saints_hq_gps, SYNC_ALL) 
  3088. 	--marker_add_trigger(M23_triggers.saints_hq_elev_up, MINIMAP_ICON_LOCATION, INGAME_EFFECT_LOCATION, OI_ASSET_LOCATION, OI_FLAGS_LOCATION, SYNC_ALL) 
  3089. end 
  3090.  
  3091. -- Callback when the player leaves the Daedalus during the Cyrus battle. 
  3092. -- 
  3093. -- player:		Player that triggered the trigger region 
  3094. -- trigger:		Trigger region that got triggered 
  3095. function m23_failure_leave_cb(player, trigger) 
  3096. 	mission_end_failure("m23", "m23_failure_cyrus_escaped") 
  3097. end 
  3098.  
  3099. -- ************************* 
  3100. -- 
  3101. -- Thread functions 
  3102. -- 
  3103. -- ************************* 
  3104.  
  3105. function m23_missile_rack_thread(missile_rack) 
  3106. 	-- Loop until the thread is killed. 
  3107. 	while true do 
  3108. 		delay(rand_float(5.0, 8.0)) 
  3109. 		local volleys = rand_int(1, 3) 
  3110. 		for i = 1, volleys do 
  3111. 			local cur_rack = missile_rack.racks[missile_rack.cur_rack] 
  3112. 			for i, missile in pairs(cur_rack) do 
  3113. 				projectile_fire_from_navpoint(missile, missile_rack.target, "Explosive-RocketLauncher", 2.0) 
  3114. 				delay(0.25) 
  3115. 			end 
  3116. 			missile_rack.cur_rack = missile_rack.cur_rack + 1 
  3117. 			if missile_rack.cur_rack > #(missile_rack.racks) then 
  3118. 				missile_rack.cur_rack = 1 
  3119. 			end 
  3120. 			delay(0.33) 
  3121. 		end 
  3122. 	end 
  3123. end 
  3124.  
  3125. -- Manages firing bursts from all the various guns on the Daedalus. 
  3126. -- 
  3127. function m23_daedalus_guns_thread() 
  3128. 	local thread_idx = 1 
  3129. 	for i=1, sizeof_table(M23_daedalus_guns.threads) do 
  3130. 		if M23_daedalus_guns.threads[i] ~= INVALID_THREAD_HANDLE then 
  3131. 			thread_kill(M23_daedalus_guns.threads[i]) 
  3132. 			M23_daedalus_guns.threads[i] = INVALID_THREAD_HANDLE 
  3133. 		end 
  3134. 	end 
  3135.  
  3136. 	-- Loop until killed. 
  3137. 	local cur_effect = "" 
  3138. 	local thread_idx = 1 
  3139. 	while true do 
  3140. 		delay(rand_float(0.1, 0.5)) 
  3141. 		threads_wait_for_completion(M23_daedalus_guns.threads[thread_idx]) 
  3142. 		cur_effect = get_random_table_entry(M23_daedalus_guns.effects) 
  3143. 		M23_daedalus_guns.threads[thread_idx] = thread_new("m23_daedalus_gun_subthread", cur_effect, thread_idx) 
  3144. 		thread_idx = thread_idx + 1 
  3145. 		if thread_idx > sizeof_table(M23_daedalus_guns.threads) then 
  3146. 			thread_idx = 1 
  3147. 		end 
  3148. 	end 
  3149. end 
  3150.  
  3151. -- Fires a burst from a gun on the Daedalus. 
  3152. -- 
  3153. function m23_daedalus_gun_subthread(effect_nav, thread_idx) 
  3154. 	-- Determine who needs to see the effects. 
  3155. 	local sync_flags = m23_get_daedalus_gunfire_sync_flags() 
  3156. 	if sync_flags < 0 then 
  3157. 		-- Huh, guess we're done. 
  3158. 		return 
  3159. 	end 
  3160.  
  3161. 	M23_daedalus_guns.active_effect_handles[thread_idx] = effect_play(effect_nav, true, sync_flags) 
  3162. 	 
  3163. 	-- Start some looping audio for the gun. 
  3164. 	M23_daedalus_guns.active_audio_loops[thread_idx] = audio_object_post_event("M23_vfx_artillery", nil, nil, effect_nav) 
  3165. 	 
  3166. 	delay(rand_float(0.5, 2.0)) 
  3167. 		 
  3168. 	if M23_daedalus_guns.active_effect_handles[thread_idx] ~= -1 then		 
  3169. 		-- Stop the effect. 
  3170. 		effect_stop(M23_daedalus_guns.active_effect_handles[thread_idx], sync_flags) 
  3171. 		M23_daedalus_guns.active_effect_handles[thread_idx] = -1 
  3172. 	end 
  3173. 	 
  3174. 	if M23_daedalus_guns.active_audio_loops[thread_idx] > 0 then 
  3175. 		-- Stop the audio. 
  3176. 		audio_stop(M23_daedalus_guns.active_audio_loops[thread_idx]) 
  3177. 		M23_daedalus_guns.active_audio_loops[thread_idx] = -1 
  3178. 	end	 
  3179. end 
  3180.  
  3181. -- Fires a cannon on the Daedalus periodically. 
  3182. -- 
  3183. -- effect_nav:  (string) name of the nav point to play the effect at. 
  3184. -- refire_min:  (float)  minimum time between shots. 
  3185. -- refire_max:  (float)  maximum time between shots. 
  3186. -- 
  3187. function m23_daedalus_cannon_firing_thread(effect_nav, refire_min, refire_max) 
  3188. 	-- Continue looping until the thread is killed. 
  3189. 	while true do 
  3190. 		delay(rand_float(refire_min, refire_max)) 
  3191. 		if M23_flags.daedalus_main_cannons_firing == true then 
  3192. 			-- Determine who needs to see the effects. 
  3193. 			local sync_flags = m23_get_daedalus_gunfire_sync_flags() 
  3194. 		 
  3195. 			if sync_flags > 0 then 
  3196. 				effect_play(effect_nav, false, sync_flags) 
  3197. 			end 
  3198. 			--explosion_create("M23_daedalus_cannon", effect_nav, nil, false, effect_nav) 
  3199. 		end 
  3200. 	end 
  3201. end 
  3202.  
  3203. -- Waits for a helicopter to take off before removing it's HUD marker 
  3204. -- 
  3205. -- helicopter:		The helicopter to wait until it goes airborn 
  3206. function m23_wait_for_heli_takeoff_thread(helicopter) 
  3207. 	-- Wait for it to go airborn, and then remove the marker 
  3208. 	while(vehicle_in_air(helicopter) == false) do 
  3209. 		thread_yield() 
  3210. 	end 
  3211. 	 
  3212. 	marker_remove(helicopter, SYNC_ALL) 
  3213. end 
  3214.  
  3215. -- Process a set of vehicle's in a dog-fight around the VTOL 
  3216. -- 
  3217. -- dog_fight_group:		A table containing all of the info for this dog-fight (should modle attack_vtols_01) 
  3218. function m23_process_dog_fight(dog_fight_group) 
  3219. 	group_create(dog_fight_group.name, true) 
  3220. 	 
  3221. 	-- Put all the guys in their vehicles 
  3222. 	vehicle_enter_group_teleport(dog_fight_group.lead_group.chars, dog_fight_group.lead_group.vehicle) 
  3223. 	set_attack_enemies_flag(dog_fight_group.lead_group.chars[1], false) -- Don't allow the leader to attack enemies (especially Cyrus) 
  3224. 	for i, chase_group in pairs(dog_fight_group.chase_groups) do  
  3225. 		vehicle_enter_group_teleport(chase_group.chars, chase_group.vehicle) 
  3226. 		turn_invulnerable(chase_group.vehicle, true) -- allow player damage 
  3227. 		turn_invulnerable(chase_group.chars[1], true) -- allow player damage 
  3228. 	end 
  3229. 	 
  3230. 	-- Start the lead vehicle on their path, and continue looping until the lead vehicle is destroyed 
  3231. 	while(vehicle_is_destroyed(dog_fight_group.lead_group.vehicle) == false) do 
  3232. 		local any_chase_heli_alive = false 
  3233. 	 
  3234. 		-- Put all the chase vehicles on chase paths 
  3235. 		for i, chase_group in pairs(dog_fight_group.chase_groups) do  
  3236. 			if (vehicle_is_destroyed(chase_group.vehicle) == false) then 
  3237. 				any_chase_heli_alive = true 
  3238. 				helicopter_fly_to_do(chase_group.vehicle, -1, true, dog_fight_group.lead_group.vehicle, true, dog_fight_group.lead_group.path, chase_group.follow_dist, false) 
  3239. 				helicopter_go_to_set_target(chase_group.vehicle, dog_fight_group.lead_group.vehicle) 
  3240. 				ai_add_enemy_target(chase_group.chars[1], dog_fight_group.lead_group.chars[1], ATTACK_NOW_NEVER_LOSE, true) 
  3241. 			end 
  3242. 		end 
  3243. 		 
  3244. 		if (any_chase_heli_alive == false) then 
  3245. 			-- All chase helis are dead, have the lead vehicle retreat when he's done. 
  3246. 			break 
  3247. 		end 
  3248. 		 
  3249. 		-- Set the lead vehicle going 
  3250. 		turn_invulnerable(dog_fight_group.lead_group.vehicle, true) -- allow player damage 
  3251. 		turn_invulnerable(dog_fight_group.lead_group.chars[1], true) -- allow player damage 
  3252. 		helicopter_fly_to_direct_dont_stop(dog_fight_group.lead_group.vehicle, 30, dog_fight_group.lead_group.path) 
  3253. 		 
  3254. 		thread_yield() 
  3255. 	end 
  3256. 	 
  3257. 	-- Have everyone retreat and stop fighting.  We don't want any Saints to attack Cyrus. 
  3258. 	for i, chase_group in pairs(dog_fight_group.chase_groups) do  
  3259. 		helicopter_enter_retreat(chase_group.vehicle) 
  3260. 		set_ignore_ai_flag(chase_group.chars[1], false) 
  3261. 		set_attack_enemies_flag(chase_group.chars[1], false) -- Don't allow the leader to attack enemies (especially Cyrus) 
  3262. 	end 
  3263. 	helicopter_enter_retreat(dog_fight_group.lead_group.vehicle) 
  3264. 	 
  3265. 	delay(10.0) 
  3266. 	 
  3267. 	release_to_world(dog_fight_group.name) 
  3268. 	group_destroy(dog_fight_group.name) 
  3269. end 
  3270.  
  3271. -- Process an attack VTOL that takes off from the Daedalus, and chases the player 
  3272. -- 
  3273. -- vtol:			The VTOL that is taking off (should already have a guy in it) 
  3274. -- pilot:			The pilot flying the VTOL 
  3275. -- take_off_pos:	The navpoint the VTOL should fly to when taking off (before chasing) 
  3276. -- delay_time:		How much time to wait, before the VTOl should take off (in seconds) 
  3277. function m23_process_attack_vtol_take_off(vtol, pilot, take_off_pos, delay_time) 
  3278. 	delay(delay_time) 
  3279.  
  3280. 	-- Make the VTOl take off 
  3281. 	helicopter_fly_to_direct_dont_stop(vtol, -1, take_off_pos) 
  3282. 	 
  3283. 	-- Engage the player(s) 
  3284. 	vehicle_chase(vtol, LOCAL_PLAYER, false, false, true, false) 
  3285. 	ai_add_enemy_target(pilot, CLOSEST_PLAYER, ATTACK_NOW_NEVER_LOSE, true) 
  3286. 	helicopter_shoot_human(vtol, LOCAL_PLAYER, false) 
  3287. 	helicopter_go_to_set_target(vtol, LOCAL_PLAYER) 
  3288. end 
  3289.  
  3290. -- Process a stag soldier running to a tank 
  3291. -- 
  3292. -- tank:	The tank they are running to 
  3293. -- char:	The guy running to the tank 
  3294. -- seat:	The seat the guy should enter 
  3295. function m23_process_run_to_tank_thread(tank, char, seat) 
  3296. 	character_show(char) 
  3297.  
  3298. 	-- Enter the tank if it is still alive 
  3299. 	if (vehicle_is_destroyed(tank) == false) then 
  3300. 		vehicle_enter(char, tank, seat, true) 
  3301. 	end 
  3302.  
  3303. 	-- Clear the ignore ai flag, and attack the closest player 
  3304. 	set_ignore_ai_flag(char, false) 
  3305. 	ai_add_enemy_target(char, LOCAL_PLAYER, ATTACK_ON_SIGHT) 
  3306. 	if (coop_is_active() == true) then 
  3307. 		ai_add_enemy_target(char, REMOTE_PLAYER, ATTACK_ON_SIGHT) 
  3308. 	end 
  3309. 	 
  3310. 	-- If the tank and character are still alive, and this character got into the driver's seat, then add a marker on the tank 
  3311. 	if (vehicle_is_destroyed(tank) == false and character_is_dead(char) == false --[[and character_is_in_a_driver_seat(char) == true--]]) then 
  3312. 		-- marker_add(tank, MINIMAP_ICON_KILL, OI_ASSET_KILL_FULL) 
  3313. 		on_vehicle_destroyed("m23_callback_daedalus_tank_destroyed_cb", tank) 
  3314. 		 
  3315. 		M23_runtime.daedalus_surface_tanks_alive = M23_runtime.daedalus_surface_tanks_alive + 1 
  3316. 	end 
  3317. end 
  3318.  
  3319. -- Thread to process Cyrus's boss AI 
  3320. function m23_process_cyrus_boss_ai_thread() 
  3321. 	local sequence_idx = 1 
  3322. 	while(true) do 
  3323. 		if (M23_flags.do_cyrus_reinforcements == true) then 
  3324. 			-- If Cyrus' health has hit a milestone, then call in reinforcements. 
  3325. 			sequence_idx = rand_int(1, #(M23_cyrus_boss_ai.reinforce_threads)) 
  3326. 			M23_threads.cyrus_boss_action = thread_new(M23_cyrus_boss_ai.reinforce_threads[sequence_idx].func) 
  3327. 			M23_flags.do_cyrus_reinforcements = false 
  3328. 		else 
  3329. 			-- Call the next attack sequence, and wait for it to complete 
  3330. 			sequence_idx = rand_int(1, #(M23_cyrus_boss_ai.attack_threads)) 
  3331. 			M23_threads.cyrus_boss_action = thread_new(M23_cyrus_boss_ai.attack_threads[sequence_idx].func) 
  3332. 		end 
  3333. 		 
  3334. 		M23_runtime.cyrus_taunt_idx = M23_runtime.cyrus_taunt_idx + 1 
  3335. 		if (M23_runtime.cyrus_taunt_idx < 0) or (M23_runtime.cyrus_taunt_idx > M23_tweak_values.taunt_idx_max) then 
  3336. 			M23_runtime.cyrus_taunt_idx = 1 
  3337. 		end 
  3338. 		 
  3339. 		while(thread_check_done(M23_threads.cyrus_boss_action) == false) do 
  3340. 			thread_yield() 
  3341. 		end 
  3342. 		 
  3343. 		-- Fly back the other way next time 
  3344. 		M23_flags.cyrus_fly_left_to_right = not M23_flags.cyrus_fly_left_to_right 
  3345. 		 
  3346. 		--[[ 
  3347. 		-- Move to the next attack in the sequence table 
  3348. 		sequence_idx = sequence_idx + 1 
  3349. 		if (sequence_idx > #(M23_cyrus_boss_ai.attack_threads)) then 
  3350. 			sequence_idx = 1 
  3351. 		end 
  3352. 		--]] 
  3353. 		 
  3354. 		thread_yield() -- Make sure we don't stall the game if an acttack thread returns early 
  3355. 	end 
  3356. end 
  3357.  
  3358. -- Helper thread to process Cyrus shooting the charge laser at a random player 
  3359. -- 
  3360. -- refire_delay:	Time delay between shots (in seconds) 
  3361. -- error_radius:	Error radius around the player for the shots (in meters) 
  3362. function m23_cyrus_boss_fire_at_player_thread(refire_delay, error_radius) 
  3363. 	delay(2.0) 
  3364. 	 
  3365. 	-- Figure out the target player (%50/%50 split, for either player in coop) 
  3366. 	local target_player = LOCAL_PLAYER 
  3367. 	if (coop_is_active() and rand_int(1, 2) == 2) then 
  3368. 		target_player = REMOTE_PLAYER 
  3369. 	end 
  3370. 	 
  3371. 	-- Register the enemy player 
  3372. 	ai_add_enemy_target(M23_groups.cyrus_vtol.cyrus, target_player, ATTACK_NOW_NEVER_LOSE, true) 
  3373. 	 
  3374. 	if (M23_runtime.cyrus_taunt_idx == 4) then 
  3375. 		audio_play_persona_line_2d(M23_personas.interrogation.persona_id, M23_dialog_lines.abandon_ship) 
  3376. 	else 
  3377. 		audio_play_persona_line_2d(M23_personas.cyrus.persona_id, M23_dialog_lines.cyrus_taunts[M23_runtime.cyrus_taunt_idx]) 
  3378. 	end 
  3379.  
  3380.  
  3381. 	-- Fire at the target player indefinitly, until this thread gets killed 
  3382. 	while(true) do 
  3383. 		helicopter_shoot_human(M23_groups.cyrus_vtol.vtol, target_player, true, error_radius) 
  3384. 		delay(refire_delay) 
  3385. 	end 
  3386. end 
  3387.  
  3388. -- Helper thread to process Cyrus doing a sweep shot at a random player 
  3389. -- 
  3390. -- refire_delay:	Time delay between shots (in seconds) 
  3391. function m23_cyrus_boss_sweep_fire_at_player_thread(refire_delay) 
  3392. 	delay(2.0) 
  3393. 	 
  3394. 	-- Figure out the target player (%50/%50 split, for either player in coop) 
  3395. 	local target_player = LOCAL_PLAYER 
  3396. 	if (coop_is_active() and rand_int(1, 2) == 2) then 
  3397. 		target_player = REMOTE_PLAYER 
  3398. 	end 
  3399. 	 
  3400. 	-- Register the enemy player 
  3401. 	ai_add_enemy_target(M23_groups.cyrus_vtol.cyrus, target_player, ATTACK_NOW_NEVER_LOSE, true) 
  3402. 	 
  3403. 	if (M23_runtime.cyrus_taunt_idx == 4) then 
  3404. 		audio_play_persona_line_2d(M23_personas.interrogation.persona_id, M23_dialog_lines.abandon_ship) 
  3405. 	else 
  3406. 		audio_play_persona_line_2d(M23_personas.cyrus.persona_id, M23_dialog_lines.cyrus_taunts[M23_runtime.cyrus_taunt_idx]) 
  3407. 	end 
  3408. 	 
  3409. 	-- Process the sweep shot indefinitely, until this thread gets killed 
  3410. 	local x_offset = 0.0 
  3411. 	while(true) do 
  3412. 		helicopter_shoot_human(M23_groups.cyrus_vtol.vtol, target_player, false, 1.0, false) 
  3413. 		--x_offset = cyrus_boss_ai_sweep_shot(M23_groups.cyrus_vtol.vtol, target_player, 5.0, x_offset, 1.0, 15.0) 
  3414. 		delay(refire_delay) 
  3415. 	end 
  3416. end 
  3417.  
  3418. -- Thread to process Cyrus's strafe attack behavior 
  3419. function m23_cyrus_boss_ai_strafe_thread() 
  3420. 	--message("strafe") 
  3421. 	-- Pick a random strafe attack definition 
  3422. 	local strafe_attack_idx = rand_int(1, #(M23_cyrus_boss_ai.strafe_attacks)) 
  3423. 	local strafe_attack_info = M23_cyrus_boss_ai.strafe_attacks[strafe_attack_idx] 
  3424. 	local path_name = "" 
  3425. 	 
  3426. 	-- Do the intro path 
  3427. 	m23_cyrus_pathfind(strafe_attack_info.paths.left_to_right.intro, strafe_attack_info.paths.right_to_left.intro, -1) 
  3428. 	 
  3429. 	-- Start the thread to process Cyrus's shooting behavior 
  3430. 	M23_threads.cyrus_fire_weapon_thread = thread_new("m23_cyrus_boss_fire_at_player_thread", strafe_attack_info.refire_delay, strafe_attack_info.error_radius) 
  3431. 	 
  3432. 	-- Set the max bank angle, and give Cyrus perfect aim 
  3433. 	helicopter_set_max_bank_angle(M23_groups.cyrus_vtol.vtol, 15) 
  3434. 	set_perfect_aim(M23_groups.cyrus_vtol.cyrus, true) 
  3435. 		 
  3436. 	-- Start up the middle path 
  3437. 	m23_cyrus_pathfind(strafe_attack_info.paths.left_to_right.middle, strafe_attack_info.paths.right_to_left.middle, strafe_attack_info.vtol_speed) 
  3438. 			 
  3439. 	-- Kill the thread processing Cyrus's shooting behavior 
  3440. 	if (thread_check_done(M23_threads.cyrus_fire_weapon_thread) == false) then 
  3441. 		thread_kill(M23_threads.cyrus_fire_weapon_thread) 
  3442. 	end 
  3443. 	 
  3444. 	-- Clear the max bank angle setting, and remove perfect aim 
  3445. 	helicopter_clear_max_bank_angle(M23_groups.cyrus_vtol.vtol) 
  3446. 	set_perfect_aim(M23_groups.cyrus_vtol.cyrus, false)	 
  3447. 	--helicopter_set_path_orientation(M23_groups.cyrus_vtol.vtol, HELI_PF_FACE_ALONG_PATH) 
  3448.  
  3449. 	-- Do the outro path 
  3450. 	m23_cyrus_pathfind(strafe_attack_info.paths.left_to_right.outro, strafe_attack_info.paths.right_to_left.outro, -1) 
  3451. end 
  3452.  
  3453. -- Thread to process Cyrus's sweep attack behavior 
  3454. function m23_cyrus_boss_ai_sweep_thread() 
  3455. 	--message("sweep") 
  3456. 	-- Pick a random strafe attack definition 
  3457. 	local sweep_attack_idx = rand_int(1, #(M23_cyrus_boss_ai.sweep_attacks)) 
  3458. 	local sweep_attack_info = M23_cyrus_boss_ai.sweep_attacks[sweep_attack_idx] 
  3459. 	local path_name = "" 
  3460. 	 
  3461. 	-- Do the intro path 
  3462. 	m23_cyrus_pathfind(sweep_attack_info.paths.left_to_right.intro, sweep_attack_info.paths.right_to_left.intro, -1) 
  3463.  
  3464. 	-- Start a thread to process the sweep shooting behavior 
  3465. 	M23_threads.cyrus_fire_weapon_thread = thread_new("m23_cyrus_boss_sweep_fire_at_player_thread", sweep_attack_info.refire_delay) 
  3466. 	 
  3467. 	-- Start up the middle path 
  3468. 	m23_cyrus_pathfind(sweep_attack_info.paths.left_to_right.middle, sweep_attack_info.paths.right_to_left.middle, sweep_attack_info.vtol_speed) 
  3469. 	helicopter_set_max_bank_angle(M23_groups.cyrus_vtol.vtol, 15) 
  3470. 	 
  3471. 	-- Kill the thread processing Cyrus's shooting behavior 
  3472. 	if (thread_check_done(M23_threads.cyrus_fire_weapon_thread) == false) then 
  3473. 		thread_kill(M23_threads.cyrus_fire_weapon_thread) 
  3474. 	end 
  3475. 	 
  3476. 	-- Do the outro path 
  3477. 	m23_cyrus_pathfind(sweep_attack_info.paths.left_to_right.outro, sweep_attack_info.paths.right_to_left.outro, -1) 
  3478. end 
  3479.  
  3480. function m23_cyrus_boss_ai_reinforcement_thread() 
  3481. 	--message("reinforcements") 
  3482. 	 
  3483. 	-- Spawn some reinforcements somewhere on the deck.  Start by releasing any dudes 
  3484. 	-- that might still be alive from the previous spawn. 
  3485. 	continuous_spawn_stop(M23_spawn_groups.offensive_01) 
  3486. 	continuous_spawn_stop(M23_spawn_groups.offensive_02) 
  3487. 	continuous_spawn_start(M23_spawn_groups.offensive_01, 1) 
  3488. 	continuous_spawn_start(M23_spawn_groups.offensive_02, 1) 
  3489. 	 
  3490. 	-- Pick a random reinforcement attack definition 
  3491. 	local reinforcement_idx = rand_int(1, #(M23_cyrus_boss_ai.reinforcement_attacks)) 
  3492. 	local reinforcement_info = M23_cyrus_boss_ai.reinforcement_attacks[reinforcement_idx] 
  3493. 	local path_name = "" 
  3494. 	 
  3495. 	-- Create (or recreate) the transport script group 
  3496. 	if (group_is_loaded(M23_groups.transport_vtol_01.name) == true) then 
  3497. 		-- Check to see if any of the guys are still alive 
  3498. 		for i, char in pairs(M23_groups.transport_vtol_01.soldiers) do 
  3499. 			if (character_is_dead(char) == false) then 
  3500. 				-- Don't continue with this action, since there is a live enemy on the Daedalus deck. 
  3501. 				-- Since we didn't actually fly anywhere, then reset the left-to-right flag. 
  3502. 				M23_flags.cyrus_fly_left_to_right = not M23_flags.cyrus_fly_left_to_right 
  3503. 				vehicle_set_vulnerable(M23_groups.cyrus_vtol.vtol) 
  3504. 				 
  3505. 				-- If this is the final phase, allow Cyrus' VTOL to death spiral again. 
  3506. 				if M23_flags.cyrus_final_phase == true then 
  3507. 					helicopter_set_dont_death_spiral(M23_groups.cyrus_vtol.vtol, false) 
  3508. 				end 
  3509. 				return 
  3510. 			end 
  3511. 		end 
  3512. 		 
  3513. 		release_to_world(M23_groups.transport_vtol_01.name)	 
  3514. 		group_destroy(M23_groups.transport_vtol_01.name) 
  3515. 		thread_yield() 
  3516. 	end 
  3517. 	group_create(M23_groups.transport_vtol_01.name, true) 
  3518. 	 
  3519. 	-- Kick off a thread to process the transport VTOL 
  3520. 	if (thread_check_done(M23_threads.cyrus_transport_thread) == false) then 
  3521. 		thread_kill(M23_threads.cyrus_transport_thread) 
  3522. 		thread_yield() 
  3523. 	end 
  3524. 	 
  3525. 	local transport_path_idx = rand_int(1, #reinforcement_info.transport_paths) 
  3526. 	local transport_path = reinforcement_info.transport_paths[transport_path_idx] 
  3527. 	M23_threads.cyrus_transport_thread = thread_new("m23_cyrus_transport_drop_off_thread", M23_groups.transport_vtol_01, transport_path) 
  3528. 	 
  3529. 	-- Do Cyrus's pathfind 
  3530. 	m23_cyrus_pathfind(reinforcement_info.cyrus_paths.left_to_right, reinforcement_info.cyrus_paths.right_to_left, -1) 
  3531. 			 
  3532. 	-- Cyrus is made invulnerable until we can start a reinforcement action; so make him vulnerable again when we're done. 
  3533. 	vehicle_set_vulnerable(M23_groups.cyrus_vtol.vtol) 
  3534. 	 
  3535. 	-- If this is the final phase, allow Cyrus' VTOL to death spiral again. 
  3536. 	if M23_flags.cyrus_final_phase == true then 
  3537. 		helicopter_set_dont_death_spiral(M23_groups.cyrus_vtol.vtol, false) 
  3538. 	end 
  3539. end 
  3540.  
  3541. -- Process a VTOL transport drop-off 
  3542. -- 
  3543. -- transport_table:		VTOL transport Lua table (as defined in M23_groups::transport_vtol_01) 
  3544. -- paths:				Paths the transport should follow to drop the soldiers off and then exit 
  3545. function m23_cyrus_transport_drop_off_thread(transport_table, paths) 
  3546. 	-- Put the characters into the VTOL 
  3547. 	local seat_idx = 0 
  3548. 	for i, char in pairs(transport_table.pilots) do 
  3549. 		-- Put the pilots into the vehicle 
  3550. 		vehicle_enter_teleport(char, transport_table.vtol, seat_idx, true) 
  3551. 		follower_remain_in_car(char, true) 
  3552. 		 
  3553. 		seat_idx = seat_idx + 1 
  3554. 	end 
  3555. 	 
  3556. 	-- Make sure we don't put a solider in a co-pilot seat, if it hasn't been filled 
  3557. 	if (seat_idx < 2) then 
  3558. 		seat_idx = 2 
  3559. 	end 
  3560. 	for j, char in pairs(transport_table.soldiers) do 
  3561. 		-- Put the soldiers into the vehicle 
  3562. 		vehicle_enter_teleport(char, transport_table.vtol, seat_idx, true) 
  3563. 		 
  3564. 		seat_idx = seat_idx + 1 
  3565. 	end 
  3566. 	 
  3567. 	delay(1.5) 
  3568. 	audio_play_persona_line_2d(M23_personas.cyrus.persona_id, M23_dialog_lines.cyrus_call_backup) 
  3569.  
  3570. 		 
  3571. 	-- Do the approach pathfind. 
  3572. 	helicopter_fly_to_direct(transport_table.vtol, -1, paths.approach_path) 
  3573. 	 
  3574. 	-- Tell the soldiers to exit the transport VTOL 
  3575. 	--[[ 
  3576. 	vehicle_exit_group_teleport(transport_table.soldiers) -- hack: teleport the dudees out until we get exit animations. 
  3577. 	delay(3.0) 
  3578. 	--]] 
  3579. 	 
  3580. 	vehicle_exit_group(transport_table.soldiers, true)	-- unenterable to make sure the soldiers don't try to get back in the transport 
  3581. 	 
  3582. 	-- Wait for everyone to get out. 
  3583. 	for j, char in pairs(transport_table.soldiers) do 
  3584. 		if character_is_in_vehicle(char, transport_table.vtol) then 
  3585. 			thread_yield() 
  3586. 			break 
  3587. 		end 
  3588. 	end	 
  3589.  
  3590. 	-- Force all the soldiers that got dropped off to take cover 
  3591. 	for j, char in pairs(transport_table.soldiers) do 
  3592. 		if (character_is_dead(char) == false) then 
  3593. 			ai_do_scripted_take_cover(char) 
  3594. 		end 
  3595. 	end 
  3596. 	 
  3597. 	-- Do the exit pathfind. 
  3598. 	helicopter_fly_to_direct(transport_table.vtol, -1, paths.exit_path) 
  3599. 	 
  3600. 	-- All drop offs are complete, so tell it to retreat 
  3601. 	helicopter_enter_retreat(transport_table.vtol) 
  3602. end 
  3603.  
  3604. -- Thread function to execute the chase behavior for Cyrus's boss AI 
  3605. -- 
  3606. -- duration:	Amount of time (in seconds) this attack should last 
  3607. function m23_cyrus_boss_ai_chase_thread(duration) 
  3608. 	-- Pick a random reinforcement attack definition 
  3609. 	local chase_idx = rand_int(1, #(M23_cyrus_boss_ai.chase_attacks)) 
  3610. 	local chase_info = M23_cyrus_boss_ai.chase_attacks[chase_idx] 
  3611. 	 
  3612. 	-- Move to the start 
  3613. 	helicopter_fly_to_direct(M23_groups.cyrus_vtol.vtol, -1, chase_info.paths.intro) 
  3614. 	 
  3615. 	-- Start chasing the player 
  3616. 	vehicle_chase(M23_groups.cyrus_vtol.vtol, LOCAL_PLAYER, false, false, true, false) 
  3617. 	 
  3618. 	delay(3.0) 
  3619. 	if (M23_runtime.cyrus_taunt_idx == 4) then 
  3620. 		audio_play_persona_line_2d(M23_personas.interrogation.persona_id, M23_dialog_lines.abandon_ship) 
  3621. 	else 
  3622. 		audio_play_persona_line_2d(M23_personas.cyrus.persona_id, M23_dialog_lines.cyrus_taunts[M23_runtime.cyrus_taunt_idx]) 
  3623. 	end 
  3624. 	 
  3625. 	delay(chase_info.duration) 
  3626. 	 
  3627. 	-- Move to the next locatoin 
  3628. 	helicopter_fly_to_direct(M23_groups.cyrus_vtol.vtol, -1, chase_info.paths.outro) 
  3629. end 
  3630.  
  3631. --[[ 
  3632. -- Thread function to execute the peak behavior for Cyrus's boss AI 
  3633. -- 
  3634. -- duration:	Amount of time (in seconds) this attack should last 
  3635. function m23_cyrus_boss_ai_peak_thread(duration) 
  3636. 	-- Pick a random peak location 
  3637. 	local peak_idx = rand_int(1, #(M23_navpoints.cyrus_boss_ai.peak.start)) 
  3638. 	 
  3639. 	-- Move the VTOL to the start position 
  3640. 	helicopter_fly_to_do(M23_groups.cyrus_vtol.vtol, -1, true, "", false, M23_navpoints.cyrus_boss_ai.peak.start[peak_idx], 0.0) 
  3641. 	helicopter_fly_to_set_goal_direction(M23_groups.cyrus_vtol.vtol, LOCAL_PLAYER, false) 
  3642. 	helicopter_go_to_set_target(M23_groups.cyrus_vtol.vtol, LOCAL_PLAYER) 
  3643. 	ai_add_enemy_target(M23_groups.cyrus_vtol.cyrus, LOCAL_PLAYER, ATTACK_NOW_NEVER_LOSE, true) 
  3644. 	 
  3645. 	while(vehicle_pathfind_check_done(M23_groups.cyrus_vtol.vtol) == 0) do 
  3646. 		thread_yield() 
  3647. 	end 
  3648. 	 
  3649. 	-- Move to the peak pos 
  3650. 	helicopter_fly_to_do(M23_groups.cyrus_vtol.vtol, -1, true, "", false, M23_navpoints.cyrus_boss_ai.peak.stop[peak_idx], 0.0) 
  3651. 	helicopter_fly_to_set_goal_direction(M23_groups.cyrus_vtol.vtol, LOCAL_PLAYER, false) 
  3652. 	helicopter_go_to_set_target(M23_groups.cyrus_vtol.vtol, LOCAL_PLAYER) 
  3653. 	 
  3654. 	while(vehicle_pathfind_check_done(M23_groups.cyrus_vtol.vtol) == 0) do 
  3655. 		thread_yield() 
  3656. 	end 
  3657. 	ai_add_enemy_target(M23_groups.cyrus_vtol.cyrus, LOCAL_PLAYER, ATTACK_NOW_NEVER_LOSE, true) 
  3658. 	 
  3659. 	delay(duration) 
  3660.  
  3661. 	-- Move back down to the start pos 
  3662. 	helicopter_fly_to_direct(M23_groups.cyrus_vtol.vtol, -1, M23_navpoints.cyrus_boss_ai.peak.start[peak_idx]) 
  3663. end 
  3664.  
  3665. -- Thread function to execute the hover behavior for Cyrus's boss AI 
  3666. -- 
  3667. -- duration:	Amount of time (in seconds) this attack should last 
  3668. function m23_cyrus_boss_ai_attack_thread(duration) 
  3669. 	-- Pick a random hover location 
  3670. 	local hover_idx = rand_int(1, #(M23_navpoints.cyrus_boss_ai.hover.start)) 
  3671. 	 
  3672. 	-- Move to the start 
  3673. 	helicopter_fly_to_direct(M23_groups.cyrus_vtol.vtol, -1, M23_navpoints.cyrus_boss_ai.hover.start[hover_idx]) 
  3674. 	helicopter_fly_to_set_goal_direction(M23_groups.cyrus_vtol.vtol, LOCAL_PLAYER, false) 
  3675. 	helicopter_go_to_set_target(M23_groups.cyrus_vtol.vtol, LOCAL_PLAYER) 
  3676. 	ai_add_enemy_target(M23_groups.cyrus_vtol.cyrus, LOCAL_PLAYER, ATTACK_NOW_NEVER_LOSE, true) 
  3677. 	 
  3678. 	-- Move to the hover location 
  3679. 	helicopter_fly_to_direct(M23_groups.cyrus_vtol.vtol, -1, M23_navpoints.cyrus_boss_ai.hover.stop[hover_idx]) 
  3680. 	helicopter_fly_to_set_goal_direction(M23_groups.cyrus_vtol.vtol, LOCAL_PLAYER, false) 
  3681. 	helicopter_go_to_set_target(M23_groups.cyrus_vtol.vtol, LOCAL_PLAYER) 
  3682. 	ai_add_enemy_target(M23_groups.cyrus_vtol.cyrus, LOCAL_PLAYER, ATTACK_NOW_NEVER_LOSE, true) 
  3683. 	delay(2.0) 
  3684.  
  3685. 	helicopter_shoot_human(M23_groups.cyrus_vtol.vtol, LOCAL_PLAYER, false) 
  3686. 	 
  3687. 	delay(duration) 
  3688. 	 
  3689. 	-- Pick a position to move to 
  3690. 	local move_to_idx = rand_int(1, #(M23_navpoints.cyrus_boss_ai.hover.start)) 
  3691. 	if (move_to_idx == hover_idx) then 
  3692. 		-- Make sure this is a different point than we started at 
  3693. 		move_to_idx = move_to_idx + 1 
  3694. 		if (move_to_idx > #(M23_navpoints.cyrus_boss_ai.hover.start)) then 
  3695. 			move_to_idx = 1 
  3696. 		end 
  3697. 	end 
  3698. 	 
  3699. 	-- Move to the next locatoin 
  3700. 	helicopter_go_to_set_target(M23_groups.cyrus_vtol.vtol, LOCAL_PLAYER) 
  3701. 	helicopter_fly_to_direct_dont_stop(M23_groups.cyrus_vtol.vtol, -1, M23_navpoints.cyrus_boss_ai.hover.stop[move_to_idx]) 
  3702. 	 
  3703. 	helicopter_shoot_human(M23_groups.cyrus_vtol.vtol, LOCAL_PLAYER, false) 
  3704. 	delay(2.2) 
  3705. 	 
  3706. 	helicopter_fly_to_direct(M23_groups.cyrus_vtol.vtol, -1, M23_navpoints.cyrus_boss_ai.hover.start[move_to_idx]) 
  3707. 	helicopter_go_to_set_target(M23_groups.cyrus_vtol.vtol, LOCAL_PLAYER) 
  3708. end 
  3709.  
  3710. --]] 
  3711.