cod4-sdk/raw/maps/sniperescape_code.gsc
2008-01-19 00:00:00 +00:00

5903 lines
No EOL
136 KiB
Text
Raw Permalink Blame History

#include maps\_hud_util;
#include maps\_utility;
#include maps\_debug;
#include animscripts\utility;
#include maps\_vehicle;
#include maps\sniperescape;
#include maps\sniperescape_exchange;
#include common_scripts\utility;
#include maps\_anim;
#include maps\sniperescape_wounding;
#include maps\_stealth_logic;
move_in()
{
assertex( isdefined( self.target ), "Move in trigger didn't have target" );
level endon( "movein_trigger" + self.target );
if ( !isdefined( level.move_in_trigger_used[ self.target ] ) )
{
level.move_in_trigger_used[ self.target ] = true;
ai = spawn_guys_from_targetname( self.target );
array_thread( ai, ::stay_put );
array_thread( ai, ::set_ignoreall, true );
level.move_in_trigger_used[ self.target ] = ai;
}
self waittill( "trigger" );
ai = level.move_in_trigger_used[ self.target ];
for ( i = 0; i < ai.size; i++ )
{
if ( !isalive( ai[ i ] ) )
continue;
if ( ai[ i ] isdog() )
ai[ i ] delete();
}
ai = remove_dead_from_array( ai );
array_thread( ai, ::set_ignoreall, false );
array_thread( ai, ::ai_move_in );
self notify( "movein_trigger" + self.target );
}
spawn_guys_from_targetname( targetname )
{
guys = [];
spawners = getentarray( targetname, "targetname" );
for ( i = 0; i < spawners.size; i++ )
{
spawner = spawners[ i ];
spawner.count = 1;
guy = spawner spawn_ai();
spawn_failed( guy );
if ( isalive( guy ) )
{
guys[ guys.size ] = guy;
}
if ( 1 )
continue;
assertEx( isalive( guy ), "Guy from spawner with targetname " + targetname + " at origin " + spawner.origin + " failed to spawn" );
guys[ guys.size ] = guy;
}
return guys;
}
chase_chopper_guys_land()
{
self endon( "death" );
self waittill( "jumpedout" );
if ( flag( "enter_burnt" ) )
{
// player is already in the apartment
nodes = getnodearray( "park_delete_node", "targetname" );
thread fall_back_and_delete( nodes );
return;
}
// player went back outside so the chase begins anew
thread ai_move_in();
}
chopper_guys_land()
{
self endon( "death" );
self waittill( "jumpedout" );
if ( flag( "player_defends_heat_area" ) )
{
self delete();
return;
}
thread ai_move_in();
}
not_move_in_guy()
{
if ( isdefined( self.dontmovein ) )
return true;
if ( !isdefined( self.script_noteworthy ) )
return false;
return self.script_noteworthy == "apartment_hunter";
}
ai_move_in()
{
// guy could be dead because we did a getent not a getai
if ( !isalive( self ) )
return;
if ( not_move_in_guy() )
return;
self endon( "death" );
self endon( "stop_moving_in" );
self notify( "stop_going_to_node" );
if ( isdefined( self.target ) )
self maps\_spawner::go_to_node();
thread reacquire_player_pos();
}
stop_moving_in()
{
self.dontmovein = true;
self notify( "stop_moving_in" );
}
reacquire_player_pos()
{
// so guys that get threaded to move in kill their old move in thread
self notify( "stop_moving_in" );
self endon( "stop_moving_in" );
self endon( "death" );
for ( ;; )
{
self setgoalpos( level.player.origin );
self.goalradius = 1500;
wait( 5 );
}
}
stay_put()
{
self setgoalpos( self.origin );
self.goalradius = 64;
}
debounce_think()
{
// assertex( isdefined( self.script_linkto ), "Trigger at " + self.origin + " had no script_linkto" );
if ( !isdefined( self.script_linkto ) )
return;
links = strtok( self.script_linkto, " " );
assertex( links.size > 0, "Trigger at " + self.origin + " had no script_linktos" );
array_levelthread( links, ::add_trigger_to_debounce_list, self );
self waittill( "trigger" );
// only delete triggers on the first touch because its redundant to do it mulitple times.
array_levelthread( links, ::delete_trigger_with_linkname );
array_levelthread( links, ::turn_off_triggers_from_links, 3 );
for ( ;; )
{
self waittill( "trigger" );
array_levelthread( links, ::turn_off_triggers_from_links, 3 );
wait( 1 );
}
}
turn_off_triggers_from_links( link, timer )
{
array_thread( level.debounce_triggers[ link ], ::turn_off_trigger_for_time, timer );
}
turn_off_trigger_for_time( timer )
{
self notify( "new_debouce" );
self endon( "new_debouce" );
self endon( "death" );
self trigger_off();
wait( timer );
self trigger_on();
}
delete_trigger_with_linkname( link )
{
trigger = getent( link, "script_linkname" );
if ( !isdefined( trigger ) )
return;
// debounce triggers arent required to have a script_linkto
if ( isdefined( trigger.script_linkto ) )
{
links = strtok( trigger.script_linkto, " " );
array_levelthread( links, ::remove_trigger_from_debounce_lists, trigger );
trigger trigger_off();
}
}
add_trigger_to_debounce_list( link, trigger )
{
if ( !isdefined( level.debounce_triggers[ link ] ) )
level.debounce_triggers[ link ] = [];
level.debounce_triggers[ link ][ level.debounce_triggers[ link ].size ] = trigger;
}
remove_trigger_from_debounce_lists( link, trigger )
{
// use getarraykeys because we set indicies of the array to undefined
keys = getarraykeys( level.debounce_triggers[ link ] );
for ( i = 0; i < keys.size; i++ )
{
key = keys[ i ];
if ( level.debounce_triggers[ link ][ key ] != trigger )
continue;
level.debounce_triggers[ link ][ key ] = undefined;
return;
}
}
enemy_override()
{
self.accuracy = 0.2;
start_min_dist = self.engagemindist;
start_min_falloff = self.engageminfalloffdist;
start_max_dist = self.engagemaxdist;
start_max_falloff = self.engagemaxfalloffdist;
// start farther out then move in
if ( isdefined( level.engagement_dist_func[ self.classname ] ) )
{
[[ level.engagement_dist_func[ self.classname ] ]]();
}
else
{
return;
}
self endon( "death" );
// got an enemy yet?
self waittill( "enemy" );
for ( ;; )
{
wait( randomfloat( 5, 8 ) );
if ( !isdefined( self.node ) )
continue;
if ( !isdefined( self.enemy ) )
continue;
if ( distance( self.origin, self.node.origin ) > 128 )
continue;
new_min_dist = self.engagemindist - 150;
new_min_falloff = self.engageminfalloffdist - 150;
new_max_dist = self.engagemaxdist - 150;
new_max_falloff = self.engagemaxfalloffdist - 150;
if ( new_min_dist < start_min_dist )
new_min_dist = start_min_dist;
if ( new_min_falloff < start_min_falloff )
new_min_falloff = start_min_falloff;
if ( new_max_dist < start_max_dist )
new_max_dist = start_max_dist;
if ( new_max_falloff < start_max_falloff )
new_max_falloff = start_max_falloff;
self setengagementmindist( new_min_dist, new_min_falloff );
self setengagementmaxdist( new_max_dist, new_max_falloff );
wait( 12 );
}
}
engagement_shotgun()
{
self setEngagementMinDist( 900, 700 );
self setEngagementMaxDist( 1000, 1200 );
}
engagement_rifle()
{
self setEngagementMinDist( 1200, 1000 );
self setEngagementMaxDist( 1400, 2000 );
}
engagement_sniper()
{
self setEngagementMinDist( 1600, 1200 );
self setEngagementMaxDist( 1800, 2000 );
}
engagement_smg()
{
self setEngagementMinDist( 900, 700 );
self setEngagementMaxDist( 1000, 1200 );
}
engagement_gun()
{
self setEngagementMinDist( 1600, 1200 );
self setEngagementMaxDist( 1800, 2000 );
}
group1_enemies_think( ent )
{
ent.count++ ;
self waittill( "death" );
ent.count -- ;
if ( ent.count <= 1 )
{
activate_trigger_with_noteworthy( "group2_movein" );
}
}
increment_count_and_spawn()
{
self.count = 1;
self spawn_ai();
}
heat_spawners_attack( spawners, start_flag, stop_flag )
{
if ( !isdefined( level.flag[ start_flag ] ) )
{
flag_init( start_flag );
}
if ( !isdefined( level.flag[ stop_flag ] ) )
{
flag_init( stop_flag );
}
array_thread( spawners, ::add_spawn_function, ::chase_friendlies );
max_dogs = 1;
if ( level.gameskill > 1 )
max_dogs = 2;
// spawn guys if the enemy count gets too low and the right flags are set
for ( ;; )
{
flag_waitopen( stop_flag );
count = getaiarray( "axis" ).size;
if ( count > 14 )
{
// random wait to vary which spawners are used
wait( randomfloatrange( 1, 2 ) );
continue;
}
flag_wait( start_flag );
if ( flag( stop_flag ) )
continue;
// vary up the guys that actually spawn
new_spawners = array_randomize( spawners );
spawn_limited_number_from_spawners( new_spawners, new_spawners, 3, max_dogs );
/*
total_dogs = getaiSpeciesArray( "axis", "dog" ).size;
for ( i = 0; i < new_spawners.size * 0.75; i++ )
{
spawners[ i ] thread increment_count_and_spawn();
}
*/
// if the spawners fail, then at least we can tell why instead of having an infinite loop
wait( 0.05 );
}
}
leave_one_think()
{
// delete all but one of the targets
targs = getentarray( self.target, "targetname" );
self waittill( "trigger" );
selected = random( targs );
for ( i = 0; i < targs.size; i++ )
{
if ( targs[ i ] == selected )
continue;
targs[ i ] delete();
}
}
objective_position_update( num )
{
level endon( "stop_updating_objective" );
for ( ;; )
{
objective_position( num, self.origin );
wait( 0.05 );
}
}
add_engagement_func( msg, func )
{
level.engagement_dist_func[ msg ] = func;
}
enemy_accuracy_assignment()
{
level.last_callout_direction = "";
level.next_enemy_call_out = 0;
level endon( "stop_adjusting_enemy_accuracy" );
level.callout_near_dist = 250;
for ( ;; )
{
wait( 0.05 );
ai = getaiarray( "axis" );
dot_ai = [];
// close guys get high accuracy
for ( i = 0; i < ai.size; i++ )
{
if ( distance( level.player.origin, ai[ i ].origin ) < 500 )
{
// even the accurate guys get close accuracy
ai[ i ].baseaccuracy = 1;
continue;
}
dot_ai[ dot_ai.size ] = ai[ i ];
}
player_angles = level.player GetPlayerAngles();
player_forward = anglesToForward( player_angles );
if ( !dot_ai.size )
{
continue;
}
ai = dot_ai;
// farther guys can't hit unless they're the guy you're looking at
// put them into either the get accuracy or dont get accuracy array
GET_ACCURACY = true;
LOSE_ACCURACY = false;
guys = [];
guys[ GET_ACCURACY ] = [];
guys[ LOSE_ACCURACY ] = [];
high_accuracy_guys = [];
lowest_dot = 1;
lowest_dot_guy = undefined;
for ( i = 0; i < ai.size; i++ )
{
guy = ai[ i ];
normal = vectorNormalize( guy.origin - level.player.origin );
dot = vectorDot( player_forward, normal );
// print3d( guy.origin + ( 0, 0, 64 ), dot + " " + guy.finalaccuracy, ( 1, 1, 0.3 ), 1 );
guy.dot = dot;
get_accuracy_result = dot > 0.8;
guys[ get_accuracy_result ][ guys[ get_accuracy_result ].size ] = guy;
if ( dot < lowest_dot )
{
lowest_dot = dot;
lowest_dot_guy = guy;
}
}
for ( i = 0; i < guys[ GET_ACCURACY ].size; i++ )
{
// guys you're looking at get a little accuracy
guys[ GET_ACCURACY ][ i ].baseAccuracy = 0.7;
}
for ( i = 0; i < guys[ LOSE_ACCURACY ].size; i++ )
{
guys[ LOSE_ACCURACY ][ i ].baseAccuracy = 0.2;
guys[ LOSE_ACCURACY ][ i ].threatbias = 0;
}
if ( isdefined( lowest_dot_guy ) )
{
// lowest_dot_guy.threatbias = 10000;
}
// disabling enemy call outs for this area
// level notify( "price_sees_enemy" );
// thread new_enemy_callout( ai );
// angles = vectorToAngles( target_origin - other.origin );
// forward = anglesToForward( angles );
// draw_arrow( level.player.origin, level.player.origin + vectorscale( forward, 150 ), ( 1, 0.5, 0 ) );
// draw_arrow( level.player.origin, level.player.origin + vectorscale( player_forward, 150 ), ( 0, 0.5, 1 ) );
}
}
ai_is_near_teammates( dist )
{
ai = getaiarray( self.team );
for ( i = 0; i < ai.size; i++ )
{
if ( ai[ i ] == self )
continue;
if ( distance( self.origin, ai[ i ].origin ) <= dist )
return true;
}
return false;
}
new_enemy_callout( ai )
{
if ( !flag( "price_calls_out_enemy_location" ) )
return;
if ( gettime() < level.next_enemy_call_out )
return;
if ( !isalive( level.price ) )
return;
near_dist = level.callout_near_dist;
// first try to find a guy outside the fov
for ( i = 0; i < ai.size; i++ )
{
guy = ai[ i ];
if ( !( guy cansee( level.player ) ) )
continue;
if ( guy.dot >= 0.2 )
continue;
if ( !( guy ai_is_near_teammates( near_dist ) ) )
continue;
price_calls_out_guy( guy );
return;
}
// ok just call out whoever then
for ( i = 0; i < ai.size; i++ )
{
guy = ai[ i ];
if ( !( guy cansee( level.player ) ) )
continue;
if ( !( guy ai_is_near_teammates( near_dist ) ) )
continue;
guy = ai[ i ];
price_calls_out_guy( guy );
return;
}
}
price_clears_dialogue()
{
// stop any radio sound currently in progress
radio_dialogue_stop();
// clear price's dialogue queue
level.price_dialogue_master delete();
create_price_dialogue_master();
}
create_price_dialogue_master()
{
level.price_dialogue_master = spawn( "script_origin", (0,0,0) );
level.price_dialogue_master.last_dialogue_line = -5000;
}
price_line( msg )
{
if ( isdefined( level.scr_sound[ "price" ][ msg ] ) )
{
level.price_dialogue_master function_stack( ::play_sound_on_price, level.scr_sound[ "price" ][ msg ] );
}
else
{
level.price_dialogue_master function_stack( ::play_sound_on_player, msg );
}
}
play_sound_on_price( alias )
{
wait_for_buffer_time_to_pass( self.last_dialogue_line, 1 );
if ( !isdefined( self ) )
return;
if ( isalive( level.price ) )
{
self linkto( level.price, "tag_eye", (0,0,0), (0,0,0) );
}
else
{
self linkto( level.player, "", (0,0,60), (0,0,0) );
}
play_sound_on_tag( alias, "", true );
if ( !isdefined( self ) )
return;
self.last_dialogue_line = gettime();
}
play_sound_on_player( alias )
{
wait_for_buffer_time_to_pass( self.last_dialogue_line, 1 );
if ( !isdefined( self ) )
return;
radio_dialogue( alias );
if ( !isdefined( self ) )
return;
self.last_dialogue_line = gettime();
}
price_is_talking()
{
if ( !isdefined( level.price_dialogue_master ) )
return false;
if ( !isdefined( level.price_dialogue_master.function_stack ) )
return false;
return level.price_dialogue_master.function_stack.size > 0;
}
price_calls_out_guy( guy )
{
if ( !flag( "price_cuts_to_woods" ) )
return;
triggers = getentarray( "incoming_trigger", "targetname" );
enemy_location = "enemies";
for ( i = 0; i < triggers.size; i++ )
{
if ( guy istouching( triggers[ i ] ) )
{
enemy_location = triggers[ i ].script_area;
break;
}
}
direction = animscripts\battlechatter::getDirectionCompass( level.player.origin, guy.origin );
if ( direction == level.last_callout_direction )
return;
level.last_callout_direction = direction;
level.next_enemy_call_out = gettime() + randomfloatrange( 4500, 6500 );
// calls out enemy position
price_line( enemy_location + "_" + direction );
}
player_hit_debug()
{
level.player endon( "death" );
for ( ;; )
{
level.player waittill( "damage", amount, attacker, three, four, five, six, seven );
if ( !isdefined( attacker ) )
continue;
/#
println( "Attacked by " + attacker getentnum() + " at distance " + distance( level.player.origin, attacker.origin ) + " with base accuracy " + attacker.baseaccuracy + " and final accuracy " + attacker.finalaccuracy );
#/
}
}
delete_living()
{
if ( isalive( self ) )
self delete();
}
heli_attacks_start()
{
heli = spawn_vehicle_from_targetname_and_drive( "heli_attacks_start" );
heli helipath( heli.target, 70, 70 );
}
heli_trigger()
{
helis = [];
if ( isdefined( self.target ) )
{
self waittill( "trigger" );
heli = spawn_vehicle_from_targetname_and_drive( self.target );
helis[ helis.size ] = heli;
}
else
{
assertEx( isdefined( self.script_vehiclespawngroup ), "heli_trigger had no target or script_vehiclespawngroup" );
level waittill( "vehiclegroup spawned" + self.script_vehiclespawngroup, spawnedVehicles );
helis = spawnedVehicles;
}
for ( i = 0; i < helis.size; i++ )
{
heli = helis[ i ];
heli helipath( heli.target, 30, 30 );
}
}
block_path()
{
// makes a blocker appear and block the path, then reconnect the path and disappear.
// this lets you force an AI to pause before going into an area.
assertex( isdefined( self.target ), "block_path at " + self.origin + " had no target" );
blocker = getent( self.target, "targetname" );
assertex( isdefined( blocker ), "block_path at " + self.origin + " had no target" );
blocker connectpaths();
blocker notsolid();
self waittill( "trigger" );
blocker solid();
blocker disconnectpaths();
timer = 0.25;
if ( isdefined( self.script_delay ) )
{
timer = self.script_delay;
}
wait( timer );
blocker connectpaths();
blocker delete();
}
get_patrol_anims()
{
patrol_anims = [];
patrol_anims[ 1 ] = "patrol_look_up_once";
patrol_anims[ 2 ] = "patrol_360_once";
patrol_anims[ 3 ] = "patrol_jog_once";
patrol_anims[ 4 ] = "patrol_orders_once";
return patrol_anims;
}
get_patrol_run_anims()
{
patrol_anims = [];
patrol_anims[ 1 ] = "patrol_look_up";
patrol_anims[ 2 ] = "patrol_360";
patrol_anims[ 3 ] = "patrol_jog";
patrol_anims[ 4 ] = "patrol_orders";
return patrol_anims;
}
patrol_guy()
{
self endon( "death" );
patrol_anims = get_patrol_anims();
self.allowdeath = true;
self set_generic_run_anim( "patrol_jog" );
goalpos = getent( self.target, "targetname" );
self add_wait( ::waittill_msg, "death" );
self add_wait( ::waittill_msg, "enemy" );
level add_func( ::flag_set, "wounding_enemy_detected" );
thread do_wait_any();
// self thread stealth_ai();
// start off with a start animation
goalpos anim_generic_reach( self, patrol_anims[ self.script_index ] );
if ( !isdefined( self.enemy ) )
{
self anim_generic_custom_animmode( self, "gravity", patrol_anims[ self.script_index ] );
self.disableArrivals = true;
if ( !isdefined( self.enemy ) )
{
targetent = getent( goalpos.target, "targetname" );
self thread maps\_spawner::go_to_origin( targetent );
}
}
while ( !isdefined( self.enemy ) )
{
wait( 0.05 );
}
self.disableArrivals = false;
delete_wounding_sight_blocker();
animscripts\init::set_anim_playback_rate();
self clear_run_anim();
self.walkdist = 16;
self.goalradius = 350;
if ( isdefined( self.script_linkname ) && self.script_linkname == "house_enter_guy" )
{
self setgoalpos( level.price.origin );
self.goalradius = 16;
self.pathenemyfightdist = 80;
self.pathenemylookahead = 80;
return;
}
for ( ;; )
{
if ( isalive( self.enemy ) )
self setgoalpos( self.enemy.origin );
wait( 5 );
}
}
delete_wounding_sight_blocker()
{
if ( flag( "wounding_sight_blocker_deleted" ) )
return;
wounding_sight_blocker = getent( "wounding_sight_blocker", "targetname" );
wounding_sight_blocker connectpaths();
wounding_sight_blocker delete();
flag_set( "wounding_sight_blocker_deleted" );
}
player_touches_wounded_blocker()
{
if ( flag( "wounding_sight_blocker_deleted" ) )
return;
level endon( "wounding_sight_blocker_deleted" );
flag_wait( "player_touches_wounding_clip" );
delete_wounding_sight_blocker();
}
countdown( timer )
{
countdown = 20 * 60;
if ( isdefined( timer ) )
countdown = timer * 60;
level.evac_fail_time = gettime() + countdown * 1000;
thread set_min_time_remaining( 10 );
hudelem = maps\_hud_util::get_countdown_hud();
hudelem SetPulseFX( 30, 1200000, 700 );//something, decay start, decay duration
hudelem.label = &"SNIPERESCAPE_TIME_REMAINING";// + minutes + ":" + seconds
hudelem settenthstimer( countdown );
if ( !flag( "player_enters_fairgrounds" ) )
{
flag_wait_or_timeout( "player_enters_fairgrounds", countdown );
if ( !flag( "player_enters_fairgrounds" ) )
{
setdvar( "ui_deadquote", &"SNIPERESCAPE_FAILED_TO_EVAC" ); //"You failed to reach the evac point in time." );
maps\_utility::missionFailedWrapper();
return;
}
}
hudelem destroy();
// countdown = 4 * 60;
// hudelem settenthstimer( countdown );
}
defend_heat_area_until_enemies_leave()
{
level endon( "heat_area_cleared" );
price_death_org = getent( "price_death_org", "targetname" ).origin;
flee_node = getnode( "enemy_flee_node", "targetname" );
fight_distance = 1250;
for ( ;; )
{
flag_set( "player_defends_heat_area" );
thread defend_heat_area_until_player_goes_back( price_death_org, flee_node, fight_distance );
// wait for the player to run back into the main heat area
flag_waitopen( "stop_heat_spawners" );
flag_clear( "player_defends_heat_area" );
level notify( "player_goes_back_to_heat_area" );
ai = getaiSpeciesArray( "axis", "all" );
array_thread( ai, ::reacquire_player_pos );
// wait for player to run back into the defend area
wait_for_targetname_trigger( "heat_enemies_back_off" );
}
}
defend_heat_area_until_player_goes_back( price_death_org, flee_node, fight_distance )
{
level endon( "heat_area_cleared" );
level.price endon( "death" );
for ( ;; )
{
ai = getaiSpeciesArray( "axis", "all" );
ai = get_array_of_closest( price_death_org, ai );
max_fighters = 5;
if ( ai.size < max_fighters )
max_fighters = ai.size;
// send all but the 5 closest that are within fight_distance fleeing
for ( i = 0; i < max_fighters; i++ )
{
ai[ i ] delaythread( i * 0.25, ::flee_heat_area, flee_node );
// if ( distance( ai[ i ].origin, price_death_org ) > fight_distance )
// {
// ai[ i ] thread flee_heat_area( flee_node );
// }
}
for ( i = max_fighters; i < ai.size; i++ )
{
ai[ i ] thread flee_heat_area( flee_node );
}
/*
ai = get_outside_range( price_death_org.origin, ai, fight_distance );
array_thread( ai, ::flee_heat_area, flee_node );
for ( i = 5; i < ai.size; i++ )
{
// make only 5 of the
ai[ i ] thread flee_heat_area( flee_node );
}
*/
wait_until_the_heat_defend_area_is_clear( price_death_org, fight_distance );
}
}
wait_until_the_heat_defend_area_is_clear( price_death_org, fight_distance )
{
if ( !isalive( level.price ) )
return;
level.price endon( "death" );
for ( ;; )
{
wait( 1 );
if ( distance( level.price.origin, price_death_org ) > 200 )
continue;
ai = getaiSpeciesArray( "axis", "all" );
guy = get_closest_living( price_death_org, ai );
if ( !isalive( guy ) )
{
flag_set( "heat_area_cleared" );
return;
}
if ( distance( guy.origin, price_death_org ) > fight_distance )
{
flag_set( "heat_area_cleared" );
flee_node = getnode( "enemy_flee_node", "targetname" );
array_thread( ai, ::flee_heat_area, flee_node );
return;
}
}
}
flee_heat_area( flee_node )
{
level endon( "player_goes_back_to_heat_area" );
self notify( "stop_moving_in" );
self notify( "stop_going_to_node" );
self setgoalnode( flee_node );
self.goalradius = 64;
self endon( "death" );
self waittill( "goal" );
if ( distance( self.origin, flee_node.origin ) <= 70 )
self delete();
}
kill_shielded_price()
{
level notify( "stop_updating_objective" );
level.price stop_magic_bullet_shield();
price_dies();
}
price_dies()
{
if ( isalive( level.price ) )
level.price dodamage( level.price.health + 150, ( 0, 0, 0 ) );
setdvar( "ui_deadquote", &"SNIPERESCAPE_CPT_MACMILLAN_DIED" );
maps\_utility::missionFailedWrapper();
}
price_wounding_kill_trigger()
{
level endon( "price_is_safe_after_wounding" );
/#
flag_assert( "price_is_safe_after_wounding" );
#/
flag_wait( "player_leaves_price_wounding" );
kill_shielded_price();
}
heli_shoots_rockets_at_ent( target )
{
attractor = missile_createAttractorEnt( target, 100000, 60000 );
// wait( 2 );
self maps\_helicopter_globals::fire_missile( "mi28_seeker", 3, target, .75 );
wait( 5 );
missile_deleteAttractor( attractor );
/*
self setVehWeapon( "cobra_seeker" );
offset = ( 0, 0, 0 );
self fireWeapon( "tag_store_L_2_a", target, offset );// tag_light_L_wing
wait( 0.2 );
self fireWeapon( "tag_store_L_2_b", target, offset );// tag_light_L_wing
wait( 0.2 );
self fireWeapon( "tag_store_L_2_c", target, offset );// tag_light_L_wing
*/
}
kills_enemies_then_wounds_price_then_leaves()
{
level endon( "price_was_hit_by_heli" );
level.price thread price_heli_hit_detection();
kill_all_visible_enemies();
flag_set( "price_heli_moves_on" );
self setturrettargetent( level.price );
// heli startfiring();
heli_fires();
// wait_for_script_noteworthy_trigger( "price_exits_apartment" );
// wait( 2 );
// flag_set( "heli_attacks_price" );
}
price_heli_hit_detection()
{
for ( ;; )
{
level.price waittill( "damage", amt, attacker );
if ( isdefined( attacker ) && attacker == level.price_heli )
break;
}
flag_set( "price_was_hit_by_heli" );
}
can_see_from_array( array )
{
for ( i = 0; i < array.size; i++ )
{
if ( bullettracepassed( self.origin, array[ i ].origin + ( 0, 0, 64 ), false, self ) )
return array[ i ];
}
return undefined;
}
remove_drivers_from_array( ai )
{
array = [];
for ( i = 0; i < ai.size; i++ )
{
if ( !isdefined( ai[ i ].drivingVehicle ) )
array[ array.size ] = ai[ i ];
}
return array;
}
kill_all_enemies()
{
ai = getaiarray( "axis" );
array_thread( ai, ::die_soon );
}
kill_all_visible_enemies()
{
for ( ;; )
{
ai = getaiarray( "axis" );
ai = remove_drivers_from_array( ai );
guy = can_see_from_array( ai );
if ( !isalive( guy ) )
return;
guy thread die_soon();
while ( isalive( guy ) )
{
self setturrettargetent( guy, randomvector( 15 ) + ( 0, 0, 16 ) );
self fireweapon();
wait( 0.15 );
}
}
}
kill_all_visible_enemies_forever()
{
self endon( "stop_killing_enemies" );
self endon( "death" );
for ( ;; )
{
kill_all_visible_enemies();
wait( 1 );
}
}
die_soon()
{
self endon( "death" );
wait( randomfloatrange( 0.5, 2.0 ) );
self dodamage( self.health + 150, ( 0, 0, 0 ) );
}
array_remove_without_model( array, model )
{
newarray = [];
for ( i = 0; i < array.size; i++ )
{
if ( array[ i ].model == model )
newarray[ newarray.size ] = array[ i ];
}
return newarray;
}
price_flees_grenades()
{
if ( flag( "fairbattle_detected" ) )
return;
grenades = getentarray( "grenade", "classname" );
grenades = array_remove_without_model( grenades, "projectile_m67fraggrenade" );
if ( !grenades.size )
return;
grenade = getClosest( level.price.origin, grenades );
grenade_dist = 450;
if ( distance( grenade.origin, level.price.origin ) > grenade_dist )
return;
old_org = ( 0, 0, 0 );
// wait for the grenade to come to rest
for ( ;; )
{
old_org = grenade.origin;
wait( 0.05 );
if ( !isdefined( grenade ) )
return;
if ( distance( grenade.origin, level.price.origin ) > grenade_dist )
return;
if ( grenade.origin == old_org )
break;
old_org = grenade.origin;
}
level.price notify( "stop_loop" );
didanim = false;
for ( ;; )
{
if ( !isdefined( grenade ) )
break;
forward = anglestoforward( level.price.angles );
normal = vectorNormalize( grenade.origin - level.price.origin );
dot = vectorDot( forward, normal );
if ( dot > 0.2 )
break;
if ( level.price should_turn_right( grenade.origin ) )
thread price_turns_right(); // needs to be threaded for the wait
else
thread price_turns_left(); // needs to be threaded for the wait
wait( 1 );
didanim = true;
}
if ( isdefined( grenade ) )
{
// level.price anim_single_solo( level.price, "wounded_crawl_start" );
for ( ;; )
{
if ( !isdefined( grenade ) )
break;
if ( distance( grenade.origin, level.price.origin ) > grenade_dist )
break;
didanim = true;
level.price anim_custom_animmode_solo( level.price, "gravity", "wounded_crawl" );
insure_crawler_is_above_ground();
}
// level.price anim_single_solo( level.price, "wounded_crawl_end" );
}
assertex( didanim, "Had to have done an anim by now!" );
level.price thread anim_loop_solo( level.price, "wounded_idle" );
}
price_teleports_to_player()
{
ent = spawn( "script_origin", level.price.origin );
level.price linkto( ent );
ent moveto( level.player.origin, 1 );
wait( 1 );
ent delete();
if ( 1 ) return;
for ( ;; )
{
timer = 10 * 20;
ent movez( 200, timer );
for ( i = 0; i < timer; i++ )
{
if ( physicstrace( level.price.origin + (0,0,2), level.price.origin + (0,0,-10 ) ) != level.price.origin + (0,0,-10 ) )
{
ent delete();
return;
}
wait( 0.05 );
}
}
}
underground()
{
return level.price.origin[ 2 ] < level.player.origin[ 2 ] - 1500;
// return physicstrace( level.price.origin + (0,0,20), level.price.origin + (0,0,-20 ) ) == level.price.origin + (0,0,-20 );
}
price_teleports_to_spot( org )
{
level.price thread anim_loop_solo( level.price, "wounded_idle" );
price_teleports_to_org( org );
level.price notify( "stop_loop" );
}
price_teleports_to_org( org )
{
ent = spawn( "script_origin", level.price.origin );
level.price linkto( ent );
ent moveto( org + ( 0, 0, 2 ), 2 );
wait( 2 );
ent delete();
}
insure_crawler_is_above_ground()
{
// should teleport?
if ( !underground() )
return;
level.price thread anim_loop_solo( level.price, "wounded_idle" );
price_teleports_to_player();
level.price notify( "stop_loop" );
waittillframeend; // for the loop end
}
price_picks_target()
{
if ( flag( "fair_hold_fire" ) )
return false;
if ( isdefined( level.price.targetorg ) && isalive( level.price_target_guy ) )
{
if ( level.price_target_time > gettime() + level.price_sticky_target_time )
{
return true;
}
}
level.callout_near_dist = 50000;
// in case we're using a start point
flag_set( "price_cuts_to_woods" );
price_flees_grenades();
/*
// put in better indexed array so we don't have to do a bunch of ifs later
ai_array = [];
for ( i = 0; i < ai.size; i++ )
{
ai_array[ ai[ i ].ai_number ] = ai[ i ];
}
*/
price_forward = anglesToForward( ( 0, level.price.angles[ 1 ], 0 ) );
// ai = get_not_in_pain( ai );
ai = getaiSpeciesArray( "axis", "all" );
array = get_array_within_fov( level.price.origin, price_forward, ai, 0.707 );
ai = array[ true ];
outside_fov_ai = array[ false ];
ai = level.price get_cantrace_array( ai );
if ( !ai.size )
{
// cant see anybody that is within our fov?
if ( outside_fov_ai.size > 0 )
{
// are there guys we can see that are outside our fov? then turn
thread new_enemy_callout( outside_fov_ai );
guy = outside_fov_ai[ 0 ];// the guy with the highest dot
level.price notify( "stop_loop" );
price_turns_towards_guy( guy );
level.price thread anim_loop_solo( level.price, "wounded_idle", undefined, "stop_loop" );
}
return false;
}
if ( outside_fov_ai.size > 0 )
{
thread new_enemy_callout( outside_fov_ai );
}
if ( !ai.size )
{
// price continues to aim at guys that are currently not in line of sight
return false;
}
guy = getClosest( level.price.origin, ai );
if ( flag( "fairbattle_high_intensity" ) && distance( level.price.origin, guy.origin ) > 650 )
{
// farthest guy so he doesn't trim the front line and make it too easy
guy = getFarthest( level.price.origin, ai );
}
/*
ai_array[ guy.ai_number ] = undefined;
keys = getarraykeys( ai_array );
for ( i = 0; i < keys.size; i++ )
{
ai_array[ keys[ i ] ].ignoreme = true;
}
guy.ignoreme = false;
*/
thread price_targets_guy( guy );
return true;
}
price_targets_guy( guy )
{
if ( isdefined( level.price.targetorg ) )
level.price.targetorg delete();
ent = spawn( "script_origin", ( 0, 0, 0 ) );
ent linkto( guy, "TAG_EYE", ( 0, 0, 0 ), ( 0, 0, 0 ) );
level.price_target_guy = guy;
level.price_target_time = gettime();
level.price.targetorg = ent;
level.price setentitytarget( ent );
ent endon( "death" );
// cleanup on pickup / placement of price
level.price waittill( "death" );
ent delete();
}
price_turns_towards_guy( guy )
{
/*
org = spawn( "script_origin", level.price.origin );
angles = vectortoangles( guy.origin - level.price.origin );
org.angles = ( 0, angles[ 1 ], 0 );
org thread anim_loop_solo( level.price, "wounded_idle", undefined, "stop_loop" );
wait( 0.5 );
org notify( "stop_loop" );
waittillframeend;
org delete();
*/
if ( level.price should_turn_right( guy.origin ) )
{
// turns_right
price_turns_right();
}
else
{
// turns_left
price_turns_left();
}
}
should_turn_right( org )
{
right = anglesToright( ( 0, self.angles[ 1 ], 0 ) );
normal = vectorNormalize( org - self.origin );
return vectorDot( right, normal ) > 0;
}
get_not_in_pain( ai )
{
guys = [];
for ( i = 0; i < ai.size; i++ )
{
if ( ai[ i ] isdog() )
guys[ guys.size ] = ai[ i ];
else
if ( ai[ i ].a.script != "pain" )
guys[ guys.size ] = ai[ i ];
}
return guys;
}
greater_dot( guy, other )
{
return guy.dot > other.dot;
}
lesser_dot( guy, other )
{
return guy.dot < other.dot;
}
insert_in_array( array, guy, compare_func )
{
newarray = [];
inserted = false;
for ( i = 0; i < array.size; i++ )
{
if ( !inserted )
{
if ( [[ compare_func ]]( array[ i ], guy ) )
{
newarray[ newarray.size ] = guy;
inserted = true;
}
}
newarray[ newarray.size ] = array[ i ];
}
if ( !inserted )
{
newarray[ newarray.size ] = guy;
}
return newarray;
}
get_array_within_fov( org, forward, ai, dot_range )
{
guys = [];
guys[ true ] = [];
guys[ false ] = [];
compare_dots[ true ] = ::lesser_dot;
compare_dots[ false ] = ::lesser_dot;
for ( i = 0; i < ai.size; i++ )
{
guy = ai[ i ];
normal = vectorNormalize( guy.origin - org );
dot = vectorDot( forward, normal );
guy.dot = dot;
in_range = dot >= dot_range;
guys[ in_range ] = insert_in_array( guys[ in_range ], guy, compare_dots[ in_range ] );
}
return guys;
}
line_for_time( pos1, pos2, color, timer )
{
timer = timer * 20;
for ( i = 0; i < timer; i++ )
{
line( pos1, pos2, color );
wait( 0.05 );
}
}
get_cantrace_array( ai )
{
guys = [];
eyepos = self geteye();
for ( i = 0; i < ai.size; i++ )
{
if ( !( bullettracepassed( eyepos, ai[ i ] geteye(), false, undefined ) ) )
{
// thread line_for_time( eyepos, ai[ i ] geteye(), ( 1, 0, 0 ), 0.5 );
continue;
}
// thread line_for_time( eyepos, ai[ i ] geteye(), ( 0, 1, 0 ), 0.5 );
guys[ guys.size ] = ai[ i ];
}
return guys;
}
get_canshoot_array( ai )
{
guys = [];
myGunPos = self GetTagOrigin( "tag_flash" );
myEyeOffset = ( self getShootAtPos() - myGunPos );
for ( i = 0; i < ai.size; i++ )
{
if ( !( self canshoot( ai[ i ], myEyeOffset ) ) )
{
// thread line_for_time( eyepos, ai[ i ] geteye(), ( 1, 0, 0 ), 0.5 );
continue;
}
// thread line_for_time( eyepos, ai[ i ] geteye(), ( 0, 1, 0 ), 0.5 );
guys[ guys.size ] = ai[ i ];
}
return guys;
}
get_cansee_array( ai )
{
guys = [];
for ( i = 0; i < ai.size; i++ )
{
if ( !( self cansee( ai[ i ] ) ) )
continue;
guys[ guys.size ] = ai[ i ];
}
return guys;
}
price_moves_to_sniping_position()
{
price_gnoll = getent( "price_gnoll", "targetname" );
org = price_gnoll.origin;
gnoll_target = ( -3039.22, -3567.34, 117.2 );
level.price notify( "stop_loop" );
for ( ;; )
{
forward = anglestoforward( level.price.angles );
normal = vectorNormalize( org - level.price.origin );
dot = vectorDot( forward, normal );
current_dist = distance( level.price.origin, org );
if ( current_dist < 16 )
break;
if ( dot > -0.7 )
{
if ( level.price should_turn_right( org ) )
price_turns_left();
else
price_turns_right();
}
else
{
if ( current_dist > 32 )
{
level.price anim_custom_animmode_solo( level.price, "gravity", "wounded_crawl" );
insure_crawler_is_above_ground();
if ( distance( level.price.origin, org ) >= current_dist - 5 )
{
// didnt make enough progress so teleport there
price_teleports_to_spot( org );
}
}
else
break;
}
}
park_reinforce = getent( "park_reinforce", "targetname" );
price_aims_at( park_reinforce.origin );
for ( ;; )
{
forward = anglestoforward( level.price.angles );
normal = vectorNormalize( park_reinforce.origin - level.price.origin );
dot = vectorDot( forward, normal );
if ( dot < 0.7 )
{
if ( level.price should_turn_right( park_reinforce.origin ) )
price_turns_right();
else
price_turns_left();
}
else
break;
}
forward = anglestoforward( level.price.angles );
normal = vectorNormalize( park_reinforce.origin - level.price.origin );
dot = vectorDot( forward, normal );
// thread line_for_time( park_reinforce.origin, level.price.origin, ( 1, 0, 0.5 ), 3 );
// can't do loop stop loop, which may happen if he's put on the right spot at the right angle
waittillframeend;
level.price thread anim_loop_solo( level.price, "wounded_idle", undefined, "stop_loop" );
flag_clear( "price_moves_to_position" );
}
price_aims_at( org )
{
if ( !isdefined( level.price.targetorg ) )
{
ent = spawn( "script_origin", ( 0, 0, 0 ) );
level.price.targetorg = ent;
}
level.price.targetorg.origin = org;
}
price_turns_right()
{
level.price anim_custom_animmode_solo( level.price, "gravity", "wounded_turn_right" );
// level.price anim_single_solo( level.price, "wounded_turn_right" );
}
price_turns_left()
{
level.price anim_custom_animmode_solo( level.price, "gravity", "wounded_turn_left" );
// level.price anim_single_solo( level.price, "wounded_turn_left" );
}
idle_until_price_has_target()
{
level.price endon( "death" );
level.price notify( "stop_loop" );
// he may be looping from turning during the pick - target phase, so we need to make sure that loop has stopped before we start a new one
waittillframeend;
level.price thread anim_loop_solo( level.price, "wounded_idle", undefined, "stop_loop" );
// price_floats_up_out_of_solid();
for ( ;; )
{
if ( price_picks_target() )
break;
if ( flag( "price_moves_to_position" ) )
{
price_moves_to_sniping_position();
continue;
}
wait( 0.1 );
}
}
should_teleport()
{
org = physicstrace( level.price.origin + ( 0, 0, 2 ), level.price.origin + ( 0, 0, -100 ) );
return org[ 2 ] > level.price.origin[ 2 ] + 60;
}
/*
price_floats_up_out_of_solid()
{
level.price endon( "death" );
level.price endon( "pickup" );
teleported = false;
for ( ;; )
{
if ( !should_teleport() )
break;
teleported = true;
price_teleports();
}
// one more time just to be sure
if ( teleported )
price_teleports();
}
*/
fight_until_price_has_no_target()
{
level.price endon( "death" );
level.price endon( "no_enemies" );
for ( ;; )
{
thread price_fights_enemies();
level.price waittill( "damage", amount, enemy, dir1, dir2, damage_type );
level.price notify( "stop_loop" );
timer = gettime();
if ( isalive( enemy ) && enemy.team == "axis" && damage_type == "MOD_RIFLE_BULLET" )
{
price_fends_off_attacker( enemy );
}
level.price notify( "stop_loop" ); // can endon enemy death above
waittillframeend;
wait_for_buffer_time_to_pass( timer, 0.05 );
level.price thread anim_loop_solo( level.price, "wounded_idle", undefined, "stop_loop" );
}
}
line_to_guy( enemy )
{
level.price endon( "death" );
enemy endon( "death" );
for ( ;; )
{
line( level.price geteye(), enemy geteye(), ( 1, 0, 1 ) );
wait( 0.05 );
}
}
price_fends_off_attacker( enemy )
{
if ( !isalive( enemy ) )
return;
enemy endon( "death" );
// thread line_to_guy( enemy );
for ( ;; )
{
forward = anglestoforward( level.price.angles );
normal = vectorNormalize( enemy.origin - level.price.origin );
dot = vectorDot( forward, normal );
if ( dot < 0.8 )
{
if ( level.price should_turn_right( enemy.origin ) )
thread price_turns_right();
else
thread price_turns_left();
wait( 1.2 );
continue;
}
thread price_targets_guy( enemy );
if ( !level.price.on_target )
{
waittillframeend;
curtime = gettime();
level.price thread anim_loop_solo( level.price, "wounded_idle", undefined, "stop_loop" );
level.price waittill_notify_or_timeout( "on_target", 0.5 );
// need to idle for at least a frame or we'll do 2 animscripteds in one frame
wait_for_buffer_time_to_pass( curtime, 0.05 );
level.price notify( "stop_loop" );
}
if ( level.price.on_target )
{
myGunPos = level.price GetTagOrigin( "tag_flash" );
myEyeOffset = ( level.price getShootAtPos() - myGunPos );
if ( level.price canshoot( level.price.targetorg.origin, myEyeOffset ) )
{
level.price anim_single_solo( level.price, "wounded_fire" );
}
else
{
level.price anim_custom_animmode_solo( level.price, "gravity", "wounded_crawl" );
insure_crawler_is_above_ground();
}
}
}
}
price_fights_enemies()
{
level.price endon( "death" );
level.price endon( "damage" );
level.price endon( "pickup" );
level.price_next_shoot_time = 0;
for ( ;; )
{
if ( gettime() < level.price_next_shoot_time )
{
wait( ( level.price_next_shoot_time - gettime() ) * 0.001 );
}
// keep shooting as long as we can acquire a target
level.price waittill_notify_or_timeout( "on_target", 2 );
if ( !level.price.fastfire )
{
timer = distance( level.price.targetorg.origin, level.price.origin );
timer -= 400;
timer *= 0.004;
if ( timer < 0.15 )
timer = 0.15;
wait( randomfloatrange( timer * 0.75, timer ) );
}
if ( gettime() < level.price.first_shot_time )
{
// wait until we're allowed to shoot
wait( ( level.price.first_shot_time - gettime() ) * 0.001 );
}
if ( level.price.on_target )
{
myGunPos = level.price GetTagOrigin( "tag_flash" );
myEyeOffset = ( level.price getShootAtPos() - myGunPos );
if ( level.price canshoot( level.price.targetorg.origin, myEyeOffset ) )
{
// dont hit guys you cant shoot
level.price notify( "stop_loop" );
level.price anim_single_solo( level.price, "wounded_fire" );
level.price thread anim_loop_solo( level.price, "wounded_idle", undefined, "stop_loop" );
}
}
if ( !price_picks_target() )
break;
}
level.price notify( "no_enemies" );
}
area_is_clear( org, debug_lines )
{
steps = 6;
chunks = 360 / steps;
for ( i = 0; i < steps; i++ )
{
angles = ( - 25, i * chunks, 0 );
forward = anglestoforward( angles );
endpos = org + vectorscale( forward, 25 );
pos = PhysicsTrace( org, endpos );
if ( distance( pos, endpos ) > 0.01 )
{
/#
if ( debug_lines )
line( org, endpos, ( 1, 0, 0 ) );
#/
return false;
}
/#
if ( debug_lines )
line( org, endpos, ( 0, 1, 0 ) );
#/
pos = PhysicsTrace( endpos + ( 0, 0, 42 ), endpos );
if ( distance( pos, endpos ) > 0.01 )
{
/#
if ( debug_lines )
{
// line( endpos + ( 0, 0, 42 ), endpos, ( 1, 0, 0 ) );
// print3d( pos, ".", ( 1.0, 0.2, 0 ), 1, 1.5 );
line( pos, endpos, ( 1, 0, 0 ) );
}
#/
return false;
}
/#
if ( debug_lines )
line( endpos + ( 0, 0, 42 ), endpos, ( 0, 1, 0 ) );
#/
}
return true;
}
upwards_normal( normal )
{
range = 0.25;
if ( abs( normal[ 0 ] ) > range )
return false;
if ( abs( normal[ 1 ] ) > range )
return false;
return( normal[ 2 ] >= 1 - range );
}
wait_for_player_to_drop_price( trigger )
{
for ( ;; )
{
wait_for_player_to_drop_price_func( trigger );
return;
}
}
wait_for_player_to_drop_price_func( trigger )
{
trigger endon( "trigger" );
price_gnoll = getent( "price_gnoll", "targetname" );
for ( ;; )
{
debug_lines = false;
/#
debug_lines = getdebugdvar( "debug_drop_price" ) == "on";
#/
trigger.origin = ( 0, 0, -1500 );
eyepos = level.player geteye();
angles = level.player getplayerangles();
pitch = angles[ 0 ] + 15;
if ( pitch > 54 )
pitch = 54;
if ( pitch < 40 )
pitch = 40;
level.pitch = pitch;
angles = ( pitch, angles[ 1 ], 0 );
forward = anglestoforward( angles );
endpos = eyepos + vectorscale( forward, 500 );
trace = bullettrace( eyepos, endpos, true, level.player );
p_trace = physicsTrace( eyepos, endpos );
level.price_trace = p_trace;
if ( p_trace != trace[ "position" ] )
{
/#
if ( debug_lines )
print3d( trace[ "position" ], ".", ( 0.8, 0.6, 0 ), 1, 2 );
#/
wait( 0.05 );
continue;
}
if ( trace[ "position" ][ 2 ] > level.player.origin[ 2 ] + 26 )
{
/#
if ( debug_lines )
print3d( trace[ "position" ], ".", ( 0.5, 0.0, 0.5 ), 1, 2 );
#/
wait( 0.05 );
continue;
}
if ( distance( level.player.origin, p_trace ) > 100 )
{
/#
if ( debug_lines )
print3d( p_trace, ".", ( 1, 0.5, 0 ), 1, 2 );
#/
wait( 0.05 );
continue;
}
if ( !upwards_normal( trace[ "normal" ] ) )
{
/#
if ( debug_lines )
print3d( p_trace, ".", ( 1, 0, 0 ), 1, 2 );
#/
wait( 0.05 );
continue;
}
if ( !area_is_clear( p_trace, debug_lines ) )
{
/#
if ( debug_lines )
print3d( p_trace, ".", ( 1, 1, 0 ), 1, 2 );
#/
wait( 0.05 );
continue;
}
/*
if ( flag( "to_the_pool" ) )
{
if ( distance( level.player.origin, price_gnoll.origin ) > level.price_gnoll_dist )
{
// too far from the place where we put him down
wait( 0.05 );
continue;
}
}
*/
level.price_drop_point = p_trace;
trigger.origin = level.player.origin;
/#
if ( debug_lines )
print3d( trace[ "position" ], ".", ( 0, 1, 0 ), 1, 2 );
#/
wait( 0.05 );
}
}
price_wounded_logic()
{
if ( isdefined( level.price.magic_bullet_shield ) )
level.price stop_magic_bullet_shield();
level.price thread wounded_setup();
for ( ;; )
{
price_defends_his_spot_until_he_is_picked_up();
player_carries_price_until_he_drops_him();
}
}
price_updates_objective_pos()
{
level.price endon( "death" );
if ( !flag( "beacon_ready" ) )
objective_position( getobj( "wounded" ), level.price.origin );
}
price_defends_his_spot_until_he_is_picked_up()
{
thread price_updates_objective_pos();
thread price_dies_if_player_goes_too_far();
thread player_loses_if_price_dies();
// thread price_calls_out_kills();
thread price_decides_if_he_can_be_picked_up();
level.price thread price_aims_at_his_enemy();
level.price endon( "pickup" );
level.price endon( "death" );
price_slides_into_proper_putdown_position();
// if ( !flag( "first_pickup" ) && level.start_point == "wounding" || is_default_start() )
if ( !flag( "first_pickup" ) )
{
node = getnode( "price_wounding_node", "targetname" );
node anim_loop_solo( level.price, "crash_idle" );
}
for ( ;; )
{
idle_until_price_has_target();
fight_until_price_has_no_target();
}
}
price_slides_into_proper_putdown_position()
{
if ( !isdefined( level.price_drop_point ) )
return;
ent = spawn( "script_origin", (0,0,0) );
ent.origin = level.price.origin;
level.price linkto( ent );
level.price thread anim_first_frame_solo( level.price, "wounded_idle_reach" );
ent moveto( level.price_drop_point, 0.5, 0.2, 0.2 );
level.price_drop_point = undefined;
wait( 0.5 );
ent delete();
level.price notify( "stop_first_frame" );
}
price_decides_if_he_can_be_picked_up()
{
level.price endon( "death" );
next_dialogue = 0;
for ( ;; )
{
level.price waittill( "trigger" );
// can't pick up price while you're being mauled
if ( isdefined ( level.player.attacked_by_dog ) )
continue;
if ( flag( "price_wants_apartment_cleared" ) && !flag( "apartment_cleared" ) )
{
if ( gettime() > next_dialogue )
{
next_dialogue = gettime() + 5000;
// Wait. Make sure these rooms are clear first.
thread price_line( "wait_make_sure" );
}
// continue;
}
break;
}
level.player.dogs_dont_instant_kill = true;
level.price notify( "pickup" );
}
price_aims_at_his_enemy()
{
level endon( "price_picked_up" );
level.price endon( "death" );
left = level.price getanim( "wounded_aim_left" );
right = level.price getanim( "wounded_aim_right" );
wounded = level.price getanim( "wounded_base" );
self setanim( wounded, 1, 0, 1 );
level.price.on_target = false;
prevyaw = 0;
/*
for ( ;; )
{
for ( i = 0; i < 1; i += 0.05 )
{
self setAnim( left, i, .05 );
self setAnim( right, 1 - i, .05 );
wait( 0.05 );
}
for ( i = 0; i < 1; i += 0.05 )
{
self setAnim( right, i, .05 );
self setAnim( left, 1 - i, .05 );
wait( 0.05 );
}
}
*/
for ( ;; )
{
// if ( !isalive( self.enemy ) )
if ( !isdefined( level.price.targetorg ) )
{
wait( 0.05 );
continue;
}
// pos = level.player.origin;
pos = level.price.targetorg.origin;
// aimyaw = self getYawToEnemy();
aimyaw = GetYawToSpot( pos );
diff = AngleClamp180( aimyaw - prevyaw );
level.price.on_target = abs( diff ) <= 7;
if ( level.price.on_target )
{
level.price notify( "on_target" );
}
else
{
diff = sign( diff ) * 3;
}
aimyaw = AngleClamp180( prevyaw + diff );
// the animations cover from - 45 to 45 degrees
if ( aimyaw < - 45.0 )
aimyaw = -45.0;
if ( aimyaw > 45.0 )
aimyaw = 45.0;
// level.aimyaw = aimyaw;
weight = aimyaw / 90;
// now the weight is 0 to 1
weight += 0.5;
// level.weight = weight;
self setAnim( left, 1 - weight, 0.05 );
self setAnim( right, weight, 0.05 );
prevyaw = aimyaw;
wait .05;
}
}
price_calls_out_kills()
{
level.price endon( "death" );
level.price endon( "pickup" );
for ( ;; )
{
if ( isalive( level.price.enemy ) )
{
enemy = level.price.enemy;
price_waits_for_enemy_death_or_new_enemy();
price_calls_out_kill_if_he_should( enemy );
}
else
{
level.price waittill( "enemy" );
}
}
}
price_waits_for_enemy_death_or_new_enemy()
{
level.price endon( "enemy" );
level.price.enemy waittill( "death", one, two, three, four );
arg = 23;
}
price_calls_out_kill_if_he_should( enemy )
{
// must've got a new enemy, old one is still alive
if ( isalive( enemy ) )
return;
// he's already talking about something else so skip the kill call out
if ( price_is_talking() )
return;
// dont call out deleted guys
if ( !isdefined( enemy ) )
return;
price_calls_out_a_kill();
wait( 2 );
}
price_calls_out_a_kill()
{
if ( !isalive( level.price ) )
return;
if ( level.last_price_kill + 10000 > gettime() )
return;
if ( randomint( 100 ) > 80 )
return;
lines = [];
// got one
lines[ lines.size ] = "got_one";
// tango down
lines[ lines.size ] = "tango_down";
// he's down
lines[ lines.size ] = "he_is_down";
if ( level.last_price_kill + 20000 > gettime() )
{
// got another one
lines[ lines.size ] = "got_another";
}
// Target neutralized.
lines[ lines.size ] = "target_neutralized";
// got him
lines[ lines.size ] = "got_him";
the_line = random( lines );
if ( isdefined( level.last_price_line ) )
{
for ( ;; )
{
if ( the_line != level.last_price_line )
break;
the_line = random( lines );
}
}
level.last_price_line = the_line;
level.last_price_kill = gettime();
thread price_line( the_line );
}
player_loses_if_price_dies()
{
level.price endon( "pickup" );
level.price waittill( "death" );
price_dies();
}
price_dies_if_player_goes_too_far()
{
if ( flag( "price_can_be_left" ) )
return;
flag_wait( "first_pickup" );
level endon( "price_can_be_left" );
level.price endon( "death" );
level.price endon( "pickup" );
for ( ;; )
{
if ( distance( level.player.origin, level.price.origin ) > 1000 )
{
break;
}
wait( 1 );
}
// Leftenant Price! Don't get too far ahead.
price_line( "dont_go_far" );
for ( ;; )
{
if ( distance( level.player.origin, level.price.origin ) > 1500 )
{
price_dies();
return;
}
wait( 1 );
}
}
draw_player_viewtag()
{
for ( ;; )
{
maps\_debug::drawArrow( level.player.origin, level.player getplayerangles() );
wait( 0.05 );
}
}
drop_to_floor()
{
trace = bullettrace( self.origin + ( 0, 0, 32 ), self.origin, false, undefined );
self.origin = trace[ "position" ];
}
player_picks_up_price()
{
level notify( "price_stops_thinking" );
pickup_scene = "wounded_pickup";
if ( !flag( "first_pickup" ) )
{
// price idles while he waits to be picked up
node = getnode( "price_wounding_node", "targetname" );
flag_set( "first_pickup" );
pickup_scene = "crash_pickup";
level.price setanimtime( level.price getanim( pickup_scene ), 0 ); // so he doesn't finish the anim and start ai behavior
level.player disableweapons();
node = getnode( "price_wounding_node", "targetname" );
// this is the player's rig for the sequence
model = spawn_anim_model( "player_carry" );
model hide();
// put the model in the first frame so the tags are in the right place
node anim_first_frame_solo( model, pickup_scene );
wait( 0.1 );// wait for the models tags to actually get in position
// this smoothly hooks the player up to the animating tag
dist = distance( model gettagorigin( "tag_player" ), level.player.origin );
timer = dist * 0.011;
model lerp_player_view_to_tag( "tag_player", timer, 1.0, 0, 0, 0, 0 );
thread blocking_fence_falls();
// If we run into trouble, you<6F>ll have to find a good spot to put me down so I can cover you.
thread price_line( "find_good_spot" );
node notify( "stop_loop" );
price_pickup_elements = make_array( model, level.price );
node notify( "stop_loop" );
model show();
node anim_single( price_pickup_elements, pickup_scene );
thread price_talks_as_he_is_picked_up();
level.player unlink();
model delete();
if ( getdvar( "no_heli_protection" ) == "" )
level.player setorigin( ( 3577, -8420, 0.125 ) );
return;
}
else
{
thread price_talks_as_he_is_picked_up();
}
org = spawn( "script_origin", ( 0, 0, 0 ) );
org.origin = level.price.origin;
org.angles = level.price.angles;
org drop_to_floor();
level.price notify( "stop_loop" );
// this is the player's rig for the sequence
model = spawn_anim_model( "player_carry" );
model hide();
// price idles while he waits to be picked up
org thread anim_loop_solo( level.price, "pickup_idle", undefined, "stop_idle" );
// put the model in the first frame so the tags are in the right place
org anim_first_frame_solo( model, pickup_scene );
wait( 0.1 );// wait for the models tags to actually get in position
// move the animation up if it would put the player in the ground
tag_player_origin = model getTagOrigin( "tag_player" );
trace = bullettrace( tag_player_origin + ( 0, 0, 32 ), tag_player_origin, false, undefined );
if ( trace[ "fraction" ] < 1 )
{
org.origin += trace[ "position" ] - tag_player_origin;
// change the model's position to the new, not stuck in ground position
model set_start_pos( pickup_scene, org.origin, org.angles );
}
// this smoothly hooks the player up to the animating tag
model lerp_player_view_to_tag_and_hit_geo( "tag_player", 0.4, 1.0, 0, 0, 0, 0 );
original_player_org = level.player.origin;
// move the model arms and price's scene org to compensate for the distance the player is from where he should be
dif = level.player.origin - model gettagorigin( "tag_player" );
model.origin += dif;
org.origin += dif;
// link the player without hit_geo, so he can duck down to pick up price
level.player playerlinkto( model, "tag_player", 0.5, 1.0, 0, 0, 0, 0 );
model show();
org notify( "stop_idle" );
price_pickup_elements = make_array( model, level.price );
// timer = gettime();
org thread anim_single( price_pickup_elements, pickup_scene );
wait( 2.0 );
org notify( pickup_scene );
// println( "result " + ( gettime() - timer ) );
trace = bullettrace( level.player.origin + ( 0, 0, 32 ), level.player.origin, false, undefined );
if ( trace[ "fraction" ] < 1 )
{
model moveto( model.origin + ( trace[ "position" ] - level.player.origin ), 0.1 );
wait( 0.1 );
}
level.player unlink();
org delete();
model delete();
level.player setorigin( original_player_org );
}
player_puts_down_price()
{
level.price notify( "stop_loop" );
org = spawn( "script_origin", ( 0, 0, 0 ) );
// price_spawner.origin = level.price_trace[ "position" ];
// org.origin = level.price_trace;
org.origin = level.player.origin;
org.angles = level.player.angles;
org drop_to_floor();
// this is the player's rig for the sequence
model = spawn_anim_model( "player_carry" );
model hide();
// put the model in the first frame so the tags are in the right place
org anim_first_frame_solo( model, "wounded_putdown" );
wait( 0.1 );// wait for the models tags to actually get in position
// move the animation up if it would put the player in the ground
tag_player_origin = model getTagOrigin( "tag_player" );
trace = bullettrace( tag_player_origin + ( 0, 0, 32 ), tag_player_origin, false, undefined );
if ( trace[ "fraction" ] < 1 )
{
org.origin += trace[ "position" ] - tag_player_origin;
// change the model's position to the new, not stuck in ground position
model set_start_pos( "wounded_putdown", org.origin, org.angles );
}
// this smoothly hooks the player up to the animating tag
model lerp_player_view_to_tag_and_hit_geo( "tag_player", 0.25, 1.0, 0, 0, 0, 0 );
model show();
original_player_org = level.player.origin;
price_spawner = getent( "price_spawner", "targetname" );
price_spawner.animname = "price";
price_spawner set_start_pos( "wounded_putdown", org.origin, org.angles );
price_spawner.count = 1;
level.price = price_spawner stalingradspawn();
spawn_failed( level.price );
level.price.animname = "price";
level.price thread wounded_setup();
price_pickup_elements = [];
price_pickup_elements[ price_pickup_elements.size ] = model;
price_pickup_elements[ price_pickup_elements.size ] = level.price;
thread price_talks_as_he_is_picked_up( true );
// link the player without hit_geo, so he can duck down to put down price
level.player playerlinkto( model, "tag_player", 0.5, 1.0, 0, 0, 0, 0 );
org anim_single( price_pickup_elements, "wounded_putdown" );
/*
trace = bullettrace( level.player.origin + ( 0, 0, 32 ), level.player.origin, false, undefined );
if ( trace[ "fraction" ] < 1 )
{
// push the player up if he's in the ground
model moveto( model.origin + ( trace[ "position" ] - level.player.origin ), 0.1 );
wait( 0.1 );
}
*/
level.player unlink();
org delete();
model delete();
level.player allowCrouch( true );
level.player allowProne( true );
level.player allowsprint( true );
level.player allowjump( true );
level.player setorigin( original_player_org );
if ( flag( "to_the_pool" ) && sufficient_time_remaining() )
{
flag_set( "can_save" );
}
else
{
flag_clear( "can_save" );
}
if ( flag( "enter_burnt" ) && !flag( "to_the_pool" ) )
{
// price doesn't get attacked in the second apartment
level.price.ignoreme = true;
}
flag_clear( "price_picked_up" );
stance_carry_icon_disable();
level notify( "price_dropped" );
thread price_asks_to_be_picked_up_when_its_safe();
}
getHealthyEnemies()
{
ai = getaiSpeciesArray( "axis", "all" );
healthy_enemies = [];
for ( i = 0; i < ai.size; i++ )
{
if ( isdefined( ai[ i ].drivingVehicle ) )
continue;
if ( !ai[ i ].ignoreForFixedNodeSafeCheck )
{
healthy_enemies[ healthy_enemies.size ] = ai[ i ];
break;
}
}
return healthy_enemies;
}
price_asks_to_be_picked_up_when_its_safe()
{
level endon( "price_picked_up" );
level endon( "price_wants_apartment_cleared" );
// wait until there are enemies, otherwise assume the player
// dropped us for a reason
for ( ;; )
{
ai = getHealthyEnemies();
if ( ai.size )
{
break;
}
wait( 1 );
}
wait( 3 );
for ( ;; )
{
ai = getHealthyEnemies();
if ( !ai.size )
{
break;
}
wait( 1 );
}
wait( 2 );
price_asks_to_be_picked_up();
}
price_talks_as_he_is_picked_up( putdown )
{
// Easy does it<69>
// Easy now<6F>
// Careful<75>
if ( randomint( 100 ) > 10 )
{
if ( !isdefined( putdown ) && randomint( 100 ) > 30 )
delaythread( 2.0, ::bonus_price_line, "pickup_breathing" );
return;
}
putdown_line = "put_down_" + ( randomint( 3 ) + 1 );
price_line( putdown_line );
}
bonus_price_line( msg )
{
if ( price_is_talking() )
return;
price_line( msg );
}
price_talks_if_player_takes_damage()
{
level endon( "price_dropped" );
for ( ;; )
{
level.player waittill( "damage" );
// You'd better put me down quick so I can fight back<63>
price_line( "put_me_down_quick" );
wait( 4 );
}
}
price_talks_if_enemies_get_near()
{
level endon( "price_dropped" );
for ( ;; )
{
ai = getaispeciesarray( "axis", "all" );
for ( i = 0; i < ai.size; i++ )
{
guy = ai[ i ];
if ( !isalive( guy ) )
continue;
if ( !isalive( guy.enemy ) )
continue;
if ( guy cansee( level.player ) )
{
price_asks_to_be_put_down();
}
wait( 0.05 );
}
wait( 0.05 );
}
}
price_talks_if_enemies_are_near()
{
level endon( "price_dropped" );
for ( ;; )
{
level waittill( "an_enemy_shot", guy );
if ( !isalive( guy ) )
continue;
if ( guy cansee( level.player ) )
{
price_asks_to_be_put_down();
}
}
}
price_asks_to_be_put_down()
{
if ( isalive( level.price ) )
return;
// Price! Put me down where I can cover you!
// Oi! Sit me down where I can cover your back!
// put_me_down_1, put_me_down_2
// " + randomint( 2 ) + 1
lines = [];
// Tangos moving in! Find a spot where I can cover you and put me down!
lines[ lines.size ] = "new_put_me_down_1" ;
// Enemy troops approaching. Find a spot where I can cover you and put me down.
lines[ lines.size ] = "new_put_me_down_2" ;
// Enemies closing in. Put me in a good spot where I can cover you.
lines[ lines.size ] = "new_put_me_down_3" ;
// Tangos closing fast! Put me in a good spot to cover you!
lines[ lines.size ] = "new_put_me_down_4" ;
if ( !isdefined( level.lastputdownline ) )
level.lastputdownline = 0;
dialogue_line = randomint( lines.size );
if ( dialogue_line == level.lastputdownline )
dialogue_line++;
if ( dialogue_line >= lines.size )
dialogue_line = 0;
level.lastputdownline = dialogue_line;
price_line( lines[ dialogue_line ] );
/*
// old dialogue
if ( cointoss() )
price_line( "put_me_down_1" );
else
price_line( "put_me_down_2" );
*/
wait( 6 );
}
wounded_combat_trigger()
{
self waittill( "trigger" );
targets = getentarray( self.target, "targetname" );
if ( !targets.size )
return;
wait( 1.35 );
// price_asks_to_be_put_down();
price_talks_if_enemies_get_near();
}
player_carries_price_until_he_drops_him()
{
level.price notify( "price_stops_aiming" );
set_objective_pos_to_extraction_point( getobj( "wounded" ) );
level.player SetMoveSpeedScale( 0.85 );
if ( !isalive( level.price ) )
{
// we can get here by price dying
level waittill( "forever and ever" );
}
level.player thread take_weapons();
level.player allowCrouch( false );
level.player allowProne( false );
level.player allowsprint( false );
level.player allowjump( false );
/#
if ( getdvar( "devtest" ) == "1" )
{
// so boring without! hmmmm
level.player allowsprint( true );
level.player allowjump( true );
}
#/
player_picks_up_price();// relative
flag_set( "price_picked_up" );
flag_set( "carry_me_music_resume" );
stance_carry_icon_enable();
if ( sufficient_time_remaining() )
flag_set( "can_save" );
if ( !flag( "enter_burnt" ) && !flag( "to_the_pool" ) )
{
autosave_by_name( "on_the_run" );
}
// poof!
level.price delete();
// thread price_talks_if_player_takes_damage();
// thread price_talks_if_enemies_are_near();
// level.player thread take_away_player_ammo();
// level.player hideviewmodel();
trigger = getent( "price_drop_trigger", "targetname" );
trigger sethintstring( &"SNIPERESCAPE_HOLD_1_TO_PUT_CPT_MACMILLAN" );
wait_for_player_to_drop_price( trigger );
trigger.origin = ( 0, 0, -1500 );
// level.player give_back_player_ammo();
// level.player showviewmodel();
player_puts_down_price();
if ( !isalive( level.price ) )
{
price_dies();
level waittill( "foreverevervever" );
}
level.player give_back_weapons();
level.player SetMoveSpeedScale( 1 );
level.player.dogs_dont_instant_kill = undefined;
}
give_back_weapons()
{
self enableweapons();
if ( 1 ) return;
level.player notify( "stop_taking_away_ammo" );
weapons = self.heldweapons;
for ( i = 0; i < weapons.size; i++ )
{
weapon = weapons[ i ];
self giveweapon( weapon );
self SetWeaponAmmoClip( weapon, self.stored_ammo[ weapon ] );
}
}
take_weapons()
{
self disableweapons();
if ( 1 ) return;
self endon( "stop_taking_away_ammo" );
self.heldweapons = self getweaponslist();
self.stored_ammo = [];
for ( i = 0; i < self.heldweapons.size; i++ )
{
weapon = self.heldweapons[ i ];
self.stored_ammo[ weapon ] = self getWeaponAmmoClip( weapon );
}
for ( ;; )
{
self takeallweapons();
wait( 0.05 );
}
}
take_away_player_ammo()
{
self endon( "stop_taking_away_ammo" );
for ( ;; )
{
weapons = self getweaponslistprimaries();
for ( i = 0; i < weapons.size; i++ )
{
self setweaponammoclip( weapons[ i ], 0 );
}
wait( 0.05 );
}
}
give_back_player_ammo()
{
weapons = self getweaponslistprimaries();
for ( i = 0; i < weapons.size; i++ )
{
self givestartammo( weapons[ i ] );
}
}
max_price_health()
{
health = [];
health[ 0 ] = 800;
health[ 1 ] = 600;
health[ 2 ] = 500;
health[ 3 ] = 400;
if ( flag( "to_the_pool" ) )
level.price.health = 50000;// 750;
else
level.price.health = health[ level.gameskill ] * 4;
level.price.health = 50000;// 750;
}
// wounded_init
wounded_setup()
{
level.last_callout_direction = "";
level.next_enemy_call_out = 0;
// level.price.threatbias = 50000;
level.price.allowpain = false;
level.price.flashbangImmunity = true;
level.price pushplayer( true );
// level.price setcandamage( false );
level.price.first_shot_time = gettime() + 2200;
level.price.deathanim = level.price getanim( "wounded_death" );
level.price.baseaccuracy = 1000;
// level.price animscripts\shared::placeWeaponOn( "m14_scoped", "right" );
// so he doesn't shoot straight down the gun
level.price.dontShootStraight = true;
max_price_health();
level.price.allowdeath = true;
level.price thread regen();
level.price.a.pose = "prone"; // so he doesn't get melee'd
level.price sethintstring( &"SNIPERESCAPE_HOLD_1_TO_PICK_UP_CPT" );
level.price setthreatbiasgroup( "price" );
level.price setgoalpos( level.price.origin );
level.price.fastfire = false;
level.price thread deathdetect();
if ( flag( "faiground_battle_begins" ) )
thread fairground_price_adjustment();
level.price endon( "death" );
for ( ;; )
{
level.price.useable = price_should_be_useable();
wait( 0.05 );
}
}
int_vec_compare( vec1, vec2 )
{
vec1 = ( int( vec1[ 0 ] ), int( vec1[ 1 ] ), int( vec1[ 2 ] ) );
vec2 = ( int( vec2[ 0 ] ), int( vec2[ 1 ] ), int( vec2[ 2 ] ) );
return vec1 == vec2;
}
price_should_be_useable()
{
drop_on_player_org = PlayerPhysicsTrace( level.player.origin + (0,0,60), level.player.origin + (0,0,2 ) );
if ( !int_vec_compare( drop_on_player_org, level.player.origin + (0,0,2 ) ) )
{
/#
if ( getdebugdvar( "debug_drop_price" ) == "on" )
print3d( drop_on_player_org, ".", ( 0.8, 0.6, 0 ), 1, 2 );
#/
return false;
}
return flag( "can_manage_price" );
}
deathdetect()
{
self waittill( "death", a, b, c, d, e, f, g );
a = a;
}
fairground_price_adjustment()
{
level.price endon( "death" );
// level.price thread stealth_ai();
if ( !isdefined( level.price._stealth ) )
level.price thread maps\_stealth_logic::friendly_logic();
flag_wait( "fairbattle_high_intensity" );
level.price.threatbias = -15000;
level.price.ignoreme = false;
}
regen()
{
self endon( "death" );
for ( ;; )
{
self waittill( "damage" );
thread regenner();
}
}
regenner()
{
self endon( "death" );
self endon( "damage" );
wait( 5 );
max_price_health();// 750;
}
price_fires( price )
{
// price calls this function from a notetrack when he shoots
// MagicBullet( level.price.weapon, level.price gettagorigin( "tag_flash" ), level.price_target_point );
// animscripts\utility::shootEnemyWrapper_normal();
self.a.lastShootTime = gettime();
self shoot( 0.25, level.price.targetorg.origin ); // + randomvector( 7 ) );
minus_time[ 0 ] = 400;
minus_time[ 1 ] = 400;
minus_time[ 2 ] = 0;
minus_time[ 3 ] = 0;
level.price_next_shoot_time = gettime() + randomintrange( 2250, 2950 ) - minus_time[ level.gameskill ];
}
enemy_spawn_zone()
{
assertex( isdefined( self.script_linkto ), "Zone trigger at " + self.origin + " had no script linkto" );
targets = strtok( self.script_linkto, " " );
array = [];
for ( i = 0; i < targets.size; i++ )
{
spawner = getent( targets[ i ], "script_linkname" );
if ( isdefined( spawner ) )
{
array[ array.size ] = spawner;
}
}
self.zone_spawners = array;
// figure out which zone is the correct zone
for ( ;; )
{
self waittill( "trigger" );
if ( isdefined( level.zone_trigger ) )
continue;
level.zone_trigger = self;
while ( level.player istouching( self ) )
{
wait( 0.05 );
}
level.zone_trigger = undefined;
}
}
dog_check()
{
if ( isdog() )
self setthreatbiasgroup( "dog" );
}
chase_friendlies()
{
if ( isdog() )
self setthreatbiasgroup( "dog" );
ai_move_in();
}
enemy_zone_spawner()
{
// spawn guys from the current enemy zone
// level.on_the_run_progress = level.player.origin;
// now AI will notify "shoot" when they shoot, so price can tell us the right time to put him down
anim.shootEnemyWrapper_func = animscripts\utility::ShootEnemyWrapper_shootNotify;
spawners = getentarray( "zone_spawner", "targetname" );
for ( i = 0; i < spawners.size; i++ )
{
spawners[ i ].script_grenades = 0;
}
// array_thread( spawners, ::add_spawn_function, ::chase_friendlies );
index = 0;
// give some time before the first wave spawns
waittill_either_function( ::player_moves, 600, ::timer, 15 );
for ( ;; )
{
// stop spawning if the player is in the burnt building
flag_waitopen( "enter_burnt" );
waittillframeend;// wait for the global spawn function to be reenabled
if ( getaiSpeciesArray( "all", "all" ).size >= 26 )
{
wait( 1 );
continue;
}
if ( !isdefined( level.zone_trigger ) )
{
wait( 1 );
continue;
}
// iprintlnbold( "spawning wave" );
// spawn 2 waves
for ( i = 0; i < 2; i++ )
{
spawners = array_randomize( spawners );
index -- ;
if ( index < 0 || index >= level.zone_trigger.zone_spawners.size )
{
index = level.zone_trigger.zone_spawners.size - 1;
}
zone_spawner = level.zone_trigger.zone_spawners[ index ];
spawn_targets = getentarray( zone_spawner.target, "targetname" );
spawn_limited_number_from_spawners( spawners, spawn_targets, 4, 1 );
}
wait_until_its_time_to_spawn_another_wave();
}
}
price_asks_to_be_picked_up()
{
the_line = "lets_get_moving_" + ( randomint( 2 ) + 1 );
// Looks like we're in the clear, we should get moving.
// It's time to move, give me a lift.
if ( flag( "price_wants_apartment_cleared" ) )
flag_wait( "apartment_cleared" );
wait( 1.5 );
if ( flag( "fair_snipers_died" ) )
return;
price_line( the_line );
}
wait_until_its_time_to_spawn_another_wave()
{
// spawn a new wave if there have been no enemies for a certain amount of time, or if the player brings price to a new area
level endon( "time_to_spawn_a_new_wave" );
thread spawn_wave_if_player_moves_far_with_price();
waittill_dead_or_dying( "axis" );
/*
org = getent( "apartment_battle_org", "targetname" );
if ( distance( org.origin, level.player.origin ) < distance( org.origin, level.on_the_run_progress ) )
{
// have we gotten closer to the destination?
if ( !isalive( level.price ) )
{
autosave_by_name( "on_the_run" );
level.on_the_run_progress = level.player.origin;
}
}
*/
if ( isalive( level.price ) )
{
price_asks_to_be_picked_up();
}
wait( 14 );
}
spawn_wave_if_player_moves_far_with_price()
{
level endon( "time_to_spawn_a_new_wave" );
// if the player makes enough spatial progress, spawn a new wave
for ( ;; )
{
if ( isalive( level.price ) )
{
flag_assert( "price_picked_up" );
flag_wait( "price_picked_up" );
}
wait_until_price_is_dropped_or_player_goes_far( level.player.origin );
}
}
wait_until_price_is_dropped_or_player_goes_far( start_org )
{
level endon( "price_dropped" );
for ( ;; )
{
if ( distance( start_org, level.player.origin ) > 1050 )
{
level notify( "time_to_spawn_a_new_wave" );
return;
}
wait( 1 );
}
}
isdog()
{
return self.classname == "actor_enemy_dog";
}
// only spawn total_to_spawn from the spawners
spawn_limited_number_from_spawners( spawners, spawn_targets, total_to_spawn, max_dogs_allowed_in_level )
{
spawned = 0;
for ( i = 0; i < spawners.size; i++ )
{
total_dogs = getaiSpeciesArray( "axis", "dog" ).size;
if ( spawned >= total_to_spawn )
break;
// only 1 dog at a time
if ( spawners[ i ] isdog() && total_dogs >= max_dogs_allowed_in_level )
continue;
spawners[ i ].origin = spawn_targets[ spawned ].origin;
spawners[ i ].count = 1;
spawners[ i ].script_grenades = 0;
spawners[ i ] dospawn();
spawned++ ;
}
}
dog_attacks_fence()
{
node = getnode( "dog_fence_node", "targetname" );
dog_spawner = getent( "fence_dog_spawner", "targetname" );
dog = dog_spawner stalingradspawn();
if ( spawn_failed( dog ) )
return;
dog.animname = "dog";
dog.health = 5;
dog.allowdeath = true;
dog endon( "death" );
dog thread apartment_dog_death();
// node anim_reach_solo( dog, "fence_attack" );
dog.ignoreme = true;
node anim_single_solo( dog, "fence_attack" );
dog.ignoreme = false;
dog.health = 50;
dog ai_move_in();
}
apartment_dog_death()
{
self waittill( "death" );
flag_set( "fence_dog_dies" );
}
price_followup_line()
{
level endon( "price_picked_up" );
flag_assert( "price_picked_up" );
wait( 3 );
for ( ;; )
{
// Sorry mate, you're gonna have to carry me!
while ( level.price_dialogue_master.function_stack.size > 0 )
{
wait( 0.05 );
}
price_line( "carry_me" );
flag_set( "carry_me_music_resume" );
wait( randomfloatrange( 8, 12 ) );
}
}
set_objective_pos_to_extraction_point( obj )
{
org = extraction_point();
objective_position( obj, org );
}
extraction_point()
{
if ( !flag( "player_moves_through_burnt_apartment" ) )
{
ent = getent( "objective_burnt_babystep", "targetname" );
return ent.origin;
}
return getent( "enemy_fair_dest", "targetname" ).origin;
}
on_the_run_enemies()
{
self notify( "stop_old_on_the_run_enemies" );
self endon( "stop_old_on_the_run_enemies" );
self endon( "death" );
if ( isdefined( self.ridingvehicle ) )
{
self waittill( "jumpedout" );
}
thread ai_move_in();
}
fairground_enemies()
{
self endon( "death" );
if ( isdefined( self.ridingvehicle ) )
{
self waittill( "jumpedout" );
}
thread ai_move_in();
}
tracks_ent( target_ent )
{
self endon( "stop_tracking_weapon" );
trigger = getent( "pool_trigger", "targetname" );
for ( ;; )
{
// if ( distance( level.player.origin, target_ent.origin ) < 200 )
// if ( sighttracepassed( self gettagorigin( "tag_barrel" ), level.player geteye(), false, undefined ) )
if ( level.player istouching( trigger ) || sighttracepassed( self gettagorigin( "tag_barrel" ), level.player geteye(), false, undefined ) )
{
self setturrettargetent( level.player, ( 0, 0, 24 ) );
}
else
{
self setturrettargetent( target_ent );
}
angles = vectortoangles( target_ent.origin - self.origin );
self setGoalyaw( angles[ 1 ] );
wait( 0.1 );
}
}
shoot_at_entity_chain( ent )
{
target_ent = spawn( "script_model", ent.origin );
// target_ent setmodel( "temp" );
self setturrettargetent( target_ent );
thread heli_fires();
thread tracks_ent( target_ent );
for ( ;; )
{
if ( !isdefined( ent.target ) )
break;
nextent = getent( ent.target, "targetname" );
timer = distance( nextent.origin, ent.origin ) * 0.0035;
if ( timer < 0.05 )
timer = 0.05;
target_ent moveto( nextent.origin, timer );
wait( timer );
ent = nextent;
}
target_ent delete();
self notify( "stop_firing_weapon" );
self notify( "stop_tracking_weapon" );
}
/*
shoot_at_entity_chain( ent )
{
thread heli_fires();
lastent = ent;
for ( ;; )
{
self setturrettargetent( ent );
angles = vectortoangles( ent.origin - self.origin );
self setGoalyaw( angles[ 1 ] );
for ( ;; )
{
forward = anglestoforward( ( 0, self.angles[ 1 ], 0 ) );
normal = vectorNormalize( ( ent.origin[ 0 ], ent.origin[ 1 ], 0 ) - ( self.origin[ 0 ], self.origin[ 1 ], 0 ) );
dot = vectorDot( forward, normal );
if ( dot > 0.95 )
break;
normal = vectorNormalize( ent.origin - lastent.origin );
progress = vectorDot( forward, normal );
wait( 0.1 );
}
if ( !isdefined( ent.target ) )
break;
lastent = ent;
ent = getent( ent.target, "targetname" );
}
self notify( "stop_firing_weapon" );
}
*/
incoming_heli_exists()
{
helis = getentarray( "script_vehicle", "classname" );
for ( i = 0; i < helis.size; i++ )
{
heli = helis[ i ];
if ( !issubstr( heli.model, "mi17" ) )
continue;
if ( heli.unload_group == "default" )
{
// hasnt dropped off his troops yet
return true;
}
}
return false;
}
seaknight_badplace()
{
seaknight_badplace = getent( "seaknight_badplace", "targetname" );
for ( ;; )
{
if ( distance( self.origin, seaknight_badplace.origin ) < 800 )
break;
wait( 0.05 );
}
badplace_cylinder( "seaknight_badplace", 0, seaknight_badplace.origin, seaknight_badplace.radius, 512, "axis" );
// iprintlnbold( "End of currently scripted level" );
}
player_navigates_burnt_apartment()
{
nodes = getnodearray( "park_delete_node", "targetname" );
level endon( "to_the_pool" );
flag_assert( "to_the_pool" );
for ( ;; )
{
flag_wait( "enter_burnt" );
flag_clear( "price_calls_out_enemy_location" );
remove_global_spawn_function( "axis", ::on_the_run_enemies );
ai = getaispeciesarray( "axis", "all" );
array_thread( ai, ::fall_back_and_delete, nodes );
flag_waitopen( "enter_burnt" );
flag_set( "price_calls_out_enemy_location" );
add_global_spawn_function( "axis", ::on_the_run_enemies );
level notify( "restarting_on_the_run" );
// player went back outside so the chase begins anew
ai = getaispeciesarray( "axis", "all" );
array_thread( ai, ::on_the_run_enemies );
}
}
apartment_hunters()
{
flag_wait( "apartment_hunters_start" );
spawners = getentarray( "apartment_hunter", "targetname" );
array_thread( spawners, ::add_spawn_function, ::apartment_hunter_think );
array_thread( spawners, ::spawn_ai );
}
apartment_hunter_think()
{
node = getnode( "apartment_hunter_delete", "targetname" );
self endon( "death" );
self setgoalnode( node );
self.goalradius = 32;
self.interval = 0;
self.ignoreall = true;
self waittill( "goal" );
self delete();
}
fall_back_and_delete( nodes )
{
if ( isdefined( self.script_noteworthy ) && ( self.script_noteworthy == "apartment_hunter" ) )
return;
self endon( "death" );
level endon( "restarting_on_the_run" );
if ( isdefined( self.ridingvehicle ) )
{
self waittill( "jumpedout" );
}
waittillframeend;// make sure reacquire player pos has started before we kill it
self notify( "stop_moving_in" );
node = random( nodes );
self setgoalnode( node );
self.goalradius = 64;
self waittill( "goal" );
assert( flag( "enter_burnt" ) );
// player is still in the apartment so delete
self delete();
}
deleteme()
{
self delete();
}
curtain( side )
{
self assign_animtree( "curtain" );
self setanim( self getanim( side ), 1, 0, 1 );
for ( ;; )
{
self setanim( self getanim( side ), 1, 0, randomfloat( 0.7, 1.6 ) );
wait( randomfloat( 0.5, 1.5 ) );
}
}
update_seaknight_objective_pos( obj )
{
for ( ;; )
{
objective_position( obj, level.seaknight.origin );
wait( 0.05 );
}
}
spawn_vehicle_from_targetname_and_create_ref( name )
{
vehicle = spawn_vehicle_from_targetname_and_drive( name );
level.ending_vehicles[ name ] = vehicle;
}
fairground_air_war()
{
flag_wait( "seaknight_flies_in" );
// flag_waitopen( "enemy_choppers_incoming" );
level.ending_vehicles = [];
delayThread( 0, ::spawn_vehicle_from_targetname_and_create_ref, "ending_bad_heli_1" );
delayThread( 10, ::spawn_vehicle_from_targetname_and_create_ref, "ending_bad_heli_2" );
delayThread( 12, ::spawn_vehicle_from_targetname_and_create_ref, "ending_bad_heli_3" );
delayThread( 16, ::spawn_vehicle_from_targetname_and_create_ref, "ending_bad_heli_4" );
delayThread( 15.5, ::spawn_vehicle_from_targetname_and_create_ref, "ending_good_heli_1" );
delayThread( 18, ::spawn_vehicle_from_targetname_and_create_ref, "ending_good_heli_2" );
wait( 20 );
// ending_good_heli_1 thread kill_all_visible_enemies_forever();
// ending_good_heli_2 thread kill_all_visible_enemies_forever();
wait( 3.5 );
ending_bad_heli_1 = level.ending_vehicles[ "ending_bad_heli_1" ];
ending_bad_heli_2 = level.ending_vehicles[ "ending_bad_heli_2" ];
ending_bad_heli_3 = level.ending_vehicles[ "ending_bad_heli_3" ];
ending_bad_heli_4 = level.ending_vehicles[ "ending_bad_heli_4" ];
ending_good_heli_1 = level.ending_vehicles[ "ending_good_heli_1" ];
ending_good_heli_2 = level.ending_vehicles[ "ending_good_heli_2" ];
// wait until the first bad heli starts to leave
ending_good_heli_1 vehicle_flag_arrived( "ending_good_helis_leave" );
ending_good_heli_1 notify( "stop_killing_enemies" );
ending_good_heli_1 shoots_down( ending_bad_heli_1 );
wait( 2 );
// go back to shooting any remaining infantry
ending_good_heli_1 thread kill_all_visible_enemies_forever();
wait( 5 );
ending_good_heli_2 vehicle_flag_arrived( "ending_good_helis_leave" );
ending_good_heli_2 notify( "stop_killing_enemies" );
flag_set( "ending_bad_heli2_leaves" );
ending_good_heli_2 shoots_down( ending_bad_heli_2 );
flag_set( "ending_bad_heli4_leaves" );
wait( 2 );
// go back to shooting any remaining infantry
ending_good_heli_2 thread kill_all_visible_enemies_forever();
ending_good_heli_1 notify( "stop_killing_enemies" );
ending_good_heli_1 shoots_down( ending_bad_heli_4 );
flag_set( "ending_bad_heli3_leaves" );
wait( 2 );
// go back to shooting any remaining infantry
ending_good_heli_1 thread kill_all_visible_enemies_forever();
wait( 1 );
ending_good_heli_2 notify( "stop_killing_enemies" );
ending_good_heli_2 shoots_down( ending_bad_heli_3 );
wait( 2 );
// go back to shooting any remaining infantry
ending_good_heli_2 thread kill_all_visible_enemies_forever();
// ending_good_heli_1 setturrettargetent( ending_bad_heli_1 );
// ending_good_heli_1 thread heli_fires();
// ending_good_heli_2 setturrettargetent( ending_bad_heli_2 );
// ending_good_heli_2 thread heli_fires();
wait( 1200 );
// ending_good_heli_2 setturrettargetent( ending_bad_heli_3 );
// ending_good_heli_1 setturrettargetent( ending_bad_heli_4 );
}
shoots_down( target, rnd )
{
self endon( "death" );
self endon( "death_spiral" );
if ( !isdefined( rnd ) )
rnd = 0;
self setVehWeapon( "cobra_seeker" );
offset = ( 0, 0, -50 );
self fireWeapon( "tag_store_L_2_a", target, randomvector( rnd ) + offset );// tag_light_L_wing
wait( 0.2 );
self fireWeapon( "tag_store_L_2_b", target, randomvector( rnd ) + offset );// tag_light_L_wing
wait( 0.2 );
self fireWeapon( "tag_store_L_2_c", target, randomvector( rnd ) + offset );// tag_light_L_wing
self setVehWeapon( "cobra_20mm" );
}
create_apartment_badplace()
{
// stop enemies from running into the apartment like mad apes
ent = getent( "apartment_bad_place", "targetname" );
badplace_cylinder( "apartment_badplace", 0, ent.origin, ent.radius, 200, "axis" );
}
delete_apartment_badplace()
{
badplace_delete( "apartment_badplace" );
}
more_plant_claymores()
{
flag_wait( "plant_claymore" );
flag_clear( "plant_claymore" );
// Quickly - plant a claymore in case they come this way!
price_line( "place_claymore" );
}
burnt_spawners()
{
burnt_spawners = getentarray( "burnt_spawner", "targetname" );
next_spawn = 0;
for ( ;; )
{
flag_wait( "deep_inside_burnt" );
if ( gettime() < next_spawn )
{
wait( ( next_spawn - gettime() ) * 0.001 );
}
array_thread( burnt_spawners, ::increment_count_and_spawn );
next_spawn = gettime() + 15000;
}
}
spooky_dog()
{
spooky_dog_spawner = getent( "spooky_dog_spawner", "targetname" );
flag_wait( "spawn_spooky_dog" );
if ( getdvar( "player_hasnt_been_spooked" ) == "" )
{
setdvar( "player_hasnt_been_spooked", "1" );
spooky_dog_spawner thread add_spawn_function( ::spooky_dog_spawns );
}
else
{
dog_tele = getent( "dog_tele", "targetname" );
spooky_dog_spawner.origin = dog_tele.origin;
spooky_dog_spawner.script_moveoverride = true;
spooky_dog_spawner thread add_spawn_function( ::spooky_dog_spawns_hidden );
}
spooky_dog_spawner spawn_ai();
}
spooky_dog_spawns_hidden()
{
trigger = getent( "spooky_dog_trigger", "targetname" );
self.goalradius = 64;
dog_end_goal = getent( "dog_end_goal", "script_noteworthy" );
self.favoriteenemy = level.player;
thread maps\_spawner::go_to_origin( dog_end_goal );
trigger add_wait( ::waittill_msg, "trigger" );
level add_func( ::flag_set, "price_wants_apartment_cleared" );
thread do_wait();
// dog only comes once
spooky_deletes_on_trigger( trigger );
}
spooky_dog_spawns()
{
self endon( "death" );
self.pathenemyfightdist = 0;
self.pathenemylookahead = 0;
trigger = getent( "spooky_dog_trigger", "targetname" );
flag_wait( "spooky_waits" );
flag_set( "price_wants_apartment_cleared" );
if ( flag( "price_picked_up" ) )
{
// if price is being carried, then the dog waits until price is put down, or waits some time
level waittill_notify_or_timeout( "price_picked_up", 2.0 );
if ( !flag( "price_picked_up" ) )
{
// price was put down, so wait a smidgen then go
wait( 0.25 );
}
flag_set( "spooky_goes" );
if ( !isalive( level.price ) )
{
// You'd better put me down and sweep the rooms, I'll cover the entrance.
thread price_line( "sweep_the_rooms" );
}
self waittill( "reached_path_end" );
spooky_deletes_on_trigger( trigger );
return;
}
price_line( "sweep_the_rooms" );
// if the player isn't carrying price, then just charge the player
self notify( "stop_going_to_node" );
self.goalradius = 2048;
set_default_pathenemy_settings();
}
spooky_deletes_on_trigger( trigger, timer )
{
self endon( "death" );
if ( !isdefined( timer ) )
timer = 5;
// is the player touching the trigger that keeps the dog in action?
if ( level.player istouching( trigger ) )
{
self setgoalpos( level.player.origin );
self.goalradius = 1024;
return;
}
// bark for awhile then disappear.. mysteriously
trigger wait_for_trigger_or_timeout( 5 );
self delete();
}
spooky_sighting()
{
spooky_dog_spawner = getent( "spooky_sighting", "targetname" );
spooky_dog_spawner thread add_spawn_function( ::spooky_dog_is_sighted );
}
spooky_dog_is_sighted()
{
self endon( "death" );
self waittill( "reached_path_end" );
self setgoalpos( self.origin );
self.goalradius = 32;
trigger = getent( "spooky_dog_trigger", "targetname" );
spooky_deletes_on_trigger( trigger, 0.1 );
}
second_apartment_line()
{
for ( ;; )
{
flag_wait( "lets_go_that_way" );
if ( isalive( level.price ) )
{
// player isn't carrying price if he's alive
flag_waitopen( "lets_go_that_way" );
continue;
}
// Head for that apartment, we'll try to lose 'em in there..
price_line( "head_for_apartment" );
return;
}
}
set_go_line()
{
assertex( isdefined( self.script_noteworthy ), "Set_go_line trigger at " + self.origin + " has no script_noteworthy" );
self waittill( "trigger", other );
if ( isalive( other ) )
{
// he will say this line the next time _colors makes him move
other._colors_go_line = self.script_noteworthy;
}
}
waittill_noteworthy_dies( msg )
{
guys = getentarray( msg, "script_noteworthy" );
for ( i = 0; i < guys.size; i++ )
{
if ( isalive( guys[ i ] ) )
guys[ i ] waittill( "death" );
}
}
door_opens( mod )
{
self playsound( "wood_door_kick" );
rotation = -120;
if ( isdefined( mod ) )
rotation *= mod;
self rotateyaw( rotation, .3, 0, .3 );
self connectpaths();
}
flee_guy_runs()
{
self endon( "death" );
self.ignoreall = true;
stop_moving_in();
for ( ;; )
{
if ( self cansee( level.player ) )
break;
wait( 0.05 );
}
wait( 1.5 );
node = getnode( self.script_linkto, "script_linkname" );
self setgoalnode( node );
self.goalradius = 64;
self waittill( "goal" );
self.ignoreall = false;
self setgoalpos( level.player.origin );
self.goalradius = 1024;
}
force_patrol_think()
{
stop_moving_in();
self endon( "death" );
if ( !isalive( level.price ) )
{
self.allowdeath = true;
self.disablearrivals = true;
patrol_anims = get_patrol_anims();
goalpos = getent( self.target, "targetname" );
// start off with a start animation
goalpos anim_generic_reach( self, patrol_anims[ self.script_index ] );
self.a.movement = "run";// needs to be in the animation
self anim_generic( self, patrol_anims[ self.script_index ] );
/*
if ( isdefined( goalpos.target ) )
{
goalpos = getent( goalpos.target, "targetname" );
self setgoalpos( goalpos.origin );
wait( 1 );
}
*/
self.disablearrivals = false;
}
thread reacquire_player_pos();
}
flicker_light()
{
maps\_lights::burning_trash_fire();
}
price_fair_defendspot()
{
price_gnoll = getent( "price_gnoll", "targetname" );
return price_gnoll.origin;
}
enemy_door_trigger()
{
self waittill( "trigger" );
doors = getentarray( self.target, "targetname" );
for ( i = 0; i < doors.size; i++ )
{
if ( doors[ i ].script_noteworthy == "enemy_door_right" )
doors[ i ] thread door_opens( - 1 );
else
doors[ i ] thread door_opens();
}
}
spawn_classname( spawners, class, num, has_flashbangs )
{
correct_spawners = [];
for ( i = 0; i < spawners.size; i++ )
{
spawner = spawners[ i ];
if ( issubstr( spawner.classname, class ) )
{
correct_spawners[ correct_spawners.size ] = spawner;
}
}
has_flashbangs = isdefined( has_flashbangs ) && level.gameskill >= 2;
assertex( correct_spawners.size >= num, "Tried to spawn " + num + " guys from " + correct_spawners.size + " spawners of class " + class );
for ( i = 0; i < num; i++ )
{
spawner = correct_spawners[ i ];
if ( level.gameskill <= 1 )
{
// on easy and normal they have far fewer grenades
level.fair_grenade_guy_countdown--;
if ( level.fair_grenade_guy_countdown <= 0 )
{
level.fair_grenade_guy_countdown = 5;
self.grenadeammo = 1;
}
else
{
self.grenadeammo = 0;
}
}
else
{
// on hard and vet they have grenades
self.grenadeammo = 1;
}
if ( has_flashbangs && randomint( 100 ) > 30 )
spawner.script_flashbangs = 3;
else
spawner.script_flashbangs = undefined;
spawner.count = 1;
spawn = spawner dospawn();
if ( isalive( spawn ) )
{
level.fair_battle_guys_spawned++;
}
}
}
best_fair_path( alt )
{
array = level.fair_paths;
if ( alt )
{
array = level.fair_paths_alt;
}
lowest = array[ 0 ];
for ( i = 1; i < array.size; i++ )
{
path = array[ i ];
if ( path.uses < lowest.uses )
lowest = path;
}
return lowest;
}
price_opens_fire()
{
flag_wait_either( "open_fire", "fairbattle_detected" );
if ( !flag( "fairbattle_detected" ) )
{
// Open fire.
price_line( "open_fire" );
wait( 2.0 );
}
// macmillan opens fire if somebody reaches their run point or dies
flag_clear( "fair_hold_fire" );
level.price.first_shot_time = gettime();
level.price.fastfire = true;
}
fair_guy_sets_high_intensity()
{
fair_guy_waits_for_run_or_death();
level.fair_runners++;
if ( level.fair_runners >= 1 )
{
flag_set( "fairbattle_high_intensity" );
}
}
fair_guy_waits_for_run_or_death()
{
self endon( "death" );
self endon( "damage" );
ent_flag_wait( "reached_run_point" );
}
fairground_force_high_intensity()
{
level endon( "fairbattle_high_intensity" );
flag_wait( "fairbattle_detected" );
wait( 18 );
flag_set( "fairbattle_high_intensity" );
}
stealth_break_detection()
{
self waittill_either( "alerted_once", "alerted_again" );
flag_set( "fairbattle_detected" );
println( "stealth broken" );
}
faiground_stealth_detection()
{
// flag_wait( "_stealth_spotted" );
level waittill( "event_awareness" );
flag_set( "fairbattle_gunshot" );
flag_set( "fairbattle_detected" );
println( "stealth3" );
}
fair_guy_pre_battle_behavior( alt )
{
alert_functions = [];
/*
alert_functions[1] = ::stealth_got_enemy1;
alert_functions[2] = ::stealth_got_enemy2;
alert_functions[3] = ::stealth_got_enemy3;
*/
// thread stealth_break_detection();
// thread stealth_ai_logic();
level endon( "fairbattle_high_intensity" );
thread patrol_fairgrounds_for_player( alt );
flag_wait( "fairbattle_detected" );
self.disableArrivals = false;
self.favoriteEnemy = level.player;
// self.ignoreall = true;
}
fair_guy_responds_to_invisible_attack()
{
// already close to cover
if ( ent_flag( "reached_run_point" ) )
return;
// somebody saw him
// if ( !flag( "fairbattle_gunshot" ) )
// return;
// the shot has rung out!
wait( randomfloatrange( 0.1, 0.8 ) );
self anim_generic_custom_animmode( self, "gravity", "prone_dive" );
self thread anim_generic_loop( self, "prone_idle", undefined, "stop_loop" );
self allowedstances( "prone" );
timer = randomfloatrange( 0.1, 2 );
add_wait( ::_wait, timer );
add_wait( ::player_gets_near );
self add_endon( "death" );
do_wait_any();
wait( 1 );
self notify( "stop_loop" );
timer = randomfloatrange( 3, 4 );
self add_wait( ::ent_flag_wait, "reached_run_point" );
self add_wait( ::_wait, timer );
do_wait_any();
self ent_flag_set( "reached_run_point" );
}
player_gets_near()
{
wait( randomfloat( 1, 2 ) );
for ( ;; )
{
if ( distance( level.player.origin, self.origin ) < 400 )
break;
wait( 0.1 );
}
}
fair_stop_path_if_near_player()
{
self endon( "death" );
for ( ;; )
{
if ( distance( self.origin, level.player.origin ) < 500 )
{
self notify( "stop_going_to_node" );
return;
}
wait( 1 );
}
}
fair_alt_spawner_think()
{
fair_guy_moves_in( true );
}
fair_spawner_think()
{
fair_guy_moves_in( false );
}
fair_guy_moves_in( alt )
{
// alt guys take a different path
// dogs just do their own thing
if ( self isdog() )
{
self setthreatbiasgroup( "dog" );
// player hasnt been detected yet
path = best_fair_path( alt );
path.uses++ ;
self thread fair_stop_path_if_near_player();
self.disableArrivals = true;
maps\_spawner::go_to_struct( path );
self.disableArrivals = false;
thread reacquire_player_pos();
return;
}
ent_flag_init( "reached_run_point" );
thread fairground_guy_modify_attack_based_on_player();
self endon( "death" );
self endon( "long_death" );
self.dontshootwhilemoving = true;
thread fair_guy_sets_high_intensity();
// can only blindfire
if ( level.gameskill < 2 )
self.a.forced_cover = "hide";
if ( !flag( "fairbattle_detected" ) )
{
fair_guy_pre_battle_behavior( alt );
// enemy must not be detected, so go prone
// if ( !self.canFight )
if ( !fairground_should_skip_prone_moment() )
fair_guy_responds_to_invisible_attack();
wait( randomfloatrange( 0.2, 2 ) );
self notify( "stop_animmode" );
}
else
{
path = best_fair_path( alt );
path.uses++ ;
self.disableArrivals = true;
thread maps\_spawner::go_to_struct( path );
// run path for a few seconds just to spread out
wait_until_near_player_or_run_point();
self.disableArrivals = false;
park_reinforce = getent( "park_reinforce", "targetname" );
self setgoalpos( park_reinforce.origin );
}
self fairground_attack_logic();
}
wait_until_near_player_or_run_point()
{
self endon( "reached_path_end" );
self endon( "reached_run_point" );
for ( ;; )
{
if ( distance( self.origin, level.player.origin ) < 1024 )
return;
wait( 1 );
}
}
found_good_cover_spot()
{
if ( !isdefined( self.goalpos ) )
return false;
if ( !isdefined( self.node ) )
return false;
if ( !issubstr( self.node.type, "over" ) )
return false;
return true;
}
fairground_should_skip_prone_moment()
{
return flag( "fairbattle_threat_visible" );
// return distance( self.origin, level.plyar.origin ) < level.player.maxvisibledist;
/*
if ( level.player getstance() != "stand" )
return false;
if ( !( self cansee( level.player ) ) )
return false;
return distance( self.origin, level.player.origin ) < 500;
*/
}
fairground_guy_modify_attack_based_on_player()
{
self endon( "death" );
for ( ;; )
{
fairguy_cant_fight();
/*
if ( level.player getstance() == "stand" )
{
if ( self cansee( level.player ) )
{
fairguy_can_fight();
wait( 5 );
}
else
wait( 1 );
continue;
}
*/
// prone can see dists
can_see_dist = 200;
must_hide_dist = 256;
must_nothide_dist = 128;
if ( level.player getstance() != "prone" )
{
can_see_dist = 750;
must_hide_dist = 900;
must_nothide_dist = 600;
}
player_dist = distance( self.origin, level.player.origin );
if ( player_dist > must_hide_dist )
{
fairguy_cant_fight();
wait( 5 );
continue;
}
if ( player_dist < must_nothide_dist )
{
fairguy_can_fight();
wait( 1 );
continue;
}
if ( player_dist < can_see_dist )
{
if ( self cansee( level.player ) )
{
fairguy_can_fight();
wait( 5 );
continue;
}
}
wait( 1 );
}
}
rpgGuy()
{
return issubstr( self.classname, "RPG" );
}
fairguy_cant_fight()
{
if ( !flag( "player_plays_nice" ) )
{
fairguy_can_fight();
return;
}
self.canFight = false;
if ( rpgGuy() )
return;
if ( level.gameskill < 2 )
self.a.forced_cover = "hide";
// self.dontshootwhilemoving = true;
}
fairguy_can_fight()
{
self.canFight = true;
self.a.forced_cover = "none";
self.dontshootwhilemoving = undefined;
}
fair_zone_orgs_init()
{
if ( isdefined( self.id_num ) )
return;
self.id_num = level.fairground_zone_orgs_all.size;
level.fairground_zone_orgs_all[ self.id_num ] = self;
}
fair_zone_trigger()
{
// controls enemies based on player's zone
orgs = get_linked_structs();
array_thread( orgs, ::fair_zone_orgs_init );
for ( ;; )
{
self waittill( "trigger" );
level.fair_zone = self;
level.fairground_zone_orgs = orgs;
level notify( "fairground_new_zone" );
self trigger_off();
level waittill_either( "fairground_new_zone", "fairground_clear_zone" );
self trigger_on();
}
}
fair_zone_clear()
{
level.fair_zone = undefined;
level notify( "fairground_clear_zone" );
}
fairground_attack_logic()
{
self notify( "stop_going_to_node" );
self endon( "death" );
self set_generic_run_anim( "sprint" );
self.ignoreall = false;
self allowedstances( "stand", "prone", "crouch" );
// park_reinforce = getent( "park_reinforce", "targetname" );
// self setgoalpos( park_reinforce.origin );
if ( rpgGuy() )
{
self setengagementmindist( 500, 500 );
self setengagementmaxdist( 800, 800 );
}
self setengagementmindist( 1500, 0 );
self setengagementmaxdist( 1800, 1800 );
support = self.classname == "actor_enemy_merc_SNPR_dragunov" || self.classname == "actor_enemy_merc_LMG_rpd";
if ( level.gameskill >= 2 )
{
self.fairground_flanker = !support;
}
else
{
self.fairground_flanker = false;
if ( !support )
{
level.fairground_generic_count--;
if ( level.fairground_generic_count <= 0 )
{
//chaser flanker
self.fairground_flanker = true;
level.fairground_generic_count = level.fairground_generic_skillcount[ level.gameskill ];
}
}
}
if ( !self.fairground_flanker )
{
fairground_generic_attack_behavior();
return;
}
// the guy picks a node near then hangs out there awhile
for ( ;; )
{
if ( isdefined( level.fair_zone ) )
fairground_zone_attack_behavior();
else
fairground_generic_attack_behavior();
wait( randomfloatrange( 2, 5 ) ); // limit erratic behavior between state changes
}
}
fairground_rotate_current_zone()
{
for ( ;; )
{
if ( isdefined( level.fairground_zone_orgs ) )
{
level.fairground_zone_index++;
if ( level.fairground_zone_index >= level.fairground_zone_orgs.size )
level.fairground_zone_index = 0;
level.fairground_current_zone_org = level.fairground_zone_orgs[ level.fairground_zone_index ];
}
wait( 6 );
}
}
fairground_zone_attack_behavior()
{
level endon( "fairground_clear_zone" );
if ( isdefined( level.engagement_dist_func[ self.classname ] ) )
{
[[ level.engagement_dist_func[ self.classname ] ]]();
}
else
{
self engagement_gun();
}
org = level.fairground_zone_orgs[ level.fairground_zone_index ];
// overwrite the zone so they stick together
if ( isdefined( level.fairground_current_zone_org ) )
org = level.fairground_current_zone_org;
wait( 0.05 ); // make sure _stealth has a chance to completely turn off
self setgoalpos( org.origin );
self.goalradius = org.radius;
self waittill( "goal" );
for ( ;; )
{
org = getclosest( level.player.origin, level.fairground_zone_orgs_all );
self setgoalpos( org.origin );
radius = distance( self.origin, org.origin );
if ( radius < 700 )
radius = 700;
self.goalradius = radius;
wait( randomfloat( 3, 5 ) );
}
}
fairground_generic_attack_behavior()
{
if ( self.fairground_flanker )
level endon( "fairground_new_zone" );
for ( ;; )
{
enemy_fair_dest = getent( "enemy_fair_dest", "targetname" );
self setgoalpos( enemy_fair_dest.origin );
self.goalradius = 3000;
if ( !isalive( self.enemy ) )
{
while ( !isalive( self.enemy ) )
{
wait( 1 );
}
}
enemy_dist = distance( self.origin, self.enemy.origin );
if ( !rpgGuy() )
{
// get a little closer
self setengagementmindist( enemy_dist * 0.85, 0 );
self setengagementmaxdist( enemy_dist * 0.95, enemy_dist );
}
for ( ;; )
{
if ( !flag( "player_plays_nice" ) && !flag( "seaknight_leaves" ) )
fairground_kill_mean_player_until_he_plays_nice();
if ( found_good_cover_spot() )
{
// found a new place?
if ( distance( self.node.origin, self.origin ) > 128 )
break;
}
wait( 1 );
}
// hide at this node for awhile
self setgoalpos( self.node.origin );
self.goalradius = 64;
if ( flag( "player_plays_nice" ) )
{
// player is playing nice so we'll take cover nice
level waittill_notify_or_timeout( "player_plays_nice", randomfloatrange( 20, 30 ) );
}
else
{
fairground_kill_mean_player_until_he_plays_nice();
}
}
}
fairground_kill_mean_player_until_he_plays_nice()
{
for ( ;; )
{
if ( flag( "player_made_it_to_seaknight" ) )
{
wait( 1 );
return;
}
self setgoalpos( level.player.origin );
self.goalradius = 1024;
wait( 5 );
}
}
fairground_detect_activity_and_set_flag()
{
waittill_stealth_broken();
flag_set( "fairbattle_gunshot" );
flag_set( "fairbattle_detected" );
}
waittill_stealth_broken()
{
self endon( "damage" );
self endon( "death" );
self endon( "explode" );
self endon( "projectile_impact" );
self endon( "explode" );
self endon( "doFlashBanged" );
self endon( "bulletwhizby" );
level waittill( "foreverevere" );
}
fairground_detect_activity_and_set_visible()
{
self endon( "death" );
level endon( "fairbattle_detected" );
if ( flag( "fairbattle_detected" ) )
return;
for ( ;; )
{
self waittill( "enemy" );
if ( !isalive( self.enemy ) )
continue;
if ( distance( self.enemy.origin, self.origin ) > self.enemy.maxvisibledist )
continue;
flag_set( "fairbattle_threat_visible" );
flag_set( "fairbattle_gunshot" );
flag_set( "fairbattle_detected" );
}
}
patrol_fairgrounds_for_player( alt )
{
self endon( "death" );
thread fairground_detect_activity_and_set_flag();
thread fairground_detect_activity_and_set_visible();
// player hasnt been detected yet
path = best_fair_path( alt );
path.uses++ ;
self set_generic_run_anim( "patrol_jog" );
self.disableArrivals = true;
// self.ignoreall = true;
thread maps\_spawner::go_to_struct( path, ::do_patrol_anim_at_org );
}
do_patrol_anim_at_org( ent )
{
thread do_patrol_anim_at_org_thread( ent );
}
print3d_forever( org, text, color, alpha, scale )
{
for ( ;; )
{
print3d( org, text, color, alpha, scale );
wait( 0.05 );
}
}
do_patrol_anim_at_org_thread( ent )
{
if ( isdefined( ent.script_noteworthy ) && ent.script_noteworthy == "run_point" )
{
// now the AI is in the open so they cant crawl
self ent_flag_set( "reached_run_point" );
}
if ( flag( "fairbattle_detected" ) )
return;
if ( !isdefined( ent.target ) )
return;
if ( !isdefined( ent.marker ) )
{
ent.marker = true;
if ( !isdefined( level.gmarker ) )
level.gmarker = 0;
level.gmarker++ ;
// thread print3d_forever( ent.origin, level.gmarker, ( 1, 1, 1 ), 1, 1 );
}
self endon( "death" );
if ( !isdefined( ent.script_index ) )
return;
/*
targs = getentarray( ent.target, "targetname" );
// do a special anim at specified ents
if ( !isdefined( ent.script_index ) )
{
thread line_for_time( ent.origin, targ.origin, ( 0, 0, 0.5 ), 3 );
return;
}
thread line_for_time( ent.origin, targ.origin, ( 0, 1, 1 ), 3 );
*/
self.allowdeath = true;
self.a.movement = "run";// add to notetrack!
patrol_anims = get_patrol_anims();
thread delayed_patrol_anim( patrol_anims[ ent.script_index ] );
ent.script_index = undefined;
}
delayed_patrol_anim( anime )
{
self endon( "stop_animmode" );
self endon( "death" );
wait( 0.5 );
anim_generic_custom_animmode( self, "gravity", anime );
}
remove_cant_see_player( array )
{
guys = [];
for ( i = 0; i < array.size; i++ )
{
guy = array[ i ];
if ( guy cansee( level.player ) )
guys[ guys.size ] = guy;
}
return guys;
}
wait_until_saw_enemy()
{
for ( ;; )
{
ai = getaiarray( "axis" );
start = self geteye();
timer = gettime();
for ( i = 0; i < ai.size; i++ )
{
guy = ai[ i ];
if ( !isalive( guy ) )
continue;
end = guy geteye();
trace = bullettrace( start, end, false, undefined );
// thread linedraw( start, trace[ "position" ], (1,0,0), 5 );
// thread linedraw( trace[ "position" ], end, (1,1,0), 5 );
if ( trace[ "fraction" ] == 1 )
{
wait_for_buffer_time_to_pass( timer, 1 );
return;
}
wait( 0.05 );
}
wait( 0.05 );
}
}
fairground_price_dialogue()
{
level endon( "fairbattle_high_intensity" );
level.price add_wait( ::wait_until_saw_enemy );
add_wait( ::flag_wait, "enemies_in_sight" );
add_wait( ::flag_wait, "tangos_in_sight" );
do_wait_any();
flag_set( "enemies_in_sight" );
// Tangos in sight. Let them get closer.
price_line( "let_them_get_closer" );
flag_wait( "get_ready_to_fire" );
// Standby to engage<67>
price_line( "standby_to_engage" );
}
fairground_player_visibility()
{
old_dist = level.player.maxvisibledist;
for ( ;; )
{
if ( flag( "fairbattle_detected" ) )
break;
if ( level.player getstance() == "stand" )
{
level.player.maxvisibledist = 1800;
}
if ( level.player getstance() == "crouch" )
{
level.player.maxvisibledist = 700;
}
if ( level.player getstance() == "prone" )
{
level.player.maxvisibledist = 128;
}
wait( 0.5 );
}
level.player.maxvisibledist = old_dist;
}
price_warns_player()
{
watch_out = "watch_out_1";
known_enemy = undefined;
for ( ;; )
{
ai = getaispeciesarray( "axis", "all" );
for ( i = 0; i < ai.size; i++ )
{
wait( 0.05 );
if ( !isalive( ai[ i ] ) )
continue;
if ( !isalive( ai[ i ].enemy ) )
continue;
if ( ai[ i ].enemy != level.player )
continue;
if ( isalive( known_enemy ) && ai[ i ] == known_enemy )
continue;
if ( distance( ai[ i ].origin, level.player.origin ) > 500 )
break;
known_enemy = ai[ i ];
price_line( watch_out );
if ( watch_out == "watch_out_1" )
{
watch_out = "watch_out_2";
}
else
{
watch_out = "watch_out_1";
}
wait( 3 );
}
wait( 0.05 );
}
}
all_guys_drop_grenades()
{
self waittill( "death" );
level.nextGrenadeDrop = -5;
}
fairground_battle() // fair_battle() fairbattle()
{
accuracy = [];
accuracy[ 0 ] = 0.5;
accuracy[ 1 ] = 0.7;
accuracy[ 2 ] = 0.85;
accuracy[ 3 ] = 0.85;
add_global_spawn_function( "axis", ::all_guys_drop_grenades );
level.price_sticky_target_time = 1000;
anim.player_attacker_accuracy = accuracy[ level.gameskill ];
level.player.attackerAccuracy = anim.player_attacker_accuracy;
if ( level.gameskill >= 2 )
{
level.longRegenTime = 2000; // faster regen for this part to make it more exciting
// a little extra invul time for the harder difs
setsaveddvar( "player_deathInvulnerableTime", 750 );
}
accuracy_scale = [];
accuracy_scale[ 0 ] = 1.25;
accuracy_scale[ 1 ] = 1.25;
accuracy_scale[ 2 ] = 1.15;
accuracy_scale[ 3 ] = 1.0;
// ai are a bit less accurate at distance in this section to emphasize the sniping
setsaveddvar( "ai_accuracydistscale", accuracy_scale[ level.gameskill ] );
level.fair_grenade_guy_countdown = 0;
level.fair_battle_guys_spawned = 0;
level.price.maxvisibledist = 1400;
// controls enemies based on player's zone
level.fairground_zone_orgs_all = [];
level.fairground_zone_index = 0;
thread fairground_rotate_current_zone();
// determines how often a guy is a "chaser"
level.fairground_generic_skillcount[ 0 ] = 3;
level.fairground_generic_skillcount[ 1 ] = 2;
level.fairground_generic_count = 0;
run_thread_on_targetname( "fair_zone_trigger", ::fair_zone_trigger );
run_thread_on_targetname( "fair_zone_clear", ::fair_zone_clear );
level add_wait( ::flag_wait, "fairbattle_detected" );
level add_func( ::send_notify, "_stealth_stop_stealth_logic" );
thread price_warns_player();
flag_clear( "open_fire" );
if ( isalive( level.price ) )
{
thread fairground_price_adjustment();
thread price_opens_fire();
}
ai = getaispeciesarray( "axis", "all" );
array_thread( ai, ::die_soon );
if ( isalive( level.price ) )
level.price clearenemy();
flag_assert( "fairbattle_high_intensity" );
setsaveddvar( "ai_eventDistGunShot", 4500 );
// thread faiground_stealth_detection();
thread fairground_keep_player_out_of_pool();
thread fairground_price_dialogue();
thread fairground_player_visibility();
level._stealth.logic.detect_range[ "hidden" ][ "stand" ] = 2048;
// thread fairground_enemy_helis();
// level.player thread stealth_ai();
flag_set( "faiground_battle_begins" );
flag_set( "aa_seaknight_rescue" );
remove_global_spawn_function( "axis", ::enemy_override );
secondary_paths = getentarray( "secondary_path", "script_noteworthy" );
array_thread( secondary_paths, ::secondary_path_think );
thread fairground_force_high_intensity();
level.fair_paths = getstructarray( "fair_path", "targetname" );
level.fair_paths_alt = getstructarray( "fair_path_alt", "targetname" );
field_ref_spot = getent( "field_ref_spot", "targetname" );
// so they're used in a certain order
level.fair_paths = get_array_of_closest( field_ref_spot.origin, level.fair_paths );
array_thread( level.fair_paths, ::init_fair_paths );
// so they're used in a certain order
level.fair_paths_alt = get_array_of_closest( field_ref_spot.origin, level.fair_paths_alt );
array_thread( level.fair_paths_alt, ::init_fair_paths );
level.fair_runners = 0;
fair_spawners = getentarray( "fair_spawner", "targetname" );
array_thread( fair_spawners, ::add_spawn_function, ::fair_spawner_think );
alt_spawners = getentarray( "fair_spawner_alt", "targetname" );
array_thread( alt_spawners, ::add_spawn_function, ::fair_alt_spawner_think );
// player is ignored until he does something to alert the enemy
level.player.ignoreme = true;
// "ak47", "rpd", "g3", "mp5", "RPG"
fairground_pre_detection();
level.player.ignoreme = false;
level.player.threatbias = 500;
flag_wait( "fairbattle_detected" );
flag_wait( "fairbattle_high_intensity" );
flag_clear( "fair_hold_fire" );
fairground_post_detection();
}
init_fair_paths()
{
self.uses = 1;
if ( isdefined( self.script_noteworthy ) )
self.uses = 0;
}
fairground_pre_detection()
{
// first spawn in a wave of guys that will patrol jog in
level endon( "fairbattle_detected" );
fair_spawners = get_fair_spawners();
if ( level.start_point != "fair_battle2" )
{
spawn_classname( fair_spawners, "ak47", 2 );
spawn_classname( fair_spawners, "g3", 2 );
spawn_classname( fair_spawners, "mp5", 2 );
wait( 4 );
fair_spawners = get_fair_spawners();
spawn_classname( fair_spawners, "ak47", 2 );
spawn_classname( fair_spawners, "g3", 2 );
spawn_classname( fair_spawners, "mp5", 2 );
wait( 4 );
}
else
{
spawn_classname( fair_spawners, "ak47", 2 );
}
// level.fair_paths = array_randomize( level.fair_paths );
}
get_fair_spawners()
{
alt_fair_trigger = getent( "alt_fair_trigger", "targetname" );
if ( level.player istouching( alt_fair_trigger ) )
{
// ai originate elsewhere if this trigger is touched
return getentarray( "fair_spawner_alt", "targetname" );
}
else
{
return getentarray( "fair_spawner", "targetname" );
}
}
spawn_intro_wave()
{
fair_spawners = get_fair_spawners();
if ( level.gameskill == 0 )
{
spawn_classname( fair_spawners, "ak47", 1 );
spawn_classname( fair_spawners, "g3", 2 );
spawn_classname( fair_spawners, "mp5", 2 );
spawn_classname( fair_spawners, "winc", 1 );
}
else
if ( level.gameskill == 1 )
{
spawn_classname( fair_spawners, "ak47", 1 );
spawn_classname( fair_spawners, "g3", 2 );
spawn_classname( fair_spawners, "mp5", 2 );
spawn_classname( fair_spawners, "winc", 1 );
}
else
if ( level.gameskill == 2 )
{
spawn_classname( fair_spawners, "winc", 2 );
spawn_classname( fair_spawners, "g3", 2, true );
spawn_classname( fair_spawners, "drag", 2 );
}
else
if ( level.gameskill == 3 )
{
spawn_classname( fair_spawners, "winc", 1, true );
spawn_classname( fair_spawners, "g3", 1, true );
spawn_classname( fair_spawners, "rpd", 1, true );
spawn_classname( fair_spawners, "drag", 3 );
}
}
spawn_lowbie_mixed()
{
fair_spawners = get_fair_spawners();
if ( level.gameskill == 0 )
{
spawn_classname( fair_spawners, "ak47", 2 );
spawn_classname( fair_spawners, "g3", 2 );
spawn_classname( fair_spawners, "winc", 2 );
}
else
if ( level.gameskill == 1 )
{
spawn_classname( fair_spawners, "winc", 2 );
spawn_classname( fair_spawners, "g3", 2 );
spawn_classname( fair_spawners, "mp5", 2 );
}
else
if ( level.gameskill == 2 )
{
spawn_classname( fair_spawners, "winc", 2, true );
spawn_classname( fair_spawners, "g3", 2, true );
spawn_classname( fair_spawners, "mp5", 2 );
}
else
if ( level.gameskill == 3 )
{
spawn_classname( fair_spawners, "ak47", 1, true );
spawn_classname( fair_spawners, "g3", 1, true );
spawn_classname( fair_spawners, "winc", 1, true );
spawn_classname( fair_spawners, "mp5", 3 );
}
}
spawn_sniper_mixed()
{
fair_spawners = get_fair_spawners();
if ( level.gameskill == 0 )
{
spawn_classname( fair_spawners, "ak47", 1 );
spawn_classname( fair_spawners, "mp5", 2 );
spawn_classname( fair_spawners, "drag", 4 );
}
else
if ( level.gameskill == 1 )
{
spawn_classname( fair_spawners, "ak47", 1 );
spawn_classname( fair_spawners, "g3", 1 );
spawn_classname( fair_spawners, "mp5", 1 );
spawn_classname( fair_spawners, "drag", 3 );
}
else
if ( level.gameskill == 2 )
{
spawn_classname( fair_spawners, "ak47", 1, true );
spawn_classname( fair_spawners, "g3", 1, true );
spawn_classname( fair_spawners, "drag", 4 );
}
else
if ( level.gameskill == 3 )
{
spawn_classname( fair_spawners, "RPG", 1 );
spawn_classname( fair_spawners, "winc", 1, true );
spawn_classname( fair_spawners, "drag", 4 );
}
}
spawn_saw_support()
{
fair_spawners = get_fair_spawners();
spawn_classname( fair_spawners, "rpd", 3, true );
if ( level.gameskill >= 2 )
{
spawn_classname( fair_spawners, "g3", 1, true );
spawn_classname( fair_spawners, "winc", 1, true );
spawn_classname( fair_spawners, "dog", 1 );
}
else
{
spawn_classname( fair_spawners, "g3", 1, true );
spawn_classname( fair_spawners, "winc", 1, true );
spawn_classname( fair_spawners, "mp5", 1 );
}
}
spawn_saw_support_no_dog()
{
fair_spawners = get_fair_spawners();
spawn_classname( fair_spawners, "rpd", 3, true );
spawn_classname( fair_spawners, "g3", 1, true );
spawn_classname( fair_spawners, "winc", 1, true );
spawn_classname( fair_spawners, "mp5", 1 );
}
spawn_rpg_support()
{
fair_spawners = get_fair_spawners();
spawn_classname( fair_spawners, "RPG", 3 );
spawn_classname( fair_spawners, "g3", 1, true );
spawn_classname( fair_spawners, "winc", 1, true );
spawn_classname( fair_spawners, "mp5", 1 );
}
spawn_dog_support()
{
fair_spawners = get_fair_spawners();
if ( level.gameskill == 0 )
{
spawn_classname( fair_spawners, "dog", 2 );
}
else
if ( level.gameskill == 1 )
{
spawn_classname( fair_spawners, "dog", 2 );
}
else
if ( level.gameskill == 2 )
{
spawn_classname( fair_spawners, "dog", 3 );
}
else
if ( level.gameskill == 3 )
{
spawn_classname( fair_spawners, "dog", 3 );
}
}
fairbattle_autosave()
{
if ( level.start_point == "seaknight" )
return;
// when the first heli pod comes we check the player's progress to see if we should do an autosave
for ( i = 0; i < 14; i++ )
{
if ( isSaveRecentlyLoaded() )
return;
wait( 1 );
if ( isSaveRecentlyLoaded() )
return;
if ( flag( "player_has_red_flashing_overlay" ) )
continue;
if ( player_is_near_live_grenade() )
continue;
ai = getaispeciesarray( "axis", "all" );
ai = remove_vehicle_riders_from_array( ai );
killed_guys = level.fair_battle_guys_spawned - ai.size;
killed_ratio = killed_guys / level.fair_battle_guys_spawned;
level.killed_guys = killed_guys;
level.killed_ratio = killed_ratio;
if ( killed_ratio < 0.7 )
continue;
if ( ai.size )
{
guy = getclosest( level.player.origin, ai );
if ( distance( guy.origin, level.player.origin ) < 760 )
continue;
}
if ( autosave_now( "final_battle" ) )
return;
}
}
remove_vehicle_riders_from_array( ai )
{
new = [];
for ( i = 0; i < ai.size; i++ )
{
if ( !isdefined( ai[ i ].ridingvehicle ) )
new[ new.size ] = ai[ i ];
}
return new;
}
spawn_heli_pod_1()
{
wait( 25 );
spawn_vehicle_from_targetname_and_drive( "fairground_heli1" );
spawn_vehicle_from_targetname_and_drive( "fairground_heli2" );
thread chopper_discussion();
thread fairbattle_autosave();
}
spawn_heli_pod_2()
{
spawn_vehicle_from_targetname_and_drive( "fairground_heli3" );
spawn_vehicle_from_targetname_and_drive( "fairground_heli4" );
// if ( level.gameskill < 3 )
// autosave_now( "final_battle" );
}
chopper_discussion()
{
wait( 4 );
// Enemy choppers inbound!
price_line( "enemy_choppers" );
wait( 7 );
wait( 38 );
// Big Bird we are heavily out numbered, where are you?
price_line( "where_are_you" );
// Copy that Alpha, we'll be there ASAP. Hold tight.
price_line( "be_there_asap" );
}
fairground_post_detection()
{
groups = [];
groups[ "intro_wave" ] = ::spawn_intro_wave;
groups[ "lowbie_mixed" ] = ::spawn_lowbie_mixed;
groups[ "heli_pod_1" ] = ::spawn_heli_pod_1;
groups[ "heli_pod_2" ] = ::spawn_heli_pod_2;
groups[ "saw_support" ] = ::spawn_saw_support;
groups[ "saw_support_no_dog" ] = ::spawn_saw_support_no_dog;
groups[ "rpg_support" ] = ::spawn_rpg_support;
groups[ "dog_support" ] = ::spawn_dog_support;
groups[ "sniper_mixed" ] = ::spawn_sniper_mixed;
counts = [];
counts[ "intro_wave" ] = 6;
counts[ "lowbie_mixed" ] = 6;
counts[ "heli_pod_1" ] = 8;
counts[ "heli_pod_2" ] = 8;
counts[ "saw_support" ] = 6;
counts[ "saw_support_no_dog" ] = 6;
counts[ "rpg_support" ] = 6;
counts[ "dog_support" ] = 3;
counts[ "sniper_mixed" ] = 6;
schedule = spawnstruct();
schedule.timer = gettime();
schedule.events = [];
if ( level.start_point != "fair_battle2" )
{
// skip these guys for fair_battle2
schedule = add_to_schedule( schedule, "intro_wave", 12 );
schedule = add_to_schedule( schedule, "lowbie_mixed", 6 );
schedule = add_to_schedule( schedule, "rpg_support", 7 );
schedule = add_to_schedule( schedule, "sniper_mixed", 12 );
schedule = add_to_schedule( schedule, "saw_support", 5 );
schedule = add_to_schedule( schedule, "rpg_support", 4 );
}
schedule = add_to_schedule( schedule, "heli_pod_1", 4 );
schedule = add_to_schedule( schedule, "heli_pod_2", 29 );
if ( level.gameskill >= 2 )
{
//hard
schedule = add_to_schedule( schedule, "lowbie_mixed", 28 );
schedule = add_to_schedule( schedule, "lowbie_mixed", 2 );
schedule = add_to_schedule( schedule, "saw_support", 2 );
}
else
{
//easy
schedule = add_to_schedule( schedule, "lowbie_mixed", 34 );
schedule = add_to_schedule( schedule, "lowbie_mixed", 2 );
}
for ( i = 0; i < 5; i++ )
{
schedule = add_to_schedule( schedule, "saw_support_no_dog", 11 );
schedule = add_to_schedule( schedule, "lowbie_mixed", 11 );
schedule = add_to_schedule( schedule, "saw_support", 11 );
schedule = add_to_schedule( schedule, "lowbie_mixed", 11 );
schedule = add_to_schedule( schedule, "rpg_support", 11 );
schedule = add_to_schedule( schedule, "lowbie_mixed", 11 );
}
index = 0;
for ( ;; )
{
event = schedule.events[ index ];
current_time = gettime();
if ( event[ "timer" ] > current_time )
{
// wait until its time for this event
wait( ( event[ "timer" ] - current_time ) * 0.001 );
}
wait_until_enough_ai_headroom( counts[ event[ "event" ] ] );
if ( getaispeciesarray( "axis", "all" ).size <= 8 )
{
// thread autosave_or_timeout( "autosave_for_good_behavior", 10 );
}
// spawn the group
thread [[ groups[ event[ "event" ] ] ]]();
index++;
if ( index >= schedule.events.size )
break;
}
}
wait_until_enough_ai_headroom( num )
{
for ( ;; )
{
if ( getaispeciesarray( "all" ).size + num <= 32 )
break;
wait( 1 );
}
}
add_to_schedule( schedule, event, timer )
{
timer *= 1000;
schedule.timer += timer;
array = [];
array[ "event" ] = event;
array[ "timer" ] = schedule.timer;
schedule.events[ schedule.events.size ] = array;
return schedule;
}
fairground_enemy_helis()
{
level endon( "seaknight_flies_in" );
flag_assert( "seaknight_flies_in" );
wait( 5 );
fairground_helinames = [];
fairground_helinames[ fairground_helinames.size ] = "fairground_heli1";
fairground_helinames[ fairground_helinames.size ] = "fairground_heli2";
fairground_helinames[ fairground_helinames.size ] = "fairground_heli3";
fairground_helinames[ fairground_helinames.size ] = "fairground_heli4";
fairground_helinames[ fairground_helinames.size ] = "fairground_heli5";
timer = 26;
for ( ;; )
{
fairground_helinames = array_randomize( fairground_helinames );
for ( i = 0; i < fairground_helinames.size; i++ )
{
while ( getaispeciesarray( "all", "all" ).size >= 31 )
{
wait( 1 );
}
name = fairground_helinames[ i ];
// thread off so we can track if there are still helis moving in to the site
thread heli_drops_off_guys_at_fairground( name );
wait( timer );
timer -= 2;
if ( timer < 8 )
timer = 8;
}
}
}
heli_drops_off_guys_at_fairground( name )
{
flag_set( "enemy_choppers_incoming" );
heli = spawn_vehicle_from_targetname_and_drive( name );
heli waittill( "unload" );
waittillframeend;// wait for our .unload_group to get set, since _vehicle is reliant on waits and notifies
wait( 6 );// give the guys a chance to get outa there
if ( !incoming_heli_exists() )
{
flag_clear( "enemy_choppers_incoming" );
}
}
price_says_this_is_fine()
{
level endon( "price_picked_up" );
for ( ;; )
{
if ( distance( level.player.origin, price_fair_defendspot() ) < level.price_gnoll_dist )
{
// This'll be fine.
thread price_line( "this_is_fine" );
flag_set( "can_manage_price" );
return;
}
wait( 0.5 );
}
}
secondary_path_think()
{
// make guys running this path choose this one as a secondary pick.
// print3d_forever( self.origin, self.gtn_uses, ( 1, 1, 1 ), 1, 1 );
array = getentarray( self.targetname, "targetname" );
array = array_remove( array, self );
array[ array.size ] = self;
level.go_to_node_arrays[ self.targetname ] = array;
}
/*
fairgrounds_wait_until_player_is_ready()
{
player_snipe_spot = getent( "player_snipe_spot", "targetname" );
for ( ;; )
{
if ( distance( level.player.origin, player_snipe_spot.origin ) < player_snipe_spot.radius )
{
display_hint( "prone_at_fair" );
}
else
{
wait( 0.05 );
continue;
}
for ( ;; )
{
if ( distance( level.player.origin, player_snipe_spot.origin ) >= player_snipe_spot.radius )
break;
if ( level.player getstance() == "prone" )
return;
wait( 0.05 );
}
}
}
*/
should_halt()
{
if ( !isalive( level.price.enemy ) )
return true;
return distance( level.price.enemy.origin, level.price.origin ) > 1024;
}
price_kill_check()
{
self waittill( "death", other );
if ( !isalive( other ) )
return;
if ( !isalive( level.price ) )
return;
if ( other != level.price )
return;
wait( 1.0 );
price_calls_out_a_kill();
}
heat_progression_summons_kill_heli()
{
level.kill_heli_progression++;
self.index = level.kill_heli_progression;
level.kill_heli_progression_triggers[ self.index ] = 0;
level.kill_heli_progression_warnings[ self.index ] = 0;
level endon( "break_for_apartment" );
// now all progression indices are defined
waittillframeend;
array = [];
triggers = getentarray( "heat_progression", "targetname" );
// lower indexed triggers get added here
for ( i = 0; i < triggers.size; i++ )
{
if ( triggers[ i ].script_index < self.script_index )
array[ array.size ] = triggers[ i ];
}
for ( ;; )
{
self waittill( "trigger" );
if ( self.index < level.kill_heli_index && gettime() > level.kill_heli_last_warning_refresh_time )
{
// reset the warning time if you backtrack
level.kill_heli_last_warning_time = 0;
level.kill_heli_last_warning_refresh_time = gettime() + 5000;
}
level.kill_heli_index = self.index;
level.kill_heli_triggers = array;
}
}
kill_heli_logic()
{
heli_kill_timer = 75;
heli_kill_previous_zone_time = 68;
current_warning = 1;
warnings = [];
warnings[ warnings.size ] = 20;
warnings[ warnings.size ] = 40;
warnings[ warnings.size ] = 60;
// level waittill( "price_sees_enemy" );
// flag_wait( "start_heat_spawners" );
level.kill_heli_last_warning_time = gettime() + 5000;
// heli comes and kills the player if he spends too much time in a zone
for ( ;; )
{
for ( i = 0; i < level.kill_heli_triggers.size; i++ )
{
// level.kill_heli_triggers gets filled in with all the triggers below and including the current touched trigger
index = level.kill_heli_triggers[ i ].index;
// raise previous zones to 35 seconds, so you cant go backtracking far
if ( level.kill_heli_progression_triggers[ index ] < heli_kill_previous_zone_time )
level.kill_heli_progression_triggers[ index ]++;
}
level.kill_heli_progression_triggers[ level.kill_heli_index ]++;
wait( 1 );
if ( flag( "break_for_apartment" ) )
return;
cumlative_time = level.kill_heli_progression_triggers[ level.kill_heli_index ];
if ( flag( "price_calls_out_kills" ) )
{
if ( cumlative_time > warnings[ 0 ] )
flag_clear( "price_calls_out_kills" );
}
else
{
if ( cumlative_time < warnings[ 0 ] )
flag_set( "price_calls_out_kills" );
}
if ( gettime() > level.kill_heli_last_warning_time )
{
// issue a warning if we've hung out here too long, or backtracked.
if ( cumlative_time > warnings[ level.kill_heli_progression_warnings[ level.kill_heli_index ] ] )
{
level.kill_heli_progression_warnings[ level.kill_heli_index ]++;
if ( level.kill_heli_progression_warnings[ level.kill_heli_index ] >= warnings.size )
{
level.kill_heli_progression_warnings[ level.kill_heli_index ] = warnings.size - 1;
}
thread price_line( "gotta_go_" + current_warning );
current_warning++;
if ( current_warning > 10 )
current_warning = 1;
level.kill_heli_last_warning_time = gettime() + 10000;
}
}
// spent too long in this zone! time to die.
if ( cumlative_time > heli_kill_timer )
break;
}
if ( flag( "break_for_apartment" ) )
return;
// thread bring_out_the_hounds();
heli = spawn_vehicle_from_targetname_and_drive( "kill_heli" );
heli setVehWeapon( "hind_turret_penetration" );
heli waittill( "reached_dynamic_path_end" );
flag_set( "kill_heli_attacks" );
points = getstructarray( "kill_heli_spot", "targetname" );
for ( ;; )
{
org = getclosest( level.player.origin, points );
heli setSpeed( 40, 10, 10 );
heli setNearGoalNotifyDist( 100 );
heli setvehgoalpos( org.origin, 1 );
heli waittill( "near_goal" );
if ( flag( "break_for_apartment" ) )
return;
for ( i = 0; i < 30; i++ )
{
angles = vectortoangles( level.player.origin - heli.origin );
heli setgoalyaw( angles[ 1 ] );
heli setturrettargetent( level.player, randomvector( 15 ) + ( 0, 0, 16 ) );
heli fireweapon();
wait( 0.05 );
}
wait( randomfloatrange( 0.8, 1.3 ) );
}
}
sufficient_time_remaining()
{
if ( flag( "player_enters_fairgrounds" ) )
return true;
return get_seconds_until_no_saving() > 0;
}
get_seconds_until_no_saving()
{
return ( ( level.evac_fail_time - level.evac_min_time_remaining * 1000 * 60 ) - gettime() ) * 0.001;
}
set_min_time_remaining( min_time )
{
level.evac_min_time_remaining = min_time;
flag_assert( "player_enters_fairgrounds" );
level notify( "new_min_time" );
level endon( "new_min_time" );
level endon( "player_enters_fairgrounds" );
seconds_until_no_saving = get_seconds_until_no_saving();
println( "^3Seconds until no saving: " + seconds_until_no_saving );
if ( seconds_until_no_saving <= 0 )
{
flag_clear( "can_save" );
return;
}
/*
for ( ;; )
{
wait( 1 );
seconds_until_no_saving -= 1;
level.sec = seconds_until_no_saving;
}
*/
wait( seconds_until_no_saving );
flag_clear( "can_save" );
}
price_fights_until_enemies_leave()
{
for ( ;; )
{
ai = getaiarray( "axis" );
if ( !ai.size )
return;
guy = getClosest( level.price.origin, ai );
if ( distance( guy.origin, level.price.origin ) > 1000 )
return;
wait( 0.05 );
}
}
should_break_where_is_he()
{
return flag( "price_picked_up" );
}
set_c4_throw_binding()
{
ps3_flipped = false;
config = getdvar ( "gpad_buttonsConfig" );
if ( isdefined ( config ) )
if ( issubstr ( config , "_alt" ) )
ps3_flipped = true;
//get the first one bound
binding = getKeyBinding( "+toggleads_throw" );
if ( binding["count"] )
{
add_hint_string( "c4_throw", &"SCRIPT_HINT_THROW_C4_TOGGLE", ::should_break_c4_throw );
return;
}
binding = getKeyBinding( "+speed_throw" );
if ( binding["count"] )
{
if ( ( level.Xenon ) || ( ps3_flipped ) )//pull X vs press X on console
add_hint_string( "c4_throw", &"SCRIPT_HINT_THROW_C4_SPEED_TRIGGER", ::should_break_c4_throw );
else
add_hint_string( "c4_throw", &"SCRIPT_HINT_THROW_C4_SPEED", ::should_break_c4_throw );
return;
}
binding = getKeyBinding( "+throw" );
if ( binding["count"] )
{
add_hint_string( "c4_throw", &"SCRIPT_HINT_THROW_C4", ::should_break_c4_throw );
return;
}
//all are unbound on PC:
add_hint_string( "c4_throw", &"SCRIPT_HINT_THROW_C4_TOGGLE", ::should_break_c4_throw );
}
c4_hint()
{
c4Count = getPlayerc4();
if ( !c4Count )
return;
thread display_hint( "c4" );
while ( !should_break_c4() )
{
wait( 1 );
}
wait( 1.5 );
level.new_c4Count = getPlayerc4();
if ( level.new_c4Count == c4count && level.player GetCurrentWeapon() == "c4" )
{
thread display_hint( "c4_throw" );
}
}
burnt_blocker()
{
trigger = getent( "burnt_retreat_blocker_trigger", "targetname" );
clip = getent( "burnt_retreat_blocker", "targetname" );
clip notsolid();
trigger waittill( "trigger" );
flag_set( "player_moves_through_burnt_apartment" );
set_objective_pos_to_extraction_point( getobj( "wounded" ) );
if ( 1 )
return;
for ( ;; )
{
trigger waittill( "trigger" );
if ( isalive( level.price ) )
continue;
break;
}
for ( ;; )
{
clip solid();
flag_waitopen( "price_picked_up" );
clip notsolid();
flag_wait( "price_picked_up" );
}
}
house_chase_spawner()
{
self endon( "death" );
for ( ;; )
{
if ( distance( level.player.origin, self.origin ) < 400 )
break;
wait( 0.05 );
}
self.goalradius = 1024;
for ( ;; )
{
self setgoalpos( level.player.origin );
wait( 0.5 );
}
}
fair_spawner_seeks_player()
{
self endon( "death" );
wait( 30 );
self delaythread( randomintrange( 25, 35 ), ::die );
self.goalradius = 512;
for ( ;; )
{
self setgoalpos( level.player.origin );
wait( 5 );
}
}
handle_radiation_warning()
{
for ( ;; )
{
level waittill( "radiation_warning" );
price_line( "scoutsniper_mcm_youdaft" );
}
}