5903 lines
No EOL
136 KiB
Text
5903 lines
No EOL
136 KiB
Text
#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" );
|
||
}
|
||
} |