./m15.lua

  1. --[[ 
  2. 	m15.lua 
  3. 	SR3 Mission Script 
  4. 	DATE: 08-12-2010 
  5. 	AUTHOR:	Craig Williams 
  6. ]]-- 
  7.  
  8.  
  9. -- Debug flags -- 
  10. 	 
  11. -- Tweakable Parameters -- 
  12. 	M15_DELAY_BETWEEN_WAVE_SPAWNS	=  0.5 -- Time to wait before spawning the next group in the wave 
  13. 	M15_ELEVATOR_OPEN_PROXIMITY	=  4.0 
  14. 	M15_LOBBY_LEASH_RADIUS			= 25.0 
  15.  
  16. 	M15_INFINITE_MASS				=  true -- Set the super computer to have infinite mass? 
  17. 	M15_KNEECAPPER_DAMAGE		=   7.0 -- Amount of damage the kneecappers should apply to the tires. 0 for the default behavior. 
  18. 	M15_TIRE_DAMGE_MULTIPLIER  =  10.0 -- Modifies how much damage is applied to the tires 
  19. 	M15_SUPER_COMPUTER_SPEED	=  65.0 -- Override the super computers speed 
  20. 	M15_VEHICLE_WARN_RADIUS		= 150.0 -- Causes the super computer truck to stall (stop) if the player is outside this radius 
  21. 	M15_VEHICLE_MAX_DISTANCE	= 250.0 -- Maximum distance the player is allowed to get away from the super computer before the mission fails. 
  22. 	 
  23. 	M15_MIN_NOTORIETY			= 1 
  24. 	M15_MAX_NOTORIETY			= 1     -- Must be <= MAX_NOTORIETY_LEVEL 
  25. 	M15_ROADBLOCKS_ENABLED	= false -- Enable notoriety based roadblocks? 
  26. 	 
  27. 	M15_WAYPOINT_REMOVE_DIST	= 70.0 -- When within this radius, the vehicle's waypoint will be removed.	 
  28.  
  29. 	M15_PED_DENSITY = 0.5 
  30. 	M15_VEHICLE_DENSITY = 0.4 
  31. 	 
  32. 	M15_soften_hit_points = 100 
  33. 	 
  34. 	RUBBER_BAND_CLOSE_DIST = 5.0 
  35. 	RUBBER_BAND_FAR_DIST = 120.0 
  36. 	RUBBER_BAND_CLOSE_SPEED = 38.0 
  37. 	RUBBER_BAND_FAR_SPEED = 1.0 
  38. 	 
  39. 	M15_attack_info = { 
  40. 		decker = { 
  41. 			situation = "M15_computer", 
  42. 			delay = 10.0, 
  43. 			callback = "m15_decker_attack_cb", 
  44. 			timer = INVALID_THREAD_HANDLE 
  45. 		}, 
  46. 		 
  47. 		stag = { 
  48. 			situation = "M15_attack", 
  49. 			delay = 10.0, 
  50. 			callback = "m15_stag_attack_cb", 
  51. 			timer = INVALID_THREAD_HANDLE 
  52. 		} 
  53. 	}	 
  54.  
  55. -- Groups -- 
  56. 	NPC_PIERCE             = "npc_pierce" 
  57. 	NPC_DRIVER             = "npc_chase_driver" 
  58. 	VEHICLE_SUPER_COMPUTER = "vehicle_chase" 
  59.  
  60. 	M15_groups = { 
  61. 		extra_homies     = {name = "group_extra_homies", members = {"npc_extra_homie 001", "npc_extra_homie 002"}}, 
  62. 		homies           = {name = "group_homies", members = {"npc_pierce"}}, 
  63. 		homies_2         = {name = "group_homies 002", members = {"npc_pierce 002"}}, 
  64. 		start_vehicle    = {name = "group_start_vehicle"}, 
  65. 		start_vehicle_2  = {name = "group_start_vehicle 002"}, 
  66. 		chase            = {name = "group_chase"}, 
  67. 		outside_vehicles = {name = "group_outside_vehicles"}, 
  68. 		outside_deckers  = {name = "group_outside_deckers"}, 
  69. 		outside_stag     = {name = "group_outside_stag"}, 
  70. 		garage           = {name = "group_garage_deckers"}, 
  71. 		tank_garage      = {name = "group_tank_garage", tank = "vehicle_tank_garage"}, 
  72. 		tank_outside     = {name = "group_tank_outside"}, 
  73. 		cars_outside_garage = {name = "group_cars_outside_garage"}, 
  74. 		kneecapper_outside={name = "group_kneecapper_outside", vehicles = {"vehicle_kneecapper_outside 002"},}, 
  75. 		 
  76. 		dead_stag = { 
  77. 			name = "group_garage_dead_stag",  
  78. 			members = { 
  79. 				"npc_garage_dead_stag 001", "npc_garage_dead_stag 002", "npc_garage_dead_stag 003",  
  80. 				"npc_garage_dead_stag 004", "npc_garage_dead_stag 005", "npc_garage_dead_stag 006",  
  81. 				"npc_garage_dead_stag 007", "npc_garage_dead_stag 008",  
  82. 			} 
  83. 		}, 
  84. 		 
  85. 		deckers_base = {name = "group_deckers_base",}, 
  86. 	} 
  87. 	 
  88. 	-- kill waves for the group fighting outside 
  89. 	M15_kill_outside = { 
  90. 		arrive = { 
  91. 			vehicle = "vehicle_cover_outside 002", 
  92. 			people = { "npc_stag_outside 002", 
  93. 						"npc_rollerblader_outside 007" }, 
  94. 		}, 
  95. 		 
  96. 		enter = { 
  97. 			vehicle = "vehicle_cover_outside 005",  
  98. 			people = { "npc_stag_outside 009", "npc_stag_outside 003", 
  99. 							"npc_rollerblader_outside 001", "npc_rollerblader_outside 002" }, 
  100. 		}, 
  101. 		 
  102. 		the_rest = { 
  103. 			vehicle = "vehicle_cover_outside 001", 
  104. 			people = { "npc_stag_outside 011", "npc_stag_outside 012", "npc_stag_outside 015", 
  105. 						"npc_deckers_outside 005", "npc_rollerblader_outside 004", "npc_rollerblader_outside 006" }, 
  106. 		} 
  107. 	} 
  108. 	 
  109. 	-- Tables of waves 
  110. 	M15_LOBBY_LEASH_POINT = "nav_lobby_leash_point" 
  111. 	M15_waves = { 
  112. 		-- Spawned when the player enters the lobby. This runs in parallel with M15_waves.lobby_decker. 
  113. 		lobby_stag = { 
  114. 			groups = { 
  115. 				{ 
  116. 					name = "group_lobby_stag_wave 001",  
  117. 					members = {"npc_inside_static_stag 001", "npc_inside_static_stag 003", "npc_inside_static_stag 005", "npc_inside_static_stag 006"}, --, "npc_inside_static_stag 007" 
  118. 					human_shield = "", 
  119. 					run_to = {}, 
  120. 					dont_run_trigger = "", 
  121. 				}, 
  122. 				{ 
  123. 					name = "group_lobby_stag_wave 002",  
  124. 					members = {"npc_inside_stag 001", "npc_inside_stag 002", "npc_inside_stag 003"}, 
  125. 					human_shield = "", 
  126. 					run_to = {"nav_middle_level 001", "nav_middle_level 002", "nav_middle_level 003", "nav_middle_level 004"}, 
  127. 					dont_run_trigger = "trigger_lobby_upper_level", 
  128. 				},--[[ 
  129. 				{  
  130. 					name = "group_lobby_stag_wave 003",  
  131. 					members = {"npc_inside_stag 004", "npc_inside_stag 005", "npc_inside_stag 006"}, 
  132. 					human_shield = "", 
  133. 					run_to = {"nav_middle_level 005", "nav_middle_level 006", "nav_middle_level 007", "nav_middle_level 008"}, 
  134. 					dont_run_trigger = "trigger_lobby_upper_level", 
  135. 				},]] 
  136. 			}, 
  137. 			 
  138. 			attack_cb = M15_attack_info.stag.callback, 
  139. 			leash_to = M15_LOBBY_LEASH_POINT, 
  140. 			leash_radius = M15_LOBBY_LEASH_RADIUS, 
  141. 			thread = INVALID_THREAD_HANDLE, 
  142. 			num_remaining = 0 
  143. 		}, 
  144.  
  145. 		-- Spawned when the player enters the lobby. This runs in parallel with M15_waves.lobby_stag. 
  146. 		lobby_decker = { 
  147. 			groups = { 
  148. 				{ 
  149. 					name = "group_lobby_deckers_wave 001",  
  150. 					members = {"npc_inside_static_decker 003", "npc_inside_static_decker 007", "npc_inside_static_decker 008", "npc_inside_static_decker 009", "npc_inside_static_decker 010", 
  151. 										"npc_inside_static_decker 011", "npc_inside_static_decker 012", "npc_inside_static_decker 013", "npc_inside_static_decker 015"}, --"npc_inside_static_decker 014", , "npc_inside_static_decker 004" 
  152. 					human_shield = "", 
  153. 					run_to = {}, 
  154. 					dont_run_trigger = "", 
  155. 				}, 
  156. 				{ 
  157. 					name = "group_lobby_deckers_wave 002",  
  158. 					members = {"npc_inside_deckers 001", "npc_inside_deckers 002", "npc_inside_deckers 003", "npc_inside_decker_hs 001"}, 
  159. 					human_shield = "npc_inside_decker_hs 001", 
  160. 					run_to = {}, 
  161. 					dont_run_trigger = "", 
  162. 				}, 
  163. 				{  
  164. 					name = "group_lobby_deckers_wave 003",  
  165. 					members = {"npc_inside_deckers 004", "npc_inside_deckers 005", "npc_inside_decker_hs 002"}, 
  166. 					human_shield = "npc_inside_decker_hs 002", 
  167. 					run_to = {}, 
  168. 					dont_run_trigger = "",			 
  169. 				}, 
  170. 			}, 
  171. 			 
  172. 			attack_cb = M15_attack_info.decker.callback, 
  173. 			leash_to = M15_LOBBY_LEASH_POINT, 
  174. 			leash_radius = M15_LOBBY_LEASH_RADIUS, 
  175. 			thread = INVALID_THREAD_HANDLE, 
  176. 			num_remaining = 0 
  177. 		}, 
  178. 	} 
  179. 	 
  180. 	M15_outside_garage = { 
  181. 		stag = { 
  182. 			name = "group_stag_rockets", 
  183. 			members = { 
  184. 				{npc = "npc_stag_rocket 003", nav = "nav_stag_rocket 003"}, {npc = "npc_stag_rocket 004", nav = "nav_stag_rocket 004"}, 
  185. 				{npc = "npc_stag_rocket 014", nav = "nav_stag_rocket 014"}, {npc = "npc_stag_rocket 015", nav = "nav_stag_rocket 015"}, 
  186. 			}, 
  187. 		}, 
  188. 		 
  189. 		stag_leashes = { 
  190. 			"nav_stag_rocket 001", 
  191. 			"nav_stag_rocket 002", 
  192. 			"nav_stag_rocket 003", 
  193. 			"nav_stag_rocket 004", 
  194. 			"nav_stag_rocket 005", 
  195. 			"nav_stag_rocket 006", 
  196. 			"nav_stag_rocket 007", 
  197. 			"nav_stag_rocket 008", 
  198. 			"nav_stag_rocket 009", 
  199. 			"nav_stag_rocket 010", 
  200. 			"nav_stag_rocket 010", 
  201. 			"nav_stag_rocket 012", 
  202. 			"nav_stag_rocket 013", 
  203. 			"nav_stag_rocket 014", 
  204. 			"nav_stag_rocket 015", 
  205. 			"nav_stag_rocket 016", 
  206. 			"nav_stag_rocket 017", 
  207. 			"nav_stag_rocket 018", 
  208. 		}, 
  209. 		 
  210. 		saints = { 
  211. 			name = "group_kneecappers", 
  212. 			members = { 
  213. 				{npcs = {"npc_kneecapper_driver 001"}, vehicle = "vehicle_kneecapper 001", path = "path_kneecapper 001", thread = INVALID_THREAD_HANDLE}, 
  214. 				{npcs = {"npc_kneecapper_driver 003"}, vehicle = "vehicle_kneecapper 002", path = "path_kneecapper 002", thread = INVALID_THREAD_HANDLE}, 
  215. 			}, 
  216. 		}, 
  217. 	} 
  218. 	 
  219. -- Continuous Spawn Groups -- 
  220. 	M15_continuous_spawns = { 
  221. 		deckers = { 
  222. 			groups	= { 
  223. --				"deckers_spawn_group 001", 
  224. 				"deckers_spawn_group 002", 
  225. 				"deckers_spawn_group 003", 
  226. 			}, 
  227. 			regions	= {"decker_spawn_region <001>", "decker_spawn_region <002>",}, 
  228. 			filter	= SRF_1, 
  229. 			respawn_delay = 10.0, 
  230. 		}, 
  231. 		 
  232. 		stag = { 
  233. 			groups	= { 
  234. --				"stag_spawn_group 001", 
  235. --				"stag_spawn_group 002", 
  236. 				"stag_spawn_group 003", 
  237. 			}, 
  238. 			regions	= {"stag_spawn_region <001>", "stag_spawn_region <002>",}, 
  239. 			filter	= SRF_2, 
  240. 			respawn_delay = 10.0, 
  241. 		}, 
  242. 	} 
  243. 	 
  244. 	M15_pr_front_doors = {"mover_pr_front_door 001", "mover_pr_front_door 004",} 
  245. 	 
  246. -- Navpoints -- 
  247. 	-- Navpoint tables. The following tables map to 
  248. 	--   [1] - Local Player 
  249. 	--   [2] - Remote Player (if M15_in_coop) 
  250. 	--   [3] - Pierce 
  251. 	-- See the helper function m15_teleport_team_to() 
  252. 	M15_NAV_START          = {"nav_start_local",          "nav_start_remote",          "nav_start_pierce"} 
  253. 	M15_NAV_OUTSIDE        = {"nav_outside_local",        "nav_outside_remote",        "nav_outside_pierce"} 
  254. 	M15_NAV_LOBBY          = {"nav_lobby_local",          "nav_lobby_remote",          "nav_lobby_pierce"} 
  255. 	M15_NAV_GARAGE         = {"nav_garage_local",         "nav_garage_remote",         "nav_garage_pierce"} 
  256. 	M15_NAV_GARAGE_OUTSIDE = {"nav_garage_outside_local", "nav_garage_outside_remote", "nav_garage_outside_pierce"} 
  257.  
  258. 	-- Mission objective nav points 
  259. 	M15_NAV_POWER_PLANT         = "nav_power_plant" 
  260. 	M15_NAV_PR_CENTER_ENTERANCE = "nav_pr_center_entrance" 
  261. 	M15_NAV_ELEVATOR_TO_STUDIO  = "nav_elevator_to_studio" 
  262. 	M15_NAV_ELEVATOR_TO_GARAGE  = "nav_elevator_to_garage" 
  263. 	M15_NAV_GARAGE_DOOR         = "nav_garage_door" 
  264. 	 
  265. 	-- Super computer route nav points. 
  266. 	M15_SUPER_COMPUTER_START = "nav_to_plant_start" 
  267. 	M15_SUPER_COMPUTER_ROUTE = {{nav = "nav_to_plant 001", delay = "",}, {nav = "nav_to_plant 002", delay = "",},  
  268. 										 {nav = "nav_to_plant 003", delay = "",}, {nav = "nav_to_plant 004", delay = "",}, 
  269. 	                            {nav = "nav_to_plant 005", delay = "",}, {nav = "nav_to_plant 006", delay = "",},  
  270. 										 {nav = "nav_to_plant 007", delay = "",}, {nav = "nav_to_plant 008", delay = "",},  
  271. 										 {nav = "nav_to_plant 009", delay = "",}, {nav = "nav_to_plant 010", delay = "",}, 
  272. 										} 
  273.  
  274. -- Triggers -- 
  275. 	M15_triggers = { 
  276. 		pr_center_front        = "trigger_pr_center_front", 
  277. 		pr_center_enterance    = "trigger_pr_center_enterance", 
  278. 		pr_center_radius       = "trigger_pr_center_radius", 
  279. 		elevator_to_studio     = "trigger_elevator_to_studio",		-- Use trigger 
  280. 		elevator_to_garage_1   = "trigger_elevator_to_garage 001", 
  281. 		elevator_to_garage_2   = "trigger_elevator_to_garage 002", 
  282. 		garage_door            = "trigger_garage_door", 
  283. 		power_plant            = "trigger_power_plant", 
  284. 		pr_center_inside       = "trigger_make_npc_critical", 
  285. 		stag_rockets           = "trigger_stag_rockets", 
  286. 	} 
  287. 	 
  288. -- Chase scene triggers 
  289. 	M15_chase_triggers = { 
  290. 		{ 
  291. 			name				= "Roadblock_group 001", -- Name of the script group to create 
  292. 			prep_trigger	= "Roadblock_prep_trigger 001", 
  293. 			trigger_name	= "Roadblock_trigger 001", -- Name of the trigger to to enable 
  294. 			on_trigger		= "m15_close_roadblock", -- Callback to call when the trigger is triggered 
  295. 			 
  296. 			-- List of the vehicles in the group that should follow a path when the trigger is triggered 
  297. 			vehicles = { 
  298. 				{ vehicle = "Roadblock_vehicle 002", members = {"Roadblock_npc 002"}, path = "Roadblock_nav 001", thread = INVALID_THREAD_HANDLE }, 
  299. 				{ vehicle = "Roadblock_vehicle 003", members = {"Roadblock_npc 003"}, path = "Roadblock_nav 002", thread = INVALID_THREAD_HANDLE }, 
  300. 				{ vehicle = "Roadblock_vehicle 004", members = {"Roadblock_npc 004"}, path = "Roadblock_nav 003", thread = INVALID_THREAD_HANDLE }, 
  301. 				{ vehicle = "Roadblock_vehicle 005", members = {"Roadblock_npc 005"}, path = "Roadblock_nav 004", thread = INVALID_THREAD_HANDLE }, 
  302. 			}, 
  303. 		}, 
  304. 		{ 
  305. 			name				= "Roadblock_group 002", 
  306. 			prep_trigger	= "Roadblock_prep_trigger 002", 
  307. 			trigger_name	= "Roadblock_trigger 002", 
  308. 			on_trigger		= "m15_close_roadblock", 
  309. 			vehicles = { 
  310. 				{ vehicle = "Roadblock_vehicle 007", members = {"Roadblock_npc 007"}, gunner = "Roadblock_npc_gunner 007", path = "Roadblock_nav 007", thread = INVALID_THREAD_HANDLE }, 
  311. 				{ vehicle = "Roadblock_vehicle 008", members = {"Roadblock_npc 008"}, gunner = "Roadblock_npc_gunner 008", path = "Roadblock_nav 008", thread = INVALID_THREAD_HANDLE }, 
  312. 				{ vehicle = "Roadblock_vehicle 009", members = {"Roadblock_npc 009"}, gunner = "Roadblock_npc_gunner 009", path = "Roadblock_nav 009", thread = INVALID_THREAD_HANDLE }, 
  313. 			}, 
  314. 		}, 
  315. 		{ 
  316. 			name				= "Roadblock_group 003", 
  317. 			prep_trigger	= "Roadblock_prep_trigger 003", 
  318. 			trigger_name	= "Roadblock_trigger 003", 
  319. 			on_trigger		= "m15_close_roadblock", 
  320. 			vehicles = { 
  321. 				{ vehicle = "Roadblock_vehicle 010", members = {"Roadblock_npc 010"}, path = "Roadblock_nav 010", thread = INVALID_THREAD_HANDLE }, 
  322. 				{ vehicle = "Roadblock_vehicle 011", members = {"Roadblock_npc 011"}, path = "Roadblock_nav 011", thread = INVALID_THREAD_HANDLE }, 
  323. 				{ vehicle = "Roadblock_vehicle 012", members = {"Roadblock_npc 012"}, path = "Roadblock_nav 012", thread = INVALID_THREAD_HANDLE }, 
  324. 				{ vehicle = "Roadblock_vehicle 013", members = {"Roadblock_npc 013"}, path = "Roadblock_nav 013", thread = INVALID_THREAD_HANDLE }, 
  325. 			}, 
  326. 		}, 
  327. 		{ 
  328. 			name				= "Roadblock_group 004", 
  329. 			prep_trigger	= "Roadblock_prep_trigger 004", 
  330. 			trigger_name	= "Roadblock_trigger 004", 
  331. 			on_trigger		= "m15_close_roadblock", 
  332. 			vehicles = { 
  333. 				{ vehicle = "Roadblock_vehicle 015", members = {"Roadblock_npc 015"}, path = "Roadblock_nav 015", thread = INVALID_THREAD_HANDLE }, 
  334. 				{ vehicle = "Roadblock_vehicle 016", members = {"Roadblock_npc 016"}, path = "Roadblock_nav 016", thread = INVALID_THREAD_HANDLE }, 
  335. 				{ vehicle = "Roadblock_vehicle 017", members = {"Roadblock_npc 017"}, path = "Roadblock_nav 017", thread = INVALID_THREAD_HANDLE }, 
  336. 			}, 
  337. 		}, 
  338. 		{ 
  339. 			name				= "Roadblock_group 005", 
  340. 			prep_trigger	= "Roadblock_prep_trigger 005", 
  341. 			trigger_name	= "Roadblock_trigger 005", 
  342. 			on_trigger		= "m15_close_roadblock", 
  343. 			vehicles = { 
  344. 				{ vehicle = "Roadblock_vehicle 019", members = {"Roadblock_npc 019"}, path = "Roadblock_nav 019", thread = INVALID_THREAD_HANDLE }, 
  345. 				{ vehicle = "Roadblock_vehicle 020", members = {"Roadblock_npc 020"}, path = "Roadblock_nav 020", thread = INVALID_THREAD_HANDLE }, 
  346. 				{ vehicle = "Roadblock_vehicle 021", members = {"Roadblock_npc 021"}, path = "Roadblock_nav 021", thread = INVALID_THREAD_HANDLE }, 
  347. 			}, 
  348. 		}, 
  349. 		{ 
  350. 			name				= "Roadblock_group 006", 
  351. 			prep_trigger	= "Roadblock_prep_trigger 006", 
  352. 			trigger_name	= "Roadblock_trigger 006", 
  353. 			on_trigger		= "m15_close_roadblock", 
  354. 			vehicles = { 
  355. 				{ vehicle = "Roadblock_vehicle 022", members = {"Roadblock_npc 022"}, path = "Roadblock_nav 022", thread = INVALID_THREAD_HANDLE }, 
  356. 				{ vehicle = "Roadblock_vehicle 023", members = {"Roadblock_npc 023"}, path = "Roadblock_nav 023", thread = INVALID_THREAD_HANDLE }, 
  357. 				{ vehicle = "Roadblock_vehicle 024", members = {"Roadblock_npc 024"}, path = "Roadblock_nav 024", thread = INVALID_THREAD_HANDLE }, 
  358. 				{ vehicle = "Roadblock_vehicle 025", members = {"Roadblock_npc 025"}, path = "Roadblock_nav 025", thread = INVALID_THREAD_HANDLE }, 
  359. 			}, 
  360. 		}, 
  361. 		{ 
  362. 			name				= "Roadblock_group 007", 
  363. 			prep_trigger	= "Roadblock_prep_trigger 007", 
  364. 			trigger_name	= "Roadblock_trigger 007", 
  365. 			on_trigger		= "m15_close_roadblock", 
  366. 			vehicles = { 
  367. 				{ vehicle = "Roadblock_vehicle 027", members = {"Roadblock_npc 027"}, gunner = "Roadblock_npc_gunner 027", path = "Roadblock_nav 027", thread = INVALID_THREAD_HANDLE }, 
  368. 				{ vehicle = "Roadblock_vehicle 028", members = {"Roadblock_npc 028"}, gunner = "Roadblock_npc_gunner 028", path = "Roadblock_nav 028", thread = INVALID_THREAD_HANDLE }, 
  369. 				{ vehicle = "Roadblock_vehicle 029", members = {"Roadblock_npc 029"}, gunner = "Roadblock_npc_gunner 029", path = "Roadblock_nav 029", thread = INVALID_THREAD_HANDLE }, 
  370. 				{ vehicle = "Roadblock_vehicle 030", members = {"Roadblock_npc 030"}, gunner = "Roadblock_npc_gunner 030", path = "Roadblock_nav 030", thread = INVALID_THREAD_HANDLE }, 
  371. 			}, 
  372. 		}, 
  373. 		{ 
  374. 			name				= "Roadblock_group 008", 
  375. 			prep_trigger	= "Roadblock_prep_trigger 008", 
  376. 			trigger_name	= "Roadblock_trigger 008", 
  377. 			on_trigger		= "m15_close_roadblock", 
  378. 			vehicles = { 
  379. 				{ vehicle = "Roadblock_vehicle 031", members = {"Roadblock_npc 031"}, path = "Roadblock_nav 031", thread = INVALID_THREAD_HANDLE }, 
  380. 				{ vehicle = "Roadblock_vehicle 032", members = {"Roadblock_npc 032"}, path = "Roadblock_nav 032", thread = INVALID_THREAD_HANDLE }, 
  381. 				{ vehicle = "Roadblock_vehicle 033", members = {"Roadblock_npc 033"}, path = "Roadblock_nav 033", thread = INVALID_THREAD_HANDLE }, 
  382. 				{ vehicle = "Roadblock_vehicle 034", members = {"Roadblock_npc 034"}, path = "Roadblock_nav 034", thread = INVALID_THREAD_HANDLE }, 
  383. 				{ vehicle = "Roadblock_vehicle 035", members = {"Roadblock_npc 035"}, path = "Roadblock_nav 035", thread = INVALID_THREAD_HANDLE }, 
  384. 			}, 
  385. 		}, 
  386. 		{ 
  387. 			name				= "Roadblock_group 009", 
  388. 			prep_trigger	= "Roadblock_prep_trigger 009", 
  389. 			trigger_name	= "Roadblock_trigger 009", 
  390. 			on_trigger		= "m15_close_roadblock", 
  391. 			vehicles = { 
  392. 				{ vehicle = "Roadblock_vehicle 036", members = {"Roadblock_npc 036"}, path = "Roadblock_nav 036", thread = INVALID_THREAD_HANDLE }, 
  393. 				{ vehicle = "Roadblock_vehicle 037", members = {"Roadblock_npc 037"}, path = "Roadblock_nav 037", thread = INVALID_THREAD_HANDLE }, 
  394. 				{ vehicle = "Roadblock_vehicle 038", members = {"Roadblock_npc 038"}, path = "Roadblock_nav 038", thread = INVALID_THREAD_HANDLE }, 
  395. 				{ vehicle = "Roadblock_vehicle 039", members = {"Roadblock_npc 039"}, path = "Roadblock_nav 039", thread = INVALID_THREAD_HANDLE }, 
  396. 			}, 
  397. 		}, 
  398. 		{ 
  399. 			name				= "Chase_group 001", 
  400. 			prep_trigger	= "Chase_prep_trigger 001", 
  401. 			trigger_name	= "Chase_trigger 001", 
  402. 			on_trigger		= "m15_chase_truck", 
  403. 			vehicles = { 
  404. 				{ vehicle = "Chase_vehicle 001", members = {"Chase_npc 001"}, gunner = "Chase_npc_gunner 001", path = "Chase_nav 001", thread = INVALID_THREAD_HANDLE }, 
  405. 				{ vehicle = "Chase_vehicle 002", members = {"Chase_npc 002"}, gunner = "Chase_npc_gunner 002", path = "Chase_nav 002", thread = INVALID_THREAD_HANDLE }, 
  406. 			}, 
  407. 		}, 
  408. 		{ 
  409. 			name				= "Chase_group 002", 
  410. 			prep_trigger	= "Chase_prep_trigger 002", 
  411. 			trigger_name	= "Chase_trigger 002", 
  412. 			on_trigger		= "m15_chase_truck", 
  413. 			vehicles = { 
  414. 				{ vehicle = "Chase_vehicle 003", members = {"Chase_npc 003"}, gunner = "Chase_npc_gunner 003", path = "Chase_nav 003", thread = INVALID_THREAD_HANDLE }, 
  415. 				{ vehicle = "Chase_vehicle 004", members = {"Chase_npc 004"}, gunner = "Chase_npc_gunner 004", path = "Chase_nav 004", thread = INVALID_THREAD_HANDLE }, 
  416. 			}, 
  417. 		}, 
  418. 		{ 
  419. 			name				= "Ambient_battle 001", 
  420. 			prep_trigger	= "", 
  421. 			trigger_name	= "Ambient_battle_trigger 001", 
  422. 			on_trigger		= "m15_spawn_and_release", 
  423. 			vehicles			= { }, 
  424. 		}, 
  425. 		{ 
  426. 			name				= "Ambient_battle 002", 
  427. 			prep_trigger	= "", 
  428. 			trigger_name	= "Ambient_battle_trigger 002", 
  429. 			on_trigger		= "m15_spawn_and_release", 
  430. 			vehicles			= { }, 
  431. 		}, 
  432. 		{ 
  433. 			name				= "", 
  434. 			prep_trigger	= "", 
  435. 			trigger_name	= "trigger_slow_down_truck", 
  436. 			on_trigger		= "m15_reduce_truck_speed", 
  437. 			vehicles			= { }, 
  438. 		}, 
  439. 		{ 
  440. 			name				= "", 
  441. 			prep_trigger	= "", 
  442. 			trigger_name	= "trigger_spawn_deckers_base", 
  443. 			on_trigger		= "m15_spawn_deckers_base", 
  444. 			vehicles			= { }, 
  445. 		} 
  446. 	} 
  447. 	 
  448. -- Trigger Flags -- 
  449. 	M15_in_coop           = false 
  450. 	M15_trigger_reached   = false 
  451. 	 
  452. 	M15_chase_notoriety_disabled     = false 
  453. 	M15_chase_waypoint_active_local  = false 
  454. 	M15_chase_waypoint_active_remote = false 
  455.  
  456. -- Characters -- 
  457.  
  458. -- Vehicles -- 
  459.  
  460. -- Mesh Movers -- 
  461. 	M15_elevators = { 
  462. 		{ 
  463. 			nav = "nav_elevator_center 001", 
  464. 			mover = "mover_elevator_doors 001", 
  465. 		}, 
  466. 		{ 
  467. 			nav = "nav_elevator_center 002", 
  468. 			mover = "mover_elevator_doors 002", 
  469. 		}, 
  470. 		{ 
  471. 			nav = "nav_elevator_center 003", 
  472. 			mover = "mover_elevator_doors 003", 
  473. 		}, 
  474. 		{ 
  475. 			nav = "nav_elevator_center 004", 
  476. 			mover = "mover_elevator_doors 004", 
  477. 		}, 
  478. 	} 
  479.  
  480. -- Text -- 
  481. 	M15_OBJ_GO_TO_PR_CENTER		= "m15_obj_go_to_pr_center" 
  482. 	M15_OBJ_GET_TO_THE_GARAGE	= "m15_obj_get_to_the_garage" 
  483. 	M15_OBJ_CLEAR_THE_LOBBY		= "m15_obj_clear_the_lobby" 
  484. 	M15_OBJ_ESCAPE_THE_GARAGE	= "m15_obj_escape_the_garage" 
  485. 	M15_OBJ_GET_IN_THE_TANK		= "m15_obj_get_in_the_tank" 
  486. 	M15_OBJ_CATCH_THE_TRUCK		= "m15_obj_catch_the_truck" 
  487. 	M15_OBJ_DISABLE_THE_TRUCK	= "m15_obj_disable_the_truck" 
  488.  
  489. 	M15_FAILURE_PIERCE_DIED			= "m15_failure_pierce_died" 
  490. 	M15_FAILURE_PIERCE_DISMISSED	= "m15_failure_pierce_dismissed" 
  491. 	M15_FAILURE_TRUCK_DECKERS_HQ	= "m15_failure_truck_deckers_hq" 
  492. 	M15_FAILURE_TRUCK_ESCAPED		= M15_FAILURE_TRUCK_DECKERS_HQ 
  493. 	M15_FAILURE_TRUCK_DESTROYED	= "m15_failure_truck_destroyed" 
  494. 	M15_FAILURE_TRUCK_CRUSHED		= "m15_failure_truck_crushed" 
  495. 	 
  496. -- Threads -- 
  497. 	-- Elevator manager 
  498. 	M15_THREAD_ELEVATOR_MANAGER	= INVALID_THREAD_HANDLE 
  499. 	 
  500. 	-- Conversation threads 
  501. 	M15_THREAD_CONVO_TO_PR_CENTER = INVALID_THREAD_HANDLE 
  502. 	M15_THREAD_CONVO_PR_CENTER    = INVALID_THREAD_HANDLE 
  503. 	M15_THREAD_CONVO_IN_LOBBY     = INVALID_THREAD_HANDLE 
  504.  
  505. 	M15_THREAD_CONVO_IN_GARAGE    = INVALID_THREAD_HANDLE 
  506. 	M15_THREAD_CONVO_TRUCK_FOUND  = INVALID_THREAD_HANDLE 
  507. 	M15_THREAD_CONVO_DONT_USE_CANNON = INVALID_THREAD_HANDLE 
  508. 	 
  509. 	-- Chase scene threads 
  510. 	M15_THREAD_TIRE_CHECK			= INVALID_THREAD_HANDLE 
  511. 	M15_THREAD_CHASE_RUBBER_BAND	= INVALID_THREAD_HANDLE 
  512. 	 
  513. 	-- Emergency spawn thread 
  514. 	M15_THREAD_SPAWN_ROCKETS		= INVALID_THREAD_HANDLE 
  515. 	 
  516. -- Checkpoints -- 
  517. 	M15_checkpoint = { 
  518. 		start  = { 
  519. 			name = MISSION_START_CHECKPOINT,	-- defined in ug_lib.lua 
  520. 			music = "M15_music_mission_start", 
  521. 			music_chkpnt = "M15_music_start_checkpoint" 
  522. 		}, 
  523. 		 
  524. 		outside_pr_center = { 
  525. 			name = "m15_checkpoint_outside_pr_center", 
  526. 			music = "M15_music_PR_center_battle", 
  527. 			music_chkpnt = "M15_music_PR_Center_Checkpoint" 
  528. 		}, 
  529. 		 
  530. 		garage = { 
  531. 			name = "m15_checkpoint_garage", 
  532. 			music = "M15_music_PR_garage", 
  533. 			music_chkpnt = "M15_music_PR_Garage_Checkpoint" 
  534. 		}, 
  535. 		 
  536. 		chase = { 
  537. 			name = "m15_checkpoint_chase", 
  538. 			music = "M15_music_truck_chase", 
  539. 			music_chkpnt = "M15_music_truck_chase_checkpoint" 
  540. 		}, 
  541. 		 
  542. 		chase_kneecapper = { 
  543. 			name = "m15_checkpoint_chase_kneecapper", 
  544. 			music = "M15_music_truck_chase", 
  545. 			music_chkpnt = "M15_music_truck_chase_checkpoint" 
  546. 		}, 
  547. 	} 
  548.  
  549. -- Cutscenes -- 
  550. 	M15_CUTSCENE_MISSION_INTRO = "15_in" 
  551. 	M15_CUTSCENE_MISSION_OUTRO = "15_Out" 
  552.  
  553. -- Conversations -- 
  554. 	-- Table of audio conversations to play. Either a actual audio file can be specifed, or a message can be used in its place. 
  555. 	-- Expected Table Members: 
  556. 	--   name    - Name of the audio file to play 
  557. 	--   delay   - Amount of time (in seconds) to delay after a audio file has played 
  558. 	--   message - Supplementary message to display if no audio file is provided 
  559. 	--    
  560. 	M15_convo = { 
  561. 		-- Starts along with the mission 
  562. 		to_pr_center = { 
  563. 			{name = "", delay = 20.0,}, 
  564. 			{name = "m15_mission_start_01", delay = 20.0,}, 
  565. 			{name = "m15_drive_01", delay = 20.0,}, 
  566. 			{name = "m15_drive_02", delay = 2.0, call_received = true, }, 
  567. 			{name = "m15_drive_03", delay = 0.0,}, 
  568. 		}, 
  569. 		 
  570. 		pr_center_outside = { 
  571. 			{name = "m15_arrival", delay = 10.0,}, 
  572. 		}, 
  573. 		 
  574. 		-- Starts when the player enters the lobby 
  575. 		pr_center_lobby = { 
  576. 			{name = "", delay = 10.0,}, 
  577. 			{name = "m15_stag_tech", delay = 10.0,}, 
  578. 			{name = "M15_PA_Speakers_1", delay = 0.0, direct = true}, 
  579. 		}, 
  580. 		 
  581. 		go_to_garage = { 
  582. 			{name = "m15_get_to_garage", delay = 0.0,}, 
  583. 		}, 
  584. 		 
  585. 		-- Starts when the player enters the garage 
  586. 		pr_center_garage = { 
  587. 			{name = "m15_garage_enter", delay = 1.0,}, 
  588. 		}, 
  589. 		 
  590. 		-- Starts when the player gets within range of the truck 
  591. 		chase_found_truck_in_tank = { 
  592. 			{name = "M15_Truck_Chase", delay = 20.0,}, 
  593. 		}, 
  594. 		 
  595. 		chase_found_truck = { 
  596. 			{name = "", delay = 15.0,}, 
  597. 			{name = "M15_Decker_Roadblocks", delay = 3.0,}, 
  598. 			{name = "m15_matt_player_convo", delay = 3.0,}, 
  599. 		}, 
  600. 	} 
  601. 	 
  602. 	M15_personas = { 
  603. 		{name = "Kinzie", handle = INVALID_PERSONA_HANDLE}, 
  604. 		{name = "Matt", handle = INVALID_PERSONA_HANDLE}, 
  605. 	} 
  606. 	 
  607. -- Other -- 
  608. 	-- vehicle_pathfind_check_done() return values defines 
  609. 	M15_PATHFINDING_IN_PROGRESS = 0 
  610. 	M15_PATHFINDING_DONE        = 1 
  611. 	M15_PATHFINDING_FAILED      = 2 
  612. 	 
  613. 	STAG_NOTORIETY    = "police" 
  614. 	DECKERS_NOTORIETY = "deckers" 
  615. 	MORNINGSTAR_NOTORIETY = "morningstar" 
  616. 	 
  617. -- Variables 
  618. 	M15_extra_npcs_in_lobby = {} -- List of NPCs that entered the lobby and are now mission critical 
  619. 	 
  620. 	M15_mark_waves = false 
  621. 	M15_radius_shown = false 
  622. 	M15_in_pr_center = false 
  623. 	 
  624. 	M15_truck_hit_by_tank_shell = false 
  625. 	 
  626. 	M15_phone_call_active = false 
  627.  
  628. -- ************************* 
  629. -- 
  630. -- Standard functions 
  631. -- 
  632. -- ************************* 
  633.  
  634. -- This is the primary entry point for the mission, and is responsible for starting up the mission 
  635. -- at the specified checkpoint. 
  636. -- CALLED FROM CODE 
  637. -- 
  638. -- m15_checkpoint:  The checkpoint the mission should begin at 
  639. -- is_restart:      TRUE if the mission is restarting, FALSE otherwise 
  640. -- 
  641. function m15_start(m15_checkpoint, is_restart) 
  642. 	M15_in_coop = coop_is_active() 
  643.  
  644. 	-- Check if this mission starting from the beginning 
  645. 	if (m15_checkpoint == M15_checkpoint.start.name) then 
  646. 		if (is_restart == false) then 
  647. 			-- First time playing mission 
  648. 			local fade_in_after = false 
  649. 			cutscene_play(M15_CUTSCENE_MISSION_INTRO, nil, nil, fade_in_after) 
  650. 		end 
  651. 	end 
  652.  
  653. 	-- Handle mission initialization for the current checkpoint 
  654. 	m15_initialize(m15_checkpoint) 
  655.  
  656. 	-- Run the mission from the current checkpoint 
  657. 	m15_run(m15_checkpoint) 
  658. end 
  659.  
  660. -- This is the primary function responsible for running the entire mission from start to finish. 
  661. -- 
  662. -- first_checkpoint:	The first checkpoint to begin running the mission at 
  663. -- 
  664. function m15_run(first_checkpoint) 
  665. 	local current_checkpoint = first_checkpoint 
  666. 	-- determine if we need to play fresh audio cues or not 
  667. 	local from_checkpoint = true 
  668.  
  669. 	-- Run the mission from the beginning 
  670. 	if current_checkpoint == M15_checkpoint.start.name then 
  671. 		m15_setup_start() 
  672. 		M15_THREAD_CONVO_TO_PR_CENTER = thread_new("m15_convo_to_pr_center") 
  673. 		m15_goto_a_trigger(M15_triggers.pr_center_radius, M15_OBJ_GO_TO_PR_CENTER, true) 
  674. 		m15_cleanup_start() 
  675. 		 
  676. 		m15_cleanup_audio_threads() 
  677. 		M15_THREAD_CONVO_IN_LOBBY = thread_new("m15_convo_pr_center") 
  678.  
  679. 		from_checkpoint = false 
  680. 		current_checkpoint = M15_checkpoint.outside_pr_center.name 
  681. 		mission_set_checkpoint(current_checkpoint, true) 
  682. 	end 
  683.  
  684. 	if current_checkpoint == M15_checkpoint.outside_pr_center.name then 
  685. 		m15_setup_outside_pr_center() 
  686. 		m15_goto_a_trigger(M15_triggers.pr_center_front, M15_OBJ_GO_TO_PR_CENTER, true) 
  687. 		-- drop density to small to try to help framerate 
  688. 		set_ped_density(0.1) 
  689. 		set_traffic_density(0.1) 
  690. 		m15_cleanup_outside_pr_center() 
  691. 		 
  692. 		m15_soften_attackers(M15_kill_outside.arrive) 
  693.  
  694. 		m15_setup_inside_pr_center() 
  695. 		 
  696. 		if not from_checkpoint then 
  697. 			m15_music(M15_checkpoint.outside_pr_center.music_chkpnt) 
  698. 		end 
  699. 		 
  700. 		M15_in_pr_center = false 
  701. 		M15_waves.lobby_stag.thread	= thread_new("m15_run_wave", M15_waves.lobby_stag) 
  702. 		M15_waves.lobby_decker.thread	= thread_new("m15_run_wave", M15_waves.lobby_decker) 
  703. 		 
  704. 		m15_goto_a_trigger(M15_triggers.pr_center_enterance, M15_OBJ_GO_TO_PR_CENTER, true) 
  705. 		M15_in_pr_center = true 
  706. 		 
  707. 		m15_soften_attackers(M15_kill_outside.enter) 
  708. 		 
  709. 		--m15_start_continuous_spawns(M15_continuous_spawns.deckers) 
  710. 		--m15_start_continuous_spawns(M15_continuous_spawns.stag) 
  711. 	 
  712. 		audio_play_persona_line(NPC_PIERCE, "M15_Inside") 
  713. 		m15_cleanup_audio_threads() 
  714. 		M15_THREAD_CONVO_IN_LOBBY = thread_new("m15_convo_in_lobby") 
  715. 	 
  716. 		objective_text(0, M15_OBJ_CLEAR_THE_LOBBY, "", "", SYNC_ALL, OI_ASSET_KILL)	 
  717. 		M15_mark_waves = true 
  718. 		m15_mark_wave_npcs(M15_waves.lobby_stag) 
  719. 		m15_mark_wave_npcs(M15_waves.lobby_decker) 
  720. 		m15_mark_extra_npcs() 
  721.  
  722. 		delay(5.0) 
  723. 		 
  724. 		m15_soften_attackers(M15_kill_outside.the_rest) 
  725. 		 
  726. 		-- Wait until the waves have been completed 
  727. 		while M15_waves.lobby_stag.thread ~= INVALID_THREAD_HANDLE or M15_waves.lobby_decker.thread ~= INVALID_THREAD_HANDLE do 
  728. 			thread_yield() 
  729. 		end 
  730. 		 
  731. 		-- Wait until all the extra npcs are dead 
  732. 		while sizeof_table(M15_extra_npcs_in_lobby) > 0 do 
  733. 			thread_yield() 
  734. 		end 
  735. 		 
  736. 		-- Prevent any additional NPCs from being marked as mission critical 
  737. 		on_trigger("", M15_triggers.pr_center_inside) 
  738. 		trigger_enable(M15_triggers.pr_center_inside, false) 
  739.  
  740. 		m15_goto_a_trigger(M15_triggers.elevator_to_garage_2, M15_OBJ_GET_TO_THE_GARAGE, false) 
  741. 	 
  742. 		m15_cleanup_all_waves() 
  743. 	 
  744. 		m15_cleanup_inside_pr_center() 
  745. 	 
  746. 		m15_setup_garage() 
  747. 		objective_text_clear(0) 
  748. 		m15_teleport_team_to(M15_NAV_GARAGE) 
  749. 	 
  750. 		m15_music(M15_checkpoint.garage.music) 
  751. 		current_checkpoint = M15_checkpoint.garage.name 
  752. 		mission_set_checkpoint(current_checkpoint, true) 
  753. 	end 
  754. 	 
  755. 	if current_checkpoint == M15_checkpoint.garage.name then 
  756. 		m15_coop_free_pierce() 
  757. 		m15_cleanup_audio_threads() 
  758. 		M15_THREAD_CONVO_IN_GARAGE = thread_new("m15_convo_in_garage") 
  759.  
  760. 		m15_enter_vehicle(M15_groups.tank_garage.tank, M15_OBJ_GET_IN_THE_TANK) 
  761. 		 
  762. 		-- Spawn dudes outside (separate thread) and wait until you come out to attack 
  763. 		M15_trigger_reached = false 
  764. 		M15_THREAD_SPAWN_ROCKETS = thread_new("m15_setup_outside_garage") 
  765. 		 
  766. 		m15_goto_a_trigger(M15_triggers.garage_door, M15_OBJ_ESCAPE_THE_GARAGE, false) 
  767. 		 
  768. 		m15_outside_garage_battle() 
  769. 		 
  770. 		m15_cleanup_garage() 
  771. 		 
  772. 		-- Don't cleanup the outside the PR Center until the player is far enough away. 
  773. 		-- This is done inside m15_chase(). 
  774.  
  775. 		if m15_player_is_in_a_tank() then 
  776. 			current_checkpoint = M15_checkpoint.chase.name 
  777. 			m15_music(M15_checkpoint.chase.music) 
  778. 		else 
  779. 			current_checkpoint = M15_checkpoint.chase_kneecapper.name 
  780. 			m15_music(M15_checkpoint.chase_kneecapper.music) 
  781. 		end 
  782. 		mission_set_checkpoint(current_checkpoint, true) 
  783. 	end 
  784. 	 
  785. 	if current_checkpoint == M15_checkpoint.chase.name or current_checkpoint == M15_checkpoint.chase_kneecapper.name then 
  786. 		m15_setup_chase() 
  787. 		m15_coop_free_pierce() 
  788. 		 
  789. 		m15_chase() 
  790. 		 
  791. 		m15_cleanup_chase() 
  792. 	end 
  793.  
  794. 	m15_music("M15_music_truck_chase_End") 
  795. 	mission_end_success("m15", M15_CUTSCENE_MISSION_OUTRO, {M15_NAV_START[1], M15_NAV_START[2]}) 
  796. end 
  797.  
  798. -- This is the primary function responsible for cleaning up the entire mission 
  799. -- CALLED FROM CODE (+++MUST RETURN IMMEDIATLY+++) 
  800. -- 
  801. function m15_cleanup() 
  802. 	--[[ INSERT ANY MISSION SPECIFIC CLEAN-UP ]]-- 
  803. 	m15_cleanup_extra_npcs() 
  804. 	 
  805. 	-- The mission may have failed due to a remote player disconnecting. Double check to see if they are connected. 
  806. 	if M15_in_coop then 
  807. 		M15_in_coop = coop_is_active() 
  808. 	end 
  809. 	 
  810. 	-- restore ped density 
  811. 	set_ped_density(1.0) 
  812. 	set_traffic_density(1.0) 
  813.  
  814. 	m15_music("M15_music_STOP") 
  815.  
  816. 	objective_text_clear(0) 
  817. 	 
  818. 	on_death("", NPC_PIERCE) 
  819. 	on_dismiss("", NPC_PIERCE) 
  820. 	waypoint_remove() 
  821. 	 
  822. 	m15_unload_all_convos() 
  823. 	 
  824. 	if M15_THREAD_TIRE_CHECK ~= INVALID_THREAD_HANDLE then 
  825. 		thread_kill(M15_THREAD_TIRE_CHECK) 
  826. 	end 
  827. 	 
  828. 	if M15_THREAD_CHASE_RUBBER_BAND ~= INVALID_THREAD_HANDLE then 
  829. 		thread_kill(M15_THREAD_CHASE_RUBBER_BAND) 
  830. 	end 
  831. 	 
  832. 	if M15_THREAD_SPAWN_ROCKETS ~= INVALID_THREAD_HANDLE then 
  833. 		thread_kill(M15_THREAD_SPAWN_ROCKETS) 
  834. 	end 
  835. 	 
  836. 	m15_cleanup_start() 
  837. 	m15_cleanup_outside_pr_center() 
  838. 	m15_cleanup_inside_pr_center() 
  839. 	m15_cleanup_garage() 
  840. 	m15_cleanup_outside_garage() 
  841. 	m15_cleanup_chase() 
  842. 	 
  843. 	m15_stop_all_continuous_spawns() 
  844. 	m15_cleanup_all_waves() 
  845. 	m15_cleanup_audio_threads() 
  846. 	 
  847. 	if group_is_loaded(M15_groups.chase.name) then 
  848. 		on_vehicle_destroyed("", VEHICLE_SUPER_COMPUTER) 
  849. 		on_vehicle_enter_water("", VEHICLE_SUPER_COMPUTER) 
  850. 		on_take_damage("", VEHICLE_SUPER_COMPUTER) 
  851. 		group_destroy(M15_groups.chase.name) 
  852. 	end 
  853. 	 
  854. 	if group_is_loaded(M15_groups.homies.name) then 
  855. 		group_destroy(M15_groups.homies.name) 
  856. 	end 
  857. 	 
  858. 	if group_is_loaded(M15_groups.homies_2.name) then 
  859. 		group_destroy(M15_groups.homies_2.name) 
  860. 	end 
  861. 	 
  862. 	for key, trigger in pairs(M15_triggers) do 
  863. 		m15_cleanup_trigger(trigger) 
  864. 	end 
  865.  
  866. 	-- Fix any notoriety related changes 
  867. 	notoriety_force_no_spawn(STAG_NOTORIETY, false) 
  868. 	notoriety_force_no_spawn(DECKERS_NOTORIETY, false) 
  869. 	roadblocks_enable(true) 
  870. 	notoriety_set_min(STAG_NOTORIETY, 0) 
  871. 	notoriety_set_max(STAG_NOTORIETY, MAX_NOTORIETY_LEVEL) 
  872. 	notoriety_set_min(DECKERS_NOTORIETY, 0) 
  873. 	notoriety_set_max(DECKERS_NOTORIETY, MAX_NOTORIETY_LEVEL) 
  874. 	notoriety_set_min_and_max(MORNINGSTAR_NOTORIETY, 0, MAX_NOTORIETY_LEVEL) 
  875. 	notoriety_force_no_spawn(MORNINGSTAR_NOTORIETY, false) 
  876.  
  877. 	 
  878. 	--party_set_recruitable(false) 
  879. 	--party_allow_max_followers(false) 
  880. 	 
  881. 	if group_is_loaded(M15_groups.tank_outside.name) then 
  882. 		group_destroy(M15_groups.tank_outside.name) 
  883. 	end 
  884. 	 
  885. 	if group_is_loaded(M15_groups.cars_outside_garage.name) then 
  886. 		group_destroy(M15_groups.cars_outside_garage.name) 
  887. 	end 
  888. 	 
  889. 	if group_is_loaded(M15_groups.kneecapper_outside.name) then 
  890. 		group_destroy(M15_groups.kneecapper_outside.name) 
  891. 	end 
  892. 	 
  893. 	if group_is_loaded(M15_groups.tank_garage) then 
  894. 		group_destroy(M15_groups.tank_garage.name) 
  895. 	end 
  896. 	 
  897. 	 
  898. 	for key, persona in pairs(M15_personas) do 
  899. 		audio_persona_remove_2d(persona.handle) 
  900. 	end 
  901. end 
  902.  
  903. -- Called when the mission has ended with success 
  904. -- CALLED FROM CODE (+++MUST RETURN IMMEDIATLY+++) 
  905. -- 
  906. function m15_success() 
  907. 	--[[ INSERT ANY MISSION SPECIFIC SUCCESS STUFF ]]-- 
  908. 	 
  909. end 
  910.  
  911.  
  912. -- ************************* 
  913. -- 
  914. -- Local functions 
  915. -- 
  916. -- ************************* 
  917.  
  918. -- Initialize the mission for the specified checkpoint 
  919. -- 
  920. -- checkpoint:		Checkpoint to initialize the mission to 
  921. -- 
  922. function m15_initialize(checkpoint) 
  923. 	-- Make sure the screen is completly faded out 
  924. 	mission_start_fade_out(0.0) 
  925.  
  926. 	-- Set the mission author 
  927. 	set_mission_author("Craig Williams") 
  928.  
  929. 	-- Common initialization 
  930. 	m15_initialize_common() 
  931.  
  932. 	-- Checkpoint specific initialization 
  933. 	m15_initialize_checkpoint(checkpoint) 
  934.  
  935. 	-- Start fading in 
  936. 	mission_start_fade_in() 
  937. end 
  938.  
  939.  
  940. -- *************************************************** 
  941. -- m15_run Helper Functions 
  942. -- *************************************************** 
  943.  
  944. -- Teleports the team to the specified nav points. 
  945. -- 
  946. -- nav_table      - Nav points to teleport the group to 
  947. -- ignore_vehicle - True to remove the player from any vehicle 
  948. function m15_teleport_team_to(nav_table, ignore_vehicle) 
  949. 	if ignore_vehicle == nil then 
  950. 		ignore_vehicle = true 
  951. 	end 
  952.  
  953. 	fade_out(0.5) 
  954. 	fade_out_block() 
  955. 	teleport_coop(nav_table[1], nav_table[2], ignore_vehicle) 
  956. 	fade_in(0.5) 
  957. 	fade_in_block() 
  958. 	 
  959. 	if ignore_vehicle then 
  960. 		teleport(NPC_PIERCE, nav_table[3], ignore_vehicle) 
  961. 	else 
  962. 		if character_is_in_vehicle(LOCAL_PLAYER) then 
  963. 			local vehicle_name = get_char_vehicle_name(LOCAL_PLAYER) 
  964. 			if not character_is_in_vehicle(NPC_PIERCE, vehicle_name) then 
  965. 				-- Pierce is in a different vehicle. Since teleporting him will remove him from his vehicle, just 
  966. 				-- put him in the players vehicle. 
  967. 				vehicle_exit_teleport(NPC_PIERCE) 
  968. 				vehicle_enter_teleport(NPC_PIERCE, vehicle_name, 1, true) 
  969. 			end 
  970. 		else 
  971. 			teleport(NPC_PIERCE, nav_table[3], ignore_vehicle) 
  972. 		end 
  973. 	end 
  974. 	thread_yield() 
  975. end 
  976.  
  977. function m15_enter_vehicle(vehicle, obj_text) 
  978. 	if vehicle_is_destroyed(vehicle) then 
  979. 		return 
  980. 	end 
  981.  
  982. 	objective_text(0, obj_text, "", "", SYNC_ALL, OI_ASSET_USE) 
  983. 	marker_add(vehicle, MINIMAP_ICON_USE, OI_ASSET_USE, OI_FLAGS_DEFAULT, SYNC_ALL) 
  984. 	 
  985. 	while not vehicle_is_destroyed(vehicle) do 
  986. 		if character_is_in_vehicle(LOCAL_PLAYER, vehicle) then 
  987. 			break 
  988. 		end 
  989. 		 
  990. 		if M15_in_coop and character_is_in_vehicle(REMOTE_PLAYER, vehicle) then 
  991. 			break 
  992. 		end 
  993. 		 
  994. 		thread_yield() 
  995. 	end 
  996. 	 
  997. 	marker_remove(vehicle) 
  998. end 
  999.  
  1000. -- General task. Instructs the player to go to the specific trigger. 
  1001. -- 
  1002. -- trigger  - Name of the trigger to activate and go to. 
  1003. -- obj_text - Objective text to display 
  1004. -- gps      - Should a gps waypoint be added? 
  1005. function m15_goto_a_trigger(trigger, obj_text, gps) 
  1006. 	if gps == nil then 
  1007. 		gps = false 
  1008. 	end 
  1009. 	 
  1010. 	m15_goto_a_trigger_setup(trigger, obj_text, gps) 
  1011.  
  1012. 	while not M15_trigger_reached do 
  1013. 		thread_yield() 
  1014. 	end 
  1015. 	 
  1016. 	m15_goto_a_trigger_cleanup(trigger, gps) 
  1017. 	 
  1018. 	-- To be on the safe side, give pathfinding a similar a full frame to remove the nav points and such 
  1019. 	thread_yield() 
  1020. end 
  1021.  
  1022. function m15_goto_a_trigger_setup(trigger, obj_text, gps) 
  1023. 	if type(trigger) == "table" then 
  1024. 		for key, element in pairs(trigger) do 
  1025. 			m15_goto_a_trigger_setup(element, obj_text, gps) 
  1026. 		end 
  1027. 		return 
  1028. 	end 
  1029.  
  1030. 	if obj_text ~= nil and obj_text ~= "" then 
  1031. 		objective_text(0, obj_text, "", "", SYNC_ALL, OI_ASSET_LOCATION) 
  1032. 	end 
  1033. 	 
  1034. 	marker_add_trigger(trigger, MINIMAP_ICON_LOCATION, INGAME_EFFECT_CHECKPOINT, OI_ASSET_LOCATION, OI_FLAGS_LOCATION, SYNC_ALL) 
  1035. 	if gps then 
  1036. 		waypoint_add(trigger) 
  1037. 	end 
  1038. 	M15_trigger_reached = false 
  1039. 	m15_setup_trigger(trigger, "m15_trigger_cback") 
  1040. end 
  1041.  
  1042. function m15_goto_a_trigger_cleanup(trigger, gps) 
  1043. 	if type(trigger) == "table" then 
  1044. 		for key, element in pairs(trigger) do 
  1045. 			m15_goto_a_trigger_cleanup(element, gps) 
  1046. 		end 
  1047. 		return 
  1048. 	end 
  1049. 	 
  1050. 	-- Cleanup the task. 
  1051. 	m15_cleanup_trigger(trigger) 
  1052. 	marker_remove_trigger(trigger) 
  1053. 	if gps then 
  1054. 		waypoint_remove() 
  1055. 	end 
  1056. end 
  1057.  
  1058. function m15_start_continuous_spawns(spawns) 
  1059. 	for key, region in pairs(spawns.regions) do 
  1060. 		spawn_region_toggle_filter(region, spawns.filter) 
  1061. 		spawn_region_enable(region, true) 
  1062. 	end 
  1063.  
  1064. 	for key, group in pairs(spawns.groups) do 
  1065. 		continuous_spawn_start(group, 0, spawns.respawn_delay, "", spawns.filter) 
  1066. 	end 
  1067.  
  1068. 	spawns.loaded = true 
  1069. end 
  1070.  
  1071. function m15_stop_continuous_spawns(spawns) 
  1072. 	if spawns.loaded ~= true then 
  1073. 		return 
  1074. 	end 
  1075.  
  1076. 	for key, group in pairs(spawns.groups) do 
  1077. 		local destroy = true 
  1078. 		continuous_spawn_stop(group, destroy) 
  1079. 	end 
  1080. 	continuous_spawn_regions_enable(spawns.regions, false) 
  1081.  
  1082. 	spawns.loaded = nil 
  1083. end 
  1084.  
  1085. function m15_stop_all_continuous_spawns() 
  1086. 	for key, spawns in pairs(M15_continuous_spawns) do 
  1087. 		m15_stop_continuous_spawns(spawns) 
  1088. 	end 
  1089. end 
  1090.  
  1091. -- *************************************************** 
  1092. -- m15_initialize Helper Functions 
  1093. -- *************************************************** 
  1094.  
  1095. -- Handle any common initialization 
  1096. -- 
  1097. function m15_initialize_common() 
  1098. 	--[[ INSERT ANY COMMON INITIALIZATION CODE HERE ]]-- 
  1099. 		 
  1100. 	set_ped_density(M15_PED_DENSITY) 
  1101. 	set_traffic_density(M15_VEHICLE_DENSITY) 
  1102.  
  1103. 	for key, persona in pairs(M15_personas) do 
  1104. 		persona.handle = audio_persona_load_2d(persona.name) 
  1105. 	end 
  1106. 	 
  1107. 	-- This is a Deckers mission in Morningstar territory.  Always have a 1 star Deckers notoriety and 0 Morningstar 
  1108. 	notoriety_set_min(DECKERS_NOTORIETY, 1) 
  1109. 	notoriety_set_min_and_max(MORNINGSTAR_NOTORIETY, 0, 0) 
  1110. 	notoriety_force_no_spawn(MORNINGSTAR_NOTORIETY, true)	 
  1111. end 
  1112.  
  1113. -- Moves the player to an area that should be by Pierce, spawns Pierce, and then moves 
  1114. -- Pierce to the correct location. 
  1115. -- 
  1116. -- pierce_group:	Group that pierce belongs to Assumes that pierce_group.members[1] == Pierce 
  1117. -- nav_table:		List of nav points. Same format as m15_teleport_team_to() 
  1118. function m15_setup_pierce_and_move_to(pierce_group, nav_table) 
  1119. 	teleport_coop(nav_table[1], nav_table[2], true) 
  1120. 	 
  1121. 	group_create(pierce_group.name, true) 
  1122. 	NPC_PIERCE = pierce_group.members[1] 
  1123.  
  1124. 	teleport(NPC_PIERCE, nav_table[3], true) 
  1125.  
  1126. 	party_add(NPC_PIERCE, LOCAL_PLAYER) 
  1127. 	follower_set_can_abandon(NPC_PIERCE, true) 
  1128. 	 
  1129. 	on_death("m15_on_death", NPC_PIERCE) 
  1130. 	on_dismiss("m15_party_member_dismissed", NPC_PIERCE) 
  1131.  
  1132. end 
  1133.  
  1134. -- Checkpoint specific initialization 
  1135. -- 
  1136. -- checkpoint:		The checkpoint to be initialized 
  1137. function m15_initialize_checkpoint(checkpoint) 
  1138. 	if checkpoint == M15_checkpoint.start.name then 
  1139. 		group_create(M15_groups.start_vehicle.name, true) 
  1140. 		group_create(M15_groups.extra_homies.name, true) 
  1141. 		m15_setup_pierce_and_move_to(M15_groups.homies, M15_NAV_START) 
  1142. 		release_to_world(M15_groups.extra_homies.name) 
  1143. 		group_destroy(M15_groups.extra_homies.name) 
  1144. 		 
  1145. 		-- Intro animations 
  1146. 		-- Player(s) look cool GO! 
  1147. 		local anim_name = "M10 Player Mission Start" 
  1148. 		local morph_name = "M10 Player Mission Start" 
  1149. 		local force_play = false 
  1150. 		local stand_still = false 
  1151. 		local zero_movement = false 
  1152. 		action_play_non_blocking(LOCAL_PLAYER, anim_name, morph_name, force_play, stand_still, zero_movement) 
  1153. 		player_script_controlled_clear(LOCAL_PLAYER)	-- let player escape this animation 
  1154. 		if (coop_is_active()) then 
  1155. 			action_play_non_blocking(REMOTE_PLAYER, anim_name, morph_name, force_play, stand_still, zero_movement) 
  1156. 			player_script_controlled_clear(REMOTE_PLAYER)	-- let player escape this animation 
  1157. 		end 
  1158.  
  1159. 	elseif checkpoint == M15_checkpoint.outside_pr_center.name then 
  1160. 		group_create(M15_groups.start_vehicle_2.name, true) 
  1161. 		m15_setup_pierce_and_move_to(M15_groups.homies_2, M15_NAV_OUTSIDE) 
  1162. 		m15_music(M15_checkpoint.outside_pr_center.music_chkpnt) 
  1163.  
  1164. 	elseif checkpoint == M15_checkpoint.garage.name then 
  1165. 		m15_setup_garage() 
  1166. 		 
  1167. 		-- give a moment for the dead stag to hit the floor. 
  1168. 		delay(2.0) 
  1169. 		 
  1170. 		m15_setup_pierce_and_move_to(M15_groups.homies_2, M15_NAV_GARAGE) 
  1171. 		m15_music(M15_checkpoint.garage.music_chkpnt) 
  1172. 	 
  1173. 	elseif checkpoint == M15_checkpoint.chase.name or checkpoint == M15_checkpoint.chase_kneecapper.name then 
  1174. 		if checkpoint == M15_checkpoint.chase.name then 
  1175. 			group_create(M15_groups.cars_outside_garage.name, true) 
  1176. 			group_create(M15_groups.tank_outside.name, true) 
  1177. 			m15_setup_pierce_and_move_to(M15_groups.homies_2, M15_NAV_GARAGE_OUTSIDE) 
  1178. 			vehicle_enter_teleport(LOCAL_PLAYER, "vehicle_tank_outside", 0, true) 
  1179. 			vehicle_enter_teleport(NPC_PIERCE, "vehicle_tank_outside", 1, true) 
  1180. 			m15_music(M15_checkpoint.chase.music_chkpnt) 
  1181. 		else 
  1182. 			group_create(M15_groups.kneecapper_outside.name, true) 
  1183. 			for key, vehicle in pairs(M15_groups.kneecapper_outside.vehicles) do 
  1184. 				vehicle_set_kneecappers(vehicle, true) 
  1185. 			end 
  1186. 			m15_setup_pierce_and_move_to(M15_groups.homies_2, M15_NAV_GARAGE_OUTSIDE) 
  1187. 			m15_music(M15_checkpoint.chase_kneecapper.music_chkpnt) 
  1188. 		end 
  1189. 	 
  1190. 		notoriety_force_no_spawn(STAG_NOTORIETY, true) 
  1191. 		--notoriety_force_no_spawn(DECKERS_NOTORIETY, true) 
  1192. 		roadblocks_enable(M15_ROADBLOCKS_ENABLED) 
  1193. 		 
  1194. 		-- Point the player in the direction of the truck 
  1195. 		marker_add(M15_SUPER_COMPUTER_START, MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION, OI_FLAGS_LOCATION, SYNC_ALL) 
  1196. 		waypoint_add(M15_SUPER_COMPUTER_START) 
  1197. 		objective_text(0, M15_OBJ_CATCH_THE_TRUCK, "", "", SYNC_ALL, OI_ASSET_LOCATION) 
  1198. 	end 
  1199. end 
  1200.  
  1201.  
  1202. -- Checkpoint specific setup/cleanup code 
  1203. -- 
  1204.  
  1205. function m15_setup_start() 
  1206. end 
  1207.  
  1208. function m15_cleanup_start() 
  1209. end 
  1210.  
  1211. function m15_setup_pr_center_npc(np) 
  1212. 	 
  1213. end 
  1214.  
  1215. function m15_setup_outside_pr_center() 
  1216. 	group_create(M15_groups.outside_stag.name, true) 
  1217. 	group_create(M15_groups.outside_deckers.name, true) 
  1218. 	group_create(M15_groups.outside_vehicles.name, true) 
  1219. 	 
  1220. 	group_foreach_npc(M15_groups.outside_stag, m15_setup_pr_center_npc) 
  1221. 	 
  1222. 	m15_disable_notoriety() 
  1223. 	on_trigger("m15_disable_notoriety", M15_triggers.pr_center_radius) 
  1224. 	on_trigger_exit("m15_enable_notoriety", M15_triggers.pr_center_radius) 
  1225. 	trigger_enable(M15_triggers.pr_center_radius, true) 
  1226. 	 
  1227. 	m15_set_notoriety_range() 
  1228. 	 
  1229. 	on_trigger("m15_make_npc_mission_critical", M15_triggers.pr_center_inside) 
  1230. 	trigger_enable(M15_triggers.pr_center_inside, true) 
  1231. end 
  1232.  
  1233. function m15_cleanup_outside_pr_center() 
  1234. 	-- Don't cleanup the outside groups yet since the player still see the battle from the lobby 
  1235. end 
  1236.  
  1237. function m15_setup_inside_pr_center() 
  1238. 	-- close these doors.  hide the people. get performance. profit! 
  1239. 	for key, mover in pairs(M15_pr_front_doors) do 
  1240. 		if door_is_open(mover) then 
  1241. 			door_close(mover) 
  1242. 		end 
  1243. 	end 
  1244.  
  1245. 	M15_THREAD_ELEVATOR_MANAGER = thread_new("m15_thread_elevator_manager") 
  1246. end 
  1247.  
  1248. function m15_cleanup_inside_pr_center() 
  1249. 	-- Groups from m15_initialize_checkpoint(M15_checkpoint.start.name) 
  1250. 	if group_is_loaded(M15_groups.start_vehicle) then 
  1251. 		group_destroy(M15_groups.start_vehicle) 
  1252. 	end 
  1253.  
  1254. 	-- Groups from m15_initialize_checkpoint(M15_checkpoint.outside_pr_center.name) 
  1255. 	if group_is_loaded(M15_groups.start_vehicle_2) then 
  1256. 		group_destroy(M15_groups.start_vehicle_2) 
  1257. 	end 
  1258.  
  1259. 	-- Groups from m15_setup_outside_pr_center() 
  1260. 	if group_is_loaded(M15_groups.outside_stag.name) then 
  1261. 		group_destroy(M15_groups.outside_stag.name) 
  1262. 	end 
  1263. 	 
  1264. 	if group_is_loaded(M15_groups.outside_deckers.name) then 
  1265. 		group_destroy(M15_groups.outside_deckers.name) 
  1266. 	end 
  1267. 	 
  1268. 	if group_is_loaded(M15_groups.outside_vehicles.name) then 
  1269. 		group_destroy(M15_groups.outside_vehicles.name) 
  1270. 	end 
  1271. 	 
  1272. 	m15_stop_continuous_spawns(M15_continuous_spawns.deckers) 
  1273. 	m15_stop_continuous_spawns(M15_continuous_spawns.stag) 
  1274. 	 
  1275. 	m15_enable_notoriety() 
  1276. 	trigger_enable(M15_triggers.pr_center_radius, false) 
  1277. 	on_trigger("", M15_triggers.pr_center_radius) 
  1278. 	on_trigger_exit("", M15_triggers.pr_center_radius) 
  1279. 	 
  1280. 	if M15_THREAD_ELEVATOR_MANAGER ~= INVALID_THREAD_HANDLE then 
  1281. 		thread_kill(M15_THREAD_ELEVATOR_MANAGER) 
  1282. 		M15_THREAD_ELEVATOR_MANAGER = INVALID_THREAD_HANDLE 
  1283. 	end 
  1284. 	 
  1285. 	on_trigger("", M15_triggers.pr_center_inside) 
  1286. 	trigger_enable(M15_triggers.pr_center_inside, false) 
  1287. end 
  1288.  
  1289. function m15_setup_garage() 
  1290. 	m15_set_notoriety_range() 
  1291.  
  1292. 	group_create(M15_groups.dead_stag.name, true) 
  1293. 	for key, npc in pairs(M15_groups.dead_stag.members) do 
  1294. 		character_kill(npc, true) 
  1295. 	end 
  1296. 	 
  1297. 	group_create(M15_groups.cars_outside_garage.name, true) 
  1298. 	group_create(M15_groups.garage.name, true) 
  1299. 	group_create(M15_groups.tank_garage.name, true) 
  1300.  
  1301. 	 
  1302. 	notoriety_force_no_spawn(STAG_NOTORIETY, true) 
  1303. 	--notoriety_force_no_spawn(DECKERS_NOTORIETY, true) 
  1304. 	roadblocks_enable(M15_ROADBLOCKS_ENABLED) 
  1305. end 
  1306.  
  1307. function m15_cleanup_garage() 
  1308. 	-- Don't cleanup M15_groups.kneecapper.name since the player will drive this vehicle till the end of 
  1309. 	-- the mission. Destroyed in m15_cleanup(). 
  1310. 	if group_is_loaded(M15_groups.garage.name) then 
  1311. 		release_to_world(M15_groups.garage.name) 
  1312. 		group_destroy(M15_groups.garage.name) 
  1313. 	end 
  1314. end 
  1315.  
  1316. function m15_outside_garage_setup_stag_member(npc) 
  1317. 	on_death("m15_release_npc_to_world", npc) 
  1318. end 
  1319.  
  1320. function m15_setup_outside_garage() 
  1321.  
  1322. 	-- create the group and assign the "on death" callback. 
  1323. 	group_create(M15_outside_garage.stag.name, true) 
  1324. 	group_foreach_npc(M15_outside_garage.stag.name, m15_outside_garage_setup_stag_member) 
  1325. 	 
  1326. 	group_create(M15_outside_garage.saints.name, true) 
  1327.  
  1328. 	-- Prevent anything bad from happening to the NPCs while they wait around 
  1329. 	for key, vehicle_group in pairs(M15_outside_garage.saints.members) do 
  1330. 		for npc_key, npc in pairs(vehicle_group.npcs) do 
  1331. 			set_ignore_ai_flag(npc, true) 
  1332. 			set_dont_attack_me_on_sight_flag(npc, true) 
  1333. 			character_prevent_explosion_fling(npc, true) 
  1334. 			character_prevent_flinching(npc, true) 
  1335. 		end 
  1336. 	end 
  1337. 	 
  1338. 	-- wait until the trigger is hit 
  1339. 	while not M15_trigger_reached do 
  1340. 		thread_yield() 
  1341. 	end 
  1342. 	 
  1343. 	delay(1.0) 
  1344. 	 
  1345. 	-- Have the STAG members move to attack the player 
  1346. 	group_foreach_npc(M15_outside_garage.stag, m15_leash_stag_outside_garage) 
  1347. 	 
  1348. 	-- Have some Saints plow through the group of STAG 
  1349. 	for key, vehicle in pairs(M15_outside_garage.saints.members) do 
  1350. 		vehicle.thread = thread_new("m15_saints_kneecapper_thread", vehicle) 
  1351. 	end 
  1352. 	 
  1353. end 
  1354.  
  1355. function m15_npc_clear_death_callback(npc) 
  1356. 	on_death("", npc) 
  1357. end 
  1358.  
  1359. function m15_cleanup_outside_garage()	 
  1360. 	if group_is_loaded(M15_groups.dead_stag.name) then 
  1361. 		group_destroy(M15_groups.dead_stag.name) 
  1362. 	end 
  1363.  
  1364. 	if group_is_loaded(M15_outside_garage.stag.name) then 
  1365. 		group_destroy(M15_outside_garage.stag.name) 
  1366.  
  1367. 		-- clear all the death callbacks. 
  1368. 		group_foreach_npc(M15_outside_garage.stag, m15_npc_clear_death_callback) 
  1369. 	end 
  1370.  
  1371. 	if group_is_loaded(M15_outside_garage.saints.name) then 
  1372. 		for key, vehicle in pairs(M15_outside_garage.saints.members) do 
  1373. 			if vehicle.thread ~= INVALID_THREAD_HANDLE then 
  1374. 				thread_kill(vehicle.thread) 
  1375. 				vehicle.thread = INVALID_THREAD_HANDLE 
  1376. 			end 
  1377. 		end 
  1378.  
  1379. 		group_destroy(M15_outside_garage.saints.name) 
  1380. 	end 
  1381. end 
  1382.  
  1383. function m15_setup_chase() 
  1384. 	m15_setup_all_chase_triggers() 
  1385. 	set_ped_density(0.3) 
  1386. 	set_traffic_density(0.8) 
  1387. end 
  1388.  
  1389. function m15_cleanup_chase() 
  1390. 	m15_cleanup_all_chase_triggers() 
  1391. 	 
  1392. 	if group_is_loaded(M15_groups.deckers_base) then 
  1393. 		group_destroy(M15_groups.deckers_base) 
  1394. 	end 
  1395. end 
  1396.  
  1397. -- In coop, Pierce doesn't need to stay with the player for the last part of the mission 
  1398. function m15_coop_free_pierce() 
  1399. 	if coop_is_active() then 
  1400. 		-- remove callbacks 
  1401. 		on_death("", NPC_PIERCE) 
  1402. 		on_dismiss("", NPC_PIERCE) 
  1403. 		 
  1404. 		-- make invulnerable 
  1405. 		turn_invulnerable(NPC_PIERCE) 
  1406. 		 
  1407. 		-- dismiss from party 
  1408. 		party_dismiss(NPC_PIERCE) 
  1409. 	end 
  1410. end 
  1411.  
  1412.  
  1413.  
  1414. -- *************************************************** 
  1415. -- Miscellaneous m15 Helper Functions 
  1416. -- *************************************************** 
  1417.  
  1418. -- play music on the local player 
  1419. function m15_music(disco) 
  1420. 	audio_object_post_event(disco, nil, nil, LOCAL_PLAYER) 
  1421. end 
  1422.  
  1423. -- Go through the list and make people really weak 
  1424. -- 
  1425. -- kill_table:		(table) information on people and vehicle to weaken 
  1426. -- 
  1427. function m15_soften_attackers(kill_table) 
  1428. 	-- check the people first to see if anyone is left 
  1429. 	local people_alive = false 
  1430. 	for i,person in pairs(kill_table.people) do 
  1431. 		if not character_is_dead(person) then 
  1432. 			set_current_hit_points(person, M15_soften_hit_points) 
  1433. 			people_alive = true 
  1434. 		end 
  1435. 	end 
  1436. 			 
  1437. 	if people_alive then 
  1438. 		set_current_hit_points(kill_table.vehicle, M15_soften_hit_points) 
  1439. 		vehicle_set_smoke_and_fire_state(kill_table.vehicle, true, true) 
  1440. 		delay(3.0) 
  1441. 		vehicle_detonate(kill_table.vehicle) 
  1442. 	end 
  1443. end 
  1444.  
  1445. -- Enables the specified trigger 
  1446. -- 
  1447. -- trigger   - Name of the trigger to enable 
  1448. -- call_back - call back function to call when the trigger is triggered. 
  1449. function m15_setup_trigger(trigger, call_back) 
  1450. 	trigger_enable(trigger, true) 
  1451. 	on_trigger(call_back, trigger) 
  1452. end 
  1453.  
  1454. -- Disables the specified trigger 
  1455. -- 
  1456. -- trigger - Name of the trigger to disable 
  1457. function m15_cleanup_trigger(trigger) 
  1458. 	on_trigger("", trigger) 
  1459. 	trigger_enable(trigger, false) 
  1460. end 
  1461.  
  1462. -- Starts loading an audio conversation 
  1463. -- 
  1464. -- convo: Conversation to load 
  1465. function m15_preload_convo(convo) 
  1466. 	if convo.name == nil or convo.name == "" then 
  1467. 		return 
  1468. 	end 
  1469. 	 
  1470. 	if convo.call_received == true or convo.call_sent == true then 
  1471. 		-- phone convos get autoloaded 
  1472. 		return 
  1473. 	end 
  1474. 	 
  1475. 	if convo.handle == nil then 
  1476. 		if convo.direct == true then 
  1477. 			convo.handle = audio_conversation_load_direct(convo.name) 
  1478. 		else 
  1479. 			convo.handle = audio_conversation_load(convo.name) 
  1480. 		end 
  1481. 	end 
  1482. end 
  1483.  
  1484. -- Plays a conversation loaded with m15_preload_convo() 
  1485. -- 
  1486. -- convo: Conversation to play 
  1487. function m15_play_convo(convo) 
  1488. 	if convo.name ~= nil and convo.name ~= "" then 
  1489. 		if convo.call_received == true or convo.call_sent == true then 
  1490. 			local auto_answer = true 
  1491. 			local receiving_call = false 
  1492. 			if convo.call_received == true then 
  1493. 				receiving_call = true 
  1494. 			end 
  1495. 			 
  1496. 			-- phone call 
  1497. 			M15_phone_call_active = true 
  1498. 			 
  1499. 			audio_play_for_mission_cellphone(convo.name, receiving_call, auto_answer, "", "m15_call_ended_cb") 
  1500. 			 
  1501. 			while M15_phone_call_active == true do 
  1502. 				thread_yield() 
  1503. 			end 
  1504. 		 
  1505. 		else 
  1506. 			if convo.handle == nil then 
  1507. 				convo.handle = audio_conversation_load(convo.name) 
  1508. 			end 
  1509.  
  1510. 			--message("Playing Convo: " .. convo.name, 2.0) 
  1511. 			audio_conversation_play(convo.handle) 
  1512. 			audio_conversation_wait_for_end(convo.handle) 
  1513. 			convo.handle = nil 
  1514. 		end 
  1515. 	end 
  1516. 	 
  1517. 	if convo.delay ~= nil and convo.delay > 0.01 then 
  1518. 		delay(convo.delay) 
  1519. 	end 
  1520. end 
  1521.  
  1522. -- Unloads a conversation loaded with m15_preload_convo() 
  1523. -- 
  1524. -- convo: Conversation to unload 
  1525. function m15_unload_convo(convo) 
  1526. 	if convo.handle == nil then 
  1527. 		if convo.call_received == true or convo.call_sent == true then 
  1528. 			audio_remove_mission_cellphone(convo.name) 
  1529. 		end 
  1530. 		return 
  1531. 	end 
  1532. 	 
  1533. 	audio_conversation_end(convo.handle) 
  1534. 	convo.handle = nil 
  1535. end 
  1536.  
  1537. -- Unloads all conversations from the convo table 
  1538. -- 
  1539. function m15_unload_all_convos() 
  1540. 	for convo in pairs(M15_convo) do 
  1541. 		if #M15_convo[convo] ~= 0 then 
  1542. 			for i = 1, #M15_convo[convo] do 
  1543. 				m15_unload_convo(M15_convo[convo][i]) 
  1544. 			end 
  1545. 		else 
  1546. 			m15_unload_convo(M15_convo[convo]) 
  1547. 		end 
  1548. 	end 
  1549. end 
  1550.  
  1551. -- Iterates through a table of conversations and plays them. 
  1552. -- 
  1553. -- convo: Table (array) of conversations 
  1554. -- start_delay: time to delay the conversation.  Minimum/default is 2.0 sec. 
  1555. -- 
  1556. function m15_play_audio_set(convo, start_delay) 
  1557. 	if #convo <= 0 then 
  1558. 		-- Empty table array. Each element should not be named. 
  1559. 		return 
  1560. 	end 
  1561. 	 
  1562. 	if (start_delay == nil or start_delay < 2.0) then 
  1563. 		start_delay = 2.0 
  1564. 	end 
  1565. 	 
  1566. 	-- Load the intial conversation 
  1567. 	m15_preload_convo(convo[1]) 
  1568. 	-- General delay to give the intial audio clip some time to load 
  1569. 	delay(start_delay) 
  1570. 	 
  1571. 	-- Play all the intermediate conversations 
  1572. 	if #convo > 1 then 
  1573. 		for i = 1, #convo - 1 do 
  1574. 			-- Preload the next conversation 
  1575. 			m15_preload_convo(convo[i + 1]) 
  1576. 			-- Play and unload the current conversation 
  1577. 			m15_play_convo(convo[i]) 
  1578. 		end 
  1579. 	end 
  1580.  
  1581. 	-- Play the final conversation 
  1582. 	m15_play_convo(convo[#convo]) 
  1583. end 
  1584.  
  1585. -- Unloads a convo table (array) 
  1586. -- 
  1587. -- convo: Table of conversations to unload 
  1588. -- 
  1589. function m15_unload_convo_set(convo) 
  1590. 	for i = 1, #convo do 
  1591. 		m15_unload_convo(convo[i]) 
  1592. 	end 
  1593. end 
  1594.  
  1595. -- Checks to see if a player is close to the chase start point 
  1596. -- 
  1597. function m15_player_is_close_to_chase_start() 
  1598. 	if get_dist(LOCAL_PLAYER, M15_SUPER_COMPUTER_START) <= 100.0 then 
  1599. 		return true 
  1600. 	end 
  1601. 	 
  1602. 	if M15_in_coop then 
  1603. 		if get_dist(REMOTE_PLAYER, M15_SUPER_COMPUTER_START) <= 100.0 then 
  1604. 			return true 
  1605. 		end 
  1606. 	end 
  1607. 	 
  1608. 	return false 
  1609. end 
  1610.  
  1611. function m15_player_in_fast_vehicle() 
  1612. 	if not character_is_in_vehicle(LOCAL_PLAYER) then 
  1613. 		return false 
  1614. 	end 
  1615. 	 
  1616. 	 local vehicle = get_char_vehicle_name(LOCAL_PLAYER) 
  1617. 	  
  1618. 	 -- Assume all non-scripted vehicles are fast 
  1619. 	 if vehicle == "" or vehicle == LOCAL_PLAYER then 
  1620. 		return true 
  1621. 	 end 
  1622. 	 
  1623. 	-- Assume anything is faster then a tank 
  1624. 	if vehicle_is_tank(vehicle) then 
  1625. 		return false 
  1626. 	end 
  1627. 	 
  1628. 	return true 
  1629. end 
  1630.  
  1631. function m15_set_notoriety_range() 
  1632. 	notoriety_set_min(STAG_NOTORIETY, M15_MIN_NOTORIETY) 
  1633. 	notoriety_set_max(STAG_NOTORIETY, M15_MAX_NOTORIETY) 
  1634. 	notoriety_set_min(DECKERS_NOTORIETY, M15_MIN_NOTORIETY) 
  1635. 	notoriety_set_max(DECKERS_NOTORIETY, M15_MAX_NOTORIETY) 
  1636. end 
  1637.  
  1638. function m15_leash_stag_outside_garage(npc) 
  1639. 	local leash_nav = get_closest_object(npc, M15_outside_garage.stag_leashes) 
  1640. 	npc_leash_to_nav(npc, leash_nav, 3.0) 
  1641. 	ai_add_enemy_target(npc, LOCAL_PLAYER, ATTACK_NOW) 
  1642. end 
  1643.  
  1644. function m15_outside_garage_battle() 
  1645. 	-- These triggers are right on top of each other.  Just consider this hit with a minimal delay 
  1646. 	delay(1.0) 
  1647. 	--M15_trigger_reached = false 
  1648. 	--on_trigger("m15_trigger_outside_battle", M15_triggers.stag_rockets) 
  1649. 	--trigger_enable(M15_triggers.stag_rockets, true) 
  1650. 	 
  1651. 	-- Point the player in the direction of the truck 
  1652. 	marker_add(M15_SUPER_COMPUTER_START, MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION, OI_FLAGS_LOCATION, SYNC_ALL) 
  1653. 	objective_text(0, M15_OBJ_CATCH_THE_TRUCK, "", "", SYNC_ALL, OI_ASSET_LOCATION) 
  1654. 	 
  1655. 	--while not M15_trigger_reached do 
  1656. 	--	thread_yield() 
  1657. 	--end 
  1658. 	 
  1659. 	-- Establish GPS to truck (we wait till you're far enough out of the garage for it to WORK) 
  1660. 	waypoint_add(M15_SUPER_COMPUTER_START) 
  1661. 	 
  1662. end 
  1663.  
  1664. function m15_prep_kneecapper() 
  1665. 	m15_prep_kneecapper_vehicle(LOCAL_PLAYER) 
  1666. 	 
  1667. 	if M15_in_coop then 
  1668. 		m15_prep_kneecapper_vehicle(REMOTE_PLAYER) 
  1669. 	end 
  1670. end 
  1671.  
  1672. function m15_prep_kneecapper_vehicle(player) 
  1673. 	local vehicle = get_char_vehicle_name(player) 
  1674. 	 
  1675. 	if vehicle == "" or vehicle == player then 
  1676. 		-- The player is in an invalid or non-scripted vehicle 
  1677. 		return 
  1678. 	end 
  1679. 	 
  1680. 	if not character_is_in_a_driver_seat(player) then 
  1681. 		-- They are not driving. Don't change a vehicle the player doesn't have explicit control over 
  1682. 		return 
  1683. 	end 
  1684.  
  1685. 	if not vehicle_is_tank(vehicle) then 
  1686. 		vehicle_suppress_flipping(vehicle, true) 
  1687. 		vehicle_set_kneecappers_damage(vehicle, M15_KNEECAPPER_DAMAGE) 
  1688. 		release_to_world(vehicle)	 
  1689. 	end 
  1690. end 
  1691.  
  1692. -- Handles the logic for the chase sequence 
  1693. --- 
  1694. function m15_chase() 
  1695. 	-- Spawn the super computer truck and it's driver (create early to nuke any custom vehicles while we can) 
  1696. 	group_create_hidden(M15_groups.chase.name, true) 
  1697. 	 
  1698. 	m15_set_notoriety_range() 
  1699. 	 
  1700. 	delay(5.0) 
  1701. 	-- Remove any ongoing conversations and start up the new sections convos 
  1702. 	m15_cleanup_audio_threads() 
  1703. 	M15_THREAD_CONVO_TRUCK_FOUND = thread_new("m15_convo_truck_found") 
  1704. 	 
  1705. 	-- Wait until the vehilce is streamed in before we do anything with it 
  1706. 	while not m15_player_is_close_to_chase_start() do 
  1707. 		thread_yield() 
  1708. 	end 
  1709. 	 
  1710. 	group_show(M15_groups.chase.name) 
  1711. 	thread_yield() 
  1712. 	 
  1713. 	-- Setup any necessary flags on the player's choosen vehicle. This will release the vehicle to the world as well 
  1714. 	m15_prep_kneecapper() 
  1715. 	 
  1716. 	-- The player is far enough from the PR Center. Clean up any groups. 
  1717. 	m15_cleanup_outside_garage() 
  1718.  
  1719. 	-- Prevent the driver for attempting to attack and from being killed 
  1720. 	npc_combat_enable(NPC_DRIVER, false) 
  1721. 	turn_invulnerable(NPC_DRIVER, false) 
  1722. 	 
  1723. 	-- Prevent Pierce from attacking the truck 
  1724. 	set_dont_attack_me_on_sight_flag(NPC_DRIVER, true) 
  1725. 	 
  1726. 	-- Force the NPC to enter the vehicle and stop him for exiting 
  1727. 	vehicle_enter_teleport(NPC_DRIVER, VEHICLE_SUPER_COMPUTER, 0, true) 
  1728. 	vehicle_suppress_npc_exit(VEHICLE_SUPER_COMPUTER, true) 
  1729. 	audio_object_post_event("m15_sfx_supercomputer_hum", nil, nil, VEHICLE_SUPER_COMPUTER) 
  1730. 	vehicle_speed_override(VEHICLE_SUPER_COMPUTER, M15_SUPER_COMPUTER_SPEED) 
  1731. 	delay(4.0) 
  1732. 	 
  1733. 	-- Cleanup our directions to the truck since it now exists 
  1734. 	marker_remove(M15_SUPER_COMPUTER_START) 
  1735. 	waypoint_remove() 
  1736. 	 
  1737. 	-- Setup the HUD to point to the actual vehicle 
  1738. 	m15_vehicle_add_marker(VEHICLE_SUPER_COMPUTER) 
  1739. 	m15_vehicle_add_waypoint(VEHICLE_SUPER_COMPUTER) 
  1740.  
  1741. 	-- Detect vehicle destruction (mission failure) 
  1742. 	on_vehicle_destroyed("m15_vehicle_destroyed", VEHICLE_SUPER_COMPUTER) 
  1743. 	on_vehicle_enter_water("m15_vehicle_destroyed", VEHICLE_SUPER_COMPUTER) 
  1744. 	on_take_damage("m15_vehicle_damaged", VEHICLE_SUPER_COMPUTER) 
  1745.  
  1746. 	-- Record the health of all the tires in case they stream out 
  1747. 	M15_THREAD_TIRE_CHECK = thread_new("m15_thread_tire_check") 
  1748. 	M15_THREAD_CHASE_RUBBER_BAND = thread_new("m15_thread_chase_rubber_band") 
  1749. 	 
  1750. 	-- destroy the group outside the garage so as to free up vehicle instances. 
  1751. 	if group_is_loaded(M15_groups.cars_outside_garage.name) then 
  1752. 		group_destroy(M15_groups.cars_outside_garage.name) 
  1753. 	end 
  1754. 	 
  1755. 	-- Update the objective and start the vehicle on its actual path 
  1756. 	objective_text(0, M15_OBJ_DISABLE_THE_TRUCK, "", "", SYNC_ALL, OI_ASSET_KILL) 
  1757. 	 
  1758. 	m15_vehicle_follow_path(VEHICLE_SUPER_COMPUTER, NPC_DRIVER, M15_SUPER_COMPUTER_ROUTE) 
  1759. 	 
  1760. 	-- If m15_vehicle_follow_path returned, then we reached the destination which is a failure 
  1761. 	-- or the truck got stuck somewhere. 
  1762. 	if get_dist(VEHICLE_SUPER_COMPUTER, M15_SUPER_COMPUTER_ROUTE[#M15_SUPER_COMPUTER_ROUTE].nav) > 100.0 then 
  1763. 		m15_music("M15_music_truck_chase_End") 
  1764. 		-- The truck is stuck somewhere. Consider this a success 
  1765. 		mission_end_success("m15", M15_CUTSCENE_MISSION_OUTRO, {M15_NAV_START[1], M15_NAV_START[2]}) 
  1766. 	else 
  1767. 		mission_end_failure("m15", M15_FAILURE_TRUCK_DECKERS_HQ) 
  1768. 	end 
  1769. end 
  1770.  
  1771. function m15_vehicle_add_marker(vehicle) 
  1772. 	marker_add(vehicle, MINIMAP_ICON_KILL, OI_ASSET_KILL_TIRES, OI_FLAGS_DEFAULT, SYNC_ALL) 
  1773. end 
  1774.  
  1775. function m15_vehicle_remove_marker(vehicle) 
  1776. 	marker_remove(vehicle, SYNC_ALL) 
  1777. end 
  1778.  
  1779. function m15_vehicle_remove_waypoint(vehicle) 
  1780. 	if M15_chase_waypoint_active_local then 
  1781. 		waypoint_remove(SYNC_LOCAL) 
  1782. 		M15_chase_waypoint_active_local = false 
  1783. 	end 
  1784.  
  1785. 	if M15_in_coop and M15_chase_waypoint_active_remote then 
  1786. 		waypoint_remove(SYNC_REMOTE) 
  1787. 		M15_chase_waypoint_active_remote = false 
  1788. 	end 
  1789. end 
  1790.  
  1791. function m15_vehicle_add_waypoint(vehicle) 
  1792. 	if not M15_chase_waypoint_active_local then 
  1793. 		waypoint_add(vehicle, SYNC_LOCAL) 
  1794. 		M15_chase_waypoint_active_local = true 
  1795. 	end 
  1796.  
  1797. 	if M15_in_coop and not M15_chase_waypoint_active_remote then 
  1798. 		waypoint_add(vehicle, SYNC_REMOTE) 
  1799. 		M15_chase_waypoint_active_remote = true 
  1800. 	end 
  1801. end 
  1802.  
  1803. -- Adds/removes a waypoint attached to a vehicle when the player is inside/outside a radius. This is 
  1804. -- done since the waypoint isn't updated each frame and it is very distracting when the player is 
  1805. -- close to the truck. This will be invidually for the local and remote player, since they can be 
  1806. -- in seperate cars. 
  1807. -- 
  1808. -- vehicle: Name of the vehicle theplayer is chasing 
  1809. function m15_update_chase_waypoint(vehicle) 
  1810. 	local dist_to_local  = get_dist(LOCAL_PLAYER, vehicle) 
  1811. 	 
  1812. 	if M15_chase_waypoint_active_local then 
  1813. 		if dist_to_local < M15_WAYPOINT_REMOVE_DIST then 
  1814. 			waypoint_remove(SYNC_LOCAL) 
  1815. 			M15_chase_waypoint_active_local = false 
  1816. 		end 
  1817. 	else 
  1818. 		if dist_to_local > M15_WAYPOINT_REMOVE_DIST then 
  1819. 			waypoint_add(vehicle, SYNC_LOCAL) 
  1820. 			M15_chase_waypoint_active_local = true 
  1821. 		end 
  1822. 	end 
  1823.  
  1824. 	if M15_in_coop then 
  1825. 		local dist_to_remote = get_dist(REMOTE_PLAYER, vehicle) 
  1826. 		 
  1827. 		if M15_chase_waypoint_active_remote then 
  1828. 			if dist_to_remote < M15_WAYPOINT_REMOVE_DIST then 
  1829. 				waypoint_remove(SYNC_REMOTE) 
  1830. 				M15_chase_waypoint_active_remote = false 
  1831. 			end 
  1832. 		else 
  1833. 			if dist_to_remote > M15_WAYPOINT_REMOVE_DIST then 
  1834. 				waypoint_add(vehicle, SYNC_REMOTE) 
  1835. 				M15_chase_waypoint_active_remote = true 
  1836. 			end 
  1837. 		end 
  1838. 	end 
  1839. end 
  1840.  
  1841. -- Gets the distance to the specific vehicle and sorts the output 
  1842. -- 
  1843. -- vehicle:	Name of the vehicle the player(s) are chasing 
  1844. -- 
  1845. -- Returns: min_dist_to_vehicle, max_dist_to_vehicle 
  1846. function m15_get_chase_distance(vehicle) 
  1847. 	local dist_to_local  = get_dist(LOCAL_PLAYER, vehicle) 
  1848. 	local dist_to_remote = dist_to_local 
  1849. 	 
  1850. 	if M15_in_coop then 
  1851. 		dist_to_remote = get_dist(REMOTE_PLAYER, vehicle) 
  1852. 	end 
  1853. 	 
  1854. 	if dist_to_local < dist_to_remote then 
  1855. 		return dist_to_local, dist_to_remote 
  1856. 	else 
  1857. 		return dist_to_remote, dist_to_local 
  1858. 	end 
  1859. end 
  1860.  
  1861. -- Checks to see if a player is in range of the vehicle. If so, this function does nothing. 
  1862. -- If no player is within range, this function will block until they are within range again. 
  1863. -- 
  1864. -- vehicle: Name of the vehicle the player(s) are chasing 
  1865. function m15_update_chase_radius(vehicle) 
  1866. 	local dist_min, dist_max = m15_get_chase_distance(vehicle) 
  1867. 	 
  1868. 	-- Check to see if the player is outside the failure radius 
  1869. 	if dist_min > M15_VEHICLE_MAX_DISTANCE then 
  1870. 		mission_end_failure("m15", M15_FAILURE_TRUCK_ESCAPED) 
  1871. 		 
  1872. 	elseif dist_min <= M15_VEHICLE_WARN_RADIUS then 
  1873. 		if M15_radius_shown == true then 
  1874. 			minimap_icon_remove_radius(vehicle, SYNC_ALL) 
  1875. 			M15_radius_shown = false 
  1876. 		end 
  1877.  
  1878. 	else		 
  1879. 		if M15_radius_shown == false then 
  1880. 			minimap_icon_add_radius(vehicle, M15_VEHICLE_MAX_DISTANCE * 0.95, SYNC_ALL) 
  1881. 			M15_radius_shown = true 
  1882. 		end 
  1883.  
  1884. 	end 
  1885. end 
  1886.  
  1887. -- Iterates through a table of nav points and tells the specific vehicle to follow it while calling the 
  1888. -- helper functions: 
  1889. --    m15_update_chase_waypoint()       - Add/remove a waypoint to the vehicle when necessary 
  1890. --    m15_update_chase_radius() - Stop the vehicle if the player is out of range. 
  1891. -- 
  1892. -- vehicle:	Name of the vehicle the player is chasing 
  1893. -- driver:	Name of the driver of the vehicle 
  1894. -- path:	Table of nav points to pathfind through 
  1895. -- 
  1896. function m15_vehicle_follow_path(vehicle, driver, path) 
  1897. 	-- Setup some paramters/flags to force the vehicle to follow the nav points. 
  1898. 	vehicle_set_script_hard_goto(vehicle, true) 
  1899. 	vehicle_set_crazy(vehicle, true) 
  1900. 	vehicle_set_tire_damage_multiplier(vehicle, M15_TIRE_DAMGE_MULTIPLIER) 
  1901. 	-- The tires won't go flat if the durability is at the default value.  
  1902. 	vehicle_set_tire_durability(vehicle, 1.01) 
  1903. 	vehicle_ignore_repulsors(vehicle, true) 
  1904. 	vehicle_set_allow_ram_ped(vehicle, true) 
  1905. 	vehicle_set_ignore_rail_obstacles(vehicle, true) 
  1906. 	vehicle_prevent_transition_to_ambient(vehicle, true) 
  1907. 	 
  1908. 	vehicle_infinite_mass(vehicle, M15_INFINITE_MASS) 
  1909.  
  1910. 	-- Give AI some time to apply all the set flags 
  1911. 	thread_yield() 
  1912.  
  1913. 	local i = 1 
  1914. 	while i <= #path do 
  1915. 		local attempts    = 0 
  1916. 		local in_progress = M15_PATHFINDING_IN_PROGRESS 
  1917. 		thread_yield() 
  1918.  
  1919. 		-- Start pathfinding 
  1920. 		local pathfind_started = vehicle_pathfind_to_do(vehicle, path[i].nav, false, true) 
  1921. 		if pathfind_started ~= false and pathfind_started ~= 0 then 
  1922. 			-- No issues starting the path. Loop until we error out or reach our destination 
  1923. 			in_progress = vehicle_pathfind_check_done(vehicle) 
  1924. 			while in_progress == M15_PATHFINDING_IN_PROGRESS do 
  1925. 				thread_yield() 
  1926. 				in_progress = vehicle_pathfind_check_done(vehicle) 
  1927. 				 
  1928. 				m15_update_chase_radius(vehicle) 
  1929.  
  1930. 				-- Add a waypoint if needed 
  1931. 				m15_update_chase_waypoint(vehicle) 
  1932. 			end 
  1933.  
  1934. 			-- If the driver has died or is not in the vehicle (still alive), then the player 
  1935. 			-- has effectivly disabled the truck since it can no longer move. 
  1936. 			if (character_is_dead(driver) or not character_is_in_vehicle(driver)) and not vehicle_is_destroyed(vehicle) then 
  1937. 				m15_music("M15_music_truck_chase_End") 
  1938. 				mission_end_success("m15", M15_CUTSCENE_MISSION_OUTRO, {M15_NAV_START[1], M15_NAV_START[2]}) 
  1939. 			end 
  1940. 			 
  1941. 			if in_progress == M15_PATHFINDING_FAILED then 
  1942. 				-- Failed to get to the nav point.  
  1943. 				if attempts < 5 then 
  1944. 					-- We have not hit our attempt limit. Go ahead and try again. 
  1945. 					thread_yield() 
  1946. 					attempts = attempts + 1 
  1947. 					delay(5.0) 
  1948. 					message("Failed to pathfind to: " .. path[i].nav, 4.0) 
  1949. 				else 
  1950. 					delay(0.5) 
  1951. 					-- Failed to many times. Attempt to pathfind to the next point 
  1952. 					i = i + 1 
  1953. 				end 
  1954. 			elseif in_progress == M15_PATHFINDING_DONE then 
  1955. 				if path[i].delay ~= "" then 
  1956. 					local dist = get_dist(vehicle, path[i].delay) 
  1957. 					while dist > 11.0 do 
  1958. 						thread_yield() 
  1959. 						dist = get_dist(vehicle, path[i].delay) 
  1960. 					end 
  1961. 				end 
  1962. 				-- We reached the specified point. Move to the next one. 
  1963. 				i = i + 1 
  1964. 			end 
  1965. 		end 
  1966.  
  1967. 		thread_yield() 
  1968. 	end 
  1969. end 
  1970.  
  1971.  
  1972.  
  1973.  
  1974.  
  1975. -- Finds a chase trigger by name 
  1976. -- 
  1977. -- trigger_name:	Name of the trigger to find 
  1978. -- 
  1979. -- Returns the trigger table or nil if it is not found 
  1980. function m15_find_trigger(trigger_name) 
  1981. 	for key, trigger in pairs(M15_chase_triggers) do  
  1982. 		if trigger.trigger_name == trigger_name then 
  1983. 			return trigger 
  1984. 		end 
  1985. 	end 
  1986. 	 
  1987. 	return nil 
  1988. end 
  1989.  
  1990. function m15_find_prep_trigger(trigger_name) 
  1991. 	for key, trigger in pairs(M15_chase_triggers) do  
  1992. 		if trigger.prep_trigger == trigger_name then 
  1993. 			return trigger 
  1994. 		end 
  1995. 	end 
  1996. 	 
  1997. 	return nil 
  1998. end 
  1999.  
  2000. -- Sets up a chase trigger 
  2001. -- 
  2002. -- trigger:	M15_chase_triggers table to setup 
  2003. -- 
  2004. function m15_setup_chase_trigger(trigger) 
  2005. 	group_create(trigger.name, true) 
  2006. 	 
  2007. 	for key, vehicle in pairs(trigger.vehicles) do 
  2008. 		vehicle_enter_group_teleport(vehicle.members, vehicle.vehicle) 
  2009. 		-- Tell the NPCs to ignore AI so they don't try to chase the player before they are triggered 
  2010. 		for npc_key, npc in pairs(vehicle.members) do 
  2011. 			set_ignore_ai_flag(npc, true) 
  2012. 		end 
  2013. 		 
  2014. 		if vehicle.gunner ~= nil and vehicle.gunner ~= "" then 
  2015. 			vehicle_enter_teleport(vehicle.gunner, vehicle.vehicle, 4, true) 
  2016. 			set_ignore_ai_flag(vehicle.gunner, true) 
  2017. 		end 
  2018. 	end 
  2019. 	 
  2020. 	on_trigger(trigger.on_trigger, trigger.trigger_name) 
  2021. 	trigger_enable(trigger.trigger_name, true) 
  2022. end 
  2023.  
  2024. -- Sets up all chase triggers 
  2025. -- 
  2026. function m15_setup_all_chase_triggers() 
  2027. 	for key, trigger in pairs(M15_chase_triggers) do 
  2028. 		if trigger.prep_trigger ~= "" then 
  2029. 			on_trigger("m15_prep_chase_trigger", trigger.prep_trigger) 
  2030. 			trigger_enable(trigger.prep_trigger, true) 
  2031. 		else 
  2032. 			on_trigger(trigger.on_trigger, trigger.trigger_name) 
  2033. 			trigger_enable(trigger.trigger_name, true) 
  2034. 		end 
  2035. 	end 
  2036. end 
  2037.  
  2038. -- Cleans up a trigger setup by m15_setup_chase_trigger() 
  2039. -- 
  2040. -- trigger:	M15_chase_triggers table to cleanup 
  2041. -- 
  2042. function m15_cleanup_chase_trigger(trigger) 
  2043. 	if trigger.prep_trigger ~= "" then 
  2044. 		on_trigger("", trigger.prep_trigger) 
  2045. 		trigger_enable(trigger.prep_trigger, false) 
  2046. 	end 
  2047. 	 
  2048. 	if trigger.trigger_name ~= "" then 
  2049. 		on_trigger("", trigger.trigger_name) 
  2050. 		trigger_enable(trigger.trigger_name, false) 
  2051. 	end 
  2052. 	 
  2053. 	for key, vehicle in pairs(trigger.vehicles) do 
  2054. 		if vehicle.thread ~= INVALID_THREAD_HANDLE then 
  2055. 			thread_kill(vehicle.thread) 
  2056. 			vehicle.thread = INVALID_THREAD_HANDLE 
  2057. 		end 
  2058. 	end 
  2059. 	 
  2060. 	if trigger.name ~= "" and group_is_loaded(trigger.name) then 
  2061. 		release_to_world(trigger.name) 
  2062. 		group_destroy(trigger.name) 
  2063. 	end 
  2064. end 
  2065.  
  2066. -- Cleanup a trigger if all the pathfinding threads are complete 
  2067. -- 
  2068. -- trigger:	M15_chase_triggers table to cleanup 
  2069. --  
  2070. function m15_maybe_cleanup_chase_trigger(trigger) 
  2071. 	for key, vehicle in pairs(trigger.vehicles) do 
  2072. 		if vehicle.thread ~= INVALID_THREAD_HANDLE then 
  2073. 			-- At least one pathfinding thread is active. Cannot cleanup the group yet. 
  2074. 			return 
  2075. 		end 
  2076. 	end 
  2077. 	 
  2078. 	m15_cleanup_chase_trigger(trigger) 
  2079. end 
  2080.  
  2081. -- Cleans up all chase triggers 
  2082. -- 
  2083. function m15_cleanup_all_chase_triggers() 
  2084. 	for key, trigger in pairs(M15_chase_triggers) do 
  2085. 		m15_cleanup_chase_trigger(trigger) 
  2086. 	end 
  2087. end 
  2088.  
  2089.  
  2090. function m15_player_is_in_a_tank() 
  2091. 	if character_is_in_a_driver_seat(LOCAL_PLAYER) then 
  2092. 		local veh_name = get_char_vehicle_name(LOCAL_PLAYER) 
  2093. 		if veh_name ~= "" and veh_name ~= LOCAL_PLAYER and vehicle_is_tank(veh_name) then 
  2094. 			return true 
  2095. 		end 
  2096. 	end 
  2097. 	 
  2098. 	if M15_in_coop and character_is_in_a_driver_seat(REMOTE_PLAYER) then 
  2099. 		local veh_name = get_char_vehicle_name(REMOTE_PLAYER) 
  2100. 		if veh_name ~= "" and veh_name ~= REMOTE_PLAYER and vehicle_is_tank(veh_name) then 
  2101. 			return true 
  2102. 		end 
  2103. 	end 
  2104. 	 
  2105. 	return false 
  2106. end 
  2107.  
  2108.  
  2109. -- ************************* 
  2110. -- 
  2111. -- Callback functions 
  2112. -- 
  2113. -- ************************* 
  2114.  
  2115. function m15_release_npc_to_world(victim, killer) 
  2116. 	on_death("", victim) 
  2117. 	release_to_world(victim) 
  2118. end 
  2119.  
  2120. -- Generic trigger callback. Whenever the trigger is triggered by the player, the 
  2121. -- M15_trigger_reached flag is set. 
  2122. -- 
  2123. -- human   - Who triggered the trigger 
  2124. -- trigger - Name of the triggered trigger. 
  2125. function m15_trigger_cback(human, trigger) 
  2126. 	if human == LOCAL_PLAYER or human == REMOTE_PLAYER then 
  2127. 		M15_trigger_reached = true 
  2128. 	end 
  2129. end 
  2130.  
  2131. -- Ends the mission if an important human is killed. 
  2132. -- 
  2133. -- victim - Who was killed 
  2134. -- killer - The killer... 
  2135. function m15_on_death(victim, killer) 
  2136. 	if victim == NPC_PIERCE then 
  2137. 		mission_end_failure("m15", M15_FAILURE_PIERCE_DIED) 
  2138. 	end 
  2139. end 
  2140.  
  2141. function m15_party_member_dismissed(npc, leader) 
  2142. 	if npc == NPC_PIERCE then 
  2143. 		mission_end_failure("m15", M15_FAILURE_PIERCE_DISMISSED) 
  2144. 	end 
  2145. end 
  2146.  
  2147. -- Fail if the super computer truck is destroyed 
  2148. -- 
  2149. function m15_vehicle_destroyed(vehicle) 
  2150. 	mission_end_failure("m15", M15_FAILURE_TRUCK_DESTROYED) 
  2151. end 
  2152.  
  2153. function m15_vehicle_damaged(truck, attacker, hp_percent, from_explosion) 
  2154. 	-- We only care about what the player did to the truck 
  2155. 	if attacker ~= LOCAL_PLAYER and attacker ~= REMOTE_PLAYER then 
  2156. 		return 
  2157. 	end 
  2158. 	 
  2159. 	-- Only consider explosion harmful to the computer 
  2160. 	if from_explosion ~= true then 
  2161. 		return 
  2162. 	end 
  2163. 	 
  2164. 	-- Check to see if the player was in a tank 
  2165. 	local vehicle = get_char_vehicle_name(attacker) 
  2166. 	if vehicle == "" or not vehicle_is_tank(vehicle) then 
  2167. 		return 
  2168. 	end 
  2169. 	 
  2170. 	-- Give them a warning if they haven't shot the truck with the cannon yet 
  2171. 	if not M15_truck_hit_by_tank_shell then 
  2172. 		m15_cleanup_audio_threads() 
  2173. 		M15_THREAD_CONVO_DONT_USE_CANNON = thread_new("m15_convo_player_used_cannon_on_truck") 
  2174. 		M15_truck_hit_by_tank_shell = true 
  2175. 		return 
  2176. 	end 
  2177. 	 
  2178. 	-- The truck was shot at least twice with the cannon. Destroy it. 
  2179. 	vehicle_detonate(truck) 
  2180. end 
  2181.  
  2182. -- Prepares a chase trigger 
  2183. -- 
  2184. -- human:					Name of the player that triggered the callback 
  2185. -- prep_trigger_name:	Name of the trigger that was activated 
  2186. -- 
  2187. function m15_prep_chase_trigger(human, prep_trigger_name) 
  2188. 	local trigger = m15_find_prep_trigger(prep_trigger_name) 
  2189.  
  2190. 	m15_setup_chase_trigger(trigger) 
  2191. 	 
  2192. 	trigger_enable(prep_trigger_name, false) 
  2193. 	on_trigger("", prep_trigger_name) 
  2194. end 
  2195.  
  2196. -- Closes a roadblock 
  2197. -- 
  2198. -- human:			Name of the player that triggered the callback 
  2199. -- trigger_name:	Name of the trigger that was activated 
  2200. -- 
  2201. function m15_close_roadblock(human, trigger_name) 
  2202. 	local trigger = m15_find_trigger(trigger_name) 
  2203. 	 
  2204. 	for key, vehicle in pairs(trigger.vehicles) do 
  2205. 		vehicle.thread = thread_new("m15_roadblock_pathfind_to_thread", trigger, vehicle) 
  2206. 	end 
  2207. 	 
  2208. 	trigger_enable(trigger_name, false) 
  2209. 	on_trigger("", trigger_name) 
  2210. end 
  2211.  
  2212. function m15_chase_truck(human, trigger_name) 
  2213. 	local trigger = m15_find_trigger(trigger_name) 
  2214. 	 
  2215. 	for key, vehicle in pairs(trigger.vehicles) do 
  2216. 		vehicle.thread = thread_new("m15_chase_pathfind_to_thread", trigger, vehicle) 
  2217. 	end 
  2218. 	 
  2219. 	trigger_enable(trigger_name, false) 
  2220. 	on_trigger("", trigger_name) 
  2221. end 
  2222.  
  2223. function m15_spawn_and_release(human, trigger_name) 
  2224. 	local trigger = m15_find_trigger(trigger_name) 
  2225.  
  2226. 	trigger_enable(trigger_name, false) 
  2227. 	on_trigger("", trigger_name) 
  2228. 	 
  2229. 	group_create(trigger.name) 
  2230. 	release_to_world(trigger.name) 
  2231. 	group_destroy(trigger.name) 
  2232. end 
  2233.  
  2234. function m15_reduce_truck_speed(human, trigger_name) 
  2235. 	if human ~= NPC_DRIVER then 
  2236. 		return 
  2237. 	end 
  2238. 	 
  2239. 	vehicle_speed_override(VEHICLE_SUPER_COMPUTER, M15_SUPER_COMPUTER_SPEED * 0.60) 
  2240. 	trigger_enable(trigger_name, false) 
  2241. 	on_trigger("", trigger_name) 
  2242. end 
  2243.  
  2244. function m15_spawn_deckers_base(human, trigger_name) 
  2245. 	group_create(M15_groups.deckers_base) 
  2246. 	 
  2247. 	trigger_enable(trigger_name, false) 
  2248. 	on_trigger("", trigger_name) 
  2249. end 
  2250.  
  2251. function m15_disable_notoriety() 
  2252. 	notoriety_force_no_spawn(STAG_NOTORIETY, true) 
  2253. 	notoriety_force_no_spawn(DECKERS_NOTORIETY, true) 
  2254. end 
  2255.  
  2256. function m15_enable_notoriety() 
  2257. 	notoriety_force_no_spawn(STAG_NOTORIETY, false) 
  2258. 	notoriety_force_no_spawn(DECKERS_NOTORIETY, false) 
  2259. end 
  2260.  
  2261. function m15_make_npc_mission_critical(npc) 
  2262. 	if npc == nil or npc == "" or npc == LOCAL_PLAYER or npc == REMOTE_PLAYER then 
  2263. 		return 
  2264. 	end 
  2265. 	 
  2266. 	-- Only mark a decker, police member, or stag member as mission critical 
  2267. 	local team = get_team(npc) 
  2268. 	if team ~= "Deckers" and team ~= "Police" and team ~= "STAG" then 
  2269. 		return 
  2270. 	end 
  2271. 	 
  2272. 	-- Ignore already marked NPCs 
  2273. 	if M15_extra_npcs_in_lobby[npc] == true then 
  2274. 		return 
  2275. 	end 
  2276. 	 
  2277. 	on_death("m15_enemy_killed", npc) 
  2278. 	if M15_mark_waves then 
  2279. 		marker_add(npc, MINIMAP_ICON_KILL, OI_ASSET_KILL, OI_FLAGS_DEFAULT, SYNC_ALL) 
  2280. 	end 
  2281. 	npc_leash_to_nav(npc, M15_LOBBY_LEASH_POINT, M15_LOBBY_LEASH_RADIUS) 
  2282. 	 
  2283. 	M15_extra_npcs_in_lobby[npc] = true 
  2284. end 
  2285.  
  2286. function m15_trigger_outside_battle(human, trigger_name) 
  2287. 	trigger_enable(trigger_name, false) 
  2288. 	on_trigger("", trigger_name) 
  2289. 	 
  2290. 	M15_trigger_reached = true 
  2291. end 
  2292.  
  2293. -- Generic callback when a phone call conversation has ended 
  2294. function m15_call_ended_cb() 
  2295. 	M15_phone_call_active = false 
  2296. end 
  2297.  
  2298. -- Handle actually playing the attack lines 
  2299. -- 
  2300. -- name:	(string) name of character 
  2301. -- attack_info:		(table) information about the attack situation to play 
  2302. -- 
  2303. function m15_process_attack(name, attack_info)		 
  2304. 	-- don't play this if we have done this recently 
  2305. 	if (not thread_check_done(attack_info.timer)) then 
  2306. 		return 
  2307. 	end 
  2308. 	 
  2309. 	-- start timer 
  2310. 	attack_info.timer = thread_new("delay", attack_info.delay) 
  2311. 	 
  2312. 	-- play situation 
  2313. 	if not audio_play_persona_line(name, attack_info.situation) then 
  2314. 		-- line didn't play, kill our timer 
  2315. 		thread_kill(attack_info.timer) 
  2316. 		attack_info.timer = INVALID_THREAD_HANDLE 
  2317. 	end 
  2318.  
  2319. end 
  2320.  
  2321. -- play attack lines for deckers 
  2322. -- 
  2323. -- name:	(string) name of character 
  2324. -- weapon:	(string) name of weapon 
  2325. -- attack:	(string) type of attack performed 
  2326. -- 
  2327. function m15_decker_attack_cb(name, weapon, attack) 
  2328. 	m15_process_attack(name, M15_attack_info.decker) 
  2329. end 
  2330.  
  2331. -- play attack lines for stag 
  2332. -- 
  2333. -- name:	(string) name of character 
  2334. -- weapon:	(string) name of weapon 
  2335. -- attack:	(string) type of attack performed 
  2336. -- 
  2337. function m15_stag_attack_cb(name, weapon, attack) 
  2338. 	m15_process_attack(name, M15_attack_info.stag) 
  2339. end 
  2340.  
  2341. -- ************************* 
  2342. -- 
  2343. -- Thread functions 
  2344. -- 
  2345. -- ************************* 
  2346.  
  2347. function m15_saints_kneecapper_thread(vehicle) 
  2348. 	local extra_delay = rand_int(0, 5) / 10 
  2349. 	delay(1.0 + extra_delay) 
  2350.  
  2351. 	vehicle_enter_group_teleport(vehicle.npcs, vehicle.vehicle) 
  2352. 	vehicle_suppress_npc_exit(vehicle.vehicle, true) 
  2353. 	vehicle_set_kneecappers(vehicle.vehicle, true) 
  2354. 	 
  2355. 	for key, npc_name in pairs(vehicle.npcs) do 
  2356. 		set_ignore_ai_flag(npc_name, false) 
  2357. 		set_dont_attack_me_on_sight_flag(npc_name, false) 
  2358. 		character_prevent_explosion_fling(npc_name, false) 
  2359. 		character_prevent_flinching(npc_name, false) 
  2360. 	end 
  2361. 	 
  2362. 	vehicle_pathfind_to(vehicle.vehicle, vehicle.path, true, true) 
  2363. 	 
  2364. 	vehicle_suppress_npc_exit(vehicle.vehicle, false) 
  2365. 	vehicle_exit_group(vehicle.npcs) 
  2366. 	vehicle.thread = INVALID_THREAD_HANDLE 
  2367. end 
  2368.  
  2369. function m15_roadblock_pathfind_to_thread(trigger, vehicle_table) 
  2370. 	vehicle_pathfind_to(vehicle_table.vehicle, vehicle_table.path, true) 
  2371. 	for key, npc in pairs(vehicle_table.members) do 
  2372. 		set_ignore_ai_flag(npc, false) 
  2373. 	end 
  2374. 	 
  2375. 	if vehicle_table.gunner ~= nil and vehicle_table.gunner ~= "" then 
  2376. 		set_ignore_ai_flag(vehicle_table.gunner, false) 
  2377. 	end 
  2378. 	 
  2379. 	vehicle_exit_group(vehicle_table.members) 
  2380. 	 
  2381. 	vehicle_table.thread = INVALID_THREAD_HANDLE 
  2382. 	m15_maybe_cleanup_chase_trigger(trigger) 
  2383. end 
  2384.  
  2385. function m15_chase_pathfind_to_thread(trigger, vehicle_table) 
  2386. 	vehicle_pathfind_to(vehicle_table.vehicle, vehicle_table.path, true) 
  2387. 	for key, npc in pairs(vehicle_table.members) do 
  2388. 		set_ignore_ai_flag(npc, false) 
  2389. 	end 
  2390. 	 
  2391. 	if vehicle_table.gunner ~= nil and vehicle_table.gunner ~= "" then 
  2392. 		set_ignore_ai_flag(vehicle_table.gunner, false) 
  2393. 	end 
  2394. 	 
  2395. 	local exit_at_stop = false 
  2396. 	vehicle_chase(vehicle_table.vehicle, NPC_DRIVER, exit_at_stop) 
  2397. 	 
  2398. 	vehicle_table.thread = INVALID_THREAD_HANDLE 
  2399. end 
  2400.  
  2401. function m15_cleanup_all_waves() 
  2402. 	for key, wave in pairs(M15_waves) do 
  2403. 		-- Kill the wave thread if it is running 
  2404. 		if wave.thread ~= INVALID_THREAD_HANDLE then 
  2405. 			thread_kill(wave.thread) 
  2406. 			wave.thread = INVALID_THREAD_HANDLE 
  2407. 		end 
  2408. 	 
  2409. 		-- Cleanup any active groups 
  2410. 		for group_key, group in pairs(wave.groups) do 
  2411. 			if group_is_loaded(group.name) then 
  2412. 				m15_cleanup_enemy_set(group) 
  2413. 				release_to_world(group.name) 
  2414. 				group_destroy(group.name) 
  2415. 			end 
  2416. 		end 
  2417. 	end 
  2418. end 
  2419.  
  2420. function m15_process_enemy_set(group, leash_to, leash_radius, attack_cb) 
  2421. 	m15_setup_enemy_set(group, attack_cb) 
  2422. 	 
  2423. 	-- Tell the group to run to a random nav point 
  2424. 	m15_enemy_set_run_to_nav(group) 
  2425. 	 
  2426. 	-- Flag the NPCs as mission critical 
  2427. 	m15_enemy_set_flag(group) 
  2428. 	 
  2429. 	-- Leash the NPCs so they don't attempt to leave their area 
  2430. 	m15_enemey_set_leash(group, leash_to, leash_radius) 
  2431. 	 
  2432. 	local members_alive = 2 
  2433. 	while members_alive > 0 do 
  2434. 		members_alive = 0 
  2435. 		for key, npc in pairs(group.members) do 
  2436. 			-- we only care that the value is not zero, so move on once we know that 
  2437. 			if (members_alive == 0) and not character_is_dead(npc) then 
  2438. 				members_alive = members_alive + 1 
  2439. 			end 
  2440. 		end 
  2441. 		 
  2442. 		thread_yield() 
  2443. 	end 
  2444. 	 
  2445. 	m15_cleanup_enemy_set(group) 
  2446. end 
  2447.  
  2448. function m15_setup_enemy_set(group, attack_cb) 
  2449. 	for key, npc in pairs(group.members) do 
  2450. 		if not character_is_dead(npc) then 
  2451. 			-- set a callback to know when the enemy is killed 
  2452. 			on_death("m15_enemy_killed", npc) 
  2453. 			on_attack_performed(attack_cb, npc) 
  2454. 		end 
  2455. 	end 
  2456. 	 
  2457. 	if group.human_shield ~= "" then 
  2458. 		character_take_human_shield(group.members[1], group.human_shield, true) 
  2459. 	end 
  2460. end 
  2461.  
  2462.  
  2463. function m15_cleanup_enemy_set(group) 
  2464. 	for key, npc in pairs(group.members) do 
  2465. 		marker_remove(npc) 
  2466. 		on_death("", npc) 
  2467. 		on_attack_performed("", npc) 
  2468. 	end 
  2469. end 
  2470.  
  2471. function m15_enemy_set_run_to_nav(group) 
  2472. 	if sizeof_table(group.run_to) == 0 then 
  2473. 		return 
  2474. 	end 
  2475. 	 
  2476. 	-- Check to see if a player is to close to the NPCs for them to run to cover 
  2477. 	if group.dont_run_trigger ~= "" then 
  2478. 		local in_trigger = object_is_in_trigger(group.dont_run_trigger, LOCAL_PLAYER) 
  2479. 		 
  2480. 		if M15_in_coop then 
  2481. 			in_trigger = in_trigger or object_is_in_trigger(group.dont_run_trigger, REMOTE_PLAYER) 
  2482. 		end 
  2483. 		 
  2484. 		if in_trigger then 
  2485. 			return 
  2486. 		end 
  2487. 	end 
  2488. 	 
  2489. 	-- Tell all NPCS to run to a random nav point 
  2490. 	for key, npc in pairs(group.members) do 
  2491. 		local nav = get_random_table_entry(group.run_to) 
  2492. 		ai_do_scripted_move(npc, nav, true, true) 
  2493. 	end 
  2494. end 
  2495.  
  2496. function m15_enemy_set_flag(group) 
  2497. 	if M15_mark_waves == false then 
  2498. 		return 
  2499. 	end 
  2500.  
  2501. 	for key, npc in pairs(group.members) do 
  2502. 		if not character_is_dead(npc) then 
  2503. 			marker_add(npc, MINIMAP_ICON_KILL, OI_ASSET_KILL, OI_FLAGS_DEFAULT, SYNC_ALL) 
  2504. 		end 
  2505. 	end 
  2506. end 
  2507.  
  2508. function m15_enemey_set_leash(group, leash_to, leash_radius) 
  2509. 	if leash_to == "" then 
  2510. 		return 
  2511. 	end 
  2512.  
  2513. 	for key, npc in pairs(group.members) do 
  2514. 		if not character_is_dead(npc) then 
  2515. 			npc_leash_to_nav(npc, leash_to, leash_radius) 
  2516. 		end 
  2517. 	end 
  2518. end 
  2519.  
  2520. function m15_enemy_killed(enemy) 
  2521. 	marker_remove(enemy) 
  2522. 	on_death("", enemy) 
  2523. 	M15_extra_npcs_in_lobby[enemy] = nil 
  2524. end 
  2525.  
  2526. -- wave: the waves of enemies to spawn. 
  2527. -- 
  2528. function m15_run_wave(wave) 
  2529.  
  2530. 	-- set up the wave counter 
  2531. 	wave.num_remaining = #wave.groups 
  2532. 	 
  2533. 	for key, group in pairs(wave.groups) do 
  2534. 		if not M15_in_pr_center then 
  2535. 			-- if we are not inside yet, just wait until we are 
  2536. 			group_create_hidden(group.name, true) 
  2537. 			while not M15_in_pr_center do 
  2538. 				thread_yield() 
  2539. 			end 
  2540. 			group_show(group.name) 
  2541. 		else 
  2542. 			group_create(group.name, true) 
  2543. 		end 
  2544. 		 
  2545. 		m15_process_enemy_set(group, wave.leash_to, wave.leash_radius, wave.attack_cb) 
  2546. 		 
  2547. 		-- decrement the wave counter 
  2548. 		wave.num_remaining = wave.num_remaining - 1 
  2549. 		 
  2550. 		release_to_world(group.name) 
  2551. 		group_destroy(group.name) 
  2552. 		 
  2553. 		delay(M15_DELAY_BETWEEN_WAVE_SPAWNS) 
  2554. 	end 
  2555. 	 
  2556. 	wave.thread = INVALID_THREAD_HANDLE 
  2557. end 
  2558.  
  2559. function m15_mark_wave_npcs(wave) 
  2560. 	if wave.thread == INVALID_THREAD_HANDLE then 
  2561. 		return 
  2562. 	end 
  2563.  
  2564. 	for key, group in pairs(wave.groups) do 
  2565. 		if group_is_loaded(group.name) then 
  2566. 			m15_enemy_set_flag(group) 
  2567. 		end 
  2568. 	end 
  2569. end 
  2570.  
  2571. function m15_mark_extra_npcs() 
  2572. 	if M15_mark_waves == false then 
  2573. 		return 
  2574. 	end 
  2575. 	 
  2576. 	-- NPC names are used as the key for the table. val is a bool that is set to true  
  2577. 	for npc, val in pairs(M15_extra_npcs_in_lobby) do 
  2578. 		marker_add(npc, MINIMAP_ICON_KILL, OI_ASSET_KILL, OI_FLAGS_DEFAULT, SYNC_ALL) 
  2579. 	end 
  2580. end 
  2581.  
  2582. function m15_cleanup_extra_npcs() 
  2583. 	for npc, val in pairs(M15_extra_npcs_in_lobby) do 
  2584. 		m15_enemy_killed(npc)		 
  2585. 	end 
  2586. end 
  2587.  
  2588. -- Kills any active audio threads and stops any audio they were playing 
  2589. -- 
  2590. function m15_cleanup_audio_threads() 
  2591. 	if M15_THREAD_CONVO_TO_PR_CENTER ~= INVALID_THREAD_HANDLE then 
  2592. 		thread_kill(M15_THREAD_CONVO_TO_PR_CENTER) 
  2593. 		M15_THREAD_CONVO_TO_PR_CENTER = INVALID_THREAD_HANDLE 
  2594. 		m15_unload_convo_set(M15_convo.to_pr_center) 
  2595. 	end 
  2596. 	 
  2597. 	if M15_THREAD_CONVO_PR_CENTER ~= INVALID_THREAD_HANDLE then 
  2598. 		thread_kill(M15_THREAD_CONVO_PR_CENTER) 
  2599. 		M15_THREAD_CONVO_PR_CENTER = INVALID_THREAD_HANDLE 
  2600. 		m15_unload_convo_set(M15_convo.pr_center_outside) 
  2601. 	end 
  2602. 	 
  2603. 	if M15_THREAD_CONVO_IN_LOBBY ~= INVALID_THREAD_HANDLE then 
  2604. 		thread_kill(M15_THREAD_CONVO_IN_LOBBY) 
  2605. 		M15_THREAD_CONVO_IN_LOBBY = INVALID_THREAD_HANDLE 
  2606. 		m15_unload_convo_set(M15_convo.pr_center_lobby) 
  2607. 	end 
  2608. 	 
  2609. 	if M15_THREAD_CONVO_IN_GARAGE ~= INVALID_THREAD_HANDLE then 
  2610. 		thread_kill(M15_THREAD_CONVO_IN_GARAGE) 
  2611. 		M15_THREAD_CONVO_IN_GARAGE = INVALID_THREAD_HANDLE 
  2612. 		m15_unload_convo_set(M15_convo.pr_center_garage) 
  2613. 	end 
  2614. 	 
  2615. 	if M15_THREAD_CONVO_TRUCK_FOUND ~= INVALID_THREAD_HANDLE then 
  2616. 		thread_kill(M15_THREAD_CONVO_TRUCK_FOUND) 
  2617. 		M15_THREAD_CONVO_TRUCK_FOUND = INVALID_THREAD_HANDLE 
  2618. 		m15_unload_convo_set(M15_convo.chase_found_truck_in_tank) 
  2619. 		m15_unload_convo_set(M15_convo.chase_found_truck) 
  2620. 	end 
  2621. 	 
  2622. 	if M15_THREAD_CONVO_DONT_USE_CANNON ~= INVALID_THREAD_HANDLE then 
  2623. 		thread_kill(M15_THREAD_CONVO_DONT_USE_CANNON) 
  2624. 		M15_THREAD_CONVO_DONT_USE_CANNON = INVALID_THREAD_HANDLE 
  2625. 	end 
  2626. end 
  2627.  
  2628. function m15_convo_to_pr_center() 
  2629. 	m15_play_audio_set(M15_convo.to_pr_center) 
  2630. 	M15_THREAD_CONVO_TO_PR_CENTER = INVALID_THREAD_HANDLE 
  2631. end 
  2632.  
  2633. function m15_convo_pr_center() 
  2634. 	m15_play_audio_set(M15_convo.pr_center_outside) 
  2635. 	audio_play_persona_line(NPC_PIERCE, "M15_Get_In_Building")	 
  2636. 	M15_THREAD_CONVO_PR_CENTER = INVALID_THREAD_HANDLE 
  2637. end 
  2638.  
  2639. function m15_convo_in_lobby() 
  2640.  
  2641. 	-- Play the conversation that happens when you first enter the lobby. 
  2642. 	m15_play_audio_set(M15_convo.pr_center_lobby) 
  2643. 	 
  2644. 	-- wait for the very last wave. 
  2645. 	while (M15_waves.lobby_decker.num_remaining + M15_waves.lobby_stag.num_remaining) > 1 do 
  2646. 		thread_yield() 
  2647. 	end 
  2648. 	 
  2649. 	-- Play the conversation to prompt you to leave the lobby. 
  2650. 	m15_play_audio_set(M15_convo.go_to_garage) 
  2651. 	 
  2652. 	m15_cleanup_audio_threads() 
  2653. 	M15_THREAD_CONVO_IN_LOBBY = INVALID_THREAD_HANDLE 
  2654. end 
  2655.  
  2656. function m15_convo_in_garage() 
  2657. 	m15_play_audio_set(M15_convo.pr_center_garage) 
  2658. 	M15_THREAD_CONVO_IN_GARAGE = INVALID_THREAD_HANDLE 
  2659. end 
  2660.  
  2661. function m15_convo_truck_found() 
  2662. 	if m15_player_is_in_a_tank() then 
  2663. 		m15_play_audio_set(M15_convo.chase_found_truck_in_tank) 
  2664. 	end 
  2665.  
  2666. 	m15_play_audio_set(M15_convo.chase_found_truck) 
  2667. 	M15_THREAD_CONVO_TRUCK_FOUND = INVALID_THREAD_HANDLE 
  2668. end 
  2669.  
  2670. function m15_convo_player_used_cannon_on_truck() 
  2671. 	--message("Kinzie: I said don't use the cannon. Use your minigun!", 4.0) 
  2672. 	-- Give at brief grace period to allow the player to hear Kinzie's warning 
  2673. 	on_take_damage("", VEHICLE_SUPER_COMPUTER) 
  2674. 	delay(2.0) 
  2675. 	on_take_damage("m15_vehicle_damaged", VEHICLE_SUPER_COMPUTER) 
  2676. 	 
  2677. 	message("M15_MSG_USE_ALT_FIRE", 8.0) 
  2678. 	 
  2679. 	M15_THREAD_CONVO_DONT_USE_CANNON = INVALID_THREAD_HANDLE 
  2680. end 
  2681.  
  2682.  
  2683. -- Check to see if all the tires have been destroyed 
  2684. -- 
  2685. function m15_thread_tire_check() 
  2686. 	while true do 
  2687. 		local n_tires_left = vehicle_tire_indicators_alive(VEHICLE_SUPER_COMPUTER) 
  2688. 		 
  2689. 		if n_tires_left == 0 then 
  2690. 			m15_music("M15_music_truck_chase_End") 
  2691. 			-- Forcefully stop the vehicle in its tracks 
  2692. 			vehicle_speed_cancel(VEHICLE_SUPER_COMPUTER) 
  2693. 			vehicle_stop(VEHICLE_SUPER_COMPUTER, true) 
  2694. 			 
  2695. 			m15_vehicle_remove_marker() 
  2696.  
  2697. 			mission_end_success("m15", M15_CUTSCENE_MISSION_OUTRO, {M15_NAV_START[1], M15_NAV_START[2]}) 
  2698. 		end 
  2699. 		 
  2700. 		thread_yield() 
  2701. 	end 
  2702. end 
  2703.  
  2704.  
  2705.  
  2706.  
  2707. function m15_thread_chase_rubber_band() 
  2708. 	 
  2709. 	while true do 
  2710. 		local dist = get_dist_closest_player_to_object(VEHICLE_SUPER_COMPUTER) - RUBBER_BAND_CLOSE_DIST 
  2711. 		local dist_diff = (RUBBER_BAND_FAR_DIST - RUBBER_BAND_CLOSE_DIST) 
  2712. 		local dist_pct = dist / dist_diff 
  2713. 		 
  2714. 		if (dist_pct < 0.0) then 
  2715. 			dist_pct = 0.0 
  2716. 		elseif (dist_pct > 1.0) then 
  2717. 			dist_pct = 1.0 
  2718. 		end 
  2719. 		 
  2720. 		local speed_diff = RUBBER_BAND_FAR_SPEED - RUBBER_BAND_CLOSE_SPEED 
  2721. 		local adjusted_speed = RUBBER_BAND_CLOSE_SPEED + (dist_pct * speed_diff) 
  2722. 		 
  2723. 		vehicle_speed_override(VEHICLE_SUPER_COMPUTER, adjusted_speed) 
  2724. 		delay(3.0) 
  2725. 	end 
  2726. 	 
  2727. end 
  2728.  
  2729. function m15_thread_elevator_manager() 
  2730. 	while true do 
  2731. 		for key, elevator in pairs(M15_elevators) do 
  2732. 			local dist_to_npc, npc = get_closest_npc_to_object(elevator.nav, M15_ELEVATOR_OPEN_PROXIMITY) 
  2733. 			local should_open = false 
  2734. 			 
  2735. 			if npc ~= "" then 
  2736. 				-- A script NPC is in range. Open the doors. 
  2737. 				should_open = true 
  2738. 			else 
  2739. 				-- A script NPC is not in range. Check to see if a player is nearby. 
  2740. 				local dist = get_dist(LOCAL_PLAYER, elevator.nav) 
  2741. 				if dist < M15_ELEVATOR_OPEN_PROXIMITY then 
  2742. 					should_open = true 
  2743. 				end 
  2744. 				 
  2745. 				if M15_in_coop == true then 
  2746. 					dist = get_dist(REMOTE_PLAYER, elevator.nav) 
  2747. 					if dist < M15_ELEVATOR_OPEN_PROXIMITY then 
  2748. 						should_open = true 
  2749. 					end 
  2750. 				end 
  2751. 			end 
  2752. 			 
  2753. 			if should_open then 
  2754. 				door_open(elevator.mover, false) 
  2755. 			else 
  2756. 				door_close(elevator.mover, true) 
  2757. 			end 
  2758. 		end 
  2759. 		 
  2760. 		thread_yield() 
  2761. 	end 
  2762. end 
  2763.