--[[
m13.lua
SR3 Mission Script
DATE: 09-13-2010
AUTHOR: Craig Williams
]]--
-- Debug flags --
M13_ENABLE_BINKS = true
-- Tweakable Parameters --
M13_config = {
-- PR Center settings
min_notoriety_after_banner_damaged = 1,
min_notoriety_after_banner_destroyed = 2,
min_notoreity_after_all_banners_destroyed = 3,
-- Chain reaction settings
chain_reaction_max_dist = 40.00, -- Radius of the chain reaction effect from a car bomb
chain_reaction_delay = 3.00, -- Delay in seconds to wait before a chain reaction detonates another car bomb
chain_reaction_scale_delay = true, -- True to scale the delay. Closer bombs will go off sooner then farther ones.
chain_reaction_scale_mul = 1.00, -- Scales the amount of delay based off the distance
-- Wave specific settings
saints_hq_radius = 75.0, -- Distance in meters that the player is allowed to get away from the Saints HQ enterance
saints_hq_radius_warn = 50.0, -- Distance to warn the player if they are getting to far away from the HQ
-- Decision scene settings
time_to_escape = 30.0, -- Time, in seconds, that the player has to escape the penthouse
fov_to_shaundi = 15.0, -- Field of view in degrees to use to check if Shaundi is in the player's view
fov_to_cyrus = 20.0, -- Field of view in degrees to use to check if Cyrus is in the player's view
-- Temporary weapon settings
grenade = "molotov",
airstrike = "Special-Airstrike",
}
-- Non-Respawning Groups --
-- List of all non-wave related groups in the mission
M13_groups = {
vehicles_start = {
name = "group_vehicles_start",
vehicles = { "vehicle_start 001", "vehicle_start 002" }
},
vehicles_cover = {
name = "group_vehicles_cover",
vehicles = { "vehicle_cover 001", "vehicle_cover 002", "vehicle_cover 003" }
},
pierce_start = {
name = "group_pierce_start",
pierce = "npc_pierce_start",
vehicle = "Script_Vehicle 003",
},
pr_static = {
name = "group_pr_static",
},
homies = {
name = "group_homies",
viola = "npc_viola",
--oleg = "npc_oleg",
},
weapons = {
name = "group_weapons",
airstrike = "weapon_airstrike",
},
pierce_rescue = {
name = "group_pierce_rescue",
pierce = "npc_pierce_rescue",
vehicle = "vehicle_pierce_rescue",
path = "path_pierce_rescue",
},
pierce_attack = {
name = "group_pierce_attack",
tank = "vehicle_pierce_tank",
tank_members = {"npc_pierce_tank_driver", "npc_pierce_tank_gunner",},
path = "path_pierce_attack",
},
penthouse_homies = {
name = "group_penthouse_homies",
josh = "npc_josh_penthouse",
shaundi = "npc_shaundi_penthouse",
},
penthouse_stag = {
name = "group_penthouse_stag",
cyrus = "npc_cyrus",
vtols = {
{
name = "vehicle_vtol 001",
members = {"npc_vtol 001",},
nav = "nav_vtol 001",
nav_fire = "nav_vtol_fire 001",
fly_to = "",
nav_flee = "nav_vtol 006",
thread = INVALID_THREAD_HANDLE,
nav_turn_around = "nav_vtol 005",
},
{
name = "vehicle_vtol 002",
members = {"npc_vtol 006", "npc_vtol 007",},
nav = "nav_vtol 002",
nav_fire = "nav_vtol_fire 002",
fly_to = "nav_vtol 002<001>",
nav_flee = "nav_vtol 007",
thread = INVALID_THREAD_HANDLE,
},
{
name = "vehicle_vtol 003",
members = {"npc_vtol 010",},
nav = "nav_vtol 003<001>",
nav_fire = "nav_vtol_fire 003",
fly_to = "nav_vtol 003",
nav_flee = "nav_vtol 009",
thread = INVALID_THREAD_HANDLE,
},
{
name = "vehicle_vtol 004",
members = {"npc_vtol 005",},
nav = "nav_vtol 004<001>",
nav_fire = "nav_vtol_fire 004",
fly_to = "nav_vtol 004",
nav_flee = "nav_vtol 008",
thread = INVALID_THREAD_HANDLE,
},
},
},
clutter_south = {
name = "grp clutter south",
vehicles = {
"veh_clutter_south_apc <001>", "veh_clutter_south_apc <002>", "veh_clutter_south_apc <003>",
"veh_clutter_south_apc <004>", "veh_clutter_south_apc <005>", "veh_clutter_south_apc <006>",
}
},
clutter_north = {
name = "grp clutter north",
vehicles = {
"veh_clutter_north_apc <001>", "veh_clutter_north_apc <002>", "veh_clutter_north_apc <003>",
"veh_clutter_north_apc <004>", "veh_clutter_north_apc <005>", "veh_clutter_north_apc <006>",
}
},
clutter_general = {
name = "grp clutter general",
vehicles = {
"veh_clutter_general_apc <001>", "veh_clutter_general_apc <002>", "veh_clutter_general_apc <003>",
"veh_clutter_general_apc <004>", "veh_clutter_general_apc <005>", "veh_clutter_general_apc <006>",
"veh_clutter_general_apc <007>", "veh_clutter_general_apc <008>", "veh_clutter_general_apc <009>",
"veh_clutter_general_apc <010>", "veh_clutter_general_apc <011>", "veh_clutter_general_apc <012>",
"veh_clutter_general_apc <013>", "veh_clutter_general_apc <014>", "veh_clutter_general_apc <015>",
}
},
}
-- Continuous Spawn Groups --
M13_continuous_spawns = {
-- pr_center_wave_1 = {
-- groups = {"group_pr_spawn 001",},
-- regions = {"Script_Spawn_Region 004", "Script_Spawn_Region 006",},
-- filter = SRF_1,
-- respawn_delay = 2.0,
-- },
-- pr_center_wave_2 = {
-- groups = {"group_pr_spawn 002", "group_pr_spawn 003",},
-- regions = {"Script_Spawn_Region 003", "Script_Spawn_Region 005",},
-- filter = SRF_1,
-- respawn_delay = 2.0,
-- },
saints_north_ground = {
groups = {"group_saints_ground 001", "group_saints_ground 002"},
regions = {"Script_Spawn_Region 001",},
filter = SRF_1,
respawn_delay = 3.0,
},
saints_north_balcony = {
groups = {"group_saints_ground 003"},
regions = {"Script_Spawn_Region 001<001>",},
filter = SRF_1,
respawn_delay = 3.0,
},
saints_south_ground = {
groups = {"group_saints_ground 005", "group_saints_ground 006",},
regions = {"Script_Spawn_Region 002",},
filter = SRF_2,
respawn_delay = 3.0,
},
saints_south_balcony = {
groups = {"group_saints_ground 007"},
regions = {"Script_Spawn_Region 001<002>",},
filter = SRF_2,
respawn_delay = 3.0,
},
stag_deck_01 = {
groups = { "deck_wave_group 001", "deck_wave_group 002" },
regions = { "stag_deck_spn 001", "stag_deck_spn 002", "stag_deck_spn 003", "stag_deck_spn 004" },
filter = SRF_3,
respawn_delay = 3.0,
},
stag_deck_02 = {
groups = { "deck_wave_group 003", "deck_wave_group 004" },
regions = { "stag_deck_spn 001", "stag_deck_spn 002", "stag_deck_spn 003", "stag_deck_spn 004" },
filter = SRF_3,
respawn_delay = 3.0,
},
}
M13_passengers_available = {
--[[ [ "group_passengers_001" ] = { members = { "npc_stag 032", "npc_stag 042", "npc_stag 072", } },
[ "group_passengers_002" ] = { members = { "npc_stag 082", "npc_stag 112", "npc_stag 122", } },
[ "group_passengers_003" ] = { members = { "npc_stag 262", "npc_stag 263", "npc_stag 264", } },
[ "group_passengers_004" ] = { members = { "npc_stag 265", "npc_stag 266", "npc_stag 267", } },
[ "group_passengers_005" ] = { members = { "npc_stag 268", "npc_stag 269", "npc_stag 270", } },
[ "group_passengers_006" ] = { members = { "npc_stag 271", "npc_stag 272", "npc_stag 273", } },
[ "group_passengers_007" ] = { members = { "npc_stag 274", "npc_stag 275", "npc_stag 276", } },
[ "group_passengers_008" ] = { members = { "npc_stag 277", "npc_stag 278", "npc_stag 279", } },
[ "group_passengers_009" ] = { members = { "npc_stag 280", "npc_stag 281", "npc_stag 282", } }, ]]
}
M13_passengers_active = { }
-- Spawn Wave Groups --
-- name - Name of the group
-- members - Script NPCs of the group
-- vehicle - Vehicle in the group. Set this to "" if there isn't one.
-- initial_delay - Amount of time to wait before spawning the first iteration of this group
-- respawn_delay - Amount of time to wait between respawns
-- thread - Lua thread controlling the group.
M13_spawn_groups = {
apc_001 = {
name = "group_stag_apc 001",
members = {"npc_stag 010", "npc_stag 011",},
vehicle = "vehicle_apc 001",
},
apc_002 = {
name = "group_stag_apc 002",
members = {"npc_stag 020", "npc_stag 021",},
vehicle = "vehicle_apc 002",
},
apc_003 = {
name = "group_stag_apc 003",
members = {"npc_stag 030", "npc_stag 031", },
vehicle = "vehicle_apc 003",
},
apc_004 = {
name = "group_stag_apc 004",
members = {"npc_stag 040", "npc_stag 041", },
vehicle = "vehicle_apc 004",
},
apc_005 = {
name = "group_stag_apc 005",
members = {"npc_stag 050", "npc_stag 051",},
vehicle = "vehicle_apc 005",
},
apc_006 = {
name = "group_stag_apc 006",
members = {"npc_stag 060", "npc_stag 061",},
vehicle = "vehicle_apc 006",
},
apc_007 = {
name = "group_stag_apc 007",
members = {"npc_stag 070", "npc_stag 071", },
vehicle = "vehicle_apc 007",
},
apc_008 = {
name = "group_stag_apc 008",
members = {"npc_stag 080", "npc_stag 081",},
vehicle = "vehicle_apc 008",
},
apc_009 = {
name = "group_stag_apc 009",
members = {"npc_stag 090", "npc_stag 091",},
vehicle = "vehicle_apc 009",
},
apc_010 = {
name = "group_stag_apc 010",
members = {"npc_stag 100", "npc_stag 101",},
vehicle = "vehicle_apc 010",
},
apc_011 = {
name = "group_stag_apc 011",
members = {"npc_stag 110", "npc_stag 111", },
vehicle = "vehicle_apc 011",
},
apc_012 = {
name = "group_stag_apc 012",
members = {"npc_stag 120", "npc_stag 121",},
vehicle = "vehicle_apc 012",
},
apc_013 = {
name = "group_stag_apc 013",
members = {"npc_stag 130", "npc_stag 131",},
vehicle = "vehicle_apc 013",
},
apc_014 = {
name = "group_stag_apc 014",
members = {"npc_stag 140", "npc_stag 141",},
vehicle = "vehicle_apc 014",
},
apc_015 = {
name = "group_stag_apc 015",
members = {"npc_stag 150", "npc_stag 151",},
vehicle = "vehicle_apc 015",
},
apc_016 = {
name = "group_stag_apc 016",
members = {"npc_stag 160", "npc_stag 161",},
vehicle = "vehicle_apc 016",
},
apc_017 = {
name = "group_stag_apc 017",
members = {"npc_stag 170", "npc_stag 171",},
vehicle = "vehicle_apc 017",
},
apc_018 = {
name = "group_stag_apc 018",
members = {"npc_stag 180", "npc_stag 181",},
vehicle = "vehicle_apc 018",
},
apc_019 = {
name = "group_stag_apc 019",
members = {"npc_stag 190", "npc_stag 191",},
vehicle = "vehicle_apc 019",
},
apc_020 = {
name = "group_stag_apc 020",
members = {"npc_stag 200", "npc_stag 201",},
vehicle = "vehicle_apc 020",
},
apc_021 = {
name = "group_stag_apc 021",
members = {"npc_stag 210", "npc_stag 211",},
vehicle = "vehicle_apc 021",
},
apc_022 = {
name = "group_stag_apc 022",
members = {"npc_stag 220", "npc_stag 221",},
vehicle = "vehicle_apc 022",
},
apc_023 = {
name = "group_stag_apc 023",
members = {"npc_stag 230", "npc_stag 231",},
vehicle = "vehicle_apc 023",
},
apc_024 = {
name = "group_stag_apc 024",
members = {"npc_stag 240", "npc_stag 241",},
vehicle = "vehicle_apc 024",
},
apc_025 = {
name = "group_stag_apc 025",
members = {"npc_stag 250", "npc_stag 251",},
vehicle = "vehicle_apc 025",
},
apc_026 = {
name = "group_stag_apc 026",
members = {"npc_stag 260", "npc_stag 261",},
vehicle = "vehicle_apc 026",
},
heli_001 = {
name = "group_stag_heli 001",
members = {"npc_heli 010", "npc_heli 011"},
vehicle = "vehicle_heli 001",
},
heli_002 = {
name = "group_stag_heli 002",
members = {"npc_heli 020", "npc_heli 021"},
vehicle = "vehicle_heli 002",
},
heli_003 = {
name = "group_stag_heli 003",
members = {"npc_heli 030", "npc_heli 031"},
vehicle = "vehicle_heli 003",
},
tank_001 = {
name = "group_stag_tank 001",
members = {"npc_tank 010", "npc_tank 011"},
vehicle = "vehicle_tank 001",
},
tank_002 = {
name = "group_stag_tank 002",
members = {"npc_tank 020", "npc_tank 021"},
vehicle = "vehicle_tank 002",
},
tank_003 = {
name = "group_stag_tank 003",
members = {"npc_tank 030", "npc_tank 031"},
vehicle = "vehicle_tank 003",
},
snipers_001 = {
name = "group_stag_snipers 001",
members = {"npc_sniper 010", "npc_sniper 011"},
vehicle = "",
},
snipers_002 = {
name = "group_stag_snipers 002",
members = {"npc_sniper 020", "npc_sniper 021"},
vehicle = "",
},
snipers_003 = {
name = "group_stag_snipers 003",
members = {"npc_sniper 030", "npc_sniper 031", "npc_sniper 032"},
vehicle = "",
},
deck_001 = {
name = "group_stag_deck 001",
members = { "stag_viola_deck 001", "stag_viola_deck 002", "stag_viola_deck 003" },
vehicle = "",
},
deck_002 = {
name = "group_stag_deck 002",
members = { "stag_deck_end 001", "stag_deck_end 002", "stag_deck_end 003" },
vehicle = "",
},
}
-- List of spawn locations a group can start at and the path(s) from the spawn point to the Saints HQ enterance
-- Expected members:
-- nav - Name of the nave point to teleport the group to
-- path - Path to follow to the Saints HQ
M13_spawn_points = {
drop_off_north = {
{nav = "nav_spawn <001>", path = "path <001>", flee = "",}, {nav = "nav_spawn <002>", path = "path <002>", flee = "",},
{nav = "nav_spawn <003>", path = "path <003>", flee = "",}, {nav = "nav_spawn <004>", path = "path <004>", flee = "",},
{nav = "nav_spawn <005>", path = "path <005>", flee = "",}, {nav = "nav_spawn <006>", path = "path <006>", flee = "",},
{nav = "nav_spawn <007>", path = "path <007>", flee = "",}, {nav = "nav_spawn <008>", path = "path <008>", flee = "",},
{nav = "nav_spawn <009>", path = "path <009>", flee = "",}, {nav = "nav_spawn <010>", path = "path <010>", flee = "",},
{nav = "nav_spawn <011>", path = "path <011>", flee = "",}, {nav = "nav_spawn <012>", path = "path <012>", flee = "",},
{nav = "nav_spawn <013>", path = "path <013>", flee = "",}, {nav = "nav_spawn <014>", path = "path <014>", flee = "",},
{nav = "nav_spawn <015>", path = "path <015>", flee = "",},
},
drop_off_south = {
{nav = "nav_spawn <016>", path = "path <016>", flee = "",}, {nav = "nav_spawn <017>", path = "path <017>", flee = "",},
{nav = "nav_spawn <018>", path = "path <018>", flee = "",}, {nav = "nav_spawn <019>", path = "path <019>", flee = "",},
{nav = "nav_spawn <020>", path = "path <020>", flee = "",}, {nav = "nav_spawn <021>", path = "path <021>", flee = "",},
},
scene_5_drop_off = {
{nav = "nav_spawn <022>", path = "path <022>", flee = "",}, {nav = "nav_spawn <023>", path = "path <023>", flee = "",},
},
flee_north = {
{nav = "nav_spawn <007>", path = "path <007>", flee = "flee_path <007>",}, {nav = "nav_spawn <013>", path = "path <013>", flee = "flee_path <008>",},
{nav = "nav_spawn <005>", path = "path <005>", flee = "flee_path <009>",}, {nav = "nav_spawn <012>", path = "path <012>", flee = "flee_path <007>",},
{nav = "nav_spawn <001>", path = "path <001>", flee = "flee_path <008>",}, {nav = "nav_spawn <006>", path = "path <006>", flee = "flee_path <009>",},
},
flee_south = {
{nav = "nav_spawn <016>", path = "path <016>", flee = "flee_path <002>",}, {nav = "nav_spawn <017>", path = "path <017>", flee = "flee_path <001>",},
{nav = "nav_spawn <018>", path = "path <018>", flee = "flee_path <003>",}, {nav = "nav_spawn <019>", path = "path <019>", flee = "flee_path <005>",},
{nav = "nav_spawn <020>", path = "path <020>", flee = "flee_path <004>",}, {nav = "nav_spawn <021>", path = "path <021>", flee = "flee_path <006>",},
},
heli_west_01 = {
{nav = "nav_heli 001", path = { "path_heli 001a", "path_heli 001b" }, flee = "",},
},
heli_west_02 = {
{nav = "nav_heli 003", path = "path_heli 003", flee = "flee_path_heli",},
},
heli_west_03 = {
{nav = "nav_heli 004", path = "path_heli 004", flee = "flee_path_heli",},
},
heli_east_01 = {
{nav = "nav_heli 002", path = "path_heli 002", flee = "",},
},
heli_east_02 = {
{nav = "nav_heli 005", path = "path_heli 005", flee = "",},
},
heli_fake = {
{nav = "nav_heli 006", path = "path_heli 006", flee = "flee_path_heli",},
{nav = "nav_heli 007", path = "path_heli 007", flee = "flee_path_heli",},
{nav = "nav_heli 008", path = "path_heli 008", flee = "flee_path_heli",},
},
dummy = {nav = "", path = "", flee = "",},
}
-- Spawn Waves --
-- Expected members:
-- groups - Table with the following members
-- group - M13_spawn_groups table to spawn
-- spawn_point - Nav point and path the group will follow
--
-- initial_delay - Delay before the first group is spawned
-- next_group_delay - Amount of time to wait before spawning the next group
-- release_delay - Amount of time to wait after a group has completed it's path before releasing and moving on to the next group.
-- Ignored if required_kill is set to true
-- required_kill - Flag the group with a kill icon
-- repeat_wave - Loop through the group until the wave is stopped.
-- Ignored if required_kill is set to true
-- thread - Thread managing the wave
M13_wave_states = {
invalid = 0,
spawning = 1,
pathfinding = 2,
release_delay = 3,
next_group_delay = 4,
complete = 5,
}
M13_wave_templates = {
scene_1 = {
vehicle_speed = 35.0,
initial_delay = 0.0,
next_group_delay = 1.0,
release_delay = -1.0, -- negative number to never release
required_kill = false,
repeat_wave = false,
thread = INVALID_THREAD_HANDLE,
state = M13_wave_states.invalid,
},
scene_2 = {
vehicle_speed = 35.0,
initial_delay = 0.0,
next_group_delay = 0.0,
release_delay = -1.0,
required_kill = false,
repeat_wave = false,
thread = INVALID_THREAD_HANDLE,
state = M13_wave_states.invalid,
},
scene_2_deck = {
vehicle_speed = 0.0,
initial_delay = 0.0,
next_group_delay = 5.0,
release_delay = 0.0,
required_kill = true,
repeat_wave = false,
attack_target = M13_groups.homies.viola,
thread = INVALID_THREAD_HANDLE,
state = M13_wave_states.invalid,
},
scene_3_snipers = {
vehicle_speed = 0.0,
initial_delay = 0.0,
next_group_delay = 2.0,
release_delay = 0.0,
required_kill = true,
repeat_wave = false,
thread = INVALID_THREAD_HANDLE,
state = M13_wave_states.invalid,
},
scene_4_tanks = {
vehicle_speed = 35.0,
initial_delay = 5.0,
next_group_delay = 5.0,
release_delay = 0.0,
required_kill = true,
repeat_wave = false,
thread = INVALID_THREAD_HANDLE,
state = M13_wave_states.invalid,
},
scene_5_drop_off = {
vehicle_speed = 35.0,
initial_delay = 0.0,
next_group_delay = 5.0,
release_delay = -1.0,
required_kill = false,
repeat_wave = false,
thread = INVALID_THREAD_HANDLE,
state = M13_wave_states.invalid,
},
scene_6_tanks = {
vehicle_speed = 35.0,
initial_delay = 0.0,
next_group_delay = 3.0,
release_delay = 0.0,
required_kill = true,
repeat_wave = false,
thread = INVALID_THREAD_HANDLE,
state = M13_wave_states.invalid,
},
scene_6_vtol = {
vehicle_speed = 0.0,
initial_delay = 0.0,
next_group_delay = 5.0,
release_delay = 0.0,
required_kill = true,
repeat_wave = false,
thread = INVALID_THREAD_HANDLE,
state = M13_wave_states.invalid,
},
scene_6_vtol_xtra = {
vehicle_speed = 0.0,
initial_delay = 0.0,
next_group_delay = 5.0,
release_delay = 0.0,
required_kill = false,
repeat_wave = false,
thread = INVALID_THREAD_HANDLE,
state = M13_wave_states.invalid,
},
scene_6_snipers = {
vehicle_speed = 0.0,
initial_delay = 0.0,
next_group_delay = 0.0,
release_delay = 0.0,
required_kill = true,
repeat_wave = false,
thread = INVALID_THREAD_HANDLE,
state = M13_wave_states.invalid,
},
scene_7_deck = {
vehicle_speed = 0.0,
initial_delay = 0.0,
next_group_delay = 0.0,
release_delay = -1.0,
required_kill = true,
repeat_wave = false,
thread = INVALID_THREAD_HANDLE,
state = M13_wave_states.invalid,
},
apcs_ambient = {
vehicle_speed = 50.0,
initial_delay = 0.0,
next_group_delay = 0.0,
release_delay = 25.0,
required_kill = false,
repeat_wave = true,
thread = INVALID_THREAD_HANDLE,
state = M13_wave_states.invalid,
},
}
M13_waves = {
apcs_north_1 = {
{groups = { {group = M13_spawn_groups.apc_001, spawn_point = M13_spawn_points.flee_north[ 1],},}, initial_delay = 0.0, template = M13_wave_templates.apcs_ambient},
{groups = { {group = M13_spawn_groups.apc_002, spawn_point = M13_spawn_points.flee_north[ 2],},}, initial_delay = 2.0, template = M13_wave_templates.apcs_ambient},
},
apcs_north_2 = {
{groups = { {group = M13_spawn_groups.apc_003, spawn_point = M13_spawn_points.flee_north[ 3],},}, initial_delay = 4.0, template = M13_wave_templates.apcs_ambient},
{groups = { {group = M13_spawn_groups.apc_004, spawn_point = M13_spawn_points.flee_north[ 4],},}, initial_delay = 6.0, template = M13_wave_templates.apcs_ambient},
},
apcs_north_3 = {
{groups = { {group = M13_spawn_groups.apc_005, spawn_point = M13_spawn_points.flee_north[ 5],},}, initial_delay = 8.0, template = M13_wave_templates.apcs_ambient},
{groups = { {group = M13_spawn_groups.apc_006, spawn_point = M13_spawn_points.flee_north[ 6],},}, initial_delay =10.0, template = M13_wave_templates.apcs_ambient},
},
apcs_south_1 = {
{groups = { {group = M13_spawn_groups.apc_007, spawn_point = M13_spawn_points.flee_south[ 1],},}, initial_delay = 0.0, template = M13_wave_templates.apcs_ambient},
{groups = { {group = M13_spawn_groups.apc_008, spawn_point = M13_spawn_points.flee_south[ 2],},}, initial_delay = 2.0, template = M13_wave_templates.apcs_ambient},
},
apcs_south_2 = {
{groups = { {group = M13_spawn_groups.apc_009, spawn_point = M13_spawn_points.flee_south[ 3],},}, initial_delay = 4.0, template = M13_wave_templates.apcs_ambient},
{groups = { {group = M13_spawn_groups.apc_010, spawn_point = M13_spawn_points.flee_south[ 4],},}, initial_delay = 6.0, template = M13_wave_templates.apcs_ambient},
},
apcs_south_3 = {
{groups = { {group = M13_spawn_groups.apc_011, spawn_point = M13_spawn_points.flee_south[ 5],},}, initial_delay = 8.0, template = M13_wave_templates.apcs_ambient},
{groups = { {group = M13_spawn_groups.apc_012, spawn_point = M13_spawn_points.flee_south[ 6],},}, initial_delay =10.0, template = M13_wave_templates.apcs_ambient},
},
scene_1 = {
{groups = { {group = M13_spawn_groups.apc_013, spawn_point = M13_spawn_points.drop_off_north[ 4],},}, template = M13_wave_templates.scene_1},
{groups = { {group = M13_spawn_groups.apc_014, spawn_point = M13_spawn_points.drop_off_north[ 5],},}, template = M13_wave_templates.scene_1},
{groups = { {group = M13_spawn_groups.apc_015, spawn_point = M13_spawn_points.drop_off_north[ 6],},}, template = M13_wave_templates.scene_1},
{groups = { {group = M13_spawn_groups.apc_016, spawn_point = M13_spawn_points.drop_off_north[ 7],},}, template = M13_wave_templates.scene_1},
{groups = { {group = M13_spawn_groups.apc_017, spawn_point = M13_spawn_points.drop_off_north[ 8],},}, template = M13_wave_templates.scene_1},
{groups = { {group = M13_spawn_groups.apc_018, spawn_point = M13_spawn_points.drop_off_north[11],},}, template = M13_wave_templates.scene_1},
{groups = { {group = M13_spawn_groups.apc_019, spawn_point = M13_spawn_points.drop_off_north[12],},}, template = M13_wave_templates.scene_1},
{groups = { {group = M13_spawn_groups.apc_020, spawn_point = M13_spawn_points.drop_off_north[13],},}, template = M13_wave_templates.scene_1},
},
scene_2 = {
{groups = { {group = M13_spawn_groups.apc_021, spawn_point = M13_spawn_points.drop_off_south[ 1],},}, template = M13_wave_templates.scene_1},
{groups = { {group = M13_spawn_groups.apc_022, spawn_point = M13_spawn_points.drop_off_south[ 2],},}, template = M13_wave_templates.scene_1},
{groups = { {group = M13_spawn_groups.apc_023, spawn_point = M13_spawn_points.drop_off_south[ 3],},}, template = M13_wave_templates.scene_1},
{groups = { {group = M13_spawn_groups.apc_024, spawn_point = M13_spawn_points.drop_off_south[ 4],},}, template = M13_wave_templates.scene_1},
{groups = { {group = M13_spawn_groups.apc_025, spawn_point = M13_spawn_points.drop_off_south[ 5],},}, template = M13_wave_templates.scene_1},
{groups = { {group = M13_spawn_groups.apc_026, spawn_point = M13_spawn_points.drop_off_south[ 6],},}, template = M13_wave_templates.scene_1},
},
scene_2_deck = {
{ groups = { {group = M13_spawn_groups.deck_001, spawn_point = M13_spawn_points.dummy,},}, template = M13_wave_templates.scene_2_deck},
},
scene_3_snipers = {
{
groups = {
{group = M13_spawn_groups.snipers_001, spawn_point = M13_spawn_points.dummy,},
{group = M13_spawn_groups.snipers_002, spawn_point = M13_spawn_points.dummy,},
},
template = M13_wave_templates.scene_3_snipers
},
{groups = { {group = M13_spawn_groups.heli_001, spawn_point = M13_spawn_points.heli_fake[ 1],},}, template = M13_wave_templates.scene_6_vtol_xtra},
{groups = { {group = M13_spawn_groups.heli_002, spawn_point = M13_spawn_points.heli_fake[ 2],},}, template = M13_wave_templates.scene_6_vtol_xtra},
{groups = { {group = M13_spawn_groups.heli_003, spawn_point = M13_spawn_points.heli_fake[ 3],},}, template = M13_wave_templates.scene_6_vtol_xtra},
{groups = { {group = M13_spawn_groups.apc_021, spawn_point = M13_spawn_points.drop_off_south[ 1],},}, template = M13_wave_templates.scene_1},
{groups = { {group = M13_spawn_groups.apc_022, spawn_point = M13_spawn_points.drop_off_south[ 2],},}, template = M13_wave_templates.scene_1},
},
scene_4_tanks = {
{
groups = {
--{group = M13_spawn_groups.tank_001, spawn_point = M13_spawn_points.drop_off_north[ 2],},
{group = M13_spawn_groups.tank_002, spawn_point = M13_spawn_points.drop_off_north[ 9],},
--{group = M13_spawn_groups.tank_003, spawn_point = M13_spawn_points.drop_off_north[14],},
},
template = M13_wave_templates.scene_4_tanks
},
{
groups = {
{group = M13_spawn_groups.tank_001, spawn_point = M13_spawn_points.drop_off_north[ 1],},
},
template = M13_wave_templates.scene_4_tanks
},
{groups = { {group = M13_spawn_groups.apc_013, spawn_point = M13_spawn_points.drop_off_north[ 4],},}, template = M13_wave_templates.scene_1},
{groups = { {group = M13_spawn_groups.apc_014, spawn_point = M13_spawn_points.drop_off_north[ 5],},}, template = M13_wave_templates.scene_1},
},
scene_5_drop_off = {
{groups = { {group = M13_spawn_groups.apc_011, spawn_point = M13_spawn_points.scene_5_drop_off[ 1],},}, template = M13_wave_templates.scene_5_drop_off},
{groups = { {group = M13_spawn_groups.apc_012, spawn_point = M13_spawn_points.scene_5_drop_off[ 2],},}, template = M13_wave_templates.scene_5_drop_off},
},
scene_6_tanks = {
{
groups = {
{group = M13_spawn_groups.tank_001, spawn_point = M13_spawn_points.drop_off_north[ 2],},
{group = M13_spawn_groups.tank_002, spawn_point = M13_spawn_points.drop_off_north[ 9],},
},
template = M13_wave_templates.scene_6_tanks
},
{
groups = {
{group = M13_spawn_groups.tank_003, spawn_point = M13_spawn_points.drop_off_north[14],},
},
template = M13_wave_templates.scene_6_tanks
},
},
scene_6_vtol_01 = {
{
groups = {
{group = M13_spawn_groups.heli_001, spawn_point = M13_spawn_points.heli_west_01[ 1],},
},
template = M13_wave_templates.scene_6_vtol
},
{groups = { {group = M13_spawn_groups.heli_002, spawn_point = M13_spawn_points.heli_west_02[ 1],},}, template = M13_wave_templates.scene_6_vtol_xtra},
{groups = { {group = M13_spawn_groups.heli_003, spawn_point = M13_spawn_points.heli_west_03[ 1],},}, template = M13_wave_templates.scene_6_vtol_xtra},
{groups = { {group = M13_spawn_groups.apc_013, spawn_point = M13_spawn_points.drop_off_north[ 4],},}, template = M13_wave_templates.scene_1},
{groups = { {group = M13_spawn_groups.apc_014, spawn_point = M13_spawn_points.drop_off_north[ 5],},}, template = M13_wave_templates.scene_1},
{groups = { {group = M13_spawn_groups.apc_015, spawn_point = M13_spawn_points.drop_off_north[ 6],},}, template = M13_wave_templates.scene_1},
{groups = { {group = M13_spawn_groups.apc_016, spawn_point = M13_spawn_points.drop_off_north[ 7],},}, template = M13_wave_templates.scene_1},
{groups = { {group = M13_spawn_groups.apc_017, spawn_point = M13_spawn_points.drop_off_north[ 8],},}, template = M13_wave_templates.scene_1},
{groups = { {group = M13_spawn_groups.apc_018, spawn_point = M13_spawn_points.drop_off_north[11],},}, template = M13_wave_templates.scene_1},
{groups = { {group = M13_spawn_groups.apc_019, spawn_point = M13_spawn_points.drop_off_north[12],},}, template = M13_wave_templates.scene_1},
{groups = { {group = M13_spawn_groups.apc_020, spawn_point = M13_spawn_points.drop_off_north[13],},}, template = M13_wave_templates.scene_1},
{groups = { {group = M13_spawn_groups.apc_021, spawn_point = M13_spawn_points.drop_off_south[ 1],},}, template = M13_wave_templates.scene_1},
{groups = { {group = M13_spawn_groups.apc_022, spawn_point = M13_spawn_points.drop_off_south[ 2],},}, template = M13_wave_templates.scene_1},
},
scene_6_vtol_02 = {
{groups = { {group = M13_spawn_groups.heli_001, spawn_point = M13_spawn_points.heli_east_01[ 1],},}, template = M13_wave_templates.scene_6_vtol},
{groups = { {group = M13_spawn_groups.heli_002, spawn_point = M13_spawn_points.heli_east_02[ 1],},}, template = M13_wave_templates.scene_6_vtol},
},
scene_6_snipers = {
{
groups = {
{group = M13_spawn_groups.snipers_001, spawn_point = M13_spawn_points.dummy,},
{group = M13_spawn_groups.snipers_003, spawn_point = M13_spawn_points.dummy,},
},
template = M13_wave_templates.scene_6_snipers
},
{groups = { {group = M13_spawn_groups.heli_001, spawn_point = M13_spawn_points.heli_fake[ 1],},}, template = M13_wave_templates.scene_6_vtol_xtra},
{groups = { {group = M13_spawn_groups.heli_002, spawn_point = M13_spawn_points.heli_fake[ 2],},}, template = M13_wave_templates.scene_6_vtol_xtra},
{groups = { {group = M13_spawn_groups.heli_003, spawn_point = M13_spawn_points.heli_fake[ 3],},}, template = M13_wave_templates.scene_6_vtol_xtra},
{groups = { {group = M13_spawn_groups.apc_025, spawn_point = M13_spawn_points.drop_off_south[ 5],},}, template = M13_wave_templates.scene_1},
{groups = { {group = M13_spawn_groups.apc_026, spawn_point = M13_spawn_points.drop_off_south[ 6],},}, template = M13_wave_templates.scene_1},
},
scene_7_deck = {
{groups = { {group = M13_spawn_groups.deck_001, spawn_point = M13_spawn_points.dummy,},}, template = M13_wave_templates.scene_7_deck},
{groups = { {group = M13_spawn_groups.deck_002, spawn_point = M13_spawn_points.dummy,},}, template = M13_wave_templates.scene_7_deck},
{groups = { {group = M13_spawn_groups.apc_017, spawn_point = M13_spawn_points.drop_off_north[ 8],},}, template = M13_wave_templates.scene_1},
{groups = { {group = M13_spawn_groups.apc_018, spawn_point = M13_spawn_points.drop_off_north[11],},}, template = M13_wave_templates.scene_1},
{groups = { {group = M13_spawn_groups.apc_019, spawn_point = M13_spawn_points.drop_off_north[12],},}, template = M13_wave_templates.scene_1},
{groups = { {group = M13_spawn_groups.apc_020, spawn_point = M13_spawn_points.drop_off_north[13],},}, template = M13_wave_templates.scene_1},
},
}
-- Navpoints --
M13_nav = {
player_start = "nav_player_start",
elevator_to_ground = "nav_elevator_to_ground",
elevator_to_balcony = "nav_elevator_to_balcony",
player_penthouse = "nav_player_penthouse",
penthouse_elevator = "nav_penthouse_elevator",
remote_start = "nav_remote_start",
remote_penthouse = "nav_remote_penthouse",
elevator_to_ground_remote = "nav_elevator_to_ground_remote",
elevator_to_balcony_remote = "nav_elevator_to_balcony_remote",
penthouse_elevator_remote = "nav_penthouse_elevator_remote",
saints_hq_base = "nav_saints_hq_base",
josh_to_cyrus = "nav_josh_to_cyrus",
josh_to_shaundi = "nav_josh_to_shaundi",
cyrus_to_vtol = "nav_cyrus_to_vtol",
jump_to = "nav_jump_to",
banners_player_start = "nav_cp_banners_player_start",
banners_remote_start = "nav_cp_banners_remote_start",
}
M13_paths = {
pierce_to_saints_hq = "path_pierce_saints_hq",
pierce_to_crash = "path_pierce_crash",
}
-- Triggers --
M13_triggers = {
pr_center_front = "trigger_pr_center_front",
saints_hq_front = "trigger_saints_hq_front",
north_side = "trigger_north_side",
south_side = "trigger_south_side",
elevator_to_ground = "trigger_elevator_to_ground", -- Use trigger
elevator_to_penthouse = "trigger_elevator_to_penthouse", -- Use trigger
penthouse_cutscene = "trigger_penthouse_cutscene",
penthouse_jumped = "trigger_penthouse_jumped",
no_traffic = "Trigger No Traffic",
elevator_proximity = "trigger_elevator_proximity",
}
-- Trigger Flags --
M13_trigger_reached = false
-- Mesh Movers --
M13_movers = {
pr_center_banners = {
{name = "mover_mission_accomplished 001", destroyed = false,},
{name = "mover_mission_accomplished 002", destroyed = false,},
},
bombs = {
{mover = "mover_bomb 001", detonate = false, delay = 0.0, north_side = false,},
{mover = "mover_bomb 002", detonate = false, delay = 0.0, north_side = true,},
{mover = "mover_bomb 003", detonate = false, delay = 0.0, north_side = false,},
{mover = "mover_bomb 004", detonate = false, delay = 0.0, north_side = false,},
{mover = "mover_bomb 005", detonate = false, delay = 0.0, north_side = false,},
{mover = "mover_bomb 006", detonate = false, delay = 0.0, north_side = true,},
{mover = "mover_bomb 007", detonate = false, delay = 0.0, north_side = true,},
{mover = "mover_bomb 008", detonate = false, delay = 0.0, north_side = false,},
{mover = "mover_bomb 009", detonate = false, delay = 0.0, north_side = false,},
{mover = "mover_bomb 010", detonate = false, delay = 0.0, north_side = true,},
{mover = "mover_bomb 011", detonate = false, delay = 0.0, north_side = false,},
{mover = "mover_bomb 012", detonate = false, delay = 0.0, north_side = false,},
{mover = "mover_bomb 013", detonate = false, delay = 0.0, north_side = false,},
{mover = "mover_bomb 014", detonate = false, delay = 0.0, north_side = false,},
{mover = "mover_bomb 015", detonate = false, delay = 0.0, north_side = true,},
{mover = "mover_bomb 016", detonate = false, delay = 0.0, north_side = true,},
{mover = "mover_bomb 017", detonate = false, delay = 0.0, north_side = true,},
{mover = "mover_bomb 018", detonate = false, delay = 0.0, north_side = true,},
{mover = "mover_bomb 019", detonate = false, delay = 0.0, north_side = true,},
{mover = "mover_bomb 020", detonate = false, delay = 0.0, north_side = true,},
{mover = "mover_bomb 021", detonate = false, delay = 0.0, north_side = true,},
{mover = "mover_bomb 022", detonate = false, delay = 0.0, north_side = true,},
{mover = "mover_bomb 023", detonate = false, delay = 0.0, north_side = true,},
{mover = "mover_bomb 024", detonate = false, delay = 0.0, north_side = false,},
{mover = "mover_bomb 025", detonate = false, delay = 0.0, north_side = false,},
{mover = "mover_bomb 026", detonate = false, delay = 0.0, north_side = false,},
{mover = "mover_bomb 027", detonate = false, delay = 0.0, north_side = true,},
},
clutter = { "mvr_vehicle_clutter 001", "mvr_vehicle_clutter 002", "mvr_vehicle_clutter 003", "mvr_vehicle_clutter 004",
"mvr_vehicle_clutter 005", "mvr_vehicle_clutter 006", "mvr_vehicle_clutter 007",
},
}
-- VFX --
M13_vfxs = {
north_01 = {
smoke_01 = { nav = "vfx_n_smoke 001", handle = -1 },
--smoke_02 = { nav = "vfx_n_smoke 002", handle = -1 },
smoke_03 = { nav = "vfx_n_smoke 003", handle = -1 },
--smoke_04 = { nav = "vfx_n_smoke 004", handle = -1 },
smoke_05 = { nav = "vfx_n_smoke 005", handle = -1 },
smoke_06 = { nav = "vfx_n_smoke 006", handle = -1 },
},
north_02 = {
fire_01 = { nav = "vfx_n_fire 001", handle = -1 },
fire_02 = { nav = "vfx_n_fire 002", handle = -1 },
fire_03 = { nav = "vfx_n_fire 003", handle = -1 },
fire_04 = { nav = "vfx_n_fire 004", handle = -1 },
fire_05 = { nav = "vfx_n_fire 005", handle = -1 },
--fire_06 = { nav = "vfx_n_fire 012", handle = -1 },
--fire_07 = { nav = "vfx_n_fire 013", handle = -1 },
smoke_01 = { nav = "vfx_n_smoke 007", handle = -1 },
smoke_02 = { nav = "vfx_n_smoke 008", handle = -1 },
},
north_03 = {
--fire_01 = { nav = "vfx_n_fire 006", handle = -1 },
fire_02 = { nav = "vfx_n_fire 007", handle = -1 },
--fire_03 = { nav = "vfx_n_fire 008", handle = -1 },
fire_04 = { nav = "vfx_n_fire 009", handle = -1 },
fire_05 = { nav = "vfx_n_fire 010", handle = -1 },
big_01 = { nav = "vfx_n_big 001", handle = -1 },
},
south_01 = {
smoke_01 = { nav = "vfx_s_smoke 001", handle = -1 },
--smoke_02 = { nav = "vfx_s_smoke 002", handle = -1 },
smoke_03 = { nav = "vfx_s_smoke 003", handle = -1 },
smoke_04 = { nav = "vfx_s_smoke 004", handle = -1 },
},
south_02 = {
fire_01 = { nav = "vfx_s_fire 001", handle = -1 },
--fire_02 = { nav = "vfx_s_fire 002", handle = -1 },
},
hq_01 = {
smoke_01 = { nav = "vfx_hq_smoke 001", handle = -1 },
smoke_02 = { nav = "vfx_hq_smoke 002", handle = -1 },
},
hq_02 = {
-- smoke_01 = { nav = "vfx_hq_smoke 003", handle = -1 },
smoke_02 = { nav = "vfx_hq_smoke 004", handle = -1 },
fire_01 = { nav = "vfx_hq_fire 001", handle = -1 },
},
}
-- Text --
M13_OBJ_GOTO_PR_CENTER = "m13_obj_goto_pr_center"
M13_OBJ_DESTROY_STAG_BANNER = "m13_obj_destroy_stag_banner"
M13_OBJ_GOTO_SAINTS_HQ = "m13_obj_goto_saints_hq"
M13_OBJ_GOTO_ELEVATOR = "m13_obj_goto_elevator"
M13_OBJ_DEFEND_THE_NORTH = "m13_obj_defend_the_north"
M13_OBJ_DEFEND_THE_SOUTH = "m13_obj_defend_the_south"
M13_OBJ_DETONATE_CAR_BOMBS = "m13_obj_detonate_car_bombs"
M13_OBJ_HELP_VIOLA = "m13_obj_help_viola"
M13_OBJ_TAKE_OUT_THE_SNIPERS = "m13_obj_take_out_the_snipers"
M13_OBJ_TAKE_OUT_THE_TANKS = "m13_obj_take_out_the_tanks"
M13_OBJ_TAKE_OUT_THE_VTOLS = "m13_obj_take_out_the_vtols"
M13_OBJ_CLEAR_THE_FLOOR = "m13_obj_clear_the_floor"
M13_OBJ_COVER_PIERCE = "m13_obj_cover_pierce"
M13_OBJ_GOTO_PIERCE = "m13_obj_goto_pierce"
M13_OBJ_THROW_JOSH = "m13_obj_throw_josh"
M13_OBJ_GOTO_PENTHOUSE = "m13_obj_goto_penthouse"
M13_OBJ_GOTO_SHAUNDI = "m13_obj_goto_shaundi"
M13_OBJ_ESCAPE = "m13_obj_escape"
M13_PROMPT_THROW_JOSH_TO_CYRUS = "m13_prompt_throw_josh_to_cyrus"
M13_PROMPT_THROW_JOSH_TO_SHAUNDI = "m13_prompt_throw_josh_to_shaundi"
M13_FAILURE_VIOLA_DIED = "m13_failure_viola_died"
M13_FAILURE_VIOLA_ABANDONED = "m13_failure_viola_abandoned"
-- M13_FAILURE_OLEG_DIED = "m13_failure_oleg_died"
M13_FAILURE_PIERCE_DIED = "m13_failure_pierce_died"
M13_FAILURE_PIERCE_ABANDONED = "m13_failure_pierce_abandoned"
M13_FAILURE_SAINTS_HQ_ABANDONED = "m13_failure_saints_hq_abandoned"
M13_FAILURE_JOSH_DIED = "m13_failure_josh_died"
M13_FAILURE_FAILED_TO_ESCAPE = "m13_failure_failed_to_escape"
-- Threads --
M13_THREAD_CAR_BOMB_MANAGER = INVALID_THREAD_HANDLE
-- Conversation threads
M13_THREAD_PIERCE_CONVO_AND_LEAVE = INVALID_THREAD_HANDLE
-- Checkpoints --
M13_CHECKPOINT_START = MISSION_START_CHECKPOINT -- defined in ug_lib.lua
M13_CHECKPOINT_BANNERS = "m13_checkpoint_banners"
M13_CHECKPOINT_WAVE_1_START = "m13_checkpoint_wave_1_start"
M13_CHECKPOINT_WAVE_2_START = "m13_checkpoint_wave_2_start"
M13_CHECKPOINT_WAVE_3_START = "m13_checkpoint_wave_3_start"
M13_CHECKPOINT_DECISION = "m13_checkpoint_decision"
-- Cutscenes --
CUTSCENE_MISSION_INTRO = "13_in"
CUTSCENE_MISSION_OUTRO = "13_out"
-- Personas --
M13_personas = {
{ name = "Oleg", handle = INVALID_PERSONA_HANDLE },
{ name = "Suko", handle = INVALID_PERSONA_HANDLE },
{ name = "Pierce", handle = INVALID_PERSONA_HANDLE },
{ name = "Shaundi", handle = INVALID_PERSONA_HANDLE },
{ name = "Saint_WM_04", handle = INVALID_PERSONA_HANDLE },
{ name = "Saint_HF_04", handle = INVALID_PERSONA_HANDLE },
}
M13_persona_line = {
--drive_to_pr = { name = "M13_Drive_To_PR_Center", character = LOCAL_PLAYER, play_2d = false },
banners = { name = "M13_Banners", character = LOCAL_PLAYER, play_2d = false },
molotov_remind = { name = "M13_Molotov_Reminder", character = LOCAL_PLAYER, play_2d = false },
attack_start = { name = "M13_Wave_One_Start", character = "Oleg", cell = true, recieving = true },
car_bombs_01 = { name = "M13_Use_Car_Bombs_01", character = "Oleg", play_2d = true },
car_bombs_02 = { name = "M13_Use_Car_Bombs_02", character = "Suko", play_2d = true },
north = { name = "M13_North", character = "Oleg", play_2d = true },
south = { name = "M13_South", character = "Oleg", play_2d = true },
east = { name = "M13_East", character = "Oleg", play_2d = true },
west = { name = "M13_West", character = "Oleg", play_2d = true },
help_viola_01 = { name = "M13_Help_Viola_In_Building", character = "Suko", play_2d = true },
help_viola_02 = { name = "M13_Go_Help_Viola", character = "Oleg", play_2d = true },
focus_south = { name = "M13_Focus_On_South_Side", character = "Suko", play_2d = true },
snipers_01 = { name = "M13_Snipers_On_South_01", character = "Suko", play_2d = true },
snipers_02 = { name = "M13_Snipers_On_South_0", character = "Suko", play_2d = true },
tanks_01 = { name = "M13_Tank_On_North_01", character = "Oleg", play_2d = true },
tanks_02 = { name = "M13_Tank_On_North_02", character = "Oleg", play_2d = true },
arriving = { name = "M13_Arriving", character = "Pierce", cell = true, recieving = true },
in_trouble_01 = { name = "M13_In_Trouble_01", character = "Pierce", play_2d = true },
in_trouble_02 = { name = "M13_In_trouble_02", character = "Pierce", cell = true, recieving = true },
elevator = { name = "M13_Elevator", character = "Oleg", play_2d = true },
stag_inside = { name = "M13_STAG_Inside_Oleg", character = "Oleg", play_2d = true },
losing = { name = "M13_Losing_Viola", character = "Suko", play_2d = true },
seconds_60 = { name = "M13_60_Seconds", character = M13_groups.penthouse_stag.cyrus, play_2d = false },
seconds_30 = { name = "M13_30_Seconds", character = M13_groups.penthouse_stag.cyrus, play_2d = false },
seconds_10 = { name = "M13_10_Seconds", character = M13_groups.penthouse_stag.cyrus, play_2d = false },
shell = { name = "M13_Shell_Building", character = M13_groups.penthouse_stag.cyrus, play_2d = false },
with_birk = { name = "M13_Shaundi_With_Birk", character = "Shaundi", play_2d = true },
without_birk = { name = "M13_Shaundi_Without_Birk", character = "Shaundi", play_2d = true },
get_out = { name = "M13_Get_Out", character = LOCAL_PLAYER, play_2d = false },
}
-- Conversations --
-- Table of audio conversations to play. Either a actual audio file can be specifed, or a message can be used in its place.
-- Expected Table Members:
-- name - Name of the audio file to play
-- delay - Amount of time (in seconds) to delay after a audio file has played
M13_convo = {
-- Played as soon as the mission starts
start = {
files = {
{name = "m13_convo_1", delay = 0.0},
},
thread = INVALID_THREAD_HANDLE,
},
-- Played after the banner is destroyed. The objective will be updated once this is completed.
banner_destroyed = {
files = {
{ name = "M13_Return_To_Crib", delay = 2.0, cell = true, recieving = false },
},
thread = INVALID_THREAD_HANDLE,
},
help_viola = {
files = {
{name = M13_persona_line.help_viola_01, delay = 3.0},
{name = M13_persona_line.help_viola_02, delay = 0.0},
},
thread = INVALID_THREAD_HANDLE,
},
pierce_drive_in = {
files = {
{name = M13_persona_line.arriving, delay = 8.0},
{name = M13_persona_line.in_trouble_01, delay = 0.0},
},
thread = INVALID_THREAD_HANDLE,
},
-- Played once the player saves Pierce
save_pierce_4 = {
files = {
{name = "M13_Thanks", delay = 0.0},
},
thread = INVALID_THREAD_HANDLE,
},
-- Played after the player returns to the Saints HQ with Pierce
airstrike = {
files = {
{name = "M13_Laser_Target", delay = 2.0},
},
thread = INVALID_THREAD_HANDLE,
},
-- Played when the first helicopter spawns.
first_heli = {
files = {
{name = "M13_Helicopters", delay = 2.0},
},
thread = INVALID_THREAD_HANDLE,
},
-- Played when the final wave is totally complete.
check_roof_01 = {
files = {
-- {name = M13_persona_line.losing, delay = 5.0},
{name = M13_persona_line.stag_inside, delay = 10.0},
-- {name = "M13_Retreating", delay = 1.0},
},
thread = INVALID_THREAD_HANDLE,
},
check_roof_02 = {
files = {
{name = M13_persona_line.losing, delay = 4.0},
-- {name = M13_persona_line.stag_inside, delay = 7.0},
-- {name = "M13_Retreating", delay = 1.0},
},
thread = INVALID_THREAD_HANDLE,
},
check_roof_03 = {
files = {
-- {name = M13_persona_line.losing, delay = 4.0},
-- {name = M13_persona_line.stag_inside, delay = 5.0},
{name = "M13_Retreating", delay = 1.0},
},
thread = INVALID_THREAD_HANDLE,
},
-- Played when Cyrus gives the player a choice.
decision1 = {
files = {
{name = "M13_Choice", delay = 0.0, direct = true},
{name = M13_persona_line.seconds_60, delay = 30.0},
{name = M13_persona_line.seconds_30, delay = 20.0},
{name = M13_persona_line.seconds_10, delay = 10.0},
},
thread = INVALID_THREAD_HANDLE,
},
shell_the_building = {
files = {
{name = M13_persona_line.shell, delay = 2.5},
-- {name = M13_persona_line.with_birk, delay = 2.0},
-- {name = M13_persona_line.get_out, delay = 0.0},
},
thread = INVALID_THREAD_HANDLE,
},
shell_with_birk = {
files = {
-- {name = M13_persona_line.shell, delay = 2.5},
{name = M13_persona_line.with_birk, delay = 2.0},
{name = M13_persona_line.get_out, delay = 0.0},
},
thread = INVALID_THREAD_HANDLE,
},
shell_without_birk = {
files = {
-- {name = M13_persona_line.shell, delay = 3.5},
{name = M13_persona_line.without_birk, delay = 1.0},
{name = M13_persona_line.get_out, delay = 0.0},
},
thread = INVALID_THREAD_HANDLE,
},
}
M13_threads = { }
M13_num_troops = 0
M13_max_troops = 40
-- Variables --
M13_in_coop = false
-- PR Center Banner variables
M13_banners_alive = 0
M13_banner_damaged = false
M13_banner_destroyed = false
M13_checkpoint = ""
-- Decision variables
M13_josh_given_to_cyrus = false
M13_josh_given_to_homies = false
M13_active_convo = ""
M13_north_apc_level = 0
M13_south_apc_level = 0
M13_status = { }
-- *************************
--
-- 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
--
-- m13_checkpoint: The checkpoint the mission should begin at
-- is_restart: TRUE if the mission is restarting, FALSE otherwise
--
function m13_start(m13_checkpoint, is_restart)
M13_in_coop = coop_is_active()
-- TODO: Remove. For Debugging only.
--if not is_restart then
--m13_checkpoint = M13_CHECKPOINT_WAVE_1_START
--m13_checkpoint = M13_CHECKPOINT_WAVE_2_START
--m13_checkpoint = M13_CHECKPOINT_WAVE_3_START
--m13_checkpoint = M13_CHECKPOINT_DECISION
--mission_set_checkpoint(m13_checkpoint, true, true)
--end
M13_checkpoint = m13_checkpoint
if is_restart then
M13_status.restart_checkpoint = m13_checkpoint
end
-- Handle mission initialization for the current checkpoint
m13_initialize(m13_checkpoint, is_restart)
-- Check if this mission starting from the beginning
if (m13_checkpoint == M13_CHECKPOINT_START) then
if (not is_restart) then
-- First time playing mission
cutscene_play(CUTSCENE_MISSION_INTRO, nil, { M13_nav.player_start, M13_nav.remote_start }, false)
m13_mission_zscene_post_init()
else
teleport_coop( M13_nav.player_start, M13_nav.remote_start, true )
m13_mission_zscene_post_init()
end
end
mission_start_fade_in()
-- Run the mission from the current checkpoint
m13_run(m13_checkpoint)
end
-- This is the primary function responsible for running the entire mission from start to finish.
--
-- first_checkpoint: The first checkpoint to begin running the mission at
--
function m13_run(first_checkpoint)
local current_checkpoint = first_checkpoint
-- Run the mission from the beginning
if current_checkpoint == M13_CHECKPOINT_START then
-- Have pierce talk to the player for a bit
M13_THREAD_PIERCE_CONVO_AND_LEAVE = thread_new("m13_thread_pierce_convo_and_leave")
-- Intro animations
-- Player(s) look cool GO!
local anim_name = "M06 Player Mission Start"
local morph_name = "M06 Player Mission Start"
local force_play = false
local stand_still = false
local zero_movement = false
action_play_non_blocking(LOCAL_PLAYER, anim_name, morph_name, force_play, stand_still, zero_movement)
player_script_controlled_clear(LOCAL_PLAYER) -- let player escape this animation
if (coop_is_active()) then
action_play_non_blocking(REMOTE_PLAYER, anim_name, morph_name, force_play, stand_still, zero_movement)
player_script_controlled_clear(REMOTE_PLAYER) -- let player escape this animation
end
-- Guide the player to the PR Center and wait until the banner is destroyed
m13_destroy_banner()
current_checkpoint = M13_CHECKPOINT_BANNERS
mission_set_checkpoint(current_checkpoint, true, true)
end
if current_checkpoint == M13_CHECKPOINT_BANNERS then
-- Setup the battle scene while the player is at the pr_center
m13_show_car_bombs()
-- Tell the player to get back to the saints hq
objective_text(0, M13_OBJ_GOTO_SAINTS_HQ, "", "", SYNC_ALL, OI_ASSET_LOCATION)
-- Have Oleg acknowledge the player's actions
m13_play_convo_set(M13_convo.banner_destroyed)
m13_goto_a_trigger(M13_triggers.saints_hq_front, M13_OBJ_GOTO_SAINTS_HQ, true)
m13_goto_balcony(M13_OBJ_GOTO_SAINTS_HQ)
audio_object_post_event("M13_Score_Start", nil, nil, LOCAL_PLAYER)
M13_status.score_start_began = true
m13_cleanup_start()
m13_setup_balcony_battle()
m13_setup_car_bombs()
current_checkpoint = M13_CHECKPOINT_WAVE_1_START
mission_set_checkpoint(current_checkpoint, true, true)
end
if current_checkpoint == M13_CHECKPOINT_WAVE_1_START then
-- Setup the battle scene while the player is at the pr_center
m13_show_car_bombs()
m13_disable_ambient_spawning( true )
m13_scene_1() -- Large northward assault, focusing on the use of the car bombs
m13_create_clutter( "south" )
m13_scene_2() -- Southern assault, focusing on the car bombs
m13_scene_3() -- Snipers take to the southern rooftops
m13_create_clutter( "north" )
m13_scene_4() -- Spawn some tanks on the north side of the building
m13_clear_clutter( "south" )
current_checkpoint = M13_CHECKPOINT_WAVE_2_START
mission_set_checkpoint(current_checkpoint, true, true)
end
m13_vfx_play(M13_vfxs.north_01)
m13_vfx_play(M13_vfxs.south_01)
if current_checkpoint == M13_CHECKPOINT_WAVE_2_START then
m13_scene_5() -- Have the player rescue Pierce
current_checkpoint = M13_CHECKPOINT_WAVE_3_START
mission_set_checkpoint(current_checkpoint, true, true)
end
m13_vfx_play(M13_vfxs.hq_01)
m13_vfx_play(M13_vfxs.north_02)
m13_distance_clutter_show()
m13_vfx_play(M13_vfxs.south_02)
m13_vfx_play(M13_vfxs.north_03)
m13_vfx_play(M13_vfxs.hq_02)
if current_checkpoint == M13_CHECKPOINT_WAVE_3_START then
m13_scene_6() -- Tanks and VTOLs from the North
m13_scene_7() -- Have the player flee to the penthouse
-- Stop all continuious spawns, remove your homies, and cleanup the the weapons
m13_cleanup_balcony_battle()
m13_cleanup_car_bombs()
m13_set_north_apc_level(0)
m13_set_south_apc_level(0)
m13_clear_clutter( "north" )
m13_clear_clutter( "general" )
current_checkpoint = M13_CHECKPOINT_DECISION
mission_set_checkpoint(current_checkpoint, true, true)
-- Spawn Josh, Shaundi, and teleport the player to the penthouse.
fade_out(0.5)
fade_out_block()
teleport_coop(M13_nav.penthouse_elevator, M13_nav.penthouse_elevator_remote, true)
m13_setup_decision()
fade_in(0.5)
fade_in_block()
end
if current_checkpoint == M13_CHECKPOINT_DECISION then
-- m13_setup_decision() will be called by m13_initialize_checkpoint() on a mission restart.
local josh = M13_groups.penthouse_homies.josh
local cyrus = M13_groups.penthouse_stag.cyrus
local shaundi = M13_groups.penthouse_homies.shaundi
local vtol = M13_groups.penthouse_stag.vtols[1]
audio_object_post_event("M13_Score_Decision", nil, nil, LOCAL_PLAYER)
M13_threads.music_cue = thread_new( "m13_audio_event_at_dist", M13_triggers.penthouse_cutscene, 20, "M13_Score_Decision_End" )
zscene_prep( "13_Z01" )
m13_goto_a_trigger(M13_triggers.penthouse_cutscene, M13_OBJ_GOTO_SHAUNDI, false)
thread_kill( M13_threads.music_cue )
-- Play the mid-mission cutscene and setup the STAG to reflect the scene
m13_penthouse_cutscene()
objective_text(0, M13_OBJ_THROW_JOSH, "", "", SYNC_ALL, OI_ASSET_USE)
m13_player_decision()
m13_cyrus_enter_vtol(cyrus, josh, M13_josh_given_to_cyrus, vtol)
m13_unrestrict_players()
M13_cyrus_fly_off(cyrus, M13_josh_given_to_cyrus, vtol)
m13_player_leave_penthouse()
end
M13_status.succeeded = true
if M13_josh_given_to_cyrus == true then
mission_set_excluded_reward("Homie_Nyteblayde")
mission_set_excluded_reward("Homie_Josh")
elseif M13_josh_given_to_homies == true then
mission_set_excluded_reward("Auto_Complete_City_Takeover_District")
end
mission_end_success("m13", CUTSCENE_MISSION_OUTRO)
end
-- This is the primary function responsible for cleaning up the entire mission
-- CALLED FROM CODE (+++MUST RETURN IMMEDIATLY+++)
--
function m13_cleanup()
--[[ INSERT ANY MISSION SPECIFIC CLEAN-UP ]]--
-- crib access is now allowed
crib_disable_interface( false )
-- The mission may have failed due to a remote player disconnecting. Double check to see if they are connected.
if M13_in_coop then
M13_in_coop = coop_is_active()
end
objective_text_clear(0)
hud_timer_stop(1)
hud_timer_hide(1, true)
m13_cleanup_start()
m13_cleanup_banner_scene()
m13_cleanup_balcony_battle()
m13_cleanup_car_bombs()
m13_cleanup_decision()
for trigger in pairs(M13_triggers) do
local trigger_name = M13_triggers[trigger]
on_trigger("", trigger_name)
on_trigger_exit("", trigger_name)
trigger_enable(trigger_name, false)
end
notoriety_set_min( "police", 0)
notoriety_force_no_spawn("police", false)
notoriety_force_no_spawn("stag", false)
notoriety_force_no_spawn("luchadores", false)
notoriety_force_no_spawn("deckers", false)
notoriety_force_no_spawn("morningstar", false)
m13_unload_all_convos()
m13_unload_personas()
set_player_can_enter_exit_vehicles(LOCAL_PLAYER, true)
inv_weapon_remove_temporary(LOCAL_PLAYER, M13_config.grenade)
inv_weapon_remove_temporary(LOCAL_PLAYER, M13_config.airstrike)
if M13_in_coop then
set_player_can_enter_exit_vehicles(REMOTE_PLAYER, true)
inv_weapon_remove_temporary(REMOTE_PLAYER, M13_config.grenade)
inv_weapon_remove_temporary(REMOTE_PLAYER, M13_config.airstrike)
end
-- Make sure any VFX are cleaned up
for key, vfx_group in pairs(M13_vfxs) do
for i, vfx in pairs(vfx_group) do
if (vfx.handle ~= -1) then
effect_stop(vfx.handle)
vfx.handle = -1
end
end
end
-- for i, vfx in pairs(M13_vfxs.south_01) do
-- if (vfx.handle ~= -1) then
-- effect_stop(vfx.handle)
-- vfx.handle = -1
-- end
-- end
-- for i, vfx in pairs(M13_vfxs.hq_01) do
-- if (vfx.handle ~= -1) then
-- effect_stop(vfx.handle)
-- vfx.handle = -1
-- end
-- end
m13_unrestrict_players()
hud_prompt_clear()
marker_remove(M13_nav.jump_to)
teleport(LOCAL_PLAYER, M13_nav.elevator_to_balcony, true)
if M13_in_coop then
teleport(REMOTE_PLAYER, M13_nav.elevator_to_balcony_remote, true)
end
m13_disable_traffic( false )
cleanup_threads( M13_threads )
m13_disable_ambient_spawning( false )
crib_disable_interface( false )
action_nodes_enable( true )
audio_object_post_event("M13_Score_Stop", nil, nil, LOCAL_PLAYER)
if M13_status.cellphone_call_in_progress ~= nil then
audio_remove_mission_cellphone( M13_status.cellphone_call_in_progress )
end
end
-- Called when the mission has ended with success
-- CALLED FROM CODE (+++MUST RETURN IMMEDIATLY+++)
--
function m13_success()
local skip_teleport = true
m13_coop_skip(skip_teleport) -- do the stuff we'd do in the skip case
city_zone_swap( "hq", false )
city_zone_swap( "hq_dmg", true )
end
-- *************************
--
-- Local functions
--
-- *************************
-- Initialize the mission for the specified checkpoint
--
-- checkpoint: Checkpoint to initialize the mission to
--
function m13_initialize(checkpoint)
-- Make sure the screen is completly faded out
mission_start_fade_out(0.0)
-- Set the mission author
set_mission_author("Craig Williams")
-- don't allow crib interaction during this mission
crib_disable_interface( true )
-- Common initialization
m13_initialize_common()
-- Checkpoint specific initialization
m13_initialize_checkpoint(checkpoint)
-- don't allow crib interaction during this mission
crib_disable_interface( true )
end
-- ***************************************************
-- m13_run Helper Functions
-- ***************************************************
-- Move the player(s) to the mission start, and setup the required npcs
--
function m13_setup_start()
group_create_hidden(M13_groups.vehicles_start.name, true)
group_create_hidden(M13_groups.pierce_start.name, true)
set_unenterable_for_player(M13_groups.pierce_start.vehicle, true)
inv_weapon_add_temporary(LOCAL_PLAYER, M13_config.grenade, 1, true, true, false)
if M13_in_coop then
inv_weapon_add_temporary(REMOTE_PLAYER, M13_config.grenade, 1, true, true, false)
end
end
function m13_mission_zscene_post_init()
vehicle_show(M13_groups.vehicles_start.vehicles[1])
if coop_is_active() then
vehicle_show(M13_groups.vehicles_start.vehicles[2])
end
group_show(M13_groups.pierce_start.name)
end
-- Unload any groups created during the start of the mission
--
function m13_cleanup_start()
if group_is_loaded(M13_groups.vehicles_start.name) then
group_destroy(M13_groups.vehicles_start.name)
end
if group_is_loaded(M13_groups.pierce_start.name) then
group_destroy(M13_groups.pierce_start.name)
end
end
-- Spawn some statically placed STAG at the pr center, some vehicles for cover,
-- and setup all the banners.
--
function m13_setup_banner_scene()
m13_play_persona_line(M13_persona_line.banners)
M13_banners_alive = 0
M13_banner_damaged = false
M13_banner_destroyed = false
for key, banner in pairs(M13_movers.pr_center_banners) do
if not mesh_mover_destroyed(banner.name) then
marker_add(banner.name, MINIMAP_ICON_KILL, OI_ASSET_KILL_FULL, OI_FLAGS_FULL, SYNC_ALL)
banner.destroyed = false
on_mover_destroyed("m13_banner_destroyed", banner.name)
on_take_damage("m13_banner_damaged", banner.name)
M13_banners_alive = M13_banners_alive + 1
else
M13_banner_damaged = true
M13_banner_destroyed = true
end
end
end
function m13_cleanup_banner_scene()
if group_is_loaded(M13_groups.pr_static.name) then
release_to_world(M13_groups.pr_static.name)
group_destroy(M13_groups.pr_static.name)
end
for key, banner in pairs(M13_movers.pr_center_banners) do
marker_remove(banner.name)
on_mover_destroyed("", banner.name)
on_take_damage("", banner.name)
end
m13_stop_all_continuous_spawns()
end
-- Move the player to the observation deck/balcony, start the ambient Saints spawns, and
-- create your homies
--
function m13_setup_balcony_battle()
action_nodes_enable( false )
m13_setup_balcony_homies()
-- Setup the some ambient spawns to ocassionaly produce Saints members to slow down the STAG
-- from entering the building, also add cars for them to take cover behind
group_create(M13_groups.vehicles_cover.name, true)
for key, car in pairs(M13_groups.vehicles_cover.vehicles) do
vehicle_make_corpse(car, false)
end
m13_start_continuous_spawns(M13_continuous_spawns.saints_north_ground)
m13_start_continuous_spawns(M13_continuous_spawns.saints_south_ground)
--m13_start_continuous_spawns(M13_continuous_spawns.saints_north_balcony)
m13_start_continuous_spawns(M13_continuous_spawns.saints_south_balcony)
notoriety_force_no_spawn("Police", true)
notoriety_force_no_spawn("stag", true)
notoriety_force_no_spawn("luchadores", true)
notoriety_force_no_spawn("deckers", true)
notoriety_force_no_spawn("morningstar", true)
notoriety_set_min("Police", 5)
notoriety_set_max("Police", 5)
if M13_checkpoint == M13_CHECKPOINT_WAVE_3_START then
local pierce = M13_groups.pierce_rescue.pierce
group_create(M13_groups.pierce_rescue.name, true)
party_add(pierce, LOCAL_PLAYER)
on_death("m13_homie_died", pierce)
teleport(pierce, M13_nav.elevator_to_ground, true, true, 2.0)
inv_weapon_add_temporary(LOCAL_PLAYER, M13_config.airstrike, 1, true, true, false)
if M13_in_coop then
inv_weapon_add_temporary(REMOTE_PLAYER, M13_config.airstrike, 1, true, true, false)
end
end
end
function m13_setup_balcony_homies()
-- Create your homies and the aviable weapons to fend off the STAG
group_create(M13_groups.homies.name, true)
group_create(M13_groups.weapons.name, true)
--npc_leash_to_nav(M13_groups.homies.oleg, "nav_oleg_leash", 15.0)
--follower_make_independent(M13_groups.homies.oleg, true)
--party_add(M13_groups.homies.oleg, LOCAL_PLAYER)
--on_death("m13_homie_died", M13_groups.homies.oleg)
npc_leash_to_nav(M13_groups.homies.viola, "nav_viola_leash", 15.0)
follower_make_independent(M13_groups.homies.viola, true)
party_add(M13_groups.homies.viola, LOCAL_PLAYER)
on_death("m13_homie_died", M13_groups.homies.viola)
turn_invulnerable( M13_groups.homies.viola )
end
function m13_start_continuous_spawns(spawns)
for key, region in pairs(spawns.regions) do
spawn_region_toggle_filter(region, spawns.filter)
spawn_region_enable(region, true)
end
for key, group in pairs(spawns.groups) do
continuous_spawn_start(group, 0, spawns.respawn_delay, "", spawns.filter)
end
spawns.loaded = true
end
function m13_stop_continuous_spawns(spawns)
if spawns.loaded ~= true then
return
end
for key, group in pairs(spawns.groups) do
continuous_spawn_stop(group, false)
end
continuous_spawn_regions_enable(spawns.regions, false)
spawns.loaded = nil
end
function m13_stop_all_continuous_spawns()
for key, spawns in pairs(M13_continuous_spawns) do
m13_stop_continuous_spawns(spawns)
end
end
-- Cleans up everything setup by m13_setup_balcony_battle()
--
function m13_cleanup_balcony_battle()
m13_cleanup_balcony_homies()
if group_is_loaded(M13_groups.pierce_rescue.name) then
if npc_is_in_party(M13_groups.pierce_rescue.pierce) then
on_dismiss("", M13_groups.pierce_rescue.pierce)
party_dismiss(M13_groups.pierce_rescue.pierce)
end
marker_remove(M13_groups.pierce_rescue.pierce, SYNC_ALL)
on_death("", M13_groups.pierce_rescue.pierce)
group_destroy(M13_groups.pierce_rescue.name)
end
if group_is_loaded(M13_groups.pierce_attack.name) then
marker_remove(M13_groups.pierce_rescue.tank, SYNC_ALL)
group_destroy(M13_groups.pierce_attack.name)
end
m13_stop_wave_set(M13_waves)
m13_stop_all_continuous_spawns()
if group_is_loaded(M13_groups.vehicles_cover.name) then
group_destroy(M13_groups.vehicles_cover.name)
end
end
function m13_cleanup_balcony_homies()
if group_is_loaded(M13_groups.homies.name) then
marker_remove(M13_groups.homies.viola)
party_dismiss(M13_groups.homies.viola)
--party_dismiss(M13_groups.homies.oleg)
--on_death("", M13_groups.homies.oleg)
on_death("", M13_groups.homies.viola)
group_destroy(M13_groups.homies.name)
end
if group_is_loaded(M13_groups.weapons.name) then
group_destroy(M13_groups.weapons.name)
end
end
-- Moves the player to the penthouse and spawn any needed homies
--
function m13_setup_decision()
world_despawn_all_vehicles()
group_create(M13_groups.penthouse_homies.name, true)
on_death("m13_homie_died", M13_groups.penthouse_homies.josh)
end
-- Cleanup any groups set up by m13_setup_decision()
--
function m13_cleanup_decision()
if group_is_loaded(M13_groups.penthouse_homies.name) then
on_death("", M13_groups.penthouse_homies.josh)
group_destroy(M13_groups.penthouse_homies.name)
end
-- penthouse_stag is setup by m13_penthouse_cutscene(). Clean it up here.
if group_is_loaded(M13_groups.penthouse_stag.name) then
for key, vtol in pairs(M13_groups.penthouse_stag.vtols) do
if vtol.thread ~= INVALID_THREAD_HANDLE then
thread_kill(vtol.thread)
vtol.thread = INVALID_THREAD_HANDLE
end
end
group_destroy(M13_groups.penthouse_stag.name)
end
end
-- Hides the car bombs
--
function m13_hide_car_bombs()
for key, bomb in pairs(M13_movers.bombs) do
local mover_name = bomb.mover
mesh_mover_hide(mover_name)
end
end
-- Unhides and resets the car bombs
--
function m13_show_car_bombs()
for key, bomb in pairs(M13_movers.bombs) do
local mover_name = bomb.mover
mesh_mover_reset(mover_name)
mesh_mover_show(mover_name)
end
end
function m13_find_closest_car_bomb(north_side)
local closest = ""
local closest_dist = 100000.0
for key, bomb in pairs(M13_movers.bombs) do
local mover_name = bomb.mover
if bomb.north_side == north_side and not mesh_mover_destroyed(mover_name) then
local dist = get_dist(LOCAL_PLAYER, mover_name)
if dist < closest_dist then
closest = mover_name
closest_dist = dist
end
end
end
return closest, closest_dist
end
function m13_car_bomb_destroyed(north_side)
for key, bomb in pairs(M13_movers.bombs) do
local mover_name = bomb.mover
if bomb.north_side == north_side and mesh_mover_destroyed(mover_name) then
return true
end
end
return false
end
-- Setup all the car bombs
--
function m13_setup_car_bombs()
-- Setup a callback to detect when the player damage the bombs
for key, bomb in pairs(M13_movers.bombs) do
local mover_name = bomb.mover
on_take_damage("m13_mover_damaged", mover_name)
end
-- Setup a thread to handle the chain reactions and bomb respawning
M13_THREAD_CAR_BOMB_MANAGER = thread_new("m13_thread_car_bomb_manager")
end
-- Cleans up everything setup by m13_setup_car_bombs()
--
function m13_cleanup_car_bombs()
for key, bomb in pairs(M13_movers.bombs) do
local mover_name = bomb.mover
on_take_damage("", mover_name)
end
if M13_THREAD_CAR_BOMB_MANAGER ~= INVALID_THREAD_HANDLE then
thread_kill(M13_THREAD_CAR_BOMB_MANAGER)
M13_THREAD_CAR_BOMB_MANAGER = INVALID_THREAD_HANDLE
end
end
-- Tell the player to go to the PR Center and destroy the STAG's banner
--
function m13_destroy_banner()
-- start creating the group now
group_create(M13_groups.pr_static.name, true)
mesh_mover_show(M13_movers.pr_center_banners[1].name)
mesh_mover_show(M13_movers.pr_center_banners[2].name)
m13_goto_a_trigger(M13_triggers.pr_center_front, M13_OBJ_GOTO_PR_CENTER, true)
m13_setup_banner_scene()
objective_text(0, M13_OBJ_DESTROY_STAG_BANNER, "", "", SYNC_ALL, OI_ASSET_KILL)
-- if not M13_banner_damaged then
-- m13_play_persona_line(M13_persona_line.molotov_remind)
-- end
-- Wait until a banner is damaged
while not M13_banner_damaged do
thread_yield()
end
-- Remove the on_take_damage callbacks since we no longer care about this event
for key, banner in pairs(M13_movers.pr_center_banners) do
on_take_damage("", banner.name)
end
-- Start some ambient STAG and notoriety spawns
-- m13_start_continuous_spawns(M13_continuous_spawns.pr_center_wave_1)
notoriety_set_min("Police", M13_config.min_notoriety_after_banner_damaged)
-- Wait until the banner is destroyed
while not M13_banner_destroyed do
thread_yield()
end
-- Start some additional STAG spawns and up the notoriety
-- m13_start_continuous_spawns(M13_continuous_spawns.pr_center_wave_2)
notoriety_set_min("Police", M13_config.min_notoriety_after_banner_destroyed)
-- Wait until all banners are destroyed
while M13_banners_alive > 0 do
thread_yield()
end
notoriety_set_min("Police", M13_config.min_notoreity_after_all_banners_destroyed)
m13_cleanup_banner_scene()
end
-- Plays the mid mission cutscene and sets up the STAG to reflect the scene.
--
function m13_penthouse_cutscene()
-- Prevent the player from moving
player_movement_disable(LOCAL_PLAYER)
group_create_hidden(M13_groups.penthouse_stag.name, true)
if false then
teleport_coop( M13_nav.player_penthouse, M13_nav.remote_penthouse )
else
cutscene_play( "13_Z01", nil, { M13_nav.player_penthouse, M13_nav.remote_penthouse } )
end
-- Ensure the local and remote player are in the proper location
-- Prevent the Player from doing anything bad
m13_restrict_players()
m13_setup_penthouse_stag()
group_show( M13_groups.penthouse_stag.name )
while character_is_ready( M13_groups.penthouse_homies.josh ) == false do
thread_yield()
end
-- Force the player to take Josh as a Human Shield
player_take_human_shield(LOCAL_PLAYER, M13_groups.penthouse_homies.josh, true)
action_play_synced_state(LOCAL_PLAYER, M13_groups.penthouse_homies.josh, "HS_Stand_M13")
player_human_shield_lock(LOCAL_PLAYER, true)
end
-- Sets up the STAG to match the cutscene
--
function m13_setup_penthouse_stag()
for key, vtol in pairs(M13_groups.penthouse_stag.vtols) do
m13_setup_penthouse_vtol(vtol)
end
end
-- Populates a vtol and moves it to the proper location
--
function m13_setup_penthouse_vtol(vtol)
-- Populate the vtol
vehicle_enter_group_teleport(vtol.members, vtol.name)
vehicle_suppress_npc_exit(vtol.name, true)
thread_yield()
-- Move the vtol to the proper location
teleport_vehicle(vtol.name, vtol.nav)
thread_yield()
if vtol.fly_to ~= "" then
M13_threads[ vtol.name .. "_fly_to" ] = thread_new( "m13_decision_heli_thread", vtol.name, vtol.fly_to)
else
M13_threads[ vtol.name .. "_fly_to" ] = thread_new( "m13_decision_heli_thread", vtol.name, vtol.nav)
end
end
-- another wrapper for the fly_to so it can be threaded without barfing Lua
function m13_decision_heli_thread( name, fly_to )
helicopter_fly_to_direct( name, -1, fly_to)
end
-- Prevents the player from doing anything harmful during the decision scene
--
function m13_restrict_players()
-- Prevent the player from using any weapons
inv_item_equip(nil, LOCAL_PLAYER)
inv_weapon_disable_all_slots(true, SYNC_LOCAL)
player_actions_disable(LOCAL_PLAYER)
-- Limit the Player's view range to Cyrus and Shaundi
camera_restrict_target_object(M13_groups.penthouse_stag.vtols[1].name, 0, LOCAL_PLAYER)
camera_restrict_set_limits(-10, 10, -35, 30, LOCAL_PLAYER)
camera_restrict_set_active(true, LOCAL_PLAYER)
player_grenades_disable()
turn_invulnerable( LOCAL_PLAYER )
-- Do the same for the remote player if needed
if M13_in_coop then
player_movement_disable(REMOTE_PLAYER)
player_actions_disable(REMOTE_PLAYER)
inv_item_equip(nil, REMOTE_PLAYER)
inv_weapon_disable_all_slots(true, SYNC_REMOTE)
camera_restrict_target_object(M13_groups.penthouse_stag.vtols[1].name, 0, REMOTE_PLAYER)
camera_restrict_set_limits(-10, 10, -35, 30, REMOTE_PLAYER)
camera_restrict_set_active(true, REMOTE_PLAYER)
turn_invulnerable( REMOTE_PLAYER )
end
end
-- Allows the player to move, use weapons, and unrestricts the camera
--
function m13_unrestrict_players()
player_movement_enable(LOCAL_PLAYER)
inv_weapon_disable_all_slots(false, SYNC_LOCAL)
camera_restrict_set_active(false, LOCAL_PLAYER)
player_grenades_enable()
player_actions_enable(LOCAL_PLAYER)
turn_vulnerable( LOCAL_PLAYER )
if M13_in_coop then
player_movement_enable(REMOTE_PLAYER)
player_actions_enable(REMOTE_PLAYER)
inv_weapon_disable_all_slots(false, SYNC_REMOTE)
camera_restrict_set_active(false, REMOTE_PLAYER)
turn_vulnerable( REMOTE_PLAYER )
end
player_human_shield_lock(LOCAL_PLAYER, false)
end
-- Haandles the logic of the Player's decision. Wait until the player throws Josh to Cyrus, the player
-- throws Josh to Shuandi, or if the player doesn't do anything for ~60 seconds.
--
function m13_player_decision()
local josh = M13_groups.penthouse_homies.josh
local cyrus = M13_groups.penthouse_stag.cyrus
local shaundi = M13_groups.penthouse_homies.shaundi
-- Initialize the variables used by the callbacks
M13_josh_given_to_cyrus = false
M13_josh_given_to_homies = false
player_human_shield_lock(LOCAL_PLAYER, true)
set_player_can_enter_exit_vehicles(LOCAL_PLAYER, false)
set_unjackable_flag( M13_groups.penthouse_stag.vtols[ 1 ].name, true )
if M13_in_coop then
set_player_can_enter_exit_vehicles(REMOTE_PLAYER, false)
end
delay(2.0)
m13_start_convo_thread( M13_convo.decision1 )
-- show tutorial after delay
marker_add( cyrus, MINIMAP_ICON_USE, OI_ASSET_USE, OI_FLAGS_FULL, SYNC_ALL)
marker_add( shaundi, MINIMAP_ICON_USE, OI_ASSET_USE, OI_FLAGS_FULL, SYNC_ALL)
object_indicator_add_objective_text( cyrus, "PLAYER_CHOICE_M13_OPTION1_TITLE", "PLAYER_CHOICE_M13_OPTION1_BODY")
object_indicator_add_objective_text( shaundi, "PLAYER_CHOICE_M13_OPTION2_TITLE", "PLAYER_CHOICE_M13_OPTION2_BODY")
local active_prompt = ""
while not M13_josh_given_to_cyrus and not M13_josh_given_to_homies do
thread_yield()
-- Check to see who the player is looking at
if fov_check_xz_plane(LOCAL_PLAYER, shaundi, M13_config.fov_to_shaundi) then
if active_prompt ~= M13_PROMPT_THROW_JOSH_TO_SHAUNDI then
hud_prompt(LOCAL_PLAYER, M13_PROMPT_THROW_JOSH_TO_SHAUNDI, "m13_josh_thrown_to_homies")
active_prompt = M13_PROMPT_THROW_JOSH_TO_SHAUNDI
end
elseif fov_check_xz_plane(LOCAL_PLAYER, cyrus, M13_config.fov_to_cyrus) then
if active_prompt ~= M13_PROMPT_THROW_JOSH_TO_CYRUS then
hud_prompt(LOCAL_PLAYER, M13_PROMPT_THROW_JOSH_TO_CYRUS, "m13_josh_thrown_to_cyrus")
active_prompt = M13_PROMPT_THROW_JOSH_TO_CYRUS
end
else
if active_prompt ~= "" then
hud_prompt_clear(LOCAL_PLAYER)
active_prompt = ""
end
end
-- If the conversation thread was terminated, then Cyrus is done waiting.
-- Assume the Player wanted to keep josh in this situation
if M13_convo.decision1.thread == INVALID_THREAD_HANDLE then
m13_josh_thrown_to_homies()
end
end
marker_remove( cyrus )
marker_remove( shaundi )
player_human_shield_lock(LOCAL_PLAYER, false)
player_release_human_shield( LOCAL_PLAYER, true )
action_stop_synced_state(LOCAL_PLAYER)
set_player_can_enter_exit_vehicles(LOCAL_PLAYER, true)
set_unjackable_flag( M13_groups.penthouse_stag.vtols[ 1 ].name, false )
if M13_in_coop then
set_player_can_enter_exit_vehicles(REMOTE_PLAYER, true)
end
hud_prompt_clear(LOCAL_PLAYER)
m13_unload_all_convos()
-- The player has made their decision. Have them release Josh.
action_play_synced( LOCAL_PLAYER, josh, "Mad13_Human_Shield_release1" )
-- Add a short delay to ensure that the NPC is in a useable state
set_ignore_ai_flag(josh, false)
delay(0.4)
npc_go_idle(josh)
-- Tell Josh to run to who ever he was told to go to
-- if M13_josh_given_to_homies then
-- ai_do_scripted_move(josh, M13_nav.josh_to_shaundi, true, false)
-- else
-- ai_do_scripted_move(josh, M13_nav.josh_to_cyrus, true, false)
-- end
while ai_scripted_action_is_processing(josh) and not ai_scripted_action_is_complete(josh) do
thread_yield()
end
delay(0.2)
set_ignore_ai_flag(josh, true)
end
-- Turns a VTOL around, tells Cyrus to walk up to it, and then have him jump on board with or without Josh
--
-- cyrus - Name of Cyrus
-- josh - Name of Josh
-- cyrus_has_josh - Was Josh given to Cyrus?
-- vtol - Name of the VTOL Cyrus should enter
--
function m13_cyrus_enter_vtol(cyrus, josh, cyrus_has_josh, vtol)
local r
if cyrus_has_josh then
vehicle_enter(cyrus, vtol.name, 4, false)
m13_start_convo_thread(M13_convo.shell_the_building)
vehicle_enter(josh, vtol.name, 3, false)
repeat
thread_yield()
r = vehicle_enter_check_done(cyrus, false, vtol.name)
until r ~= 0
repeat
thread_yield()
r = vehicle_enter_check_done(josh, false, vtol.name)
until r ~= 0
else
m13_start_convo_thread(M13_convo.shell_the_building)
vehicle_enter(cyrus, vtol.name, 4, true)
end
end
-- Tells Cyrus to fly off. If Josh was given to cryus, the guard VTOLs will follow; otherwise,
-- the VTOLs will be told to attack the player.
--
-- cyrus - Name of the Cyrus NPC
-- cyrus_has_josh - Was josh given to cyrus?
-- cyrus_vtol - VTOL Cyrus is in
--
function M13_cyrus_fly_off(cyrus, cyrus_has_josh, cyrus_vtol)
ai_do_scripted_move(M13_groups.penthouse_homies.shaundi, M13_nav.penthouse_elevator, true, false)
if not cyrus_has_josh then
ai_do_scripted_move(M13_groups.penthouse_homies.josh, M13_nav.penthouse_elevator, true, false)
end
for key, vtol in pairs(M13_groups.penthouse_stag.vtols) do
if vtol == cyrus_vtol then
vtol.thread = thread_new("m13_thread_vtol_fly_away", vtol)
else
local driver = vtol.members[1]
ai_set_action_delay(driver, "throw grenade", 9999)
set_ignore_ai_flag(driver, false)
npc_hearing_enable(driver, true)
ai_add_enemy_target(driver, LOCAL_PLAYER, ATTACK_NOW_NEVER_LOSE, true)
end
end
if cyrus_has_josh then
m13_start_convo_thread(M13_convo.shell_without_birk)
else
m13_start_convo_thread(M13_convo.shell_with_birk)
end
end
-- Blocks until the player runs to the elevator or jumps off the building
--
function m13_player_leave_penthouse()
-- Setup a time limit to escape the battle
hud_timer_set(1, M13_config.time_to_escape * 1000.0, "m13_time_is_up", SYNC_ALL)
hud_timer_hide(1, false)
-- The player can complete this objective by jumping off the building. Enable to trigger to disable this.
trigger_enable(M13_triggers.penthouse_jumped, true)
on_trigger_exit("m13_jumped_off_penthouse", M13_triggers.penthouse_jumped)
-- Instruct the player to get to the Penthouse elevator
M13_status.jumped_off_penthouse = false
objective_text(0, M13_OBJ_ESCAPE, "", "", SYNC_ALL, OI_ASSET_LOCATION)
marker_add(M13_nav.jump_to, MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION, OI_FLAGS_FULL, SYNC_ALL)
-- wait for a player to leave area
while M13_status.jumped_off_penthouse == false do
thread_yield()
end
hud_timer_stop( 1 )
end
-- Marks a car bomb to explode
--
-- mover_name: Name of the mover to detonate
--
function m13_car_bomb_detonate(mover_name)
for key, bomb in pairs(M13_movers.bombs) do
if bomb.mover == mover_name then
-- Mark the bomb to explode
bomb.detonate = true
-- Set the bomb to explode without a delay
bomb.delay = 0.0
return
end
end
end
-- A bomb has exploded. Find all bombs that should detontate based off the chain reaction effect.
--
-- exploding_bomb: Bomb that has just exploded
--
function m13_car_bomb_start_chain_reaction(exploding_bomb)
-- Iterate through the entire table and check to see if the other bombs are affected.
-- Since these are all movers, we cannot cache the relationship between bombs.
for key, bomb in pairs(M13_movers.bombs) do
local dist = get_dist(exploding_bomb.mover, bomb.mover)
if not mesh_mover_destroyed(bomb.mover) and dist < M13_config.chain_reaction_max_dist then
-- The bomb is alive and within the chain reaction range. Calculte the explosion delay and update
-- the bomb as such.
local delay = M13_config.chain_reaction_delay
if M13_config.chain_reaction_scale_delay == true then
-- Scale the delay based off how far the bomb is from the exploding bomb.
delay = M13_config.chain_reaction_scale_mul * delay * dist / M13_config.chain_reaction_max_dist
end
if not bomb.detonate or delay < bomb.delay then
bomb.detonate = true
bomb.delay = delay
end
end
end
end
-- Iterates through the active bomb list and check for any bombs that should explode.
-- Returns an updated list of active bombs
--
-- active: Table of active car bombs
--
function m13_car_bombs_check_for_detonation(active)
if #active == 0 then
return active
end
local frame_time = get_frame_time()
local still_active = {}
for key, bomb in pairs(active) do
-- Check to see if the bomb is marked to explode
if bomb.detonate and bomb.delay <= 0.0 then
-- Bomb timer is up.
m13_car_bomb_start_chain_reaction(bomb)
-- Destroy the mover and trigger the on death explosion
mesh_mover_kill(bomb.mover)
else
if bomb.detonate then
-- Bomb timer still has some time left. Wait to actually detonate it.
bomb.delay = bomb.delay - frame_time
end
still_active[#still_active + 1] = bomb
end
end
return still_active
end
function m13_setup_save_pierce_wave()
-- Spawn Pierce and have him enter his car
group_create(M13_groups.pierce_rescue.name, true)
group_create(M13_groups.pierce_attack.name, true)
local pierce = M13_groups.pierce_rescue.pierce
local vehicle = M13_groups.pierce_rescue.vehicle
local tank = M13_groups.pierce_attack.tank
local tank_members = M13_groups.pierce_attack.tank_members
on_death("m13_homie_died", pierce)
-- Don't allow Pierce to take damage until he gets to the crash site
turn_invulnerable(pierce)
-- It may take a few frames for Pierce to enter his vehicle, so prevent him from being disrupted
set_ignore_ai_flag(pierce, true)
character_prevent_explosion_fling(pierce, true)
character_prevent_flinching(pierce, true)
vehicle_suppress_npc_exit(tank, true)
vehicle_enter_teleport(tank_members[1], tank, 0, true)
vehicle_enter_teleport(tank_members[2], tank, 1, true)
vehicle_enter_teleport(pierce, vehicle, 0, true)
vehicle_suppress_npc_exit(vehicle, true)
set_ignore_ai_flag(pierce, false)
character_prevent_flinching(pierce, false)
-- Set the tank to be hostile to Pierce
for key, npc in pairs(tank_members) do
ai_add_enemy_target(npc, pierce, ATTACK_NOW_NEVER_LOSE)
end
end
function m13_pierce_drive_in()
local pierce = M13_groups.pierce_rescue.pierce
local vehicle = M13_groups.pierce_rescue.vehicle
local tank = M13_groups.pierce_attack.tank
-- Make sure the tank and pierce actually get to their destination
-- vehicle_infinite_mass(tank, true)
vehicle_infinite_mass(vehicle, true)
vehicle_set_script_hard_goto(vehicle, true)
vehicle_suppress_flipping(vehicle, true)
-- Add the marker as soon as possible, since it's hard to pick him out otherwise
marker_add(pierce, MINIMAP_ICON_PROTECT_ACQUIRE, OI_ASSET_DEFEND, OI_FLAGS_FULL, SYNC_ALL)
m13_start_convo_thread(M13_convo.pierce_drive_in)
if M13_status.restart_checkpoint == M13_CHECKPOINT_WAVE_2_START then
audio_object_post_event("M13_Score_Checkpoint_Wave2", nil, nil, LOCAL_PLAYER)
else
audio_object_post_event("M13_Score_Cover_Pierce", nil, nil, LOCAL_PLAYER)
end
objective_text(0, M13_OBJ_COVER_PIERCE, "", "", SYNC_ALL, OI_ASSET_DEFEND)
m13_setup_side("clear")
-- vehicle_chase(tank, pierce, false, false, true, false)
vehicle_speed_override(vehicle, 30.0)
vehicle_speed_override(tank, 20.0)
M13_threads.pierce_flee = thread_new( "m13_thread_wrapper", vehicle_pathfind_to, vehicle, M13_groups.pierce_rescue.path, true, true, false, true )
M13_threads.tank_chase_pierce = thread_new( "m13_thread_wrapper", vehicle_pathfind_to, tank, M13_groups.pierce_attack.path, true, true, false, true )
local time_waited = 0
while time_waited < 45 and vehicle_pathfind_check_done( vehicle ) == 0 do
time_waited = time_waited + get_frame_time()
thread_yield()
end
thread_kill( M13_threads.pierce_flee )
vehicle_stop( vehicle )
-- Allow the tank and pierce's car to be pushed around again
-- vehicle_infinite_mass(tank, false)
vehicle_infinite_mass(vehicle, false)
-- Setting a vehicle on fire will force pierce to exit as well
vehicle_suppress_npc_exit(vehicle, false)
vehicle_set_smoke_and_fire_state(vehicle, true, true)
-- lets make sure he gets out and stays out
vehicle_exit_teleport( pierce )
ai_clear_scripted_action ( pierce )
marker_remove(pierce)
end
function m13_cleanup_save_pierce_wave()
end
function m13_goto_ground(obj_text)
m13_play_persona_line(M13_persona_line.elevator)
m13_goto_a_trigger(M13_triggers.elevator_to_ground, obj_text)
fade_out(0.5)
fade_out_block()
teleport_coop(M13_nav.elevator_to_balcony, M13_nav.elevator_to_balcony_remote)
fade_in(0.5)
fade_in_block()
end
function m13_goto_balcony(obj_text)
m13_goto_a_trigger(M13_triggers.elevator_proximity, obj_text)
fade_out(0.5)
fade_out_block()
teleport_coop(M13_nav.elevator_to_ground, M13_nav.elevator_to_ground_remote, true)
fade_in(0.5)
fade_in_block()
end
function m13_save_pierce()
local pierce = M13_groups.pierce_rescue.pierce
local normal_hitpoints = 0
normal_hitpoints = get_max_hit_points(pierce)
set_max_hit_points(pierce, 50000, true)
-- Allow Pierce to be killed now
turn_vulnerable(pierce)
objective_text(0, M13_OBJ_GOTO_PIERCE, "", "", SYNC_ALL, OI_ASSET_LOCATION)
m13_setup_side("clear")
marker_add(pierce, MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION, OI_FLAGS_FULL, SYNC_ALL)
m13_vfx_play(M13_vfxs.hq_01)
m13_vfx_play(M13_vfxs.north_02)
m13_distance_clutter_show()
m13_vfx_play(M13_vfxs.south_02)
m13_play_persona_line(M13_persona_line.in_trouble_02)
-- Wait until the player is in range of pierce
while true do
if get_dist( pierce, LOCAL_PLAYER ) < 7 then
party_add( pierce, LOCAL_PLAYER )
break
end
if coop_is_active() then
if get_dist( pierce, REMOTE_PLAYER ) < 7 then
party_add( pierce, REMOTE_PLAYER )
break
end
end
thread_yield()
end
marker_remove(pierce, SYNC_ALL)
follower_set_can_abandon(pierce, true)
on_dismiss("m13_pierce_abandoned", pierce)
m13_play_convo_set(M13_convo.save_pierce_4)
set_max_hit_points(pierce, normal_hitpoints, true)
end
function m13_pierce_give_player_airstrike()
-- m13_play_convo_set(M13_convo.save_pierce_4)
inv_weapon_add_temporary(LOCAL_PLAYER, M13_config.airstrike, 1, true, true, false)
if M13_in_coop then
inv_weapon_add_temporary(REMOTE_PLAYER, M13_config.airstrike, 1, true, true, false)
end
m13_play_convo_set(M13_convo.airstrike)
end
function m13_mini_tank_wave()
end
-- Tells Pierce to drive into the scene, get shot up, and wait until the player picks up Pierce
--
function m13_save_pierce_wave()
m13_setup_save_pierce_wave()
m13_pierce_drive_in()
m13_start_wave_set(M13_waves.scene_5_drop_off)
M13_threads.music_cue = thread_new( "m13_audio_event_at_dist", M13_triggers.elevator_to_ground, 10, "M13_Score_Elevator" )
m13_goto_ground(M13_OBJ_GOTO_ELEVATOR)
thread_kill( M13_threads.music_cue )
m13_cleanup_balcony_homies()
audio_object_post_event("M13_Score_Get_Pierce", nil, nil, LOCAL_PLAYER)
m13_save_pierce()
audio_object_post_event("M13_Score_Return_HQ", nil, nil, LOCAL_PLAYER)
M13_threads.music_cue = thread_new( "m13_audio_event_at_dist", M13_triggers.elevator_proximity, 25, "M13_Score_Arrive_HQ" )
m13_goto_balcony(M13_OBJ_GOTO_SAINTS_HQ)
m13_vfx_play(M13_vfxs.north_03)
m13_distance_clutter_show()
m13_vfx_play(M13_vfxs.hq_02)
thread_kill( M13_threads.music_cue )
m13_stop_wave_set(M13_waves.scene_5_drop_off)
objective_text(0, M13_OBJ_DEFEND_THE_NORTH, "", "", SYNC_ALL, OI_ASSET_DEFEND)
m13_setup_side("north")
m13_setup_balcony_homies()
m13_pierce_give_player_airstrike()
m13_cleanup_save_pierce_wave()
end
function m13_audio_event_at_dist( target, dist, event )
local l_dist
local r_dist = 999999
while true do
l_dist = get_dist( LOCAL_PLAYER, target )
if coop_is_active() then
r_dist = get_dist( REMOTE_PLAYER, target )
end
if l_dist < dist or r_dist < dist then
audio_object_post_event( event, nil, nil, LOCAL_PLAYER )
return
end
thread_yield()
end
end
function m13_flag_closest_car_bomb(north_side)
if m13_car_bomb_destroyed(north_side) then
return
end
objective_text(0, M13_OBJ_DETONATE_CAR_BOMBS, "", "", SYNC_ALL, OI_ASSET_KILL)
m13_setup_side("clear")
if north_side then
m13_play_persona_line(M13_persona_line.car_bombs_01)
else
m13_play_persona_line(M13_persona_line.car_bombs_02)
end
for key, bomb in pairs(M13_movers.bombs) do
if bomb.north_side == north_side and not mesh_mover_destroyed(bomb.mover) then
marker_add(bomb, MINIMAP_ICON_KILL, OI_ASSET_KILL, OI_FLAGS_FULL, SYNC_ALL)
end
end
while not m13_car_bomb_destroyed(north_side) do
thread_yield()
end
for key, bomb in pairs(M13_movers.bombs) do
if bomb.north_side == north_side then
marker_remove(bomb)
end
end
end
-- Automatically enable and disable the proper waves, based of the provided level.
-- Up to 3 levels are supported
--
-- level: (integer) Defines the number of wave sets to attack the North side.
--
function m13_set_north_apc_level(level, trigger)
if level >= 1 then
if M13_north_apc_level < 1 then
m13_start_wave_set(M13_waves.apcs_north_1)
end
elseif M13_north_apc_level >= 1 then
m13_stop_wave_set(M13_waves.apcs_north_1, trigger)
end
if level >= 2 then
if M13_north_apc_level < 2 then
m13_start_wave_set(M13_waves.apcs_north_2)
end
elseif M13_north_apc_level >= 2 then
m13_stop_wave_set(M13_waves.apcs_north_2, trigger)
end
if level >= 3 then
if M13_north_apc_level < 3 then
m13_start_wave_set(M13_waves.apcs_north_3)
end
elseif M13_north_apc_level >= 3 then
m13_stop_wave_set(M13_waves.apcs_north_3, trigger)
end
M13_north_apc_level = level
end
-- Automatically enable and disable the proper waves, based of the provided level.
-- Up to 3 levels are supported
--
-- level: (integer) Defines the number of wave sets to attack the South side.
--
function m13_set_south_apc_level(level)
if level >= 1 then
if M13_south_apc_level < 1 then
m13_start_wave_set(M13_waves.apcs_south_1)
end
elseif M13_south_apc_level >= 1 then
m13_stop_wave_set(M13_waves.apcs_south_1)
end
if level >= 2 then
if M13_south_apc_level < 2 then
m13_start_wave_set(M13_waves.apcs_south_2)
end
elseif M13_south_apc_level >= 2 then
m13_stop_wave_set(M13_waves.apcs_south_2)
end
if level >= 3 then
if M13_south_apc_level < 3 then
m13_start_wave_set(M13_waves.apcs_south_3)
end
elseif M13_south_apc_level >= 3 then
m13_stop_wave_set(M13_waves.apcs_south_3)
end
M13_south_apc_level = level
end
-- Draw the player's attention towards the north side of the building, bring in a large convoy of
-- STAG, and then point out a car bomb if the player didn't already detonate (shoot) one
--
function m13_scene_1()
objective_text(0, M13_OBJ_DEFEND_THE_NORTH, "", "", SYNC_ALL, OI_ASSET_DEFEND)
m13_setup_side("north")
if M13_status.score_start_began ~= true then
audio_object_post_event("M13_Score_Start", nil, nil, LOCAL_PLAYER)
M13_status.score_start_began = true
end
delay(3.0)
m13_play_persona_line(M13_persona_line.attack_start)
-- M13_waves.scene_1 uses most of the APC groups. The north and south APC level must be set
-- to 0 for the convoy to work.
m13_set_north_apc_level(0)
m13_set_south_apc_level(0)
-- Bring in the massive convoy
m13_start_wave_set(M13_waves.scene_1)
-- objective_text(0, M13_OBJ_TAKE_OUT_THE_TANKS, "", "", SYNC_ALL, OI_ASSET_KILL)
-- Wait until all the groups are finished pathfinding
m13_wait_for_waves_to_complete_state(M13_waves.scene_1, M13_wave_states.pathfinding)
m13_set_north_apc_level(2)
m13_set_south_apc_level(0)
local north_side = true
m13_flag_closest_car_bomb(north_side)
-- objective_text(0, M13_OBJ_TAKE_OUT_THE_TANKS, "", "", SYNC_ALL, OI_ASSET_KILL)
--m13_wait_for_required_kills(M13_waves.scene_1)
objective_text(0, M13_OBJ_DEFEND_THE_NORTH, "", "", SYNC_ALL, OI_ASSET_DEFEND)
m13_setup_side("north")
m13_set_north_apc_level(2)
m13_set_south_apc_level(0)
delay(30.0)
m13_stop_wave_set(M13_waves.scene_1, M13_triggers.south_side)
end
-- Spawn some STAG on the observation deck to attack Viola, followed by a large convoy
--
function m13_scene_2()
turn_vulnerable( M13_groups.homies.viola )
m13_set_north_apc_level(0, M13_triggers.south_side)
m13_set_south_apc_level(0)
-- Give the south side some time to become populated with STAG
-- delay(30.0)
-- Spawn some STAG on the observation deck to attack Viola
m13_start_wave_set(M13_waves.scene_2_deck)
m13_start_convo_thread(M13_convo.help_viola)
objective_text(0, M13_OBJ_HELP_VIOLA, "", "", SYNC_ALL, OI_ASSET_DEFEND)
m13_setup_side("clear")
audio_object_post_event("M13_Score_Viola", nil, nil, LOCAL_PLAYER)
marker_add(M13_groups.homies.viola, MINIMAP_ICON_PROTECT_ACQUIRE, OI_ASSET_DEFEND, OI_FLAGS_FULL, SYNC_ALL)
m13_wait_for_required_kills(M13_waves.scene_2_deck)
marker_remove(M13_groups.homies.viola)
m13_stop_wave_set(M13_waves.scene_2_deck)
-- these are delayed in scene 1
-- make absolutely sure these get turned off now
m13_set_north_apc_level(0)
m13_stop_wave_set(M13_waves.scene_1)
-- Bring in the massive convoy
m13_start_wave_set(M13_waves.scene_2)
m13_play_persona_line(M13_persona_line.focus_south)
objective_text(0, M13_OBJ_DEFEND_THE_SOUTH, "", "", SYNC_ALL, OI_ASSET_DEFEND)
m13_setup_side("south")
audio_object_post_event("M13_Score_South1", nil, nil, LOCAL_PLAYER)
m13_wait_for_waves_to_complete_state(M13_waves.scene_2, M13_wave_states.pathfinding)
local north_side = false
m13_flag_closest_car_bomb(north_side)
objective_text(0, M13_OBJ_DEFEND_THE_SOUTH, "", "", SYNC_ALL, OI_ASSET_DEFEND)
m13_setup_side("south")
-- Turn on north side VFX
m13_vfx_play(M13_vfxs.north_01)
end
-- Spawn some snipers on the rooftops across the street
--
function m13_scene_3()
-- Focus the waves on the south side
m13_set_north_apc_level(1)
m13_set_south_apc_level(3)
delay(15.0)
m13_start_wave_set(M13_waves.scene_3_snipers)
m13_play_persona_line(M13_persona_line.snipers_01)
objective_text(0, M13_OBJ_TAKE_OUT_THE_SNIPERS, "", "", SYNC_ALL, OI_ASSET_KILL)
m13_setup_side("clear")
audio_object_post_event("M13_Score_Snipers", nil, nil, LOCAL_PLAYER)
m13_wait_for_required_kills(M13_waves.scene_3_snipers)
objective_text(0, M13_OBJ_DEFEND_THE_SOUTH, "", "", SYNC_ALL, OI_ASSET_DEFEND)
m13_setup_side("south")
audio_object_post_event("M13_Score_South2", nil, nil, LOCAL_PLAYER)
m13_stop_wave_set(M13_waves.scene_3_snipers)
end
-- Continue the assault from the North with some tanks
--
function m13_scene_4()
turn_invulnerable( M13_groups.homies.viola )
m13_set_north_apc_level(3)
m13_set_south_apc_level(0)
delay(2.0)
m13_start_wave_set(M13_waves.scene_4_tanks)
objective_text(0, M13_OBJ_TAKE_OUT_THE_TANKS, "", "", SYNC_ALL, OI_ASSET_KILL)
m13_setup_side("clear")
m13_play_persona_line(M13_persona_line.tanks_01)
m13_wait_for_required_kills(M13_waves.scene_4_tanks)
objective_text(0, M13_OBJ_DEFEND_THE_NORTH, "", "", SYNC_ALL, OI_ASSET_DEFEND)
m13_setup_side("north")
-- Turn on south side VFX
m13_vfx_play(M13_vfxs.south_01)
m13_stop_wave_set(M13_waves.scene_4_tanks)
end
-- Have Pierce drive on the scene and instruct the player to save him
--
function m13_scene_5()
-- Only have some light waves from the North, since the player will be on the ground
m13_set_north_apc_level(2)
m13_set_south_apc_level(0)
delay(3.0)
m13_save_pierce_wave()
end
-- Large Northward assault with some tanks and VTOls
--
function m13_scene_6()
-- Focus the waves on the North
m13_set_north_apc_level(3)
m13_set_south_apc_level(1)
m13_start_wave_set(M13_waves.scene_6_tanks)
objective_text(0, M13_OBJ_TAKE_OUT_THE_TANKS, "", "", SYNC_ALL, OI_ASSET_KILL)
m13_setup_side("clear")
if M13_status.restart_checkpoint == M13_CHECKPOINT_WAVE_3_START then
audio_object_post_event("M13_Score_Checkpoint_Wave3", nil, nil, LOCAL_PLAYER)
else
audio_object_post_event("M13_Score_Tanks", nil, nil, LOCAL_PLAYER)
end
m13_wait_for_required_kills(M13_waves.scene_6_tanks)
m13_stop_wave_set(M13_waves.scene_6_tanks)
objective_text(0, M13_OBJ_DEFEND_THE_NORTH, "", "", SYNC_ALL, OI_ASSET_DEFEND)
m13_setup_side("north")
delay(2.0)
m13_start_wave_set(M13_waves.scene_6_vtol_01)
m13_setup_side("clear")
audio_object_post_event("M13_Score_VTOLS", nil, nil, LOCAL_PLAYER)
m13_play_convo_set(M13_convo.first_heli)
objective_text(0, M13_OBJ_TAKE_OUT_THE_VTOLS, "", "", SYNC_ALL, OI_ASSET_KILL)
m13_wait_for_required_kills(M13_waves.scene_6_vtol_01)
m13_stop_wave_set(M13_waves.scene_6_vtol_01)
m13_start_wave_set(M13_waves.scene_6_vtol_02)
m13_setup_side("clear")
objective_text(0, M13_OBJ_TAKE_OUT_THE_VTOLS, "", "", SYNC_ALL, OI_ASSET_KILL)
m13_wait_for_required_kills(M13_waves.scene_6_vtol_02)
m13_stop_wave_set(M13_waves.scene_6_vtol_02)
objective_text(0, M13_OBJ_DEFEND_THE_NORTH, "", "", SYNC_ALL, OI_ASSET_DEFEND)
m13_setup_side("north")
delay(2.0)
m13_set_north_apc_level(3)
m13_set_south_apc_level(1)
turn_vulnerable( M13_groups.homies.viola )
-- m13_start_wave_set(M13_waves.scene_6_snipers)
-- objective_text(0, M13_OBJ_TAKE_OUT_THE_SNIPERS, "", "", SYNC_ALL, OI_ASSET_KILL)
-- m13_play_persona_line(M13_persona_line.snipers_02)
-- m13_wait_for_required_kills(M13_waves.scene_6_snipers)
-- m13_stop_wave_set(M13_waves.scene_6_snipers)
end
-- Large on going assault from the North, South, and the observation deck. Instruct the player to flee.
--
function m13_scene_7()
turn_invulnerable( M13_groups.homies.viola )
-- Full out assault on both sides
m13_set_north_apc_level(3)
m13_set_south_apc_level(3)
-- m13_stop_wave_set(M13_waves.scene_2_deck)
-- Spawn some STAG on the observation deck
delay(1.0)
m13_start_wave_set(M13_waves.scene_7_deck)
m13_setup_side("clear")
objective_text(0, M13_OBJ_CLEAR_THE_FLOOR, "", "", SYNC_ALL, OI_ASSET_KILL)
m13_play_convo_set(M13_convo.check_roof_01)
m13_wait_for_required_kills(M13_waves.scene_7_deck)
objective_text(0, M13_OBJ_DEFEND_THE_NORTH, "", "", SYNC_ALL, OI_ASSET_DEFEND)
m13_setup_side("north")
m13_play_convo_set(M13_convo.check_roof_02)
delay(1.0)
m13_start_continuous_spawns(M13_continuous_spawns.stag_deck_02)
delay(2.0)
m13_start_continuous_spawns(M13_continuous_spawns.stag_deck_01)
m13_play_convo_set(M13_convo.check_roof_03)
M13_threads.music_cue = thread_new( "m13_audio_event_at_dist", M13_triggers.elevator_to_penthouse, 14, "M13_Score_To_Roof" )
m13_setup_side("clear")
m13_goto_a_trigger(M13_triggers.elevator_to_penthouse, M13_OBJ_GOTO_PENTHOUSE, false)
thread_kill( M13_threads.music_cue )
m13_stop_wave_set(M13_waves.scene_7_deck)
m13_setup_side("clear")
end
-- ***************************************************
-- m13_initialize Helper Functions
-- ***************************************************
-- Handle any common initialization
--
function m13_initialize_common()
--[[ INSERT ANY COMMON INITIALIZATION CODE HERE ]]--
m13_load_personas()
m13_disable_traffic( true )
M13_threads.passenger_cleanup = thread_new( "m13_monitor_passengers_thread" )
end
-- Checkpoint specific initialization
--
-- checkpoint: The checkpoint to be initialized
function m13_initialize_checkpoint(checkpoint)
if checkpoint == M13_CHECKPOINT_START then
m13_setup_start()
m13_hide_car_bombs()
m13_distance_clutter_hide()
elseif checkpoint == M13_CHECKPOINT_BANNERS then
-- create banner group
group_create(M13_groups.pr_static.name, true)
-- increase notoriety
notoriety_set( "Police", 3 )
teleport_coop( M13_nav.banners_player_start, M13_nav.banners_remote_start, true )
elseif checkpoint == M13_CHECKPOINT_DECISION then
teleport_coop(M13_nav.penthouse_elevator, M13_nav.penthouse_elevator_remote, true)
m13_setup_decision()
else -- Wave 1, Wave 2, or Wave 3
-- The car bombs are detonated in the first wave. Hide them for the 2nd and 3rd waves.
if checkpoint ~= M13_CHECKPOINT_WAVE_1_START then
m13_hide_car_bombs()
end
objective_text(0, M13_OBJ_DEFEND_THE_NORTH, "", "", SYNC_ALL, OI_ASSET_DEFEND)
m13_setup_side("north")
teleport_coop(M13_nav.elevator_to_ground, M13_nav.elevator_to_ground_remote, true)
m13_setup_balcony_battle()
m13_setup_car_bombs()
m13_disable_ambient_spawning( true )
end
end
-- **********************************************************
-- Miscellaneous m13 Helper Functions
-- ***************************************************
-- General task. Instructs the player to go to the specific trigger. Blocks until the
-- trigger is reached/used.
--
-- trigger - Name of the trigger to activate and go to.
-- obj_text - Objective text to display
-- gps - Should a gps waypoint be added?
--
function m13_goto_a_trigger(trigger, obj_text, gps)
if gps == nil then
gps = false
end
m13_goto_a_trigger_setup(trigger, obj_text, gps)
while not M13_trigger_reached do
thread_yield()
end
m13_goto_a_trigger_cleanup(trigger, gps)
end
-- Sets up the trigger to be used and updates the objective text to the specified string.
--
-- trigger - Name of the trigger the player is going to
-- obj_text - Name of the localized objective string to use
-- gps - True if a GPS waypoint should be added
--
function m13_goto_a_trigger_setup(trigger, obj_text, gps)
-- Teleportation and navagation related functions don't play nice so give pathfinding
-- and similar a frame to finialize everything.
thread_yield()
if obj_text ~= "" and obj_text ~= nil then
objective_text(0, obj_text, "", "", SYNC_ALL, OI_ASSET_LOCATION)
end
marker_add_trigger(trigger, MINIMAP_ICON_LOCATION, INGAME_EFFECT_CHECKPOINT, OI_ASSET_LOCATION, OI_FLAGS_LOCATION, SYNC_ALL)
if gps then
waypoint_add(trigger)
end
M13_trigger_reached = false
trigger_enable(trigger, true)
on_trigger("m13_trigger_cback", trigger)
end
-- Cleans up a trigger and gps setup by m13_goto_a_trigger_setup().
--
-- trigger - Name of the trigger to disable
-- gps - True if a GPS waypoint was setup
--
function m13_goto_a_trigger_cleanup(trigger, gps)
on_trigger("", trigger)
trigger_enable(trigger, false)
marker_remove_trigger(trigger)
if gps then
waypoint_remove()
end
-- To be on the safe side, give pathfinding a similar a full frame to remove the nav points and such
thread_yield()
end
-- Checks to see if a vehicle is a helicopter or a vtol
--
-- vehicle: Name of the script vehicle to check
--
function m13_vehicle_is_helicopter(vehicle)
if vehicle == nil or vehicle == "" then
return false
end
return vehicle_is_helicopter(vehicle) or vehicle_is_vtol(vehicle)
end
-- Check to see if a vehicle is a tank
--
-- vehicle: Name of the script vehicle to check
--
function m13_vehicle_is_tank(vehicle)
if vehicle == nil or vehicle == "" then
return false
end
return vehicle_is_tank(vehicle)
end
-- *************************
--
-- Callback functions
--
-- *************************
-- Called when the player jumps off the penthouse. This is a valid escape scenario
--
-- human: Name of the human that triggered the trigger
-- tirgger: Name of the triggered trigger
--
function m13_jumped_off_penthouse(human, trigger)
if human ~= LOCAL_PLAYER and human ~= REMOTE_PLAYER then
return
end
marker_remove(M13_nav.jump_to)
M13_status.jumped_off_penthouse = true
end
-- General trigger callback. Sets M13_trigger_reached if a player triped a trigger.
--
-- human: Name of the human that triggered the trigger
-- tirgger: Name of the triggered trigger
--
function m13_trigger_cback(human, trigger)
if human == LOCAL_PLAYER or human == REMOTE_PLAYER then
M13_trigger_reached = true
end
end
-- Called when a car bomb is shot.
--
-- mover_name: Name of the mover that was damaged
-- attacker: Who did the damage
-- damage: Amount of damage done
-- from_explosion: Was the damage from an explosion?
-- melee_used: Was melee used?
--
function m13_mover_damaged(mover_name, attacker, damage, from_explosion, melee_used)
-- Don't allow the player to detonate a car bomb with a melee attack.
if melee_used == true then
return
end
-- Ensure that is was actually a player that caused the damage.
if attacker == LOCAL_PLAYER or attacker == REMOTE_PLAYER then
-- Mark the car bomb to explode
m13_car_bomb_detonate(mover_name)
end
end
-- Sets M13_banner_damaged when a banner is damaged by a player
--
-- mover_name: Name of the mover that was damaged
-- attacker: Who did the damage
-- damage: Amount of damage done
-- from_explosion: Was the damage from an explosion?
-- melee_used: Was melee used?
--
function m13_banner_damaged(mover_name, attacker, damage, from_explosion, melee_used)
if attacker == LOCAL_PLAYER or attacker == REMOTE_PLAYER then
M13_banner_damaged = true
end
end
-- Called when a banner is destroyed
--
-- mover_name: Name of the banner that was destroyed
-- attacker: Who destroyed the banner
--
function m13_banner_destroyed(mover_name, attacker)
local movers_alive = 0
-- Search through the list of banners and mark which banner was destroyed
for key, banner in pairs(M13_movers.pr_center_banners) do
if banner.name == mover_name then
banner.destroyed = true
elseif banner.destroyed == false then
movers_alive = movers_alive + 1
end
end
on_mover_destroyed("", mover_name)
marker_remove(mover_name)
M13_banners_alive = movers_alive
M13_banner_damaged = true
M13_banner_destroyed = true
end
-- Called when Josh is throw to Cyrus
--
function m13_josh_thrown_to_cyrus()
M13_josh_given_to_cyrus = true
end
-- Called when Josh is thrown to your homies
--
function m13_josh_thrown_to_homies()
M13_josh_given_to_homies = true
end
-- Called when a mission critical homie has died.
--
function m13_homie_died(victim, attacker)
if victim == M13_groups.homies.viola then
mission_end_failure("m13", M13_FAILURE_VIOLA_DIED)
end
-- if victim == M13_groups.homies.oleg then
-- mission_end_failure("m13", M13_FAILURE_OLEG_DIED)
-- end
if victim == M13_groups.pierce_rescue.pierce then
mission_end_failure("m13", M13_FAILURE_PIERCE_DIED)
end
if victim == M13_groups.penthouse_homies.josh then
mission_end_failure("m13", M13_FAILURE_JOSH_DIED)
end
end
-- Called when the alloted time to escape the penthouse has elapsed.
--
function m13_time_is_up()
mission_end_failure("m13", M13_FAILURE_FAILED_TO_ESCAPE)
end
function m13_pierce_abandoned()
mission_end_failure("m13", M13_FAILURE_PIERCE_ABANDONED)
end
-- *************************
--
-- Thread functions
--
-- *************************
-- Detonate and respawns car bombs as necessary
--
function m13_thread_car_bomb_manager()
local active = {}
for key, bomb in pairs(M13_movers.bombs) do
if not mesh_mover_destroyed(bomb.mover) then
active[#active + 1] = bomb
end
end
while #active > 0 do
active = m13_car_bombs_check_for_detonation(active)
thread_yield()
end
M13_THREAD_CAR_BOMB_MANAGER = INVALID_THREAD_HANDLE
end
-- Initial conversation between Pierce and the player. Once the converstion is over, have
-- Pierce leave the area.
--
function m13_thread_pierce_convo_and_leave()
local target_vehicle = M13_groups.pierce_start.vehicle
local pierce = M13_groups.pierce_start.pierce
set_unrecruitable_flag(pierce, true)
character_allow_ragdoll(pierce, false)
character_prevent_explosion_fling(pierce, true)
character_prevent_flinching(pierce, true)
character_prevent_bumping(pierce, true)
-- Play the initial conversation and wait for it to end.
m13_play_convo_set(M13_convo.start)
ai_clear_scripted_action(pierce)
npc_go_idle(pierce)
-- set_player_can_enter_exit_vehicles(LOCAL_PLAYER, false)
-- if M13_in_coop then
-- set_player_can_enter_exit_vehicles(REMOTE_PLAYER, false)
-- end
if vehicle_enter(pierce, target_vehicle, 0, true, true) then
set_ignore_ai_flag(pierce, false)
vehicle_set_ambient(target_vehicle)
end
-- set_player_can_enter_exit_vehicles(LOCAL_PLAYER, true)
-- if M13_in_coop then
-- set_player_can_enter_exit_vehicles(REMOTE_PLAYER, true)
-- end
-- Wait until both players are pretty far away from Pierce
while get_dist(LOCAL_PLAYER, pierce) < 150.0 or (M13_in_coop and get_dist(LOCAL_PLAYER, pierce) < 150.0) do
thread_yield()
end
--m13_play_persona_line(M13_persona_line.drive_to_pr)
-- Allow Pierce to stream out
release_to_world(target_vehicle)
release_to_world(pierce)
M13_THREAD_PIERCE_CONVO_AND_LEAVE = INVALID_THREAD_HANDLE
end
function m13_thread_vtol_fly_away(vehicle)
helicopter_fly_to_dont_stop(vehicle.name, -1.0, vehicle.nav_flee)
vehicle.thread = INVALID_THREAD_HANDLE
end
-- Plays a conversation
--
-- convo: Conversation to play
function m13_play_convo(convo)
if convo.name ~= "" and convo.name ~= nil then
if type(convo.name) == "table" then
m13_play_persona_line(convo.name)
else
--local msg_handle = message("Playing Convo: " .. convo.name, 99999999.0)
if convo.cell ~= true then
if convo.direct == true then
convo.handle = audio_conversation_load_direct(convo.name)
else
convo.handle = audio_conversation_load(convo.name)
end
end
if convo.cell == true then
m13_cellphone_call_wait( convo.name, convo.recieving )
else
audio_conversation_play(convo.handle)
audio_conversation_wait_for_end(convo.handle)
convo.handle = nil
end
--message_remove(msg_handle)
end
end
if convo.delay ~= nil and convo.delay > 0.01 then
delay(convo.delay)
end
end
-- Unloads a conversation
--
-- convo: Conversation to unload
function m13_unload_convo(convo)
if convo.handle == nil then
return
end
audio_conversation_end(convo.handle)
convo.handle = nil
end
-- Unloads all conversations from the convo table
--
function m13_unload_all_convos()
for convo_key, convo_set in pairs(M13_convo) do
m13_unload_convo_set(convo_set)
if convo_set.thread ~= INVALID_THREAD_HANDLE then
thread_kill(convo_set.thread)
end
end
if M13_THREAD_PIERCE_CONVO_AND_LEAVE ~= INVALID_THREAD_HANDLE then
thread_kill(M13_THREAD_PIERCE_CONVO_AND_LEAVE)
M13_THREAD_PIERCE_CONVO_AND_LEAVE = INVALID_THREAD_HANDLE
end
end
-- Iterates through a table of conversations and plays them.
--
-- convo_set: Table of conversations
--
function m13_play_convo_set(convo_set)
for key, convo in pairs(convo_set.files) do
m13_play_convo(convo)
end
end
-- Unloads a convo table (array)
--
-- convo_set Table of conversations to unload
--
function m13_unload_convo_set(convo_set)
for key, convo in pairs(convo_set.files) do
m13_unload_convo(convo)
end
end
-- Starts an audio conversation as a thread
--
-- convo_table: Conversation to play
--
function m13_start_convo_thread(convo_table)
if M13_active_convo ~= "" then
m13_unload_convo_set(M13_active_convo)
M13_active_convo = ""
end
convo_table.thread = thread_new("m13_audio_thread", convo_table)
end
-- Loads the necessary 2D personas for the heli rail sequence
--
function m13_load_personas()
for key, persona in pairs(M13_personas) do
persona.handle = audio_persona_load_2d(persona.name)
end
end
-- Unloads all 2d personas
--
function m13_unload_personas()
for key, persona in pairs(M13_personas) do
if persona.handle ~= INVALID_PERSONA_HANDLE then
audio_persona_remove_2d(persona.handle)
persona.handle = INVALID_PERSONA_HANDLE
end
end
end
-- Gets the 2d persona handle from a character name
--
function m13_get_persona_handle(line)
for key, persona in pairs(M13_personas) do
if persona.name == line.character then
return persona.handle
end
end
return nil
end
-- Plays a persona line.
--
function m13_play_persona_line(line)
--message("Playing Persona Line: " .. line.name, 4.0)
if line.cell == true then
m13_cellphone_call_wait( line.name, line.recieving, m13_get_persona_handle(line) )
elseif line.play_2d then
audio_play_persona_line_2d(m13_get_persona_handle(line), line.name)
else
audio_play_persona_line(line.character, line.name)
end
end
-- Play a audio conversation
--
-- convo_table: Table of the audio conversation files to play
--
function m13_audio_thread(convo_table)
M13_active_convo = convo_table
m13_play_convo_set(convo_table)
convo_table.thread = INVALID_THREAD_HANDLE
M13_active_convo = ""
end
-- Starts a table of waves. If a template is specified, propagate the values to all the waves.
function m13_start_wave_set(wave_set)
for key, wave in pairs(wave_set) do
-- Propagate the template values to the wave
local template = wave.template
if template ~= nil and template ~= "" then
for key, value in pairs(template) do
-- If the wave doesn't contain the value, copy the template value to the wave
if wave[key] == nil then
wave[key] = value
end
end
end
m13_start_wave(wave)
end
end
-- Stop a table of waves.
--
function m13_stop_wave_set(wave_set, trigger)
for key, wave in pairs(wave_set) do
if wave.groups ~= nil then
m13_stop_wave(wave, nil, trigger)
else
m13_stop_wave_set(wave, trigger)
end
end
end
-- Sets up a wave to start spawning enemies
--
-- wave: M13_waves member to setup
--
function m13_start_wave(wave)
if wave.thread ~= INVALID_THREAD_HANDLE then
debug_print ( "MAD", "ERROR: Wave is already running: " .. wave.groups[1].group.name .. "\n" )
return
end
wave.state = M13_wave_states.invalid
wave.thread = thread_new("m13_wave_thread", wave)
end
-- Cleans up all groups in a wave
--
function m13_stop_wave(wave, kill_thread, trigger)
if wave.thread == nil or wave.thread == INVALID_THREAD_HANDLE then
return
end
-- if a trigger was passed then set up a trigger kill
if trigger ~= nil then
wave.kill_trigger = trigger
return
end
-- Remove any markers or callbacks
local pass_to_destroy = { }
for group_key, group_set in pairs(wave.groups) do
m13_destroy_wave_group(group_set.group, false)
-- flag associated groups for destruction
for pass_group_name, pass_group_data in pairs( M13_passengers_active ) do
if pass_group_data.spawn_group == group_set.group.name then
pass_to_destroy[ pass_group_name ] = true
end
end
end
if kill_thread ~= false then
thread_kill(wave.thread)
wave.thread = INVALID_THREAD_HANDLE
end
-- destroy the passengers
for pass_group_name, duh in pairs( pass_to_destroy ) do
m13_destroy_passenger_group( pass_group_name, false )
end
end
-- Cleans up a wave's group
--
function m13_destroy_wave_group(group, release)
if group_is_loaded(group.name) then
local vehicle = group.vehicle
local members = group.members
for key, npc in pairs(members) do
on_death("", npc)
marker_remove(npc)
end
if vehicle ~= "" and vehicle ~= nil then
on_vehicle_destroyed("", vehicle)
marker_remove(vehicle)
end
if release ~= false then
release_to_world(group.name)
end
group_destroy(group.name)
M13_num_troops = M13_num_troops - #members
end
end
-- Wait until all of the required kills have been taken care of
--
function m13_wait_for_required_kills(wave_set)
for key, wave in pairs(wave_set) do
if wave.required_kill then
while wave.thread ~= INVALID_THREAD_HANDLE do
thread_yield()
end
end
end
end
-- Wait for all non repeating waves to completely end
function m13_wait_for_all_non_repeating_waves(wave_set)
for key, wave in pairs(wave_set) do
if wave.required_kill or wave.repeat_wave == false then
while wave.thread ~= INVALID_THREAD_HANDLE do
thread_yield()
end
end
end
end
-- Wait until all the non repeating waves have completed the specified state
--
function m13_wait_for_waves_to_complete_state(wave_set, state)
for key, wave in pairs(wave_set) do
if wave.required_kill or wave.repeat_wave == false then
while wave.state <= state do
thread_yield()
end
end
end
end
-- Checks to see how many waves are in the specified state
--
function m13_waves_in_state(wave_set, state)
local in_state = 0
for key, wave in pairs(wave_set) do
if wave.required_kill or wave.repeat_wave == false then
if wave.state == state then
in_state = in_state + 1
end
end
end
return in_state
end
-- Spawns a group.
--
-- group: Group to spawn
-- spawn_point: Location to spawn the group at
function m13_group_spawn(wave, group, spawn_point)
if group_is_loaded(group.name) then
debug_print( "MAD", "ERROR: Group " .. group.name .. " is already loaded\n" )
return
end
if wave.required_kill ~= true and wave.critical_spawn ~= true then
-- wait until we have the room to create some more
while M13_num_troops >= M13_max_troops do
thread_yield()
end
end
M13_num_troops = M13_num_troops + #group.members
group_create(group.name, true)
debug_print( "MAD", "M13_num_troops: " .. M13_num_troops .. "\n" )
local death_cb
if group.vehicle ~= "" then
if wave.vehicle_speed ~= nil and wave.vehicle_speed ~= "" and wave.vehicle_speed > 0.1 then
vehicle_speed_override(group.vehicle, wave.vehicle_speed)
end
if m13_vehicle_is_tank( group.vehicle ) or m13_vehicle_is_helicopter( group.vehicle ) then
-- just load em up
vehicle_enter_group_teleport( group.members, group.vehicle )
else
-- driver and gunner
vehicle_enter_teleport( group.members[ 1 ], group.vehicle, 0 )
vehicle_enter_teleport( group.members[ 2 ], group.vehicle, 1 )
end
teleport_vehicle( group.vehicle, spawn_point.nav )
-- Make the driver invulnerable to ensure he can get to his destination. If the vehicle is
-- destroyed, the driver will be taken care of in the callback.
local driver = vehicle_get_driver(group.vehicle)
turn_invulnerable(driver)
if not m13_vehicle_is_tank(group.vehicle) and not m13_vehicle_is_helicopter(group.vehicle) then
-- look for some passengers
if M13_num_troops < M13_max_troops and sizeof_table( M13_passengers_available ) > 0 then
local pass_group_name, pass_group_data
for k,v in pairs( M13_passengers_available ) do
pass_group_name = k
pass_group_data = v
break
end
-- move to active
M13_passengers_active[ pass_group_name ] = pass_group_data
M13_passengers_available[ pass_group_name ] = nil
-- set the attached spawn group for cleanup later
pass_group_data.spawn_group = group.name
M13_num_troops = M13_num_troops + #pass_group_data.members
group_create( pass_group_name, true )
-- load them up after the driver, starting as seat 3
for i = 1, #pass_group_data.members do
vehicle_enter_teleport( pass_group_data.members[ i ], group.vehicle, i + 1 )
end
end
set_ignore_ai_flag(driver, true)
vehicle_suppress_npc_exit(group.vehicle, true)
end
-- special case: if a list of paths are given then OI will be set later
if wave.required_kill and type( spawn_point.path ) ~= "table" then
marker_add(group.vehicle, MINIMAP_ICON_KILL, OI_ASSET_KILL_FULL, OI_FLAGS_DEFAULT, SYNC_ALL)
end
on_vehicle_destroyed("m13_wave_vehicle_killed_cb", group.vehicle)
if m13_vehicle_is_helicopter(group.vehicle) then
-- turn off missile firing, we'll fire them from script
ai_set_action_delay( vehicle_get_driver( group.vehicle ), "throw grenade", 99999 )
end
else
if wave.required_kill then
death_cb = "m13_required_kill_cb"
for key, npc in pairs(group.members) do
marker_add(npc, MINIMAP_ICON_KILL, OI_ASSET_KILL, OI_FLAGS_DEFAULT, SYNC_ALL)
end
end
end
if death_cb ~= nil then
for key, npc in pairs(group.members) do
on_death(death_cb, npc)
end
end
-- Prevent STAG from dropping their guns since the player won't be able to get to them
-- and for memory related reasons.
for key, npc in pairs(group.members) do
npc_dont_drop_weapon_on_death(npc, true)
end
end
-- Returns true if all the script npcs are dead
--
-- group: group to check the members state of
--
function m13_group_is_dead(group)
if m13_vehicle_is_tank(group.vehicle) or m13_vehicle_is_helicopter(group.vehicle) then
return vehicle_is_destroyed(group.vehicle)
end
return group_members_alive(group.name) == 0
end
-- Instruct a group to pathfind along a path or to a nav point.
--
-- group: Group to instruct to move
-- nav_or_path: Name of a nav point to go to or a path to follow
--
function m13_group_pathfind_to(group, nav_or_path)
if nav_or_path == "" or group.vehicle == "" or vehicle_is_destroyed(group.vehicle) then
return
end
if m13_vehicle_is_helicopter(group.vehicle) then
if type( nav_or_path ) == "table" then
-- special case - totally one off
-- if we have more than one path then we will set the OI after the first one
helicopter_fly_to_direct( group.vehicle, -1.0, nav_or_path[ 1 ] )
marker_add( group.vehicle, MINIMAP_ICON_KILL, OI_ASSET_KILL_FULL, OI_FLAGS_DEFAULT, SYNC_ALL )
helicopter_fly_to_direct( group.vehicle, -1.0, nav_or_path[ 2 ] )
else
helicopter_fly_to_direct( group.vehicle, -1.0, nav_or_path )
end
else
vehicle_pathfind_to(group.vehicle, nav_or_path, true, true, false, false)
end
end
-- Tell all the passengers in the vehicle to get out, and flag them with a kill icon if necessary.
--
function m13_group_drop_off_passengers(wave, group)
if group.vehicle == "" or vehicle_is_destroyed(group.vehicle) then
return
end
-- Tanks and Heli's cannot drop anyone off.
if m13_vehicle_is_tank(group.vehicle) then
vehicle_speed_cancel(group.vehicle)
vehicle_speed_override(group.vehicle, 0.0)
return
end
if m13_vehicle_is_helicopter(group.vehicle) then
vehicle_speed_cancel(group.vehicle)
return
end
local driver = vehicle_get_driver(group.vehicle)
if driver ~= "" and driver ~= nil then
turn_vulnerable(driver)
end
vehicle_speed_cancel(group.vehicle)
vehicle_stop(group.vehicle)
vehicle_suppress_npc_exit(group.vehicle, false)
if wave.required_kill then
marker_remove(group.vehicle)
end
local gunner = get_char_in_vehicle( group.vehicle, 1 )
if gunner ~= nil then
if not character_is_dead( gunner ) then
set_ignore_ai_flag( gunner, true )
squad_enable( gunner, false )
end
end
for i = 0, 7 do
local npc = get_char_in_vehicle( group.vehicle, i )
if npc ~= nil and npc ~= "" then
if not character_is_dead(npc) then
if i ~= 1 then -- skip 1, that's the gunner
set_ignore_ai_flag( npc, false )
vehicle_exit(npc)
if wave.attack_target ~= nil then
ai_add_enemy_target( npc, wave.attack_target, ATTACK_NOW_NEVER_LOSE, true )
else
ai_add_enemy_target( npc, m13_get_closest_player( npc ), ATTACK_NOW_NEVER_LOSE, true )
end
end -- if
if wave.required_kill then
marker_add(npc, MINIMAP_ICON_KILL, OI_ASSET_KILL, OI_FLAGS_DEFAULT, SYNC_ALL)
on_death("m13_required_kill_cb", npc)
end -- if
end -- if
end -- if
end -- for
vehicle_suppress_npc_exit(group.vehicle, true)
-- after everyone is out except the gunner, process the gunner
if gunner ~= nil and gunner ~= "" then
if not character_is_dead( gunner ) then
set_ignore_ai_flag( gunner, false )
ai_add_enemy_target( gunner, m13_get_closest_player( gunner ), ATTACK_NOW_NEVER_LOSE, true )
end
end
end -- function
function m13_vehicle_flee(group, spawn_point)
if group.vehicle == "" or vehicle_is_destroyed(group.vehicle) then
return
end
-- Helicopters and Tanks cannot flee. Tell them to attack the player instead.
if m13_vehicle_is_tank(group.vehicle) then
local driver = vehicle_get_driver(group.vehicle)
ai_add_enemy_target(driver, CLOSEST_PLAYER, ATTACK_NOW_NEVER_LOSE, true)
if (character_is_ready(group.members[2])) then
ai_add_enemy_target(group.members[2], CLOSEST_PLAYER, ATTACK_NOW_NEVER_LOSE, true)
set_perfect_aim(group.members[2], true)
end
return
end
if (m13_vehicle_is_helicopter(group.vehicle) and spawn_point.flee == "") then
return
end
m13_group_pathfind_to(group, spawn_point.flee)
on_vehicle_destroyed("", group.vehicle)
local driver = vehicle_get_driver(group.vehicle)
local driver_valid = driver ~= nil and driver ~= ""
local flee_valid = spawn_point.flee ~= "" and spawn_point.flee ~= nil
if driver_valid and flee_valid and not vehicle_is_destroyed(group.vehicle) then
-- The vehicle was not stopped by the player. Kill the driver so he doesn't attempt to get
-- back to the player.
character_kill(driver)
else
-- The vehicle did not complete it's path. Tell the driver to get out and release everyone to the world
if driver_valid then
vehicle_exit(driver)
release_to_world(driver)
end
release_to_world(group.vehicle)
end
end
-- Main wave logic. Iterates through all the groups, and then restart the wave is told to do so.
--
function m13_wave_thread( wave )
local dont_repeat = false
delay( wave.initial_delay )
while true do
-- Iterate through all the groups in the wave
for key, group_set in pairs( wave.groups ) do
local group = group_set.group
local spawn_point = group_set.spawn_point
-- Spawn the group
wave.state = M13_wave_states.spawning
m13_group_spawn( wave, group, spawn_point )
-- Have the group follow their path, exit the vehicle, and fire at the player
wave.state = M13_wave_states.pathfinding
m13_group_pathfind_to( group, spawn_point.path )
m13_group_drop_off_passengers( wave, group )
if m13_vehicle_is_tank( group.vehicle ) then
local driver = vehicle_get_driver( group.vehicle )
ai_add_enemy_target( driver, m13_get_closest_player( group.vehicle ), ATTACK_NOW_NEVER_LOSE, true )
if character_is_ready( group.members[ 2 ] ) then
ai_add_enemy_target( group.members[ 2 ], m13_get_closest_player( group.vehicle ), ATTACK_NOW_NEVER_LOSE, true )
set_perfect_aim( group.members[ 2 ], true )
end
vehicle_freeze(group.vehicle)
vehicle_set_keyframed_physics(group.vehicle, true)
elseif m13_vehicle_is_helicopter( group.vehicle ) then
ai_add_enemy_target( vehicle_get_driver( group.vehicle ), m13_get_closest_player( group.vehicle ), ATTACK_NOW_NEVER_LOSE, true )
helicopter_shoot_human( group.vehicle, m13_get_closest_player( group.vehicle ) )
helicopter_go_to_set_target( group.vehicle, m13_get_closest_player( group.vehicle ) )
else
for i, m in pairs( group.members ) do
if wave.attack_target ~= nil then
ai_add_enemy_target( m, wave.attack_target , ATTACK_NOW_NEVER_LOSE, true )
else
ai_add_enemy_target( m, m13_get_closest_player( m ), ATTACK_NOW_NEVER_LOSE, true )
end
end
end
wave.state = M13_wave_states.release_delay
-- Wait until the group is dead
local fire_delay = 100
while true do
-- all dead? move on.
if group_is_loaded( group.name ) == false or m13_group_is_dead( group ) == true then
break
end
-- if a kill trigger has been given, check it
if wave.kill_trigger ~= nil and object_is_in_trigger( wave.kill_trigger, LOCAL_PLAYER ) == true then
dont_repeat = true
break
end
if m13_vehicle_is_helicopter( group.vehicle ) then
-- fire up the missiles
if fire_delay > 10 then
local closest_player = LOCAL_PLAYER
if coop_is_active() then
if get_dist( group.vehicle, LOCAL_PLAYER ) > get_dist( group.vehicle, REMOTE_PLAYER ) then
closest_player = REMOTE_PLAYER
end
end
helicopter_shoot_human( group.vehicle, closest_player, true, 10 )
fire_delay = 0
end
fire_delay = fire_delay + get_frame_time()
end
thread_yield()
end
m13_destroy_wave_group(group)
-- Wait the specified amount of time before spawning the next group
wave.state = M13_wave_states.next_group_delay
delay(wave.next_group_delay)
end
-- If we are not allowed to repeat the wave, break out
if dont_repeat == true or wave.repeat_wave == false or wave.required_kill then
break
end
end
wave.state = M13_wave_states.complete
local kill_thread = false
m13_stop_wave(wave, kill_thread)
wave.thread = INVALID_THREAD_HANDLE
end
-- Sets up the system to tell the player to go to the selected side of the building.
function m13_setup_side(side)
M13_status.current_side = side
if M13_threads.side_marker == nil then
M13_threads.side_marker = thread_new( "m13_setup_side_thread" )
end
end
function m13_setup_side_thread()
local north_marked_local = false
local north_marked_coop = false
local south_marked_local = false
local south_marked_coop= false
local should_mark_north_local = false
local should_mark_north_coop = false
local should_mark_south_local = false
local should_mark_south_coop = false
trigger_enable(M13_triggers.north_side, true)
trigger_enable(M13_triggers.south_side, true)
while true do
if M13_status.current_side == "north" then
should_mark_north_local = object_is_in_trigger( M13_triggers.north_side, LOCAL_PLAYER ) ~= true
if coop_is_active() then
should_mark_north_coop = object_is_in_trigger( M13_triggers.north_side, REMOTE_PLAYER ) ~= true
end
should_mark_south_local = false
should_mark_south_coop = false
elseif M13_status.current_side == "south" then
should_mark_south_local = object_is_in_trigger( M13_triggers.south_side, LOCAL_PLAYER ) ~= true
if coop_is_active() then
should_mark_south_coop = object_is_in_trigger( M13_triggers.south_side, REMOTE_PLAYER ) ~= true
end
should_mark_north_local = false
should_mark_north_coop = false
else
should_mark_south_local = false
should_mark_south_coop = false
should_mark_north_local = false
should_mark_north_coop = false
end
if north_marked_local ~= should_mark_north_local then
m13_side_change_marked( M13_triggers.north_side, should_mark_north_local, SYNC_LOCAL )
north_marked_local = should_mark_north_local
end
if south_marked_local ~= should_mark_south_local then
m13_side_change_marked( M13_triggers.south_side, should_mark_south_local, SYNC_LOCAL )
south_marked_local = should_mark_south_local
end
if north_marked_coop ~= should_mark_north_coop then
m13_side_change_marked( M13_triggers.north_side, should_mark_north_coop, SYNC_REMOTE )
north_marked_coop = should_mark_north_coop
end
if south_marked_coop ~= should_mark_south_coop then
m13_side_change_marked( M13_triggers.south_side, should_mark_south_coop, SYNC_REMOTE )
south_marked_coop = should_mark_south_coop
end
thread_yield()
end
end
function m13_side_change_marked( trig, mark, sync )
if mark then
marker_add_trigger( trig, MINIMAP_ICON_PROTECT_ACQUIRE, INGAME_EFFECT_LOCATION, OI_ASSET_DEFEND, OI_FLAGS_FULL, sync )
else
marker_remove_trigger( trig, SYNC_ALL )
end
end
-- Removes any markers from a killed NPC
--
function m13_required_kill_cb(victim, killer)
on_death("", victim)
marker_remove(victim)
end
-- Removes any markers attached to a vehicle, and kill the driver if they are still alive
--
function m13_wave_vehicle_killed_cb(vehicle)
on_vehicle_destroyed("", vehicle)
marker_remove(vehicle)
local driver = vehicle_get_driver(vehicle)
if driver ~= nil and driver ~= "" then
turn_vulnerable(driver)
if not character_is_dead(driver) then
character_kill(driver, true)
end
release_to_world(driver)
end
release_to_world(vehicle)
end
function m13_disable_traffic( b )
local enable = false
if b == false then
enable = true
end
sidewalk_disable_nodes ( M13_triggers.no_traffic, enable )
traffic_disable_lanes ( M13_triggers.no_traffic, enable )
end
-- create destroyed vehicles to give illusion of chaos
-- area can be "north", "south" or "general"
function m13_create_clutter( area )
local groups, r
groups = m13_get_clutter_groups( area )
for i, g in pairs( groups ) do
group_create( g.name, true )
for j, v in pairs( g.vehicles ) do
r = rand_int( 1, 4 )
if r == 1 then
vehicle_hide( v )
elseif r == 2 then
vehicle_set_smoke_and_fire_state( v, true, true )
elseif r == 3 then
vehicle_make_corpse( v, true )
else
vehicle_make_corpse( v, false )
end
end
end
end
function m13_clear_clutter( area )
local groups
groups = m13_get_clutter_groups( area )
for i, g in pairs( groups ) do
group_destroy( g )
end
end
function m13_get_clutter_groups( area )
if area == "north" then
return { M13_groups.clutter_north }
elseif area == "south" then
return { M13_groups.clutter_south }
elseif area == "general" then
return {M13_groups.clutter_north, M13_groups.clutter_south, M13_groups.clutter_general }
else
return { }
end
end
function m13_monitor_passengers_thread()
local groups_cleared = { }
while true do
-- check to see if any passenger groups have been killed
-- so they can be reused
for group_name, group_data in pairs( M13_passengers_active ) do
local all_dead = true
for i, member in pairs( group_data.members ) do
if character_is_dead( member ) == false then
all_dead = false
break
end
end
if all_dead then
groups_cleared[ group_name ] = true
end
end
-- clear the groups up now so we don't mess up iteration above
for group_name, duh in pairs( groups_cleared ) do
m13_destroy_passenger_group( group_name )
end
groups_cleared = { }
thread_yield()
end
end
function m13_destroy_passenger_group( group_name, release )
if M13_passengers_active[ group_name ] == nil then
return
end
if release ~= false then
release_to_world( group_name )
end
group_destroy( group_name )
M13_num_troops = M13_num_troops - #M13_passengers_active[ group_name ].members
M13_passengers_available[ group_name ] = M13_passengers_active[ group_name ]
M13_passengers_active[ group_name ] = nil
end
function m13_get_closest_player( obj )
local closest = LOCAL_PLAYER
if coop_is_active() then
if get_dist( obj, REMOTE_PLAYER ) < get_dist( obj, LOCAL_PLAYER ) then
closest = REMOTE_PLAYER
end
end
return closest
end
function m13_disable_ambient_spawning( b )
local spawn = ( b == false )
spawning_vehicles( spawn )
spawning_pedestrians( spawn )
end
function m13_vfx_play(vfx_group)
for i, vfx in pairs(vfx_group) do
if vfx.handle == -1 then
vfx.handle = effect_play(vfx.nav, true)
end
end
end
function m13_distance_clutter_show()
for i, mover in pairs(M13_movers.clutter) do
mesh_mover_reset(mover)
mesh_mover_show(mover)
mesh_mover_set_invulnerable(mover, true)
end
end
function m13_distance_clutter_hide()
for i, mover in pairs(M13_movers.clutter) do
mesh_mover_hide(mover)
end
end
function m13_cellphone_call_wait( convo, recieving, persona )
M13_status.cellphone_call_in_progress = convo
audio_play_for_mission_cellphone( convo, recieving, true, "", "m13_cellphone_call_cb", persona )
while M13_status.cellphone_call_in_progress do
thread_yield()
end
end
function m13_cellphone_call_cb()
M13_status.cellphone_call_in_progress = nil
end
function m13_thread_wrapper( function_ref, ... )
function_ref( unpack( arg ) )
end