IW4-Dump-Files/maps/so_download_arcadia_code.gsc

1487 lines
31 KiB
Plaintext

#include maps\_utility;
#include common_scripts\utility;
#include maps\_hud_util;
#include maps\_specialops;
#include maps\_specialops_code;
#include maps\so_download_arcadia;
// make sure this is the same as in arcadia_code.gsc
STRYKER_SUPPRESSION_RADIUS = 1500 * 1500;
// -----------------------
// --- DOWNLOAD STUFF ---
// -----------------------
so_download_objective_init( objIdx, objStr )
{
level.downloadObjectiveStr = objStr;
level.downloadObjectiveIdx = objIdx;
level.downloadsComplete = 0;
level.downloads = GetStructArray( "download", "targetname" );
foreach( index, download in level.downloads )
{
download.objPos = index;
}
// first one sets the objective
Objective_Add( level.downloadObjectiveIdx, "current", objStr, level.downloads[ 0 ].origin );
// the rest are added as additional positions
for( i = 1; i < level.downloads.size; i++ )
{
download = level.downloads[ i ];
Objective_AdditionalPosition( level.downloadObjectiveIdx, download.objPos, download.origin );
}
array_thread( level.players, ::ent_flag_init, "download_hint_on" );
array_thread( level.downloads, ::download_obj_setup );
}
// sets up each DSM group and starts it thinking
download_obj_setup()
{
computer = Spawn( "script_model", self.origin );
computer SetModel( "com_laptop_rugged_open" );
computer.angles = self.angles;
dsmSpot = GetStruct( self.target, "targetname" );
dsm = Spawn( "script_model", dsmSpot.origin );
dsm SetModel( "mil_wireless_dsm" );
dsm.angles = dsmSpot.angles;
dsm_obj = Spawn( "script_model", dsm.origin );
dsm_obj SetModel( "mil_wireless_dsm_obj" );
dsm_obj.angles = dsm.angles;
dsm Hide();
self.computer = computer;
self.dsm = dsm;
self.dsm_obj = dsm_obj;
// self.chargeTarget = Spawn( "script_origin", self.origin ); // for AIs to target
self.trig = GetEnt( self.target, "targetname" );
self.trig download_trig_sethintstring();
self thread download_obj_think();
}
download_trig_sethintstring()
{
self SetHintString( &"SO_DOWNLOAD_ARCADIA_DSM_USE_HINT" );
}
download_trig_clearhintstring()
{
self SetHintString( "" );
}
download_obj_think()
{
self ent_flag_init( "download_stopped" );
self.downloading = false;
self.firstDownload = true;
self.downloadTimeElapsed = 0;
self.filesDone = 0;
self.download_complete = false;
while( 1 )
{
self.trig waittill( "trigger" );
// swap the models
self.dsm_obj Hide();
self.dsm Show();
self.trig download_trig_clearhintstring();
// downloads can be interrupted by enemies
success = self download_files();
// if we downloaded successfully then break out
if( success )
{
self.dsm Hide();
break;
}
else
{
self.trig download_trig_sethintstring();
self.dsm Hide();
self.dsm_obj Show();
}
}
// this one's done
level.downloadsComplete++;
self.download_complete = true;
thread download_obj_dialogue();
// if we got them all, complete the objective
if( level.downloadsComplete >= level.downloads.size )
{
Objective_Complete( level.downloadObjectiveIdx );
flag_set( "all_downloads_finished" );
}
// otherwise remove this position from the objective
else
{
Objective_AdditionalPosition( level.downloadObjectiveIdx, self.objPos, ( 0, 0, 0 ) );
// give "objective updated" message and ping locations
Objective_String( level.downloadObjectiveIdx, level.downloadObjectiveStr );
Objective_Ring( level.downloadObjectiveIdx );
}
}
download_obj_dialogue()
{
downloadsLeft = level.downloads.size - level.downloadsComplete;
if( downloadsLeft == 2 )
{
// "Good job, Hunter Two-One. Our intel indicates that there are two more laptops in the area - go find them and get their data."
so_radio_dialogue( "so_dwnld_hqr_gofindthem" );
return;
}
else if( downloadsLeft == 1 )
{
// "Stay frosty, Hunter Two-One, there's one laptop left."
so_radio_dialogue( "so_dwnld_hqr_onelaptop" );
return;
}
else if( downloadsLeft == 0 )
{
// "Nice work, Hunter Two-One. Now get back to the Stryker, we're pulling you out of the area."
so_radio_dialogue( "so_dwnld_hqr_pullingyouout" );
bugWaitTime = 30;
aliases = [];
// "Hunter Two-One, get back to the Stryker for extraction!"
aliases[ 0 ] = "so_dwnld_hqr_extraction";
// "Hunter Two-One, return to the Stryker to complete your mission!"
aliases[ 1 ] = "so_dwnld_hqr_completemission";
level endon( "stryker_extraction_done" );
while( 1 )
{
foreach( alias in aliases )
{
wait( bugWaitTime );
so_radio_dialogue( alias );
}
}
}
}
so_radio_dialogue( alias )
{
if ( !flag( "special_op_terminated" ) )
{
radio_dialogue( alias );
}
}
so_character_dialogue( alias )
{
if ( !flag( "special_op_terminated" ) )
{
self dialogue_queue( alias );
}
}
download_files()
{
downloadTime = level.DOWNLOAD_TIME - self.downloadTimeElapsed;
if( !flag( "first_download_started" ) )
{
flag_set( "first_download_started" );
// "Hunter Two-One, there are hostiles in the area that can wirelessly disrupt the data transfer."
thread so_radio_dialogue( "so_dwnld_hqr_wirelesslydisrupt" );
}
self.downloading = true;
self notify( "downloading" );
success = false;
startTime = GetTime();
endTime = GetTime() + milliseconds( downloadTime );
// only spawn the defenders once, in case the download gets interrupted
if( !IsDefined( self.defenders_spawned ) )
{
self.defenders_spawned = true;
self.waveDead = false;
self thread download_files_enemies_attack( downloadTime );
}
self delaythread( 0.1, ::download_files_wave_death ); // delay so we can start waiting for the notify before it fires
self thread download_files_catch_interrupt();
self ent_flag_clear( "download_stopped" );
// This function returns the 'new' timeLeft from within it since it has a lengthy intro
downloadTime = download_files_hud_countdown( downloadTime );
// If the wave is dead and the player triggered the download, then it'll do a SUPER fast download
// so we need to wait for the time instead of the interrupt.
if ( self.waveDead )
{
wait( downloadTime );
}
else
{
self waittill_any_timeout( downloadTime, "download_interrupted" );
}
self notify( "downloading_stopped" );
self.downloading = false;
self.downloadTimeElapsed += seconds( GetTime() - startTime );
// if we killed all the enemies or used all the time, it was successful
if( self.waveDead || GetTime() >= endTime )
{
success = true;
}
self ent_flag_set( "download_stopped" );
if( !success )
{
self thread download_files_hud_countdown_abort();
thread download_interrupt_dialogue();
}
else
{
self thread download_files_hud_finish();
}
return success;
}
download_interrupt_dialogue()
{
wait( 1 );
lines = [];
// "Hunter Two-One, the download has been interrupted! You'll have to restart the data transfer manually."
lines[ 0 ] = "so_dwnld_hqr_restartmanually";
// "Hunter Two-One, hostiles have interrupted the download! Get back there and manually resume the transfer!"
lines[ 1 ] = "so_dwnld_hqr_getbackrestart";
if( !IsDefined( level.interruptLineIndex ) || ( level.interruptLineIndex >= lines.size ) )
{
level.interruptLineIndex = 0;
}
so_radio_dialogue( lines[ level.interruptLineIndex ] );
level.interruptLineIndex++;
}
download_files_wave_death()
{
self endon( "downloading_stopped" );
while( !self.waveDead )
{
wait( 0.05 );
}
self notify( "download_interrupted" );
}
dsm_wait( hudelem, time )
{
hudelem SetValue( 0 );
wait( 1 );
delay = 0.1;
steps = time / delay;
for( i = 0; i < steps; i++ )
{
num = clamp( int( ( i / steps ) * 100 ), 0, 100 );
hudelem SetValue( num );
wait( delay );
}
hudelem SetValue( 100 );
wait( 0.5 );
}
download_files_hud_countdown( timeLeft )
{
functionStartTime = GetTime();
x = -200;
y_offset = 50;
if ( IsSplitscreen() )
{
x = -220;
y_offset = 120;
}
if( self.firstDownload )
{
y = y_offset + ( level.hud_download_count * 20 );
level.hud_download_count++;
self.hudelem_y = y;
// SETUP
hudelem = get_countdown_hud( x, self.hudelem_y );
hudelem.alignX = "right";
hudelem SetPulseFX( 30, 900000, 700 );
hudelem.label = &"SO_DOWNLOAD_ARCADIA_DSM_FRAME"; // DSM v6.04
wait 0.65;
hudelem_status = get_countdown_hud( x, self.hudelem_y );
hudelem_status SetPulseFX( 30, 900000, 700 );
hudelem_status.label = &"SO_DOWNLOAD_ARCADIA_DSM_INIT"; // Initiliazing
dsm_wait( hudelem_status, 2.5 );
hudelem_status Destroy();
hudelem_status = get_countdown_hud( x, self.hudelem_y );
hudelem_status SetPulseFX( 30, 900000, 700 );
hudelem_status.label = &"SO_DOWNLOAD_ARCADIA_DSM_CONNECTING"; // Connecting
dsm_wait( hudelem_status, 0.9 );
hudelem_status Destroy();
hudelem_status = get_countdown_hud( x, self.hudelem_y );
hudelem_status SetPulseFX( 30, 900000, 700 );
hudelem_status.label = &"SO_DOWNLOAD_ARCADIA_DSM_LOGIN"; // Bypassing Login
dsm_wait( hudelem_status, 3.75 );
hudelem_status Destroy();
hudelem_status = get_countdown_hud( x, self.hudelem_y );
hudelem_status SetPulseFX( 30, 900000, 700 );
hudelem_status.label = &"SO_DOWNLOAD_ARCADIA_DSM_LOCATE"; // Locating Files
dsm_wait( hudelem_status, 1.5 );
hudelem Destroy();
hudelem_status Destroy();
self.firstDownload = false;
}
// START COUNTDOWN
// old -205
x = -250;
x_offset = x + 170;
hudelem = get_countdown_hud( x, self.hudelem_y, undefined, true );
hudelem SetPulseFX( 30, 900000, 700 );
hudelem.label = &"SO_DOWNLOAD_ARCADIA_DSM_PROGRESS"; // Files copied:
hudelem_status = get_download_state_hud( x_offset, self.hudelem_y, undefined, true );
hudelem_status.alignX = "right";
hudelem_status SetPulseFX( 30, 900000, 700 );
hudelem_status_total = get_countdown_hud( x_offset, self.hudelem_y, undefined, true );
hudelem_status_total SetPulseFX( 30, 900000, 700 );
if( !IsDefined( self.totalFiles ) )
{
self.totalFiles = RandomIntRange( level.NUM_FILES_MIN, level.NUM_FILES_MAX );
}
hudelem_status_total.label = &"SO_DOWNLOAD_ARCADIA_DSM_TOTALFILES";
hudelem_status_total SetValue( self.totalfiles );
timeLeft -= seconds( GetTime() - functionStartTime );
// If area is clear, SUPER fast download
if ( self.waveDead && timeLeft > 3 )
{
timeLeft = 3;
}
self thread download_files_update( hudelem, hudelem_status, hudelem_status_total, timeLeft );
return timeLeft;
}
download_files_update( hudelem, hudelem_status, hudelem_status_total, timeLeft )
{
// POLISH: it would be cool if some files were faster/slower to download
endtime = GetTime() + milliseconds( timeLeft );
filesLeft = self.totalfiles - self.filesDone;
incrementTime = 0.05; // timeLeft / filesLeft
file_inc = incrementTime / ( timeLeft / filesLeft );
while( GetTime() < endtime && !self ent_flag( "download_stopped" ) )
{
self.filesDone += file_inc;
hudelem_status SetValue( int( self.filesDone ) );
wait( incrementTime );
}
if ( !self ent_flag( "download_stopped" ) )
{
hudelem_status SetValue( self.totalfiles );
}
hudelem Destroy();
hudelem_status Destroy();
hudelem_status_total Destroy();
}
download_files_hud_countdown_abort()
{
x = -200;
if ( IsSplitscreen() )
{
x = -220;
}
hudelem = get_countdown_hud( x, self.hudelem_y );
hudelem.alignx = "right";
//hudelem.label = "";
//hudelem SetText( "ERROR: DOWNLOAD INTERRUPTED!" );
hudelem.label = &"SO_DOWNLOAD_ARCADIA_DSM_FRAME"; // DSM v6.04
hudelem.fontScale = 1.4;
hudelem set_hud_red();
hudelem_status = get_countdown_hud( x, self.hudelem_y );
hudelem_status.label = &"SO_DOWNLOAD_ARCADIA_DOWNLOAD_INTERRUPTED"; // DOWNLOAD INTERRUPTED
hudelem_status.fontScale = 1.4;
hudelem_status set_hud_red();
hudelem thread hud_blink();
hudelem_status thread hud_blink();
self waittill_any_timeout( 25, "downloading" );
hudelem Destroy();
hudelem_status Destroy();
}
download_files_hud_finish()
{
x = -200;
if ( IsSplitscreen() )
{
x = -220;
}
hudelem = get_countdown_hud( x, self.hudelem_y );
hudelem.alignx = "right";
hudelem.label = &"SO_DOWNLOAD_ARCADIA_DSM_FRAME"; // DSM v6.04
hudelem.fontScale = 1.4;
hudelem set_hud_blue();
hudelem_status = get_countdown_hud( x, self.hudelem_y );
hudelem_status.label = &"SO_DOWNLOAD_ARCADIA_DOWNLOAD_COMPLETE"; // DOWNLOAD COMPLETE
hudelem_status.fontScale = 1.4;
hudelem_status set_hud_blue();
hudelem thread hud_blink();
hudelem_status thread hud_blink();
wait( 10 );
hudelem Destroy();
hudelem_status Destroy();
}
hud_blink( maxFontScale )
{
self endon( "death" );
fadeTime = 0.1;
stateTime = 0.5;
while( 1 )
{
self FadeOverTime( fadeTime );
self.alpha = 1;
wait( stateTime );
self FadeOverTime( fadeTime );
self.alpha = 0;
wait( stateTime );
}
}
download_files_enemies_attack( downloadTime )
{
self.spawned = [];
self.totalDefenders = 0;
self.totalDefenders = self download_files_nearby_defenders_charge();
self.totalDefenders += self download_files_spawn_chargers();
self thread download_enemies_attack_dialogue();
while( self.spawned.size < self.totalDefenders )
{
wait( 0.05 );
}
waittill_dead_or_dying( self.spawned, ( self.spawned.size - level.NUM_ENEMIES_LEFT_TOLERANCE ), downloadTime );
self.waveDead = true;
}
download_enemies_attack_dialogue()
{
alias = undefined;
waitTime = undefined;
alias2 = undefined;
switch( self.script_parameters )
{
case "download_1_charger":
// "Hunter Two-One, ten-plus foot-mobiles approaching from the east!"
alias = "so_dwnld_stk_tenfootmobiles";
break;
case "download_2_charger":
// "We've got activity to the west, they're coming from the light brown mansion!"
alias = "so_dwnld_stk_brownmansion";
break;
case "download_3_charger":
// "Hostiles spotted across the street, they're moving to your position!"
alias = "so_dwnld_stk_acrossstreet";
waitTime = 10;
// "Hunter Two-One, you got movement right outside your location!"
alias2 = "so_dwnld_stk_gotmovement";
break;
}
if( IsDefined( alias ) )
{
so_radio_dialogue( alias );
}
if( IsDefined( waitTime ) )
{
wait( waitTime );
}
if( IsDefined( alias2 ) )
{
so_radio_dialogue( alias2 );
}
}
download_files_nearby_defenders_charge()
{
axis = GetAiArray( "axis" );
close = [];
foreach( guy in axis )
{
if( Distance( guy.origin, self.origin ) <= level.NEARBY_CHARGE_RADIUS )
{
close[ close.size ] = guy;
self.spawned[ self.spawned.size ] = guy;
}
}
array_thread( close, ::defender_charge_dsm, self );
return close.size;
}
download_files_spawn_chargers()
{
chargers = GetEntArray( self.script_parameters, "targetname" );
chargers = array_randomize( chargers );
array_thread( chargers, ::download_files_spawn_charger, self );
return chargers.size;
}
download_files_spawn_charger( download )
{
self script_delay();
wait( RandomFloat( 8 ) ); // we don't want all of a group of guys rolling exactly together
guy = self spawn_ai();
if( spawn_failed( guy ) )
{
download.totalDefenders--; // don't count him toward wave completion if he couldn't spawn
return;
}
download.spawned[ download.spawned.size ] = guy;
guy thread defender_charge_dsm( download );
}
defender_charge_dsm( download )
{
goal_ent = GetEnt( download.script_linkto, "script_linkname" );
self.goalradius = 1800;
self SetGoalEntity( goal_ent );
self thread ai_delayed_seek_think( download, goal_ent );
}
ai_delayed_seek_think( download, goal_ent )
{
self endon( "death" );
// player1_max_seekers = 0;
// player2_max_seekers = 0;
//
// foreach ( player in level.players )
// {
// num = 3;
// switch ( player.gameskill )
// {
// case 0:
// case 1:
// num = 3;
// break;
// case 2:
// case 3:
// num = 5;
// break;
// }
//
// if ( player == level.player )
// {
// player1_max_seekers = num;
// }
// else
// {
// player2_max_seekers = num;
// }
// }
player1_max_seekers = 3;
player2_max_seekers = 3;
// secondaries = GetEntArray( primary.target, "targetname" );
while ( IsAlive( self ) )
{
if ( self.goalradius > 200 )
{
self.goalradius -= 200;
}
if ( self.goalradius < 200 )
{
self.goalradius = 200;
}
count = 0;
player1_seek_count = 0;
player2_seek_count = 0;
ais = GetAiArray( "axis" );
foreach ( ai in ais )
{
if ( IsDefined( ai.seeking_player ) )
{
if ( ai.seeking_player == level.player )
{
player1_seek_count++;
}
else if( IsDefined( level.player2 ) && ai.seeking_player == level.player2 )
{
player2_seek_count++;
}
}
if ( ai == self )
{
continue;
}
if ( DistanceSquared( ai.origin, goal_ent.origin ) < 250 * 250 )
{
count++;
}
}
if ( count > 2 || download.download_complete )
{
if ( !IsDefined( self.seeking_player ) )
{
array = level.players;
array = array_randomize( array );
goal_player = undefined;
foreach ( player in array )
{
if ( player == level.player && player1_seek_count < player1_max_seekers )
{
goal_player = level.player;
break;
}
else if ( IsDefined( level.player2 ) && player == level.player2 && player2_seek_count < player2_max_seekers )
{
goal_player = level.player2;
break;
}
}
if ( IsDefined( goal_player ) )
{
self.seeking_player = goal_player;
// Let's seek out the player
self SetGoalEntity( goal_player );
self.goalradius = 1000;
}
}
// The AI still does not have a proper goal, then increase their goalradius
if ( !IsDefined( self.seek_player ) )
{
self.goalradius = 1000;
}
}
wait( RandomFloatRange( 6, 9 ) );
}
}
download_files_catch_interrupt()
{
self endon( "downloading_stopped" );
while( 1 )
{
axis = GetAiArray( "axis" );
foreach( guy in axis )
{
if( self ai_near_download( guy ) )
{
self notify( "download_interrupted" );
break;
}
}
wait( 2 );
}
}
ai_near_download( guy )
{
verticalDist = abs( guy GetTagOrigin( "J_SpineLower" )[ 2 ] - self.origin[ 2 ] );
if( verticalDist > 50 )
{
return false;
}
if( Distance( guy.origin, self.origin ) < level.DOWNLOAD_INTERRUPT_RADIUS )
{
return true;
}
return false;
}
// ----------------
// --- STRYKER ---
// ----------------
stryker_think()
{
stryker = maps\_vehicle::spawn_vehicle_from_targetname( "stryker" );
ASSERT( IsDefined( stryker ) );
level.stryker = stryker;
// hack so we don't get sound asserts
org = Spawn( "script_origin", stryker.origin );
org LinkTo( stryker );
org.animname = "foley";
level.foley = org;
CreateThreatBiasGroup( "stryker" );
CreateThreatBiasGroup( "stryker_ignoreme" );
stryker.threatBiasGroup = "stryker";
SetIgnoreMeGroup( "stryker_ignoreme", "stryker" );
stryker.target = "stryker_pathstart";
pathStart = GetVehicleNode( stryker.target, "targetname" );
stryker AttachPath( pathStart );
stryker.veh_pathtype = "follow";
stryker vehPhys_DisableCrashing();
stryker maps\_vehicle::godon();
stryker setVehicleLookAtText( "Honey Badger", &"" );
foreach( player in level.players )
{
// Workaround for setting the C4 actionslot, setting player.remotemissile_actionslot swaps the actionslot
player.remotemissile_actionslot = 4;
level thread maps\arcadia_code::laser_targeting_device( player );
}
level.stryker.lastTarget = level.stryker;
stryker maps\arcadia_stryker::setup_stryker_modes();
stryker thread maps\arcadia_stryker::stryker_setmode_ai();
stryker thread stryker_so_download_arcadia_laser_reminder_dialogue();
stryker thread stryker_greenlight_enemies_in_suppression_zone();
stryker thread stryker_disable_laser_reminder_thread();
// first move: go to the end of the covered bridge when player moves out of the way
waittill_both_players_touch_targetname( "trig_bridge_end" );
stryker StartPath();
firstMoveNode = GetVehicleNode( "vnode_bridge", "script_noteworthy" );
stryker stryker_move_to_node( firstMoveNode, false );
stryker thread stryker_move_with_players();
stryker thread stryker_extraction();
}
stryker_so_download_arcadia_laser_reminder_dialogue()
{
foreach ( player in level.players )
{
player thread so_laser_input();
}
flag_wait( "intro_dialogue_done" );
self thread stryker_laser_reminder_dialog_prethink();
// "All Hunter units, Badger One will not engage targets without your explicit authorization."
so_radio_dialogue( "so_dwnld_stk_explicitauth" );
self thread so_laser_hint_print();
// self thread maps\arcadia_code::laser_hint_print();
self thread maps\arcadia_code::stryker_dialog();
if( flag( "used_laser" ) )
{
return;
}
level endon( "used_laser" );
self endon( "laser_coordinates_received" );
wait( 45 );
while ( flag( "no_living_enemies" ) )
{
wait( 5 );
}
// "Hunter Two-One, I repeat, Badger One is not authorized to engage targets that you haven't designated."
so_radio_dialogue( "so_dwnld_stk_designated" );
wait( 45 );
while ( flag( "no_living_enemies" ) )
{
wait( 5 );
}
// "Hunter Two-One, we can't fire on enemies without your authorization!"
so_radio_dialogue( "so_dwnld_stk_cantfire" );
}
so_laser_hint_print()
{
foreach ( player in level.players )
{
if ( !IsAlive( player ) )
{
continue;
}
player thread so_laser_hint_print_internal();
}
}
so_laser_input()
{
self NotifyOnPlayerCommand( "use_laser", "+actionslot 4" );
self NotifyOnPlayerCommand( "fired_laser", "+attack" );
if ( flag( "used_laser" ) )
{
self ent_flag_set( "used_laser1" );
self ent_flag_set( "used_laser2" );
}
self waittill_either( "use_laser", "used_laser" );
self ent_flag_set( "used_laser1" );
if ( flag( "used_laser" ) )
{
self ent_flag_set( "used_laser1" );
self ent_flag_set( "used_laser2" );
}
self waittill_either( "fired_laser", "used_laser" );
self ent_flag_set( "used_laser2" );
}
so_laser_hint_print_internal()
{
self thread display_hint( "use_laser1" );
self ent_flag_wait( "used_laser1" );
wait( 0.1 );
self thread display_hint( "use_laser2" );
}
so_stop_laser_hint1()
{
if ( flag( "used_laser" ) )
{
return true;
}
if ( self ent_flag( "used_laser1" ) )
{
return true;
}
return false;
}
so_stop_laser_hint2()
{
if ( flag( "used_laser" ) )
{
return true;
}
if ( self ent_flag( "used_laser2" ) )
{
return true;
}
return false;
}
stryker_laser_reminder_dialog_prethink()
{
self waittill( "laser_coordinates_received" );
wait( 30 );
self thread maps\arcadia_stryker::stryker_laser_reminder_dialog();
}
stryker_greenlight_enemies_in_suppression_zone()
{
while( 1 )
{
if( !IsDefined( self.targetSearchOrigin ) )
{
wait( 0.1 );
continue;
}
axis = GetAiArray( "axis" );
foreach( guy in axis )
{
if( !IsAlive( guy ) )
{
continue;
}
if( DistanceSquared( guy.origin, self.targetSearchOrigin ) <= STRYKER_SUPPRESSION_RADIUS )
{
// he's in the suppression area
if( guy GetThreatBiasGroup() == "stryker_ignoreme" )
{
guy SetThreatBiasGroup( "axis" );
self thread stryker_enemy_reset_to_ignore( guy );
}
}
}
wait( 0.25 );
}
}
stryker_disable_laser_reminder_thread()
{
while ( 1 )
{
wait( 0.5 );
count = 0;
enemies = GetAiArray( "axis" );
count = enemies.size;
if ( !count )
{
flag_set( "no_living_enemies" );
}
else
{
flag_clear( "no_living_enemies" );
}
}
}
stryker_enemy_reset_to_ignore( guy )
{
guy endon( "death" );
while( IsDefined( self.targetSearchOrigin ) )
{
wait( 0.1 );
}
if( IsAlive( guy ) )
{
guy SetThreatBiasGroup( "stryker_ignoreme" );
}
}
stryker_move_with_players()
{
level endon( "all_downloads_finished" );
trig1 = GetEnt( "trig_stryker_house1", "targetname" );
node1 = GetVehicleNode( "vnode_house1", "script_noteworthy" );
trig2 = GetEnt( "trig_stryker_house2", "targetname" );
node2 = GetVehicleNode( "vnode_house2", "script_noteworthy" );
trig3 = GetEnt( "trig_stryker_house3", "targetname" );
node3 = GetVehicleNode( "vnode_house3", "script_noteworthy" );
trigs[ 0 ] = trig1;
trigs[ 1 ] = trig2;
trigs[ 2 ] = trig3;
nodes[ 0 ] = node1;
nodes[ 1 ] = node2;
nodes[ 2 ] = node3;
timeInTrig = 5;
currNode = undefined;
while( 1 )
{
activeTrigIndex = undefined;
foreach( index, trig in trigs )
{
if( all_players_istouching( trig ) )
{
endTime = GetTime() + milliseconds( timeInTrig );
while( GetTime() < endTime )
{
if( !all_players_istouching( trig ) )
{
break;
}
wait( 0.1 );
}
if( GetTime() >= endTime )
{
// success
activeTrigIndex = index;
break;
}
}
}
if( IsDefined( activeTrigIndex ) )
{
thenode = nodes[ activeTrigIndex ];
if( !IsDefined( currNode ) || ( IsDefined( currNode ) && currNode != thenode ) )
{
currNode = thenode;
self stryker_move_to_node( thenode );
}
}
wait( 0.5 );
}
}
stryker_move_to_node( node, doDialogue )
{
goalradius = 96;
// move forward or backward?
if( node.origin[ 0 ] < self.origin[ 0 ] )
{
self.veh_pathdir = "reverse";
self.veh_transmission = "reverse";
self maps\_vehicle::vehicle_wheels_backward();
}
else
{
self.veh_pathdir = "forward";
self.veh_transmission = "forward";
self maps\_vehicle::vehicle_wheels_forward();
}
if( !IsDefined( doDialogue ) || ( IsDefined( doDialogue ) && doDialogue ) )
{
self notify( "resuming speed" );
}
self maps\_vehicle::vehicle_setspeed_wrapper( 10, 5, "stryker_rolling" );
//waittill at node
while( Distance( self.origin, node.origin ) > goalradius )
{
wait( 0.05 );
}
self maps\_vehicle::vehicle_setspeed_wrapper( 0, 5, "stryker_stopping" );
if( !IsDefined( doDialogue ) || ( IsDefined( doDialogue ) && doDialogue ) )
{
self notify( "wait for gate" );
}
}
stryker_extraction()
{
flag_wait( "all_downloads_finished" );
//array_thread( level.players, ::laser_targeting_device_remove );
// level.stryker thread maps\arcadia_stryker::stryker_setmode_ai();
node = GetVehicleNode( "vnode_house1", "script_noteworthy" );
level.stryker thread stryker_move_to_node( node );
strykerObjIdx = level.downloadObjectiveIdx + 1;
Objective_Add( strykerObjIdx, "current", &"SO_DOWNLOAD_ARCADIA_OBJ_EXTRACT", self.origin );
Objective_OnEntity( strykerObjIdx, self );
thread stryker_extraction_enemies();
while( !all_players_closeto( self, 280 ) )
{
wait( 0.05 );
}
flag_set( "stryker_extraction_done" );
// Stop the Stryker dialogue
level notify( "golf_course_mansion" );
fade_challenge_out();
}
stryker_extraction_enemies()
{
org = level.players[ 0 ].origin;
// get the average origin if there's more than one player
if( level.players.size > 1 )
{
for( i = 1; i < level.players.size; i++ )
{
org += level.players[ i ].origin;
}
org /= level.players.size;
}
spawners = GetSpawnerTeamArray( "axis" );
spawners = get_array_of_farthest( org, spawners );
arr = [];
foreach( index, spawner in spawners )
{
if( index > 15 )
{
break;
}
spawner.count = 3;
arr[ arr.size ] = spawner;
}
array_thread( spawners, ::stryker_extraction_spawn_enemy );
}
stryker_extraction_spawn_enemy()
{
wait( RandomFloat( 10 ) );
guy = self spawn_ai();
if( spawn_failed( guy ) )
{
return;
}
guy endon( "death" );
guy SetThreatBiasGroup( "axis" );
guy SetGoalPos( level.stryker.origin );
}
// ------------------------
// --- LASER TARGETING ---
// ------------------------
// Handles the usability of the laser weapon
player_laser_targeting_think()
{
is_laser_disabled = false;
while ( 1 )
{
disable_laser = should_laser_disabled();
if ( disable_laser )
{
if ( !is_laser_disabled )
{
is_laser_disabled = true;
self laser_targeting_device_remove();
}
}
else
{
if ( is_laser_disabled )
{
is_laser_disabled = false;
level thread maps\arcadia_code::laser_targeting_device( self );
}
}
wait( 0.05 );
}
}
should_laser_disabled()
{
// if ( self GetCurrentWeapon() == "claymore" )
// {
// return true;
// }
if ( !self ent_flag_exist( "coop_downed" ) )
{
return false;
}
// Disable the player if downed part2.
return self ent_flag( "coop_downed" ) && IsDefined( self.down_part2_proc_ran );
}
// self = a player
laser_targeting_device_remove()
{
self notify( "remove_laser_targeting_device" );
self SetWeaponHudIconOverride( "actionslot4", "none" );
if ( !self.laserForceOn )
{
return;
}
self notify( "cancel_laser" );
self laserForceOff();
self allowFire( true );
self.laserForceOn = false;
}
// -----------------
// --- AI STUFF ---
// -----------------
so_download_arcadia_enemy_setup()
{
level.enemies = [];
allspawners = GetSpawnerTeamArray( "axis" );
array_thread( allspawners, ::add_spawn_function, ::so_download_arcadia_enemy_spawnfunc );
insideGuys = [];
outsideGuys = [];
foreach( spawner in allspawners )
{
if( !IsDefined( spawner.targetname ) )
{
continue;
}
if( IsSubStr( spawner.targetname, "inside" ) )
{
insideGuys[ insideGuys.size ] = spawner;
}
else if( IsSubStr( spawner.targetname, "outside" ) )
{
outsideGuys[ outsideGuys.size ] = spawner;
}
}
array_thread( outsideGuys, ::add_spawn_function, ::so_download_arcadia_outside_enemy_spawnfunc );
level.enemyspawners = allspawners;
// DEPRECATED
//trigs = GetEntArray( "enemy_spawn", "targetname" );
//array_thread( trigs, ::so_download_arcadia_enemy_spawn_manager );
}
so_download_arcadia_enemy_spawnfunc()
{
if( RandomInt( 100 ) > 10 )
{
self SetThreatBiasGroup( "stryker_ignoreme" );
}
self pathrandompercent_set( 800 );
level.activeEnemies[ level.enemies.size ] = self;
self thread so_download_arcadia_enemy_deathcleanup();
}
so_download_arcadia_enemy_deathcleanup()
{
self waittill( "death" );
level.activeEnemies = array_remove( level.enemies, self );
}
so_download_arcadia_outside_enemy_spawnfunc()
{
self endon( "death" );
if( IsDefined( self.script_linkto ) && IsDefined( self.script_parameters ) )
{
retreatTrig = GetEnt( self.script_linkto, "script_linkname" );
retreatVol = GetEnt( self.script_parameters, "targetname" );
ASSERT( IsDefined( retreatTrig ) && IsDefined( retreatVol ) );
retreatTrig waittill( "trigger" );
self.combatMode = "ambush";
self SetGoalVolumeAuto( retreatVol );
}
}
// -------------------
// --- MISC UTILS ---
// -------------------
all_players_closeto( ent, dist )
{
foundOne = false;
foreach( player in level.players )
{
if( Distance( player.origin, ent.origin ) > dist)
{
foundOne = true;
break;
}
}
if( foundOne )
{
return false;
}
return true;
}
waittill_both_players_touch_targetname( tn )
{
trig = GetEnt( tn, "targetname" );
touchers = [];
while( touchers.size < level.players.size )
{
trig waittill( "trigger", other );
if( IsPlayer( other ) && !is_in_array( touchers, other ) )
{
touchers[ touchers.size ] = other;
}
}
}
// TODO refactor to use the _utility version
// kinda rough method to test if an AI is in view of the player - only checks three points (low, mid, high)
any_player_can_see_ai( ai )
{
feetOrigin = ai.origin;
if ( any_player_can_see_origin( feetOrigin ) )
return true;
midOrigin = ai GetTagOrigin( "J_SpineLower" );
if ( any_player_can_see_origin( midOrigin ) )
return true;
eyeOrigin = ai GetEye();
if ( any_player_can_see_origin( eyeOrigin ) )
return true;
return false;
}
any_player_can_see_origin( origin )
{
foreach( player in level.players )
{
player.canSeeOrigin = true;
// FOV check
if( !level.player animscripts\battlechatter::pointInFov( origin ) )
{
player.canSeeOrigin = false;
}
// sight trace check
if( !SightTracePassed( player GetEye(), origin, true, player ) )
{
player.canSeeOrigin = false;
}
}
foreach( player in level.players )
{
if( player.canSeeOrigin )
{
return true;
}
}
return false;
}
milliseconds( seconds )
{
return seconds * 1000;
}
seconds( milliseconds )
{
return milliseconds / 1000;
}