2791 lines
81 KiB
Text
2791 lines
81 KiB
Text
#include maps\_utility;
|
|
#include common_scripts\utility;
|
|
#include maps\_anim;
|
|
#include maps\_hud_util;
|
|
precacheLevelStuff()
|
|
{
|
|
precacheString( &"VILLAGE_ASSAULT_OBJECTIVE_LOCATE_ALASAD" );
|
|
precacheString( &"SCRIPT_ARMOR_DAMAGE" );
|
|
precacheString( &"SCRIPT_LEARN_CHOPPER_AIR_SUPPORT1" );
|
|
precacheString( &"SCRIPT_LEARN_CHOPPER_AIR_SUPPORT1_PC" );
|
|
precacheShader( "black" );
|
|
precacheShader( "hud_icon_cobra" );
|
|
precacheShader( "popmenu_bg" );
|
|
precacheShader( "hud_dpad" );
|
|
precacheShader( "hud_arrow_right" );
|
|
precacheModel( "sundirection_arrow" );
|
|
precacheModel( "com_folding_chair" );
|
|
precacheModel( "com_flashlight_off" );
|
|
precacheModel( "com_flashlight_on" );
|
|
precacheItem( "mi28_ffar_village_assault" );
|
|
precacheItem( "flash_grenade" );
|
|
precacheItem( "colt45_alasad_killer" );
|
|
|
|
flag_init( "gave_air_support_hint" );
|
|
flag_init( "alasad_sequence_started" );
|
|
flag_init( "air_support_refueling" );
|
|
flag_init( "delete_attack_coord_hint" );
|
|
|
|
level.weaponClipModels = [];
|
|
level.weaponClipModels[0] = "weapon_ak47_clip";
|
|
level.weaponClipModels[1] = "weapon_mp5_clip";
|
|
level.weaponClipModels[2] = "weapon_m16_clip";
|
|
level.weaponClipModels[3] = "weapon_g36_clip";
|
|
level.weaponClipModels[4] = "weapon_dragunov_clip";
|
|
level.weaponClipModels[5] = "weapon_g3_clip";
|
|
}
|
|
|
|
setLevelDVars()
|
|
{
|
|
setSavedDvar( "r_specularColorScale", "1.8" );
|
|
|
|
if ( getdvar( "village_assault_debug_marker") == "" )
|
|
setdvar( "village_assault_debug_marker", "0" );
|
|
|
|
level.seekersUsingColors = false;
|
|
level.BMP_Safety_Distance = 512 * 512;
|
|
level.goodFriendlyDistanceFromPlayerSquared = 512 * 512;
|
|
level.chopperSupportCallNextAudio = 0;
|
|
level.buildingClearNextAudio = 0;
|
|
level.air_support_hint_print_dialog_next = 0;
|
|
level.chopperSupportHoverLocations = [];
|
|
hoverEnts = getentarray( "chopper_location", "targetname" );
|
|
for( i = 0 ; i < hoverEnts.size ; i++ )
|
|
{
|
|
level.chopperSupportHoverLocations[ level.chopperSupportHoverLocations.size ] = hoverEnts[ i ].origin;
|
|
hoverEnts[ i ] delete();
|
|
}
|
|
assert( level.chopperSupportHoverLocations.size > 0 );
|
|
level.cosine[ "25" ] = cos( 25 );
|
|
level.cosine[ "45" ] = cos( 45 );
|
|
level.cosine[ "55" ] = cos( 55 );
|
|
level.cosine[ "60" ] = cos( 60 );
|
|
level.cosine[ "70" ] = cos( 70 );
|
|
|
|
level.alasad_possible_objective_locations = [];
|
|
level.alasad_possible_objective_locations_remaining[ 0 ] = "2";
|
|
level.alasad_possible_objective_locations_remaining[ 1 ] = "6";
|
|
|
|
level.next_genocide_audio = 0;
|
|
level.genocide_audio[ 0 ] = "assault_killing_distance1";
|
|
level.genocide_audio[ 1 ] = "assault_killing_interior1";
|
|
level.genocide_audio[ 2 ] = "assault_killing_interior2";
|
|
level.genocide_audio[ 3 ] = "assault_killing_interior3";
|
|
|
|
level.timedAutosaveNumber = 0;
|
|
level.timedAutosaveTime = undefined;
|
|
skill = getdifficulty();
|
|
switch( skill )
|
|
{
|
|
case "gimp":
|
|
case "easy":
|
|
level.timedAutosaveTime = 60;
|
|
array_thread( getentarray( "bmp_spawn_trigger", "script_noteworthy" ), ::trigger_off );
|
|
break;
|
|
case "medium":
|
|
level.timedAutosaveTime = 120;
|
|
break;
|
|
case "hard":
|
|
case "difficult":
|
|
level.timedAutosaveTime = 180;
|
|
break;
|
|
case "fu":
|
|
level.timedAutosaveTime = 0;
|
|
break;
|
|
}
|
|
assert( isdefined( level.timedAutosaveTime ) );
|
|
}
|
|
|
|
scriptCalls()
|
|
{
|
|
maps\village_assault_anim::main();
|
|
level thread maps\village_assault_amb::main();
|
|
maps\_compass::setupMiniMap("compass_map_village_assault");
|
|
|
|
array_thread( getentarray( "seek_player", "script_noteworthy" ), ::add_spawn_function, ::seek_player );
|
|
array_thread( getentarray( "indoor_enemy", "script_noteworthy" ), ::add_spawn_function, ::indoor_enemy );
|
|
array_thread( getentarray( "seek_player_smart", "script_noteworthy" ), ::add_spawn_function, ::seek_player_smart );
|
|
array_thread( getentarray( "dog", "script_noteworthy" ), ::add_spawn_function, ::seek_player_dog );
|
|
array_thread( getentarray( "enemy_color_hint_trigger", "targetname" ), ::enemy_color_hint_trigger_think );
|
|
array_thread( getentarray( "genocide_audio_trigger", "targetname" ), ::genocide_audio_trigger );
|
|
array_thread( getentarray( "dead_civilian", "targetname" ), ::dead_civilian );
|
|
array_thread( getentarray( "trigger_upstairs_guys", "targetname" ), ::trigger_upstairs_guys );
|
|
array_thread( getentarray( "alasad_barn_deletable", "script_noteworthy" ), ::alasad_deletable_hide );
|
|
array_thread( getentarray( "alasad_house_deletable", "script_noteworthy" ), ::alasad_deletable_hide );
|
|
|
|
add_hint_string( "call_air_support2", &"SCRIPT_PLATFORM_LEARN_CHOPPER_AIR_SUPPORT2", ::should_delete_attack_coord_hint );
|
|
|
|
thread chopper_air_support();
|
|
thread vehicle_patrol_init();
|
|
thread roaming_bmp();
|
|
thread timedAutosaves();
|
|
|
|
if ( getdvar( "village_assault_disable_gameplay") == "1" )
|
|
thread disable_gameplay();
|
|
|
|
wait 6.5;
|
|
|
|
objective_add( 0, "current", &"VILLAGE_ASSAULT_OBJECTIVE_LOCATE_ALASAD", ( 0, 0, 0 ) );
|
|
}
|
|
|
|
disable_gameplay()
|
|
{
|
|
array_thread( getentarray( "trigger_multiple", "classname" ), ::disable_gameplay_trigger );
|
|
array_thread( getentarray( "trigger_radius", "classname" ), ::disable_gameplay_trigger );
|
|
}
|
|
|
|
movePlayerToLocation( sTargetname )
|
|
{
|
|
assert( isdefined( sTargetname ) );
|
|
start = getent( sTargetname, "targetname" );
|
|
assert( isdefined( start ) );
|
|
assert( isdefined( level.player ) );
|
|
level.player setOrigin( start.origin );
|
|
level.player setPlayerAngles( ( 0, start.angles[ 1 ], 0 ) );
|
|
}
|
|
|
|
disable_gameplay_trigger()
|
|
{
|
|
gameplayTrigger = false;
|
|
|
|
if ( self.spawnflags & 32 )
|
|
gameplayTrigger = true;
|
|
|
|
if ( isdefined( self.targetname ) )
|
|
{
|
|
if ( self.targetname == "flood_and_secure" )
|
|
gameplayTrigger = true;
|
|
else if ( self.targetname == "flood_spawner" )
|
|
gameplayTrigger = true;
|
|
}
|
|
|
|
if ( gameplayTrigger )
|
|
self thread trigger_off();
|
|
}
|
|
|
|
spawn_starting_friendlies( sTargetname )
|
|
{
|
|
level.friendlies = [];
|
|
spawners = getentarray( sTargetname, "targetname" );
|
|
for( i = 0 ; i < spawners.size ; i++ )
|
|
{
|
|
friend = spawners[ i ] stalingradSpawn();
|
|
if ( spawn_failed( friend ) )
|
|
assertMsg( "A friendly failed to spawn" );
|
|
|
|
friend.goalradius = 32;
|
|
friend.fixednode = false;
|
|
|
|
if ( issubstr( friend.classname, "price" ) )
|
|
{
|
|
level.price = friend;
|
|
}
|
|
else if ( issubstr( friend.classname, "gaz" ) )
|
|
{
|
|
level.gaz = friend;
|
|
}
|
|
else if ( issubstr( friend.classname, "russian" ) )
|
|
{
|
|
level.opening_guy = friend;
|
|
level.opening_guy.animname = "opening_guy";
|
|
}
|
|
|
|
if ( friend isHero() )
|
|
friend thread magic_bullet_shield( undefined, 5.0 );
|
|
|
|
level.friendlies[ level.friendlies.size ] = friend;
|
|
|
|
friend thread friendly_adjust_movement_speed();
|
|
friend thread friendly_bmp_damage_ignore_timer();
|
|
}
|
|
|
|
assert( isdefined( level.price ) );
|
|
level.price.animname = "price";
|
|
level.price make_hero();
|
|
|
|
assert( isdefined( level.gaz ) );
|
|
level.gaz.animname = "gaz";
|
|
level.gaz make_hero();
|
|
|
|
//array_thread( getaiarray( "allies" ), ::replace_on_death );
|
|
assert( level.friendlies.size == spawners.size );
|
|
}
|
|
|
|
friendly_bmp_damage_ignore_timer()
|
|
{
|
|
self endon( "death" );
|
|
|
|
for(;;)
|
|
{
|
|
self waittill( "damage", amount, attacker );
|
|
if ( !isdefined( attacker ) )
|
|
continue;
|
|
if ( !isdefined( attacker.classname ) )
|
|
continue;
|
|
if ( attacker.classname != "script_vehicle" )
|
|
continue;
|
|
self.ignored_by_tank_cannon = true;
|
|
wait randomfloatrange( 4.0, 6.0 );
|
|
self.ignored_by_tank_cannon = undefined;
|
|
}
|
|
}
|
|
|
|
friendly_adjust_movement_speed()
|
|
{
|
|
self endon( "death" );
|
|
|
|
for(;;)
|
|
{
|
|
wait randomfloatrange( 1.0, 3.0 );
|
|
|
|
while( friendly_should_speed_up() )
|
|
{
|
|
self.moveplaybackrate = 2.0;
|
|
wait 0.05;
|
|
}
|
|
|
|
self.moveplaybackrate = 1.0;
|
|
}
|
|
}
|
|
|
|
friendly_should_speed_up()
|
|
{
|
|
prof_begin( "friendly_movement_rate_math" );
|
|
|
|
if ( !isdefined( self.goalpos ) )
|
|
{
|
|
prof_end( "friendly_movement_rate_math" );
|
|
return false;
|
|
}
|
|
|
|
if ( distanceSquared( self.origin, self.goalpos ) <= level.goodFriendlyDistanceFromPlayerSquared )
|
|
{
|
|
prof_end( "friendly_movement_rate_math" );
|
|
return false;
|
|
}
|
|
|
|
// check if AI is visible in player's FOV
|
|
if ( within_fov( level.player.origin, level.player getPlayerAngles(), self.origin, level.cosine[ "60" ] ) )
|
|
{
|
|
prof_end( "friendly_movement_rate_math" );
|
|
return false;
|
|
}
|
|
|
|
prof_end( "friendly_movement_rate_math" );
|
|
|
|
return true;
|
|
}
|
|
|
|
isHero()
|
|
{
|
|
if ( !isdefined( self ) )
|
|
return false;
|
|
|
|
if ( !isdefined( self.script_noteworthy ) )
|
|
return false;
|
|
|
|
if ( self.script_noteworthy == "hero" )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
friendly_sight_distance( fDistance )
|
|
{
|
|
dist = fDistance * fDistance;
|
|
for( i = 0 ; i < level.friendlies.size ; i++ )
|
|
level.friendlies[ i ].maxsightdistsqrd = dist;
|
|
}
|
|
|
|
friendly_movement_speed( speed )
|
|
{
|
|
for( i = 0 ; i < level.friendlies.size ; i++ )
|
|
level.friendlies[ i ].moveplaybackrate = speed;
|
|
}
|
|
|
|
friendly_stance( stance1, stance2, stance3 )
|
|
{
|
|
for( i = 0 ; i < level.friendlies.size ; i++ )
|
|
{
|
|
if ( isdefined ( stance3 ) )
|
|
level.friendlies[ i ] allowedStances( stance1, stance2, stance3 );
|
|
else
|
|
if ( isdefined ( stance2 ) )
|
|
level.friendlies[ i ] allowedStances( stance1, stance2 );
|
|
else
|
|
level.friendlies[ i ] allowedStances( stance1 );
|
|
}
|
|
}
|
|
|
|
distracted_guys_spawn()
|
|
{
|
|
script_org = getent( self.target, "targetname" );
|
|
assert( isdefined( script_org ) );
|
|
assert( script_org.classname == "script_origin" );
|
|
distractedGuyStruct = spawnStruct();
|
|
|
|
targeted = getentarray( script_org.target, "targetname" );
|
|
distractedGuyStruct.alert_triggers = [];
|
|
distractedGuyStruct.spawners = [];
|
|
for( i = 0 ; i < targeted.size ; i++ )
|
|
{
|
|
if ( issubstr( targeted[ i ].classname, "trigger" ) )
|
|
{
|
|
assert( isdefined( targeted[ i ].script_noteworthy ) );
|
|
distractedGuyStruct.alert_triggers[ distractedGuyStruct.alert_triggers.size ] = targeted[ i ];
|
|
}
|
|
else if ( targeted[ i ] isSpawner() )
|
|
{
|
|
assert( isdefined( targeted[ i ].script_animation ) );
|
|
distractedGuyStruct.spawners[ distractedGuyStruct.spawners.size ] = targeted[ i ];
|
|
}
|
|
}
|
|
assert( distractedGuyStruct.alert_triggers.size > 0 );
|
|
assert( distractedGuyStruct.spawners.size > 0 );
|
|
|
|
distractedGuyStruct.nodes = [];
|
|
for( i = 0 ; i < distractedGuyStruct.spawners.size ; i++ )
|
|
{
|
|
assert( isdefined( distractedGuyStruct.spawners[ i ].target ) );
|
|
node = getnode( distractedGuyStruct.spawners[ i ].target, "targetname" );
|
|
assert( isdefined( node ) );
|
|
distractedGuyStruct.nodes[ distractedGuyStruct.nodes.size ] = node;
|
|
}
|
|
|
|
assert( distractedGuyStruct.nodes.size > 0 );
|
|
assert( distractedGuyStruct.nodes.size == distractedGuyStruct.spawners.size );
|
|
|
|
self waittill( "trigger" );
|
|
|
|
// spawn the guys
|
|
distractedGuyStruct.guys = [];
|
|
for( i = 0 ; i < distractedGuyStruct.spawners.size ; i++ )
|
|
{
|
|
spawned = distractedGuyStruct.spawners[ i ] stalingradSpawn();
|
|
if ( spawn_failed( spawned ) )
|
|
{
|
|
assertMsg( "distracted guy failed to spawn" );
|
|
return;
|
|
}
|
|
distractedGuyStruct.guys[ distractedGuyStruct.guys.size ] = spawned;
|
|
}
|
|
assert( distractedGuyStruct.guys.size > 0 );
|
|
|
|
thread distractedGuys_animate( distractedGuyStruct );
|
|
}
|
|
|
|
distractedGuys_animate( distractedGuyStruct )
|
|
{
|
|
for( i = 0 ; i < distractedGuyStruct.alert_triggers.size ; i++ )
|
|
distractedGuyStruct.alert_triggers[ i ] thread distractedGuys_alert_trigger( distractedGuyStruct );
|
|
|
|
for( i = 0 ; i < distractedGuyStruct.guys.size ; i++ )
|
|
{
|
|
distractedGuyStruct.guys[ i ].distracted = true;
|
|
//distractedGuyStruct.guys[ i ].ignoreme = true;
|
|
distractedGuyStruct.guys[ i ] thread alert_event_notify( distractedGuyStruct );
|
|
distractedGuyStruct.guys[ i ].animname = distractedGuyStruct.guys[ i ].script_animation;
|
|
distractedGuyStruct.nodes[ i ] thread anim_loop_solo( distractedGuyStruct.guys[ i ], "idle", undefined, "stop_idle" );
|
|
distractedGuyStruct.guys[ i ].allowdeath = true;
|
|
if ( isdefined( level.scr_anim[ distractedGuyStruct.guys[ i ].animname ][ "death" ] ) )
|
|
distractedGuyStruct.guys[ i ].deathanim = level.scr_anim[ distractedGuyStruct.guys[ i ].animname ][ "death" ];
|
|
}
|
|
|
|
thread distractedGuys_alert( distractedGuyStruct );
|
|
}
|
|
|
|
distractedGuys_alert_trigger( distractedGuyStruct )
|
|
{
|
|
self waittill( self.script_noteworthy );
|
|
distractedGuyStruct notify( "alerted" );
|
|
}
|
|
|
|
distractedGuys_alert( distractedGuyStruct )
|
|
{
|
|
switch( distractedGuyStruct.guys.size )
|
|
{
|
|
case 1:
|
|
level waittill_any_ents( distractedGuyStruct, "alerted",
|
|
distractedGuyStruct.guys[ 0 ] , "alerted",
|
|
distractedGuyStruct.guys[ 0 ], "death",
|
|
distractedGuyStruct.guys[ 0 ], "damage" );
|
|
break;
|
|
case 2:
|
|
level waittill_any_ents( distractedGuyStruct, "alerted",
|
|
distractedGuyStruct.guys[ 0 ] , "alerted",
|
|
distractedGuyStruct.guys[ 0 ], "death",
|
|
distractedGuyStruct.guys[ 0 ], "damage",
|
|
distractedGuyStruct.guys[ 1 ], "alerted",
|
|
distractedGuyStruct.guys[ 1 ], "death",
|
|
distractedGuyStruct.guys[ 1 ], "damage" );
|
|
break;
|
|
}
|
|
|
|
distractedGuyStruct notify( "alerted" );
|
|
wait randomfloatrange( 0, 1.3 );
|
|
|
|
for( i = 0 ; i < distractedGuyStruct.guys.size ; i++ )
|
|
{
|
|
if ( !isalive( distractedGuyStruct.guys[ i ] ) )
|
|
continue;
|
|
|
|
distractedGuyStruct.guys[ i ].distracted = undefined;
|
|
//distractedGuyStruct.guys[ i ].ignoreme = false;
|
|
distractedGuyStruct.guys[ i ] notify( "alerted" );
|
|
distractedGuyStruct.guys[ i ] notify( "stop_idle" );
|
|
distractedGuyStruct.guys[ i ].deathanim = undefined;
|
|
if ( isdefined( level.scr_anim[ distractedGuyStruct.guys[ i ].animname ][ "react" ] ) )
|
|
distractedGuyStruct.nodes[ i ] thread anim_single_solo( distractedGuyStruct.guys[ i ], "react" );
|
|
else
|
|
distractedGuyStruct.guys[ i ] stopanimscripted();
|
|
}
|
|
}
|
|
|
|
assasination()
|
|
{
|
|
targeted = getentarray( self.target, "targetname" );
|
|
script_org = undefined;
|
|
assasinate_trigger = undefined;
|
|
for( i = 0 ; i < targeted.size ; i++ )
|
|
{
|
|
if ( targeted[ i ].classname == "script_origin" )
|
|
script_org = targeted[ i ];
|
|
if ( issubstr( targeted[ i ].classname, "trigger" ) )
|
|
assasinate_trigger = targeted[ i ];
|
|
}
|
|
assert( isdefined( script_org ) );
|
|
assasinationStruct = spawnStruct();
|
|
if ( isdefined( assasinate_trigger ) )
|
|
assasinationStruct.assasinate_trigger = assasinate_trigger;
|
|
|
|
targeted = getentarray( script_org.target, "targetname" );
|
|
assasinationStruct.assasination_triggers = [];
|
|
assasinationStruct.spawners = [];
|
|
for( i = 0 ; i < targeted.size ; i++ )
|
|
{
|
|
if ( issubstr( targeted[ i ].classname, "trigger" ) )
|
|
{
|
|
assert( isdefined( targeted[ i ].script_noteworthy ) );
|
|
assasinationStruct.assasination_triggers[ assasinationStruct.assasination_triggers.size ] = targeted[ i ];
|
|
}
|
|
else if ( targeted[ i ] isSpawner() )
|
|
{
|
|
assasinationStruct.spawners[ assasinationStruct.spawners.size ] = targeted[ i ];
|
|
}
|
|
}
|
|
assert( assasinationStruct.assasination_triggers.size > 0 );
|
|
assert( assasinationStruct.spawners.size > 0 );
|
|
|
|
for( i = 0 ; i < assasinationStruct.spawners.size ; i++ )
|
|
{
|
|
assert( isdefined( assasinationStruct.spawners[ i ].target ) );
|
|
node = getnode( assasinationStruct.spawners[ i ].target, "targetname" );
|
|
assert( isdefined( node ) );
|
|
assasinationStruct.spawners[ i ].animnode = node;
|
|
}
|
|
|
|
self waittill( "trigger" );
|
|
|
|
// spawn the guys
|
|
assasinationStruct.guys = [];
|
|
for( i = 0 ; i < assasinationStruct.spawners.size ; i++ )
|
|
{
|
|
spawned = assasinationStruct.spawners[ i ] stalingradSpawn();
|
|
if ( spawn_failed( spawned ) )
|
|
{
|
|
assertMsg( "assasination guy failed to spawn" );
|
|
return;
|
|
}
|
|
assert( isdefined( assasinationStruct.spawners[ i ].animnode ) );
|
|
spawned.animnode = assasinationStruct.spawners[ i ].animnode;
|
|
assasinationStruct.guys[ assasinationStruct.guys.size ] = spawned;
|
|
}
|
|
assert( assasinationStruct.guys.size > 0 );
|
|
assasinationStruct.executioners = [];
|
|
allGuys = assasinationStruct.guys;
|
|
for( i = 0 ; i < allGuys.size ; i++ )
|
|
{
|
|
if ( allGuys[ i ].team != "axis" )
|
|
{
|
|
//allGuys[ i ].ignoreme = true;
|
|
continue;
|
|
}
|
|
|
|
assasinationStruct.executioners[ assasinationStruct.executioners.size ] = allGuys[ i ];
|
|
assasinationStruct.guys = array_remove( assasinationStruct.guys, allGuys[ i ] );
|
|
}
|
|
assert( assasinationStruct.executioners.size > 0 );
|
|
assert( assasinationStruct.guys.size > 0 );
|
|
assert( assasinationStruct.guys.size + assasinationStruct.executioners.size == assasinationStruct.spawners.size );
|
|
|
|
thread assasination_think( assasinationStruct );
|
|
}
|
|
|
|
assasination_think( assasinationStruct )
|
|
{
|
|
for( i = 0 ; i < assasinationStruct.executioners.size ; i++ )
|
|
assasinationStruct.executioners[ i ] endon( "death" );
|
|
|
|
for( i = 0 ; i < assasinationStruct.guys.size ; i++ )
|
|
thread assasination_assasinated_idle( assasinationStruct, i );
|
|
|
|
for( i = 0 ; i < assasinationStruct.executioners.size ; i++ )
|
|
thread assasination_executioner_idle( assasinationStruct, i );
|
|
|
|
thread assasination_alert( assasinationStruct );
|
|
|
|
assasinationStruct waittill_any( "alerted", "assasinate" );
|
|
|
|
createthreatbiasgroup( "executioner" );
|
|
createthreatbiasgroup( "assasinated" );
|
|
setthreatbias( "assasinated", "executioner", 100000 );
|
|
|
|
for( i = 0 ; i < assasinationStruct.executioners.size ; i++ )
|
|
{
|
|
assasinationStruct.executioners[ i ] setthreatbiasgroup( "executioner" );
|
|
assasinationStruct.executioners[ i ] notify( "stop_idle" );
|
|
assasinationStruct.executioners[ i ] stopanimscripted();
|
|
assasinationStruct.executioners[ i ].goalradius = 16;
|
|
assasinationStruct.executioners[ i ] setGoalNode( assasinationStruct.executioners[ i ].animnode );
|
|
assasinationStruct.executioners[ i ].old_baseAccuracy = assasinationStruct.executioners[ i ].baseAccuracy;
|
|
assasinationStruct.executioners[ i ].baseAccuracy = 1000;
|
|
}
|
|
|
|
for( i = 0 ; i < assasinationStruct.guys.size ; i++ )
|
|
{
|
|
assasinationStruct.guys[ i ] setthreatbiasgroup( "assasinated" );
|
|
assasinationStruct.guys[ i ].deathanim = level.scr_anim[ "assasinated" ][ "knees_fall" ];
|
|
assasinationStruct.guys[ i ] thread assasination_ragdoll_death();
|
|
assasinationStruct.guys[ i ].allowdeath = true;
|
|
//assasinationStruct.guys[ i ].ignoreme = false;
|
|
}
|
|
|
|
switch( assasinationStruct.guys.size )
|
|
{
|
|
case 1:
|
|
assasinationStruct.guys[ 0 ] waittill( "death" );
|
|
break;
|
|
case 2:
|
|
waittill_multiple_ents( assasinationStruct.guys[ 0 ], "death", assasinationStruct.guys[ 1 ], "death" );
|
|
break;
|
|
case 3:
|
|
waittill_multiple_ents( assasinationStruct.guys[ 0 ], "death", assasinationStruct.guys[ 1 ], "death", assasinationStruct.guys[ 2 ], "death" );
|
|
break;
|
|
case 4:
|
|
waittill_multiple_ents( assasinationStruct.guys[ 0 ], "death", assasinationStruct.guys[ 1 ], "death", assasinationStruct.guys[ 2 ], "death", assasinationStruct.guys[ 3 ], "death" );
|
|
break;
|
|
}
|
|
|
|
for( i = 0 ; i < assasinationStruct.executioners.size ; i++ )
|
|
{
|
|
assasinationStruct.executioners[ i ].baseAccuracy = assasinationStruct.executioners[ i ].old_baseAccuracy;
|
|
assasinationStruct.executioners[ i ].old_baseAccuracy = undefined;
|
|
}
|
|
}
|
|
|
|
assasination_alert( assasinationStruct )
|
|
{
|
|
for( i = 0 ; i < assasinationStruct.assasination_triggers.size ; i++ )
|
|
assasinationStruct.assasination_triggers[ i ] thread assasination_kill_trigger( assasinationStruct );
|
|
|
|
for( i = 0 ; i < assasinationStruct.executioners.size ; i++ )
|
|
{
|
|
assasinationStruct.executioners[ i ] thread alert_event_notify( assasinationStruct );
|
|
thread assasination_alert_thread( assasinationStruct.executioners[ i ], assasinationStruct );
|
|
}
|
|
}
|
|
|
|
assasination_alert_thread( guy, assasinationStruct )
|
|
{
|
|
level waittill_any_ents( assasinationStruct, "alerted",
|
|
guy , "alerted",
|
|
guy, "death",
|
|
guy, "damage" );
|
|
|
|
assasinationStruct notify( "assasinate" );
|
|
}
|
|
|
|
assasination_ragdoll_death()
|
|
{
|
|
self waittill( "death" );
|
|
wait 0.5;
|
|
if ( isdefined( self ) )
|
|
self startRagDoll();
|
|
}
|
|
|
|
assasination_assasinated_idle( assasinationStruct, guyIndex )
|
|
{
|
|
assasinationStruct.guys[ guyIndex ] thread gun_remove();
|
|
assasinationStruct.guys[ guyIndex ].animname = "assasinated";
|
|
if ( randomint( 3 ) == 0 )
|
|
{
|
|
if ( randomint( 3 ) == 0 )
|
|
assasinationStruct.guys[ guyIndex ].animnode anim_single_solo( assasinationStruct.guys[ guyIndex ], "stand_idle2" );
|
|
assasinationStruct.guys[ guyIndex ].animnode anim_single_solo( assasinationStruct.guys[ guyIndex ], "stand_fall" );
|
|
}
|
|
assasinationStruct.guys[ guyIndex ].animnode thread anim_loop_solo( assasinationStruct.guys[ guyIndex ], "knees_idle", undefined, "stop_idle" );
|
|
}
|
|
|
|
assasination_executioner_idle( assasinationStruct, guyIndex )
|
|
{
|
|
assasinationStruct.executioners[ guyIndex ].allowdeath = true;
|
|
assasinationStruct.executioners[ guyIndex ].animname = "executioner";
|
|
assasinationStruct.executioners[ guyIndex ].animnode thread anim_loop_solo( assasinationStruct.executioners[ guyIndex ], "idle", undefined, "stop_idle" );
|
|
}
|
|
|
|
assasination_kill_trigger( assasinationStruct )
|
|
{
|
|
self waittill( self.script_noteworthy );
|
|
assasinationStruct notify( "assasinate" );
|
|
}
|
|
|
|
alert_event_notify( struct )
|
|
{
|
|
struct endon( "alerted" );
|
|
self endon( "death" );
|
|
|
|
self thread add_event_listener( "grenade danger" );
|
|
self thread add_event_listener( "gunshot" );
|
|
self thread add_event_listener( "silenced_shot" );
|
|
self thread add_event_listener( "bulletwhizby" );
|
|
self thread add_event_listener( "projectile_impact" );
|
|
|
|
self waittill( "event_notify" );
|
|
|
|
struct notify( "alerted" );
|
|
}
|
|
|
|
add_event_listener( sEventString )
|
|
{
|
|
self endon( "death" );
|
|
self endon( "event_notify" );
|
|
self addAIEventListener( sEventString );
|
|
self waittill( sEventString );
|
|
self removeAIEventListener( sEventString );
|
|
self notify( "event_notify" );
|
|
}
|
|
|
|
seek_player()
|
|
{
|
|
self endon( "death" );
|
|
|
|
if ( ( isdefined( self.distracted ) ) && ( self.distracted == true ) )
|
|
self waittill( "alerted" );
|
|
|
|
self.goalradius = 600;
|
|
self setgoalentity( level.player );
|
|
}
|
|
|
|
enemy_color_hint_trigger_think()
|
|
{
|
|
for(;;)
|
|
{
|
|
// trigger is hit - notify the targeted trigger to make enemies use color nodes
|
|
self waittill( "trigger" );
|
|
|
|
getent( self.target, "targetname" ) notify( "trigger" );
|
|
level.seekersUsingColors = true;
|
|
|
|
while( level.player isTouching( self ) )
|
|
wait 0.1;
|
|
|
|
// player not in trigger anymore - make enemies use players goal pos
|
|
level.seekersUsingColors = false;
|
|
level notify( "seekers_chase_player" );
|
|
}
|
|
}
|
|
|
|
seek_player_smart()
|
|
{
|
|
self endon( "death" );
|
|
|
|
if ( ( isdefined( self.distracted ) ) && ( self.distracted == true ) )
|
|
self waittill( "alerted" );
|
|
|
|
self set_force_color( "r" );
|
|
for(;;)
|
|
{
|
|
if ( !level.seekersUsingColors )
|
|
{
|
|
self.goalradius = 2000;
|
|
self.pathenemyfightdist = 1500;
|
|
self setEngagementMinDist( 1300, 1000 );
|
|
self setgoalentity( level.player );
|
|
}
|
|
level waittill( "seekers_chase_player" );
|
|
}
|
|
}
|
|
|
|
seek_player_dog()
|
|
{
|
|
self.goalradius = 1000;
|
|
self setgoalentity( level.player );
|
|
}
|
|
|
|
indoor_enemy()
|
|
{
|
|
//self.engagemaxdist = 512;
|
|
//self.engagemaxfalloffdist = 1024;
|
|
}
|
|
|
|
waittill_ai_in_volume_dead( volumeTargetname )
|
|
{
|
|
volume = getent( volumeTargetname, "targetname" );
|
|
axis = getaiarray( "axis" );
|
|
volumeAxis = [];
|
|
for( i = 0 ; i < axis.size ; i++ )
|
|
{
|
|
if ( !axis[ i ] isTouching( volume ) )
|
|
continue;
|
|
volumeAxis[ volumeAxis.size ] = axis[ i ];
|
|
}
|
|
|
|
if( volumeAxis.size > 0 )
|
|
waittill_dead( volumeAxis );
|
|
}
|
|
|
|
add_objective_building( aiGroupNum )
|
|
{
|
|
if ( !isdefined( level._ai_group ) )
|
|
return;
|
|
|
|
if ( !isdefined( level._ai_group[ aiGroupNum ] ) )
|
|
return;
|
|
|
|
if ( !isdefined( level.buildings_remaining ) )
|
|
level.buildings_remaining = 0;
|
|
level.buildings_remaining++;
|
|
|
|
if ( !isdefined( level.suggested_objective_order ) )
|
|
level.suggested_objective_order = [];
|
|
|
|
// Find the matching script_origin building location for this objective. It will have the same script_aigroup as the AI
|
|
all_obj_locs = getentarray( "objective_location", "targetname" );
|
|
objective_location = undefined;
|
|
for( i = 0 ; i < all_obj_locs.size ; i++ )
|
|
{
|
|
assert( isdefined( all_obj_locs[ i ].script_aigroup ) );
|
|
if ( all_obj_locs[ i ].script_aigroup != aiGroupNum )
|
|
continue;
|
|
objective_location = all_obj_locs[ i ].origin;
|
|
break;
|
|
}
|
|
assert( isdefined( objective_location ) );
|
|
|
|
// add this objective to the suggested order
|
|
objectiveIndex = level.suggested_objective_order.size;
|
|
level.suggested_objective_order[ objectiveIndex ] = spawnStruct();
|
|
level.suggested_objective_order[ objectiveIndex ].aiGroupNum = aiGroupNum;
|
|
level.suggested_objective_order[ objectiveIndex ].completed = false;
|
|
level.suggested_objective_order[ objectiveIndex ].additionalPositionIndex = level.buildings_remaining;
|
|
level.suggested_objective_order[ objectiveIndex ].location = objective_location;
|
|
|
|
// Wait until all AI at this building objective are dead
|
|
waittill_aigroupcleared( aiGroupNum );
|
|
|
|
wait randomfloatrange( 1.5, 3.0 );
|
|
|
|
arcademode_checkpoint( 4, "building_" + aiGroupNum );
|
|
|
|
if ( ( isdefined( level.alasad_objective_location ) ) && ( aiGroupNum == level.alasad_objective_location ) )
|
|
return;
|
|
|
|
// Buildings cleared - update waypoints
|
|
level.buildings_remaining--;
|
|
level.suggested_objective_order[ objectiveIndex ].completed = true;
|
|
thread objective_updateNextWaypoints();
|
|
|
|
if ( !flag( "alasad_sequence_started" ) )
|
|
{
|
|
if ( level.buildingClearNextAudio == 0 )
|
|
{
|
|
// Building clear. No sign of Al-Asad. Move on.
|
|
level.gaz thread anim_single_solo( level.gaz, "nosign" );
|
|
|
|
// increase the ambient
|
|
thread maps\_utility::set_ambient( "exterior3" );
|
|
}
|
|
else if ( level.buildingClearNextAudio == 1 )
|
|
{
|
|
// Building is clear. Move on to the next one.
|
|
level.gaz thread anim_single_solo( level.gaz, "nextone" );
|
|
}
|
|
else if ( level.buildingClearNextAudio == 2 )
|
|
{
|
|
// This building's clear! Let's check the other buildings!
|
|
level.gaz thread anim_single_solo( level.gaz, "checkother" );
|
|
}
|
|
else if ( level.buildingClearNextAudio == 3 )
|
|
{
|
|
// Building clear. Let's check the next one.
|
|
level.gaz thread anim_single_solo( level.gaz, "checknext" );
|
|
|
|
// settle the ambient
|
|
thread maps\_utility::set_ambient( "exterior1" );
|
|
}
|
|
else if ( level.buildingClearNextAudio == 4 )
|
|
{
|
|
// Building clear. No sign of Al-Asad. Move on.
|
|
level.gaz thread anim_single_solo( level.gaz, "nosign" );
|
|
}
|
|
level.buildingClearNextAudio++;
|
|
}
|
|
|
|
// Autosave the game at this point
|
|
thread doAutoSave( "building_" + aiGroupNum + "_cleared" );
|
|
|
|
// if there is only one possible alasad location remaining then activate it now
|
|
level.alasad_possible_objective_locations_remaining = array_remove( level.alasad_possible_objective_locations_remaining, aiGroupNum );
|
|
if ( level.alasad_possible_objective_locations_remaining.size > 1 )
|
|
return;
|
|
if ( isdefined( level.alasad_sequence_init ) )
|
|
return;
|
|
if ( level.alasad_possible_objective_locations_remaining[ 0 ] == "2" )
|
|
thread do_alasad( "house" );
|
|
else if ( level.alasad_possible_objective_locations_remaining[ 0 ] == "6" )
|
|
thread do_alasad( "barn" );
|
|
}
|
|
|
|
objective_updateNextWaypoints()
|
|
{
|
|
numObjectivesDisplayed = 2;
|
|
numObjectivesAdded = 0;
|
|
|
|
// clear all objective waypoints
|
|
for ( i = 0 ; i < level.suggested_objective_order.size ; i++ )
|
|
objective_additionalposition( 0, i, ( 0, 0, 0 ) );
|
|
|
|
// get the next locations to be shown
|
|
for ( objectiveIndex = 0 ; objectiveIndex < level.suggested_objective_order.size ; objectiveIndex++ )
|
|
{
|
|
if ( level.suggested_objective_order[ objectiveIndex ].completed )
|
|
continue;
|
|
|
|
// add objective waypoint
|
|
positionIndex = level.suggested_objective_order[ objectiveIndex ].additionalPositionIndex;
|
|
location = level.suggested_objective_order[ objectiveIndex ].location;
|
|
objective_additionalposition( 0, numObjectivesAdded + 1, location );
|
|
|
|
// make sure we only add as many waypoints as specified
|
|
numObjectivesAdded++;
|
|
if ( numObjectivesAdded == numObjectivesDisplayed )
|
|
return;
|
|
assert( numObjectivesAdded < numObjectivesDisplayed );
|
|
}
|
|
}
|
|
|
|
chopper_air_support()
|
|
{
|
|
dialogIndex = 0;
|
|
level.lastUsedWeapon = undefined;
|
|
level.fake_chopper_ammo = 1;
|
|
flag_init("ammo_cheat_for_chopper");
|
|
|
|
for(;;)
|
|
{
|
|
while( level.player getcurrentweapon() != "cobra_air_support" )
|
|
{
|
|
level.lastUsedWeapon = level.player GetCurrentWeapon();
|
|
wait 0.05;
|
|
}
|
|
|
|
if(getdvar("player_sustainAmmo") == "0" && !flag("ammo_cheat_for_chopper"))
|
|
ammo = level.player getAmmoCount( "cobra_air_support" );
|
|
else
|
|
{
|
|
flag_set("ammo_cheat_for_chopper"); //once cheat has been called maintain fake ammo. going in and out breaks things. - Nate
|
|
ammo = level.fake_chopper_ammo;
|
|
}
|
|
|
|
if ( ( !isdefined( ammo ) ) || ( ammo <= 0 ) )
|
|
{
|
|
// give player his weapon back
|
|
chopper_air_support_giveBackWeapon();
|
|
|
|
if ( flag( "air_support_refueling" ) )
|
|
{
|
|
if ( dialogIndex == 0 )
|
|
{
|
|
// Negative, we are refueling at this time. Standby.
|
|
thread radio_dialogue_queue( "refueling" );
|
|
dialogIndex = 1;
|
|
}
|
|
else
|
|
{
|
|
// We are rearming at this time. Standby.
|
|
thread radio_dialogue_queue( "rearming" );
|
|
dialogIndex = 0;
|
|
}
|
|
}
|
|
|
|
wait 1;
|
|
continue;
|
|
}
|
|
|
|
thread chopper_air_support_activate();
|
|
|
|
while( level.player getcurrentweapon() == "cobra_air_support" )
|
|
wait 0.05;
|
|
|
|
level notify( "air_support_canceled" );
|
|
thread chopper_air_support_deactive();
|
|
}
|
|
}
|
|
|
|
chopper_air_support_removeFunctionality()
|
|
{
|
|
level.player takeWeapon( "cobra_air_support" );
|
|
level notify( "air_support_canceled" );
|
|
level notify( "air_support_deleted" );
|
|
thread chopper_air_support_deactive();
|
|
if ( isdefined( level.chopper ) )
|
|
{
|
|
level.chopper.delete_on_death = true;
|
|
level.chopper notify( "death" );
|
|
}
|
|
}
|
|
|
|
chopper_air_support_activate()
|
|
{
|
|
level endon( "air_support_canceled" );
|
|
level endon( "air_support_called" );
|
|
thread chopper_air_support_paint_target();
|
|
thread air_support_hint_print_call();
|
|
|
|
// Make the arrow
|
|
level.chopperAttackArrow = spawn( "script_model", ( 0, 0, 0 ) );
|
|
level.chopperAttackArrow setModel( "tag_origin" );
|
|
level.chopperAttackArrow.angles = ( -90, 0, 0 );
|
|
level.chopperAttackArrow.offset = 4;
|
|
|
|
playfxontag( getfx( "air_support_fx_yellow" ), level.chopperAttackArrow, "tag_origin" );
|
|
|
|
level.playerActivatedAirSupport = true;
|
|
|
|
coord = undefined;
|
|
|
|
traceOffset = 15;
|
|
traceLength = 15000;
|
|
minValidLength = 300 * 300;
|
|
|
|
trace = [];
|
|
|
|
trace[ 0 ] = spawnStruct();
|
|
trace[ 0 ].offsetDir = "vertical";
|
|
trace[ 0 ].offsetDist = traceOffset;
|
|
|
|
trace[ 1 ] = spawnStruct();
|
|
trace[ 1 ].offsetDir = "vertical";
|
|
trace[ 1 ].offsetDist = traceOffset * -1;
|
|
|
|
trace[ 2 ] = spawnStruct();
|
|
trace[ 2 ].offsetDir = "horizontal";
|
|
trace[ 2 ].offsetDist = traceOffset;
|
|
|
|
trace[ 3 ] = spawnStruct();
|
|
trace[ 3 ].offsetDir = "horizontal";
|
|
trace[ 3 ].offsetDist = traceOffset * -1;
|
|
|
|
rotateTime = 0;
|
|
|
|
for(;;)
|
|
{
|
|
wait 0.05;
|
|
|
|
prof_begin( "spotting_marker" );
|
|
|
|
// Trace to where the player is looking
|
|
direction = level.player getPlayerAngles();
|
|
direction_vec = anglesToForward( direction );
|
|
eye = level.player getEye();
|
|
|
|
for ( i = 0 ; i < trace.size ; i++ )
|
|
{
|
|
start = eye;
|
|
vec = undefined;
|
|
if ( trace[ i ].offsetDir == "vertical" )
|
|
vec = anglesToUp( direction );
|
|
else if ( trace[ i ].offsetDir == "horizontal" )
|
|
vec = anglesToRight( direction );
|
|
assert( isdefined( vec ) );
|
|
start = start + vector_multiply( vec, trace[ i ].offsetDist );
|
|
trace[ i ].trace = bullettrace( start, start + vector_multiply( direction_vec , traceLength ), 0, undefined );
|
|
trace[ i ].length = distanceSquared( start, trace[ i ].trace[ "position" ] );
|
|
|
|
if ( getdvar( "village_assault_debug_marker") == "1" )
|
|
thread draw_line_for_time( start, trace[ i ].trace[ "position" ], 1, 1, 1, 0.05 );
|
|
}
|
|
|
|
validLocations = [];
|
|
validNormals = [];
|
|
for ( i = 0 ; i < trace.size ; i++ )
|
|
{
|
|
if ( trace[ i ].length < minValidLength )
|
|
continue;
|
|
index = validLocations.size;
|
|
validLocations[ index ] = trace[ i ].trace[ "position" ];
|
|
validNormals[ index ] = trace[ i ].trace[ "normal" ];
|
|
|
|
if ( getdvar( "village_assault_debug_marker") == "1" )
|
|
thread draw_line_for_time( level.player getEye(), validLocations[ index ], 0, 1, 0, 0.05 );
|
|
}
|
|
|
|
// if all points are too close just use all of them since none are good
|
|
if ( validLocations.size == 0 )
|
|
{
|
|
for ( i = 0 ; i < trace.size ; i++ )
|
|
{
|
|
validLocations[ i ] = trace[ i ].trace[ "position" ];
|
|
validNormals[ i ] = trace[ i ].trace[ "normal" ];
|
|
}
|
|
}
|
|
|
|
assert( validLocations.size > 0 );
|
|
|
|
if ( validLocations.size == 4 )
|
|
{
|
|
fxLocation = findAveragePointVec( validLocations[ 0 ], validLocations[ 1 ], validLocations[ 2 ], validLocations[ 3 ] );
|
|
fxNormal = findAveragePointVec( validNormals[ 0 ], validNormals[ 1 ], validNormals[ 2 ], validNormals[ 3 ] );
|
|
}
|
|
else if ( validLocations.size == 3 )
|
|
{
|
|
fxLocation = findAveragePointVec( validLocations[ 0 ], validLocations[ 1 ], validLocations[ 2 ] );
|
|
fxNormal = findAveragePointVec( validNormals[ 0 ], validNormals[ 1 ], validNormals[ 2 ] );
|
|
}
|
|
else if ( validLocations.size == 2 )
|
|
{
|
|
fxLocation = findAveragePointVec( validLocations[ 0 ], validLocations[ 1 ] );
|
|
fxNormal = findAveragePointVec( validNormals[ 0 ], validNormals[ 1 ] );
|
|
}
|
|
else
|
|
{
|
|
fxLocation = validLocations[ 0 ];
|
|
fxNormal = validNormals[ 0 ];
|
|
}
|
|
|
|
if ( getdvar( "village_assault_debug_marker") == "1" )
|
|
thread draw_line_for_time( level.player getEye(), fxLocation, 1, 0, 0, 0.05 );
|
|
|
|
thread drawChopperAttackArrow( fxLocation, fxNormal, rotateTime );
|
|
|
|
rotateTime = 0.2;
|
|
|
|
prof_end( "spotting_marker" );
|
|
}
|
|
}
|
|
|
|
findAveragePointVec( point1, point2, point3, point4 )
|
|
{
|
|
assert( isdefined( point1 ) );
|
|
assert( isdefined( point2 ) );
|
|
|
|
if ( isdefined( point4 ) )
|
|
{
|
|
x = findAveragePoint( point1[ 0 ], point2[ 0 ], point3[ 0 ], point4[ 0 ] );
|
|
y = findAveragePoint( point1[ 1 ], point2[ 1 ], point3[ 1 ], point4[ 1 ] );
|
|
z = findAveragePoint( point1[ 2 ], point2[ 2 ], point3[ 2 ], point4[ 2 ] );
|
|
}
|
|
else if ( isdefined( point3 ) )
|
|
{
|
|
x = findAveragePoint( point1[ 0 ], point2[ 0 ], point3[ 0 ] );
|
|
y = findAveragePoint( point1[ 1 ], point2[ 1 ], point3[ 1 ] );
|
|
z = findAveragePoint( point1[ 2 ], point2[ 2 ], point3[ 2 ] );
|
|
}
|
|
else
|
|
{
|
|
x = findAveragePoint( point1[ 0 ], point2[ 0 ] );
|
|
y = findAveragePoint( point1[ 1 ], point2[ 1 ] );
|
|
z = findAveragePoint( point1[ 2 ], point2[ 2 ] );
|
|
}
|
|
return( x, y, z );
|
|
}
|
|
|
|
findAveragePoint( point1, point2, point3, point4 )
|
|
{
|
|
assert( isdefined( point1 ) );
|
|
assert( isdefined( point2 ) );
|
|
|
|
if ( isdefined( point4 ) )
|
|
return ( ( point1 + point2 + point3 + point4 ) / 4 );
|
|
else if ( isdefined( point3 ) )
|
|
return ( ( point1 + point2 + point3 ) / 3 );
|
|
else
|
|
return ( ( point1 + point2 ) / 2 );
|
|
}
|
|
|
|
chopper_air_support_deactive()
|
|
{
|
|
thread delete_attack_coord_hint();
|
|
wait 0.05;
|
|
if ( isdefined( level.chopperAttackArrow ) )
|
|
level.chopperAttackArrow delete();
|
|
}
|
|
|
|
chopper_air_support_giveBackWeapon()
|
|
{
|
|
if ( ( isdefined( level.lastUsedWeapon ) ) && ( level.player HasWeapon( level.lastUsedWeapon ) ) )
|
|
{
|
|
level.player switchToWeapon( level.lastUsedWeapon );
|
|
}
|
|
else
|
|
{
|
|
weaponList = level.player GetWeaponsListPrimaries();
|
|
if ( isdefined( weaponList[ 0 ] ) )
|
|
level.player switchToWeapon( weaponList[ 0 ] );
|
|
}
|
|
}
|
|
|
|
chopper_air_support_paint_target()
|
|
{
|
|
level endon( "air_support_canceled" );
|
|
level.player waittill ( "weapon_fired" );
|
|
|
|
level.fake_chopper_ammo = 0;
|
|
level.playerCalledAirSupport = true;
|
|
|
|
thread chopper_air_support_mark();
|
|
|
|
// give player his weapon back
|
|
chopper_air_support_giveBackWeapon();
|
|
|
|
thread chopper_air_support_call_chopper( level.chopperAttackArrow.origin );
|
|
|
|
level notify( "air_support_called" );
|
|
chopper_air_support_deactive();
|
|
|
|
if ( level.chopperSupportCallNextAudio == 0 )
|
|
thread radio_dialogue_queue( "ontheway" ); // Mosin Two-Five here. We're on the way. Standby for air support.
|
|
else if ( level.chopperSupportCallNextAudio == 1 )
|
|
thread radio_dialogue_queue( "helicopteronway" ); // Helicopter is on the way. We'll handle it. Out.
|
|
else if ( level.chopperSupportCallNextAudio == 2 )
|
|
thread radio_dialogue_queue( "wehavetarget" ); // This is Mosin Two-Five, we have the target. Standby.
|
|
|
|
level.chopperSupportCallNextAudio++;
|
|
if ( level.chopperSupportCallNextAudio > 2 )
|
|
level.chopperSupportCallNextAudio = 0;
|
|
}
|
|
|
|
chopper_dialog()
|
|
{
|
|
|
|
}
|
|
|
|
chopper_air_support_mark()
|
|
{
|
|
marker = spawn( "script_model", level.chopperAttackArrow.origin );
|
|
marker setModel( "tag_origin" );
|
|
marker.angles = level.chopperAttackArrow.angles;
|
|
|
|
wait 0.1;
|
|
|
|
playfxontag( getfx( "air_support_fx_red" ), marker, "tag_origin" );
|
|
|
|
wait 5.0;
|
|
|
|
marker delete();
|
|
}
|
|
|
|
chopper_air_support_friendlyFire()
|
|
{
|
|
self endon( "death" );
|
|
chopper_accumulated_friendly_damage = 0;
|
|
for(;;)
|
|
{
|
|
self waittill( "damage", amount, attacker, direction, point, type );
|
|
if ( attacker != level.player )
|
|
continue;
|
|
if ( ( isdefined( type ) ) && ( !issubstr( tolower( type ), "bullet" ) ) )
|
|
break;
|
|
|
|
if ( isdefined( amount ) && ( amount > 0 ) )
|
|
chopper_accumulated_friendly_damage += amount;
|
|
|
|
if ( chopper_accumulated_friendly_damage >= 500 )
|
|
break;
|
|
}
|
|
thread maps\_friendlyfire::missionfail();
|
|
}
|
|
|
|
chopper_air_support_call_chopper( coordinate )
|
|
{
|
|
closestPoint = findBestChopperWaypoint( coordinate, 45 );
|
|
if ( closestPoint <= -1 )
|
|
{
|
|
wait 0.05;
|
|
closestPoint = findBestChopperWaypoint( coordinate, 70 );
|
|
if ( closestPoint <= -1 )
|
|
{
|
|
wait 0.05;
|
|
closestPoint = findBestChopperWaypoint( coordinate, 70, true );
|
|
}
|
|
}
|
|
assert( closestPoint > -1 );
|
|
|
|
if ( getdvar( "debug_chopper_air_support") == "1" )
|
|
print3d( level.chopperSupportHoverLocations[ closestPoint ] + ( 0, 0,20 ), "chosen", ( 0, 0, 1 ), 1.0, 3.0, 10000 );
|
|
|
|
// spawn the chopper
|
|
level.chopper = maps\_vehicle::spawn_vehicle_from_targetname( "chopper" );
|
|
assert( isdefined( level.chopper ) );
|
|
level.chopper endon( "death" );
|
|
|
|
level.chopper thread chopper_air_support_friendlyFire();
|
|
|
|
returnToBasePos = level.chopper.origin;
|
|
|
|
// fly chopper to that point and make it face the direction of the target
|
|
eTarget = spawn( "script_origin", coordinate );
|
|
level.chopper setLookAtEnt( eTarget );
|
|
|
|
level.chopper setspeed( 65, 10, 20 );
|
|
level.chopper sethoverparams( 250, 60, 35 );
|
|
yawAngle = vectorToAngles( coordinate - level.chopperSupportHoverLocations[ closestPoint ] );
|
|
level.chopper setgoalyaw( yawAngle[ 1 ] );
|
|
level.chopper setvehgoalpos( level.chopperSupportHoverLocations[ closestPoint ], true );
|
|
|
|
level.chopper setNearGoalNotifyDist( 4000 );
|
|
level.chopper waittill( "near_goal" );
|
|
level.chopper thread chopper_ai_mode();
|
|
level.chopper settargetyaw( yawAngle[ 1 ] );
|
|
|
|
level.chopper waittill( "goal" );
|
|
|
|
// kill all the spawners nearby the coordinate
|
|
killspawns = getentarray( "helicopter_force_kill_spawn", "targetname" );
|
|
for ( i = 0 ; i < killspawns.size ; i++ )
|
|
{
|
|
if ( eTarget isTouching( killspawns[ i ] ) )
|
|
{
|
|
assert( isdefined( killspawns[ i ].target ) );
|
|
trig = getentarray( killspawns[ i ].target, "targetname" );
|
|
for ( j = 0 ; j < trig.size ; j++ )
|
|
trig[ j ] notify( "trigger" );
|
|
}
|
|
}
|
|
|
|
level.chopper thread chopper_ai_mode_missiles( eTarget );
|
|
|
|
badplace_cylinder( "air_support_AOE", 30.0, eTarget.origin, 1050, 10000, "allies" );
|
|
thread chopper_air_support_end( returnToBasePos );
|
|
|
|
}
|
|
|
|
player_activated_air_support()
|
|
{
|
|
return isdefined( level.playerActivatedAirSupport );
|
|
}
|
|
|
|
player_called_air_support()
|
|
{
|
|
return isdefined( level.playerCalledAirSupport );
|
|
}
|
|
|
|
delete_hint_print_activated_air_support()
|
|
{
|
|
if ( isdefined( level.air_support_hint_delete ) )
|
|
{
|
|
level.air_support_hint_delete = undefined;
|
|
return true;
|
|
}
|
|
|
|
return isdefined( level.playerActivatedAirSupport );
|
|
}
|
|
|
|
delete_attack_coord_hint()
|
|
{
|
|
flag_set( "delete_attack_coord_hint" );
|
|
level waittill( "checked_should_delete_hint" );
|
|
flag_clear( "delete_attack_coord_hint" );
|
|
}
|
|
|
|
should_delete_attack_coord_hint()
|
|
{
|
|
ans = flag( "delete_attack_coord_hint" );
|
|
level notify( "checked_should_delete_hint" );
|
|
return ans;
|
|
}
|
|
|
|
findBestChopperWaypoint( coordinate, fov_angle, bForceLocation )
|
|
{
|
|
if ( getdvar( "debug_chopper_air_support") == "1" )
|
|
iprintln( "chopper deciding which location to fly to" );
|
|
|
|
playerCoordinate = level.player.origin;
|
|
playerFaceAngle = level.player getPlayerAngles();
|
|
targetFaceAngle = playerFaceAngle + ( 0, 180, 0 );
|
|
cosine = cos( fov_angle );
|
|
|
|
if ( !isdefined( bForceLocation ) )
|
|
bForceLocation = false;
|
|
|
|
closestPoint = -1;
|
|
closestDist = 1000000000;
|
|
minimumSafeDistance = 1000 * 1000;
|
|
for( i = 0 ; i < level.chopperSupportHoverLocations.size ; i++ )
|
|
{
|
|
p = level.chopperSupportHoverLocations[ i ];
|
|
|
|
if ( !bForceLocation )
|
|
{
|
|
// dont use the point if it's not on the same side of the target as the player ( using imaginary perpindicular line to players facing direction )
|
|
if( !within_fov( flat_origin( coordinate ), flat_angle( targetFaceAngle ), flat_origin( p ), cosine ) )
|
|
continue;
|
|
}
|
|
|
|
// get the closest point on the segment to the point
|
|
nearestPointOnLine = pointOnSegmentNearestToPoint( coordinate, playerCoordinate, p );
|
|
d = distanceSquared( nearestPointOnLine, p );
|
|
|
|
if ( !bForceLocation )
|
|
{
|
|
// make sure the chopper wont fly to a location too close to the target
|
|
if ( d < minimumSafeDistance )
|
|
continue;
|
|
}
|
|
|
|
if( d < closestDist )
|
|
{
|
|
closestPoint = i;
|
|
closestDist = d;
|
|
}
|
|
|
|
if ( getdvar( "debug_chopper_air_support") == "1" )
|
|
print3d( p, d, ( 1, 1, 1 ), 1.0, 3.0, 10000 );
|
|
}
|
|
return closestPoint;
|
|
}
|
|
|
|
chopper_air_support_end( returnToBasePos )
|
|
{
|
|
level endon( "air_support_deleted" );
|
|
|
|
flag_clear( "air_support_refueling" );
|
|
|
|
wait 30;
|
|
|
|
flag_set( "air_support_refueling" );
|
|
|
|
// This is Two-Five. We have to refuel and rearm. We will not be available for some time.
|
|
thread radio_dialogue_queue( "refuelandrearm" );
|
|
|
|
level notify( "air_support_over" );
|
|
flyHomeVec = vectorToAngles( returnToBasePos - level.chopper.origin );
|
|
|
|
if ( !isdefined( level.chopper ) )
|
|
return;
|
|
|
|
level.chopper clearLookatEnt();
|
|
level.chopper setTargetYaw( flyHomeVec[ 1 ] );
|
|
level.chopper setVehGoalPos( returnToBasePos );
|
|
|
|
level.chopper waittill( "goal" );
|
|
level.chopper delete();
|
|
level.chopper = undefined;
|
|
|
|
wait 20;
|
|
|
|
flag_clear( "air_support_refueling" );
|
|
|
|
// Mosin Two-Five here. We are ready to attack and are standing by for new orders.
|
|
thread radio_dialogue_queue( "readytoattack" );
|
|
|
|
level.player giveStartAmmo( "cobra_air_support" );
|
|
level.fake_chopper_ammo = 1;
|
|
}
|
|
|
|
chopper_ai_mode()
|
|
{
|
|
self thread chopper_ai_mode_aim_turret();
|
|
self thread chopper_ai_mode_shoot_turret();
|
|
self thread chopper_ai_mode_flares();
|
|
}
|
|
|
|
chopper_ai_mode_aim_turret()
|
|
{
|
|
self endon( "death" );
|
|
level endon( "air_support_over" );
|
|
|
|
for(;;)
|
|
{
|
|
eTarget = maps\_helicopter_globals::getEnemyTarget( 6000, level.cosine[ "45" ], true, true, true, true );
|
|
if( isdefined( eTarget ) )
|
|
{
|
|
eTargetOffset = ( 0, 0, 0 );
|
|
if ( isdefined( eTarget.script_targetoffset_z ) )
|
|
eTargetOffset += ( 0, 0, eTarget.script_targetoffset_z );
|
|
else if ( isSentient( eTarget ) )
|
|
eTargetOffset = ( 0, 0, 32 );
|
|
self setTurretTargetEnt( eTarget, eTargetOffset );
|
|
}
|
|
wait randomfloatrange( 0.2, 1.0 );
|
|
}
|
|
}
|
|
|
|
chopper_ai_mode_shoot_turret()
|
|
{
|
|
self endon( "death" );
|
|
level endon( "air_support_over" );
|
|
|
|
for(;;)
|
|
{
|
|
randomShots = randomintrange( 30, 60 );
|
|
self setVehWeapon( "hind_turret" );
|
|
for( i = 0 ; i < randomShots ; i++ )
|
|
{
|
|
self fireWeapon( "tag_flash" );
|
|
wait 0.05;
|
|
}
|
|
wait randomfloatrange( 1.0, 1.75 );
|
|
}
|
|
}
|
|
|
|
chopper_ai_mode_flares()
|
|
{
|
|
self endon( "death" );
|
|
level endon( "air_support_over" );
|
|
|
|
for(;;)
|
|
{
|
|
iNumFlares = randomintrange( 2, 8 );
|
|
thread maps\_helicopter_globals::flares_fire_burst( self, iNumFlares, 1, 5.0 );
|
|
wait randomfloatrange( 4.0, 8.0 );
|
|
}
|
|
}
|
|
|
|
chopper_ai_mode_missiles( eTarget )
|
|
{
|
|
eTargetOriginal = eTarget;
|
|
|
|
self endon( "death" );
|
|
level endon( "air_support_over" );
|
|
for(;;)
|
|
{
|
|
iShots = randomintrange( 1, 5 );
|
|
eTarget = maps\_helicopter_globals::getEnemyTarget( 6000, level.cosine[ "25" ], true, true, true, true );
|
|
if ( ( isdefined( eTarget ) ) && ( isdefined( eTarget.origin ) ) )
|
|
self maps\_helicopter_globals::fire_missile( "ffar_mi28_village_assault", iShots, eTarget );
|
|
else
|
|
self maps\_helicopter_globals::fire_missile( "ffar_mi28_village_assault", iShots, eTargetOriginal );
|
|
wait randomfloatrange( 3.5, 6.0 );
|
|
}
|
|
}
|
|
|
|
drawChopperAttackArrow( coord, normal, rotateTime )
|
|
{
|
|
assert( isdefined( level.chopperAttackArrow ) );
|
|
assert( isdefined( coord ) );
|
|
assert( isdefined( normal ) );
|
|
assert( isdefined( rotateTime ) );
|
|
|
|
coord += vector_multiply( normal, level.chopperAttackArrow.offset );
|
|
level.chopperAttackArrow.origin = coord;
|
|
|
|
if ( rotateTime > 0 )
|
|
level.chopperAttackArrow rotateTo( vectortoangles( normal ), 0.2 );
|
|
else
|
|
level.chopperAttackArrow.angles = vectortoangles( normal );
|
|
}
|
|
|
|
getClosestInFOV( startOrigin, arrayEnts, fov_angle, minDistance )
|
|
{
|
|
cos = cos( fov_angle );
|
|
|
|
closestEnt = undefined;
|
|
secondClosestEnt = undefined;
|
|
closestDist = 1000000000;
|
|
for( i = 0 ; i < arrayEnts.size ; i++ )
|
|
{
|
|
//if( !within_fov( flat_origin( startOrigin ), flat_angle( level.player getPlayerAngles() ), flat_origin( arrayEnts[ i ].origin ), cos ) )
|
|
// continue;
|
|
|
|
d = distancesquared( startOrigin, arrayEnts[ i ].origin );
|
|
|
|
if ( d < minDistance )
|
|
continue;
|
|
|
|
if( d < closestDist )
|
|
{
|
|
secondClosestEnt = closestEnt;
|
|
closestEnt = arrayEnts[ i ];
|
|
closestDist = d;
|
|
}
|
|
}
|
|
array = [];
|
|
array[ 0 ] = closestEnt;
|
|
array[ 1 ] = secondClosestEnt;
|
|
return array;
|
|
}
|
|
|
|
vehicle_c4_think()
|
|
{
|
|
iEntityNumber = self getentitynumber();
|
|
rearOrgOffset = (0, -33, 10);
|
|
rearAngOffset = (0, 90, -90);
|
|
frontOrgOffset = (129, 0, 35);
|
|
frontAngOffset = (0, 90, 144);
|
|
|
|
self maps\_c4::c4_location( "rear_hatch_open_jnt_left", rearOrgOffset, rearAngOffset );
|
|
self maps\_c4::c4_location( "tag_origin", frontOrgOffset, frontAngOffset );
|
|
self.rearC4location = spawn( "script_origin", self.origin );
|
|
self.frontC4location = spawn( "script_origin", self.origin );
|
|
self.rearC4location linkto( self, "rear_hatch_open_jnt_left", rearOrgOffset, rearAngOffset );
|
|
self.frontC4location linkto( self, "tag_origin", frontOrgOffset, frontAngOffset );
|
|
|
|
self waittill( "c4_detonation" );
|
|
|
|
self.frontC4location delete();
|
|
self.rearC4location delete();
|
|
|
|
self thread vehicle_death( iEntityNumber );
|
|
}
|
|
|
|
vehicle_death( iEntityNumber )
|
|
{
|
|
self notify( "clear_c4" );
|
|
setplayerignoreradiusdamage( true );
|
|
|
|
//-----------------------
|
|
// FINAL EXPLOSION
|
|
//-----------------------
|
|
earthquake( 0.6, 2, self.origin, 2000 );
|
|
self notify( "death" );
|
|
thread play_sound_in_space( "exp_armor_vehicle", self gettagorigin( "tag_turret" ) );
|
|
AI = get_ai_within_radius( 1024, self.origin, "axis" );
|
|
if ( (isdefined(AI)) && (AI.size > 0) )
|
|
array_thread(AI, ::AI_stun, .85);
|
|
|
|
radiusdamage( self.origin, 256, 200, 100 );
|
|
|
|
if ( distancesquared( self.origin, level.player.origin ) <= ( 256 * 256 ) )
|
|
level.player dodamage( level.player.health / 3, ( 0, 0, 0 ) );
|
|
}
|
|
|
|
AI_stun( fAmount )
|
|
{
|
|
self endon( "death" );
|
|
if( ( isdefined( self ) ) && ( isalive( self ) ) && ( self getFlashBangedStrength() == 0 ) )
|
|
self setFlashBanged( true, fAmount );
|
|
}
|
|
|
|
get_ai_within_radius( fRadius, org, sTeam )
|
|
{
|
|
if( isdefined( sTeam ) )
|
|
ai = getaiarray( sTeam );
|
|
else
|
|
ai = getaiarray();
|
|
|
|
aDudes = [];
|
|
for( i = 0 ; i < ai.size ; i++ )
|
|
{
|
|
if ( distance( org, self.origin ) <= fRadius )
|
|
array_add( aDudes, ai[ i ] );
|
|
}
|
|
return aDudes;
|
|
}
|
|
|
|
roaming_bmp()
|
|
{
|
|
bmp = maps\_vehicle::waittill_vehiclespawn( "roaming_bmp" );
|
|
assert( isdefined( bmp ) );
|
|
|
|
target_set( bmp, ( 0, 0, 32 ) );
|
|
target_setJavelinOnly( bmp, true );
|
|
|
|
bmp thread vehicle_patrol_think();
|
|
bmp thread vehicle_turret_think();
|
|
bmp thread vehicle_c4_think();
|
|
bmp thread maps\_vehicle::damage_hints();
|
|
bmp thread bmp_autosave_on_death();
|
|
bmp thread vehicle_death_think();
|
|
}
|
|
|
|
getDamageType( type )
|
|
{
|
|
//returns a simple damage type: melee, bullet, splash, or unknown
|
|
|
|
if ( !isdefined( type ) )
|
|
return "unknown";
|
|
|
|
type = tolower( type );
|
|
switch( type )
|
|
{
|
|
case "mod_explosive":
|
|
case "mod_explosive_splash":
|
|
return "c4";
|
|
case "mod_projectile":
|
|
case "mod_projectile_splash":
|
|
return "rocket";
|
|
case "mod_grenade":
|
|
case "mod_grenade_splash":
|
|
return "grenade";
|
|
case "unknown":
|
|
return "unknown";
|
|
default:
|
|
return "unknown";
|
|
}
|
|
}
|
|
|
|
vehicle_death_think()
|
|
{
|
|
self endon ("death");
|
|
for(;;)
|
|
{
|
|
self waittill( "damage", damage, attacker, direction_vec, point, type );
|
|
|
|
if (attacker != level.player)
|
|
continue;
|
|
|
|
if ( !isdefined( damage ) )
|
|
continue;
|
|
|
|
if ( damage <= 0 )
|
|
continue;
|
|
|
|
type = getDamageType( type );
|
|
assert( isdefined( type ) );
|
|
|
|
if ( ( type == "rocket" ) && ( damage >= 300 ) )
|
|
break;
|
|
|
|
if ( ( type == "c4" ) && ( damage >= 250 ) )
|
|
break;
|
|
}
|
|
self notify( "c4_detonation" );
|
|
}
|
|
|
|
|
|
|
|
|
|
vehicle_patrol_init()
|
|
{
|
|
level.aVehicleNodes = [];
|
|
array1 = getvehiclenodearray( "go_forward", "script_noteworthy" );
|
|
array2 = getvehiclenodearray( "go_backward", "script_noteworthy" );
|
|
level.aVehicleNodes = array_merge( array1, array2 );
|
|
}
|
|
|
|
vehicle_patrol_think()
|
|
{
|
|
level endon( "alasad_sequence_started" );
|
|
self endon( "death" );
|
|
|
|
ePathstart = self.attachedpath;
|
|
self waittill( "reached_end_node" );
|
|
|
|
for(;;)
|
|
{
|
|
prof_begin( "bmp_logic" );
|
|
|
|
//-----------------------
|
|
// REINITIALIZE ALL VARIABLES
|
|
//-----------------------
|
|
aLinked_nodes = [];
|
|
eCurrentNode = undefined;
|
|
go_backward_node = undefined;
|
|
go_forward_node = undefined;
|
|
eStartNode = undefined;
|
|
closestEndNodes = undefined;
|
|
|
|
//-----------------------
|
|
// GET LAST NODE IN CHAIN (CURRENT POSITION
|
|
//-----------------------
|
|
assert( isdefined( ePathstart ) );
|
|
eCurrentNode = ePathstart get_last_ent_in_chain( "vehiclenode" );
|
|
|
|
//-----------------------
|
|
// GET ALL NODES THAT ARE GROUPED WITH THIS PATH END
|
|
//-----------------------
|
|
aLinked_nodes = level.aVehicleNodes;
|
|
aLinked_nodes = array_remove( aLinked_nodes, eCurrentNode);
|
|
aVehicleNodes = level.aVehicleNodes;
|
|
sScript_vehiclenodegroup = eCurrentNode.script_vehiclenodegroup;
|
|
assert(isdefined(sScript_vehiclenodegroup));
|
|
for(i=0;i<aVehicleNodes.size;i++)
|
|
{
|
|
assertEx((isdefined(aVehicleNodes[i].script_vehiclenodegroup)), "Vehiclenode at " + aVehicleNodes[i].origin + " needs to be assigned a script_vehiclenodegroup");
|
|
if ( aVehicleNodes[i].script_vehiclenodegroup != sScript_vehiclenodegroup )
|
|
aLinked_nodes = array_remove( aLinked_nodes, aVehicleNodes[i] );
|
|
}
|
|
//-----------------------
|
|
// GET START NODES TO GO FORWARD/BACKWARD FROM HERE
|
|
//-----------------------
|
|
assertEx(aLinked_nodes.size > 0, "Ends of vehicle paths need to be grouped with at least one other chain of nodes for moving forward, backward or both");
|
|
for(i=0;i<aLinked_nodes.size;i++)
|
|
{
|
|
if ( isdefined(aLinked_nodes[i].script_noteworthy) && (aLinked_nodes[i].script_noteworthy == "go_backward") )
|
|
{
|
|
go_backward_node = aLinked_nodes[i];
|
|
go_backward_node.end = undefined;
|
|
}
|
|
|
|
else if ( isdefined(aLinked_nodes[i].script_noteworthy) && (aLinked_nodes[i].script_noteworthy == "go_forward") )
|
|
{
|
|
go_forward_node = aLinked_nodes[i];
|
|
go_forward_node.end = undefined;
|
|
}
|
|
}
|
|
|
|
//-----------------------
|
|
// DEFINE THE END NODE FOR EACH START NODE
|
|
//-----------------------
|
|
if ( isdefined( go_backward_node ) )
|
|
go_backward_node.end = go_backward_node get_last_ent_in_chain( "vehiclenode" );
|
|
|
|
if ( isdefined( go_forward_node ) )
|
|
go_forward_node.end = go_forward_node get_last_ent_in_chain( "vehiclenode" );
|
|
|
|
//-----------------------
|
|
// STAY PUT, OR START A NEW PATH?
|
|
//-----------------------
|
|
closestEndNodes = getClosestInFOV( level.player.origin, level.aVehicleNodes, 55, level.BMP_Safety_Distance );
|
|
assert( isdefined( closestEndNodes[ 0 ] ) );
|
|
assert( isdefined( closestEndNodes[ 0 ].script_vehiclenodegroup ) );
|
|
if ( isdefined( closestEndNodes[ 1 ] ) )
|
|
{
|
|
assert( isdefined( closestEndNodes[ 1 ].script_vehiclenodegroup ) );
|
|
if ( closestEndNodes[ 1 ].script_vehiclenodegroup < closestEndNodes[ 0 ].script_vehiclenodegroup )
|
|
{
|
|
temp = closestEndNodes[ 0 ];
|
|
closestEndNodes[ 0 ] = closestEndNodes[ 1 ];
|
|
closestEndNodes[ 1 ] = temp;
|
|
}
|
|
}
|
|
if ( closestEndNodes[ 0 ] == eCurrentNode )
|
|
eStartNode = undefined;
|
|
else if ( ( isdefined( go_forward_node ) ) && ( closestEndNodes[ 0 ].script_vehiclenodegroup >= go_forward_node.end.script_vehiclenodegroup ) )
|
|
eStartNode = go_forward_node;
|
|
else if ( ( isdefined( go_backward_node ) ) && ( closestEndNodes[ 0 ].script_vehiclenodegroup <= go_backward_node.end.script_vehiclenodegroup ) )
|
|
eStartNode = go_backward_node;
|
|
|
|
prof_end( "bmp_logic" );
|
|
|
|
//-----------------------
|
|
// GO ON THE NEW PATH TO GET CLOSER TO PLAYER OTHERWISE STAY PUT
|
|
//-----------------------
|
|
if ( isdefined(eStartNode) )
|
|
{
|
|
self attachpath( eStartNode );
|
|
ePathstart = eStartNode;
|
|
wait randomfloatrange( 0.2, 1.2 );
|
|
self resumeSpeed( 100 );
|
|
self waittill( "reached_end_node" );
|
|
}
|
|
else
|
|
{
|
|
wait randomfloatrange( 3, 6 );
|
|
}
|
|
}
|
|
}
|
|
|
|
vehicle_turret_think()
|
|
{
|
|
level endon( "alasad_sequence_started" );
|
|
self endon( "death" );
|
|
|
|
eTarget = undefined;
|
|
|
|
for(;;)
|
|
{
|
|
prof_begin( "bmp_logic" );
|
|
|
|
eTarget = maps\_helicopter_globals::getEnemyTarget( 3000, undefined, true, true, false, true );
|
|
|
|
prof_end( "bmp_logic" );
|
|
|
|
if ( isdefined( eTarget ) )
|
|
{
|
|
self setTurretTargetEnt( eTarget, ( 0, 0, 32 ) );
|
|
self waittill_notify_or_timeout( "turret_rotate_stopped", randomfloatrange( 2.0, 3.0 ) );
|
|
|
|
iFireTime = weaponfiretime( "bmp_turret" );
|
|
assert( isdefined( iFireTime ) );
|
|
assert( iFireTime > 0 );
|
|
|
|
iShots = randomintrange( 3, 8 );
|
|
for( i = 0 ; i < iShots ; i++ )
|
|
{
|
|
self fireWeapon();
|
|
wait iFireTime;
|
|
}
|
|
}
|
|
wait randomfloat( 3.0, 6.0 );
|
|
}
|
|
}
|
|
|
|
doAutoSave( sSaveName )
|
|
{
|
|
assert( isdefined( sSaveName ) );
|
|
thread autosave_by_name( sSaveName );
|
|
thread timedAutosaves();
|
|
}
|
|
|
|
bmp_autosave_on_death()
|
|
{
|
|
self waittill( "death" );
|
|
if ( isdefined( self ) )
|
|
target_remove( self );
|
|
thread doAutoSave( "bmp_destroyed" );
|
|
}
|
|
|
|
timedAutosaves()
|
|
{
|
|
level endon( "alasad_sequence_started" );
|
|
level notify( "timedAutosaveThread" );
|
|
level endon( "timedAutosaveThread" );
|
|
|
|
if ( level.timedAutosaveTime == 0 )
|
|
return;
|
|
|
|
for(;;)
|
|
{
|
|
wait level.timedAutosaveTime;
|
|
level.timedAutosaveNumber++;
|
|
thread doAutoSave( "timed_autosave" + level.timedAutosaveNumber );
|
|
}
|
|
}
|
|
|
|
genocide_audio_trigger()
|
|
{
|
|
soundEnt = getent( self.target, "targetname" );
|
|
assert( isdefined( soundEnt ) );
|
|
|
|
self waittill( "trigger" );
|
|
|
|
if ( isdefined( self.script_delay ) )
|
|
wait self.script_delay;
|
|
|
|
assert( isdefined( level.genocide_audio[ level.next_genocide_audio ] ) );
|
|
|
|
soundEnt playSound( level.genocide_audio[ level.next_genocide_audio ] );
|
|
|
|
level.next_genocide_audio++;
|
|
}
|
|
|
|
dead_civilian()
|
|
{
|
|
wait randomfloatrange( 0.05, 0.2 );
|
|
spawned = dronespawn( self );
|
|
spawned setContents( 0 );
|
|
spawned startRagDoll();
|
|
}
|
|
|
|
air_support_hint_print_activate()
|
|
{
|
|
level endon( "alasad_sequence_started" );
|
|
|
|
while( !player_activated_air_support() )
|
|
{
|
|
if ( level.air_support_hint_print_dialog_next == 0 )
|
|
{
|
|
// Soap! Call in air support on that building!
|
|
level.price thread anim_single_solo( level.price, "airsupport" );
|
|
}
|
|
else if ( level.air_support_hint_print_dialog_next == 1 )
|
|
{
|
|
// Use our air support to soften up that building!
|
|
level.price thread anim_single_solo( level.price, "softenup" );
|
|
}
|
|
else
|
|
{
|
|
// Mosin Two-Five here. We are ready to attack and are standing by for new orders.
|
|
thread radio_dialogue_queue( "readytoattack" );
|
|
}
|
|
level.air_support_hint_print_dialog_next++;
|
|
|
|
if ( !flag( "gave_air_support_hint" ) )
|
|
{
|
|
flag_set( "gave_air_support_hint" );
|
|
if ( isdefined( level.console ) && level.console )
|
|
thread display_air_support_hint_console();
|
|
else
|
|
thread display_air_support_hint_pc();
|
|
}
|
|
wait 5;
|
|
level.air_support_hint_delete = true;
|
|
wait 60;
|
|
}
|
|
}
|
|
|
|
display_air_support_hint_console()
|
|
{
|
|
level endon( "clearing_hints" );
|
|
|
|
add_hint_background();
|
|
|
|
level.hintElem = createFontString( "default", 1.6 );
|
|
level.hintElem setPoint( "TOP", undefined, 0, 130 );
|
|
level.hintElem setText( &"SCRIPT_LEARN_CHOPPER_AIR_SUPPORT1" );
|
|
|
|
level.iconElem1 = createIcon( "hud_dpad", 32, 32 );
|
|
level.iconElem1 setPoint( "TOP", undefined, -32, 165 );
|
|
|
|
level.iconElem3 = createIcon( "hud_arrow_right", 24, 24 );
|
|
level.iconElem3 setPoint( "TOP", undefined, -31.5, 170 );
|
|
level.iconElem3.sort = 1;
|
|
level.iconElem3.color = (1,1,0);
|
|
level.iconElem3.alpha = .7;
|
|
|
|
level.iconElem2 = createIcon( "hud_icon_cobra", 64, 32 );
|
|
level.iconElem2 setPoint( "TOP", undefined, 16, 165 );
|
|
|
|
wait 4;
|
|
|
|
level.iconElem1 setPoint( "CENTER", "BOTTOM", -320, -20, 1.0 );
|
|
level.iconElem2 setPoint( "CENTER", "BOTTOM", -320, -20, 1.0 );
|
|
level.iconElem3 setPoint( "CENTER", "BOTTOM", -320, -20, 1.0 );
|
|
|
|
level.iconElem1 scaleovertime(1, 20, 20);
|
|
level.iconElem2 scaleovertime(1, 20, 20);
|
|
level.iconElem3 scaleovertime(1, 20, 20);
|
|
|
|
wait .70;
|
|
|
|
level.hintElem fadeovertime(.15);
|
|
level.hintElem.alpha = 0;
|
|
|
|
level.iconElem1 fadeovertime(.15);
|
|
level.iconElem1.alpha = 0;
|
|
|
|
level.iconElem2 fadeovertime(.15);
|
|
level.iconElem2.alpha = 0;
|
|
|
|
level.iconElem3 fadeovertime(.15);
|
|
level.iconElem3.alpha = 0;
|
|
|
|
level.hintbackground fadeovertime(.15);
|
|
level.hintbackground.alpha = 0;
|
|
|
|
wait 0.15;
|
|
|
|
clear_hints();
|
|
}
|
|
|
|
display_air_support_hint_pc()
|
|
{
|
|
level endon( "clearing_hints" );
|
|
|
|
add_hint_background();
|
|
|
|
level.hintElem = createFontString( "default", 1.6 );
|
|
level.hintElem setPoint( "TOP", undefined, 0, 130 );
|
|
level.hintElem setText( &"SCRIPT_LEARN_CHOPPER_AIR_SUPPORT1_PC" );
|
|
|
|
level.iconElem2 = createIcon( "hud_icon_cobra", 64, 32 );
|
|
level.iconElem2 setPoint( "TOP", undefined, 16, 165 );
|
|
|
|
wait 4;
|
|
|
|
level.iconElem2 setPoint( "CENTER", "BOTTOM", -320, -20, 1.0 );
|
|
|
|
level.iconElem2 scaleovertime(1, 20, 20);
|
|
|
|
wait .70;
|
|
|
|
level.hintElem fadeovertime(.15);
|
|
level.hintElem.alpha = 0;
|
|
|
|
level.iconElem2 fadeovertime(.15);
|
|
level.iconElem2.alpha = 0;
|
|
|
|
level.hintbackground fadeovertime(.15);
|
|
level.hintbackground.alpha = 0;
|
|
|
|
wait 0.15;
|
|
|
|
clear_hints();
|
|
}
|
|
|
|
add_hint_background( double_line )
|
|
{
|
|
if ( isdefined ( double_line ) )
|
|
level.hintbackground = createIcon( "popmenu_bg", 650, 50 );
|
|
else
|
|
level.hintbackground = createIcon( "popmenu_bg", 650, 30 );
|
|
level.hintbackground.hidewheninmenu = true;
|
|
level.hintbackground setPoint( "TOP", undefined, 0, 125 );
|
|
level.hintbackground.alpha = .5;
|
|
}
|
|
|
|
clear_hints()
|
|
{
|
|
level notify ( "clearing_hints" );
|
|
if ( isDefined( level.hintElem ) )
|
|
level.hintElem destroy();
|
|
if ( isDefined( level.iconElem1 ) )
|
|
level.iconElem1 destroy();
|
|
if ( isDefined( level.iconElem2 ) )
|
|
level.iconElem2 destroy();
|
|
if ( isDefined( level.iconElem3 ) )
|
|
level.iconElem3 destroy();
|
|
if ( isDefined( level.hintbackground ) )
|
|
level.hintbackground destroy();
|
|
}
|
|
|
|
air_support_hint_print_call()
|
|
{
|
|
if ( player_called_air_support() )
|
|
return;
|
|
|
|
level endon( "alasad_sequence_started" );
|
|
thread clear_hints();
|
|
thread display_hint( "call_air_support2" );
|
|
wait 5;
|
|
level.air_support_hint_delete = true;
|
|
}
|
|
|
|
trigger_upstairs_guys()
|
|
{
|
|
assert( isdefined( self.target ) );
|
|
|
|
volume = getent( self.target, "targetname" );
|
|
assert( isdefined( volume ) );
|
|
assert( isdefined( volume.target ) );
|
|
|
|
node = getnode( volume.target, "targetname" );
|
|
assert( isdefined( node ) );
|
|
assert( isdefined( node.radius ) );
|
|
|
|
self waittill( "trigger" );
|
|
|
|
wait randomfloatrange( 5.0, 10.0 );
|
|
|
|
enemies = getaiarray( "axis" );
|
|
for( i = 0 ; i < enemies.size ; i++ )
|
|
{
|
|
if ( !( enemies[ i ] istouching( volume ) ) )
|
|
continue;
|
|
|
|
enemies[i].goalradius = node.radius;
|
|
enemies[i] setgoalnode( node );
|
|
}
|
|
}
|
|
|
|
delete_dropped_weapons()
|
|
{
|
|
wc = [];
|
|
wc = array_add( wc, "weapon_ak47" );
|
|
wc = array_add( wc, "weapon_beretta" );
|
|
wc = array_add( wc, "weapon_g36c" );
|
|
wc = array_add( wc, "weapon_m14" );
|
|
wc = array_add( wc, "weapon_m16" );
|
|
wc = array_add( wc, "weapon_m203" );
|
|
wc = array_add( wc, "weapon_rpg" );
|
|
wc = array_add( wc, "weapon_saw" );
|
|
wc = array_add( wc, "weapon_m4" );
|
|
wc = array_add( wc, "weapon_m40a3" );
|
|
wc = array_add( wc, "weapon_mp5" );
|
|
wc = array_add( wc, "weapon_mp5sd" );
|
|
wc = array_add( wc, "weapon_usp" );
|
|
wc = array_add( wc, "weapon_at4" );
|
|
wc = array_add( wc, "weapon_dragunov" );
|
|
wc = array_add( wc, "weapon_g3" );
|
|
wc = array_add( wc, "weapon_uzi" );
|
|
|
|
for( i = 0 ; i < wc.size ; i ++ )
|
|
{
|
|
weapons = getentarray( wc[i], "classname" );
|
|
for( n = 0 ; n < weapons.size ; n ++ )
|
|
{
|
|
if ( isdefined( weapons[n].targetname ) )
|
|
continue;
|
|
weapons[n] delete();
|
|
}
|
|
}
|
|
}
|
|
|
|
alasad_deletable_hide()
|
|
{
|
|
if ( isdefined( self.spawnflags ) && ( self.spawnflags & 1 ) )
|
|
self connectpaths();
|
|
self.origin -= ( 0, 0, 5000 );
|
|
}
|
|
|
|
alasad_deletable_show()
|
|
{
|
|
self.origin += ( 0, 0, 5000 );
|
|
if ( isdefined( self.spawnflags ) && ( self.spawnflags & 1 ) )
|
|
self disconnectpaths();
|
|
}
|
|
|
|
spawn_ai_and_make_dumb( spawnerTargetname, linkInPlace )
|
|
{
|
|
spawner = getent( spawnerTargetname, "targetname" );
|
|
assert( isdefined( spawner ) );
|
|
if ( isdefined( spawner.script_drone ) )
|
|
{
|
|
guy = droneSpawn( spawner );
|
|
}
|
|
else
|
|
{
|
|
guy = spawner stalingradSpawn();
|
|
spawn_failed( guy );
|
|
guy.maxsightdistsqrd = 0;
|
|
guy.ignoreme = true;
|
|
guy.ignoreall = true;
|
|
guy thread ignoreAllEnemies( true );
|
|
}
|
|
guy.health = 100000;
|
|
|
|
if ( isdefined( linkInPlace ) )
|
|
{
|
|
dummy = spawn( "script_origin", spawner.origin );
|
|
guy linkto( dummy );
|
|
}
|
|
|
|
return guy;
|
|
}
|
|
|
|
headshot( guy, killguy )
|
|
{
|
|
if ( !isdefined( guy ) )
|
|
return;
|
|
if ( !isAlive( guy ) )
|
|
return;
|
|
if ( !isdefined( killguy ) )
|
|
killguy = true;
|
|
playFX( getfx( "headshot" ), guy getTagOrigin( "tag_eye" ) );
|
|
if ( killguy )
|
|
guy doDamage( guy.health + 100, guy getTagOrigin( "tag_eye" ) );
|
|
}
|
|
|
|
goBlack( fDelay, fFadeTimeIn, fFadeTimeOut )
|
|
{
|
|
overlay = newHudElem();
|
|
overlay.x = 0;
|
|
overlay.y = 0;
|
|
overlay.alignX = "left";
|
|
overlay.alignY = "top";
|
|
overlay.horzAlign = "fullscreen";
|
|
overlay.vertAlign = "fullscreen";
|
|
overlay setshader ( "black", 640, 480 );
|
|
overlay.sort = 1;
|
|
overlay.alpha = 0;
|
|
|
|
assert( isdefined( fFadeTimeIn ) );
|
|
assert( isdefined( fFadeTimeOut ) );
|
|
assert( fFadeTimeIn >= 0 );
|
|
assert( fFadeTimeOut >= 0 );
|
|
|
|
if ( fFadeTimeIn > 0 )
|
|
overlay fadeOverTime( fFadeTimeIn );
|
|
overlay.alpha = 1.0;
|
|
wait fFadeTimeIn;
|
|
|
|
if ( !isdefined( fDelay ) )
|
|
return;
|
|
assert( fDelay > 0 );
|
|
|
|
wait fDelay;
|
|
|
|
level notify( "fade_from_black" );
|
|
wait 0.1;
|
|
|
|
if ( fFadeTimeOut > 0 )
|
|
overlay fadeOverTime( fFadeTimeOut );
|
|
overlay.alpha = 0.0;
|
|
wait fFadeTimeOut;
|
|
|
|
overlay destroy();
|
|
}
|
|
|
|
do_alasad( location )
|
|
{
|
|
assert( isdefined( location ) );
|
|
|
|
level.alasad_sequence_init = true;
|
|
|
|
struct = spawnStruct();
|
|
|
|
if ( location == "barn" )
|
|
{
|
|
println( "Al Asad is in the ^3BARN" );
|
|
|
|
struct.nodeTargetname1 = "alasad_barn_node";
|
|
struct.nodeTargetname2 = "alasad_barn_node2";
|
|
struct.deletableNoteworthy = "alasad_barn_deletable";
|
|
struct.brushDoorTargetname = "alasad_barn_door";
|
|
struct.spawnersToDeleteKillspawner = 12;
|
|
struct.friendlyColorTriggerTargetname1 = "alasad_barn_friendly_color_trigger";
|
|
struct.friendlyColorTriggerTargetname2 = "alasad_barn_last_friendly_trigger";
|
|
struct.AlAsadSpawnerTargetname = "alasad_spawner_barn";
|
|
struct.AlAsadFirstShotSpawnerTargetname = "alasad_barn_first_shot_spawner";
|
|
struct.AlAsadSecondShotSpawnerTargetname = "alasad_barn_second_shot_spawner";
|
|
struct.startSequenceTriggerTargetname = "alasad_barn_trigger";
|
|
struct.playerLocationSceneBTargetname = "alasad_barn_playerlocation";
|
|
struct.setupAreaTriggerTargetname = "alasad_barn_area";
|
|
struct.AItoDeleteAreaTargetname = "area_barn";
|
|
|
|
level.alasad_flashbang_location = getent( "alasad_barn_flash_location", "targetname" ).origin;
|
|
|
|
level.alasad_objective_location = "6";
|
|
}
|
|
else if ( location == "house" )
|
|
{
|
|
println( "Al Asad is in the ^3HOUSE" );
|
|
|
|
struct.nodeTargetname1 = "alasad_house_node";
|
|
struct.nodeTargetname2 = "alasad_house_node2";
|
|
struct.deletableNoteworthy = "alasad_house_deletable";
|
|
struct.brushDoorTargetname = "alasad_house_door";
|
|
struct.spawnersToDeleteKillspawner = 2;
|
|
struct.friendlyColorTriggerTargetname1 = "alasad_house_friendly_color_trigger";
|
|
struct.friendlyColorTriggerTargetname2 = "alasad_house_last_friendly_trigger";
|
|
struct.AlAsadSpawnerTargetname = "alasad_spawner_house";
|
|
struct.AlAsadFirstShotSpawnerTargetname = "alasad_house_first_shot_spawner";
|
|
struct.AlAsadSecondShotSpawnerTargetname = "alasad_house_second_shot_spawner";
|
|
struct.startSequenceTriggerTargetname = "alasad_house_trigger";
|
|
struct.playerLocationSceneBTargetname = "alasad_house_playerlocation";
|
|
struct.setupAreaTriggerTargetname = "alasad_house_area";
|
|
struct.AItoDeleteAreaTargetname = "area_grandmas_house";
|
|
|
|
level.alasad_flashbang_location = getent( "alasad_house_flash_location", "targetname" ).origin;
|
|
|
|
level.alasad_objective_location = "2";
|
|
}
|
|
|
|
assert( isdefined( struct ) );
|
|
assert( isdefined( struct.nodeTargetname1 ) );
|
|
assert( isdefined( struct.nodeTargetname2 ) );
|
|
assert( isdefined( struct.deletableNoteworthy ) );
|
|
assert( isdefined( struct.brushDoorTargetname ) );
|
|
assert( isdefined( struct.friendlyColorTriggerTargetname1 ) );
|
|
assert( isdefined( struct.friendlyColorTriggerTargetname2 ) );
|
|
assert( isdefined( struct.AlAsadSpawnerTargetname ) );
|
|
assert( isdefined( struct.AlAsadFirstShotSpawnerTargetname ) );
|
|
assert( isdefined( struct.AlAsadSecondShotSpawnerTargetname ) );
|
|
assert( isdefined( struct.startSequenceTriggerTargetname ) );
|
|
assert( isdefined( struct.playerLocationSceneBTargetname ) );
|
|
assert( isdefined( struct.setupAreaTriggerTargetname ) );
|
|
assert( isdefined( level.alasad_flashbang_location ) );
|
|
|
|
alasad_sequence_init( struct );
|
|
}
|
|
|
|
alasad_sequence_init( struct )
|
|
{
|
|
// prepares the correct location for the scene by removing spawners and setting up doors etc.
|
|
|
|
array_thread( getentarray( struct.deletableNoteworthy, "script_noteworthy" ), ::alasad_deletable_show );
|
|
|
|
// get the first node
|
|
struct.node = getnode( struct.nodeTargetname1, "targetname" );
|
|
assert( isdefined( struct.node ) );
|
|
|
|
// spawn the door and make it play frame 0 so it's shut
|
|
struct.door = spawn_anim_model( "door" );
|
|
struct.node thread anim_first_frame_solo( struct.door, "interrogationA" );
|
|
|
|
// link the door to the model door that animates and hide the model door
|
|
struct.brushmodel_door = getent( struct.brushDoorTargetname, "targetname" );
|
|
assert( isdefined( struct.brushmodel_door ) );
|
|
struct.brushmodel_door linkto( struct.door, "door_hinge_jnt" );
|
|
struct.door hide();
|
|
|
|
// delete AI and spawners with this noteworthy when the barn will be the location of al asad
|
|
if ( isdefined( struct.spawnersToDeleteKillspawner ) )
|
|
thread maps\_spawner::kill_spawnerNum( struct.spawnersToDeleteKillspawner );
|
|
if ( isdefined( struct.AItoDeleteAreaTargetname ) )
|
|
{
|
|
area = getent( struct.AItoDeleteAreaTargetname, "targetname" );
|
|
axis = getAIArray( "axis" );
|
|
for ( i = 0 ; i < axis.size ; i++ )
|
|
{
|
|
if ( !axis[ i ] istouching( area ) )
|
|
continue;
|
|
axis[ i ].dieQuietly = true;
|
|
axis[ i ] doDamage( axis[ i ].health + 100, axis[ i ].origin );
|
|
}
|
|
}
|
|
|
|
alasad_sequence_wait( struct );
|
|
}
|
|
|
|
alasad_sequence_wait( struct )
|
|
{
|
|
// Waits for the player to get close to Al Asad's location and moves the friendlies to the door
|
|
// If the player runs off the friendlies leave the door and go back to normal AI until the player returns
|
|
|
|
level endon( "alasad_sequence_started" );
|
|
|
|
struct.alasad_area = getent( struct.setupAreaTriggerTargetname, "targetname" );
|
|
assert( isdefined( struct.alasad_area ) );
|
|
|
|
struct.color_trigger = getent( struct.friendlyColorTriggerTargetname1, "targetname" );
|
|
assert( isdefined( struct.color_trigger ) );
|
|
|
|
for(;;)
|
|
{
|
|
if ( level.player isTouching( struct.alasad_area ) )
|
|
{
|
|
// make all friendlies orange color group and send them to the door
|
|
array_thread( getAIArray( "allies" ), ::set_force_color, "o" );
|
|
struct.color_trigger notify( "trigger" );
|
|
|
|
thread alasad_sequence_ready( struct );
|
|
|
|
while( level.player isTouching( struct.alasad_area ) )
|
|
wait 0.05;
|
|
}
|
|
else
|
|
{
|
|
level notify( "alasad_sequence_canceled" );
|
|
|
|
// make all friendlies red color group again because player is leaving the area
|
|
array_thread( getAIArray( "allies" ), ::set_force_color, "r" );
|
|
|
|
while( !level.player isTouching( struct.alasad_area ) )
|
|
wait 0.05;
|
|
}
|
|
}
|
|
}
|
|
|
|
alasad_sequence_ready( struct )
|
|
{
|
|
level endon( "alasad_sequence_canceled" );
|
|
|
|
// get price into position
|
|
struct.node thread anim_reach_solo( level.price, "interrogationA" );
|
|
|
|
// wait for the player to get close
|
|
getent( struct.startSequenceTriggerTargetname, "targetname" ) waittill( "trigger" );
|
|
|
|
alasad_sequence_start( struct );
|
|
}
|
|
|
|
alasad_sequence_start( struct )
|
|
{
|
|
level notify( "alasad_sequence_started" );
|
|
level.air_support_hint_delete = true;
|
|
|
|
// take away flash, grenade, smoke, etc
|
|
removeWeaponFromPlayer( "fraggrenade" );
|
|
removeWeaponFromPlayer( "smoke_grenade_american" );
|
|
removeWeaponFromPlayer( "c4" );
|
|
removeWeaponFromPlayer( "flash_grenade" );
|
|
|
|
thread battlechatter_off( "allies" );
|
|
thread battlechatter_off( "axis" );
|
|
|
|
thread doAutoSave( "capturing_al_asad" );
|
|
|
|
//---------------
|
|
// SCENE A
|
|
//---------------
|
|
|
|
// spawn and prepare Al Asad
|
|
level.alasad = spawn_ai_and_make_dumb( struct.AlAsadSpawnerTargetname );
|
|
level.alasad thread removeWeapon();
|
|
level.alasad.animname = "alasad";
|
|
waittillframeend; // waittillframeend so that Al Asad can finish spawning before he gets teleported
|
|
struct.node thread anim_teleport_solo( level.alasad, "interrogationA" );
|
|
|
|
// spawn the guys guarding Al Asad
|
|
level.alasad_guard1 = spawn_ai_and_make_dumb( struct.AlAsadFirstShotSpawnerTargetname, true );
|
|
level.alasad_guard2 = spawn_ai_and_make_dumb( struct.AlAsadSecondShotSpawnerTargetname, true );
|
|
|
|
// spawn the phone
|
|
phone = spawn_anim_model( "phone" );
|
|
struct.node thread anim_first_frame_solo( phone, "interrogationA" );
|
|
|
|
struct.guys = [];
|
|
struct.guys[ struct.guys.size ] = level.price;
|
|
|
|
// get them into position to start the sequence
|
|
struct.node anim_reach( struct.guys, "interrogationA" );
|
|
struct.guys[ struct.guys.size ] = level.alasad;
|
|
|
|
// give price his special weapon for the scene
|
|
level.price animscripts\init::initWeapon( "colt45_alasad_killer", "sidearm" );
|
|
level.price.sidearm = "colt45_alasad_killer";
|
|
|
|
// wait until the player can see the sequence
|
|
level.price waittill_player_lookat( level.cosine[ "60" ] );
|
|
|
|
flag_set( "alasad_sequence_started" );
|
|
|
|
level.price thread play_sound_on_entity( "scn_assault_interogation_enter" );
|
|
|
|
// Remember, we want Al-Asad alive. He's no good to us dead. Let's go.
|
|
level.price thread anim_single_solo( level.price, "nogooddead" );
|
|
|
|
// start the seqence
|
|
delayThread( 5.9, ::activate_trigger_with_targetname, struct.friendlyColorTriggerTargetname2 );
|
|
delayThread( 6.0, ::disconnectPathsWrapper, struct.brushmodel_door );
|
|
struct.guys[ struct.guys.size ] = struct.door;
|
|
struct.guys[ struct.guys.size ] = phone;
|
|
struct.node anim_single( struct.guys, "interrogationA" );
|
|
|
|
// take away ability to call air support
|
|
thread chopper_air_support_removeFunctionality();
|
|
|
|
thread goBlack( 18.0, 0.0, 0.5 );
|
|
thread blackscreen1_dialog();
|
|
thread alasad_kill_axis();
|
|
level.player NightVisionForceOff();
|
|
|
|
//---------------
|
|
// SCENE B
|
|
//---------------
|
|
|
|
objective_state( 0, "done" );
|
|
|
|
struct.node = getnode( struct.nodeTargetname2, "targetname" );
|
|
assert( isdefined( struct.node ) );
|
|
|
|
level.price detach( "weapon_m4grunt_sp_silencer", "tag_weapon_chest" );
|
|
level.price.a.weaponPos[ "chest" ] = "none";
|
|
|
|
// spawn the chair
|
|
chair = spawn_anim_model( "chair" );
|
|
|
|
// first frame of next scene so it's ready
|
|
struct.guys = [];
|
|
struct.guys[ struct.guys.size ] = level.price;
|
|
struct.guys[ struct.guys.size ] = level.gaz;
|
|
struct.guys[ struct.guys.size ] = level.alasad;
|
|
struct.guys[ struct.guys.size ] = chair;
|
|
struct.guys[ struct.guys.size ] = phone;
|
|
|
|
struct.node thread anim_first_frame( struct.guys, "interrogationB" );
|
|
|
|
// put the player in a good spot
|
|
level.player freezeControls( true );
|
|
delete_dropped_weapons();
|
|
level.player takeAllWeapons();
|
|
movePlayerToLocation( struct.playerLocationSceneBTargetname );
|
|
|
|
level waittill( "fade_from_black" );
|
|
level.player freezeControls( false );
|
|
|
|
level.price thread alasad_execution_notes();
|
|
level.price thread alasad_cell_phone_sounds( phone );
|
|
level.gaz thread play_sound_on_entity( "scn_assault_interogation_pickup" );
|
|
level.price thread play_sound_on_entity( "scn_assault_interogation_beating" );
|
|
level.alasad thread play_sound_on_entity( "scn_assault_interogation_breathing" );
|
|
struct.node anim_single( struct.guys, "interrogationB" );
|
|
|
|
level.price.weaponInfo["m4_silencer"].position = "none";
|
|
}
|
|
|
|
blackscreen1_dialog()
|
|
{
|
|
wait 2;
|
|
|
|
level.player thread play_sound_on_entity( "scn_assault_interogation_black" );
|
|
|
|
// Why'd you do it? Where did you get the bomb?
|
|
level.price thread delayThread( 0.0, ::anim_single_solo, level.price, "whydyoudoit" );
|
|
|
|
// It wasn't me!!
|
|
level.alasad thread delayThread( 3.05, ::anim_single_solo, level.alasad, "wasntme1" );
|
|
|
|
// Who then?
|
|
level.price thread delayThread( 5.3, ::anim_single_solo, level.price, "whothen" );
|
|
|
|
// It wasn't me!!
|
|
level.alasad thread delayThread( 8.3, ::anim_single_solo, level.alasad, "wasntme2" );
|
|
|
|
// Who!? Give me a name!
|
|
level.price thread delayThread( 10.85, ::anim_single_solo, level.price, "givemeaname" );
|
|
|
|
// A name! I - want - his - name!
|
|
level.price thread delayThread( 13.65, ::anim_single_solo, level.price, "aname" );
|
|
|
|
wait 16;
|
|
}
|
|
|
|
blackscreen2_dialog()
|
|
{
|
|
wait 1;
|
|
|
|
// Who was that sir?
|
|
level.gaz thread anim_single_solo( level.gaz, "whowasthat" );
|
|
|
|
wait 2;
|
|
|
|
// Zakhaev.
|
|
level.price thread anim_single_solo( level.price, "zakhaev" );
|
|
|
|
wait 2;
|
|
|
|
// Imran Zakhaev.
|
|
level.price thread anim_single_solo( level.price, "imran" );
|
|
}
|
|
|
|
alasad_execution_notes()
|
|
{
|
|
level.price waittillmatch( "single anim", "pistol_pickup" );
|
|
level.price detach( "weapon_colt1911_black", "tag_weapon_right" );
|
|
wait 0.2;
|
|
level.price attach( "weapon_colt1911_black", "tag_weapon_right" );
|
|
|
|
level.price waittillmatch( "single anim", "fire" );
|
|
wait 3.5;
|
|
|
|
level.player freezeControls( true );
|
|
thread goBlack( 60.0, 1.0, 0.5 );
|
|
thread blackscreen2_dialog();
|
|
wait 7;
|
|
nextmission();
|
|
}
|
|
|
|
alasad_cell_phone_sounds( phone )
|
|
{
|
|
wait 2;
|
|
|
|
thread alasad_cell_phone_ring( phone );
|
|
|
|
wait 7;
|
|
|
|
phone notify( "stop ringing" );
|
|
|
|
wait 1;
|
|
|
|
// Sir. It's his cell phone.
|
|
level.gaz thread anim_single_solo( level.gaz, "cellphone" );
|
|
}
|
|
|
|
alasad_cell_phone_ring( phone )
|
|
{
|
|
phone endon( "stop ringing" );
|
|
for(;;)
|
|
{
|
|
level.gaz thread play_sound_on_entity( "scn_assault_mobile_ring" );
|
|
wait 2;
|
|
}
|
|
}
|
|
|
|
alasad_notetracks( guy )
|
|
{
|
|
// called from a notetrack
|
|
|
|
sHandTag = "J_Mid_RI_3";
|
|
guy attach( "projectile_m84_flashbang_grenade", sHandTag );
|
|
|
|
wait 2.0;
|
|
|
|
// price tosses in a flashbang
|
|
guy detach( "projectile_m84_flashbang_grenade", sHandTag );
|
|
thread alasad_flashbang( 1.0 );
|
|
|
|
// price picks up pistol so need to replace the rifle
|
|
guy waittillmatch( "single anim", "pistol_pickup" );
|
|
|
|
// price drops his gun
|
|
guy waittillmatch( "single anim", "pistol_drop" );
|
|
guy gun_remove();
|
|
|
|
// al asad gets shot
|
|
guy waittillmatch( "single anim", "fire" );
|
|
headshot( level.alasad, false );
|
|
}
|
|
|
|
alasad_flashbang( fDelay )
|
|
{
|
|
assert( isdefined( level.alasad_flashbang_location ) );
|
|
wait fDelay;
|
|
playFX( getfx( "alasad_flash" ), level.alasad_flashbang_location );
|
|
thread play_sound_in_space( "flashbang_explode_default", level.alasad_flashbang_location );
|
|
|
|
// two guards get shot
|
|
wait 1.0;
|
|
headshot( level.alasad_guard1 );
|
|
wait 0.5;
|
|
headshot( level.alasad_guard2 );
|
|
}
|
|
|
|
alasad_kill_axis()
|
|
{
|
|
axis = getaiarray( "axis" );
|
|
for ( i = 0 ; i < axis.size ; i++ )
|
|
{
|
|
if ( !isAlive( axis[ i ] ) )
|
|
continue;
|
|
if ( axis[ i ] == level.alasad )
|
|
continue;
|
|
if ( axis[ i ] == level.alasad_guard1 )
|
|
continue;
|
|
if ( axis[ i ] == level.alasad_guard2 )
|
|
continue;
|
|
axis[ i ].dieQuietly = true;
|
|
axis[ i ] doDamage( axis[ i ].health + 100, axis[ i ].origin );
|
|
}
|
|
}
|
|
|
|
disconnectPathsWrapper( ent )
|
|
{
|
|
ent connectPaths();
|
|
}
|
|
|
|
opening_sequence()
|
|
{
|
|
assert( isdefined( level.opening_guy ) );
|
|
node = getnode( "opening_sequence_node", "targetname" );
|
|
assert( isdefined( node ) );
|
|
guys = [];
|
|
guys[ 0 ] = level.price;
|
|
guys[ 1 ] = level.opening_guy;
|
|
node anim_first_frame( guys, "opening" );
|
|
wait 4.0;
|
|
thread opening_sequence_notetracks( level.opening_guy );
|
|
thread opening_sequence_dialog( level.opening_guy );
|
|
node anim_single( guys, "opening" );
|
|
}
|
|
|
|
opening_sequence_notetracks( guy )
|
|
{
|
|
guy attach( "com_flashlight_off", "tag_inhand" );
|
|
|
|
guy waittillmatch( "single anim", "flash" );
|
|
thread opening_sequence_flashLight( guy );
|
|
|
|
guy waittillmatch( "single anim", "flash" );
|
|
thread opening_sequence_flashLight( guy );
|
|
|
|
guy waittillmatch( "single anim", "flash" );
|
|
thread opening_sequence_flashLight( guy );
|
|
|
|
guy waittillmatch( "single anim", "detach flashlight" );
|
|
guy detach( "com_flashlight_off", "tag_inhand" );
|
|
}
|
|
|
|
opening_sequence_flashLight( guy )
|
|
{
|
|
tagName = "tag_inhand";
|
|
modelOn = "com_flashlight_on";
|
|
modelOff = "com_flashlight_off";
|
|
|
|
// on
|
|
if ( guy isModelAttached( modelOff, tagName ) )
|
|
guy detach( modelOff, tagName );
|
|
guy attach( modelOn, tagName );
|
|
guy thread flashlight_light( true );
|
|
wait 0.1;
|
|
|
|
// off
|
|
if ( guy isModelAttached( modelOn, tagName ) )
|
|
guy detach( modelOn, tagName );
|
|
guy attach( modelOff, tagName );
|
|
guy thread flashlight_light( false );
|
|
}
|
|
|
|
opening_sequence_dialog( guy )
|
|
{
|
|
wait 3;
|
|
|
|
//There's Kamarov's man, let's go.
|
|
level.price thread anim_single_solo( level.price, "kamarovsman" );
|
|
|
|
wait 5;
|
|
|
|
//Al-Asad is in the village. The Ultranationalists are protecting him.
|
|
guy thread anim_single_solo( guy, "asadinvillage" );
|
|
|
|
wait 4.5;
|
|
|
|
//Perfect. Move out.
|
|
level.price thread anim_single_solo( level.price, "perfect" );
|
|
|
|
wait 10;
|
|
|
|
//What the bloody hell's going on up there?
|
|
level.gaz thread anim_single_solo( level.gaz, "whatsgoingon" );
|
|
|
|
wait 2.5;
|
|
|
|
//It's the Ultranationalists. They're killing the villagers.
|
|
guy thread anim_single_solo( guy, "killingvillagers" );
|
|
|
|
wait 3.5;
|
|
|
|
//Not for long they're not.
|
|
level.gaz thread anim_single_solo( level.gaz, "notforlong" );
|
|
}
|
|
|
|
isModelAttached( modelName, tagName )
|
|
{
|
|
qAttached = false;
|
|
|
|
modelName = tolower( modelName );
|
|
tagName = tolower( tagName );
|
|
|
|
assert( isdefined( modelName ) );
|
|
if ( !isdefined( tagName ) )
|
|
return qAttached;
|
|
|
|
attachedModelCount = self getattachsize();
|
|
attachedModels = [];
|
|
for ( i = 0 ; i < attachedModelCount ; i++ )
|
|
attachedModels[ i ] = tolower( self getAttachModelName( i ) );
|
|
|
|
for ( i = 0 ; i < attachedModels.size ; i++ )
|
|
{
|
|
if ( attachedModels[ i ] != modelName )
|
|
continue;
|
|
|
|
sName = tolower( self getattachtagname( i ) );
|
|
if ( tagName != sName )
|
|
continue;
|
|
|
|
qAttached = true;
|
|
break;
|
|
}
|
|
|
|
return qAttached;
|
|
}
|
|
|
|
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
|
|
self notify( "flashlight_off" );
|
|
}
|
|
|
|
flashlight_light_death( flashlight_fx_ent )
|
|
{
|
|
self waittill_either( "death", "flashlight_off" );
|
|
flashlight_fx_ent delete();
|
|
}
|
|
|
|
removeWeaponFromPlayer( weaponName )
|
|
{
|
|
assert( isdefined( weaponName ) );
|
|
if( level.player HasWeapon( weaponName ) )
|
|
level.player takeWeapon( weaponName );
|
|
}
|
|
|
|
removeWeapon( optionalWeaponName )
|
|
{
|
|
if( IsAI( self ) )
|
|
self gun_remove();
|
|
else
|
|
{
|
|
size = self getattachsize();
|
|
for ( i = 0; i < size; i++ )
|
|
{
|
|
model = self getattachmodelname( i );
|
|
tag = self GetAttachTagName( i );
|
|
if ( isdefined( optionalWeaponName ) )
|
|
{
|
|
if ( model == optionalWeaponName )
|
|
self detach( model, tag );
|
|
}
|
|
else
|
|
{
|
|
if ( issubstr( tolower( model ), "weapon_" ) )
|
|
self detach( model, tag );
|
|
}
|
|
}
|
|
}
|
|
}
|