// 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;
}
