2491 lines
61 KiB
Plaintext
2491 lines
61 KiB
Plaintext
// IW6 GSC SOURCE
|
|
// Generated by https://github.com/xensik/gsc-tool
|
|
|
|
onenteranimstate( var_0, var_1 )
|
|
{
|
|
onexitanimstate( var_0, var_1 );
|
|
self.currentanimstate = var_1;
|
|
|
|
switch ( var_1 )
|
|
{
|
|
case "idle":
|
|
maps\mp\agents\alien\_alien_idle::main();
|
|
break;
|
|
case "move":
|
|
maps\mp\agents\alien\_alien_move::main();
|
|
break;
|
|
case "traverse":
|
|
maps\mp\agents\alien\_alien_traverse::main();
|
|
break;
|
|
case "melee":
|
|
maps\mp\agents\alien\_alien_melee::main();
|
|
break;
|
|
}
|
|
}
|
|
|
|
onexitanimstate( var_0, var_1 )
|
|
{
|
|
self notify( "killanimscript" );
|
|
|
|
switch ( var_0 )
|
|
{
|
|
case "idle":
|
|
maps\mp\agents\alien\_alien_idle::end_script();
|
|
break;
|
|
case "move":
|
|
maps\mp\agents\alien\_alien_move::end_script();
|
|
break;
|
|
case "traverse":
|
|
maps\mp\agents\alien\_alien_traverse::end_script();
|
|
break;
|
|
case "melee":
|
|
maps\mp\agents\alien\_alien_melee::end_script();
|
|
break;
|
|
}
|
|
}
|
|
|
|
monitorflash()
|
|
{
|
|
self endon( "death" );
|
|
|
|
for (;;)
|
|
{
|
|
self waittill( "flashbang", var_0, var_1, var_2, var_3, var_4, var_5 );
|
|
|
|
switch ( self.currentanimstate )
|
|
{
|
|
case "idle":
|
|
break;
|
|
case "move":
|
|
maps\mp\agents\alien\_alien_move::onflashbanged();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
ondamagefinish( var_0, var_1, var_2, var_3, var_4, var_5, var_6, var_7, var_8, var_9 )
|
|
{
|
|
self finishagentdamage( var_0, var_1, var_2, var_3, var_4, var_5, var_6, var_7, var_8, var_9, 0.0 );
|
|
|
|
if ( self.health <= 0 )
|
|
return 1;
|
|
|
|
var_10 = maps\mp\alien\_utility::is_trap( var_0 );
|
|
registerdamage( var_2 );
|
|
|
|
if ( isdefined( var_1 ) )
|
|
{
|
|
if ( isplayer( var_1 ) || isdefined( var_1.owner ) && isplayer( var_1.owner ) )
|
|
{
|
|
if ( !var_10 )
|
|
var_1 maps\mp\alien\_damage::check_for_special_damage( self, var_5, var_4 );
|
|
|
|
if ( var_2 > 0 )
|
|
level.alienbbdata["damage_done"] = level.alienbbdata["damage_done"] + var_2;
|
|
}
|
|
}
|
|
|
|
var_11 = should_do_stun_damage( var_5, var_4, var_1 );
|
|
|
|
if ( !var_11 )
|
|
{
|
|
var_12 = belowcumulativepainthreshold( var_1, var_5 );
|
|
|
|
if ( var_4 != "MOD_MELEE" && var_12 )
|
|
return;
|
|
|
|
if ( var_4 == "MOD_MELEE" && !var_12 && !should_melee_pushback() )
|
|
return;
|
|
}
|
|
|
|
if ( !isdefined( var_7 ) )
|
|
var_7 = anglestoforward( self.angles );
|
|
|
|
notifyjumppain( var_7, var_8, var_2, var_11 );
|
|
cleardamagehistory();
|
|
|
|
if ( var_11 && !var_10 )
|
|
{
|
|
thread maps\mp\alien\_alien_fx::fx_stun_damage();
|
|
var_3 = var_3 | level.idflags_stun;
|
|
}
|
|
|
|
switch ( self.currentanimstate )
|
|
{
|
|
case "idle":
|
|
maps\mp\agents\alien\_alien_idle::ondamage( var_0, var_1, var_2, var_3, var_4, var_5, var_6, var_7, var_8, var_9 );
|
|
break;
|
|
case "move":
|
|
maps\mp\agents\alien\_alien_move::ondamage( var_0, var_1, var_2, var_3, var_4, var_5, var_6, var_7, var_8, var_9 );
|
|
break;
|
|
case "melee":
|
|
maps\mp\agents\alien\_alien_melee::ondamage( var_0, var_1, var_2, var_3, var_4, var_5, var_6, var_7, var_8, var_9 );
|
|
break;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
should_do_stun_damage( var_0, var_1, var_2 )
|
|
{
|
|
if ( maps\mp\alien\_utility::get_alien_type() == "elite" )
|
|
return 0;
|
|
|
|
if ( maps\mp\alien\_utility::is_true( self.is_burning ) )
|
|
return 0;
|
|
|
|
if ( isdefined( var_2 ) && isplayer( var_2 ) && var_1 != "MOD_MELEE" )
|
|
{
|
|
var_3 = isdefined( var_0 ) && var_0 == var_2 getcurrentprimaryweapon();
|
|
return var_3 && var_2 maps\mp\alien\_utility::has_stun_ammo();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
should_melee_pushback()
|
|
{
|
|
if ( maps\mp\alien\_utility::get_alien_type() == "elite" )
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
notifyjumppain( var_0, var_1, var_2, var_3 )
|
|
{
|
|
self notify( "jump_pain", var_0, var_1, var_2, var_3 );
|
|
}
|
|
|
|
cleardamagehistory()
|
|
{
|
|
self.recentdamages = [];
|
|
self.damagelistindex = 0;
|
|
}
|
|
|
|
registerdamage( var_0 )
|
|
{
|
|
var_1 = [];
|
|
var_1["amount"] = var_0;
|
|
var_1["time"] = gettime();
|
|
self.recentdamages[self.damagelistindex] = var_1;
|
|
self.damagelistindex++;
|
|
|
|
if ( self.damagelistindex == level.damagelistsize )
|
|
self.damagelistindex = 0;
|
|
}
|
|
|
|
belowcumulativepainthreshold( var_0, var_1 )
|
|
{
|
|
var_2 = maps\mp\alien\_utility::get_alien_type();
|
|
var_3 = getcumulativedamage();
|
|
var_4 = level.alien_types[var_2].attributes["min_cumulative_pain_threshold"];
|
|
return var_3 < var_4;
|
|
}
|
|
|
|
getcumulativedamage()
|
|
{
|
|
var_0 = maps\mp\alien\_utility::get_alien_type();
|
|
var_1 = level.alien_types[var_0].attributes["min_cumulative_pain_buffer_time"] * 1000.0;
|
|
var_2 = 0;
|
|
var_3 = gettime();
|
|
|
|
for ( var_4 = 0; var_4 < self.recentdamages.size; var_4++ )
|
|
{
|
|
if ( var_3 - self.recentdamages[var_4]["time"] < var_1 )
|
|
var_2 = var_2 + self.recentdamages[var_4]["amount"];
|
|
}
|
|
|
|
return var_2;
|
|
}
|
|
|
|
gettargetpredictedposition( var_0, var_1 )
|
|
{
|
|
var_2 = var_0 getentityvelocity();
|
|
var_3 = var_0.origin + var_1 * var_2;
|
|
return var_3;
|
|
}
|
|
|
|
getattackposition( var_0, var_1, var_2 )
|
|
{
|
|
var_3 = 15;
|
|
var_4 = gettargetpredictedposition( var_0, var_2 );
|
|
var_5 = vectornormalize( self.origin - var_4 );
|
|
var_6 = var_4 + var_5 * var_1;
|
|
var_6 = getgroundposition( var_6, var_3, 64, 64 );
|
|
return var_6;
|
|
}
|
|
|
|
attemptmelee()
|
|
{
|
|
if ( !isdefined( self.enemy ) )
|
|
return 0;
|
|
|
|
self scragentbeginmelee( self.enemy );
|
|
return 1;
|
|
}
|
|
|
|
main()
|
|
{
|
|
self endon( "death" );
|
|
common_scripts\utility::waitframe();
|
|
var_0 = 0;
|
|
var_1 = 0;
|
|
|
|
if ( should_react_to_downed_enemies() )
|
|
thread downed_enemy_monitor();
|
|
|
|
for (;;)
|
|
{
|
|
if ( var_0 )
|
|
{
|
|
alien_test_loop();
|
|
continue;
|
|
}
|
|
|
|
if ( var_1 )
|
|
{
|
|
alien_test_jump();
|
|
continue;
|
|
}
|
|
|
|
alien_main_loop();
|
|
}
|
|
}
|
|
|
|
should_react_to_downed_enemies()
|
|
{
|
|
switch ( maps\mp\alien\_utility::get_alien_type() )
|
|
{
|
|
case "seeder":
|
|
case "gargoyle":
|
|
case "spitter":
|
|
case "minion":
|
|
case "elite":
|
|
return 0;
|
|
default:
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
downed_enemy_monitor()
|
|
{
|
|
self endon( "death" );
|
|
|
|
for (;;)
|
|
{
|
|
if ( !isplayer( self.enemy ) )
|
|
{
|
|
wait 0.05;
|
|
continue;
|
|
}
|
|
|
|
thread monitor_enemy_for_downed( self.enemy );
|
|
common_scripts\utility::waittill_any( "downed_enemy", "enemy" );
|
|
}
|
|
}
|
|
|
|
monitor_enemy_for_downed( var_0 )
|
|
{
|
|
self endon( "enemy" );
|
|
self endon( "death" );
|
|
var_0 common_scripts\utility::waittill_any( "death", "last_stand" );
|
|
var_1 = 65536;
|
|
|
|
if ( distancesquared( var_0.origin, self.origin ) < var_1 )
|
|
{
|
|
self.enemy_downed = 1;
|
|
self.downed_enemy_location = var_0.origin;
|
|
}
|
|
|
|
self notify( "downed_enemy" );
|
|
}
|
|
|
|
alien_test_loop()
|
|
{
|
|
var_0 = [ ( -296, 448, -352 ), ( 808, 300, -368 ), ( 1320.6, 482.8, -320 ) ];
|
|
wait 10;
|
|
|
|
for (;;)
|
|
{
|
|
foreach ( var_2 in var_0 )
|
|
{
|
|
if ( distancesquared( self.origin, var_2 ) < 100 )
|
|
continue;
|
|
|
|
self scragentsetgoalpos( var_2 );
|
|
self waittill( "goal_reached" );
|
|
wait 3;
|
|
}
|
|
}
|
|
}
|
|
|
|
alien_test_jump()
|
|
{
|
|
var_0 = [ ( -203.3, -898, 151.033 ), ( -1282.2, -669.1, -26.529 ) ];
|
|
wait 10;
|
|
|
|
for (;;)
|
|
{
|
|
foreach ( var_2 in var_0 )
|
|
{
|
|
if ( distancesquared( self.origin, var_2 ) < 100 )
|
|
continue;
|
|
|
|
self scragentsetgoalpos( var_2 );
|
|
self waittill( "goal_reached" );
|
|
wait 3;
|
|
}
|
|
}
|
|
}
|
|
|
|
handle_attractor_flare( var_0, var_1 )
|
|
{
|
|
if ( var_1 )
|
|
self.attractor_flare = var_0;
|
|
else
|
|
{
|
|
if ( !isdefined( self.attractor_flare ) )
|
|
return;
|
|
|
|
if ( isdefined( var_0 ) && var_0 != self.attractor_flare )
|
|
return;
|
|
|
|
self.attractor_flare = undefined;
|
|
}
|
|
|
|
self notify( "alien_main_loop_restart" );
|
|
}
|
|
|
|
react_to_attractor_flare()
|
|
{
|
|
var_0 = 3.0;
|
|
var_1 = 6.0;
|
|
var_2 = get_flare_node();
|
|
|
|
if ( isdefined( var_2 ) )
|
|
{
|
|
self scragentsetgoalnode( var_2 );
|
|
self scragentsetgoalradius( 64.0 );
|
|
self waittill( "goal_reached" );
|
|
|
|
while ( isdefined( self.attractor_flare ) )
|
|
wait 0.2;
|
|
}
|
|
}
|
|
|
|
get_flare_node()
|
|
{
|
|
var_0 = getnodesinradius( self.attractor_flare.origin, 300, 50, 128, "path" );
|
|
|
|
if ( var_0.size == 0 )
|
|
return undefined;
|
|
|
|
var_1 = [];
|
|
var_2 = vectornormalize( self.origin - self.attractor_flare.origin );
|
|
|
|
foreach ( var_4 in var_0 )
|
|
{
|
|
var_5 = vectornormalize( var_4.origin - self.attractor_flare.origin );
|
|
|
|
if ( vectordot( var_5, var_2 ) < 0 )
|
|
continue;
|
|
|
|
var_1[var_1.size] = var_4;
|
|
}
|
|
|
|
if ( var_1.size == 0 )
|
|
return var_0[randomint( var_0.size )];
|
|
|
|
return var_1[randomint( var_1.size )];
|
|
}
|
|
|
|
alien_main_loop()
|
|
{
|
|
self endon( "alien_main_loop_restart" );
|
|
|
|
for (;;)
|
|
{
|
|
self.looktarget = undefined;
|
|
var_0 = self.enemy;
|
|
|
|
if ( isdefined( self.alien_scripted ) && self.alien_scripted == 1 )
|
|
{
|
|
|
|
}
|
|
else if ( isdefined( self.attractor_flare ) )
|
|
react_to_attractor_flare();
|
|
else if ( isdefined( self.enemy_downed ) && self.enemy_downed )
|
|
{
|
|
posture_after_enemy_downed();
|
|
self.enemy_downed = 0;
|
|
self.downed_enemy_location = undefined;
|
|
}
|
|
else if ( isalive( var_0 ) )
|
|
{
|
|
if ( self.badpath )
|
|
[[ level.alien_funcs[maps\mp\alien\_utility::get_alien_type()]["badpath"] ]]( var_0 );
|
|
else
|
|
[[ level.alien_funcs[maps\mp\alien\_utility::get_alien_type()]["combat"] ]]( var_0 );
|
|
}
|
|
else if ( isdefined( self.pet ) && self.pet )
|
|
alien_pet_follow();
|
|
else
|
|
alien_noncombat();
|
|
|
|
wait 0.05;
|
|
}
|
|
}
|
|
|
|
posture_after_enemy_downed()
|
|
{
|
|
self endon( "damage" );
|
|
self endon( "enemy_downed_proximity_breached" );
|
|
var_0 = 4.0;
|
|
var_1 = 6.0;
|
|
var_2 = get_downed_posture_node();
|
|
|
|
if ( isdefined( var_2 ) )
|
|
{
|
|
self scragentsetgoalnode( var_2 );
|
|
self scragentsetgoalradius( 64.0 );
|
|
self waittill( "goal_reached" );
|
|
}
|
|
|
|
thread monitor_enemy_proximity_during_enemy_downed();
|
|
wait( randomfloatrange( var_0, var_1 ) );
|
|
}
|
|
|
|
monitor_enemy_proximity_during_enemy_downed()
|
|
{
|
|
self endon( "death" );
|
|
self endon( "damage" );
|
|
self endon( "alien_main_loop_restart" );
|
|
var_0 = 16384;
|
|
|
|
for (;;)
|
|
{
|
|
foreach ( var_2 in level.players )
|
|
{
|
|
if ( distancesquared( var_2.origin, self.origin ) < var_0 )
|
|
{
|
|
self notify( "enemy_downed_proximity_breached" );
|
|
return;
|
|
}
|
|
}
|
|
|
|
wait 0.1;
|
|
}
|
|
}
|
|
|
|
get_downed_posture_node()
|
|
{
|
|
var_0 = getnodesinradius( self.origin, 300, 50, 128, "path" );
|
|
|
|
if ( var_0.size == 0 )
|
|
return;
|
|
|
|
var_1 = [];
|
|
var_1["direction"] = "override";
|
|
var_1["direction_override"] = vectornormalize( self.origin - self.downed_enemy_location );
|
|
var_1["direction_weight"] = 10.0;
|
|
var_1["min_height"] = 64.0;
|
|
var_1["max_height"] = 400.0;
|
|
var_1["height_weight"] = 0.0;
|
|
var_1["enemy_los"] = 0;
|
|
var_1["enemy_los_weight"] = 0.0;
|
|
var_1["min_dist_from_enemy"] = 400.0;
|
|
var_1["max_dist_from_enemy"] = 800.0;
|
|
var_1["desired_dist_from_enemy"] = 600.0;
|
|
var_1["dist_from_enemy_weight"] = 0.0;
|
|
var_1["min_dist_from_all_enemies"] = 200.0;
|
|
var_1["min_dist_from_all_enemies_weight"] = 6.0;
|
|
var_1["not_recently_used_weight"] = 2.0;
|
|
var_1["random_weight"] = 1.0;
|
|
var_2 = get_retreat_node_rated( self.enemy, var_1, var_0 );
|
|
return var_2;
|
|
}
|
|
|
|
default_alien_combat( var_0 )
|
|
{
|
|
var_0 endon( "death" );
|
|
self endon( "enemy" );
|
|
self endon( "bad_path" );
|
|
clear_attacking( var_0 );
|
|
|
|
while ( isalive( var_0 ) )
|
|
{
|
|
self.looktarget = var_0;
|
|
|
|
if ( should_i_attack( var_0 ) )
|
|
{
|
|
set_attacking( var_0 );
|
|
alien_attack_enemy( var_0 );
|
|
clear_attacking( var_0 );
|
|
|
|
if ( should_i_retreat( var_0 ) )
|
|
alien_retreat( var_0 );
|
|
|
|
continue;
|
|
}
|
|
|
|
alien_wait_for_combat( var_0 );
|
|
}
|
|
}
|
|
|
|
alien_attack_enemy( var_0 )
|
|
{
|
|
if ( use_synched_attack( var_0 ) )
|
|
alien_synch_attack_enemy( var_0 );
|
|
else
|
|
alien_attack_sequence( var_0 );
|
|
}
|
|
|
|
use_synched_attack( var_0 )
|
|
{
|
|
switch ( maps\mp\alien\_utility::get_alien_type() )
|
|
{
|
|
case "seeder":
|
|
case "mammoth":
|
|
case "gargoyle":
|
|
case "locust":
|
|
case "spitter":
|
|
case "minion":
|
|
case "elite":
|
|
return 0;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return isdefined( var_0.synch_attack_setup );
|
|
}
|
|
|
|
alien_attack_sequence( var_0 )
|
|
{
|
|
var_1 = get_attack_sequence_num();
|
|
|
|
for ( var_2 = 0; var_2 < var_1; var_2++ )
|
|
{
|
|
var_3 = get_attack_num();
|
|
|
|
for ( var_4 = 0; var_4 < var_3; var_4++ )
|
|
{
|
|
if ( has_attack_abort_been_requested( self ) )
|
|
return;
|
|
|
|
var_5 = [[ level.alien_funcs[maps\mp\alien\_utility::get_alien_type()]["approach"] ]]( var_0, var_4 );
|
|
alien_attack( var_0, var_5 );
|
|
|
|
if ( distancesquared( self.origin, self.enemy.origin ) < 4096 )
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
alien_synch_attack_enemy( var_0 )
|
|
{
|
|
if ( distance2dsquared( self.origin, var_0.origin ) > 100 )
|
|
{
|
|
self scragentsetgoalradius( 100 );
|
|
self scragentsetgoalentity( var_0 );
|
|
self waittill( "goal_reached" );
|
|
}
|
|
|
|
var_1 = isalive( var_0.synch_attack_setup.primary_attacker ) && var_0.synch_attack_setup.primary_attacker != self;
|
|
var_2 = 1;
|
|
|
|
if ( isdefined( var_0.synch_attack_setup.can_synch_attack_func ) )
|
|
var_2 = var_0 [[ var_0.synch_attack_setup.can_synch_attack_func ]]();
|
|
|
|
if ( !var_1 && var_2 )
|
|
{
|
|
var_0.synch_attack_setup.primary_attacker = self;
|
|
select_synch_index( var_0 );
|
|
|
|
if ( should_move_to_synch_attack_pos( var_0 ) )
|
|
{
|
|
self scragentsetgoalradius( 30 );
|
|
self scragentsetgoalpos( self.synch_attack_pos );
|
|
self waittill( "goal_reached" );
|
|
}
|
|
|
|
synch_melee( var_0 );
|
|
}
|
|
else
|
|
swipe_static_melee( var_0 );
|
|
}
|
|
|
|
select_synch_index( var_0 )
|
|
{
|
|
var_1 = var_0 maps\mp\alien\_utility::get_synch_direction_list( self );
|
|
var_2 = vectornormalize( self.origin - var_0.origin );
|
|
var_3 = undefined;
|
|
var_4 = undefined;
|
|
var_5 = undefined;
|
|
var_6 = -1.1;
|
|
|
|
foreach ( var_17, var_8 in var_1 )
|
|
{
|
|
var_9 = var_8["attackerAnimState"];
|
|
var_10 = self getanimentry( var_9, 0 );
|
|
var_11 = getstartorigin( var_0.origin, var_0.angles, var_10 );
|
|
var_12 = length( var_11 - var_0.origin );
|
|
var_13 = var_8["offset_direction"] * var_12;
|
|
var_14 = var_0 localtoworldcoords( var_13 );
|
|
var_15 = vectornormalize( var_14 - var_0.origin );
|
|
var_16 = vectordot( var_15, var_2 );
|
|
|
|
if ( var_16 > var_6 )
|
|
{
|
|
var_3 = var_17;
|
|
var_4 = var_9;
|
|
var_5 = var_14;
|
|
var_6 = var_16;
|
|
}
|
|
}
|
|
|
|
self.synch_attack_index = var_3;
|
|
self.synch_anim_state = var_4;
|
|
self.synch_attack_pos = var_5;
|
|
}
|
|
|
|
should_move_to_synch_attack_pos( var_0 )
|
|
{
|
|
var_1 = 0.707;
|
|
var_2 = vectornormalize( self.synch_attack_pos - var_0.origin );
|
|
var_3 = vectornormalize( self.origin - var_0.origin );
|
|
var_4 = vectordot( var_2, var_3 ) > var_1;
|
|
var_5 = distancesquared( var_0.origin, self.origin ) > distancesquared( var_0.origin, self.synch_attack_pos );
|
|
return var_5 || !var_4;
|
|
}
|
|
|
|
alien_attack( var_0, var_1 )
|
|
{
|
|
self notify( "start_attack" );
|
|
|
|
switch ( var_1 )
|
|
{
|
|
case "swipe":
|
|
swipe_melee( var_0 );
|
|
break;
|
|
case "leap":
|
|
leap_melee( var_0 );
|
|
break;
|
|
case "wall":
|
|
wall_leap_melee( var_0 );
|
|
break;
|
|
case "badpath_jump":
|
|
badpath_jump( var_0 );
|
|
break;
|
|
case "spit":
|
|
maps\mp\agents\alien\_alien_spitter::spit_projectile( var_0 );
|
|
break;
|
|
case "charge":
|
|
maps\mp\agents\alien\_alien_elite::charge_attack( var_0 );
|
|
break;
|
|
case "slam":
|
|
maps\mp\agents\alien\_alien_elite::ground_slam( var_0 );
|
|
break;
|
|
case "angered":
|
|
maps\mp\agents\alien\_alien_elite::angered( var_0 );
|
|
break;
|
|
case "synch":
|
|
synch_melee( var_0 );
|
|
break;
|
|
case "swipe_static":
|
|
swipe_static_melee( var_0 );
|
|
break;
|
|
case "explode":
|
|
maps\mp\agents\alien\_alien_minion::explode_attack( var_0 );
|
|
case "none":
|
|
break;
|
|
default:
|
|
if ( isdefined( level.alien_attack_override_func ) )
|
|
{
|
|
if ( [[ level.alien_attack_override_func ]]( var_0, var_1 ) )
|
|
break;
|
|
}
|
|
|
|
wait 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
handle_badpath( var_0 )
|
|
{
|
|
var_0 endon( "death" );
|
|
var_0 endon( "disconnect" );
|
|
self endon( "bad_path" );
|
|
self.badpath = 0;
|
|
|
|
if ( !can_attempt_badpath_move() )
|
|
return;
|
|
|
|
if ( self.badpathcount > 3 )
|
|
{
|
|
if ( attempt_bad_path_move_nearby_node( var_0 ) )
|
|
self.badpathcount = 0;
|
|
|
|
return;
|
|
}
|
|
|
|
if ( !should_bad_path_melee() )
|
|
return;
|
|
|
|
if ( self.badpathcount == 1 )
|
|
var_1 = attempt_badpath_move_to_node( var_0, 0, 100, 50 );
|
|
else
|
|
var_1 = 0;
|
|
|
|
if ( !var_1 )
|
|
{
|
|
var_1 = attempt_badpath_move_to_node( var_0, 100, 256, 128 );
|
|
|
|
if ( !var_1 )
|
|
return;
|
|
}
|
|
|
|
if ( attempt_bad_path_melee( var_0 ) )
|
|
self.badpathcount = 0;
|
|
}
|
|
|
|
can_attempt_badpath_move()
|
|
{
|
|
switch ( self.currentanimstate )
|
|
{
|
|
case "traverse":
|
|
return 0;
|
|
default:
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
should_bad_path_melee()
|
|
{
|
|
switch ( maps\mp\alien\_utility::get_alien_type() )
|
|
{
|
|
case "seeder":
|
|
case "spitter":
|
|
return 0;
|
|
default:
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
attempt_bad_path_move_nearby_node( var_0 )
|
|
{
|
|
var_1 = 128;
|
|
var_2 = 512;
|
|
var_3 = getnodesinradius( self.origin, var_2, var_1, 256, "node_pathnode" );
|
|
|
|
if ( var_3.size == 0 )
|
|
return 0;
|
|
|
|
self scragentsetgoalpos( self.origin );
|
|
self scragentsetgoalradius( 2048 );
|
|
var_4 = var_3[randomint( var_3.size )];
|
|
|
|
if ( attempt_badpath_jump( var_0, var_4 ) )
|
|
return 1;
|
|
else
|
|
{
|
|
self scragentsetgoalnode( var_4 );
|
|
self scragentsetgoalradius( 64 );
|
|
self waittill( "goal_reached" );
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
attempt_bad_path_melee( var_0 )
|
|
{
|
|
var_1 = abs( self.origin[2] - var_0.origin[2] );
|
|
var_2 = distance2d( self.origin, var_0.origin );
|
|
|
|
if ( var_2 > 256 )
|
|
return 0;
|
|
|
|
var_3 = self agentcanseesentient( var_0 );
|
|
|
|
if ( var_3 && var_1 <= 50 && var_2 <= 150 )
|
|
{
|
|
self.bad_path_handled = 1;
|
|
|
|
if ( maps\mp\alien\_utility::should_explode() )
|
|
{
|
|
alien_attack( var_0, "explode" );
|
|
return 1;
|
|
}
|
|
else if ( maps\mp\alien\_utility::is_normal_upright( anglestoup( self.angles ) ) )
|
|
{
|
|
alien_attack( var_0, "swipe" );
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
self.leapendpos = maps\mp\agents\alien\_alien_melee::get_leap_end_pos( 1.0, 48, var_0 );
|
|
var_4 = maps\mp\agents\_scriptedagents::droppostoground( self.leapendpos, 256 );
|
|
|
|
if ( !isdefined( var_4 ) )
|
|
return 0;
|
|
|
|
if ( !trajectorycanattemptaccuratejump( self.origin, anglestoup( self.angles ), self.leapendpos, anglestoup( var_0.angles ), level.alien_jump_melee_gravity, 1.01 * level.alien_jump_melee_speed ) )
|
|
return 0;
|
|
|
|
var_5 = getnodesinradiussorted( var_4, 256, 0, 256 );
|
|
|
|
if ( !var_5.size )
|
|
return 0;
|
|
|
|
var_6 = getpathdist( var_4, var_5[0].origin, 512 );
|
|
|
|
if ( var_6 < 0 )
|
|
return 0;
|
|
|
|
leap_melee( var_0 );
|
|
return 1;
|
|
}
|
|
|
|
attempt_badpath_move_to_node( var_0, var_1, var_2, var_3 )
|
|
{
|
|
var_4 = getnodesinradius( var_0.origin, var_2, var_1, var_3 );
|
|
|
|
if ( var_4.size > 0 )
|
|
{
|
|
var_5 = var_4[randomint( var_4.size )];
|
|
self scragentsetgoalnode( var_5 );
|
|
self scragentsetgoalradius( 64 );
|
|
self waittill( "goal_reached" );
|
|
return 1;
|
|
}
|
|
|
|
wait 0.1;
|
|
return 0;
|
|
}
|
|
|
|
attempt_badpath_jump( var_0, var_1 )
|
|
{
|
|
var_2 = trajectorycanattemptaccuratejump( self.origin, anglestoup( self.angles ), var_1.origin, anglestoup( var_1.angles ), level.alien_jump_melee_gravity, 1.01 * level.alien_jump_melee_speed );
|
|
|
|
if ( var_2 || self.oriented )
|
|
{
|
|
self.leapendpos = var_1.origin;
|
|
self.leapendangles = var_1.angles;
|
|
alien_attack( var_0, "badpath_jump" );
|
|
self scragentsetgoalpos( self.origin );
|
|
self scragentsetgoalradius( 2048 );
|
|
self waittill( "goal_reached" );
|
|
}
|
|
|
|
wait 0.5;
|
|
return var_2;
|
|
}
|
|
|
|
restart_loop_near_enemy( var_0 )
|
|
{
|
|
self endon( "alien_main_loop_restart" );
|
|
var_0 endon( "death" );
|
|
self endon( "death" );
|
|
self endon( "bad_path" );
|
|
var_1 = 65536.0;
|
|
|
|
for (;;)
|
|
{
|
|
if ( distancesquared( self.origin, var_0.origin ) < var_1 )
|
|
self notify( "alien_main_loop_restart" );
|
|
|
|
wait 0.05;
|
|
}
|
|
}
|
|
|
|
set_attacking( var_0 )
|
|
{
|
|
var_0.current_attackers[var_0.current_attackers.size] = self;
|
|
self.attacking_player = 1;
|
|
self.bypass_max_attacker_counter = 0;
|
|
}
|
|
|
|
clear_attacking( var_0 )
|
|
{
|
|
if ( !isdefined( var_0.current_attackers ) )
|
|
var_0.current_attackers = [];
|
|
|
|
var_0.current_attackers = common_scripts\utility::array_remove( var_0.current_attackers, self );
|
|
self.attacking_player = 0;
|
|
self.abort_attack_requested = 0;
|
|
}
|
|
|
|
clean_up_attackers()
|
|
{
|
|
var_0 = [];
|
|
|
|
foreach ( var_2 in self.current_attackers )
|
|
{
|
|
if ( isalive( var_2 ) && isalive( var_2.enemy ) && var_2.enemy == self )
|
|
var_0[var_0.size] = var_2;
|
|
}
|
|
|
|
self.current_attackers = var_0;
|
|
}
|
|
|
|
should_i_attack( var_0 )
|
|
{
|
|
if ( !maps\mp\alien\_utility::is_idle_state_locked() && self.statelocked )
|
|
return 0;
|
|
|
|
var_0 clean_up_attackers();
|
|
return 1;
|
|
}
|
|
|
|
should_i_retreat( var_0 )
|
|
{
|
|
if ( isdefined( level.dlc_alien_can_retreat_override_func ) )
|
|
{
|
|
if ( ![[ level.dlc_alien_can_retreat_override_func ]]( var_0 ) )
|
|
return 0;
|
|
}
|
|
|
|
switch ( maps\mp\alien\_utility::get_alien_type() )
|
|
{
|
|
case "elite":
|
|
return 0;
|
|
default:
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
replace_attacker_request( var_0 )
|
|
{
|
|
var_0.abort_attack_requested = 1;
|
|
}
|
|
|
|
has_attack_abort_been_requested( var_0 )
|
|
{
|
|
return isdefined( var_0.abort_attack_requested ) && var_0.abort_attack_requested;
|
|
}
|
|
|
|
find_attacker_to_replace( var_0, var_1 )
|
|
{
|
|
var_2 = level.alien_types[self.alien_type].attributes["attacker_priority"];
|
|
var_3 = level.alien_types[self.alien_type].attributes["attacker_difficulty"] - ( level.maxalienattackerdifficultyvalue - var_1 );
|
|
var_4 = [];
|
|
|
|
foreach ( var_6 in var_0.current_attackers )
|
|
{
|
|
if ( has_attack_abort_been_requested( var_6 ) )
|
|
continue;
|
|
|
|
if ( var_2 < level.alien_types[var_6.alien_type].attributes["attacker_priority"] )
|
|
{
|
|
var_3 = var_3 - level.alien_types[var_6.alien_type].attributes["attacker_difficulty"];
|
|
var_4[var_4.size] = var_6;
|
|
|
|
if ( var_3 <= 0 )
|
|
break;
|
|
}
|
|
}
|
|
|
|
return var_4;
|
|
}
|
|
|
|
get_current_attacker_value( var_0 )
|
|
{
|
|
var_1 = 0.0;
|
|
|
|
if ( !isdefined( var_0.current_attackers ) )
|
|
return var_1;
|
|
|
|
foreach ( var_3 in var_0.current_attackers )
|
|
{
|
|
if ( !isalive( var_3 ) )
|
|
continue;
|
|
|
|
if ( has_attack_abort_been_requested( var_3 ) )
|
|
continue;
|
|
|
|
var_1 = var_1 + level.alien_types[var_3.alien_type].attributes["attacker_difficulty"];
|
|
}
|
|
|
|
return var_1;
|
|
}
|
|
|
|
alien_noncombat()
|
|
{
|
|
self scragentsetgoalpos( self.origin );
|
|
|
|
for (;;)
|
|
{
|
|
if ( isalive( self.enemy ) )
|
|
break;
|
|
|
|
wait 1;
|
|
}
|
|
}
|
|
|
|
alien_pet_follow()
|
|
{
|
|
var_0 = 768;
|
|
|
|
if ( isdefined( self.petfollowdist ) )
|
|
var_0 = self.petfollowdist;
|
|
|
|
var_1 = var_0 * var_0;
|
|
self scragentsetgoalradius( var_0 );
|
|
|
|
while ( !isalive( self.enemy ) )
|
|
{
|
|
if ( !isdefined( self.owner ) || !isalive( self.owner ) )
|
|
{
|
|
var_2 = undefined;
|
|
|
|
foreach ( var_4 in level.players )
|
|
{
|
|
if ( isalive( var_4 ) )
|
|
{
|
|
var_2 = var_4;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( isdefined( var_2 ) )
|
|
self.owner = var_2;
|
|
else
|
|
self scragentsetgoalpos( self.origin );
|
|
}
|
|
else
|
|
{
|
|
var_6 = distancesquared( self.owner.origin, self.origin );
|
|
|
|
if ( var_6 > var_1 )
|
|
{
|
|
var_7 = get_pet_follow_node( self.owner );
|
|
|
|
if ( !isdefined( var_7 ) )
|
|
{
|
|
wait 1.0;
|
|
continue;
|
|
}
|
|
|
|
self scragentsetgoalnode( var_7 );
|
|
self scragentsetgoalradius( 64 );
|
|
self waittill( "goal_reached" );
|
|
wait( randomfloatrange( 0.5, 1.5 ) );
|
|
}
|
|
}
|
|
|
|
wait 0.05;
|
|
}
|
|
}
|
|
|
|
alien_wait_for_combat( var_0 )
|
|
{
|
|
self endon( "go to combat" );
|
|
thread monitor_proximity_with_enemy( var_0 );
|
|
thread watch_for_damage( var_0 );
|
|
thread random_movemode_change( 0, 70, 30, 1.5, 3.0 );
|
|
|
|
for (;;)
|
|
{
|
|
var_1 = common_scripts\utility::cointoss();
|
|
var_2 = getnodesinradius( self.origin, 512, 256, 256 );
|
|
|
|
if ( var_2.size == 0 )
|
|
{
|
|
wait 1;
|
|
self notify( "go to combat" );
|
|
return;
|
|
}
|
|
|
|
var_3 = self.origin - var_0.origin;
|
|
var_4 = vectortoangles( var_3 );
|
|
var_5 = anglestoright( var_4 );
|
|
|
|
if ( var_1 )
|
|
var_5 = var_5 * -1;
|
|
|
|
var_6 = [];
|
|
var_6["direction"] = "override";
|
|
var_6["direction_weight"] = 2.0;
|
|
var_6["min_height"] = -32.0;
|
|
var_6["max_height"] = 128.0;
|
|
var_6["height_weight"] = 1.0;
|
|
var_6["enemy_los"] = 1;
|
|
var_6["enemy_los_weight"] = 2.0;
|
|
var_6["min_dist_from_enemy"] = 600.0;
|
|
var_6["max_dist_from_enemy"] = 1000.0;
|
|
var_6["desired_dist_from_enemy"] = 800.0;
|
|
var_6["dist_from_enemy_weight"] = 3.0;
|
|
var_6["min_dist_from_all_enemies"] = 400.0;
|
|
var_6["min_dist_from_all_enemies_weight"] = 1.0;
|
|
var_6["not_recently_used_weight"] = 4.0;
|
|
var_6["random_weight"] = 1.0;
|
|
var_6["direction_override"] = var_5;
|
|
var_7 = get_retreat_node_rated( var_0, var_6, var_2 );
|
|
self scragentsetgoalnode( var_7 );
|
|
self scragentsetgoalradius( 64 );
|
|
self waittill( "goal_reached" );
|
|
wait( randomfloatrange( 1.5, 3.5 ) );
|
|
|
|
if ( should_i_attack( var_0 ) )
|
|
{
|
|
self notify( "go to combat" );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
alien_retreat( var_0 )
|
|
{
|
|
self notify( "start retreat" );
|
|
set_alien_movemode( "run" );
|
|
var_1 = "elevated_delay";
|
|
var_2 = "alien_forward";
|
|
|
|
if ( !isdefined( var_1 ) || var_1 == "" )
|
|
var_1 = "randomize";
|
|
|
|
if ( !isdefined( var_2 ) || var_2 == "" )
|
|
var_2 = "alien_forward";
|
|
|
|
if ( var_1 == "randomize" )
|
|
{
|
|
var_3 = [ "elevated_delay", "cover", "cover", "cover" ];
|
|
var_4 = randomint( 4 );
|
|
var_1 = var_3[var_4];
|
|
}
|
|
|
|
switch ( var_1 )
|
|
{
|
|
case "elevated_delay":
|
|
elevated_delay_retreat( var_0, var_2 );
|
|
break;
|
|
case "cover":
|
|
cover_retreat( var_0, var_2 );
|
|
break;
|
|
default:
|
|
wait 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
monitor_proximity_with_enemy( var_0 )
|
|
{
|
|
self endon( "go to combat" );
|
|
self endon( "damage" );
|
|
self endon( "death" );
|
|
self endon( "alien_main_loop_restart" );
|
|
var_0 endon( "death" );
|
|
var_0 endon( "disconnect" );
|
|
wait_for_proximity_check_activation( var_0 );
|
|
|
|
for (;;)
|
|
{
|
|
if ( distancesquared( self.origin, var_0.origin ) < 65536 )
|
|
{
|
|
self.attack_sequence_num = 1;
|
|
self.attack_num = 1;
|
|
self.bypass_max_attacker_counter = 1;
|
|
self notify( "go to combat" );
|
|
break;
|
|
}
|
|
|
|
common_scripts\utility::waitframe();
|
|
}
|
|
}
|
|
|
|
watch_for_damage( var_0 )
|
|
{
|
|
self endon( "go to combat" );
|
|
self endon( "death" );
|
|
self endon( "alien_main_loop_restart" );
|
|
var_0 endon( "death" );
|
|
self waittill( "damage" );
|
|
self.bypass_max_attacker_counter = 1;
|
|
self notify( "go to combat" );
|
|
}
|
|
|
|
wait_for_proximity_check_activation( var_0 )
|
|
{
|
|
var_1 = 2;
|
|
var_2 = gettime();
|
|
|
|
for (;;)
|
|
{
|
|
if ( distancesquared( self.origin, var_0.origin ) > 65536 )
|
|
break;
|
|
else if ( gettime() - var_2 > var_1 * 1000 )
|
|
break;
|
|
|
|
common_scripts\utility::waitframe();
|
|
}
|
|
}
|
|
|
|
elevated_delay_retreat( var_0, var_1 )
|
|
{
|
|
var_2 = get_elevated_jump_node( var_0, var_1 );
|
|
|
|
if ( !isdefined( var_2 ) )
|
|
{
|
|
wait 0.05;
|
|
return;
|
|
}
|
|
|
|
self scragentsetgoalnode( var_2 );
|
|
self scragentsetgoalradius( 32 );
|
|
self waittill( "goal_reached" );
|
|
wait 1.5;
|
|
}
|
|
|
|
get_elevated_jump_node( var_0, var_1 )
|
|
{
|
|
var_2 = getnodesinradius( var_0.origin, 800, 400, 256, "jump" );
|
|
|
|
if ( var_2.size == 0 )
|
|
return;
|
|
|
|
var_3 = [];
|
|
|
|
if ( getdvarint( "alien_retreat_towards_spawn" ) == 1 )
|
|
{
|
|
var_3["direction"] = "override";
|
|
var_3["direction_override"] = vectornormalize( self.spawnorigin - var_0.origin );
|
|
var_3["direction_weight"] = 8.0;
|
|
}
|
|
else
|
|
{
|
|
var_3["direction"] = var_1;
|
|
var_3["direction_weight"] = 1.0;
|
|
}
|
|
|
|
var_3["min_height"] = 64.0;
|
|
var_3["max_height"] = 400.0;
|
|
var_3["height_weight"] = 2.0;
|
|
var_3["enemy_los"] = 1;
|
|
var_3["enemy_los_weight"] = 2.0;
|
|
var_3["min_dist_from_enemy"] = 400.0;
|
|
var_3["max_dist_from_enemy"] = 800.0;
|
|
var_3["desired_dist_from_enemy"] = 600.0;
|
|
var_3["dist_from_enemy_weight"] = 3.0;
|
|
var_3["min_dist_from_all_enemies"] = 200.0;
|
|
var_3["min_dist_from_all_enemies_weight"] = 1.0;
|
|
var_3["not_recently_used_weight"] = 4.0;
|
|
var_3["random_weight"] = 1.0;
|
|
var_4 = get_retreat_node_rated( var_0, var_3, var_2 );
|
|
return var_4;
|
|
}
|
|
|
|
cover_retreat( var_0, var_1 )
|
|
{
|
|
var_2 = 1;
|
|
self endon( "go to combat" );
|
|
thread monitor_proximity_with_enemy( var_0 );
|
|
thread watch_for_damage( var_0 );
|
|
var_3 = [];
|
|
|
|
if ( getdvarint( "alien_cover_node_retreat" ) == 1 )
|
|
{
|
|
var_3["direction"] = "cover";
|
|
var_3["direction_weight"] = 2.0;
|
|
var_3["enemy_los_weight"] = 0.0;
|
|
var_3["max_dist_from_enemy"] = 1200.0;
|
|
}
|
|
else if ( getdvarint( "alien_retreat_towards_spawn" ) == 1 )
|
|
{
|
|
var_3["direction"] = "override";
|
|
var_3["direction_override"] = vectornormalize( self.spawnorigin - var_0.origin );
|
|
var_3["direction_weight"] = 8.0;
|
|
var_3["enemy_los_weight"] = 6.0;
|
|
var_3["max_dist_from_enemy"] = 800.0;
|
|
}
|
|
else
|
|
{
|
|
var_3["direction"] = var_1;
|
|
var_3["direction_weight"] = 1.0;
|
|
var_3["enemy_los_weight"] = 6.0;
|
|
var_3["max_dist_from_enemy"] = 800.0;
|
|
}
|
|
|
|
var_3["min_height"] = -32.0;
|
|
var_3["max_height"] = 128.0;
|
|
var_3["height_weight"] = 1.0;
|
|
var_3["enemy_los"] = 0;
|
|
var_3["min_dist_from_enemy"] = 400.0;
|
|
var_3["desired_dist_from_enemy"] = 600.0;
|
|
var_3["dist_from_enemy_weight"] = 2.0;
|
|
var_3["min_dist_from_all_enemies"] = 200.0;
|
|
var_3["min_dist_from_all_enemies_weight"] = 1.0;
|
|
var_3["min_dist_from_current_position"] = 256.0;
|
|
var_3["min_dist_from_current_position_weight"] = 3.0;
|
|
var_3["not_recently_used_weight"] = 4.0;
|
|
var_3["random_weight"] = 1.0;
|
|
var_4 = get_cover_node( var_0, var_3 );
|
|
|
|
if ( !isdefined( var_4 ) )
|
|
return;
|
|
|
|
self scragentsetgoalnode( var_4 );
|
|
self scragentsetgoalradius( 64 );
|
|
self waittill( "goal_reached" );
|
|
|
|
for ( var_5 = 0; var_5 < var_2; var_5++ )
|
|
{
|
|
var_3["direction"] = "alien_forward";
|
|
var_4 = get_cover_node( var_0, var_3 );
|
|
|
|
if ( !isdefined( var_4 ) )
|
|
return;
|
|
|
|
self scragentsetgoalnode( var_4 );
|
|
self scragentsetgoalradius( 64 );
|
|
self waittill( "goal_reached" );
|
|
}
|
|
}
|
|
|
|
get_cover_node( var_0, var_1 )
|
|
{
|
|
if ( getdvarint( "alien_cover_node_retreat" ) == 1 )
|
|
var_2 = getnodesinradius( var_0.origin, 800, 400, 256, "cover stand" );
|
|
else
|
|
var_2 = getnodesinradius( var_0.origin, 800, 400, 256 );
|
|
|
|
if ( var_2.size == 0 )
|
|
return undefined;
|
|
|
|
var_3 = get_retreat_node_rated( var_0, var_1, var_2 );
|
|
return var_3;
|
|
}
|
|
|
|
circling_retreat( var_0, var_1 )
|
|
{
|
|
self endon( "go to combat" );
|
|
thread monitor_proximity_with_enemy( var_0 );
|
|
thread watch_for_damage( var_0 );
|
|
var_2 = getnodesinradius( var_0.origin, 800, 400, 256 );
|
|
|
|
if ( var_2.size == 0 )
|
|
var_2 = getnodesinradius( var_0.origin, 2000, 400, 256 );
|
|
|
|
var_3 = [];
|
|
var_3["direction"] = var_1;
|
|
var_3["direction_weight"] = 1.0;
|
|
var_3["min_height"] = -32.0;
|
|
var_3["max_height"] = 32.0;
|
|
var_3["height_weight"] = 2.0;
|
|
var_3["enemy_los"] = 1;
|
|
var_3["enemy_los_weight"] = 2.0;
|
|
var_3["min_dist_from_enemy"] = 400.0;
|
|
var_3["max_dist_from_enemy"] = 800.0;
|
|
var_3["desired_dist_from_enemy"] = 600.0;
|
|
var_3["dist_from_enemy_weight"] = 3.0;
|
|
var_3["min_dist_from_all_enemies"] = 200.0;
|
|
var_3["min_dist_from_all_enemies_weight"] = 1.0;
|
|
var_3["not_recently_used_weight"] = 4.0;
|
|
var_3["random_weight"] = 2.0;
|
|
var_4 = get_retreat_node_rated( var_0, var_3, var_2 );
|
|
self scragentsetgoalnode( var_4 );
|
|
self scragentsetgoalradius( 64 );
|
|
self waittill( "goal_reached" );
|
|
var_5 = randomint( 2 );
|
|
|
|
for ( var_6 = 0; var_6 < getdvarint( "alien_circling_retreat_num_nodes" ) - 1; var_6++ )
|
|
{
|
|
var_7 = self.origin - var_0.origin;
|
|
var_8 = vectortoangles( var_7 );
|
|
var_9 = anglestoright( var_8 );
|
|
|
|
if ( var_5 )
|
|
var_9 = var_9 * -1;
|
|
|
|
var_2 = getnodesinradius( var_0.origin, 800, 500, 256 );
|
|
|
|
if ( var_2.size == 0 )
|
|
var_2 = getnodesinradius( var_0.origin, 2000, 400, 256 );
|
|
|
|
var_3["direction"] = "override";
|
|
var_3["direction_override"] = var_9;
|
|
var_3["direction_weight"] = 2.0;
|
|
var_3["random_weight"] = 1.0;
|
|
var_3["min_dist_from_current_position"] = 256.0;
|
|
var_3["min_dist_from_current_position_weight"] = 3.0;
|
|
var_10 = get_retreat_node_rated( var_0, var_3, var_2 );
|
|
self scragentsetgoalnode( var_10 );
|
|
self scragentsetgoalradius( 64 );
|
|
self waittill( "goal_reached" );
|
|
}
|
|
}
|
|
|
|
elevated_circling_retreat( var_0, var_1 )
|
|
{
|
|
self endon( "go to combat" );
|
|
thread monitor_proximity_with_enemy( var_0 );
|
|
thread watch_for_damage( var_0 );
|
|
var_2 = get_elevated_jump_node( var_0, var_1 );
|
|
|
|
if ( !isdefined( var_2 ) )
|
|
return;
|
|
|
|
self scragentsetgoalnode( var_2 );
|
|
self scragentsetgoalradius( 64 );
|
|
self waittill( "goal_reached" );
|
|
var_3 = [];
|
|
var_3["direction"] = var_1;
|
|
var_3["direction_weight"] = 1.0;
|
|
var_3["min_height"] = -32.0;
|
|
var_3["max_height"] = 32.0;
|
|
var_3["height_weight"] = 2.0;
|
|
var_3["enemy_los"] = 1;
|
|
var_3["enemy_los_weight"] = 2.0;
|
|
var_3["min_dist_from_enemy"] = 400.0;
|
|
var_3["max_dist_from_enemy"] = 800.0;
|
|
var_3["desired_dist_from_enemy"] = 600.0;
|
|
var_3["dist_from_enemy_weight"] = 3.0;
|
|
var_3["min_dist_from_all_enemies"] = 200.0;
|
|
var_3["min_dist_from_all_enemies_weight"] = 1.0;
|
|
var_3["not_recently_used_weight"] = 4.0;
|
|
var_3["random_weight"] = 2.0;
|
|
var_4 = randomint( 2 );
|
|
|
|
for ( var_5 = 0; var_5 < getdvarint( "alien_circling_retreat_num_nodes" ) - 1; var_5++ )
|
|
{
|
|
var_6 = self.origin - var_0.origin;
|
|
var_7 = vectortoangles( var_6 );
|
|
var_8 = anglestoright( var_7 );
|
|
|
|
if ( var_4 )
|
|
var_8 = var_8 * -1;
|
|
|
|
var_9 = getnodesinradius( self.origin, 800, 250, 256, "jump" );
|
|
|
|
if ( var_9.size == 0 )
|
|
return;
|
|
|
|
var_3["direction"] = "override";
|
|
var_3["direction_override"] = var_8;
|
|
var_3["direction_weight"] = 2.0;
|
|
var_3["random_weight"] = 1.0;
|
|
var_3["min_dist_from_current_position"] = 256.0;
|
|
var_3["min_dist_from_current_position_weight"] = 3.0;
|
|
var_10 = get_retreat_node_rated( var_0, var_3, var_9 );
|
|
self scragentsetgoalnode( var_10 );
|
|
self scragentsetgoalradius( 64 );
|
|
self waittill( "goal_reached" );
|
|
}
|
|
}
|
|
|
|
close_range_retreat( var_0 )
|
|
{
|
|
self endon( "go to combat" );
|
|
thread monitor_proximity_with_enemy( var_0 );
|
|
thread watch_for_damage( var_0 );
|
|
set_alien_movemode( "run" );
|
|
var_1 = 55;
|
|
var_2 = 75;
|
|
var_3 = 256;
|
|
var_4 = 256;
|
|
var_5 = get_offset_location_from_enemy( var_0, var_3, var_4, var_1, var_2 );
|
|
var_6 = getnodesinradius( var_5, 256, 0, 128, "path" );
|
|
|
|
if ( var_6.size == 0 )
|
|
var_6 = getnodesinradius( var_5, 500, 256, 128, "path" );
|
|
|
|
if ( var_6.size == 0 )
|
|
{
|
|
wait 0.2;
|
|
return;
|
|
}
|
|
|
|
var_7 = [];
|
|
|
|
if ( getdvarint( "alien_retreat_towards_spawn" ) == 1 )
|
|
var_7["direction_weight"] = 8.0;
|
|
else
|
|
var_7["direction_weight"] = 3.0;
|
|
|
|
var_7["direction"] = "override";
|
|
var_7["direction_override"] = vectornormalize( var_5 - self.origin );
|
|
var_7["min_height"] = -32.0;
|
|
var_7["max_height"] = 32.0;
|
|
var_7["height_weight"] = 6.0;
|
|
var_7["enemy_los"] = 0;
|
|
var_7["enemy_los_weight"] = 0.0;
|
|
var_7["min_dist_from_enemy"] = 150.0;
|
|
var_7["max_dist_from_enemy"] = 800.0;
|
|
var_7["desired_dist_from_enemy"] = 200.0;
|
|
var_7["dist_from_enemy_weight"] = 3.0;
|
|
var_7["min_dist_from_all_enemies"] = 150.0;
|
|
var_7["min_dist_from_all_enemies_weight"] = 1.0;
|
|
var_7["not_recently_used_weight"] = 4.0;
|
|
var_7["random_weight"] = 2.0;
|
|
var_8 = get_retreat_node_rated( var_0, var_7, var_6 );
|
|
self scragentsetgoalnode( var_8 );
|
|
self scragentsetgoalradius( 64 );
|
|
self waittill( "goal_reached" );
|
|
}
|
|
|
|
get_retreat_node_rated( var_0, var_1, var_2 )
|
|
{
|
|
if ( var_2.size == 0 )
|
|
return undefined;
|
|
|
|
var_3 = var_1["direction"];
|
|
var_4 = var_1["direction_weight"];
|
|
var_5 = var_1["min_height"];
|
|
var_6 = var_1["max_height"];
|
|
var_7 = var_1["height_weight"];
|
|
var_8 = var_1["enemy_los"];
|
|
var_9 = var_1["enemy_los_weight"];
|
|
var_10 = var_1["min_dist_from_enemy"];
|
|
var_11 = var_1["max_dist_from_enemy"];
|
|
var_12 = var_1["desired_dist_from_enemy"];
|
|
var_13 = var_1["dist_from_enemy_weight"];
|
|
var_14 = var_1["min_dist_from_all_enemies"];
|
|
var_15 = var_1["min_dist_from_all_enemies_weight"];
|
|
var_16 = var_1["min_dist_from_current_position"];
|
|
var_17 = var_1["min_dist_from_current_position_weight"];
|
|
var_18 = var_1["not_recently_used_weight"];
|
|
var_19 = var_1["random_weight"];
|
|
|
|
if ( isdefined( var_1["recently_used_time_limit"] ) )
|
|
var_20 = var_1["recently_used_time_limit"];
|
|
else
|
|
var_20 = 10.0;
|
|
|
|
if ( isdefined( var_1["test_offset"] ) )
|
|
var_21 = var_1["test_offset"];
|
|
else
|
|
var_21 = ( 0, 0, 0 );
|
|
|
|
var_22 = undefined;
|
|
|
|
if ( isplayer( var_0 ) )
|
|
var_22 = anglestoforward( var_0 getplayerangles() );
|
|
else if ( isdefined( var_0 ) )
|
|
var_22 = anglestoforward( var_0.angles );
|
|
|
|
var_23 = undefined;
|
|
var_24 = 0;
|
|
|
|
if ( var_3 == "player_front" )
|
|
var_23 = var_22;
|
|
else if ( var_3 == "player_behind" )
|
|
var_23 = var_22 * -1;
|
|
else if ( var_3 == "alien_forward" )
|
|
var_23 = anglestoforward( self.angles );
|
|
else if ( var_3 == "alien_backward" )
|
|
var_23 = anglestoforward( self.angles ) * -1;
|
|
else if ( var_3 == "cover" )
|
|
var_24 = 1;
|
|
else if ( var_3 == "override" )
|
|
var_23 = var_1["direction_override"];
|
|
else
|
|
{
|
|
|
|
}
|
|
|
|
var_25 = 0;
|
|
var_26 = -1.0;
|
|
var_27 = 0;
|
|
|
|
for ( var_28 = 0; var_25 < var_2.size; var_25++ )
|
|
{
|
|
var_29 = var_2[var_25];
|
|
var_30 = var_29.origin + var_21;
|
|
var_31 = 0.0;
|
|
|
|
if ( var_7 > 0.0 )
|
|
{
|
|
if ( var_30[2] - var_0.origin[2] > var_5 && var_30[2] - var_0.origin[2] < var_6 )
|
|
var_31 = var_31 + var_7;
|
|
}
|
|
|
|
var_32 = undefined;
|
|
|
|
if ( var_24 )
|
|
{
|
|
var_23 = anglestoforward( var_29.angles );
|
|
var_32 = vectornormalize( var_0.origin - var_30 );
|
|
}
|
|
else
|
|
var_32 = vectornormalize( var_30 - self.origin );
|
|
|
|
var_33 = vectordot( var_23, var_32 );
|
|
var_31 = var_31 + ( var_33 + 1.0 ) * 0.5 * var_4;
|
|
|
|
if ( var_13 > 0.0 )
|
|
{
|
|
var_34 = distance( var_30, var_0.origin );
|
|
|
|
if ( var_34 > var_10 && var_34 < var_11 )
|
|
{
|
|
var_35 = 0.0;
|
|
|
|
if ( var_34 > var_12 )
|
|
var_35 = var_35 + ( 1 - ( var_34 - var_12 ) / ( var_11 - var_12 ) );
|
|
else
|
|
var_35 = var_35 + ( var_34 - var_10 ) / ( var_12 - var_10 );
|
|
|
|
var_31 = var_31 + var_35 * var_13;
|
|
}
|
|
}
|
|
|
|
if ( var_15 )
|
|
{
|
|
var_36 = 1;
|
|
|
|
foreach ( var_38 in level.players )
|
|
{
|
|
if ( !isdefined( var_0 ) || var_38 != var_0 )
|
|
{
|
|
if ( distancesquared( var_30, var_38.origin ) < var_14 * var_14 )
|
|
{
|
|
var_36 = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( var_36 )
|
|
var_31 = var_31 + var_15;
|
|
}
|
|
|
|
if ( isdefined( var_17 ) && var_17 > 0.0 )
|
|
{
|
|
if ( distancesquared( self.origin, var_30 ) > var_16 * var_16 )
|
|
var_31 = var_31 + var_17;
|
|
}
|
|
|
|
if ( !node_recently_used( var_29, var_20 ) )
|
|
var_31 = var_31 + var_18;
|
|
|
|
if ( var_19 > 0.0 )
|
|
var_31 = var_31 + randomfloat( var_19 );
|
|
|
|
if ( var_9 > 0.0 && var_31 > var_26 - var_9 )
|
|
{
|
|
while ( max_traces_reached() )
|
|
{
|
|
var_28++;
|
|
|
|
if ( var_28 >= 20 )
|
|
break;
|
|
|
|
common_scripts\utility::waitframe();
|
|
}
|
|
|
|
if ( isdefined( var_0 ) )
|
|
{
|
|
var_40 = sighttracepassed( var_0 get_eye_position(), var_30 + ( 0, 0, 50 ), 0, self );
|
|
level.nodefiltertracesthisframe++;
|
|
|
|
if ( var_8 == var_40 )
|
|
var_31 = var_31 + var_9;
|
|
}
|
|
}
|
|
|
|
if ( var_31 > var_26 )
|
|
{
|
|
var_26 = var_31;
|
|
var_27 = var_25;
|
|
}
|
|
}
|
|
|
|
register_node( var_2[var_27] );
|
|
return var_2[var_27];
|
|
}
|
|
|
|
get_eye_position()
|
|
{
|
|
if ( isalive( self ) && ( isplayer( self ) || isagent( self ) ) )
|
|
return self geteye();
|
|
|
|
return self.origin;
|
|
}
|
|
|
|
max_traces_reached()
|
|
{
|
|
var_0 = 5;
|
|
|
|
if ( gettime() > level.nodefiltertracestime )
|
|
{
|
|
level.nodefiltertracestime = gettime();
|
|
level.nodefiltertracesthisframe = 0;
|
|
}
|
|
|
|
return level.nodefiltertracesthisframe >= var_0;
|
|
}
|
|
|
|
default_approach( var_0, var_1 )
|
|
{
|
|
var_2 = do_initial_approach( var_0 );
|
|
var_3 = self.swipechance;
|
|
var_4 = randomfloat( 1.0 ) < var_3;
|
|
|
|
if ( !var_4 && go_to_leaping_melee_position( var_0 ) )
|
|
return "leap";
|
|
|
|
return go_for_swipe( var_0, var_2 );
|
|
}
|
|
|
|
do_initial_approach( var_0 )
|
|
{
|
|
thread jogwhenclosetoenemy( var_0 );
|
|
var_1 = undefined;
|
|
|
|
if ( distancesquared( self.origin, var_0.origin ) > 250000.0 )
|
|
var_1 = approach_enemy( 400, var_0, 3 );
|
|
|
|
return var_1;
|
|
}
|
|
|
|
jogwhenclosetoenemy( var_0 )
|
|
{
|
|
self notify( "jogWhenCloseToEnemy" );
|
|
self endon( "jogWhenCloseToEnemy" );
|
|
self endon( "death" );
|
|
var_0 endon( "death" );
|
|
var_0 endon( "disconnect" );
|
|
level endon( "game_ended" );
|
|
|
|
if ( distancesquared( self.origin, var_0.origin ) >= 4000000 )
|
|
set_alien_movemode( "run" );
|
|
|
|
for (;;)
|
|
{
|
|
wait 1.0;
|
|
|
|
if ( distancesquared( self.origin, var_0.origin ) < 4000000 )
|
|
break;
|
|
}
|
|
|
|
switchtojog();
|
|
}
|
|
|
|
switchtojog()
|
|
{
|
|
if ( self.movemode == "jog" )
|
|
return;
|
|
|
|
var_0 = 0.9;
|
|
set_alien_movemode( "jog" );
|
|
self.moveplaybackrate = self.moveplaybackrate * var_0;
|
|
thread backtorunondamage( 1 );
|
|
}
|
|
|
|
backtorunondamage( var_0 )
|
|
{
|
|
self notify( "backToRunOnDamage" );
|
|
self endon( "backToRunOnDamage" );
|
|
self endon( "death" );
|
|
level endon( "game_ended" );
|
|
|
|
if ( isdefined( var_0 ) && var_0 )
|
|
common_scripts\utility::waittill_any( "damage", "start_attack", "bulletwhizby" );
|
|
else
|
|
common_scripts\utility::waittill_any( "damage", "start_attack" );
|
|
|
|
set_alien_movemode( "run" );
|
|
self.moveplaybackrate = self.defaultmoveplaybackrate;
|
|
}
|
|
|
|
sneak_up_on( var_0 )
|
|
{
|
|
self endon( "death" );
|
|
self endon( "start_attack" );
|
|
set_alien_movemode( "walk" );
|
|
var_1 = 1.05;
|
|
|
|
for (;;)
|
|
{
|
|
wait 1.0;
|
|
|
|
if ( in_front_players() || distancesquared( self.origin, var_0.origin ) > 160000 * var_1 )
|
|
{
|
|
set_alien_movemode( "run" );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
in_front_players()
|
|
{
|
|
foreach ( var_1 in level.players )
|
|
{
|
|
if ( in_front_of( var_1 ) )
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
in_front_of( var_0 )
|
|
{
|
|
var_1 = 0.5;
|
|
var_2 = self.origin - var_0.origin;
|
|
var_3 = anglestoforward( var_0.angles );
|
|
var_4 = vectordot( var_2, var_3 );
|
|
|
|
if ( var_4 < 0 )
|
|
return 0;
|
|
|
|
var_5 = var_4 > var_1;
|
|
return var_5;
|
|
}
|
|
|
|
go_for_swipe( var_0, var_1 )
|
|
{
|
|
var_2 = getdvarint( "alien_melee_distance" );
|
|
|
|
if ( var_2 < 100 )
|
|
var_2 = 100;
|
|
|
|
run_near_enemy( var_2, var_0 );
|
|
|
|
if ( !self agentcanseesentient( var_0 ) )
|
|
return "none";
|
|
|
|
return "swipe";
|
|
}
|
|
|
|
find_wall_leap_node( var_0 )
|
|
{
|
|
var_1 = distance( self.origin, var_0.origin );
|
|
|
|
if ( var_1 < 200 )
|
|
return;
|
|
|
|
var_2 = var_0.origin - self.origin;
|
|
var_3 = self.origin + var_2 * 0.5;
|
|
var_4 = var_0 get_eye_position();
|
|
var_5 = 0.95757;
|
|
var_6 = getnodesinradius( var_3, var_1 + 100.0, 100.0, 256.0, "node_jump" );
|
|
var_7 = [];
|
|
|
|
foreach ( var_9 in var_6 )
|
|
{
|
|
if ( var_9.origin[2] < var_0.origin[2] + 32.0 )
|
|
continue;
|
|
|
|
var_10 = var_0.origin - var_9.origin;
|
|
var_11 = self.origin - var_0.origin;
|
|
|
|
if ( vectordot( var_11, var_10 ) > 0 )
|
|
continue;
|
|
|
|
var_12 = self.origin - var_9.origin;
|
|
var_13 = var_11 * -1;
|
|
|
|
if ( vectordot( var_13, var_12 ) > 0 )
|
|
continue;
|
|
|
|
if ( distancesquared( self.origin, var_9.origin ) < 65536.0 )
|
|
continue;
|
|
|
|
if ( distancesquared( var_0.origin, var_9.origin ) < 65536.0 )
|
|
continue;
|
|
|
|
var_14 = vectornormalize( var_9.origin - var_4 );
|
|
var_15 = vectornormalize( var_14 * ( 1, 1, 0 ) );
|
|
var_16 = vectordot( var_14, var_15 );
|
|
|
|
if ( var_16 < var_5 )
|
|
continue;
|
|
|
|
var_17 = self geteye();
|
|
var_18 = var_9.origin + ( 0, 0, 32 );
|
|
var_19 = bullettrace( var_17, var_18, 0, self );
|
|
|
|
if ( var_19["surfacetype"] != "none" )
|
|
continue;
|
|
|
|
var_4 = var_0 get_eye_position();
|
|
var_19 = bullettrace( var_18, var_4, 0, var_0 );
|
|
|
|
if ( var_19["surfacetype"] != "none" )
|
|
continue;
|
|
|
|
var_7[var_7.size] = var_9;
|
|
}
|
|
|
|
if ( var_7.size == 0 )
|
|
return undefined;
|
|
else
|
|
{
|
|
var_21 = [];
|
|
var_21["direction"] = "alien_forward";
|
|
var_21["direction_weight"] = 1.0;
|
|
var_21["height_weight"] = 0.0;
|
|
var_21["enemy_los_weight"] = 0.0;
|
|
var_21["dist_from_enemy_weight"] = 0.0;
|
|
var_21["min_dist_from_all_enemies_weight"] = 0.0;
|
|
var_21["not_recently_used_weight"] = 4.0;
|
|
var_21["random_weight"] = 1.0;
|
|
var_22 = get_retreat_node_rated( var_0, var_21, var_7 );
|
|
return var_22;
|
|
}
|
|
}
|
|
|
|
swipe_melee( var_0 )
|
|
{
|
|
self.melee_type = "swipe";
|
|
alien_melee( var_0 );
|
|
}
|
|
|
|
leap_melee( var_0 )
|
|
{
|
|
self.melee_type = "leap";
|
|
alien_melee( var_0 );
|
|
}
|
|
|
|
wall_leap_melee( var_0 )
|
|
{
|
|
self.melee_type = "wall";
|
|
alien_melee( var_0 );
|
|
}
|
|
|
|
synch_melee( var_0 )
|
|
{
|
|
self.melee_type = "synch";
|
|
alien_melee( var_0 );
|
|
}
|
|
|
|
badpath_jump( var_0 )
|
|
{
|
|
self.melee_type = "badpath_jump";
|
|
alien_melee( var_0 );
|
|
}
|
|
|
|
swipe_static_melee( var_0 )
|
|
{
|
|
self.melee_type = "swipe_static";
|
|
alien_melee( var_0 );
|
|
}
|
|
|
|
alien_melee( var_0 )
|
|
{
|
|
if ( melee_okay() && attemptmelee() )
|
|
{
|
|
if ( maps\mp\alien\_utility::get_alien_type() != "spitter" && maps\mp\alien\_utility::get_alien_type() != "seeder" )
|
|
{
|
|
self scragentsetgoalentity( var_0 );
|
|
self scragentsetgoalradius( 4096.0 );
|
|
}
|
|
|
|
self waittill( "melee_complete" );
|
|
}
|
|
else
|
|
wait 0.2;
|
|
}
|
|
|
|
watch_for_scripted()
|
|
{
|
|
self endon( "death" );
|
|
|
|
for (;;)
|
|
{
|
|
if ( isdefined( self.alien_scripted ) && self.alien_scripted == 1 )
|
|
{
|
|
self notify( "alien_main_loop_restart" );
|
|
|
|
while ( isdefined( self.alien_scripted ) && self.alien_scripted == 1 )
|
|
wait 0.05;
|
|
}
|
|
|
|
wait 0.05;
|
|
}
|
|
}
|
|
|
|
watch_for_badpath()
|
|
{
|
|
self endon( "death" );
|
|
self.badpath = 0;
|
|
|
|
for (;;)
|
|
{
|
|
self waittill( "bad_path", var_0, var_1 );
|
|
self.badpath = 1;
|
|
|
|
if ( !isdefined( self.badpathcount ) || isdefined( self.badpathtime ) && gettime() > self.badpathtime + 2000 )
|
|
self.badpathcount = 0;
|
|
|
|
self.badpathtime = gettime();
|
|
self.badpathcount++;
|
|
self notify( "alien_main_loop_restart" );
|
|
wait 0.05;
|
|
}
|
|
}
|
|
|
|
set_alien_movemode( var_0 )
|
|
{
|
|
switch ( var_0 )
|
|
{
|
|
case "jog":
|
|
case "run":
|
|
case "walk":
|
|
self.movemode = var_0;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
watch_for_insolid()
|
|
{
|
|
self endon( "death" );
|
|
|
|
if ( self.insolid )
|
|
handleinsolid();
|
|
|
|
for (;;)
|
|
{
|
|
self waittill( "insolid" );
|
|
handleinsolid();
|
|
}
|
|
}
|
|
|
|
handleinsolid()
|
|
{
|
|
while ( self.insolid )
|
|
wait 0.2;
|
|
|
|
self scragentsetgoalpos( self.origin );
|
|
self notify( "alien_main_loop_restart" );
|
|
}
|
|
|
|
approach_enemy( var_0, var_1, var_2 )
|
|
{
|
|
if ( var_0 < 32 )
|
|
var_0 = 32;
|
|
|
|
var_3 = get_approach_node( var_1 );
|
|
var_4 = var_0 * var_0;
|
|
|
|
for ( var_5 = 0; isdefined( var_3 ) && var_5 < var_2; var_3 = get_approach_node( var_1 ) )
|
|
{
|
|
if ( run_to_approach_node( var_3, var_0, var_1 ) )
|
|
return var_3;
|
|
|
|
if ( distancesquared( self.origin, var_1.origin ) < 250000.0 )
|
|
break;
|
|
|
|
var_5++;
|
|
}
|
|
|
|
run_to_enemy( var_0, var_1 );
|
|
}
|
|
|
|
run_to_approach_node( var_0, var_1, var_2 )
|
|
{
|
|
self notify( "approach_goal_invalid" );
|
|
self scragentsetgoalradius( 64 );
|
|
self scragentsetgoalnode( var_0 );
|
|
wait_till_reached_goal_or_distance_from_enemy( var_0, var_1, var_2 );
|
|
return distancesquared( var_2.origin, self.origin ) <= var_1 * var_1;
|
|
}
|
|
|
|
run_to_enemy( var_0, var_1 )
|
|
{
|
|
self notify( "approach_goal_invalid" );
|
|
var_2 = max( var_0 + -48, 32 );
|
|
self scragentsetgoalradius( var_2 );
|
|
self scragentsetgoalentity( var_1 );
|
|
wait_till_distance_from_enemy( var_0, var_1 );
|
|
}
|
|
|
|
wait_till_reached_goal_or_distance_from_enemy( var_0, var_1, var_2 )
|
|
{
|
|
self endon( "goal_reached" );
|
|
self endon( "approach_goal_invalid" );
|
|
thread monitor_approach_goal_invalid( var_0, var_2 );
|
|
wait_till_distance_from_enemy( var_1, var_2 );
|
|
}
|
|
|
|
monitor_approach_goal_invalid( var_0, var_1 )
|
|
{
|
|
self endon( "goal_reached" );
|
|
self endon( "death" );
|
|
self endon( "approach_goal_invalid" );
|
|
var_1 endon( "death" );
|
|
var_2 = 202500;
|
|
|
|
while ( isdefined( var_0 ) && isdefined( var_1 ) )
|
|
{
|
|
if ( distancesquared( var_0.origin, var_1.origin ) > var_2 )
|
|
break;
|
|
|
|
var_3 = vectornormalize( self.origin - var_1.origin );
|
|
var_4 = vectornormalize( var_0.origin - var_1.origin );
|
|
|
|
if ( vectordot( var_3, var_4 ) < 0 )
|
|
break;
|
|
|
|
wait 0.2;
|
|
}
|
|
|
|
self notify( "approach_goal_invalid" );
|
|
}
|
|
|
|
wait_till_distance_from_enemy( var_0, var_1 )
|
|
{
|
|
var_2 = var_0 * var_0;
|
|
|
|
for (;;)
|
|
{
|
|
if ( get_distance_squared_to_enemy( var_1 ) < var_2 )
|
|
break;
|
|
|
|
common_scripts\utility::waitframe();
|
|
}
|
|
}
|
|
|
|
get_distance_squared_to_enemy( var_0 )
|
|
{
|
|
if ( isplayer( var_0 ) && var_0 isonladder() )
|
|
return distance2dsquared( self.origin, var_0.origin );
|
|
|
|
return distancesquared( self.origin, var_0.origin );
|
|
}
|
|
|
|
run_near_enemy( var_0, var_1, var_2 )
|
|
{
|
|
if ( var_0 < 32 )
|
|
var_0 = 32;
|
|
|
|
if ( !isdefined( var_2 ) || !run_to_approach_node( var_2, var_0, var_1 ) )
|
|
run_to_enemy( var_0, var_1 );
|
|
}
|
|
|
|
get_offset_location_from_enemy( var_0, var_1, var_2, var_3, var_4 )
|
|
{
|
|
if ( getdvarint( "alien_retreat_towards_spawn" ) == 1 )
|
|
var_5 = self.spawnorigin;
|
|
else
|
|
var_5 = self.origin;
|
|
|
|
var_6 = vectornormalize( ( var_5 - var_0.origin ) * ( 1, 1, 0 ) );
|
|
var_7 = randomintrange( var_3, var_4 );
|
|
|
|
if ( common_scripts\utility::cointoss() )
|
|
var_7 = var_7 * -1;
|
|
|
|
var_8 = ( 0, var_7, 0 );
|
|
var_9 = rotatevector( var_6, var_8 );
|
|
var_10 = var_1;
|
|
|
|
if ( var_1 < var_2 )
|
|
var_10 = randomintrange( var_1, var_2 );
|
|
|
|
return var_0.origin + var_9 * var_10;
|
|
}
|
|
|
|
get_approach_node( var_0 )
|
|
{
|
|
var_1 = 20;
|
|
var_2 = 30;
|
|
var_3 = getdvarint( "alien_melee_distance" );
|
|
|
|
if ( var_3 < 100 )
|
|
var_3 = 100;
|
|
|
|
var_4 = get_offset_location_from_enemy( var_0, var_3, var_3, var_1, var_2 );
|
|
var_5 = getnodesinradius( var_4, 150, 0, 128, "path" );
|
|
|
|
if ( var_5.size == 0 )
|
|
var_5 = getnodesinradius( var_4, 300, 150, 128, "path" );
|
|
|
|
var_6 = [];
|
|
var_6["direction"] = "override";
|
|
var_6["direction_weight"] = 6.0;
|
|
var_6["direction_override"] = vectornormalize( var_0.origin - self.origin );
|
|
var_6["min_height"] = -32.0;
|
|
var_6["max_height"] = 32.0;
|
|
var_6["height_weight"] = 6.0;
|
|
var_6["enemy_los"] = 0;
|
|
var_6["enemy_los_weight"] = 0.0;
|
|
var_6["min_dist_from_enemy"] = 150.0;
|
|
var_6["max_dist_from_enemy"] = 800.0;
|
|
var_6["desired_dist_from_enemy"] = distance( var_4, var_0.origin );
|
|
var_6["dist_from_enemy_weight"] = 3.0;
|
|
var_6["min_dist_from_all_enemies"] = 150.0;
|
|
var_6["min_dist_from_all_enemies_weight"] = 1.0;
|
|
var_6["not_recently_used_weight"] = 4.0;
|
|
var_6["random_weight"] = 2.0;
|
|
return get_retreat_node_rated( var_0, var_6, var_5 );
|
|
}
|
|
|
|
wait_for_valid_leap_melee( var_0 )
|
|
{
|
|
var_1 = randomintrange( -100, 100 ) + 400;
|
|
var_2 = var_1 * var_1;
|
|
var_3 = 43264;
|
|
|
|
for (;;)
|
|
{
|
|
if ( distancesquared( self.origin, var_0.origin ) < var_2 )
|
|
break;
|
|
|
|
wait 0.05;
|
|
}
|
|
|
|
for (;;)
|
|
{
|
|
if ( !isalive( var_0 ) )
|
|
return 0;
|
|
|
|
if ( distancesquared( self.origin, var_0.origin ) < var_3 )
|
|
return 0;
|
|
|
|
if ( can_leap_melee( var_0, 400, 208 ) )
|
|
return 1;
|
|
|
|
wait 0.05;
|
|
}
|
|
}
|
|
|
|
go_to_leaping_melee_position( var_0 )
|
|
{
|
|
self scragentsetgoalentity( var_0 );
|
|
self scragentsetgoalradius( 160 );
|
|
return wait_for_valid_leap_melee( var_0 );
|
|
}
|
|
|
|
go_to_leaping_melee_node( var_0 )
|
|
{
|
|
var_1 = getnodesinradius( var_0.origin, 512.0, 200.0, 256.0, "node_jump" );
|
|
var_2 = [];
|
|
var_3 = var_0 get_eye_position();
|
|
var_4 = ( 0, 0, 32 );
|
|
var_5 = undefined;
|
|
|
|
foreach ( var_7 in var_1 )
|
|
{
|
|
var_8 = bullettracepassed( var_7.origin + var_4, var_3, 0, self );
|
|
|
|
if ( var_8 )
|
|
{
|
|
var_5 = var_7;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( !isdefined( var_5 ) )
|
|
return 0;
|
|
|
|
self scragentsetgoalnode( var_5 );
|
|
self scragentsetgoalradius( 160 );
|
|
var_10 = 160000;
|
|
var_11 = 0.0;
|
|
return wait_for_valid_leap_melee( var_0 );
|
|
}
|
|
|
|
can_leap_melee( var_0, var_1, var_2 )
|
|
{
|
|
if ( !melee_okay() )
|
|
return 0;
|
|
|
|
if ( isdefined( var_1 ) )
|
|
{
|
|
if ( distancesquared( self.origin, var_0.origin ) > var_1 * var_1 )
|
|
return 0;
|
|
}
|
|
|
|
var_3 = self.origin + ( 0, 0, 32 );
|
|
var_4 = var_0 get_eye_position();
|
|
var_5 = maps\mp\agents\alien\_alien_melee::get_melee_position( 1.0, 48, var_0 );
|
|
self.leapendpos = var_5;
|
|
|
|
if ( !isdefined( var_5 ) )
|
|
return 0;
|
|
|
|
if ( distancesquared( self.origin, var_5 ) < var_2 )
|
|
return 0;
|
|
|
|
var_6 = trajectorycanattemptaccuratejump( self.origin, anglestoup( self.angles ), var_5, anglestoup( var_0.angles ), level.alien_jump_melee_gravity, 1.01 * level.alien_jump_melee_speed );
|
|
return var_6;
|
|
}
|
|
|
|
melee_okay()
|
|
{
|
|
switch ( self.currentanimstate )
|
|
{
|
|
case "move":
|
|
return 1;
|
|
case "melee":
|
|
return 1;
|
|
case "idle":
|
|
return 1;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
register_node( var_0 )
|
|
{
|
|
var_1 = [];
|
|
var_1["node"] = var_0;
|
|
var_1["time_stamp"] = gettime();
|
|
level.used_nodes[level.used_nodes_list_index] = var_1;
|
|
level.used_nodes_list_index++;
|
|
|
|
if ( level.used_nodes_list_index == level.used_nodes_list_size )
|
|
level.used_nodes_list_index = 0;
|
|
}
|
|
|
|
node_recently_used( var_0, var_1 )
|
|
{
|
|
var_2 = 0;
|
|
|
|
for ( var_3 = 0; var_3 < level.used_nodes_list_size; var_3++ )
|
|
{
|
|
var_4 = level.used_nodes_list_index - var_3;
|
|
|
|
if ( var_4 < 0 )
|
|
var_4 = level.used_nodes_list_size + var_4;
|
|
|
|
if ( isdefined( level.used_nodes[var_4] ) )
|
|
{
|
|
var_5 = level.used_nodes[var_4];
|
|
|
|
if ( var_0 == var_5["node"] )
|
|
{
|
|
if ( gettime() - var_5["time_stamp"] < var_1 * 1000 )
|
|
var_2 = 1;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return var_2;
|
|
}
|
|
|
|
get_attack_sequence_num()
|
|
{
|
|
if ( isdefined( self.bypass_max_attacker_counter ) && self.bypass_max_attacker_counter == 1 )
|
|
return 1;
|
|
|
|
if ( isdefined( self.attack_sequence_num ) )
|
|
{
|
|
var_0 = self.attack_sequence_num;
|
|
self.attack_sequence_num = undefined;
|
|
return var_0;
|
|
}
|
|
|
|
switch ( maps\mp\alien\_utility::get_alien_type() )
|
|
{
|
|
case "seeder":
|
|
case "gargoyle":
|
|
case "locust":
|
|
case "spitter":
|
|
case "elite":
|
|
return 1;
|
|
default:
|
|
return randomint( 3 ) + 6;
|
|
}
|
|
}
|
|
|
|
get_attack_num()
|
|
{
|
|
if ( isdefined( self.attack_num ) )
|
|
{
|
|
var_0 = self.attack_num;
|
|
self.attack_num = undefined;
|
|
return var_0;
|
|
}
|
|
|
|
switch ( maps\mp\alien\_utility::get_alien_type() )
|
|
{
|
|
case "gargoyle":
|
|
case "locust":
|
|
return 1;
|
|
default:
|
|
return randomint( 6 ) + 3;
|
|
}
|
|
}
|
|
|
|
random_movemode_change( var_0, var_1, var_2, var_3, var_4 )
|
|
{
|
|
self endon( "go to combat" );
|
|
self endon( "death" );
|
|
var_5 = [];
|
|
var_5["run"] = var_0;
|
|
var_5["jog"] = var_1;
|
|
var_5["walk"] = var_2;
|
|
var_6 = var_0 + var_1 + var_2;
|
|
var_7 = 262144.0;
|
|
|
|
for (;;)
|
|
{
|
|
if ( maps\mp\alien\_utility::any_player_nearby( self.origin, var_7 ) )
|
|
var_8 = "run";
|
|
else
|
|
{
|
|
var_9 = 0;
|
|
var_10 = randomintrange( 0, var_6 );
|
|
var_8 = undefined;
|
|
|
|
foreach ( var_13, var_12 in var_5 )
|
|
{
|
|
var_9 = var_9 + var_12;
|
|
|
|
if ( var_10 <= var_9 )
|
|
{
|
|
var_8 = var_13;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
set_alien_movemode( var_8 );
|
|
wait( randomfloatrange( var_3, var_4 ) );
|
|
}
|
|
}
|
|
|
|
armormitigation( var_0, var_1, var_2 )
|
|
{
|
|
|
|
}
|
|
|
|
play_shield_impact_fx( var_0, var_1 )
|
|
{
|
|
if ( !isdefined( var_1 ) || !isdefined( var_0 ) )
|
|
return;
|
|
|
|
var_2 = var_1 * -1;
|
|
var_3 = anglestoup( vectortoangles( var_2 ) );
|
|
playfx( level._effect["shield_impact"], var_0, var_2, var_3 );
|
|
self playsound( "bullet_large_metal" );
|
|
}
|
|
|
|
has_shock_ammo( var_0 )
|
|
{
|
|
var_1 = maps\mp\alien\_utility::getrawbaseweaponname( var_0 );
|
|
|
|
if ( isdefined( self.special_ammocount ) && isdefined( self.special_ammocount[var_1] ) && self.special_ammocount[var_1] > 0 )
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
get_pet_follow_node( var_0 )
|
|
{
|
|
var_1 = getnodesinradius( var_0.origin, 512, 128, 350, "node_jump" );
|
|
var_2 = [];
|
|
var_2["direction"] = "player_front";
|
|
var_2["direction_weight"] = 2.0;
|
|
var_2["min_height"] = -32.0;
|
|
var_2["max_height"] = 350.0;
|
|
var_2["height_weight"] = 2.0;
|
|
var_2["enemy_los"] = 1;
|
|
var_2["enemy_los_weight"] = 2.0;
|
|
var_2["min_dist_from_enemy"] = 128.0;
|
|
var_2["max_dist_from_enemy"] = 512.0;
|
|
var_2["desired_dist_from_enemy"] = 350.0;
|
|
var_2["dist_from_enemy_weight"] = 3.0;
|
|
var_2["min_dist_from_all_enemies"] = 200.0;
|
|
var_2["min_dist_from_all_enemies_weight"] = 0.0;
|
|
var_2["not_recently_used_weight"] = 4.0;
|
|
var_2["random_weight"] = 2.0;
|
|
var_3 = get_retreat_node_rated( var_0, var_2, var_1 );
|
|
return var_3;
|
|
}
|