--[[
m05.lua
SR3 Mission Script
DATE: 04-09-2010
AUTHOR: Albert McDaniel
]]--
-- Debug flags --
-- Groups --
M05_groups = {
heli_host = {
name = "m05_grp_heli_host",
heli = "m05_heli_host",
},
heli_client = {
name = "m05_grp_heli_client",
heli = "m05_heli_client",
},
pierce = {
name = "m05_grp_pierce",
heli = "m05_heli_pierce",
pierce = "m05_pierce",
},
shaundi = {
name = "m05_grp_shaundi",
shaundi = "m05_shaundi",
},
saints = {
name = "m05_grp_saints",
npcs = { "m05_saint<001>", "m05_saint<002>", "m05_saint<003>", "m05_saint<004>"},
},
party_1 = {
name = "m05_grp_party_1",
npcs = { "m05_partier_f<001>", "m05_partier_f<002>", "m05_partier_f<004>", "m05_partier_f<005>",
"m05_partier_f<006>", "m05_partier_f<007>", "m05_partier_f<008>", "m05_partier_f<009>", "m05_partier_f<010>",
"m05_partier_f<011>", "m05_partier_f<012>", "m05_partier_f<013>", "m05_partier_f<014>", "m05_partier_f<015>",
"m05_partier_f<016>", "m05_partier_f<017>", "m05_partier_f<018>", "m05_partier_f<019>", "m05_partier_f<020>",
"m05_partier_f<021>", "m05_partier_f<022>", "m05_partier_f<023>", "m05_partier_m<001>", "m05_partier_m<002>",
"m05_partier_m<003>", "m05_partier_m<004>", "m05_partier_m<005>", "m05_partier_m<006>", "m05_partier_m<007>",
"m05_partier_m<009>", "m05_partier_m<010>", "m05_partier_m<011>", "m05_partier_m<014>", },
nodes = { "Smoker", "Dancer", "Dancer", "Dancer",
"Drinker", "Drinker", "Dancer", "Drinker", "Dancer",
"Dancer", "Smoker", "Drinker", "Drinker", "Dancer",
"Drinker", "Smoker", "Dancer", "Dancer", "Smoker",
"Smoker", "Dancer", "Dancer", "Smoker", "Dancer",
"Drinker", "Drinker", "Drinker", "Drinker", "Dancer",
"Drinker", "Dancer", "Dancer", "Dancer", },
--nodes = { "p_smoke<001>", "p_dance<001>", "p_talk<001>", "p_dance<002>",
-- "p_drink<002>", "p_drink<003>", "p_dance<003>", "p_drink<004>", "p_dance<004>",
-- "p_dance<005>", "p_smoke<014>", "p_drink<006>", "p_bench<001>", "p_talk<002>",
-- "p_drink<007>", "p_smoke<002>", "p_dance<006>", "p_dance<007>", "p_smoke<003>",
-- "p_smoke<004>", "p_dance<008>", "p_dance<009>", "p_smoke<005>", "p_talk<001>",
-- "p_talk<003>", "p_drink<008>", "p_drink<009>", "p_drink<010>", "p_dance<010>",
-- "p_drink<011>", "p_talk<004>", "p_cell<001>", "p_talk<005>",
-- "p_drink<012>", "p_talk<006>", },
},
party_2 = {
name = "m05_grp_party_2",
npcs = { "m05_partier_f<025>", "m05_partier_f<027>", "m05_partier_f<028>",
"m05_partier_f<029>", "m05_partier_f<031>", "m05_partier_f<032>", "m05_partier_f<033>",
"m05_partier_f<034>", "m05_partier_f<035>", "m05_partier_m<015>", "m05_partier_m<016>",
"m05_partier_m<017>", "m05_partier_m<019>", "m05_partier_m<020>" },
nodes = { "Dancer", "Smoker", "Dancer",
"Dancer", "Smoker", "Dancer", "Dancer",
"Drinker", "Drinker", "Smoker", "Dancer",
"Dancer", "Smoker", "Dancer" },
},
guards = {
name = "m05_grp_guards",
npcs = { "m05_guard<001>", "m05_guard<002>", "m05_guard<003>", "m05_guard<004>", "m05_guard<005>",
"m05_guard<006>", "m05_guard<007>", "m05_guard<008>", "m05_guard<009>", "m05_guard<010>",
"m05_guard<011>", "m05_guard<012>", "m05_guard<013>" },
nodes = { "Drinker", "Drinker", "Smoker", "Drinker", "Drinker",
"Drinker", "Smoker", "Smoker", "Smoker", "Drinker",
"Drinker", "Drinker", "Smoker", },
},
barricade = {
name = "m05_grp_barricade",
npcs = { "m05_barr<001>", "m05_barr<002>", "m05_barr<003>", "m05_barr<004>", "m05_barr<005>",
"m05_barr<006>", "m05_barr<007>", "m05_barr<008>", "m05_barr<009>" },
script = { "m05_barr<007>", "m05_barr<003>", "m05_barr<005>", "m05_barr<004>", "m05_barr<009>", "m05_barr<001>" },
},
backup_1 = {
name = "m05_grp_backup_1",
npcs = { "m05_ms_backup<001>", "m05_ms_backup<002>", "m05_ms_backup<003>" },
},
drop_1 = {
name = "m05_grp_drop_1",
npcs = { "m05_drop<001>", "m05_drop<002>", "m05_drop<003>", "m05_drop<004>" },
},
drop_2 = {
name = "m05_grp_drop_2",
npcs = { "m05_drop<005>", "m05_drop<006>", "m05_drop<007>", "m05_drop<008>" },
},
targets = {
name = "m05_grp_targets",
npcs = { "m05_target<001>",},
nodes = { "Drinker",},
taunt = { false,},
},
elevator = {
name = "m05_grp_elevator_enemies",
npcs = {
"m05_enemy_elevator<001>", "m05_enemy_elevator<002>", "m05_enemy_elevator<003>", "m05_enemy_elevator<004>", "m05_enemy_elevator<005>",
},
destination = {
-- At the entrance of the basement
{"m05_nav_elev_enemies_01<001>", "m05_nav_elev_enemies_01<002>", "m05_nav_elev_enemies_01<003>", "m05_nav_elev_enemies_01<004>", "m05_nav_elev_enemies_01<005>"},
-- Near the elevator
{"m05_nav_elev_enemies_02<001>", "m05_nav_elev_enemies_02<002>", "m05_nav_elev_enemies_02<003>", "m05_nav_elev_enemies_02<004>", "m05_nav_elev_enemies_02<005>"},
-- Do the same again.
{"m05_nav_elev_enemies_02<001>", "m05_nav_elev_enemies_02<002>", "m05_nav_elev_enemies_02<003>", "m05_nav_elev_enemies_02<004>", "m05_nav_elev_enemies_02<005>"},
},
},
chase_host = {
name = "m05_grp_chase_host",
heli = "m05_heli_chase_host",
pilot = "m05_pilot_host",
target = "m05_target_chase_host"
},
warehouse = {
name = "m05_grp_warehouse",
},
rockets = {
name = "m05_grp_rockets",
npcs = { "m05_rocket<001>", "m05_rocket<002>", "m05_rocket<003>", "m05_rocket<004>",
"m05_rocket<005>", "m05_rocket<006>", "m05_rocket<007>", "m05_rocket<008>",
"m05_rocket<009>", "m05_rocket<010>", "m05_rocket<011>", "m05_rocket<012>", }
},
}
-- Navpoints --
M05_nav = {
start_navs = {"m05_cp_start_host", "m05_cp_start_client"},
cp_start_host = "m05_cp_start_host",
cp_start_client = "m05_cp_start_client",
cp_saints_host = "m05_cp_saints_host",
cp_saints_client = "m05_cp_saints_client",
cp_shaundi = "m05_cp_shaundi",
end_navs = {"m05_nav_end_local", "m05_nav_end_remote"},
pierce = "m05_nav_pierce",
hover_host = "m05_nav_hover_host",
hover_client = "m05_nav_hover_client",
land_host = "m05_nav_land_host",
land_client = "m05_nav_land_client",
leap_host = "m05_nav_leap_host",
leap_client = "m05_nav_leap_client",
cancel_host = "m05_nav_cancel_host",
cancel_client = "m05_nav_cancel_client",
chase_outside = "m05_nav_chase_outside",
chase_end = "m05_nav_chase_end",
guards = { "m05_nav_barr<001>", "m05_nav_barr<002>", "m05_nav_barr<003>", "m05_nav_barr<004>", "m05_nav_barr<005>", "m05_nav_barr<006>" },
backup = { "m05_nav_backup<001>", "m05_nav_backup<002>", "m05_nav_backup<003>", "m05_nav_backup<004>", "m05_nav_backup<005>" },
saints01 = { "m05_nav_saint<001>", "m05_nav_saint<002>", "m05_nav_saint<003>", "m05_nav_saint<004>" },
saints02 = { "m05_nav_saint<005>", "m05_nav_saint<006>", "m05_nav_saint<007>", "m05_nav_saint<008>" },
saints03 = { "m05_nav_saint<009>", "m05_nav_saint<010>", "m05_nav_saint<011>", "m05_nav_saint<012>" },
saints04 = { "m05_nav_saint<013>", "m05_nav_saint<014>", "m05_nav_saint<015>", "m05_nav_saint<016>" },
rockets = { "m05_nav_rocket<001>", "m05_nav_rocket<002>", "m05_nav_rocket<003>", "m05_nav_rocket<004>",
"m05_nav_rocket<005>", "m05_nav_rocket<006>", "m05_nav_rocket<007>", "m05_nav_rocket<008>",
"m05_nav_rocket<009>", "m05_nav_rocket<010>", "m05_nav_rocket<011>", "m05_nav_rocket<012>", },
flee = {"m05_party_flee_nav<001>", "m05_party_flee_nav<002>", "m05_party_flee_nav<003>"},
}
M05_paths = {
heli_host = { "m05_heli_path<001>", "m05_heli_path<002>" },
heli_client = { "m05_heli_path<001>", "m05_heli_path<002>" },
heli_drop_host = { "m05_sp_chase_host_01", "m05_sp_chase_host_02", },
heli_drop_client = { "m05_sp_chase_client_01", "m05_sp_chase_client_02", },
}
-- Triggers --
M05_triggers = {
kill = "m05_trigger_kill",
left = "m05_trigger_left",
pool = "m05_trigger_pool",
land = "m05_trigger_land",
downstairs = "m05_trigger_downstairs",
grenades = "m05_trigger_grenades",
saints = "m05_trigger_saints",
barricade = "m05_trigger_barricade",
chase = "m05_trigger_chase",
chase_end = "m05_trigger_chase_end",
warehouse = "m05_trigger_warehouse",
saints02 = "m05_trigger_saints02",
saints03 = "m05_trigger_saints03",
saints04 = "m05_trigger_saints04",
enemy_elevator = "m05_trig_enemy_elevator",
lt_pool = "m05_trigger_lt_kill",
}
-- Spawn Regions --
M05_regions = {
e_base = "m05_sr_elevator_base",
e_mid = "m05_sr_elevator_mid",
e_top = "m05_sr_elevator_top",
s_base = "m05_sr_stairs_base",
s_top = "m05_sr_stairs_top",
}
-- Spawn Groups --
M05_cspawn = {
enemy_1 = "m05_grp_cs_enemy_1",
enemy_2 = "m05_grp_cs_enemy_2",
enemy_3 = "m05_grp_cs_enemy_3",
saints_1 = "m05_grp_cs_saints_1",
saints_2 = "m05_grp_cs_saints_2",
saints_3 = "m05_grp_cs_saints_3",
}
-- Movers --
M05_movers = {
"Barrel_Mover<001>", "Barrel_Mover<002>", "Barrel_Mover<003>", "Barrel_Mover<004>",
"Barrel_Mover<005>", "Barrel_Mover<006>", "Barrel_Mover<007>", "Barrel_Mover<008>",
"Barrel_Mover<009>",
}
M05_doors = {
bathroom = "m05_door_bathroom",
bedroom = "m05_door_bedroom",
bedroom2= "m05_door_bedroom<001>",
bedroom3= "m05_door_bedroom<002>",
greenhouse = "m05_door_greenhouse",
ne1 = "m05_door_ne1",
ne2 = "m05_door_ne2",
nw1 = "m05_door_nw1",
stairs_e = "m05_door_stairs_e",
openme = "m05_door_openme",
elevator = "m05_door_elevator",
chase = "m05_door_chase",
enemy_elevator = "m05_elevator_door_mid",
}
-- persona lines --
M05_lines = {
jump = "M05_Jump",--
jump_waiting = "M05_Jump_Waiting",--
why_jump = "M05_Why_Am_I_Jumping",--
penthouse = "M05_React_To_Penthouse",--
come_get_us = "M05_Come_Get_Us",--
barrier = "M05_Barrier",--
stored_items = "M05_Comment_On_Stored_Items",--
heli_dropoff = "M05_Helicopter_Dropping_off_01",--
warehouse = "M05_Warehouse",--
}
-- Conversations --
M05_conv = {
land = {
name = "M05_Landed",--
handle = INVALID_CONVERSATION_HANDLE,
},
int1 = {
name = "M05_Interrogation_Roof",--
handle = INVALID_CONVERSATION_HANDLE,
persona = "Interrogation",
},
elevator = {
name = "M05_Elevator",--
handle = INVALID_CONVERSATION_HANDLE
},
clear_out = {
name = "M05_Clean_Out_Penthouse",--
handle = INVALID_CONVERSATION_HANDLE
},
explosive = {
name = "M05_Finding_Explosives",--
handle = INVALID_CONVERSATION_HANDLE
},
escape = {
name = "M05_Heli_Escape",--
handle = INVALID_CONVERSATION_HANDLE
},
early_chase = {
name = "M05_Early_Heli_Chase",
handle = INVALID_CONVERSATION_HANDLE
},
chase = {
name = "M05_Heli_Chase",
handle = INVALID_CONVERSATION_HANDLE
},
int2 = {
name = "M05_Warehouse_Interrogation",--
handle = INVALID_CONVERSATION_HANDLE,
persona = "Interrogation",
},
shaundi_color = {
name = "M05_Tell_Shaundi_Color",
handle = INVALID_CONVERSATION_HANDLE,
},
}
M05_persona = {
shaundi = {
name = "Shaundi",
id = INVALID_PERSONA_HANDLE
},
}
-- Threads --
M05_threads = {
nag = INVALID_THREAD_HANDLE,
chase_host = INVALID_THREAD_HANDLE,
heli_client_thread = INVALID_THREAD_HANDLE,
dist_host = INVALID_THREAD_HANDLE,
dist_client = INVALID_THREAD_HANDLE,
rockets = INVALID_THREAD_HANDLE,
elevator_spawn = INVALID_THREAD_HANDLE,
attack_line = INVALID_THREAD_HANDLE,
}
-- Checkpoints --
M05_checkpoints = {
start = MISSION_START_CHECKPOINT, -- defined in ug_lib.lua
saints = "m05_cp_saints",
chase = "m05_cp_chase",
}
-- Cutscenes --
M05_CUTSCENE_MISSION_INTRO = "05_IN"
M05_CUTSCENE_MISSION_OUTRO = "05_out"
-- Other --
M05_in_coop = false
M05_jumped = false
M05_goal_reached = false
M05_barricade_breached = false
M05_heli_arrived = false
M05_elevator_spawn_num = 0
M05_elevator_spawn_num_min = 2
M05_elevator_spawn_num_max = 4
M05_attack_line_time = 10.0
M05_dont_kill_lt = false
M05_land_call_completed = false
M05_color_call_completed = false
M05_succeeded = false
M05_chase = {
local_player_ready = false,
remote_player_ready = false,
min_dist = 20,
max_dist = 225,
min_speed = 10,
max_speed = 100,
rocket_dist = 150,
}
M05_anims = { "cheering a", "observe a", "observe b", "observe c", "ovserve E", }
-- *************************
--
-- 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
--
-- m05_checkpoint: The checkpoint the mission should begin at
-- is_restart: TRUE if the mission is restarting, FALSE otherwise
--
function m05_start(m05_cp, is_restart)
M05_in_coop = coop_is_active()
-- Make sure the screen is completly faded out
mission_start_fade_out(0.0)
spawning_vehicles( false )
spawning_pedestrians( false )
crib_disable_interface( true )
-- do this before starting the cutscene so that the cutscene doesn't think it has to turn it back off
city_zone_swap( "m05", true )
-- Check if this mission starting from the beginning
if (m05_cp == M05_checkpoints.start) then
if (is_restart == false) then
-- First time playing mission
-- Play an intro cutscene???
if (M05_CUTSCENE_MISSION_INTRO ~= "") then
cutscene_play(M05_CUTSCENE_MISSION_INTRO, nil, M05_nav.start_navs, false)
--bink_play(M05_CUTSCENE_MISSION_INTRO)
end
end
fade_out(0)
end
-- Handle mission initialization for the current checkpoint
m05_initialize(m05_cp)
-- Run the mission from the current checkpoint
m05_run(m05_cp)
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 m05_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(M05_nav.cancel_host, M05_nav.cancel_client)
-- Set up failure if the player leaves the penthouse
trigger_enable(M05_triggers.left, true)
on_trigger_exit("m05_trigger_left", M05_triggers.left)
-- Run the mission from the beginning
if current_checkpoint == M05_checkpoints.start then
-- Parachute in, find out how to let the Saints in, and do so
m05_parachute_in()
m05_get_info()
m05_let_saints_in()
-- Set the next checkpoint
current_checkpoint = M05_checkpoints.saints
mission_set_checkpoint(M05_checkpoints.saints, true)
end
if current_checkpoint == M05_checkpoints.saints then
-- Kill all remaining Morningstar
m05_clear_penthouse()
-- Kill each lieutenant
--m05_kill_lieutenant_1()
--m05_kill_lieutenant_2()
-- Set the next checkpoint
current_checkpoint = M05_checkpoints.chase
mission_set_checkpoint(M05_checkpoints.chase, true, true)
end
if current_checkpoint == M05_checkpoints.chase then
-- Chase down the last lieutenant
m05_spawn_heli()
m05_get_on_heli()
m05_chase_heli()
end
M05_succeeded = true
mission_end_success("m05", M05_CUTSCENE_MISSION_OUTRO, M05_nav.end_navs)
end
-- This is the primary function responsible for cleaning up the entire mission
-- CALLED FROM CODE
--
function m05_cleanup()
-- Stop any conversations
cleanup_conversations(M05_conv)
audio_remove_mission_cellphone(M05_conv.land.name)
audio_remove_mission_cellphone(M05_conv.early_chase.name)
audio_remove_mission_cellphone(M05_conv.chase.name)
audio_remove_mission_cellphone(M05_conv.shaundi_color.name)
helicopters_set_jitter_override(1.0, 1.0)
-- Unload personas
for i, pers in pairs(M05_persona) do
if (pers.id ~= INVALID_PERSONA_HANDLE) then
audio_persona_remove_2d(pers.id)
pers.id = INVALID_PERSONA_HANDLE
end
end
-- Stop any threads
cleanup_threads(M05_threads)
-- Clear any triggers
for i, trig in pairs(M05_triggers) do
m05_clear_trigger(trig)
end
--clear guard callbacks
cleanup_callbacks( { M05_groups, M05_triggers, M05_movers } )
-- Clean up everything left at the penthouse
m05_cleanup_penthouse()
if group_is_loaded(M05_groups.pierce.name) then
group_destroy(M05_groups.pierce.name)
end
-- Clear the rest of the groups
if group_is_loaded(M05_groups.heli_host.name) then
on_vehicle_enter("", M05_groups.heli_host.heli)
marker_remove(M05_groups.heli_host.heli)
group_destroy(M05_groups.heli_host.name)
end
if group_is_loaded(M05_groups.heli_client.name) then
on_vehicle_enter("", M05_groups.heli_client.heli)
marker_remove(M05_groups.heli_client.heli)
group_destroy(M05_groups.heli_client.name)
end
if group_is_loaded(M05_groups.chase_host.name) then
marker_remove(M05_groups.chase_host.target)
group_destroy(M05_groups.chase_host.name)
end
if group_is_loaded(M05_groups.elevator.name) then
group_destroy(M05_groups.elevator.name)
end
if group_is_loaded(M05_groups.warehouse.name) then
group_destroy(M05_groups.warehouse.name)
end
if group_is_loaded(M05_groups.rockets.name) then
group_destroy(M05_groups.rockets.name)
end
-- Clear any objective text
objective_text_clear(0)
hud_bar_off(0)
hud_bar_off(1)
hud_timer_stop(1)
-- Restore player controls
player_human_shield_lock(LOCAL_PLAYER, false)
hud_prompt_clear(LOCAL_PLAYER)
on_taunt("", LOCAL_PLAYER)
character_allow_ragdoll(LOCAL_PLAYER, true)
if (M05_in_coop) then
player_human_shield_lock(REMOTE_PLAYER, false)
hud_prompt_clear(REMOTE_PLAYER)
on_taunt("", REMOTE_PLAYER)
character_allow_ragdoll(REMOTE_PLAYER, true)
end
-- Remove costumes
-- customization_item_revert()
-- crib access is now allowed
crib_disable_interface( false )
-- Re-enable base jumping
base_jumping_enable(true)
-- Re-enable elevator triggers
trigger_type_enable( "warp", true)
-- Restore notoriety spawns
notoriety_reset("morningstar")
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_set_can_decay(true)
city_zone_swap( "m05", false )
if M05_succeeded == true then
city_zone_swap( "hq", true )
end
-- something wonky with ped spawns
-- it's spawning street peds in hq
-- so just kill them all
world_despawn_all_pedestrians()
spawning_vehicles( true )
spawning_pedestrians( true )
crib_disable_interface( false )
end
-- Called when the mission has ended with success
-- CALLED FROM CODE
--
function m05_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 m05_initialize(checkpoint)
-- Set the mission author
set_mission_author("Albert McDaniel")
-- Prevent notoriety spawns
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_can_decay(false)
-- Dress up players
-- customization_outfit_wear("Lets Pretend Male C")
-- crib access is not allowed
crib_disable_interface( true )
-- Disable Base Juming
base_jumping_enable(false)
party_dismiss_all()
-- Disable elevator triggers
trigger_type_enable( "warp", false)
-- Set up the mission based on the checkpoint
if (checkpoint == M05_checkpoints.start) then
-- Spawn Pierce's helicopter
group_create(M05_groups.pierce.name, true)
vehicle_suppress_npc_exit(M05_groups.pierce.heli, true)
vehicle_enter_teleport(M05_groups.pierce.pierce, M05_groups.pierce.heli)
helicopter_fly_to_direct(M05_groups.pierce.heli, -1, M05_nav.pierce)
vehicle_set_keyframed_physics( M05_groups.pierce.heli, true )
set_ignore_ai_flag(M05_groups.pierce.pierce, true)
set_dont_attack_me_on_sight_flag(M05_groups.pierce.pierce, true)
radio_block( M05_groups.pierce.heli )
-- Put the player(s) into the helicopter
vehicle_enter_teleport(LOCAL_PLAYER, M05_groups.pierce.heli, 5)
if (M05_in_coop == true) then
vehicle_enter_teleport(REMOTE_PLAYER, M05_groups.pierce.heli, 3)
end
-- Prevent the players from re-entering the heli
set_unjackable_flag(M05_groups.pierce.heli, true)
-- Spawn the penthouse
m05_spawn_penthouse(true, true)
-- Play Morningstar music
audio_ambient_emitter_start("M05_Morningstar_Music<001>")
for i, mover in pairs(M05_movers) do
mesh_mover_set_invulnerable(mover, true)
end
end
if (checkpoint == M05_checkpoints.saints) then
-- Teleport the players (so the resources can stream in)
teleport_coop(M05_nav.cp_saints_host, M05_nav.cp_saints_client, true)
-- Spawn the penthouse
m05_spawn_penthouse(true, false)
m05_spawn_saints(false, false)
end
if (checkpoint == M05_checkpoints.chase) then
-- Teleport the players (so the resources can stream in)
teleport_coop(M05_nav.cp_start_host, M05_nav.cp_start_client, true)
-- Spawn the penthouse
m05_spawn_penthouse(false, false)
m05_spawn_saints(true, false)
-- Spawn the heli in the correct location
group_create(M05_groups.heli_host.name, true)
teleport_vehicle(M05_groups.heli_host.heli, M05_nav.land_host)
if (M05_in_coop) then
group_create(M05_groups.heli_client.name, true)
teleport_vehicle(M05_groups.heli_client.heli, M05_nav.land_client)
end
end
-- Start fading in
mission_start_fade_in()
end
function m05_setup_guard(npc)
on_attack_performed("m05_guard_attacked", npc)
end
-- Set up and spawn everything in the penthouse
--
-- party: (bool) true if party guards should spawn
-- barricade: (bool) true if barricade guards should spawn
--
function m05_spawn_penthouse(party, barricade)
-- Set up the kill trigger for thrown NPCs
trigger_enable(M05_triggers.kill, true)
on_trigger_exit("m05_trigger_kill_zone", M05_triggers.kill)
-- Open a bunch of doors for AI
door_open(M05_doors.bathroom)
door_open(M05_doors.bedroom)
door_open(M05_doors.bedroom2)
door_open(M05_doors.bedroom3)
door_open(M05_doors.greenhouse)
door_open(M05_doors.ne1, true)
door_open(M05_doors.ne2, true)
door_open(M05_doors.nw1, true)
door_open(M05_doors.openme, true)
door_open(M05_doors.stairs_e)
door_lock(M05_doors.elevator, true)
door_lock(M05_doors.enemy_elevator, true)
-- Spawn party-goers
group_create(M05_groups.party_1.name, true)
--for i, npc in pairs(M05_groups.party_1.npcs) do
-- npc_use_closest_action_node_of_type(npc, M05_groups.party_1.nodes[i], 3)
--end
-- Enable the spawn regions
spawn_region_enable(M05_regions.e_top, true)
spawn_region_enable(M05_regions.e_mid, true)
spawn_region_enable(M05_regions.s_top, true)
spawn_region_enable(M05_regions.s_base, true)
-- Spawn the party guards
if (party) then
group_create(M05_groups.guards.name, true)
group_foreach_npc(M05_groups.guards.name, m05_setup_guard)
end
-- Spawn or hide the barricade
if (barricade) then
-- Spawn additional temporary party-goers to fill out the area
group_create(M05_groups.party_2.name, true)
-- Attach them to their action nodes.
--for i, npc in pairs(M05_groups.party_2.npcs) do
-- npc_use_closest_action_node_of_type(npc, M05_groups.party_2.nodes[i], 3)
--end
-- Spawn the first objective target
m05_spawn_target(M05_groups.targets)
-- Don't let the player grab the targets until they are actually targets, to prevent tossing them off the roof
for i, npc in pairs (M05_groups.targets.npcs) do
character_set_counter_on_grabbed_by_player(npc, true)
on_death( "m05_lt_died", npc )
end
-- set up kill zone for lt
trigger_enable(M05_triggers.lt_pool, true)
on_trigger_exit("m05_kill_lt", M05_triggers.lt_pool)
else
-- The barricade is already cleared, so hide it
for i, mover in pairs(M05_movers) do
mesh_mover_hide(mover)
end
-- Force initial notoriety
notoriety_set_min("morningstar", 2)
end
end
function m05_lt_died()
if M05_dont_kill_lt == false then
mission_end_failure( "m05", "m05_fail_lt_died" )
end
end
function m05_kill_lt( human_name, trigger_name )
if human_name == M05_groups.targets.npcs[ 1 ] and M05_dont_kill_lt == false then
trigger_enable( trigger_name, false )
on_trigger_exit( "", trigger_name )
character_kill( human_name )
-- don't knock the lt around too much bro!
mission_end_failure( "m05", "m05_fail_lt_died" )
end
end
-- Sets up and spawns the Saints reinforcements
--
-- restart: (bool) true if starting from a checkpoint
-- open: (bool) true to animate the door open
--
function m05_spawn_saints(restart, open)
-- Spawn Shaundi
group_create(M05_groups.shaundi.name, true)
on_death("m05_failure_shaundi_died", M05_groups.shaundi.shaundi)
-- Switch to the elevator spawn region
spawn_region_enable(M05_regions.s_base, false)
spawn_region_enable(M05_regions.e_base, true)
-- Enable the spawn groups
continuous_spawn_start(M05_cspawn.saints_1)
continuous_spawn_start(M05_cspawn.saints_2)
continuous_spawn_start(M05_cspawn.saints_3)
-- Open the door to let them out
door_open(M05_doors.elevator, false, open)
-- Spawn additional Saints to fill out the area
group_create(M05_groups.saints.name, true)
-- If at a checkpoint, teleport everyone; otherwise script move them
if (restart) then
-- Teleport Shaundi to the player and add her to the party
teleport(M05_groups.shaundi.shaundi, M05_nav.cp_shaundi, true)
party_add(M05_groups.shaundi.shaundi, LOCAL_PLAYER)
-- Teleport the Saints upstairs
for i, saint in pairs(M05_groups.saints.npcs) do
teleport(saint, M05_nav.saints04[i], true)
end
-- Play Saints music
audio_ambient_emitter_stop("M05_Morningstar_Music<001>")
audio_ambient_emitter_start("M05_Saints_Music<002>")
else
-- Wait for the elevator doors to open
if open then
delay(1.5)
end
-- Add Shandi to the party
party_add(M05_groups.shaundi.shaundi, LOCAL_PLAYER)
-- Send the Saints running upstairs
for i, saint in pairs(M05_groups.saints.npcs) do
ai_do_scripted_move(saint, M05_nav.saints01[i])
delay(.35)
end
trigger_enable(M05_triggers.saints02, true)
on_trigger("m05_move_saints_up02", M05_triggers.saints02)
trigger_enable(M05_triggers.saints03, true)
on_trigger("m05_move_saints_up03", M05_triggers.saints03)
trigger_enable(M05_triggers.saints04, true)
on_trigger("m05_move_saints_up04", M05_triggers.saints04)
end
end
function m05_move_saints_up02()
m05_clear_trigger(M05_triggers.saints02)
for i, saint in pairs(M05_groups.saints.npcs) do
if not character_is_dead(saint) then
ai_do_scripted_move(saint, M05_nav.saints02[i], true, true)
npc_leash_to_nav(saint, M05_nav.saints02[i], 0)
end
end
end
function m05_move_saints_up03()
m05_clear_trigger(M05_triggers.saints03)
for i, saint in pairs(M05_groups.saints.npcs) do
if not character_is_dead(saint) then
npc_leash_remove(saint)
ai_do_scripted_move(saint, M05_nav.saints03[i], true, false)
npc_leash_to_nav(saint, M05_nav.saints03[i], 0)
end
end
end
function m05_move_saints_up04()
m05_clear_trigger(M05_triggers.saints04)
for i, saint in pairs(M05_groups.saints.npcs) do
if not character_is_dead(saint) then
npc_leash_remove(saint)
ai_attack_region(saint, M05_nav.saints04[i], 8)
end
end
-- Play Saints music
audio_ambient_emitter_stop("M05_Morningstar_Music<001>")
audio_ambient_emitter_start("M05_Saints_Music<002>")
end
-- Spawn an invulnerable interrogation target
--
-- target: (table) group and name of the target to spawn
--
function m05_spawn_target(target)
-- Create the target
group_create(target.name, true)
-- Make him invulnerable and immovable until until taken hostage to force human shield
turn_invulnerable(target.npcs[1])
character_prevent_explosion_fling(target.npcs[1], true)
character_allow_ragdoll(target.npcs[1], false)
character_set_only_player_grabs(target.npcs[1], true) -- Only the player should grab
end
-- Make a group of partygoers panic!
--
-- npc_list: a list of the npcs that should panic
--
function m05_partygoers_panic(npc_list)
-- Make them all run or cower
for i, npc in pairs(npc_list) do
if character_exists(npc) then
if rand_float(0.0, 1.0) < 0.25 then
local flee_idx = rand_int(1, #M05_nav.flee)
npc_leash_remove( npc )
flee_to_navpoint(npc, M05_nav.flee[flee_idx], LOCAL_PLAYER, true)
else
cower(npc, LOCAL_PLAYER)
end
end
end
end
-- Wait until a player interrogates the target
--
-- target: (string) name of the target to interrogate
-- conv: (table) name and handle of the interrogation conversation
-- tutor: (bool) true to show the tutorial
--
function m05_interrogate(target, conv, tutor)
-- persona overriiiiiide.
if conv.persona ~= nil then
persona_override_persona_start(target, conv.persona)
end
-- Change the objective to interrogation
objective_text_clear(0)
marker_remove(target, SYNC_ALL)
objective_text(0, "M05_OBJ_INTERROGATE", "", "", SYNC_ALL, OI_ASSET_USE)
marker_add(target, MINIMAP_ICON_USE, OI_ASSET_USE, OI_FLAG_STICKY + OI_FLAG_DISPLAY_DISTANCE, SYNC_ALL)
-- Show the tutorial
if tutor then
tutorial_start("human_shield", 0, true)
end
-- Wait until a player takes the target hostage
local hostage_taken = false
local char = LOCAL_PLAYER
while not hostage_taken do
if character_has_specific_human_shield(LOCAL_PLAYER, target) then
hostage_taken = true
elseif (M05_in_coop and character_has_specific_human_shield(REMOTE_PLAYER, target)) then
hostage_taken = true
char = REMOTE_PLAYER
end
thread_yield()
end
-- Load the interrogation conversation
conv.handle = audio_conversation_load_player(conv.name, char)
-- End the tutorial
if tutor then
tutorial_advance("human_shield")
end
if target == M05_groups.chase_host.target then
hud_timer_stop(1)
end
-- make player invulnerable
turn_invulnerable( char )
-- no ragdolling
character_allow_ragdoll( char, false )
character_allow_ragdoll( target, false )
-- Block controls until the interrogation is complete
player_human_shield_lock(char, true)
delay(1)
-- play a synced interrogate animation
action_play_synced_state(char, target, "Gat Interrogation State")
action_play_synced(char, target, "Gat Interrogation Entry")
-- TODO: Play the interrogation conversation
audio_conversation_play(conv.handle)
audio_conversation_wait_for_end(conv.handle)
conv.handle = INVALID_CONVERSATION_HANDLE
action_play_synced_state(char, target, "HS_Stand")
action_play_synced(char, target, "Gat Interrogation Return")
-- Restore control
player_human_shield_lock(char, false)
action_stop_synced_state(char, true)
if conv.persona ~= nil then
persona_override_persona_stop(target)
end
-- Clear invulnerability
turn_vulnerable(target)
turn_vulnerable(char)
character_allow_ragdoll( char, true )
character_allow_ragdoll( target, true )
character_prevent_explosion_fling(target, false)
character_allow_ragdoll(target, true)
-- Clear objective
marker_remove(target, SYNC_ALL)
objective_text_clear(0)
end
-- Clean up everything in the penthouse
function m05_cleanup_penthouse()
-- Disable the kill and left triggers
on_trigger_exit("", M05_triggers.kill)
on_trigger_exit("", M05_triggers.left)
trigger_enable(M05_triggers.kill, false)
trigger_enable(M05_triggers.left, false)
-- Stop the music
audio_ambient_emitter_stop("M05_Morningstar_Music<001>")
audio_ambient_emitter_stop("M05_Saints_Music<002>")
-- Remove callbacks and markers and destroy groups
if group_is_loaded(M05_groups.shaundi.name) then
on_death("", M05_groups.shaundi.shaundi)
group_destroy(M05_groups.shaundi.name)
end
if group_is_loaded(M05_groups.party_1.name) then
group_destroy(M05_groups.party_1.name)
end
if group_is_loaded(M05_groups.party_2.name) then
group_destroy(M05_groups.party_2.name)
end
if group_is_loaded(M05_groups.guards.name) then
for i, guard in pairs(M05_groups.guards.npcs) do
on_death("", guard)
marker_remove(guard)
end
group_destroy(M05_groups.guards.name)
end
if group_is_loaded(M05_groups.barricade.name) then
group_destroy(M05_groups.barricade.name)
end
if group_is_loaded(M05_groups.backup_1.name) then
group_destroy(M05_groups.backup_1.name)
end
if group_is_loaded(M05_groups.drop_1.name) then
for i, guard in pairs(M05_groups.drop_1.npcs) do
on_vehicle_exit("", guard)
end
group_destroy(M05_groups.drop_1.name)
end
if group_is_loaded(M05_groups.drop_2.name) then
for i, guard in pairs(M05_groups.drop_2.npcs) do
on_vehicle_exit("", guard)
end
group_destroy(M05_groups.drop_2.name)
end
if group_is_loaded(M05_groups.saints.name) then
group_destroy(M05_groups.saints.name)
end
if group_is_loaded(M05_groups.targets.name) then
for i, npc in pairs(M05_groups.targets.npcs) do
marker_remove(npc)
on_death( "", npc )
end
group_destroy(M05_groups.targets.name)
end
-- Clean up spawn regions and spawn groups
for i, group in pairs(M05_cspawn) do
continuous_spawn_stop(group, true)
end
for i, reg in pairs(M05_regions) do
spawn_region_enable(reg, false)
end
end
-- Disable trigger
--
-- trigger: (string) Name of the trigger
--
function m05_clear_trigger(trigger)
on_trigger("", trigger)
trigger_enable(trigger, false)
marker_remove_trigger(trigger, SYNC_ALL)
end
-- *************************
-- OBJECTIVE: Parachute In
-- *************************
function m05_parachute_in()
-- Prevent people from attacking until the players land
notoriety_set_max("morningstar", 0)
helicopters_set_jitter_override(0.01, 0.01)
audio_object_post_event("Mission_05", "Mission_05", "M05_Power_Teaser", M05_groups.pierce.heli)
-- Display the new objective
objective_text(0, "M05_OBJ_PARACHUTE", "", "", SYNC_ALL, OI_ASSET_LOCATION)
trigger_enable(M05_triggers.pool, true)
marker_add_trigger(M05_triggers.pool, MINIMAP_ICON_LOCATION, INGAME_EFFECT_CHECKPOINT, OI_ASSET_LOCATION, OI_FLAGS_LOCATION, SYNC_ALL)
-- Prompt the players to jump
M05_jumped = false
hud_prompt(LOCAL_PLAYER, "M05_JUMP", "m05_jump_local")
player_supress_falling_scream( LOCAL_PLAYER )
if (M05_in_coop) then
hud_prompt(REMOTE_PLAYER, "M05_JUMP", "m05_jump_remote")
player_supress_falling_scream( REMOTE_PLAYER )
end
-- Play intro line
delay(2)
audio_play_persona_line(M05_groups.pierce.pierce, M05_lines.jump)
-- Set up a nag line
M05_threads.nag = thread_new("m05_nag_thread")
-- Wait for the player to jump
while not M05_jumped do
thread_yield()
end
-- Wait for the player to land
M05_goal_reached = false
trigger_enable(M05_triggers.land, true)
on_trigger("m05_land_trigger_reached", M05_triggers.land)
--play line
delay(3)
audio_play_persona_line(LOCAL_PLAYER, M05_lines.why_jump)
while not M05_goal_reached do
thread_yield()
end
objective_text_clear(0)
marker_remove_trigger(M05_triggers.pool, SYNC_ALL)
trigger_enable(M05_triggers.pool, false)
notoriety_set_max("morningstar", 5)
thread_kill(M05_threads.nag)
M05_threads.nag = INVALID_THREAD_HANDLE
helicopters_set_jitter_override(1.0, 1.0)
end
-- *************************
-- OBJECTIVE: Get Info
-- *************************
function m05_get_info()
-- Load then play the landing conversation
M05_persona.shaundi.id = audio_persona_load_2d(M05_persona.shaundi.name)
--M05_conv.land.handle = audio_conversation_load(M05_conv.land.name)
delay(4)
M05_land_call_completed = false
audio_play_for_mission_cellphone(M05_conv.land.name, false, true, "", "m05_land_call_finished_cb")
--audio_conversation_play(M05_conv.land.handle)
--audio_conversation_wait_for_end(M05_conv.land.handle)
--M05_conv.land.handle = INVALID_CONVERSATION_HANDLE
while (M05_land_call_completed == false) do
thread_yield()
end
-- Wait until a player interrogates the target
M05_dont_kill_lt = true
character_set_counter_on_grabbed_by_player(M05_groups.targets.npcs[1], false)
m05_interrogate(M05_groups.targets.npcs[1], M05_conv.int1, true)
-- it's ok to lose the lt now
trigger_enable(M05_triggers.lt_pool, false)
on_trigger_exit("", M05_triggers.lt_pool)
-- Display the new objective
objective_text(0, "M05_OBJ_KILL_LIEUTENANT", "", "", SYNC_ALL, OI_ASSET_KILL)
marker_add(M05_groups.targets.npcs[1], MINIMAP_ICON_KILL, OI_ASSET_KILL_FULL, OI_FLAGS_FULL, SYNC_ALL)
-- Display the throw Human Shield tutorial
tutorial_start("throw_kill", 0, true)
-- Run or hide.
m05_partygoers_panic(M05_groups.party_1.npcs)
m05_partygoers_panic(M05_groups.party_2.npcs)
-- Wait until the lieutenant is thrown
while (character_has_specific_human_shield(LOCAL_PLAYER, M05_groups.targets.npcs[1]) or (M05_in_coop and character_has_specific_human_shield(REMOTE_PLAYER, M05_groups.targets.npcs[1]))) do
thread_yield()
end
tutorial_advance("throw_kill")
-- Make sure the throw kills the lieutenant
delay(2.5)
marker_remove(M05_groups.targets.npcs[1], SYNC_ALL)
if not character_is_dead(M05_groups.targets.npcs[1]) then
character_kill(M05_groups.targets.npcs[1], true)
end
-- Release him and the partiers so we can spawn more guards
release_to_world(M05_groups.targets.name)
release_to_world(M05_groups.party_2.name)
release_to_world(M05_groups.party_1.name)
audio_play_persona_line(LOCAL_PLAYER, M05_lines.penthouse)
objective_text_clear(0)
end
-- *************************
-- OBJECTIVE: Let the Saints in
-- *************************
function m05_let_saints_in()
-- Head to the basement to let your homies in
objective_text(0, "M05_OBJ_BASEMENT", "", "", SYNC_ALL, OI_ASSET_LOCATION)
-- Make the enemies hostile
notoriety_set_min("morningstar", 2)
--continuous_spawn_start(M05_cspawn.enemy_1)
--continuous_spawn_start(M05_cspawn.enemy_2)
--continuous_spawn_start(M05_cspawn.enemy_3)
M05_goal_reached = false
trigger_enable(M05_triggers.downstairs, true)
marker_add_trigger(M05_triggers.downstairs, MINIMAP_ICON_LOCATION, "", OI_ASSET_LOCATION, OI_FLAGS_LOCATION, SYNC_ALL)
on_trigger("m05_trigger_reached", M05_triggers.downstairs)
while not M05_goal_reached do
thread_yield()
end
objective_text_clear(0)
-- Spawn the barricade guards
group_create(M05_groups.barricade.name, true)
-- Turn on the trigger to detect when the player enters the barricade room
M05_barricade_breached = false
trigger_enable(M05_triggers.barricade, true)
on_trigger("m05_barricade_triggered", M05_triggers.barricade)
--== WAYPOINT ==--
-- Display the new objective
objective_text(0, "M05_OBJ_GRENADES", "", "", SYNC_ALL, OI_ASSET_USE)
M05_goal_reached = false
trigger_enable(M05_triggers.grenades, true)
marker_add_trigger(M05_triggers.grenades, MINIMAP_ICON_USE, "", OI_ASSET_USE, OI_FLAGS_LOCATION, SYNC_ALL)
on_trigger("m05_trigger_reached", M05_triggers.grenades)
delay(3)
audio_play_persona_line(LOCAL_PLAYER, M05_lines.barrier)
-- Wait until the player picks up the grenades
while M05_goal_reached == false and M05_barricade_breached == false do
thread_yield()
end
if game_is_active_input_gamepad() then
tutorial_start("combat_grenades", 0, true)
else
tutorial_start("combat_grenades_pc", 0, true)
end
objective_text_clear(0)
--== WAYPOINT ==--
-- Display the new objective
objective_text(0, "M05_OBJ_BARRIER", "", "", SYNC_ALL, OI_ASSET_KILL)
marker_add(M05_movers[1], MINIMAP_ICON_KILL, OI_ASSET_KILL_FULL, OI_FLAGS_FULL, SYNC_ALL)
-- Make the barricade vulnerable
for i, mover in pairs(M05_movers) do
mesh_mover_set_invulnerable(mover, false)
end
-- Wait until the player kills a mover
while m05_barricade_destroyed() == false and M05_barricade_breached == false do
thread_yield()
end
explosion_create( "Barrel Exp", M05_movers[ 1 ], LOCAL_PLAYER )
marker_remove(M05_movers[1])
tutorial_advance("combat_grenades")
tutorial_advance("combat_grenades_pc")
objective_text_clear(0)
--== WAYPOINT ==--
delay(2)
audio_play_persona_line(LOCAL_PLAYER, M05_lines.stored_items)
-- Display the new objective
objective_text(0, "M05_OBJ_LET_IN_SAINTS", "", "", SYNC_ALL, OI_ASSET_USE)
-- Wait until the player activates the elevator
M05_goal_reached = false
trigger_enable(M05_triggers.saints, true)
marker_add_trigger(M05_triggers.saints, MINIMAP_ICON_USE, INGAME_EFFECT_CHECKPOINT, OI_ASSET_USE, OI_FLAGS_LOCATION, SYNC_ALL)
on_trigger("m05_trigger_reached", M05_triggers.saints)
while not M05_goal_reached do
thread_yield()
end
objective_text_clear(0)
objective_text(0, "M05_OBJ_WAIT_FOR_SAINTS", "", "", SYNC_ALL, OI_ASSET_DEFEND)
-- Stop enemy continuous spawns
continuous_spawn_stop(M05_cspawn.enemy_1)
continuous_spawn_stop(M05_cspawn.enemy_2)
--continuous_spawn_stop(M05_cspawn.enemy_3)
-- Done with the barricade guards; release them to free up ped instances
release_to_world(M05_groups.barricade.name)
-- Spawn backup and have them rush downstairs
group_create(M05_groups.backup_1.name, true)
for i, npc in pairs(M05_groups.backup_1.npcs) do
ai_do_scripted_move(npc, M05_nav.backup[i])
end
-- Load and play the elevator conversation
M05_conv.elevator.handle = audio_conversation_load(M05_conv.elevator.name)
audio_conversation_play(M05_conv.elevator.handle)
-- Play the elevator sound for 10 seconds
local aid = audio_object_post_event("Misc_SFX", "Misc_SFX", "Elevator_Motor", M05_doors.elevator)
delay(15)
audio_stop(aid)
audio_conversation_wait_for_end(M05_conv.elevator.handle)
M05_conv.elevator.handle = INVALID_CONVERSATION_HANDLE
if (M05_persona.shaundi.id ~= INVALID_PERSONA_HANDLE) then
audio_persona_remove_2d(M05_persona.shaundi.id)
M05_persona.shaundi.id = INVALID_PERSONA_HANDLE
end
-- Spawn the Saints and open the door
delay(2)
m05_spawn_saints(false, true)
-- Done with the backup guards; release them to free up ped instances
release_to_world(M05_groups.backup_1.name)
end
function m05_barricade_destroyed()
for i, m in pairs( M05_movers ) do
if mesh_mover_destroyed( m ) == true then
return true
end
end
return false
end
-- *************************
-- OBJECTIVE: Clear Penthouse
-- *************************
function m05_release_group( group )
if group_is_loaded( group.name ) then
for i, npc in pairs( group.npcs ) do
if character_exists( npc ) then
marker_remove( npc, SYNC_ALL )
end
end
release_to_world( group.name )
end
end
function m05_clear_penthouse()
-- Kill all remaining Morningstar
objective_text_clear(0)
objective_text(0, "M05_OBJ_CLEAR_AREA", "", "", SYNC_ALL, OI_ASSET_KILL)
-- Mark any left alive
for i, guard in pairs(M05_groups.guards.npcs) do
if (character_exists(guard) and not character_is_dead(guard)) then
on_death("m05_enemy_killed", guard)
marker_add(guard, MINIMAP_ICON_KILL, OI_ASSET_KILL)
end
end
-- Start bringing guys in on the elevator.
M05_threads.elevator_spawn = thread_new("m05_elevator_spawn_thread")
-- Load and play the clear area conversation
M05_conv.clear_out.handle = audio_conversation_load(M05_conv.clear_out.name)
audio_conversation_play(M05_conv.clear_out.handle)
audio_conversation_wait_for_end(M05_conv.clear_out.handle)
M05_conv.clear_out.handle = INVALID_CONVERSATION_HANDLE
-- Wait until only a few are left
local num_targets = m05_get_num_remaining_targets()
while (num_targets > 4) do
thread_yield()
num_targets = m05_get_num_remaining_targets()
end
-- Send the heli to land on the heli pad
M05_threads.chase_host = thread_new("m05_land_thread", M05_groups.heli_host, M05_nav.land_host, M05_paths.heli_drop_host, M05_groups.drop_1, 0)
-- Tell the player about them
audio_play_persona_line(M05_groups.shaundi.shaundi, M05_lines.heli_dropoff)
-- Repeat for co-op
if (M05_in_coop) then
M05_threads.heli_client_thread = thread_new("m05_land_thread", M05_groups.heli_client, M05_nav.land_client, M05_paths.heli_drop_client, M05_groups.drop_2, 10)
end
-- Wait until all are defeated
while (m05_get_num_remaining_targets() > 0) or (M05_elevator_spawn_num < M05_elevator_spawn_num_min) do
thread_yield()
end
-- Done with all guards; release them to free up ped instances
m05_release_group( M05_groups.elevator )
m05_release_group( M05_groups.guards )
m05_release_group( M05_groups.drop_1 )
if (M05_in_coop) then
m05_release_group( M05_groups.drop_2 )
end
objective_text_clear(0)
-- Load and play the explosive conversation
M05_conv.explosive.handle = audio_conversation_load(M05_conv.explosive.name)
audio_conversation_play(M05_conv.explosive.handle)
audio_conversation_wait_for_end(M05_conv.explosive.handle)
M05_conv.explosive.handle = INVALID_CONVERSATION_HANDLE
-- Make sure all the markers get removed, then kill the thread.
marker_remove_script_group(M05_groups.elevator.name)
thread_kill(M05_threads.elevator_spawn)
M05_threads.elevator_spawn = INVALID_THREAD_HANDLE
end
-- *************************
-- OBJECTIVE: Chase the final lieutenant
-- *************************
-- Spawn the final lieutenant
--
function m05_spawn_heli()
-- Create the heli group
group_create(M05_groups.chase_host.name, true)
-- Set the target as immovable until until taken hostage to force human shield
character_set_only_player_grabs(M05_groups.chase_host.target, true) -- Only the player should grab
character_prevent_explosion_fling(M05_groups.chase_host.target, true)
character_allow_ragdoll(M05_groups.chase_host.target, false)
-- Put everyone in the heli
vehicle_enter_teleport(M05_groups.chase_host.pilot, M05_groups.chase_host.heli, 0, true)
vehicle_enter_teleport(M05_groups.chase_host.target, M05_groups.chase_host.heli, 1, true)
-- Set both the pilot and target as invulnerable and turn off their AI to prevent accidents
vehicle_set_invulnerable(M05_groups.chase_host.heli)
turn_invulnerable(M05_groups.chase_host.pilot)
turn_invulnerable(M05_groups.chase_host.target)
set_ignore_ai_flag(M05_groups.chase_host.pilot, true)
set_ignore_ai_flag(M05_groups.chase_host.target, true)
set_unjackable_flag(M05_groups.chase_host.heli, true)
-- Tell the helicopter to take off (must do this immediately or it falls)
thread_kill(M05_threads.chase_host)
M05_threads.chase_host = thread_new("m05_fly_to_thread", M05_groups.chase_host.heli, M05_nav.hover_host)
-- Disable the kill trigger, since we're leaving it
on_trigger_exit("", M05_triggers.kill)
trigger_enable(M05_triggers.kill, false)
end
-- Chase the final lieutenant
--
function m05_get_on_heli()
-- Direct the player to the helicopter
M05_goal_reached = false
trigger_enable(M05_triggers.chase, true)
on_trigger("m05_trigger_reached", M05_triggers.chase)
-- Display the new objective
objective_text(0, "M05_OBJ_GET_TO_HELI", "", "", SYNC_ALL, OI_ASSET_USE)
-- Start a thread to update the distance bar
M05_threads.dist_host = thread_new("m05_chase_distance", M05_groups.chase_host.heli, SYNC_LOCAL)
if (M05_in_coop) then
M05_threads.dist_client = thread_new("m05_chase_distance", M05_groups.chase_host.heli, SYNC_REMOTE)
end
-- Unlock and mark the helis
on_vehicle_enter("m05_heli_entered", M05_groups.heli_host.heli)
set_unjackable_flag(M05_groups.heli_host.heli, false)
vehicle_max_speed(M05_groups.heli_host.heli, -1)
marker_add(M05_groups.heli_host.heli, MINIMAP_ICON_USE, OI_ASSET_USE, OI_FLAGS_LOCATION, SYNC_ALL)
if group_is_loaded(M05_groups.heli_client.name) then
on_vehicle_enter("m05_heli_entered", M05_groups.heli_client.heli)
set_unjackable_flag(M05_groups.heli_client.heli, false)
vehicle_max_speed(M05_groups.heli_client.heli, -1)
marker_add(M05_groups.heli_client.heli, MINIMAP_ICON_USE, OI_ASSET_USE, OI_FLAGS_LOCATION, SYNC_ALL)
end
-- Load and play the helicopter escape conversation
M05_conv.escape.handle = audio_conversation_load(M05_conv.escape.name)
audio_conversation_play(M05_conv.escape.handle)
-- Wait until the player gets to the helipad
while not M05_goal_reached do
thread_yield()
end
-- Leave Shaundi behind
party_dismiss(M05_groups.shaundi.shaundi)
on_death("", M05_groups.shaundi.shaundi)
end
-- Play the heli cutscene
--function m05_setup_leap()
-- -- Put the player(s) in the right spot
-- teleport_coop(M05_nav.leap_host, M05_nav.leap_client, true)
--end
-- Start the leap-onto-heli QTE sequence
--
--function m05_start_leap()
-- -- Start the QTE
-- M05_qte_complete = 0
-- qte_start(LOCAL_PLAYER, "m05_leap", "m05_qte_completed")
-- if (M05_in_coop == true) then
-- M05_qte_complete = -1
-- qte_start(REMOTE_PLAYER, "m05_leap", "m05_qte_completed_coop")
-- end
--
-- -- Loop until the QTE is complete (on both clients)
-- while (M05_qte_complete < 1) do
-- thread_yield()
-- end
--end
function m05_thread_lt_flee_to_warehouse()
-- Send the target up to the building and wait for streaming (force run, no shooting)
ai_do_scripted_move(M05_groups.chase_host.target, M05_nav.chase_outside, true, false)
npc_leash_to_nav(M05_groups.chase_host.target, M05_nav.chase_outside, 0)
while not M05_goal_reached do
thread_yield()
end
door_open(M05_doors.chase)
-- Send the target into the building (force run, no shooting)
npc_leash_remove(M05_groups.chase_host.target)
repeat
ai_clear_scripted_action( M05_groups.chase_host.target )
ai_do_scripted_move(M05_groups.chase_host.target, M05_nav.chase_end, true, false)
while ai_scripted_action_is_processing(M05_groups.chase_host.target) do
thread_yield()
end
thread_yield()
until get_dist( M05_groups.chase_host.target, M05_nav.chase_end ) < 2 or character_is_dead( M05_groups.chase_host.target ) == true
if character_is_dead( M05_groups.chase_host.target ) == false then
npc_leash_to_nav(M05_groups.chase_host.target, M05_nav.chase_end, 3)
end
set_animation_state(M05_groups.chase_host.target, "cower stand")
end
-- Start the heli chase sequence
--
function m05_chase_heli()
-- Start the thread to send the heli to the final building
M05_chase.local_player_ready = false
M05_chase.remote_player_ready = false
M05_heli_arrived = false
spawning_vehicles( true )
spawning_pedestrians( true )
-- let it reach the hover navpoint first.
while get_dist(M05_groups.chase_host.heli, M05_nav.hover_host) > 10 do
thread_yield()
end
thread_kill(M05_threads.chase_host)
M05_threads.chase_host = thread_new("m05_chase_thread", M05_groups.chase_host, M05_paths.heli_host, M05_nav.hover_host)
-- Set up the rocket guys
group_create(M05_groups.rockets.name, true)
M05_threads.rockets = thread_new("m05_rockets_thread")
-- Enable the destination trigger so we know when the crib is streamed in
M05_goal_reached = false
trigger_enable(M05_triggers.chase_end, true)
on_trigger("m05_trigger_reached", M05_triggers.chase_end)
-- Enable the warehouse trigger so we know when the player enters it
trigger_enable(M05_triggers.warehouse, true)
on_trigger("m05_warehouse_reached", M05_triggers.warehouse)
delay(25)
--play a conversation
M05_persona.shaundi.id = audio_persona_load_2d(M05_persona.shaundi.name)
audio_play_for_mission_cellphone(M05_conv.early_chase.name, false, true, "", "")
-- Wait until the heli has arrived at its destination
while not M05_heli_arrived do
thread_yield()
end
-- Kill the distance update thread
thread_kill(M05_threads.dist_host)
M05_threads.dist_host = INVALID_THREAD_HANDLE
if (M05_threads.dist_client ~= INVALID_THREAD_HANDLE) then
thread_kill(M05_threads.dist_client)
M05_threads.dist_client = INVALID_THREAD_HANDLE
end
hud_bar_off(0)
hud_bar_off(1)
-- Load and play the helicopter chase conversation
--M05_conv.chase.handle = audio_conversation_load(M05_conv.chase.name)
--audio_conversation_play(M05_conv.chase.handle)
audio_play_for_mission_cellphone(M05_conv.chase.name, true, true, "", "")
-- Set a fail timer
hud_timer_set(1, 180000, "m05_fail_timer", SYNC_ALL)
thread_kill(M05_threads.chase_host)
M05_threads.chase_host = thread_new( "m05_thread_lt_flee_to_warehouse" )
while not M05_goal_reached do
thread_yield()
end
trigger_enable(M05_triggers.chase_end, false)
on_trigger("", M05_triggers.chase_end)
-- Create the guards
group_create(M05_groups.warehouse.name, false)
-- Wait for the player to interrogate the target
m05_interrogate(M05_groups.chase_host.target, M05_conv.int2, false)
-- Display the new objective
-- hud_timer_stop(1)
objective_text(0, "M05_OBJ_KILL_LIEUTENANT", "", "", SYNC_ALL, OI_ASSET_KILL)
marker_add(M05_groups.chase_host.target, MINIMAP_ICON_KILL, OI_ASSET_KILL_FULL, OI_FLAGS_FULL, SYNC_ALL)
-- Display the execute Human Shield tutorial
tutorial_start("quick_kill", 0, true)
-- Wait until the lieutenant is dead
while not character_is_dead(M05_groups.chase_host.target) do
thread_yield()
end
thread_kill(M05_threads.chase_host)
marker_remove(M05_groups.chase_host.target, SYNC_ALL)
tutorial_advance("quick_kill")
objective_text_clear(0)
M05_color_call_completed = false
audio_play_for_mission_cellphone(M05_conv.shaundi_color.name, false, true, "", "m05_color_call_finished_cb")
while (M05_color_call_completed == false) do
thread_yield()
end
delay(2)
end
-- *************************
--
-- Callback functions
--
-- *************************
function m05_guard_attacked(name,weapon,attack)
local line = "M05_Attack"
if (not thread_check_done(M05_threads.attack_line)) then
return
end
-- start timer
M05_threads.attack_line = thread_new("delay", M05_attack_line_time)
-- play line
if not audio_play_persona_line(name, line) then
-- line didn't play, kill our timer
thread_kill(M05_threads.attack_line)
M05_threads.attack_line = INVALID_THREAD_HANDLE
end
end
-- Catch the local player jumping
function m05_jump_local()
hud_prompt_clear(LOCAL_PLAYER)
vehicle_exit(LOCAL_PLAYER)
M05_jumped = true
end
-- Catch the remote player jumping
function m05_jump_remote()
hud_prompt_clear(REMOTE_PLAYER)
vehicle_exit(REMOTE_PLAYER)
M05_jumped = true
end
-- Kill anyone who leaves the penthouse
function m05_trigger_kill_zone(human_name, trigger_name)
-- Don't kill players or characters in vehicles
if (human_name ~= nil) and ((not character_is_player(human_name)) and (not character_is_in_vehicle(human_name))) then
-- Override invulnerability
character_kill(human_name, true)
end
end
-- Trigger if a player leaves the penthouse
function m05_trigger_left(human_name, trigger_name)
if (character_is_player(human_name)) then
-- If the player is in a script heli, they're allowed to leave
local v_name = get_char_vehicle_name(human_name)
if ((v_name == M05_groups.heli_host.heli) or (v_name == M05_groups.heli_client.heli)) then
-- The player has left the penthouse, so it can now be cleaned up
audio_conversation_wait_for_end(M05_conv.escape.handle)
M05_conv.escape.handle = INVALID_CONVERSATION_HANDLE
m05_cleanup_penthouse()
else
-- Not allowed to leave, yet, so fail
mission_end_failure("m05", "m05_fail_left")
end
end
end
-- Catch when the player taunts and advance the mission accordingly
function m05_taunted(char)
-- Find which target was taunted, keeping count of the number taunted thus-far
local num_taunted = 0
local target = nil
for i, npc in pairs(M05_groups.targets.npcs) do
if (M05_groups.targets.taunt[i]) then
-- This target has already been taunted
num_taunted = num_taunted + 1
else
-- Check if the player is within the threshold distance of this target
if (get_dist(char, npc) < 3) then
-- This guy has now been taunted
target = npc
marker_remove(target)
M05_groups.targets.taunt[i] = true
num_taunted = num_taunted + 1
end
end
end
-- Once the 3rd guy is taunted, move on; until then return
if (num_taunted < 3) then
-- TODO: Play a response/prompt to move on?
return
end
on_taunt("", LOCAL_PLAYER)
if (M05_in_coop) then
on_taunt("", REMOTE_PLAYER)
end
-- This guy knows something; remove other potential targets and wait until a player interrogates this one
for i, npc in pairs (M05_groups.targets.npcs) do
character_set_counter_on_grabbed_by_player(npc, false)
marker_remove(npc)
end
m05_interrogate(target, M05_conv.int1, true)
-- Allow the players to kill the interrogation targets now.
for i, npc in pairs(M05_groups.targets.npcs) do
on_death("", npc)
end
-- Display the new objective
objective_text(0, "M05_OBJ_KILL_LIEUTENANT", "", "", SYNC_ALL, OI_ASSET_KILL)
marker_add(target, MINIMAP_ICON_KILL, OI_ASSET_KILL_FULL, OI_FLAGS_FULL, SYNC_ALL)
-- Display the throw Human Shield tutorial
tutorial_start("throw_kill", 0, true)
-- Wait until the target is thrown
while (character_has_specific_human_shield(LOCAL_PLAYER, target) or (M05_in_coop and character_has_specific_human_shield(REMOTE_PLAYER, target))) do
thread_yield()
end
tutorial_advance("throw_kill")
-- Make sure the throw kills the lieutenant
delay(2.5)
marker_remove(target, SYNC_ALL)
if not character_is_dead(target) then
character_kill(target, true)
end
-- Allow the mission to advance
M05_goal_reached = true
end
-- Reached the basement barricade
function m05_barricade_triggered(char, trig)
M05_barricade_breached = true
m05_clear_trigger(trig)
persona_override_persona_start(M05_groups.barricade.script[1], "Interrogation")
audio_play_persona_line(M05_groups.barricade.script[1], M05_lines.come_get_us)
for i, guard in pairs(M05_groups.barricade.script) do
ai_do_scripted_move(guard, M05_nav.guards[i])
delay(.35)
end
delay(2)
persona_override_persona_stop(M05_groups.barricade.script[1])
end
--hit the land trigger
function m05_land_trigger_reached(char, trig)
--put party-goers in their action nodes
for i, npc in pairs(M05_groups.party_1.npcs) do
if not character_is_dead(npc) then
npc_use_closest_action_node_of_type(npc, M05_groups.party_1.nodes[i], 3)
end
end
for i, npc in pairs(M05_groups.party_2.npcs) do
if not character_is_dead(npc) then
npc_use_closest_action_node_of_type(npc, M05_groups.party_2.nodes[i], 3)
end
end
for i, npc in pairs(M05_groups.guards.npcs) do
if not character_is_dead(npc) then
npc_use_closest_action_node_of_type(npc, M05_groups.guards.nodes[i], 3)
end
end
npc_use_closest_action_node_of_type(M05_groups.targets.npcs[ 1 ], M05_groups.targets.nodes[ 1 ], 3)
m05_clear_trigger(trig)
M05_goal_reached = true
end
-- The next trigger has been activated
function m05_trigger_reached(char, trig)
m05_clear_trigger(trig)
M05_goal_reached = true
end
-- The next door has been opened
function m05_door_opened(door)
marker_remove(door)
on_door_opened("", door)
M05_goal_reached = true
end
function m05_failure_shaundi_died()
-- End the mission, Shaundi died
mission_end_failure("m05", "m01_failure_shaundi_died")
end
function m05_fail_timer()
-- End the mission, time ran out
mission_end_failure("m05", "m05_fail_time")
end
-- When one of the guys you're supposed to taunt is killed.
function m05_tauntee_killed(victim, attacker)
on_death("", victim)
marker_remove(victim)
mission_end_failure("m05", "m12_failure_cover_blown")
end
-- Display the grenade tutorial
function m05_enemy_killed(victim, attacker)
on_death("", victim)
marker_remove(victim)
end
-- Turn the pilot vulnerable upon exiting the heli
function m05_pilot_exit(human, vehicle, index)
on_vehicle_exit("", human)
turn_vulnerable(human)
end
-- A player has entered a heli to start the chase sequence
function m05_heli_entered(player, vehicle, seat)
-- remove the marker for this heli for both players
marker_remove(vehicle, SYNC_ALL)
vehicle_set_vulnerable(vehicle)
vehicle_prevent_explosion_fling(vehicle, false)
-- if we haven't changed objectives yet, do it now
if M05_chase.remote_player_ready == false and M05_chase.local_player_ready == false then
objective_text(0, "M05_OBJ_CHASE_HELI", "", "", SYNC_ALL, OI_ASSET_LOCATION)
marker_add(M05_groups.chase_host.target, MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION, OI_FLAGS_LOCATION, SYNC_ALL)
end
-- remove the marker from the other heli for this player only
if coop_is_active() then
local other_heli = M05_groups.heli_client.heli
if vehicle == other_heli then
other_heli = M05_groups.heli_host.heli
end
local sync = SYNC_LOCAL
if player == REMOTE_PLAYER then
sync = SYNC_REMOTE
end
marker_remove( other_heli, sync )
end
-- mark this player as ready to chase
if (player == LOCAL_PLAYER) then
M05_chase.local_player_ready = true
elseif (player == REMOTE_PLAYER) then
M05_chase.remote_player_ready = true
end
vehicle_max_speed( vehicle, -1 )
end
-- The player entered the warehouse
function m05_warehouse_reached(char, trig)
m05_clear_trigger(trig)
audio_conversation_wait_for_end(M05_conv.chase.handle)
M05_conv.chase.handle = INVALID_CONVERSATION_HANDLE
audio_play_persona_line(LOCAL_PLAYER, M05_lines.warehouse)
end
-- See how many targets remain in the "let in saints" objective.
--
function m05_get_num_remaining_targets()
local num_enemies = 0
if group_is_loaded(M05_groups.elevator.name) then
num_enemies = num_enemies + group_members_alive(M05_groups.elevator.name)
end
if group_is_loaded(M05_groups.guards.name) then
num_enemies = num_enemies + group_members_alive(M05_groups.guards.name)
end
if group_is_loaded(M05_groups.drop_1.name) then
num_enemies = num_enemies + group_members_alive(M05_groups.drop_1.name)
end
if group_is_loaded(M05_groups.drop_2.name) then
num_enemies = num_enemies + group_members_alive(M05_groups.drop_2.name)
end
return num_enemies
end
function m05_land_call_finished_cb()
M05_land_call_completed = true
end
function m05_color_call_finished_cb()
M05_color_call_completed = true
end
-- *************************
--
-- Thread functions
--
-- *************************
-- Spawn in new bad guys periodically until all bad guys are dead.
--
function m05_elevator_spawn_thread()
local done_spawning = false
M05_elevator_spawn_num = 0
while not done_spawning do
group_create(M05_groups.elevator.name, true)
while not group_is_loaded(M05_groups.elevator.name) do
thread_yield()
end
for i, guard in pairs(M05_groups.elevator.npcs) do
if (character_exists(guard) and not character_is_dead(guard)) then
on_death("m05_enemy_killed", guard)
marker_add(guard, MINIMAP_ICON_KILL, OI_ASSET_KILL)
ai_set_personality(guard, "gang defensive")
end
end
delay(2.0)
door_open(M05_doors.enemy_elevator, false)
delay(2.0)
-- If we have a destination list, use that.
local dest_list = M05_groups.elevator.destination[M05_elevator_spawn_num + 1]
if dest_list ~= nil then
for i, guard in pairs(M05_groups.elevator.npcs) do
if (character_exists(guard) and not character_is_dead(guard)) then
local idx = (i % #dest_list) + 1
local dest_nav = dest_list[idx]
if (dest_nav ~= nil) then
ai_do_scripted_move(guard, dest_nav, true, false)
end
end
end
end
-- don't close the door until the elevator is empty.
-- Need to find out if this will return dead humans... would be a problem if it does.
while (get_num_humans_in_trigger(M05_triggers.enemy_elevator) > 0) do
delay(1.0)
end
while true do
door_close(M05_doors.enemy_elevator)
delay( 3 )
if get_num_humans_in_trigger(M05_triggers.enemy_elevator) == 0 then
break
end
door_open(M05_doors.enemy_elevator, false)
delay( 3 )
end
while group_is_loaded(M05_groups.elevator.name) and group_members_alive(M05_groups.elevator.name) > 0 do
thread_yield()
end
-- Make sure all the markers get removed.
marker_remove_script_group(M05_groups.elevator.name)
delay(5.0)
-- Release the (now dead) group so you can create it again.
if group_is_loaded(M05_groups.elevator.name) then
release_to_world(M05_groups.elevator.name)
end
-- Run no less than 3 times, no more than 5.
M05_elevator_spawn_num = M05_elevator_spawn_num + 1
if ((m05_get_num_remaining_targets() == 0 and M05_elevator_spawn_num >= M05_elevator_spawn_num_min) or M05_elevator_spawn_num >= M05_elevator_spawn_num_max) then
done_spawning = true
end
end
end
-- Nag the player to get out of the heli
function m05_nag_thread()
-- Wait before nagging
delay(20)
-- If either player is in a vehicle, nag them
if (character_is_in_vehicle(LOCAL_PLAYER) or (M05_in_coop and character_is_in_vehicle(REMOTE_PLAYER))) then
audio_play_persona_line(M05_groups.pierce.pierce, M05_lines.jump_waiting)
end
end
-- Fly a helicopter to a specified point
--
-- heli: (string) name of the helicotper to move
-- nav: (string) name of the navpoint to move to
--
function m05_fly_to_thread(heli, nav)
while true do
helicopter_fly_to_direct(heli, -1, nav)
thread_yield()
end
end
-- Fly a helicopter to a specified point then land
function m05_land_thread(heli_group, landing_nav, sp, npc_group, delay_time)
local heli = heli_group.heli
local npc_list = npc_group.npcs
delay( delay_time )
-- Spawn the reinforcements in a heli
group_create_hidden(heli_group.name, true)
group_create_hidden(npc_group.name, true)
vehicle_set_invulnerable(heli)
vehicle_prevent_explosion_fling(heli, true)
vehicle_enter_group_teleport(npc_list, heli)
vehicle_suppress_npc_exit( heli, true )
-- Mark them as required kills
for i, guard in pairs(npc_list) do
on_death("m05_enemy_killed", guard)
-- Make them come right at the player.
set_always_sees_player_flag(guard, true)
ai_set_personality(guard, "gang offensive")
marker_add(guard, MINIMAP_ICON_KILL, OI_ASSET_KILL)
end
-- Make the heli unenterable by the player.
set_unjackable_flag(heli, true)
-- Make sure the pilot is invulnerable until the heli lands
local pilot = vehicle_get_driver(heli)
turn_invulnerable(pilot)
on_vehicle_exit("m05_pilot_exit", pilot)
group_show( heli_group.name )
group_show( npc_group.name )
vehicle_max_speed(heli, 30)
set_ignore_ai_flag( pilot, true )
helicopter_fly_to_direct( heli, 30, sp[ 1 ] )
-- Land at the navpoint and drop off all NPCs
helicopter_fly_to_do( heli, 5, true, "", false, sp[ 2 ] )
local emergency_exit = false
local frames_close = 0
-- Wait until either the chopper comes to a stop or hits the deck.
while get_char_vehicle_is_in_air( pilot ) == true and not emergency_exit do
thread_yield()
-- emergency plan in case we don't 'land' (bug 41980)
if get_dist(heli, landing_nav) < 2.0 then
-- we are pretty close
frames_close = frames_close + 1
if frames_close > 60 then
-- we have been close for like 2 seconds and we are still here? Abort! (expected values are in the 3-5 range)
emergency_exit = true
end
end
end
-- Stop the pathfind.
helicopter_fly_to_stop( heli )
delay(1.5)
set_ignore_ai_flag( pilot, false )
vehicle_suppress_npc_exit( heli, false )
vehicle_exit_group(npc_list, true)
end
-- Fly a helicopter along the specified path, then have the NPCs exit
--
-- group: (string) name of the helicotper group to use
-- paths: (table) table of paths to move along
-- nav: (string) navpoint to return to afterward
--
function m05_chase_thread(group, paths, nav)
-- Force the heli to follow the paths (slowly)
vehicle_max_speed(group.heli, M05_chase.min_speed)
for i, path in pairs(paths) do
helicopter_fly_to_direct_dont_stop(group.heli, -1, path)
end
-- Once the path is complete, have the passengers exit (the pilot MUST stay in or the heli crashes)
vehicle_exit(group.target)
-- Reenable their AI
vehicle_set_vulnerable(group.heli)
turn_vulnerable(group.pilot)
set_ignore_ai_flag(group.target, true)
set_unjackable_flag(group.heli, false)
delay(.75)
vehicle_exit(group.pilot)
set_ignore_ai_flag(group.pilot, false)
-- Continue onward
M05_heli_arrived = true
end
function m05_chase_distance(heli, sync)
-- Turn on the distance meter
local hud_index = 0
if (sync == SYNC_REMOTE) then
hud_index = 1
end
hud_bar_on(hud_index, "annoyance", "", M05_chase.max_dist - M05_chase.min_dist, sync)
local my_dist = 9999
local co_dist = 9999
local closest = 9999
local speed = M05_chase.min_speed
while(true) do
-- Get the current distances
my_dist = get_dist(LOCAL_PLAYER, heli)
if not M05_in_coop then
closest = my_dist
else
co_dist = get_dist(REMOTE_PLAYER, heli)
if (my_dist < co_dist) then
closest = my_dist
else
closest = co_dist
end
if (sync == SYNC_REMOTE) then
my_dist = co_dist
end
end
-- Update the bar
if (my_dist > M05_chase.max_dist) then
hud_bar_set_value(hud_index, 0, sync)
elseif (my_dist < M05_chase.min_dist) then
-- They're close enough, so show a full bar
hud_bar_set_value(hud_index, M05_chase.max_dist - M05_chase.min_dist, sync)
else
hud_bar_set_value(hud_index, M05_chase.max_dist - my_dist, sync)
end
-- Fail if all players strayed too far
if (closest > M05_chase.max_dist) then
mission_end_failure("m05", "m05_fail_chase")
end
-- Update the heli's speed based on the distance
if M05_chase.local_player_ready or M05_chase.remote_player_ready then
-- Calculate percent distance
speed = 1 - (closest / M05_chase.max_dist)
-- The closer the player, the faster the heli should fly
speed = M05_chase.min_speed + ((M05_chase.max_speed - M05_chase.min_speed) * speed)
vehicle_max_speed(heli, speed)
end
thread_yield()
end
end
-- Fire off rockets when the player nears
--
function m05_rockets_thread()
while(true) do
for i, npc in pairs(M05_groups.rockets.npcs) do
if (get_dist_closest_player_to_object(npc) < M05_chase.rocket_dist) then
force_fire(npc, M05_nav.rockets[i], true)
end
delay(0.5)
end
end
end