//**************************************************************************** // ** // Confidential - (C) Activision Publishing, Inc. 2010 ** // ** //**************************************************************************** // ** // Module: Border, Border ** // ** // Created: 11/11/11 - Travis Chen (trchen x 4143) ** // ** //**************************************************************************** #include maps\_utility; #include maps\_nx_utility; #include common_scripts\utility; #include maps\_vehicle; #include maps\_anim; //******************************************************************* // * // * //******************************************************************* border_start() { maps\nx_border_util::player_start( "player_start_border" ); } border() { // Global variables level.vehicle_convoy = []; level.convoy_player_vehicle_allies = []; level.allies = []; level.border_enemies = []; level.enemy_vehicles = []; level.convoy_intro_speed = undefined; // Threat bias groups CreateThreatBiasGroup( "player" ); CreateThreatBiasGroup( "enemies" ); level._player SetThreatBiasGroup( "player" ); // Spawn convoy with allies and player and set on path thread convoy_driveup(); // Dialogue for section thread border_dialogue(); // Sets flag for when player is at border thread player_at_border(); // Setup the vehicle path disconnector //run_thread_on_targetname( "vehicle_path_disconnector", maps\nx_border_util::vehicle_path_disconnector ); // Spawn initial baddies level.border_enemies[ "wave_1" ] = spawn_enemy_ground_wave( "actor_axis_wave_1", "notify_unloading_convoy", ::spawnfunc_enemy_initial_ground_wave, "flag_wave_1_half_dead", "flag_wave_1_almost_dead", "flag_wave_1_dead" ); level.border_enemies[ "roof_1" ] = []; level.border_enemies[ "bridge" ] = []; thread spawn_enemy_rooftops( "bridge", "actor_axis_wave_roof_1", "notify_unloading_convoy", ::spawnfunc_enemy_rooftops_bridge ); thread spawn_enemy_rooftops( "roof_1", "actor_axis_wave_roof_2", "notify_unloading_convoy", ::spawnfunc_enemy_rooftops_rpg ); thread spawn_enemy_rooftops( "border_rpg", "actor_border_rocket", "notify_spawn_border_rpgs", ::spawnfunc_enemy_border_bridge_rpg ); // Setup spawn functions for baddies that will be spawned during gameplay level.border_enemies[ "border_bridge_rpg" ] = []; level.border_enemies[ "border_buildings" ] = []; //array_spawn_function_noteworthy( "actor_border_rocket", ::spawnfunc_enemy_border_bridge_rpg, "border_bridge_rpg" ); //array_spawn_function_noteworthy( "actor_border_left_buildings", ::spawnfunc_enemy_building_side_spawn, "border_buildings" ); array_spawn_function_noteworthy( "actor_border_right_buildings", ::spawnfunc_enemy_building_side_spawn, "border_buildings" ); // Enemy vehicles drop off wave 2 thread spawn_enemy_vehicle( "veh_1", "vehicle_enemy_1", "node_enemy_drive_in_1", "node_enemy_pickup_cover_1" ); thread spawn_enemy_vehicle( "veh_2", "vehicle_enemy_2", "node_enemy_drive_in_2", "node_enemy_pickup_cover_2" ); // Send enemies to border thread enemy_movement(); // Razor Wire //thread razor_wire(); // Kills snipers once player is in intersection thread advance_2_cleanup(); // Cleans up rest of border thread border_cleanup(); // Shut off building triggers once allies advance thread turn_off_spawners(); // AUtosaves thread autosaves(); } //******************************************************************* // * // * //******************************************************************* section_precache() { PreCacheShellShock( "nx_border_intro" ); PreCacheModel( "nx_vehicle_border_hummer2" ); } section_flag_inits() { flag_init( "flag_player_advance_1" ); flag_init( "flag_wave_1_half_dead" ); flag_init( "flag_wave_1_almost_dead" ); flag_init( "flag_wave_1_dead" ); flag_init( "flag_wave_2_half_dead" ); flag_init( "flag_wave_2_almost_dead" ); flag_init( "flag_wave_2_dead" ); flag_init( "flag_advance_1_timeout" ); flag_init( "flag_border_final_advance" ); flag_init( "flag_border_done" ); flag_init( "flag_advance_1" ); flag_init( "flag_advance_2" ); flag_init( "flag_advance_3" ); flag_init( "flag_border_intro_start" ); flag_init( "flag_player_at_border" ); } //******************************************************************* // * // * //******************************************************************* section_objectives( objective_num ) { level waittill( "notify_border_intro_player_anim_done" ); objective_add( objective_num, "current", &"NX_BORDER_OBJECTIVE_BORDER" ); flag_wait( "flag_border_done" ); objective_complete( objective_num ); objective_num++; return objective_num; } //******************************************************************* // * // * //******************************************************************* autosaves() { // Autosave after explosion //level waittill( "notify_border_explosion_done" ); level waittill( "notify_border_intro_player_anim_done" ); thread autosave_by_name( "border_intro_done" ); // Autosave after all enemies dead flag_wait( "flag_border_done" ); thread autosave_by_name( "border_done" ); } //******************************************************************* // * // * //******************************************************************* // Spawn convoy vehicles and allies convoy_driveup() { // Spawn vehicles and allies spawn_convoy_vehicles_and_allies(); level.convoy_intro_speed = GetSpeedFromAnims(); //level.convoy_intro_speed = 1; thread ally_movement(); // Set vehicles on their paths level.vehicle_convoy[ "vehicle_convoy_1" ] thread convoy_path_solo( "node_convoy_start_1", "node_convoy_1_stop_1", "node_convoy_1_stop_2", "node_convoy_1_stop_3", "node_convoy_1_stop_4" ); level.vehicle_convoy[ "vehicle_convoy_2" ] thread convoy_path_solo( "node_convoy_start_2", "node_convoy_2_stop_1", "node_convoy_2_stop_2", "node_convoy_2_stop_3", "node_convoy_2_stop_4" ); //tagJC: This section is for deleting the bad place brush. Currently commented out until the convoy is moving again //delete_bad_place_node = GetVehicleNode ( "node_convoy_1_stop_1", "targetname" ); //assert ( isDefined (delete_bad_place_node )); //delete_bad_place_node thread maps\nx_border_util::waitForVehicleToPass(); //*********************************************************************************** // Ally vehicle gets destroyed during intro level.vehicle_convoy[ "vehicle_convoy_kill" ] thread convoy_path_kill( "node_convoy_start_kill", "node_convoy_kill_1" ); } //******************************************************************* // * // * //******************************************************************* spawn_convoy_vehicles_and_allies() { // Get convoy vehicle spawners convoy_spawners = GetEntArray( "vehicle_convoy", "script_noteworthy" ); Assert( IsDefined( convoy_spawners )); array_thread( convoy_spawners, ::add_spawn_function, ::spawnfunc_convoy_vehicle ); // Setup ally spawners squad = GetEntArray( "actor_squad", "script_noteworthy" ); Assert( IsDefined( squad )); array_thread( squad, ::add_spawn_function, ::spawnfunc_allies ); intro_hummer_allies = []; intro = false; // Spawn vehicles and allies foreach( vehicle in convoy_spawners ) { // Setup allies Assert( IsDefined( vehicle.targetname )); Assert( IsDefined( vehicle.target )); // If it's the border checkpoint, add the other allies to the vehicle if(( level._start_point == "default" ) || ( level._start_point == "border" )) { intro = true; if( vehicle.targetname == "vehicle_convoy_1" ) { allies = GetEntArray( vehicle.targetname + "_ally_group", "targetname" ); Assert( IsDefined( allies )); foreach( spawner in allies ) { // Allies with spawn with vehicle spawner.targetname = vehicle.target; } } else { allies = GetEntArray( vehicle.targetname + "_ally_group", "targetname" ); Assert( IsDefined( allies )); foreach( spawner in allies ) { // Spawn allies separate from hummer so we can apply intro anims ally = spawner spawn_ai(); intro_hummer_allies = array_add( intro_hummer_allies, ally ); } } } else { // Starting from another checkpoint (than border/default) allies = GetEntArray( vehicle.targetname + "_ally_group", "targetname" ); Assert( IsDefined( allies )); foreach( ally in allies ) { Assert( IsDefined( ally.script_startingposition )); // Attach drivers if( ally.script_startingposition == 0 ) ally.targetname = vehicle.target; } } // Spawn vehicle level.vehicle_convoy[ vehicle.targetname ] = vehicle spawn_vehicle(); level.vehicle_convoy[ vehicle.targetname ].script_parameters = vehicle.targetname; } // Intro anims if( intro ) { level.vehicle_convoy[ "vehicle_convoy_2" ] thread convoy_intro_anims( intro_hummer_allies ); } } // spawnfunc for convoy vehicles spawnfunc_convoy_vehicle() { self godon(); } // spawnfunc for allies spawnfunc_allies() { if( IsDefined( level.leader )) { if( self == level.leader ) { return; } } self thread magic_bullet_shield(); // tagTC - Remove magic bullet shield when turret is destroyed // or player has pushed through the intro blockade section flag_wait_either( "intro_turret_destroyed", "player_through_intro_funnel" ); self stop_magic_bullet_shield(); } // Wait for death, then report attacker death_watch() { self waittill( "death", attacker ); iprintlnbold( attacker.classname ); } //******************************************************************* // * // * //******************************************************************* // Intro animations convoy_intro_anims( riders ) { actors = []; //node = GetEnt( "intro_test", "targetname" ); //anim_origin = spawn( "script_origin", self.origin ); //anim_origin LinkTo( self, "tag_origin", (0, 0, 0), (0, 0, 0) ); unload_guys = []; driver = undefined; // Setup guys Assert( IsDefined( riders )); foreach( guy in riders ) { Assert( IsDefined( guy.script_startingposition )); switch( guy.script_startingposition ) { case 0: guy.animname = "driver"; driver = guy; break; case 1: guy.animname = "passengerfront"; unload_guys = array_add( unload_guys, guy ); break; case 3: guy.animname = "passengerrear"; unload_guys = array_add( unload_guys, guy ); break; default: AssertMsg( "nx_border_border: Unknown ally vehicle starting position (" + guy.script_startingposition + ") for intro anim!" ); } guy LinkTo( self ); actors = array_add( actors, guy ); } // Setup humvee, hide script vehicle, spawn in animated script model intro_hummer = spawn_anim_model( "player_humvee", ( self.origin )); // Windshield intro_hummer thread convoy_intro_anims_broken_windshield(); intro_hummer thread maps\nx_border_fx::fx_hummer_interior_light(); intro_hummer LinkTo( self ); self Hide(); actors = array_add( actors, intro_hummer ); intro_hummer playsound("scn_border_intro_hummer_explo_lr"); // Setup player to ride self thread player_driveup(); // Start intro anims flag_set( "flag_border_intro_start" ); self anim_single( actors, "intro_ride", "tag_origin" ); // End of animation // unlink guys, show hummer level notify( "notify_border_intro_complete" ); foreach( guy in unload_guys ) { guy Unlink(); } // Start driver idle self thread anim_loop_solo( driver, "idle", undefined, "tag_driver" ); // Put hummer back //self Show(); //intro_hummer Delete(); } //******************************************************************* // * // * //******************************************************************* convoy_intro_anims_broken_windshield() { // Hide broken windshield self HidePart( "TAG_GLASS_FRONT_D" ); self HidePart( "TAG_GLASS_FRONT_FX" ); level waittill( "notify_border_intro_player_loses_control" ); // Show broken windshield wait 0.5; self ShowPart( "TAG_GLASS_FRONT_FX" ); } //******************************************************************* // * // * //******************************************************************* // Will return the mi/h to set vehicles at start of level based on anim times GetSpeedFromAnims() { humvee_anim_time = GetAnimLength( level._scr_anim[ "player_humvee" ][ "intro_ride" ] ); player_anim_time = GetAnimLength( level._scr_anim[ "player_rig" ][ "intro_ride" ] ); // Find time to explosion in hours anim_time = (humvee_anim_time - player_anim_time) * ((1/60)/60); start = GetVehicleNode( "node_convoy_start_kill", "targetname" ); end = GetVehicleNode( "node_convoy_kill_1", "targetname" ); Assert( IsDefined( start )); Assert( IsDefined( end )); // Find distance from start node to explosion node (in miles). Subtracting a bit since the vehicle hits the node is slightly out of alignment with the vehicle's origin. distance = ( Distance( start.origin, end.origin ) - 56 ) * 0.000015782828283; speed = distance / anim_time; return speed; } //******************************************************************* // * // * //******************************************************************* spawn_enemy_vehicle( veh_name, tVehicle, sNodes_path, sNodes_cover ) { // Grab vehicle spawner vehicle = GetEnt( tVehicle, "targetname" ); Assert( IsDefined( vehicle )); Assert( IsDefined( vehicle.target )); // Grab rider spawners targets = GetEntArray( vehicle.target, "targetname" ); Assert( IsDefined( targets )); foreach( target in targets ) { if( IsSubStr( target.classname, "actor" )) { target add_spawn_function( ::spawnfunc_enemy_vehicle ); } } // Wait for first push flag_wait( "flag_advance_1" ); // Spawn and drive level.enemy_vehicles[ veh_name ] = vehicle spawn_vehicle_and_gopath(); level.border_enemies[ veh_name ] = level.enemy_vehicles[ veh_name ].riders; level.enemy_vehicles[ veh_name ] waittill( "reached_end_node" ); level.enemy_vehicles[ veh_name ] vehicle_unload(); level notify( "notify_border_add_razor_wire" ); } //******************************************************************* // * // * //******************************************************************* // Controls razor wire blocking border razor_wire() { wire_brush = GetEnt( "brushmodel_razorwire", "targetname" ); Assert( IsDefined( wire_brush )); level waittill( "notify_border_add_razor_wire" ); // // Razor wire pullout // enemy_pullout_wire = maps\_nx_vignette_util::vignette_actor_spawn("vignette_razorwire_enemy", "enemy_pullout_wire"); node = getstruct("vignette_razorwire", "script_noteworthy"); razorwire = spawn_anim_model("razorwire_pullout"); razorwire02 = spawn_anim_model("razorwire_pullout_02"); Assert( IsDefined( enemy_pullout_wire )); Assert( IsDefined( node )); Assert( IsDefined( razorwire )); guys = []; guys["enemy_pullout_wire"] = enemy_pullout_wire; guys["razorwire_pullout"] = razorwire; guys["razorwire_pullout_02"] = razorwire02; node anim_single(guys, "razorwire_pullout"); enemy_pullout_wire maps\_nx_vignette_util::vignette_actor_delete(); // // Razor wire pullback // level waittill( "notify_border_outro_remove_wire" ); while( 1 ) { ally = random( level.allies ); if( ally.script_startingposition != 0 ) break; } ally.animname = "ally_pullback_wire"; razorwire.animname = "razorwire_pullback"; razorwire02.animname = "razorwire_pullback_02"; guys = []; guys["ally_pullback_wire"] = ally; guys["razorwire_pullback"] = razorwire; guys["razorwire_pullback_02"] = razorwire02; ally playsound("scn_border_barbed_wire_remove"); node anim_reach_solo( guys["ally_pullback_wire"], "razorwire_pullback" ); node anim_single( guys, "razorwire_pullback" ); level notify( "notify_border_razor_wire_done" ); // Wait until last line, then put ally back on color grid level waittill( "notify_border_outro_dialogue_complete" ); // // Connect paths and done! // wire_brush ConnectPaths(); wire_brush Delete(); ally enable_ai_color(); } //******************************************************************* // * // * //******************************************************************* // Ally hummer bumps enemy vehicle convoy_vehicle_bump() { // Wait until the specified "bump" vehicle node self vehicle_waittill_node( "node_border_vehicle_bump", "targetname" ); level notify( "notify_border_hummer_bump" ); // Enemy vehicle enemy_veh = level.enemy_vehicles[ "veh_1" ]; // Ally vehicle speeds through and bumps enemy vehicle force_pos = enemy_veh.origin + (((-1) * AnglesToForward( enemy_veh.angles )) * 32 ); force_vec = (((-1) * AnglesToRight( self.angles )) + AnglesToForward( self.angles )) * 100; self playsound( "scn_border_humvee_hit" ); self Vehicle_SetSpeed( 15, 5 ); wait 0.5; enemy_veh VehPhys_Launch( force_vec, undefined, force_pos ); //enemy_veh PlaySound( "scn_car_crash" ); wait 1; self ResumeSpeed( 3 ); } //******************************************************************* // * // * //******************************************************************* // Player's drive up sequence player_driveup() { // Set up player legs player_legs_spawner = GetEnt( "actor_border_intro_player_legs", "targetname" ); Assert( IsDefined( player_legs_spawner )); //player_legs = player_legs_spawner spawn_ai(); //Assert( IsDefined( player_legs )); //player_legs.animname = "player_legs"; // Take weapons enablePlayerWeapons( false ); level._player allowprone( false ); level._player allowcrouch( false ); // Bulletproof level._player magic_bullet_shield(); level._player.ignoreme = true; // Setup the player's rig and attach to hummer player_rig = spawn_anim_model( "player_rig" ); player_rig.angles = self getTagAngles( "tag_passenger" ); // Adjust player position in car relative to the "tag_passenger" player_rig.origin = self getTagOrigin( "tag_passenger" ) - (0,0,92) + vector_multiply( (-1) * AnglesToForward( self.angles ), 45 ) + vector_multiply( (-1) * AnglesToRight( self.angles ), 57 ); player_rig linkTo( self, "tag_passenger" ); //player_rig hide(); level._player playerLinkToDelta( player_rig, "tag_player", 1.0, 80, 80, 60, 20 ); // Wait for notetrack, then take player control away and play level waittill( "notify_border_intro_player_loses_control" ); //level._player playerLinkToDelta( player_rig, "tag_origin", 0, 0, 0, 0, 0 ); level._player shellshock( "nx_border_intro", 8 ); self thread maps\nx_border_fx::fx_border_cabin_smoke(); // PlayFX( GetFx( "border_intro_smoke" ), self.origin ); //self thread anim_single_solo( player_legs, "intro_ride" ); self anim_single_solo( player_rig, "intro_ride" ); /* // Wait for convoy unload self waittill( "notify_unloading_convoy" ); // Unload player (Spawn an exit point location and move player to it) exit_point = spawn_tag_origin(); exit_point.origin = GetGroundPosition( player_rig.origin + vector_multiply( (-1) * AnglesToRight( self.angles ), 40 ), 5 ); exit_point.angles = self.angles; dummy = spawn( "script_model", level._player.origin ); dummy.angles = level._player GetPlayerAngles(); dummy setmodel( "tag_origin" ); level._player playerLinkTo( dummy, "tag_player", 1.0, 45, 45, 45, 20 ); MOVETIME = 1.5; ACCEL = 0.3; DECEL = 0.3; dummy moveTo( exit_point.origin, MOVETIME, ACCEL, DECEL ); dummy rotateTo( exit_point.angles, MOVETIME, ACCEL, DECEL ); wait( MOVETIME ); //level waittill( "notify_border_intro_complete" ); */ level notify( "notify_border_intro_player_anim_done" ); // UnBulletproof level._player stop_magic_bullet_shield(); level._player.ignoreme = false; level._player unlink(); player_rig delete(); //player_legs delete(); flag_set( "music_battle_start" ); // Give player weapons enablePlayerWeapons( true ); level._player allowprone( true ); level._player allowcrouch( true ); } //******************************************************************* // * // * //******************************************************************* // Controls movement of convoy vehicles convoy_path_solo( start_node, stop_node_1, stop_node_2, stop_node_3, stop_node_4 ) { flag_wait( "flag_border_intro_start" ); // Setup start of path and move path = GetVehicleNode( start_node, "targetname" ); Assert( IsDefined( path )); self AttachPath( path ); self Vehicle_SetSpeedImmediate( level.convoy_intro_speed, level.convoy_intro_speed ); self StartPath(); // First stopping point self vehicle_waittill_node( stop_node_1, "targetname" ); self Vehicle_SetSpeed( 0, 10 ); // Unload self notify( "notify_unloading_convoy" ); level notify( "notify_unloading_convoy" ); Assert( IsDefined( self.script_parameters )); if( self.script_parameters == "vehicle_convoy_1" ) self vehicle_unload(); /* flag_wait( "flag_advance_1" ); // Wait for convoy_1 to move first Assert( IsDefined( self.script_parameters )); if( self.script_parameters == "vehicle_convoy_2" ) wait( 1 ); self Vehicle_SetSpeed( 3, 1 ); self thread maps\nx_border_util::actor_detection_movement_control( 300, 45 ); // Second stopping point self vehicle_waittill_node( stop_node_2, "targetname" ); self notify ( "terminate_actor_detection" ); self Vehicle_SetSpeed( 0, 10 ); flag_wait( "flag_advance_2" ); // Wait for convoy_1 to move first Assert( IsDefined( self.script_parameters )); if( self.script_parameters == "vehicle_convoy_2" ) wait( 1 ); self ResumeSpeed( 3 ); self thread maps\nx_border_util::actor_detection_movement_control( 300, 45 ); // Third stopping point self vehicle_waittill_node( stop_node_3, "targetname" ); self notify ( "terminate_actor_detection" ); self Vehicle_SetSpeed( 0, 10 ); flag_wait( "flag_border_final_advance" ); // Wait for convoy_1 to move first, if convoy 1, setup bump Assert( IsDefined( self.script_parameters )); if( self.script_parameters == "vehicle_convoy_2" ) { wait( 1 ); self ResumeSpeed( 3 ); self thread maps\nx_border_util::actor_detection_movement_control( 300, 45 ); } else { // Vehicle 1 convoy bump sequence self ResumeSpeed( 3 ); self thread maps\nx_border_util::actor_detection_movement_control( 300, 45 ); self convoy_vehicle_bump(); } // Last stopping point self vehicle_waittill_node( stop_node_4, "targetname" ); self notify ( "terminate_actor_detection" ); self Vehicle_SetSpeed( 0, 10 ); level notify( "notify_convoy_stopped" ); */ } //******************************************************************* // * // * //******************************************************************* // Convoy vehicle that gets killed convoy_path_kill( start_node, stop_node_1 ) { // Setup start of path and move path = GetVehicleNode( start_node, "targetname" ); Assert( IsDefined( path )); self AttachPath( path ); self Vehicle_SetSpeed( level.convoy_intro_speed, 1 ); self StartPath(); self thread maps\nx_border_fx::fx_border_explosion(); self waittill( "reached_end_node" ); // Flip vehicle and kill it self VehPhys_Launch( (AnglesToUp( self.angles ) + ((-1) * AnglesToRight( self.angles ))) * 40000, undefined, self.origin + vector_multiply( AnglesToRight( self.angles ), 32) ); self kill(); //slowmo(); level notify( "notify_border_explosion_done" ); } slowmo() { // Don't slowmo sounds SoundSetTimeScaleFactor( "Mission", 0 ); SoundSetTimeScaleFactor( "Shellshock", 0 ); SoundSetTimeScaleFactor( "Voice", 0 ); SoundSetTimeScaleFactor( "Menu", 0 ); SoundSetTimeScaleFactor( "Effects1", 0 ); SoundSetTimeScaleFactor( "Effects2", 0 ); SoundSetTimeScaleFactor( "Announcer", 0 ); SoundSetTimeScaleFactor( "Music", 0 ); SoundSetTimeScaleFactor( "vignette3d", 0 ); SoundSetTimeScaleFactor( "vignette2d", 0 ); SoundSetTimeScaleFactor( "ambient", 0 ); SoundSetTimeScaleFactor( "weapon", 0 ); SoundSetTimeScaleFactor( "weapon2d", 0 ); SoundSetTimeScaleFactor( "auto2d", 0 ); SoundSetTimeScaleFactor( "auto", 0 ); SoundSetTimeScaleFactor( "auto2d", 0 ); SoundSetTimeScaleFactor( "element", 0 ); SoundSetTimeScaleFactor( "local", 0 ); SoundSetTimeScaleFactor( "local3", 0 ); SoundSetTimeScaleFactor( "physics", 0 ); // Start slow motion slowmo_setspeed_slow( 0.5 ); slowmo_setlerptime_in( 0 ); slowmo_lerp_in(); level._player SetMoveSpeedScale( 0.1 ); // Wait slow mo duration wait( 2 ); // Stop slo motion slowmo_setlerptime_out( 0 ); slowmo_lerp_out(); } //******************************************************************* // * // * //******************************************************************* // Controls movement of allies ally_movement() { badplace = GetEnt( "vol_border_badplace_1", "targetname" ); Assert( IsDefined( badplace )); badplace DisconnectPaths(); // Timer to force first advancement of allies //thread advance_1_timeout(); level waittill( "notify_unloading_convoy" ); issue_color_orders( "r1", "allies" ); issue_color_orders( "y1", "allies" ); flag_wait_any( "flag_wave_1_almost_dead", "flag_player_advance_1", "flag_advance_1_timeout" ); flag_set( "flag_advance_1" ); level notify( "notify_spawn_wave_2" ); badplace ConnectPaths(); badplace delete(); //issue_color_orders( "r2", "allies" ); //issue_color_orders( "y2", "allies" ); // Wait for two vehicles to spawn while( level.enemy_vehicles.size < 2 ) wait 0.05; thread enemy_dead_flag_set( "all", 7, "flag_advance_2", "notify_spawn_border_rpgs" ); flag_wait_any( "flag_advance_2", "flag_player_advance_2" ); flag_set( "flag_advance_2" ); level notify( "notify_spawn_border_rpgs" ); //issue_color_orders( "r3", "allies" ); //issue_color_orders( "y3", "allies" ); /* flag_wait( "flag_border_done" ); issue_color_orders( "r4", "allies" ); issue_color_orders( "y4", "allies" ); level waittill( "notify_border_outro_dialogue_complete" ); */ // Up ally accuracy to take out stragglers in retreat level waittill( "notify_border_final_retreat" ); foreach( guy in level.allies ) { guy.baseaccuracy = 10000; } // Disable color triggers triggers = GetEntArray( "trig_border_colors", "script_noteworthy" ); Assert( IsDefined( triggers )); foreach( trigger in triggers ) trigger trigger_off(); wait( 0.05 ); issue_color_orders( "r99", "allies" ); issue_color_orders( "y99", "allies" ); flag_wait( "flag_border_done" ); // Return ally accuracy after all enemies dead foreach( guy in level.allies ) { guy.baseaccuracy = 1; } issue_color_orders( "r100", "allies" ); issue_color_orders( "y100", "allies" ); } //******************************************************************* // * // * //******************************************************************* // Player reaches border player_at_border() { trigger_wait_targetname( "trig_border_player_at_border" ); flag_set( "flag_player_at_border" ); } //******************************************************************* // * // * //******************************************************************* player_in_side_building() { level endon( "flag_border_done" ); trigger_wait_targetname( "trig_border_player_in_right_building" ); SetThreatBias( "enemies", "player", 1000 ); // Have allies take out RPGs so they can progress foreach( guy in level.border_enemies[ "border_rpg" ] ) { if( IsAlive( guy )) { foreach( ally in level.allies ) { ally.favoriteenemy = guy; ally.baseaccuracy = 1000; } while( IsAlive( guy )) wait( 0.05 ); } } while( IsAlive_array( level.border_enemies[ "border_rpg" ] )) wait 0.05; // Lower ally accuracy foreach( ally in level.allies ) { ally.baseaccuracy = 1; } } //******************************************************************* // * // * //******************************************************************* player_on_rooftop() { level endon( "flag_border_done" ); while( 1 ) { flag_wait( "flag_border_player_rooftop" ); SetThreatBias( "enemies", "player", 1000 ); flag_waitopen( "flag_border_player_rooftop" ); SetThreatBias( "enemies", "player", 0 ); } } //******************************************************************* // * // * //******************************************************************* border_dialogue() { battlechatter_off( "allies" ); battlechatter_off( "axis" ); /* // // Intro // // Dialogue: Loudspeaker - "Mexico is a sovreign country and we will not submit to this unauthorized invasion of our border. // Proceed and you will be fired upon with the full resources of the Mexican Army. Stop and stand down." thread radio_dialogue( "bor_ancr_intro_warning" ); wait 3; // Dialogue: Chief - "Convoy 6-2, Battalion Chief, proceed with assault plan Alpha, // I repeat proceed with assault plan Alpha and push through the checkpoint into Mexico to establish our buffer zone." radio_dialogue_overlap( "bor_chf_intro_proceed" ); // Dialogue: Leader - "Get ready fellas, this might get hairy quick." radio_dialogue_overlap( "bor_bak_intro_mightgethairy" ); // Dialogue: Humvee Driver - "Hooah" thread radio_dialogue_overlap( "bor_hum_intro_hooah" ); // Dialogue: Ally - "Hooah" thread radio_dialogue_overlap( "bor_gon_intro_hooah" ); wait 7; // Dialogue: Chief - "Incoming R-P-!" (get's cutoff by the explosion) radio_dialogue_overlap( "bor_chf_intro_incoming" ); wait 2; // Dialogue: Humvee Driver - "Shit, everybody ok?" radio_dialogue( "bor_hum_intro_everybodyok" ); wait 1; // Dialogue: Leader - "Exit the vehicle!" radio_dialogue( "bor_bak_intro_exitvehicle" ); // Dialogue: Ally - (Grunts, Groans, trying to free himself of his seatbelt) thread radio_dialogue( "bor_gon_intro_grunts" ); wait 1; // Dialogue: Humvee Driver - "You, get out, go, go, go!" thread radio_dialogue_overlap( "bor_hum_intro_getoutgogogo" ); wait 2; // Dialogue: Leader - "C'mon! Let's go!" radio_dialogue_overlap( "bor_bak_intro_cmonletsgo" ); */ level waittill( "notify_border_intro_player_anim_done" ); flag_wait( "flag_advance_1" ); // Dialogue: Leader - "Panther One to Olympus, come in!" level.leader dialogue_queue( "bor_bak_battle_olympuscomein" ); // Dialogue: Command - "Panther One, this is Olympus, what is your sitrep? Over." radio_dialogue( "bor_oly_battle_sitrep" ); // Dialogue: Leader - "We're encountering heavy fire at the border checkpoint, over!" level.leader dialogue_queue( "bor_bak_battle_heavyfire" ); // Dialogue: Command - "Roger Panther One. Hawks with eggs are inbound. ETA 2 mikes." radio_dialogue( "bor_oly_battle_hawksinbound" ); battlechatter_on( "allies" ); battlechatter_on( "axis" ); // // RPGs above border // thread border_dialogue_border_rpgs(); // // Hummer bumps enemy vehicle // //thread border_dialogue_hummer_bump(); // // End of border encounters // flag_wait( "flag_border_done" ); wait (0.75); // Dialogue: Leader - "We're clear. Move up!" level.leader dialogue_queue( "bor_bak_barricade_moveup" ); radio_dialogue( "bor_oly_barr_blackhawksready" ); wait (0.6); radio_dialogue( "bor_eag_barricade_inairspace" ); //need this flag so the next vo doesn't start too early. this transition is complicated. flag_set( "vo_border_section_done"); level notify( "notify_move_to_streets" ); // // Calling in for support // //level notify( "notify_border_outro_dialogue_start" ); // // Blockade removal scene // //trigger_wait_targetname( "trig_border_blockade_dialogue" ); //flag_wait( "flag_border_start_wire_cut" ); // dialogue: Leader - "Kimoto, Friedrich, get that razor wire off the road!" //radio_dialogue( "bor_bak_barricade_razorwire" ); //level notify( "notify_border_outro_remove_wire" ); //level waittill( "notify_border_razor_wire_done" ); // Dialogue: Leader - "Alright, let's move!" //radio_dialogue( "bor_bak_barricade_letsmove" ); //level notify( "notify_border_outro_dialogue_complete" ); } border_dialogue_border_rpgs() { level endon( "flag_border_done" ); level waittill( "notify_spawn_border_rpgs" ); wait 4; // Dialogue: Leader - "RPGs. 12 o'clock. Above the checkpoint. Take 'em out!" level.leader dialogue_queue( "bor_bak_border_rpgs12oclock" ); } border_dialogue_hummer_bump() { level endon( "notify_border_outro_dialogue_start" ); level waittill( "notify_border_hummer_bump" ); // Dialogue: Humvee Driver - "Pardon me, comin' through!" radio_dialogue( "bor_hum_hit_pardonme" ); } //******************************************************************* // * // * //******************************************************************* enemy_dead_flag_set( enemy_group, number, flag, end_notify ) { level endon( end_notify ); enemies = []; if( enemy_group == "all" ) { enemies = GetAIArray( "axis" ); } else { Assert( IsDefined( level.border_enemies[ enemy_group ] )); enemies = level.border_enemies[ enemy_group ]; } while( enemies.size > number ) { enemies = remove_dead_from_array( enemies ); wait 0.05; } flag_set( flag ); } //******************************************************************* // * // * //******************************************************************* // Force ally advance after a certain time period advance_1_timeout() { level waittill( "notify_unloading_convoy" ); wait 30; flag_set( "flag_advance_1_timeout" ); } //******************************************************************* // * // * //******************************************************************* advance_2_cleanup() { flag_wait( "flag_advance_2" ); kill_deathflag( "flag_border_sniper_kill", 3 ); } border_cleanup() { flag_wait( "flag_player_at_border" ); kill_deathflag( "flag_border_sniper_kill_2", 2 ); } //******************************************************************* // * // * //******************************************************************* // Spawn rooftop enemies spawn_enemy_rooftops( wave_name, noteworthy, waittill_notify, spawnfunc ) { level waittill( waittill_notify ); guys = GetEntArray( noteworthy, "script_noteworthy" ); Assert( IsDefined( guys )); array_thread( guys, ::add_spawn_function, spawnfunc ); level.border_enemies[ wave_name ] = array_spawn( guys ); } //******************************************************************* // * // * //******************************************************************* // Spawn ground enemies spawn_enemy_ground_wave( noteworthy, waittill_notify, spawnfunc, half_dead_flag, almost_dead_flag, full_dead_flag ) { level waittill( waittill_notify ); spawners = GetentArray( noteworthy, "script_noteworthy" ); Assert( IsDefined( spawners )); array_thread( spawners, ::add_spawn_function, spawnfunc ); enemies = []; foreach( spawner in spawners ) { guy = spawner spawn_ai(); enemies = array_add( enemies, guy ); } if( isdefined( half_dead_flag )) thread spawnfunc_enemy_ground_wave_flags( enemies, spawners.size, half_dead_flag, almost_dead_flag, full_dead_flag ); return enemies; } spawnfunc_enemy_ground_wave_flags( enemies, spawner_size, half_dead_flag, almost_dead_flag, full_dead_flag ) { // Some enemies are dead while( enemies.size > int( (spawner_size / 3) * 2 )) { enemies = remove_dead_from_array( enemies ); wait 0.05; } flag_set( half_dead_flag ); // Almost all enemies are dead while( enemies.size > int( spawner_size / 3)) { enemies = remove_dead_from_array( enemies ); wait 0.05; } flag_set( almost_dead_flag ); while( enemies.size > 0 ) { enemies = remove_dead_from_array( enemies ); wait 0.05; } flag_set( full_dead_flag ); } //******************************************************************* // * // * //******************************************************************* spawnfunc_enemy_rooftops_bridge() { self endon( "death" ); self.goalradius = 5; self.ignoreall = true; self.border_ground = true; self.maxfaceenemydist = 1024; self SetThreatBiasGroup( "enemies" ); self waittill( "goal" ); self.ignoreall = false; } spawnfunc_enemy_initial_ground_wave() { self.goalradius = 256; self.border_ground = true; self.maxfaceenemydist = 1024; self SetThreatBiasGroup( "enemies" ); self SetGoalVolumeAuto_targetname( "vol_enemy_initial" ); } spawnfunc_enemy_murder_squad() { self.goalradius = 256; self.border_ground = true; self.maxfaceenemydist = 1024; self.baseaccuracy = 10000; self.border_action = "player_seek"; self SetThreatBiasGroup( "enemies" ); self thread player_seek_enable(); } spawnfunc_enemy_initial_ground_wave_island() { self.goalradius = 256; self.border_ground = true; self.maxfaceenemydist = 1024; self SetThreatBiasGroup( "enemies" ); self SetGoalVolumeAuto_targetname( "vol_enemy_initial_island" ); } spawnfunc_enemy_vehicle() { self.goalradius = 256; self.border_ground = true; self.maxfaceenemydist = 1024; self SetThreatBiasGroup( "enemies" ); pullback_volume = GetEnt( "vol_border_pullback_first", "targetname" ); Assert( IsDefined( pullback_volume )); self SetGoalVolumeAuto( pullback_volume ); } #using_animtree( "generic_human" ); spawnfunc_enemy_rooftops_rpg() { self endon( "death" ); //death_anims = [ %death_rooftop_B, %death_rooftop_C, %death_rooftop_D ]; //self.deathanim = random( death_anims ); //self set_allowdeath( true ); self.health = 1; self.goalradius = 256; self.border_ground = false; self.ignoreall = true; self SetThreatBiasGroup( "enemies" ); level waittill( "notify_border_intro_player_anim_done" ); self.ignoreall = false; } spawnfunc_enemy_building_side_spawn( wave_name ) { self.goalradius = 256; self.border_ground = true; self.maxfaceenemydist = 1024; self SetThreatBiasGroup( "enemies" ); // Trigger spawned, add to array here Assert( IsDefined( wave_name )); level.border_enemies[ wave_name ] = array_add( level.border_enemies[ wave_name ], self ); } spawnfunc_enemy_border_bridge_rpg() { self endon( "death" ); //death_anims = [ %death_rooftop_B, %death_rooftop_C, %death_rooftop_D ]; //self.deathanim = random( death_anims ); //self set_allowdeath( true ); self.goalradius = 5; self.ignoreall = true; self.border_ground = false; self.health = 1; self SetThreatBiasGroup( "enemies" ); self waittill( "goal" ); self.ignoreall = false; } //******************************************************************* // * // * //******************************************************************* // Turn off triggers after allies advance into checkpoint (to avoid backspawning) turn_off_spawners() { flag_wait( "flag_advance_2" ); triggers = GetEntArray( "trig_border_side_spawners", "script_noteworthy" ); Assert( IsDefined( triggers )); foreach( trigger in triggers ) { trigger trigger_off(); } } //******************************************************************* // * // * //******************************************************************* // Main enemy control and cleanup func for border enemy_movement() { thread player_in_side_building(); thread player_on_rooftop(); // Prepare murder squad if player feels like going rambo thread enemy_movement_player_rambo(); // If player doesn't initiate rambo, last enemies will retreat at end thread enemy_movement_final_retreat(); flag_wait( "flag_advance_1" ); // Enemies pull back on ally advance thread enemy_pullback( "vol_border_pullback_first" ); flag_wait( "flag_advance_2" ); // Pullback to border level notify( "notify_pullback_clear" ); thread enemy_pullback( "vol_border" ); } //******************************************************************* // * // * //******************************************************************* enemy_movement_final_retreat() { level endon( "notify_murder_squad_enabled" ); flag_wait( "flag_advance_2" ); // Build an array of the remaining ground enemies all_enemies = GetAIArray( "axis" ); retreating_enemies = []; ground_enemies = []; foreach( guy in all_enemies ) { if( IsAlive( guy )) { if( guy.border_ground ) ground_enemies = array_add( ground_enemies, guy ); } } // Wait until only a few enemies left while( 1 ) { ground_enemies = remove_dead_from_array( ground_enemies ); if( ground_enemies.size < 5 ) break; wait( 0.05 ); } // Kill deathsquad spawn level notify( "notify_border_stop_murder_squad" ); // Enemies retreat foreach( enemy in ground_enemies ) { if( IsAlive( enemy )) { enemy ClearGoalVolume(); enemy SetGoalVolumeAuto_targetname( "vol_border_final_retreat" ); enemy.goalradius = 2000; enemy.health = 20; enemy.ignoreall = true; enemy.border_action = "retreat"; retreating_enemies = array_add( retreating_enemies, enemy ); } } thread AI_delete_when_out_of_sight( retreating_enemies, 2048 ); // Give enemies a head start wait 1.5; level notify( "notify_border_final_retreat" ); ground_enemies = remove_dead_from_array( ground_enemies ); waittill_dead( ground_enemies, ground_enemies.size, 5 ); flag_set( "flag_border_done" ); } //******************************************************************* // * // * //******************************************************************* // If the player tries to rambo through, make it very dangerous enemy_movement_player_rambo() { level endon( "flag_border_done" ); level endon( "notify_border_stop_murder_squad" ); flag_wait( "flag_player_at_border" ); // Kill final retreat level notify( "notify_murder_squad_enabled" ); num = GetAICount( "axis" ); SetThreatBias( "enemies", "player", 1000 ); array_spawn_function_targetname( "actor_border_murder_squad", ::spawnfunc_enemy_murder_squad ); level.border_enemies[ "murder_squad" ] = array_spawn_targetname( "actor_border_murder_squad" ); // Clear any volume advances level notify( "notify_pullback_clear" ); // Enemies accurate and gunning for player foreach( group in level.border_enemies ) { foreach( enemy in group ) { if( IsAlive( enemy )) { enemy thread player_seek_enable(); enemy.baseaccuracy = 10000; enemy.border_action = "player_seek"; } } } enemies = GetAIArray( "axis" ); waittill_dead( enemies ); flag_set( "flag_border_done" ); } //******************************************************************* // * // * //******************************************************************* // Ground enemies pull back to volume enemy_pullback( tVol ) { level endon( "notify_pullback_clear" ); guys = []; if( self == level ) { foreach( group in level.border_enemies ) { foreach( guy in group ) { if( IsAlive( guy )) guys = array_add( guys, guy ); } } } else { guys = self; } foreach( enemy in guys ) { if( IsAlive( enemy )) { if( enemy.border_ground ) { wait_random( 0, 0.5 ); enemy SetGoalVolumeAuto_targetname( "vol_border" ); } } } } retreat_check() { while( 1 ) { enemies = GetAIArray( "axis" ); foreach( guy in enemies ) { if( guy.border_ground ) { if(( guy._goal_volume.targetname != "vol_border_final_retreat" ) || ( guy.border_action != "retreat" )) AssertMsg( "fail" ); } } wait 0.05; } }