--[[
m08.lua
SR3 Mission Script
DATE: 4/23/10
AUTHOR: Albert McDaniel, Nick Heilmann, Sean Rose, Stephen Tobias
]]--
M08_status = {
obj_reached = false,
targets_left = 0,
cookie_trail_navs = { },
player_given_rocket_launcher = false,
}
M08_weapon = {
sniper_rifle = "Special-SniperRifle",
rocket_launcher = "Explosive-RocketLauncher",
}
M08_navpoint = {
end_local = "Nav End Local Player",
end_remote = "Nav End Remote Player",
heli_teleport = {
{ "Nav Heli1 Teleport 001", "Nav Heli1 Teleport 002" },
{ "Nav Heli2 Teleport 001", "Nav Heli2 Teleport 002" },
{ "Nav Heli3 Teleport 001", "Nav Heli3 Teleport 002" },
},
-- Targets that the helis will randomly fire at
heli_target = {
"Nav Heli_Attack_Target_01",
"Nav Heli_Attack_Target_02",
"Nav Heli_Attack_Target_03",
},
cp_starts = {
zimos = {
player_local = "Nav CP Zimos Local",
player_remote = "Nav CP Zimos Remote",
},
bar = {
player_local = "Nav CP Bar Local",
player_remote = "Nav CP Bar Remote",
pierce = "Nav CP Bar Pierce",
zimos = "Nav CP Bar Zimos",
},
roof = {
player_local = "Nav CP Roof Local",
player_remote = "Nav CP Roof Remote",
pierce = "Nav CP Roof Pierce",
zimos = "Nav CP Roof Zimos",
},
utility = {
player_local = "Nav CP Utility Local",
player_remote = "Nav CP Utility Remote",
pierce = "Nav CP Utility Pierce",
zimos = "Nav CP Utility Zimos",
}
},
circut_breaker = "Nav Circuit Breaker",
pierce_behind_bar = "Nav Pierce Behind Bar",
trail_to_rifle = {
{ name = "Nav Trail <001>", next_nav = 2 },
{ name = "Nav Trail <002>", next_nav = 3 },
{ name = "Nav Trail <003>", next_nav = 4 },
{ name = "Nav Trail <004>", type = "use" },
},
trail_to_roof = {
{ name = "Nav Stairs_To_Roof_01", next_nav = 2 },
{ name = "Nav Stairs_To_Roof_02", next_nav = 3 },
{ name = "Nav Stairs_To_Roof_03" },
},
trail_to_maint = {
{ name = "Nav Stairs_To_Basement_01", next_nav = 2, objective = "M08_OBJ_GET_TO_BASEMENT" },
{ name = "Nav Stairs_To_Basement_02", next_nav = 3, objective = "M08_OBJ_GET_TO_BASEMENT" },
{ name = "Nav Stairs_To_Basement_03", next_nav = 4, objective = "M08_OBJ_GET_TO_BASEMENT" },
{ name = "Nav Stairs_To_Basement_04", next_nav = 5, objective = "M08_OBJ_GET_TO_BASEMENT" },
{ name = "Nav Stairs_To_Basement_05", next_nav = 6, objective = "M08_OBJ_GET_TO_BASEMENT" },
{ name = "Nav Stairs_To_Basement_06", next_nav = 7, objective = "M08_OBJ_GET_TO_BASEMENT" },
{ name = "Nav Circuit Breaker", type = "use", trigger = "Trigger Circuit Breaker", objective = "M08_OBJ_RESTORE_POWER" },
},
area_finders = {
"Nav Area Finder Pool", "Nav Area Finder Left", "Nav Area Finder Right",
}
}
M08_audio = {
music_emitter = "M08_Saints_Music<001>",
walla_emitter = "M08_Chaotic_Walla<001>", -- low level loop of screaming and stuff
walla_fade_event = "M08_Chaotic_Walla_Stop",
chaotic_screams_start_event = "M08_Chaotic_Screams",
chaotic_screams_stop_event = "M08_Chaotic_Screams_Stop",
music_queues = {
pause = "M08_Party_Music_Pause",
resume = "M08_Party_Music_Resume",
stop = "M08_Party_Music_Stop",
},
}
M08_mover = {
doors = {
"SM Door Downstairs 001", "SM Door Downstairs 002", "SM Door Downstairs 003", "SM Door Downstairs 004",
"SM Door Downstairs 005", "SM Door Downstairs 006", "SM Door Downstairs 007",
"SM Door Upstairs 001", "SM Door Upstairs 002", "SM Door Upstairs 003", "SM Door Upstairs 004",
"SM Door Upstairs 005", "SM Door Upstairs 006", "SM Door Upstairs 007", "SM Door Upstairs 008",
},
locked_elevators = { "Locked Elevator 001", "Locked Elevator 002", "Locked Elevator 003" },
}
M08_trigger = {
basement = "Trigger Basement",
circuit_breaker = "Trigger Circuit Breaker",
massacre = "Trigger Massacre",
roof = "Trigger Rooftop",
stairs_to_roof = "Trigger Stairs to Roof",
stairs_to_basement = "Trigger Stairs to Basement",
utility_stairs = "Trigger Utility",
lobby_skylight = "Trigger Skylight",
bar = "Trigger Bar",
rocket_pickup = "Trigger Rocket Pickup",
}
M08_group = {
zimos = {
name = "GRP Zimos",
npcs = { "NPC Zimos" }
},
pierce = {
name = "GRP Pierce",
npcs = { "NPC Pierce" }
},
saints = {
name = "GRP Saints",
npcs = { "NPC Saint 001", "NPC Saint 002", "NPC Saint 003", "NPC Saint 004", "NPC Saint 005", "NPC Saint 006" }
},
prostitutes = {
name = "GRP Prostitutes",
npcs = { "NPC Prostitute 001", "NPC Prostitute 002", "NPC Prostitute 003", "NPC Prostitute 004", "NPC Prostitute 005", "NPC Prostitute 006",
"NPC Prostitute 007", "NPC Prostitute 008", "NPC Prostitute 009", "NPC Prostitute 010", "NPC Prostitute 011", "NPC Prostitute 012",
"NPC Prostitute 013", "NPC Prostitute 014", "NPC Prostitute 015", "NPC Prostitute 016", "NPC Prostitute 017", "NPC Prostitute 018" }
},
snipers = {
{ name = "GRP Snipers 01", npcs = { "NPC Sniper 003", "NPC Sniper 007" }, fire_atx= { "Nav Sniper Fire At 01", "Nav Sniper Fire At 02" } },
{ name = "GRP Snipers 02", npcs = { "NPC Sniper 005", "NPC Sniper 006" } },
{ name = "GRP Snipers 03", npcs = { "NPC Sniper 001", "NPC Sniper 002", "NPC Sniper 004", } },
},
circuit_guards = {
name = "GRP Circuit Guards",
npcs = { "NPC Circuit Guard 001", "NPC Circuit Guard 002", "NPC Circuit Guard 003", "NPC Circuit Guard 004",
"NPC Circuit Guard 005", "NPC Circuit Guard 006", "NPC Circuit Guard 007", "NPC Circuit Guard 008" }
},
heli_veh = {
name = "GRP Heli Player",
vehicle = "Veh Heli Player"
},
heli_guards = {
name = "GRP Heli Guards",
npcs = { "NPC Heli Guard 001", "NPC Heli Guard 002", "NPC Heli Guard 003", "NPC Heli Guard 004", "NPC Heli Guard 005", "NPC Heli Guard 006" }
},
helis = {
{ name = "GRP Heli Enemies A", npcs = { "NPC Heli1 Enemy 001", "NPC Heli1 Enemy 002" }, vehicle = "Veh Heli Fighter 001", start = "Nav CP Heli 1" },
{ name = "GRP Heli Enemies B", npcs = { "NPC Heli2 Enemy 001", "NPC Heli2 Enemy 002" }, vehicle = "Veh Heli Fighter 002", start = "Nav CP Heli 2" },
},
heli_saints = { name = "GRP Saint Helibait" },
sniper_rifle_item = { name = "GRP Item Sniper Rifle", item = "Item Sniper Rifle" },
rocket_launcher = { name = "GRP Item RPG_Rocket", item = "Item RPG_Rocket" },
cte_npc_group = { name = "m8_cte_npc_01" },
partiers = {
{ name = "GRP Partiers 1", npcs = { "Partier <001>", "Partier <002>", "Partier <003>", "Partier <004>", }, fee_nav = "NP Partiers Flee 1", cleaned = false },
{ name = "GRP Partiers 2", npcs = { "Partier <005>", "Partier <006>", "Partier <007>", "Partier <008>", }, fee_nav = "NP Partiers Flee 2", cleaned = false },
{ name = "GRP Partiers 3", npcs = { "Partier <009>", "Partier <010>", "Partier <011>", "Partier <012>", }, fee_nav = "NP Partiers Flee 3", cleaned = false },
},
heli_guards_respawn = {
{ name = "GRP Heli Enemies Respawn 01", npcs = { "NPC Heli Enemies Respawn 01" } },
{ name = "GRP Heli Enemies Respawn 02", npcs = { "NPC Heli Enemies Respawn 02" } },
{ name = "GRP Heli Enemies Respawn 03", npcs = { "NPC Heli Enemies Respawn 03" } },
{ name = "GRP Heli Enemies Respawn 04", npcs = { "NPC Heli Enemies Respawn 04" } },
{ name = "GRP Heli Enemies Respawn 05", npcs = { "NPC Heli Enemies Respawn 05" } },
{ name = "GRP Heli Enemies Respawn 06", npcs = { "NPC Heli Enemies Respawn 06" } },
},
}
M08_blackout_chatter_groups = {
M08_group.prostitutes.npcs,
M08_group.circuit_guards.npcs,
}
M08_spawn_group = {
ms_waves = { "GRP Morningstar 3A", "GRP Morningstar 3B", "GRP Morningstar 3C", "GRP Morningstar 3D" },
ms_waves_coop = { "GRP Morningstar 3E", "GRP Morningstar 3F", },
ms_waves_upstairs = { "GRP MS 3A", "GRP MS 3B", "GRP MS 3C", "GRP MS 3D" },
ms_waves_upstairs_coop = { "GRP MS 3E", "GRP MS 3F", },
}
M08_spawn_region = {
upstairs = { "Spawn Reg Up Elev 001", "Spawn Reg Up Elev 002", "Spawn Reg Up Elev 003", "Spawn Reg Up Elev 004" },
downstairs = { "Spawn Reg Down Elev 001", "Spawn Reg Down Elev 002", "Spawn Reg Down Elev 003", "Spawn Reg Down Elev 004", "Spawn Reg Down Elev 005" },
}
--M08_vfx_smoke = {
-- { name = "VFX Smoke 001", handle = -1 },
-- { name = "VFX Smoke 002", handle = -1 },
-- { name = "VFX Smoke 003", handle = -1 },
-- { name = "VFX Smoke 004", handle = -1 },
-- { name = "VFX Smoke 005", handle = -1 },
-- { name = "VFX Smoke 006", handle = -1 },
-- { name = "VFX Smoke 007", handle = -1 },
--}
M08_text = {
survive_assault = "M08_OBJ_SURVIVE_ASSAULT",
protect_pierce = "M08_OBJ_PROTECT_PIERCE",
find_sniper_rifle = "M08_OBJ_FIND_SNIPER_RIFLE",
get_to_roof = "M08_OBJ_GET_TO_ROOF",
kill_snipers = "M08_OBJ_KILL_SNIPERS",
get_to_basement = "M08_OBJ_GET_TO_BASEMENT",
restore_power = "M08_OBJ_RESTORE_POWER",
get_rocket_launcher = "M08_OBJ_GO_TO_CHOPPER",
enter_chopper = "M08_OBJ_ENTER_CHOPPER",
destroy_vehicles = "M08_OBJ_DESTROY_VEHICLES",
failure_death = {
[M08_group.zimos.npcs[1]] = "m08_failure_zimos_died",
[M08_group.pierce.npcs[1]] = "m08_failure_pierce_died"
},
go_up_to_bar = "M08_OBJ_GO_UP_TO_BAR", -- UNUSED
take_cover_behind_bar = "M08_OBJ_TAKE_COVER_BEHIND_BAR", -- UNUSED
revive_pierce = "M08_OBJ_REVIVE_PIERCE", -- UNUSED
go_to_roof = "M08_OBJ_GO_TO_ROOF", -- UNUSED
stairs_to_roof = "M08_OBJ_STAIRS_TO_ROOF", -- UNUSED
go_to_basement = "M08_OBJ_GO_TO_BASEMENT", -- UNUSED
stairs_to_basement = "M08_OBJ_STAIRS_TO_BASEMENT", -- UNUSED
}
M08_conv = {
survive = {
name = "m08_convo_1",
handle = INVALID_CONVERSATION_HANDLE,
},
pierce = {
name = "M08_Find_Pierce",
handle = INVALID_CONVERSATION_HANDLE,
},
bar = {
name = "M08_Combat_At_Bar",
handle = INVALID_CONVERSATION_HANDLE,
},
no_power = {
name = "M08_No_Power",
handle = INVALID_CONVERSATION_HANDLE,
},
snipers = {
name = "M08_Snipers",
handle = INVALID_CONVERSATION_HANDLE,
},
fix_power = {
name = "M08_Head_To_Power",
handle = INVALID_CONVERSATION_HANDLE,
},
oleg_call = {
name = "m08_convo_5",
handle = INVALID_CONVERSATION_HANDLE,
},
heli_pad = {
name = "M08_Get_To_Helipad",
handle = INVALID_CONVERSATION_HANDLE,
},
}
M08_persona = {
oleg = {
name = "Oleg",
id = INVALID_PERSONA_HANDLE
},
}
M08_thread = {
chopper_flyby = { INVALID_THREAD_HANDLE, INVALID_THREAD_HANDLE, INVALID_THREAD_HANDLE },
cookie_trails_local = INVALID_THREAD_HANDLE,
cookie_trails_remote = INVALID_THREAD_HANDLE,
zimos_gives_a_rocket = INVALID_THREAD_HANDLE,
pierce_gives_a_light = INVALID_THREAD_HANDLE,
partier_behavior = INVALID_THREAD_HANDLE,
pierce_runs_to_bar = INVALID_THREAD_HANDLE,
}
M08_checkpoint = {
start = MISSION_START_CHECKPOINT, -- defined in ug_lib.lua
snipers = "snipers",
power = "power",
heli = "heli",
}
M08_cutscene = {
mission_intro = "08_in",
heli_attack = {
name = "m08_cte_01"
},
mission_outro = "08_out",
}
M08_cookie_trail_manager = { }
M08_light_groups = {
world = "Script_Light_Group_everyday_ALL",
mission = "Script_Light_Group_m08_ALL",
emergency = "Script_Light_Group_m08_EMERG",
}
M08_num_helis_to_create = 5
--------------------------------------------------------------------------------------------------
--[[********************]]--
--[[ 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
--
-- m08_checkpoint: (string) The checkpoint the mission should begin at
-- is_restart: (bool) TRUE if the mission is restarting, FALSE otherwise
--
function m08_start(m08_checkpoint, is_restart)
-- Handle mission initialization for the current checkpoint
m08_initialize(m08_checkpoint)
-- Check if this mission starting from the beginning
if (m08_checkpoint == M08_checkpoint.start) then
if (not is_restart) then
-- First time playing mission
cutscene_play(M08_cutscene.mission_intro, nil, { M08_navpoint.cp_starts.zimos.player_local, M08_navpoint.cp_starts.zimos.player_remote }, false)
m08_mission_start_zscene_post_init()
else
teleport_coop( M08_navpoint.cp_starts.zimos.player_local, M08_navpoint.cp_starts.zimos.player_remote )
m08_mission_start_zscene_post_init()
end
end
mission_start_fade_in()
-- Run the mission from the current checkpoint
m08_run(m08_checkpoint)
end
function m08_mission_start_zscene_post_init()
-- Homies always spawn
group_show( M08_group.zimos.name )
group_show( M08_group.pierce.name )
on_death("m08_homie_death_fail_cb", M08_group.zimos.npcs[1])
on_death("m08_homie_death_fail_cb", M08_group.pierce.npcs[1])
party_add(M08_group.zimos.npcs[1], LOCAL_PLAYER)
teleport( M08_group.pierce.npcs[1], M08_navpoint.cp_starts.bar.pierce, true )
group_show( M08_group.saints.name )
group_show( M08_group.prostitutes.name )
-- set up attack lines cb
for i, n in pairs( M08_group.prostitutes.npcs ) do
on_attack_performed( "m08_on_attack_performed_cb", n )
end
-- bring in the partiers
group_show( M08_group.partiers[ 1 ].name )
group_show( M08_group.partiers[ 2 ].name )
group_show( M08_group.partiers[ 3 ].name )
audio_object_post_event( M08_audio.chaotic_screams_start_event, nil, nil, LOCAL_PLAYER )
audio_ambient_emitter_start( M08_audio.walla_emitter )
-- switch to mission lighting
light_group_set_intensity( M08_light_groups.mission, 1 )
M08_status.laser_effect_01 = effect_play( "Vfx Laser Lights<001>", true )
M08_status.laser_effect_02 = effect_play( "Vfx Laser Lights<002>", true )
end
-- This is the primary function responsible for running the entire mission from start to finish.
--
-- first_checkpoint: (string) The first checkpoint to begin running the mission at
--
function m08_run(first_checkpoint)
local current_checkpoint = first_checkpoint
-- For the entire mission, warp to the base of the tower on cancel
mission_set_cancel_warp_location(M08_navpoint.end_local, M08_navpoint.end_remote)
-- Run the mission from the beginning
if (current_checkpoint == M08_checkpoint.start) then
m08_survive_initial_assault()
m08_protect_pierce()
-- Now move on to the next checkpoint
current_checkpoint = M08_checkpoint.snipers
mission_set_checkpoint(M08_checkpoint.snipers, true, true)
end
if (current_checkpoint == M08_checkpoint.snipers) then
m08_kill_snipers()
-- Now move on to the next checkpoint
current_checkpoint = M08_checkpoint.power
mission_set_checkpoint(M08_checkpoint.power, true, true)
end
if (current_checkpoint == M08_checkpoint.power) then
m08_restore_power()
--- m08_cutscene_heli_attack()
-- Now move on to the next checkpoint
current_checkpoint = M08_checkpoint.heli
mission_set_checkpoint(M08_checkpoint.heli, true, true)
end
if (current_checkpoint == M08_checkpoint.heli) then
m08_kill_helis()
end
mission_end_success( "m08", M08_cutscene.mission_outro, { M08_navpoint.end_local, M08_navpoint.end_remote } )
end
-- This is the primary function responsible for cleaning up the entire mission
-- CALLED FROM CODE (+++MUST RETURN IMMEDIATLY+++)
--
function m08_cleanup()
-- crib access is now allowed
crib_disable_interface( false )
-- turn base jumping back on
base_jumping_enable( true )
-- Re-enable elevator triggers
trigger_type_enable( "warp", true)
-- Reset notoriety
notoriety_force_no_spawn("luchadores", false)
notoriety_force_no_spawn("deckers", false)
notoriety_force_no_spawn("morningstar", false)
notoriety_force_no_spawn("police", false)
notoriety_reset("morningstar")
-- Stop any conversations
cleanup_conversations(M08_conv)
-- Unload personas
for i, pers in pairs(M08_persona) do
if (pers.id ~= INVALID_PERSONA_HANDLE) then
audio_persona_remove_2d(pers.id)
pers.id = INVALID_PERSONA_HANDLE
end
end
-- Clear any triggers
for i, trig in pairs(M08_trigger) do
m08_clear_trigger(trig)
end
-- Stop any threads
cleanup_threads(M08_thread)
audio_object_post_event(M08_audio.music_queues.stop, nil, nil, M08_audio.music_emitter)
-- Remove markers and callbacks
for j, g in pairs( M08_group.snipers ) do
if group_is_loaded( g.name ) then
for i, npc in pairs( g.npcs ) do
marker_remove( npc )
on_death( "", npc )
end
end
end
for i, heli in pairs(M08_group.helis) do
if group_is_loaded(heli.name) then
marker_remove(heli.vehicle)
on_vehicle_destroyed("", heli.vehicle)
end
end
if group_is_loaded(M08_group.zimos.name) then
on_death("", M08_group.zimos.npcs[1])
end
if group_is_loaded(M08_group.pierce.name) then
marker_remove(M08_group.pierce.npcs[1])
on_death("", M08_group.pierce.npcs[1])
end
on_pickup("", M08_group.sniper_rifle_item.item)
if group_is_loaded( M08_group.circuit_guards.name ) then
for i, n in pairs( M08_group.circuit_guards.npcs ) do
on_attack_performed( "", n )
end
end
if group_is_loaded( M08_group.prostitutes.name ) then
for i, n in pairs( M08_group.prostitutes.npcs ) do
on_attack_performed( "", n )
end
end
cleanup_spawn_groups(M08_spawn_group)
cleanup_groups(M08_group)
cleanup_spawn_regions(M08_spawn_region)
cleanup_temporary_weapons(M08_weapon)
m08_end_cookie_trail()
if M08_status.player_given_rocket_launcher then
inv_weapon_remove_temporary( LOCAL_PLAYER, "Explosive-RocketLauncher" )
if coop_is_active() then
inv_weapon_remove_temporary( REMOTE_PLAYER, "Explosive-RocketLauncher" )
end
end
-- return to normal lighting
light_group_set_intensity( M08_light_groups.mission, 1, true )
light_group_set_intensity( M08_light_groups.emergency, 0, true )
if (nil ~= M08_status.laser_effect_01) then
effect_stop( M08_status.laser_effect_01 )
M08_status.laser_effect_01 = nil
end
if (nil ~= M08_status.laser_effect_02) then
effect_stop( M08_status.laser_effect_02 )
M08_status.laser_effect_02 = nil
end
city_zone_swap( "m08", false )
city_zone_swap( "hq", true )
-- kill mission audio
-- audio_ambient_emitter_stop( M08_audio.music_emitter )
audio_ambient_emitter_stop( M08_audio.walla_emitter )
audio_object_post_event( M08_audio.chaotic_screams_stop_event, nil, nil, LOCAL_PLAYER )
if M08_status.cellphone_call_in_progress ~= nil then
audio_remove_mission_cellphone( M08_status.cellphone_call_in_progress )
end
end
-- Called when the mission has ended with success
-- CALLED FROM CODE (+++MUST RETURN IMMEDIATLY+++)
--
function m08_success()
--[[ INSERT ANY MISSION SPECIFIC SUCCESS STUFF ]]--
end
--------------------------------------------------------------------------------------------------
--[[*****************]]--
--[[ Local functions ]]--
--[[*****************]]--
-- Initialize the mission for the specified checkpoint
--
-- checkpoint: Checkpoint to initialize the mission to
--
function m08_initialize(checkpoint)
-- Make sure the screen is completly faded out
mission_start_fade_out(0.0)
-- Set the mission author
set_mission_author("Albert McDaniel")
-- don't allow crib interaction during this mission
crib_disable_interface( true )
-- no base jumping i guess
base_jumping_enable( false )
-- Disable elevator triggers
trigger_type_enable( "warp", false)
-- Common initialization
notoriety_force_no_spawn("luchadores", true)
notoriety_force_no_spawn("deckers", true)
notoriety_force_no_spawn("morningstar", true)
notoriety_force_no_spawn("police", true)
notoriety_set_max("morningstar", 3)
trigger_enable(M08_trigger.massacre, true)
on_trigger("m08_massacre_cb", M08_trigger.massacre)
-- Just open all the doors when the mission starts...
for i, door in pairs(M08_mover.doors) do
door_open(door, false, false)
end
-- Lock the elevators
for i, elev in pairs(M08_mover.locked_elevators) do
door_lock(elev, true)
end
--m08_start_smoke_effects()
city_zone_swap( "hq", false )
city_zone_swap( "m08", true )
-- Checkpoint specific initialization
m08_initialize_checkpoint(checkpoint)
end
-- Checkpoint specific initialization
--
-- checkpoint: The checkpoint to be initialized
--
function m08_initialize_checkpoint(checkpoint)
if checkpoint == M08_checkpoint.snipers then
audio_ambient_emitter_start( M08_audio.walla_emitter )
end
if (checkpoint == M08_checkpoint.start) then
-- Turn on the music again
audio_object_post_event(M08_audio.music_queues.resume, nil, nil, M08_audio.music_emitter)
-- Homies always spawn
group_create_hidden(M08_group.zimos.name, true)
group_create_hidden(M08_group.pierce.name, true)
group_create_hidden(M08_group.saints.name, true)
group_create_hidden(M08_group.prostitutes.name, true)
-- bring in the partiers
group_create_hidden( M08_group.partiers[ 1 ].name, true )
group_create_hidden( M08_group.partiers[ 2 ].name, true )
group_create_hidden( M08_group.partiers[ 3 ].name, true )
return
end
-- Homies always spawn
group_create(M08_group.zimos.name, true)
group_create(M08_group.pierce.name, true)
on_death("m08_homie_death_fail_cb", M08_group.zimos.npcs[1])
on_death("m08_homie_death_fail_cb", M08_group.pierce.npcs[1])
party_add(M08_group.zimos.npcs[1], LOCAL_PLAYER)
-- Peirce becomes homie after he is protected
if (coop_is_active()) then
party_add(M08_group.pierce.npcs[1], REMOTE_PLAYER)
else
party_add(M08_group.pierce.npcs[1], LOCAL_PLAYER)
end
if (checkpoint == M08_checkpoint.snipers) then
teleport_coop(M08_navpoint.cp_starts.bar.player_local, M08_navpoint.cp_starts.bar.player_remote, true)
-- Cut the power
m08_cut_power()
return
end
if (checkpoint == M08_checkpoint.power) then
teleport_coop(M08_navpoint.cp_starts.roof.player_local, M08_navpoint.cp_starts.roof.player_remote, true)
-- Cut the power
m08_cut_power()
return
end
if (checkpoint == M08_checkpoint.heli) then
-- Power restored
light_group_set_intensity( M08_light_groups.mission, 1 )
light_group_set_intensity( M08_light_groups.emergency, 0 )
M08_status.laser_effect_01 = effect_play( "Vfx Laser Lights<001>", true )
M08_status.laser_effect_02 = effect_play( "Vfx Laser Lights<002>", true )
teleport_coop(M08_navpoint.cp_starts.utility.player_local, M08_navpoint.cp_starts.utility.player_remote, true)
teleport( M08_group.zimos.npcs[1], M08_navpoint.cp_starts.utility.zimos )
teleport( M08_group.pierce.npcs[1], M08_navpoint.cp_starts.utility.pierce )
end
end
--[[ ]]--
--[[ OBJECTIVE (START OF MISSION) ]]--
--[[ ]]--
-- Survive the initial assault
--
function m08_survive_initial_assault()
audio_ambient_emitter_start(M08_audio.music_emitter)
-- Tell the player to survive
objective_text(0, M08_text.survive_assault, nil, nil, SYNC_ALL, OI_ASSET_DEFEND)
M08_thread.partier_behavior = thread_new( "m08_partier_behavior" )
M08_thread.pierce_runs_to_bar = thread_new( "m08_pierce_runs_to_bar" )
delay(2)
M08_conv.survive.handle = audio_conversation_load(M08_conv.survive.name)
audio_conversation_play(M08_conv.survive.handle)
-- Spawn enemies for 60 seconds
continuous_spawn_regions_enable(M08_spawn_region.downstairs, true)
call_function_on_each_member(continuous_spawn_start, M08_spawn_group.ms_waves)
if coop_is_active() then
call_function_on_each_member(continuous_spawn_start, M08_spawn_group.ms_waves_coop)
end
delay(60)
call_function_on_each_member(continuous_spawn_stop, M08_spawn_group.ms_waves)
continuous_spawn_regions_enable(M08_spawn_region.downstairs, false)
if coop_is_active() then
call_function_on_each_member(continuous_spawn_stop, M08_spawn_group.ms_waves_coop)
end
-- Objective clear
audio_conversation_wait_for_end(M08_conv.survive.handle)
M08_conv.survive.handle = INVALID_CONVERSATION_HANDLE
end
-- thread to manage the behavior of the partiers
function m08_partier_behavior()
-- have them stand around for a few seconds
delay( 4 )
-- flee to their designated flee point
for i, g in pairs( M08_group.partiers ) do
g.path_idx = { }
for j, m in pairs( g.npcs ) do
g.path_idx[ j ] = move_to_do( m, g.fee_nav, 2, true, false, false, 0 )
end
end
while true do
-- despawn if all memebers are either dead or at their flee point
for i, g in pairs( M08_group.partiers ) do
if g.cleaned == false then
local clean = true
for j, m in pairs( g.npcs ) do
if character_is_dead( m ) == false and move_to_check_done( g.path_idx[ j ], m, g.fee_nav, 2, true, false, false, 0 ) == false then
clean = false
break
end
end
if clean then
release_to_world( g.name )
g.cleaned = true
end
end
end
thread_yield()
end
end
-----------------------------------
--[[ ]]--
--[[ OBJECTIVE (DEFEND PIERCE) ]]--
--[[ ]]--
-- Have the player go upstairs to defend Pierce
--
function m08_protect_pierce()
if (coop_is_active()) then
party_add(M08_group.pierce.npcs[1], REMOTE_PLAYER)
else
party_add(M08_group.pierce.npcs[1], LOCAL_PLAYER)
end
audio_play_persona_line(LOCAL_PLAYER, "M08_Pierce_Down_Generic") -- bar alternate: "M08_Pierce_Down"
delay(2)
M08_conv.pierce.handle = audio_conversation_load(M08_conv.pierce.name)
audio_conversation_play(M08_conv.pierce.handle)
-- Tell the player to help Pierce
objective_text_clear(0)
objective_text(0, M08_text.protect_pierce, nil, nil, SYNC_ALL, OI_ASSET_DEFEND)
marker_add(M08_group.pierce.npcs[1], MINIMAP_ICON_PROTECT_ACQUIRE, OI_ASSET_DEFEND, OI_FLAGS_FULL, SYNC_ALL)
-- Down Pierce
effect_play_on_human( "Effect BloodHit", M08_group.pierce.npcs[ 1 ], "Head" )
turn_vulnerable( M08_group.pierce.npcs[ 1 ] )
npc_leash_remove( M08_group.pierce.npcs[ 1 ] )
ai_clear_scripted_action( M08_group.pierce.npcs[ 1 ] )
if human_is_downed( M08_group.pierce.npcs[ 1 ] ) ~= true then
human_enter_downed( M08_group.pierce.npcs[ 1 ] )
end
-- Spawn enemies until Pierce has been revived plus 60 seconds
continuous_spawn_regions_enable(M08_spawn_region.upstairs, true)
call_function_on_each_member(continuous_spawn_start, M08_spawn_group.ms_waves_upstairs)
if coop_is_active() then
call_function_on_each_member(continuous_spawn_start, M08_spawn_group.ms_waves_upstairs_coop)
end
audio_conversation_wait_for_end(M08_conv.pierce.handle)
M08_conv.pierce.handle = INVALID_CONVERSATION_HANDLE
repeat
thread_yield()
until (not human_is_downed(M08_group.pierce.npcs[1]))
audio_play_persona_line( M08_group.pierce.npcs[1], "M08_Pierce_Thanks_01" )
delay( 5 )
M08_conv.bar.handle = audio_conversation_load(M08_conv.bar.name)
audio_conversation_play(M08_conv.bar.handle)
audio_conversation_wait_for_end(M08_conv.bar.handle)
M08_conv.bar.handle = INVALID_CONVERSATION_HANDLE
-- Cut the power
m08_cut_power()
delay(2)
M08_conv.no_power.handle = audio_conversation_load(M08_conv.no_power.name)
audio_conversation_play(M08_conv.no_power.handle)
audio_conversation_wait_for_end(M08_conv.no_power.handle)
M08_conv.no_power.handle = INVALID_CONVERSATION_HANDLE
delay(2)
-- Objective clear
call_function_on_each_member(continuous_spawn_stop, M08_spawn_group.ms_waves_upstairs)
continuous_spawn_regions_enable(M08_spawn_region.upstairs, false)
if coop_is_active() then
call_function_on_each_member(continuous_spawn_stop, M08_spawn_group.ms_waves_upstairs_coop)
end
marker_remove(M08_group.pierce.npcs[1])
objective_text_clear(0)
-- Make it so Pierce isn't stuck anymore
follower_make_independent(M08_group.pierce.npcs[1], false)
end
----------------------------------
--[[ ]]--
--[[ OBJECTIVE (KILL SNIPERS) ]]--
--[[ ]]--
-- Fend off the snipers
--
function m08_kill_snipers()
-- Bring in the snipers
M08_status.targets_left = 0
M08_status.snipers_alive = 0
-- init total number of targets
for i, g in pairs( M08_group.snipers ) do
M08_status.targets_left = M08_status.targets_left + #g.npcs
end
M08_thread.manage_snipers = thread_new( "m08_manage_snipers_thread" )
delay(2)
-- Get a sniper rifle
objective_text_clear(0)
objective_text(0, M08_text.find_sniper_rifle, nil, nil, SYNC_ALL, OI_ASSET_USE)
group_create( M08_group.sniper_rifle_item, true )
M08_thread.cookie_trails_local = m08_start_cookie_trail( M08_navpoint.trail_to_rifle, LOCAL_PLAYER, SYNC_LOCAL )
if coop_is_active() then
M08_thread.cookie_trails_remote= m08_start_cookie_trail( M08_navpoint.trail_to_rifle, REMOTE_PLAYER, SYNC_REMOTE )
end
M08_conv.snipers.handle = audio_conversation_load(M08_conv.snipers.name)
audio_conversation_play(M08_conv.snipers.handle)
audio_conversation_wait_for_end(M08_conv.snipers.handle)
M08_conv.snipers.handle = INVALID_CONVERSATION_HANDLE
-- wait until a player is near the rifle
while M08_status.targets_left > 0 do
if get_dist( LOCAL_PLAYER, "Nav Trail <004>" ) < 3 then
break
end
if coop_is_active() and get_dist( REMOTE_PLAYER, "Nav Trail <004>" ) < 3 then
break
end
thread_yield()
end
-- Give the players both a "real" rifle to keep and a temporary version with unlimited ammo
inv_item_add(M08_weapon.sniper_rifle, 1, LOCAL_PLAYER, false)
inv_weapon_add_temporary(LOCAL_PLAYER, M08_weapon.sniper_rifle, 1, true, true, true)
audio_object_post_event( M08_audio.chaotic_screams_stop_event, nil, nil, LOCAL_PLAYER )
if coop_is_active() then
inv_item_add(M08_weapon.sniper_rifle, 1, REMOTE_PLAYER, false)
inv_weapon_add_temporary(REMOTE_PLAYER, M08_weapon.sniper_rifle, 1, true, true, true)
end
group_destroy( M08_group.sniper_rifle_item )
m08_end_cookie_trail( M08_thread.cookie_trails_local )
M08_thread.cookie_trails_local = INVALID_THREAD_HANDLE
if coop_is_active() then
m08_end_cookie_trail( M08_thread.cookie_trails_remote, SYNC_REMOTE )
M08_thread.cookie_trails_remote = INVALID_THREAD_HANDLE
end
objective_text_clear(0)
-- Get to the roof
objective_text(0, M08_text.get_to_roof, nil, nil, SYNC_ALL, OI_ASSET_LOCATION)
M08_thread.cookie_trails_local = m08_start_cookie_trail( M08_navpoint.trail_to_roof, LOCAL_PLAYER, SYNC_LOCAL )
if coop_is_active() then
M08_thread.cookie_trails_remote = m08_start_cookie_trail( M08_navpoint.trail_to_roof, REMOTE_PLAYER, SYNC_REMOTE )
end
audio_play_persona_line(M08_group.pierce.npcs[1], "M08_On_Way_To_Roof")
M08_status.obj_reached = false
trigger_enable(M08_trigger.roof, true)
on_trigger("m08_trigger_reached", M08_trigger.roof)
while M08_status.obj_reached == false and M08_status.targets_left > 0 do
thread_yield()
end
m08_end_cookie_trail( M08_thread.cookie_trails_local )
M08_thread.cookie_trails_local = INVALID_THREAD_HANDLE
if coop_is_active() then
m08_end_cookie_trail( M08_thread.cookie_trails_remote, SYNC_REMOTE )
M08_thread.cookie_trails_remote = INVALID_THREAD_HANDLE
end
objective_text_clear(0)
-- Kill the snipers
objective_text(0, M08_text.kill_snipers, nil, nil, SYNC_ALL, OI_ASSET_KILL)
-- Mark the snipers
M08_status.mark_snipers = true
for i, g in pairs( M08_group.snipers ) do
for j, sniper in pairs( g.npcs) do
if character_exists( sniper ) == true and character_is_dead( sniper ) == false then
marker_add( sniper, MINIMAP_ICON_KILL, OI_ASSET_KILL, OI_FLAGS_DEFAULT, SYNC_ALL )
end
end
end
-- Wait until all snipers are dead
while M08_status.targets_left > 0 do
thread_yield()
end
M08_thread.fade_walla = thread_new( "m08_fade_walla_thread" )
objective_text_clear(0)
end
-----------------------------------
--[[ ]]--
--[[ OBJECTIVE (RESTORE POWER) ]]--
--[[ ]]--
-- Restore the power
--
function m08_restore_power()
-- Get to the basement
M08_thread.cookie_trails_local = m08_start_cookie_trail( M08_navpoint.trail_to_maint, LOCAL_PLAYER, SYNC_LOCAL )
if coop_is_active() then
M08_thread.cookie_trails_remote = m08_start_cookie_trail( M08_navpoint.trail_to_maint, REMOTE_PLAYER, SYNC_REMOTE )
end
delay(1)
M08_conv.fix_power.handle = audio_conversation_load(M08_conv.fix_power.name)
audio_conversation_play(M08_conv.fix_power.handle)
-- wait for convo to end before enabling power trigger
audio_conversation_wait_for_end(M08_conv.fix_power.handle)
M08_conv.fix_power.handle = INVALID_CONVERSATION_HANDLE
-- Restore the power
M08_status.obj_reached = false
trigger_enable(M08_trigger.circuit_breaker, true)
on_trigger("m08_power_trigger_activated", M08_trigger.circuit_breaker)
while not M08_status.obj_reached do
thread_yield()
end
m08_end_cookie_trail( M08_thread.cookie_trails_local )
M08_thread.cookie_trails_local = INVALID_THREAD_HANDLE
if coop_is_active() then
m08_end_cookie_trail( M08_thread.cookie_trails_remote, SYNC_REMOTE )
M08_thread.cookie_trails_remote = INVALID_THREAD_HANDLE
end
-- load oleg persona early for later conversation
M08_persona.oleg.id = audio_persona_load_2d(M08_persona.oleg.name)
delay( 3 )
-- Power restored
light_group_set_intensity( M08_light_groups.mission, 1 )
light_group_set_intensity( M08_light_groups.emergency, 0 )
M08_status.laser_effect_01 = effect_play( "Vfx Laser Lights<001>", true )
M08_status.laser_effect_02 = effect_play( "Vfx Laser Lights<002>", true )
if M08_thread.blackout_chatter_thread ~= nil then
thread_kill( M08_thread.blackout_chatter_thread )
M08_thread.blackout_chatter_thread = nil
end
-- Music comes back up
audio_object_post_event(M08_audio.music_queues.resume, nil, nil, M08_audio.music_emitter)
-- Enable the elevators
for i, elev in pairs(M08_mover.locked_elevators) do
door_lock(elev, false)
end
objective_text_clear(0)
-- cell call from oleg
m08_cellphone_call_wait( M08_conv.oleg_call.name, true )
M08_conv.oleg_call.handle = INVALID_CONVERSATION_HANDLE
if (M08_persona.oleg.id ~= INVALID_PERSONA_HANDLE) then
audio_persona_remove_2d(M08_persona.oleg.id)
M08_persona.oleg.id = INVALID_PERSONA_HANDLE
end
end
function m08_cellphone_call_wait( convo, recieving, persona )
M08_status.cellphone_call_in_progress = convo
audio_play_for_mission_cellphone( convo, recieving, true, "", "m08_cellphone_call_cb", persona )
while M08_status.cellphone_call_in_progress ~= nil do
thread_yield()
end
end
function m08_cellphone_call_cb()
M08_status.cellphone_call_in_progress = nil
end
---------------------------------
--[[ ]]--
--[[ OBJECTIVE (GET TO HELI) ]]--
--[[ ]]--
-- Go to the helipad and get in the helicopter
--
function m08_kill_helis()
-- Get to the helipad
objective_text(0, M08_text.get_rocket_launcher, nil, nil, SYNC_ALL, OI_ASSET_USE)
-- spawn and mark weapon
group_create( M08_group.rocket_launcher.name, true )
marker_add( M08_group.rocket_launcher.item, MINIMAP_ICON_USE, OI_ASSET_USE, OI_FLAGS_FULL, SYNC_ALL)
trigger_enable( M08_trigger.rocket_pickup, true )
on_trigger( "m08_on_trigger_rocket_pickup", M08_trigger.rocket_pickup )
-- enable stair, lobby and bar triggers
trigger_enable( M08_trigger.utility_stairs, true )
trigger_enable( M08_trigger.lobby_skylight, true )
trigger_enable( M08_trigger.bar, true )
-- threads to spawn and manage helis
M08_status.targets_left = M08_num_helis_to_create
M08_status.helis_created = 0
M08_thread.heli1_behavior = thread_new( "m08_heli1_behavior" )
M08_thread.heli2_behavior = thread_new( "m08_heli2_behavior" )
-- spawn heli saints
group_create( M08_group.heli_saints.name, true )
-- Spawn some dudes to fight
group_create(M08_group.heli_guards.name, false)
-- watch for various trigger events, exit when player has grabbed weapon
M08_status.stair_rocket_fire = false
M08_status.skylight_rocket_fire = false
M08_status.helibait_rocket_fire = false
M08_status.heli_release = false
while true do
-- if any helis are destroyed then skip the staging and attack
-- also if the rocket gets grabbed
if M08_status.targets_left < M08_num_helis_to_create or M08_status.rocket_picked_up == true then
break
end
-- if stair trigger hit, fire stair rocket
if M08_status.stair_rocket_fire == false and m08_player_is_in_trigger( M08_trigger.utility_stairs ) then
M08_status.stair_rocket_fire = true
end
-- if lobby trigger hit, fire skylight rocket
if M08_status.skylight_rocket_fire == false and m08_player_is_in_trigger( M08_trigger.lobby_skylight ) then
M08_status.skylight_rocket_fire = true
end
-- if bar trigger hit, kill saints
if M08_status.helibait_rocket_fire == false and m08_player_is_in_trigger( M08_trigger.bar ) then
M08_status.helibait_rocket_fire = true
end
thread_yield()
end
objective_text(0, M08_text.destroy_vehicles, nil, nil, SYNC_ALL, OI_ASSET_KILL)
-- if any rockets not fired yet, do it now
M08_status.stair_rocket_fire = true
M08_status.skylight_rocket_fire = true
M08_status.helibait_rocket_fire = true
-- release helis to ai
M08_status.heli_release = true
while M08_status.targets_left > 0 do
thread_yield()
end
end
function m08_on_trigger_rocket_pickup( char, trigger )
trigger_enable( trigger, false )
inv_weapon_add_temporary( LOCAL_PLAYER, "Explosive-RocketLauncher", nil, true, true )
if coop_is_active() then
inv_weapon_add_temporary( REMOTE_PLAYER, "Explosive-RocketLauncher", nil, true, true )
end
-- clean up rocket launcher
marker_remove( M08_group.rocket_launcher.item )
group_destroy( M08_group.rocket_launcher.name )
M08_status.rocket_picked_up = true
end
--------------------------------------------------------------------------------------------------
--[[************************************]]--
--[[ Miscellaneous m08 Helper Functions ]]--
--[[************************************]]--
-- Disable trigger
--
-- trigger: (string) Name of the trigger
--
function m08_clear_trigger(trigger)
on_trigger("", trigger)
trigger_enable(trigger, false)
marker_remove_trigger(trigger, SYNC_ALL)
end
function m08_cutscene_heli_attack()
-- Don't process this function if the cutscene hasn't been set up yet
if (M08_cutscene.heli_attack.name == "") then
return
end
-- Do all the stuff for actually playing the cutscene below
cutscene_in()
group_create( M08_group.cte_npc_group.name, true )
cutscene_play( M08_cutscene.heli_attack.name )
group_destroy( M08_group.cte_npc_group.name )
cutscene_out()
end
function m08_cut_power()
-- Cut the lights
light_group_use_intensity( M08_light_groups.mission, true )
light_group_set_intensity( M08_light_groups.mission, 0 )
if (nil ~= M08_status.laser_effect_01) then
effect_stop( M08_status.laser_effect_01 )
M08_status.laser_effect_01 = nil
end
if (nil ~= M08_status.laser_effect_02) then
effect_stop( M08_status.laser_effect_02 )
M08_status.laser_effect_02 = nil
end
light_group_use_intensity( M08_light_groups.emergency, true )
light_group_set_intensity( M08_light_groups.emergency, 1 )
-- Create some guards to slow the player's path to the circuit breaker
group_create(M08_group.circuit_guards.name, false)
-- set up attack lines cb
for i, n in pairs( M08_group.circuit_guards.npcs ) do
on_attack_performed( "m08_on_attack_performed_cb", n )
end
audio_object_post_event(M08_audio.music_queues.pause, nil, nil, M08_audio.music_emitter)
M08_thread.blackout_chatter_thread = thread_new( "m08_blackout_chatter_thread", M08_blackout_chatter_groups )
end
--function m08_start_smoke_effects()
-- for i,vfx in pairs(M08_vfx_smoke) do
-- -- Only start the effect if it's not already playing (this is just a safety precaution)
-- if (vfx.handle == -1) then
-- vfx.handle = effect_play(vfx.name, true)
-- end
-- end
--end
--function m08_stop_smoke_effects()
-- for i,vfx in pairs(M08_vfx_smoke) do
-- -- Only try to stop the effect if we have a valid handle
-- if (vfx.handle ~= -1) then
-- effect_stop(vfx.handle)
-- vfx.handle = -1
-- end
-- end
--end
--------------------------------------------------------------------------------------------------
--[[********************]]--
--[[ Callback functions ]]--
--[[********************]]--
-- Callback for a sniper being killed (should only be enabled during the "kill snipers" objective
--
-- sniper: (string) name of the sniper that died
--
function m08_sniper_died_cb(sniper)
on_death("", sniper)
marker_remove(sniper, SYNC_ALL)
M08_status.targets_left = M08_status.targets_left - 1
M08_status.snipers_alive = M08_status.snipers_alive - 1
end
-- Callback for a chopper being blown up
--
function m08_chopper_destroyed_cb(chopper)
on_vehicle_destroyed("", chopper)
marker_remove(chopper)
M08_status.targets_left = M08_status.targets_left - 1
end
-- Callback for a homie dying
--
-- char: (string) name of the homie that died
--
function m08_homie_death_fail_cb(char)
mission_end_failure("m08", M08_text.failure_death[char])
end
-- Returns true if the NPC name passed in is one of the heli pilots
--
-- npc_name: (string) name of the NPC we're looking at
--
function m08_is_heli_pilot(npc_name)
if (M08_group.helis[1].npcs[1] == npc_name) then
return true
end
if (M08_group.helis[1].npcs[2] == npc_name) then
return true
end
if (M08_group.helis[2].npcs[1] == npc_name) then
return true
end
if (M08_group.helis[2].npcs[2] == npc_name) then
return true
end
return false
end
-- Callback for player (or anyone else, for that matter) falling off the building
--
-- poor_sumbitch: (string) name of the poor sumbitch that fell off the building
--
function m08_massacre_cb(poor_sumbitch)
if poor_sumbitch ~= nil then
if (m08_is_heli_pilot(poor_sumbitch)) then
return
end
local v = get_char_vehicle_name( poor_sumbitch )
if v == "" then
character_kill(poor_sumbitch, true)
end
end
end
-- Callback for reaching the next trigger
--
function m08_trigger_reached(char, trigger)
m08_clear_trigger(trigger)
M08_status.obj_reached = true
end
function m08_power_trigger_activated( char, trigger )
m08_clear_trigger(trigger)
M08_status.obj_reached = true
action_play( char, "m24 computer hack", nil, nil, nil, nil, true, M08_navpoint.circut_breaker )
end
--------------------------------------------------------------------------------------------------
--[[******************]]--
--[[ Thread functions ]]--
--[[******************]]--
-- why cookie trail? because cookies are better than bread crumbs!
function m08_start_cookie_trail( navs, player, sync )
local thread_id = thread_new( "m08_manage_cookie_trail", navs, player, sync )
M08_cookie_trail_manager[ thread_id ] = navs
return thread_id
end
function m08_end_cookie_trail( id )
-- if id is nil we call them all up
if id == nil then
for i, n in pairs( M08_cookie_trail_manager ) do
m08_end_cookie_trail( i )
end
M08_cookie_trail_manager = { }
end
local navs = M08_cookie_trail_manager[ id ]
if navs == nil then
return
end
-- local sync = navs.sync
--if sync == nil then
local sync = SYNC_ALL
--end
thread_kill( id )
for i = 1, #navs do
local n = navs[ i ]
if n.trigger ~= nil then
marker_remove_trigger( n.trigger, sync )
else
marker_remove( n.name, sync )
end
if n.objective ~= nil then
objective_text_clear( 0, sync )
end
end
M08_cookie_trail_manager[ id ] = nil
end
function m08_manage_cookie_trail( navs, player, sync )
-- This will have all the basic information on where we are going
local path_info = { }
local last_shown_index
if player == nil then
player = LOCAL_PLAYER
end
if sync == nil then
sync = SYNC_ALL
end
navs.sync = sync
-- This now finds the absolute nearest nav point, we don't return the next nav if we're close to another
local function find_closest_nav()
local best_dist_to_player
local best_nav_index = -1
local d
for i = 1, #navs do
-- favor navs on a similar y to player
d = get_dist( player, navs[ i ].name, true )
-- otherwise find the closest nav
if best_nav_index == -1 or d < best_dist_to_player then
best_nav_index = i
best_dist_to_player = d
end
end
--if best_dist_to_player < 4 and navs[ best_nav_index ].next_nav ~= nil then
-- best_nav_index = navs[ best_nav_index ].next_nav
--end
return best_nav_index
end
-- Builds all the basic path information from scratch
local function reset_path_info( seed_nav_index )
path_info = { }
if (nil == seed_nav_index) then
-- Nearest index is always the nearest index (absolute nearest)
path_info.nearest_nav_index = find_closest_nav()
else
-- I'm assuming the nearest index is the one passed in
path_info.nearest_nav_index = seed_nav_index
end
local new_next_nav_index = navs[ path_info.nearest_nav_index ].next_nav
if (nil == new_next_nav_index) then
-- Use the same point if we don't have a next
path_info.next_nav_index = path_info.nearest_nav_index
else
-- Set the next nav point
path_info.next_nav_index = new_next_nav_index
end
-- Set the lost distance as what ever the current distance is plus a small margin
path_info.lost_distance = get_dist( player, navs[ path_info.next_nav_index ].name, true ) + 5
end
local function show_cookie( n )
local icon, effect, asset, flags
icon = MINIMAP_ICON_LOCATION
effect = INGAME_EFFECT_LOCATION
asset = OI_ASSET_LOCATION
flags = OI_FLAGS_LOCATION
if n.type == "use" then
icon = MINIMAP_ICON_USE
asset = OI_ASSET_USE
end
if n.trigger ~= nil then
marker_add_trigger( n.trigger,icon, effect, asset, flags, sync )
else
marker_add( n.name, icon, asset, flags, sync )
end
if n.objective ~= nil then
objective_text( 0, n.objective, nil, nil, sync, asset )
end
end
local function hide_cookie( n )
if n.trigger ~= nil then
marker_remove_trigger( n.trigger, sync )
else
marker_remove( n.name, sync )
end
if n.objective ~= nil then
objective_text_clear( 0, sync )
end
end
-- Reset all the path data to a default state
reset_path_info();
-- d_to_next = dist_to_next( navs[ current_nav ] )
-- show_cookie( navs[ current_nav ] )
while true do
local d_nearest
local d_next
-- How far is it to the next point?
d_next = get_dist( player, navs[ path_info.next_nav_index ].name, true )
d_nearest = get_dist( player, navs[ path_info.nearest_nav_index ].name, true )
-- If the destinations are not the same, we should consider updating the nearest index
if (path_info.nearest_nav_index ~= path_info.next_nav_index) then
-- The nearest is farther away than the next, we should advance to the next waypoint
if (d_nearest > d_next) then
-- We should advance to the next nearest point now
reset_path_info( path_info.next_nav_index );
-- Update the distance so we have an acurate distance in there
d_next = get_dist( player, navs[ path_info.next_nav_index ].name, true )
d_nearest = get_dist( player, navs[ path_info.nearest_nav_index ].name, true )
end
end
-- If we are real close to the nearest waypoint, we should make the destination the NEXT waypoint
-- We have to check to see if they are the same again because we may have just reset them
if (path_info.nearest_nav_index ~= path_info.next_nav_index) then
if (5 > d_nearest) then
reset_path_info( path_info.next_nav_index );
-- Update the distance so we have an acurate distance in there
d_next = get_dist( player, navs[ path_info.next_nav_index ].name, true )
d_nearest = get_dist( player, navs[ path_info.nearest_nav_index ].name, true )
end
end
--If we're over the "lost" distance, then we should start over from scratch
if (path_info.lost_distance < d_nearest) then
reset_path_info();
end
-- Alright, we should have the destination index we want in "path_info.nearest_nav_index"
-- If this isn't the same as the last one we showed, we need to update it
if (nil == last_shown_index) then
-- There was no previous index, just show what ever we have
show_cookie( navs[ path_info.nearest_nav_index ] )
last_shown_index = path_info.nearest_nav_index
else
-- If it is not the same cookie, we need to update it
if (last_shown_index ~= path_info.nearest_nav_index) then
hide_cookie( navs[ last_shown_index ] )
show_cookie( navs[ path_info.nearest_nav_index ] )
-- Make this index the last shown index so we don't do this over and over
last_shown_index = path_info.nearest_nav_index
end
end
-- Done, wait a short period before we update this again
delay( 1 )
end
end
-- TODO: kill me
function m08_zimos_gives_a_rocket()
ai_do_scripted_move( M08_group.zimos.npcs[ 1 ], LOCAL_PLAYER, true, false )
while ai_scripted_action_is_complete( M08_group.zimos.npcs[ 1 ] ) ~= true do
thread_yield()
end
inv_weapon_add_temporary( LOCAL_PLAYER, "Explosive-RocketLauncher", nil, true, true )
if coop_is_active() then
inv_weapon_add_temporary( REMOTE_PLAYER, "Explosive-RocketLauncher", nil, true, true )
end
M08_status.player_given_rocket_launcher = true
M08_thread.zimos_gives_a_rocket = INVALID_THREAD_HANDLE
end
function m08_pierce_runs_to_bar()
turn_invulnerable(M08_group.pierce.npcs[1])
character_set_can_take_human_shield( M08_group.pierce.npcs[1], false )
ai_do_scripted_move( M08_group.pierce.npcs[ 1 ], M08_navpoint.pierce_behind_bar, true, false )
while ai_scripted_action_is_complete( M08_group.pierce.npcs[ 1 ] ) ~= true do
thread_yield()
end
-- leash him to navpoint
npc_leash_to_nav( M08_group.pierce.npcs[1], M08_navpoint.pierce_behind_bar, 0.0 )
character_set_can_take_human_shield( M08_group.pierce.npcs[1], true )
M08_thread.pierce_runs_to_bar = INVALID_THREAD_HANDLE
end
function m08_manage_snipers_thread()
local current_wave = 0
while true do
if M08_status.snipers_alive < 2 then
current_wave = current_wave + 1
local g = M08_group.snipers[ current_wave ]
if g == nil then
-- no more snipers... move on
return
end
-- create next group of snipers
group_create( g.name, true )
M08_status.snipers_alive = M08_status.snipers_alive + #g.npcs
for i,sniper in pairs( M08_group.snipers[ current_wave ].npcs ) do
on_death( "m08_sniper_died_cb", sniper )
ai_add_enemy_target( sniper, CLOSEST_PLAYER, ATTACK_NOW, true )
set_cant_cower_flag( sniper, true )
set_animation_set( sniper, "COP" )
if g.fire_at ~= nil then
if g.fire_at[ i ] ~= nil then
force_fire( sniper, g.fire_at[ i ], true )
npc_aim_at_point( sniper, g.fire_at[ i ] )
end
end
if M08_status.mark_snipers == true and character_exists( sniper ) == true and character_is_dead( sniper ) == false then
marker_add( sniper, MINIMAP_ICON_KILL, OI_ASSET_KILL, OI_FLAGS_DEFAULT, SYNC_ALL )
end
end
end
thread_yield()
end
end
function m08_fade_walla_thread()
audio_object_post_event( M08_audio.walla_fade_event, nil, nil, M08_audio.walla_emitter )
delay( 3 )
audio_ambient_emitter_stop( M08_audio.walla_emitter )
end
function m08_blackout_chatter_thread( groups )
local npcs = { }
local speaker
for i, g in pairs( groups ) do
for j, n in pairs( g ) do
npcs[ #npcs + 1 ] = n
end
end
while true do
speaker = get_random_table_entry( npcs )
if character_exists( speaker ) == true and character_is_dead( speaker ) == false then
audio_play_persona_line( speaker, "M08_Blackout" )
end
delay( rand_float( 5, 15 ) )
end
end
function m08_on_attack_performed_cb( name )
if M08_thread.attack_line_timer ~= nil and thread_check_done( M08_thread.attack_line_timer ) == false then
return
end
M08_thread.attack_line_timer = thread_new( "delay", rand_float( 5, 15 ) )
audio_play_persona_line( name, "m08_attack" )
end
function m08_player_is_in_trigger( trigger_name )
local in_trigger = object_is_in_trigger( trigger_name, LOCAL_PLAYER )
if coop_is_active() == true and in_trigger == false then
in_trigger = object_is_in_trigger( trigger_name, REMOTE_PLAYER )
end
return in_trigger
end
function m08_heli1_behavior()
local nav = "Nav Heli To Pool End 1"
local heli = M08_group.helis[ 1 ]
m08_heli_create_and_setup( heli )
M08_status.helis_created = M08_status.helis_created + 1
if M08_status.helis_created < 3 then
-- move into position
helicopter_fly_to_direct( heli.vehicle, 45, "NS Heli To Pool 1" )
-- orient to nav point
-- have to do this manually since the system doesn't properly support it
helicopter_fly_to_do( heli.vehicle, 45, true, "", false, nav, 0, false, false, false, false)
helicopter_fly_to_set_goal_direction( heli.vehicle, nav, true )
while vehicle_pathfind_check_done( heli.vehicle ) == 0 do
thread_yield()
end
while M08_status.stair_rocket_fire == false do
thread_yield()
end
-- fire rocket at stairs
helicopter_shoot_navpoint( heli.vehicle, "Nav Missile Door", true )
while M08_status.skylight_rocket_fire == false do
thread_yield()
end
-- fire rockets at skylight
helicopter_shoot_navpoint( heli.vehicle, "Nav Missile Skylight1", true )
delay( 0.5 )
helicopter_shoot_navpoint( heli.vehicle, "Nav Missile Skylight2", true )
while M08_status.heli_release == false do
thread_yield()
end
end
marker_add( heli.vehicle, MINIMAP_ICON_KILL, OI_ASSET_KILL, OI_FLAGS_FULL, SYNC_ALL)
m08_heli_release_to_ai( heli )
-- wait for the heli to be destroyed
while vehicle_exists( heli.vehicle ) == true and vehicle_is_destroyed( heli.vehicle ) == false do
thread_yield()
end
-- maybe do it again and quit
if M08_status.helis_created < M08_num_helis_to_create then
delay( 5 )
group_destroy( heli.name )
thread_yield()
M08_thread.heli1_behavior = thread_new( "m08_heli1_behavior" )
end
end
function m08_heli2_behavior()
local nav = "Nav Heli To Pool End 2"
local heli = M08_group.helis[ 2 ]
m08_heli_create_and_setup( heli )
M08_status.helis_created = M08_status.helis_created + 1
if M08_status.helis_created < 3 then
-- move into position
helicopter_fly_to_direct( heli.vehicle, 45, "NS Heli To Pool 2" )
-- orient to nav point
-- have to do this manually since the system doesn't properly support it
helicopter_fly_to_do( heli.vehicle, 45, true, "", false, nav, 0, false, false, false, false)
helicopter_fly_to_set_goal_direction( heli.vehicle, nav, true )
while vehicle_pathfind_check_done( heli.vehicle ) == 0 do
thread_yield()
end
while M08_status.helibait_rocket_fire == false do
thread_yield()
end
-- fire rockets at saints
helicopter_shoot_navpoint( heli.vehicle, "Nav Missile Saint1", true )
delay( 0.5 )
helicopter_shoot_navpoint( heli.vehicle, "Nav Missile Saint2", true )
while M08_status.heli_release == false do
thread_yield()
end
end
marker_add( heli.vehicle, MINIMAP_ICON_KILL, OI_ASSET_KILL, OI_FLAGS_FULL, SYNC_ALL)
m08_heli_release_to_ai( heli, true )
-- wait for the heli to be destroyed
while vehicle_exists( heli.vehicle ) == true and vehicle_is_destroyed( heli.vehicle ) == false do
thread_yield()
end
-- maybe do it again and quit
if M08_status.helis_created < M08_num_helis_to_create then
delay( 5 )
group_destroy( heli.name )
thread_yield()
M08_thread.heli1_behavior = thread_new( "m08_heli2_behavior" )
end
end
function m08_heli_create_and_setup( heli )
group_create( heli.name, true )
on_vehicle_destroyed( "m08_chopper_destroyed_cb", heli.vehicle )
vehicle_enter_group_teleport( heli.npcs, heli.vehicle )
turn_invulnerable( heli.npcs[ 1 ] )
turn_invulnerable( heli.npcs[ 2 ] )
set_ignore_ai_flag( heli.npcs[ 1 ], true )
set_ignore_ai_flag( heli.npcs[ 2 ], true )
teleport_vehicle( heli.vehicle, heli.start )
vehicle_disable_chase( heli.vehicle )
end
function m08_heli_release_to_ai( heli, target_remote )
helicopter_set_dont_use_constraints( heli.vehicle, true )
set_ignore_ai_flag( heli.npcs[ 1 ], false )
set_ignore_ai_flag( heli.npcs[ 2 ], false )
local target
if target_remote == true and coop_is_active() then
target = REMOTE_PLAYER
else
target = LOCAL_PLAYER
end
ai_add_enemy_target( heli.npcs[ 1 ], target, ATTACK_NOW_NEVER_LOSE, true )
ai_add_enemy_target( heli.npcs[ 2 ], target, ATTACK_NOW_NEVER_LOSE, true )
vehicle_chase( heli.vehicle, target )
end