--[[
m18.lua
SR3 Mission Script
DATE: 08/12/10
AUTHOR: Matt.Gawalek
]]--
-- Debug flags --
-- Tweakable Parameters --
M18_tweak_values = {
ambient_plane_camera_shake = "cargo_plane_interior",
ambient_plane_camera_shake_intensity = 0.5,
escape_time_limit = 60000, -- miliseconds
escape_initial_cam_shake_amount = 1.5,
escape_looping_cam_shake_amount = 0.2,
escape_drunk_amount = 0.8,
escape_high_amount = 0.0,
escape_box_impulse_delay = { 0.1, 0.3 },
escape_box_impulse_amount = { 5, 75 },
skydive_looping_cam_shake_amount = 1.0,
skydive_collision_cam_shake_amount = 1.6,
enemy_tank_threat_level = 3, -- how many skydiving guys a tank is equivalent to when determining when to spawn reinforcements
-- Values to control when tank health warnings occur
debris_flow_min_speed_mult = 0.4,
debris_flow_time_to_max_speed = 5.0, -- how long it takes for the debris flow to go full speed
tank_streamers_tags = { "wingtip_vortex", "headlight_glare" },
-- Values to control how often random clouds appear
skydive_cloud_min_cooldown_time = 15.0,
skydive_cloud_max_cooldown_time = 25.0,
-- Values to control the tank bail out and stealing the skydiving enemy tank
tank_impact_start_player_fall_speed = 9.0,
tank_impact_force_dive_dist = 100.0, -- distance before tank impacts cargo plane, to force players into vertical dive (so they can see it)
steal_tank_fall_speed = 9.0,
steal_tank_player_fall_speed = 12.0,
steal_tank_stop_dive_elev = 20.0, -- distance above the steal tank the player should stop diving
steal_tank_ai_spread_mult = 0.01,
steal_tank_driver_refire_rates = { 3000, 2000, 1000 },
steal_tank_gunner_refire_rates = { 1000, 750, 500 },
steal_tank_success_radius = 35.0,
-- SMG to give the player while skydiving
player_smg = "SMG-Storm",
}
-- Debug switches for easy development
M18_debug_switches = {
skip_to_bail_out = true,
}
-- Groups --
M18_groups = {
-- Group for the tanks in the cargo plane
cargo_plane_tanks = {
name = "Group_cargo_plane_tanks 001",
tanks = { "veh_cargo_plane_tank 001", "veh_cargo_plane_tank 002", "veh_cargo_plane_tank 003", "veh_cargo_plane_tank 004", "veh_cargo_plane_tank 005", "veh_cargo_plane_tank 006" },
},
-- Group for all the script objects in the cargo plane interior
cargo_plane_interior = {
name = "Group_cargo_plane_interior 001",
chars = { "char_stag_catwalk 001", "char_stag_catwalk 002", "char_stag_door_guard 001", "char_stag_door_guard 002",
"char_stag_grunt_01_ 001", "char_stag_grunt_01_ 002", "char_stag_grunt_02_ 001", "char_stag_grunt_02_ 002",
"char_stag_grunt_04_ 001", "char_stag_grunt_04_ 002", "char_stag_grunt_06_ 001" },
door_guards = { "char_stag_door_guard 001", "char_stag_door_guard 002" },
sonic_guns = { "itm_sonic_gun 001", "itm_sonic_gun 002" },
dead_guys = { "char_stag_grunt_dead 001" },
-- The "squads" for the grunts
grunt_squads = {
catwalk = {
grunts = { "char_stag_catwalk 001", "char_stag_catwalk 002"},
anims = { "ATM User", "Browse Crouch" },
on_detection = "m18_grunt_detection_defend_cb",
},
grunt_squad_01 = {
grunts = { "char_stag_grunt_01_ 001", "char_stag_grunt_01_ 002" },
anims = { "Smoker A", "Bus Loiter B" },
on_detection = "m18_grunt_detection_attack_immediate_cb",
},
grunt_squad_02 = {
grunts = { "char_stag_grunt_02_ 001", "char_stag_grunt_02_ 002" },
anims = { "Bus Loiter B", "Smoker B" },
on_detection = "m18_grunt_detection_defend_cb",
},
grunt_squad_04 = {
grunts = { "char_stag_grunt_04_ 001", "char_stag_grunt_04_ 002" },
anims = { "Smoker B", "Smoker C" },
on_detection = "m18_grunt_detection_defend_cb",
},
grunt_squad_06 = {
grunts = { "char_stag_grunt_06_ 001" },
anims = { "Bus Loiter B", "Bench Sit Hunched", "Bench Sit", },
on_detection = "m18_grunt_detection_defend_cb",
},
},
},
-- STAG 'reinforcements'
stag_reinf = {
name = "group_stag_reinf 001",
chars = { "char_stag_reinf 001", "char_stag_reinf 002", "char_stag_reinf 003", "char_stag_reinf 004" },
},
-- The player's tank group
player_tank = {
name = "Group_player_tank 001",
vehicles = "veh_player_tank 001",
tank = "veh_player_tank 001",
fire_handle = -1,
exp_handle = -1,
contrail_handles = { },
},
-- The first wave of enemies during the tank free fall section
stag_free_fall_01 = {
name = "Group_stag_falling 001",
skydive_chars = {
{ name = "char_stag_diver_01_ 001", nav = "nav_stag_diver_dest_01_ 001", forced_dive = false },
{ name = "char_stag_diver_01_ 002", nav = "nav_stag_diver_dest_01_ 002", forced_dive = false },
{ name = "char_stag_diver_01_ 003", nav = "nav_stag_diver_dest_01_ 003", forced_dive = false },
{ name = "char_stag_diver_01_ 004", nav = "nav_stag_diver_dest_01_ 004", forced_dive = false },
{ name = "char_stag_diver_01_ 005", nav = "nav_stag_diver_dest_01_ 005", forced_dive = false },
{ name = "char_stag_diver_01_ 006", nav = "nav_stag_diver_dest_01_ 006", forced_dive = false },
{ name = "char_stag_diver_01_ 007", nav = "nav_stag_diver_dest_01_ 007", forced_dive = false },
{ name = "char_stag_diver_01_ 008", nav = "nav_stag_diver_dest_01_ 008", forced_dive = false },
},
},
-- The second wave of enemies during the tank free fall section
stag_free_fall_02 = {
name = "Group_stag_falling 002",
skydive_chars = {
{ name = "char_stag_diver_02_ 001", nav = "nav_stag_diver_dest_02_ 001", forced_dive = false },
{ name = "char_stag_diver_02_ 002", nav = "nav_stag_diver_dest_02_ 002", forced_dive = false },
{ name = "char_stag_diver_02_ 003", nav = "nav_stag_diver_dest_02_ 003", forced_dive = false },
{ name = "char_stag_diver_02_ 004", nav = "nav_stag_diver_dest_02_ 004", forced_dive = false },
{ name = "char_stag_diver_02_ 005", nav = "nav_stag_diver_dest_02_ 005", forced_dive = false },
{ name = "char_stag_diver_02_ 006", nav = "nav_stag_diver_dest_02_ 006", forced_dive = false },
},
-- Group the objects for each enemy tank together
tank_groups = {
tank_01 = {
tank = "veh_stag_tank_02_ 001",
chars = { "char_stag_tank_driver_02_ 001", "char_stag_tank_gunner_02_ 001" },
orient = "nav_stag_tank_02_ 001",
dest = "nav_stag_tank_dest_02_ 001",
fire_handle = -1,
exp_handle = -1,
contrail_handles = { },
thread_id = -1,
},
},
},
-- The third wave of enemies during the tank free fall section
stag_free_fall_03 = {
name = "Group_stag_falling 003",
skydive_chars = {
{ name = "char_stag_diver_03_ 001", nav = "nav_stag_diver_dest_03_ 001", forced_dive = false },
{ name = "char_stag_diver_03_ 002", nav = "nav_stag_diver_dest_03_ 002", forced_dive = false },
{ name = "char_stag_diver_03_ 003", nav = "nav_stag_diver_dest_03_ 003", forced_dive = false },
{ name = "char_stag_diver_03_ 004", nav = "nav_stag_diver_dest_03_ 004", forced_dive = false },
{ name = "char_stag_diver_03_ 005", nav = "nav_stag_diver_dest_03_ 005", forced_dive = false },
{ name = "char_stag_diver_03_ 006", nav = "nav_stag_diver_dest_03_ 006", forced_dive = false },
{ name = "char_stag_diver_03_ 007", nav = "nav_stag_diver_dest_03_ 007", forced_dive = false },
},
},
-- The fourth wave of enemies during the tank free fall section
stag_free_fall_04 = {
name = "Group_stag_falling 004",
-- skydive_chars = {
-- { name = "char_stag_diver_04_ 001", nav = "nav_stag_diver_dest_04_ 001", forced_dive = false },
-- { name = "char_stag_diver_04_ 002", nav = "nav_stag_diver_dest_04_ 002", forced_dive = false },
-- { name = "char_stag_diver_04_ 003", nav = "nav_stag_diver_dest_04_ 003", forced_dive = false },
-- { name = "char_stag_diver_04_ 004", nav = "nav_stag_diver_dest_04_ 004", forced_dive = false },
-- { name = "char_stag_diver_04_ 005", nav = "nav_stag_diver_dest_04_ 005", forced_dive = false },
-- { name = "char_stag_diver_04_ 006", nav = "nav_stag_diver_dest_04_ 006", forced_dive = false },
-- { name = "char_stag_diver_04_ 007", nav = "nav_stag_diver_dest_04_ 007", forced_dive = false },
-- },
-- Group the objects for each enemy tank together
tank_groups = {
tank_01 = {
tank = "veh_stag_tank_04_ 001",
chars = { "char_stag_tank_driver_04_ 001", "char_stag_tank_gunner_04_ 001" },
orient = "nav_stag_tank_04_ 001",
dest = "nav_stag_tank_dest_04_ 001",
fire_handle = -1,
exp_handle = -1,
contrail_handles = { },
thread_id = -1,
},
tank_02 = {
tank = "veh_stag_tank_04_ 002",
chars = { "char_stag_tank_driver_04_ 002", "char_stag_tank_gunner_04_ 002" },
orient = "nav_stag_tank_04_ 002",
dest = "nav_stag_tank_dest_04_ 002",
fire_handle = -1,
exp_handle = -1,
contrail_handles = { },
thread_id = -1,
},
},
},
-- The fifth wave of enemies during the tank free fall section
stag_free_fall_05 = {
name = "Group_stag_falling 005",
-- Group the objects for each enemy tank together
tank_groups = {
tank_01 = {
tank = "veh_stag_tank_05_ 001",
chars = { "char_stag_tank_driver_05_ 001", "char_stag_tank_gunner_05_ 001" },
orient = "nav_stag_tank_05_ 001",
dest = "nav_stag_tank_dest_05_ 001",
fire_handle = -1,
exp_handle = -1,
contrail_handles = { },
thread_id = -1,
},
tank_02 = {
tank = "veh_stag_tank_05_ 002",
chars = { "char_stag_tank_driver_05_ 002", "char_stag_tank_gunner_05_ 002" },
orient = "nav_stag_tank_05_ 002",
dest = "nav_stag_tank_dest_05_ 002",
fire_handle = -1,
exp_handle = -1,
contrail_handles = { },
thread_id = -1,
},
},
},
-- The sixth wave of enemies during the tank free fall section
stag_free_fall_06 = {
name = "Group_stag_falling 006",
skydive_chars = {
{ name = "char_stag_diver_06_ 001", nav = "nav_stag_diver_dest_06_ 001", forced_dive = false },
{ name = "char_stag_diver_06_ 002", nav = "nav_stag_diver_dest_06_ 002", forced_dive = false },
{ name = "char_stag_diver_06_ 003", nav = "nav_stag_diver_dest_06_ 003", forced_dive = false },
{ name = "char_stag_diver_06_ 004", nav = "nav_stag_diver_dest_06_ 004", forced_dive = false },
{ name = "char_stag_diver_06_ 005", nav = "nav_stag_diver_dest_06_ 005", forced_dive = false },
{ name = "char_stag_diver_06_ 006", nav = "nav_stag_diver_dest_06_ 006", forced_dive = false },
},
},
-- The seventh wave of enemies during the tank free fall section
stag_free_fall_07 = {
name = "Group_stag_falling 007",
skydive_chars = {
{ name = "char_stag_diver_07_ 001", nav = "nav_stag_diver_dest_07_ 001", forced_dive = false },
{ name = "char_stag_diver_07_ 002", nav = "nav_stag_diver_dest_07_ 002", forced_dive = false },
{ name = "char_stag_diver_07_ 003", nav = "nav_stag_diver_dest_07_ 003", forced_dive = false },
{ name = "char_stag_diver_07_ 004", nav = "nav_stag_diver_dest_07_ 004", forced_dive = false },
},
tank_groups = {
tank_01 = {
tank = "veh_stag_tank_07_ 001",
chars = { "char_stag_tank_driver_07_ 001", "char_stag_tank_gunner_07_ 001" },
orient = "nav_stag_tank_07_ 001",
dest = "nav_stag_tank_dest_07_ 001",
fire_handle = -1,
exp_handle = -1,
contrail_handles = { },
thread_id = -1,
},
},
},
-- The first group of VTOLs that flyby the player's tank
stag_vtol_flyby_01 = {
name = "Group_stag_vtols 001",
-- Group the objects for each enemy VTOL
vtol_groups = {
vtol_01 = {
vtol = "veh_stag_vtol_01_ 001",
chars = { "char_stag_vtol_pilot_01_ 001" },
animation = "MAD18 Flyby A",
start_pos = "nav_stag_vtol_root_01_ 001",
speed_multiplier = 0.45,
delay = 0.0,
whoosh_trigger = 0.7,
thread_id = -1,
},
vtol_02 = {
vtol = "veh_stag_vtol_01_ 002",
chars = { "char_stag_vtol_pilot_01_ 002" },
animation = "MAD18 Flyby B",
start_pos = "nav_stag_vtol_root_01_ 002",
speed_multiplier = 0.45,
delay = 0.5,
whoosh_trigger = 0.5,
thread_id = -1,
},
vtol_03 = {
vtol = "veh_stag_vtol_01_ 003",
chars = { "char_stag_vtol_pilot_01_ 003" },
animation = "MAD18 Flyby C",
start_pos = "nav_stag_vtol_root_01_ 003",
speed_multiplier = 0.45,
delay = 1.0,
whoosh_trigger = 0.80,
thread_id = -1,
},
vtol_04 = {
vtol = "veh_stag_vtol_01_ 004",
chars = { "char_stag_vtol_pilot_01_ 004" },
animation = "MAD18 Flyby D",
start_pos = "nav_stag_vtol_root_01_ 004",
speed_multiplier = 0.45,
delay = 2.0,
whoosh_trigger = 0.8,
thread_id = -1,
},
},
-- Special VTOL group that collides with the player's tank
vtol_collide = {
vtol = "veh_stag_vtol_01_ 005",
chars = { "char_stag_vtol_pilot_01_ 005" },
animation = "MAD18 Flyby B",
start_pos = "nav_stag_vtol_root_01_ 005",
speed_multiplier = 0.30,
delay = 2.5,
whoosh_trigger = 0.5,
},
restricted_camera = "nav_vtol_flyby_camera 001",
},
-- The second group of VTOLs that flyby the player's tank
stag_vtol_flyby_02 = {
name = "Group_stag_vtols 002",
-- Group the objects for each enemy VTOL together
vtol_groups = {
vtol_01 = {
vtol = "veh_stag_vtol_02_ 001",
chars = { "char_stag_vtol_pilot_02_ 001" },
animation = "MAD18 Flyby C",
start_pos = "nav_stag_vtol_root_02_ 001",
speed_multiplier = 0.45,
delay = 0.0,
whoosh_trigger = 0.77,
thread_id = -1,
},
vtol_02 = {
vtol = "veh_stag_vtol_02_ 002",
chars = { "char_stag_vtol_pilot_02_ 002" },
animation = "MAD18 Flyby C",
start_pos = "nav_stag_vtol_root_02_ 002",
speed_multiplier = 0.45,
delay = 1.0,
whoosh_trigger = 0.79,
thread_id = -1,
},
vtol_03 = {
vtol = "veh_stag_vtol_02_ 003",
chars = { "char_stag_vtol_pilot_02_ 003" },
animation = "MAD18 Flyby C",
start_pos = "nav_stag_vtol_root_02_ 003",
speed_multiplier = 0.45,
delay = 1.5,
whoosh_trigger = 0.80,
thread_id = -1,
},
vtol_04 = {
vtol = "veh_stag_vtol_02_ 004",
chars = { "char_stag_vtol_pilot_02_ 004" },
animation = "MAD18 Flyby B",
start_pos = "nav_stag_vtol_root_02_ 004",
speed_multiplier = 0.45,
delay = 2.0,
whoosh_trigger = 0.46,
thread_id = -1,
},
vtol_05 = {
vtol = "veh_stag_vtol_02_ 005",
chars = { "char_stag_vtol_pilot_02_ 005" },
animation = "MAD18 Flyby B",
start_pos = "nav_stag_vtol_root_02_ 005",
speed_multiplier = 0.45,
delay = 2.5,
whoosh_trigger = 0.47,
thread_id = -1,
},
vtol_06 = {
vtol = "veh_stag_vtol_02_ 006",
chars = { "char_stag_vtol_pilot_02_ 006" },
animation = "MAD18 Flyby D",
start_pos = "nav_stag_vtol_root_02_ 006",
speed_multiplier = 0.45,
delay = 0.5,
whoosh_trigger = 0.76,
thread_id = -1,
},
vtol_07 = {
vtol = "veh_stag_vtol_02_ 007",
chars = { "char_stag_vtol_pilot_02_ 007" },
animation = "MAD18 Flyby D",
start_pos = "nav_stag_vtol_root_02_ 007",
speed_multiplier = 0.45,
delay = 3.0,
whoosh_trigger = 0.78,
thread_id = -1,
},
},
vtol_collide = {
vtol = "veh_stag_vtol_02_ 008",
chars = { "char_stag_vtol_pilot_02_ 008" },
animation = "MAD18 Flyby A",
start_pos = "nav_stag_vtol_root_02_ 008",
speed_multiplier = 0.33,
delay = 3.5,
whoosh_trigger = 0.68,
thread_id = -1,
},
restricted_camera = "nav_vtol_flyby_camera 002",
},
stag_dive_bombers_01 = {
name = "Group_stag_dive_bombers 001",
vtols = {
{
vtol = "veh_stag_dive_bomber 001",
chars = { "char_stag_dive_bomber 001" },
start_path = "path_stag_dive_bomber_01_ 001",
looping_path = "path_stag_dive_bomber_01_ 002",
thread_id = -1,
},
{
vtol = "veh_stag_dive_bomber 002",
chars = { "char_stag_dive_bomber 002" },
start_path = "path_stag_dive_bomber_02_ 001",
looping_path = "path_stag_dive_bomber_02_ 002",
thread_id = -1,
},
},
restricted_camera = "nav_vtol_dive_bomb_camera 001",
death_path = "path_stag_dive_bomber_death 001",
},
-- Group for the cargo plane formation that the player's tank smashes through
stag_cargo_plane = {
name = "Group_stag_cargo_plane 001",
planes = {
{ chars = { "char_stag_cargo_pilot 001" }, plane = "veh_stag_cargo_plane 001", path = "path_stag_cargo_plane 001", thread_id = INVALID_THREAD_HANDLE },
{ chars = { "char_stag_cargo_pilot 002" }, plane = "veh_stag_cargo_plane 002", path = "path_stag_cargo_plane 002", thread_id = INVALID_THREAD_HANDLE },
{ chars = { "char_stag_cargo_pilot 003" }, plane = "veh_stag_cargo_plane 003", path = "path_stag_cargo_plane 003", thread_id = INVALID_THREAD_HANDLE },
{ chars = { "char_stag_cargo_pilot 004" }, plane = "veh_stag_cargo_plane 004", path = "path_stag_cargo_plane 004", thread_id = INVALID_THREAD_HANDLE },
{ chars = { "char_stag_cargo_pilot 005" }, plane = "veh_stag_cargo_plane 005", path = "path_stag_cargo_plane 005", thread_id = INVALID_THREAD_HANDLE },
{ chars = { "char_stag_cargo_pilot 006" }, plane = "veh_stag_cargo_plane 006", path = "path_stag_cargo_plane 006", thread_id = INVALID_THREAD_HANDLE },
{ chars = { "char_stag_cargo_pilot 007" }, plane = "veh_stag_cargo_plane 007", path = "path_stag_cargo_plane 007", thread_id = INVALID_THREAD_HANDLE },
{ chars = { "char_stag_cargo_pilot 008" }, plane = "veh_stag_cargo_plane 008", path = "path_stag_cargo_plane 008", thread_id = INVALID_THREAD_HANDLE },
{ chars = { "char_stag_cargo_pilot 009" }, plane = "veh_stag_cargo_plane 009", path = "path_stag_cargo_plane 009", thread_id = INVALID_THREAD_HANDLE },
{ chars = { "char_stag_cargo_pilot 010" }, plane = "veh_stag_cargo_plane 010", path = "path_stag_cargo_plane 010", thread_id = INVALID_THREAD_HANDLE },
}
},
skydiving_tank = {
name = "Group_skydiving_tank 001",
tank_group = {
tank = "veh_skydiving_tank 001",
chars = { "char_skydiving_tank_driver 001", "char_skydiving_tank_gunner 001" },
orient = "nav_skydiving_tank_orient 001",
dest = "nav_skydiving_tank_pos 001",
fire_handle = -1,
exp_handle = -1,
contrail_handles = { },
},
},
}
-- Navpoints --
M18_navpoints = {
player_start_cargo_plane = { "nav_player_local_start 001", "nav_player_remote_start 001" },
player_start_escape = { "nav_player_local_start 002", "nav_player_remote_start 002" },
player_start_free_fall = { "nav_player_local_start 003", "nav_player_remote_start 003" },
player_end = { "nav_player_local_end 001", "nav_player_remote_end 001" },
turbulance_direction_01 = "nav_turbulance_direction 001",
cargo_dust = {
"vfx_dust_drop 001", "vfx_dust_drop 002", "vfx_dust_drop 003", "vfx_dust_drop 004", "vfx_dust_drop 005",
"vfx_dust_drop 006", "vfx_dust_drop 007", "vfx_dust_drop 008", "vfx_dust_drop 009", "vfx_dust_drop 010",
"vfx_dust_drop 011", "vfx_dust_drop 012"
},
cabin_door_marker = "nav_cabin_door 001",
cockpit_door_marker = "nav_cockpit_door 001",
gun_crate_orients = { "OpenCrate_Offset", "OpenCrate_Offset<001>", "OpenCrate_Offset<002>" },
grunt_catwalk_start = "nav_grunt_catwalk 001",
grunt_catwalk_positions = { "nav_grunt_catwalk_dest 001", "nav_grunt_catwalk_dest 002" },
cargo_door_ejection_point = "nav_door_ejection_point 001",
plane_box_turbulance = { "nav_plane_box_turbulance 001", "nav_plane_box_turbulance 002", "nav_plane_box_turbulance 003", "nav_plane_box_turbulance 004" },
player_tank_center_pos = "nav_player_tank_center",
player_tank_orient_01 = "nav_player_tank_orient 001",
player_tank_orient_02 = "nav_player_tank_orient 002",
player_tank_orient_03 = "nav_player_tank_orient 003",
player_tank_orient_04 = "nav_player_tank_orient 004",
cargo_plane_start_pos = "nav_stag_cargo_plane 001",
player_tank_fall_pos = "nav_player_tank_fall_pos 001",
debris_emitter_pos_01 = "nav_debris_flow_emitter 001",
debris_emitter_pos_02 = "nav_debris_flow_emitter 002",
debris_emitter_pos_03 = "nav_debris_flow_emitter 003",
}
M18_paths = {
cargo_plane_crash_02 = { "path_stag_cargo_plane_crash 001", "path_stag_cargo_plane_crash 002", "path_stag_cargo_plane_crash 003", "path_stag_cargo_plane_crash 004" },
}
-- Triggers --
M18_triggers = {
start_combat = "tgr_combat 001",
cabin_door = "tgr_cabin_door 001",
cabin_door_region = "tgr_cabin_door_destroy 001",
cockpit_door_region = "tgr_cockpit_door_destroy 001",
-- to_tank = "tgr_to_tank 001",
stumble_01 = "tgr_stumble 001",
stumble_02 = "tgr_stumble 002",
tank_region = "tgr_tank_region 001",
gun_crate_001 = "tgr_gun_crate 001",
gun_crate_002 = "tgr_gun_crate 002",
gun_crate_003 = "tgr_gun_crate 003",
falling_tank_01 = "tgr_falling_tank 001",
falling_tank_02 = "tgr_falling_tank 002",
falling_tank_03 = "tgr_falling_tank 003",
falling_tank_04 = "tgr_falling_tank 004",
}
-- Characters --
-- Vehicles --
-- Mesh Movers --
M18_movers = {
cockpit_door = "mov_cockpit_door 001",
cabin_door = "mov_cabin_door 001",
lower_door = "mov_lower_door 001",
cargo_bay_door = "mov_cargo_bay_door 001",
gun_crate = { "mvr_stag_crate_open 001", "mvr_stag_crate_open 002", "mvr_stag_crate_open 003" },
plane_boxes_01 = {
{ box = "mov_plane_box_01_ 001", launch_dir = "nav_plane_box_01_ 001", impulse = 1500, delay = 0.4 },
{ box = "mov_plane_box_01_ 002", launch_dir = "nav_plane_box_01_ 002", impulse = 200, delay = 0.1 },
{ box = "mov_plane_box_01_ 003", launch_dir = "nav_plane_box_01_ 003", impulse = 2000, delay = 0.4 },
{ box = "mov_plane_box_01_ 004", launch_dir = "nav_plane_box_01_ 004", impulse = 200, delay = 0.3 },
{ box = "mov_plane_box_01_ 005", launch_dir = "nav_plane_box_01_ 005", impulse = 200, delay = 0.2 },
{ box = "mov_plane_box_01_ 006", launch_dir = "nav_plane_box_01_ 006", impulse = 200, delay = 0.3 },
{ box = "mov_plane_box_01_ 007", launch_dir = "nav_plane_box_01_ 007", impulse = 200, delay = 0.1 },
{ box = "mov_plane_box_01_ 008", launch_dir = "nav_plane_box_01_ 008", impulse = 200, delay = 0.3 },
{ box = "mov_plane_box_02_ 001", launch_dir = "nav_plane_box_02_ 001", impulse = 2000, delay = 0.2 },
{ box = "mov_plane_box_02_ 002", launch_dir = "nav_plane_box_02_ 002", impulse = 250, delay = 0.4 },
{ box = "mov_plane_box_03_ 001", launch_dir = "nav_plane_box_03_ 001", impulse = 1200, delay = 0.3 },
{ box = "mov_plane_box_03_ 002", launch_dir = "nav_plane_box_03_ 002", impulse = 200, delay = 0.2 },
{ box = "mov_plane_box_03_ 003", launch_dir = "nav_plane_box_03_ 003", impulse = 200, delay = 0.5 },
{ box = "mov_plane_box_03_ 004", launch_dir = "nav_plane_box_03_ 004", impulse = 200, delay = 0.3 },
{ box = "mov_plane_box_03_ 005", launch_dir = "nav_plane_box_03_ 005", impulse = 200, delay = 0.4 },
{ box = "mov_plane_box_03_ 006", launch_dir = "nav_plane_box_03_ 006", impulse = 200, delay = 0.4 },
{ box = "mov_plane_box_03_ 007", launch_dir = "nav_plane_box_03_ 007", impulse = 2000, delay = 0.1 },
},
free_fall_debris = {
"mov_free_fall_debris 001", "mov_free_fall_debris 002", "mov_free_fall_debris 003", "mov_free_fall_debris 004", "mov_free_fall_debris 005",
"mov_free_fall_debris 006", "mov_free_fall_debris 007", "mov_free_fall_debris 008", "mov_free_fall_debris 009", "mov_free_fall_debris 010",
"mov_free_fall_debris 011", "mov_free_fall_debris 012", "mov_free_fall_debris 013", "mov_free_fall_debris 014", "mov_free_fall_debris 015",
"mov_free_fall_debris 016", "mov_free_fall_debris 017", "mov_free_fall_debris 018", "mov_free_fall_debris 019", "mov_free_fall_debris 020",
"mov_free_fall_debris 021", "mov_free_fall_debris 022", "mov_free_fall_debris 023", "mov_free_fall_debris 024", "mov_free_fall_debris 025",
"mov_free_fall_debris 026", "mov_free_fall_debris 027", "mov_free_fall_debris 028", "mov_free_fall_debris 029", "mov_free_fall_debris 030",
"mov_free_fall_debris 031", "mov_free_fall_debris 032", "mov_free_fall_debris 033", "mov_free_fall_debris 034", "mov_free_fall_debris 035",
"mov_free_fall_battlebox 001", "mov_free_fall_battlebox 002", "mov_free_fall_battlebox 003", "mov_free_fall_battlebox 004", "mov_free_fall_battlebox 005",
"mov_free_fall_battlebox 006", "mov_free_fall_battlebox 007", "mov_free_fall_battlebox 008", "mov_free_fall_battlebox 009", "mov_free_fall_battlebox 010",
"mov_free_fall_battlebox 011", "mov_free_fall_battlebox 012",
},
free_fall_debris_02 = {
"mov_free_fall_debris_02 001", "mov_free_fall_debris_02 002", "mov_free_fall_debris_02 003", "mov_free_fall_debris_02 004", "mov_free_fall_debris_02 005",
"mov_free_fall_debris_02 006", "mov_free_fall_debris_02 007", "mov_free_fall_debris_02 008", "mov_free_fall_debris_02 009", "mov_free_fall_debris_02 010",
"mov_free_fall_debris_02 011", "mov_free_fall_debris_02 012", "mov_free_fall_debris_02 013", "mov_free_fall_debris_02 014", "mov_free_fall_debris_02 015",
"mov_free_fall_debris_02 016", "mov_free_fall_debris_02 017", "mov_free_fall_debris_02 018", "mov_free_fall_debris_02 019", "mov_free_fall_debris_02 020",
"mov_free_fall_debris_02 021", "mov_free_fall_debris_02 022", "mov_free_fall_debris_02 023", "mov_free_fall_debris_02 024", "mov_free_fall_debris_02 025",
"mov_free_fall_debris_02 026", "mov_free_fall_debris_02 027", "mov_free_fall_debris_02 028", "mov_free_fall_debris_02 029", "mov_free_fall_debris_02 030",
"mov_free_fall_debris_02 031", "mov_free_fall_debris_02 032", "mov_free_fall_debris_02 033", "mov_free_fall_debris_02 034", "mov_free_fall_debris_02 035",
--[[
"mov_free_fall_battlebox_02 001", "mov_free_fall_battlebox_02 002", "mov_free_fall_battlebox_02 003", "mov_free_fall_battlebox_02 004", "mov_free_fall_battlebox_02 005",
"mov_free_fall_battlebox_02 006", "mov_free_fall_battlebox_02 007", "mov_free_fall_battlebox_02 008", "mov_free_fall_battlebox_02 009", "mov_free_fall_battlebox_02 010",
"mov_free_fall_battlebox_02 011", "mov_free_fall_battlebox_02 012",
--]]
},
wreckage_debris = {
"mov_wreckage_debris 001", "mov_wreckage_debris 002", "mov_wreckage_debris 003", "mov_wreckage_debris 004", "mov_wreckage_debris 005",
"mov_wreckage_debris 006", "mov_wreckage_debris 007", "mov_wreckage_debris 008", "mov_wreckage_debris 009", "mov_wreckage_debris 010",
"mov_wreckage_debris 011", "mov_wreckage_debris 012", "mov_wreckage_debris 013", "mov_wreckage_debris 014", "mov_wreckage_debris 015",
"mov_wreckage_debris 016", "mov_wreckage_debris 017", "mov_wreckage_debris 018", "mov_wreckage_debris 019", "mov_wreckage_debris 020",
"mov_wreckage_debris 021", "mov_wreckage_debris 022", "mov_wreckage_debris 023", "mov_wreckage_debris 024", "mov_wreckage_debris 025",
"mov_wreckage_debris 026", "mov_wreckage_debris 027", "mov_wreckage_debris 028", "mov_wreckage_debris 029", "mov_wreckage_debris 030",
"mov_wreckage_debris 031", "mov_wreckage_debris 032", "mov_wreckage_debris 033", "mov_wreckage_debris 034", "mov_wreckage_debris 035",
"mov_wreckage_debris 036", "mov_wreckage_debris 037", "mov_wreckage_debris 038", "mov_wreckage_debris 039", "mov_wreckage_debris 040",
"mov_wreckage_debris 041", "mov_wreckage_debris 042", "mov_wreckage_debris 043", "mov_wreckage_debris 044", "mov_wreckage_debris 045",
"mov_wreckage_debris 046", "mov_wreckage_debris 047", "mov_wreckage_debris 048", "mov_wreckage_debris 049", "mov_wreckage_debris 050",
"mov_wreckage_debris 051", "mov_wreckage_debris 052", "mov_wreckage_debris 053", "mov_wreckage_debris 054", "mov_wreckage_debris 055",
"mov_wreckage_debris 056", "mov_wreckage_debris 057", "mov_wreckage_debris 058", "mov_wreckage_debris 059", "mov_wreckage_debris 060",
"mov_wreckage_debris 061", "mov_wreckage_debris 062", "mov_wreckage_debris 063", "mov_wreckage_debris 064", "mov_wreckage_debris 065",
}
}
-- Text --
M18_objectives = {
get_to_the_cockpit = {
tag = "M18_OBJ_GET_TO_COCKPIT",
icon = OI_ASSET_USE,
},
search_for_gun = {
tag = "M18_OBJ_SEARCH_FOR_GUN",
icon = OI_ASSET_USE,
},
destroy_cockpit = {
tag = "M18_OBJ_DESTROY_COCKPIT",
icon = OI_ASSET_KILL,
},
escape_in_tank = {
tag = "M18_OBJ_ESCAPE_IN_TANK",
icon = OI_ASSET_LOCATION,
},
survive = {
tag = "M18_OBJ_SURVIVE",
icon = OI_ASSET_KILL,
},
bail_out_of_tank = {
tag = "M18_OBJ_BAIL_FROM_TANK",
icon = OI_ASSET_USE,
},
kill_tank_gunner = {
tag = "M18_OBJ_KILL_THE_GUNNER",
icon = OI_ASSET_KILL,
},
hijack_tank = {
tag = "M18_OBJ_HIJACK_TANK",
icon = OI_ASSET_LOCATION,
},
}
M18_placholder_dialog = {
intro_lines = {
{ text = "Player: I'm in.", duration = 1.5 },
{ text = "Viola: Took you long enough.", duration = 2.0 },
{ text = "Player: How about you jump out of the plane next time.", duration = 5.0 },
{ text = "Viola: ... Just keep your eyes open.", duration = 1.0 },
{ text = "Viola: STAG's probably got some gear onboard that you could use.", duration = 4.0 },
{ text = "Player: I do need a new microwave.", duration = 1.0 },
{ text = "Viola: [[sigh]...", duration = 5.0 },
},
found_gun = {
{ text = "Player: What do we have here?", duration = 2.0 },
{ text = "Viola: What did you find?", duration = 1.5 },
{ text = "Player: Not quite sure. Definitely beats the hell outa a microwave!", duration = 4.0 },
{ text = "Viola: Well, whatever it is, be careful with it.", duration = 4.0 },
},
door_open_no_gun = {
{ text = "Player: The door won't budge.", duration = 2.0 },
{ text = "Viola: Well, then find something to blow it open. Isn't that your specialty?", duration = 3.0 },
{ text = "Player: You don't need to ask me twice.", duration = 3.0 },
},
door_open_with_gun = {
{ text = "Player: The door won't budge.", duration = 2.0 },
{ text = "Viola: Well, then find something to blow it open.", duration = 4.0 },
{ text = "Viola: Maybe your new microwave will do the trick.", duration = 3.0 },
{ text = "Player: I know one way to find out.", duration = 2.5 },
{ text = "Viola: Don't do anything stupid, now.", duration = 2.0 },
{ text = "Player: You know me too well.", duration = 3.0 },
},
aquired_gun = {
{ text = "Player: What do we have here?", duration = 2.0 },
{ text = "Viola: What did you find?", duration = 1.5 },
{ text = "Player: Not quite sure. Definitely beats the hell outa a microwave!", duration = 4.0 },
{ text = "Viola: Maybe your new microwave will do the trick on the door.", duration = 1.5 },
{ text = "Player: I know one way to find out.", duration = 2.5 },
{ text = "Viola: Don't do anything stupid, now.", duration = 2.0 },
{ text = "Player: You know me too well.", duration = 3.0 },
},
door_damaged_no_gun = {
{ text = "Player: This fucking door is solid.", duration = 2.0 },
{ text = "Viola: Take a look around - there's got to be something that can open the door.", duration = 3.0 },
{ text = "Viola: You are on a STAG military plane after all.", duration = 2.0 },
{ text = "Player: Yeah, yeah.", duration = 3.0 },
},
door_damaged_with_gun = {
{ text = "Player: Fuck this door!", duration = 2.0 },
{ text = "Viola: Perhaps it's time to try that new microwave you found.", duration = 3.0 },
},
too_far_away = {
{
{ text = "Player: This sonic gun fucking sucks!", duration = 3.0 },
{ text = "Viola: Maybe you're just too far away.", duration = 2.0 },
{ text = "Viola: Sound energy dissipates quickly, you know.", duration = 4.0 },
{ text = "Player: What is this? The fucking Learning channel?", duration = 2.0 },
{ text = "Player: Do you want to open the door, or not?", duration = 2.0 },
},
{
{ text = "Player: This gun is fucking worthless!", duration = 3.0 },
{ text = "Viola: Try getting closer to the door.", duration = 2.0 },
},
},
door_destroyed = {
{ text = "Player: Fucking Shit!", duration = 2.0 },
{ text = "Viola: What's wrong", duration = 1.0 },
{ text = "Player: I'm fine... but this plane is fucked!", duration = 1.0 },
{ text = "Viola: You need to get out of there, NOW!", duration = 1.0 },
{ text = "Player: I've got an idea!", duration = 2.0 },
{ text = "Viola: Wait, what are you about to do?", duration = 6.0 },
{ text = "Viola: Shit!", duration = 1.0 },
},
}
-- Help Text
M18_help_text = {
get_closer_to_door = "M18_HELP_GET_CLOSER_TO_DOOR",
clearing_debris = "M18_HELP_CLEARING_DEBRIS",
}
-- Threads --
M18_threads = {
dialog = -1,
place_holder_dialog = -1,
box_jiggle = -1,
plane_dust = -1,
debris_flow_speed = -1,
random_clouds = -1,
vtol_collide = -1,
local_player_steal_tank = -1,
remote_player_steal_tank = -1,
cargo_plane_crash_02 = -1,
}
-- Checkpoints --
M18_checkpoints = {
start = MISSION_START_CHECKPOINT, -- defined in ug_lib.lua.
cargo_plane_escape = "m18_checkpoint_escape",
tank_free_fall = "m18_checkpoint_free_fall",
dive_bombers = "m18_checkpoint_dive_bombers",
debug_bail_out = "m18_debug_checkpoint_bail_out",
}
-- Cutscenes --
M18_cutscenes = {
mission_intro = "18_in",
tank_zscene = "18_Z01",
mission_outro = "18_out",
}
-- Conversations --
M18_convo = {
mission_start = {
name = "M18_Mission_Start",
is_convo = true, load_direct = false, in_queue = false, started = false, completed = false, ended = false,
},
plane_combat = {
name = "M18_Plane_Combat",
is_convo = true, load_direct = false, in_queue = false, started = false, completed = false, ended = false,
},
cockpit_locked_no_gun = {
name = "M18_Cockpit_Door",
is_convo = true, load_direct = false, in_queue = false, started = false, completed = false, ended = false,
},
falling_out_bad = {
name = "M18_Falling_Out_Is_Bad",
is_convo = true, load_direct = false, in_queue = false, started = false, completed = false, ended = false,
},
sonic_gun_failed_01 = {
name = "M18_Not_Working_Door_1",
is_convo = true, load_direct = false, in_queue = false, started = false, completed = false, ended = false,
},
sonic_gun_failed_02 = {
name = "M18_Not_Working_Door_2",
is_convo = true, load_direct = false, in_queue = false, started = false, completed = false, ended = false,
},
sonic_gun = {
name = "M18_Sonic_Gun",
is_convo = true, load_direct = false, in_queue = false, started = false, completed = false, ended = false,
},
not_close_enough = {
name = "M18_Not_Close_Enough",
is_convo = true, load_direct = false, in_queue = false, started = false, completed = false, ended = false,
},
cockpit_gone = {
name = "M18_Cockpit_Gone",
is_convo = true, load_direct = false, in_queue = false, started = false, completed = false, ended = false,
},
gooing_people = {
name = "M18_Gooing_People_01",
is_convo = false, play_2d = false, character = LOCAL_PLAYER, in_queue = false, started = false, completed = false, ended = false,
},
blast_containers = {
name = "M18_Blast_Container_Aside",
is_convo = false, play_2d = false, character = LOCAL_PLAYER, in_queue = false, started = false, completed = false, ended = false,
},
damn_stumbles = {
name = "M18_Damn_Stumbles",
is_convo = false, play_2d = false, character = LOCAL_PLAYER, in_queue = false, started = false, completed = false, ended = false,
},
begin_drop = {
name = "M18_Beginning_Of_Tank_Drop",
is_convo = false, play_2d = false, character = LOCAL_PLAYER, in_queue = false, started = false, completed = false, ended = false,
},
vtol_hit_01 = {
name = "M18_VTOL_Hit_01",
is_convo = false, play_2d = false, character = LOCAL_PLAYER, in_queue = false, started = false, completed = false, ended = false,
},
falling_again = {
name = "M18_Falling_Yet_Again",
is_convo = false, play_2d = false, character = LOCAL_PLAYER, in_queue = false, started = false, completed = false, ended = false,
},
vtol_hit_02 = {
name = "M18_VTOL_Hit_02",
is_convo = false, play_2d = false, character = LOCAL_PLAYER, in_queue = false, started = false, completed = false, ended = false,
},
generic_falling_01 = {
name = "M18_Generic_Tank_01",
is_convo = false, play_2d = false, character = LOCAL_PLAYER, in_queue = false, started = false, completed = false, ended = false,
},
generic_falling_02 = {
name = "M18_Generic_Tank_02",
is_convo = false, play_2d = false, character = LOCAL_PLAYER, in_queue = false, started = false, completed = false, ended = false,
},
generic_falling_03 = {
name = "M18_Generic_Tank_03",
is_convo = false, play_2d = false, character = LOCAL_PLAYER, in_queue = false, started = false, completed = false, ended = false,
},
generic_falling_04 = {
name = "M18_Generic_Tank_04",
is_convo = false, play_2d = false, character = LOCAL_PLAYER, in_queue = false, started = false, completed = false, ended = false,
},
generic_falling_05 = {
name = "M18_Generic_Tank_05",
is_convo = false, play_2d = false, character = LOCAL_PLAYER, in_queue = false, started = false, completed = false, ended = false,
},
generic_falling_06 = {
name = "M18_Generic_Tank_06",
is_convo = false, play_2d = false, character = LOCAL_PLAYER, in_queue = false, started = false, completed = false, ended = false,
},
generic_falling_07 = {
name = "M18_Generic_Tank_07",
is_convo = false, play_2d = false, character = LOCAL_PLAYER, in_queue = false, started = false, completed = false, ended = false,
},
generic_falling_08 = {
name = "M18_Generic_Tank_08",
is_convo = false, play_2d = false, character = LOCAL_PLAYER, in_queue = false, started = false, completed = false, ended = false,
},
exit_tank = {
name = "M18_Exit_The_Tank_01",
is_convo = false, play_2d = false, character = LOCAL_PLAYER, in_queue = false, started = false, completed = false, ended = false,
},
steal_plane = {
name = "M18_Steal_Plane_01",
is_convo = false, play_2d = false, character = LOCAL_PLAYER, in_queue = false, started = false, completed = false, ended = false,
},
plane_blows_up = {
name = "M18_Plane_Blows_Up_01",
is_convo = false, play_2d = false, character = LOCAL_PLAYER, in_queue = false, started = false, completed = false, ended = false,
},
dive_through = {
name = "M18_Dive_Through_Plane_Wreck_01",
is_convo = false, play_2d = false, character = LOCAL_PLAYER, in_queue = false, started = false, completed = false, ended = false,
},
while_skydiving = {
name = "M18_While_Skydiving_01",
is_convo = false, play_2d = false, character = LOCAL_PLAYER, in_queue = false, started = false, completed = false, ended = false,
},
tank_health = {
{
name = "M18_Tank_Health_01",
is_convo = false, play_2d = false, character = LOCAL_PLAYER, in_queue = false, started = false, completed = false, ended = false,
},
{
name = "M18_Tank_Health_02",
is_convo = false, play_2d = false, character = LOCAL_PLAYER, in_queue = false, started = false, completed = false, ended = false,
},
{
name = "M18_Tank_Health_03",
is_convo = false, play_2d = false, character = LOCAL_PLAYER, in_queue = false, started = false, completed = false, ended = false,
},
},
}
-- Personas --
M18_personas = {
viola = {
name = "Suko",
persona_id = -1,
},
}
-- Audio Emitters --
M18_audio_emitters = {
plane_interior = {
"M18_interior_cargo_plane<001>",
"Cargo_rattles_a", "Cargo_rattles_a<002>", "Cargo_rattles_a<003>", "Cargo_rattles_a<004>", "Cargo_rattles_a<005>",
"Cargo_rattles_a<006>", "Cargo_rattles_a<007>", "Cargo_rattles_a<008>", "Cargo_rattles_a<009>", "Cargo_rattles_a<010>",
"Cargo_rattles_a<011>", "Cargo_rattles_a<012>", "Cargo_rattles_a<013>", "Cargo_rattles_a<014>", "Cargo_rattles_a<015>",
"Cargo_rattles_a<016>", "Cargo_rattles_a<017>", "Cargo_rattles_a<018>", "Cargo_rattles_a<019>", "Cargo_rattles_a<020>",
"Cargo_rattles_a<021>", "Cargo_rattles_a<022>", "Cargo_rattles_a<023>", "Cargo_rattles_a<024>",
"Cargo_rattles_b", "Cargo_rattles_b<001>", "Cargo_rattles_b<002>", "Cargo_rattles_b<003>", "Cargo_rattles_b<004>",
"Cargo_rattles_b<005>", "Cargo_rattles_b<006>", "Cargo_rattles_b<007>", "Cargo_rattles_b<008>", "Cargo_rattles_b<009>",
"Cargo_rattles_b<010>",
},
plane_crashing = {
"M18_plane_crash_cargo", "M18_interior_after_Explo<001>", "M18_alarm_klaxxon",
},
}
-- Audio Events --
M18_audio_events = {
kick_door = "M18_sfx_PC_kick_locked_door",
destroy_door = "M18_sfx_PC_smash_door",
destroy_cockpit = "M18_sfx_PC_destroy_cockpit",
plane_violent_shake = "M18_sfx_plane_violent_shake",
plane_shudder = "M18_sfx_plane_shudder",
skydiving_wind = "M18_amb_skydiving_wind",
vtol_flyby = "M18_sfx_VTOL_flybys",
vtol_whalla = "M18_VTOL_walla",
vtol_whalla_stop = "m18_VTOL_walla_STOP",
cargo_plane_flying = "m18_sfx_plane_fly_beneath",
cargo_plane_crashing = "m18_sfx_plane_plummet",
tank_hit_wing = "m18_sfx_tank_hit_plane",
cargo_plane_wing_groan = "m18_sfx_plane_wing_groan",
-- music --
music_start = "M18_music_mission_start",
music_plane_crashing = "M18_music_plane_crash",
music_skydive_start = "M18_music_tank_skydive",
music_bail_out = "M18_music_tank_bail_out",
music_mission_complete = "M18_music_tank_skydive_end",
music_stop = "M18_music_STOP",
music_escape_checkpoint = "M18_music_cargo_plane_checkpoint",
music_skydive_checkpoint = "M18_music_tank_skydive_checkpoint",
}
-- Script Interiors --
M18_interiors = {
skydiving_volume = "int_skydiving_volume 001",
}
-- HUD display states --
M18_hud_states = {
hide_minimap = -1,
}
-- List of enemy spawns in the free fall sections --
M18_free_fall_spawns = {
set_01 = {
{ group = M18_groups.stag_free_fall_01, min_threat_level = 4, max_duration = 20.0, line = "" },
{ group = M18_groups.stag_free_fall_02, min_threat_level = 5, max_duration = 20.0, line = M18_convo.generic_falling_01 },
{ group = M18_groups.stag_free_fall_03, min_threat_level = 6, max_duration = 20.0, line = "" },
{ group = M18_groups.stag_free_fall_04, min_threat_level = 0, max_duration = 20.0, line = M18_convo.generic_falling_03 },
},
set_02 = {
{ group = M18_groups.stag_free_fall_05, min_threat_level = 2, max_duration = 20.0, line = "" },
{ group = M18_groups.stag_free_fall_06, min_threat_level = 5, max_duration = 20.0, line = M18_convo.generic_falling_05 },
{ group = M18_groups.stag_free_fall_07, min_threat_level = 0, max_duration = 20.0, line = "" },
},
}
-- Other --
M18_runtime = {
num_grunts_to_reach_catwalk = 0,
-- Counts for the first group of enemies
num_free_fall_chars_alive = 0,
num_free_fall_vehicles_alive = 0,
debris_flow_handle = 0,
debris_flow_handle_02 = 0,
wreckage_debris_flow_handle = 0,
debirs_fire_handles = { },
convo_queue = {
playing = {
thread_id = -1,
conv_handle = INVALID_CONVERSATION_HANDLE,
convo_table = nil,
},
list = {},
size = 0,
},
skydiving_tanks = { },
}
-- Mission Scripting Flags --
M18_flags = {
sonic_gun_failed_once = false,
sonic_gun_aquired = false,
played_too_far_away_conversation = false,
cabin_door_open_attempted = false,
in_door_destruction_region_local = false,
in_door_destruction_region_remote = false,
in_cabin_destruction_region_local = false,
in_cabin_destruction_region_remote = false,
cabin_door_destroyed = false,
cockpit_door_destroyed = false,
triggered_tank_region = false,
steal_tank_gunner_killed = false,
}
-- VFX --
M18_vfxs = {
cockpit_door_explosion = { nav = "vfx_cockpit_door_exp 001", handle = -1 },
cargo_plane_interior_explosion = { nav = "vfx_plane_interior_exp 001", handle = -1 },
stag_cargo_plane_explosion = { nav = "vfx_cargo_plane_exp 001", handle = -1 },
plane_wind = { nav = "vfx_plane_cabin_wind 001", handle = -1 },
bottom_clouds = { nav = "vfx_bottom_clouds 001", handle = -1 },
clouds = { nav = "vfx_clouds 001", handle = -1 },
city = { nav = "vfx_city 001", handle = -1 },
random_clouds = { nav = "vfx_random_clouds 001", handle = -1 },
random_clouds_remote = { nav = "vfx_random_clouds 001", handle = -1 },
tank_streamers = { nav = "vfx_tank_streamers 001", handle = -1 },
debris_fire = { nav = "vfx_fire_debris 001", handle = -1 },
car_exp = { nav = "vfx_car_explosion 001", handle = -1 },
cargo_plane_smoke = { nav = "vfx_cargo_plane_smoke 001", handle = -1 },
}
local M18_CONVO_PLAY_LAST = 0
local M18_CONVO_PLAY_NEXT = 1
local M18_CONVO_PLAY_IMMEDIATE = 2
-- *************************
--
-- Standard functions
--
-- *************************
-- This is the primary entry point for the mission, and is responsible for starting up the mission
-- at the specified checkpoint.
-- CALLED FROM CODE
--
-- m18_checkpoint: The checkpoint the mission should begin at
-- is_restart: TRUE if the mission is restarting, FALSE otherwise
--
function m18_start(m18_checkpoint, is_restart)
-- Do the initial fade-out
mission_start_fade_out(0.0)
city_zone_swap("m18", true)
city_zone_swap("m18fx", true)
-- Dismiss the players' party
party_dismiss_all()
-- Check if this mission starting from the beginning
if (m18_checkpoint == M18_checkpoints.start) then
if (is_restart == false) then
-- First time playing mission
-- Play an intro cutscene???
if (M18_cutscenes.mission_intro ~= "") then
cutscene_play(M18_cutscenes.mission_intro, nil, M18_navpoints.player_start_cargo_plane, false)
--bink_play(M18_cutscenes.mission_intro)
end
else
teleport_coop(M18_navpoints.player_start_cargo_plane[1], M18_navpoints.player_start_cargo_plane[2])
end
end
-- Handle mission initialization for the current checkpoint
m18_initialize(m18_checkpoint)
-- Start fading in
mission_start_fade_in()
-- Run the mission from the current checkpoint
m18_run(m18_checkpoint)
end
-- This is the primary function responsible for cleaning up the entire mission
-- CALLED FROM CODE (+++MUST RETURN IMMEDIATLY+++)
--
function m18_cleanup()
--[[ INSERT ANY MISSION SPECIFIC CLEAN-UP ]]--
-- Call the cleanup helper for the free fall section of the mission
m18_cleanup_cargo_plane_open_cockpit()
m18_cleanup_cargo_plane_interior()
m18_cleanup_tank_free_fall()
-- Cleanup any groups that are still loaded
for i, group in pairs(M18_groups) do
if (group_is_loaded(group.name) == true) then
group_destroy(group.name)
end
end
-- Stop any active threads
for i, thread in pairs(M18_threads) do
if (thread ~= -1 and thread_check_done(thread) == false) then
thread_kill(thread)
end
end
for i, plane in pairs(M18_groups.stag_cargo_plane.planes) do
if (thread_check_done(plane.thread_id) == false) then
thread_kill(plane.thread_id)
end
end
-- Unload any loaded personas
for i, persona in pairs(M18_personas) do
if (persona.persona_id ~= -1) then
audio_persona_remove_2d(persona.persona_id)
persona.persona_id = -1
end
end
-- Make sure any VFX are cleaned up
for i, vfx in pairs(M18_vfxs) do
if (vfx.handle ~= -1) then
effect_stop(vfx.handle)
vfx.handle = -1
end
end
-- Kill the fire VFX on any wreckage debris
for i, effect_handle in pairs(M18_runtime.debirs_fire_handles) do
if (effect_handle ~= -1) then
effect_stop(effect_handle)
effect_handle = -1
end
end
-- Kill all the triggers
for i, trigger in pairs(M18_triggers) do
on_trigger("", trigger)
trigger_enable(trigger, false)
end
-- Remove the fake notoriety
hud_set_fake_notoriety("Police", false, 0)
-- Restore the HUD
for i, hud_state in pairs(M18_hud_states) do
if (hud_state ~= -1) then
hud_display_remove_state(hud_state)
hud_state = -1
end
end
-- Kill any playing conversation
m18_helper_conversation_kill_all()
-- Kill all the audio emitters
for i, emitter in pairs(M18_audio_emitters) do
if (type(emitter) == "table") then
for j, sub_emitter in pairs(emitter) do
audio_ambient_emitter_stop(sub_emitter)
end
else
audio_ambient_emitter_stop(emitter)
end
end
-- Clear any restricted camera
camera_restrict_set_active(false)
skydive_set_player_dive_fall_speed()
-- Reset the wind
wind_override_clear()
-- Remove all temporary weapons and re-enable the weapon radial
inv_weapon_remove_temporary(LOCAL_PLAYER, M18_tweak_values.player_smg)
inv_weapon_remove_temporary(REMOTE_PLAYER, M18_tweak_values.player_smg)
inv_weapon_disable_all_slots(false) -- enable
character_set_skydiving(LOCAL_PLAYER, false)
inv_weapon_remove_temporary(LOCAL_PLAYER, "Pistol-Gang")
clear_animation_state(LOCAL_PLAYER)
character_set_never_fall(LOCAL_PLAYER, false)
if (coop_is_active() == true) then
character_set_skydiving(REMOTE_PLAYER, false)
inv_weapon_remove_temporary(REMOTE_PLAYER, "Pistol-Gang")
clear_animation_state(REMOTE_PLAYER)
character_set_never_fall(REMOTE_PLAYER, false)
end
notoriety_reset("police")
-- Turn peds, vehicles, and action nodes back on
spawning_pedestrians(true)
spawning_vehicles(true)
action_nodes_enable(true)
city_zone_swap("m18", false)
city_zone_swap("m18fx", false)
end
-- Called when the mission has ended with success
-- CALLED FROM CODE (+++MUST RETURN IMMEDIATLY+++)
--
function m18_success()
local skip_teleport = true
m18_coop_skip(skip_teleport) -- do the stuff we'd do in the skip case
end
-- *************************
--
-- Local functions
--
-- *************************
-- Initialize the mission for the specified checkpoint
--
-- checkpoint: Checkpoint to initialize the mission to
--
function m18_initialize(checkpoint)
-- Set the mission author
set_mission_author("Matt.Gawalek")
-- Common initialization
m18_initialize_common()
-- Checkpoint specific initialization
m18_initialize_checkpoint(checkpoint)
end
-- ***************************************************
-- m18_initialize Helper Functions
-- ***************************************************
-- Handle any common initialization
--
function m18_initialize_common()
-- Load the persona for Viola
M18_personas.viola.persona_id = audio_persona_load_2d(M18_personas.viola.name)
-- Kick of a thread to process conversation VO
M18_threads.dialog = thread_new("m18_thread_process_conversations")
-- Hide the minimap
M18_hud_states.hide_minimap = hud_display_create_state()
hud_display_set_element(M18_hud_states.hide_minimap, HUD_ELEM_MINIMAP, HUD_FADE_HIDDEN)
hud_display_commit_state(M18_hud_states.hide_minimap)
-- Hide all the debris that will be spawned when the cargo plane explodes
for i, debris in pairs(M18_movers.wreckage_debris) do
mesh_mover_hide(debris)
end
-- Lock the cargo bay door
door_lock(M18_movers.cargo_bay_door, true)
-- Disable notoriety
notoriety_set_max("police", 0)
-- Turn off peds, vehicles, and action nodes
spawning_pedestrians(false)
spawning_vehicles(false)
action_nodes_enable(false)
-- Set the cancel warp locations
mission_set_cancel_warp_location(M18_navpoints.player_end[1], M18_navpoints.player_end[2])
end
-- Checkpoint specific initialization
--
-- checkpoint: The checkpoint to be initialized
function m18_initialize_checkpoint(checkpoint)
if (checkpoint == M18_checkpoints.start) then
-- Initialize the cargo plane interior
m18_initialize_cargo_plane_interior()
elseif (checkpoint == M18_checkpoints.cargo_plane_escape) then
-- Initialize the cargo plane escape sequence
m18_initialize_cargo_plane_escape()
-- Start the music at the right spot
audio_object_post_event(M18_audio_events.music_escape_checkpoint, nil, nil, LOCAL_PLAYER)
elseif (checkpoint == M18_checkpoints.tank_free_fall or checkpoint == M18_checkpoints.dive_bombers) then
-- Initialize the tank free falling
m18_initialize_tank_free_fall(true)
-- Start the music at the right spot
audio_object_post_event(M18_audio_events.music_skydive_checkpoint, nil, nil, LOCAL_PLAYER)
elseif (checkpoint == M18_checkpoints.debug_bail_out) then
-- Create the group for the cargo plane that the tank is going to smash into
group_create_hidden(M18_groups.stag_cargo_plane.name, true)
-- Initialize the tank free falling
m18_initialize_tank_free_fall()
skydive_setup_tank_bailout(1)
interior_disable_exterior(M18_interiors.skydiving_volume, false)
if (M18_vfxs.city.handle ~= -1) then
effect_stop(M18_vfxs.city.handle)
M18_vfxs.city.handle = -1
end
--[[
if (M18_vfxs.bottom_clouds.handle ~= -1) then
effect_stop(M18_vfxs.bottom_clouds.handle)
M18_vfxs.bottom_clouds.handle = -1
end
--]]
-- Start the music at the right spot
audio_object_post_event(M18_audio_events.music_skydive_checkpoint, nil, nil, LOCAL_PLAYER)
-- Make sure the player's tank is using the right orient
vehicle_skydiving_start(M18_groups.player_tank.tank, M18_navpoints.player_tank_orient_04)
vehicle_skydiving_move_to_do(M18_groups.player_tank.tank, M18_navpoints.player_tank_center_pos, 0.0, 2.0)
end
end
-- Common initialization for the cargo plane checkpoints
function m18_initialize_cargo_plane_common()
-- Change to the scripted camera to pull it it tighter to the player
camera_script_enable()
-- Create all the script objects for the cargo plane
-- Create all the script objects for the cargo plane
group_create(M18_groups.cargo_plane_tanks.name, true)
-- Initialize the tanks
for i, tank in pairs(M18_groups.cargo_plane_tanks.tanks) do
set_unjackable_flag(tank, true)
turn_invulnerable(tank)
end
-- Turn on the ambient audio emitters
for i, emitter in pairs(M18_audio_emitters.plane_interior) do
audio_ambient_emitter_start(emitter)
end
inv_weapon_add_temporary(LOCAL_PLAYER, "Pistol-Gang", 1, true, true)
if (coop_is_active() == true) then
inv_weapon_add_temporary(REMOTE_PLAYER, "Pistol-Gang", 1, true, true)
end
end
-- ***************************************************
-- m18_run Helper Functions
-- ***************************************************
-- This is the primary function responsible for running the entire mission from start to finish.
--
-- first_checkpoint: The first checkpoint to begin running the mission at
--
function m18_run(first_checkpoint)
local current_checkpoint = first_checkpoint
-- Run the mission from the beginning
if (current_checkpoint == M18_checkpoints.start) then
-- Cargo Plane [Part 1] - Destroy the cockpit
m18_run_cargo_plane_open_cockpit()
m18_cleanup_cargo_plane_open_cockpit()
-- Set the checkpoint
current_checkpoint = M18_checkpoints.cargo_plane_escape
mission_set_checkpoint(M18_checkpoints.cargo_plane_escape, true)
end
if (current_checkpoint == M18_checkpoints.cargo_plane_escape) then
-- Cargo Plane Escape [Part 1] - Escape
m18_run_cargo_plane_escape()
-- Cargo Plane Escape [Part 2] - Transition to Tank Free Fall
m18_run_cargo_plane_escape_scene()
-- Clean-up the cargo plane and setup the free fall
m18_cleanup_cargo_plane_interior()
m18_initialize_tank_free_fall(true)
mission_start_fade_in() -- fade back in after. the cutscene left the screen faded out
-- Set the checkpoint
current_checkpoint = M18_checkpoints.tank_free_fall
mission_set_checkpoint(M18_checkpoints.tank_free_fall, true)
end
if (current_checkpoint == M18_checkpoints.tank_free_fall) then
-- Tank Free Fall [Part 1] - Kill the initial bad guys
m18_run_ff_set_01()
-- Tank Free Fall [Part 2] - VTOL flybys (including the VTOL that crashes into the player's tank)
m18_run_ff_vtol_flybys_01()
-- Tank Free Fall [Part 3] - Tank flip exposes more enemies to kill
m18_run_ff_set_02()
-- Tank Free Fall [Part 4] - Second VTOL flybys
m18_run_ff_vtol_flybys_02()
current_checkpoint = M18_checkpoints.dive_bombers
mission_set_checkpoint(M18_checkpoints.dive_bombers, true)
end
if (current_checkpoint == M18_checkpoints.dive_bombers) then
-- Process dive-bomber wave 01
m18_run_ff_vtol_dive_bombers_01()
current_checkpoint = M18_checkpoints.debug_bail_out
end
if (current_checkpoint == M18_checkpoints.debug_bail_out) then
-- Tank Free Fall [Part 4] - The tank smashes into a cargo plane
m18_run_bail_out_of_tank()
m18_run_hijack_skydiving_tank()
end
delay(2.0)
--[[ DO SOME IMMEDIATE CLEANUP ]]--
-- Start fading out now
mission_start_fade_out()
-- Kill the thread processing the random clouds (needs to happen before we clean up M18_vfx)
thread_kill(M18_threads.random_clouds)
-- Make sure any VFX are cleaned up
for i, vfx in pairs(M18_vfxs) do
if (vfx.handle ~= -1) then
effect_stop(vfx.handle)
vfx.handle = -1
end
end
-- Kill the fire VFX on any wreckage debris
for i, effect_handle in pairs(M18_runtime.debirs_fire_handles) do
if (effect_handle ~= -1) then
effect_stop(effect_handle)
effect_handle = -1
end
end
-- Make sure there aren't any special vehicle VFX still playing
for i, tank_group in pairs(M18_runtime.skydiving_tanks) do
m18_helper_cleanup_skydiving_tank_common(tank_group)
end
m18_helper_cleanup_skydiving_tank_common(M18_groups.player_tank)
m18_helper_cleanup_skydiving_tank_common(M18_groups.skydiving_tank.tank_group)
-- Cleanup any groups that are still loaded
for i, group in pairs(M18_groups) do
if (group_is_loaded(group.name) == true) then
group_destroy(group.name)
end
end
-- Call mission success??
mission_end_success("m18", M18_cutscenes.mission_outro, M18_navpoints.player_end)
end
--[[
Cargo Plane [Part 1] - Destroy the cockpit
--]]
-- Initialize the cargo plane interior
function m18_initialize_cargo_plane_interior()
group_create(M18_groups.cargo_plane_interior.name, true)
-- Initialize the grunts
for i, squad in pairs(M18_groups.cargo_plane_interior.grunt_squads) do
for j, grunt in pairs(squad.grunts) do
character_set_combat_ready(grunt, true)
follower_make_independent(grunt, true)
ai_set_action_delay(grunt, "throw grenade", 9999)
on_take_damage("m18_cb_gooing_people", grunt)
end
end
-- Make the dead guys dead
for i, dead_guy in pairs(M18_groups.cargo_plane_interior.dead_guys) do
character_kill(dead_guy)
end
-- Force equip whatever's in the pistol slot
local pistol_type = inv_item_in_slot(LOCAL_PLAYER, "pistol")
inv_item_equip(pistol_type)
-- Handle any common initialization for the cargo plane
m18_initialize_cargo_plane_common()
-- Start the camera shake for the cargo plane interior
camera_shake_play_looping("cargo_plane_interior", M18_tweak_values.escape_looping_cam_shake_amount)
-- Make all of the boxes invulnerable (until the player gets the sonic gun)
for i, box_group in pairs(M18_movers.plane_boxes_01) do
mesh_mover_set_invulnerable(box_group.box, true)
end
-- Start the camera shake for the cargo plane interior
camera_shake_play_looping(M18_tweak_values.ambient_plane_camera_shake, M18_tweak_values.ambient_plane_camera_shake_intensity)
delay(0.2)
end
-- Setup and process the mission leading up to the player destroying the cockpit door
function m18_run_cargo_plane_open_cockpit()
-- Add the objective text
objective_text(0, M18_objectives.get_to_the_cockpit.tag, nil, nil, SYNC_ALL, M18_objectives.get_to_the_cockpit.icon)
-- Start the music
audio_object_post_event(M18_audio_events.music_start, nil, nil, LOCAL_PLAYER)
hud_set_fake_notoriety("Police", true, 1)
M18_runtime.num_grunts_to_reach_catwalk = 0
-- Register a callback for when a sonic gun is picked-up by the player
M18_flags.sonic_gun_aquired = false
-- Enable the trigger for the cabin door
M18_flags.cabin_door_open_attempted = false
trigger_enable(M18_triggers.cabin_door, true)
on_trigger("m18_cb_triggered_cabin_door", M18_triggers.cabin_door)
marker_add_trigger(M18_triggers.cabin_door, MINIMAP_ICON_USE, INGAME_EFFECT_LOCATION, OI_ASSET_USE, OI_FLAGS_FULL)
-- Enable the trigger for the cockpit door destruction region
M18_flags.in_cabin_destruction_region_local = false
M18_flags.in_cabin_destruction_region_remote = false
trigger_enable(M18_triggers.cabin_door_region, true)
on_trigger("m18_cb_cabin_door_region_entered", M18_triggers.cabin_door_region)
on_trigger_exit("m18_cb_cabin_door_region_exited", M18_triggers.cabin_door_region)
-- Setup the cabin door that gets destroyed by the sonic gun
M18_flags.cabin_door_destroyed = false
M18_flags.cockpit_door_destroyed = false
set_current_hit_points(M18_movers.cabin_door, 100000000)
set_current_hit_points(M18_movers.cockpit_door, 100000000)
on_take_damage("m18_cb_damaged_cabin_door", M18_movers.cabin_door)
on_take_damage("m18_cb_damaged_cockpit_door", M18_movers.cockpit_door)
trigger_enable(M18_triggers.start_combat, true)
on_trigger("m18_start_combat_cb", M18_triggers.start_combat)
-- Wait until the cabin door has been destroyed
while(M18_flags.cabin_door_destroyed == false) do
thread_yield()
end
-- Enable the trigger for the cockpit door destruction region
M18_flags.in_door_destruction_region_local = false
M18_flags.in_door_destruction_region_remote = false
trigger_enable(M18_triggers.cockpit_door_region, true)
on_trigger("m18_cb_cargo_door_region_entered", M18_triggers.cockpit_door_region)
on_trigger_exit("m18_cb_cargo_door_region_exited", M18_triggers.cockpit_door_region)
marker_add(M18_navpoints.cockpit_door_marker, MINIMAP_ICON_KILL, OI_ASSET_KILL_FULL, OI_FLAGS_FULL, SYNC_ALL)
delay(1.0)
m18_helper_conversation_play(M18_convo.mission_start, M18_CONVO_PLAY_LAST, 0.2)
-- Wait until the cock pit door has been destroyed
while(M18_flags.cockpit_door_destroyed == false) do
thread_yield()
end
end
-- Callback for when the player triggers the combat area in the plane interior
function m18_start_combat_cb(player, trigger)
-- Kill the trigger
trigger_enable(M18_triggers.start_combat, false)
on_trigger("", M18_triggers.start_combat)
ai_do_scripted_move(M18_groups.cargo_plane_interior.grunt_squads.catwalk.grunts[1], M18_navpoints.grunt_catwalk_positions[1], true, false)
-- ai_do_scripted_move(M18_groups.cargo_plane_interior.grunt_squads.catwalk.grunts[2], M18_navpoints.grunt_catwalk_positions[2], true, false)
-- Queue up a conversation
delay(2.0)
m18_helper_conversation_play(M18_convo.plane_combat, M18_CONVO_PLAY_LAST, 3.0)
m18_helper_conversation_play(M18_convo.falling_out_bad, M18_CONVO_PLAY_LAST, 1.5)
end
-- Callback for when the player attempts to open the cock pit door manualy (and fails to do so)
--
-- player: Player that attempted to open the cockpit door
-- trigger: The trigger
function m18_cb_triggered_cabin_door(player, trigger)
M18_flags.sonic_gun_failed_once = false
-- Handle special behavior if this is the first attempt to open the door
if (M18_flags.cabin_door_open_attempted == false) then
-- Remove the marker for the trigger region
marker_remove_trigger(M18_triggers.cabin_door)
trigger_enable(M18_triggers.cabin_door, false)
-- Get the animation group for the player's currently equipped weapon
local anim_group = nil
local equipped_weapon = inv_item_get_equipped_item(player)
if (equipped_weapon ~= nil) then
anim_group = inv_item_get_anim_group(equipped_weapon)
end
-- Make sure they have a weapon of the right type equipped to play the animation (pistol, dualpistol, rifle, or RPG)
if (anim_group ~= "Pistol" and anim_group ~= "DualPistol" and anim_group ~= "Rifle" and anim_group ~= "RPG") then
-- Force equip the pistol we previously gave the player
inv_item_equip(inv_item_in_slot(player, "Pistol"), player)
end
-- Play the "door locked" action on the player that is trying to open the door --
action_play(player, "door locked", "", false, 0.27, true, true, M18_navpoints.cabin_door_marker)
-- Play the thud audio for the kick
audio_object_post_event(M18_audio_events.kick_door, nil, nil, M18_triggers.cabin_door)
-- Wait for the animation to finish all the way
while(action_play_is_finished(player,0.7) == false) do
thread_yield()
end
-- Play a conversation
m18_helper_conversation_play(M18_convo.cockpit_locked_no_gun, M18_CONVO_PLAY_NEXT, 1.5, player)
delay(2.0)
-- They don't have the sonic gun, so mark the gun and update the objective
trigger_enable(M18_triggers.gun_crate_001, true)
trigger_enable(M18_triggers.gun_crate_002, true)
trigger_enable(M18_triggers.gun_crate_003, true)
on_trigger("m18_cb_gun_crate_empty", M18_triggers.gun_crate_001)
on_trigger("m18_cb_gun_crate_empty", M18_triggers.gun_crate_002)
on_trigger("m18_cb_gun_crate_give_sonic_gun", M18_triggers.gun_crate_003)
marker_add_trigger(M18_triggers.gun_crate_001, MINIMAP_ICON_USE, INGAME_EFFECT_LOCATION, OI_ASSET_USE, OI_FLAGS_FULL)
marker_add_trigger(M18_triggers.gun_crate_002, MINIMAP_ICON_USE, INGAME_EFFECT_LOCATION, OI_ASSET_USE, OI_FLAGS_FULL)
marker_add_trigger(M18_triggers.gun_crate_003, MINIMAP_ICON_USE, INGAME_EFFECT_LOCATION, OI_ASSET_USE, OI_FLAGS_FULL)
objective_text(0, M18_objectives.search_for_gun.tag, nil, nil, SYNC_ALL, M18_objectives.search_for_gun.icon)
M18_flags.cabin_door_open_attempted = true
end
end
-- Callback for when a player enters the cabin door destruction region
--
-- player: The player that entered the region around the cabin door
-- trigger: The trigger that the player entered
function m18_cb_cabin_door_region_entered(player, trigger)
-- Update the status on the player entering the region
if (player == LOCAL_PLAYER) then
M18_flags.in_cabin_destruction_region_local = true
elseif (player == REMOTE_PLAYER) then
M18_flags.in_cabin_destruction_region_remote = true
end
end
-- Callback for when a player enters the cargo door destruction region
--
-- player: The player that entered the region around the cockpit door
-- trigger: The trigger that the player entered
function m18_cb_cargo_door_region_entered(player, trigger)
-- Update the status on the player entering the region
if (player == LOCAL_PLAYER) then
M18_flags.in_door_destruction_region_local = true
elseif (player == REMOTE_PLAYER) then
M18_flags.in_door_destruction_region_remote = true
end
end
-- Callback for when a player exits the cabin door destruction region
--
-- player: The player the exited the region around the cabin door
-- trigger: The trigger that the player exited
function m18_cb_cabin_door_region_exited(player, trigger)
-- Update the status on the player leaving the region
if (player == LOCAL_PLAYER) then
M18_flags.in_cabin_destruction_region_local = false
elseif (player == REMOTE_PLAYER) then
M18_flags.in_cabin_destruction_region_remote = false
end
end
-- Callback for when a player exits the cargo door destruction region
--
-- player: The player the exited the region around the cockpit door
-- trigger: The trigger that the player exited
function m18_cb_cargo_door_region_exited(player, trigger)
-- Update the status on the player leaving the region
if (player == LOCAL_PLAYER) then
M18_flags.in_door_destruction_region_local = false
elseif (player == REMOTE_PLAYER) then
M18_flags.in_door_destruction_region_remote = false
end
end
-- Callback for when the player enters the Get-To-A-Tank trigger
-- function m18_cb_to_tank_trigger()
-- vehicle_suppress_npc_exit(M18_groups.cargo_plane_tanks.tanks[4], true)
-- vehicle_enter(M18_groups.cargo_plane_interior.grunt_squads.mechanics.grunts[1], M18_groups.cargo_plane_tanks.tanks[4], 0, false, false)
-- end
-- Callback for when the cockpit door is damaged by the sonic gun
--
-- mover: The mover that was damaged (the door)
-- attacker: The person that damaged the door
-- hitpoints: The remaining hitpoints for the door
-- from_explosion: Whether the damage came from an explosion
-- from_melee: Whether the damage came from a melee attack
-- from_sonic: Whether the damage came from a sonic gun attack
function m18_cb_damaged_cockpit_door(mover, attacker, hitpoints, from_explosion, from_melee, from_sonic)
if (from_sonic == true) then
-- If all weapons have been aquired, then check if the player attacking the door is in the destruction region
if (M18_flags.sonic_gun_aquired == true and ((M18_flags.in_door_destruction_region_local == true and attacker == LOCAL_PLAYER) or
(M18_flags.in_door_destruction_region_remote == true and attacker == REMOTE_PLAYER)) ) then
-- The destruction conditions have been met, destroy the door
set_current_hit_points(M18_movers.cockpit_door, 0)
-- Play some SFX
audio_object_post_event(M18_audio_events.destroy_cockpit, nil, nil, M18_navpoints.cockpit_door_marker)
-- Flag the cockpit door as destroyed
M18_flags.cockpit_door_destroyed = true
-- Play the explosion effect
M18_vfxs.cockpit_door_explosion.handle = effect_play(M18_vfxs.cockpit_door_explosion.nav)
else
-- The player that damaged the door is not in the destruction region, repair the door
set_current_hit_points(M18_movers.cockpit_door, 100000000)
-- Check if all players have the weapon
if (M18_flags.sonic_gun_aquired == true) then
if (M18_flags.played_too_far_away_conversation == false) then
-- Play a conversation, to tell the player to get closer
m18_helper_conversation_play(M18_convo.not_close_enough, M18_CONVO_PLAY_NEXT, 1.0, attacker)
-- m18_run_placeholder_dialog_lines(M18_placholder_dialog.too_far_away[1], false)
M18_flags.played_too_far_away_conversation = true
else
-- Play a conversation, to tell the player to get closer
-- m18_run_placeholder_dialog_lines(M18_placholder_dialog.too_far_away[2], false)
end
end
end
end
end
-- Callback for when the cabin door is damaged
--
-- mover: The mover that was damaged (the door)
-- attacker: The person that damaged the door
-- hitpoints: The remaining hitpoints for the door
-- from_explosion: Whether the damage came from an explosion
-- from_melee: Whether the damage came from a melee attack
-- from_sonic: Whether the damage came from a sonic gun attack
function m18_cb_damaged_cabin_door(mover, attacker, hitpoints, from_explosion, from_melee, from_sonic)
if (from_sonic == true) then
-- If all weapons have been aquired, then check if the player attacking the door is in the destruction region
if (M18_flags.sonic_gun_aquired == true and ((M18_flags.in_cabin_destruction_region_local == true and attacker == LOCAL_PLAYER) or
(M18_flags.in_cabin_destruction_region_remote == true and attacker == REMOTE_PLAYER)) ) then
-- The destruction conditions have been met, destroy the door
set_current_hit_points(M18_movers.cabin_door, 0)
audio_object_post_event(M18_audio_events.destroy_door, nil, nil, M18_navpoints.cabin_door_marker)
-- Flag the cockpit door as destroyed
M18_flags.cabin_door_destroyed = true
-- Cleanup the cabin door mover
on_take_damage("", M18_movers.cabin_door)
marker_remove(M18_navpoints.cabin_door_marker)
marker_remove_trigger(M18_triggers.cabin_door)
else
-- The player that damaged the door is not in the destruction region, repair the door
--mesh_mover_reset(M18_movers.cabin_door)
set_current_hit_points(M18_movers.cabin_door, 100000000)
-- Check if all players have the weapon
if (M18_flags.sonic_gun_aquired == true) then
if (M18_flags.played_too_far_away_conversation == false) then
-- Play a conversation, to tell the player to get closer
m18_helper_conversation_play(M18_convo.not_close_enough, M18_CONVO_PLAY_NEXT, 1.0, attacker)
-- m18_run_placeholder_dialog_lines(M18_placholder_dialog.too_far_away[1], false)
M18_flags.played_too_far_away_conversation = true
else
-- Play a conversation, to tell the player to get closer
-- m18_run_placeholder_dialog_lines(M18_placholder_dialog.too_far_away[2], false)
end
end
end
elseif (character_is_player(attacker)) then
if (M18_flags.cabin_door_open_attempted == true) then
if (M18_flags.sonic_gun_aquired == true) then
-- Play a conversation, to tell the player to try the sonic gun
-- m18_run_placeholder_dialog_lines(M18_placholder_dialog.door_damaged_with_gun, false)
else
-- Play a conversation, to tell the player to look for the gun
if (m18_helper_conversation_playing_or_queued(M18_convo.cockpit_locked_no_gun) == false) then
m18_helper_conversation_play(M18_convo.cockpit_locked_no_gun, M18_CONVO_PLAY_NEXT, 1.0, attacker)
end
end
end
end
end
-- Callback for when the player gooes someone in the interior
function m18_cb_gooing_people(npc, attacker, hitpoints, from_explosion, from_melee, from_sonic)
if ((from_sonic == true) and (hitpoints <= 0)) then
m18_helper_conversation_play(M18_convo.gooing_people, M18_CONVO_PLAY_NEXT, 1.0, attacker)
for i, squad in pairs(M18_groups.cargo_plane_interior.grunt_squads) do
for j, grunt in pairs(squad.grunts) do
if (character_exists(grunt)) then
on_take_damage("", grunt)
end
end
end
end
end
-- Clean-up the portion of the mission leading up to opening the cockpit door
function m18_cleanup_cargo_plane_open_cockpit()
-- Exit the special camera mode
camera_script_disable()
-- Clean-up the sonic guns
trigger_enable(M18_triggers.gun_crate_001, false)
trigger_enable(M18_triggers.gun_crate_002, false)
trigger_enable(M18_triggers.gun_crate_003, false)
marker_remove_trigger(M18_triggers.gun_crate_001, SYNC_ALL)
marker_remove_trigger(M18_triggers.gun_crate_002, SYNC_ALL)
marker_remove_trigger(M18_triggers.gun_crate_003, SYNC_ALL)
on_trigger("", M18_triggers.gun_crate_001)
on_trigger("", M18_triggers.gun_crate_002)
on_trigger("", M18_triggers.gun_crate_003)
-- Cleanup the Get-To-A-Tank trigger
-- on_trigger("", M18_triggers.to_tank)
-- Cleanup the cabin door trigger
on_trigger("", M18_triggers.cabin_door)
trigger_enable(M18_triggers.cabin_door, false)
marker_remove_trigger(M18_triggers.cabin_door)
-- Cleanup the cabin door destruction trigger
on_trigger("", M18_triggers.cabin_door_region)
on_trigger_exit("", M18_triggers.cabin_door_region)
trigger_enable(M18_triggers.cabin_door_region)
-- Cleanup the cabin door mover
on_take_damage("", M18_movers.cabin_door)
marker_remove(M18_navpoints.cabin_door_marker)
-- Cleanup the cockpit door destruction trigger
on_trigger("", M18_triggers.cockpit_door_region)
on_trigger_exit("", M18_triggers.cockpit_door_region)
trigger_enable(M18_triggers.cockpit_door_region)
-- Cleanup the cockpit door mover
on_take_damage("", M18_movers.cockpit_door)
marker_remove(M18_navpoints.cockpit_door_marker)
-- Stop the camera shake
camera_shake_stop()
end
--[[
Cargo Plane Escape [Part 1] - Escape
--]]
-- Initialize the cargo plane escape sequence
function m18_initialize_cargo_plane_escape()
-- Set the ragdoll restore position, so characters don't get teleported outside of the cargo plane
character_ragdoll_set_last_resort_position(M18_navpoints.player_start_escape[1])
-- Teleport the players to the cargo plane
teleport_coop(M18_navpoints.player_start_escape[1], M18_navpoints.player_start_escape[2], true)
-- Handle any common initialization for the cargo plane
m18_initialize_cargo_plane_common()
-- Give the players the sonic gun
inv_weapon_add_temporary(LOCAL_PLAYER, "Special-SonicGun", 1, true, true, false)
if (coop_is_active() == true) then
inv_weapon_add_temporary(REMOTE_PLAYER, "Special-SonicGun", 1, true, true, false)
end
-- Destroy the cockpit door
set_current_hit_points(M18_movers.cockpit_door, 0)
set_current_hit_points(M18_movers.cabin_door, 0)
--mesh_mover_kill(M18_movers.cockpit_door)
--mesh_mover_kill(M18_movers.cabin_door)
end
-- Setup and process for the player escaping the cargo plane in a tank
function m18_run_cargo_plane_escape()
-- Start some camera shakes
camera_shake_play("explosion_very_large", M18_tweak_values.escape_initial_cam_shake_amount)
camera_shake_play_looping("m18_plane_crash", M18_tweak_values.escape_looping_cam_shake_amount)
trigger_enable(M18_triggers.stumble_01, true)
on_trigger("m18_stumble_cb_alt", M18_triggers.stumble_01)
trigger_enable(M18_triggers.stumble_02, true)
on_trigger("m18_stumble_cb", M18_triggers.stumble_02)
-- Start a thread to make the boxes on the plane jiggle around in the turbulance
M18_threads.box_jiggle = thread_new("m18_thread_process_box_jiggle")
-- Start a thread to play some dust VFX falling from the cargo plane ceiling
M18_threads.plane_dust = thread_new("m18_thread_do_plane_dust_vfx")
-- Play the music
audio_object_post_event(M18_audio_events.music_plane_crashing, nil, nil, LOCAL_PLAYER)
-- Call the stumble callback directly to make everyone stumble
m18_stumble_cb()
-- Set some fake notoriety (HUD)
hud_set_fake_notoriety("Police", true, 3)
-- Make them drunk
drug_effect_set_override_values(M18_tweak_values.escape_drunk_amount, M18_tweak_values.escape_high_amount)
-- Turn on the cabin wind VFX
M18_vfxs.plane_wind.handle = effect_play(M18_vfxs.plane_wind.nav, true, SYNC_ALL)
-- Start the plane crashing audio emitters
for i, emitter in pairs(M18_audio_emitters.plane_crashing) do
audio_ambient_emitter_start(emitter)
end
-- Open the lower door, spawn dudes
door_open(M18_movers.lower_door)
group_create(M18_groups.stag_reinf.name)
for i, char in pairs(M18_groups.stag_reinf.chars) do
ai_do_scripted_advance(char, LOCAL_PLAYER)
end
-- Setup the trigger for the escape tank
on_trigger("m18_cb_tank_region_entered", M18_triggers.tank_region)
trigger_enable(M18_triggers.tank_region, true)
delay(1.0)
-- Play the conersation that is triggered by opening the door
m18_helper_conversation_play(M18_convo.cockpit_gone, M18_CONVO_PLAY_IMMEDIATE, 1.0)
m18_helper_topple_boxes(M18_movers.plane_boxes_01)
-- Add a new objective to escape
objective_text(0, M18_objectives.escape_in_tank.tag, nil, nil, SYNC_ALL, M18_objectives.escape_in_tank.icon)
marker_add_trigger(M18_triggers.tank_region, MINIMAP_ICON_LOCATION, INGAME_EFFECT_LOCATION, OI_ASSET_LOCATION, OI_FLAGS_LOCATION)
hud_timer_set(1, M18_tweak_values.escape_time_limit, "m18_cb_escape_time_expired")
-- Start prepping the Z-scene
zscene_prep(M18_cutscenes.tank_zscene)
delay(5.0)
m18_helper_conversation_play(M18_convo.blast_containers, M18_CONVO_PLAY_LAST, 1.0)
-- Wait until a players is in the tank trigger regoin
M18_flags.triggered_tank_region = false
while(M18_flags.triggered_tank_region == false) do
thread_yield()
end
end
-- Callback for when a player enters the tank trigger region
--
-- player: The player the entered the tank region
-- trigger: The trigger that was entered (the tank region)
function m18_cb_tank_region_entered(player, trigger)
M18_flags.triggered_tank_region = true
end
-- Callback for when the time limit has expired
function m18_cb_escape_time_expired()
-- Blow up the plane
M18_vfxs.cargo_plane_interior_explosion.handle = effect_play(M18_vfxs.cargo_plane_interior_explosion.nav)
-- Kill the characters
character_kill(LOCAL_PLAYER, true)
if (coop_is_active() == true) then
character_kill(REMOTE_PLAYER, true)
end
end
-- Thread to process player stumble animations (we can't just call the non-blocking version since some cleanup for the player happens in the complete check)
--
-- player: Player to play the stumble animation for
-- stumble_dir: Navpoint indicating the direction to stumble
-- direction_anim: specific animation to play
function m18_thread_do_play_stumble_animation(player, stumble_dir, direction_anim)
player_release_human_shield(player, true)
if (direction_anim ~= "") then
action_play(player, stumble_dir)
else
action_play(player, "Plane Cabin Stumble")
end
end
-- Stumble callback for the trigger stumbles.
function m18_stumble_cb()
-- Play some plane turbulance noises
audio_object_post_event(M18_audio_events.plane_shudder)
-- Start a thread to play some dust VFX falling from the cargo plane ceiling
M18_threads.plane_dust = thread_new("m18_thread_do_plane_dust_vfx")
-- Play the player stumbles
thread_new("m18_thread_do_play_stumble_animation", LOCAL_PLAYER, "Plane Stumble Left", false)
if (coop_is_active() == true) then
thread_new("m18_thread_do_play_stumble_animation", REMOTE_PLAYER, "Plane Stumble Left", false)
end
-- Play a stumble on all the enemies
if (group_is_loaded(M18_groups.cargo_plane_interior.name) == true) then
for i, char in pairs(M18_groups.cargo_plane_interior.chars) do
if (m18_helper_human_can_play_anim(char) == true) then
action_play_do(char, "Plane Stumble Left")
end
end
end
if (group_is_loaded(M18_groups.stag_reinf.name) == true) then
for i, char in pairs(M18_groups.stag_reinf.chars) do
if (m18_helper_human_can_play_anim(char) == true) then
action_play_do(char, "Plane Stumble Right")
end
end
end
end
-- Stumble callback for the trigger stumbles.
function m18_stumble_cb_alt()
-- Play some conversation
m18_helper_conversation_play(M18_convo.damn_stumbles, M18_CONVO_PLAY_LAST, 1.0)
-- Play some plane turbulance noises
audio_object_post_event(M18_audio_events.plane_violent_shake)
-- Start a thread to play some dust VFX falling from the cargo plane ceiling
M18_threads.plane_dust = thread_new("m18_thread_do_plane_dust_vfx")
-- Play the player stumbles
thread_new("m18_thread_do_play_stumble_animation", LOCAL_PLAYER, "Plane Stumble Right", false)
if (coop_is_active() == true) then
thread_new("m18_thread_do_play_stumble_animation", REMOTE_PLAYER, "Plane Stumble Right", false)
end
-- Play a stumble on all the enemies
if (group_is_loaded(M18_groups.cargo_plane_interior.name) == true) then
for i, char in pairs(M18_groups.cargo_plane_interior.chars) do
if (m18_helper_human_can_play_anim(char) == true) then
action_play(char, "Plane Stumble Left")
end
end
end
if (group_is_loaded(M18_groups.stag_reinf.name) == true) then
for i, char in pairs(M18_groups.stag_reinf.chars) do
if (m18_helper_human_can_play_anim(char) == true) then
action_play(char, "Plane Stumble Right")
end
end
end
end
-- Helper to check if a human is ready to play a custom animation
--
-- char_name: Name of the characer
--
-- returns: TRUE if the character is ready to play an animation, FALSE otherwise
function m18_helper_human_can_play_anim(char_name)
-- Check if they're ready (checks that they aren't dead, ragdolled
if (character_is_ready(char_name) == false) then
return false
end
if (character_playing_combat_move(char_name) == true) then
return false
end
if (character_is_jumping(char_name) == true) then
return false
end
return true
end
--[[
Cargo Plane Escape [Part 2] - Transition to Tank Free Fall
--]]
-- Cleanup for the cargo plane interior
function m18_cleanup_cargo_plane_interior()
-- Clear the ragdoll restore position
character_ragdoll_clear_last_resort_position()
-- Clean-up the tanks in the cargo plane
if (group_is_loaded(M18_groups.cargo_plane_tanks.name) == true) then
group_destroy(M18_groups.cargo_plane_tanks.name)
end
-- Remove the HUD timer
hud_timer_stop(1)
-- Kill the box giggle thread
if (M18_threads.box_jiggle ~= -1) then
thread_kill(M18_threads.box_jiggle)
M18_threads.box_jiggle = -1
end
-- Cleanup the grunts
for i, squad in pairs(M18_groups.cargo_plane_interior.grunt_squads) do
for j, grunt in pairs(squad.grunts) do
-- Clear any callbacks that may have been registered for this grunt
on_detection("", grunt)
on_ai_do_action_complete("", grunt)
on_take_damage("", grunt)
end
end
-- Remove the sonic gun items for the player's inventory
inv_weapon_remove_temporary(LOCAL_PLAYER, "Special-SonicGun")
if (coop_is_active() == true) then
inv_weapon_remove_temporary(REMOTE_PLAYER, "Special-SonicGun")
end
-- Clean-up any callback on a tank trigger region
trigger_enable(M18_triggers.tank_region, false)
marker_remove_trigger(M18_triggers.tank_region)
on_trigger("", M18_triggers.tank_region)
-- Clean-up stumble triggers
trigger_enable(M18_triggers.stumble_01, false)
on_trigger("", M18_triggers.stumble_01)
trigger_enable(M18_triggers.stumble_02, false)
on_trigger("", M18_triggers.stumble_02)
-- Stop any camera shakes
camera_shake_stop()
-- Clean-up any VFX
if (M18_vfxs.plane_wind.handle ~= -1) then
effect_stop(M18_vfxs.plane_wind.handle)
M18_vfxs.plane_wind.handle = -1
end
-- Stop the drug effects
drug_effect_clear_override_values()
-- Destroy the group for the cargo plane interior
if (group_is_loaded(M18_groups.cargo_plane_interior.name) == true) then
group_destroy(M18_groups.cargo_plane_interior.name)
group_destroy(M18_groups.stag_reinf.name)
end
-- Stop the audio emitters
for i, emitter in pairs(M18_audio_emitters.plane_interior) do
audio_ambient_emitter_stop(emitter)
end
for i, emitter in pairs(M18_audio_emitters.plane_crashing) do
audio_ambient_emitter_stop(emitter)
end
end
-- Handle running the setup and teardown for the escape Zscene
function m18_run_cargo_plane_escape_scene()
-- Remove the HUD timer
hud_timer_stop(1)
-- Clean-up any callback on a tank trigger region
trigger_enable(M18_triggers.tank_region, false)
marker_remove_trigger(M18_triggers.tank_region)
on_trigger("", M18_triggers.tank_region)
cutscene_play(M18_cutscenes.tank_zscene, nil, nil, false) -- don't fade back in. we need to clean-up the plane and setup the free fall afterwards
-- Start the skydiving music
audio_object_post_event(M18_audio_events.music_skydive_start, nil, nil, LOCAL_PLAYER)
end
--[[
Tank Free Fall - [Part 1] Kill the initial bad guys
--]]
function m18_initialize_tank_free_fall(play_tank_anim)
-- Add a new objective
objective_text(0, M18_objectives.survive.tag, nil, nil, SYNC_ALL, M18_objectives.survive.icon)
-- Make sure the player is not in any sort of vehicle
vehicle_exit_teleport(LOCAL_PLAYER)
if (coop_is_active() == true) then
vehicle_exit_teleport(REMOTE_PLAYER)
end
-- Turn off vehicle weapon physics so that the skydiving tank animations work nicely with the turret
vehicle_disable_weapon_physics(true)
-- Setup the players' tank
group_create(M18_groups.player_tank.name, true)
vehicle_skydiving_start(M18_groups.player_tank.tank, M18_navpoints.player_tank_orient_01)
vehicle_skydiving_move_to_do(M18_groups.player_tank.tank, M18_groups.player_tank.tank)
-- Register a callback for when the player's tank is destroyed and make the remote player invulnerable (since they can be struck by gunfire)
on_vehicle_destroyed("m18_player_tank_destroyed_cb", M18_groups.player_tank.tank)
if (coop_is_active() == true) then
turn_invulnerable(REMOTE_PLAYER, false)
end
-- Teleport the players and create the tank group
teleport_coop(M18_navpoints.player_start_free_fall[1], M18_navpoints.player_start_free_fall[2], true)
-- Disable rendering exterior objects (steelport city)
interior_disable_exterior(M18_interiors.skydiving_volume, true)
-- Teleport the player(s) into the tank
vehicle_enter_teleport(LOCAL_PLAYER, M18_groups.player_tank.tank, 0, true)
set_player_can_enter_exit_vehicles(LOCAL_PLAYER, false)
if (coop_is_active() == true) then
vehicle_enter_teleport(REMOTE_PLAYER, M18_groups.player_tank.tank, 1, true)
set_player_can_enter_exit_vehicles(REMOTE_PLAYER, false)
end
-- HACK: Disable notoriety after vehicle_enter(putting the players into the tank raises notoriety, which causes some problems in the mission)
notoriety_set_max("police", 0)
notoriety_set_min("police", 0)
notoriety_set("police", 0) -- HACK: setting the min after the level is 5 doesn't drop the level to 0, so we set that manually
-- Setup the player's tank, and set the tank invulnerable
m18_helper_setup_skydiving_tank_common(M18_groups.player_tank, true)
turn_invulnerable(M18_groups.player_tank.tank)
-- Set the global wind override
wind_override_set(0.0, 1.0, 0.0, 12.0)
-- Play the skydiving VFX
M18_vfxs.bottom_clouds.handle = effect_play(M18_vfxs.bottom_clouds.nav, true, SYNC_ALL)
M18_vfxs.clouds.handle = effect_play_on_human(M18_vfxs.clouds.nav, LOCAL_PLAYER, nil, true, SYNC_ALL)
M18_vfxs.city.handle = effect_play(M18_vfxs.city.nav, true, SYNC_ALL)
M18_threads.random_clouds = thread_new("m18_thread_generate_clouds")
-- Play some wind audio attacked to the player
audio_object_post_event(M18_audio_events.skydiving_wind, nil, nil, LOCAL_PLAYER)
if (coop_is_active() == true) then
audio_object_post_event(M18_audio_events.skydiving_wind, nil, nil, REMOTE_PLAYER)
end
-- Setup the debris flows
M18_runtime.debris_flow_handle = debris_flow_create()
for i, mover in pairs(M18_movers.free_fall_debris) do
debris_flow_add_object(M18_runtime.debris_flow_handle, mover, 10.0, 15.0, 5.0, true, true)
end
debris_flow_set_active(M18_runtime.debris_flow_handle, M18_navpoints.debris_emitter_pos_01, 15.0, 60.0, 350.0, LOCAL_PLAYER)
M18_runtime.debris_flow_handle_02 = debris_flow_create()
for i, mover in pairs(M18_movers.free_fall_debris_02) do
debris_flow_add_object(M18_runtime.debris_flow_handle_02, mover, 10.0, 15.0, 5.0, true, true)
end
debris_flow_set_active(M18_runtime.debris_flow_handle_02, M18_navpoints.debris_emitter_pos_01, 15.0, 60.0, 350.0, LOCAL_PLAYER)
M18_runtime.wreckage_debris_flow_handle = debris_flow_create()
for i, debris in pairs(M18_movers.wreckage_debris) do
debris_flow_add_object(M18_runtime.wreckage_debris_flow_handle, debris, 30.0, 50.0, 5.0, true, true)
if (rand_int(1, 4) == 1) then
M18_runtime.debirs_fire_handles[#M18_runtime.debirs_fire_handles + 1] = effect_play_on_script_object(M18_vfxs.debris_fire.nav, debris, nil, true)
end
end
debris_flow_add_avoid_object(M18_runtime.wreckage_debris_flow_handle, M18_groups.skydiving_tank.tank_group.tank)
-- Disable police notoriety spawning
notoriety_force_no_spawn("Police", true)
notoriety_force_no_spawn("stag", true)
-- Disable players going into the downed state (can not be revived while free falling)
set_players_can_be_downed(LOCAL_PLAYER, false)
if (coop_is_active() == true) then
set_players_can_be_downed(REMOTE_PLAYER, false)
end
-- Start a camera shake
camera_shake_play_looping("cargo_plane_interior", M18_tweak_values.skydive_looping_cam_shake_amount)
if (play_tank_anim == true) then
-- Create a thread to kick off the player's tank animation so it's start while the screen is fading in
thread_new("m18_delay_tank_start_animation_thread")
end
end
-- Thread to delay setting the player's tank start animation
function m18_delay_tank_start_animation_thread()
delay(0.2)
-- Start the player's tank animating
vehicle_anim_start(M18_groups.player_tank.tank, "", "tank roll a")
end
-- Setup and process Wave 01 of attackers in the Part 1 of the tank free fall
function m18_run_ff_set_01()
-- Tell the ai to stay above the tank
skydive_set_elev_angles_deg(10, 30)
hud_set_fake_notoriety("Police", true, 5)
-- Play a VO line
m18_helper_conversation_play(M18_convo.begin_drop, M18_CONVO_PLAY_NEXT, 1.0)
M18_threads.debris_flow_speed = thread_new("m18_process_debris_flow_speed_thread")
-- Process the enemy waves in the first spawn set
for i, enemy_wave in pairs(M18_free_fall_spawns.set_01) do
-- Create the wave, and then set them up
group_create_hidden(enemy_wave.group.name, true)
m18_helper_setup_free_fall_wave(enemy_wave.group)
if (enemy_wave.line ~= "") then
m18_helper_conversation_play(enemy_wave.line, M18_CONVO_PLAY_NEXT, 1.0)
end
-- Wait until we've gone under the minimum threat level or the maximum duration time has been reached
local elapsed_time = 0.0
while(m18_helper_get_free_fall_threat_level() > enemy_wave.min_threat_level and elapsed_time < enemy_wave.max_duration) do
thread_yield()
elapsed_time = elapsed_time + get_frame_time()
end
end
-- while(M18_runtime.num_free_fall_vehicles_alive > 0) do
-- thread_yield()
-- end
end
-- Function to process the debris flow objects speeding up
function m18_process_debris_flow_speed_thread()
--[[
local iterations = 10
local iteration_delay = M18_tweak_values.debris_flow_time_to_max_speed / iterations
for i=1, iterations do
local speed_mult = M18_tweak_values.debris_flow_min_speed_mult + ((1.0 - M18_tweak_values.debris_flow_min_speed_mult) * (i / iterations))
debris_flow_set_active(M18_runtime.debris_flow_handle, M18_navpoints.debris_emitter_pos_01, 15.0, 60.0, 200.0, LOCAL_PLAYER, speed_mult, false)
delay(iteration_delay)
end
--]]
end
--[[
Tank Free Fall - [Part 2] VTOL flybys (including the VTOL that crashes into the player's tank)
--]]
-- Run the first encounter with VTOLs as they do fly-bys past the player(s)
function m18_run_ff_vtol_flybys_01()
-- Create the VTOL 01 group
group_create_hidden(M18_groups.stag_vtol_flyby_01.name, true)
-- Remove all the object indicators on all the enemies in the first enemy set
m18_helper_clear_free_fall_wave_markers()
-- Set the restricted camera
-- camera_restrict_set_limits( -5, 5, -5, 5 )
-- camera_restrict_target_object()
-- camera_restrict_set_active(true)
m18_helper_conversation_play(M18_convo.generic_falling_02, M18_CONVO_PLAY_NEXT, 3.0)
-- camera_restrict_target_object(M18_groups.stag_vtol_flyby_01.restricted_camera, 2000)
-- camera_restrict_set_limits( -25, 25, -35, 35 )
-- Loop over each VTOL group, and spawn a new thread to setup and process their pathfind
for i, vtol_group in pairs(M18_groups.stag_vtol_flyby_01.vtol_groups) do
vtol_group.thread_id = thread_new("m18_run_vtol_flyby_hide_thread", vtol_group, 200)
end
-- Setup the VTOL that will collide with the player's tank
turn_invulnerable(M18_groups.stag_vtol_flyby_01.vtol_collide.vtol) -- make sure the player doesn't kill this VTOL before it collides with the tank
on_collision("m18_vtol_collision_cb", M18_groups.stag_vtol_flyby_01.vtol_collide.vtol)
M18_threads.vtol_collide = thread_new("m18_run_vtol_flyby_thread", M18_groups.stag_vtol_flyby_01.vtol_collide, 200)
delay(3.0)
-- Wait for the VTOL that collides with the tank to finish it's animation
while(thread_check_done(M18_threads.vtol_collide) == false) do
thread_yield()
end
-- Detonate the VTOL at the end of it's path
turn_vulnerable(M18_groups.stag_vtol_flyby_01.vtol_collide.vtol)
vehicle_detonate(M18_groups.stag_vtol_flyby_01.vtol_collide.vtol)
--vehicle_set_smoke_and_fire_state(M18_groups.player_tank.tank, true, false)
camera_shake_play("explosion_very_large", M18_tweak_values.skydive_collision_cam_shake_amount)
-- Set the new orientation for the player's tank (as a result of the collision/explosion)
vehicle_skydiving_start(M18_groups.player_tank.tank, M18_navpoints.player_tank_orient_02)
vehicle_skydiving_move_to_do(M18_groups.player_tank.tank, M18_groups.player_tank.tank)
vehicle_anim_start(M18_groups.player_tank.tank, "", "tank roll b")
delay(1.0)
-- Play a VO line
m18_helper_conversation_play(M18_convo.vtol_hit_01, M18_CONVO_PLAY_NEXT, 3.0)
-- Play a VO line
m18_helper_conversation_play(M18_convo.falling_again, M18_CONVO_PLAY_NEXT, 1.0)
-- Destroy the group of VTOLs
group_destroy(M18_groups.stag_vtol_flyby_01.name)
-- Clear the restricted camera
camera_restrict_set_active(false)
end
--[[
Tank Free Fall - [Part 3] Tank flip exposes more enemies to kill
--]]
-- Setup and process the 2nd set of enemies
function m18_run_ff_set_02()
-- Restore the markers
m18_helper_restore_free_fall_wave_markers()
M18_runtime.num_free_fall_chars_alive = 0
M18_runtime.num_free_fall_vehicles_alive = 0
-- Process the enemy waves in the second spawn set
for i, enemy_wave in pairs(M18_free_fall_spawns.set_02) do
-- Create the wave, and then set them up
group_create_hidden(enemy_wave.group.name, true)
m18_helper_setup_free_fall_wave(enemy_wave.group)
if (enemy_wave.line ~= "") then
m18_helper_conversation_play(enemy_wave.line, M18_CONVO_PLAY_NEXT, 1.0)
end
-- Wait until we've gone under the minimum thread level or the maximum duration time has been reached
local elapsed_time = 0.0
while(m18_helper_get_free_fall_threat_level() > enemy_wave.min_threat_level and elapsed_time < enemy_wave.max_duration) do
thread_yield()
elapsed_time = elapsed_time + get_frame_time()
end
end
-- while(M18_runtime.num_free_fall_vehicles_alive > 0) do
-- thread_yield()
-- end
end
-- Run the second encounter with VTOLs as they do fly-bys past the player(s)
function m18_run_ff_vtol_flybys_02()
-- Create the VTOL flyby 02 group
group_create_hidden(M18_groups.stag_vtol_flyby_02.name, true)
-- Remove all the object indicators on all the enemies in the first enemy set
m18_helper_clear_free_fall_wave_markers()
-- camera_restrict_set_limits( -5, 5, -5, 5 )
-- camera_restrict_target_object()
-- camera_restrict_set_active(true)
m18_helper_conversation_play(M18_convo.generic_falling_06, M18_CONVO_PLAY_NEXT, 3.0)
-- camera_restrict_target_object(M18_groups.stag_vtol_flyby_02.restricted_camera, 2000)
-- camera_restrict_set_limits( -25, 25, -35, 35 )
-- Create a thread for each VTOL to process it's pathfind
for i, vtol_group in pairs(M18_groups.stag_vtol_flyby_02.vtol_groups) do
vtol_group.thread_id = thread_new("m18_run_vtol_flyby_hide_thread", vtol_group, 200)
end
-- Setup the VTOL that will collide with the player's tank
turn_invulnerable(M18_groups.stag_vtol_flyby_02.vtol_collide.vtol) -- make sure the player doesn't kill this VTOL before it collides with the tank
on_collision("m18_vtol_collision_cb", M18_groups.stag_vtol_flyby_02.vtol_collide.vtol)
M18_threads.vtol_collide = thread_new("m18_run_vtol_flyby_thread", M18_groups.stag_vtol_flyby_02.vtol_collide, 200)
-- Wait for the VTOL that collides with the tank to finish it's animation
while(thread_check_done(M18_threads.vtol_collide) == false) do
thread_yield()
end
-- Detonate the VTOL at the end of it's path
turn_vulnerable(M18_groups.stag_vtol_flyby_02.vtol_collide.vtol)
vehicle_detonate(M18_groups.stag_vtol_flyby_02.vtol_collide.vtol)
camera_shake_play("explosion_very_large", M18_tweak_values.skydive_collision_cam_shake_amount)
-- Play the VO line
m18_helper_conversation_play(M18_convo.vtol_hit_02, M18_CONVO_PLAY_NEXT, 1.0)
-- Clear the restricted camera
camera_restrict_set_active(false)
--vehicle_set_smoke_and_fire_state(M18_groups.player_tank.tank, true, true)
vehicle_anim_start(M18_groups.player_tank.tank, "", "tank roll c")
group_destroy(M18_groups.stag_vtol_flyby_02.name)
end
-- Thread to process a dive-bombing VTOL
--
-- vtol_table: Lua table defining the dive-bombing VTOL
function m18_thread_process_vtol_dive_bomb(vtol_table)
-- Setup the VTOL
vehicle_show(vtol_table.vtol)
vehicle_enter_group_teleport(vtol_table.chars, vtol_table.vtol)
for i, char in pairs(vtol_table.chars) do
character_show(char)
character_set_skydiving(char, true)
turn_invulnerable(char)
end
-- Add an object indicatoro
marker_add(vtol_table.vtol, MINIMAP_ICON_KILL, OI_ASSET_KILL_FULL, OI_FLAGS_FULL, SYNC_ALL)
-- Start the pathfinding
helicopter_set_path_orientation(vtol_table.vtol, 4, M18_groups.player_tank.tank)
helicopter_fly_to_direct_dont_stop(vtol_table.vtol, 12.0, vtol_table.start_path)
repeat
helicopter_fly_to_direct_dont_stop(vtol_table.vtol, 7.0, vtol_table.looping_path)
thread_yield()
until (vehicle_is_destroyed(vtol_table.vtol) == true)
end
-- Process the mission sequence with the dive-bombing VTOLs
function m18_run_ff_vtol_dive_bombers_01()
-- Change the player tank's orient
vehicle_skydiving_start(M18_groups.player_tank.tank, M18_navpoints.player_tank_orient_03)
vehicle_set_smoke_and_fire_state(M18_groups.player_tank.tank, true, true)
group_create_hidden(M18_groups.stag_dive_bombers_01.name, true)
-- Set the restricted camera
camera_restrict_set_limits( -20, 20, -20, 20 )
camera_restrict_target_object()
camera_restrict_set_active(true)
camera_restrict_target_object(M18_groups.stag_dive_bombers_01.restricted_camera, 2000)
-- Kick off threads to process the VTOL dive bomb behavior
M18_runtime.num_ff_part_03_vehicles = 0
for i, vtol_table in pairs(M18_groups.stag_dive_bombers_01.vtols) do
vtol_table.thread_id = thread_new("m18_thread_process_vtol_dive_bomb", vtol_table)
local new_min = get_max_hit_points(vtol_table.vtol) * 0.2
set_min_hit_points(vtol_table.vtol, new_min)
on_damage("m18_dive_bomber_damaged_cb", vtol_table.vtol, 0.3)
on_vehicle_destroyed("m18_dive_bomb_vtol_destroyed_cb", vtol_table.vtol)
M18_runtime.num_ff_part_03_vehicles = M18_runtime.num_ff_part_03_vehicles + 1
end
M18_runtime.num_ff_part_03_vehicles_alive = M18_runtime.num_ff_part_03_vehicles
-- Play some audio for the VTOLs
audio_object_post_event(M18_audio_events.vtol_whalla, nil, nil, M18_groups.stag_dive_bombers_01.vtols[1].vtol)
-- Create the group for the cargo plane that the tank is going to smash into
group_create_hidden(M18_groups.stag_cargo_plane.name)
-- Enable rendering exterior objects (steelport city)
delay(4.0)
interior_disable_exterior(M18_interiors.skydiving_volume, false)
if (M18_vfxs.city.handle ~= -1) then
effect_stop(M18_vfxs.city.handle)
M18_vfxs.city.handle = -1
end
--[[
if (M18_vfxs.bottom_clouds.handle ~= -1) then
effect_stop(M18_vfxs.bottom_clouds.handle)
M18_vfxs.bottom_clouds.handle = -1
end
--]]
-- Wait until all the VTOLs have been destroyed
while(M18_runtime.num_ff_part_03_vehicles_alive > 0) do
thread_yield()
end
-- Stop the Whalla audio
audio_object_post_event(M18_audio_events.vtol_whalla_stop, nil, nil, M18_groups.stag_dive_bombers_01.vtols[1].vtol)
-- Make the tank flip, and set a new orient
vehicle_skydiving_start(M18_groups.player_tank.tank, M18_navpoints.player_tank_orient_04)
vehicle_skydiving_move_to_do(M18_groups.player_tank.tank, M18_navpoints.player_tank_center_pos, 0.0, 2.0)
vehicle_anim_start(M18_groups.player_tank.tank, "", "tank roll b")
camera_shake_play("explosion_very_large", M18_tweak_values.skydive_collision_cam_shake_amount)
delay(2.0)
group_destroy(M18_groups.stag_dive_bombers_01.name)
-- Clear the restricted camera
camera_restrict_set_active(false)
end
-- Callback for when a dive bomber VTOL has taken enough damage to get destroyed
--
-- victim: VTOL that was damage
function m18_dive_bomber_damaged_cb(victim)
-- Remove this callback
on_damage("", victim)
-- If this is the last dive bomber, then we need to crash it into the player's tank
if (M18_runtime.num_ff_part_03_vehicles_alive == 1) then
m18_helper_conversation_play(M18_convo.generic_falling_04, M18_CONVO_PLAY_NEXT, 3.0)
turn_invulnerable(victim)
marker_remove(victim)
for i, vtol_group in pairs(M18_groups.stag_dive_bombers_01.vtols) do
if (vtol_group.vtol == victim) then
thread_kill(vtol_group.thread_id)
end
end
--vehicle_set_smoke_and_fire_state(victim, true, false)
M18_runtime.debirs_fire_handles[#M18_runtime.debirs_fire_handles + 1] = effect_play_on_script_object(M18_vfxs.debris_fire.nav, victim, nil, true)
helicopter_fly_to_direct_dont_stop(victim, -1, M18_groups.stag_dive_bombers_01.death_path)
end
-- Remove the marker
marker_remove(victim)
-- Make it skydiving so the debris floats
vehicle_skydiving_start(victim)
-- Make it go bomb
set_min_hit_points(victim, 0)
turn_vulnerable(victim)
vehicle_detonate(victim)
end
-- Callback when a vehicle from free fall 03 is destroyed
function m18_dive_bomb_vtol_destroyed_cb(vehicle)
-- Decrement the number of vehicles alive
M18_runtime.num_ff_part_03_vehicles_alive = M18_runtime.num_ff_part_03_vehicles_alive - 1
-- Clean-up the destroyed vehicle
on_vehicle_destroyed("", vehicle)
marker_remove(vehicle)
end
-- Helper function to setup each plane in the cargo plane formation
--
-- cargo_plane_group: Lua table defining the cargo plane
function m18_helper_setup_cargo_plane_thread(cargo_plane_group)
vehicle_set_invulnerable_to_player_explosives(cargo_plane_group.plane, true)
vehicle_enter_group_teleport(cargo_plane_group.chars, cargo_plane_group.plane)
for i, char in pairs(cargo_plane_group.chars) do
character_set_skydiving(char, true)
end
vehicle_max_speed(cargo_plane_group.plane, 120.0)
helicopter_set_path_orientation(cargo_plane_group.plane, HELI_PF_PATH_PITCH)
helicopter_fly_to_do(cargo_plane_group.plane, 120.0, true, "", true, cargo_plane_group.path, 0.0, false, false, true)
-- Wait until the plane is a certain distance away from the player's tank, then play a whosh SFX
while (get_dist(cargo_plane_group.plane, LOCAL_PLAYER, false, true) > 100.0) do
thread_yield()
end
audio_object_post_event(M18_audio_events.vtol_flyby, nil, nil, cargo_plane_group.plane)
end
-- Process the player bailing out of the tank to avoid colliding with the cargo plane
function m18_run_bail_out_of_tank()
skydive_setup_tank_bailout(1)
-- Remove the city VFX
if (M18_vfxs.city.handle ~= -1) then
effect_stop(M18_vfxs.city.handle)
M18_vfxs.city.handle = -1
end
skydive_set_player_dive_fall_speed(M18_tweak_values.tank_impact_start_player_fall_speed)
-- Create the group for the skydiving tank the player will steal
group_create_hidden(M18_groups.skydiving_tank.name, true)
turn_invulnerable(M18_groups.skydiving_tank.tank_group.tank)
for i, char in pairs(M18_groups.skydiving_tank.tank_group.chars) do
turn_invulnerable(char)
end
m18_helper_setup_skydiving_tank_common(M18_groups.skydiving_tank.tank_group, true)
vehicle_anim_start(M18_groups.skydiving_tank.tank_group.tank, "mad18 stag tank", "")
-- Wait to make sure the player's tank is safely within the player's skydiving boundary
while(get_dist(M18_groups.player_tank.tank, M18_navpoints.player_tank_center_pos) > 1.0) do
thread_yield()
end
delay(5.0)
vehicle_freeze(M18_groups.player_tank.tank, true)
-- Setup the cargo plane formation
group_show(M18_groups.stag_cargo_plane.name)
for i, plane in pairs(M18_groups.stag_cargo_plane.planes) do
if (i ~= 1) then
plane.thread_id = thread_new("m18_helper_setup_cargo_plane_thread", plane)
end
end
skydive_setup_tank_bailout(2)
turn_invulnerable(M18_groups.stag_cargo_plane.planes[1].plane)
vehicle_freeze(M18_groups.stag_cargo_plane.planes[1].plane, true)
-- Play some engine audio on the giant cargo planes
audio_object_post_event(M18_audio_events.cargo_plane_flying, nil, nil, M18_groups.stag_cargo_plane.planes[1].plane)
audio_object_post_event(M18_audio_events.cargo_plane_flying, nil, nil, M18_groups.stag_cargo_plane.planes[2].plane)
delay(1.5)
-- Do the restricted camera to focus on the cargo plane
camera_restrict_set_limits(-20, 20, -20, 20)
camera_restrict_target_object(nil, 0)
camera_restrict_set_active(true)
camera_restrict_target_object(M18_groups.stag_cargo_plane.planes[1].plane, 2000)
-- Add a new objective
delay(1.0)
objective_text(0, M18_objectives.bail_out_of_tank.tag, nil, nil, SYNC_ALL, M18_objectives.bail_out_of_tank.icon)
-- Play the VO line
m18_helper_conversation_play(M18_convo.exit_tank, M18_CONVO_PLAY_NEXT, 1.0)
-- Allow the player's to exit the vehicle now
hud_prompt(LOCAL_PLAYER, "M18_BAIL_FROM_TANK", "m18_cb_local_player_exited_tank") -- BORKED
if (coop_is_active() == true) then
hud_prompt(REMOTE_PLAYER, "M18_BAIL_FROM_TANK", "m18_cb_remote_player_exited_tank")
end
-- Stop the camera shake
camera_shake_stop()
m18_helper_conversation_play(M18_convo.steal_plane, M18_CONVO_PLAY_NEXT, 1.0)
skydive_set_player_dive_fall_speed(M18_tweak_values.steal_tank_player_fall_speed)
-- Wait until the animation has gotten to the point where the tank impacts the cargo plane
while(vehicle_anim_finished(M18_groups.player_tank.tank, 0.745) == false) do
thread_yield()
end
-- Start the cargo plane on it's crash path
M18_threads.cargo_plane_crash_02 = thread_new("m18_process_plane_crash_thread")
-- Remove the HUD prompt and if a player is still in the tank, kill them now (since they may be invulnerable)
hud_prompt_clear(LOCAL_PLAYER)
if (character_is_in_vehicle(LOCAL_PLAYER) == true) then
character_kill(LOCAL_PLAYER, true)
end
if (coop_is_active() == true) then
hud_prompt_clear(REMOTE_PLAYER)
if (character_is_in_vehicle(REMOTE_PLAYER) == true) then
character_kill(REMOTE_PLAYER, true)
end
end
-- Detonate the the tank and play an explosion and some VFX
vehicle_set_keyframed_physics(M18_groups.player_tank.tank, false)
turn_vulnerable(M18_groups.player_tank.tank)
vehicle_detonate(M18_groups.player_tank.tank)
M18_vfxs.stag_cargo_plane_explosion.handle = effect_play(M18_vfxs.stag_cargo_plane_explosion.nav)
m18_helper_conversation_play(M18_convo.plane_blows_up, M18_CONVO_PLAY_NEXT, 1.0)
-- Update the plane's audio, and add some explosion audio
audio_object_post_event(M18_audio_events.cargo_plane_crashing, nil, nil, M18_groups.stag_cargo_plane.planes[1].plane)
audio_object_post_event(M18_audio_events.tank_hit_wing, nil, nil, M18_groups.stag_cargo_plane.planes[1].plane)
-- Update the debris flow again, now that the player's are outside of the tank
debris_flow_add_avoid_object(M18_runtime.debris_flow_handle, M18_groups.skydiving_tank.tank_group.tank)
debris_flow_add_avoid_object(M18_runtime.debris_flow_handle_02, M18_groups.skydiving_tank.tank_group.tank)
debris_flow_set_active(M18_runtime.debris_flow_handle, M18_navpoints.debris_emitter_pos_03, 0.0, 40.0, 300.0, LOCAL_PLAYER, 1.0)
debris_flow_set_active(M18_runtime.debris_flow_handle_02, M18_navpoints.debris_emitter_pos_03, 0.0, 40.0, 300.0, LOCAL_PLAYER, 1.0)
-- Show all the wreckage debris
for i, debris in pairs(M18_movers.wreckage_debris) do
if (rand_int(1, 4) == 1) then
M18_runtime.debirs_fire_handles[#M18_runtime.debirs_fire_handles + 1] = effect_play_on_script_object(M18_vfxs.debris_fire.nav, debris, nil, true)
end
end
debris_flow_set_active(M18_runtime.wreckage_debris_flow_handle, M18_navpoints.debris_emitter_pos_03, 10.0, 25.0, 300.0, LOCAL_PLAYER, 1.0, true)
thread_yield()
explosion_create("Car Bomb Big", M18_vfxs.stag_cargo_plane_explosion.nav)
delay(0.1)
-- Play some groan audio on the wing
audio_object_post_event(M18_audio_events.cargo_plane_wing_groan, nil, nil, M18_groups.stag_cargo_plane.planes[1].plane)
end
function m18_process_plane_crash_thread()
-- Destroy the components
vehicle_component_detach(M18_groups.stag_cargo_plane.planes[1].plane, "engine_RMid", true)
vehicle_component_detach(M18_groups.stag_cargo_plane.planes[1].plane, "R_End", true)
vehicle_component_detach(M18_groups.stag_cargo_plane.planes[1].plane, "Object01", true)
M18_vfxs.cargo_plane_smoke.handle = effect_play_on_script_object(M18_vfxs.cargo_plane_smoke.nav, M18_groups.stag_cargo_plane.planes[1].plane, "headlight_glare", true, SYNC_ALL, 2)
-- Wait until the animation has gotten to the point where the tank impacts the cargo plane
while(vehicle_anim_finished(M18_groups.stag_cargo_plane.planes[1].plane, 0.9) == false) do
thread_yield()
end
effect_stop(M18_vfxs.cargo_plane_smoke.handle)
M18_vfxs.cargo_plane_smoke.handle = effect_play_on_script_object(M18_vfxs.stag_cargo_plane_explosion.nav, M18_groups.stag_cargo_plane.planes[1].plane, "headlight_glare", true, SYNC_ALL, 2)
delay(0.1)
vehicle_hide(M18_groups.stag_cargo_plane.planes[1].plane)
end
-- Function to check if all players have bailed from the tank (and does some setup if they have)
function m18_check_all_players_bailed_from_tank()
local player_in_tank = false
if (character_is_in_vehicle(LOCAL_PLAYER) == true) then
player_in_tank = true
elseif (coop_is_active() == true and character_is_in_vehicle(REMOTE_PLAYER) == true) then
player_in_tank = true
end
if (player_in_tank == false) then
objective_text_clear(0)
-- Make the player's tank invulnerable and clear the on destroyed callback
turn_invulnerable(M18_groups.player_tank.tank)
on_vehicle_destroyed("", M18_groups.player_tank.tank)
-- Change to the bail out music
audio_object_post_event(M18_audio_events.music_bail_out, nil, nil, LOCAL_PLAYER)
end
end
-- Callback for when a player bails out of the tank
function m18_cb_local_player_exited_tank(player)
-- Clear the HUD prompt and the restricted camera
hud_prompt_clear(LOCAL_PLAYER)
camera_restrict_set_active(false, LOCAL_PLAYER)
-- Exit the vehicle, equip dual SMGs, and start skydiving
set_animation_state(LOCAL_PLAYER, "FreeFalling_Dive_AIM")
action_play(LOCAL_PLAYER, "exit mission")
vehicle_exit_teleport(LOCAL_PLAYER, true)
character_set_skydiving(LOCAL_PLAYER, true)
inv_weapon_add_temporary(LOCAL_PLAYER, M18_tweak_values.player_smg, 1, true, true, true) -- SMG has unlimited ammo and is equipped immediatly, and dual weidling
inv_weapon_disable_all_but_this_slot(WEAPON_SLOT_SMG, false, SYNC_LOCAL)
clear_animation_state(LOCAL_PLAYER)
-- Check if all the players have exited the tank
m18_check_all_players_bailed_from_tank()
-- Force them into a vertical dive, if the tank has already crossed the threshold that triggers the vertical dive
character_set_skydiving_state(LOCAL_PLAYER, 8, true)
-- Register a callback for when the playered is damaged
on_take_damage("m18_player_damaged_while_diving_cb", LOCAL_PLAYER)
end
-- Callback for when a player bails out of the tank
function m18_cb_remote_player_exited_tank()
-- Clear the HUD prompt and the restricted camera
hud_prompt_clear(REMOTE_PLAYER)
camera_restrict_set_active(false, REMOTE_PLAYER)
-- Exit the vehicle, equip dual SMGs, and start skydiving
set_animation_state(REMOTE_PLAYER, "FreeFalling_Dive_AIM")
action_play(REMOTE_PLAYER, "exit mission")
vehicle_exit_teleport(REMOTE_PLAYER, true)
character_set_skydiving(REMOTE_PLAYER, true)
inv_weapon_add_temporary(REMOTE_PLAYER, M18_tweak_values.player_smg, 1, true, true, true) -- SMG has unlimited ammo and is equipped immediatly, and dual weidling
inv_weapon_disable_all_but_this_slot(WEAPON_SLOT_SMG, false, SYNC_LOCAL)
clear_animation_state(REMOTE_PLAYER)
-- Check if all the players have exited the tank
m18_check_all_players_bailed_from_tank()
-- Force them into a vertical dive, if the tank has already crossed the threshold that triggers the vertical dive
character_set_skydiving_state(REMOTE_PLAYER, 8, true)
-- Make them vunlerable again (since they're no longer in the tank)
turn_vulnerable(REMOTE_PLAYER, false)
-- Register a callback for when the playered is damaged
on_take_damage("m18_player_damaged_while_diving_cb", REMOTE_PLAYER)
end
-- Process the player entering the skydiving tank
function m18_run_hijack_skydiving_tank()
-- Add a new objective, and object indicator
objective_text(0, M18_objectives.hijack_tank.tag, nil, nil, SYNC_ALL, M18_objectives.hijack_tank.icon)
marker_add(M18_groups.skydiving_tank.tank_group.tank, MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION, OI_FLAGS_FULL, SYNC_ALL)
-- Enable the triggers for the falling tank
trigger_enable(M18_triggers.falling_tank_01, true)
trigger_enable(M18_triggers.falling_tank_02, true)
trigger_enable(M18_triggers.falling_tank_03, true)
trigger_enable(M18_triggers.falling_tank_04, true)
on_trigger("m18_cb_triggered_falling_tank_region", M18_triggers.falling_tank_01)
on_trigger("m18_cb_triggered_falling_tank_region", M18_triggers.falling_tank_02)
on_trigger("m18_cb_triggered_falling_tank_region", M18_triggers.falling_tank_03)
on_trigger("m18_cb_triggered_falling_tank_region", M18_triggers.falling_tank_04)
-- Put the player's into the regular diving state (so they get the normal camera)
character_set_skydiving_state(LOCAL_PLAYER, 1, true)
if (coop_is_active() == true) then
character_set_skydiving_state(REMOTE_PLAYER, 1, true)
end
delay(1.0)
-- Show the tank the player is going to steal (and make it vulnerable again)
group_show(M18_groups.skydiving_tank.name)
local tank_group = M18_groups.skydiving_tank.tank_group
vehicle_disable_chase(tank_group.tank, true)
vehicle_disable_flee(tank_group.tank, true)
vehicle_enter_group_teleport(tank_group.chars, tank_group.tank)
vehicle_set_keyframed_physics(tank_group.tank, true)
-- Set the tank skydiving
vehicle_skydiving_start(tank_group.tank, tank_group.orient)
vehicle_skydiving_move_to_do(tank_group.tank, tank_group.dest, (M18_tweak_values.steal_tank_fall_speed - 1.0), M18_tweak_values.steal_tank_fall_speed)
-- Setup the player skydiving for this sequence
M18_threads.local_player_steal_tank = thread_new("m18_thread_process_player_steal_tank_pose", LOCAL_PLAYER)
if (coop_is_active()) then
M18_threads.local_player_steal_tank = thread_new("m18_thread_process_player_steal_tank_pose", REMOTE_PLAYER)
end
-- Loop over each character, and set them up
for j, char in pairs(tank_group.chars) do
if (character_is_dead(char) == false) then
ai_add_enemy_target(char, CLOSEST_PLAYER, ATTACK_NOW_NEVER_LOSE)
npc_weapon_spread(char, M18_tweak_values.steal_tank_ai_spread_mult)
set_trailing_aim_flag(char, false)
turn_vulnerable(char)
end
end
delay(5.0)
turn_vulnerable(tank_group.tank)
for i, char in pairs(tank_group.chars) do
turn_vulnerable(char)
end
skydive_set_player_dive_fall_speed(M18_tweak_values.steal_tank_player_fall_speed)
-- Wait until the player gets close enough to the tank
local player_reached_tank = false
while(player_reached_tank == false) do
if (get_dist(M18_groups.skydiving_tank.tank_group.tank, LOCAL_PLAYER) < M18_tweak_values.steal_tank_success_radius) then
player_reached_tank = true
end
if (coop_is_active() == true and get_dist(M18_groups.skydiving_tank.tank_group.tank, REMOTE_PLAYER) < M18_tweak_values.steal_tank_success_radius) then
player_reached_tank = true
end
thread_yield()
end
-- Remove the callback on the kill trigger
on_trigger("", M18_triggers.falling_tank_04)
-- Enter the tank
marker_remove(M18_groups.skydiving_tank.tank_group.tank, SYNC_ALL)
character_kill(M18_groups.skydiving_tank.tank_group.chars[1])
character_kill(M18_groups.skydiving_tank.tank_group.chars[2])
vehicle_anim_start(M18_groups.skydiving_tank.tank_group.tank, "", "M18 Enter Tank")
vehicle_enter(LOCAL_PLAYER, M18_groups.skydiving_tank.tank_group.tank, 0, true, true, false, "M18 Enter Tank")
-- Play the mission completion music
audio_object_post_event(M18_audio_events.music_mission_complete, nil, nil, LOCAL_PLAYER)
--[[
vehicle_enter_teleport(LOCAL_PLAYER, M18_groups.skydiving_tank.tank_group.tank)
if (coop_is_active() == true) then
vehicle_enter_teleport(REMOTE_PLAYER, M18_groups.skydiving_tank.tank_group.tank)
end
--]]
end
-- Callback as the tank enters the various triggers while falling (so we can increase the threat from the tank
--
-- triggerer: Human that entered the trigger region
-- trigger: Trigger that was entered
function m18_cb_triggered_falling_tank_region(triggerer, trigger)
if (trigger == M18_triggers.falling_tank_01) then
npc_refire_rate_override(M18_groups.skydiving_tank.tank_group.chars[1], M18_tweak_values.steal_tank_driver_refire_rates[1])
npc_refire_rate_override(M18_groups.skydiving_tank.tank_group.chars[2], M18_tweak_values.steal_tank_gunner_refire_rates[1])
m18_helper_conversation_play(M18_convo.dive_through, M18_CONVO_PLAY_NEXT, 1.0)
elseif (trigger == M18_triggers.falling_tank_02) then
npc_refire_rate_override(M18_groups.skydiving_tank.tank_group.chars[1], M18_tweak_values.steal_tank_driver_refire_rates[2])
npc_refire_rate_override(M18_groups.skydiving_tank.tank_group.chars[2], M18_tweak_values.steal_tank_gunner_refire_rates[2])
m18_helper_conversation_play(M18_convo.while_skydiving, M18_CONVO_PLAY_NEXT, 1.0)
elseif (trigger == M18_triggers.falling_tank_03) then
npc_refire_rate_override(M18_groups.skydiving_tank.tank_group.chars[1], M18_tweak_values.steal_tank_driver_refire_rates[3])
npc_refire_rate_override(M18_groups.skydiving_tank.tank_group.chars[2], M18_tweak_values.steal_tank_gunner_refire_rates[3])
set_perfect_aim(M18_groups.skydiving_tank.tank_group.chars[1], true)
set_perfect_aim(M18_groups.skydiving_tank.tank_group.chars[2], true)
elseif (trigger == M18_triggers.falling_tank_04) then
ai_add_enemy_target(M18_groups.skydiving_tank.tank_group.chars[1], LOCAL_PLAYER, ATTACK_NOW_NEVER_LOSE)
--delay(1.0)
--force_fire_target_do(M18_groups.skydiving_tank.tank_group.chars[1], LOCAL_PLAYER)
delay(0.1)
explosion_create("Tank_Rpg", LOCAL_PLAYER, M18_groups.skydiving_tank.tank_group.chars[1], false)
character_kill(LOCAL_PLAYER, true)
if (coop_is_active() == true) then
character_kill(REMOTE_PLAYER, true)
end
end
end
-- Function to process the player as they approach the tank they must steal (so we can stop their dive when the get close enough)
--
-- player_name: Name of the player the thread is processing
function m18_thread_process_player_steal_tank_pose(player_name)
local delta_y = 0
repeat
local player_x, player_y, player_z = get_object_pos(player_name)
local tank_x, tank_y, tank_z = get_object_pos(M18_groups.skydiving_tank.tank_group.tank)
delta_y = player_y - tank_y
thread_yield()
until (delta_y < M18_tweak_values.steal_tank_stop_dive_elev)
skydive_set_player_dive_fall_speed(M18_tweak_values.steal_tank_fall_speed)
end
-- Callback for when a player is damage while diving to steal a tank
function m18_player_damaged_while_diving_cb(player_name, attacker, damage_amt, from_exp)
-- If this isn't from an explosion, then play the collision animation on the player (since this must have been from hitting debris)
if (from_exp == false and attacker == nil) then
audio_object_post_event("object_impact", "object_type", "generic_medium_wood", player_name)
if (action_play_is_finished(player_name)) then
audio_play_persona_line(player_name, "voc_pain")
action_play(player_name, "FreeFall Collision")
end
end
end
-- Clean for the tank free fall section of the mission
function m18_cleanup_tank_free_fall()
-- Turn vehicle weapon physics back on
vehicle_disable_weapon_physics(true)
if (M18_runtime.debris_flow_handle ~= 0) then
debris_flow_destroy(M18_runtime.debris_flow_handle)
M18_runtime.debris_flow_handle = 0
end
if (M18_runtime.debris_flow_handle_02 ~= 0) then
debris_flow_destroy(M18_runtime.debris_flow_handle_02)
M18_runtime.debris_flow_handle_02 = 0
end
if (M18_runtime.wreckage_debris_flow_handle ~= 0) then
debris_flow_destroy(M18_runtime.wreckage_debris_flow_handle)
M18_runtime.wreckage_debris_flow_handle = 0
end
-- Allow the players to freely enter/exit vehicles again
set_player_can_enter_exit_vehicles(LOCAL_PLAYER, true)
if (coop_is_active() == true) then
set_player_can_enter_exit_vehicles(REMOTE_PLAYER, true)
end
for i, set in pairs(M18_free_fall_spawns) do
for j, wave in pairs(set) do
m18_helper_cleanup_free_fall_wave(wave.group)
end
end
-- Clean-up the first wave of VTOL flybys
for i, vtol_group in pairs(M18_groups.stag_vtol_flyby_01.vtol_groups) do
if (vtol_group.thread_id ~= -1 and thread_check_done(vtol_group.thread_id) == false) then
thread_kill(vtol_group.thread_id)
end
on_vehicle_destroyed("", vtol_group.vtol)
end
-- Clean-up the second wave of VTOL flybys
for i, vtol_group in pairs(M18_groups.stag_vtol_flyby_02.vtol_groups) do
if (vtol_group.thread_id ~= -1 and thread_check_done(vtol_group.thread_id) == false) then
thread_kill(vtol_group.thread_id)
end
on_vehicle_destroyed("", vtol_group.vtol)
end
-- Clean-up the dive bombers
for i, vtol_group in pairs(M18_groups.stag_dive_bombers_01.vtols) do
if (vtol_group.thread_id ~= -1 and thread_check_done(vtol_group.thread_id) == false) then
thread_kill(vtol_group.thread_id)
end
on_damage("", vtol_group.vtol)
on_vehicle_destroyed("", vtol_group.vtol)
end
-- Make sure there aren't any special vehicle VFX still playing
for i, tank_group in pairs(M18_runtime.skydiving_tanks) do
m18_helper_cleanup_skydiving_tank_common(tank_group)
end
m18_helper_cleanup_skydiving_tank_common(M18_groups.player_tank)
m18_helper_cleanup_skydiving_tank_common(M18_groups.skydiving_tank.tank_group)
thread_kill(M18_threads.random_clouds)
on_death("", M18_groups.skydiving_tank.tank_group.chars[2])
-- Clean-up the collide VTOL
on_vehicle_destroyed("", M18_groups.stag_vtol_flyby_01.vtol_collide.vtol)
on_collision("", M18_groups.stag_vtol_flyby_01.vtol_collide.vtol)
on_vehicle_destroyed("", M18_groups.stag_vtol_flyby_02.vtol_collide.vtol)
on_collision("", M18_groups.stag_vtol_flyby_02.vtol_collide.vtol)
-- Clear the on destroyed callback on the player's tank
on_vehicle_destroyed("", M18_groups.player_tank.tank)
if (coop_is_active() == true) then
turn_vulnerable(REMOTE_PLAYER)
end
-- Remove the player on-damaged callbacks
on_take_damage("", LOCAL_PLAYER)
if (coop_is_active() == true) then
on_take_damage("", REMOTE_PLAYER)
end
marker_remove(M18_groups.skydiving_tank.tank_group.tank)
hud_prompt_clear(LOCAL_PLAYER)
if (coop_is_active() == true) then
hud_prompt_clear(REMOTE_PLAYER)
end
-- Allow players to go into the downed state
set_players_can_be_downed(LOCAL_PLAYER, true)
if (coop_is_active() == true) then
set_players_can_be_downed(REMOTE_PLAYER, true)
end
-- Re-enable police notoriety spawning
notoriety_force_no_spawn("Police", false)
notoriety_force_no_spawn("stag", false)
end
-- ***************************************************
-- Miscellaneous m18 Helper Funcrtions
-- ***************************************************
-- Calculate the current threat level for free falling (count the number of tanks and guys on screen)
function m18_helper_get_free_fall_threat_level()
return M18_runtime.num_free_fall_chars_alive + (M18_runtime.num_free_fall_vehicles_alive * M18_tweak_values.enemy_tank_threat_level)
end
-- Helper to setup a skydiving enemy STAG guy
--
-- diver_table: Lua table defining the STAG skydiver
function m18_helper_setup_diver(diver_table)
character_show(diver_table.name)
character_set_skydiving(diver_table.name, true)
ai_add_enemy_target(diver_table.name, CLOSEST_PLAYER, ATTACK_NOW_NEVER_LOSE)
npc_leash_to_nav(diver_table.name, diver_table.nav, 3.0)
skydive_move_to_do(diver_table.name, diver_table.nav, false, 0, false, diver_table.forced_dive)
marker_add(diver_table.name, MINIMAP_ICON_KILL, OI_ASSET_KILL, OI_FLAGS_DEFAULT, SYNC_ALL)
ai_set_action_delay(diver_table.name, "fire", rand_float(1.0, 6.0))
turn_invulnerable(diver_table.name, true)
npc_suppress_persona(diver_table.name, true)
set_trailing_aim_flag(diver_table.name)
end
-- Setup a wave of free falling STAG enemies
--
-- group_table: Lua table defining the STAG wave group
function m18_helper_setup_free_fall_wave(group_table)
-- Loop over all the skydiving guys, and set them into the correct state
if (group_table.skydive_chars ~= nil) then
for i, skydive_char in pairs(group_table.skydive_chars) do
if (character_is_dead(skydive_char.name) == false) then
-- Set the skydiving state and give them to attack the player(s)
m18_helper_setup_diver(skydive_char)
-- Register for when this guy dies, so we can keep a count
on_death("m18_free_fall_character_killed_cb", skydive_char.name)
M18_runtime.num_free_fall_chars_alive = M18_runtime.num_free_fall_chars_alive + 1
end
end
end
-- Setup all the tanks
if (group_table.tank_groups ~= nil) then
local delay_time = 2.0
for i, tank_group in pairs(group_table.tank_groups) do
if (vehicle_is_destroyed(tank_group.tank) == false) then
-- Setup the tank
tank_group.thread_id = thread_new("m18_run_tank_fall_in_thread", tank_group, delay_time)
-- Register for when this vehicle is destroyed and add an object indicator
on_vehicle_destroyed("m18_free_fall_vehicle_destroyed_cb", tank_group.tank)
M18_runtime.num_free_fall_vehicles_alive = M18_runtime.num_free_fall_vehicles_alive + 1
end
delay_time = delay_time + 3.0
end
end
end
-- Cleanup a wave of free falling STAG enemies
--
-- group_table: Lua table defining the STAG wave group
function m18_helper_cleanup_free_fall_wave(group_table)
-- Loop over all the skydiving guys, and clear any callbacks
if (group_table.skydive_chars ~= nil) then
for i, skydive_char in pairs(group_table.skydive_chars) do
on_death("", skydive_char.name)
end
end
-- Kill any running threads and remove and callbacks for the tanks
if (group_table.tank_groups ~= nil) then
for i, tank_group in pairs(group_table.tank_groups) do
m18_helper_cleanup_skydiving_tank_common(tank_group)
end
end
end
-- Helper to remove the markers on enemies in the free fall waves
function m18_helper_clear_free_fall_wave_markers()
-- Remove all the object indicators on all the enemies in the first enemy set
for i, spawn_set in pairs(M18_free_fall_spawns) do
for j, wave in pairs(spawn_set) do
if (group_is_loaded(wave.group.name) == true) then
if (wave.group.skydive_chars ~= nil) then
for k, skydive_char in pairs(wave.group.skydive_chars) do
marker_remove(skydive_char.name)
end
end
if (wave.group.tank_groups ~= nil) then
for k, tank_group in pairs(wave.group.tank_groups) do
marker_remove(tank_group.tank)
end
end
end
end
end
end
-- Helper to restore the markers on enemies in the free fall waves
function m18_helper_restore_free_fall_wave_markers()
-- Remove all the object indicators on all the enemies in the first enemy set
for i, spawn_set in pairs(M18_free_fall_spawns) do
for j, wave in pairs(spawn_set) do
if (group_is_loaded(wave.group.name) == true) then
if (wave.group.skydive_chars ~= nil) then
for k, skydive_char in pairs(wave.group.skydive_chars) do
if (character_is_dead(skydive_char.name) == false) then
marker_add(skydive_char.name, MINIMAP_ICON_KILL, OI_ASSET_KILL)
end
end
end
if (wave.group.tank_groups ~= nil) then
for k, tank_group in pairs(wave.group.tank_groups) do
if (vehicle_is_destroyed(tank_group.tank) == false) then
marker_add(tank_group.tank, MINIMAP_ICON_KILL, OI_ASSET_KILL_FULL)
end
end
end
end
end
end
end
-- Callback for when an ememy character from Part 1 is killed
--
-- victim: The character that was killed
-- attacker: The character that killed the victim
function m18_free_fall_character_killed_cb(victim, attacker)
-- Decrement the number of guys alive
M18_runtime.num_free_fall_chars_alive = M18_runtime.num_free_fall_chars_alive - 1
marker_remove(victim)
-- Clean-up the dead guy
on_death("", victim)
end
-- Callback for when an enemy vehicle from Part 1 is killed
--
-- vehicle: The vehicle that was destroyed
function m18_free_fall_vehicle_destroyed_cb(vehicle)
-- Decrement the number of vehicles alive
M18_runtime.num_free_fall_vehicles_alive = M18_runtime.num_free_fall_vehicles_alive - 1
-- Clean-up the destroyed vehicle
on_vehicle_destroyed("", vehicle)
marker_remove(vehicle)
m18_cb_skydiving_vehicle_destroyed_common(vehicle)
end
-- A helper function to display the placeholder dialog lines
--
-- dialog: Lua table speicifying the a set of dialog lines (as defined in M18_placholder_dialog)
function m18_run_placeholder_dialog_lines(dialog, override)
-- If a previous dialog thread is still active, then kill it first
if (M18_threads.place_holder_dialog ~= -1 and thread_check_done(M18_threads.place_holder_dialog) == false) then
if (override == false) then
return
end
thread_kill(M18_threads.place_holder_dialog)
thread_yield()
end
-- Start the new thread
M18_threads.place_holder_dialog = thread_new("m18_process_placeholder_dialog_thread", dialog)
end
-- Setup for the VTOLs that flyby the player
--
-- vtol_group: The VTOL group Lua table (as defined at the top of this file)
function m18_helper_setup_vtol_flyby_group(vtol_group)
vehicle_enter_group_teleport(vtol_group.chars, vtol_group.vtol)
for j, char in pairs(vtol_group.chars) do
character_set_skydiving(char, true)
ai_add_enemy_target(char, CLOSEST_PLAYER, ATTACK_NOW_NEVER_LOSE, true)
end
end
-- Thread to process launching a box with a delay
function m18_thread_launch_box(box_group)
delay(box_group.delay)
mesh_mover_apply_impulse(box_group.box, box_group.launch_dir, box_group.impulse)
end
-- Function to process toppling a set of boxes
function m18_helper_topple_boxes(box_set)
for i, box_group in pairs(box_set) do
thread_new("m18_thread_launch_box", box_group)
end
end
-- Check if a particular conversation is done
--
-- convo_table: Conversation Lua table (see M18_conversations)
function m18_helper_conversation_check_done(convo_table)
if (convo_table.in_queue == false) then
return true
else
return convo_table.ended
end
end
-- Check if a particular conversation is playing or queued
--
-- conver_table: Conversatino Lua table (see M18_conversations)
function m18_helper_conversation_playing_or_queued(convo_table)
return (convo_table.in_queue == true or (convo_table.started == true and convo_table.ended == false))
end
-- Helper to play conversations, by adding them to the cue
--
-- convo_table: Conversation Lua table (see M18_conversations)
-- priority: Desired priority for the conversation
-- delay: Amonut of time to dalya after this conversation before playing the next conversation (in seconds)
-- player: Player who should be speaking in the conversation, or nil to always play on the host (defaults to nil)
function m18_helper_conversation_play(convo_table, priority, delay, player)
if (m18_helper_conversation_check_done(convo_table) == false) then
return
end
convo_table.in_queue = true
convo_table.started = false
convo_table.completed = false
convo_table.ended = false
convo_table.delay = delay
convo_table.player = player
if (priority == M18_CONVO_PLAY_LAST) then
-- Insert this entry at the end of hte lsit
M18_runtime.convo_queue.list[M18_runtime.convo_queue.size] = convo_table
M18_runtime.convo_queue.size = M18_runtime.convo_queue.size + 1
elseif (priority == M18_CONVO_PLAY_NEXT) then
-- Shift the list to the right
for i = M18_runtime.convo_queue.size - 1, 0, -1 do
M18_runtime.convo_queue.list[i + 1] = M18_runtime.convo_queue.list[i]
end
M18_runtime.convo_queue.list[0] = convo_table
M18_runtime.convo_queue.size = M18_runtime.convo_queue.size + 1
elseif (priority == M18_CONVO_PLAY_IMMEDIATE) then
-- Shift the list to the right
for i = M18_runtime.convo_queue.size - 1, 0, -1 do
M18_runtime.convo_queue.list[i + 1] = M18_runtime.convo_queue.list[i]
end
M18_runtime.convo_queue.list[0] = convo_table
M18_runtime.convo_queue.size = M18_runtime.convo_queue.size + 1
-- Stop any actively playing conversations, and start this one immediatly
m18_helper_conversation_cleanup_playing(true)
end
end
-- Kill any active conversation, and clear out the conversation queue
function m18_helper_conversation_kill_all()
-- Stop any active conversation
m18_helper_conversation_cleanup_playing(false)
-- Clear out the queue
for i = 0, M18_runtime.convo_queue.size - 1 do
M18_runtime.convo_queue.list[i].ended = true
end
M18_runtime.convo_queue.size = 0
end
-- Cleanup any playing conversation
function m18_helper_conversation_cleanup_playing(wait_for_end)
-- Stop the thread processing a playing conversation
if (M18_runtime.convo_queue.playing.thread_id ~= -1) then
thread_kill(M18_runtime.convo_queue.playing.thread_id)
M18_runtime.convo_queue.playing.thread_id = -1
end
-- Cleanup and conversation data for a playing conversation
if (M18_runtime.convo_queue.playing.conv_handle ~= INVALID_CONVERSATION_HANDLE) then
if (M18_runtime.convo_queue.playing.convo_table.is_convo == true) then
audio_conversation_end(M18_runtime.convo_queue.playing.conv_handle)
if (wait_for_end) then
audio_conversation_wait_for_end(M18_runtime.convo_queue.playing.conv_handle)
end
else
audio_stop(M18_runtime.convo_queue.playing.conv_handle)
end
M18_runtime.convo_queue.playing.conv_handle = INVALID_CONVERSATION_HANDLE
end
-- Mark the playing conversation as ended
if (M18_runtime.convo_queue.playing.convo_table ~= nil) then
M18_runtime.convo_queue.playing.convo_table.ended = true
M18_runtime.convo_queue.playing.convo_table.in_queue = false
end
end
-- Thread to process playing a single converation
function m18_thread_play_convo(convo_table)
-- Add this conversatin to the playing conversation data
M18_runtime.convo_queue.playing.convo_table = convo_table
convo_table.started = true -- it has now started
convo_table.in_queue = false
-- Handle playing a conversation or one-off line
if (convo_table.is_convo == true) then
-- Play the conversation
if (convo_table.load_direct == false) then
if (convo_table.player ~= nil) then
M18_runtime.convo_queue.playing.conv_handle = audio_conversation_load_player(convo_table.name, convo_table.player)
else
M18_runtime.convo_queue.playing.conv_handle = audio_conversation_load(convo_table.name)
end
else
M18_runtime.convo_queue.playing.conv_handle = audio_conversation_load_direct(convo_table.name)
end
-- Play the conversation and wait for it to end
audio_conversation_play(M18_runtime.convo_queue.playing.conv_handle)
audio_conversation_wait_for_end(M18_runtime.convo_queue.playing.conv_handle)
audio_conversation_end(M18_runtime.convo_queue.playing.conv_handle)
else
-- Play the dialog line
if (convo_table.play_2d == true) then
M18_runtime.convo_queue.playing.conv_handle = audio_play_persona_line_2d(convo_table.character, convo_table.name)
else
M18_runtime.convo_queue.playing.conv_handle = audio_play_persona_line(convo_table.character, convo_table.name)
end
-- Wait for the line to finish
while(audio_is_playing(M18_runtime.convo_queue.playing.conv_handle) == true) do
thread_yield()
end
end
-- Do some book-keeping
M18_runtime.convo_queue.playing.conv_handle = INVALID_CONVERSATION_HANDLE
convo_table.completed = true
convo_table.ended = true
-- Delay the desired amount
delay(convo_table.delay)
end
-- Process the conversation queue (should be running the duration of the mission)
function m18_thread_process_conversations()
-- Loop forever
while(true) do
-- Wait until something is added to the queue and there isn't an active conversation thread playing
while(M18_runtime.convo_queue.size == 0 or thread_check_done(M18_runtime.convo_queue.playing.thread_id) == false) do
thread_yield()
end
-- Play the first conversation from the queue, and then remove it from the qeue
M18_runtime.convo_queue.playing.thread_id = thread_new("m18_thread_play_convo", M18_runtime.convo_queue.list[0])
for i = 1, M18_runtime.convo_queue.size do
M18_runtime.convo_queue.list[i - 1] = M18_runtime.convo_queue.list[i]
end
M18_runtime.convo_queue.size = M18_runtime.convo_queue.size - 1
-- Wait for the active conversation thread to end
while(thread_check_done(M18_runtime.convo_queue.playing.thread_id) == false) do
thread_yield()
end
M18_runtime.convo_queue.playing.thread_id = INVALID_THREAD_HANDLE
delay(0.2)
end
end
-- Function to setup common skydiving tank properties
--
-- tank_group: Lua table defining the tank group
--set_destroyed_callback: TRUE to set the default vehicle destroyed callback, FALSE if a callback is already set (callback should call destroyed common)
function m18_helper_setup_skydiving_tank_common(tank_group, set_destroyed_callback)
-- Start the looping "wobble" animation
vehicle_anim_start(tank_group.tank, "MAD18 Tank", "")
-- Attach some contrail effects to the tank
for i, tag in pairs(M18_tweak_values.tank_streamers_tags) do
for j=0, 1 do
tank_group.contrail_handles[1 + (i - 1) * 2 + j] = effect_play_on_script_object(M18_vfxs.tank_streamers.nav, tank_group.tank, tag, true, SYNC_ALL, (j + 1))
end
end
-- Store this tank in the skydiving tanks, and register the damage callback
M18_runtime.skydiving_tanks[#M18_runtime.skydiving_tanks + 1] = tank_group
vehicle_disable_explosion_and_damage_vfx(tank_group.tank, true)
on_damage("m18_cb_skydiving_vehicle_damaged", tank_group.tank, 0.2)
if (set_destroyed_callback == true) then
on_vehicle_destroyed("m18_cb_skydiving_vehicle_destroyed_common", tank_group.tank)
end
end
-- Function to cleanup common skydiving tank properties
--
-- tank_group: Lua table defining the tank group
function m18_helper_cleanup_skydiving_tank_common(tank_group)
if (tank_group.thread_id ~= nil and thread_check_done(tank_group.thread_id) == false) then
thread_kill(tank_group.thread_id)
tank_group.thread_id = INVALID_THREAD_HANDLE
end
if (tank_group.fire_handle ~= -1) then
effect_stop(tank_group.fire_handle)
tank_group.fire_handle = -1
end
if (tank_group.exp_handle ~= -1) then
effect_stop(tank_group.exp_handle)
tank_group.exp_handle = -1
end
for i, handle in pairs(tank_group.contrail_handles) do
if (handle ~= nil) then
effect_stop(handle)
tank_group.contrail_handles[i] = nil
end
end
on_damage("", tank_group.tank)
on_vehicle_destroyed("", tank_group.tank)
end
-- *************************
--
-- Callback functions
--
-- *************************
-- Gun crate functions
function m18_cb_gun_crate_empty(player, trigger)
-- Disable the trigger and remove the marker
trigger_enable(trigger, false)
marker_remove_trigger(trigger, SYNC_ALL)
-- Play a rummaging animation
local orientation_nav = M18_navpoints.gun_crate_orients[1]
local crate_mover = M18_movers.gun_crate[1]
if (trigger == M18_triggers.gun_crate_002) then
orientation_nav = M18_navpoints.gun_crate_orients[2]
crate_mover = M18_movers.gun_crate[2]
end
door_open(crate_mover, false, true, player, "M18 Open Crate", orientation_nav)
--action_play(player, "M18 Open Crate", "M18 Open Crate", false, 0.8, true, true, orientation_nav)
delay(2.0)
-- Play some dialog
if (M18_flags.sonic_gun_failed_once) then
m18_helper_conversation_play(M18_convo.sonic_gun_failed_02, M18_CONVO_PLAY_IMMEDIATE, 1.0, player)
else
m18_helper_conversation_play(M18_convo.sonic_gun_failed_01, M18_CONVO_PLAY_IMMEDIATE, 1.0, player)
M18_flags.sonic_gun_failed_once = true
end
end
-- Callback for when the crate containing the sonic gun is opened
--
-- player: player that opened the crate with the sonic gun
-- trigger: trigger volume for the crate
function m18_cb_gun_crate_give_sonic_gun(player, trigger)
-- Disable the trigger and remove the marker
trigger_enable(trigger, false)
marker_remove_trigger(trigger, SYNC_ALL)
-- Play a rummaging animation
door_open(M18_movers.gun_crate[3], false, true , player, "M18 Open Crate", M18_navpoints.gun_crate_orients[3])
-- action_play(player, "M18 Open Crate", "M18 Open Crate", false, 0.8, true, true, M18_navpoints.gun_crate_orients[3])
delay(2.0)
-- Add this weapon again as a temporary weapon, so that the player cannot drop it
local equip = true
inv_weapon_add_temporary(LOCAL_PLAYER, "Special-SonicGun", 1, true, equip, false)
if (coop_is_active() == true) then
-- MLG (06/30/11): Always equip the sonic gun
--local equip = inv_item_is_equipped("Special-SonicGun", REMOTE_PLAYER) -- obey whatever the equip status was after picking up the sonic gun
inv_weapon_add_temporary(REMOTE_PLAYER, "Special-SonicGun", 1, true, equip, false)
end
-- They have gotten the sonic gun
M18_flags.sonic_gun_aquired = true
-- Remove other triggers
trigger_enable(M18_triggers.gun_crate_001, false)
trigger_enable(M18_triggers.gun_crate_002, false)
trigger_enable(M18_triggers.gun_crate_003, false)
marker_remove_trigger(M18_triggers.gun_crate_001, SYNC_ALL)
marker_remove_trigger(M18_triggers.gun_crate_002, SYNC_ALL)
marker_remove_trigger(M18_triggers.gun_crate_003, SYNC_ALL)
-- Make all of the boxes vulnerable now
for i, box_group in pairs(M18_movers.plane_boxes_01) do
mesh_mover_set_invulnerable(box_group.box, false)
end
-- If the player(s) have already attempted to open the door, then we need to update some object indicators
if (M18_flags.cabin_door_open_attempted == true) then
-- Setup the door to be destroyed
marker_add(M18_navpoints.cabin_door_marker, MINIMAP_ICON_KILL, OI_ASSET_KILL_FULL, OI_FLAGS_FULL, SYNC_ALL)
objective_text(0, M18_objectives.destroy_cockpit.tag, nil, nil, SYNC_ALL, M18_objectives.destroy_cockpit.icon)
-- Start a dialog conversation
m18_helper_conversation_play(M18_convo.sonic_gun, M18_CONVO_PLAY_NEXT, 1.0, player)
end
end
-- Common processing for when a grunt detects a player
function m18_grunt_detection_common_cb(grunt, player)
-- Unregister the grunt's on_detection callback
on_detection("", grunt)
-- Cleanup his idle animation state
clear_animation_state(grunt)
npc_combat_enable(grunt, true)
follower_make_independent(grunt, false)
end
-- Callback for when a grunt with attack immediate orders detects a player
function m18_grunt_detection_attack_immediate_cb(grunt, player)
-- Do common processing/cleanup on this grunt
m18_grunt_detection_common_cb(grunt, player)
-- Start attacking the player
npc_leash_remove(grunt)
ai_add_enemy_target(grunt, player, ATTACK_NOW, false)
end
-- Callback for when a grunt with defend orders detects a player
function m18_grunt_detection_defend_cb(grunt, player)
-- Do common processing/cleanup on this grunt
m18_grunt_detection_common_cb(grunt, player)
-- Tell him to take cover
ai_do_scripted_take_cover(grunt)
end
-- Callback for when a grunt with move to cat walk orders detects a player
function m18_grunt_detection_cat_walk_cb(grunt, player)
-- Do common processing/cleanup on this grunt
m18_grunt_detection_common_cb(grunt, player)
-- Do a scripted rush up to the cat-walk, and then advance to the player
npc_leash_remove(grunt)
ai_do_scripted_move(grunt, M18_navpoints.grunt_catwalk_start, true, true)
on_ai_do_action_complete("m18_grunt_reached_catwalk_cb", grunt)
end
-- Callback for when a grunt reaches the catwalk (so that we can tell them which node to run to based on the order they reach the cat walk)
function m18_grunt_reached_catwalk_cb(grunt)
-- Clear the ai action complete callback
on_ai_do_action_complete("", grunt)
-- Move the grunt to the appropriate navpoint on the catwalk, and increment our count
M18_runtime.num_grunts_to_reach_catwalk = M18_runtime.num_grunts_to_reach_catwalk + 1
ai_do_scripted_move(grunt, M18_navpoints.grunt_catwalk_positions[M18_runtime.num_grunts_to_reach_catwalk], true, true)
end
-- Find a skydiving vehicle Lua table, by vehicle name
--
-- vehicle_name: Name of the vehicle to search for
function m18_helper_find_skydiving_vehicle(vehicle_name)
for i, tank_group in pairs(M18_runtime.skydiving_tanks) do
if (tank_group.tank == vehicle_name) then
return tank_group
end
end
return nil
end
-- Callback when one a skydiving vehicles gets damaged
--
-- vehicle_name: Name of the vehicle that was damaged
function m18_cb_skydiving_vehicle_damaged(vehicle_name)
-- Remove the on_damage callback
on_damage("", vehicle_name)
-- Find the vehicle, and turn it on fire
local vehicle_table = m18_helper_find_skydiving_vehicle(vehicle_name)
if (vehicle_table ~= nil) then
if (vehicle_table.fire_handle == -1) then
-- We found the vehicle, spawn some fire on it
vehicle_table.fire_handle = effect_play_on_script_object(M18_vfxs.debris_fire.nav, vehicle_table.tank, nil, true)
return
end
end
end
-- Callback when one of the debris vehicles gets destroyed
--
-- vehicle_name: Name of the vehicle that was destroyed
function m18_cb_skydiving_vehicle_destroyed_common(vehicle_name)
-- Remove the callback and trigger an explosion
on_vehicle_destroyed("", vehicle_name)
-- Find the vehicle and turn it on fire
local vehicle_table = m18_helper_find_skydiving_vehicle(vehicle_name)
if (vehicle_table ~= nil) then
if (vehicle_table.fire_handle == -1) then
-- We found the vehicle, spawn some fire on it
vehicle_table.fire_handle = effect_play_on_script_object(M18_vfxs.debris_fire.nav, vehicle_table.tank, nil, true)
return
end
vehicle_table.exp_handle = explosion_create("Mission02 Car Exp", vehicle_table.tank, nil, true, M18_vfxs.car_exp.nav)
end
end
-- Callback for whent he player's tank has been destroyed
function m18_player_tank_destroyed_cb()
character_kill(LOCAL_PLAYER, true)
if (coop_is_active() == true) then
character_kill(REMOTE_PLAYER, true)
end
end
-- Callback for when one of the flyby vehicles is destroyed
function m18_flyby_vtol_destroyed_cb(vehicle)
-- Remove the keyframed physics, so the VTOL can explode properly
vehicle_set_keyframed_physics(vehicle, false)
-- Remove the marker
marker_remove(vehicle)
end
-- Callback for when a VTOL collides with an object (used to check when a VTOL collides with the player's
function m18_vtol_collision_cb(vehicle, collided_with)
if (collided_with == M18_groups.player_tank.tank) then
on_collision("", vehicle)
thread_kill(M18_threads.vtol_collide)
end
end
-- *************************
--
-- Thread functions
--
-- *************************
-- Process the placeholder dialog lines
--
-- dialog: Lua table speicifying the a set of dialog lines (as defined in M18_placholder_dialog)
function m18_process_placeholder_dialog_thread(dialog)
for i, line in pairs(dialog) do
message(line.text, 8.0)
delay(line.duration)
end
end
-- Processing for "dropping" the enemy tanks in from above the player
--
-- tank_group: The tank group Lua table (as defined at the top of this file)
function m18_run_tank_fall_in_thread(tank_group, delay_time)
-- Wait for the delay time
delay(delay_time)
-- Setup the tank
vehicle_show(tank_group.tank)
if (vehicle_is_destroyed(tank_group.tank) == false) then
-- Make sure the AI doesn't try and flee or chase (they can't anyways, and it caused them not to fire)
vehicle_disable_chase(tank_group.tank, true)
vehicle_disable_flee(tank_group.tank, true)
m18_helper_setup_skydiving_tank_common(tank_group, false)
-- Set the tank skydiving, and teleport all the characters into the tank
vehicle_skydiving_start(tank_group.tank, tank_group.orient)
if (tank_group.dest ~= nil) then
vehicle_skydiving_move_to_do(tank_group.tank, tank_group.dest, 8.0, 8.0)
end
vehicle_enter_group_teleport(tank_group.chars, tank_group.tank)
-- Add an object indicatoro
marker_add(tank_group.tank, MINIMAP_ICON_KILL, OI_ASSET_KILL_FULL, OI_FLAGS_FULL, SYNC_ALL)
end
-- Loop over each character, and set them up
for j, char in pairs(tank_group.chars) do
character_show(char)
if (character_is_dead(char) == false) then
-- Set them skydiving, give them attack orders, and register a callback for when they die
--character_set_skydiving(char, true)
ai_add_enemy_target(char, CLOSEST_PLAYER, ATTACK_NOW_NEVER_LOSE)
end
end
end
-- Processing for the VTOL flyby pathfind
--
-- vtol_group: The VTOL group Lua table (as defined at the top of this file)
function m18_run_vtol_flyby_thread(vtol_group)
delay(vtol_group.delay)
-- Register a callback for when the VTOL is destroyed (so we can remove the keyframed physics)
on_vehicle_destroyed("m18_flyby_vtol_destroyed_cb", vtol_group.vtol)
-- Set the vehicle as skydiving (so the debris will have zero gravity if the VTOL gets destroyed
vehicle_skydiving_start(vtol_group.vtol)
-- Move the VTOL into place and start the vehicle animation
vehicle_set_special_override_never_ghost(vtol_group.vtol, true)
vtol_flyby_animation_for_m18(vtol_group.vtol, vtol_group.animation, vtol_group.start_pos, vtol_group.speed_multiplier)
delay(1.0)
-- Make sure the VTOL objects are visible
vehicle_show(vtol_group.vtol)
for i, char in pairs(vtol_group.chars) do
character_show(char)
end
-- Add a marker for the VTOL
marker_add(vtol_group.vtol, MINIMAP_ICON_KILL, OI_ASSET_KILL_FULL, OI_FLAGS_FULL, SYNC_ALL)
if (vtol_group.whoosh_trigger ~= nil) then
-- Wait until the animation reaches the whoosh trigger
while (vehicle_anim_finished(vtol_group.vtol, vtol_group.whoosh_trigger) == false) do
thread_yield()
end
audio_object_post_event(M18_audio_events.vtol_flyby, nil, nil, vtol_group.vtol)
end
-- Wait until the animation is finished
while(vehicle_anim_playing(vtol_group.vtol) == true) do
thread_yield()
end
-- Remove the marker
marker_remove(vtol_group.vtol)
end
-- Processing for the vTOL flyby pathfind, but also hides the vehicle once the pathfind has completed
--
-- vtol_group: The VTOL group Lua table (as defined at the top of this file)
-- speed: The speed for the pathfind
function m18_run_vtol_flyby_hide_thread(vtol_group, speed)
-- Setup the vtol group and then wait the specified delay
m18_helper_setup_vtol_flyby_group(vtol_group)
-- Do the base pathfind
m18_run_vtol_flyby_thread(vtol_group, speed)
-- If the VTOL was not destroyed, then hide it
if (vehicle_is_destroyed(vtol_group.vtol) == false) then
vehicle_hide(vtol_group.vtol)
for i, char in pairs(vtol_group.chars) do
character_hide(char)
end
end
end
-- Thread to process randomly generated cloud VFX
function m18_thread_generate_clouds()
-- loop forever
while(true) do
delay(rand_int(M18_tweak_values.skydive_cloud_min_cooldown_time, M18_tweak_values.skydive_cloud_max_cooldown_time))
-- Make sure we clean up the old effect first
if (M18_vfxs.random_clouds.handle ~= -1) then
effect_stop(M18_vfxs.random_clouds.handle)
thread_yield()
end
if (M18_vfxs.random_clouds_remote.handle ~= -1) then
effect_stop(M18_vfxs.random_clouds_remote.handle)
thread_yield()
end
-- Play the cloud "puff" effect
M18_vfxs.random_clouds.handle = effect_play_on_human(M18_vfxs.random_clouds.nav, LOCAL_PLAYER, nil, false, SYNC_LOCAL)
if (coop_is_active() == true) then
M18_vfxs.random_clouds_remote.handle = effect_play_on_human(M18_vfxs.random_clouds_remote.nav, REMOTE_PLAYER, nil, false, SYNC_REMOTE)
end
end
end
-- Thread to process giggling the boxes from turbulance
function m18_thread_process_box_jiggle()
while(true) do
delay(rand_float(M18_tweak_values.escape_box_impulse_delay[1], M18_tweak_values.escape_box_impulse_delay[2]))
local impulse = rand_int(M18_tweak_values.escape_box_impulse_amount[1], M18_tweak_values.escape_box_impulse_amount[2])
local direction = M18_navpoints.plane_box_turbulance[rand_int(1, #(M18_navpoints.plane_box_turbulance))]
for i, box_group in pairs(M18_movers.plane_boxes_01) do
mesh_mover_apply_impulse(box_group.box, direction, impulse)
end
thread_yield()
end
end
-- Thread to process the dust VFX in the cargo plane cabin during turbulance
function m18_thread_do_plane_dust_vfx()
-- Trigger the turbulance VFX
local idx = rand_int(1, #(M18_navpoints.cargo_dust))
for i, nav in pairs(M18_navpoints.cargo_dust) do
effect_play(nav)
delay(0.07)
idx = idx + 1
if (idx > #(M18_navpoints.cargo_dust)) then
idx = 1
end
end
end