sr2lua/ep04.lua

  1. -- ep04.lua 
  2. -- SR2 mission script 
  3. -- 3/28/07 
  4. -- Mission help table text tags 
  5.    HT_ARMOR = "ep04_armor" 
  6.    HT_BUILDING_LOCKED_DOWN = "ep04_building_locked_down" 
  7.    HT_CATCH_UP = "ep04_catch_up" 
  8.    HT_GET_TO_THE_TOP = "ep04_get_to_the_top" 
  9.    HT_KILL_VOGEL = "ep04_kill_vogel" 
  10. 	HT_VOGELS_HEALTH = "ep04_vogels_health" 
  11.    HT_ON_THE_STREETS = "ep04_on_the_streets" 
  12.    HT_VOGEL_ESCAPED = "ep04_vogel_escaped" 
  13.    HT_X_OF_Y_SECURITY_NODES = "ep04_x_of_y_power_stations" 
  14.    HT_X_OF_Y_SECURITY_NODES_DESTROYED = "ep04_x_of_y_power_stations_ht" 
  15.    HT_VOGELS_HEADING_BACK = "ep04_vogels_heading_back" 
  16.    HT_HELICOPTER_DESTROYED = "ep04_heli_destroyed" 
  17.    HT_HELICOPTER_ATTACKING = "ep03_ultor_sent_heli" 
  18.  
  19. -- Mission states 
  20.    MS_START = 1 
  21.    MS_VOGEL_RETURN_TO_TOWER = 2 
  22.    MS_VOGEL_ENTER_THE_TOWER = 3 
  23.    MS_DESTROY_SECURITY_NODES = 4 
  24.    MS_GO_TO_TOP_OF_TOWER = 5 
  25.    MS_KILL_VOGEL = 6 
  26.  
  27. -- Cutscene names 
  28.    CUTSCENE_NAME = "IG_ep04_scene1" 
  29.  
  30.    CT_INTRO = "tsse04-01" 
  31.    CT_HELICOPTER = "tsse04-02" 
  32.    CT_OUTRO = "tsse04-03" 
  33.  
  34. -- Groups, NPCs, vehicles, navpoints, and other names 
  35.    -- Mission constant names 
  36.    MISSION_NAME = "ep04" 
  37.    -- ( Mission Prefix ) 
  38.    MP = MISSION_NAME.."_$" 
  39.    ENEMY_GANG = "Police" 
  40.  
  41.    -- Checkpoints 
  42.    CP_VOGEL_ENTERED_BUILDING = "Vogel_Entered_Building" 
  43.  
  44.    -- Weapons 
  45.    SNIPER_RIFLE = "mcmanus2010" 
  46.  
  47.    -- Groups 
  48.    STARTER_CAR_GROUP = MP.."Starter_Car" 
  49.    VOGEL_GROUP = MP.."Vogel" 
  50.    VOGEL_LIMO_GROUP = MP.."Vogel_Limo" 
  51.    VOGEL_DEFENSE_SQUAD = MP.."Vogel_Defense_Squad" 
  52.  
  53.    APC_GROUP = MP.."APC" 
  54.  
  55.    VOGEL_DEFENSE_SQUAD_GROUP = MP.."Vogel_Defense_Squad" 
  56.  
  57.    ATTACK_HELICOPTER_GROUP = MP.."Attack_Helicopter" 
  58.    SECURITY_NODE_DEFENDERS_GROUP = MP.."Security_Node_Defenders" 
  59.  
  60.    ENEMY_HELICOPTER_GROUP = MP.."Enemy_Attack_Helicopter" 
  61.  
  62.    CUTSCENE_GROUP = MP.."Cutscene" 
  63.  
  64.    -- NPC names 
  65.    VOGEL_NAME = MP.."Vogel" 
  66.    VOGEL_LIMO_DRIVER = MP.."Driver" 
  67.    VOGEL_LIMO_BODYGUARD = MP.."Bodyguard" 
  68.  
  69.    LIMO_CHARACTERS = { VOGEL_LIMO_DRIVER, VOGEL_LIMO_BODYGUARD, VOGEL_NAME } 
  70.  
  71.    APC_SQUAD_MEMBERS = { MP.."APC_SM01", MP.."APC_SM02", MP.."APC_SM03", 
  72.                          MP.."APC_SM04", MP.."APC_SM05", MP.."APC_SM06" } 
  73.  
  74.    VOGEL_DEFENSE_SQUAD_MEMBERS = { MP.."VDS_01", MP.."VDS_02", MP.."VDS_03", 
  75.                                    MP.."VDS_04", MP.."VDS_05", MP.."VDS_06" } 
  76.  
  77.    ENEMY_PILOT = MP.."Enemy_Pilot" 
  78.  
  79.    NODE1_DEFENDERS = { MP.."Node1_AR1", MP.."Node1_AR2", MP.."Node1_RPG" } 
  80.    NODE2_DEFENDERS = { MP.."Node2_AR1", MP.."Node2_AR2", MP.."Node2_RPG" } 
  81.    NODE3_DEFENDERS = { MP.."Node3_AR1", MP.."Node3_AR2", MP.."Node3_RPG" } 
  82.    NODE4_DEFENDERS = { MP.."Node4_AR1", MP.."Node4_AR2", MP.."Node4_RPG" } 
  83.  
  84.    NODE_DEFENDERS = { NODE1_DEFENDERS, NODE2_DEFENDERS, NODE3_DEFENDERS, NODE4_DEFENDERS } 
  85.  
  86.    -- Vehicle names 
  87.    STARTER_CAR_NAME = MP.."Starter_Car" 
  88.    VOGELS_LIMO_NAME = MP.."Vogels_Limo" 
  89.  
  90.    APC_NAME = MP.."APC" 
  91.  
  92.    ATTACK_HELICOPTER = MP.."Attack_Helicopter" 
  93.  
  94.    ENEMY_ATTACK_HELICOPTER = MP.."Enemy_Attack_Helicopter" 
  95.  
  96.    -- Navpoints and paths 
  97.    LOCAL_PLAYER_START = MP.."Player_Start" 
  98.    REMOTE_PLAYER_START = MP.."Remote_Player_Start" 
  99.  
  100. 	LOCAL_FRONT_OF_TOWER = MP.."In_Front_of_Tower_Local" 
  101. 	REMOTE_FRONT_OF_TOWER = MP.."In_Front_of_Tower_Remote" 
  102.  
  103.    VOGELS_LIMO_PATHS = { MP.."Limo_Looping_Path_01", MP.."Limo_Looping_Path_02" } 
  104.    PHILLIPS_TOWER_LIMO_RETURN_POINT_ONE = MP.."Phillips_Tower_Return_Point01" 
  105.    PHILLIPS_TOWER_LIMO_RETURN_POINT_TWO = MP.."Phillips_Tower_Return_Point02" 
  106.    PHILLIPS_TOWER_EXIT_POINT = MP.."Phillips_Tower_Exit" 
  107.    TO_LOOPING_PATH = MP.."To_Looping_Path" 
  108.  
  109.    VOGEL_OFFICE_LOCATION = MP.."Vogel_Office_Location" 
  110.    PLAYER_OFFICE_LOCATION = MP.."Player_Office_Location" 
  111. 	REMOTE_PLAYER_OFFICE_LOCATION = MP.."Remote_Player_Office_Location" 
  112.  
  113.    ENEMY_ATTACK_HELICOPTER_WARP_POINTS = { MP.."Attack_Heli_Warp01", MP.."Attack_Heli_Warp02", MP.."Attack_Heli_Warp03" } 
  114.  
  115.    BODYGUARD_CHECKPOINT_WARP = MP.."Bodyguard_Checkpoint_Warp" 
  116.    DRIVER_CHECKPOINT_WARP = MP.."Driver_Checkpoint_Warp" 
  117.  
  118.    VOGEL_FLEE_POINTS = { MP.."EscapeP_01", MP.."EscapeP_02", MP.."EscapeP_03", 
  119.                          MP.."EscapeP_04", MP.."EscapeP_05", MP.."EscapeP_06" } 
  120.  
  121.    ATTACK_HELI_FALL_LOCATION = MP.."Attack_Heli_Fall_Warp" 
  122.  
  123.    -- Triggers 
  124.    TOP_OF_TOWER_TRIGGER = MP.."Top_of_Tower" 
  125.    NODE_ATTACK_AREA_TRIGGERS = { MP.."Node1_Attack_Area", MP.."Node2_Attack_Area", 
  126.                                  MP.."Node3_Attack_Area", MP.."Node4_Attack_Area" } 
  127.  
  128.  
  129.    -- Movers 
  130.    SECURITY_NODES = { MP.."Security_Node_01", MP.."Security_Node_02", 
  131.                       MP.."Security_Node_03", MP.."Security_Node_04" } 
  132.  
  133.    NODE_SMOKE_ORIGINS = { [SECURITY_NODES[1]] = MP.."Node1_Smoke_Origin", 
  134.                           [SECURITY_NODES[2]] = MP.."Node2_Smoke_Origin", 
  135.                           [SECURITY_NODES[3]] = MP.."Node3_Smoke_Origin", 
  136.                           [SECURITY_NODES[4]] = MP.."Node4_Smoke_Origin" } 
  137.    NODE_MARKER_LOCATIONS = { [SECURITY_NODES[1]] = MP.."Node1_Marker_Location", 
  138.                              [SECURITY_NODES[2]] = MP.."Node2_Marker_Location", 
  139.                              [SECURITY_NODES[3]] = MP.."Node3_Marker_Location", 
  140.                              [SECURITY_NODES[4]] = MP.."Node4_Marker_Location" } 
  141.  
  142.    -- Effects and animation states 
  143.    SMOKE_EFFECTS = { "Fire_flame_smk_lg" } 
  144.  
  145. -- Sound 
  146.  
  147.    -- Persona overrides 
  148.    VOGEL_PERSONA_OVERRIDES = { { "threat - alert (solo attack)", "DANE_TSSE04_ATTACK" } } 
  149.  
  150.    -- Lines/Dialog stream 
  151.    GAT_AND_PLAYER_CONVERSATION = 
  152.    { 
  153.    { "TSSE4_TOWER_L1", nil, 0 }, 
  154.    { "PLAYER_TSSE4_TOWER_L2", LOCAL_PLAYER, 0 }, 
  155.    { "TSSE4_TOWER_L3", nil, 0 } 
  156.    } 
  157.  
  158. -- Distances 
  159.    VOGELS_LIMO_MAX_DIST_METERS = 62.5 
  160.  
  161. -- Percents and multipliers 
  162.    LIMO_HEALTH_LEVEL_FLEE_PERCENT = 0.50 
  163.  
  164.    PLAYER_VEHICLE_HEALTH_MULTIPLIER = 1.5 
  165.  
  166.    VOGEL_RUN_TO_NEXT_POINT_DAMAGE_PERCENT = 0.20 
  167.  
  168.    VOGEL_FLEEING_DAMAGE_MULTIPLIER = 0.25 
  169.  
  170. -- Time values 
  171.    CHASE_VOGEL_FAIL_TIME_MS = 20000 
  172.    BETWEEN_ENEMY_HELICOPTERS_SECONDS = 30 
  173.    AFTER_CHUNK_SWAP_FADE_IN_TIME_SECONDS = 3.0 
  174.    TIME_PER_CATCH_UP_UPDATE_SECONDS = 5 
  175.  
  176.    PRE_DEPARTURE_DELAY_TIME_SECONDS = 3.0 
  177.    POST_DEPARTURE_PROMPT_DELAY_TIME_SECONDS = 3.0 
  178.  
  179. -- Speeds 
  180.    VOGELS_LIMO_ESCAPE_SPEED_MPS = 60 
  181.    VOGELS_LIMO_RETURN_TO_BASE_SPEED_MPS = 80 
  182.  
  183. -- Constant values and counts 
  184.    INVALID_THREAD_HANDLE = -1 
  185.    NUM_SECURITY_NODES = sizeof_table( SECURITY_NODES ) 
  186.    MISSION_MIN_NOTORIETY = 3 
  187.    VOGELS_LIMO_HEALTH = 30000 
  188.    VOGELS_HEALTH = 3000 
  189.    NUM_SMOKE_EFFECTS = sizeof_table( SMOKE_EFFECTS ) 
  190.    INVALID_EFFECT_HANDLE = -1 
  191.    NUM_HELI_WARP_POINTS = sizeof_table( ENEMY_ATTACK_HELICOPTER_WARP_POINTS ) 
  192.  
  193. -- Global variables 
  194.    Vogel_limo_pathfinding_thread_handle = INVALID_THREAD_HANDLE 
  195.    Vogel_return_to_tower_thread_handle = INVALID_THREAD_HANDLE 
  196.    Num_nodes_killed = 0 
  197.     
  198.    Node_smoke_handles = { [SECURITY_NODES[1]] = INVALID_EFFECT_HANDLE, 
  199.                           [SECURITY_NODES[2]] = INVALID_EFFECT_HANDLE, 
  200.                           [SECURITY_NODES[3]] = INVALID_EFFECT_HANDLE, 
  201.                           [SECURITY_NODES[4]] = INVALID_EFFECT_HANDLE } 
  202.  
  203.    Nodes_destroyed = { [SECURITY_NODES[1]] = false, 
  204.                        [SECURITY_NODES[2]] = false, 
  205.                        [SECURITY_NODES[3]] = false, 
  206.                        [SECURITY_NODES[4]] = false } 
  207.  
  208.    Currently_marked_node_name = SECURITY_NODES[1] 
  209.    Marked_node_currently_marked = false 
  210.  
  211.    Cur_heli_warp_point_index = 1 
  212.    Heli_spawn_thread_handle = INVALID_THREAD_HANDLE 
  213.    Vogel_is_fleeing = false 
  214.    Vogel_percent_damage_since_last_flee = 0 
  215.    Limo_getting_away_thread_handle = INVALID_THREAD_HANDLE 
  216.    Gat_call_received = false 
  217.  
  218.    Players_in_range_of_limo = { [LOCAL_PLAYER] = false, [REMOTE_PLAYER] = false } 
  219.    Players_in_helicopter = { [LOCAL_PLAYER] = false, [REMOTE_PLAYER] = false } 
  220.  
  221.    Gat_and_player_cellphone_call_thread_handle = INVALID_THREAD_HANDLE 
  222.    Destroyed_all_nodes = false 
  223.    Node_destruction_started = false 
  224.  
  225. 	Entered_tower = false 
  226.  
  227. function ep04_start( checkpoint_name, is_restart ) 
  228. 	-- Start trigger is hit...the activate button was hit 
  229. 	set_mission_author("Mark Gabby and Anoop Shekar") 
  230. 	homie_mission_lock("gat") 
  231.  
  232. 	-- TEMP 
  233. 	--checkpoint_name = CP_VOGEL_ENTERED_BUILDING 
  234. 	-- END TEMP 
  235.  
  236.    ep04_start_or_resume_from_checkpoint( checkpoint_name, is_restart ) 
  237. end 
  238.  
  239. -- Starts the mission or resumes it from a checkpoint, based on 
  240. -- the value of the passed-in checkpoint name. 
  241. -- 
  242. -- This function does any group creation or other work that causes 
  243. -- the game to "load" before the mission is ready. Therefore, it 
  244. -- fades the screen out before it starts and fades it back in when 
  245. -- it's done. 
  246. -- 
  247. function ep04_start_or_resume_from_checkpoint( checkpoint_name, is_restart ) 
  248.  
  249.    mission_start_fade_out() 
  250. 	 
  251.    notoriety_set_min( ENEMY_GANG, MISSION_MIN_NOTORIETY ) 
  252.  
  253.    group_create_hidden( VOGEL_DEFENSE_SQUAD_GROUP, true ) 
  254.  
  255.    -- Temporarily swap the tower back to the normal state if this mission is being replayed 
  256.    if ( mission_is_complete( MISSION_NAME ) ) then 
  257.       local interior, blocking, temporary 
  258.       interior = true 
  259.       blocking = true 
  260.       temporary = true 
  261.    	city_chunk_swap("SR2_IntSRMisPhiltwr", "normal", interior, blocking, temporary ) 
  262.    end 
  263.  
  264.    local state_to_setup 
  265.    if ( checkpoint_name == MISSION_START_CHECKPOINT ) then 
  266. 		if (not is_restart) then 
  267. 			cutscene_play( CT_INTRO, "", { LOCAL_PLAYER_START, REMOTE_PLAYER_START }, false ) 
  268. 		else 
  269.          teleport_coop( LOCAL_PLAYER_START, REMOTE_PLAYER_START ) 
  270. 		end 
  271.       group_create( VOGEL_GROUP, true ) 
  272.       group_create( VOGEL_LIMO_GROUP, true ) 
  273.       group_create( STARTER_CAR_GROUP, true ) 
  274.       group_create_hidden( ATTACK_HELICOPTER_GROUP, true ) 
  275.       group_create( APC_GROUP, true ) 
  276.       vehicle_enter_group_teleport( APC_SQUAD_MEMBERS, APC_NAME ) 
  277. 	  vehicle_set_untowable( VOGELS_LIMO_NAME, true ) 
  278.  
  279.       vehicle_enter_group_teleport( LIMO_CHARACTERS, VOGELS_LIMO_NAME ) 
  280.       state_to_setup = MS_START 
  281.    elseif ( checkpoint_name == CP_VOGEL_ENTERED_BUILDING ) then 
  282.       group_create( VOGEL_GROUP, true ) 
  283.       group_create( VOGEL_LIMO_GROUP, true ) 
  284.       group_create( ATTACK_HELICOPTER_GROUP, true ) 
  285.       character_hide( VOGEL_NAME ) 
  286.       teleport_vehicle( VOGELS_LIMO_NAME, PHILLIPS_TOWER_LIMO_RETURN_POINT_TWO ) 
  287.       teleport( VOGEL_LIMO_BODYGUARD, BODYGUARD_CHECKPOINT_WARP ) 
  288.       teleport( VOGEL_LIMO_DRIVER, DRIVER_CHECKPOINT_WARP ) 
  289.  
  290.       state_to_setup = MS_DESTROY_SECURITY_NODES 
  291.    end 
  292.  
  293.    mission_start_fade_in() 
  294.  
  295.    ep04_setup_state( state_to_setup ) 
  296. end 
  297.  
  298. -- Causes the defenders of the specified node to attack the specified player. 
  299. -- 
  300. function ep04_node_defenders_attack( node_index, player_name ) 
  301.    for index, name in pairs( NODE_DEFENDERS[node_index] ) do 
  302.       attack_safe( name, player_name ) 
  303.    end 
  304. end 
  305.  
  306. function ep04_node1_defenders_attack( triggerer_name ) 
  307.    ep04_node_defenders_attack( 1, triggerer_name ) 
  308. end 
  309.  
  310. function ep04_node2_defenders_attack( triggerer_name ) 
  311.    ep04_node_defenders_attack( 2, triggerer_name ) 
  312. end 
  313.  
  314. function ep04_node3_defenders_attack( triggerer_name ) 
  315.    ep04_node_defenders_attack( 3, triggerer_name ) 
  316. end 
  317.  
  318. function ep04_node4_defenders_attack( triggerer_name ) 
  319.    ep04_node_defenders_attack( 4, triggerer_name ) 
  320. end 
  321.  
  322.  
  323. -- This function tracks when the player enters a vehicle initially - it's 
  324. -- used to have the APC chase the player. 
  325. -- 
  326. function ep04_entered_vehicle_initial( player_name, vehicle_name ) 
  327.    if ( coop_is_active() ) then 
  328.       on_vehicle_enter( "", REMOTE_PLAYER ) 
  329.    end 
  330.    on_vehicle_enter( "", LOCAL_PLAYER ) 
  331.    on_vehicle_enter( "", STARTER_CAR_NAME ) 
  332.  
  333.    vehicle_chase( APC_NAME, player_name ) 
  334. end 
  335.  
  336. function ep04_next_heli_spawn() 
  337.    Heli_spawn_thread_handle = thread_new( "ep04_enemy_heli_spawn_and_attack" ) 
  338. end 
  339.  
  340. function ep04_get_next_heli_warp_point() 
  341.    local next_warp_point = ENEMY_ATTACK_HELICOPTER_WARP_POINTS[Cur_heli_warp_point_index] 
  342.  
  343.    Cur_heli_warp_point_index = Cur_heli_warp_point_index + 1 
  344.    if ( Cur_heli_warp_point_index > NUM_HELI_WARP_POINTS ) then 
  345.       Cur_heli_warp_point_index = 1 
  346.    end 
  347.  
  348.    return next_warp_point 
  349. end 
  350.  
  351. -- Causes an enemy attack helicopter to spawn and come at the player. 
  352. -- 
  353. -- delay_before_spawn: (optional, default true) Whether there should be 
  354. --                     a short delay before the helicopter spawns. 
  355. -- 
  356. function ep04_enemy_heli_spawn_and_attack( delay_before_spawn ) 
  357.    if ( delay_before_spawn == nil or delay_before_spawn == true ) then 
  358.       delay( BETWEEN_ENEMY_HELICOPTERS_SECONDS ) 
  359.    end 
  360.  
  361.    release_to_world( ENEMY_HELICOPTER_GROUP ) 
  362.  
  363.    -- Create the helicopter 
  364.    group_create_hidden( ENEMY_HELICOPTER_GROUP, true ) 
  365.    vehicle_enter_teleport( ENEMY_PILOT, ENEMY_ATTACK_HELICOPTER, 0, true ) 
  366.  
  367.    -- Once it's loaded, immediately seat the pilot and teleport it to a location nearer to the player 
  368.    group_show( ENEMY_HELICOPTER_GROUP ) 
  369.    local warp_point = ep04_get_next_heli_warp_point() 
  370.    teleport_vehicle( ENEMY_ATTACK_HELICOPTER, warp_point ) 
  371.    mission_help_table_nag( HT_HELICOPTER_ATTACKING ) 
  372.   
  373. 	-- Set the attack heli to use the lockon system so that it will be more difficult 
  374. 	vehicle_set_use_lockon_system( ENEMY_ATTACK_HELICOPTER, true ) 
  375.  
  376.    -- Find which player's closest to the position it was teleported to and have it attack that player 
  377.    local distance, player = get_dist_closest_player_to_object( ENEMY_ATTACK_HELICOPTER ) 
  378.    vehicle_chase( ENEMY_ATTACK_HELICOPTER, player ) 
  379.  
  380.    -- Set up the spawning - when this helicopter dies, spawn the next one 
  381.    on_vehicle_destroyed( "ep04_next_heli_spawn", ENEMY_ATTACK_HELICOPTER ) 
  382.  
  383.    Heli_spawn_thread_handle = INVALID_THREAD_HANDLE 
  384. end 
  385.  
  386. function ep04_no_player_in_helicopter() 
  387.    if ( Players_in_helicopter[LOCAL_PLAYER] == false ) then 
  388.       if ( coop_is_active() ) then 
  389.          if ( Players_in_helicopter[REMOTE_PLAYER] == false ) then 
  390.             return true 
  391.          end 
  392.       else 
  393.          return true 
  394.       end 
  395.    end 
  396.  
  397.    return false 
  398. end 
  399.  
  400. function ep04_entered_attack_heli_tower_attack( player_name, vehicle_name ) 
  401.    -- If no one's in the helicopter before this player got in, remove the marker, because it had one 
  402.    if ( ep04_no_player_in_helicopter() ) then 
  403.       marker_remove_vehicle( vehicle_name, SYNC_ALL ) 
  404.       if ( Destroyed_all_nodes == false ) then 
  405.          marker_add_navpoint( NODE_MARKER_LOCATIONS[Currently_marked_node_name], MINIMAP_ICON_KILL, INGAME_EFFECT_VEHICLE_KILL, SYNC_ALL ) 
  406.          Marked_node_currently_marked = true 
  407.       end 
  408.    end 
  409.  
  410.    Players_in_helicopter[player_name] = true 
  411. end 
  412.  
  413. function ep04_left_attack_heli_tower_attack( player_name, vehicle_name ) 
  414.    Players_in_helicopter[player_name] = false 
  415.  
  416.    -- If no one's in the helicopter after this player gets out, then add a marker for it 
  417.    if ( ep04_no_player_in_helicopter() ) then 
  418.       marker_add_vehicle( vehicle_name, MINIMAP_ICON_LOCATION, INGAME_EFFECT_VEHICLE_INTERACT, SYNC_ALL ) 
  419.       if ( Destroyed_all_nodes == false ) then 
  420.          marker_remove_navpoint( NODE_MARKER_LOCATIONS[Currently_marked_node_name], SYNC_ALL ) 
  421.          Marked_node_currently_marked = false 
  422.       end 
  423.    end 
  424. end 
  425.  
  426. function ep04_entered_vehicle_attack_tower( player_name, vehicle_name ) 
  427.    if ( Gat_and_player_cellphone_call_thread_handle ~= INVALID_THREAD_HANDLE ) then 
  428.       thread_kill( Gat_and_player_cellphone_call_thread_handle ) 
  429.       Gat_and_player_cellphone_call_thread_handle = INVALID_THREAD_HANDLE 
  430.       mid_mission_phonecall_reset() 
  431.    end 
  432.    marker_remove_vehicle( ATTACK_HELICOPTER, SYNC_ALL ) 
  433.    on_vehicle_enter( "ep04_entered_attack_heli_tower_attack", ATTACK_HELICOPTER ) 
  434.    on_vehicle_exit( "ep04_left_attack_heli_tower_attack", ATTACK_HELICOPTER ) 
  435.  
  436.    mission_help_table( HT_BUILDING_LOCKED_DOWN ) 
  437.  
  438.    objective_text(0, HT_X_OF_Y_SECURITY_NODES, Num_nodes_killed, NUM_SECURITY_NODES ) 
  439.    marker_add_navpoint( NODE_MARKER_LOCATIONS[SECURITY_NODES[1]], MINIMAP_ICON_KILL, INGAME_EFFECT_VEHICLE_KILL, SYNC_ALL ) 
  440.    Currently_marked_node_name = SECURITY_NODES[1] 
  441.    Marked_node_currently_marked = true 
  442.  
  443.    -- We're controlling the helicopter notoriety - don't spawn another one 
  444.    notoriety_force_no_spawn( ENEMY_GANG, true ) 
  445.    notoriety_force_no_spawn( "ultor", true ) 
  446.  
  447.    -- Spawn a new helicopter - send in false for the delay because we want this first one to 
  448.    -- spawn instantly 
  449.    ep04_enemy_heli_spawn_and_attack( false ) 
  450. end 
  451.  
  452. function ep04_gat_call_received() 
  453.    Gat_call_received = true 
  454. end 
  455.  
  456. function ep04_gat_and_player_converse() 
  457.    mid_mission_phonecall("ep04_gat_call_received") 
  458.    repeat 
  459.       thread_yield() 
  460.    until Gat_call_received 
  461.    Gat_and_player_cellphone_call_thread_handle = INVALID_THREAD_HANDLE 
  462.    audio_play_conversation( GAT_AND_PLAYER_CONVERSATION, INCOMING_CALL ) 
  463. end 
  464.  
  465. -- Sets the mission to a specified state. For example, 
  466. -- when the player damages Vogel's limo enough, it needs 
  467. -- to flee back to the Phillips Tower. 
  468. -- 
  469. function ep04_setup_state( state_to_setup, actor_name ) 
  470.    -- Mission is starting from the beginning 
  471.    if ( state_to_setup == MS_START ) then 
  472.       -- Increase the car's HP by the design-specified multiplier 
  473.       local car_cur_max_hp = get_max_hit_points( STARTER_CAR_NAME ) 
  474.       local car_new_max_hp = car_cur_max_hp * PLAYER_VEHICLE_HEALTH_MULTIPLIER 
  475.       set_max_hit_points( STARTER_CAR_NAME, car_new_max_hp ) 
  476.       set_current_hit_points( STARTER_CAR_NAME, car_new_max_hp ) 
  477.  
  478.  
  479.       on_vehicle_enter( "ep04_entered_vehicle_initial", LOCAL_PLAYER ) 
  480.       on_vehicle_enter( "ep04_entered_vehicle_initial", STARTER_CAR_NAME ) 
  481.       if ( coop_is_active() ) then 
  482.          on_vehicle_enter( "ep04_entered_vehicle_initial", REMOTE_PLAYER ) 
  483.       end 
  484.  
  485.  
  486.       ep04_setup_vogel_limo() 
  487.  
  488.       ep04_setup_vogel_limo_tracking() 
  489.  
  490.       delay( PRE_DEPARTURE_DELAY_TIME_SECONDS ) 
  491.       Vogel_limo_pathfinding_thread_handle = thread_new( "ep04_limo_loop_pathfind" ) 
  492.  
  493.       -- Let the player know what he should be doing and guide 
  494.       -- him to the objective 
  495.       delay( POST_DEPARTURE_PROMPT_DELAY_TIME_SECONDS ) 
  496.       mission_help_table( HT_ON_THE_STREETS ) 
  497.    elseif ( state_to_setup == MS_VOGEL_RETURN_TO_TOWER ) then 
  498.       thread_kill( Vogel_limo_pathfinding_thread_handle ) 
  499.  
  500.    elseif ( state_to_setup == MS_VOGEL_ENTER_THE_TOWER ) then 
  501.       -- Play the cutscene 
  502.       cutscene_play( CUTSCENE_NAME, "", "", false ) 
  503.  
  504.       -- Hide the group - if the cutscene was skipped, we don't want the group getting in the way 
  505.       group_hide( CUTSCENE_GROUP ) 
  506.       -- Have the helicopter appear so that the player can get in 
  507.       -- it after the cutscene 
  508.       group_show( ATTACK_HELICOPTER_GROUP ) 
  509. 		fade_in( 1.0 ) 
  510.  
  511.       -- Make the passengers and driver vulnerable 
  512.       for index, name in pairs( LIMO_CHARACTERS ) do 
  513.          turn_vulnerable( name ) 
  514.       end    
  515.       -- Allow the limo to be hijacked again. 
  516.       set_unjackable_flag( VOGELS_LIMO_NAME, false) 
  517.  
  518.       -- Have Vogel disappear 
  519.       vehicle_exit_teleport( VOGEL_NAME ) 
  520.       character_hide( VOGEL_NAME ) 
  521.       -- Have the other characters get out 
  522.       vehicle_suppress_npc_exit( VOGELS_LIMO_NAME, false ) 
  523.       vehicle_exit( VOGEL_LIMO_DRIVER ) 
  524.       vehicle_exit( VOGEL_LIMO_BODYGUARD ) 
  525.  
  526.       -- Make the limo vulnerable 
  527.       turn_vulnerable( VOGELS_LIMO_NAME ) 
  528.        
  529.       mission_set_checkpoint( CP_VOGEL_ENTERED_BUILDING ) 
  530.  
  531.       -- Switch to the next state 
  532.       ep04_setup_state( MS_DESTROY_SECURITY_NODES ) 
  533.    elseif ( state_to_setup == MS_DESTROY_SECURITY_NODES ) then 
  534.       -- Lead the player to the helicopter 
  535.       Gat_and_player_cellphone_call_thread_handle = thread_new( "ep04_gat_and_player_converse" ) 
  536.  
  537.       on_vehicle_enter( "ep04_entered_vehicle_attack_tower", ATTACK_HELICOPTER ) 
  538.       on_vehicle_destroyed( "ep04_helicopter_destroyed", ATTACK_HELICOPTER ) 
  539.  
  540.       marker_add_vehicle( ATTACK_HELICOPTER, MINIMAP_ICON_LOCATION, INGAME_EFFECT_VEHICLE_INTERACT ) 
  541.  
  542.       -- Setup the power node on-death callbacks 
  543.       for index, name in pairs( SECURITY_NODES ) do 
  544.          mesh_mover_reset( name ) 
  545.          on_mover_destroyed( "ep04_security_node_destroyed", name ) 
  546.       end 
  547.  
  548.       -- Setup the node triggers  
  549.       group_create( SECURITY_NODE_DEFENDERS_GROUP ) 
  550.  
  551.       for index, name in pairs( NODE_ATTACK_AREA_TRIGGERS ) do 
  552.          trigger_enable( name, true ) 
  553.          on_trigger( "ep04_node"..index.."_defenders_attack", name ); 
  554.       end 
  555.  
  556.    elseif ( state_to_setup == MS_GO_TO_TOP_OF_TOWER ) then 
  557.       -- We've destroyed all the security nodes 
  558.       Destroyed_all_nodes = true 
  559.  
  560.       -- Activate a trigger near the top of the tower 
  561.       trigger_enable( TOP_OF_TOWER_TRIGGER, true ) 
  562.       on_trigger( "ep04_reached_top_of_tower", TOP_OF_TOWER_TRIGGER ) 
  563.       marker_add_trigger( TOP_OF_TOWER_TRIGGER, MINIMAP_ICON_LOCATION, "", SYNC_ALL ) 
  564.  
  565.       -- No need to know how many security nodes remain 
  566.       objective_text_clear(0) 
  567.  
  568.       -- Tell the player where to go 
  569.       mission_help_table( HT_GET_TO_THE_TOP ) 
  570.    elseif ( state_to_setup == MS_KILL_VOGEL ) then 
  571.       ep04_stop_heli_attack() 
  572.       fade_out( 0 ) 
  573.       if ( coop_is_active() ) then 
  574.          vehicle_exit_teleport( REMOTE_PLAYER ) 
  575.       end 
  576.       vehicle_exit_teleport( LOCAL_PLAYER ) 
  577.       group_destroy( ATTACK_HELICOPTER_GROUP ) 
  578.  
  579.       cutscene_play( CT_HELICOPTER, "", {PLAYER_OFFICE_LOCATION, REMOTE_PLAYER_OFFICE_LOCATION}, false ) 
  580. 		Entered_tower = true 
  581.  
  582.       action_nodes_restrict_spawning(true) 
  583. 	  local interior, blocking, temporary 
  584.       interior = true 
  585.       blocking = true 
  586.       temporary = false 
  587.    	city_chunk_swap("SR2_IntSRMisPhiltwr", "blowup", interior, blocking, temporary ) 
  588.  
  589.       group_show( VOGEL_DEFENSE_SQUAD_GROUP ) 
  590.  
  591.       -- Teleport the player and Vogel into a good location 
  592.       character_show( VOGEL_NAME ) 
  593.       teleport( VOGEL_NAME, VOGEL_OFFICE_LOCATION ) 
  594.  
  595.       -- Do all the overrides for Vogel 
  596.       for index, override in pairs( VOGEL_PERSONA_OVERRIDES ) do 
  597.          persona_override_character_start( VOGEL_NAME, override[1], override[2] ) 
  598.       end 
  599.  
  600. 		--Players should not use a chainsaw against Vogel it makes bad things happen 
  601. 		if coop_is_active() then 
  602. 			 if inv_has_item("chainsaw", REMOTE_PLAYER) then 
  603. 				inv_weapon_disable_slot(WEAPON_SLOT_MELEE) 
  604. 			 end 
  605. 		end 
  606.       if inv_has_item("chainsaw", LOCAL_PLAYER) then 
  607. 			inv_weapon_disable_slot(WEAPON_SLOT_MELEE) 
  608. 		end 
  609.       fade_in( AFTER_CHUNK_SWAP_FADE_IN_TIME_SECONDS ) 
  610.  
  611.       -- Setup Vogel 
  612.       turn_invulnerable( VOGEL_NAME ) 
  613.       set_max_hit_points( VOGEL_NAME, VOGELS_HEALTH ) 
  614.       set_current_hit_points( VOGEL_NAME, VOGELS_HEALTH ) 
  615.       character_prevent_flinching( VOGEL_NAME, true ) 
  616.       character_allow_ragdoll( VOGEL_NAME, false ) 
  617.       on_death( "ep04_vogel_died", VOGEL_NAME ) 
  618.       marker_add_npc( VOGEL_NAME, MINIMAP_ICON_KILL, INGAME_EFFECT_KILL, SYNC_ALL ) 
  619.       hud_bar_on(0, "Health", HT_VOGELS_HEALTH, VOGELS_HEALTH ) 
  620.       hud_bar_set_range(0, 0, VOGELS_HEALTH, SYNC_ALL ) 
  621.       hud_bar_set_value(0, VOGELS_HEALTH, SYNC_ALL ) 
  622.       on_take_damage( "ep04_vogel_damaged", VOGEL_NAME ) 
  623.  
  624.       attack_safe( VOGEL_NAME, LOCAL_PLAYER ) 
  625.  
  626. 		mission_help_table( HT_KILL_VOGEL ) 
  627.    end 
  628. end 
  629.  
  630. -- Has Vogel flee to the point farthest from the location of any player. 
  631. -- 
  632. function ep04_vogel_flee() 
  633.    Vogel_is_fleeing = true 
  634.  
  635.    local farthest_dist, farthest_point 
  636.    farthest_dist = get_dist_closest_player_to_object( VOGEL_FLEE_POINTS[1] ) 
  637.    farthest_point = VOGEL_FLEE_POINTS[1] 
  638.  
  639.    for index, cur_flee_point in pairs( VOGEL_FLEE_POINTS ) do 
  640.       local cur_point_dist = get_dist_closest_player_to_object( cur_flee_point ) 
  641.  
  642.       if ( cur_point_dist > farthest_dist  ) then 
  643.          farthest_point = cur_flee_point 
  644.          farthest_dist = cur_point_dist 
  645.       end 
  646.    end 
  647.    mission_debug( "point found was: "..farthest_point, 20 ) 
  648.    set_ignore_ai_flag( VOGEL_NAME, true ) 
  649.    move_to_safe( VOGEL_NAME, farthest_point, 2, false, false ) 
  650.    set_ignore_ai_flag( VOGEL_NAME, false ) 
  651.    local distance, player_name = get_dist_closest_player_to_object( VOGEL_NAME ) 
  652.    attack_safe( VOGEL_NAME, player_name ) 
  653.  
  654.    Vogel_is_fleeing = false 
  655. end 
  656.  
  657. -- Called when Vogel takes damage. Causes him to flee if he isn't already doing so. 
  658. -- 
  659. function ep04_vogel_damaged( attacked_object_name, attacker_name, percent_hp_remaining_after_attack ) 
  660.  
  661.    -- Find out the percent of Vogel's total hit points this attack did 
  662.    local cur_damage_percent = get_current_hit_points( VOGEL_NAME ) / get_max_hit_points( VOGEL_NAME ) 
  663.    local percent_damage_done = cur_damage_percent - percent_hp_remaining_after_attack 
  664.  
  665.    -- By default, do a normal amount of damage to Vogel 
  666.    local percent_to_set = percent_hp_remaining_after_attack 
  667.  
  668.    -- If Vogel's not fleeing, then update his "percent until next flee." 
  669.    if ( Vogel_is_fleeing == false ) then 
  670.       -- Update the amount of damage Vogel has taken since he last fleed 
  671.       Vogel_percent_damage_since_last_flee = Vogel_percent_damage_since_last_flee + percent_damage_done 
  672.  
  673.       -- If it's greater than the flee threshold, then have him flee, unless this is the last point. 
  674.       if ( Vogel_percent_damage_since_last_flee > VOGEL_RUN_TO_NEXT_POINT_DAMAGE_PERCENT and 
  675.            percent_hp_remaining_after_attack > VOGEL_RUN_TO_NEXT_POINT_DAMAGE_PERCENT ) then 
  676.          -- Set Vogel's HP to the amount after the attack minus the amount done is over the threshold 
  677.          local damage_done_over_threshold_percent = ( Vogel_percent_damage_since_last_flee - VOGEL_RUN_TO_NEXT_POINT_DAMAGE_PERCENT ) 
  678.          percent_to_set = percent_hp_remaining_after_attack + damage_done_over_threshold_percent 
  679.          mission_debug( "vogel fleeing. setting percent at "..percent_to_set ) 
  680.  
  681.          Vogel_percent_damage_since_last_flee = 0 
  682.          thread_new( "ep04_vogel_flee" ) 
  683.       end 
  684.    else 
  685.       -- Do a different amount of damage when Vogel is fleeing, and don't have it registered against the "percent since last flee." 
  686.       percent_to_set = cur_damage_percent - ( percent_damage_done * VOGEL_FLEEING_DAMAGE_MULTIPLIER ) 
  687.    end 
  688.     
  689.    local max_hp = get_max_hit_points( VOGEL_NAME ) 
  690.    set_current_hit_points( VOGEL_NAME, percent_to_set * max_hp ) 
  691.  
  692.    local vogel_hp =  get_current_hit_points( VOGEL_NAME ) 
  693.    hud_bar_set_value(0, vogel_hp, SYNC_ALL ) 
  694. end 
  695.  
  696. function ep04_vogel_died() 
  697.    character_allow_ragdoll( VOGEL_NAME, true ) 
  698.    mission_end_success( MISSION_NAME, CT_OUTRO, { LOCAL_FRONT_OF_TOWER, REMOTE_FRONT_OF_TOWER } ) 
  699. end 
  700.  
  701. -- Sets up Vogel's limo itself so that it's ready to travel. 
  702. -- 
  703. function ep04_setup_vogel_limo() 
  704.    turn_invulnerable( VOGELS_LIMO_NAME ) 
  705.  
  706.    vehicle_disable_chase( VOGELS_LIMO_NAME, true ) 
  707.    vehicle_infinite_mass( VOGELS_LIMO_NAME, true ) 
  708.    vehicle_ignore_repulsors( VOGELS_LIMO_NAME, true ) 
  709.  
  710.    vehicle_set_allow_ram_ped( VOGELS_LIMO_NAME, true ) 
  711.    vehicle_suppress_npc_exit( VOGELS_LIMO_NAME, true ) 
  712.    vehicle_prevent_explosion_fling( VOGELS_LIMO_NAME, true ) 
  713.  
  714.    vehicle_set_bulletproof_glass( VOGELS_LIMO_NAME, true ) 
  715.    for index, name in pairs( LIMO_CHARACTERS ) do 
  716.       turn_invulnerable( name ) 
  717.    end 
  718.  
  719.    set_max_hit_points( VOGELS_LIMO_NAME, VOGELS_LIMO_HEALTH ) 
  720.    set_current_hit_points( VOGELS_LIMO_NAME, VOGELS_LIMO_HEALTH ) 
  721. end 
  722.  
  723. function ep04_reached_top_of_tower( triggerer_name ) 
  724.    trigger_enable( TOP_OF_TOWER_TRIGGER, false ) 
  725.    marker_remove_trigger( TOP_OF_TOWER_TRIGGER, SYNC_ALL ) 
  726.  
  727.    ep04_setup_state( MS_KILL_VOGEL, triggerer_name ) 
  728. end 
  729.  
  730. -- Stops the attack helicopter spawn chain. 
  731. -- 
  732. function ep04_stop_heli_attack() 
  733.    -- If the helicopter spawn thread is running, stop it - no more attack helicopters should 
  734.    -- spawn. 
  735.    if ( Heli_spawn_thread_handle ~= INVALID_THREAD_HANDLE ) then 
  736.       thread_kill( Heli_spawn_thread_handle ) 
  737.    end 
  738.  
  739.    -- Clear the on-killed callback if an attack helicopter is still alive 
  740.    if ( vehicle_is_destroyed( ENEMY_ATTACK_HELICOPTER ) == false ) then 
  741.       on_vehicle_destroyed( "", ENEMY_ATTACK_HELICOPTER ) 
  742.    end 
  743.  
  744.    if ( group_is_loaded( ENEMY_HELICOPTER_GROUP ) ) then 
  745.       group_destroy( ENEMY_HELICOPTER_GROUP ) 
  746.    end 
  747. end 
  748.  
  749. -- Finds the first node after the passed-in one in the list of nodes that is 
  750. -- still alive, and returns its name. 
  751. -- 
  752. -- NOTE: If no nodes survive, will return nil. 
  753. -- 
  754. -- this_node_name: The node to search after. 
  755. -- 
  756. function ep04_get_next_living_node( this_node_name ) 
  757.    -- Find the index of the node 
  758.    local this_nodes_index 
  759.  
  760.    for node_index, node_name in pairs( SECURITY_NODES ) do 
  761.       if ( this_node_name == node_name ) then 
  762.          this_nodes_index = node_index 
  763.          break 
  764.       end 
  765.    end 
  766.  
  767.    -- Start looking through the nodes one past this one 
  768.    local cur_node_index = this_nodes_index + 1 
  769.  
  770.    -- Now, go through the indices until you find a living node 
  771.    while ( cur_node_index <= NUM_SECURITY_NODES ) do 
  772.  
  773.       -- If this node isn't destroyed, then return its name 
  774.       if ( Nodes_destroyed[SECURITY_NODES[cur_node_index]] == false ) then 
  775.          return SECURITY_NODES[cur_node_index] 
  776.       end 
  777.  
  778.       cur_node_index = cur_node_index + 1 
  779.    end 
  780.  
  781.    return nil 
  782. end 
  783.  
  784. function ep04_security_node_destroyed( security_node_name ) 
  785.    Num_nodes_killed = Num_nodes_killed + 1 
  786.  
  787.    Nodes_destroyed[security_node_name] = true 
  788.  
  789.    local smoke_effect_to_play = SMOKE_EFFECTS[rand_int( 1, NUM_SMOKE_EFFECTS )] 
  790.  
  791.    if ( Currently_marked_node_name == security_node_name ) then 
  792.       marker_remove_navpoint( NODE_MARKER_LOCATIONS[security_node_name], SYNC_ALL ) 
  793.       Marked_node_currently_marked = false 
  794.    end 
  795.    Node_smoke_handles[security_node_name] = effect_play( smoke_effect_to_play, 
  796.                                                          NODE_SMOKE_ORIGINS[security_node_name], true ) 
  797.  
  798.    mission_help_table_nag( HT_X_OF_Y_SECURITY_NODES_DESTROYED, Num_nodes_killed, NUM_SECURITY_NODES ) 
  799.    objective_text(0, HT_X_OF_Y_SECURITY_NODES, Num_nodes_killed, NUM_SECURITY_NODES ) 
  800.  
  801.    -- If there are more nodes to kill, we might need to update the player's guidance 
  802.    if ( Num_nodes_killed < NUM_SECURITY_NODES ) then 
  803.       -- If this node that was just killed had a marker before it was killed, then mark the next living node 
  804.       -- in the list and store that node's name as the currently marked node 
  805.       if ( Currently_marked_node_name == security_node_name ) then 
  806.          local next_living_node = ep04_get_next_living_node( security_node_name ) 
  807.  
  808.          marker_add_navpoint( NODE_MARKER_LOCATIONS[next_living_node], MINIMAP_ICON_KILL, INGAME_EFFECT_VEHICLE_KILL, SYNC_ALL ) 
  809.          Currently_marked_node_name = next_living_node 
  810.          Marked_node_currently_marked = true 
  811.       end 
  812.    else 
  813.       ep04_setup_state( MS_GO_TO_TOP_OF_TOWER ) 
  814.    end 
  815. end 
  816.  
  817. -- Sets up the distance and damaged tracking for Vogel's limo. 
  818. -- 
  819. function ep04_setup_vogel_limo_tracking() 
  820.    local full_value = 1.0 
  821.    local min_value = 0 
  822.  
  823.    hud_bar_on(0, "Damage", HT_ARMOR, full_value ) 
  824.    hud_bar_set_range(0, min_value, full_value, SYNC_ALL ) 
  825.    hud_bar_set_value(0, full_value, SYNC_ALL ) 
  826.    on_take_damage( "ep04_vogel_limo_initial_damage", VOGELS_LIMO_NAME ) 
  827.    on_collision( "ep04_vogel_limo_collision", VOGELS_LIMO_NAME ) 
  828.  
  829.    if ( get_dist( LOCAL_PLAYER, VOGELS_LIMO_NAME ) < VOGELS_LIMO_MAX_DIST_METERS ) then 
  830.       Players_in_range_of_limo[LOCAL_PLAYER] = true 
  831.    end 
  832.    if ( coop_is_active() ) then 
  833.       if ( get_dist( REMOTE_PLAYER, VOGELS_LIMO_NAME ) < VOGELS_LIMO_MAX_DIST_METERS ) then 
  834.          Players_in_range_of_limo[REMOTE_PLAYER] = true 
  835.       end 
  836.    end 
  837.  
  838.    distance_display_on( VOGELS_LIMO_NAME, 0, VOGELS_LIMO_MAX_DIST_METERS, 0, VOGELS_LIMO_MAX_DIST_METERS, SYNC_ALL ) 
  839.    --on_tailing_good( "ep04_reached_vogels_limo_initial" ) 
  840.    on_tailing_good( "ep04_good_distance_from_limo" ) 
  841.    on_tailing_too_far( "ep04_too_far_from_vogels_limo" ) 
  842.    marker_add_vehicle( VOGELS_LIMO_NAME, MINIMAP_ICON_KILL, INGAME_EFFECT_VEHICLE_KILL, SYNC_ALL ) 
  843. end 
  844.  
  845. -- Causes Vogel's limo to continually pathfind in a loop. 
  846. -- 
  847. function ep04_limo_loop_pathfind() 
  848.    --  
  849.    set_ignore_ai_flag( VOGEL_LIMO_DRIVER, true ) 
  850.  
  851.    set_unjackable_flag( VOGELS_LIMO_NAME, true ) 
  852.  
  853.    vehicle_set_crazy( VOGELS_LIMO_NAME, true ) 
  854.    vehicle_disable_chase( VOGELS_LIMO_NAME, true ) 
  855.    vehicle_disable_flee( VOGELS_LIMO_NAME, true ) 
  856.  
  857.    local stop_at_goal = false 
  858.    local navmesh_pathfind = true 
  859.    vehicle_pathfind_to( VOGELS_LIMO_NAME, TO_LOOPING_PATH, navmesh_pathfind, stop_at_goal ) 
  860.  
  861.    while ( true ) do 
  862.       mission_debug( "looping started" ) 
  863.       stop_at_goal = false 
  864.       navmesh_pathfind = false 
  865.  
  866.       for index, path_name in pairs( VOGELS_LIMO_PATHS ) do 
  867.          vehicle_pathfind_to( VOGELS_LIMO_NAME, path_name, navmesh_pathfind, stop_at_goal ) 
  868.       end 
  869.       thread_yield() 
  870.    end 
  871. end 
  872.  
  873. -- Called the first time Vogel's limo is damaged - results in the limo running away faster, to make 
  874. -- it seem to react intelligently to the attack. 
  875. -- 
  876. function ep04_vogel_limo_initial_damage( attacked_object_name, attacker_name, percent_hp_remaining_after_attack ) 
  877.    if ( attacker_name == LOCAL_PLAYER or attacker_name == REMOTE_PLAYER ) then 
  878.       mission_debug( "limo initial damage" ) 
  879.       vehicle_speed_override( VOGELS_LIMO_NAME, VOGELS_LIMO_ESCAPE_SPEED_MPS ) 
  880.  
  881.       on_take_damage( "ep04_vogel_limo_damaged", VOGELS_LIMO_NAME ) 
  882.       ep04_vogel_limo_damaged( attacked_object_name, attacker_name, percent_hp_remaining_after_attack ) 
  883.    end 
  884. end 
  885.  
  886. function ep04_vogel_limo_collision() 
  887.    local cur_hp = get_current_hit_points( VOGELS_LIMO_NAME ) 
  888.    local max_hp = get_max_hit_points( VOGELS_LIMO_NAME ) 
  889.  
  890.    ep04_limo_damage_handler( cur_hp / max_hp ) 
  891. end 
  892.  
  893. -- Called when Vogel's limo is damaged - updates the HUD bar and possibly changes the limo's behavior. 
  894. -- 
  895. function ep04_vogel_limo_damaged( attacked_object_name, attacker_name, percent_hp_remaining_after_attack ) 
  896.    ep04_limo_damage_handler( percent_hp_remaining_after_attack ) 
  897. end 
  898.  
  899. function ep04_limo_damage_handler( percent_hp_remaining_after_attack ) 
  900.    -- Check to see how much damage was done as a percent of the limo's total health - use the limo's current 
  901.    -- health and the percent left after the attack to calculate 
  902.    local cur_limo_hp_percent = ( get_current_hit_points( VOGELS_LIMO_NAME ) / get_max_hit_points( VOGELS_LIMO_NAME ) ) 
  903.    local damage_done_percent = cur_limo_hp_percent - percent_hp_remaining_after_attack 
  904.  
  905.    -- If the remaining HP is less than the flee threshold, then flee if we haven't already. 
  906.    if ( percent_hp_remaining_after_attack <= LIMO_HEALTH_LEVEL_FLEE_PERCENT ) then 
  907.       if ( Vogel_return_to_tower_thread_handle == INVALID_THREAD_HANDLE ) then 
  908.          on_take_damage( "", VOGELS_LIMO_NAME ) 
  909.          on_collision( "", VOGELS_LIMO_NAME ) 
  910.  
  911.          mission_debug( "return to tower pathfind called" ) 
  912.          Vogel_return_to_tower_thread_handle = thread_new( "ep04_limo_return_to_tower_pathfind" ) 
  913.          -- smoke, fire 
  914.          vehicle_set_smoke_and_fire_state( VOGELS_LIMO_NAME, true, false ) 
  915.       end 
  916.    end 
  917.  
  918.    -- We want to set the HP at the normal amount of damage the car would have taken 
  919.    local percent_to_set_hp_at = percent_hp_remaining_after_attack 
  920.  
  921.    -- Do not allow the limo's health to fall below the value it was at when it fled 
  922.    if ( percent_to_set_hp_at <= LIMO_HEALTH_LEVEL_FLEE_PERCENT ) then 
  923.       percent_to_set_hp_at = LIMO_HEALTH_LEVEL_FLEE_PERCENT 
  924.    end 
  925.  
  926.    local cur_limo_max_hp = get_max_hit_points( VOGELS_LIMO_NAME ) 
  927.    local limo_hp_to_set = percent_to_set_hp_at * cur_limo_max_hp 
  928.    set_current_hit_points( VOGELS_LIMO_NAME, limo_hp_to_set ) 
  929.  
  930.    local percent_to_set_bar_at = ( percent_to_set_hp_at - LIMO_HEALTH_LEVEL_FLEE_PERCENT ) / ( 1.0 - LIMO_HEALTH_LEVEL_FLEE_PERCENT ) 
  931.  
  932.    hud_bar_set_value(0, percent_to_set_bar_at, SYNC_ALL ) 
  933. end 
  934.  
  935. -- Causes Vogel's limo to return to the Phillips tower when it's been 
  936. -- damaged enough. 
  937. -- 
  938. function ep04_limo_return_to_tower_pathfind() 
  939.    mission_debug( "vogel's limo returning to the tower called" ) 
  940.  
  941.    -- Stop "He's getting away!" mission failure and clear out any messages 
  942.    if ( Limo_getting_away_thread_handle ~= INVALID_THREAD_HANDLE ) then 
  943.       thread_kill( Limo_getting_away_thread_handle ) 
  944.       Limo_getting_away_thread_handle = INVALID_THREAD_HANDLE 
  945.       mission_help_clear( SYNC_ALL ) 
  946.    end 
  947.    hud_bar_off(0) 
  948.    hud_timer_stop(0) 
  949.    distance_display_off(SYNC_ALL) 
  950.  
  951.    mission_help_table_nag( HT_VOGELS_HEADING_BACK ) 
  952.  
  953.    vehicle_speed_override( VOGELS_LIMO_NAME, VOGELS_LIMO_RETURN_TO_BASE_SPEED_MPS ) 
  954.  
  955.    thread_kill( Vogel_limo_pathfinding_thread_handle ) 
  956.    Vogel_limo_pathfinding_thread_handle = INVALID_THREAD_HANDLE 
  957.  
  958.    -- Pathfind up to the first point, still on the road 
  959.    local stop_at_goal = false 
  960.    local navmesh_pathfind = false 
  961.    vehicle_pathfind_to( VOGELS_LIMO_NAME, PHILLIPS_TOWER_LIMO_RETURN_POINT_ONE, navmesh_pathfind, stop_at_goal ) 
  962.  
  963.    mission_debug( "return part 1 finished" ) 
  964.  
  965.    -- Now continue on the navmesh till you're near the structure 
  966.    stop_at_goal = true 
  967.    navmesh_pathfind = true 
  968.    vehicle_pathfind_to( VOGELS_LIMO_NAME, PHILLIPS_TOWER_LIMO_RETURN_POINT_TWO, navmesh_pathfind, stop_at_goal ) 
  969.  
  970.    set_ignore_ai_flag( VOGEL_LIMO_DRIVER, false ) 
  971.    mission_debug( "return part 2 finished" ) 
  972.  
  973.  
  974.    marker_remove_vehicle( VOGELS_LIMO_NAME ) 
  975.  
  976.    mission_debug( "vogel enter tower ..." ) 
  977.    ep04_setup_state( MS_VOGEL_ENTER_THE_TOWER ) 
  978. end 
  979.  
  980. function ep04_all_players_too_far_from_limo() 
  981.    if ( Players_in_range_of_limo[LOCAL_PLAYER] == false ) then 
  982.       if ( coop_is_active() ) then 
  983.          if ( Players_in_range_of_limo[REMOTE_PLAYER] == false ) then 
  984.             return true 
  985.          end 
  986.       else 
  987.          return true 
  988.       end 
  989.    end 
  990.  
  991.    return false 
  992. end 
  993.  
  994. function ep04_reached_vogels_limo_initial() 
  995.    mission_debug( "reached initial" ) 
  996.    on_tailing_good( "ep04_good_distance_from_limo" ) 
  997.    on_tailing_too_far( "ep04_too_far_from_vogels_limo" ) 
  998. end 
  999.  
  1000. function ep04_good_distance_from_limo( triggerer_name ) 
  1001.    Players_in_range_of_limo[triggerer_name] = true 
  1002.  
  1003.    if ( Limo_getting_away_thread_handle ~= INVALID_THREAD_HANDLE ) then 
  1004.       thread_kill( Limo_getting_away_thread_handle ) 
  1005.       mission_help_clear( SYNC_ALL ) 
  1006.       Limo_getting_away_thread_handle = INVALID_THREAD_HANDLE 
  1007.    end 
  1008. end 
  1009.  
  1010. function ep04_too_far_from_vogels_limo( triggerer_name ) 
  1011.    Players_in_range_of_limo[triggerer_name] = false 
  1012.  
  1013.    if ( ep04_all_players_too_far_from_limo() ) then 
  1014.       Limo_getting_away_thread_handle = thread_new( "ep04_vogel_fail_help_text_timer" ) 
  1015.    end 
  1016. end 
  1017.  
  1018. function ep04_helicopter_destroyed() 
  1019.    mission_end_failure( MISSION_NAME, HT_HELICOPTER_DESTROYED ) 
  1020. end 
  1021.  
  1022. function ep04_vogel_fail_help_text_timer() 
  1023.    local cur_time_left_seconds = CHASE_VOGEL_FAIL_TIME_MS / 1000 
  1024.    mission_help_table_nag( HT_CATCH_UP, cur_time_left_seconds ) 
  1025.    while ( cur_time_left_seconds > 0 ) do 
  1026.       delay( TIME_PER_CATCH_UP_UPDATE_SECONDS ) 
  1027.       cur_time_left_seconds = cur_time_left_seconds - TIME_PER_CATCH_UP_UPDATE_SECONDS 
  1028.       mission_help_table_nag( HT_CATCH_UP, cur_time_left_seconds ) 
  1029.    end 
  1030.  
  1031.    mission_end_failure( MISSION_NAME, HT_VOGEL_ESCAPED ) 
  1032. end 
  1033.  
  1034. function ep04_cleanup() 
  1035. 	-- Cleanup mission here 
  1036.    notoriety_set_min( ENEMY_GANG, 0 ) 
  1037.    on_vehicle_enter( "", LOCAL_PLAYER ) 
  1038.    if ( coop_is_active() ) then 
  1039.       on_vehicle_enter( "", REMOTE_PLAYER ) 
  1040.    end 
  1041.    on_tailing_good( "" ) 
  1042.    on_tailing_too_far( "" ) 
  1043.    distance_display_off(SYNC_ALL) 
  1044.     
  1045.    vehicle_set_untowable( VOGELS_LIMO_NAME, false ) 
  1046.  
  1047.    for index, effect_handle in pairs( Node_smoke_handles ) do 
  1048.       if ( effect_handle ~= INVALID_EFFECT_HANDLE ) then 
  1049.          effect_stop( effect_handle ) 
  1050.       end 
  1051.    end 
  1052.  
  1053.    if ( Marked_node_currently_marked == true ) then 
  1054.       marker_remove_navpoint( NODE_MARKER_LOCATIONS[Currently_marked_node_name], SYNC_ALL ) 
  1055.    end 
  1056.  
  1057.    -- If either player is in the attack helicopter, release it to the world so that 
  1058.    -- they don't fall to their deaths. 
  1059.    if ( character_is_in_vehicle( LOCAL_PLAYER, ATTACK_HELICOPTER ) ) then 
  1060.       release_to_world( ATTACK_HELICOPTER_GROUP ) 
  1061.    elseif ( coop_is_active() ) then 
  1062.       if ( character_is_in_vehicle( REMOTE_PLAYER, ATTACK_HELICOPTER ) ) then 
  1063.          release_to_world( ATTACK_HELICOPTER_GROUP ) 
  1064.       end 
  1065.    end 
  1066.     
  1067.    action_nodes_restrict_spawning(false) 
  1068.  
  1069. 	if ( Entered_tower ) then 
  1070. 		teleport( LOCAL_PLAYER, LOCAL_FRONT_OF_TOWER ) 
  1071. 		if ( coop_is_active() ) then 
  1072. 			teleport( REMOTE_PLAYER, REMOTE_FRONT_OF_TOWER ) 
  1073. 		end 
  1074. 	end 
  1075.  
  1076.    -- Swap the tower back to the blown up state if this mission was being replayed 
  1077.    if ( mission_is_complete( MISSION_NAME ) ) then 
  1078.       local interior, blocking, temporary 
  1079.       interior = true 
  1080.       blocking = false 
  1081.       temporary = false 
  1082.    	city_chunk_swap("SR2_IntSRMisPhiltwr", "blowup", interior, blocking, temporary ) 
  1083.    end 
  1084.    inv_weapon_enable_or_disable_all_slots( true ) 
  1085.    mid_mission_phonecall_reset() 
  1086. 	homie_mission_unlock("gat")  
  1087. end 
  1088.  
  1089. function ep04_success() 
  1090. 	-- Called when the mission has ended with success 
  1091.  
  1092. 	-- Post the news event 
  1093. 	radio_post_event("JANE_NEWS_TSSE04", true) 
  1094.  
  1095. end 
  1096.