//**************************************************************************** // ** // Confidential - (C) Activision Publishing, Inc. 2010 ** // ** //**************************************************************************** // ** // Module: Mission Utils ** // ** // Created: DATE - CREATOR ** // ** //**************************************************************************** #include maps\_utility; #include common_scripts\utility; #include maps\_vehicle; // Use more // AssertEx( IsDefined( object ), "Assert message" ); //******************************************************************* // * // * //******************************************************************* pre_turret_event() { smoke_plumes_hide(); pre_turret_destruction_event(); } post_turret_event() { smoke_plumes_show(); post_turret_destruction_event(); } // Hide all the plumes smoke_plumes_hide() { smoke_plumes = GetEntArray( "rocket_fuel_smoke", "targetname" ); foreach( plume in smoke_plumes ) { //iprintln( "hiding plume" ); plume hide(); } } // Show all the plumes smoke_plumes_show() { smoke_plumes = GetEntArray( "rocket_fuel_smoke", "targetname" ); foreach( plume in smoke_plumes ) { //iprintln( "showing plume" ); plume show(); } } // SHOW/HIDE VARIOUS OBJECTS BEFORE TURRET DESTRUCTION. pre_turret_destruction_event() { pre_destruction_objects = GetEntArray( "pre_turret_destruction_event", "targetname" ); foreach( object in pre_destruction_objects ) { object show(); } post_destruction_objects = GetEntArray( "post_turret_destruction_event", "targetname" ); foreach( object in post_destruction_objects ) { object hide(); } } // SHOW/HIDE VARIOUS OBJECTS AFTER TURRET DESTRUCTION. post_turret_destruction_event() { pre_destruction_objects = GetEntArray( "pre_turret_destruction_event", "targetname" ); foreach( object in pre_destruction_objects ) { object hide(); } post_destruction_objects = GetEntArray( "post_turret_destruction_event", "targetname" ); foreach( object in post_destruction_objects ) { object show(); } } // Causes an APC's turret to fire at target // JR - Add a distance check apc_turret_logic( main_target, other_targets ) { self endon( "death" ); self thread apc_chooses_target( main_target, other_targets ); for(;;) { shots = randomintrange( 5, 10 ); for( i = 0 ; i < shots ; i++ ) { self fireWeapon(); wait 0.1; } wait randomfloatrange( 1.0, 3.0 ); } } apc_chooses_target( main_target, other_targets ) { self endon( "death" ); main_target endon( "death" ); self.dummy_target = spawn( "script_origin", self.origin + ( 0, 0, 70 ) ); self thread delete_on_death( self.dummy_target ); self SetTurretTargetEnt( self.dummy_target ); self.accuracy = 0.1; // Default if ( !isDefined( self.kill_player_max_dist_sqr ) ) { self.kill_player_max_dist_sqr = 3500 * 3500; } if ( !isDefined( self.kill_player_time ) ) { self.kill_player_time = 2.0; } if ( !isDefined( self.kill_player_fov_cos ) ) { self.kill_player_fov_cos = 0.3; } time_in_kill_player_range = 0.0; killing_player = false; while ( 1 ) { dist_sqr_to_main = DistanceSquared( main_target.origin, self.origin ); //println( "APC dist to player: " + Distance( main_target.origin, self.origin ) ); if ( dist_sqr_to_main < self.kill_player_max_dist_sqr ) { player_copter_right = AnglesToRight( main_target.angles ); player_to_apc = VectorNormalize( self.origin - main_target.origin ); dot = VectorDot( player_copter_right, player_to_apc ); //println( "APC dot: " + dot ); if ( dot > self.kill_player_fov_cos ) { tag_flash = self GetTagOrigin( "tag_flash" ); bullet_trace = BulletTracePassed( tag_flash, level._player GetEye(), false, self ); if ( bullet_trace ) { // Player should see APC, start counting time_in_kill_player_range time_in_kill_player_range += 0.5; //Println( "APC KILL COUNTDOWN: " + time_in_kill_player_range ); } else { //println( "Bullet Trace FAILED" ); } } else { time_in_kill_player_range = 0.0; } } else { time_in_kill_player_range = 0.0; if ( killing_player ) { killing_player = false; self SetVehWeapon( "nx_btr80_rocket_turret" ); //iPrintLn( "APC Killing player CLEARED" ); } } if ( time_in_kill_player_range >= self.kill_player_time ) { // Kill the player //iPrintLn( "APC Killing player SET" ); //self SetVehWeapon( "btr80_turret" ); self SetTurretTargetEnt( level._player ); killing_player = true; self.accuracy = self.accuracy + 0.2; if ( isdefined ( self.mgturret [ 0 ] )) { self.mgturret [ 0 ] SetAISpread ( 0.1 ); } } else { // Don't kill the player dist_sqr_to_best_other = dist_sqr_to_main; best_other = undefined; foreach( other_target in other_targets ) { if ( !isAlive( other_target ) ) { continue; } dist_sqr_to_other = DistanceSquared( other_target.origin, self.origin ); if ( dist_sqr_to_other < dist_sqr_to_best_other ) { best_other = other_target; dist_sqr_to_best_other = dist_sqr_to_other; } } // Fire at the other target if it is closer than the player and in front of the player target = level._player; if ( isDefined( best_other ) && dist_sqr_to_best_other < dist_sqr_to_main && within_fov( level._player GetEye(), level._player.angles, best_other.origin, 90 ) ) { target = best_other; } self SetTurretTargetEnt( target ); // Show target debug //line( self.origin, target.origin, (1,0,0) ); } wait 0.5; } } update_fake_spread( target ) { self endon( "death" ); target endon( "death" ); self notify( "stop_update_fake_spread" ); self endon( "stop_update_fake_spread" ); dummy_target = self.dummy_target; dummy_target Unlink(); min_miss_dist_sqr = 512 * 512; while ( 1 ) { accuracy_test = RandomFloat( 1.0 ); dist_sqr = DistanceSquared( target.origin, self.origin ); // This looks bad at short distances, so never miss if we're close. if ( dist_sqr < min_miss_dist_sqr || accuracy_test < self.accuracy ) { // Hit self SetTurretTargetEnt( target ); } else { // Miss! offset = ( RandomFloatRange( 100, 200 ), RandomFloatRange( 100, 200 ), RandomFloatRange( 100, 200 ) ); dummy_target LinkTo( target, undefined, offset, target.angles ); //box( target.origin + offset, 16, target.angles[1], (1,0,0), 1, 1, 5 ); self SetTurretTargetEnt( dummy_target ); } wait .3; } } // Blockout spawning script for groups of enemies spawn_guys_from_targetname( targetname ) { new_guys = []; guys = getentarray( targetname, "targetname" ); foreach ( guy in guys ) { if( IsDefined( guy.script_drone ) && guy.script_drone == 1 ) { new_guy = dronespawn( guy ); new_guys[ new_guys.size ] = new_guy; } else { new_guy = guy stalingradSpawn(); if ( spawn_failed( new_guy ) ) { //iprintlnbold( "force_spawn_guys failed" ); continue; } new_guys[ new_guys.size ] = new_guy; } } return new_guys; } // Safely delete an object safe_delete( object ) { if( isDefined( object )) { object delete(); } } // Safely deletes a bunch of objects safe_delete_array( array ) { foreach( object in array ) { safe_delete( object ); } } spawn_ai_group( spawner_value, spawner_key ) { ai_array = []; foreach( spawner in GetEntArray( spawner_value, spawner_key ) ) { ai = spawner spawn_ai(); ai_array[ ai_array.size ] = ai; wait 0.25; } return ai_array; } // Copied from dcburning.gsc // Spawns and endless stream of drones a random interval apart // Be sure to set "script_noteworthy = delete_on_goal" on the spawners drone_flood_start( aSpawners, groupName, r1, r2, immediate ) { level endon( "stop_drone_flood" + groupName ); if( isDefined( immediate )) { foreach( spawner in aSpawners ) { dronespawn( spawner ); } } while( true ) { foreach( spawner in aSpawners ) { delaythread( randomfloatrange( r1, r2 ), ::dronespawn, spawner ); } wait( randomfloatrange( r1, r2 ) ); } } drone_flood_stop( groupName ) { level notify( "stop_drone_flood" + groupName ); } // Delays a thread untill a specific notify occurs delayThreadNotify( event, func, param1, param2, param3 ) { self waittill( event ); if ( !IsDefined( param1 ) ) { assertex( !isdefined( param2 ), "delayThreadNotify does not support vars after undefined." ); assertex( !isdefined( param3 ), "delayThreadNotify does not support vars after undefined." ); thread [[ func ]](); } else if ( !IsDefined( param2 ) ) { assertex( !isdefined( param3 ), "delayThreadNotify does not support vars after undefined." ); thread [[ func ]]( param1 ); } else if ( !IsDefined( param3 ) ) { thread [[ func ]]( param1, param2 ); } else { thread [[ func ]]( param1, param2, param3 ); } } delete_objects_on_notify( event, objects ) { //iprintln( "waiting" ); self waittill( event ); //iprintln( "delete objects on notify" ); safe_delete_array( objects ); } set_goal_volume_array( actors, volume_targetname ) { foreach( actor in actors ) { actor thread set_goal_volume( volume_targetname ); } } set_goal_volume( volume_targetname ) { goal_volume = GetEnt( volume_targetname, "targetname" ); self.goalheight = 80; self.fixednode = false; self ClearGoalVolume(); self SetGoalPos( goal_volume.origin ); self waittill( "goal" ); self SetGoalVolume( goal_volume ); self.goalradius = 2000; } // Helper script for timing dialogue wait_play_dialogue_wait( wait_in, dialogue1, wait_out, flag ) { wait( wait_in ); radio_dialogue( dialogue1 ); if( isDefined( flag )) { flag_set( flag ); } if( isDefined( wait_out )) { wait( wait_out ); } } // Nags the player to fire the railgun nag_for_fire_railgun( event ) { level endon( event ); while( 1 ) { wait RandomIntRange( 8, 12 ); if( cointoss() ) { maps\nx_rocket_util::wait_play_dialogue_wait( 0, "roc_bak_alpha_paintrocket" ); } else { maps\nx_rocket_util::wait_play_dialogue_wait( 0, "roc_bak_alpha_painttargetnow" ); } } } //******************************************************************* // OBJECTIVES * // * //******************************************************************* add_objective( objective_name ) { if( !IsDefined( level._mission_objective ) ) level._mission_objective = []; level._mission_objective[ objective_name ] = level._mission_objective.size; } get_objective( objective_name ) { return level._mission_objective[ objective_name ]; } //******************************************************************* // SQUAD * // * //******************************************************************* squad_teleport( teleport_info ) { // teleport_info should be an array with entries that follow the form: // teleport_info[ "ALLY_NAME" ] = "SCRIPT_ORIGIN_NOTEWORTHY"; // ALLY_NAME should match one of the keys in level.squad (see nx_rocket.gsc) foreach( ally_name, origin_noteworthy in teleport_info ) { ally = level.squad[ ally_name ]; origin = GetEnt( origin_noteworthy, "script_noteworthy" ); ally ForceTeleport( origin.origin, origin.angles ); } } squad_ally( spawner_script_noteworthy, animname, color ) { spawner = GetEnt( spawner_script_noteworthy, "script_noteworthy" ); ai = spawner spawn_ai( true ); ai thread magic_bullet_shield(); ai.animname = animname; ai.ai_color = color; ai ai_color_reset(); return ai; } squad_color_reset() { ai_array_color_reset( level.squad ); } //******************************************************************* // AI * // * //******************************************************************* ai_color_reset( color ) { if( !IsDefined( color ) ) { if( IsDefined( self.ai_color ) ) color = self.ai_color; } if( IsDefined( color ) ) self set_force_color( color ); } ai_array_color_reset( ai_array, color ) { foreach( ai in ai_array ) { ai ai_color_reset( color ); } } // The AI will run to their goal node, then become aggresive // Do this: // array_spawn_function_targetname( "base_alpha_roof_runners_1", ::run_to_goal_then_aggro ); run_to_goal_then_aggro() { //self.script_forcegoal = true; //self.ignoreall = true; self waittill( "goal" ); self.ignoreall = false; } //******************************************************************* // HELICOPTER * // * //******************************************************************* heli_shoots_rockets_at_ent( target ) { attractor = missile_createAttractorEnt( target, 100000, 60000 ); self maps\_helicopter_globals::fire_missile( "mi28_seeker", 3, target, .75 ); wait( 5 ); missile_deleteAttractor( attractor ); } // Changes the spread on allied choppers turrets // This effects their accuracy // Default 2 set_ally_chopper_spread( spread ) { foreach ( turret in self.mgturret ) { turret SetAISpread( spread ); // Default is 2 } } heli_start_path( path_value, path_key ) { // Get rid of old path self thread vehicle_detachfrompath(); // Get the new path transition_node = getstruct( path_value, path_key ); // Use new patch self.currentnode = transition_node; //iprintln( "new path go" ); // Continue on new path self thread vehicle_resumepath(); self GoPath(); } // Moves a chopper from one path to another transition_chopper_to_new_path( new_path_start ) { AssertEx( maps\_vehicle::ishelicopter(), "Called transition_chopper_to_new_path, but self isnt a chopper" ); self thread vehicle_detachfrompath(); self notify( "newpath" ); transition_node = getstruct( new_path_start, "targetname" ); self.currentnode = transition_node; self thread vehicle_resumepath(); self thread GoPath(); } // Moves a chopper from one path to another transition_chopper_to_new_path_noteworthy( new_path_start ) { AssertEx( maps\_vehicle::ishelicopter(), "Called transition_chopper_to_new_path, but self isnt a chopper" ); self thread vehicle_detachfrompath(); self notify( "newpath" ); transition_node = getstruct( new_path_start, "script_noteworthy" ); self.currentnode = transition_node; self thread vehicle_resumepath(); self thread GoPath(); } // Low powered earthquake used to simulate chopper rumble slightly_vibrate_camera() { level endon( "end_camera_vibrate" ); for( ;; ) { Earthquake( 0.05, 60, level._player.origin, 0 ); wait 5; } } slightly_vibrate_camera_end() { level notify( "end_camera_vibrate" ); // HACK! // In order to clear out the long duration earthquakes in slightly_vibrate_camera(), // use four short duration earthquakes that are slightly stronger. // This works because the game only remembers the four largest earthquakes (MAX_CAMERA_SHAKE == 4). Earthquake( 0.06, 0.05, level._player.origin, 0 ); Earthquake( 0.06, 0.05, level._player.origin, 0 ); Earthquake( 0.06, 0.05, level._player.origin, 0 ); Earthquake( 0.06, 0.05, level._player.origin, 0 ); } /# // Debug helper draw_chopper_name( text ) { self endon( "death" ); while ( true ) { Print3D( self.origin, text ); //println( self GetEntNum() ); wait 0.05; } } #/ // Displays a 3d hint text untill the specified notify is hit display_hint_until_notify( text, location, event ) { level endon( event ); for( ;; ) { Print3d( location.origin, text, (1,1,1), 1, 1, 1 ); wait(0.05); } } dialogue_nag_temp( actor, line, display_time, wait_min, wait_max, end_on ) { level endon( end_on ); while( 1 ) { if( flag(end_on) ) return; level thread add_dialogue_line( actor, line, undefined, display_time ); wait display_time; wait RandomFloatRange( wait_min, wait_max ); } } dialogue_nag( line, wait_min, wait_max, end_on ) { level endon( end_on ); while( 1 ) { if( flag(end_on) ) return; wait_play_dialogue_wait(0, line ); wait RandomFloatRange( wait_min, wait_max ); } } aa_turret_fire( target, hit_offset ) { if( !IsDefined( hit_offset ) ) hit_offset = (0, 0, 0); MagicBullet( "nx_rocket_aa_turret", self.origin, target.origin + hit_offset ); angles_to_target = VectorToAngles( target.origin - self.origin ); fx_forward = AnglesToForward( angles_to_target ); fx_up = AnglesToUp( angles_to_target ); fx_org = self.origin; playfx( level._effect[ "nx_rocket_aa_flash_view" ], fx_org, fx_forward, fx_up ); self stopsounds(); } track_anim_speed() { self endon( "death" ); self endon( "end_track_anim_velocity" ); speed = 0; while ( true ) { prev_origin = self.origin; wait 0.05; self.anim_speed = speed; // track previous frame's speed, as all anims seem to have one frame of reduced velocity at their end speed = Length( ( self.origin - prev_origin ) / 0.05 ); } } rescue_chopper_setup( chopper_value, chopper_key ) { chopper = vehicle_spawn( GetEnt( chopper_value, chopper_key ) ); chopper rescue_chopper_player_setup(); chopper rescue_chopper_allies_setup(); chopper thread godon(); chopper SetMaxPitchRoll( 10, 10 ); chopper GoPath(); return chopper; } rescue_chopper_allies_setup() { level.squad[ "ALLY_WILLIAMS" ].script_startingposition = 7; level.squad[ "ALLY_JENKINS" ].script_startingposition = 2; level.squad[ "ALLY_BAKER" ].script_startingposition = 3; foreach( guy in level.squad ) { self guy_enter_vehicle( guy ); } } rescue_chopper_player_setup() { player_tag = spawn_tag_origin(); tag_name = "tag_guy2"; player_tag.angles = self GetTagAngles( tag_name ); player_tag_forward = AnglesToForward( player_tag.angles ); player_tag_offset = player_tag_forward * 30 + (0, 0, -25); player_tag.origin = self GetTagOrigin( tag_name ) + player_tag_offset; level thread draw_line_for_time( player_tag.origin, player_tag.origin + player_tag_offset, 1, 1, 1, 10 ); level._player SetOrigin( player_tag.origin ); level._player SetPlayerAngles( player_tag.angles ); level._player PlayerLinkToDelta( player_tag, "tag_origin", 1, 90, 90, 35, 100, true ); player_tag LinkTo( self, tag_name ); } player_prevent_damage_from_behind_until_flag( flag_name ) { // Dan: While close to working, this script does not work // because previous_normal_health does not know about // any regeneration which may have occured since the last // damage event. Disabling for now. Justin has said it is // OK for this to be changed so that actors which are out of // view have very low accuracy. // // Also, Justin has said that he would like this to not be // based directly on the player's view, but rather the // general facing of the helicopter. (So the player can not // look away from enemies to get them to miss.) /* self endon( "death" ); self endon( flag_name ); while ( 1 ) { previous_normal_health = level._player GetNormalHealth(); self waittill( "damage", damage, attacker, direction_vec ); playerangles = level._player GetPlayerAngles(); player_forward = AnglesToForward( playerangles ); anglesFromPlayer = VectorToAngles( direction_vec ); forward_to_self = AnglesToForward( anglesFromPlayer ); dot = vectordot( player_forward, forward_to_self ); //iPrintln( "Direction_vec: " + direction_vec + " dot: " + dot ); // Heal health from behind if ( dot > 0.2 ) { level._player SetNormalHealth( previous_normal_health ); } } */ } // Let the player take damage but not die heli_god_mode( end_notify ) { self endon( end_notify ); while( true ) { self waittill( "damage", damage, attacker, direction_vec, point, damageType, modelName, tagName ); //iprintln( "Dmg: " + damage + " from " + attacker.className ); normal_health = level._player GetNormalHealth(); if ( normal_health < 0.02 ) { level._player SetNormalHealth( 0.02 ); } // Dan: Note that this wait opens a window in which the player can die. //wait 0.05; } } //******************************************************************* // * // * //******************************************************************* CINEMATIC_LINK_VIEW_FRACTION = 0.9; GAMEPLAY_LINK_VIEW_FRACTION = 0.1; //******************************************************************* // * // * //******************************************************************* set_link_view_fraction_cinematic( lerp_duration ) { if ( !IsDefined( lerp_duration ) ) { lerp_duration = 0; } level._player LerpLinkViewFraction( CINEMATIC_LINK_VIEW_FRACTION, lerp_duration ); } //******************************************************************* // * // * //******************************************************************* set_link_view_fraction_gameplay( lerp_duration ) { if ( !IsDefined( lerp_duration ) ) { lerp_duration = 0; } level._player LerpLinkViewFraction( GAMEPLAY_LINK_VIEW_FRACTION, lerp_duration ); } //******************************************************************* // * // * //******************************************************************* lerp_link_view_fraction_cinematic_trigger() { lerp_link_view_fraction_trigger( CINEMATIC_LINK_VIEW_FRACTION ); } //******************************************************************* // * // * //******************************************************************* lerp_link_view_fraction_gameplay_trigger() { lerp_link_view_fraction_trigger( GAMEPLAY_LINK_VIEW_FRACTION ); } //******************************************************************* // * // * //******************************************************************* lerp_link_view_fraction_trigger( view_fraction ) { self waittill( "trigger", ent ); assert( IsPlayer( ent ) ); level._player LerpLinkViewFraction( view_fraction, 3 ); //IPrintLnBold( "level._player LerpLinkViewFraction( " + view_fraction + ", 3 );"); // exit; trigger only works once count = 3 / 0.05; for ( i = 0; i < count; i++ ) { //IPrintLn( "lerping to " + view_fraction ); wait 0.05; } //IPrintLnBold( "Done!"); } player_ledge_walk( trigger ) { self endon( "end_ledge" ); curr_node = undefined; dest_node = undefined; if( IsDefined( trigger.target ) ) { curr_node = GetEnt( trigger.target, "targetname" ); } move_speed = 20.0; // units per second interval = 0.05; mover = spawn_tag_origin(); // mover.origin = curr_node.origin; // mover.angles = curr_node.angles; while( 1 ) { flag_wait( trigger.script_flag ); self SetMoveSpeedScale( 0.3 ); self HideViewModel(); self DisableWeapons(); mover.origin = self.origin; mover.angles = self.angles; self PlayerLinkToDelta( mover, "tag_origin", 1.0, 45, 45, 15, 60, true ); mover RotateTo( curr_node.angles, 0.65 ); mover waittill( "rotatedone" ); while( flag( trigger.script_flag ) ) { if( DistanceSquared( mover.origin, curr_node.origin ) <= curr_node.radius * curr_node.radius ) { if( IsDefined( curr_node.target ) ) curr_node = GetEnt( curr_node.target, "targetname" ); else break; } dest_org = curr_node.origin - mover.origin; dest_angles = curr_node.angles - mover.angles; movement_scale = self GetNormalizedMovement(); dir = VectorNormalize( dest_org); velocity = dir * movement_scale[ 1 ] * move_speed; mover.origin += velocity * interval; // mover.angles += dest_angles * interval * movement_scale[ 1 ]; wait interval; } self SetMoveSpeedScale( 1.0 ); self ShowViewModel(); self Enableweapons(); self Unlink(); wait 0.05; } } trigger_waittill_use( hint_text ) { self trigger_on(); self SetHintString( hint_text ); self waittill( "trigger" ); self trigger_off(); } ignore_until_damage() { self endon( "death" ); self.ignoreAll = true; self.ignoreMe = true; self waittill( "damage" ); self.ignoreAll = false; self.ignoreMe = false; } ignore_until_damage_group( team ) { self.ignoreAll = true; self.ignoreMe = true; self waittill( "damage" ); guys = array_removedead( team ); foreach( guy in guys ) { guy.ignoreAll = false; guy.ignoreMe = false; } } ignore_until_flag( flag_name ) { self endon( "death" ); self.ignoreAll = true; self.ignoreMe = true; flag_wait( flag_name ); self.ignoreAll = false; self.ignoreMe = false; } vehicle_enable_fire( enable ) { foreach( turret in self.mgturret ) { if( enable ) turret TurretFireEnable(); else turret TurretFireDisable(); } } vehicle_search_ents( ents, end_on ) { if( IsDefined( end_on ) ) { self endon( end_on ); level endon( end_on ); } self endon( "death" ); while( 1 ) { self SetTurretTargetEnt( random( ents ) ); wait RandomFloatRange( 1.0, 3.0 ); } } vehicle_firing( fire_min, fire_max, hold_min, hold_max, end_on ) { if( IsDefined( end_on ) ) { self endon( end_on ); level endon( end_on ); } self endon( "death" ); enable = false; while( 1 ) { enable = !enable; self maps\nx_rocket_util::vehicle_enable_fire( enable ); if(enable) wait RandomFloatRange( fire_min, fire_max ); else wait RandomFloatRange( hold_min, hold_max ); } } VIEW_DOT = 0.25; //Goes from 0-1, smaller numbers mean larger fov. //called on an actor. protect_player_helicopter_rear() { self endon( "death" ); self.oldbaseaccuracy = self.baseAccuracy; while( true ) { if( !IsDefined( level.playerHeli ) ) { return; } //The player is in the right bay door, so we use Angles to Right. Then see if the actor's position puts them too //far behind. If it does, then set the accuracy low. if( vectordot(self.origin - level.playerHeli.origin, AnglesToRight( level.playerHeli.angles )) > VIEW_DOT ) //actor "in view". { self.baseAccuracy = self.oldbaseaccuracy; ///#debug_draw_origin( self.origin, true);#/ } else { self.baseAccuracy = 0; ///#debug_draw_origin( self.origin, false);#/ } wait 0.05; } } //called on a vehicle. protect_player_helicopter_rear_from_vehicle() { self endon( "death" ); //bail if the vehicle doesn't have a turret so we can call this on vehicles blindly. if( !IsDefined( self.mgturret ) || self.mgturret.size < 1 ) { return; } old_accuracy = []; //some have multiple turrets, so grab each one. for ( i = 0; i < self.mgturret.size; i++ ) { old_accuracy[i] = self.mgturret[i].accuracy; } while( true ) { if( !IsDefined( level.playerHeli ) ) { return; } //The player is in the right bay door, so we use Angles to Right. Then see if the actor's position puts them too //far behind. If it does, then set the accuracy low. if( vectordot(self.origin - level.playerHeli.origin, AnglesToRight( level.playerHeli.angles )) > VIEW_DOT ) //actor "in view". { for ( i = 0; i < self.mgturret.size; i++ ) { self.mgturret[ i ].accuracy = old_accuracy[i]; } ///#debug_draw_origin( self.origin, true);#/ } else { for ( i = 0; i < self.mgturret.size; i++ ) { self.mgturret[ i ].accuracy = 0; } ///#debug_draw_origin( self.origin, false);#/ } wait 0.05; } } protect_player_helicopter_rear_from_each_vehicle( vehicles ) { //to make this as unlikely to fail as possible, check for the case where what's returned is a single item and not an array. if( IsArray( vehicles ) ) { foreach ( vehicle in vehicles ) { vehicle thread protect_player_helicopter_rear_from_vehicle(); } } else { vehicles thread protect_player_helicopter_rear_from_vehicle(); } } /# debug_draw_origin( origin, on ) { draw_color = ( 1, 0, 0 ); if( on ) { draw_color = ( 0, 1, 0 ); } Line( origin + ( 16, 0, 0 ), origin + ( -16, 0, 0 ), draw_color, 1, 0, 1 ); Line( origin + ( 0, 16, 0 ), origin + ( 0, -16, 0 ), draw_color, 1, 0, 1 ); Line( origin + ( 0, 0, 16 ), origin + ( 0, 0, -16 ), draw_color, 1, 0, 1 ); } #/ // FLASHLIGHT ON GUN attach_flashlight_gun( state ) { effect_id = level._effect[ "flashlight" ]; effect_tag = "tag_flash"; if( state ) { PlayFXOnTag( effect_id, self, "tag_flash" ); self thread detach_flashlight_gun_on_death(); } else { StopFXOnTag( effect_id, self, "tag_flash" ); } self.have_flashlight = state; } detach_flashlight_gun() { self attach_flashlight_gun( false ); } detach_flashlight_gun_on_death() { self waittill( "death" ); self detach_flashlight_gun(); } // FLASHLIGHT IN HAND attach_flashlight( state ) { self attach( "com_flashlight_on", "tag_inhand", true ); self.have_flashlight = true; self flashlight_light( state ); self thread detach_flashlight_on_death(); } detach_flashlight_on_death() { self waittill( "death" ); if ( isdefined( self ) ) self detach_flashlight(); } detach_flashlight() { if ( !isdefined( self.have_flashlight ) ) return; self detach( "com_flashlight_on", "tag_inhand" ); self flashlight_light( false ); self.have_flashlight = undefined; } flashlight_light( state ) { flash_light_tag = "tag_light"; if ( state ) { flashlight_fx_ent = spawn( "script_model", ( 0, 0, 0 ) ); flashlight_fx_ent setmodel( "tag_origin" ); flashlight_fx_ent hide(); flashlight_fx_ent linkto( self, flash_light_tag, ( 0, 0, 0 ), ( 0, 0, 0 ) ); self thread flashlight_light_death( flashlight_fx_ent ); playfxontag( level._effect[ "flashlight" ], flashlight_fx_ent, "tag_origin" ); } else if ( isdefined( self.have_flashlight ) ) self notify( "flashlight_off" ); } flashlight_light_death( flashlight_fx_ent ) { self waittill_either( "death", "flashlight_off" ); flashlight_fx_ent delete(); self.have_flashlight = undefined; } caravan_setup( caravan_targetname, end_flag ) { caravan = []; for ( i = 1 ;; i++) { targetname_concatenated = caravan_targetname + i; vehicle_spawner = GetEnt( targetname_concatenated , "targetname"); if ( !isdefined( vehicle_spawner ) ) break; vehicle = spawn_vehicle_from_targetname_and_drive ( targetname_concatenated ); caravan [caravan.size] = vehicle; // lag mitigator, so they don't all spawn on the same frame wait .1; } protect_player_helicopter_rear_from_each_vehicle( caravan ); level thread handle_caravan_stopping_2( caravan, end_flag ); return caravan; } get_my_index( caravan ) { foreach ( index, vehicle in caravan ) { if ( vehicle == self ) break; } return index; } handle_caravan_stopping_2( caravan, end_flag ) { level endon( end_flag ); while ( 1 ) { foreach( vehicle in caravan ) { healthbuffer = 0; if ( isDefined( vehicle.healthbuffer ) ) { healthbuffer = vehicle.healthbuffer; } if ( !isAlive( vehicle ) || vehicle.health - healthbuffer <= 1 ) { if ( isdefined (vehicle) ) { dead_index = vehicle get_my_index ( caravan ); foreach ( remaining_vehicle in caravan ) { living_index = remaining_vehicle get_my_index ( caravan ); if ( living_index > dead_index ) { remaining_vehicle thread stop_caravan_vehicle ( ); } } if( vehicle Vehicle_IsPhysVeh()) { vehicle VehPhys_Crash (); } } return; } } wait 0.05; } } handle_caravan_stopping( vehicles, end_flag ) { level endon( end_flag ); while ( 1 ) { foreach( vehicle in vehicles ) { healthbuffer = 0; if ( isDefined( vehicle.healthbuffer ) ) { healthbuffer = vehicle.healthbuffer; } if ( !isAlive( vehicle ) || vehicle.health - healthbuffer <= 1 ) { if ( isdefined (vehicle) && vehicle Vehicle_IsPhysVeh() ) { // speed = vehicle Vehicle_GetSpeed ( ); // vehicle VehPhys_Launch( (0,4,4), 0.7 ); vehicle VehPhys_Crash (); } // Stop caravan stop_caravan( vehicles ); return; } } wait 0.05; } } stop_caravan( vehicles ) { foreach ( vehicle in vehicles ) { if ( isAlive( vehicle ) ) { vehicle delayThread( RandomFloatRange( 0.0, 0.2 ), ::stop_caravan_vehicle ); } } } stop_caravan_vehicle() { self endon( "death" ); self Vehicle_SetSpeed( 0.0, RandomFloatRange( 55.0, 75.0 ) ); wait .3; self vehicle_unload(); } vehicle_follow( target, dist, min_speed, max_speed, look_at ) { self endon( "death" ); self endon( "reached_dynamic_path_end" ); self endon( "reached_end_node" ); self endon( "end_follow" ); if( self isHelicopter() && IsDefined( look_at ) ) { self SetLookAtEnt( look_at ); } interval = 0.05; while( 1 ) { // if( DistanceSquared( target.origin, self.origin ) >= ( dist * dist ) ) if( !within_fov( target.origin, target.angles, self.origin, cos( 90 ) ) ) { if( self Vehicle_GetSpeed() <= max_speed ) self Vehicle_SetSpeed( self Vehicle_GetSpeed() + 1.0, 15 ); } else if( self Vehicle_GetSpeed() > min_speed ) self Vehicle_SetSpeed( self Vehicle_GetSpeed() - 1.0, 10 ); wait interval; } } ShootEnemyWrapper_blanks() { // Shoot blanks if we're using a rifle like weapon if ( !animscripts\utility::usingRifleLikeWeapon() ) { animscripts\utility::shootEnemyWrapper_shootNotify(); return; } self.a.lastShootTime = gettime(); // set accuracy at time of shoot rather than in a separate thread that is vulnerable to timing issues maps\_gameskill::set_accuracy_based_on_situation(); self notify( "shooting" ); self ShootBlank(); } // DIALOGUE actor_dialogue_queue( dialogue_line, delay ) { if( IsDefined( delay ) ) wait delay; self dialogue_queue( dialogue_line ); } // ALLY CHOPPER intro_chopper_allies_setup() { level.squad[ "ALLY_WILLIAMS" ].script_startingposition = 4; level.squad[ "ALLY_JENKINS" ].script_startingposition = 3; level.squad[ "ALLY_BAKER" ].script_startingposition = 2; foreach( guy in level.squad ) { guy notify( "newanim" ); self guy_enter_vehicle( guy ); } } chopper_allies_remove() { foreach( guy in level.squad ) { guy notify( "newanim" ); self guy_exit_vehicle( guy ); // guy notify( "animontagdone", "end" ); self StopAnimScripted(); self Unlink(); } } // Sends a notify when a rocket is 10s from launching launch_coutdown_logic( timer, id, cancel_flag ) { level endon( cancel_flag ); AssertEx( timer > 10 , "launch_coutdown_logic only works with a LAUNCH_DELAY > 10" ); wait (timer-10); // Safety check to make sure the rocket wasnt destroyed during this window if( flag( cancel_flag )) { return; } level notify( "rocket_" + id + "_10s_warning" ); } chopper_debug_speed() { while( isDefined( self )) { speed = self vehicle_getSpeed(); iprintln( speed ); wait 0.25; } }