--[[
m16.lua
SR3 Mission Script
DATE: 07-21-10
AUTHOR: John Karczewski
]]--
-- Debug flags --
-- Tweakable Parameters --
DELAY_BETWEEN_DECKER_GROUP_SPAWNS = 0.3 -- in ms -- this controls the time between each individual decker spawn when spawning a group
-- Firewalls --
TIME_BETWEEN_GATE_SPAWNS = 8 -- seconds
TIME_UNTIL_KINZIE_UNLOCKS_LOCK = 45 -- seconds
FW1_SLOW_DURATION = 5000 -- ms
FW1_CHEAT_PERIOD = 10000 -- ms, how often the cheat will occur
FW2_LAG_DURATION = 6000 -- ms
FW2_CHEAT_PERIOD = 7000 -- ms, how often the cheat will occur
FW3_INVERT_DURATION = 3000 -- ms
FW3_CHEAT_PERIOD = 10000 -- ms, how often the cheat will occur
-- Matt Boss Battle--
MATT_COOP_HEALTH_MULTIPLIER = 2.0 -- increases matt's max hp when in coop
TIME_BETWEEN_AIR_TELEPORTS = 3.8 -- seconds
TIME_BETWEEN_GROUND_TELEPORTS = 5 -- seconds
HP_PERCENT_TO_BULLRUSH = .50
HP_PERCENT_TO_DOWN_P2 = .75
HP_PERCENT_TO_DOWN_P3 = .35
HP_PERCENT_TO_DOWN_P5 = .25
-- QTE Fail Hp values --
HP_P1_QTE_FAIL = .75
HP_P5_QTE_FAIL = .50
-- Decker Phase --
DECKER_SPAWN_RATE = 1.5
DECKER_SEQUENCE_DURATION = 45
-- Avatar Battle --
M16_MIN_DISTANCE_FOR_TELEPORT = 22.5 -- Min distance for a teleport navopint to be valid
M16_PLAYER_DISTANCE_FOR_TELEPORT = 15 -- Distance from the player at which Matt should teleport away
M16_phase_matt_health = {
1.0, -- phase 1 - "wing rip" QTE
0.75, -- phase 2 - "downed" QTE
0.5, -- phase 3 - standard fight
0.25, -- phase 4 - decker phase, same as next value
0.25, -- phase 5 - avatar fight
0.1, -- final QTE
}
-- how high to set Matt's health when the final phase triggers.
M16_final_phase_health_reset = 1.0
-- Don't add customization items to wordrobe
M16_add_to_wardrobe = false
-- Groups --
M16_groups = {
----------------------------------
-- FIRST SECTION SURPRISE GROUPS --
----------------------------------
surprise1_group1 = {
name = "SURPRISE1_GROUP_01",
members = { "Surprise1_NPC 004" }
},
surprise1_group2 = {
name = "SURPRISE1_GROUP_02",
members = { "Surprise1_NPC 005", "Surprise1_NPC 014", "Surprise1_NPC 013" }
},
surprise1_group3 = {
name = "SURPRISE1_GROUP_03",
members = { "Surprise1_NPC 003", "Surprise1_NPC 001" }
},
surprise1_group4 = {
name = "SURPRISE1_GROUP_04",
members = { "Surprise1_NPC 002", "Surprise1_NPC 012", "Surprise1_NPC 006", "Surprise1_NPC 007" }
},
surprise1_group5 = {
name = "SURPRISE1_GROUP_05",
members = { "Surprise1_NPC 008", "Surprise1_NPC 009", "Surprise1_NPC 010" }
},
surprise1_group6 = {
name = "SURPRISE1_GROUP_06",
members = { "Surprise1_NPC 015", "Surprise1_NPC 018", "Surprise1_NPC 011" }
},
surprise1_group7 = {
name = "SURPRISE1_GROUP_07",
members = { "Surprise1_NPC 016", "Surprise1_NPC 017" }
},
-----------------------------------
-- SECOND SECTION SURPRISE GROUPS --
-----------------------------------
surprise2_group1 = {
name = "SURPRISE2_GROUP_01",
members = { "Surprise2_NPC 007", "Surprise2_NPC 002", "Surprise2_NPC 004" }
},
surprise2_group2 = {
name = "SURPRISE2_GROUP_02",
members = { "Surprise2_NPC 009", "Surprise2_NPC 001", "Surprise2_NPC 005" }
},
surprise2_group3 = {
name = "SURPRISE2_GROUP_03",
members = { "Surprise2_NPC 003" }
},
surprise2_group4 = {
name = "SURPRISE2_GROUP_04",
members = { "Surprise2_NPC 006", "Surprise2_NPC 011"}
},
----------------------------------
-- THIRD SECTION SURPRISE GROUPS --
----------------------------------
surprise3_group1 = {
name = "SURPRISE3_GROUP_01",
members = { "Surprise3_NPC 001", "Surprise3_NPC 004", "Surprise3_NPC 003" }
},
surprise3_group2 = {
name = "SURPRISE3_GROUP_02",
members = { "Surprise3_NPC 002", "Surprise3_NPC 006" }
},
surprise3_group3 = {
name = "SURPRISE3_GROUP_03",
members = { "Surprise3_NPC 009" }
},
surprise3_group4 = {
name = "SURPRISE3_GROUP_04",
members = { "Surprise3_NPC 014", "Surprise3_NPC 015" }
},
---------------------
-- FIREWALL GROUPS --
---------------------
firewall_one = {
name = "FIREWALL_GROUP_01",
members = { "Gate1_NPC<001>", "Gate1_NPC<002>", "Gate1_NPC<003>", "Gate1_NPC<004>", "Gate1_NPC<005>" }
},
firewall_two = {
name = "FIREWALL_GROUP_02",
members = { "Gate1_NPC<006>", "Gate1_NPC<007>", "Gate1_NPC<008>", "Gate1_NPC<009>" }
},
firewall_three = {
name = "FIREWALL_GROUP_03",
members = { "Gate1_NPC<010>", "Gate1_NPC<011>", "Gate1_NPC<012>", "Gate1_NPC<013>" }
},
firewall_four = {
name = "FIREWALL_GROUP_04",
members = { "Gate1_NPC<014>", "Gate1_NPC<015>", "Gate1_NPC<016>", "Gate1_NPC<017>" }
},
firewall_five = {
name = "FIREWALL_GROUP_05",
members = { "Gate1_NPC<018>", "Gate1_NPC<019>", "Gate1_NPC<020>", "Gate1_NPC<021>" }
},
firewall_six = {
name = "FIREWALL_GROUP_06",
members = { "Gate1_NPC<022>", "Gate1_NPC<023>", "Gate1_NPC<024>", "Gate1_NPC<025>" }
},
firewall_seven = {
name = "FIREWALL_GROUP_07",
members = { "Gate1_NPC<026>", "Gate1_NPC<027>", "Gate1_NPC<028>", "Gate1_NPC<029>" }
},
firewall_eight = {
name = "FIREWALL_GROUP_08",
members = { "Gate1_NPC<030>", "Gate1_NPC<031>", "Gate1_NPC<032>", "Gate1_NPC<033>",
"Gate1_NPC<034>", "Gate1_NPC<035>" }
},
----------------------
-- ANTIVIRUS GROUPS --
----------------------
antivirus_one = {
name = "ANTIVIRUS_GROUP_01",
members_single = { "Gate2_NPC_Group_1_Single<001>" },
members_coop = { "Gate2_NPC_Group_1_Coop<001>" },
members = { "Gate2_NPC_Group_1_Single<001>", "Gate2_NPC_Group_1_Coop<001>" }
},
antivirus_two = {
name = "ANTIVIRUS_GROUP_02",
members_single = { "Gate2_NPC_Group_2_Single<001>"},
members_coop = { "Gate2_NPC_Group_2_Coop<001>", "Gate2_NPC_Group_2_Coop<002>" },
members = { "Gate2_NPC_Group_2_Single<001>",
"Gate2_NPC_Group_2_Coop<001>", "Gate2_NPC_Group_2_Coop<002>"}
},
antivirus_three = {
name = "ANTIVIRUS_GROUP_03",
members_single = { "Gate2_NPC_Group_3_Single<001>"}, --removed , "Gate2_NPC_Group_3_Single<002>"
members_coop = { "Gate2_NPC_Group_3_Coop<001>", "Gate2_NPC_Group_3_Coop<002>", "Gate2_NPC_Group_3_Coop<003>" },
members = { "Gate2_NPC_Group_3_Single<001>", "Gate2_NPC_Group_3_Single<002>",
"Gate2_NPC_Group_3_Coop<001>", "Gate2_NPC_Group_3_Coop<002>", "Gate2_NPC_Group_3_Coop<003>"}
},
antivirus_four = {
name = "ANTIVIRUS_GROUP_04",
members_single = { "Gate2_NPC_Group_4_Single<001>", "Gate2_NPC_Group_4_Single<002>" },
members_coop = { "Gate2_NPC_Group_4_Coop<001>", "Gate2_NPC_Group_4_Coop<002>", "Gate2_NPC_Group_4_Coop<003>" },
members = { "Gate2_NPC_Group_4_Single<001>", "Gate2_NPC_Group_4_Single<002>",
"Gate2_NPC_Group_4_Coop<001>", "Gate2_NPC_Group_4_Coop<002>", "Gate2_NPC_Group_4_Coop<003>"}
},
------------------------------
-- INTERNET SECURITY GROUPS --
------------------------------
security = {
name = "SECURITY_GROUP",
members = { "Gate3_NPC 001", "Gate3_NPC 003", "Gate3_NPC 005",
"Gate3_NPC 008", "Gate3_NPC 009", "Gate3_NPC 010",
"Gate3_NPC 011", "Gate3_NPC 012",
"Gate3_NPC 018", "Gate3_NPC 019" },
wave1 = { "Gate3_NPC 001", "Gate3_NPC 005", "Gate3_NPC 008"},
wave2 = { "Gate3_NPC 003", "Gate3_NPC 009" },
wave3 = { "Gate3_NPC 010" },
wave4 = { "Gate3_NPC 018", "Gate3_NPC 019" },
wave5 = { "Gate3_NPC 011", "Gate3_NPC 012"},
},
security_coop = {
name = "SECURITY_GROUP_COOP",
members = { "Gate3_NPC_Coop<001>", "Gate3_NPC_Coop<002>", "Gate3_NPC_Coop<003>", "Gate3_NPC_Coop<004>", "Gate3_NPC_Coop<005>" },
wave1 = { "Gate3_NPC_Coop<001>" },
wave2 = { "Gate3_NPC_Coop<002>" },
wave3 = { "Gate3_NPC_Coop<003>" },
wave4 = { "Gate3_NPC_Coop<004>" },
wave5 = { "Gate3_NPC_Coop<005>" },
},
-----------------------------------
-- TOP DOWN TANK SEQUENCE GROUPS --
-----------------------------------
tank_combat_player_one = {
name = "PLAYER_ONE_TANK_GROUP",
members = { "Player_One_Tank 001" },
player_tank_veh = "Player_One_Tank 001"
},
tank_combat_npc_one = {
name = "NPC_ONE_TANK_GROUP",
members = { "Tank_NPC 001", "NPC_Tank 001" },
tank_npc = "Tank_NPC 001",
npc_tank_veh = "NPC_Tank 001",
},
tank_combat_player_two = {
name = "PLAYER_TWO_TANK_GROUP",
members = { "Player_Two_Tank 001" },
player_tank_veh = "Player_Two_Tank 001"
},
tank_combat_npc_two = {
name = "NPC_TWO_TANK_GROUP",
members = { "Tank_NPC 002", "NPC_Tank 002" },
tank_npc = "Tank_NPC 002",
npc_tank_veh = "NPC_Tank 002",
},
----------
-- MATT --
----------
matt = {
name = "MATT_GROUP",
members = { "matt" },
matt = "matt"
},
-------------------------------
-- BOSS BATTLE DECKER GROUPS --
-------------------------------
wave1 = {
name = "DECKER_GROUP 001",
members = { "decker_phase_npc 003", "decker_phase_npc 004", "decker_phase_npc 004a", "decker_phase_npc 004b",
"decker_phase_npc 004c", "decker_phase_npc 004d", "decker_phase_npc 004f", "decker_phase_npc 004g" }
},
wave2 = {
name = "DECKER_GROUP 002",
members = { "decker_phase_npc 006", "decker_phase_npc 008", "decker_phase_npc 008a", "decker_phase_npc 008c",
"decker_phase_npc 008d", "decker_phase_npc 008e", "decker_phase_npc 008f", "decker_phase_npc 008h" }
},
wave3 = {
name = "DECKER_GROUP 003",
members = { "decker_phase_npc 010", "decker_phase_npc 011", "decker_phase_npc 012",
"decker_phase_npc 012a", "decker_phase_npc 012d", "decker_phase_npc 012f", "decker_phase_npc 012h" }
},
}
-- decker waves
M16_wave_groups = { M16_groups.wave1, M16_groups.wave2, M16_groups.wave3 }
M16_internet_security_waves = { M16_groups.security.wave1, M16_groups.security.wave2, M16_groups.security.wave3,
M16_groups.security.wave4, M16_groups.security.wave5 }
M16_internet_security_coop_waves = { M16_groups.security_coop.wave1, M16_groups.security_coop.wave2, M16_groups.security_coop.wave3,
M16_groups.security_coop.wave4, M16_groups.security_coop.wave5 }
-- Navpoints --
M16_navpoints = {
local_start = "Local_Start_Navpoint",
remote_start = "Remote_Start_Navpoint",
start_navs = {"Local_Start_Navpoint", "Remote_Start_Navpoint"},
local_exit = "M16_Local_Player_Exit",
remote_exit = "M16_Remote_Player_Exit",
waiting_room = {"Navpoint_WaitingRoom_Local", "Navpoint_WaitingRoom_Remote"},
firewall_destroyed = { "FW1_Destroy_Nav_Local", "FW1_Destroy_Nav_Remote"},
antivirus_destroyed = { "FW2_Destroy_Nav_Local", "FW2_Destroy_Nav_Remote"},
security_destroyed = { "FW3_Destroy_Nav_Local", "FW3_Destroy_Nav_Remote"},
tank_combat_camera = "Tank_Camera_Navpoint",
local_matt_battle_start = "Local_Boss_Start_Navpoint",
remote_matt_battle_start = "Remote_Boss_Start_Navpoint",
matt_teleports = { "Matt_Teleport 001", "Matt_Teleport 002", "Matt_Teleport 003",
"Matt_Teleport 004", "Matt_Teleport 005", "Matt_Teleport 006" },
matt_hide_loc = "Matt_Hide_Loc_Navpoint",
matt_summon = "Matt_Summon_Nav",
first_qte = "First_QTE_Nav",
final_qte = "Final_QTE_Nav",
tank_warp_local = "Tank_Warp_Navpoint_Local",
tank_warp_remote = "Tank_Warp_Navpoint_Remote",
error_warp_local = "Error_Warp_Navpoint_Local",
error_warp_remote = "Error_Warp_Navpoint_Remote",
final_warp_local = "Final_Warp_Navpoint_Local",
final_warp_remote = "Final_Warp_Navpoint_Remote",
final_choice_local = "Local_Final_Choice_Navpoint",
final_choice_remote = "Remote_Final_Choice_Navpoint"
}
-- Triggers --
M16_triggers = {
surprise1 = { "Surprise1_Trigger_01", "Surprise1_Trigger_02", "Surprise1_Trigger_03", "Surprise1_Trigger_04",
"Surprise1_Trigger_05", "Surprise1_Trigger_06", "Surprise1_Trigger_07" },
surprise2 = { "Surprise2_Trigger_01", "Surprise2_Trigger_02", "Surprise2_Trigger_03", "Surprise2_Trigger_04" },
surprise3 = { "Surprise3_Trigger_01", "Surprise3_Trigger_02", "Surprise3_Trigger_03", "Surprise3_Trigger_04" },
firewall = { "Firewall_01_Trigger_01", "Firewall_01_Trigger_02", "Firewall_01_Trigger_03",
"Firewall_01_Trigger_04", "Firewall_01_Trigger_05", "Firewall_01_Trigger_06",
"Firewall_01_Trigger_07", "Firewall_01_Trigger_08" },
cathedral_wall = { "Cathedral_Wall_Trigger<001>", "Cathedral_Wall_Trigger<002>" , "Cathedral_Wall_Trigger<003>" },
firewall_destination = "Trigger_Firewall",
gate1 = "Gate1_Trigger",
gate2 = "Gate2_Trigger",
gate3 = "Gate3_Trigger",
final = "Final_Trigger",
choicea = "Company_A_Trigger",
choiceb = "Company_B_Trigger",
death = "Death_Region",
}
M16_surprise_triggers = {
surprise1_01 = {
name = M16_triggers.surprise1[1],
script_group = M16_groups.surprise1_group1
},
surprise1_02 = {
name = M16_triggers.surprise1[2],
script_group = M16_groups.surprise1_group2
},
surprise1_03 = {
name = M16_triggers.surprise1[3],
script_group = M16_groups.surprise1_group3
},
surprise1_04 = {
name = M16_triggers.surprise1[4],
script_group = M16_groups.surprise1_group4
},
surprise1_05 = {
name = M16_triggers.surprise1[5],
script_group = M16_groups.surprise1_group5
},
surprise1_06 = {
name = M16_triggers.surprise1[6],
script_group = M16_groups.surprise1_group6
},
surprise1_07 = {
name = M16_triggers.surprise1[7],
script_group = M16_groups.surprise1_group7
},
surprise2_01 = {
name = M16_triggers.surprise2[1],
script_group = M16_groups.surprise2_group1
},
surprise2_02 = {
name = M16_triggers.surprise2[2],
script_group = M16_groups.surprise2_group2
},
surprise2_03 = {
name = M16_triggers.surprise2[3],
script_group = M16_groups.surprise2_group3
},
surprise2_04 = {
name = M16_triggers.surprise2[4],
script_group = M16_groups.surprise2_group4
},
surprise3_01 = {
name = M16_triggers.surprise3[1],
script_group = M16_groups.surprise3_group1
},
surprise3_02 = {
name = M16_triggers.surprise3[2],
script_group = M16_groups.surprise3_group2
},
surprise3_03 = {
name = M16_triggers.surprise3[3],
script_group = M16_groups.surprise3_group3
},
surprise3_04 = {
name = M16_triggers.surprise3[4],
script_group = M16_groups.surprise3_group4
},
}
M16_firewall_trigger_groups = {
firewall_01 = {
name = M16_triggers.firewall[1],
script_group = M16_groups.firewall_one
},
firewall_02 = {
name = M16_triggers.firewall[2],
script_group = M16_groups.firewall_two
},
firewall_03 = {
name = M16_triggers.firewall[3],
script_group = M16_groups.firewall_three
},
firewall_04 = {
name = M16_triggers.firewall[4],
script_group = M16_groups.firewall_four
},
firewall_05 = {
name = M16_triggers.firewall[5],
script_group = M16_groups.firewall_five
},
firewall_06 = {
name = M16_triggers.firewall[6],
script_group = M16_groups.firewall_six
},
firewall_07 = {
name = M16_triggers.firewall[7],
script_group = M16_groups.firewall_seven
},
firewall_08 = {
name = M16_triggers.firewall[8],
script_group = M16_groups.firewall_eight
},
}
M16_surprise1_trigger_groups = { M16_surprise_triggers.surprise1_01, M16_surprise_triggers.surprise1_02, M16_surprise_triggers.surprise1_03, M16_surprise_triggers.surprise1_04, M16_surprise_triggers.surprise1_05, M16_surprise_triggers.surprise1_06, M16_surprise_triggers.surprise1_07 }
M16_surprise2_trigger_groups = { M16_surprise_triggers.surprise2_01, M16_surprise_triggers.surprise2_02, M16_surprise_triggers.surprise2_03, M16_surprise_triggers.surprise2_04 }
M16_surprise3_trigger_groups = { M16_surprise_triggers.surprise3_01, M16_surprise_triggers.surprise3_02, M16_surprise_triggers.surprise3_03, M16_surprise_triggers.surprise3_04 }
-- Characters --
M16_characters = {
tank_combat_tank_npc_one = M16_groups.tank_combat_npc_one.tank_npc,
tank_combat_tank_npc_two = M16_groups.tank_combat_npc_two.tank_npc,
matt = M16_groups.matt.matt
}
-- Vehicles --
M16_vehicles = {
tank_combat_npc_tank_one = M16_groups.tank_combat_npc_one.npc_tank_veh,
tank_combat_npc_tank_two = M16_groups.tank_combat_npc_two.npc_tank_veh,
tank_combat_player_tank_one = M16_groups.tank_combat_player_one.player_tank_veh,
tank_combat_player_tank_two = M16_groups.tank_combat_player_two.player_tank_veh
}
-- Mesh Movers --
M16_movers = {
gate1 = "Gate1_Mover",
gate2 = "Gate2_Mover",
gate3 = "Gate3_Mover",
final_gate_mover = "Final_Gate_Mover<001>",
triggered_final_gate_movers = { "Final_Gate_Mover<002>", "Final_Gate_Mover<003>", "Final_Gate_Mover<004>" }
}
-- Text --
-- Threads --
M16_threads = {
process_convo = INVALID_THREAD_HANDLE,
tank_one_thread_handle = INVALID_THREAD_HANDLE,
tank_two_thread_handle = INVALID_THREAD_HANDLE,
matt_teleport_thread_handle = INVALID_THREAD_HANDLE,
matt_health_thread_handle = INVALID_THREAD_HANDLE,
text_adventure_audio_handle = INVALID_THREAD_HANDLE,
cheat_audio_handle = INVALID_THREAD_HANDLE,
attack_line = INVALID_THREAD_HANDLE,
avatar_transform_handle = INVALID_THREAD_HANDLE,
local_avatar_transform_handle = INVALID_THREAD_HANDLE,
remote_avatar_transform_handle = INVALID_THREAD_HANDLE,
decker_spawn_handle = INVALID_THREAD_HANDLE,
decker_spawn_handle2 = INVALID_THREAD_HANDLE
}
-- Checkpoints --
M16_checkpoints = {
CHECKPOINT_START = MISSION_START_CHECKPOINT, -- defined in ug_lib.lua
TEXT_ADVENTURE_COMPLETE = "m16_checkpoint_text_adventure_complete",
TANK_COMBAT_COMPLETE = "m16_checkpoint_tank_combat_complete",
ERROR_SCREEN_DISABLED = "m16_checkpoint_error_screen_disabled",
MATT_BATTLE_START = "m16_checkpoint_matt_battle_start",
MATT_DEWINGED = "m16_checkpoint_matt_dewinged",
MATT_PHASE3 = "m16_checkpoint_matt_phase3",
DECKER_PHASE = "m16_checkpoint_decker_phase",
AVATAR_BATTLE ="m16_checkpoint_avatar_battle"
}
-- Cutscenes --
M16_scene = {
intro = "16_IN",
matt_intro = "16_z01",
matt_defeated = "16_Z02",
outro = "16_out"
}
M16_cte_01 = {
name = "m16_cte_01"
}
-- Conversations --
M16_conv = {
mission_start = {
name = "m16_convo_1",
load_direct = false,
queued = false,
started = false,
completed = false,
ended = false,
},
second_avatar = {
name = "m16_second_avatar",
load_direct = false,
queued = false,
started = false,
completed = false,
ended = false,
},
actual_avatar = {
name = "m16_actual_avatar",
load_direct = false,
queued = false,
started = false,
completed = false,
ended = false,
},
defenses = {
name = "m16_defenses",
load_direct = false,
queued = false,
started = false,
completed = false,
ended = false,
},
attack_firewall= {
name = "m16_attack_firewall",
load_direct = false,
queued = false,
started = false,
completed = false,
ended = false,
},
text_adventure = {
name = "m16_convo_4",
load_direct = false,
queued = false,
started = false,
completed = false,
ended = false,
},
firewall_destroyed = {
name = "m16_firewall_destroyed",
load_direct = true,
queued = false,
started = false,
completed = false,
ended = false,
},
toilet_again = {
name = "m16_toilet_again",
load_direct = false,
queued = false,
started = false,
completed = false,
ended = false,
},
nyte_blade = {
name = "m16_matt_player_convo",
load_direct = false,
queued = false,
started = false,
completed = false,
ended = false,
},
tank_sequence = {
name = "m16_tank",
load_direct = false,
queued = false,
started = false,
completed = false,
ended = false,
},
see_last_wall = {
name = "m16_see_last_wall",
load_direct = false,
queued = false,
started = false,
completed = false,
ended = false,
},
attack_security = {
name = "m16_attack_security",
load_direct = false,
queued = false,
started = false,
completed = false,
ended = false,
},
doll_again = {
name = "m16_doll_again",
load_direct = false,
queued = false,
started = false,
completed = false,
ended = false,
},
error_message = {
name = "m16_error_message",
load_direct = false,
queued = false,
started = false,
completed = false,
ended = false,
},
security_destroyed = {
name = "m16_destroy_security",
load_direct = false,
queued = false,
started = false,
completed = false,
ended = false,
},
graves_two = {
name = "m16_graves_2",
load_direct = false,
queued = false,
started = false,
completed = false,
ended = false,
},
cheat_one = {
name = "M16_Cheat_1",
load_direct = false,
queued = false,
started = false,
completed = false,
ended = false,
},
cheat_two = {
name = "M16_Cheat_2",
load_direct = false,
queued = false,
started = false,
completed = false,
ended = false,
},
graves_one = {
name = "m16_graves_1",
load_direct = false,
queued = false,
started = false,
completed = false,
ended = false,
},
matt_battle_begins = {
name = "m16_battle_begins",
load_direct = false,
queued = false,
started = false,
completed = false,
ended = false,
},
player_turned_into_avatar = {
name = "m16_bahamut",
load_direct = true,
queued = false,
started = false,
completed = false,
ended = false,
},
ability_explanation = {
name = "m16_ability_explanation",
load_direct = false,
queued = false,
started = false,
completed = false,
ended = false,
},
matt_returns = {
name = "m16_matt_returns",
load_direct = false,
queued = false,
started = false,
completed = false,
ended = false,
},
matt_qte_charge_three = {
name = "m16_charge_3",
load_direct = false,
queued = false,
started = false,
completed = false,
ended = false,
},
reward_choice = {
name = "m16_reward_choice",
load_direct = false,
queued = false,
started = false,
completed = false,
ended = false,
},
}
M16_dialog_lines = {
---------------------------
-- TEXT ADVENTURE LINES --
---------------------------
M16_TA_Go_Through_Hole_Fail = {
name = "M16_TA_Go_Through_Hole_Fail",
played = false
},
M16_TA_Open_Door_Fail = {
name = "M16_TA_Open_Door_Fail",
played = false
},
M16_TA_Nap_Fail_01 = {
name = "M16_TA_Nap_Fail_01",
played = false
},
M16_TA_Nap_Fail_02 = {
name = "M16_TA_Nap_Fail_02",
played = false
},
M16_TA_Secret_Door_Fail = {
name = "M16_TA_Secret_Door_Fail",
played = false
},
M16_TA_Run_Back_Fail = {
name = "M16_TA_Run_Back_Fail",
played = false
},
M16_TA_Cast_Spell_Fail = {
name = "M16_TA_Cast_Spell_Fail",
played = false
},
M16_TA_Draw_Sword_Fail = {
name = "M16_TA_Draw_Sword_Fail",
played = false
},
M16_TA_Look_At_Unicorn_Fail = {
name = "M16_TA_Look_At_Unicorn_Fail",
played = false
},
M16_TA_Pet_Unicorn_Fail = {
name = "M16_TA_Pet_Unicorn_Fail",
played = false
},
M16_TA_Kill_Unicorn_Win = {
name = "M16_TA_Kill_Unicorn_Win",
played = false
},
banish_to_tank = {
name = "M16_Banish_To_Tank",
played = false
},
kinzie_boss_start = {
name = "M16_Boss_Fight",
played = false
},
-------------------------
-- KINZIE CHEAT LINES --
-------------------------
kinzie_lag_cheat = {
name = "M16_Lag_Cheat_Kinzie_01",
played = false
},
kinzie_inverted_cheat = {
name = "M16_Inverted_Cheat_Kinzie_01",
played = false
},
kinzie_weak_weapon_cheat = {
name = "M16_Weak_Weapon_Cheat_Kinzie_01",
played = false
},
kinzie_shrink_cheat = {
name = "M16_Shrink_Cheat_Kinzie_01",
played = false
},
kinzie_slow_cheat = {
name = "M16_Slow_Cheat_Kinzie_01",
played = false
},
-------------------------
-- MATT CHEAT LINES --
-------------------------
matt_lag_cheat_01 = {
name = "M16_Lag_Cheat_Matt",
played = false
},
matt_lag_cheat_02 = {
name = "M16_Lag_Cheat_Matt_01",
played = false
},
matt_lag_cheat_03 = {
name = "M16_Lag_Cheat_Matt_02",
played = false
},
matt_inverted_cheat_01 = {
name = "M16_Inverted_Cheat_Matt",
played = false
},
matt_inverted_cheat_02 = {
name = "M16_Inverted_Cheat_Matt_01",
played = false
},
matt_inverted_cheat_03 = {
name = "M16_Inverted_Cheat_Matt_02",
played = false
},
matt_weak_weapon_cheat_01 = {
name = "M16_Weak_Weapon_Cheat_Matt",
played = false
},
matt_weak_weapon_cheat_02 = {
name = "M16_Weak_Weapon_Cheat_Matt_01",
played = false
},
matt_weak_weapon_cheat_03 = {
name = "M16_Weak_Weapon_Cheat_Matt_02",
played = false
},
matt_shrink_cheat_01 = {
name = "M16_Shrink_Cheat_Matt",
played = false
},
matt_shrink_cheat_02 = {
name = "M16_Shrink_Cheat_Matt_01",
played = false
},
matt_shrink_cheat_03 = {
name = "M16_Shrink_Cheat_Matt_02",
played = false
},
matt_slow_cheat_01 = {
name = "M16_Slow_Cheat_Matt",
played = false
},
matt_slow_cheat_02 = {
name = "M16_Slow_Cheat_Matt_01",
played = false
},
matt_slow_cheat_03 = {
name = "M16_Slow_Cheat_Matt_02",
played = false
},
}
M16_text_adventure_lines = {
{1, M16_dialog_lines.M16_TA_Go_Through_Hole_Fail},
{2, M16_dialog_lines.M16_TA_Open_Door_Fail},
{0, M16_dialog_lines.M16_TA_Nap_Fail_01},
{0, M16_dialog_lines.M16_TA_Nap_Fail_02},
{4, M16_dialog_lines.M16_TA_Secret_Door_Fail},
{5, M16_dialog_lines.M16_TA_Run_Back_Fail},
{7, M16_dialog_lines.M16_TA_Cast_Spell_Fail},
{8, M16_dialog_lines.M16_TA_Draw_Sword_Fail},
{10, M16_dialog_lines.M16_TA_Look_At_Unicorn_Fail},
{11, M16_dialog_lines.M16_TA_Pet_Unicorn_Fail},
{12, M16_dialog_lines.M16_TA_Kill_Unicorn_Win},
}
M16_kinzie_cheat_lines = {
M16_dialog_lines.kinzie_inverted_cheat,
M16_dialog_lines.kinzie_shrink_cheat,
M16_dialog_lines.kinzie_lag_cheat,
M16_dialog_lines.kinzie_weak_weapon_cheat,
M16_dialog_lines.kinzie_slow_cheat,
}
M16_matt_cheat_lines_01 = {
M16_dialog_lines.matt_inverted_cheat_01,
M16_dialog_lines.matt_shrink_cheat_01,
M16_dialog_lines.matt_lag_cheat_01,
M16_dialog_lines.matt_weak_weapon_cheat_01,
M16_dialog_lines.matt_slow_cheat_01,
}
M16_matt_cheat_lines_02 = {
M16_dialog_lines.matt_inverted_cheat_02,
M16_dialog_lines.matt_shrink_cheat_02,
M16_dialog_lines.matt_lag_cheat_02,
M16_dialog_lines.matt_weak_weapon_cheat_02,
M16_dialog_lines.matt_slow_cheat_02,
}
M16_matt_cheat_lines_03 = {
M16_dialog_lines.matt_inverted_cheat_03,
M16_dialog_lines.matt_shrink_cheat_03,
M16_dialog_lines.matt_lag_cheat_03,
M16_dialog_lines.matt_weak_weapon_cheat_03,
M16_dialog_lines.matt_slow_cheat_03,
}
-- Persona Handles --
M16_personas = {
kinzie = {
name = "Kinzie",
persona_id = INVALID_PERSONA_HANDLE,
},
matt = {
name = "Matt",
persona_id = INVALID_PERSONA_HANDLE,
}
}
M16_animations = {
matt_taunt_a = "taunt 1",
matt_taunt_b = "taunt 2",
tele_start = "avatar tele start",
tele_end = "avatar tele end",
matt_summon = "avatar summon"
}
M16_animation_states = {
avatar_stunned = "dbno suffer"
}
-- Other --
convo_queue = {
playing = {
thread_id = -1,
conv_handle = INVALID_CONVERSATION_HANDLE,
convo_table = nil,
},
list = {},
size = 0,
}
dialog_line_audio_id = -1
M16_music = ""
M16_hud_states = {
minimap = -1,
hide_all = -1,
gsi = -1,
}
in_coop = false
gate_reached = false
gate_destroyed = false
player_choice = ""
M16_TYPE_NAME = "Mission"
M16_MISSION = "Mission_16"
M16_music_event_instance_id = -1
-- Cheats
M16_CHEAT_INVALID = -1
M16_CHEAT_INVERTED = 0
M16_CHEAT_SIZE = 1
M16_CHEAT_LAG = 2
M16_CHEAT_WEAPON = 3
M16_CHEAT_SLOW = 4
-- Effect navpoint names
m16_vfx_spawn = "Vfx Cyberspace Spawn"
m16_vfx_despawn = "Vfx Cyberspace Death"
m16_vfx_deckers_damaged = "Vfx Emoticon Damaged"
m16_vfx_deckers_attacking = "Vfx Emoticon Attacking"
m16_vfx_forcefield_destroyed = "Vfx forcefield destroyed"
m16_vfx_avatar_spawn = "Vfx Avatar Shockwave"
-- Conversation enums
M16_CONVO_PLAY_LAST = 0
M16_CONVO_PLAY_NEXT = 1
M16_CONVO_PLAY_IMMEDIATE = 2
M16_PLAYER_GUN = "Special-CyberCannon"
M16_AVATAR_SWORD = "Avatar_Sword"
AVATAR_LOADOUT = { M16_AVATAR_SWORD }
M16_LOADOUT = { M16_PLAYER_GUN, M16_AVATAR_SWORD }
m16_local_player_special_weapon = "none"
m16_remote_player_special_weapon = "none"
-- Tank Combat --
ENEMY_TANK_PATHS_ONE_FORWARD = { "Enemy_Tank_One_Path 001", "Enemy_Tank_One_Path 002" }
ENEMY_TANK_PATHS_ONE_BACK = { "Enemy_Tank_One_Path 001a", "Enemy_Tank_One_Path 002a" }
ENEMY_TANK_PATHS_ONE = { ENEMY_TANK_PATHS_ONE_FORWARD, ENEMY_TANK_PATHS_ONE_BACK }
ENEMY_TANK_PATHS_ONE_SINGLE_FORWARD = { "Enemy_Tank_One_Path 001", "Enemy_Tank_One_Path 002", "Enemy_Tank_One_Path 003" }
ENEMY_TANK_PATHS_ONE_SINGLE_BACK = { "Enemy_Tank_One_Path 001a", "Enemy_Tank_One_Path 002a", "Enemy_Tank_One_Path 003a1" }
ENEMY_TANK_PATHS_ONE_SINGLE = { ENEMY_TANK_PATHS_ONE_SINGLE_FORWARD, ENEMY_TANK_PATHS_ONE_SINGLE_BACK }
ENEMY_TANK_PATHS_TWO_FORWARD = { "Enemy_Tank_Two_Path 001", "Enemy_Tank_Two_Path 002" }
ENEMY_TANK_PATHS_TWO_BACK = { "Enemy_Tank_Two_Path 001a", "Enemy_Tank_Two_Path 002a" }
ENEMY_TANK_PATHS_TWO = { ENEMY_TANK_PATHS_TWO_FORWARD, ENEMY_TANK_PATHS_TWO_BACK }
CAMERA = M16_navpoints.tank_combat_camera
M16_PHASE_ONE = 1
M16_PHASE_TWO = 2
M16_PHASE_THREE = 3
M16_PHASE_FOUR = 4
M16_PHASE_FIVE= 5
-- Matt Battle --
Matt_health_pct = 1.0
Matt_qte_complete = false
Matt_qte_success = false
current_phase = 0
NUM_WAVES_DECKER_SEQUENCE = 6
num_times_matt_has_teleported = 0
-- Zone Swap --
M16_ZONE_NAME = "vr"
-- *************************
--
-- 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
--
-- m16_checkpoint: The checkpoint the mission should begin at
-- is_restart: TRUE if the mission is restarting, FALSE otherwise
--
function m16_start(m16_checkpoint, is_restart)
in_coop = coop_is_active()
--m16_checkpoint = M16_checkpoints.TEXT_ADVENTURE_COMPLETE
--m16_checkpoint = M16_checkpoints.TANK_COMBAT_COMPLETE
--m16_checkpoint = M16_checkpoints.ERROR_SCREEN_DISABLED
--m16_checkpoint = M16_checkpoints.MATT_BATTLE_START
--m16_checkpoint = M16_checkpoints.MATT_DEWINGED
--m16_checkpoint = M16_checkpoints.DECKER_PHASE
--m16_checkpoint = M16_checkpoints.AVATAR_BATTLE
-- Check if this mission starting from the beginning
if (m16_checkpoint == M16_checkpoints.CHECKPOINT_START) then
if (is_restart == false) then
-- First time playing mission
-- Play the intro cinematic
if (M16_scene.intro ~= "") then
cutscene_play(M16_scene.intro, nil, nil, false)
end
end
end
city_zone_swap(M16_ZONE_NAME, true)
-- Handle mission initialization for the current checkpoint
m16_initialize(m16_checkpoint)
-- Run the mission from the current checkpoint
m16_run(m16_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 m16_run(first_checkpoint)
local current_checkpoint = first_checkpoint
mission_set_cancel_warp_location(M16_navpoints.local_exit, M16_navpoints.remote_exit)
if current_checkpoint == M16_checkpoints.CHECKPOINT_START then
character_ragdoll_set_last_resort_position(M16_navpoints.local_start)
m16_intro_sequence()
m16_firewall_sequence()
m16_text_adventure_process()
m16_music_switch("M16_Music_01b_Play")
m16_watch_firewall_disintegrate()
current_checkpoint = M16_checkpoints.TEXT_ADVENTURE_COMPLETE
mission_set_checkpoint(M16_checkpoints.TEXT_ADVENTURE_COMPLETE)
end
if current_checkpoint == M16_checkpoints.TEXT_ADVENTURE_COMPLETE then
character_ragdoll_set_last_resort_position(M16_navpoints.tank_warp_local)
m16_goto_antivirus()
m16_antivirus_sequence()
--can't do the tank sequence until both players are un-downed
while human_is_downed(LOCAL_PLAYER) or (in_coop and human_is_downed(REMOTE_PLAYER)) do
thread_yield()
end
m16_tank_combat_setup()
m16_tank_combat_process()
m16_tank_combat_clean_up()
m16_watch_antivirus_disintegrate()
current_checkpoint = M16_checkpoints.TANK_COMBAT_COMPLETE
mission_set_checkpoint(M16_checkpoints.TANK_COMBAT_COMPLETE)
end
if current_checkpoint == M16_checkpoints.TANK_COMBAT_COMPLETE then
character_ragdoll_set_last_resort_position(M16_navpoints.error_warp_local)
m16_goto_internet_security()
m16_internet_security_sequence()
m16_error_screen_process()
m16_watch_internet_security_disintegrate()
current_checkpoint = M16_checkpoints.ERROR_SCREEN_DISABLED
mission_set_checkpoint(M16_checkpoints.ERROR_SCREEN_DISABLED)
end
if current_checkpoint == M16_checkpoints.ERROR_SCREEN_DISABLED then
character_ragdoll_set_last_resort_position(M16_navpoints.final_warp_local)
m16_music_switch("M16_Music_Pre_Boss")
m16_goto_cathedral()
current_checkpoint = M16_checkpoints.MATT_BATTLE_START
mission_set_checkpoint(M16_checkpoints.MATT_BATTLE_START)
end
if current_checkpoint == M16_checkpoints.MATT_BATTLE_START then
character_ragdoll_set_last_resort_position(M16_navpoints.local_matt_battle_start)
m16_set_phase(M16_PHASE_ONE)
m16_run_matt_phase_one()
current_checkpoint = M16_checkpoints.MATT_DEWINGED
mission_set_checkpoint(M16_checkpoints.MATT_DEWINGED)
end
if current_checkpoint == M16_checkpoints.MATT_DEWINGED then
character_ragdoll_set_last_resort_position(M16_navpoints.local_matt_battle_start)
m16_set_phase(M16_PHASE_TWO)
m16_run_matt_phase_two()
current_checkpoint = M16_checkpoints.MATT_PHASE3
mission_set_checkpoint(M16_checkpoints.MATT_PHASE3)
end
if current_checkpoint == M16_checkpoints.MATT_PHASE3 then
character_ragdoll_set_last_resort_position(M16_navpoints.local_matt_battle_start)
m16_set_phase(M16_PHASE_THREE)
m16_run_matt_phase_three()
current_checkpoint = M16_checkpoints.DECKER_PHASE
mission_set_checkpoint(M16_checkpoints.DECKER_PHASE)
end
if current_checkpoint == M16_checkpoints.DECKER_PHASE then
character_ragdoll_set_last_resort_position(M16_navpoints.local_matt_battle_start)
m16_set_phase(M16_PHASE_FOUR)-- increment the phase on the code side
m16_run_decker_phase_four()
current_checkpoint = M16_checkpoints.AVATAR_BATTLE
mission_set_checkpoint(M16_checkpoints.AVATAR_BATTLE)
end
if current_checkpoint == M16_checkpoints.AVATAR_BATTLE then
character_ragdoll_set_last_resort_position(M16_navpoints.local_matt_battle_start)
m16_set_phase(M16_PHASE_FIVE) -- increment the phase on the code side
zscene_prep(M16_scene.matt_defeated)
m16_run_matt_phase_five()
inv_remove_temp_loadout(AVATAR_LOADOUT)
boss_battle_matt_set_player_as_avatar(DISABLE)
customization_outfit_wear("Cyber Avatar") -- put on the cyber suit.
inv_item_equip(M16_PLAYER_GUN, LOCAL_PLAYER)
if in_coop then
inv_item_equip(M16_PLAYER_GUN, REMOTE_PLAYER)
end
m16_matt_defeated_zscene()
m16_player_choice()
end
-- Prevent Shaundi from being called as a homie until the end of M17
homie_mission_lock("shaundi")
-- SP 7/18: turn off the bloom/refraction screen effects before playing the outro cutscene
hdr_bloom_set_multiplier(1)
refraction_situation_clear()
-- Call mission success??
mission_end_success("m16", M16_scene.outro, {M16_navpoints.local_exit, M16_navpoints.remote_exit})
end
-- This is the primary function responsible for cleaning up the entire mission
-- CALLED FROM CODE (+++MUST RETURN IMMEDIATLY+++)
--
function m16_cleanup()
set_player_can_enter_exit_vehicles(LOCAL_PLAYER, ENABLE)
character_disable_revival(LOCAL_PLAYER, DISABLE)
if in_coop then
character_disable_revival(REMOTE_PLAYER, DISABLE)
set_player_can_enter_exit_vehicles(REMOTE_PLAYER, ENABLE)
end
city_zone_swap(M16_ZONE_NAME, false)
on_damage("", M16_characters.matt) -- TEMP
on_human_killed("")
on_qte_animation_trigger("")
on_hud_screen_exit( "", "msn_text_adventure" )
on_hud_screen_exit( "", "msn_cyber" )
-- cleanup groups
m16_cleanup_groups()
-- Kill all running threads
m16_cleanup_threads()
-- re-enable sprint, just in case they quit while it was disabled.
player_can_sprint(true)
-- kill the vehicle destroyed callbacks
on_vehicle_destroyed("", M16_vehicles.tank_combat_npc_tank_one)
on_vehicle_destroyed("", M16_vehicles.tank_combat_npc_tank_two)
on_vehicle_destroyed("", M16_vehicles.tank_combat_player_tank_one)
on_vehicle_destroyed("", M16_vehicles.tank_combat_player_tank_two)
-- clean up triggers
m16_cleanup_triggers(M16_triggers)
m16_end_conversations()
-- End cheats
boss_battle_matt_cheats_stop()
notoriety_force_no_spawn("police", false)
notoriety_force_no_spawn("deckers", false)
camera_end_look_through()
vehicle_set_2d_tank_controls(false)
qte_cleanup()
player_grenades_enable()
inv_remove_temp_loadout(AVATAR_LOADOUT)
inv_item_equip(nil, LOCAL_PLAYER) -- Unequip the current weapon on the player
inv_item_remove(M16_PLAYER_GUN, LOCAL_PLAYER)
-- Add back any permenant special weapons
if m16_local_player_special_weapon ~= "none" then
inv_item_add(m16_local_player_special_weapon, 1, LOCAL_PLAYER)
end
if in_coop then
inv_item_equip(nil, REMOTE_PLAYER) -- Unequip the current weapon on the player
inv_item_remove(M16_PLAYER_GUN, REMOTE_PLAYER)
if m16_remote_player_special_weapon ~= "none" then
inv_item_add(m16_remote_player_special_weapon, 1, REMOTE_PLAYER)
end
end
-- restore characters
character_show(LOCAL_PLAYER)
player_controls_enable(LOCAL_PLAYER)
turn_vulnerable(LOCAL_PLAYER)
clear_animation_state(LOCAL_PLAYER)
if in_coop then
character_show(REMOTE_PLAYER)
if character_exists(REMOTE_PLAYER) then
player_controls_enable(REMOTE_PLAYER)
end
turn_vulnerable(REMOTE_PLAYER)
clear_animation_state(REMOTE_PLAYER)
end
customization_item_revert()
-- Stop using the mission specified ragdoll get up last resort.
character_ragdoll_clear_last_resort_position()
-- enable the players weapon radial
hud_inventory_disable(false)
if in_coop then
hud_inventory_disable(false, REMOTE_PLAYER)
end
-- SP 7/13: turn off the bloom/refraction screen effects
hdr_bloom_set_multiplier(1)
refraction_situation_clear()
-- turn off the music
m16_music_switch("")
audio_object_post_event( "M16_reset_all" )
-- Restore the HUD
for i, hud_state in pairs(M16_hud_states) do
if (hud_state ~= -1) then
hud_display_remove_state(hud_state)
hud_state = -1
end
end
end
-- Called when the mission has ended with success
-- CALLED FROM CODE (+++MUST RETURN IMMEDIATLY+++)
--
function m16_success()
--[[ INSERT ANY MISSION SPECIFIC SUCCESS STUFF ]]--
end
-- *************************
--
-- Local functions
--
-- *************************
function m16_music_switch(music_name)
if (M16_music ~= music_name) then
audio_object_post_event("M16_Music_Stop", nil, nil, LOCAL_PLAYER)
audio_stop(M16_music_event_instance_id)
M16_music_event_instance_id = -1
if (music_name ~= "") then
M16_music_event_instance_id = audio_object_post_event(music_name, nil, nil, LOCAL_PLAYER)
end
M16_music = music_name
end
end
-- Initialize the mission for the specified checkpoint
--
-- checkpoint: Checkpoint to initialize the mission to
--
function m16_initialize(checkpoint)
-- Make sure the screen is completly faded out
mission_start_fade_out(0.0)
-- Set the mission author
set_mission_author("John Karczewski")
-- Common initialization
m16_initialize_common()
-- Checkpoint specific initialization
m16_initialize_checkpoint(checkpoint)
-- Start fading in
--mission_start_fade_in()
end
-- Mission intro sequence, involving moving the player, setting up the surprise and conversation
function m16_intro_sequence()
teleport_coop(M16_navpoints.start_navs[1], M16_navpoints.start_navs[2], true)
m16_music_switch("M16_Music_01_Play")
cutscene_play( M16_cte_01.name, nil, nil, false)
-- Setup surprise triggers
m16_helper_surprise_groups_setup(M16_triggers.surprise1, "m16_cb_spawn_surprise_group")
player_can_sprint(false)
customization_item_wear("cm_toilet", "cm_toilet.cmeshx", "Material#9", M16_add_to_wardrobe)
mission_start_fade_in()
delay(2)
-- Play the intro conversation
m16_helper_conversation_play(M16_conv.mission_start, M16_CONVO_PLAY_IMMEDIATE, 1.5)
objective_text( 0, "M16_OBJ_MOVE_THROUGH_DATA", "", "", SYNC_ALL, OI_ASSET_LOCATION )
delay(25)
m16_helper_conversation_play(M16_conv.second_avatar, M16_CONVO_PLAY_IMMEDIATE, 2.5)
-- Play spawning effect as the player changes shapes
effect_play_on_human(m16_vfx_spawn, LOCAL_PLAYER)
if in_coop then
effect_play_on_human(m16_vfx_spawn, REMOTE_PLAYER)
end
customization_item_wear("cm_blowupdoll", "cm_blowupdoll.cmeshx", "Blow_Up_Doll_A", M16_add_to_wardrobe)
delay(10)
-- Make sure the players aren't in the middle of anything
player_can_sprint(true)
m16_transform_player_into_human_avatar()
delay(10)
m16_helper_conversation_play(M16_conv.defenses, M16_CONVO_PLAY_IMMEDIATE, 4.0) -- play goto firewall conversation
-- Set objective
objective_text( 0, "m16_obj_goto_firewall", "", "", SYNC_ALL, OI_ASSET_LOCATION )
marker_add_trigger(M16_triggers.gate1, MINIMAP_ICON_LOCATION, INGAME_EFFECT_CHECKPOINT, OI_ASSET_LOCATION, OI_FLAGS_LOCATION, SYNC_ALL)
on_trigger("m16_cb_firewall_area_reached", M16_triggers.gate1)
trigger_enable(M16_triggers.gate1, true)
tutorial_start("weap_charge_weapon", 0, true, true)
-- Wait until a player gets to the firewall
while not gate_reached do
thread_yield()
end
gate_reached = false
end
-- First onslaught sequence, the player must destroy the firewall
function m16_firewall_sequence()
m16_helper_surprise_groups_disable(M16_surprise1_trigger_groups) -- Destroy the surprise gruops
m16_firewall_setup() -- begin firewall sequence
-- Wait until the gate has been destroyed
while(not gate_destroyed) do
thread_yield()
end
gate_destroyed = false
boss_battle_matt_cheats_stop()
-- Disable firewall triggers and groups
for i, firewall_trigger_group in pairs(M16_firewall_trigger_groups) do
on_trigger("", firewall_trigger_group.name)
trigger_enable(firewall_trigger_group.name, DISABLE)
if group_is_loaded(firewall_trigger_group.script_group.name) then
group_destroy(firewall_trigger_group.script_group.name)
end
end
delay(4)
end
-- Spawning function for the firewall
function m16_firewall_setup()
-- Onslaught started, so a cheat, Slow!
boss_battle_matt_cheats_start(M16_CHEAT_SLOW, FW1_SLOW_DURATION, FW1_CHEAT_PERIOD, false)
m16_helper_conversation_play(M16_conv.cheat_one, M16_CONVO_PLAY_NEXT, 2.0)
-- Set up the surprise triggers for the firewall groups
for i, firewall_trigger_group in pairs(M16_firewall_trigger_groups) do
on_trigger("m16_cb_spawn_firewall_group", firewall_trigger_group.name)
trigger_enable(firewall_trigger_group.name, ENABLE)
end
-- Player must make it to the firewall to win, set up the trigger region
marker_add_trigger(M16_triggers.firewall_destination, MINIMAP_ICON_LOCATION, INGAME_EFFECT_CHECKPOINT, OI_ASSET_LOCATION, OI_FLAGS_LOCATION, SYNC_ALL)
on_trigger("m16_cb_firewall_reached", M16_triggers.firewall_destination)
trigger_enable(M16_triggers.firewall_destination, true)
end
-- Sets up the text adventure, handles audio, etc.
UI_completion = { }
function m16_UI_text_complete( screen_name, player_name )
if (screen_name ~= "msn_text_adventure") then
return
end
player_controls_enable( player_name )
-- flag the player as completed
UI_completion[ player_name ] = true
end
function m16_UI_error_complete( screen_name, player_name )
if (screen_name ~= "msn_cyber") then
return
end
-- flag the player as completed
UI_completion[ player_name ] = true
-- if one finished first, teleport them to the waiting room until the other player is done
if (not (UI_completion[ LOCAL_PLAYER ] and UI_completion[ REMOTE_PLAYER ])) then
if player_name == LOCAL_PLAYER then
player_controls_enable(LOCAL_PLAYER)
teleport( player_name, M16_navpoints.waiting_room[1] )
else
player_controls_enable(REMOTE_PLAYER)
teleport( player_name, M16_navpoints.waiting_room[2] )
end
end
end
function m16_text_adventure_process()
mission_start_fade_out()
delay(1)
if in_coop then
-- teleport to the waiting room if in coop
teleport_coop(M16_navpoints.waiting_room[1], M16_navpoints.waiting_room[2], true)
end
objective_text_clear(0)
objective_text( 0, "m16_obj_survive_text", "", "", SYNC_ALL, OI_ASSET_DEFEND)
-- Play the intro conversation
m16_helper_conversation_play(M16_conv.text_adventure, M16_CONVO_PLAY_IMMEDIATE, 1.0)
-- Only play text adventure VO lines in single player
if not in_coop then
M16_threads.text_adventure_audio_handle = thread_new("m16_thread_text_adventure_audio_thread")
end
UI_completion[ LOCAL_PLAYER ] = false
UI_completion[ REMOTE_PLAYER ] = not coop_is_active()
-- start the text adventure and hook up a callback to know when they're done
hud_push_screen( "msn_text_adventure", SYNC_ALL )
on_hud_screen_exit( "m16_UI_text_complete", "msn_text_adventure" )
mission_start_fade_in()
player_controls_disable(LOCAL_PLAYER)
if in_coop then
player_controls_disable(REMOTE_PLAYER)
end
m16_music_switch("")
audio_object_post_event("Text_Adventure_Mute_Audio")
-- wait until both players have completed the adventure
while (not (UI_completion[ LOCAL_PLAYER ] and UI_completion[ REMOTE_PLAYER ])) do
thread_yield()
end
mission_start_fade_out()
audio_object_post_event("Text_Adventure_Unmute_Audio")
if not in_coop then
thread_kill(M16_threads.text_adventure_audio_handle)
M16_threads.text_adventure_audio_handle = INVALID_THREAD_HANDLE
end
end
-- Players watch the firewall disintegrate
function m16_watch_firewall_disintegrate()
teleport_coop(M16_navpoints.firewall_destroyed[1], M16_navpoints.firewall_destroyed[2], true)
mission_start_fade_in()
player_controls_disable(LOCAL_PLAYER)
if in_coop then
player_controls_disable(REMOTE_PLAYER)
end
m16_helper_conversation_play(M16_conv.firewall_destroyed, M16_CONVO_PLAY_NEXT, 1.0)
delay(2)
effect_play_on_script_object(m16_vfx_forcefield_destroyed, M16_movers.gate1)
delay(1.5)
mesh_mover_hide(M16_movers.gate1)
delay(5.0)
player_controls_enable(LOCAL_PLAYER)
if in_coop then
player_controls_enable(REMOTE_PLAYER)
end
mission_start_fade_out()
end
-- Sets up the gameplay leading to the antivirus
function m16_goto_antivirus()
teleport_coop(M16_navpoints.tank_warp_local, M16_navpoints.tank_warp_remote, true)
customization_item_wear("cm_toilet", "cm_toilet.cmeshx", "Material#9", M16_add_to_wardrobe)
-- Setup surprise triggers
m16_helper_surprise_groups_setup(M16_triggers.surprise2, "m16_cb_spawn_surprise_group")
objective_text_clear(0)
objective_text( 0, "m16_obj_goto_anti_virus", "", "", SYNC_ALL, OI_ASSET_LOCATION)
on_trigger("m16_cb_antivirus_reached", M16_triggers.gate2)
trigger_enable(M16_triggers.gate2, true)
marker_add_trigger(M16_triggers.gate2, MINIMAP_ICON_LOCATION, INGAME_EFFECT_CHECKPOINT, OI_ASSET_LOCATION, OI_FLAGS_LOCATION, SYNC_ALL)
-- Make sure the cybercannon is equipped
inv_item_equip(M16_PLAYER_GUN, LOCAL_PLAYER)
if in_coop then
inv_item_equip(M16_PLAYER_GUN, REMOTE_PLAYER)
end
mission_start_fade_in()
m16_helper_conversation_play(M16_conv.toilet_again, M16_CONVO_PLAY_IMMEDIATE, 4.0)
-- Wait until a player reaches the gate 2 trigger
while not gate_reached do
thread_yield()
end
gate_reached = false
end
-- 2nd onslaught, player must destroy the antivirus
function m16_antivirus_sequence()
customization_outfit_wear("Cyber Avatar") -- put on the cyber suit.
m16_helper_surprise_groups_disable(M16_surprise2_trigger_groups)
tutorial_start("weap_charge_weapon", 0, true, true)
-- Onslaught started, so a cheat, Lag!
boss_battle_matt_cheats_start(M16_CHEAT_LAG, FW2_LAG_DURATION, FW2_CHEAT_PERIOD, false)
m16_helper_conversation_play(M16_conv.cheat_two, M16_CONVO_PLAY_IMMEDIATE, 4.0)
--m16_helper_conversation_play(M16_conv.graves_one, M16_CONVO_PLAY_NEXT, 6.0)
objective_text_clear(0)
objective_text( 0, "m16_obj_kill_all_enemies", "", "", SYNC_ALL, OI_ASSET_KILL )
m16_antivirus_process() -- spawns npcs
boss_battle_matt_cheats_stop() -- Stop the cheats
m16_helper_play_dialog_line(M16_personas.matt.persona_id, M16_dialog_lines.banish_to_tank.name)
end
-- Spawning function for the antivirus fight sequence
--
-- gate_groups: (string) name of the group to spawn
--
function m16_antivirus_process()
m16_process_antivirus_wave(M16_groups.antivirus_one)
delay(1)
m16_process_antivirus_wave(M16_groups.antivirus_two)
delay(1)
m16_process_antivirus_wave(M16_groups.antivirus_three)
delay(1)
m16_process_antivirus_wave(M16_groups.antivirus_four)
group_destroy(M16_groups.antivirus_one)
group_destroy(M16_groups.antivirus_two)
group_destroy(M16_groups.antivirus_three)
group_destroy(M16_groups.antivirus_four)
end
-- Spawns a group, sets it up, and then blocks until it is killed
--
-- group: (string) group to spawn
function m16_process_antivirus_wave(group)
-- Spawn wave one and wait for it to die
group_create_hidden(group, true)
-- hide the coop only npcs
if not in_coop then
for i, member in pairs(group.members_single) do
m16_setup_cyberdecker(member)
end
else
for i, member in pairs(group.members) do
m16_setup_cyberdecker(member)
end
end
-- Need to process different sets of enemies based on single/coop
if not in_coop then
m16_process_enemy_set(group.members_single)
else
m16_process_enemy_set(group.members)
end
end
-- Creates tanks, teleports the player, and whatever else needs to be done to set up the tank combat
function m16_tank_combat_setup()
delay(1)
mission_start_fade_out()
-- restore player health, so we don't get any low hp blips
set_current_hit_points(LOCAL_PLAYER, get_max_hit_points(LOCAL_PLAYER))
if in_coop then
set_current_hit_points(REMOTE_PLAYER, get_max_hit_points(REMOTE_PLAYER))
end
-- Hide everything on the HUD
M16_hud_states.hide_all = hud_display_create_state()
hud_display_set_element(M16_hud_states.hide_all, HUD_ALL_ELEM, HUD_FADE_HIDDEN)
hud_display_commit_state(M16_hud_states.hide_all)
-- Only display the GSI
M16_hud_states.gsi = hud_display_create_state()
hud_display_set_element(M16_hud_states.gsi, HUD_ELEM_GSI, HUD_FADE_VISIBLE)
hud_display_commit_state(M16_hud_states.gsi)
-- Setup player/npc tank one
group_create(M16_groups.tank_combat_player_one.name, true)
group_create(M16_groups.tank_combat_npc_one.name, true)
vehicle_enter_teleport(LOCAL_PLAYER, M16_vehicles.tank_combat_player_tank_one)
turn_invulnerable(LOCAL_PLAYER)
set_player_can_enter_exit_vehicles(LOCAL_PLAYER, DISABLE)
vehicle_enter_teleport(M16_characters.tank_combat_tank_npc_one, M16_vehicles.tank_combat_npc_tank_one)
npc_suppress_persona(M16_characters.tank_combat_tank_npc_one, ENABLE)
on_vehicle_destroyed("m16_tank_one_destroyed_cb", M16_vehicles.tank_combat_npc_tank_one)
on_vehicle_destroyed("m16_player_tank_destroyed_cb", M16_vehicles.tank_combat_player_tank_one)
turn_invulnerable(M16_characters.tank_combat_tank_npc_one)
vehicle_prevent_vehicle_collision_damage(M16_vehicles.tank_combat_player_tank_one, true)
vehicle_prevent_vehicle_collision_damage(M16_vehicles.tank_combat_npc_tank_one, true)
vehicle_max_speed(M16_vehicles.tank_combat_npc_tank_one, 35)
if (in_coop) then
group_create(M16_groups.tank_combat_player_two.name,true)
group_create(M16_groups.tank_combat_npc_two.name, true)
vehicle_enter_teleport(REMOTE_PLAYER, M16_vehicles.tank_combat_player_tank_two)
turn_invulnerable(REMOTE_PLAYER)
set_player_can_enter_exit_vehicles(REMOTE_PLAYER, DISABLE)
vehicle_enter_teleport(M16_characters.tank_combat_tank_npc_two, M16_vehicles.tank_combat_npc_tank_two)
npc_suppress_persona(M16_characters.tank_combat_tank_npc_two, ENABLE)
on_vehicle_destroyed("m16_tank_two_destroyed_cb", M16_vehicles.tank_combat_npc_tank_two)
on_vehicle_destroyed("m16_player_tank_destroyed_cb", M16_vehicles.tank_combat_player_tank_two)
turn_invulnerable(M16_characters.tank_combat_tank_npc_two)
vehicle_prevent_vehicle_collision_damage(M16_vehicles.tank_combat_player_tank_two, true)
vehicle_prevent_vehicle_collision_damage(M16_vehicles.tank_combat_npc_tank_two, true)
vehicle_max_speed(M16_vehicles.tank_combat_npc_tank_two, 35)
end
objective_text_clear(0)
objective_text( 0, "m16_obj_kill_tanks", "", "", SYNC_ALL, OI_ASSET_KILL)
m16_music_switch("Tank_Battle_Music")
camera_look_through(M16_navpoints.tank_combat_camera, 0, false, false)
vehicle_set_2d_tank_controls(true)
mission_start_fade_in()
m16_helper_conversation_play(M16_conv.tank_sequence, M16_CONVO_PLAY_IMMEDIATE, 0.0)
end
-- Actually starts the combat, then waits for the combat to be completed
function m16_tank_combat_process()
if character_is_in_vehicle(M16_characters.tank_combat_tank_npc_one, M16_vehicles.tank_combat_npc_tank_one) then
local tank_paths = ENEMY_TANK_PATHS_ONE
if not in_coop then
-- we want the enemy tank to take different paths in single player
tank_paths = ENEMY_TANK_PATHS_ONE_SINGLE
end
M16_threads.tank_one_thread_handle = thread_new("m16_do_tank_pathing_thread", M16_vehicles.tank_combat_npc_tank_one, tank_paths)
ai_add_enemy_target(M16_characters.tank_combat_tank_npc_one, LOCAL_PLAYER, ATTACK_NOW_NEVER_LOSE)
end
if (in_coop and character_is_in_vehicle(M16_characters.tank_combat_tank_npc_two, M16_vehicles.tank_combat_npc_tank_two)) then
M16_threads.tank_two_thread_handle = thread_new("m16_do_tank_pathing_thread", M16_vehicles.tank_combat_npc_tank_two, ENEMY_TANK_PATHS_TWO)
ai_add_enemy_target(M16_characters.tank_combat_tank_npc_one, REMOTE_PLAYER, ATTACK_NOW_NEVER_LOSE)
ai_add_enemy_target(M16_characters.tank_combat_tank_npc_two, LOCAL_PLAYER, ATTACK_NOW_NEVER_LOSE)
ai_add_enemy_target(M16_characters.tank_combat_tank_npc_two, REMOTE_PLAYER, ATTACK_NOW_NEVER_LOSE)
end
while(not m16_tank_combat_end_battle()) do
thread_yield()
end
thread_kill(M16_threads.tank_one_thread_handle)
M16_threads.tank_one_thread_handle = INVALID_THREAD_HANDLE
vehicle_set_invulnerable(M16_vehicles.tank_combat_player_tank_one) -- Make tank invulnerable, player has won.
if (in_coop) then
thread_kill(M16_threads.tank_two_thread_handle)
M16_threads.tank_two_thread_handle = INVALID_THREAD_HANDLE
vehicle_set_invulnerable(M16_vehicles.tank_combat_player_tank_two) -- Make tank invulnerable, player has won.
-- restore player controls so we can prep for teleporting them
if vehicle_is_destroyed(M16_vehicles.tank_combat_player_tank_one) then
character_show(LOCAL_PLAYER)
player_controls_enable(LOCAL_PLAYER)
end
if vehicle_is_destroyed(M16_vehicles.tank_combat_player_tank_two) then
character_show(REMOTE_PLAYER)
player_controls_enable(REMOTE_PLAYER)
end
end
m16_music_switch("Tank_Battle_Music_Win")
delay(6)
end
-- Checks to see if the NPC tanks have been killed yet
function m16_tank_combat_end_battle()
local continue = false
continue = vehicle_is_destroyed(M16_vehicles.tank_combat_npc_tank_one)
if (in_coop) then
if (continue) then
-- The tank associated with player one has been destroyed, whats the status of player two's?
continue = vehicle_is_destroyed(M16_vehicles.tank_combat_npc_tank_two)
return continue
end
end
return continue
end
-- Clean up tank combat
function m16_tank_combat_clean_up()
mission_start_fade_out()
delay(1)
-- Unhide specific hud elements
hud_display_remove_state(M16_hud_states.hide_all)
M16_hud_states.hide_all = -1
hud_display_remove_state(M16_hud_states.gsi)
M16_hud_states.gsi = -1
camera_end_look_through()
vehicle_set_2d_tank_controls(false)
vehicle_exit_do(LOCAL_PLAYER, true)
turn_vulnerable(LOCAL_PLAYER)
group_destroy(M16_groups.tank_combat_player_one.name)
set_player_can_enter_exit_vehicles(LOCAL_PLAYER, ENABLE)
on_vehicle_destroyed("", M16_vehicles.tank_combat_player_tank_one)
if (in_coop) then
vehicle_exit_do(REMOTE_PLAYER, true)
turn_vulnerable(REMOTE_PLAYER)
group_destroy(M16_groups.tank_combat_player_two.name)
set_player_can_enter_exit_vehicles(REMOTE_PLAYER, ENABLE)
on_vehicle_destroyed("", M16_vehicles.tank_combat_player_tank_two)
end
end
-- Warp the player to watch the antivirus disintegrate
function m16_watch_antivirus_disintegrate()
m16_music_switch("M16_Music_02_Play")
teleport_coop(M16_navpoints.antivirus_destroyed[1], M16_navpoints.antivirus_destroyed[2], true)
mission_start_fade_in()
player_controls_disable(LOCAL_PLAYER)
if in_coop then
player_controls_disable(REMOTE_PLAYER)
end
delay(1)
effect_play_on_script_object(m16_vfx_forcefield_destroyed, M16_movers.gate2)
delay(1.5)
mesh_mover_hide(M16_movers.gate2)
delay(0.5)
player_controls_enable(LOCAL_PLAYER)
if in_coop then
player_controls_enable(REMOTE_PLAYER)
end
mission_start_fade_out() -- fade out to prep for the teleport
end
-- Sets up the gameplay leading to the antivirus
function m16_goto_internet_security()
teleport_coop(M16_navpoints.error_warp_local, M16_navpoints.error_warp_remote, true)
objective_text_clear(0)
objective_text( 0, "m16_obj_goto_internet_security", "", "", SYNC_ALL, OI_ASSET_LOCATION)
-- Setup surprise triggers
m16_helper_surprise_groups_setup(M16_triggers.surprise3, "m16_cb_spawn_surprise_group")
customization_item_wear("cm_blowupdoll", "cm_blowupdoll.cmeshx", "Blow_Up_Doll_A", M16_add_to_wardrobe)
m16_helper_conversation_play(M16_conv.doll_again, M16_CONVO_PLAY_IMMEDIATE, 3.0)
m16_helper_conversation_play(M16_conv.see_last_wall, M16_CONVO_PLAY_NEXT, 10.0)
--m16_helper_conversation_play(M16_conv.graves_two, M16_CONVO_PLAY_NEXT, 10.0)
on_trigger("m16_cb_internet_security_reached", M16_triggers.gate3)
trigger_enable(M16_triggers.gate3, true)
marker_add_trigger(M16_triggers.gate3, MINIMAP_ICON_LOCATION, INGAME_EFFECT_CHECKPOINT, OI_ASSET_LOCATION, OI_FLAGS_LOCATION, SYNC_ALL)
-- Make sure the cybercannon is equipped
inv_item_equip(M16_PLAYER_GUN, LOCAL_PLAYER)
if in_coop then
inv_item_equip(M16_PLAYER_GUN, REMOTE_PLAYER)
end
mission_start_fade_in()
while not gate_reached do
thread_yield()
end
gate_reached = false
end
-- Third gate sequence
function m16_internet_security_sequence()
customization_outfit_wear("Cyber Avatar") -- put on the cyber suit.
-- Onslaught started, so a cheat, Inverted!
boss_battle_matt_cheats_start(M16_CHEAT_INVERTED, FW3_INVERT_DURATION, FW3_CHEAT_PERIOD, false)
m16_helper_conversation_play(M16_conv.attack_security, M16_CONVO_PLAY_NEXT, 2.0)
m16_helper_conversation_play(M16_conv.nyte_blade, M16_CONVO_PLAY_LAST, 4.0)
objective_text_clear(0)
objective_text( 0, "m16_obj_kill_all_enemies", "", "", SYNC_ALL, OI_ASSET_KILL )
m16_internet_security_process()-- spawns npcs
boss_battle_matt_cheats_stop() -- stop the cheats
delay(2) -- wait 2 seconds for the line to complete
end
-- Function handles the spawning/tracking of npcs at the internet_security wall
function m16_internet_security_process()
m16_helper_surprise_groups_disable(M16_surprise3_trigger_groups) -- destroy the surprise groups
group_create_hidden(M16_groups.security, true)
if in_coop then
group_create_hidden(M16_groups.security_coop, true)
end
for i, wave in pairs(M16_internet_security_waves) do
for k, member in pairs(wave) do
m16_setup_cyberdecker(member)
marker_add(member, MINIMAP_ICON_KILL, OI_ASSET_KILL, OI_FLAGS_DEFAULT, SYNC_ALL)
delay(DELAY_BETWEEN_DECKER_GROUP_SPAWNS)
end
if in_coop then
for k, coop_member in pairs(M16_internet_security_coop_waves[i]) do
m16_setup_cyberdecker(coop_member)
marker_add(coop_member, MINIMAP_ICON_KILL, OI_ASSET_KILL, OI_FLAGS_DEFAULT, SYNC_ALL)
delay(DELAY_BETWEEN_DECKER_GROUP_SPAWNS)
end
end
delay(TIME_BETWEEN_GATE_SPAWNS)
thread_yield()
end
m16_process_enemy_set(M16_groups.security.members)
if in_coop then
m16_process_enemy_set(M16_groups.security_coop.members)
end
group_destroy(M16_groups.security)
if in_coop then
group_destroy(M16_groups.security_coop)
end
end
-- Sets up the error screen, handles audio, etc.
function m16_error_screen_process()
player_controls_disable(LOCAL_PLAYER)
if in_coop then
player_controls_disable(REMOTE_PLAYER)
end
m16_music_switch("M16_Screen_Crash")
audio_object_post_event("M16_PC_Beep")
UI_completion[ LOCAL_PLAYER ] = false
UI_completion[ REMOTE_PLAYER ] = not coop_is_active()
hud_push_screen("msn_cyber", SYNC_ALL)
on_hud_screen_exit( "m16_UI_error_complete", "msn_cyber" )
objective_text_clear(0)
objective_text( 0, "m16_obj_debug_error", "", "", SYNC_ALL)
-- Play the conversation
m16_helper_conversation_play(M16_conv.error_message, M16_CONVO_PLAY_IMMEDIATE, 6.0)
while (not (UI_completion[ LOCAL_PLAYER ] and UI_completion[ REMOTE_PLAYER ])) do
thread_yield()
end
audio_object_post_event("M16_Screen_Crash_Stop")
player_controls_enable(LOCAL_PLAYER)
if in_coop then
player_controls_enable(REMOTE_PLAYER)
end
end
-- Warp the player to watch the security disintegrate
function m16_watch_internet_security_disintegrate()
mission_start_fade_out()
teleport_coop(M16_navpoints.security_destroyed[1], M16_navpoints.security_destroyed[2], true)
mission_start_fade_in()
player_controls_disable(LOCAL_PLAYER)
if in_coop then
player_controls_disable(REMOTE_PLAYER)
end
delay(1)
effect_play_on_script_object(m16_vfx_forcefield_destroyed, M16_movers.gate3)
delay(1.5)
mesh_mover_hide(M16_movers.gate3)
delay(0.5)
player_controls_enable(LOCAL_PLAYER)
if in_coop then
player_controls_enable(REMOTE_PLAYER)
end
mission_start_fade_out()
end
-- All three defenses disabled, proceed to the cathedral
function m16_goto_cathedral()
m16_music_switch("m16_pre_boss_music")
objective_text_clear(0)
zscene_prep(M16_scene.matt_intro)
teleport_coop(M16_navpoints.final_warp_local, M16_navpoints.final_warp_remote, true)
mission_start_fade_in()
m16_helper_conversation_play(M16_conv.security_destroyed, M16_CONVO_PLAY_IMMEDIATE, 1.0) -- play firewall conversation
marker_add_trigger(M16_triggers.final, MINIMAP_ICON_LOCATION, INGAME_EFFECT_CHECKPOINT, OI_ASSET_LOCATION, OI_FLAGS_LOCATION, SYNC_ALL)
on_trigger("m16_final_cb", M16_triggers.final)
trigger_enable(M16_triggers.final, true)
-- set up the triggers to cause the walls to fade
for i, wall_trigger in pairs(M16_triggers.cathedral_wall) do
on_trigger("m16_cathedral_walk_wall_fade", wall_trigger)
trigger_enable(wall_trigger, true)
end
delay(1)
effect_play_on_script_object(m16_vfx_forcefield_destroyed, M16_movers.final_gate_mover)
delay(1.5)
mesh_mover_hide(M16_movers.final_gate_mover)
while(not gate_destroyed) do
thread_yield()
end
m16_music_switch("")
m16_matt_intro_zscene()
end
-- function yields until matt reaches a specified health
function m16_wait_for_matt_health(health_pct)
while not character_exists(M16_characters.matt) do
thread_yield()
end
Matt_health_pct = get_current_hit_points(M16_characters.matt) / get_max_hit_points(M16_characters.matt)
while (Matt_health_pct > health_pct) do
thread_yield()
end
end
-- Mark the QTE globals accordingly so m16_wait_for_qte_complete can function.
--
function m16_qte_complete(success)
Matt_qte_complete = true
Matt_qte_success = success
end
-- Wait for a QTE to complete.
--
-- Return true if the player won the QTE, false if they failed.
--
function m16_wait_for_qte_complete()
Matt_qte_complete = false
while not Matt_qte_complete do
thread_yield()
end
return Matt_qte_success
end
function m16_set_current_phase_hitpoints()
local pct = M16_phase_matt_health[current_phase]
-- the final phase sets the health a bit higher before continuing.
if (current_phase == #M16_phase_matt_health - 1) then
pct = M16_final_phase_health_reset
end
set_current_hit_points(M16_characters.matt, (get_max_hit_points(M16_characters.matt)*pct)) -- reset matt
end
function m16_set_phase(phase)
current_phase = phase
boss_battle_matt_set_phase(phase)
-- Leave the first phase alone, since it'll start at full health.
if (phase ~= 1) then
m16_set_current_phase_hitpoints()
end
if M16_threads.matt_health_thread_handle ~= INVALID_THREAD_HANDLE then
thread_kill(M16_threads.matt_health_thread_handle)
M16_threads.matt_health_thread_handle = INVALID_THREAD_HANDLE
end
-- Min-cap matt's health for the phase.
local next_index = phase+1
if (next_index <= #M16_phase_matt_health) then
M16_threads.matt_health_thread_handle = thread_new("m16_matt_health_thread", M16_phase_matt_health[next_index])
end
end
-- Run phase one fo the Matt boss battle.
function m16_run_matt_phase_one()
-- Initialize stuff...
m16_init_matt_battle(M16_checkpoints.MATT_BATTLE_START)
boss_battle_matt_set_matt_flying(ENABLE)
set_ignore_ai_flag(M16_characters.matt, ENABLE)
human_gravity_enable(M16_characters.matt, DISABLE)
-- Fade in and play the conversation and a taunt
mission_start_fade_in()
m16_helper_conversation_play(M16_conv.matt_battle_begins, M16_CONVO_PLAY_IMMEDIATE, 0.0)
action_play(M16_characters.matt, M16_animations.matt_taunt_b, nil, false, 1.0)
-- Matt is in the air, so change his animation group
set_script_animation_group(M16_characters.matt, "Pistol")
-- Take off
action_play(M16_characters.matt, "stand to ready", nil, false, 1.0)
set_ignore_ai_flag(M16_characters.matt, DISABLE)
M16_threads.matt_teleport_thread_handle = thread_new("m16_matt_air_teleport_thread")
M16_threads.cheat_audio_handle = thread_new("m16_thread_cheat_audio_thread")
-- Make sure the intro conversation is done
while not m16_helper_conversation_check_done(M16_conv.matt_battle_begins) do
thread_yield()
end
m16_helper_play_dialog_line(M16_personas.kinzie.persona_id, M16_dialog_lines.kinzie_boss_start.name)
boss_battle_matt_begin(false) -- begin the fight, start cheats immediately
-- Wait for him to get below the specified health level.
m16_wait_for_matt_health(M16_phase_matt_health[current_phase+1])
-- If Matt is in the air, we need to bring him down
m16_matt_land()
m16_do_qte(M16_navpoints.first_qte)
set_script_animation_group(M16_characters.matt, "Rifle")
while (m16_wait_for_qte_complete() == false) do
marker_add(M16_characters.matt, MINIMAP_ICON_KILL, OI_ASSET_KILL_FULL, OI_FLAGS_FULL, SYNC_ALL)
m16_set_current_phase_hitpoints()
m16_matt_lift_off_again() -- Matt goes back into the air on failure
-- Wait for him to get below the specified health level (again).
m16_wait_for_matt_health(M16_phase_matt_health[current_phase+1])
-- If Matt is in the air, we need to bring him down
m16_matt_land()
m16_do_qte(M16_navpoints.first_qte)
set_script_animation_group(M16_characters.matt, "Rifle")
end
-- Put matt back on the ground and turn back on his AI
human_gravity_enable(M16_characters.matt, ENABLE)
set_ignore_ai_flag(M16_characters.matt, DISABLE)
boss_battle_matt_set_matt_flying(DISABLE)
-- Kill Matt's teleport thread.
thread_kill(M16_threads.matt_teleport_thread_handle)
M16_threads.matt_teleport_thread_handle = INVALID_THREAD_HANDLE
end
-- Matt just had his wings ripped off, he is grounded
function m16_run_matt_phase_two()
debug_print( "MAD", "-- PHASE 2 --" )
set_behavior_set(M16_characters.matt, "Matt Avatar Phase 2")
set_script_animation_group(M16_characters.matt, "Rifle")
-- Set up the 'shoot him in the head' sequence.
marker_add(M16_characters.matt, MINIMAP_ICON_KILL, OI_ASSET_KILL_FULL, OI_FLAGS_FULL, SYNC_ALL)
m16_wait_for_matt_health(M16_phase_matt_health[current_phase+1])
human_enter_downed(M16_characters.matt)
end
-- Matt has been blasted, next time he gets low the decker phase will start
function m16_run_matt_phase_three()
debug_print( "MAD", "-- PHASE 3 --" )
set_behavior_set(M16_characters.matt, "Matt Avatar Phase 2")
set_script_animation_group(M16_characters.matt, "Rifle")
-- After Matt's health is low enough, do the decker phase.
m16_wait_for_matt_health(M16_phase_matt_health[current_phase+1])
-- Set up the player as an avatar.
m16_prep_avatar_for_decker_battle()
end
-- Player avatar vs lots of deckers.
function m16_run_decker_phase_four()
debug_print( "MAD", "-- PHASE 4 --" )
if M16_threads.cheat_audio_handle ~= INVALID_THREAD_HANDLE then
thread_kill(M16_threads.cheat_audio_handle)
M16_threads.cheat_audio_handle = INVALID_THREAD_HANDLE
end
m16_helper_conversation_play(M16_conv.ability_explanation, M16_CONVO_PLAY_IMMEDIATE, 0.0)
-- Remove the marker from Matt
marker_remove(M16_characters.matt)
objective_text( 0, "m16_obj_kill_all_enemies", "", "", SYNC_ALL, OI_ASSET_KILL )
M16_threads.decker_spawn_handle = thread_new("m16_thread_boss_battle_decker_spawn")
delay(0.5)
M16_threads.decker_spawn_handle2 = thread_new("m16_thread_boss_battle_decker_spawn")
delay(DECKER_SEQUENCE_DURATION) -- this phase is timed, just wait for it to end
set_ignore_ai_flag(M16_characters.matt, ENABLE)
-- Cleanup spawning threads
thread_kill(M16_threads.decker_spawn_handle)
M16_threads.decker_spawn_handle = INVALID_THREAD_HANDLE
thread_kill(M16_threads.decker_spawn_handle2)
M16_threads.decker_spawn_handle2 = INVALID_THREAD_HANDLE
delay(1)
m16_helper_conversation_play(M16_conv.matt_returns, M16_CONVO_PLAY_IMMEDIATE, 0.0)
-- Kill all remaining deckers
for i, decker_group in pairs(M16_wave_groups) do
if group_is_loaded(decker_group) then
for member_number, member in pairs(decker_group.members) do
if character_exists(member) and not character_is_dead(member) then
character_kill(member)
end
end
delay(0.5)
group_destroy(decker_group)
end
end
inv_item_remove_all(M16_characters.matt)
inv_item_add("Avatar_Sword", 1, M16_characters.matt, true)
teleport(M16_characters.matt, M16_navpoints.matt_summon, nil, false, 1.0)
character_show(M16_characters.matt)
action_play(M16_characters.matt, M16_animations.tele_end, nil, false, 1.0)
action_play(M16_characters.matt, M16_animations.matt_taunt_b, nil, false, 1.0)
turn_vulnerable(M16_characters.matt)
set_ignore_ai_flag(M16_characters.matt, DISABLE)
objective_text( 0, "m16_obj_kill_matt", "", "", SYNC_ALL, OI_ASSET_KILL)
end
function m16_run_matt_phase_five()
set_behavior_set(M16_characters.matt, "Matt Avatar Phase 4")
marker_add(M16_characters.matt, MINIMAP_ICON_KILL, OI_ASSET_KILL_FULL, OI_FLAGS_FULL, SYNC_ALL)
set_script_animation_group(M16_characters.matt, "Default")
M16_threads.matt_teleport_thread_handle = thread_new("m16_matt_ground_teleport_thread")
m16_wait_for_matt_health(M16_phase_matt_health[current_phase+1])
thread_kill(M16_threads.matt_teleport_thread_handle)
M16_threads.matt_teleport_thread_handle = INVALID_THREAD_HANDLE
-- Warp Matt out
character_prevent_flinching(M16_characters.matt, ENABLE)
turn_invulnerable(M16_characters.matt)
set_ignore_ai_flag(M16_characters.matt, true)
action_stop_custom(M16_characters.matt)
delay(0.5)
action_play(M16_characters.matt, M16_animations.matt_taunt_b, nil, false, 1.0)
action_play(M16_characters.matt, M16_animations.tele_start, nil, false, 1.0)
boss_battle_matt_set_matt_flying(ENABLE) -- turn on flying so we can teleport him under the ground temporarily
character_hide(M16_characters.matt)
inv_item_remove_all(M16_characters.matt)
marker_remove(M16_characters.matt)
human_gravity_enable(M16_characters.matt, DISABLE)
teleport(M16_characters.matt, M16_navpoints.matt_hide_loc)
delay(1)
character_show(M16_characters.matt)
delay(1)
on_qte_animation_trigger("m16_final_qte_fade_cb")
m16_do_qte(M16_navpoints.final_qte)
inv_item_add("Avatar_Sword", 1, M16_characters.matt, true)
while (m16_wait_for_qte_complete() == false) do
M16_threads.matt_teleport_thread_handle = thread_new("m16_matt_ground_teleport_thread")
-- Player failed, reset HP and set up the gameplay qte
m16_set_current_phase_hitpoints()
turn_vulnerable(M16_characters.matt)
set_ignore_ai_flag(M16_characters.matt, DISABLE)
human_gravity_enable(M16_characters.matt, ENABLE)
boss_battle_matt_set_matt_flying(DISABLE)
character_prevent_flinching(M16_characters.matt, DISABLE)
marker_add(M16_characters.matt, MINIMAP_ICON_KILL, OI_ASSET_KILL_FULL, OI_FLAGS_FULL, SYNC_ALL)
-- Wait for him to get back below the amount, and do it again.
m16_wait_for_matt_health(M16_phase_matt_health[current_phase+1])
thread_kill(M16_threads.matt_teleport_thread_handle)
M16_threads.matt_teleport_thread_handle = INVALID_THREAD_HANDLE
turn_invulnerable(M16_characters.matt)
character_prevent_flinching(M16_characters.matt, ENABLE)
set_ignore_ai_flag(M16_characters.matt, true)
action_stop_custom(M16_characters.matt)
delay(0.5)
action_play(M16_characters.matt, M16_animations.matt_taunt_b, nil, false, 1.0)
action_play(M16_characters.matt, M16_animations.tele_start, nil, false, 1.0)
character_hide(M16_characters.matt)
inv_item_remove_all(M16_characters.matt)
marker_remove(M16_characters.matt)
human_gravity_enable(M16_characters.matt, DISABLE)
boss_battle_matt_set_matt_flying(ENABLE)
teleport(M16_characters.matt, M16_navpoints.matt_hide_loc)
delay(1)
character_show(M16_characters.matt)
delay(1)
m16_do_qte(M16_navpoints.final_qte)
inv_item_add("Avatar_Sword", 1, M16_characters.matt, true)
end
if M16_threads.matt_health_thread_handle ~= INVALID_THREAD_HANDLE then
thread_kill(M16_threads.matt_health_thread_handle)
M16_threads.matt_health_thread_handle = INVALID_THREAD_HANDLE
end
on_qte_animation_trigger("")
boss_battle_matt_set_matt_flying(DISABLE)
marker_remove(M16_characters.matt, SYNC_ALL)
objective_text_clear(0)
end
-- Player choice sequence that happens once Matt has been defeated
function m16_player_choice()
if group_is_loaded(M16_groups.matt.name) then
group_destroy(M16_groups.matt.name)
end
customization_item_revert()
customization_outfit_wear("Cyber Avatar")
objective_text_clear(0)
teleport_coop(M16_navpoints.final_choice_local, M16_navpoints.final_choice_remote , true)
mission_start_fade_in()
delay(1.0)
-- Play matt's conversation
m16_helper_conversation_play(M16_conv.reward_choice, M16_CONVO_PLAY_IMMEDIATE, 0.0)
delay(3.0)
on_trigger("m16_player_choice_made_cb", M16_triggers.choicea)
trigger_enable(M16_triggers.choicea, true)
on_trigger("m16_player_choice_made_cb", M16_triggers.choiceb)
trigger_enable(M16_triggers.choiceb, true)
marker_add_trigger(M16_triggers.choicea, MINIMAP_ICON_USE, INGAME_EFFECT_CHECKPOINT, OI_ASSET_USE, OI_FLAGS_LOCATION, SYNC_ALL)
marker_add_trigger(M16_triggers.choiceb, MINIMAP_ICON_USE, INGAME_EFFECT_CHECKPOINT, OI_ASSET_USE, OI_FLAGS_LOCATION, SYNC_ALL)
object_indicator_add_objective_text(M16_triggers.choicea, "PLAYER_CHOICE_M16_OPTION2_TITLE", "PLAYER_CHOICE_M16_OPTION2_BODY")
object_indicator_add_objective_text(M16_triggers.choiceb, "PLAYER_CHOICE_M16_OPTION1_TITLE", "PLAYER_CHOICE_M16_OPTION1_BODY")
while (not M16_conv.reward_choice.completed) and (player_choice == "") do
thread_yield()
end
objective_text( 0, "M16_OBJ_CHOOSE_A_COMPANY", "", "", SYNC_ALL, OI_ASSET_USE)
while(player_choice == "") do
thread_yield()
end
if (player_choice == "choicea") then
mission_set_excluded_reward("Vehicle_Customization_Price")
else
mission_set_excluded_reward("Weapon_Customization_Price")
end
fade_out(0)
delay(2)
inv_item_equip(nil, LOCAL_PLAYER) -- Unequip the current weapon on the player
if in_coop then
inv_item_equip(nil, REMOTE_PLAYER) -- Unequip the current weapon on the player
end
end
function m16_matt_intro_zscene()
while (not zscene_is_loaded(M16_scene.matt_intro)) do
thread_yield()
end
cutscene_play(M16_scene.matt_intro, nil, nil, false)
end
function m16_matt_defeated_zscene()
m16_music_switch("")
while (not zscene_is_loaded(M16_scene.matt_defeated)) do
thread_yield()
end
cutscene_play(M16_scene.matt_defeated, nil, nil, false)
end
-- ***************************************************
-- m16_run Helper Functions
-- ***************************************************
-- Perform the necessary things to get Matt back into the air after failing a QTE.
--
function m16_matt_lift_off_again()
set_behavior_set(M16_characters.matt, "Matt Avatar Phase 1")
human_gravity_enable(M16_characters.matt, DISABLE)
-- change his AI and animation group
set_script_animation_group(M16_characters.matt, "Pistol")
delay(3)
set_animation_state(M16_characters.matt, "stand ready")
set_ignore_ai_flag(M16_characters.matt, false)
-- Fire back up the teleport thread
M16_threads.matt_teleport_thread_handle = thread_new("m16_matt_air_teleport_thread")
end
-- Make Matt land on the ground
function m16_matt_land()
thread_kill(M16_threads.matt_teleport_thread_handle)
M16_threads.matt_teleport_thread_handle = INVALID_THREAD_HANDLE
set_ignore_ai_flag(M16_characters.matt, true)
action_stop_custom(M16_characters.matt)
delay(0.5)
action_play_non_blocking(M16_characters.matt, "ready to stand")
repeat
thread_yield()
until action_play_is_finished(M16_characters.matt, 0.75)
marker_remove(M16_characters.matt)
repeat
thread_yield()
until action_play_is_finished(M16_characters.matt, 1.0)
inv_item_remove_all(M16_characters.matt)
teleport(M16_characters.matt, M16_navpoints.matt_hide_loc)
inv_item_add("Avatar_Sword", 1, M16_characters.matt, true)
delay(1)
character_show(M16_characters.matt)
end
function m16_attach_emoticon(member)
if(rand_int(1,2) == 1) then
effect_play_on_human(m16_vfx_deckers_damaged, member, "Head", true)
else
effect_play_on_human(m16_vfx_deckers_attacking, member, "Head", true)
end
end
function m16_setup_cyberdecker(member)
turn_invulnerable(member)
effect_play_on_human(m16_vfx_spawn, member)
npc_suppress_persona(member, ENABLE)
character_show(member)
character_set_counter_on_grabbed_by_player(member, true)
on_death("m16_clear_callbacks", member)
if not character_is_dead(member) then
m16_attach_emoticon(member)
end
ai_add_enemy_target(member, CLOSEST_PLAYER, ATTACK_NOW)
turn_vulnerable(member)
delay(DELAY_BETWEEN_DECKER_GROUP_SPAWNS)
end
-- Spawns a group as hidden, and plays the spawning effect on them just before unhiding them.
--
-- group_name: (string) name of the group to spawn
--
function m16_spawn_cyberdecker_group(group_name)
group_create_hidden(group_name, true)
group_foreach_npc(group_name, m16_setup_cyberdecker)
end
-- Checks to see if the players are in the middle of a combat move and if they are 'ready'
--
-- returns: (bool) true - both players are not in a combat move and are ready, false otherwise
function m16_players_are_ready_to_transform()
local local_player_ready = false
local remote_player_ready = false
if not character_playing_combat_move(LOCAL_PLAYER) and character_is_ready(LOCAL_PLAYER) then
local_player_ready = true
end
if in_coop then
if not character_playing_combat_move(REMOTE_PLAYER) and character_is_ready(REMOTE_PLAYER) then
remote_player_ready = true
else
remote_player_ready = false
end
else
remote_player_ready = true -- just force this to true when no coop player is present
end
if local_player_ready and remote_player_ready then
return true
else
return false
end
end
-- Handles transforming the players into the human avatar and makes sure it is safe to do so
function m16_transform_player_into_human_avatar()
local safe_to_transform = false
-- We need to make sure the players aren't doing anything like melee moves during the transform
while not safe_to_transform do
-- Check and see if the player is in the middle of anything
while not m16_players_are_ready_to_transform() do
-- They are, so block
thread_yield()
end
-- Both players are either ready or are exiting synced melee animations
delay(5) -- wait a few seconds for any animations to finish blending, then check again
if m16_players_are_ready_to_transform() then
-- Still not doing anything, its now safe to transform
safe_to_transform = true
end
thread_yield()
end
m16_helper_conversation_play(M16_conv.actual_avatar, M16_CONVO_PLAY_IMMEDIATE, 2.0)
-- Play spawning effect as the player changes shapes
effect_play_on_human(m16_vfx_spawn, LOCAL_PLAYER)
if in_coop then
effect_play_on_human(m16_vfx_spawn, REMOTE_PLAYER)
end
customization_outfit_wear("Cyber Avatar") -- put on the cyber suit.
inv_item_add(M16_PLAYER_GUN, 1, LOCAL_PLAYER, true)
if in_coop then
inv_item_add(M16_PLAYER_GUN, 1, REMOTE_PLAYER, true)
end
end
-- ***************************************************
-- m16_initialize Helper Functions
-- ***************************************************
-- Handle any common initialization
--
function m16_initialize_common()
on_human_killed("m16_cyberdecker_died_cb")
-- No notoriety for this mission
notoriety_force_no_spawn("police", true)
notoriety_force_no_spawn("deckers", true)
-- Bring no homies.
party_dismiss_all()
-- set up the death trigger
on_trigger("m16_death_trigger", M16_triggers.death)
trigger_enable(M16_triggers.death, true)
-- Keep track of the special weapon for both players
inv_item_equip(nil, LOCAL_PLAYER) -- Unequip the current weapon on the player
m16_local_player_special_weapon = inv_item_in_slot(LOCAL_PLAYER, "special") -- if the player has a special weapon, remove it for the mission
if m16_local_player_special_weapon ~= nil then
inv_item_remove(m16_local_player_special_weapon, LOCAL_PLAYER)
end
if in_coop then
inv_item_equip(nil, REMOTE_PLAYER) -- Unequip the current weapon on the player
m16_remote_player_special_weapon = inv_item_in_slot(REMOTE_PLAYER, "special") -- remove the current special weapon for the mission
if m16_remote_player_special_weapon ~= nil then
inv_item_remove(m16_remote_player_special_weapon, REMOTE_PLAYER)
end
end
-- Hide the minimap
M16_hud_states.hide_minimap = hud_display_create_state()
hud_display_set_element(M16_hud_states.hide_minimap, HUD_ELEM_MINIMAP, HUD_FADE_HIDDEN)
hud_display_commit_state(M16_hud_states.hide_minimap)
-- disable the players weapon radial
hud_inventory_disable(true)
if in_coop then
hud_inventory_disable(true, REMOTE_PLAYER)
end
player_grenades_disable()
-- Load 2d personas
M16_personas.kinzie.persona_id = audio_persona_load_2d(M16_personas.kinzie.name)
M16_personas.matt.persona_id = audio_persona_load_2d(M16_personas.matt.name)
-- Start the conversation thread
M16_threads.process_convo = thread_new("m16_thread_process_conversations")
-- SP 7/13: screen effects turn on when mission starts
hdr_bloom_set_multiplier(1.5)
refraction_situation_set("cyber_m16")
end
-- Checkpoint specific initialization
--
-- checkpoint: The checkpoint to be initialized
function m16_initialize_checkpoint(checkpoint)
if (checkpoint == M16_checkpoints.TEXT_ADVENTURE_COMPLETE) then
m16_music_switch("M16_Music_01b_Play")
end
if (checkpoint == M16_checkpoints.TANK_COMBAT_COMPLETE) then
m16_music_switch("M16_Music_02_Play")
end
-- Put on the cyber suit.
if (checkpoint ~= M16_checkpoints.CHECKPOINT_START) then
inv_item_add(M16_PLAYER_GUN, 1, LOCAL_PLAYER, true)
if in_coop then
inv_item_add(M16_PLAYER_GUN, 1, REMOTE_PLAYER, true)
end
if (checkpoint ~= M16_checkpoints.DECKER_PHASE) and (checkpoint ~= M16_checkpoints.AVATAR_BATTLE) then
customization_outfit_wear("Cyber Avatar")
end
end
if (checkpoint == M16_checkpoints.MATT_DEWINGED) then
m16_init_matt_battle(M16_checkpoints.MATT_DEWINGED)
boss_battle_matt_begin() -- begin the fight, start cheats
boss_battle_matt_set_matt_flying(DISABLE)
delay(1)
boss_battle_matt_hide_wings()
M16_threads.cheat_audio_handle = thread_new("m16_thread_cheat_audio_thread") -- start up the cheat audio thread
mission_start_fade_in()
end
if (checkpoint == M16_checkpoints.MATT_PHASE3) then
m16_init_matt_battle(M16_checkpoints.MATT_PHASE3)
boss_battle_matt_begin() -- begin the fight, start cheats
boss_battle_matt_set_matt_flying(DISABLE)
delay(1)
boss_battle_matt_hide_wings()
M16_threads.cheat_audio_handle = thread_new("m16_thread_cheat_audio_thread") -- start up the cheat audio thread
mission_start_fade_in()
end
if (checkpoint == M16_checkpoints.DECKER_PHASE) then
m16_init_matt_battle(M16_checkpoints.DECKER_PHASE)
boss_battle_matt_set_player_as_avatar(ENABLE)
set_behavior_set(M16_characters.matt, "Matt Avatar Phase 2") -- Override Matts behavior
character_hide(M16_characters.matt)
boss_battle_matt_set_matt_flying(DISABLE)
delay(1)
boss_battle_matt_hide_wings()
inv_add_temp_loadout(AVATAR_LOADOUT)
inv_item_remove_all(M16_characters.matt)
delay(1)
mission_start_fade_in()
end
if (checkpoint == M16_checkpoints.AVATAR_BATTLE) then
m16_init_matt_battle(M16_checkpoints.AVATAR_BATTLE)
set_ignore_ai_flag(M16_characters.matt, ENABLE)
boss_battle_matt_set_player_as_avatar(ENABLE)
set_behavior_set(M16_characters.matt, "Matt Avatar Phase 4")
boss_battle_matt_set_matt_flying(DISABLE)
delay(1)
boss_battle_matt_hide_wings()
inv_add_temp_loadout(AVATAR_LOADOUT)
delay(1)
set_ignore_ai_flag(M16_characters.matt, DISABLE)
mission_start_fade_in()
end
end
-- Initialzation for the boss battle, generic stuff - nothing phase specific
function m16_init_matt_battle(checkpoint_name)
teleport_coop(M16_navpoints.local_matt_battle_start, M16_navpoints.remote_matt_battle_start, true)
objective_text( 0, "m16_obj_kill_matt", "", "", SYNC_ALL, OI_ASSET_KILL)
group_create(M16_groups.matt.name, true)
character_set_only_scripted_grabs(M16_characters.matt, true)
set_behavior_set(M16_characters.matt, "Matt Avatar Phase 1") -- Set his behavior to the default behavior
if checkpoint_name ~= M16_checkpoints.DECKER_PHASE then
marker_add(M16_characters.matt, MINIMAP_ICON_KILL, OI_ASSET_KILL_FULL, OI_FLAGS_FULL, SYNC_ALL)
end
inv_item_remove_all(M16_characters.matt)
set_cant_flee_flag(M16_characters.matt, ENABLE)
inv_item_add("Avatar_Sword", 1, M16_characters.matt, true)
character_allow_ragdoll(M16_characters.matt, false)
character_set_never_fall(M16_characters.matt, false)
ai_add_enemy_target(M16_characters.matt, CLOSEST_PLAYER, ATTACK_NOW_NEVER_LOSE)
character_disable_revival(LOCAL_PLAYER, ENABLE)
if in_coop then
character_disable_revival(REMOTE_PLAYER, ENABLE)
local single_player_hp = get_max_hit_points(M16_characters.matt)
set_max_hit_points(M16_characters.matt, single_player_hp * MATT_COOP_HEALTH_MULTIPLIER, true)
end
-- Make sure the cybercannon is equipped
inv_item_equip(M16_PLAYER_GUN, LOCAL_PLAYER)
if in_coop then
inv_item_equip(M16_PLAYER_GUN, REMOTE_PLAYER)
end
m16_music_switch("M16_Boss_Music_Play")
end
-- ***************************************************
-- Miscellaneous m16 Helper Functions
-- ***************************************************
-- Cleanup all threads
--
function m16_cleanup_threads()
cleanup_threads(M16_threads)
end
-- Cleanup all the groups of characters and vehicles
--
function m16_cleanup_groups()
cleanup_groups(M16_groups)
for i, group in pairs(M16_groups) do
group_foreach_npc(group.name, m16_clear_callbacks)
end
end
function m16_cleanup_triggers(trigger_group)
for i, trigger in pairs(trigger_group) do
if (type(trigger) == "table") then
m16_cleanup_triggers(trigger)
else
on_trigger("", trigger)
trigger_enable(trigger, false)
marker_remove(trigger)
end
end
end
function m16_end_conversations()
-- Kill the conversation thread
m16_helper_conversation_kill_all()
if (thread_check_done(M16_threads.process_convo) == false) then
thread_kill(M16_threads.process_convo)
M16_threads.process_convo = INVALID_THREAD_HANDLE
end
audio_persona_remove_2d(M16_personas.kinzie.persona_id)
M16_personas.kinzie.persona_id = INVALID_PERSONA_HANDLE
audio_persona_remove_2d(M16_personas.matt.persona_id)
M16_personas.matt.persona_id = INVALID_PERSONA_HANDLE
end
function m16_kill_group_member(member)
if (not character_is_dead(member) and not character_hidden(member)) then
character_kill(member)
end
end
-- Kills all alive group members
function m16_kill_all_group_members(gate_groups)
for i, group in pairs(gate_groups) do
group_foreach_npc(group.name, m16_kill_group_member)
end
end
-- Helper function that enables all the surprise group triggers, and sets up their callbacks
--
-- surprise_groups: (table) Table of groups to set up
-- callback: (string) Correstponding on_trigger callback
function m16_helper_surprise_groups_setup(surprise_groups, callback)
for i, trigger in pairs(surprise_groups) do
on_trigger(callback, trigger)
trigger_enable(trigger, ENABLE)
end
end
-- Helper function that disables all surprise group triggers, and cleans up all the surprise groups
--
-- surprise_groups: (table) Table of groups to set up (ex. M16_surprise_triggers.surprise1)
function m16_helper_surprise_groups_disable(surprise_groups)
for i, trigger in pairs(surprise_groups) do
on_trigger("", trigger.name)
trigger_enable(trigger.name, DISABLE)
if group_is_loaded(trigger.script_group.name) then
-- Remove all the callbacks on the group members
for i, member in pairs(trigger.script_group.members) do
on_death("", member)
end
group_destroy(trigger.script_group.name)
end
end
end
-- Custom process enemey set for m16. Marks all npcs in the group spawned and waits for their death.
function m16_process_enemy_set(enemy_table)
enemy_set_setup(enemy_table, true)
while (not Process_enemy_set_cleared) do
thread_yield()
end
-- make sure everything is cleaned up
enemy_set_cleanup(enemy_table)
end
-- Check if a particular conversation is done (Originally written by Matt Gawalek for Mission 02)
--
-- convo_table: Conversation Lua table (see M16_conversations)
function m16_helper_conversation_check_done(convo_table)
if (convo_table.queued == false) then
return true
else
return convo_table.ended
end
end
-- Helper to play conversations, by adding them to the cue (Originally written by Matt Gawalek for Mission 02)
--
-- convo_table: Conversation Lua table (see M16_conversations)
-- priority: Desired priority for the conversation
-- delay: Amonut of time to dalya after this conversation before playing the next conversation (in seconds)
function m16_helper_conversation_play(convo_table, priority, delay)
convo_table.queued = true
convo_table.delay = delay
if (priority == M16_CONVO_PLAY_LAST) then
-- Insert this entry at the end of hte lsit
convo_queue.list[convo_queue.size] = convo_table
convo_queue.size = convo_queue.size + 1
elseif (priority == M16_CONVO_PLAY_NEXT) then
-- Shift the list to the right
for i = convo_queue.size - 1, 0, -1 do
convo_queue.list[i + 1] = convo_queue.list[i]
end
convo_queue.list[0] = convo_table
convo_queue.size = convo_queue.size + 1
elseif (priority == M16_CONVO_PLAY_IMMEDIATE) then
-- Stop any actively playing conversations, and start this one immediatly
m16_helper_conversation_cleanup_playing()
convo_queue.playing.thread_id = thread_new("m16_thread_play_convo", convo_table)
end
end
-- Kill any active conversation, and clear out the conversation queue (Originally written by Matt Gawalek for Mission 02)
function m16_helper_conversation_kill_all()
-- Stop any active conversation
m16_helper_conversation_cleanup_playing()
-- Clear out the queue
for i = 0, convo_queue.size - 1 do
convo_queue.list[i].ended = true
end
convo_queue.size = 0
end
-- Cleanup any playing conversation (Originally written by Matt Gawalek for Mission 02)
function m16_helper_conversation_cleanup_playing()
-- Stop the thread processing a playing conversation
if (convo_queue.playing.thread_id ~= -1) then
thread_kill(convo_queue.playing.thread_id)
convo_queue.playing.thread_id = -1
end
-- Cleanup and conversation data for a playing conversation
if (convo_queue.playing.conv_handle ~= INVALID_CONVERSATION_HANDLE) then
audio_conversation_end(convo_queue.playing.conv_handle)
convo_queue.playing.conv_handle = INVALID_CONVERSATION_HANDLE
end
-- Mark the playing conversation as ended
if (convo_queue.playing.convo_table ~= nil) then
convo_queue.playing.convo_table.ended = true
end
end
-- Thread to process playing a single converation (Originally written by Matt Gawalek for Mission 02)
function m16_thread_play_convo(convo_table)
-- Add this conversatin to the playing conversation data
convo_queue.playing.convo_table = convo_table
convo_table.started = true -- it has now started
-- Load the conversation data
if (convo_table.load_direct == false) then
convo_queue.playing.conv_handle = audio_conversation_load(convo_table.name)
else
convo_queue.playing.conv_handle = audio_conversation_load_direct(convo_table.name)
end
-- Delay the desired amount
delay(convo_table.delay)
-- Play the conversation and wait for it to end
audio_conversation_play(convo_queue.playing.conv_handle)
audio_conversation_wait_for_end(convo_queue.playing.conv_handle)
audio_conversation_end(convo_queue.playing.conv_handle)
-- Do some book-keeping
convo_queue.playing.conv_handle = INVALID_CONVERSATION_HANDLE
convo_table.completed = true
convo_table.ended = true
end
-- Given a persona and line, plays and blocks until completion
--
-- persona_id: (int) id of the persona speaking
-- line: (string) name of the line
function m16_helper_play_dialog_line(persona_id, line)
dialog_line_audio_id = audio_play_persona_line_2d(persona_id, line)
while(audio_is_playing(dialog_line_audio_id) == true) do
thread_yield()
end
dialog_line_audio_id = -1
end
-- Stops any currently playing dialog line
function m16_helper_stop_dialog_line()
if dialog_line_audio_id ~= -1 then
audio_stop(dialog_line_audio_id)
end
end
-- *************************
--
-- Callback functions
--
-- *************************
function m16_clear_callbacks(npc)
on_death("", npc)
end
-- Callback for on_human_death that plays the despawn effect on any human killed during the mission that is not
-- the player or in a vehicle
--
-- npc_team: (string) team this npc belongs to
-- killer_name: (string) name of the person who killed this human
-- npc_name: (string) name of the npc that died
--
function m16_cyberdecker_died_cb(npc_team, killer_name, npc_name)
if npc_name ~= LOCAL_PLAYER and npc_name ~= REMOTE_PLAYER and npc_name ~= nil then
if (not character_is_in_vehicle(npc_name) and character_exists(npc_name) and not character_hidden(npc_name)) then
effect_play_on_human(m16_vfx_despawn, npc_name)
delay(0.5)
character_hide(npc_name)
end
end
end
-- On_trigger callback used to spawn in cyberdeckers in the areas before the gates
--
--
-- triggerer: (string) name of the player who entered
-- trigger: (string) name of the trigger that was hit
function m16_cb_spawn_surprise_group(triggerer, trigger)
on_trigger("", trigger)
trigger_enable(trigger, DISABLE)
-- Find which surprise group to spawn
local trigger_group
for i, surprise_trigger in pairs(M16_surprise_triggers) do
if trigger == surprise_trigger.name then
trigger_group = surprise_trigger.script_group
break
end
end
m16_spawn_cyberdecker_group(trigger_group)
end
-- On_trigger callback used to spawn in cyberdeckers during the firewall sequence
--
--
-- triggerer: (string) name of the player who entered
-- trigger: (string) name of the trigger that was hit
function m16_cb_spawn_firewall_group(triggerer, trigger)
on_trigger("", trigger)
trigger_enable(trigger, DISABLE)
-- Find which surprise group to spawn
local firewall_group
for i, firewall_trigger in pairs(M16_firewall_trigger_groups) do
if trigger == firewall_trigger.name then
firewall_group = firewall_trigger.script_group
break
end
end
m16_spawn_cyberdecker_group(firewall_group)
end
-- On_trigger callback for the death trigger
--
-- triggerer: (string) name of the player who entered
-- trigger: (string) name of the trigger that was hit
function m16_death_trigger(triggerer, trigger)
character_kill(triggerer)
end
-- On_trigger callback used when the player enters the firewall area
--
-- triggerer: (string) name of the player who entered
-- trigger: (string) name of the trigger that was hit
function m16_cb_firewall_area_reached(triggerer, trigger)
on_trigger("", trigger)
trigger_enable(trigger, false)
marker_remove(trigger)
gate_reached = true
end
-- On_trigger callback used when the player reaches the firewall, and completes the objective
--
-- triggerer: (string) name of the player who entered
-- trigger: (string) name of the trigger that was hit
function m16_cb_firewall_reached(triggerer, trigger)
on_trigger("", trigger)
trigger_enable(trigger, false)
marker_remove(trigger)
gate_destroyed = true
end
-- On_trigger callbacked used when a player reaches the antivirus
function m16_cb_antivirus_reached(triggerer, trigger)
on_trigger("", trigger)
trigger_enable(trigger, false)
marker_remove(trigger)
gate_reached = true
end
function m16_cb_internet_security_reached(triggerer, trigger)
on_trigger("", trigger)
trigger_enable(trigger, false)
marker_remove(trigger)
gate_reached = true
end
function m16_final_cb(triggerer, trigger)
on_trigger("", trigger)
trigger_enable(trigger, false)
marker_remove(trigger)
gate_destroyed = true
end
function m16_player_tank_destroyed_cb(vehicle)
if not in_coop then
m16_music_switch("")
audio_object_post_event( "Tank_Battle_Music_Loss" )
delay(4)
turn_vulnerable(LOCAL_PLAYER)
mission_end_failure("m16", "m16_failure_tank_destroyed")
else
if vehicle == M16_vehicles.tank_combat_player_tank_one then
if vehicle_is_destroyed(M16_vehicles.tank_combat_player_tank_two) then
-- if the other tank has been destroyed
m16_music_switch("")
audio_object_post_event( "Tank_Battle_Music_Loss" )
turn_vulnerable(LOCAL_PLAYER)
turn_vulnerable(REMOTE_PLAYER)
mission_end_failure("m16", "m16_failure_tank_destroyed")
else
character_hide(LOCAL_PLAYER)
player_controls_disable(LOCAL_PLAYER)
effect_play_on_script_object(m16_vfx_avatar_spawn, M16_vehicles.tank_combat_player_tank_two)
delay(2)
group_destroy(M16_groups.tank_combat_player_one.name)
end
else
if vehicle_is_destroyed(M16_vehicles.tank_combat_player_tank_one) then
-- if the other tank has been destroyed
m16_music_switch("")
audio_object_post_event( "Tank_Battle_Music_Loss" )
turn_vulnerable(LOCAL_PLAYER)
turn_vulnerable(REMOTE_PLAYER)
mission_end_failure("m16", "m16_failure_tank_destroyed")
else
character_hide(REMOTE_PLAYER)
player_controls_disable(REMOTE_PLAYER)
effect_play_on_script_object(m16_vfx_avatar_spawn, M16_vehicles.tank_combat_player_tank_one)
delay(2)
group_destroy(M16_groups.tank_combat_player_two.name)
end
end
end
audio_object_post_event( "Tank_Battle_Explode" )
on_vehicle_destroyed("", vehicle)
end
-- Kill the driver when the first tank is destroyed
function m16_tank_one_destroyed_cb()
-- The npc driver will pop out of the tank, turn off his AI so he won't attack the player
character_hide(M16_characters.tank_combat_tank_npc_one) -- hide the npc
set_ignore_ai_flag(M16_characters.tank_combat_tank_npc_one, ENABLE)
turn_vulnerable(M16_characters.tank_combat_tank_npc_one, true)
character_kill(M16_characters.tank_combat_tank_npc_one)
on_vehicle_destroyed("", M16_vehicles.tank_combat_npc_tank_one)
audio_object_post_event( "Tank_Battle_Explode" )
effect_play_on_script_object(m16_vfx_avatar_spawn, M16_vehicles.tank_combat_npc_tank_one)
delay(2)
group_destroy(M16_groups.tank_combat_npc_one.name)
end
-- Kill the driver when the second tank is destroyed
function m16_tank_two_destroyed_cb()
-- The npc driver will pop out of the tank, turn off his AI so he won't attack the player
character_hide(M16_characters.tank_combat_tank_npc_two) -- hide the npc
set_ignore_ai_flag(M16_characters.tank_combat_tank_npc_two, ENABLE)
turn_vulnerable(M16_characters.tank_combat_tank_npc_two, true)
character_kill(M16_characters.tank_combat_tank_npc_two)
on_vehicle_destroyed("", M16_vehicles.tank_combat_npc_tank_two)
audio_object_post_event( "Tank_Battle_Explode" )
effect_play_on_script_object(m16_vfx_avatar_spawn, M16_vehicles.tank_combat_npc_tank_two)
delay(2)
group_destroy(M16_groups.tank_combat_npc_two.name)
end
function m16_cathedral_walk_wall_fade(triggerer, trigger_name)
on_trigger("", trigger_name)
trigger_enable(trigger_name, false)
for i, trigger in pairs(M16_triggers.cathedral_wall) do
if trigger_name == trigger then
-- we found which number this trigger is, get the mover and perform the effect
local mover = M16_movers.triggered_final_gate_movers[i]
effect_play_on_script_object(m16_vfx_forcefield_destroyed, mover)
delay(1.5)
mesh_mover_hide(mover)
break
end
end
end
-- Stats the final sequence up to and including the qte
function m16_do_qte(play_at_nav)
marker_remove(M16_characters.matt)
boss_battle_matt_qte_begin(LOCAL_PLAYER, play_at_nav)
end
-- Once Matt gets to a certain health, this function hides him and beings the next phase
function m16_prep_avatar_for_decker_battle()
m16_helper_stop_dialog_line() -- stop cheat dialog
boss_battle_matt_cheats_stop() -- stop cheats
M16_threads.player_transform_handle = thread_new("m16_thread_boss_battle_avatar_player_transform")
m16_helper_conversation_play(M16_conv.player_turned_into_avatar, M16_CONVO_PLAY_IMMEDIATE, 2.0)
turn_invulnerable(M16_characters.matt)
set_ignore_ai_flag(M16_characters.matt, ENABLE)
-- Teleport to the summoning location
action_play_non_blocking(M16_characters.matt, M16_animations.tele_start)
repeat
thread_yield()
until action_play_is_finished(M16_characters.matt, 0.75)
marker_remove(M16_characters.matt)
repeat
thread_yield()
until action_play_is_finished(M16_characters.matt, 1.0)
character_hide(M16_characters.matt)
teleport(M16_characters.matt, M16_navpoints.matt_summon)
inv_item_remove_all(M16_characters.matt)
delay(1)
character_show(M16_characters.matt)
action_play(M16_characters.matt, M16_animations.tele_end, nil, false, 1.0)
action_play(M16_characters.matt, M16_animations.matt_summon, nil, false, 1.0)
action_play(M16_characters.matt, M16_animations.tele_start, nil, false, 1.0)
character_hide(M16_characters.matt)
threads_wait_for_completion(M16_threads.player_transform_handle)
M16_threads.player_transform_handle = INVALID_THREAD_HANDLE
end
function m16_player_choice_made_cb(triggerer, trigger)
-- Cleanup triggers
on_trigger("", M16_triggers.choicea)
trigger_enable(M16_triggers.choicea, false)
on_trigger("", M16_triggers.choiceb)
trigger_enable(M16_triggers.choiceb, false)
if player_choice == "" then
if (trigger == M16_triggers.choicea) then
player_choice = "choicea"
else
player_choice = "choiceb"
end
end
end
function m16_final_qte_fade_cb()
mission_start_fade_out()
m16_qte_complete(true)
qte_cleanup()
end
-- *************************
--
-- Thread functions
--
-- *************************
-- Simple thread that keeps a tank on a path. Each path has a forward and backwards spline
--
-- tank: (string) name of tank
-- path_list: (table) list of viable paths names for that tank
--
function m16_do_tank_pathing_thread(tank, path_set)
local forward_path_set = path_set[1]
local backward_path_set = path_set[2]
while true do
local path_index = rand_int(1, sizeof_table(forward_path_set))
local forward_path = forward_path_set[path_index]
local backward_path = backward_path_set[path_index]
vehicle_pathfind_to(tank, forward_path, true, false, false, false)
vehicle_pathfind_to(tank, backward_path, true, false, false, false)
thread_yield()
end
end
-- Keeps matt's health above the appropriate amount.
function m16_matt_health_thread(min_pct)
while not character_exists(M16_characters.matt) do
thread_yield()
end
while true do
local min_hp = get_max_hit_points(M16_characters.matt) * min_pct
min_hp = min_hp - 100 -- make sure it gets below the threshold so the battle will continue.
local cur_hp = get_current_hit_points(M16_characters.matt)
if cur_hp < min_hp then
set_current_hit_points(M16_characters.matt, get_max_hit_points(M16_characters.matt) * min_pct) -- reset matt
Matt_health_pct = min_pct
end
thread_yield()
end
end
-- Teleports Matt to one of x number of navpoints within M16_navpoints.matt_teleports every TIME_BETWEEN_AIR_TELEPORTS seconds during the air phase
function m16_matt_air_teleport_thread()
local previous_teleport_navpoint_name = M16_navpoints.matt_teleports[2] -- matt is basically already at this one after liftoff
while true do
set_ignore_ai_flag(M16_characters.matt, ENABLE)
turn_invulnerable(M16_characters.matt)
delay(0.5)
local random_navpoint = get_random_table_entry(M16_navpoints.matt_teleports)
-- Make sure we dont warp to the same spot
while previous_teleport_navpoint_name == random_navpoint do
random_navpoint = get_random_table_entry(M16_navpoints.matt_teleports)
thread_yield()
end
previous_teleport_navpoint_name = random_navpoint -- update the previous spot
action_play(M16_characters.matt, M16_animations.tele_start, nil, false, 1.0)
teleport(M16_characters.matt, random_navpoint)
action_play(M16_characters.matt, M16_animations.tele_end, nil, false, 1.0)
turn_vulnerable(M16_characters.matt)
set_ignore_ai_flag(M16_characters.matt, DISABLE)
ai_set_action_delay(M16_characters.matt, "avatar fireballs", 1.0)
ai_add_enemy_target(M16_characters.matt, CLOSEST_PLAYER, 2)
delay(TIME_BETWEEN_AIR_TELEPORTS)
thread_yield()
end
end
-- Teleports Matt to one of x number of navpoints within M16_navpoints.matt_teleports every TIME_BETWEEN_GROUND_TELEPORTS seconds when hes on the ground
function m16_matt_ground_teleport_thread()
delay(TIME_BETWEEN_GROUND_TELEPORTS)
while true do
local distance_from_local_player_to_matt = get_dist(M16_characters.matt, LOCAL_PLAYER)
local distance_from_remote_player_to_matt = 0
if in_coop then
distance_from_remote_player_to_matt = get_dist(M16_characters.matt, REMOTE_PLAYER)
end
local player_is_within_teleport_range = false
if distance_from_local_player_to_matt <= M16_PLAYER_DISTANCE_FOR_TELEPORT then
player_is_within_teleport_range = true
else
if in_coop then
if distance_from_remote_player_to_matt <= M16_PLAYER_DISTANCE_FOR_TELEPORT then
player_is_within_teleport_range = true
end
end
end
if player_is_within_teleport_range then
local distance_to_navpoint = 0
local local_dist_to_nav = 0
local remote_dist_to_nav = 0
local random_navpoint = ""
local valid_teleport_navpoint = false
-- Find a random navpoint that is atleast M16_MIN_DISTANCE_FOR_TELEPORT away from Matt and one that
while not valid_teleport_navpoint do
random_navpoint = get_random_table_entry(M16_navpoints.matt_teleports)
distance_to_navpoint = get_dist(M16_characters.matt, random_navpoint)
local local_dist_to_nav = get_dist(LOCAL_PLAYER, random_navpoint)
if in_coop then
remote_dist_to_nav = get_dist(REMOTE_PLAYER, random_navpoint)
end
if distance_to_navpoint >= M16_MIN_DISTANCE_FOR_TELEPORT then
if local_dist_to_nav >= M16_MIN_DISTANCE_FOR_TELEPORT then
if in_coop then
if remote_dist_to_nav >= M16_MIN_DISTANCE_FOR_TELEPORT then
valid_teleport_navpoint = true
end
else
valid_teleport_navpoint = true
end
end
end
thread_yield()
end
set_ignore_ai_flag(M16_characters.matt, ENABLE)
character_prevent_flinching(M16_characters.matt, ENABLE)
turn_invulnerable(M16_characters.matt)
delay(1)
action_play(M16_characters.matt, M16_animations.tele_start, nil, false, 1.0)
teleport(M16_characters.matt, random_navpoint)
action_play(M16_characters.matt, M16_animations.tele_end, nil, false, 1.0)
turn_vulnerable(M16_characters.matt)
character_prevent_flinching(M16_characters.matt, DISABLE)
set_ignore_ai_flag(M16_characters.matt, DISABLE)
ai_add_enemy_target(M16_characters.matt, CLOSEST_PLAYER, 2)
end
delay(TIME_BETWEEN_GROUND_TELEPORTS)
thread_yield()
end
end
-- Process the conversation queue (should be running the duration of the mission) (Originally written by Matt Gawalek for Mission 02)
function m16_thread_process_conversations()
-- Loop forever
while(true) do
-- Wait until something is added to the queue
while(convo_queue.size == 0 or convo_queue.playing.conv_handle ~= INVALID_CONVERSATION_HANDLE) do
thread_yield()
end
-- Play the first conversation from the queue, and then remove it from the queue
-- Slone TODO: See if this works--Lua indexing starts at 1, not 0.
convo_queue.playing.thread_id = thread_new("m16_thread_play_convo", convo_queue.list[0])
for i = 1, convo_queue.size do
convo_queue.list[i - 1] = convo_queue.list[i]
end
convo_queue.size = convo_queue.size - 1
-- Wait for the active conversation thread to end
while(thread_check_done(convo_queue.playing.thread_id) == false) do
thread_yield()
end
end
end
--callback function to play a sound if you fire the lame weapon
function m16_thread_lame_weapon_cheat_cb(char, weap, attack)
local cheat = boss_battle_matt_get_cheat()
if (cheat == M16_CHEAT_WEAPON) then
audio_object_post_event("M16_hotdog_fire")
end
end
-- Thread that monitors the status of the cheats, playing audio when needed
function m16_thread_text_adventure_audio_thread()
local death_index = -1
local audio_play_id = -1
-- wait for the text adventure intro conversation to end
while not m16_helper_conversation_check_done(M16_conv.text_adventure) do
death_index = hud_get_text_adventure_current_screen_index() -- keep grabbing the index so that one wont play when the convo ends
thread_yield()
end
while true do
death_index = hud_get_text_adventure_current_screen_index()
if not audio_is_playing(audio_play_id) then
audio_play_id = -1
if death_index ~= -1 then
for index, screen_line in pairs(M16_text_adventure_lines) do
if death_index == screen_line[1] then
local line = screen_line[2]
if not line.played then
delay(1)
audio_play_id = audio_play_persona_line(LOCAL_PLAYER, line.name)
line.played = true
end
end
end
death_index = -1
end
end
thread_yield()
end
end
-- Thread that monitors the status of the cheats, playing audio when needed
function m16_thread_cheat_audio_thread()
local cheat = M16_CHEAT_INVALID
local line_played_for_current_cheat = false
while true do
cheat = boss_battle_matt_get_cheat()
if cheat ~= M16_CHEAT_INVALID then
if not line_played_for_current_cheat then
debug_print( "MAD", "Boss battle cheat " .. cheat )
-- Make sure we only play one set of lines per cheat
local cheat_index = cheat + 1 -- offset the index since tables start at 1
if not M16_matt_cheat_lines_01[cheat_index].played then
delay(0.5)
-- play
m16_helper_play_dialog_line(M16_personas.matt.persona_id, M16_matt_cheat_lines_01[cheat_index].name)
M16_matt_cheat_lines_01[cheat_index].played = true
delay(0.5)
-- Make sure the cheat is still playing
cheat = boss_battle_matt_get_cheat()
if cheat ~= M16_CHEAT_INVALID then
m16_helper_play_dialog_line(M16_personas.kinzie.persona_id, M16_kinzie_cheat_lines[cheat_index].name)
M16_kinzie_cheat_lines[cheat_index].played = true
end
line_played_for_current_cheat = true
else
-- try playing line 2 for this cheat
if not M16_matt_cheat_lines_02[cheat_index].played then
-- play
m16_helper_play_dialog_line(M16_personas.matt.persona_id, M16_matt_cheat_lines_02[cheat_index].name)
M16_matt_cheat_lines_02[cheat_index].played = true
line_played_for_current_cheat = true
else
-- try playing line 3 for this cheat
if not M16_matt_cheat_lines_03[cheat_index].played then
-- play
m16_helper_play_dialog_line(M16_personas.matt.persona_id, M16_matt_cheat_lines_03[cheat_index].name)
M16_matt_cheat_lines_03[cheat_index].played = true
line_played_for_current_cheat = true
end
end
end
end
else
line_played_for_current_cheat = false
end
thread_yield()
end
end
-- Thread that handles the players transformation into an avatar
function m16_thread_boss_battle_avatar_player_transform()
effect_play_on_human(m16_vfx_spawn, LOCAL_PLAYER)
if in_coop then
effect_play_on_human(m16_vfx_spawn, REMOTE_PLAYER)
end
delay(0.5)
character_hide(LOCAL_PLAYER)
if in_coop then
character_hide(REMOTE_PLAYER)
end
customization_item_revert()
delay(1)
boss_battle_matt_set_player_as_avatar(ENABLE)
inv_add_temp_loadout(AVATAR_LOADOUT)
M16_threads.local_avatar_transform_handle = thread_new("m16_thread_boss_battle_avatar_individual_transform", LOCAL_PLAYER)
if in_coop then
M16_threads.remote_avatar_transform_handle = thread_new("m16_thread_boss_battle_avatar_individual_transform", REMOTE_PLAYER)
end
threads_wait_for_completion(M16_threads.local_avatar_transform_handle)
threads_wait_for_completion(M16_threads.remote_avatar_transform_handle)
M16_threads.local_avatar_transform_handle = INVALID_THREAD_HANDLE
M16_threads.remote_avatar_transform_handle = INVALID_THREAD_HANDLE
tutorial_start("mis_16_avatar_attacks", 0, true, false) --SP 7/14: Added tutorial, feel free to move it if it's in a bad place
end
function m16_thread_boss_battle_avatar_individual_transform(player)
player_controls_disable(player)
effect_play_on_human(m16_vfx_avatar_spawn, player)
delay(0.5)
character_show(player)
action_play(player, M16_animations.matt_taunt_a, nil, false, 1.0)
player_controls_enable(player)
end
-- Thread that will handle the spawning during the boss battle's 4th phase
function m16_thread_boss_battle_decker_spawn()
while true do
local number_spawn_attempts = 0
while number_spawn_attempts < 6 do
local random_decker_group = get_random_table_entry(M16_wave_groups)
if group_is_loaded(random_decker_group) then
-- group already exists, try again
number_spawn_attempts = number_spawn_attempts + 1
else
-- group doesn't already exist, spawn it
m16_spawn_cyberdecker_group(random_decker_group)
number_spawn_attempts = 6
end
end
-- Go through and clean up any killed groups
for i, decker_group in pairs(M16_wave_groups) do
if group_is_loaded(decker_group) then
local group_dead = true -- assume the group has been killed
for member_number, member in pairs(decker_group.members) do
if character_exists(member) and not character_is_dead(member) then
group_dead = false
break
end
end
if group_dead then
delay(1)
group_destroy(decker_group)
end
end
end
thread_yield()
delay(DECKER_SPAWN_RATE)
end
end