--[[
m14.lua
SR3 Mission Script
DATE: 9/21/2010
AUTHOR: Nick Heilmann
]]--
M14_TIMER_INDEX = 1
M14_PROGRESS_INDEX = 1
VEHICLE_SEAT_DRIVER = 0
VEHICLE_SEAT_PASSENGER = 1
VEHICLE_SEAT_HELI_BACK_DOOR = 2
HUD_BAR_MAX_VALUE = 100
HUD_BAR_STEP_TRANSMITTER = 2
HUD_BAR_STEP_VAN = 1
HUD_BAR_DELAY_TRANSMITTER = .5
HUD_BAR_DELAY_VAN = .25
HUD_FAKE_RETICLE_WEAPON_NAME = "sp_vtol01_w"
HUD_FAKE_RETICLE_WEAPON_CATEGORY_NAME = "WPNCAT_RIFLE"
M14_DEBUG = {
infinity = 999999999,
message_handle = INVALID_MESSAGE_HANDLE,
}
M14_status = {
do_timer_validation = false,
do_tower1_validation = false,
do_tower2_validation = false,
do_interview_validation = false,
transmitter_placed = false,
helipad_reached = false,
interview_stairs_reached = false,
helipad_left = false,
timer_active = false,
target_progress_displayed = false,
transmitter_bar_displayed = false,
deckers_alive = 0,
proxy_navpoint = nil, -- Navpoint that's being used as a proxy for placement of an icon when a trigger is set
play_radio_call_in = false, -- we only want to play this on linear play through but not on checkpoint restart
}
M14_objective_text = {
gsi_index = nil,
text = nil,
sub1 = nil,
sub2 = nil,
sync_type = nil,
oi_asset = nil,
}
M14_char = {
-- M14_char.shaundi will be a reference to whichever version of Shaundi is currently active
shaundi = nil,
shaundi_sj = "NPC Shaundi SJ",
shaundi_heli = "NPC Shaundi Heli",
shaundi_t1 = "NPC Shaundi Tower 001",
shaundi_t2 = "NPC Shaundi Tower 002",
shaundi_studio = "NPC Shaundi Studio",
t1_small = { "NPC T1 SG 001", "NPC T1 SG 002", "NPC T1 SG 003", "NPC T1 SG 004" },
deckers_t1_1 = { "NPC T1 Decker 001", "NPC T1 Decker 002", "NPC T1 Decker 003" },
t2_small = { "NPC T2 SG 001", "NPC T2 SG 002" },
helipad = {
"NPC Helipad 001", "NPC Helipad 002", "NPC Helipad 003", "NPC Helipad 004",
"NPC Helipad 005", "NPC Helipad 006", "NPC Helipad 007", "NPC Helipad 008",
},
deckers_studio = {
"NPC Decker Studio 001", "NPC Decker Studio 002", "NPC Decker Studio 003", "NPC Decker Studio 004",
"NPC Decker Studio 005", "NPC Decker Studio 006", "NPC Decker Studio 007", "NPC Decker Studio 008",
},
deckers_elevator_rb = { "NPC Decker Elevator RB 001", "NPC Decker Elevator RB 002" },
deckers_elevator_fs = { "NPC Decker Elevator FS 001", "NPC Decker Elevator FS 002", "NPC Decker Elevator FS 003" },
deckers_corner_rb = { "NPC Decker Corner RB 001" },
deckers_corner_fs = { "NPC Decker Corner FS 001" },
deckers_side_rb = { "NPC Decker Side RB 001" },
deckers_side_fs = { "NPC Decker Side FS 001", "NPC Decker Side FS 002" },
deckers_stairs_rb = { "NPC Decker Stairs RB 001", "NPC Decker Stairs RB 002", "NPC Decker Stairs RB 003" },
deckers_stairs_fs = { "NPC Decker Stairs FS 001", "NPC Decker Stairs FS 002" },
broadcast_van = "NPC Broadcast Van Driver",
jane = "NPC Jane Valderama",
killbane = "NPC Killbane",
}
M14_vehicle = {
cp_smiling_jacks = "Veh CP Smiling Jacks",
-- M14_vehicle.spotlight_heli will be a reference to whichever version of the spotlight heli is currently active
spotlight_heli = "",
cp_sj_spotlight_heli = "Veh CP SJ Spotlight Heli",
cp_heli_spotlight_heli = "Veh CP Heli Spotlight Heli",
cp_t1_spotlight_heli = "Veh CP T1 Spotlight Heli",
cp_t2_spotlight_heli = "Veh CP T2 Spotlight Heli",
cp_studio_spotlight_heli = "Veh CP Studio Spotlight Heli",
broadcast_van = "Veh Broadcast Van",
killbane_escape = "Veh Killbane Escape",
killbane_chase = "Veh Killbane Chase",
}
M14_group = {
cp_smiling_jacks = { name = "GRP CP Smiling Jacks", chars = { M14_char.shaundi_sj }, vehicles = { M14_vehicle.cp_smiling_jacks, M14_vehicle.cp_sj_spotlight_heli } },
cp_heli = { name = "GRP CP Heli", chars = { M14_char.shaundi_heli }, vehicles = { M14_vehicle.cp_heli_spotlight_heli } },
cp_tower1 = { name = "GRP CP Tower 001", chars = { M14_char.shaundi_t1 }, vehicles = { M14_vehicle.cp_t1_spotlight_heli } },
cp_tower2 = { name = "GRP CP Tower 002", chars = { M14_char.shaundi_t2 }, vehicles = { M14_vehicle.cp_t2_spotlight_heli } },
cp_studio = { name = "GRP CP Studio", chars = { M14_char.shaundi_studio }, vehicles = { M14_vehicle.cp_studio_spotlight_heli } },
--spotlight_heli = { name = "GRP Veh Spotlight Heli", vehicles = { M14_vehicle.cp_heli_spotlight_heli } },
--shaundi = { name = "GRP Shaundi", chars = { M14_char.shaundi } },
t1_small = { name = "GRP T1 Small", chars = M14_char.t1_small },
t2_small = { name = "GRP T2 Small", chars = M14_char.t2_small },
deckers_t1_1 = { name = "GRP Tower One Deckers 001", chars = M14_char.deckers_t1_1 },
deckers_t1_2 = { name = "GRP Tower One Deckers 002" },
deckers_t2_4 = { name = "GRP Tower Two Deckers 004" },
broadcast_van = { name = "GRP Broadcast Van", chars = { M14_char.broadcast_van }, vehicles = { M14_vehicle.broadcast_van } },
helipad = { name = "GRP Helipad", chars = M14_char.helipad },
deckers_studio = { name = "GRP Studio Deckers", chars = M14_char.deckers_studio },
deckers_elevator = { name = "GRP Deckers Elevator", chars = { M14_char.deckers_elevator_rb, M14_char.deckers_elevator_fs } },
deckers_corner = { name = "GRP Deckers Corner", chars = { M14_char.deckers_corner_rb, M14_char.deckers_corner_fs } },
deckers_side = { name = "GRP Deckers Side", chars = { M14_char.deckers_side_rb, M14_char.deckers_side_fs } },
deckers_stairs = { name = "GRP Deckers Stairs", chars = { M14_char.deckers_stairs_rb, M14_char.deckers_stairs_fs } },
jane = { name = "GRP Jane Valderama", chars = { M14_char.jane } },
killbane = { name = "GRP Killbane", chars = { M14_char.killbane }, vehicles = { M14_vehicle.killbane_escape, M14_vehicle.killbane_chase } },
}
M14_spawn_group = {
deckers_t2 = { "GRP Tower Two Deckers 001", "GRP Tower Two Deckers 002", "GRP Tower Two Deckers 003" },
}
M14_spawn_region = {
deckers_t2 = { "Spawn Reg Ttwo 001", "Spawn Reg Ttwo 002", "Spawn Reg Ttwo 003" },
}
M14_navpoint = {
cp_sj_lp = "Nav CP SJ Local",
cp_sj_rp = "Nav CP SJ Remote",
cp_heli_lp = "Nav CP Heli Local",
cp_heli_rp = "Nav CP Heli Remote",
cp_tower1_lp = "Nav CP T1 Local",
cp_tower1_rp = "Nav CP T1 Remote",
cp_tower2_lp = "Nav CP T2 Local",
cp_tower2_rp = "Nav CP T2 Remote",
cp_van_complete_heli = "Nav CP Van Heli",
cp_studio_lp = "Nav CP Studio Local",
cp_studio_rp = "Nav CP Studio Remote",
sj_spotlight_heli = "Nav CP SJ Spotlight Heli",
t1_helipad = "Nav T1 Helipad",
t2_helipad = "Nav T2 Helipad",
interview_helipad = "Nav Interview Helipad",
deckers_elevator = { "Nav Elevator 001", "Nav Elevator 002", "Nav Elevator 003" },
deckers_corner = { "Nav Corner 001" },
deckers_side = { "Nav Side 001", "Nav Side 002" },
deckers_stairs = { "Nav Stairs 001", "Nav Stairs 002" },
elevator_rb = "Nav Elevator RB",
corner_rb = "Nav Corner RB",
side_rb = "Nav Side RB",
stairs_rb = "Nav Stairs RB",
killbane_escape = "Nav Killbane Dest",
end_local = "Nav Mission End Local",
end_remote = "Nav Mission End Remote",
jane_tether = "Nav Jane Tether",
tower_one_placement = "Nav Tower One Placement",
tower_two_placement = "Nav Tower Two Placement",
}
M14_cam_nav = {
transmitters = { "Cam Nav Transmitter 001", "Cam Nav Transmitter 002" },
helipads = { "Cam Nav Helipad 001", "Cam Nav Helipad 002" },
jane = "Cam Nav Jane",
deckers = "Cam Nav Deckers",
elevator = { "Cam Nav Elevator 001", "Cam Nav Elevator 002" },
doors = { "Cam Nav Doors 001", "Cam Nav Doors 002" },
stairs = { "Cam Nav Stairs 001", "Cam Nav Stairs 002" },
}
M14_trigger = {
tower1_heli_validation = "Trigger Heli Validation 001",
--tower1_helipad = "Trigger T1 Helipad",
tower1 = "Trigger Tower 001",
tower2_heli_validation = "Trigger Heli Validation 002",
--tower2_helipad = "Trigger T2 Helipad",
tower2 = "Trigger Tower 002",
helipad = "Trigger Helipad",
studio_stairs1 = "Trigger Stairs1",
studio_stairs2 = "Trigger Stairs2",
interview_stairs = "Trigger Interview Stairs",
studio_massacre = "Trigger Studio Massacre",
t1_massacre = "Trigger T1 Massacre",
t2_massacre = "Trigger T2 Massacre",
}
M14_scripted_path = {
killbane_escape = "Scripted Path Killbane Escape",
}
M14_script_mover = {
elevator = "SM Elevator",
side_door = { "SM Side Door 001", "SM Side Door 002" },
}
M14_text = {
go_to_heli = "M14_OBJ_GO_TO_HELI",
get_in_heli = "M14_OBJ_GET_IN_HELI",
go_to_tower = "M14_OBJ_GO_TO_TOWER",
plant_transmitter = "M14_OBJ_PLANT_TRANSMITTER",
go_to_van = "M14_OBJ_GO_TO_VAN",
target_van = "M14_OBJ_TARGET_VAN",
go_to_interview = "M14_OBJ_GO_TO_INTERVIEW",
enter_building = "M14_OBJ_ENTER_BUILDING",
talk_to_jane = "M14_OBJ_TALK_TO_JANE",
clear_deckers = "M14_OBJ_CLEAR_DECKERS",
catch_killbane = "M14_OBJ_CATCH_KILLBANE",
label_acquiring_target = "M14_LABEL_ACQUIRING_TARGET",
label_planting_transmitter = "M14_LABEL_PLANTING_TRANSMITTER",
failure_van_destroyed = "m14_failure_van_destroyed",
failure_heli_destroyed = "m14_failure_heli_destroyed",
failure_shaundi_died = "m14_failure_shaundi_died",
failure_shaundi_abandoned = "m14_failure_shaundi_abandoned",
failure_heli_unreachable = "m14_failure_heli_unreachable",
failure_heli_abandoned = "m14_failure_heli_abandoned",
failure_jane_died = "m14_failure_jane_died",
failure_killbane_escaped = "m14_failure_killbane_escaped",
}
M14_thread = {
that_was_easy = INVALID_THREAD_HANDLE,
get_out_place_transmitter = INVALID_THREAD_HANDLE,
surprise_for_you = INVALID_THREAD_HANDLE,
crazy_bitch = INVALID_THREAD_HANDLE,
killbane_escape = INVALID_THREAD_HANDLE,
failure_validation = INVALID_THREAD_HANDLE,
one_last_transmitter = INVALID_THREAD_HANDLE,
radio_call_in = INVALID_THREAD_HANDLE,
audio_failsafe = INVALID_THREAD_HANDLE,
}
M14_2d_personas = {
anna = {
name = "Anna",
handle = -1,
},
shaundi = {
name = "Shaundi",
handle = -1,
},
kinzie = {
name = "Kinzie",
handle = -1,
},
}
M14_convo = {
-- Shaundi, Player
drive_01 = { convo_name = "m14_drive_01", handle = INVALID_CONVERSATION_HANDLE, speakers_2d = { }, player_speaks = true },
-- Shaundi, Player
drive_02 = { convo_name = "m14_drive_02", handle = INVALID_CONVERSATION_HANDLE, speakers_2d = { }, player_speaks = true },
-- Kinzie, Player
reach_helicopter = { cell_name = "m14_reach_helicopter", handle = INVALID_CONVERSATION_HANDLE, speakers_2d = { M14_2d_personas.kinzie }, player_speaks = true, recieving = false },
-- Kinzie, Player
first_antenna = { cell_name = "m14_first_antenna", handle = INVALID_CONVERSATION_HANDLE, speakers_2d = { M14_2d_personas.kinzie }, player_speaks = true, recieving = false },
-- Player, Shaundi
first_rooftop = { convo_name = "M14_First_Rooftop", handle = INVALID_CONVERSATION_HANDLE, speakers_2d = { }, player_speaks = true },
-- Kinzie, Player
second_antenna = { cell_name = "m14_second_antenna", handle = INVALID_CONVERSATION_HANDLE, speakers_2d = { M14_2d_personas.kinzie }, player_speaks = true, recieving = false },
-- Player, Shaundi
second_rooftop = { convo_name = "M14_Second_Rooftop", handle = INVALID_CONVERSATION_HANDLE, speakers_2d = { }, player_speaks = true },
-- Kinzie, Player
target_van = { cell_name = "m14_target_van", handle = INVALID_CONVERSATION_HANDLE, speakers_2d = { M14_2d_personas.kinzie }, player_speaks = true, recieving = true },
van_escaping = { persona_2d_params = { "M14_Too_Far_Away_From_Van" }, handle = INVALID_CONVERSATION_HANDLE, speakers_2d = { M14_2d_personas.kinzie } },
spooked_van = { persona_2d_params = { "M14_Spooked_News_Van" }, handle = INVALID_CONVERSATION_HANDLE, speakers_2d = { M14_2d_personas.shaundi } },
-- Kinzie, Player
got_location = { cell_name = "m14_got_location", handle = INVALID_CONVERSATION_HANDLE, speakers_2d = { M14_2d_personas.kinzie }, player_speaks = true, recieving = true },
-- Shaundi, Player
land_on_office = { convo_name = "m14_land_on_office", handle = INVALID_CONVERSATION_HANDLE, speakers_2d = { }, player_speaks = true },
-- Shaundi, Player
enter_office = { convo_name = "m14_enter_office", handle = INVALID_CONVERSATION_HANDLE, speakers_2d = { M14_2d_personas.shaundi }, player_speaks = true },
-- Jane, Player
question_jane = { convo_name = "m14_question_jane", handle = INVALID_CONVERSATION_HANDLE, speakers_2d = { M14_2d_personas.anna }, player_speaks = true },
-- Shaundi, Anna
anna_thanks = { convo_name = "m14_anna_thanks", handle = INVALID_CONVERSATION_HANDLE, speakers_2d = { M14_2d_personas.anna, M14_2d_personas.shaundi }, player_speaks = false },
-- Shaundi, Player
go_after_killbane = { convo_name = "m14_go_after_killbane", handle = INVALID_CONVERSATION_HANDLE, speakers_2d = { }, player_speaks = true },
-- player, shaundi
helecopter_end = { convo_name = "M14_End_Heli_Convo", handle = INVALID_CONVERSATION_HANDLE, speakers_2d = { }, player_speaks = true },
}
--M14_CHECKPOINT_MISSION_START = MISSION_START_CHECKPOINT, -- defined in ug_lib.lua
M14_CHECKPOINT_GET_TO_HELI = "heli"
M14_CHECKPOINT_TOWER1_COMPLETE = "t1"
M14_CHECKPOINT_TOWER2_COMPLETE = "t2"
M14_CHECKPOINT_TARGET_VAN_COMPLETE = "van"
M14_CHECKPOINT_GET_TO_STUDIO = "studio"
-- the global timer for each checkpoint
M14_mission_start_time = 16
M14_checkpoint_time_get_to_heli = 15
M14_checkpoint_time_tower1_complete = 12
M14_checkpoint_time_tower2_complete = 8
M14_checkpoint_time_target_van_complete = 6
M14_checkpoint_time_get_to_studio = 5
M14_cutscene = {
mission_intro = "14_in",
mission_outro = "14_out",
}
-- *************************
--
-- Standard functions
--
-- *************************//sr3/main/sr3/data/levels/sr3_city/missions/m14.lua
-- This is the primary entry point for the mission, and is responsible for starting up the mission
-- at the specified checkpoint.
-- CALLED FROM CODE
--
-- m14_checkpoint: The checkpoint the mission should begin at
-- is_restart: TRUE if the mission is restarting, FALSE otherwise
--
function m14_start(m14_checkpoint, is_restart)
-- Make sure the screen is completly faded out
mission_start_fade_out(0.0)
-- Check if this mission starting from the beginning
if m14_checkpoint == MISSION_START_CHECKPOINT then
m14_initialize_smiling_jacks()
if is_restart == false then
cutscene_play(M14_cutscene.mission_intro, nil, { M14_navpoint.cp_sj_lp, M14_navpoint.cp_sj_rp } )
else
teleport_coop( M14_navpoint.cp_sj_lp, M14_navpoint.cp_sj_rp )
end
m14_initialize_smiling_jacks_post()
end
-- Handle mission initialization for the current checkpoint
m14_initialize(m14_checkpoint)
-- Run the mission from the current checkpoint
m14_run(m14_checkpoint)
end
-- This is the primary function responsible for running the entire mission from start to finish.
--
-- first_checkpoint: The first checkpoint to begin running the mission at
--
function m14_run(first_checkpoint)
local current_checkpoint = first_checkpoint
local ignore_vehicles = true
local ignore_notoriety = true
-- Start a thread that will do constant validation of failure conditions
-- M14_thread.failure_validation = thread_new("m14_failure_validation_thread")
-- Run the mission from the beginning
if (current_checkpoint == MISSION_START_CHECKPOINT) then
hud_timer_set(M14_TIMER_INDEX, M14_mission_start_time * 60 * 1000, "m14_timer_validation_fail_cb")
m14_objective_go_to_heli_smiling_jacks()
current_checkpoint = M14_CHECKPOINT_GET_TO_HELI
mission_set_checkpoint(M14_CHECKPOINT_GET_TO_HELI, ignore_vehicles, ignore_notoriety)
end
if (current_checkpoint == M14_CHECKPOINT_GET_TO_HELI) then
M14_thread.abandon_heli = thread_new( "m14_abandon_heli_thread" )
m14_objective_go_to_first_tower()
m14_objective_plant_first_transmitter()
m14_objective_get_in_heli_first_tower()
current_checkpoint = M14_CHECKPOINT_TOWER1_COMPLETE
mission_set_checkpoint(M14_CHECKPOINT_TOWER1_COMPLETE, ignore_vehicles, ignore_notoriety)
end
if (current_checkpoint == M14_CHECKPOINT_TOWER1_COMPLETE) then
m14_objective_go_to_second_tower()
m14_objective_plant_second_transmitter()
m14_objective_get_in_heli_second_tower()
current_checkpoint = M14_CHECKPOINT_TOWER2_COMPLETE
mission_set_checkpoint(M14_CHECKPOINT_TOWER2_COMPLETE, ignore_vehicles, ignore_notoriety)
end
if (current_checkpoint == M14_CHECKPOINT_TOWER2_COMPLETE) then
m14_objective_target_the_van()
current_checkpoint = M14_CHECKPOINT_TARGET_VAN_COMPLETE
mission_set_checkpoint(M14_CHECKPOINT_TARGET_VAN_COMPLETE, ignore_vehicles, ignore_notoriety)
end
if current_checkpoint == M14_CHECKPOINT_TARGET_VAN_COMPLETE then
m14_objective_go_to_interview()
M14_status.at_tower = true
m14_objective_enter_building()
current_checkpoint = M14_CHECKPOINT_GET_TO_STUDIO
mission_set_checkpoint(M14_CHECKPOINT_GET_TO_STUDIO, ignore_vehicles, ignore_notoriety)
end
if (current_checkpoint == M14_CHECKPOINT_GET_TO_STUDIO) then
M14_status.at_tower = true
m14_objective_clear_deckers()
m14_objective_talk_to_jane()
m14_objective_get_in_heli_chase_killbane()
M14_status.at_tower = false
m14_objective_catch_killbane()
end
mission_end_success("m14", M14_cutscene.mission_outro)
end
-- This is the primary function responsible for cleaning up the entire mission
-- CALLED FROM CODE (+++MUST RETURN IMMEDIATLY+++)
--
function m14_cleanup()
-- Make it early morning, so the sun will rise soon
--set_time_of_day(06, 00)
radio_global_block( false )
spotlight_heli_laser_enable(false)
vehicle_spotlight_cancel( LOCAL_PLAYER, true )
if coop_is_active() then
vehicle_spotlight_cancel( REMOTE_PLAYER, true )
end
notoriety_force_no_spawn("luchadores", false)
notoriety_force_no_spawn("deckers", false)
notoriety_force_no_spawn("morningstar", false)
notoriety_force_no_spawn("police", false)
if (M14_navpoint.end_local ~= nil) then
teleport(LOCAL_PLAYER, M14_navpoint.end_local, true)
if (coop_is_active()) then
teleport(REMOTE_PLAYER, M14_navpoint.end_remote, true)
end
end
-- Just in case these never got cleared
on_vehicle_enter("", LOCAL_PLAYER)
if (coop_is_active()) then
on_vehicle_enter("", REMOTE_PLAYER)
end
mission_waypoint_remove()
cleanup_threads(M14_thread)
m14_radio_call_in_stop( false )
m14_cleanup_audio(M14_convo)
hud_timer_stop(M14_TIMER_INDEX)
if (M14_status.target_progress_displayed or M14_status.transmitter_bar_displayed) then
hud_bar_off(M14_PROGRESS_INDEX)
M14_status.target_progress_displayed = false
M14_status.transmitter_bar_displayed = false
end
m14_interview_kill()
cleanup_callbacks( { M14_char, M14_vehicle } )
cleanup_groups(M14_group)
call_function_on_each_member(m14_clear_trigger, M14_trigger)
cleanup_spawn_regions(M14_spawn_region)
cleanup_spawn_groups(M14_spawn_group)
if M14_status.cellphone_call_in_progress ~= nil then
audio_remove_mission_cellphone( M14_status.cellphone_call_in_progress )
end
-- clear any residual animation settings if the player
-- quits while planting a transmitter
clear_animation_state( LOCAL_PLAYER )
player_movement_enable( LOCAL_PLAYER )
if coop_is_active() then
clear_animation_state( REMOTE_PLAYER )
player_movement_enable( REMOTE_PLAYER )
end
hud_critical_timer_stop()
m14_cleanup_fake_laser_reticle()
-- Clean up 2D personas.
for i, persona in pairs(M14_2d_personas) do
audio_persona_remove_2d(persona.handle)
persona.handle = -1
end
end
-- Called when the mission has ended with success
-- CALLED FROM CODE (+++MUST RETURN IMMEDIATLY+++)
--
function m14_success()
m14_coop_skip( ) -- do the stuff we'd do in the skip case
end
-- *************************
--
-- Local functions
--
-- *************************
-- Initialize the mission for the specified checkpoint
--
-- checkpoint: Checkpoint to initialize the mission to
--
function m14_initialize(checkpoint)
-- Set the mission author
set_mission_author("Nick Heilmann")
-- Common initialization
m14_initialize_common()
-- Checkpoint specific initialization
m14_initialize_checkpoint(checkpoint)
-- Start fading in
mission_start_fade_in()
end
-- ***************************************************
--
-- m14_run Helper Functions
--
-- ***************************************************
--[[ MISSION START / SMILING JACKS ]]--
function m14_initialize_smiling_jacks()
group_create(M14_group.cp_smiling_jacks, true)
vehicle_car_alarm_enable(M14_vehicle.cp_smiling_jacks, false)
M14_char.shaundi = M14_char.shaundi_sj
M14_vehicle.spotlight_heli = M14_vehicle.cp_sj_spotlight_heli
end
function m14_initialize_smiling_jacks_post()
party_add(M14_char.shaundi)
follower_set_can_abandon(M14_char.shaundi, true)
on_dismiss("m14_shaundi_dismissed_cb", M14_char.shaundi)
on_vehicle_destroyed("m14_spotlight_heli_destroyed_cb", M14_vehicle.spotlight_heli)
on_death("m14_shaundi_died_cb", M14_char.shaundi)
radio_block( M14_vehicle.spotlight_heli, true )
group_show( M14_group.cp_smiling_jacks )
-- Intro animations
-- Player(s) look cool GO!
local anim_name = "M10 Player Mission Start"
local morph_name = "M10 Player Mission Start"
local force_play = false
local stand_still = false
local zero_movement = false
action_play_non_blocking(LOCAL_PLAYER, anim_name, morph_name, force_play, stand_still, zero_movement)
player_script_controlled_clear(LOCAL_PLAYER) -- let player escape this animation
if (coop_is_active()) then
action_play_non_blocking(REMOTE_PLAYER, anim_name, morph_name, force_play, stand_still, zero_movement)
player_script_controlled_clear(REMOTE_PLAYER) -- let player escape this animation
end
end
function m14_objective_go_to_heli_smiling_jacks()
m14_objective_text(0, M14_text.go_to_heli, nil, nil, SYNC_ALL, OI_ASSET_LOCATION)
M14_status.do_timer_validation = false
-- Play Kinzie's mission start persona line
m14_cellphone_call_wait( "M14_Mission_Start", true, M14_2d_personas.kinzie.handle )
marker_add(M14_navpoint.sj_spotlight_heli, MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION, OI_FLAGS_FULL)
mission_waypoint_add(M14_navpoint.sj_spotlight_heli)
-- if player gets into car before they arrive at the heli
-- they get to hear the first interview segment
local interview_1_played = false
while true do
local player_in_any_veh = character_is_in_vehicle( LOCAL_PLAYER )
-- if player is near heli and not in vehicle we are done
if player_in_any_veh == false and get_dist( LOCAL_PLAYER, M14_vehicle.spotlight_heli ) < 60 then
break
end
-- if player enters vehicle the play interview 1
if interview_1_played == false and player_in_any_veh == true then
m14_convo_play( M14_convo.drive_01, true )
delay( 1 )
m14_interview_play( "m14_interview_part1", "#PLAYER1_VEHICLE#" )
interview_1_played = true
end
thread_yield()
end
m14_cleanup_audio( M14_convo )
m14_convo_play( M14_convo.drive_02 )
m14_objective_text_clear(0)
m14_objective_text(0, M14_text.get_in_heli, nil, nil, SYNC_ALL, OI_ASSET_LOCATION)
m14_wait_for_player_to_enter_vehicle()
M14_status.do_timer_validation = true
marker_remove( M14_navpoint.sj_spotlight_heli )
mission_waypoint_remove()
m14_objective_text_clear(0)
-- heli reached convo
m14_cleanup_audio( M14_convo )
m14_convo_play( M14_convo.reach_helicopter, true )
end
--[[ HELI ]]--
function m14_initialize_heli()
teleport(LOCAL_PLAYER, M14_navpoint.cp_heli_lp, true)
if (coop_is_active()) then
teleport(REMOTE_PLAYER, M14_navpoint.cp_heli_rp, true)
end
group_create(M14_group.cp_heli, true)
M14_char.shaundi = M14_char.shaundi_heli
M14_vehicle.spotlight_heli = M14_vehicle.cp_heli_spotlight_heli
party_add(M14_char.shaundi)
follower_set_can_abandon(M14_char.shaundi, true)
on_dismiss("m14_shaundi_dismissed_cb", M14_char.shaundi)
on_vehicle_destroyed("m14_spotlight_heli_destroyed_cb", M14_vehicle.spotlight_heli)
on_death("m14_shaundi_died_cb", M14_char.shaundi)
-- Since the first objective ends after you enter the heli, we need to put you in it now
vehicle_enter_teleport(LOCAL_PLAYER, M14_vehicle.spotlight_heli, VEHICLE_SEAT_DRIVER, true)
vehicle_enter_teleport(M14_char.shaundi, M14_vehicle.spotlight_heli, VEHICLE_SEAT_PASSENGER, true)
if (coop_is_active()) then
vehicle_enter_teleport(REMOTE_PLAYER, M14_vehicle.spotlight_heli, VEHICLE_SEAT_HELI_BACK_DOOR, true)
end
hud_timer_set(M14_TIMER_INDEX, M14_checkpoint_time_get_to_heli * 60 * 1000, "m14_timer_validation_fail_cb")
end
function m14_objective_go_to_first_tower()
m14_objective_text(0, M14_text.go_to_tower, nil, nil, SYNC_ALL, OI_ASSET_LOCATION)
m14_interview_play( "m14_interview_part2" )
M14_status.helipad_reached = false
-- We'll set the whole validation trigger to go off if they get out of their vehicle while in it, but put the marker on the helipad
m14_set_helipad_trigger(M14_trigger.tower1_heli_validation, nil, M14_navpoint.t1_helipad, true, true, MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION)
-- Then spawn the Deckers defending the tower
group_create(M14_group.t1_small.name, true)
group_create(M14_group.deckers_t1_1.name, true)
for i, n in pairs( M14_group.t1_small.chars ) do
on_attack_performed( "m14_on_attack_performed_cb", n )
end
for i, n in pairs( M14_group.deckers_t1_1.chars ) do
on_attack_performed( "m14_on_attack_performed_cb", n )
end
-- wait until the heli is in the trigger and one of the players gets out
local in_trigger = false
local has_been_in_trigger = false
local local_player_in_heli = true
local remote_player_in_heli = true
local kinzi_convo_played = false
while true do
in_trigger = object_is_in_trigger( M14_trigger.tower1_heli_validation, M14_vehicle.spotlight_heli )
if in_trigger then
if has_been_in_trigger == false then
-- guards... attack!
for i,npc in pairs(M14_char.t1_small) do
ai_add_enemy_target(npc, LOCAL_PLAYER, ATTACK_ON_SIGHT)
if (coop_is_active()) then
ai_add_enemy_target(npc, REMOTE_PLAYER, ATTACK_ON_SIGHT)
end
end
-- if radio spot is over play kinzie convo
if audio_is_playing( M14_status.interview_audio_id ) == false then
m14_convo_play( M14_convo.first_antenna )
m14_convo_play( M14_convo.first_rooftop )
kinzi_convo_played = true
end
has_been_in_trigger = true
end
local_player_in_heli = character_is_in_vehicle( LOCAL_PLAYER, M14_vehicle.spotlight_heli )
remote_player_in_heli = true
if coop_is_active() then
remote_player_in_heli = character_is_in_vehicle( REMOTE_PLAYER, M14_vehicle.spotlight_heli )
end
if in_trigger == true then
if local_player_in_heli == false or remote_player_in_heli == false then
break
end
end
end
thread_yield()
end
m14_helipad_reached_cb( nil, M14_trigger.tower1_heli_validation )
-- kick off the kinzi convo if it wasn't already played
if kinzi_convo_played == false then
m14_interview_kill()
m14_convo_play( M14_convo.first_antenna )
m14_convo_play( M14_convo.first_rooftop )
end
M14_status.do_tower1_validation = true
M14_status.do_timer_validation = false
thread_kill(M14_thread.surprise_for_you)
M14_thread.surprise_for_you = INVALID_THREAD_HANDLE
M14_status.placement_nav = M14_navpoint.tower_one_placement
M14_status.transmitter_placed = false
M14_status.transmitter_progress = 0
trigger_set_hold_to_repeat( M14_trigger.tower1, true )
m14_set_trigger(M14_trigger.tower1, "m14_transmitter_placement_started_cb", true, true, MINIMAP_ICON_USE, OI_ASSET_USE)
m14_objective_text_clear(0)
end
function m14_objective_plant_first_transmitter()
m14_objective_text(0, M14_text.plant_transmitter, nil, nil, SYNC_ALL, OI_ASSET_USE)
M14_status.transmitter_bar_displayed = true
M14_status.at_tower = true
trigger_enable(M14_trigger.t1_massacre, true)
on_trigger( "m14_studio_massacre_cb", M14_trigger.t1_massacre )
-- Spawn the second group of guys after a few seconds
delay(3)
group_create(M14_group.deckers_t1_2.name, false)
local line_played = false
repeat
thread_yield()
if line_played == false and M14_status.transmitter_progress > 0 then
if m14_convo_is_playing() == false then
audio_play_persona_line( M14_status.transmitter_activator, "M14_Placing_First_Transmitter" )
end
line_played = true
end
until M14_status.transmitter_placed
audio_ambient_emitter_start( "transmitter_1" )
M14_status.transmitter_bar_displayed = false
hud_bar_off(M14_PROGRESS_INDEX)
end
function m14_objective_get_in_heli_first_tower()
m14_objective_text(0, M14_text.get_in_heli, nil, nil, SYNC_ALL, OI_ASSET_LOCATION)
marker_add(M14_vehicle.spotlight_heli, MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION, OI_FLAGS_FULL)
-- Start the timer validation now, in case the helicopter is somehow unreachable, yet within the validation trigger
M14_status.do_timer_validation = true
m14_wait_for_player_to_enter_vehicle()
M14_status.do_tower1_validation = false
marker_remove(M14_vehicle.spotlight_heli)
m14_objective_text_clear(0)
M14_status.at_tower = false
trigger_enable(M14_trigger.t1_massacre, false)
on_trigger( "", M14_trigger.t1_massacre )
end
--[[ TOWER 1 ]]--
function m14_initialize_tower1()
teleport(LOCAL_PLAYER, M14_navpoint.cp_tower1_lp, true)
if (coop_is_active()) then
teleport(REMOTE_PLAYER, M14_navpoint.cp_tower1_rp, true)
end
group_create(M14_group.cp_tower1, true)
M14_char.shaundi = M14_char.shaundi_t1
M14_vehicle.spotlight_heli = M14_vehicle.cp_t1_spotlight_heli
party_add(M14_char.shaundi)
follower_set_can_abandon(M14_char.shaundi, true)
on_dismiss("m14_shaundi_dismissed_cb", M14_char.shaundi)
on_vehicle_destroyed("m14_spotlight_heli_destroyed_cb", M14_vehicle.spotlight_heli)
on_death("m14_shaundi_died_cb", M14_char.shaundi)
radio_block( M14_vehicle.spotlight_heli, true )
-- Since the previous objective ends after you enter the heli, we need to put you in it now
vehicle_enter_teleport(LOCAL_PLAYER, M14_vehicle.spotlight_heli, VEHICLE_SEAT_DRIVER, true)
vehicle_enter_teleport(M14_char.shaundi, M14_vehicle.spotlight_heli, VEHICLE_SEAT_PASSENGER, true)
if (coop_is_active()) then
vehicle_enter_teleport(REMOTE_PLAYER, M14_vehicle.spotlight_heli, VEHICLE_SEAT_HELI_BACK_DOOR, true)
end
hud_timer_set(M14_TIMER_INDEX, M14_checkpoint_time_tower1_complete * 60 * 1000, "m14_timer_validation_fail_cb")
end
function m14_objective_go_to_second_tower()
m14_objective_text(0, M14_text.go_to_tower, nil, nil, SYNC_ALL, OI_ASSET_LOCATION)
m14_interview_play( "m14_interview_part3" )
M14_status.helipad_reached = false
m14_set_helipad_trigger(M14_trigger.tower2_heli_validation, nil, M14_navpoint.t2_helipad, true, true, MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION)
-- Wait until the player gets near the vicinity of the second tower
repeat
thread_yield()
until (get_dist_closest_player_to_object(M14_navpoint.t2_helipad) < 25)
m14_convo_play( M14_convo.second_antenna )
m14_convo_play( M14_convo.second_rooftop )
group_create(M14_group.t2_small.name, true)
for i, n in pairs( M14_group.t2_small.chars ) do
on_attack_performed( "m14_on_attack_performed_cb", n )
end
-- wait until the heli is in the trigger and one of the players gets out
local in_trigger = false
local has_been_in_trigger = false
local local_player_in_heli = true
local remote_player_in_heli = true
while true do
in_trigger = object_is_in_trigger( M14_trigger.tower2_heli_validation, M14_vehicle.spotlight_heli )
if in_trigger then
if has_been_in_trigger == false then
-- Then spawn the Deckers defending the tower
continuous_spawn_regions_enable(M14_spawn_region.deckers_t2, true)
--m14_continuous_spawns_start(M14_spawn_group.deckers_t2, 3, 3)
call_function_on_each_member(continuous_spawn_start, M14_spawn_group.deckers_t2, 2, 2)
has_been_in_trigger = true
end
local_player_in_heli = character_is_in_vehicle( LOCAL_PLAYER, M14_vehicle.spotlight_heli )
remote_player_in_heli = true
if coop_is_active() then
remote_player_in_heli = character_is_in_vehicle( REMOTE_PLAYER, M14_vehicle.spotlight_heli )
end
if in_trigger == true then
if local_player_in_heli == false or remote_player_in_heli == false then
break
end
end
end
thread_yield()
end
m14_helipad_reached_cb( nil, M14_trigger.tower2_heli_validation )
M14_status.do_tower2_validation = true
M14_status.do_timer_validation = false
M14_status.placement_nav = M14_navpoint.tower_two_placement
M14_status.transmitter_placed = false
M14_status.transmitter_progress = 0
trigger_set_hold_to_repeat( M14_trigger.tower2, true )
m14_set_trigger(M14_trigger.tower2, "m14_transmitter_placement_started_cb", true, true, MINIMAP_ICON_USE, OI_ASSET_USE)
m14_objective_text_clear(0)
end
function m14_objective_plant_second_transmitter()
m14_objective_text(0, M14_text.plant_transmitter, nil, nil, SYNC_ALL, OI_ASSET_USE)
M14_status.transmitter_bar_displayed = true
M14_status.at_tower = true
trigger_enable(M14_trigger.t2_massacre, true)
on_trigger( "m14_studio_massacre_cb", M14_trigger.t2_massacre )
local line_played = false
repeat
if line_played == false and M14_status.transmitter_progress > 0 then
if m14_convo_is_playing() ~= true then
audio_play_persona_line( M14_status.transmitter_activator, "M14_Placing_Second_Transmitter" )
end
line_played = true
end
thread_yield()
until M14_status.transmitter_placed
audio_ambient_emitter_start( "transmitter_2" )
call_function_on_each_member(continuous_spawn_stop, M14_spawn_group.deckers_t2)
continuous_spawn_regions_enable(M14_spawn_region.deckers_t2, false)
M14_status.transmitter_bar_displayed = false
hud_bar_off(M14_PROGRESS_INDEX)
end
function m14_objective_get_in_heli_second_tower()
-- create some more enemies
group_create( M14_group.deckers_t2_4.name, false )
m14_objective_text(0, M14_text.get_in_heli, nil, nil, SYNC_ALL, OI_ASSET_LOCATION)
marker_add(M14_vehicle.spotlight_heli, MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION, OI_FLAGS_FULL)
spotlight_heli_laser_enable(true)
-- Start the timer validation now, in case the helicopter is somehow unreachable, yet within the validation trigger
M14_status.do_timer_validation = true
m14_convo_play( M14_convo.target_van )
m14_wait_for_player_to_enter_vehicle()
M14_status.do_tower2_validation = false
marker_remove(M14_vehicle.spotlight_heli)
m14_objective_text_clear(0)
M14_status.at_tower = false
trigger_enable(M14_trigger.t2_massacre, false)
on_trigger( "", M14_trigger.t2_massacre )
-- wait until convo is done to start radio bit
while m14_convo_is_playing() == true do
thread_yield()
end
m14_interview_play( "m14_interview_part4" )
end
--[[ TOWER 2 ]]--
function m14_initialize_tower2()
teleport(LOCAL_PLAYER, M14_navpoint.cp_tower2_lp, true)
if (coop_is_active()) then
teleport(REMOTE_PLAYER, M14_navpoint.cp_tower2_rp, true)
end
spotlight_heli_laser_enable(true)
group_create(M14_group.cp_tower2, true)
M14_char.shaundi = M14_char.shaundi_t2
M14_vehicle.spotlight_heli = M14_vehicle.cp_t2_spotlight_heli
party_add(M14_char.shaundi)
follower_set_can_abandon(M14_char.shaundi, true)
on_dismiss("m14_shaundi_dismissed_cb", M14_char.shaundi)
--teleport_coop(M14_navpoint.cp_tower2_lp, M14_navpoint.cp_tower2_rp, true)
-- Shaundi should teleport with us since she's in our party
--teleport(M14_char.shaundi, M14_navpoint.cp_tower2_shaundi, true)
on_vehicle_destroyed("m14_spotlight_heli_destroyed_cb", M14_vehicle.spotlight_heli)
on_death("m14_shaundi_died_cb", M14_char.shaundi)
radio_block( M14_vehicle.spotlight_heli, true )
-- Since the previous objective ends after you enter the heli, we need to put you in it now
vehicle_enter_teleport(LOCAL_PLAYER, M14_vehicle.spotlight_heli, VEHICLE_SEAT_DRIVER, true)
vehicle_enter_teleport(M14_char.shaundi, M14_vehicle.spotlight_heli, VEHICLE_SEAT_PASSENGER, true)
if (coop_is_active()) then
vehicle_enter_teleport(REMOTE_PLAYER, M14_vehicle.spotlight_heli, VEHICLE_SEAT_HELI_BACK_DOOR, true)
end
hud_timer_set(M14_TIMER_INDEX, M14_checkpoint_time_tower2_complete * 60 * 1000, "m14_timer_validation_fail_cb")
end
function m14_objective_target_the_van()
local obj_target_van = true
local obj_switch_dist = 110
local van_fleeing = false
local target_progress = 0
local dist, player
-- set up van
group_create(M14_group.broadcast_van, true)
on_vehicle_destroyed("m14_broadcast_van_destroyed_cb", M14_vehicle.broadcast_van)
vehicle_enter_teleport(M14_char.broadcast_van, M14_vehicle.broadcast_van)
vehicle_set_ambient(M14_vehicle.broadcast_van)
vehicle_suppress_npc_exit(M14_vehicle.broadcast_van)
vehicle_infinite_mass( M14_vehicle.broadcast_van )
spotlight_heli_laser_enable(true)
spotlight_heli_laser_size( 1 )
local was_spotted = false
local target_audio = -1
while target_progress < HUD_BAR_MAX_VALUE do
-- see if we need to switch the objective due to distance
dist, player = get_dist_closest_player_to_object(M14_vehicle.broadcast_van)
if obj_target_van then
if dist > obj_switch_dist + 10 then
-- switch to "approach the van" objective
hud_bar_off(M14_PROGRESS_INDEX)
m14_objective_text_clear(0)
m14_objective_text(0, M14_text.go_to_van, nil, nil, SYNC_ALL, OI_ASSET_LOCATION)
marker_remove(M14_vehicle.broadcast_van)
marker_add(M14_vehicle.broadcast_van, MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION, OI_FLAGS_FULL)
-- Remove the fake reticle.
m14_cleanup_fake_laser_reticle()
if van_fleeing == true and m14_convo_is_playing() == false then
m14_convo_play( M14_convo.van_escaping )
end
obj_target_van = false
end
else
if dist < obj_switch_dist - 10 then
-- switch to "target the van" objective
m14_objective_text_clear(0)
hud_bar_on(M14_PROGRESS_INDEX, "health", M14_text.target_van, HUD_BAR_MAX_VALUE)
hud_bar_set_value(M14_PROGRESS_INDEX, target_progress)
marker_remove(M14_vehicle.broadcast_van)
marker_add(M14_vehicle.broadcast_van, MINIMAP_ICON_USE, OI_ASSET_USE, OI_FLAGS_FULL)
obj_target_van = true
-- Give the player a fake reticle.
m14_setup_fake_laser_reticle()
if van_fleeing == false then
-- the set crazy works, but is a little too fast
local max_speed = vehicle_get_max_speed(M14_vehicle.broadcast_van) * 0.65
vehicle_max_speed(M14_vehicle.broadcast_van, max_speed)
vehicle_flee(M14_vehicle.broadcast_van, player)
vehicle_set_crazy(M14_vehicle.broadcast_van, true)
van_fleeing = true
if m14_convo_is_playing() == false then
m14_convo_play( M14_convo.spooked_van )
end
end
end
end
-- see if we need to tick up the target meter
if obj_target_van then
local is_spotted = false
if (coop_is_active() and vehicle_spotlight_is_target_spotted(REMOTE_PLAYER, M14_vehicle.broadcast_van)) then
target_progress = target_progress + HUD_BAR_STEP_VAN
is_spotted = true
elseif (vehicle_spotlight_is_target_spotted(LOCAL_PLAYER, M14_vehicle.broadcast_van)) then
target_progress = target_progress + HUD_BAR_STEP_VAN
is_spotted = true
end
if is_spotted == true and was_spotted == false then
target_audio = audio_object_post_event( "M14_target_in_range" )
elseif is_spotted == false and was_spotted == true then
audio_object_post_event( "M14_target_in_range_stop" )
audio_stop( target_audio )
target_audio = -1
end
was_spotted = is_spotted
hud_bar_set_value(M14_PROGRESS_INDEX, target_progress)
spotlight_heli_laser_size( 1 - ( target_progress / 100 ) )
end
delay( HUD_BAR_DELAY_VAN )
end
if target_audio ~= -1 then
audio_stop( target_audio )
end
audio_object_post_event( "M14_signal_intercepted" )
-- clean up objective
marker_remove(M14_vehicle.broadcast_van)
spotlight_heli_laser_enable( false )
vehicle_spotlight_cancel( LOCAL_PLAYER )
-- Remove the fake reticle.
m14_cleanup_fake_laser_reticle()
if coop_is_active() then
vehicle_spotlight_cancel( REMOTE_PLAYER )
end
hud_bar_off(M14_PROGRESS_INDEX)
m14_objective_text_clear(0)
-- make sure call in gets played at proper time
M14_status.play_radio_call_in = true
end
function m14_radio_call_in_stop( block )
-- kill the thread
if M14_thread.radio_call_in ~= INVALID_THREAD_HANDLE then
thread_kill( M14_thread.radio_call_in )
-- We probably set up an audio failsafe, clear it.
thread_kill(M14_thread.audio_failsafe)
M14_thread.audio_failsafe = INVALID_THREAD_HANDLE
end
-- if there's a radio event playing, stop that
if M14_status.radio_event ~= nil then
audio_stop( M14_status.radio_event )
M14_status.radio_event = nil
end
-- the player may be speaking
-- there isn't a way to stop that so we'll just
-- wait for it to play out.
-- of course we can't do this during clean up
if block == true then
m14_wait_for_persona_line_safe(LOCAL_PLAYER)
end
end
function m14_radio_call_in_thread()
local switch_groups = { "Radio_News_Breaks" }
local switch_ids = { "M14_Interview_Call_In_Part1" }
M14_status.radio_event = audio_object_post_event("Radio_News_Breaks", switch_groups, switch_ids, LOCAL_PLAYER)
-- Wait until event is not active
m14_wait_for_audio_safe(M14_status.radio_event)
-- play player voice
audio_play_persona_line(LOCAL_PLAYER, "M14_Radio_Interview_Call_In_02")
-- wait for player line to finish
m14_wait_for_persona_line_safe(LOCAL_PLAYER)
switch_ids = { "M14_Interview_Call_In_Part2" }
M14_status.radio_event = audio_object_post_event("Radio_News_Breaks", switch_groups, switch_ids, LOCAL_PLAYER)
-- Wait until event is not active
m14_wait_for_audio_safe(M14_status.radio_event)
-- play player voice
audio_play_persona_line(LOCAL_PLAYER, "M14_Radio_Interview_Call_In_04")
-- wait for player line to finish
m14_wait_for_persona_line_safe(LOCAL_PLAYER)
switch_ids = { "M14_Interview_Call_In_Part3" }
M14_status.radio_event = audio_object_post_event("Radio_News_Breaks", switch_groups, switch_ids, LOCAL_PLAYER)
-- Wait until event is not active
m14_wait_for_audio_safe(M14_status.radio_event)
-- play player voice
audio_play_persona_line(LOCAL_PLAYER, "M14_Radio_Interview_Call_In_07")
-- wait for player line to finish
m14_wait_for_persona_line_safe(LOCAL_PLAYER)
switch_ids = { "M14_Interview_Call_In_Part4" }
M14_status.radio_event = audio_object_post_event("Radio_News_Breaks", switch_groups, switch_ids, LOCAL_PLAYER)
-- Wait until event is not active
m14_wait_for_audio_safe(M14_status.radio_event)
-- play player voice
audio_play_persona_line(LOCAL_PLAYER, "M14_Radio_Interview_Call_In_10")
-- wait for player line to finish
m14_wait_for_persona_line_safe(LOCAL_PLAYER)
switch_ids = { "M14_Interview_Call_In_Part5" }
M14_status.radio_event = audio_object_post_event("Radio_News_Breaks", switch_groups, switch_ids, LOCAL_PLAYER)
-- Wait until event is not active
m14_wait_for_audio_safe(M14_status.radio_event)
-- play player voice
audio_play_persona_line(LOCAL_PLAYER, "M14_Radio_Interview_Call_In_12")
-- wait for player line to finish
m14_wait_for_persona_line_safe(LOCAL_PLAYER)
switch_ids = { "M14_Interview_Call_In_Part6" }
M14_status.radio_event = audio_object_post_event("Radio_News_Breaks", switch_groups, switch_ids, LOCAL_PLAYER)
end
function m14_objective_go_to_interview()
spotlight_heli_laser_enable(false)
m14_objective_text(0, M14_text.go_to_interview, nil, nil, SYNC_ALL, OI_ASSET_LOCATION)
M14_status.helipad_reached = false
m14_set_helipad_trigger(M14_trigger.helipad, "m14_helipad_reached_cb", M14_navpoint.interview_helipad, true, true, MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION)
delay(1)
-- do the player radio call-in in another thread
if M14_status.play_radio_call_in then
m14_convo_play(M14_convo.got_location, true)
M14_thread.radio_call_in = thread_new("m14_radio_call_in_thread")
end
-- Wait until the player gets near the vicinity of the helipad
repeat
thread_yield()
until (get_dist_closest_player_to_object(M14_trigger.helipad) < 100)
m14_radio_call_in_stop( true )
m14_convo_play( M14_convo.land_on_office )
group_create(M14_group.helipad, false)
for i, n in pairs( M14_group.helipad.chars ) do
on_attack_performed( "m14_on_attack_performed_cb", n )
end
repeat
thread_yield()
until (M14_status.helipad_reached)
trigger_enable(M14_trigger.studio_massacre, true)
on_trigger("m14_studio_massacre_cb", M14_trigger.studio_massacre)
M14_status.do_interview_validation = true
M14_status.do_timer_validation = false
m14_objective_text_clear(0)
end
function m14_objective_enter_building()
m14_objective_text(0, M14_text.enter_building, nil, nil, SYNC_ALL, OI_ASSET_LOCATION)
M14_status.interview_stairs_reached = false
m14_set_trigger(M14_trigger.interview_stairs, "m14_interview_stairs_reached_cb", true, true, MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION)
repeat
thread_yield()
until (M14_status.interview_stairs_reached)
m14_objective_text_clear(0)
end
--[[ INTERVIEW LOCATION ]]--
function m14_initialize_van()
teleport(LOCAL_PLAYER, M14_navpoint.cp_studio_lp, true)
if (coop_is_active()) then
teleport(REMOTE_PLAYER, M14_navpoint.cp_studio_rp, true)
end
group_create(M14_group.cp_studio, true)
M14_char.shaundi = M14_char.shaundi_studio
M14_vehicle.spotlight_heli = M14_vehicle.cp_studio_spotlight_heli
party_add(M14_char.shaundi)
follower_set_can_abandon(M14_char.shaundi, true)
on_dismiss("m14_shaundi_dismissed_cb", M14_char.shaundi)
on_vehicle_destroyed("m14_spotlight_heli_destroyed_cb", M14_vehicle.spotlight_heli)
on_death("m14_shaundi_died_cb", M14_char.shaundi)
radio_block( M14_vehicle.spotlight_heli, true )
teleport_vehicle( M14_vehicle.spotlight_heli, M14_navpoint.cp_van_complete_heli, true )
-- Since the previous objective ends after you enter the heli, we need to put you in it now
vehicle_enter_teleport(LOCAL_PLAYER, M14_vehicle.spotlight_heli, VEHICLE_SEAT_DRIVER, true)
vehicle_enter_teleport(M14_char.shaundi, M14_vehicle.spotlight_heli, VEHICLE_SEAT_PASSENGER, true)
if (coop_is_active()) then
vehicle_enter_teleport(REMOTE_PLAYER, M14_vehicle.spotlight_heli, VEHICLE_SEAT_HELI_BACK_DOOR, true)
end
hud_timer_set(M14_TIMER_INDEX, M14_checkpoint_time_target_van_complete * 60 * 1000, "m14_timer_validation_fail_cb")
end
function m14_initialize_studio()
teleport(LOCAL_PLAYER, M14_navpoint.cp_studio_lp, true)
if (coop_is_active()) then
teleport(REMOTE_PLAYER, M14_navpoint.cp_studio_rp, true)
end
group_create(M14_group.cp_studio, true)
M14_char.shaundi = M14_char.shaundi_studio
M14_vehicle.spotlight_heli = M14_vehicle.cp_studio_spotlight_heli
party_add(M14_char.shaundi)
follower_set_can_abandon(M14_char.shaundi, true)
on_dismiss("m14_shaundi_dismissed_cb", M14_char.shaundi)
on_vehicle_destroyed("m14_spotlight_heli_destroyed_cb", M14_vehicle.spotlight_heli)
on_death("m14_shaundi_died_cb", M14_char.shaundi)
M14_status.do_interview_validation = true
M14_status.do_timer_validation = false
trigger_enable(M14_trigger.studio_massacre, true)
on_trigger("m14_studio_massacre_cb", M14_trigger.studio_massacre)
radio_block( M14_vehicle.spotlight_heli, true )
hud_timer_set(M14_TIMER_INDEX, M14_checkpoint_time_get_to_studio * 60 * 1000, "m14_timer_validation_fail_cb")
end
function m14_objective_clear_deckers()
group_create(M14_group.jane.name, true)
group_create(M14_group.deckers_studio.name, true)
character_prevent_explosion_fling( M14_char.jane, true )
M14_thread.jane_cower = thread_new( "m14_make_jane_cower" )
npc_leash_to_nav(M14_char.jane, M14_navpoint.jane_tether, 1)
set_ignore_ai_flag( M14_char.jane, true )
character_prevent_bumping( M14_char.jane, true )
character_prevent_flinching( M14_char.jane, true )
on_death("m14_jane_died_cb", M14_char.jane)
set_dont_attack_me_on_sight_flag( M14_char.jane, true )
m14_convo_play(M14_convo.enter_office, true)
m14_objective_text(0, M14_text.clear_deckers, nil, nil, SYNC_ALL, OI_ASSET_KILL)
M14_status.deckers_alive = 0
for i,npc in pairs(M14_char.deckers_studio) do
if (character_exists(npc) and not character_is_dead(npc)) then
marker_add( npc, MINIMAP_ICON_KILL, OI_ASSET_KILL )
on_death("m14_remove_marker_cb", npc)
M14_status.deckers_alive = M14_status.deckers_alive + 1
on_attack_performed( "m14_on_attack_performed_cb", npc )
end
end
repeat
thread_yield()
until (M14_status.deckers_alive <= 2)
--[[ Elevator Group ]]--
turn_invulnerable(LOCAL_PLAYER)
if (coop_is_active()) then
turn_invulnerable(REMOTE_PLAYER)
end
group_create(M14_group.deckers_elevator.name, true)
for i,npc in pairs(M14_char.deckers_elevator_fs) do
--teleport(npc, M14_navpoint.deckers_elevator[i])
npc_leash_to_nav(npc, M14_navpoint.deckers_elevator[i], 5)
ai_do_scripted_move(npc, M14_navpoint.deckers_elevator[i], true, false)
marker_add( npc, MINIMAP_ICON_KILL, OI_ASSET_KILL )
on_death("m14_remove_marker_cb", npc)
M14_status.deckers_alive = M14_status.deckers_alive + 1
on_attack_performed( "m14_on_attack_performed_cb", npc )
end
for i,npc in pairs(M14_char.deckers_elevator_rb) do
--teleport(npc, M14_navpoint.deckers_elevator[1])
ai_do_scripted_move(npc, M14_navpoint.elevator_rb, true, false)
marker_add( npc, MINIMAP_ICON_KILL, OI_ASSET_KILL )
on_death("m14_remove_marker_cb", npc)
M14_status.deckers_alive = M14_status.deckers_alive + 1
end
turn_vulnerable(LOCAL_PLAYER)
if (coop_is_active()) then
turn_vulnerable(REMOTE_PLAYER)
end
door_open(M14_script_mover.elevator)
repeat
thread_yield()
until (M14_status.deckers_alive <= 3)
--[[ Corner Group ]]--
turn_invulnerable(LOCAL_PLAYER)
if (coop_is_active()) then
turn_invulnerable(REMOTE_PLAYER)
end
group_create(M14_group.deckers_corner.name, true)
for i,npc in pairs(M14_char.deckers_corner_fs) do
npc_leash_to_nav(npc, M14_navpoint.deckers_corner[i], 5)
ai_do_scripted_move(npc, M14_navpoint.deckers_corner[i], true, false)
marker_add( npc, MINIMAP_ICON_KILL, OI_ASSET_KILL )
on_death("m14_remove_marker_cb", npc)
M14_status.deckers_alive = M14_status.deckers_alive + 1
on_attack_performed( "m14_on_attack_performed_cb", npc )
end
for i,npc in pairs(M14_char.deckers_corner_rb) do
ai_do_scripted_move(npc, M14_navpoint.corner_rb, true, false)
marker_add( npc, MINIMAP_ICON_KILL, OI_ASSET_KILL )
on_death("m14_remove_marker_cb", npc)
M14_status.deckers_alive = M14_status.deckers_alive + 1
on_attack_performed( "m14_on_attack_performed_cb", npc )
end
delay(1)
--[[ Side Group ]]--
group_create(M14_group.deckers_side.name, true)
for i,npc in pairs(M14_char.deckers_side_fs) do
--teleport(npc, M14_navpoint.deckers_side[i])
npc_leash_to_nav(npc, M14_navpoint.deckers_side[i], 5)
ai_do_scripted_move(npc, M14_navpoint.deckers_side[i], true, false)
marker_add( npc, MINIMAP_ICON_KILL, OI_ASSET_KILL )
on_death("m14_remove_marker_cb", npc)
M14_status.deckers_alive = M14_status.deckers_alive + 1
on_attack_performed( "m14_on_attack_performed_cb", npc )
end
for i,npc in pairs(M14_char.deckers_side_rb) do
--teleport(npc, M14_navpoint.deckers_side[1])
ai_do_scripted_move(npc, M14_navpoint.side_rb, true, false)
marker_add( npc, MINIMAP_ICON_KILL, OI_ASSET_KILL )
on_death("m14_remove_marker_cb", npc)
M14_status.deckers_alive = M14_status.deckers_alive + 1
on_attack_performed( "m14_on_attack_performed_cb", npc )
end
door_open(M14_script_mover.side_door[1])
door_open(M14_script_mover.side_door[2])
turn_vulnerable(LOCAL_PLAYER)
if (coop_is_active()) then
turn_vulnerable(REMOTE_PLAYER)
end
repeat
thread_yield()
until (M14_status.deckers_alive <= 4)
--[[ Stairs Group ]]--
turn_invulnerable(LOCAL_PLAYER)
if (coop_is_active()) then
turn_invulnerable(REMOTE_PLAYER)
end
group_create(M14_group.deckers_stairs.name, true)
for i,npc in pairs(M14_char.deckers_stairs_fs) do
npc_leash_to_nav(npc, M14_navpoint.deckers_stairs[i], 5)
ai_do_scripted_move(npc, M14_navpoint.deckers_stairs[i], true, false)
marker_add( npc, MINIMAP_ICON_KILL, OI_ASSET_KILL )
on_death("m14_remove_marker_cb", npc)
M14_status.deckers_alive = M14_status.deckers_alive + 1
on_attack_performed( "m14_on_attack_performed_cb", npc )
end
for i,npc in pairs(M14_char.deckers_stairs_rb) do
ai_do_scripted_move(npc, M14_navpoint.stairs_rb, true, false)
marker_add( npc, MINIMAP_ICON_KILL, OI_ASSET_KILL )
on_death("m14_remove_marker_cb", npc)
M14_status.deckers_alive = M14_status.deckers_alive + 1
on_attack_performed( "m14_on_attack_performed_cb", npc )
end
turn_vulnerable(LOCAL_PLAYER)
if (coop_is_active()) then
turn_vulnerable(REMOTE_PLAYER)
end
repeat
thread_yield()
until (M14_status.deckers_alive <= 0)
clear_animation_state( M14_char.jane )
if M14_thread.jane_cower ~= nil then
thread_kill( M14_thread.jane_cower )
M14_thread.jane_cower = nil
end
m14_objective_text_clear(0)
end
function m14_objective_talk_to_jane()
-- keep Shaundi from attacking anyone
npc_combat_enable( M14_char.shaundi, false )
m14_objective_text(0, M14_text.talk_to_jane, nil, nil, SYNC_ALL, OI_ASSET_LOCATION)
marker_add(M14_char.jane, MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION, OI_FLAGS_FULL)
local dist, player
repeat
thread_yield()
dist, player = get_dist_closest_player_to_object( M14_char.jane )
until ( dist < 3 )
marker_remove(M14_char.jane)
m14_objective_text_clear(0)
M14_convo.question_jane.coop_player = player
M14_convo.go_after_killbane.coop_player = player
m14_convo_play( M14_convo.question_jane, nil, nil )
m14_convo_play( M14_convo.go_after_killbane, nil, nil )
npc_combat_enable( M14_char.shaundi, true )
end
function m14_objective_get_in_heli_chase_killbane()
m14_objective_text(0, M14_text.get_in_heli, nil, nil, SYNC_ALL, OI_ASSET_LOCATION)
M14_status.helipad_reached = false
m14_set_trigger(M14_trigger.studio_stairs1, "m14_helipad_reached_cb", false, true, MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION)
repeat
thread_yield()
until (M14_status.helipad_reached)
M14_status.helipad_reached = false
m14_set_trigger(M14_trigger.studio_stairs2, "m14_helipad_reached_cb", false, true, MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION)
repeat
thread_yield()
until (M14_status.helipad_reached)
M14_status.helipad_reached = false
m14_set_trigger(M14_trigger.helipad, "m14_helipad_reached_cb", false, true, MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION)
repeat
thread_yield()
until (M14_status.helipad_reached)
marker_add(M14_vehicle.spotlight_heli, MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION, OI_FLAGS_FULL)
group_create(M14_group.killbane, true)
vehicle_enter_teleport(M14_char.killbane, M14_vehicle.killbane_escape)
vehicle_suppress_npc_exit(M14_vehicle.killbane_escape, true)
set_unjackable_flag( M14_vehicle.killbane_escape, true )
-- Start the timer validation now, in case the helicopter is somehow unreachable, yet within the validation trigger
M14_status.do_timer_validation = true
m14_wait_for_player_to_enter_vehicle()
marker_remove(M14_vehicle.spotlight_heli)
trigger_enable(M14_trigger.studio_massacre, false)
on_trigger("", M14_trigger.studio_massacre)
m14_objective_text_clear(0)
end
function m14_objective_catch_killbane()
m14_objective_text(0, M14_text.catch_killbane, nil, nil, SYNC_ALL, OI_ASSET_LOCATION)
M14_thread.killbane_escape = thread_new("m14_wrapper_thread", vehicle_pathfind_to, M14_vehicle.killbane_escape, M14_navpoint.killbane_escape)
marker_add(M14_vehicle.killbane_escape, MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION, OI_FLAGS_FULL)
delay( 5 )
m14_convo_play( M14_convo.helecopter_end )
-- finish when close enough and in heli
if coop_is_active() then
repeat
thread_yield()
local local_caught_kb = character_is_in_vehicle( LOCAL_PLAYER, M14_vehicle.spotlight_heli ) and get_dist( LOCAL_PLAYER, M14_vehicle.killbane_escape ) < 55
local remote_caught_kb = character_is_in_vehicle( REMOTE_PLAYER, M14_vehicle.spotlight_heli ) and get_dist( REMOTE_PLAYER, M14_vehicle.killbane_escape ) < 55
until local_caught_kb or remote_caught_kb
else
while character_is_in_vehicle( LOCAL_PLAYER, M14_vehicle.spotlight_heli ) == false or get_dist( LOCAL_PLAYER, M14_vehicle.killbane_escape ) > 55 do
thread_yield()
end
end
M14_status.do_interview_validation = false
object_indicator_remove(M14_vehicle.killbane_escape)
hud_timer_stop(M14_TIMER_INDEX)
m14_objective_text_clear(0)
end
-- Waits for an audio event to finish or until a maximum amount of time has elapsed.
--
-- audio_id: (int) the event to wait for.
-- max_wait: (float, optional) the maximum amount of time to wait.
--
function m14_wait_for_audio_safe(audio_id, max_wait)
if max_wait == nil then
max_wait = 60.0
end
-- Wait for anything that's using the failsafe thread to finish.
while M14_thread.audio_failsafe ~= INVALID_THREAD_HANDLE do
thread_yield()
end
M14_thread.audio_failsafe = thread_new("delay", max_wait)
-- Wait for the audio to finish or for our failsafe to kick in.
while audio_is_playing(audio_id) and thread_check_done(M14_thread.audio_failsafe) == false do
thread_yield()
end
-- If the audio is still playing, kill it.
if audio_is_playing(audio_id) then
audio_stop(audio_id)
end
thread_kill(M14_thread.audio_failsafe)
M14_thread.audio_failsafe = INVALID_THREAD_HANDLE
end
-- Waits for a conversation to finish or until a maximum amount of time has elapsed.
--
-- convo_handle: (int) handle to the conversation to wait for.
-- max_wait: (float, optional) the maximum amount of time to wait.
--
function m14_wait_for_convo_safe(convo_handle, max_wait)
if max_wait == nil then
max_wait = 60.0
end
-- Wait for anything that's using the failsafe thread to finish.
while M14_thread.audio_failsafe ~= INVALID_THREAD_HANDLE do
thread_yield()
end
M14_thread.audio_failsafe = thread_new("delay", max_wait)
-- Wait for the conversation to finish or for our failsafe to kick in.
while audio_conversation_playing(convo_handle) and thread_check_done(M14_thread.audio_failsafe) == false do
thread_yield()
end
audio_conversation_end(convo_handle)
thread_kill(M14_thread.audio_failsafe)
M14_thread.audio_failsafe = INVALID_THREAD_HANDLE
end
-- Waits for a persona line to finish on a human or until a maximum amount of time has elapsed.
--
-- human_name: (string) name of the human.
-- max_wait: (float, optional) the maximum amount of time to wait.
--
function m14_wait_for_persona_line_safe(human_name, max_wait)
if max_wait == nil then
max_wait = 30.0
end
-- Wait for anything that's using the failsafe thread to finish.
while M14_thread.audio_failsafe ~= INVALID_THREAD_HANDLE do
thread_yield()
end
M14_thread.audio_failsafe = thread_new("delay", max_wait)
-- Wait for the conversation to finish or for our failsafe to kick in.
while audio_persona_line_playing(human_name) and thread_check_done(M14_thread.audio_failsafe) == false do
thread_yield()
end
thread_kill(M14_thread.audio_failsafe)
M14_thread.audio_failsafe = INVALID_THREAD_HANDLE
end
-- ***************************************************
--
-- m14_initialize Helper Functions
--
-- ***************************************************
-- Handle any common initialization
--
function m14_initialize_common()
-- Always have timer validation when the mission starts
M14_status.do_timer_validation = true
notoriety_force_no_spawn("luchadores", true)
notoriety_force_no_spawn("deckers", true)
notoriety_force_no_spawn("morningstar", true)
notoriety_force_no_spawn("police", true)
radio_global_block( true )
-- Start up the conversation manager.
M14_thread.convo_manager = thread_new( "m14_convo_manager" )
-- Load 2D personas.
for i, persona in pairs(M14_2d_personas) do
persona.handle = audio_persona_load_2d( persona.name )
end
end
-- Checkpoint specific initialization
--
-- checkpoint: The checkpoint to be initialized
--
function m14_initialize_checkpoint(checkpoint)
if (checkpoint == M14_CHECKPOINT_GET_TO_HELI) then
m14_initialize_heli()
elseif (checkpoint == M14_CHECKPOINT_TOWER1_COMPLETE) then
m14_initialize_tower1()
elseif (checkpoint == M14_CHECKPOINT_TOWER2_COMPLETE) then
m14_initialize_tower2()
elseif checkpoint == M14_CHECKPOINT_TARGET_VAN_COMPLETE then
m14_initialize_van()
elseif (checkpoint == M14_CHECKPOINT_GET_TO_STUDIO) then
m14_initialize_studio()
end
if checkpoint ~= MISSION_START_CHECKPOINT and checkpoint ~= M14_CHECKPOINT_GET_TO_HELI then
M14_thread.abandon_heli = thread_new( "m14_abandon_heli_thread" )
end
end
-- ***************************************************
--
-- Miscellaneous m14 Helper Funcrtions
--
-- ***************************************************
function m14_set_helipad_trigger(trigger, trigger_callback, navpoint, add_waypoint, add_marker, minimap_icon, indicator_id)
M14_status.proxy_navpoint = navpoint
trigger_enable(trigger, true)
if (add_waypoint ~= false) then
mission_waypoint_add(navpoint)
end
if (add_marker ~= false) then
if (minimap_icon == nil) then
minimap_icon = MINIMAP_ICON_LOCATION
end
marker_add(navpoint, minimap_icon, indicator_id, OI_FLAGS_FULL)
end
if trigger_callback ~= nil then
on_trigger(trigger_callback, trigger)
end
end
-- Set a trigger enabled with a mission marker
--
-- trigger: (string) Name of the trigger
-- trigger_callback: (string) Function name to call when trigger is activated
-- add_waypoint: (bool, optional) true to add a waypoint, false otherwise (defaults to true)
-- add_marker: (bool, optional) true to add a marker, false otherwise (defaults to true)
-- minimap_icon: (enum, optional) name of the minimap icon to add to the trigger
-- indicator_id: (enum, optional) ID of the object indicator to add to the trigger
--
function m14_set_trigger(trigger, trigger_callback, add_waypoint, add_marker, minimap_icon, indicator_id)
trigger_enable(trigger, true)
if (add_waypoint ~= false) then
mission_waypoint_add(trigger)
end
if (add_marker ~= false) then
if (minimap_icon == nil) then
minimap_icon = MINIMAP_ICON_LOCATION
end
marker_add_trigger(trigger, minimap_icon, INGAME_EFFECT_CHECKPOINT, indicator_id, OI_FLAGS_FULL, SYNC_ALL)
end
on_trigger(trigger_callback, trigger)
end
-- Disable trigger
--
-- trigger: (string) Name of the trigger
--
function m14_clear_trigger(trigger)
on_trigger("", trigger)
trigger_enable(trigger, false)
marker_remove_trigger(trigger, SYNC_ALL)
mission_waypoint_remove()
end
function m14_continuous_spawns_start(spawn_group, num_spawns, delay, callback)
call_function_on_each_member(continuous_spawn_start, spawn_group, num_spawns, delay, callback)
end
function m14_continuous_spawns_stop(spawn_group)
call_function_on_each_member(continuous_spawn_stop, spawn_group)
end
function m14_wait_for_player_to_enter_vehicle()
if (coop_is_active()) then
repeat
thread_yield()
until (character_is_in_vehicle(LOCAL_PLAYER, M14_vehicle.spotlight_heli) or character_is_in_vehicle(REMOTE_PLAYER, M14_vehicle.spotlight_heli))
else
repeat
thread_yield()
until character_is_in_vehicle(LOCAL_PLAYER, M14_vehicle.spotlight_heli)
end
end
function m14_wait_for_players_to_exit_vehicle()
if (coop_is_active()) then
while (character_is_in_vehicle(LOCAL_PLAYER, M14_vehicle.spotlight_heli) or character_is_in_vehicle(REMOTE_PLAYER, M14_vehicle.spotlight_heli)) do
thread_yield()
end
else
while character_is_in_vehicle(LOCAL_PLAYER, M14_vehicle.spotlight_heli) do
thread_yield()
end
end
end
-- Displays the heli warning objective
--
function m14_display_heli_warning_objective()
if (M14_status.transmitter_bar_displayed or M14_status.target_progress_displayed) then
hud_bar_off(M14_PROGRESS_INDEX)
end
-- The warning message replaces whatever objective we currently have
objective_text(0, M14_text.get_in_heli, nil, nil, SYNC_ALL, OI_ASSET_LOCATION)
marker_add(M14_vehicle.spotlight_heli, MINIMAP_ICON_LOCATION, OI_ASSET_LOCATION)
end
-- Clears the heli warning objective, and restores the current objective if we have one
--
function m14_clear_heli_warning_objective()
objective_text_clear(0)
marker_remove(M14_vehicle.spotlight_heli)
-- There may not be any text currently displayed
if (M14_objective_text.gsi_index ~= nil) then
-- Set the objective text back to what it was before the warning went up
objective_text(M14_objective_text.gsi_index, M14_objective_text.text, M14_objective_text.sub1, M14_objective_text.sub2, M14_objective_text.sync_type, M14_objective_text.oi_asset)
elseif (M14_status.target_progress_displayed) then
hud_bar_on(M14_PROGRESS_INDEX, "health", M14_text.target_van, HUD_BAR_MAX_VALUE)
elseif (M14_status.transmitter_bar_displayed) then
hud_bar_on(M14_PROGRESS_INDEX, "health", M14_text.plant_transmitter, HUD_BAR_MAX_VALUE)
end
end
-- Mission-specific wrapper for objective_text() that saves off the current objective in case the helicopter re-entry warning
-- is displayed, to allow it to be restored when the helicopter has been re-entered
--
-- gsi_index: (int) index of the objective to display
-- text: (string) the objective text to display
-- sub1: (string) sub-string to be placed into the string (if the main text has format tags)
-- sub2: (string) sub-string to be placed into the string (if the main text has format tags)
-- sync_type: (enum) SYNC_LOCAL, SYNC_REMOTE, SYNC_ALL
-- oi_asset: (enum) asset to be displayed next to the objective (i.e. OI_ASSET_KILL, OI_ASSET_LOCATION, etc.)
--
function m14_objective_text(gsi_index, text, sub1, sub2, sync_type, oi_asset)
M14_objective_text.gsi_index = gsi_index
M14_objective_text.text = text
M14_objective_text.sub1 = sub1
M14_objective_text.sub2 = sub2
M14_objective_text.sync_type = sync_type
M14_objective_text.oi_asset = oi_asset
-- Only change the objective text if the helicopter re-entry warning isn't currently active
if (not M14_status.timer_active) then
objective_text(gsi_index, text, sub1, sub2, sync_type, oi_asset)
end
end
-- Mission-specific wrapper for objective_text_clear() that ensures the helicopter re-entry warning isn't cleared accidentally
--
-- gsi_index: (int) index of the objective text to clear
--
function m14_objective_text_clear(gsi_index)
-- If the indices match, we are simply clearing the objective text so that it can be set to something else
M14_objective_text.gsi_index = nil
M14_objective_text.text = nil
M14_objective_text.sub1 = nil
M14_objective_text.sub2 = nil
M14_objective_text.sync_type = nil
M14_objective_text.oi_asset = nil
-- Only clear the objective text if the helicopter re-entry warning isn't currently active
if (not M14_status.timer_active) then
objective_text_clear(gsi_index)
end
end
-- *************************
--
-- Callback functions
--
-- *************************
function m14_transmitter_placement_started_cb( activator, tower )
-- only one at a time please
if M14_status.transmitter_activator ~= nil and M14_status.transmitter_activator ~= activator then
return
end
player_movement_disable( activator )
local progress = M14_status.transmitter_progress
if progress == 0 then
m14_objective_text_clear(0)
hud_bar_on(M14_PROGRESS_INDEX, "health", M14_text.plant_transmitter, HUD_BAR_MAX_VALUE)
-- wait until player is ready to play an animation
while character_is_ready( LOCAL_PLAYER ) == false do
thread_yield()
end
M14_status.transmitter_activator = activator
-- Play the intro animation
if M14_status.transmitter_started ~= true then
action_play( activator, "m14 transmitter in", "m14 transmitter in", false, 0.8, true, true, M14_status.placement_nav )
end
-- Play the middle section of the animation.
set_animation_state( activator, "m14 transmitter idle", M14_status.placement_nav )
end
if M14_thread.transmitter_monitor == nil then
M14_thread.transmitter_monitor = thread_new( "m14_maybe_cancel_transmitter_thread" )
end
progress = progress + HUD_BAR_STEP_TRANSMITTER
hud_bar_set_value( M14_PROGRESS_INDEX, progress )
if progress >= HUD_BAR_MAX_VALUE then
player_movement_enable( activator )
M14_status.transmitter_placed = true
M14_status.transmitter_activator = nil
m14_clear_trigger( tower )
-- kill the monitor thread, not needed any more
if M14_thread.transmitter_monitor ~= nil then
thread_kill( M14_thread.transmitter_monitor )
M14_thread.transmitter_monitor = nil
end
-- Play the outro animation.
clear_animation_state( activator )
action_play( activator, "m14 transmitter out", "m14 transmitter out", false, 1, true, true )
M14_status.transmitter_started = nil
else
M14_status.transmitter_progress = progress
end
hud_bar_set_value( M14_PROGRESS_INDEX, progress )
end
-- watches for lack of progress in getting the transmitter up
-- and cancels if there is none
function m14_maybe_cancel_transmitter_thread()
local prev_progress = M14_status.transmitter_progress
while true do
delay( 1 )
if M14_status.transmitter_progress <= prev_progress then
-- no progress so break out and kill it
break
end
prev_progress = M14_status.transmitter_progress
end
if M14_status.transmitter_activator ~= nil then
player_movement_enable( M14_status.transmitter_activator )
-- remove the triangulator left behind by the anim
character_remove_child_item_by_name( M14_status.transmitter_activator, "Triangulator" )
-- Play the outro animation.
clear_animation_state( M14_status.transmitter_activator )
end
hud_bar_off( M14_PROGRESS_INDEX )
m14_objective_text(0, M14_text.plant_transmitter, nil, nil, SYNC_ALL, OI_ASSET_USE)
M14_status.transmitter_progress = 0
M14_status.transmitter_activator = nil
hud_bar_set_value( M14_PROGRESS_INDEX, 0 )
M14_thread.transmitter_monitor = nil
M14_status.transmitter_started = true
end
function m14_studio_massacre_cb(poor_sumbitch)
if poor_sumbitch == LOCAL_PLAYER or poor_sumbitch == REMOTE_PLAYER then
mission_end_failure( "m14", M14_text.failure_heli_abandoned )
elseif poor_sumbitch ~= nil then
character_kill(poor_sumbitch, true, nil, false)
end
end
function m14_helipad_reached_cb(activator_name, trigger_name)
m14_clear_trigger(trigger_name)
mission_waypoint_remove()
marker_remove(M14_status.proxy_navpoint)
M14_status.helipad_reached = true
end
function m14_left_studio_cb()
trigger_enable(M14_trigger.helipad, false)
on_trigger_exit("", M14_trigger.helipad)
M14_status.helipad_left = true
end
function m14_interview_stairs_reached_cb()
m14_clear_trigger(M14_trigger.interview_stairs)
M14_status.interview_stairs_reached = true
end
function m14_spotlight_heli_destroyed_cb()
on_vehicle_destroyed("", M14_vehicle.spotlight_heli)
mission_end_failure("m14", M14_text.failure_heli_destroyed)
end
function m14_broadcast_van_destroyed_cb()
on_vehicle_destroyed("", M14_vehicle.broadcast_van)
mission_end_failure("m14", M14_text.failure_van_destroyed)
end
function m14_shaundi_died_cb()
on_death("", M14_char.shaundi)
mission_end_failure("m14", M14_text.failure_shaundi_died)
end
function m14_jane_died_cb()
on_death("", M14_char.jane)
mission_end_failure("m14", M14_text.failure_jane_died)
end
function m14_shaundi_dismissed_cb()
on_dismiss("", M14_char.shaundi)
mission_end_failure("m14", M14_text.failure_shaundi_abandoned)
end
function m14_timer_validation_fail_cb()
hud_timer_stop(M14_TIMER_INDEX)
mission_end_failure("m14", M14_text.failure_killbane_escaped)
end
function m14_remove_marker_cb(npc)
marker_remove(npc)
M14_status.deckers_alive = M14_status.deckers_alive - 1
end
-- *************************
--
-- Thread functions
--
-- *************************
-- Thread that runs for the entirety of the mission to validate mission status for things that can't be caught with callbacks
--
function m14_failure_validation_thread()
while (1) do
if (vehicle_exists(M14_vehicle.spotlight_heli)) then
local player_is_in_heli = character_is_in_vehicle(LOCAL_PLAYER, M14_vehicle.spotlight_heli)
if (not player_is_in_heli and coop_is_active()) then
player_is_in_heli = character_is_in_vehicle(REMOTE_PLAYER, M14_vehicle.spotlight_heli)
end
if (not player_is_in_heli) then
-- it's ok for the player to be out of the heli if they in one of the action zones
local heli_not_in_action_zone = false
local total_time = 60000 -- 60 seconds by default
-- If we're at tower 1, make sure the heli stays within the validation trigger
if (M14_status.do_tower1_validation) then
if (not object_is_in_trigger(M14_trigger.tower1_heli_validation, M14_vehicle.spotlight_heli)) then
heli_not_in_action_zone = true
end
-- If we're at tower 2, make sure the heli stays within the validation trigger
elseif (M14_status.do_tower2_validation) then
total_time = 90000 -- a bit more to do, give more time
if (not object_is_in_trigger(M14_trigger.tower2_heli_validation, M14_vehicle.spotlight_heli)) then
heli_not_in_action_zone = true
end
-- If we're at the interview location, make sure the heli stays within the validation trigger
elseif (M14_status.do_interview_validation) then
if (not object_is_in_trigger(M14_trigger.helipad, M14_vehicle.spotlight_heli)) then
heli_not_in_action_zone = true
end
end
-- If we're not at any of the locations, give the player a timer to get back in their heli
if heli_not_in_action_zone == true or M14_status.do_timer_validation then
if (M14_status.timer_active) then
if (not M14_status.timer_displayed and hud_timer_get_remainder(M14_TIMER_INDEX) < 15000) then
-- Display the timer for the last 10 seconds
hud_timer_hide(M14_TIMER_INDEX, false)
M14_status.timer_displayed = true
end
else -- Timer not active, start it up, but keep it hidden at first
if (M14_status.target_progress_displayed) then
hud_bar_off(M14_PROGRESS_INDEX)
end
m14_display_heli_warning_objective()
hud_timer_set(M14_TIMER_INDEX, total_time, "m14_timer_validation_fail_cb")
hud_timer_hide(M14_TIMER_INDEX, true)
M14_status.timer_active = true
M14_status.timer_displayed = false
end
else -- Don't do timer validation
if (M14_status.timer_active) then
m14_clear_heli_warning_objective()
hud_timer_stop(M14_TIMER_INDEX)
M14_status.timer_active = false
if (M14_status.timer_displayed) then
hud_timer_hide(M14_TIMER_INDEX, true)
M14_status.timer_displayed = false
end
if (M14_status.target_progress_displayed) then
hud_bar_on(M14_PROGRESS_INDEX, "health", M14_text.label_acquiring_target, HUD_BAR_MAX_VALUE)
end
end
end
else -- player_is_in_heli
-- Removing this for now as I suspect it's causing problems
--if (not character_is_in_vehicle(M14_char.shaundi, M14_vehicle.spotlight_heli)) then
-- vehicle_enter_teleport(M14_char.shaundi, M14_vehicle.spotlight_heli, VEHICLE_SEAT_PASSENGER, false)
--end
-- Timer validation stuffs
if (M14_status.timer_active) then
m14_clear_heli_warning_objective()
hud_timer_stop(M14_TIMER_INDEX)
M14_status.timer_active = false
if (M14_status.timer_displayed) then
hud_timer_hide(M14_TIMER_INDEX, true)
M14_status.timer_displayed = false
end
if (M14_status.target_progress_displayed) then
hud_bar_on(M14_PROGRESS_INDEX, "health", M14_text.label_acquiring_target, HUD_BAR_MAX_VALUE)
end
end
end
end
thread_yield()
end
end
-- During the conversation "Where's Killbane", "Bet she knows", etc., pan the camera to view Jane and the Deckers in the studio
--
function m14_studio_cam_panning_thread()
camera_look_through(M14_cam_nav.jane, 2, true)
delay(2)
camera_look_through(M14_cam_nav.deckers, 2, true)
delay(1)
camera_end_look_through(false)
end
function m14_wrapper_thread(func, ...)
while true do
func(unpack(arg))
thread_yield()
end
end
function m14_make_jane_cower()
while character_is_ready( M14_char.jane ) == false do
thread_yield()
end
set_animation_state(M14_char.jane, "cower stand")
M14_thread.jane_cower = nil
end
function m14_cellphone_call_wait( convo, recieving, persona )
M14_status.cellphone_call_in_progress = convo
audio_play_for_mission_cellphone( convo, recieving, true, "", "m14_cellphone_call_cb", persona )
while M14_status.cellphone_call_in_progress ~= nil do
thread_yield()
end
end
function m14_cellphone_call_cb()
M14_status.cellphone_call_in_progress = nil
end
function m14_abandon_heli_thread()
local dist, dist_remote
local should_show_timer = false
local showing_timer = false
local time_away = 0
local in_heli
while true do
-- no heli, nothing to do
if vehicle_exists( M14_vehicle.spotlight_heli ) == false or vehicle_is_destroyed( M14_vehicle.spotlight_heli ) == true then
return
end
-- get greatest distance from heli
dist = get_dist( M14_vehicle.spotlight_heli, LOCAL_PLAYER )
if coop_is_active() then
dist_remote = get_dist( M14_vehicle.spotlight_heli, REMOTE_PLAYER )
-- since coop player is optional we take the clostest d
if dist_remote < dist then
dist = dist_remote
end
end
if M14_status.at_tower ~= true then
in_heli = character_is_in_vehicle( LOCAL_PLAYER, M14_vehicle.spotlight_heli )
-- either player in heli counts
if coop_is_active() == true and in_heli == false then
in_heli = character_is_in_vehicle( REMOTE_PLAYER, M14_vehicle.spotlight_heli )
end
if in_heli then
should_show_timer = false
time_away = 0
elseif should_show_timer == false then -- once we show the timer, keep it up until the heli is occupied
time_away = time_away + get_frame_time()
should_show_timer = time_away > 90 or dist > 50
end
else
should_show_timer = false
time_away = 0
end
-- show/hide the critical timer as appropriate
if should_show_timer == true and showing_timer == false then
hud_critical_timer_set( ( 120 - time_away ) * 1000, M14_text.get_in_heli, "m14_timer_validation_fail_cb", SYNC_ALL )
showing_timer = true
elseif should_show_timer == false and showing_timer == true then
hud_critical_timer_stop()
showing_timer = false
end
thread_yield()
end
end
function m14_on_attack_performed_cb( name )
if M14_thread.attack_line_timer ~= nil and thread_check_done( M14_thread.attack_line_timer ) == false then
return
end
M14_thread.attack_line_timer = thread_new( "delay", rand_float( 5, 15 ) )
audio_play_persona_line( name, "m14_attack" )
end
function m14_cleanup_audio( convos )
-- clear pending events
M14_convo_queue = { }
-- sweep all convo data and clean it up
for i, convo in pairs( convos ) do
m14_cleanup_audio_item( convo )
end
end
function m14_cleanup_audio_item( convo )
if convo.convo_handle ~= nil then
audio_conversation_end( convo.convo_handle )
convo.convo_handle = nil
end
if convo.audio_id ~= nil then
audio_stop( convo.audio_id )
convo.audio_id = nil
end
-- clean up loaded personas
if convo.persona_handles ~= nil then
for i, handle in pairs( convo.persona_handles ) do
audio_persona_remove_2d( handle )
end
convo.persona_handles = nil
end
end
M14_convo_queue = { }
-- Play an audio conversation
--
-- convo: (table) the conversation to play - contains a name, handle, and table of non-player speakers
-- wait: (bool) don't return until convo has played
-- clear: (bool) clear any pending convos
--
function m14_convo_play( convo, wait, clear )
if (convo == nil) then
return
end
-- add to end of queue
M14_convo_queue[ #M14_convo_queue + 1 ] = convo
-- wait for convo to finish playing if requested
if wait == true then
while m14_convo_is_playing( convo ) == true do
thread_yield()
end
end
end
function m14_convo_is_playing( convo )
if convo == nil then
return sizeof_table( M14_convo_queue ) > 0
end
for i, c in pairs( M14_convo_queue ) do
if c == convo then
return true
end
end
return false
end
function m14_convo_manager()
local convo
-- Loop infinitely until the mission is cleaned up.
while true do
thread_yield()
if #M14_convo_queue > 0 then
convo = M14_convo_queue[ 1 ]
convo.persona_handles = { }
--[[
-- Load 2D personas when necessary
if convo.speakers_2d ~= nil then
for i, persona in pairs( convo.speakers_2d ) do
convo.persona_handles[ i ] = audio_persona_load_2d( persona )
end
end
--]]
-- Load the conversation
if convo.persona_3d_params ~= nil then
audio_play_persona_line( unpack( convo.persona_3d_params ) )
m14_wait_for_persona_line_safe( convo.persona_3d_params[ 1 ] )
elseif convo.persona_2d_params ~= nil then
convo.audio_id = audio_play_persona_line_2d( convo.speakers_2d[ 1 ].handle, convo.persona_2d_params[ 1 ] )
-- see note below
if convo.persona_2d_params[ 2 ] ~= nil then
delay( convo.persona_2d_params[ 2 ] )
end
-- audio_is_playing() doesn't currently work with this id
-- I am told it should so I'll leave it here but the delay above
-- is what's going to make this work right now -SDR
m14_wait_for_audio_safe( convo.audio_id )
convo.audio_id = nil
elseif convo.cell_name ~= nil then
m14_cellphone_call_wait( convo.cell_name, convo.recieving, convo.speakers_2d[ 1 ].handle )
elseif convo.convo_name ~= nil then
-- load convo
if convo.coop_player ~= nil then
convo.convo_handle = audio_conversation_load_player( convo.convo_name, convo.coop_player )
elseif convo.player_speaks then
convo.convo_handle = audio_conversation_load( convo.convo_name )
else
convo.convo_handle = audio_conversation_load_direct( convo.convo_name )
end
-- play the conversation
debug_print( "MAD", "Playing convo: " .. convo.convo_name .. "\n" )
audio_conversation_play( convo.convo_handle )
thread_yield()
-- wait for the conversation to end
m14_wait_for_convo_safe( convo.convo_handle )
convo.convo_handle = nil
end
--[[
-- clean up personas
for i, handle in pairs( convo.persona_handles ) do
audio_persona_remove_2d( handle )
end
convo.persona_handles = nil
--]]
-- delay if needed
if convo.delay_after ~= nil then
delay( convo.delay_after )
end
-- roll up the queue
if #M14_convo_queue > 1 then
for i = 2, #M14_convo_queue do
M14_convo_queue[ i - 1 ] = M14_convo_queue[ i ]
end
end
M14_convo_queue[ #M14_convo_queue ] = nil
end
end
end
function m14_interview_kill()
if (M14_status.interview_audio ~= nil) then
-- one or the other should work..... depends on who you ask
audio_stop( M14_status.interview_audio_id )
audio_object_post_event( "radio_news_breaks_stop", "radio_news_breaks", M14_status.interview_audio, M14_status.interview_vehicle )
M14_status.interview_audio = nil
end
end
function m14_interview_play( interview, veh )
if veh == nil then
veh = M14_vehicle.spotlight_heli
end
m14_interview_kill()
M14_status.interview_audio = interview
M14_status.interview_vehicle = veh
M14_status.interview_audio_id = audio_object_post_event( "radio_news_breaks", "radio_news_breaks", interview, veh )
end
function m14_setup_fake_laser_reticle()
-- If a player exits the helicopter, clean up the fake reticle.
on_vehicle_exit("m14_set_fake_reticle_for_players", M14_vehicle.spotlight_heli)
on_vehicle_enter("m14_set_fake_reticle_for_players", M14_vehicle.spotlight_heli)
m14_set_fake_reticle_for_players()
end
function m14_cleanup_fake_laser_reticle()
on_vehicle_exit("", M14_vehicle.spotlight_heli)
on_vehicle_enter("", M14_vehicle.spotlight_heli)
reticle_override_clear(SYNC_ALL)
end
-- Sets the fake reticle for the pilot of the spotlight heli if there's only
-- one player in that vehicle, or the passenger if there are two.
function m14_set_fake_reticle_for_players(player, vehicle, seat_idx)
local local_player_in_heli = character_is_in_vehicle(LOCAL_PLAYER, M14_vehicle.spotlight_heli)
local remote_player_in_heli = coop_is_active() and character_is_in_vehicle(REMOTE_PLAYER, M14_vehicle.spotlight_heli)
local pilot_name = get_char_in_vehicle(M14_vehicle.spotlight_heli, 0)
-- If both players are in the heli, give the fake reticle to the guy that's not flying.
if local_player_in_heli and remote_player_in_heli then
if pilot_name == LOCAL_PLAYER then
reticle_override_clear(SYNC_LOCAL)
reticle_override_set(HUD_FAKE_RETICLE_WEAPON_NAME, HUD_FAKE_RETICLE_WEAPON_CATEGORY_NAME, SYNC_REMOTE)
elseif pilot_name == REMOTE_PLAYER then
reticle_override_set(HUD_FAKE_RETICLE_WEAPON_NAME, HUD_FAKE_RETICLE_WEAPON_CATEGORY_NAME, SYNC_LOCAL)
reticle_override_clear(SYNC_REMOTE)
else
-- Neither is flying?
reticle_override_clear(SYNC_ALL)
end
elseif pilot_name == LOCAL_PLAYER then
reticle_override_set(HUD_FAKE_RETICLE_WEAPON_NAME, HUD_FAKE_RETICLE_WEAPON_CATEGORY_NAME, SYNC_LOCAL)
reticle_override_clear(SYNC_REMOTE)
elseif pilot_name == REMOTE_PLAYER then
reticle_override_clear(SYNC_LOCAL)
reticle_override_set(HUD_FAKE_RETICLE_WEAPON_NAME, HUD_FAKE_RETICLE_WEAPON_CATEGORY_NAME, SYNC_REMOTE)
else
reticle_override_clear(SYNC_ALL)
end
end