IW4-Dump-Files/maps/so_chopper_invasion_code.gsc

1677 lines
35 KiB
Plaintext
Raw Permalink Blame History

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include maps\_utility;
#include common_scripts\utility;
#include maps\_hud_util;
#include maps\_specialops;
#include maps\_specialops_code;
#include maps\so_chopper_invasion;
init_dialogue()
{
// "Gunslinger One  to ground, primary LZ is too hot! We've got ten-plus hostiles in our immediate AO and cannot remain on the ground, over!"
level.scr_radio[ "lift_off" ] = "so_chop_inv_hp1_lz2hot";
// "Ground forces, we're going to link up at the secondary extraction point. Head for the roof of Nate's Sports Bar, to the East."
level.scr_radio[ "objective" ] = "so_chop_inv_hp1_enghost";
// "Gunner, you are cleared to engage hostiles. Watch out for friendlies on the ground, over."
level.scr_radio[ "objective2" ] = "so_chop_inv_hp1_gunner";
// "Gunslinger-One to ground forces, find some cover! We are tracking a platoon-sized group of hostiles behind that barricade at the end of the street, over!"
level.scr_radio[ "drive_by" ] = "so_chop_inv_hp1_findcover";
// "Danger close ground forces, we're comin' in hot! Gunner, you are cleared to engage hostiles by the barricade."
level.scr_radio[ "start_drive_by" ] = "so_chop_inv_hp1_by_barricade";
// "Good effect on target, Gunner - whoa, hang on!"
level.scr_radio[ "evade_rpgs" ] = "so_chop_inv_hp1_goodeffect";
// "Ground forces be advised, we've got RPGs in the area, over.  Were coming back around for a strafing run here in a second."
level.scr_radio[ "evade_extra" ] = "so_chop_inv_hp1_rpgs";
// "Gunslinger-One to ground, we are starting our strafing run, over. Gunner, light 'em up."
level.scr_radio[ "drive_by_payback" ] = "so_chop_inv_hp1_lightemup";
// "Guns guns guns!"
level.scr_radio[ "drive_by_guns_guns_guns" ] = "so_chop_inv_hp1_guns";
// "Gunslinger-One to ground, repositioning to your location, over."
level.scr_radio[ "back_to_squad" ] = "so_chop_inv_hp1_reposition";
// "Gunslinger-One to ground, be advised, we are tracking a convoy of enemy trucks movin' in from the southeast, recommend you let us handle those, over."
level.scr_radio[ "convoy" ] = "so_chop_inv_hp1_ba_trucks";
// "Gunslinger-One to ground, we see you! Maintain your location on the roof, we're en route!"
level.scr_radio[ "on_the_roof" ] = "so_chop_inv_hp1_weseeyou";
// "Ground forces, let's go let's go! We are at the roof and ready to link up for extraction!"
level.scr_radio[ "end_reminder_1" ] = "so_chop_inv_hp1_letsgo";
// "Ground forces, pick up the pace, we're sitting ducks up here!"
level.scr_radio[ "end_reminder_2" ] = "so_chop_inv_hp1_pace";
// "Jump! You'll make it!"
level.scr_radio[ "jump" ] = "so_chop_inv_hp1_jump";
// "Ground forces, link up on the roof of Nate's Sports Bar!"
level.scr_radio[ "objective_reminder_1" ] = "so_chop_inv_hp1_linkup";
// "Gunslinger One to ground, meet us up on the roof of Nate's Sports Bar!"
level.scr_radio[ "objective_reminder_2" ] = "so_chop_inv_hp1_meetus";
// "Ground forces, get to the roof of Nate's Sports Bar!"
level.scr_radio[ "objective_reminder_3" ] = "so_chop_inv_hp1_gettoroof";
// "Gunner, watch your fire - that's a friendly!"
level.scr_radio[ "friendlyfire_1" ] = "so_chop_inv_hp1_friendly_01";
// "Gunner, that is friendly fire! Check your aim!"
level.scr_radio[ "friendlyfire_2" ] = "so_chop_inv_hp1_friendly_02";
// "That's a friendly down there, Gunner! Focus up!"
level.scr_radio[ "friendlyfire_3" ] = "so_chop_inv_hp1_friendly_03";
}
so_chopper_invasion_fx()
{
level._effect[ "chopper_minigun_shells" ] = LoadFX( "shellejects/20mm_cargoship" );
}
chopper_minigun_shells()
{
fx = getfx( "chopper_minigun_shells" );
tag = "tag_turret";
while ( 1 )
{
if ( self AttackButtonPressed() )
{
PlayFXOnTag( fx, level.chopper, tag );
}
wait( 0.05 );
}
}
so_chopper_invasion_enemy_setup()
{
level.enemies = [];
allspawners = GetSpawnerTeamArray( "axis" );
array_thread( allspawners, ::add_spawn_function, ::so_chopper_invasion_enemy_spawnfunc );
}
so_chopper_invasion_enemy_spawnfunc()
{
self pathrandompercent_set( 800 );
if ( IsSubStr( self.code_classname, "juggernaut" ) )
{
self thread so_chopper_invasion_juggernaut_init();
}
level.activeEnemies[ level.enemies.size ] = self;
self thread so_chopper_invasion_enemy_deathcleanup();
}
so_chopper_invasion_juggernaut_init()
{
self SetThreatBiasGroup( "juggernauts" );
//self thread juggernaut_hud_box();
}
/*
juggernaut_hud_box()
{
offset = ( 0, 0, 32 );
Target_Set( self, offset );
self waittill( "death" );
Target_Remove( self );
}
*/
so_chopper_invasion_enemy_deathcleanup()
{
self waittill( "death" );
level.activeEnemies = array_remove( level.enemies, self );
}
// TODO maybe genericize this
get_targeted_line_array( start )
{
arr = [];
arr[ 0 ] = start;
point = start;
while ( IsDefined( point.target ) )
{
nextpoint = getstruct( point.target, "targetname" );
if ( !IsDefined( nextpoint ) )
{
nextpoint = GetEnt( point.target, "targetname" );
}
if ( !IsDefined( nextpoint ) )
{
nextpoint = GetNode( point.target, "targetname" );
}
if ( !IsDefined( nextpoint ) )
{
nextpoint = GetVehicleNode( point.target, "targetname" );
}
if ( IsDefined( nextpoint ) )
{
arr[ arr.size ] = nextpoint;
}
else
{
break;
}
point = nextpoint;
}
return arr;
}
milliseconds( seconds )
{
return seconds * 1000;
}
seconds( milliseconds )
{
return milliseconds / 1000;
}
// AI Section ---------------------------------------------
ai_post_spawn()
{
self endon( "death" );
if ( !IsDefined( self.target ) )
{
return;
}
points = getstructarray( self.target, "targetname" );
while ( 1 )
{
if ( points.size == 0 )
{
return;
}
point = points[ 0 ];
if ( points.size > 1 )
{
point = points[ RandomInt( points.size ) ];
}
if ( IsDefined( point.radius ) )
{
self.goalradius = point.radius;
}
self SetGoalPos( point.origin );
self waittill( "goal" );
if ( IsDefined( point.script_noteworthy ) )
{
if ( point.script_noteworthy == "so_shoot_rpg" )
{
self.a.rockets = 1;
// target = GetEnt( "so_rpg_target", "targetname" );
self SetEntityTarget( level.chopper );
self.ignoreall = false;
level notify( "so_rpgs_shot" );
}
}
if ( IsDefined( point.script_flag_wait ) )
{
flag_wait( point.script_flag_wait );
if ( IsDefined( point.script_noteworthy ) )
{
if ( point.script_noteworthy == "so_shoot_rpg" )
{
self SetCanDamage( true );
}
}
}
point script_delay();
if ( IsDefined( point.script_noteworthy ) )
{
if ( point.script_noteworthy == "so_shoot_rpg" )
{
self ClearEntityTarget();
}
}
if ( !IsDefined( point.target ) )
{
break;
}
points = getstructarray( point.target, "targetname" );
}
self.goalradius = level.default_goalradius;
}
so_rpg_post_spawn()
{
self SetCanDamage( false );
}
friendlyfire()
{
next_time = 0;
duration = 3000;
while ( 1 )
{
level.groundplayer waittill( "damage", dmg, attacker );
if ( attacker == level.chopper )
{
if ( GetTime() > next_time )
{
next_time = GetTime() + duration;
chopper_dialog( "friendlyfire" );
}
}
}
}
// ---------------------
// --- CHOPPER STUFF ---
// ---------------------
#using_animtree( "vehicles" );
build_chopper()
{
maps\_blackhawk_minigun::main( "vehicle_blackhawk_minigun_hero", "blackhawk_minigun_so" );
}
chopper_defaults()
{
self ClearGoalYaw();
self.speed_setting = "none";
self chopper_default_speed();
self SetHoverParams( 50, 10, 3 );
self chopper_default_pitch_roll();
self SetNearGoalNotifyDist( 200 );
}
chopper_default_pitch_roll()
{
self SetMaxPitchRoll( 0, 0 );
}
chopper_default_speed()
{
if ( self.speed_setting == "default" )
{
return;
}
self.speed_setting = "default";
// self Vehicle_SetSpeed( 15, 7.5 );
// self Vehicle_SetSpeed( 20, 10, 10 );
self Vehicle_SetSpeed( 20, 20, 20 );
}
chopper_slow_speed()
{
if ( self.speed_setting == "slow" && self.speed_setting != "force_default" )
{
return;
}
self.speed_setting = "slow";
self Vehicle_SetSpeed( 10, 20, 20 );
}
chopper_high_speed()
{
if ( self.speed_setting == "high" )
{
return;
}
self.speed_setting = "high";
self Vehicle_SetSpeed( 30, 20, 20 );
}
// Mouns the player to the chopper
chopper_playermount( player )
{
player AllowCrouch( false );
player AllowProne( false );
player AllowSprint( false );
player AllowJump( false );
self maps\_blackhawk_minigun::player_mount_blackhawk_gun( true, player, false );
self chopper_defaults();
}
chopper_dialog( alias )
{
if ( flag( "special_op_terminated" ) )
{
return;
}
aliases = [];
switch( alias )
{
case "end_reminder":
aliases[ 0 ] = "end_reminder_1";
aliases[ 1 ] = "end_reminder_2";
break;
case "objective_reminder":
aliases[ 0 ] = "objective_reminder_1";
aliases[ 1 ] = "objective_reminder_2";
aliases[ 2 ] = "objective_reminder_3";
break;
case "friendlyfire":
aliases[ 0 ] = "friendlyfire_1";
aliases[ 1 ] = "friendlyfire_2";
aliases[ 2 ] = "friendlyfire_3";
break;
default:
break;
}
if ( aliases.size > 0 )
{
alias = aliases[ RandomInt( aliases.size ) ];
}
thread radio_dialogue( alias );
}
// Kicks off the chopper threads
chopper_think()
{
// draw_high_obstacles();
self SetMaxPitchRoll( 30, 30 );
level.chopper_segment_points = 15;
level.chopper_range_from_point = 1300;
level.chopper_base_elevation = 3100;
level.chopper_lookat_point = level.groundplayer.origin;
chopper_dialog( "lift_off" );
// initial getting into the air
liftoffPath = get_targeted_line_array( self.start );
for ( i = 1; i < liftoffPath.size; i++ )
{
if ( i == 1 )
{
self Vehicle_SetSpeed( 20, 6, 6 );
}
else
{
self chopper_default_speed();
}
node = liftoffPath[ i ];
self SetGoalYaw( node.angles[ 1 ] );
self SetVehGoalPos( node.origin, 0 );
self waittill_either( "near_goal", "goal" );
}
chopper_dialog( "objective" );
chopper_dialog( "objective2" );
self chopper_defaults();
level.chopperhint_time = GetTime();
level.chopperplayer thread display_hint_timeout( "ads_slowdown", 5 );
self thread chopper_gun_face_entity( level.groundplayer );
self thread chopper_move_with_player();
// self thread chopper_target();
self thread debug_chopper_base_path();
}
so_ads_slowdown_hint()
{
if ( GetTime() > level.chopperhint_time + 2000 )
{
if ( chopperplayer_pressing_slowdown() )
{
return true;
}
}
return false;
}
so_fake_choppergunner()
{
spawner = GetEnt( "so_choppergunner_spawner", "targetname" );
drone = maps\_spawner::spawner_dronespawn( spawner );
drone LinkTo( level.chopper, "tag_player" );
}
test_chopper_paths()
{
level.chopper chopper_follow_path( "so_chopper_driveby", false );
level.chopper notify( "stop_chopper_gun_face_entity" );
level.chopper chopper_defaults();
level.chopper SetHoverParams( 10, 2, 1 );
level.chopper ClearLookAtEnt();
level.chopper thread chopper_gun_face_entity( getstruct( "so_chopper_gasstation_lookat", "targetname" ) );
wait( 1 );
struct = getstruct( "so_last_driveby_point", "script_noteworthy" );
level.chopper SetVehGoalPos( struct.origin, 1 );
level.chopper SetHoverParams( 10, 2, 1 );
level.chopper Vehicle_SetSpeed( 5, 1, 1 );
level.chopper thread chopper_fake_hover( struct.origin );
level waittill( "never" );
}
chopper_fake_hover( origin, dist, use_goal )
{
self endon( "stop_chopper_fake_hover" );
if ( !IsDefined( dist ) )
{
dist = 100;
}
while ( 1 )
{
x = RandomFloatRange( dist * -1, dist );
y = RandomFloatRange( dist * -1, dist );
z = RandomFloatRange( dist * -1, dist );
self SetVehGoalPos( origin + ( x, y, z ), 1 );
if ( IsDefined( use_goal ) && use_goal )
{
self Vehicle_SetSpeed( 5 + RandomInt( 10 ), 3, 3 );
self waittill( "goal" );
}
else
{
wait( RandomFloatRange( 3, 5 ) );
}
}
}
//chopper_target()
//{
// while ( 1 )
// {
// wait( 0.5 );
// foreach ( ai in GetAIArray( "axis" ) )
// {
// if ( !IsDefined( ai.showing_as_target ) && IsAlive( ai ) && !( IsDefined( ai.a.special ) && ai.a.special == "none" ) )
// {
// ai.showing_as_target = true;
// Target_Set( ai, ( 0, 0, 32 ) );
// Target_SetShader( ai, "remotemissile_infantry_target" );
// Target_ShowToPlayer( ai, level.chopperplayer );
// }
// }
// }
//}
// Handles the chopper orientation with the ground player
chopper_gun_face_entity( ent, wait_for_goal, delay )
{
self notify( "stop_chopper_gun_face_entity" );
self endon( "stop_chopper_gun_face_entity" );
if ( !IsDefined( level.chopper_gun_ground_entity ) )
{
level.chopper_gun_ground_entity = Spawn( "script_origin", self.origin );
}
if ( IsDefined( wait_for_goal ) && wait_for_goal )
{
self SetMaxPitchRoll( 20, 20 );
// self waittill_either( "near_goal", "goal" );
self waittill( "chopper_near_goal" );
self chopper_default_pitch_roll();
}
if ( !IsDefined( delay ) )
{
delay = 1;
}
self delayCall( delay, ::SetLookAtEnt, level.chopper_gun_ground_entity );
while ( 1 )
{
if ( ent == level.groundplayer )
{
lookat_origin = level.chopper_lookat_point;
}
else
{
lookat_origin = ent.origin;
}
// "forward" = vector from the chopper to the groundplayer
forwardvec = VectorNormalize( lookat_origin - self.origin );
forwardangles = VectorToAngles( forwardvec );
rightvec = AnglesToRight( forwardangles );
backvec = rightvec * -1;
neworigin = self.origin + ( backvec * 100 );
level.chopper_gun_ground_entity.origin = neworigin;
wait( 0.05 );
}
}
// Overall chopper movement thread
chopper_move_with_player( player )
{
thread debug_player_pos();
self.chopper_pathpoint = chopper_get_closest_pathpoint( 3 );
self.no_bline_to_goal = true;
just_started = true;
// update_direction_duration = 5000;
// next_update_direction = GetTime() + update_direction_duration;
self chopper_reset_range_points();
self.slowdown_points = [];
while ( 1 )
{
if ( self ent_flag( "manual_control" ) )
{
wait( 0.1 );
continue;
}
self SetNearGoalNotifyDist( 200 );
chopper_move_till_goal();
self.chopper_pathpoint = chopper_get_next_pathpoint( self.chopper_pathpoint[ "index" ] );
if ( just_started )
{
just_started = false;
self.no_bline_to_goal = false;
}
// if ( GetTime() > next_update_direction )
// {
// next_update_direction = GetTime() + update_direction_duration;
// chopper_update_enemy_direction();
// }
}
}
//chopper_update_enemy_direction()
//{
// enemies = GetAiArray( "axis" );
//
// self.slowdown_points = [];
//
// if ( GetDvarInt( "test_chopper_path" ) < 1 )
// {
// return;
// }
//
// if ( enemies.size == 0 )
// {
// return;
// }
//
// origins = ( 0, 0, 0 );
// foreach ( enemy in enemies )
// {
// origins += enemy.origin;
// }
//
// avg_origin = ( origins[ 0 ] / enemies.size, origins[ 1 ] / enemies.size, origins[ 2 ] / enemies.size );
// angles = VectorToAngles( avg_origin - level.groundplayer.origin );
// angles = ( AngleClamp( angles[ 0 ] ), AngleClamp( angles[ 1 ] ), AngleClamp( angles[ 2 ] ) );
//
// // Figure out what points along the chopper points for the angles
// y = AngleClamp( angles[ 1 ] + 180 );
//
// within = 60;
//
//
// for ( i = 0; i < level.chopper_segment_points; i++ )
// {
// temp = AngleClamp( ( ( 360 / level.chopper_segment_points ) * -1 ) * i );//* - 1 to have the reverse effect of movement( forward )
// if ( temp <= ( y + within ) && temp >= ( y - within ) )
// {
// self.slowdown_points[ i ] = true;
// }
// else
// {
// self.slowdown_points[ i ] = false;
// }
// }
//
// level thread debug_draw_enemy_direction( angles, "update_enemy_direction" );
//}
// Keeps updating the choppers goal, incase the ground player moves, will end once the chopper
// reaches it's goal.
chopper_move_till_goal()
{
self endon( "chopper_near_goal" );
self endon( "manual_control" );
self thread chopper_notify_near_goal();
is_far = false;
while ( 1 )
{
pos = chopper_get_pathpoint( self.chopper_pathpoint[ "index" ] );
level thread debug_draw_chopper_line( pos, "final_destination", ( 0, 1, 0 ) );
// If the chopper is too far away from it's goal, figure out a b-line path to the closest
// Assume that we need to get back on track...
if ( !self.no_bline_to_goal && distance2d_squared( pos, self.origin ) > 1000 * 1000 )
{
// Stop the endon until we are close enough
is_far = true;
self notify( "stop_chopper_notify_near_goal" );
info = chopper_get_closest_pathpoint();
pos = info[ "point" ];
self.chopper_pathpoint = info;
level thread debug_draw_chopper_line( pos, "final_destination", ( 0, 1, 0 ) );
pos = chopper_get_bline_path_point( pos );
level thread debug_draw_chopper_line( pos, "closer_point" );
if ( self ent_flag( "manual_control" ) )
{
return;
}
self SetVehGoalPos( pos );
self waittill_either( "near_goal", "goal" );
continue;
}
else
{
if ( is_far )
{
// Reinitiate the chopper_notify_near_goal since we stopped it before
self thread chopper_notify_near_goal();
}
is_far = false;
}
if ( self ent_flag( "manual_control" ) )
{
return;
}
chopper_slow_down();
// Line( pos, pos + ( 0, 0, 2000 ), ( 1, 1, 0 ), 2 );
level thread debug_draw_chopper_line( pos, "closer_point" );
self SetVehGoalPos( pos );
wait( 0.1 );
}
}
chopperplayer_pressing_slowdown()
{
if ( level.chopperplayer AdsButtonPressed() || level.chopperplayer UseButtonPressed() )
{
return true;
}
return false;
}
chopper_slow_down()
{
// if ( GetDvarInt( "test_chopper_slowdown" ) == 1 )
// {
if ( chopperplayer_pressing_slowdown() )
{
chopper_slow_speed();
}
else
{
chopper_default_speed();
}
// }
}
chopper_notify_near_goal()
{
self notify( "stop_chopper_notify_near_goal" );
self endon( "stop_chopper_notify_near_goal" );
self waittill_either( "near_goal", "goal" );
self notify( "chopper_near_goal" );
}
// Returns the 1 chopper flight path, depending on the num passed in
chopper_get_pathpoint( num )
{
add_angles = ( 360 / level.chopper_segment_points ) * -1;//* - 1 to have the reverse effect of movement( forward )
angles = ( 0, add_angles * num, 0 );
forward = AnglesToForward( angles );
// point = level.groundplayer.origin + vector_multiply( forward, level.chopper_range_from_point );
if ( is_player_in_parking_lot() )
{
level.chopper_lookat_point = get_parkinglot_point();
point = level.chopper_lookat_point + vector_multiply( forward, level.chopper_range_from_point );
}
else
{
level.chopper_lookat_point = get_closest_point_on_base_path();
point = level.chopper_lookat_point + vector_multiply( forward, level.chopper_range_from_point );
}
point = chopper_get_pointheight( point );
return point;
}
chopper_get_bline_path_point( pos )
{
angles = VectorToAngles( pos - level.chopper.origin );
forward = AnglesToForward( angles );
point = level.chopper.origin + vector_multiply( forward, 500 );
point = chopper_get_pointheight( point );
return point;
}
// Returns all of the choppers flight path points
chopper_get_pathpoints()
{
points = [];
for ( i = 0; i < level.chopper_segment_points; i++ )
{
points[ i ] = chopper_get_pathpoint( i );
}
return points;
}
// Takes the given point and adjusts it's Z coordinate depending on the obstacles.
chopper_get_pointheight( point )
{
base = level.chopper_base_elevation;
height = base;
info = chopper_get_closest_obstacle_info( point );
if( IsDefined( info[ "struct" ] ) )
{
if ( info[ "dist" ] < info[ "min_radius" ] )
{
height = info[ "struct" ].origin[ 2 ];
}
else
{
// height = level.chopper_base_elevation + ( ( info[ "struct" ].origin[ 2 ] - level.chopper_base_elevation ) * ( info[ "dist" ] / ( info[ "max_radius" ] - info[ "min_radius" ] ) ) );
height_diff = info[ "struct" ].origin[ 2 ] - level.chopper_base_elevation;
height_perc = info[ "dist" ] / ( info[ "max_radius" ] - info[ "min_radius" ] );
height = base + ( height_diff * height_perc );
}
if( height < base )
{
height = base;
}
}
point = ( point[ 0 ], point[ 1 ], height );
return point;
}
// Return the closest and highest struct
chopper_get_closest_obstacle_info( point )
{
structs = getstructarray( "high_obstacle", "targetname" );
// First find all of the structs the point within it's radius.
close_structs = [];
dist_array = [];
min_radius_array = [];
max_radius_array = [];
foreach ( struct in structs )
{
max_radius = 600;
if ( IsDefined( struct.radius ) )
{
max_radius = struct.radius;
}
min_radius = max_radius * 0.5;
test_dist = Distance2D( point, struct.origin );
if ( test_dist < max_radius )
{
close_structs[ close_structs.size ] = struct;
dist_array[ dist_array.size ] = test_dist;
min_radius_array[ min_radius_array.size ] = min_radius;
max_radius_array[ max_radius_array.size ] = max_radius;
}
}
// Now filter out the highest struct and return it
highest_struct = undefined;
dist = undefined;
min_radius = undefined;
max_radius = undefined;
if ( close_structs.size > 0 )
{
highest_struct = close_structs[ 0 ];
dist = dist_array[ 0 ];
min_radius = min_radius_array[ 0 ];
max_radius = max_radius_array[ 0 ];
for ( i = 1; i < close_structs.size; i++ )
{
if ( close_structs[ i ].origin[ 2 ] > highest_struct.origin [ 2 ] )
{
highest_struct = close_structs[ i ];
dist = dist_array[ i ];
min_radius = min_radius_array[ i ];
max_radius = max_radius_array[ i ];
}
}
}
info = [];
info[ "struct" ] = highest_struct;
info[ "dist" ] = dist;
info[ "min_radius" ] = min_radius;
info[ "max_radius" ] = max_radius;
return info;
}
// 0 = along the X
chopper_set_range_points( min_num, max_num )
{
self.min_point_on_pathpoints = min_num;
self.max_point_on_pathpoints = max_num;
}
chopper_reset_range_points()
{
self.min_point_on_pathpoints = 0;
self.max_point_on_pathpoints = 0;
self.hover_direction = 1;
}
// Returns the next point (in array form for extra info) on the path
chopper_get_next_pathpoint( num )
{
points = chopper_get_pathpoints();
min_point = self.min_point_on_pathpoints;
max_point = self.max_point_on_pathpoints;
// if not 0 and 0, then stay within the range
if ( min_point - max_point != 0 )
{
if ( num == min_point )
{
self.hover_direction = 1;
}
else if ( num == max_point )
{
self.hover_direction = -1;
}
num = num + self.hover_direction;
}
else
{
self.hover_direction = 1;
num++;
}
if ( num < 0 )
{
num = level.chopper_segment_points - 1;
}
if ( num >= points.size )
{
num = 0;
}
info = [];
info[ "point" ] = points[ num ];
info[ "index" ] = num;
// Slow down section
// if ( GetDvarInt( "test_chopper_path" ) > 0 )
// {
// if ( self.slowdown_points.size > 0 )
// {
// if ( self.slowdown_points[ num ] )
// {
// info[ "enemydir" ] = true;
// }
// }
// }
return info;
}
// Returns the closest point (in array form for extra info) on the path
chopper_get_closest_pathpoint( add_index )
{
points = chopper_get_pathpoints();
dist = DistanceSquared( points[ 0 ], level.chopper.origin );
closest = points[ 0 ];
index = 0;
foreach ( i, point in points )
{
test = DistanceSquared( point, level.chopper.origin );
if ( test < dist )
{
closest = point;
index = i;
dist = test;
}
}
info = [];
if ( IsDefined( add_index ) )
{
index = index + add_index;
if ( index > level.chopper_segment_points )
{
index = index - level.chopper_segment_points;
}
info[ "point" ] = chopper_get_pathpoint( index );
info[ "index" ] = index;
}
else
{
info[ "point" ] = closest;
info[ "index" ] = index;
}
return info;
}
chopper_follow_path( path_targetname, follow_player_when_done, dialog, safe_flight )
{
self notify( "stop_chopper_fake_hover" );
self notify( "stop_chopper_gun_face_entity" );
self ClearLookAtEnt();
self.speed_setting = "none";
self ent_flag_set( "manual_control" );
if ( !IsDefined( safe_flight ) )
{
safe_flight = false;
}
path_start = getstruct( path_targetname, "targetname" );
path_point = path_start;
going_to_start = true;
while ( IsDefined( path_point ) )
{
if ( IsDefined( path_point.speed ) )
{
speed = path_point.speed;
accel = 20;
decel = 10;
if ( IsDefined( path_point.script_accel ) )
{
accel = path_point.script_accel;
}
if ( IsDefined( path_point.script_decel ) )
{
decel = path_point.script_decel;
}
self Vehicle_SetSpeed( path_point.speed, accel, decel );
}
if ( IsDefined( path_point.script_speed ) )
{
speed = path_point.script_speed;
accel = 20;
decel = 10;
if ( IsDefined( path_point.script_accel ) )
{
accel = path_point.script_accel;
}
if ( IsDefined( path_point.script_decel ) )
{
decel = path_point.script_decel;
}
self Vehicle_SetSpeedImmediate( path_point.script_speed, accel, decel );
}
if ( IsDefined( path_point.radius ) )
{
self SetNearGoalNotifyDist( path_point.radius );
}
stop_at_goal = false;
if ( IsDefined( path_point.script_stopnode ) && path_point.script_stopnode )
{
stop_at_goal = true;
}
self SetGoalYaw( path_point.angles[ 1 ] );
// If the chopper is too far away from it's goal, figure out a b-line path
if ( going_to_start && safe_flight )
{
while ( distance2d_squared( path_point.origin, self.origin ) > 1000 * 1000 )
{
point = chopper_get_bline_path_point( path_point.origin );
self SetVehGoalPos( point, stop_at_goal );
self waittill_either( "near_goal", "goal" );
}
}
self SetVehGoalPos( path_point.origin, stop_at_goal );
self waittill_either( "near_goal", "goal" );
if ( IsDefined( path_point.script_flag_set ) )
{
flag_set( path_point.script_flag_set );
}
going_to_start = false;
if ( IsDefined( path_point.script_noteworthy ) )
{
[[ level.chopper_funcs[ path_point.script_noteworthy ]]]();
}
path_point script_delay();
if ( !IsDefined( path_point.target ) )
{
break;
}
path_point = getstruct( path_point.target, "targetname" );
}
self notify( "follow_path_done" );
if ( IsDefined( follow_player_when_done ) && follow_player_when_done )
{
self chopper_defaults();
self.chopper_pathpoint = chopper_get_closest_pathpoint();
self ent_flag_clear( "manual_control" );
self thread chopper_gun_face_entity( level.groundplayer, true );
}
if ( IsDefined( dialog ) )
{
chopper_dialog( dialog );
}
}
get_parkinglot_point()
{
point = level.groundplayer.origin;
point = ( clamp( point[ 0 ], -2400, 3100 ), clamp( point[ 1 ], -5300, -700 ), point[ 2 ] );
return point;
}
get_closest_point_on_base_path()
{
paths = [];
struct_array = getstructarray( "base_player_path", "targetname" );
foreach ( struct in struct_array )
{
paths[ paths.size ] = get_targeted_line_array( struct );
}
points = [];
foreach ( path in paths )
{
for ( i = 0; i < path.size - 1; i++ )
{
points[ points.size ] = PointOnSegmentNearestToPoint( path[ i ].origin, path[ i + 1 ].origin, level.groundplayer.origin );
}
}
dist = DistanceSquared( points[ 0 ], level.groundplayer.origin );
closest_point = points[ 0 ];
foreach ( point in points )
{
test_dist = DistanceSquared( point, level.groundplayer.origin );
if ( test_dist < dist )
{
closest_point = point;
dist = test_dist;
}
}
// Let's not go more than 200 units off the base path
if ( distance2d_squared( closest_point, level.groundplayer.origin ) > 200 * 200 )
{
angles = VectorToAngles( level.groundplayer.origin - closest_point );
forward = AnglesToForward( angles );
closest_point = closest_point + vector_multiply( forward, 200 );
}
else
{
closest_point = level.groundplayer.origin;
}
return closest_point;
}
distance2d_squared( pos1, pos2 )
{
pos1 = ( pos1[ 0 ], pos1[ 1 ], 0 );
pos2 = ( pos2[ 0 ], pos2[ 1 ], 0 );
return DistanceSquared( pos1, pos2 );
}
is_player_in_parking_lot()
{
return level.groundplayer IsTouching( GetEnt( "so_parkinglot", "targetname" ) );
}
// TRUCK Section ------------------------------------------
truck_init()
{
level.truck_spawner = GetEnt( "gas_station_truck", "targetname" );
level.truck_ai_spawners = GetEntArray( "so_truck_ai_spawner", "targetname" );
}
spawn_truck( targetname )
{
spawner = level.truck_spawner;
ai_spawners = level.truck_ai_spawners;
spawner.script_startinghealth = 5000;
spawner.targetname = "so_truck";
spawner.target = targetname;
foreach ( ai_spawner in ai_spawners )
{
ai_spawner.targetname = targetname;
}
truck = maps\_vehicle::spawn_vehicle_from_targetname_and_drive( "so_truck" );
truck thread truck_brakes();
// So the corpse of the truck cannot be moved
truck.free_on_death = true;
}
truck_brakes()
{
self waittill( "unloading" );
self set_brakes( 0.5 );
}
// FX -----------------------------------------------------
smoke_mover()
{
ent = Spawn( "script_model", ( 600, -4525, 2610 ) );
ent.angles = ( 357, 179, 177 );
ent SetModel( "tag_origin" );
PlayFxOnTag( level._effect[ "objective_smoke" ], ent, "tag_origin" );
ent thread smoke_mover_thread();
}
// Will need a new FX to finish this off.
smoke_mover_thread()
{
spawn_angles = self.angles;
full_pitch = 60;
range = 1500;
while ( 1 )
{
wait( 1 );
dist = Distance2D( level.chopper.origin, self.origin );
percent = dist / range;
if ( percent < 1 )
{
percent = 1 - percent;
angles = VectorToAngles( vector2d( level.player.origin ) - vector2d( self.origin ) );
angles = ( angles[ 0 ] + ( full_pitch * percent ), angles[ 1 ], angles[ 2 ] );
self RotateTo( spawn_angles + angles, 0.5 );
}
else
{
self RotateTo( spawn_angles, 0.5 );
}
}
}
vector2d( vec )
{
return ( vec[ 0 ], vec[ 1 ], 0 );
}
// Exploders ----------------------------------------------
do_exploder_custom( current, option )
{
while( 1 )
{
exploder_stripped( current.script_prefab_exploder, option );
if( !isdefined( current.target ) )
{
break;
}
next = GetEnt( current.target, "targetname" );
if( !isdefined( next ) )
{
break;
}
current = next;
}
}
exploder_stripped( num, option )
{
num += "";
//here's a hook so you can know when a certain number of an exploder is going off
level notify( "exploding_" + num );
for ( i = 0;i < level.createFXent.size;i++ )
{
ent = level.createFXent[ i ];
if ( !isdefined( ent ) )
{
continue;
}
if ( ent.v[ "type" ] != "exploder" )
{
continue;
}
// make the exploder actually removed the array instead?
if ( !isdefined( ent.v[ "exploder" ] ) )
{
continue;
}
if ( ent.v[ "exploder" ] + "" != num )
{
continue;
}
ent.v[ "soundalias" ] = undefined;
ent.v[ "loopsound" ] = undefined;
ent.v[ "damage" ] = undefined;
ent.v[ "delay" ] = 0;
ent.v[ "delay_min" ] = undefined;
ent.v[ "delay_max" ] = undefined;
ent.v[ "earthquake" ] = undefined;
if ( IsDefined( option ) && option == "just_swap" )
{
ent.v[ "firefx" ] = undefined;
ent.v[ "fxid" ] = undefined;
}
ent activate_individual_exploder();
}
}
// DEBUG Section ------------------------------------------
debug_chopper_base_path()
{
/#
if ( !debug_chopper_enabled() )
{
return;
}
while ( 1 )
{
wait( 0.05 );
if ( is_player_in_parking_lot() )
{
continue;
}
closest_point = get_closest_point_on_base_path();
// level thread draw_linesegment_point( closest_point );
Line( closest_point, closest_point + ( 0, 0, 1000 ), ( 1, 0.5, 0 ) );
Line( closest_point, level.groundplayer.origin, ( 1, 1, 1 ) );
}
#/
}
// Draw the player's location with chopper flight path
// Dvar debug_follow + number will have the fake ground player move along a path
// If not using debug_follow, the player can hit use to update the fake ground player's origin
// to whatever the chopper player is aiming at.
debug_player_pos()
{
/#
if ( !debug_chopper_enabled() )
{
return;
}
level.groundplayer.origin = ( 84, 4450, 2260 );
thread draw_player_pos();
thread draw_chopper_path();
if ( GetDvarInt( "debug_follow" ) != 0 )
{
num = GetDvarInt( "debug_follow" );
start = getstruct( "follow_player_path_start" + num, "targetname" );
struct = start;
speed = 200;
debug_trigger_everything();
while ( 1 )
{
dist = Distance( level.groundplayer.origin, struct.origin );
time = dist / speed;
level.groundplayer MoveTo( struct.origin, time, 0, 0 );
level.groundplayer waittill( "movedone" );
struct script_delay();
if( IsDefined( struct.target ) )
{
struct = getstruct( struct.target, "targetname" );
}
else
{
struct = start;
debug_trigger_everything();
so_chopper_invasion_moments();
debug_kill_ai();
}
}
}
else
{
while ( 1 )
{
wait( 0.05 );
if ( level.player UseButtonPressed() )
{
eye = level.player GetEye();
forward = AnglesToForward( level.player GetPlayerAngles() );
forward_origin = eye + vector_multiply( forward, 10000 );
trace = BulletTrace( level.player GetEye(), forward_origin, false, self );
level.groundplayer.origin = trace[ "position" ];
}
}
}
#/
}
debug_trigger_everything()
{
/#
foreach ( trigger in GetEntArray( "trigger_multiple_spawn", "classname" ) )
{
trigger thread debug_trigger_everything_think();
}
#/
}
debug_trigger_everything_think()
{
/#
self notify( "stop_debug_trigger_everything_think" );
self endon( "stop_debug_trigger_everything_think" );
if ( !IsDefined( self.spawners ) )
{
self.spawners = GetEntArray( self.target, "targetname" );
foreach ( spawner in self.spawners )
{
spawner.old_count = spawner.count;
}
}
else
{
foreach ( spawner in self.spawners )
{
spawner.count = spawner.old_count;
}
}
while ( 1 )
{
wait( 0.05 );
if ( level.groundplayer IsTouching( self ) )
{
break;
}
}
self notify( "trigger" );
#/
}
// Draws the chopper flight path
draw_chopper_path()
{
/#
while ( 1 )
{
wait( 0.05 );
points = chopper_get_pathpoints();
for ( i = 0; i < points.size; i++ )
{
next = i + 1;
if ( next == points.size )
{
next = 0;
}
color = ( 1, 1, 0.3 );
// if ( GetDvarInt( "test_chopper_path" ) > 0 )
// {
// if ( self.slowdown_points.size > 0 )
// {
// if ( self.slowdown_points[ i ] )
// {
// color = ( 0.3, 1, 0.3 );
// }
// }
// }
Line( points[ i ], points[ next ], color );
}
}
#/
}
draw_linesegment_point( pos )
{
/#
level notify( "stop_draw_linesegment_point" );
level endon( "stop_draw_linesegment_point" );
while ( 1 )
{
Line( pos, pos + ( 0, 0, 1000 ), ( 1, 1, 0.1 ) );
wait( 0.05 );
}
#/
}
// Draws the ground player's position
draw_player_pos( pos )
{
/#
while ( 1 )
{
wait( 0.05 );
Line( level.groundplayer.origin, level.groundplayer.origin + ( 0, 0, 1000 ), ( 0.3, 1, 0.3 ) );
}
#/
}
// Draws all of the high objstacle points
draw_high_obstacles()
{
/#
structs = getstructarray( "high_obstacle", "targetname" );
foreach ( struct in structs )
{
struct thread draw_high_obstacle();
}
#/
}
draw_high_obstacle()
{
/#
while ( 1 )
{
wait( 0.05 );
Line( self.origin, self.origin + ( 0, 0, -5000 ), ( 1, 1, 1 ) );
}
#/
}
debug_kill_ai()
{
/#
foreach ( ai in GetAIArray( "axis" ) )
{
ai Kill();
}
#/
}
debug_chopper_enabled()
{
/#
return GetDvarInt( "debug_chopper" ) == 1;
#/
}
debug_draw_chopper_line( pos, note, color )
{
/#
level notify( note );
level endon( note );
if ( !IsDefined( color ) )
{
color = ( 1, 1, 1 );
}
if ( !debug_chopper_enabled() )
{
return;
}
while ( 1 )
{
wait( 0.05 );
Line( pos, level.chopper.origin, color );
}
#/
}
debug_draw_enemy_direction( angle, note )
{
/#
level notify( note );
level endon( note );
color = ( 1, 1, 1 );
if ( !debug_chopper_enabled() )
{
return;
}
while ( 1 )
{
wait( 0.05 );
pos = level.groundplayer.origin + vector_multiply( AnglesToForward( angle ), 1000 );
Line( pos, level.groundplayer.origin, color );
}
#/
}