--[[
m21.lua
SR3 Mission Script
DATE: 4-19-10
AUTHOR: John Karczewski
]]--
-- Debug flags --
-- Tweakable Parameters --
ANGEL_HEALTH_MULTIPLIER = .50 -- temp value for tweaking angel's health
-- Phase 1: Defend Angel - Angel vs Killbane --
TIME_BETWEEN_WAVES = 6 -- in seconds
TIME_BETWEEN_HARASSER_TO_DISTRACTOR = 6
TIME_BETWEEN_KILLBANE_ANGEL_ACTIONS = 2
TIME_BETWEEN_KILLBANE_ANGEL_CHEATS = 2
-- Temp phase 1 angel dmg
CHEAPSHOT_INTERVAL = 1 -- in seconds
CHEAPSHOT_DAMAGE = 35
ANGEL_DAMAGE_FROM_KILLBANE_PER_SEC = 10 -- damage per second
-- Phase 2: Defend Angel - Chainsaw --
ANGEL_DAMAGE_FROM_STOMPER_PER_SEC = 5
NUM_STOMPERS_TO_MAINTAIN = 4
-- Phase 3: Killbane Fight --
LUCHADORE_RAGDOLL_TIME = 3000 -- in ms
NUM_WEAPON_HITS_FOR_FINISHER = 4
NUM_KILLBANE_WAVES_TO_WIN = 3
KILLBANE_RIDE_MAX_TIME = 20.0 -- in seconds
-- Groups --
M21_groups = {
crowd_props = {
name = "Crowd_props_group",
},
angel = {
name = "Angel_Group",
members = { "M21_Angel" },
angel = "M21_Angel"
},
killbane = {
name = "Killbane_Group",
members = { "M21_Killbane" },
killbane = "M21_Killbane"
},
ref = {
name = "Ref_Group",
members = { "Ref" },
ref = "Ref"
},
fight_club_phase_reinforcements = {
name = "Fight_Club_Phase_Group",
members = { "Fight_club_phase_npc 001", "Fight_club_phase_npc 002", "Fight_club_phase_npc 003", "Fight_club_phase_npc 004" }
},
wave1 = {
name = "Wave1_Group",
members = { "Distractor_NPC 001",
"Harasser_Npc 001", "Harasser_Npc 002", "Harasser_Npc 002a", "Harasser_Npc 002b", "Harasser_Npc 002c", "Harasser_Npc 002d", "Harasser_Npc 002e"},
harassers = { "Harasser_Npc 001", "Harasser_Npc 002", "Harasser_Npc 002a", "Harasser_Npc 002b", "Harasser_Npc 002c", "Harasser_Npc 002d", "Harasser_Npc 002e" },
distractors = { "Distractor_NPC 001" },
effect_navpoints = { "Tunnel_effect 001", "Tunnel_effect 002"}
},
wave2 = {
name = "Wave2_Group",
members = { "Distractor_NPC 002", "Distractor_NPC 003",
"Harasser_Npc 004", "Harasser_Npc 005", "Harasser_Npc 006", "Harasser_Npc 007",
"Harasser_Npc 008", "Harasser_Npc 009" },
harassers = { "Harasser_Npc 004", "Harasser_Npc 005", "Harasser_Npc 006", "Harasser_Npc 007",
"Harasser_Npc 008", "Harasser_Npc 009" },
distractors = { "Distractor_NPC 002", "Distractor_NPC 003" },
effect_navpoints = { "Tunnel_effect 001", "Tunnel_effect 002", "Tunnel_effect 003", "Tunnel_effect 004"}
},
wave3 = {
name = "Wave3_Group",
members = { "Distractor_NPC 004", "Distractor_NPC 005",
"Harasser_Npc 010", "Harasser_Npc 011", "Harasser_Npc 012", "Harasser_Npc 013",
"Harasser_Npc 014", "Harasser_Npc 015" },
harassers = { "Harasser_Npc 010", "Harasser_Npc 011", "Harasser_Npc 012", "Harasser_Npc 013",
"Harasser_Npc 014", "Harasser_Npc 015" },
distractors = { "Distractor_NPC 004", "Distractor_NPC 005" },
effect_navpoints = { "Tunnel_effect 001", "Tunnel_effect 002", "Tunnel_effect 003", "Tunnel_effect 004" }
},
wave4 = {
name = "Wave4_Group",
members = { "Distractor_NPC 007", "Distractor_NPC 008", "Distractor_NPC 009", "Distractor_NPC 010",
"Harasser_Npc 016", "Harasser_Npc 017", "Harasser_Npc 018", "Harasser_Npc 019",
"Harasser_Npc 020", "Harasser_Npc 021", "Harasser_Npc 022", "Harasser_Npc 023",
"Harasser_Npc 024" },
harassers = { "Harasser_Npc 016", "Harasser_Npc 017", "Harasser_Npc 018", "Harasser_Npc 019",
"Harasser_Npc 020", "Harasser_Npc 021", "Harasser_Npc 022", "Harasser_Npc 023",
"Harasser_Npc 024"},
distractors = { "Distractor_NPC 007", "Distractor_NPC 008", "Distractor_NPC 009", "Distractor_NPC 010" },
effect_navpoints = { "Tunnel_effect 001", "Tunnel_effect 002", "Tunnel_effect 003", "Tunnel_effect 004",
"Tunnel_effect 005", "Tunnel_effect 006", "Tunnel_effect 007", "Tunnel_effect 008" }
},
angel_stompers = {
name = "Angel_Stomper",
members = { "npc_angel_stomper_001", "npc_angel_stomper_002", "npc_angel_stomper_003", "npc_angel_stomper_004" },
},
chainsaw_wave_01 = {
name = "Chainsaw_Wave1_Group",
members = { "Chainsaw_sequence_npc 001", "Chainsaw_sequence_npc 002", "Chainsaw_sequence_npc 003", "Chainsaw_sequence_npc 004",
"Chainsaw_sequence_npc 005", "Chainsaw_sequence_npc 006", "Chainsaw_sequence_npc 007", "Chainsaw_sequence_npc 008" },
},
chainsaw_wave_02 = {
name = "Chainsaw_Wave2_Group",
members = { "Chainsaw_sequence_npc 009", "Chainsaw_sequence_npc 010", "Chainsaw_sequence_npc 011", "Chainsaw_sequence_npc 012",
"Chainsaw_sequence_npc 013", "Chainsaw_sequence_npc 014", "Chainsaw_sequence_npc 015", "Chainsaw_sequence_npc 016" },
},
chainsaw_wave_03 = {
name = "Chainsaw_Wave3_Group",
members = { "Chainsaw_sequence_npc 017", "Chainsaw_sequence_npc 018", "Chainsaw_sequence_npc 019", "Chainsaw_sequence_npc 020",
"Chainsaw_sequence_npc 021", "Chainsaw_sequence_npc 022", "Chainsaw_sequence_npc 023", "Chainsaw_sequence_npc 024" },
},
chainsaw_wave_04 = {
name = "Chainsaw_Wave4_Group",
members = { "Chainsaw_sequence_npc 025", "Chainsaw_sequence_npc 026", "Chainsaw_sequence_npc 027", "Chainsaw_sequence_npc 028",
"Chainsaw_sequence_npc 029", "Chainsaw_sequence_npc 030", "Chainsaw_sequence_npc 031", "Chainsaw_sequence_npc 032" },
},
coop_cont_spawn_01 = {
name = "Coop_cont_spawn_01",
},
coop_cont_spawn_02 = {
name = "Coop_cont_spawn_02",
},
cte_luch_group = {
name = "m21_cte_luch_group_01",
},
M21_cte = {
name = "m21_cte_01",
}
}
-- Navpoints --
M21_navpoints = {
player_mission_start = { "Player_Mission_Start_Navpoint", "Coop_Mission_Start_Navpoint" },
player_defend_angel_start = { "nav_player_start_chk_02_ 001", "nav_player_start_chk_02_ 002" },
player_fight_start = { "Player_Fight_Start_Navpoint", "Coop_Fight_Start_Navpoint" },
player_fight_start_alt = { "Player_Fight_Start_Navpoint_Alt", "Coop_Fight_Start_Navpoint_Alt" },
player_mission_end = { "M21_Local_Player_Exit", "M21_Remote_Player_Exit" },
killbane_corner = "Killbane_Start_Navpoint",
angel_landing_position = "Angel_Landing_Position",
player_reacherd_angel = "nav_player_reached_angel 001",
lookat_angel = "nav_player_angel_lookat 001",
killswitch_ring_taunt = "nav_ring_center",
player_enter_ring = "Player_enter_ring_start",
player_enter_ring_dest = "Player_enter_ring_apron_dest",
player_over_ropes_dest = "Player_over_ropes_dest",
player_outside_ring = "Player_tag_in_navpoint",
player_outside_ring_dest = "Player_tag_in_navpoint_dest",
player_inside_ring_dest = "Player_tag_out_navpoint_dest",
player_inside_ring = "Player_tag_out_navpoint",
npc_outside_arena_tele_points = { "hallway_spawn_point 001", "hallway_spawn_point 002", "hallway_spawn_point 003", "hallway_spawn_point 004" },
killbane_pace_end = "Killbane_Pace_Navpoint 003",
killbane_pace_end_tele = "Killbane_Pace_Navpoint_Start",
killbane_beatup_trigger_points = { "beatup_trigger_navpoint 001", "beatup_trigger_navpoint 002", "beatup_trigger_navpoint 003",
"beatup_trigger_navpoint 004"},
killbane_enter_ring = { "Killbane_enter_ring_nav 001", "Killbane_enter_ring_nav 002", "Killbane_enter_ring_nav 003", "Killbane_enter_ring_nav 004" },
ref_points = { "Ref_Navpoint 001", "Ref_Navpoint 002", "Ref_Navpoint 003", "Ref_Navpoint 004" },
ref_standing_point = "Ref_standing_point 001",
--Points where npcs can harass the fight
npc_harass_points = { "Npc_Harass_Point 001", "Npc_Harass_Point 002", "Npc_Harass_Point 003", "Npc_Harass_Point 004" },
npc_harass_dest_points = { "Npc_Harass_Point_Dest 001", "Npc_Harass_Point_Dest 002", "Npc_Harass_Point_Dest 003", "Npc_Harass_Point_Dest 004" },
npc_harass_points_out_ring = { "Npc_Harass_Point_02 001", "Npc_Harass_Point_02 002", "Npc_Harass_Point_02 003", "Npc_Harass_Point_02 004" },
npc_harass_points_in_ring = { "Npc_Harass_Point_In_Ring 001", "Npc_Harass_Point_In_Ring 002", "Npc_Harass_Point_In_Ring 003", "Npc_Harass_Point_In_Ring 004" },
firework_navs = { "Tunnel_effect 001", "Tunnel_effect 002", "Tunnel_effect 003", "Tunnel_effect 004", "Tunnel_effect 005", "Tunnel_effect 006", "Tunnel_effect 007", "Tunnel_effect 008" },
camera_flash_navs = { "vfx_camera_flashes 001", "vfx_camera_flashes 002", "vfx_camera_flashes 003", "vfx_camera_flashes 004", "vfx_camera_flashes 005" },
}
-- Paths --
-- Triggers --
M21_triggers = {
beatup_killbane = { "beatup_killbane_trigger 001", "beatup_killbane_trigger 002", "beatup_killbane_trigger 003",
"beatup_killbane_trigger 004" },
player_enter_ring = "Player_Enter_Ring_Trigger 001",
player_reached_angel = "Player_Reached_Angel_Trigger 001",
tag_trigger_outside = "Player_tag_team_outside_trigger",
tag_trigger_inside = "Player_tag_team_inside_trigger",
ring_trigger = "Ring_Trigger",
}
-- Spawn Groups --
M21_spawn_groups = {
luch2_group1 = "m21_luch2_group 001",
luch2_group2 = "m21_luch2_group 002",
luch2_group3 = "m21_luch2_group 003",
luch2_group4 = "m21_luch2_group 004",
luch2_group5 = "m21_luch2_group 005",
luch2_group6 = "m21_luch2_group 006"
}
-- Characters --
M21_characters = {
angel = M21_groups.angel.angel,
killbane = M21_groups.killbane.killbane,
ref = M21_groups.ref.ref
}
-- Vehicles --
-- Mesh Movers --
-- Text --
-- Threads --
M21_threads = {
process_dialog = INVALID_THREAD_HANDLE,
Killbane_angel_fight_anim_handle = INVALID_THREAD_HANDLE,
Killbane_angel_damage_handle = INVALID_THREAD_HANDLE,
Ref_distractor_handles = { INVALID_THREAD_HANDLE, INVALID_THREAD_HANDLE, INVALID_THREAD_HANDLE, INVALID_THREAD_HANDLE },
Ref_handle = INVALID_THREAD_HANDLE,
Process_defend_the_ring_handle = INVALID_THREAD_HANDLE,
Harasser_processing_handle = INVALID_THREAD_HANDLE,
angel_stompers_handle = INVALID_THREAD_HANDLE,
Killbane_pacing_handle = INVALID_THREAD_HANDLE,
Killbane_mounted_processing = INVALID_THREAD_HANDLE,
Killbane_reinforcements_handles = { INVALID_THREAD_HANDLE, INVALID_THREAD_HANDLE, INVALID_THREAD_HANDLE, INVALID_THREAD_HANDLE },
enforce_character_locations = INVALID_THREAD_HANDLE,
}
-- Checkpoints --
M21_checkpoints = {
start = MISSION_START_CHECKPOINT, -- defined in ug_lib.lua
defend_angel = "m21_checkpoint_defend_angel",
fight_killbane = "m21_checkpoint_fight_killbane",
fight_killbane_remote = "m21_checkpoint_fight_killbane_02",
}
-- Cutscenes --
M21_cutscenes = {
mission_intro = "21_in",
angle_thrown_out = "21_Z01",
unmask_threat = "21_Z02",
remove_mask = "21_Z03",
release_killbane = "21_Z04",
mission_outro = "21_out",
}
-- Persona Handles --
M21_personas = {
bobby = {
name = "Bobby",
persona_id = INVALID_PERSONA_HANDLE,
},
zach = {
name = "Zach",
persona_id = INVALID_PERSONA_HANDLE,
},
}
-- Conversations --
M21_conversations = {
pickup_dildo = { name = "M21_Pick_Up_Dildo_Bat", load_direct = true },
angel_beat_down = { name = "M21_Defend_Angel", load_direct = true },
talk_to_angel = { name = "M21_Convo_4", load_direct = false },
player_killbane_fight = { name = "M21_Convo_5", load_direct = true },
player_killbane_banter = { name = "M21_Main_Event_Start", load_direct = false },
killbane_player_taunt = { name = "M21_Taunting_Player", load_direct = false },
killswitch_blocked_01 = { name = "M21_1st_Killswitch_Blocked", load_direct = true },
killswitch_blocked_02 = { name = "M21_2nd_Killswitch_Blocked", load_direct = true },
killswitch_blocked_03 = { name = "M21_3rd_Killswitch_Blocked", load_direct = true },
killbane_out_of_ring_01 = { name = "M21_1st_Killbane_Out_Of_Ring", load_direct = true },
killbane_out_of_ring_02 = { name = "M21_2nd_Killbane_Out_Of_Ring", load_direct = true },
}
M21_dialog_lines = {
angel_killbane_commentary = {
{ name = "M21_Mission_Start_01", persona = LOCAL_PLAYER, can_interrupt = false },
{ name = "M21_Mission_Start_02", persona = "Zach", can_interrupt = false },
--{ name = "M21_Mission_Start_03", persona = "Bobby", can_interrupt = false },
{ name = "M21_Mission_Start_04", persona = "Zach", can_interrupt = true },
{ name = "M21_Call_Out_Prop_05", persona = "Bobby", can_interrupt = true },
{ name = "M21_Mission_Start_05", persona = "Bobby", can_interrupt = true },
{ name = "M21_Taunting_Angel_01", persona = M21_characters.killbane, can_interrupt = false },
{ name = "M21_Taunting_Angel_02", persona = M21_characters.angel, can_interrupt = false },
{ name = "M21_Taunting_Angel_03", persona = M21_characters.killbane, can_interrupt = false },
{ name = "M21_Taunting_Angel_04", persona = M21_characters.angel, can_interrupt = false },
{ name = "M21_Match_Commentary_01_01", persona = "Zach", can_interrupt = true },
{ name = "M21_Match_Commentary_01_02", persona = "Bobby", can_interrupt = true },
{ name = "M21_Match_Commentary_01_03", persona = "Zach", can_interrupt = true },
{ name = "M21_Match_Commentary_01_04", persona = "Bobby", can_interrupt = true },
{ name = "M21_Match_Commentary_01_05", persona = "Zach", can_interrupt = true },
{ name = "M21_Match_Commentary_01_06", persona = "Bobby", can_interrupt = true },
{ name = "M21_Match_Commentary_01_07", persona = "Zach", can_interrupt = true },
{ name = "M21_Match_Commentary_01_08", persona = "Bobby", can_interrupt = true },
{ name = "M21_Match_Commentary_01_09", persona = "Zach", can_interrupt = true },
{ name = "M21_Match_Commentary_01_10", persona = "Bobby", can_interrupt = true },
{ name = "M21_Match_Commentary_01_11", persona = "Zach", can_interrupt = true },
{ name = "M21_Match_Commentary_01_12", persona = "Bobby", can_interrupt = true },
{ name = "M21_Match_Commentary_01_13", persona = "Zach", can_interrupt = true },
{ name = "M21_Match_Commentary_01_14", persona = "Bobby", can_interrupt = true },
{ name = "M21_Match_Commentary_01_15", persona = "Zach", can_interrupt = true },
{ name = "M21_Match_Commentary_01_16", persona = "Bobby", can_interrupt = true },
{ name = "M21_Match_Commentary_01_17", persona = "Zach", can_interrupt = true },
},
ref_distracted = {
{ name = "M21_Ref_Distracted_01", persona = "Bobby", can_interrupt = false },
--{ name = "M21_Ref_Distracted_02", persona = "Zach", can_interrupt = false },
{ name = "M21_Ref_Distracted_03", persona = "Bobby", can_interrupt = false },
{ name = "M21_Ref_Distracted_04", persona = "Zach", can_interrupt = false },
{ name = "M21_Ref_Distracted_06", persona = "Zach", can_interrupt = false },
},
chainsaw_commentary = {
{ name = "M21_Defend_Angel_01", persona = "Zach", can_interrupt = false },
{ name = "M21_Defend_Angel_02", persona = "Bobby", can_interrupt = false },
{ name = "M21_Defend_Angel_03", persona = "Zach", can_interrupt = false },
{ name = "M21_Defend_Angel_04", persona = "Bobby", can_interrupt = false },
},
chainsaw_kills = {
{ name = "M21_Chainsaw_01", persona = "Zach", can_interrupt = false },
--{ name = "M21_Chainsaw_02", persona = "Bobby", can_interrupt = false },
--{ name = "M21_Chainsaw_03", persona = "Zach", can_interrupt = false },
{ name = "M21_Chainsaw_04", persona = "Bobby", can_interrupt = false },
{ name = "M21_Chainsaw_05", persona = "Zach", can_interrupt = false },
{ name = "M21_Chainsaw_06", persona = "Bobby", can_interrupt = false },
},
exclamation = {
{ name = "M21_Chainsaw_02", persona = "Bobby", can_interrupt = false },
{ name = "M21_Chainsaw_03", persona = "Zach", can_interrupt = false },
{ name = "M21_Killswitch_Coming_04", persona = "Bobby", can_interrupt = false },
{ name = "M21_Break_Out_Of_Commentary_03", persona = "Zach", can_interrupt = false },
{ name = "M21_Ref_Distracted_05", persona = "Bobby", can_interrupt = false },
},
player_killbane_start = {
{ name = "M21_Fight_Killbane_01", persona = "Zach", can_interrupt = true },
{ name = "M21_Fight_Killbane_02", persona = "Bobby", can_interrupt = true },
},
player_killbane_commentary = {
{ name = "M21_Main_Event_Fight_01", persona = "Zach", can_interrupt = true },
{ name = "M21_Main_Event_Fight_02", persona = "Bobby", can_interrupt = true },
{ name = "M21_Main_Event_Fight_03", persona = "Zach", can_interrupt = true },
{ name = "M21_Main_Event_Fight_04", persona = "Bobby", can_interrupt = true },
{ name = "M21_Main_Event_Fight_05", persona = "Zach", can_interrupt = true },
{ name = "M21_Main_Event_Fight_06", persona = "Bobby", can_interrupt = true },
},
killswitch_tell = {
{ name = "M21_Killswitch_Coming_01", persona = "Bobby", can_interrupt = false },
{ name = "M21_Killswitch_Coming_02", persona = "Bobby", can_interrupt = false },
{ name = "M21_Killswitch_Coming_03", persona = "Bobby", can_interrupt = false },
{ name = "M21_Killswitch_Coming_04", persona = "Bobby", can_interrupt = false },
{ name = "M21_Killswitch_Coming_05", persona = "Bobby", can_interrupt = false },
{ name = "M21_Killswitch_Coming_06", persona = "Bobby", can_interrupt = false },
},
qte_failed = {
{ name = "M21_Failed_QTE_01", persona = "Bobby", can_interrupt = false },
{ name = "M21_Failed_QTE_02", persona = "Bobby", can_interrupt = false },
{ name = "M21_Failed_QTE_03", persona = "Bobby", can_interrupt = false },
{ name = "M21_Failed_QTE_04", persona = "Bobby", can_interrupt = false },
{ name = "M21_Failed_QTE_05", persona = "Bobby", can_interrupt = false },
{ name = "M21_Failed_QTE_06", persona = "Bobby", can_interrupt = false },
{ name = "M21_Failed_QTE_07", persona = "Bobby", can_interrupt = false },
{ name = "M21_Failed_QTE_08", persona = "Bobby", can_interrupt = false },
{ name = "M21_Failed_QTE_09", persona = "Bobby", can_interrupt = false },
{ name = "M21_Failed_QTE_10", persona = "Bobby", can_interrupt = false },
},
killbane_out_of_ring_01 = {
{ name = "M21_First_Killbane_Out_Of_Ring_01", persona = "Zach", can_interrupt = false },
},
killbane_back_in_ring_01 = {
{ name = "M21_First_Killbane_Out_Of_Ring_02", persona = "Bobby", can_interrupt = false },
{ name = "M21_First_Killbane_Out_Of_Ring_03", persona = "Zach", can_interrupt = false },
{ name = "M21_First_Killbane_Out_Of_Ring_04", persona = "Bobby", can_interrupt = false },
},
killbane_posturing = {
{ name = "M21_Killbane_Plays_To_Crowd_01", persona = "Zach", can_interrupt = false },
{ name = "M21_Killbane_Plays_To_Crowd_02", persona = "Zach", can_interrupt = false },
{ name = "M21_Killbane_Plays_To_Crowd_03", persona = "Zach", can_interrupt = false },
{ name = "M21_Killbane_Plays_To_Crowd_04", persona = "Zach", can_interrupt = false },
{ name = "M21_Killbane_Plays_To_Crowd_05", persona = "Zach", can_interrupt = false },
{ name = "M21_Killbane_Plays_To_Crowd_06", persona = "Zach", can_interrupt = false },
},
commentater_break_out = {
{ name = "M21_Break_Out_Of_Commentary_01", persona = "Zach", can_interrupt = false },
{ name = "M21_Break_Out_Of_Commentary_02", persona = "Bobby", can_interrupt = false },
{ name = "M21_Break_Out_Of_Commentary_03", persona = "Zach", can_interrupt = false },
{ name = "M21_Break_Out_Of_Commentary_04", persona = "Bobby", can_interrupt = false },
{ name = "M21_Break_Out_Of_Commentary_05", persona = "Zach", can_interrupt = false },
{ name = "M21_Break_Out_Of_Commentary_06", persona = "Bobby", can_interrupt = false },
{ name = "M21_Break_Out_Of_Commentary_07", persona = "Zach", can_interrupt = false },
{ name = "M21_Break_Out_Of_Commentary_08", persona = "Bobby", can_interrupt = false },
{ name = "M21_Break_Out_Of_Commentary_09", persona = "Zach", can_interrupt = false },
{ name = "M21_Break_Out_Of_Commentary_10", persona = "Bobby", can_interrupt = false },
},
commentater_break_in = {
{ name = "M21_Break_Into_Commentary_01", persona = "Bobby", can_interrupt = false },
{ name = "M21_Break_Into_Commentary_02", persona = "Bobby", can_interrupt = false },
{ name = "M21_Break_Into_Commentary_03", persona = "Zach", can_interrupt = false },
{ name = "M21_Break_Into_Commentary_04", persona = "Zach", can_interrupt = false },
},
prop_call_out = {
{ name = "M21_Call_Out_Prop_01", persona = "Bobby", can_interrupt = false },
{ name = "M21_Call_Out_Prop_02", persona = "Zach", can_interrupt = false },
{ name = "M21_Call_Out_Prop_03", persona = "Bobby", can_interrupt = false },
{ name = "M21_Call_Out_Prop_04", persona = "Zach", can_interrupt = false },
{ name = "M21_Call_Out_Prop_06", persona = "Zach", can_interrupt = false },
},
prop_in_ring = {
{ name = "M21_Call_Out_Prop_In_Ring_01", persona = "Bobby", can_interrupt = false },
{ name = "M21_Call_Out_Prop_In_Ring_02", persona = "Zach", can_interrupt = false },
{ name = "M21_Call_Out_Prop_In_Ring_03", persona = "Bobby", can_interrupt = false },
{ name = "M21_Call_Out_Prop_In_Ring_04", persona = "Zach", can_interrupt = false },
{ name = "M21_Call_Out_Prop_In_Ring_05", persona = "Bobby", can_interrupt = false },
{ name = "M21_Call_Out_Prop_In_Ring_06", persona = "Zach", can_interrupt = false },
},
}
M21_audio_events = {
crowd_against = "M21_crowd_bed_against",
crowd_with = "M21_crowd_bed_with",
music_your_the_best = "M21_mus_youre_the_best",
music_your_the_best_stop = "M21_mus_youre_the_best_STOP",
-- Chants
angel_long = "M21_chant_angel_long",
angel_short = "M21_chant_angel_three",
killbane_long = "M21_chant_killbane_long",
killbane_short = "M21_chant_killbane_three",
dildo = "M21_chant_dildo_long",
we_want_blood = "M21_chant_we_want_blood",
murderbrawl = "M21_chant_murderbrawl",
-- Cheers
crowd_cheer_low = "m21_crowd_cheer_low",
crowd_cheer_mid = "m21_crowd_cheer_mid",
crowd_cheer_high = "m21_crowd_cheer_high",
boo_killbane = "m21_crowd_boo_killbane",
boo_short = "m21_crowd_boo_short",
crowd_count_cheer = "m21_crowd_count_cheer",
crowd_disappoint = "m21_crowd_disappoint",
crowd_chainsaw = "m21_crowd_get_chainsaw",
-- Crowd count
crowd_count = {
"m21_crowd_count_01",
"m21_crowd_count_02",
"m21_crowd_count_03",
"m21_crowd_count_04",
"m21_crowd_count_05",
"m21_crowd_count_06",
"m21_crowd_count_07",
"m21_crowd_count_08",
"m21_crowd_count_09",
"m21_crowd_count_10",
},
-- Riding Killbane
ride_killbane_start = "m21_crowd_killbane_ride",
ride_killbane_stop = "m21_crowd_killbane_ride_STOP",
-- Misc
crowd_shocked = "m21_crowd_ohh_shocked",
-- Zscenes
z01 = "m21_Z01_crowds",
z02 = "m21_Z02_crowds",
z03 = "m21_Z03_crowds",
z04 = "m21_Z04_crowds",
}
M22_audio_emitters = {
room_tone = "M21_amb_int_murderbrawl_arena",
}
-- Animations --
M21_animations = {
luchadore_jump_on_ring = "Lucha Enter Apron",
luchadore_jump_over_ropes = "Lucha Enter Ring",
luchadore_enter_ring = "Enter Ring From Floor",
player_jump_on_ring = "Lucha Enter Apron",
player_jump_over_ropes = "Lucha Enter Ring",
player_tag_in = "m21_plym_tagTeam_swapA",
player_tag_out = "m21_plym_tagTeam_swapB",
killbane_angel_grapple = "Wrestling Grapple",
killbane_angel_fight = { "Wrestling Seq 1", "Wrestling Seq 2", "Wrestling Seq 3", "Wrestling Seq 4", "Wrestling Seq 5" },
killbane_angel_cheats = {
{
intro = "Wrestling to Cheat 1",
state = "Cheat 1",
outro = "Cheat to Wrestling 1",
},
{
intro = "Wrestling to Cheat 2",
state = "Cheat 2",
outro = "Cheat to Wrestling 2"
},
},
killbane_flinches = { "base flinch chest front a", "base flinch chest front b" },
killbane_pacing = "KillBane Pacing",
killbane_enter_ring = "Enter Ring",
--KILLBANE_WRESTLE = "killbane_wrestle"
--ANGEL_WRESTLE = "angel_wrestle"
}
-- Animation States --
M21_animation_state = {
luchadore_ring_stand = "Lucha Apron distract",
ref_watch = "Ref Watch",
ref_distracted = "Ref Distracted",
}
-- Other --
dialog_queue = {
playing = {
thread_id = INVALID_THREAD_HANDLE,
dialog_handle = INVALID_CONVERSATION_HANDLE,
dialog_table = nil,
},
list = {},
size = 0,
}
active_conversation = {
dialog_table = nil,
}
M21_hud_states = {
hide_hud = -1,
}
M21_spawn_regions = {
"spawn_region_coop 001",
"spawn_region_coop 002",
"spawn_region_coop 003",
"spawn_region_coop 004",
}
M21_defend_angel_waves = { M21_groups.wave1, M21_groups.wave2, M21_groups.wave3, M21_groups.wave4 }
M21_angel_stomper_locations = {
{ nav = "nav_angel_stomper_pos 001", anim = "M21 angel beat down b", occupant = "", thread_id = INVALID_THREAD_HANDLE },
{ nav = "nav_angel_stomper_pos 002", anim = "M21 angel beat down c", occupant = "", thread_id = INVALID_THREAD_HANDLE },
{ nav = "nav_angel_stomper_pos 003", anim = "M21 angel beat down d", occupant = "", thread_id = INVALID_THREAD_HANDLE },
{ nav = "nav_angel_stomper_pos 004", anim = "M21 angel beat down e", occupant = "", thread_id = INVALID_THREAD_HANDLE },
}
M21_pontential_stomper_list = { }
PHASE_DEFEND_RING = 1
PHASE_FIGHT_KILLBANE = 2
player_win = false
player_unmasked_killbane = false
ENABLE = true
DISABLE = false
in_coop = false
enabled_trigger_index = 0
local_melee_weapon = "none"
remote_melee_weapon = "none"
-- Angel harasser variables (m21 part 1)
NUM_TOTAL_ANGEL_HARASSERS = 8
player_completed_phase_one = false
num_distractors_on_ring = 0
distractors_on_ring = { "", "", "", "" }
ref_target = ""
ref_location_idx = 0
-- Defend Angel variables (m21 part 2)
Chainsaw_luchadors_alive = 0
Player_entered_ring = false
player_reached_angel = false
-- Fight harasser variables (m21 part 3)
num_times_killbane_hit_by_weapon = 0
killbane_wave = 1
killbane_thug_enemies_to_kill = 0
killbane_thug_enemies_living = 0
Killbane_should_be_in_ring = true
player_in_ring = LOCAL_PLAYER
player_outside_ring = REMOTE_PLAYER
player_ready_to_tag_in = false
M21_prop_called_out = false
fight_club_phase = false
M21_killbane_ride_success = false
M21_corner_qte_cb_count = 1
Play_choice_selection = -1
-- HUD indices
GSI_OBJECTIVE_INDEX = 0
GSI_ANGEL_HEALTH_INDEX = 1
-- Conversation enums
M21_CONVO_PLAY_LAST = 0
M21_CONVO_PLAY_NEXT = 1
M21_CONVO_PLAY_IMMEDIATE = 2
-- *************************
--
-- 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
--
-- m21_checkpoint: The checkpoint the mission should begin at
-- is_restart: TRUE if the mission is restarting, FALSE otherwise
--
function m21_start(m21_checkpoint, is_restart)
in_coop = coop_is_active()
mission_start_fade_out()
city_zone_swap("m21", true)
-- Handle mission initialization for the current checkpoint
m21_initialize(m21_checkpoint)
-- Check if this mission starting from the beginning
if (m21_checkpoint == M21_checkpoints.start) then
if (is_restart == false) then
-- First time playing mission
-- Play an intro cutscene???
if (M21_cutscenes.mission_intro ~= "") then
cutscene_play(M21_cutscenes.mission_intro, nil, M21_navpoints.player_mission_start, false)
--bink_play(M21_cutscenes.mission_intro)
end
end
end
mission_start_fade_in()
-- Run the mission from the current checkpoint
m21_run(m21_checkpoint)
end
-- This is the primary function responsible for cleaning up the entire mission
-- CALLED FROM CODE (+++MUST RETURN IMMEDIATLY+++)
--
function m21_cleanup()
city_zone_swap("m21", false)
player_can_sprint(true) -- allow sprinting once again
party_use_melee_weapons_only(false)
m21_cleanup_defend_the_ring()
m21_cleanup_defend_angel()
m21_cleanup_goto_angel()
m21_cleanup_enter_the_ring()
-- end any conversations
m21_cleanup_conversations()
persona_suppress_ambient_lines(DISABLE)
-- Cleanup callbacks
on_mount("", M21_characters.killbane)
on_dismount("", M21_characters.killbane)
on_take_damage("", M21_characters.killbane)
on_revived("", M21_characters.killbane)
on_death("", M21_characters.angel)
on_qte_animation_trigger("")
on_take_damage("", LOCAL_PLAYER)
on_weapon_pickup("", LOCAL_PLAYER)
if (coop_is_active() == true) then
on_take_damage("", REMOTE_PLAYER)
on_weapon_pickup("", REMOTE_PLAYER)
end
for i, enemy in pairs(M21_groups.fight_club_phase_reinforcements.members) do
-- Assign enemy callbacks, add markers
if (character_exists(enemy)) then
on_death("", enemy)
end
end
-- cleanup groups
m21_cleanup_groups(M21_groups)
hud_bar_off(GSI_ANGEL_HEALTH_INDEX)
objective_text_clear(GSI_OBJECTIVE_INDEX)
m21_helper_hide_hud(false)
-- Kill all alive threads
m21_cleanup_threads(M21_threads)
-- clean up triggers
m21_cleanup_triggers(M21_triggers)
qte_cleanup()
boss_battle_kb_enable(DISABLE)
boss_battle_kb_enable_crowd_props(DISABLE)
-- Stop all the audio emitters
for i, emitter in pairs(M22_audio_emitters) do
audio_ambient_emitter_stop(emitter)
end
--customization_item_revert()
customization_item_revert()
-- Restore the HUD
for i, hud_state in pairs(M21_hud_states) do
if (hud_state ~= -1) then
hud_display_remove_state(hud_state)
hud_state = -1
end
end
-- Remove always combat ready flag for Luchadores
set_force_combat_ready_team("")
--Clean-up stuff for the players
character_set_always_combat_ready(LOCAL_PLAYER, false)
hud_prompt_clear(LOCAL_PLAYER)
human_riding_trigger_end(LOCAL_PLAYER)
player_movement_enable(LOCAL_PLAYER)
player_actions_enable(LOCAL_PLAYER)
inv_item_remove_in_slot("single_use", LOCAL_PLAYER)
-- Add back any permenant melee weapons
if local_melee_weapon ~= "none" then
inv_item_add(local_melee_weapon, 1, LOCAL_PLAYER)
end
inv_weapon_remove_temporary(LOCAL_PLAYER, "chainsaw") -- Remove temp chainsaw
set_players_can_be_downed(LOCAL_PLAYER, ENABLE)
clear_animation_state(LOCAL_PLAYER)
character_disable_human_downed_interactions(LOCAL_PLAYER, false)
if (coop_is_active() == true) then
character_set_always_combat_ready(REMOTE_PLAYER, false)
hud_prompt_clear(REMOTE_PLAYER)
human_riding_trigger_end(REMOTE_PLAYER)
player_movement_enable(REMOTE_PLAYER)
player_actions_enable(REMOTE_PLAYER)
inv_item_remove_in_slot("single_use", REMOTE_PLAYER)
-- Add back any permenant melee weapons
if remote_melee_weapon ~= "none" then
inv_item_add(remote_melee_weapon, 1, REMOTE_PLAYER)
end
inv_weapon_remove_temporary(REMOTE_PLAYER, "chainsaw")
set_players_can_be_downed(REMOTE_PLAYER, ENABLE)
clear_animation_state(REMOTE_PLAYER)
character_disable_human_downed_interactions(REMOTE_PLAYER, false)
end
-- Clean-up any continuous spawning
continuous_spawn_stop(M21_groups.coop_cont_spawn_01.name, true)
continuous_spawn_stop(M21_groups.coop_cont_spawn_02.name, true)
npc_drop_grenades(true)
-- Turn peds, vehicles, and action nodes back on
spawning_pedestrians(true)
spawning_vehicles(true)
action_nodes_enable(true)
-- Remove the callback for the player choice sequence
on_m21_player_choice("")
end
-- Called when the mission has ended with success
-- CALLED FROM CODE (+++MUST RETURN IMMEDIATLY+++)
--
function m21_success()
--[[ INSERT ANY MISSION SPECIFIC SUCCESS STUFF ]]--
if (player_unmasked_killbane == true) then
game_choice_set_state( MISSION_21_CHOICE, M21_CHOICE_KILLBANE_UNMASKED )
else
game_choice_set_state( MISSION_21_CHOICE, M21_CHOICE_KILLBANE_NOT_UNMASKED )
end
end
-- *************************
--
-- Local functions
--
-- *************************
-- Initialize the mission for the specified checkpoint
--
-- checkpoint: Checkpoint to initialize the mission to
--
function m21_initialize(checkpoint)
-- Set the mission author
set_mission_author("John Karczewski")
-- Common initialization
m21_initialize_common()
-- Checkpoint specific initialization
m21_initialize_checkpoint(checkpoint)
end
-- Handle any common initialization
--
function m21_initialize_common()
-- Turn on the audio emitter to adjust the room tone
audio_ambient_emitter_start(M22_audio_emitters.room_tone)
-- Dismiss the players' party
party_dismiss_all()
-- Put the players' wrestling costumes on
if (character_get_gender(LOCAL_PLAYER) == GENDER_TYPE_MALE) then
customization_outfit_wear("Murderbrawl Wrestling Male", 0, SYNC_LOCAL)
else
customization_outfit_wear("Murderbrawl Wrestling Female", 0, SYNC_LOCAL)
end
if (coop_is_active() == true) then
if (character_get_gender(REMOTE_PLAYER) == GENDER_TYPE_MALE) then
customization_outfit_wear("Murderbrawl Wrestling Male", 0, SYNC_REMOTE)
else
customization_outfit_wear("Murderbrawl Wrestling Female", 0, SYNC_REMOTE)
end
end
-- Initialize the dialog lines
for i, convo in pairs(M21_conversations) do
convo.is_convo = true
convo.queued = false
convo.started = false
convo.completed = false
convo.ended = false
end
for i, line_group in pairs(M21_dialog_lines) do
for j, line in pairs(line_group) do
line.is_convo = false
line.queued = false
line.started = false
line.completed = false
line.ended = false
end
end
-- Spawn Killbane
group_create(M21_groups.killbane.name, true)
set_behavior_set(M21_characters.killbane, "Killbane")
set_ignore_ai_flag(M21_characters.killbane, true)
character_allow_ragdoll(M21_characters.killbane, false) -- Killbane should never ragdoll
-- Spawn Angel
group_create(M21_groups.angel.name, true)
set_ignore_ai_flag(M21_characters.angel, true)
inv_item_remove_all(M21_characters.angel) -- Make sure Angel has nothing
character_prevent_flinching(M21_characters.angel, true)
character_prevent_bumping(M21_characters.angel, true)
character_allow_ragdoll(M21_characters.angel, false)
set_max_hit_points(M21_characters.angel, get_max_hit_points(M21_characters.angel) * ANGEL_HEALTH_MULTIPLIER, true)
set_dont_attack_me_on_sight_flag(M21_characters.angel, true)
-- Create the crowd props group
group_create(M21_groups.crowd_props.name, true)
-- Do not allow the player to use any weapons but melee
party_use_melee_weapons_only(true)
local_melee_weapon = inv_item_in_slot(LOCAL_PLAYER, "melee") -- if the player has a melee weapon, remove it for the mission
if local_melee_weapon ~= nil then
inv_item_remove(local_melee_weapon, LOCAL_PLAYER)
end
inv_item_equip_slot("unarmed", LOCAL_PLAYER)
if in_coop then
remote_melee_weapon = inv_item_in_slot(REMOTE_PLAYER, "melee")
if remote_melee_weapon ~= nil then
inv_item_remove(remote_melee_weapon, REMOTE_PLAYER)
end
inv_item_equip_slot("unarmed", REMOTE_PLAYER)
end
boss_battle_kb_enable(ENABLE) -- Initializes everything, and forces the murderbrawl camera mode
-- Load the 2d personas
M21_personas.bobby.persona_id = audio_persona_load_2d(M21_personas.bobby.name)
M21_personas.zach.persona_id = audio_persona_load_2d(M21_personas.zach.name)
persona_suppress_ambient_lines(ENABLE)
-- Set the cancel mission warp locations
mission_set_cancel_warp_location(M21_navpoints.player_mission_end[1], M21_navpoints.player_mission_end[2])
-- Start the conversation thread
M21_threads.process_dialog = thread_new("m21_thread_process_dialog")
-- Set the Luchadores always combat ready
set_force_combat_ready_team("Luchadores")
-- Set the player's always combat
character_set_always_combat_ready(LOCAL_PLAYER, true)
if (coop_is_active() == true) then
character_set_always_combat_ready(REMOTE_PLAYER, true)
end
-- Turn peds, vehicles, and action nodes back on
spawning_pedestrians(false)
spawning_vehicles(false)
action_nodes_enable(false)
-- NPCs shouldn't drop grenades
npc_drop_grenades(false)
end
-- Checkpoint specific initialization
--
-- checkpoint: The checkpoint to be initialized
function m21_initialize_checkpoint(checkpoint)
if (checkpoint == M21_checkpoints.start) then
m21_initialize_defend_the_ring()
end
if checkpoint == M21_checkpoints.defend_angel then
group_create(M21_groups.angel_stompers.name, true)
group_create(M21_groups.chainsaw_wave_01.name, true)
-- Set up the players at their positions
teleport_coop(M21_navpoints.player_defend_angel_start[1], M21_navpoints.player_defend_angel_start[1], true)
turn_to("#PLAYER1#", M21_navpoints.player_defend_angel_start[1], true)
if (in_coop) then
turn_to("#PLAYER2#", M21_navpoints.player_defend_angel_start[2], true)
end
m21_setup_defend_angel(false)
end
if checkpoint == M21_checkpoints.fight_killbane then
player_in_ring = LOCAL_PLAYER
player_outside_ring = REMOTE_PLAYER
-- Set up the players at their positions
teleport_coop(M21_navpoints.player_fight_start[1], M21_navpoints.player_fight_start[2], true)
turn_to(LOCAL_PLAYER, M21_navpoints.player_fight_start[1], true)
if (in_coop) then
turn_to(REMOTE_PLAYER, M21_navpoints.player_fight_start[2], true)
end
-- Teleport Angel and Killane to their correct locations
teleport(M21_characters.angel, M21_navpoints.angel_landing_position)
teleport(M21_characters.killbane, M21_navpoints.killbane_corner)
thread_yield()
-- The crowd is now with the player, so switch the audio
audio_object_post_event(M21_audio_events.crowd_with, nil, nil, LOCAL_PLAYER)
m21_setup_fight_killbane()
end
if checkpoint == M21_checkpoints.fight_killbane_remote then
player_in_ring = REMOTE_PLAYER
player_outside_ring = LOCAL_PLAYER
-- Set up the players at their positions
teleport_coop(M21_navpoints.player_fight_start[2], M21_navpoints.player_fight_start[1], true)
turn_to(LOCAL_PLAYER, M21_navpoints.player_fight_start[2], true)
if (in_coop) then
turn_to(REMOTE_PLAYER, M21_navpoints.player_fight_start[1], true)
end
-- Teleport Angel and Killane to their correct locations
teleport(M21_characters.angel, M21_navpoints.angel_landing_position)
teleport(M21_characters.killbane, M21_navpoints.killbane_corner)
thread_yield()
-- The crowd is now with the player, so switch the audio
audio_object_post_event(M21_audio_events.crowd_with, nil, nil, LOCAL_PLAYER)
m21_setup_fight_killbane()
end
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 m21_run(first_checkpoint)
local current_checkpoint = first_checkpoint
-- Run the mission from the beginning
if (current_checkpoint == M21_checkpoints.start) then
m21_run_defend_the_ring()
m21_run_angel_throw_out()
current_checkpoint = M21_checkpoints.defend_angel
mission_set_checkpoint(current_checkpoint, true) -- ignore vehicles
end
if (current_checkpoint == M21_checkpoints.defend_angel) then
m21_run_defend_angel()
m21_run_goto_angel()
m21_run_enter_the_ring()
m21_setup_fight_killbane()
if (player_in_ring == LOCAL_PLAYER) then
current_checkpoint = M21_checkpoints.fight_killbane
else
current_checkpoint = M21_checkpoints.fight_killbane_remote
end
mission_set_checkpoint(current_checkpoint, true) -- ignore vehicles
end
if (current_checkpoint == M21_checkpoints.fight_killbane or current_checkpoint == M21_checkpoints.fight_killbane_remote) then
m21_fight_killbane()
m21_killbane_unmask_threat()
m21_player_choice_sequence()
-- Set the play choice game-size. We need to do this here in addition to m21_success(), since the
-- final cinematic needs to know the choice and that gets called before m21_success()
if (player_unmasked_killbane == true) then
game_choice_set_state( MISSION_21_CHOICE, M21_CHOICE_KILLBANE_UNMASKED )
else
game_choice_set_state( MISSION_21_CHOICE, M21_CHOICE_KILLBANE_NOT_UNMASKED )
end
-- Play the Z-scene depending on the player's choice
if(player_unmasked_killbane) then
mission_set_excluded_reward("M21_Weapon_Killbanes_Gloves")
m21_player_unmasked_killbane()
else
mission_set_excluded_reward("M21_Clothing_Killbanes_Mask")
m21_player_didnt_unmask_killbane()
end
end
mission_end_success("m21", M21_cutscenes.mission_outro, M21_navpoints.player_mission_end)
end
function m21_initialize_defend_the_ring()
-- Load the Ref and set his animation state
group_create(M21_groups.ref.name, true)
set_script_animation_state(M21_characters.ref, M21_animation_state.ref_watch)
npc_combat_enable(M21_characters.ref, false)
-- Load the first set of enemies
if (coop_is_active() == false) then
group_create_hidden(M21_groups.wave1.name, true)
else
group_create_hidden(M21_groups.wave3.name, true)
end
-- Set up the players at their positions
teleport_coop(M21_navpoints.player_mission_start[1], M21_navpoints.player_mission_start[2], true)
-- Setup Angel
marker_add(M21_characters.angel, MINIMAP_ICON_PROTECT_ACQUIRE, OI_ASSET_DEFEND, OI_FLAGS_FULL)
on_death("m21_angel_died_1", M21_characters.angel)
-- Start up a thread for processing the Killbane/Angel fight
M21_threads.Killbane_angel_fight_anim_handle = thread_new("m21_manage_killbane_angel_fight_thread")
-- Start up the threads for processing the Ref AI
M21_threads.Process_defend_the_ring_handle = thread_new("m21_process_ref_ai_thread")
end
-- Main function for the defense of the ring portion of the mission
--
function m21_run_defend_the_ring()
objective_text( GSI_OBJECTIVE_INDEX, "m21_obj_defend_the_ring", "", "", SYNC_ALL, OI_ASSET_DEFEND )
hud_bar_on(GSI_ANGEL_HEALTH_INDEX, "health", "", get_max_hit_points(M21_characters.angel), SYNC_ALL)
hud_bar_set_value(GSI_ANGEL_HEALTH_INDEX, get_current_hit_points(M21_characters.angel))
-- Start the crowd up
audio_object_post_event(M21_audio_events.crowd_against, nil, nil, LOCAL_PLAYER)
-- Start a Murderbrawl chant
audio_object_post_event(M21_audio_events.murderbrawl, nil, nil, LOCAL_PLAYER)
-- Register callbacks so that we know when one of the players' wieldable props is destroyed
on_wieldable_prop_destroy("m21_player_prop_destroyed_cb", LOCAL_PLAYER)
if (coop_is_active() == true) then
on_wieldable_prop_destroy("m21_player_prop_destroyed_cb", REMOTE_PLAYER)
end
-- Queue up some dialog
for i, line in pairs(M21_dialog_lines.angel_killbane_commentary) do
m21_helper_dialog_play(line, M21_CONVO_PLAY_LAST, 0.0)
end
-- Register a callback so we know when the player picks up a prop
on_weapon_pickup("m21_player_picked_up_weapon_cb", LOCAL_PLAYER)
if (coop_is_active() == true) then
on_weapon_pickup("m21_player_picked_up_weapon_cb", REMOTE_PLAYER)
end
-- Start prepping the Z-scene we're going to play after this objective
zscene_prep(M21_cutscenes.angle_thrown_out)
delay(5.0) -- Wait for the dialog to catch up
-- Start a thread to process Angel's Health
M21_threads.Killbane_angel_damage_handle = thread_new("m21_manage_killbane_angel_damage_thread", ANGEL_DAMAGE_FROM_KILLBANE_PER_SEC)
-- Start the props
boss_battle_kb_enable_crowd_props(ENABLE, PHASE_DEFEND_RING)
-- Process the enemey Luchador waves
if (coop_is_active() == false) then
-- Start loading the next wave of enemies
group_create_hidden(M21_groups.wave2.name)
-- Process the first wave (were already created)
m21_helper_process_phase1_wave(M21_groups.wave1)
delay(TIME_BETWEEN_WAVES)
-- Make sure the second wave is ready to go
while(group_is_loaded(M21_groups.wave2.name) == false) do
thread_yield()
end
-- Process the second wave
m21_helper_process_phase1_wave(M21_groups.wave2)
else
-- Start loading the next wave of enemies
group_create_hidden(M21_groups.wave4.name)
-- Process the first wave (were already created)
m21_helper_process_phase1_wave(M21_groups.wave3)
delay(TIME_BETWEEN_WAVES)
-- Make sure the second wave is ready to go
while(group_is_loaded(M21_groups.wave4.name) == false) do
thread_yield()
end
-- Process the second wave
m21_helper_process_phase1_wave(M21_groups.wave4)
end
-- Wait for the current dialog line to finish (up to a max of 12 seconds)
local elapsed_time = 0.0
while(thread_check_done(dialog_queue.playing.thread_id) == false) do
thread_yield()
elapsed_time = elapsed_time + get_frame_time()
if (elapsed_time > 12.0) then
break
end
end
end
-- Clean up the sequence where you defend the ring from guys trying to run and jump in it
--
function m21_cleanup_defend_the_ring()
thread_kill(M21_threads.Process_defend_the_ring_handle)
M21_threads.Process_defend_the_ring_handle = INVALID_THREAD_HANDLE
thread_kill(M21_threads.Killbane_angel_fight_anim_handle)
M21_threads.KILLBANE_ANDLE_FIGHT_ANIM_HANDLE = INVALID_THREAD_HANDLE
thread_kill(M21_threads.Killbane_angel_damage_handle)
M21_threads.Killbane_angel_damage_handle = INVALID_THREAD_HANDLE
action_stop_synced_state(M21_characters.angel)
action_stop_synced_state(M21_characters.killbane)
group_destroy(M21_groups.ref.name)
boss_battle_kb_enable_crowd_props(DISABLE)
-- Remove the weapon pickup callback on the player's
on_weapon_pickup("", LOCAL_PLAYER)
if (coop_is_active() == true) then
on_weapon_pickup("", REMOTE_PLAYER)
end
-- Remove callbacks for when the players' wieldable prop is destroyed
on_wieldable_prop_destroy("", LOCAL_PLAYER)
if (coop_is_active() == true) then
on_wieldable_prop_destroy("", REMOTE_PLAYER)
end
-- Clean-up the waves of enemies
for i, group in pairs(M21_defend_angel_waves) do
if (group_is_loaded(group.name) == true) then
for j, member in pairs(group.members) do
on_take_damage("", member)
end
release_to_world(group.name)
group_destroy(group.name)
end
end
end
-- Callback for when one of the players' wieldable props is destroyed
function m21_player_picked_up_weapon_cb()
-- Play a crowd boo
audio_object_post_event(M21_audio_events.boo_short, nil, nil, LOCAL_PLAYER)
end
-- Handles setting up and processing of one wave during phase 1
--
-- group_table (string) name of the group for the current wavef
function m21_helper_process_phase1_wave(group_table)
group_show(group_table.name)
-- Setup the distractors
for i, npc in pairs(group_table.distractors) do
set_suppress_synced_attacks_flag(npc)
M21_threads.Ref_distractor_handles[i] = thread_new("m21_manage_distractor_thread", npc, i)
end
-- Setup the harassers
for i, npc in pairs(group_table.harassers) do
set_suppress_synced_attacks_flag(npc)
ai_add_enemy_target(npc, CLOSEST_PLAYER, ATTACK_NOW_NEVER_LOSE)
end
-- Start up a thread for making player harassers into ref distractors
M21_threads.Harasser_processing_handle = thread_new("m21_harasser_processing_thread", group_table)
delay(3.0)
-- Play the effects
m21_play_arena_entrance_fireworks(group_table)
m21_process_enemy_set(group_table.members)
-- all npcs are dead, clean up threads used to move them in this wave
for i, npc in pairs(group_table.distractors) do
thread_kill(M21_threads.Ref_distractor_handles[i])
M21_threads.Ref_distractor_handles[i] = INVALID_THREAD_HANDLE
end
thread_kill(M21_threads.Harasser_processing_handle)
M21_threads.Harasser_processing_handle = INVALID_THREAD_HANDLE
end
-- Directs a single npc to the side of, then onto the ring
-- npc_name: (string) name of the npc directed to distract the ref
-- location_number: (int) number designating the location to run to
function m21_manage_distractor_thread(npc_name, location_number)
if (location_number < 1 or location_number > #M21_navpoints.npc_harass_points) then
return
end
distractors_on_ring[location_number] = npc_name
on_take_damage("m21_distractor_hit", npc_name)
set_attack_player_flag(npc_name, false)
character_prevent_bumping(npc_name, true)
character_prevent_flinching(npc_name, true)
npc_combat_enable(npc_name, false)
-- Move them to the ring
local start_nav = M21_navpoints.npc_harass_points[location_number]
local dest_nav = M21_navpoints.npc_harass_dest_points[location_number]
ai_do_scripted_move(npc_name, start_nav, true)
while(ai_scripted_action_is_processing(npc_name) and get_dist(npc_name, start_nav) > 1.25) do
thread_yield()
end
if (character_is_dead(npc_name)) then
distractors_on_ring[location_number] = ""
return
end
if (get_dist(npc_name, start_nav) > 1.5) then
on_take_damage("", npc_name)
set_attack_player_flag(npc_name, true)
character_prevent_bumping(npc_name, true)
character_prevent_flinching(npc_name, true)
npc_combat_enable(npc_name, false)
distractors_on_ring[location_number] = ""
return
end
-- They ignore all AI from here on out
set_ignore_ai_flag(npc_name, ENABLE)
-- Turn them to face their target
inv_item_remove_all(npc_name)
turn_to(npc_name, start_nav, true)
-- Play the animation to get up onto the ring - need to disable gravity to prevent fall animation from playing
human_gravity_enable(npc_name, false)
character_collision_enable(npc_name, false)
action_play(npc_name, M21_animations.luchadore_jump_on_ring, "", false, 0.75, true, true, start_nav, dest_nav)
character_collision_enable(npc_name, true)
human_gravity_enable(npc_name, true)
if (character_is_dead(npc_name) == false) then
-- Play the looping distracting animation
set_script_animation_state(npc_name, M21_animation_state.luchadore_ring_stand)
-- Replace the small object indicator with the full kill indicator
marker_remove(npc_name)
marker_add(npc_name, MINIMAP_ICON_KILL, OI_ASSET_KILL_FULL, OI_FLAGS_FULL)
end
end
-- Function to continuously apply damage to Killbane while fighting Angel
function m21_manage_killbane_angel_damage_thread(dmg_per_sec)
while (true) do
character_damage(M21_characters.angel, dmg_per_sec * get_frame_time())
hud_bar_set_value(GSI_ANGEL_HEALTH_INDEX, get_current_hit_points(M21_characters.angel))
thread_yield()
end
end
-- Continuously plays the fight between killbane and angel
function m21_manage_killbane_angel_fight_thread()
action_play_synced_state(M21_characters.killbane, M21_characters.angel, M21_animations.killbane_angel_grapple)
local wrestling_move_idx = 1
local cheat_move_idx = 1
while(true) do
delay(TIME_BETWEEN_KILLBANE_ANGEL_ACTIONS)
if (ref_target ~= "") then
-- Switch to the looping cheating state
action_play_synced_state(M21_characters.killbane, M21_characters.angel, M21_animations.killbane_angel_cheats[cheat_move_idx].state)
-- Play some dialog telling the player that Killbane is cheating
m21_helper_play_interrupting_commentary_line(M21_dialog_lines.ref_distracted, true, true, true, 0.0, true) -- allow repeats
-- Play the setup action to get to the cheating state
action_play_synced(M21_characters.killbane, M21_characters.angel, M21_animations.killbane_angel_cheats[cheat_move_idx].intro)
-- Loop in the cheating animation state and apply damage until the ref is no longer distracted
delay(2.0) -- stay in the cheating state for a minimum of 2 seconds
while(ref_target ~= "") do
character_damage(M21_characters.angel, CHEAPSHOT_DAMAGE)
delay(CHEAPSHOT_INTERVAL)
end
-- Switch back to the wrestling grabble state
action_play_synced_state(M21_characters.killbane, M21_characters.angel, M21_animations.killbane_angel_grapple)
-- Play thr outro action to return to the grapple state
action_play_synced(M21_characters.killbane, M21_characters.angel, M21_animations.killbane_angel_cheats[cheat_move_idx].outro)
-- Move to the next cheat
cheat_move_idx = cheat_move_idx + 1
if (cheat_move_idx > #M21_animations.killbane_angel_cheats) then
cheat_move_idx = 1
end
else
action_play_synced(M21_characters.killbane, M21_characters.angel, M21_animations.killbane_angel_fight[wrestling_move_idx])
-- Move to the next wrestling move
wrestling_move_idx = wrestling_move_idx + 1
if (wrestling_move_idx > #M21_animations.killbane_angel_fight) then
wrestling_move_idx = 1
end
end
end
end
function m21_harasser_processing_thread(group_name)
while true do
delay(TIME_BETWEEN_HARASSER_TO_DISTRACTOR) -- wait before checking the status of the ring
-- Count the number of active distractors
local num_distractors = 0
for i, distractor in pairs(distractors_on_ring) do
if (distractor ~= "") then
num_distractors = num_distractors + 1
end
end
-- If theres no distractors on the ring, try to send a harasser to the nearest spot on the ring
if (num_distractors < 2) then
-- See if there's any guys to promote
for i, npc_name in pairs(group_name.harassers) do
if not character_is_dead(npc_name) and character_is_ready(npc_name) then
-- Make sure they're not already distracting
local already_distracting = false
for i, distractor in pairs(distractors_on_ring) do
if (distractor == npc_name) then
already_distracting = true
break
end
end
if (already_distracting == false) then
-- Find the closest distract point
local closest_idx = m21_closest_distract_point(npc_name)
if (closest_idx ~= 0) then
-- Clean-up the old thread
if (thread_check_done(M21_threads.Ref_distractor_handles[closest_idx]) == false) then
thread_kill(M21_threads.Ref_distractor_handles[closest_idx])
end
set_suppress_synced_attacks_flag(npc_name)
set_attack_player_flag(npc_name, false)
M21_threads.Ref_distractor_handles[closest_idx] = thread_new("m21_manage_distractor_thread", npc_name, closest_idx)
break
end
end
end
end
end
end
end
-- Plays the Z-Scene of Angel getting thrown out of the ring
function m21_run_angel_throw_out()
zscene_prep(M21_cutscenes.angle_thrown_out)
while(zscene_is_loaded(M21_cutscenes.angle_thrown_out) == false) do
thread_yield()
end
thread_yield()
audio_object_post_event(M21_audio_events.z02, nil, nil, LOCAL_PLAYER)
m21_helper_dialog_kill_all()
cutscene_play(M21_cutscenes.angle_thrown_out, nil, M21_navpoints.player_defend_angel_start, false)
m21_cleanup_defend_the_ring()
m21_setup_defend_angel(true)
mission_start_fade_in()
end
-- Set up the sequence where you defend Angel from the 40+ guys
--
function m21_setup_defend_angel(create_groups)
if (create_groups == true) then
group_create(M21_groups.angel_stompers.name, true)
group_create(M21_groups.chainsaw_wave_01.name, true)
end
inv_weapon_disable_slot(WEAPON_SLOT_UNARMED, true)
inv_weapon_add_temporary(LOCAL_PLAYER, "chainsaw", 1, true, true)
if (in_coop) then
inv_weapon_add_temporary(REMOTE_PLAYER, "chainsaw", 1, true, true)
end
-- Teleport Angel and Killbane
teleport(M21_characters.angel, M21_navpoints.angel_landing_position, true, true, 0.0, 0.0, 0.0, false)
teleport(M21_characters.killbane, M21_navpoints.killswitch_ring_taunt)
-- Play some appropriate crowd cheers
audio_object_post_event(M21_audio_events.crowd_chainsaw, nil, nil, LOCAL_PLAYER)
-- The crowd is now with the player, so switch the audio
audio_object_post_event(M21_audio_events.crowd_with, nil, nil, LOCAL_PLAYER)
-- Setup Angel
on_death("m21_angel_died_2", M21_characters.angel)
marker_add(M21_characters.angel, MINIMAP_ICON_PROTECT_ACQUIRE, OI_ASSET_DEFEND, OI_FLAGS_FULL)
npc_leash_to_nav(M21_characters.angel, M21_navpoints.angel_landing_position, 5)
set_script_animation_state(M21_characters.angel, "M21 angel beat down a")
set_current_hit_points(M21_characters.angel, get_max_hit_points(M21_characters.angel))
set_suppress_synced_attacks_flag(M21_characters.angel, true)
-- Make Angel invulnerable
turn_invulnerable(M21_characters.angel)
-- Setup Killbane
set_script_animation_state(M21_characters.killbane, "KillBane Pacing")
thread_yield()
-- Setup the initial stompers
Chainsaw_luchadors_alive = 0
m21_helper_setup_chainsaw_group(M21_groups.angel_stompers)
for i, member in pairs(M21_groups.angel_stompers.members) do
-- Teleport to the nav (exit vehicle, reset camera, 0.0 X-offset, 0.0 Y-offset, 0.0 Z-offset, don't check for obstacles)
teleport(member, M21_angel_stomper_locations[i].nav, true, true, 0.0, 0.0, 0.0, false)
set_suppress_synced_attacks_flag(member)
M21_angel_stomper_locations[i].thread_id = thread_new("m21_process_angel_stomper_thread", member, M21_angel_stomper_locations[i])
end
-- Start up a thread to process the HUD for Angel's health
M21_threads.Killbane_angel_damage_handle = thread_new("m21_manage_killbane_angel_damage_thread", 0.0)
-- Start up a thread to process the Angel stompers
M21_threads.angel_stompers_handle = thread_new("m21_process_angel_stompers_thread")
-- Setup the first wave of guys
m21_helper_setup_chainsaw_group(M21_groups.chainsaw_wave_01)
end
-- Main function for the defend angel sequence of the fight
--
function m21_run_defend_angel()
-- Update the objective text
objective_text( GSI_OBJECTIVE_INDEX, "m21_obj_protect_angel", "", "", SYNC_ALL, OI_ASSET_DEFEND )
hud_bar_on(GSI_ANGEL_HEALTH_INDEX, "health", "", get_max_hit_points(M21_characters.angel), SYNC_ALL)
-- Wait a sec, then play some music
delay(1.0)
audio_object_post_event(M21_audio_events.music_your_the_best, nil, nil, LOCAL_PLAYER)
-- Queue up some dialog
delay(1.5)
for i=#M21_dialog_lines.chainsaw_commentary, 1, -1 do
m21_helper_dialog_play(M21_dialog_lines.chainsaw_commentary[i], M21_CONVO_PLAY_NEXT, 0.0)
end
-- Do some fireworks
m21_play_arena_entrance_fireworks()
-- Wait until all there are only 5 guys remaining
while (Chainsaw_luchadors_alive > 5) do
thread_yield()
end
-- Spawn the second wave of guys
group_create(M21_groups.chainsaw_wave_02.name)
m21_helper_setup_chainsaw_group(M21_groups.chainsaw_wave_02)
-- Do some fireworks
delay(3.0)
m21_play_arena_entrance_fireworks()
-- Wait until all there are only 5 guys remaining
while (Chainsaw_luchadors_alive > 7) do
thread_yield()
end
-- Spawn the third wave of guys
group_create(M21_groups.chainsaw_wave_03.name)
m21_helper_setup_chainsaw_group(M21_groups.chainsaw_wave_03)
-- Do some fireworks
delay(3.0)
m21_play_arena_entrance_fireworks()
-- Wait until all there are only 5 guys remaining
while (Chainsaw_luchadors_alive > 5) do
thread_yield()
end
-- Spawn the fourth wave of guys
group_create(M21_groups.chainsaw_wave_04.name)
m21_helper_setup_chainsaw_group(M21_groups.chainsaw_wave_04)
-- Do some fireworks
delay(3.0)
m21_play_arena_entrance_fireworks()
-- Wait until everyone has been killed
while (Chainsaw_luchadors_alive > 0) do
thread_yield()
end
-- MLG (07/13/11): Design wants the "You're the best" music to play out
--[[
-- Wait a sec and the stop the music (if it's still playing)
delay(1.5)
audio_object_post_event(M21_audio_events.music_your_the_best_stop, nil, nil, LOCAL_PLAYER)
--]]
m21_cleanup_defend_angel()
end
function m21_cleanup_defend_angel()
hud_bar_off(GSI_ANGEL_HEALTH_INDEX)
marker_remove(M21_characters.angel)
inv_weapon_disable_slot(WEAPON_SLOT_UNARMED, false)
for i, member in pairs(M21_groups.angel_stompers.members) do
on_death("", member)
on_detection("", member)
end
for i, member in pairs(M21_groups.chainsaw_wave_01.members) do
on_death("", member)
end
for i, member in pairs(M21_groups.chainsaw_wave_02.members) do
on_death("", member)
end
release_to_world(M21_groups.angel_stompers.name)
release_to_world(M21_groups.chainsaw_wave_01.name)
release_to_world(M21_groups.chainsaw_wave_02.name)
group_destroy(M21_groups.angel_stompers.name)
group_destroy(M21_groups.chainsaw_wave_01.name)
group_destroy(M21_groups.chainsaw_wave_02.name)
thread_kill(M21_threads.angel_stompers_handle)
M21_threads.angel_stompers_handle = INVALID_THREAD_HANDLE
for i, stomp_location in pairs(M21_angel_stomper_locations) do
if (stomp_location.occupant ~= "") then
set_script_animation_state(stomp_location.occupant, nil)
end
thread_kill(stomp_location.thread_id)
stomp_location.thread_id = INVALID_THREAD_HANDLE
end
m21_helper_cleanup_chainsaw_group(M21_groups.chainsaw_wave_01)
m21_helper_cleanup_chainsaw_group(M21_groups.chainsaw_wave_02)
m21_helper_cleanup_chainsaw_group(M21_groups.chainsaw_wave_03)
m21_helper_cleanup_chainsaw_group(M21_groups.chainsaw_wave_04)
end
function m21_helper_setup_chainsaw_group(group_table)
group_show(group_table.name)
for i, member in pairs(group_table.members) do
on_death("m21_chainsaw_luchador_killed_cb", member)
marker_add(member, MINIMAP_ICON_KILL, OI_ASSET_KILL)
set_suppress_synced_attacks_flag(member)
ai_add_enemy_target(member, CLOSEST_PLAYER, ATTACK_NOW_NEVER_LOSE, true)
M21_pontential_stomper_list[#M21_pontential_stomper_list + 1] = member
Chainsaw_luchadors_alive = Chainsaw_luchadors_alive + 1
end
end
function m21_helper_cleanup_chainsaw_group(group_table)
for i, member in pairs(group_table.members) do
on_death("", member)
end
end
-- Thread to process a Luchador running over to stomp on Angel some
--
-- human_name: Name of the Luchador
-- location_table: Lua table defining the stomp location
function m21_process_angel_stomper_thread(human_name, location_table)
set_ignore_ai_flag(human_name, true)
-- Remove this guy from the potential stomper list
for i, member in pairs(M21_pontential_stomper_list) do
if (member == human_name) then
M21_pontential_stomper_list[i] = ""
break
end
end
-- Store the occupant with this human
location_table.occupant = human_name
-- Move to the navpoint
if (m21_move_script_npc_to(human_name, location_table.nav, true, false) == false) then
set_ignore_ai_flag(human_name, false)
location_table.occupant = ""
return
end
-- They made it, turn off bumping and flinching
character_prevent_bumping(human_name, true)
character_prevent_flinching(human_name, true)
turn_to(human_name, location_table.nav, true) -- use the navpoints orientation
-- Play the animation
set_script_animation_state(human_name, location_table.anim)
-- Spin until the character has died or has moved away from the navpoint
while(true) do
local is_dead = character_is_dead(human_name)
if (is_dead == true or get_dist(human_name, location_table.nav) > 0.5) then
set_ignore_ai_flag(human_name, false)
set_script_animation_state(human_name, nil)
character_prevent_bumping(human_name, false)
character_prevent_flinching(human_name, false)
location_table.occupant = ""
if (is_dead == false) then
-- Try again
location_table.occupant = human_name
location_table.thread_id = thread_new("m21_process_angel_stomper_thread", human_name, location_table)
end
return
end
thread_yield()
end
end
-- Process the Luchador Angel stompers
function m21_process_angel_stompers_thread()
-- Loop forever (we'll be killed when it's time to stop)
while(true) do
-- Determine how many Luchadors are stomping on Angel
local num_stompers = 0
local num_active_stompers = 0
local free_stomp_locations = { }
for i, stomp_location in pairs(M21_angel_stomper_locations) do
if (stomp_location.occupant ~= "") then
num_stompers = num_stompers + 1
if (check_script_animation_state(stomp_location.occupant, stomp_location.anim) == true) then
num_active_stompers = num_active_stompers + 1
end
else
free_stomp_locations[#free_stomp_locations + 1] = stomp_location
end
end
-- Do we need to recruit a new stomper?
if (num_stompers < NUM_STOMPERS_TO_MAINTAIN) then
-- Find the best chainsaw guy that is alive to recruit for some stompin
local best_guy = nil
local best_dist = 1000000
for i, member in pairs(M21_pontential_stomper_list) do
if (member ~= "" and character_is_dead(member) == false) then
local dist = get_dist(member, M21_characters.angel)
if (dist < best_dist) then
best_guy = member
best_dist = dist
end
end
end
-- If we found a guy, recruit him
if (best_guy ~= nil) then
local stomp_location = free_stomp_locations[rand_int(1, #free_stomp_locations)]
stomp_location.thread_id = thread_new("m21_process_angel_stomper_thread", best_guy, stomp_location)
end
end
if (num_active_stompers > 0) then
if (check_script_animation_state(M21_characters.angel, "M21 angel beat down a") == false) then
set_script_animation_state(M21_characters.angel, "M21 angel beat down a")
end
else
if (check_script_animation_state(M21_characters.angel, "M24 Suffering") == false) then
set_script_animation_state(M21_characters.angel, "M24 Suffering")
end
end
-- Apply damage to Angel based on how many stompers are still stomping
local damage_to_apply = num_active_stompers * ANGEL_DAMAGE_FROM_STOMPER_PER_SEC * get_frame_time()
character_damage(M21_characters.angel, damage_to_apply)
thread_yield()
end
end
-- Callback when one of the Luchadors stomping on angle is killed
--
-- victim: Name of the Luchador that was killed
-- attacker: Name of the person that attacked the luchador
function m21_chainsaw_luchador_killed_cb(victim, attacker)
-- Remove the makrer and on-death callback
marker_remove(victim)
on_death("", victim)
-- Maybe play some commentary
if (rand_int(1, 3) == 1) then
m21_helper_play_interrupting_commentary_line(M21_dialog_lines.chainsaw_kills, false) -- don't repeat lines
end
-- Remove this guy from the stomper list
for i, member in pairs(M21_pontential_stomper_list) do
if (member == victim) then
M21_pontential_stomper_list[i] = ""
break
end
end
-- Update the number of chainsaw luchadors still alive
Chainsaw_luchadors_alive = Chainsaw_luchadors_alive - 1
end
-- Callback when one of the Luchadors stomping on angel detects a player
--
-- enemy: Name of the Luchador that detected the player
-- player: Name of the player that was detected
function m21_luchador_stomper_detect_player_cb(enemy, player)
-- Register the player as an Enemy
ai_add_enemy_target(enemy, player, ATTACK_NOW_NEVER_LOSE)
-- Remove the callback
on_detection("", enemy)
end
-- Player needs to goto angel and check up on him
function m21_run_goto_angel()
-- Update the objective text
objective_text(GSI_OBJECTIVE_INDEX, "m21_obj_go_to_angel", "", "", SYNC_ALL, OI_ASSET_LOCATION)
on_death("m21_angel_died_1", M21_characters.angel)
-- Set up trigger and marker for player to goto angel to talk
marker_add_trigger(M21_triggers.player_reached_angel, MINIMAP_ICON_LOCATION, INGAME_EFFECT_CHECKPOINT, OI_ASSET_LOCATION, OI_FLAGS_LOCATION, SYNC_ALL)
-- Add a small delay, since the player is likely already standing right next to angel
delay(2.0)
-- Enable the trigger
on_trigger("m21_player_reached_angel", M21_triggers.player_reached_angel)
trigger_enable(M21_triggers.player_reached_angel, ENABLE)
-- Wait for the player to reach Angel
player_reached_angel = false
while(not player_reached_angel) do
thread_yield()
end
-- Play the main event starting conversation, followed by the commentary
m21_helper_dialog_kill_all()
m21_helper_dialog_play(M21_conversations.player_killbane_fight, M21_CONVO_PLAY_IMMEDIATE, 0.0)
-- Wait for the announcers to finish talking (up to 25 seconds)
local elapsed_time = 0.0
while(m21_helper_dialog_check_done(M21_conversations.player_killbane_fight) == false) do
thread_yield()
elapsed_time = elapsed_time + get_frame_time()
if (elapsed_time > 12.0) then
break
end
end
m21_cleanup_goto_angel()
end
-- Cleanup goto angel objective
function m21_cleanup_goto_angel()
marker_remove_trigger(M21_triggers.player_reached_angel)
inv_weapon_remove_temporary("#player1#", "chainsaw")
if (in_coop) then
inv_weapon_remove_temporary("#player2#", "chainsaw")
end
camera_end_look_through(false)
end
-- Do what needs to be done to get the player into the ring and
-- ready to fight Killbane
--
function m21_run_enter_the_ring()
-- Update the objective text
objective_text(GSI_OBJECTIVE_INDEX, "m21_obj_enter_the_ring", "", "", SYNC_ALL, OI_ASSET_LOCATION)
-- Stop throwing the props
boss_battle_kb_enable_crowd_props(DISABLE, PHASE_FIGHT_KILLBANE)
-- Enable the trigger to enter the ring
trigger_enable(M21_triggers.player_enter_ring, ENABLE)
on_trigger("m21_player_enter_ring", M21_triggers.player_enter_ring)
marker_add_trigger(M21_triggers.player_enter_ring, MINIMAP_ICON_LOCATION, INGAME_EFFECT_CHECKPOINT, OI_ASSET_LOCATION, OI_FLAGS_LOCATION, SYNC_ALL)
-- Wait until the player has entered the ring
while(Player_entered_ring == false) do
thread_yield()
end
-- Set a safe respawn point if the player can't get up from a ragdoll (so they don't spawn on the wrong side of the ropes)
character_ragdoll_set_last_valid_position(LOCAL_PLAYER, M21_navpoints.player_fight_start[1], true)
character_ragdoll_set_last_valid_position(LOCAL_PLAYER, M21_navpoints.player_fight_start_alt[1], false)
if (coop_is_active() == true) then
character_ragdoll_set_last_valid_position(REMOTE_PLAYER, M21_navpoints.player_fight_start[2])
character_ragdoll_set_last_valid_position(REMOTE_PLAYER, M21_navpoints.player_fight_start_alt[2], false)
end
-- Turn Killbane to face the player
set_script_animation_state(M21_characters.killbane, nil)
thread_yield()
thread_yield()
turn_to_do(M21_characters.killbane, player_in_ring)
-- Hide the HUD
m21_helper_hide_hud(true)
-- Move the player into the ring
player_movement_disable(player_in_ring)
player_actions_disable(player_in_ring)
inv_item_remove_in_slot("single_use", player_in_ring)
move_to(player_in_ring, M21_navpoints.player_enter_ring, 1)
turn_to_do(player_in_ring, M21_navpoints.player_enter_ring, true) -- turn to face angle
-- Start some dialog
m21_helper_dialog_kill_all()
m21_helper_dialog_play(M21_conversations.player_killbane_banter, M21_CONVO_PLAY_IMMEDIATE, 0.0, player_in_ring)
-- Play the enter animation
human_gravity_enable(player_in_ring, false)
character_collision_enable(player_in_ring, false)
action_play(player_in_ring, M21_animations.luchadore_enter_ring, "", false, 0.6, true, true, M21_navpoints.player_enter_ring, M21_navpoints.player_over_ropes_dest)
human_gravity_enable(player_in_ring, true)
character_collision_enable(player_in_ring, true)
player_movement_enable(player_in_ring)
player_actions_enable(player_in_ring)
-- Re-enable the HUD
m21_helper_hide_hud(false)
m21_cleanup_enter_the_ring()
end
-- Cleanup entering the ring
function m21_cleanup_enter_the_ring()
-- NOTHING TO DO HERE YET
end
-- All the required setup before the boss fight starts
function m21_setup_fight_killbane()
-- Set a safe respawn point if the player can't get up from a ragdoll (so they don't spawn on the wrong side of the ropes)
character_ragdoll_set_last_valid_position(LOCAL_PLAYER, M21_navpoints.player_fight_start[1], true)
character_ragdoll_set_last_valid_position(LOCAL_PLAYER, M21_navpoints.player_fight_start_alt[1], false)
if (coop_is_active() == true) then
character_ragdoll_set_last_valid_position(REMOTE_PLAYER, M21_navpoints.player_fight_start[2], true)
character_ragdoll_set_last_valid_position(REMOTE_PLAYER, M21_navpoints.player_fight_start_alt[2], false)
end
-- Set Angel into his animation state
npc_leash_to_nav(M21_characters.angel, M21_navpoints.angel_landing_position, 5)
set_script_animation_state(M21_characters.angel, "M24 Suffering")
-- Setup Killbane
set_ignore_ai_flag(M21_characters.killbane, false)
set_attack_player_flag(M21_characters.killbane, true)
end
-- Main function for the Killbane battle
-- The Killswitch, additional reinforcements, and success are handled here
--
function m21_fight_killbane()
-- Update the objective text
objective_text( GSI_OBJECTIVE_INDEX, "m21_obj_fight_killbane", "", "", SYNC_ALL, OI_ASSET_KILL )
-- Kick off a thread to process mission critical characters and enforce they are where the out to be
Killbane_should_be_in_ring = true
M21_threads.enforce_character_locations = thread_new("m21_thread_enforce_character_locations")
-- Make Angel invulnerable
turn_invulnerable(M21_characters.angel)
-- Hide the HUD
m21_helper_hide_hud(true)
-- Player can't sprint
player_can_sprint(false)
-- Setup for coop
if in_coop then
-- Players can't be downed in coop
set_players_can_be_downed(LOCAL_PLAYER, DISABLE)
set_players_can_be_downed(REMOTE_PLAYER, DISABLE)
continuous_spawn_start(M21_groups.coop_cont_spawn_01.name, 0, 5.0)
continuous_spawn_start(M21_groups.coop_cont_spawn_02.name, 0, 5.0)
character_disable_human_downed_interactions(player_outside_ring, true)
end
-- Initialize the turnbuckle triggers to the correct callback
for i, trigger in pairs(M21_triggers.beatup_killbane) do
on_trigger("m21_killbane_beatup_callback", trigger)
end
m21_helper_setup_killbane_ring_fighting()
-- Register callbacks for when Killbane is mounted and dismounter
on_mount("m21_killbane_mounted_callback", M21_characters.killbane)
on_dismount("m21_killbane_dismounted_callback", M21_characters.killbane)
-- Register a callback for when the player is damaged
on_take_damage("m21_player_damaged_in_ring_cb", player_in_ring)
on_weapon_pickup("m21_player_got_prop_in_ring_cb", player_in_ring)
on_trigger("m21_cb_tag_partner_inside_ring", M21_triggers.tag_trigger_inside)
on_trigger("m21_cb_tag_partner_outside_ring", M21_triggers.tag_trigger_outside)
m21_enable_coop_tag_triggers(ENABLE)
-- Play the main event starting conversation, followed by the commentary
for i, line in pairs(M21_dialog_lines.player_killbane_commentary) do
m21_helper_dialog_play(line, M21_CONVO_PLAY_LAST, 0.0)
end
-- Start prepping the next Z-scene
zscene_prep(M21_cutscenes.unmask_threat)
-- Start throwing the props
if (M21_conversations.player_killbane_banter.started == true) then
while(m21_helper_dialog_check_done(M21_conversations.player_killbane_banter) == false) do
thread_yield()
end
else
delay(3.0)
end
boss_battle_kb_enable_crowd_props(ENABLE, PHASE_FIGHT_KILLBANE)
-- Process the killbane fight
killbane_wave = 1
while (not player_win) do
if (not fight_club_phase) then
if (num_times_killbane_hit_by_weapon >= NUM_WEAPON_HITS_FOR_FINISHER) then
on_take_damage("", M21_characters.killbane) -- turn of the callback for the QTE, or it will count
-- Crowd cheers
--audio_object_post_event(M21_audio_events.crowd_cheer_low, nil, nil, LOCAL_PLAYER)
if (killbane_wave == 3) then
-- If this is the final Killswitch, kill the Killbane/player taunt
if (dialog_queue.playing.dialog_table.name == M21_conversations.killbane_player_taunt.name) then
m21_helper_dialog_cleanup_playing()
end
end
-- Play some dialog for Killbane's tell for the incoming Killswitch
m21_helper_play_interrupting_commentary_line(M21_dialog_lines.killswitch_tell, true, false, false, 10.0, true) -- allow repeat lines for this
--delay(1.0)
-- Drop all their weapons
inv_item_remove_in_slot( "single_use", player_in_ring )
-- Register a callback so we know when to play the commentary lines
on_qte_animation_trigger("m21_killswitch_intermediary_cb")
-- Do the Killswitch
perform_killswitch(M21_characters.killbane, player_in_ring)
num_times_killbane_hit_by_weapon = 0
end
if (in_coop) then
end
end
thread_yield()
end
-- Stop the props
boss_battle_kb_enable_crowd_props(DISABLE)
end
-- Cutscene that happens after the player chokes out Killbane in which the
-- player threatens to demask him
--
function m21_killbane_unmask_threat()
--m21_helper_set_player_headlock_anim(player_in_ring)
-- Kill the thread enforcing everybody is where they need to be (don't want it messing with the cutscenes)
if (thread_check_done(M21_threads.enforce_character_locations) == false) then
thread_kill(M21_threads.enforce_character_locations)
end
-- Clear the HUD prompts for both players
hud_prompt_clear(LOCAL_PLAYER)
if (coop_is_active() == true) then
hud_prompt_clear(REMOTE_PLAYER)
end
-- Remove the callbacks for the tag in/out triggers
on_trigger("", M21_triggers.tag_trigger_inside)
on_trigger("", M21_triggers.tag_trigger_outside)
zscene_prep(M21_cutscenes.unmask_threat)
while(zscene_is_loaded(M21_cutscenes.unmask_threat) == false) do
thread_yield()
end
thread_yield()
local teleport_navs = { }
if (player_in_ring == LOCAL_PLAYER) then
teleport_navs[1] = M21_navpoints.killswitch_ring_taunt
teleport_navs[2] = M21_navpoints.player_outside_ring
else
teleport_navs[1] = M21_navpoints.player_outside_ring
teleport_navs[2] = M21_navpoints.killswitch_ring_taunt
end
cutscene_play(M21_cutscenes.unmask_threat, nil, teleport_navs, false)
thread_yield()
teleport(M21_characters.killbane, M21_navpoints.killswitch_ring_taunt)
set_ignore_ai_flag(M21_characters.killbane, true)
character_allow_ragdoll(M21_characters.killbane, false) -- Killbane should never ragdoll
player_movement_disable(player_in_ring)
player_actions_disable(player_in_ring)
m21_helper_hide_hud(true)
m21_helper_set_player_headlock_anim(player_in_ring)
delay(0.2)
fade_in(0.1)
fade_in_block()
end
-- Blocking function which waits for the choice callback to let us know the
-- player made a choice
--
function m21_player_choice_sequence()
-- Start a Murderbrawl chant
audio_object_post_event(M21_audio_events.we_want_blood, nil, nil, LOCAL_PLAYER)
delay(1.0) -- minor delay
-- Push the selection screen
Play_choice_selection = -1
on_m21_player_choice("m21_player_made_choice_cb")
hud_push_screen("msn_killbane", sync_from_player(player_in_ring))
thread_yield()
while(Play_choice_selection == -1) do
thread_yield()
end
player_movement_enable(player_in_ring)
player_actions_enable(player_in_ring)
-- Set the player's choice
player_unmasked_killbane = false
if (Play_choice_selection == 1) then
player_unmasked_killbane = true
end
end
-- Callback when a player has made their decision
--
-- selection: (integer) The player choice (0 = unmask Killbane, 1 = leave Killbane's mask)
function m21_player_made_choice_cb(selection)
Play_choice_selection = selection
end
-- Plays the cutscene where the player unmasked killbane
--
function m21_player_unmasked_killbane()
zscene_prep(M21_cutscenes.remove_mask)
while(zscene_is_loaded(M21_cutscenes.remove_mask) == false) do
thread_yield()
end
thread_yield()
audio_object_post_event(M21_audio_events.z03, nil, nil, LOCAL_PLAYER)
cutscene_play(M21_cutscenes.remove_mask, nil, nil, false)
end
-- Plays the cutscene where the player didnt unmask killbane
--
function m21_player_didnt_unmask_killbane()
zscene_prep(M21_cutscenes.release_killbane)
while(zscene_is_loaded(M21_cutscenes.release_killbane) == false) do
thread_yield()
end
thread_yield()
audio_object_post_event(M21_audio_events.z04, nil, nil, LOCAL_PLAYER)
cutscene_play(M21_cutscenes.release_killbane, nil, nil, false)
end
-- ***************************************************
-- m21_run Helper Functions
-- ***************************************************
-- ***************************************************
-- m21_initialize Helper Functions
-- ***************************************************
-- This callback gets called when Killbane first gets ridden.
-- It finds the appropriate turnbuckle trigger region and turns it on.
function m21_set_killbane_beatup_trigger()
-- Find the trigger furthest away from the player
local largest_distance_found = 0
local furthest_trigger = 0
for i, trigger in pairs(M21_triggers.beatup_killbane) do
local distance = get_dist(player_in_ring, trigger)
if (distance > largest_distance_found) then
largest_distance_found = distance
furthest_trigger = i
end
end
-- Now we have the furthest trigger, enable it
enabled_trigger_index = furthest_trigger
trigger_enable(M21_triggers.beatup_killbane[enabled_trigger_index], ENABLE)
marker_add_trigger(M21_triggers.beatup_killbane[enabled_trigger_index], MINIMAP_ICON_LOCATION, INGAME_EFFECT_CHECKPOINT, OI_ASSET_LOCATION, OI_FLAGS_LOCATION, sync_from_player(player_in_ring))
end
-- Remove and clean up the trigger used to tell if the player has reached the corner
--
function m21_remove_killbane_beatup_trigger()
trigger_enable(M21_triggers.beatup_killbane[enabled_trigger_index], DISABLE)
marker_remove_trigger(M21_triggers.beatup_killbane[enabled_trigger_index], sync_from_player(player_in_ring))
end
-- Turns on/off the coop tag triggers, used during riding.. etc
function m21_enable_coop_tag_triggers(enable)
if in_coop then
if enable then
if (player_ready_to_tag_in == false) then
trigger_enable(M21_triggers.tag_trigger_outside, ENABLE)
ingame_effect_add_trigger(M21_triggers.tag_trigger_outside, INGAME_EFFECT_LOCATION, sync_from_player(player_outside_ring))
else
trigger_enable(M21_triggers.tag_trigger_inside, ENABLE)
ingame_effect_add_trigger(M21_triggers.tag_trigger_inside, INGAME_EFFECT_LOCATION, sync_from_player(player_in_ring))
end
else
trigger_enable(M21_triggers.tag_trigger_outside, DISABLE)
ingame_effect_remove_trigger(M21_triggers.tag_trigger_outside, SYNC_ALL)
trigger_enable(M21_triggers.tag_trigger_inside, DISABLE)
ingame_effect_remove_trigger(M21_triggers.tag_trigger_inside, SYNC_ALL)
end
end
end
-- This is called after Killbane has been beat up. It will spawn the fight club phase npcs and
-- have them run into the ring.
function m21_spawn_fight_club_phase_npcs()
objective_text( GSI_OBJECTIVE_INDEX, "m21_obj_kill_luchadores", "", "", SYNC_ALL, OI_ASSET_KILL )
group_create( M21_groups.fight_club_phase_reinforcements.name, true )
killbane_thug_enemies_to_kill = 0
for side, enemy in pairs(M21_groups.fight_club_phase_reinforcements.members) do
if (not character_is_dead(enemy)) then
-- Assign enemy callbacks, add markers
on_death("m21_killbane_thug_enemy_killed", enemy)
set_attack_player_flag(enemy, true)
set_attack_enemies_flag(enemy, false)
set_suppress_synced_attacks_flag(enemy)
M21_threads.Killbane_reinforcements_handles[side] = thread_new("m21_killbane_reinforcements_thread", enemy, side)
killbane_thug_enemies_to_kill = killbane_thug_enemies_to_kill + 1
end
end
killbane_thug_enemies_living = killbane_thug_enemies_to_kill
fight_club_phase = true
if (coop_is_active()) then
end
M21_threads.Killbane_pacing_handle = thread_new("m21_killbane_pacing_thread")
-- Wait a second and play some boos from the crowd
delay(2.0)
audio_object_post_event(M21_audio_events.boo_killbane, nil, nil, LOCAL_PLAYER)
-- Do some fireworks
delay(1.0)
m21_play_arena_entrance_fireworks()
end
-- Cleans up the thugs that join the right after Killbane leaves the ring
function m21_cleanup_fight_club_phase_npcs()
for side, enemy in pairs(M21_groups.fight_club_phase_reinforcements.members) do
-- Assign enemy callbacks, add markers
if (character_exists(enemy)) then
on_death("", enemy)
release_to_world(enemy)
end
if (M21_threads.Killbane_reinforcements_handles[side] ~= INVALID_THREAD_HANDLE) then
thread_kill(M21_threads.Killbane_reinforcements_handles[side])
M21_threads.Killbane_reinforcements_handles[side] = INVALID_THREAD_HANDLE
end
end
group_destroy(M21_groups.fight_club_phase_reinforcements.name)
end
function m21_find_closest_killbane_enter_ring_nav()
-- Find the closest navpoint
local closest_nav = M21_navpoints.killbane_enter_ring[1]
local closest_dist = 9999999
for i, nav in pairs(M21_navpoints.killbane_enter_ring) do
local dist = get_dist(nav, M21_characters.killbane)
if (dist < closest_dist) then
closest_nav = nav
closest_dist = dist
end
end
return closest_nav
end
-- Thread to process Killbane getting back into the ring
function m21_killbane_back_into_ring_thread()
ai_clear_scripted_action(M21_characters.killbane)
set_ignore_ai_flag(M21_characters.killbane, false)
-- Find the closest navpoint
local closest_nav = m21_find_closest_killbane_enter_ring_nav()
-- Move into position
m21_move_script_npc_to(M21_characters.killbane, closest_nav, false, false)
turn_to(M21_characters.killbane, closest_nav, true)
-- Play the enter animation
human_gravity_enable(M21_characters.killbane, false)
character_collision_enable(M21_characters.killbane, false)
action_play(M21_characters.killbane, M21_animations.killbane_enter_ring, M21_animations.killbane_enter_ring, false, 0.8, false, true, closest_nav)
human_gravity_enable(M21_characters.killbane, true)
character_collision_enable(M21_characters.killbane, true)
Killbane_should_be_in_ring = true
-- Setup Killbane now that he's back in the ring
m21_helper_setup_killbane_ring_fighting()
end
-- Checks the number of thugs remaining in the fight club phase and handles the transition for when they die
function m21_check_for_remaining_thugs()
if (killbane_thug_enemies_living <= 0) then
if (fight_club_phase) then
-- thugs were just killed, bring in killbane and port out player if needed
fight_club_phase = false
objective_text( GSI_OBJECTIVE_INDEX, "m21_obj_fight_killbane", "", "", SYNC_ALL, OI_ASSET_KILL )
thread_kill(M21_threads.Killbane_pacing_handle)
M21_threads.Killbane_pacing_handle = thread_new("m21_killbane_back_into_ring_thread")
-- Stop the pacing animation
set_script_animation_state(M21_characters.killbane, nil)
-- Play another conversation
m21_helper_dialog_play(M21_conversations.killbane_player_taunt, M21_CONVO_PLAY_NEXT, 0.0, player_in_ring)
end
end
end
-- Helper function to move and block until an npc gets to a destination
--
-- npc: (string) name of the npc
-- dest: (string) name of the destination
-- run: (bool, optional) should the npc run?
-- move_and_fire: (bool, optional) should the npc move and fire?
--
function m21_move_script_npc_to(npc, dest, run, move_and_fire)
-- Do the scripted move
if (ai_do_scripted_move(npc, dest, run, move_and_fire) == false) then
-- Scripted move failed
return false
end
-- Wait for the scripted pathfind to finish process
while(ai_scripted_action_is_processing(npc) == true) do
thread_yield()
end
-- Return if the scripted pathfind succeeded
return ai_scripted_action_is_complete(npc)
end
-- Player finished the QTE beatup, start the transition
--
function m21_killbane_qte_beatup_finished()
killbane_wave = killbane_wave + 1
if (killbane_wave > NUM_KILLBANE_WAVES_TO_WIN) then
player_win = true
--m21_helper_set_player_headlock_anim(player_in_ring)
elseif (killbane_wave == 3) then
m21_cleanup_fight_club_phase_npcs() -- clean up any previously spawned npcs
m21_spawn_fight_club_phase_npcs()
else
M21_threads.Killbane_pacing_handle = thread_new("m21_killbane_back_into_ring_thread")
end
end
-- ***************************************************
-- Miscellaneous m21 Helper Functions
-- ***************************************************
-- Cleanup all the threads
--
function m21_cleanup_threads()
cleanup_threads(M21_threads)
end
-- Cleanup all the groups of characters and vehicles
--
function m21_cleanup_groups()
cleanup_groups(M21_groups)
end
function m21_cleanup_triggers(trigger_group)
for i, trigger in pairs(trigger_group) do
if (type(trigger) == "table") then
m21_cleanup_triggers(trigger)
else
m21_clear_trigger(trigger)
end
end
end
function m21_cleanup_conversations()
-- Kill the conversation thread
m21_helper_dialog_kill_all()
if (thread_check_done(M21_threads.process_dialog) == false) then
thread_kill(M21_threads.process_dialog)
M21_threads.process_dialog = INVALID_THREAD_HANDLE
end
audio_persona_remove_2d(M21_personas.bobby.persona_id)
M21_personas.bobby.persona_id = INVALID_PERSONA_HANDLE
audio_persona_remove_2d(M21_personas.zach.persona_id)
M21_personas.zach.persona_id = INVALID_PERSONA_HANDLE
end
-- Disable trigger
--
-- trigger: (string) Name of the trigger
--
function m21_clear_trigger(trigger)
on_trigger("", trigger)
trigger_enable(trigger, false)
marker_remove_trigger(trigger, SYNC_ALL)
end
-- Disables a characters callbacks and releases them to the world
--
-- npc_name: (string) name of the character
--
function m21_release_harasser_to_world(npc_name)
on_death("", npc_name)
on_take_damage("", npc_name)
if(character_exists(npc_name)) then
release_to_world(npc_name)
end
end
function m21_process_enemy_set(enemy_table)
enemy_set_setup(enemy_table, false)
while (not Process_enemy_set_cleared) do
thread_yield()
end
-- make sure everything is cleaned up
enemy_set_cleanup(enemy_table)
end
-- Determines which distracting navpoint the given npc is closest to
--
-- npc_name: (string) name of the npc
--
-- returns: index of the closest distract navpoint
function m21_closest_distract_point(npc_name)
local cur_lowest_dist = 99999999
local best_navpoint_number = 0
for i, navpoint in pairs(M21_navpoints.npc_harass_points) do
if (distractors_on_ring[i] == "") then
local dist = get_dist(navpoint, npc_name)
if dist < cur_lowest_dist then
cur_lowest_dist = dist
best_navpoint_number = i
end
end
end
return best_navpoint_number
end
-- Check if a particular conversation is done (Originally written by Matt Gawalek for Mission 02)
--
-- dialog_table: Conversation Lua table (see M21_conversations)
function m21_helper_dialog_check_done(dialog_table)
if (dialog_table.queued == false and dialog_table.started == false) then
return true
else
return dialog_table.ended
end
end
-- Helper to play conversations, by adding them to the cue (Originally written by Matt Gawalek for Mission 02)
--
-- dialog_table: Conversation Lua table (see M21_conversations)
-- priority: Desired priority for the conversation
-- delay: Amonut of time to dalya after this conversation before playing the next conversation (in seconds)
-- player: Player to play the line on if in coop (if player speaks in dialog), or nil to play on the HOST (defaults to nil)
function m21_helper_dialog_play(dialog_table, priority, delay, player)
dialog_table.queued = true
dialog_table.delay = delay
dialog_table.player = player
if (priority == M21_CONVO_PLAY_LAST) then
-- Insert this entry at the end of hte lsit
dialog_queue.list[dialog_queue.size] = dialog_table
dialog_queue.size = dialog_queue.size + 1
elseif (priority == M21_CONVO_PLAY_NEXT) then
-- Shift the list to the right
for i = dialog_queue.size - 1, 0, -1 do
dialog_queue.list[i + 1] = dialog_queue.list[i]
end
dialog_queue.list[0] = dialog_table
dialog_queue.size = dialog_queue.size + 1
elseif (priority == M21_CONVO_PLAY_IMMEDIATE) then
-- Stop any actively playing conversations, and start this one immediatly
m21_helper_dialog_cleanup_playing()
dialog_queue.playing.thread_id = thread_new("m21_thread_play_dialog", dialog_table)
end
end
-- Kill any active dialog, and clear out the dialog queue (Originally written by Matt Gawalek for Mission 02)
function m21_helper_dialog_kill_all()
-- Stop any active conversation
m21_helper_dialog_cleanup_playing()
-- Clear out the queue
for i = 0, dialog_queue.size - 1 do
dialog_queue.list[i].ended = true
end
dialog_queue.size = 0
end
-- Cleanup any playing dialog (Originally written by Matt Gawalek for Mission 02)
function m21_helper_dialog_cleanup_playing()
-- Stop the thread processing a playing dialog
if (dialog_queue.playing.thread_id ~= INVALID_THREAD_HANDLE) then
thread_kill(dialog_queue.playing.thread_id)
dialog_queue.playing.thread_id = INVALID_THREAD_HANDLE
end
-- Cleanup any dialog data for a playing dialog
if (dialog_queue.playing.dialog_handle ~= INVALID_CONVERSATION_HANDLE) then
if (dialog_queue.playing.dialog_table.is_convo == true) then
audio_conversation_end(dialog_queue.playing.dialog_handle)
else
audio_stop(dialog_queue.playing.dialog_handle)
end
dialog_queue.playing.dialog_handle = INVALID_CONVERSATION_HANDLE
end
-- Mark the playing dialog as ended
if (dialog_queue.playing.dialog_table ~= nil) then
dialog_queue.playing.dialog_table.ended = true
end
end
-- Thread to process playing a single converation or dialog line (Originally written by Matt Gawalek for Mission 02)
function m21_thread_play_dialog(dialog_table)
-- Add this conversatin to the playing dialog data
dialog_queue.playing.dialog_table = dialog_table
dialog_table.started = true -- it has now started
dialog_table.queued = false
-- Play the dialog
if (dialog_table.is_convo == true) then
-- Load the conversation data
if (dialog_table.load_direct == false) then
if (dialog_table.player ~= nil) then
dialog_queue.playing.dialog_handle = audio_conversation_load_player(dialog_table.name, dialog_table.player)
else
dialog_queue.playing.dialog_handle = audio_conversation_load(dialog_table.name)
end
else
dialog_queue.playing.dialog_handle = audio_conversation_load_direct(dialog_table.name)
end
-- Play the conversation and wait for it to end
audio_conversation_play(dialog_queue.playing.dialog_handle)
audio_conversation_wait_for_end(dialog_queue.playing.dialog_handle)
audio_conversation_end(dialog_queue.playing.dialog_handle)
dialog_queue.playing.dialog_handle = INVALID_CONVERSATION_HANDLE
else
-- Find the persona ID for this line
local persona_id = INVALID_PERSONA_HANDLE
for i, persona in pairs (M21_personas) do
if (persona.name == dialog_table.persona) then
persona_id = persona.persona_id
break
end
end
if (persona_id ~= INVALID_PERSONA_HANDLE) then
-- Play the line
dialog_queue.playing.dialog_handle = audio_play_persona_line_2d(persona_id, dialog_table.name)
else
-- Assume the persona listed is an actual character
dialog_queue.playing.dialog_handle = audio_play_persona_line(dialog_table.persona, dialog_table.name)
end
-- Wait for the line to end
while(audio_is_playing(dialog_queue.playing.dialog_handle) == true) do
thread_yield()
end
end
delay(0.1)
delay(dialog_table.delay)
-- Do some book-keeping
dialog_queue.playing.dialog_handle = INVALID_CONVERSATION_HANDLE
dialog_table.completed = true
dialog_table.ended = true
end
-- Process the dialog queue (should be running the duration of the mission) (Originally written by Matt Gawalek for Mission 02)
function m21_thread_process_dialog()
-- Loop forever
while(true) do
-- Wait until something is added to the queue
while(dialog_queue.size == 0 or thread_check_done(dialog_queue.playing.thread_id) == false) do
thread_yield()
end
-- Play the first dialog from the queue, and then remove it from the qeue
dialog_queue.playing.thread_id = thread_new("m21_thread_play_dialog", dialog_queue.list[0])
for i = 1, dialog_queue.size do
dialog_queue.list[i - 1] = dialog_queue.list[i]
end
dialog_queue.size = dialog_queue.size - 1
-- Wait for the active dialog thread to end
while(thread_check_done(dialog_queue.playing.thread_id) == false) do
thread_yield()
end
dialog_queue.playing.thread_id = INVALID_THREAD_HANDLE
delay(0.2)
end
end
function m21_helper_find_commentary_line_variant(dialog_line_group, desired_speaker, allow_repeat)
local best_line = nil
local index = rand_int(1, #(dialog_line_group))
-- Start looking for a suitable line
for i=1,#(dialog_line_group) do
-- Only look at lines that aren't currently queued
if (dialog_line_group[index].queued == false) then
-- Look for lines that haven't been played before first
if (dialog_line_group[index].started == false) then
best_line = dialog_line_group[index]
-- If this matches the desired speaker, this is as good as it gets
if (desired_speaker == nil or dialog_line_group[index].persona == desired_speaker) then
break
end
elseif (allow_repeat == true) then
-- This is better than no line
if (best_line == nil) then
best_line = dialog_line_group[index]
else
-- If the previous line has already been played also, check if we match the speaker
if (best_line.started == true and dialog_line_group[index].persona == desired_speaker) then
best_line = dialog_line_group[index]
end
end
end
end
-- Increment the index
index = index + 1
if (index > #(dialog_line_group)) then
index = 1
end
end
return best_line
end
function m21_helper_play_interrupting_commentary_line(dialog_line_group, allow_repeat, break_out, break_in, delay, play_immediate)
if (allow_repeat == nil) then
allow_repeat = false
end
if (break_out == nil) then
break_out = true
end
if (break_in == nil) then
break_in = true
end
if (delay == nil) then
delay = 0.0
end
if (play_immediate == nil) then
play_immediate = false
end
-- Find a line variant to play
local line_variant = nil
local break_out_line = nil
local break_in_line = nil
-- Check if there is any dialog currently playing
if (thread_check_done(dialog_queue.playing.thread_id) == false) then
-- If the line is part of a conversation or cannot be interrupted, then just return without playing this line
if (dialog_queue.playing.dialog_table.is_convo == true or dialog_queue.playing.dialog_table.can_interrupt == false) then
return
end
-- If we're not playing immediatly, check to see if we can interrupt the next dialog on the queue (this keeps interrupts from piling up)
if (play_immediate == false and dialog_queue.size ~= 0 and (dialog_queue.list[0].is_convo == true or dialog_queue.list[0].can_interrupt == false)) then
return
end
-- We want to play the line on whoever isn't talking
local speaker_order = { }
if (dialog_queue.playing.dialog_table.persona == "Zach") then
-- Try Bobby first, and then Zach
speaker_order = { "Bobby", "Zach" }
else
-- Try Zach first, and then Bobby
speaker_order = { "Zach", "Bobby" }
end
-- Try to find some lines to play
for i, speaker in pairs(speaker_order) do
-- Try to find lines for Bobby first
line_variant = m21_helper_find_commentary_line_variant(dialog_line_group, speaker, allow_repeat)
if (break_out == true) then
break_out_line = m21_helper_find_commentary_line_variant(M21_dialog_lines.commentater_break_out, speaker, true)
end
if (break_in == true) then
break_in_line = m21_helper_find_commentary_line_variant(M21_dialog_lines.commentater_break_in, speaker, true)
end
-- If we found two suitable lines, then stop looking
if (line_variant ~= nil and (break_out == false or break_out_line ~= nil) and (break_in == false or break_in_line ~= nil)) then
break
end
line_variant = nil
break_out_line = nil
break_in_line = nil
end
-- If we couldn't find suitable lines, then just return
if (line_variant == nil or (break_out == true and break_out_line == nil) or (break_in == true and break_in_line == nil)) then
return
end
else
-- Don't need to worry about interrupting a line, just find a variant to play
line_variant = m21_helper_find_commentary_line_variant(dialog_line_group, nil, allow_repeat)
end
if (play_immediate == true) then
-- Play the break out line if we have one
if (break_out_line ~= nil) then
m21_helper_dialog_play(break_out_line, M21_CONVO_PLAY_IMMEDIATE, 0.0)
end
-- Play the break in line if we have one
-- (this goes before the actual line varient, since playing next is pushing the line at the front of the queue)
if (break_in_line ~= nil) then
m21_helper_dialog_play(break_in_line, M21_CONVO_PLAY_NEXT, delay)
delay = 0.0
end
-- Play the line variant if we have one
if (line_variant ~= nil) then
if (break_out == true) then
m21_helper_dialog_play(line_variant, M21_CONVO_PLAY_NEXT, delay)
else
m21_helper_dialog_play(line_variant, M21_CONVO_PLAY_IMMEDIATE, delay)
end
end
else
-- Play the break in line if we have one
-- (this goes before the actual line varient, since playing next is pushing the line at the front of the queue)
if (break_in_line ~= nil) then
m21_helper_dialog_play(break_in_line, M21_CONVO_PLAY_NEXT, delay)
delay = 0.0
end
-- Play the line variant if we have one
if (line_variant ~= nil) then
m21_helper_dialog_play(line_variant, M21_CONVO_PLAY_NEXT, delay)
end
-- Play the break out line if we have one
if (break_out_line ~= nil) then
m21_helper_dialog_play(break_out_line, M21_CONVO_PLAY_NEXT, 0.0)
end
end
end
-- Hide or unhide the hud
--
-- hide: TRUE to hide the HUD, FALSE to unhide it
function m21_helper_hide_hud(hide)
if (hide == true) then
if (M21_hud_states.hide_hud == -1) then
M21_hud_states.hide_hud = hud_display_create_state()
hud_display_set_element(M21_hud_states.hide_hud, HUD_ELEM_MINIMAP, HUD_FADE_HIDDEN)
hud_display_set_element(M21_hud_states.hide_hud, HUD_ELEM_WEAPONS, HUD_FADE_HIDDEN)
hud_display_commit_state(M21_hud_states.hide_hud)
end
else
if (M21_hud_states.hide_hud ~= -1) then
hud_display_remove_state(M21_hud_states.hide_hud)
M21_hud_states.hide_hud = -1
end
end
end
-- Helper to restore Killbane back to his fighting state in the ring
function m21_helper_setup_killbane_ring_fighting()
ai_clear_scripted_action(M21_characters.killbane)
set_ignore_ai_flag(M21_characters.killbane, false)
ai_add_enemy_target(M21_characters.killbane, player_in_ring, ATTACK_NOW_NEVER_LOSE, true)
-- Register a callback for when Killbane is damaged
on_take_damage("m21_killbane_damaged", M21_characters.killbane)
on_revived("m21_killbane_revived", M21_characters.killbane)
end
-- Helper function to set the correct synced animation between the player and Killbane
function m21_helper_set_player_headlock_anim(player)
if (character_get_gender(LOCAL_PLAYER) == GENDER_TYPE_MALE) then
action_play_synced_state(player_in_ring, M21_characters.killbane, "MB HeadLock")
else
action_play_synced_state(player_in_ring, M21_characters.killbane, "MB HeadLock Female")
end
end
-- Play the firework VFX at the end of the entry tunnels to the arena
function m21_play_arena_entrance_fireworks(group_table)
if (group_table ~= nil) then
for i, navpoint in pairs(group_table.effect_navpoints) do
effect_play(navpoint)
end
else
for i, navpoint in pairs(M21_navpoints.firework_navs) do
effect_play(navpoint)
end
end
end
-- *************************
--
-- Callback functions
--
-- *************************
-- Thug has died, update the count and check for remaing thugs
--
-- enemy: (string) name of the npc to move
--
function m21_killbane_thug_enemy_killed(npc)
-- Make sure to stop the npc's thread.
for side, enemy in pairs(M21_groups.fight_club_phase_reinforcements.members) do
if (npc == enemy) then
thread_kill(M21_threads.Killbane_reinforcements_handles[side])
M21_threads.Killbane_reinforcements_handles[side] = INVALID_THREAD_HANDLE
end
end
killbane_thug_enemies_living = killbane_thug_enemies_living - 1
m21_check_for_remaining_thugs()
end
-- Player successfully brought Killbane to a corner
--
-- char_name: (string) name of the player that hit the trigger
-- trigger_name: (string) name of the trigger hit
--
function m21_killbane_beatup_callback(char_name, trigger_name)
if (char_name == player_in_ring) then
-- Disable the trigger
m21_remove_killbane_beatup_trigger()
-- Kill the thread processing the player mounted on Killbane
if (thread_check_done(M21_threads.Killbane_mounted_processing) == false) then
thread_kill(M21_threads.Killbane_mounted_processing)
M21_threads.Killbane_mounted_processing = INVALID_THREAD_HANDLE
end
-- Move the player and killbane into player
--player_controls_disable(player_in_ring)
--move_to(player_in_ring, M21_navpoints.killbane_beatup_trigger_points[enabled_trigger_index], 1, true)
--player_controls_enable(player_in_ring)
-- Mark the ride as a success, and dismount the player
M21_killbane_ride_success = true
human_riding_trigger_end(player_in_ring)
-- Initialize the player and Killbane for the QTE
character_set_never_fall(player_in_ring, true)
character_allow_ragdoll(player_in_ring, false)
character_set_never_fall(M21_characters.killbane, true)
-- Register a callback so we know when to play the commentary lines
M21_corner_qte_cb_count = 1 -- reset the crowd counting index
on_qte_animation_trigger("m21_corner_qte_intermediary_cb")
-- Start the QTE
Killbane_should_be_in_ring = false -- disable this now, so we don't try to teleport Killbane back into the ring as he flies out
local qte_name
if (killbane_wave == 1) then
qte_name = "Mission21_CORNERQTE1"
elseif (killbane_wave == 2) then
qte_name = "Mission21_CORNERQTE2"
else
qte_name = "Mission21_CORNERQTE3"
end
qte_start(player_in_ring, qte_name, "m21_corner_qte_complete_cb", M21_characters.killbane, false, M21_navpoints.killbane_beatup_trigger_points[enabled_trigger_index])
end
end
-- Player mounted killbane, enable the corresponding corner trigger
--
function m21_killbane_mounted_callback()
m21_enable_coop_tag_triggers(DISABLE)
m21_set_killbane_beatup_trigger()
set_attack_player_flag(M21_characters.killbane, false)
-- Reset the successful ride flag
M21_killbane_ride_success = false
-- Start a thread to process the player mounted on Killbane
M21_threads.Killbane_mounted_processing = thread_new("m21_killbane_mounter_process_thread")
-- Start the crowd cheers for the player riding Killbane
audio_object_post_event(M21_audio_events.ride_killbane_start, nil, nil, LOCAL_PLAYER)
end
-- Player was dismounted from Killbane, check to see if they were dismounted early
--
function m21_killbane_dismounted_callback()
-- Kill the thread processing the player mounted on Killbane
if (thread_check_done(M21_threads.Killbane_mounted_processing) == false) then
thread_kill(M21_threads.Killbane_mounted_processing)
M21_threads.Killbane_mounted_processing = INVALID_THREAD_HANDLE
end
-- Clean-up the corner trigger
if (M21_killbane_ride_success == false) then
m21_remove_killbane_beatup_trigger()
end
enabled_trigger_index = 0
-- Stop the crowd cheers for the player riding Killbane
audio_object_post_event(M21_audio_events.ride_killbane_stop, nil, nil, LOCAL_PLAYER)
delay(1) -- let the animations blend out
m21_helper_setup_killbane_ring_fighting()
if (M21_killbane_ride_success == false) then
-- Play some dissapointed cheers
audio_object_post_event(M21_audio_events.crowd_disappoint, nil, nil, LOCAL_PLAYER)
end
end
-- The player entered the trigger region needed to enter the ring to fight Killbane
--
function m21_player_enter_ring(player)
-- Disable the trigger
trigger_enable(M21_triggers.player_enter_ring, DISABLE)
on_trigger("", M21_triggers.player_enter_ring)
marker_remove_trigger(M21_triggers.player_enter_ring, SYNC_ALL)
if (player == REMOTE_PLAYER) then
player_in_ring = REMOTE_PLAYER
player_outside_ring = LOCAL_PLAYER
end
Player_entered_ring = true
end
-- Callback for the ref distractor on_take_damage. These npcs need to ragdoll and reduce the count of distractors on the ring.
--
-- npc_name: (string) name of the ref distractor that was hit by a player
--
function m21_distractor_hit(npc_name)
on_take_damage("", npc_name)
for i, npc in pairs(distractors_on_ring) do
if (npc == npc_name) then
distractors_on_ring[i] = ""
end
end
-- The crowd boos
audio_object_post_event(M21_audio_events.boo_short, nil, nil, LOCAL_PLAYER)
set_script_animation_state(npc_name, nil)
character_ragdoll(npc_name)
character_kill(npc_name)
end
-- Callback for the reinforcements that come in during the Killbane fight
-- This allows the player to knock the npcs off while they climb onto the ring
--
-- npc_name: name of the reinforcement
--
function m21_killbane_reinforcement_hit(npc_name)
character_ragdoll(npc_name, LUCHADORE_RAGDOLL_TIME, 5.0)
human_gravity_enable(npc_name, true)
character_collision_enable(npc_name, true)
character_kill(npc_name)
on_take_damage("",npc_name)
end
-- Callback for when the player reaches Angel
--
function m21_player_reached_angel(player)
on_trigger("", M21_triggers.player_reached_angel)
trigger_enable(M21_triggers.player_reached_angel, DISABLE)
marker_remove(M21_characters.angel)
-- Move the player into position
player_movement_disable(player)
player_actions_disable(player)
-- Disable always combat ready and remove the chainsaw
character_set_always_combat_ready(player, false)
inv_weapon_remove_temporary(player, "chainsaw")
--[[
move_to(player, M21_navpoints.player_reacherd_angel, 1)
-- Check if they're ready (checks that they aren't dead, ragdolled
local ready = false
while(ready == false) do
thread_yield()
ready = true
if (character_is_ready(player) == false) then
ready = false
end
if (character_playing_combat_move(player) == true) then
ready = false
end
if (character_is_jumping(player) == true) then
ready = false
end
end
-- Change the camera to look at the PC and Angel
camera_look_through(M21_navpoints.lookat_angel, 0.6)
crouch_start(player, true) -- set as scripted crouch
action_play(player, "crouch", "", false, 0.5, true, true, M21_navpoints.player_reacherd_angel)
--]]
-- The crowd starts cheering Angel's name
audio_object_post_event(M21_audio_events.angel_long, nil, nil, LOCAL_PLAYER)
-- Play the conversation and block until it is complete
m21_helper_dialog_play(M21_conversations.talk_to_angel, M21_CONVO_PLAY_IMMEDIATE, 0.0, player)
-- Wait for end of the angel conversation
while (m21_helper_dialog_check_done(M21_conversations.talk_to_angel) == false) do
thread_yield()
end
-- Stand the player up and re-enable their controls
--crouch_stop(player)
player_movement_enable(player)
player_actions_enable(player)
-- Return the camera to the player
camera_end_look_through(false)
-- Make the player always combat ready again
character_set_always_combat_ready(player, true)
player_reached_angel = true
end
-- Callback for angel's death during the "defend the ring" portion of the fight
--
function m21_angel_died_1()
m21_cleanup_defend_the_ring()
mission_end_failure("m21", "m21_obj_angel_died")
end
-- Callback for angel's death during the "defend angel" portion of the fight
--
function m21_angel_died_2()
m21_cleanup_defend_angel()
mission_end_failure("m21", "m21_obj_angel_died")
end
-- Callback when a player picks up a weapon
--
function m21_player_picked_up_weapon_cb(player, weapon)
-- If this is the dildo bat, then play some commentary
if (weapon == "WP_baseball_bat") then
m21_helper_dialog_play(M21_conversations.pickup_dildo, M21_CONVO_PLAY_IMMEDIATE, 0.0, player)
end
-- Remove the weapon pickup callback
on_weapon_pickup("", LOCAL_PLAYER)
if (coop_is_active() == true) then
on_weapon_pickup("", REMOTE_PLAYER)
end
end
-- Callback when one of the intermediary triggers is triggered from a QTE animation
--
-- node_idx: Index of the current QTE node
function m21_killswitch_intermediary_cb(node_idx)
if (node_idx == 1) then
-- The player failed... the Killswitch landed
local idx = rand_int(1, #M21_dialog_lines.qte_failed)
m21_helper_dialog_play(M21_dialog_lines.qte_failed[idx], M21_CONVO_PLAY_IMMEDIATE, 0.0)
--m21_helper_play_interrupting_commentary_line(M21_dialog_lines.qte_failed, true, false, true, 0.0, true)
elseif (node_idx == 2) then
-- The player successfully dodged the Killswitch, play some success dialog
if (M21_conversations.killswitch_blocked_01.started == false) then
m21_helper_dialog_play(M21_conversations.killswitch_blocked_01, M21_CONVO_PLAY_IMMEDIATE, 0.0)
elseif (M21_conversations.killswitch_blocked_02.started == false) then
m21_helper_dialog_play(M21_conversations.killswitch_blocked_02, M21_CONVO_PLAY_IMMEDIATE, 0.0)
elseif (M21_conversations.killswitch_blocked_03.started == false) then
m21_helper_dialog_play(M21_conversations.killswitch_blocked_03, M21_CONVO_PLAY_IMMEDIATE, 0.0)
thread_yield()
M21_conversations.killswitch_blocked_01.started = false
M21_conversations.killswitch_blocked_02.started = false
M21_conversations.killswitch_blocked_03.started = false
end
end
end
function m21_killswitch_qte_complete_cb(success)
-- Remove the callback
on_qte_animation_trigger("")
if success then
-- NOTHING TO DO HERE
else
m21_helper_setup_killbane_ring_fighting()
end
end
-- Callback when one of the intermediary triggers is triggered from a QTE animation
--
-- node_idx: Index of the current QTE node
function m21_corner_qte_intermediary_cb(node_idx)
-- Play some dialog
if (killbane_wave == 1) then
if (node_idx == 0) then
-- Crowd counts
audio_object_post_event(M21_audio_events.crowd_count[M21_corner_qte_cb_count], nil, nil, LOCAL_PLAYER)
elseif (node_idx == 1) then
if (M21_corner_qte_cb_count == 11) then
-- Play some success commentary
for i=#M21_dialog_lines.killbane_back_in_ring_01, 1, -1 do
m21_helper_dialog_play(M21_dialog_lines.killbane_back_in_ring_01[i], M21_CONVO_PLAY_NEXT, 0.0)
end
m21_helper_dialog_play(M21_dialog_lines.killbane_out_of_ring_01[1], M21_CONVO_PLAY_NEXT, 5.0)
m21_helper_dialog_play(M21_dialog_lines.commentater_break_out[1], M21_CONVO_PLAY_IMMEDIATE)
elseif (M21_corner_qte_cb_count == 12) then
-- Do some fireworks
m21_play_arena_entrance_fireworks()
end
elseif (node_idx == 2) then
-- Play a failure line
local idx = rand_int(1, #M21_dialog_lines.qte_failed)
m21_helper_dialog_play(M21_dialog_lines.qte_failed[idx], M21_CONVO_PLAY_IMMEDIATE, 0.0)
end
elseif (killbane_wave == 2) then
if (node_idx == 1) then
if (M21_corner_qte_cb_count == 1) then
-- Player kicked killbane in the nuts
m21_helper_dialog_play(M21_dialog_lines.exclamation[2], M21_CONVO_PLAY_IMMEDIATE)
else
-- Player's getting ready to drop a flying elbow
m21_helper_dialog_play(M21_dialog_lines.exclamation[3], M21_CONVO_PLAY_IMMEDIATE, 2.0)
end
elseif (node_idx == 2) then
-- Play a failure line
local idx = rand_int(1, #M21_dialog_lines.qte_failed)
m21_helper_dialog_play(M21_dialog_lines.qte_failed[idx], M21_CONVO_PLAY_IMMEDIATE, 0.0)
elseif (node_idx == 3) then
if (M21_corner_qte_cb_count == 3) then
m21_helper_dialog_play(M21_dialog_lines.exclamation[4], M21_CONVO_PLAY_IMMEDIATE, 2.0)
m21_helper_dialog_play(M21_dialog_lines.exclamation[5], M21_CONVO_PLAY_NEXT)
elseif (M21_corner_qte_cb_count == 4) then
-- Play some success commentary
m21_helper_dialog_play(M21_conversations.killbane_out_of_ring_02, M21_CONVO_PLAY_IMMEDIATE)
else
-- Do some fireworks
m21_play_arena_entrance_fireworks()
end
end
elseif (killbane_wave == 3) then
if (node_idx == 0) then
-- Crowd counts
audio_object_post_event(M21_audio_events.crowd_count[M21_corner_qte_cb_count], nil, nil, LOCAL_PLAYER)
elseif (node_idx == 3) then
if (M21_corner_qte_cb_count == 5) then
-- Play some camera flashes
for i, nav in pairs(M21_navpoints.camera_flash_navs) do
effect_play(nav)
end
elseif (M21_corner_qte_cb_count == 6) then
-- Do some fireworks
m21_play_arena_entrance_fireworks()
else
-- Player lands the elbow
m21_helper_dialog_play(M21_dialog_lines.exclamation[1], M21_CONVO_PLAY_IMMEDIATE)
end
elseif (node_idx == 2) then
-- Play a failure line
m21_helper_play_interrupting_commentary_line(M21_dialog_lines.qte_failed, true)
end
end
M21_corner_qte_cb_count = M21_corner_qte_cb_count + 1
end
-- Callback for the corner qtes
--
-- success: (bool) true - if the player was successful, false - if they failed
function m21_corner_qte_complete_cb(success)
-- Remove the callback
on_qte_animation_trigger("")
-- Clear a bunch of flags we set
character_set_never_fall(player_in_ring, false)
character_allow_ragdoll(player_in_ring, true)
character_set_never_fall(M21_characters.killbane, false)
if success then
m21_killbane_qte_beatup_finished()
else
-- Killbane won, set everything back up
m21_helper_setup_killbane_ring_fighting()
end
m21_enable_coop_tag_triggers(ENABLE)
end
-- Killbane damaged callback
-- When Killbane takes damage, figure out what caused it, and restore his hit points
--
-- killbane_name: (string) name of killbane
-- attacker_name: (string) name of the attacker
-- percent_health: (float) what the attack left killbane at
-- explosion: (bool) explosion?
-- melee: (bool) melee attack?
--
function m21_killbane_damaged(killbane_name, attacker_name, percent_health, explosion, melee)
local killbane_hit = false
if (attacker_name ~= nil) then
if(not melee) then
-- thrown wieldable prop
--audio_object_post_event(M21_audio_events.crowd_cheer_mid, nil, nil, LOCAL_PLAYER)
killbane_hit = true
else
-- melee weapon hit
local weapon_name = inv_item_get_equipped_item(attacker_name)
if (weapon_name ~= nil) then
killbane_hit = true
end
end
end
if (killbane_hit == true) then
-- Play a random Killbane flinch animation
action_play_do(M21_characters.killbane, M21_animations.killbane_flinches[rand_int(1, #M21_animations.killbane_flinches)])
-- Increment the times hit count
num_times_killbane_hit_by_weapon = num_times_killbane_hit_by_weapon + 1
else
-- If Killbane blocked it, the crowd is shocked
--audio_object_post_event(M21_audio_events.crowd_shocked, nil, nil, LOCAL_PLAYER)
end
-- Killbane can't die, refill his hp
set_current_hit_points(M21_characters.killbane, get_max_hit_points(M21_characters.killbane))
end
-- Callback when Killbane is revived from the downed state
function m21_killbane_revived()
m21_helper_setup_killbane_ring_fighting()
turn_invulnerable(M21_characters.killbane)
end
-- Callback for when the player takes damage while in the ring
--
-- player_name: (string) name of the player damaged
-- attacker: (string) name of the attacker
-- damage_amt: (float) amount of hp remaining after attack
-- from_expo: (boolean) damage came from an explosion
-- from_melee: (boolean) damage came from a melee attack
--
function m21_player_damaged_in_ring_cb(player_name, attacker, damage_amt, from_exp, from_melee)
if (attacker == M21_characters.killbane and from_melee == true) then
audio_object_post_event(M21_audio_events.boo_short, nil, nil, LOCAL_PLAYER)
end
end
-- Callback for when the player picks up a weapon (prop) while in the ring
--
-- player_name: (string) name of the player that picked up the prop
function m21_player_got_prop_in_ring_cb(player_name)
audio_object_post_event(M21_audio_events.crowd_cheer_low, nil, nil, LOCAL_PLAYER)
end
-- Callback for when a wieldable prop is created
--
-- defend_ring: TRUE if the prop was created outside the ring, FALSE if it was created for inside the ring
function m21_wieldable_prop_created_cb(outside_ring)
if (outside_ring == true) then
--[[
if (rand_int(1, 4) ~= 1) then
return
end
m21_helper_play_interrupting_commentary_line(M21_dialog_lines.prop_call_out, false, true, true)
--]]
else
if (--[[M21_prop_called_out == false or --]](thread_check_done(dialog_queue.playing.thread_id) and dialog_queue.size == 0)) then
M21_prop_called_out = true
m21_helper_play_interrupting_commentary_line(M21_dialog_lines.prop_in_ring, true, true, true, 0.0, true)
--delay(2.0)
--audio_play_persona_line(LOCAL_PLAYER, "M21_Should_Pick_Up_Prop")
end
end
end
-- Callback for when the player's prop is destroyed
--
-- player_name: (string) name of the player who's prop was destroyed
function m21_player_prop_destroyed_cb(player_name)
-- Play some dissapointed cheers
audio_object_post_event(M21_audio_events.crowd_disappoint, nil, nil, LOCAL_PLAYER)
end
function m21_cb_tag_partner_outside_ring(triggerer, trigger_name)
if (triggerer == player_outside_ring) then
-- Disable the trigger
trigger_enable(M21_triggers.tag_trigger_outside, DISABLE)
ingame_effect_remove_trigger(M21_triggers.tag_trigger_outside, SYNC_ALL)
-- Clear their inventory
inv_item_remove_in_slot( "single_use", player_outside_ring )
-- Move to the correct place
player_movement_disable(player_outside_ring)
player_actions_disable(player_outside_ring)
turn_to(player_outside_ring, M21_navpoints.player_outside_ring, true) -- turn to face ring
-- Play the animation to get up onto the ring
human_gravity_enable(player_outside_ring, false)
character_collision_enable(player_outside_ring, false)
set_animation_state(player_outside_ring, "m21_plym_tageTeam_rope_idle")
action_play(player_outside_ring, M21_animations.player_jump_on_ring, "", false, 0.6, true, true, M21_navpoints.player_outside_ring, M21_navpoints.player_inside_ring_dest)
-- The player is now on the ring
player_ready_to_tag_in = true
trigger_enable(M21_triggers.tag_trigger_inside, ENABLE)
ingame_effect_add_trigger(M21_triggers.tag_trigger_inside, INGAME_EFFECT_LOCATION, sync_from_player(player_in_ring))
message("M21_HELP_TEXT_WATING_TO_TAG", 5.0, true, sync_from_player(player_outside_ring))
hud_prompt(player_outside_ring, "M21_USE_TEXT_LEAVE_RING_SIDE", "m21_cb_player_leaving_ring_side")
end
end
-- On_trigger call back for the trigger inside the ring, this will cause a swap of the host and remote players
function m21_cb_tag_partner_inside_ring(triggerer, trigger_name)
if (triggerer == player_in_ring) then
-- Disable the trigger
trigger_enable(M21_triggers.tag_trigger_inside, DISABLE)
ingame_effect_remove_trigger(M21_triggers.tag_trigger_inside, SYNC_ALL)
-- Remove the HUD prompt
hud_prompt_clear(player_outside_ring)
-- Clear their inventory
inv_item_remove_in_slot( "single_use", player_in_ring )
-- Make Killbane not attack the player's
set_attack_player_flag(M21_characters.killbane, false)
-- Disable the player's movement in the ring and move them into position
player_actions_disable(player_in_ring)
player_movement_disable(player_in_ring)
-- Player that was inside the ring no cannot interact with downed humans
character_disable_human_downed_interactions(player_in_ring, true)
turn_to(player_in_ring, M21_navpoints.player_inside_ring, true) -- turn to face outside of the ring
audio_play_persona_line(player_in_ring, "M21_Tag_In_Partner")
-- Disable gravity and collision on the player's so we can force them through the ropes
human_gravity_enable(player_outside_ring, false)
human_gravity_enable(player_in_ring, false)
character_collision_enable(player_outside_ring, false)
character_collision_enable(player_in_ring, false)
character_prevent_bumping(player_outside_ring, true)
character_prevent_bumping(player_in_ring, true)
delay(0.3)
-- Play the synced tag animation (well not synced really... since they're both players)
action_play_non_blocking(player_outside_ring, M21_animations.player_tag_in, "", false, true, true, M21_navpoints.player_inside_ring_dest, M21_navpoints.player_outside_ring_dest)
action_play_non_blocking(player_in_ring, M21_animations.player_tag_out, "", false, true, true, M21_navpoints.player_inside_ring, M21_navpoints.player_inside_ring_dest)
-- Wait for the animations to finish
delay(0.5)
clear_animation_state(player_outside_ring)
set_animation_state(player_in_ring, "m21_plym_tageTeam_rope_idle")
while(action_play_is_finished(REMOTE_PLAYER) == false) do
thread_yield()
end
while(action_play_is_finished(LOCAL_PLAYER) == false) do
thread_yield()
end
-- Turn gravity and collision back on
character_collision_enable(player_outside_ring, true)
human_gravity_enable(player_outside_ring, true)
character_prevent_bumping(player_outside_ring, false)
-- Check to make sure the player that was outside the ring made it into the ring correctly
if (object_is_in_trigger(M21_triggers.ring_trigger, player_outside_ring) == false) then
teleport(player_outside_ring, M21_navpoints.player_outside_ring_dest)
end
if (object_is_in_trigger(M21_triggers.ring_trigger, player_in_ring) == true) then
teleport(player_in_ring, M21_navpoints.player_inside_ring_dest)
end
-- Re-enable the control for the player that was outside the ring
player_actions_enable(player_outside_ring)
player_movement_enable(player_outside_ring)
-- Player that was outside of the ring can now interact with downed humans
character_disable_human_downed_interactions(player_outside_ring, false)
-- Update the callbacks for the player in the ring
on_take_damage("", player_in_ring)
on_weapon_pickup("", player_in_ring)
on_take_damage("m21_player_damaged_in_ring_cb", player_outside_ring)
on_weapon_pickup("m21_player_got_prop_in_ring_cb", player_outside_ring)
-- Do the swap
local swap_buffer = player_outside_ring
player_outside_ring = player_in_ring
player_in_ring = swap_buffer
-- Killbane can attack the player in the ring now
set_attack_player_flag(M21_characters.killbane, true)
ai_add_enemy_target(M21_characters.killbane, player_in_ring, ATTACK_NOW_NEVER_LOSE, true)
-- Enable the trigger again
trigger_enable(M21_triggers.tag_trigger_inside, ENABLE)
ingame_effect_add_trigger(M21_triggers.tag_trigger_inside, INGAME_EFFECT_LOCATION, sync_from_player(player_in_ring))
-- Tell the player that's now outside the ring what's up
message("M21_HELP_TEXT_WATING_TO_TAG", 5.0, true, sync_from_player(player_outside_ring))
hud_prompt(player_outside_ring, "M21_USE_TEXT_LEAVE_RING_SIDE", "m21_cb_player_leaving_ring_side")
end
end
function m21_cb_player_leaving_ring_side()
-- Remove the HUD prompt
hud_prompt_clear(player_outside_ring)
-- Disable the trigger inside the ring
trigger_enable(M21_triggers.tag_trigger_inside, DISABLE)
ingame_effect_remove_trigger(M21_triggers.tag_trigger_inside, SYNC_ALL)
-- Clear their animation state
clear_animation_state(player_outside_ring)
-- Move off the ring
--move_to(player_outside_ring, M21_navpoints.player_outside_ring, 1, true)
-- Turn on gravity and collision gain
character_collision_enable(player_outside_ring, true)
human_gravity_enable(player_outside_ring, true)
-- Re-enable the control for the player outside the ring
player_actions_enable(player_outside_ring)
player_movement_enable(player_outside_ring)
-- Enable the trigger outside the ring
trigger_enable(M21_triggers.tag_trigger_outside, ENABLE)
ingame_effect_add_trigger(M21_triggers.tag_trigger_outside, INGAME_EFFECT_LOCATION, sync_from_player(player_outside_ring))
end
-- *************************
--
-- Thread functions
--
-- *************************
-- Direct an npc from a starting entrance into the ring
--
-- npc: (string) name of the npc to move
-- side: (int) which side to enter from, determins which navpoints to use
--
function m21_killbane_reinforcements_thread(npc, side)
set_ignore_ai_flag(npc, true)
-- Move into position
if (m21_move_script_npc_to(npc, M21_navpoints.npc_harass_points_out_ring[side], true, false) == false) then
character_kill(npc)
return
end
character_prevent_bumping(npc, true)
character_prevent_flinching(npc, true)
-- Don't start entering the ring if the player will block our destination (causes the NPCs to get stuck in the ropes, and other undesirable behaviors)
local elapsed_time = 0
while(get_dist(player_in_ring, M21_navpoints.npc_harass_points_in_ring[side]) < 1.0) do
elapsed_time = elapsed_time + get_frame_time()
if (elapsed_time > 7.0) then
break
end
thread_yield()
end
-- Set their last valid ragdoll position to inside the ring
character_ragdoll_set_last_valid_position(npc, M21_navpoints.npc_harass_points_in_ring[side], true) -- clear out the queue
-- Start the enter animation
human_gravity_enable(npc, false)
character_collision_enable(npc, false)
action_play(npc, M21_animations.luchadore_enter_ring, M21_animations.luchadore_enter_ring, false, 0.52, true, true, M21_navpoints.npc_harass_points_out_ring[side], M21_navpoints.npc_harass_points_in_ring[side])
if (get_dist(player_in_ring, M21_navpoints.npc_harass_points_in_ring[side]) < 1.0) then
character_ragdoll(player_in_ring, 750)
thread_yield()
end
-- Turn gravity and collision back on, and register a callback to kill the player until they are safely in the ring
on_take_damage("m21_killbane_reinforcement_hit", npc)
character_collision_enable(npc, true)
human_gravity_enable(npc, true)
-- Wait until the animation is far enough along that they are safely within the ring
while(action_play_is_finished(npc, 0.75) == false) do
thread_yield()
end
-- Remove our callback that was forcefully killing the guy
on_take_damage("", npc)
delay(0.25)
-- Do a safety check to ensure that the NPC actually made it into the ring
if (character_is_dead(npc) == false and object_is_in_trigger(M21_triggers.ring_trigger, npc) == false) then
-- Just teleport them into the ring to make sure that we don't soft lock the mission
teleport(npc, M21_navpoints.npc_harass_points_in_ring[side])
thread_yield()
end
set_ignore_ai_flag(npc, false)
character_prevent_flinching(npc, false)
ai_add_enemy_target(npc, player_in_ring, 2)
-- Make sure the Luchadore stays in the ring - if they leave kill them to prevent a soft crash
while(true) do
if (character_is_dead(npc) == true) then
return
elseif (object_is_in_trigger(M21_triggers.ring_trigger, npc) == false) then
character_kill(npc)
end
thread_yield()
end
end
-- Thread that will move Killbane to different points outside of the ring
--
function m21_killbane_pacing_thread()
local closest_nav = m21_find_closest_killbane_enter_ring_nav()
-- Move into position
m21_move_script_npc_to(M21_characters.killbane, closest_nav, false, false)
-- Turn off AI, and set Killbane's animation state
set_ignore_ai_flag(M21_characters.killbane, true) -- turned back off when the thread is killed
set_script_animation_state(M21_characters.killbane, M21_animations.killbane_pacing)
delay(4.0)
m21_helper_play_interrupting_commentary_line(M21_dialog_lines.killbane_posturing, true, false, true)
end
-- Process the ref's AI
function m21_process_ref_ai_thread()
while(true) do
delay(0.1)
if (ref_target == "") then
-- Ref doesn't have a target, see if he should
local distractor_idx = 0
for i, distractor in pairs(distractors_on_ring) do
if (distractor ~= "" and character_is_dead(distractor) == false and check_script_animation_state(distractor, M21_animation_state.luchadore_ring_stand)) then
ref_target = distractor
distractor_idx = i
break
end
end
-- Do we still not have a taget?
if (ref_target ~= "") then
-- Check if the ref needs to move to an intermediary point to avoid running through the fight
local intermediary_point = 0
if (ref_location_idx == 1) then
if (distractor_idx == 2) then
intermediary_point = 4
end
elseif (ref_location_idx == 2) then
if (distractor_idx == 1) then
intermediary_point = 3
end
elseif (ref_location_idx == 3 or ref_location_idx == 0) then
if (distractor_idx == 4) then
intermediary_point = 1
end
elseif (ref_location_idx == 4) then
if (distractor_idx == 3) then
intermediary_point = 1
end
end
ref_location_idx = distractor_idx
-- Clear the ref's animation state
set_script_animation_state(M21_characters.ref, nil)
-- Move to an intermediary target if necessary
if (intermediary_point ~= 0 ) then
-- Move towards the intermediary point
ai_do_scripted_move(M21_characters.ref, M21_navpoints.ref_points[intermediary_point], true)
while(ai_scripted_action_is_processing(M21_characters.ref) == true and get_dist(M21_characters.ref, M21_navpoints.ref_points[intermediary_point]) > 3.0) do
thread_yield()
end
end
-- Move to go yell at the target
m21_move_script_npc_to(M21_characters.ref, M21_navpoints.ref_points[distractor_idx], true, true)
turn_to(M21_characters.ref, M21_navpoints.ref_points[distractor_idx], true)
set_script_animation_state(M21_characters.ref, M21_animation_state.ref_distracted)
else
if (ref_location_idx ~= 0) then
set_script_animation_state(M21_characters.ref, nil)
if (ref_location_idx == 4) then
-- Move towards the intermediary point
ai_do_scripted_move(M21_characters.ref, M21_navpoints.ref_points[2], true)
while(ai_scripted_action_is_processing(M21_characters.ref) == true and get_dist(M21_characters.ref, M21_navpoints.ref_points[2]) > 3.0) do
thread_yield()
end
end
ref_location_idx = 0
m21_move_script_npc_to(M21_characters.ref, M21_navpoints.ref_standing_point, true, false)
turn_to(M21_characters.ref, M21_characters.killbane)
end
set_script_animation_state(M21_characters.ref, M21_animation_state.ref_watch)
end
else
-- Check to make sure out target is still valid
local found = false
for i, distractor in pairs(distractors_on_ring) do
if (distractor == ref_target) then
found = true
end
end
if (found == false) then
ref_target = ""
end
end
end
end
function m21_killbane_mounter_process_thread()
delay(KILLBANE_RIDE_MAX_TIME)
human_riding_trigger_end(player_in_ring)
end
function m21_thread_enforce_character_locations()
while(true) do
-- Make sure the player in the ring is ACTUALLY in the ring
if (action_play_is_finished(player_in_ring, 1.0) and object_is_in_trigger(M21_triggers.ring_trigger, player_in_ring) == false) then
-- They got out of the ring somehow, teleport them back in
teleport(player_in_ring, M21_navpoints.player_fight_start[1])
repeat thread_yield() until teleport_check_done(player_in_ring)
end
-- If coop is active, we need to make sure the player outside of the ring is ACTUALLY outside of the ring
if (coop_is_active() == true) then
if (action_play_is_finished(player_outside_ring, 1.0) and object_is_in_trigger(M21_triggers.ring_trigger, player_outside_ring) == true) then
-- They got into the ring somehow, teleport them back out
teleport(player_outside_ring, M21_navpoints.player_fight_start[2])
repeat thread_yield() until teleport_check_done(player_outside_ring)
end
end
-- If Killbane should be in the ring, make sure he's ACTUALLY inside the ring
if (Killbane_should_be_in_ring == true) then
if (action_play_is_finished(M21_characters.killbane, 1.0) and object_is_in_trigger(M21_triggers.ring_trigger, M21_characters.killbane) == false) then
teleport(M21_characters.killbane, M21_navpoints.killbane_corner)
end
end
thread_yield()
end
end