// IW6 GSC SOURCE
// Generated by https://github.com/xensik/gsc-tool

spawnalien( var_0, var_1, var_2 )
{
    return maps\mp\gametypes\aliens::addalienagent( "axis", var_0, var_1, var_2 );
}

alien_health_per_player_init()
{
    level.alien_health_per_player_scalar = [];
    level.alien_health_per_player_scalar[1] = 0.9;
    level.alien_health_per_player_scalar[2] = 1.0;
    level.alien_health_per_player_scalar[3] = 1.3;
    level.alien_health_per_player_scalar[4] = 1.8;
}

alien_wave_init()
{
    level.use_spawn_director = 1;

    if ( use_spawn_director() )
        maps\mp\alien\_spawn_director::init();

    wave_spawners_init();
}

escape_choke_init()
{
    level.choke_trigs = [];
    level.choke_trigs[0] = getent( "choke_trig_0", "targetname" );
    level.choke_trigs[1] = getent( "choke_trig_1", "targetname" );
    level.choke_trigs[2] = getent( "choke_trig_2", "targetname" );
    level.choke_trigs[3] = getent( "choke_trig_3", "targetname" );

    if ( !isdefined( level.choke_trigs ) || !level.choke_trigs.size )
        return;

    foreach ( var_1 in level.choke_trigs )
    {
        var_2 = common_scripts\utility::getstruct( var_1.target, "targetname" );
        var_3 = common_scripts\utility::getstruct( var_2.target, "targetname" );
        var_1.choke_loc = var_2.origin;
        var_1.spit_at_struct = var_3;
    }

    level thread monitor_trig_activation();
}

monitor_trig_activation()
{
    level endon( "game_ended" );

    if ( !common_scripts\utility::flag_exist( "nuke_countdown" ) )
        return;

    level.latest_choke_trig_active = level.choke_trigs[0];
    level.escape_spitter_target_node = level.choke_trigs[0].spit_at_struct;

    if ( !isdefined( level.escape_spitter_target_node.angles ) )
        level.escape_spitter_target_node.angles = ( 0, 0, 0 );

    if ( !common_scripts\utility::flag( "nuke_countdown" ) )
        common_scripts\utility::flag_wait( "nuke_countdown" );

    update_extraction_waypoint_location( level.latest_choke_trig_active get_choke_trig_id() );

    for (;;)
    {
        foreach ( var_1 in level.players )
        {
            foreach ( var_3 in level.choke_trigs )
            {
                if ( isalive( var_1 ) && var_1 istouching( var_3 ) && var_1.sessionstate == "playing" )
                {
                    var_4 = var_3 get_choke_trig_id();
                    var_5 = level.latest_choke_trig_active get_choke_trig_id();

                    if ( var_4 > var_5 )
                    {
                        level.latest_choke_trig_active = var_3;
                        update_extraction_waypoint_location( var_3 get_choke_trig_id() );
                        level.escape_spitter_target_node = var_3.spit_at_struct;

                        if ( !isdefined( level.escape_spitter_target_node.angles ) )
                            level.escape_spitter_target_node.angles = ( 0, 0, 0 );

                        thread escape_spawn_special_minion_wave( 6 );
                    }
                }
            }
        }

        wait 1;
    }
}

update_extraction_waypoint_location( var_0 )
{
    if ( !isdefined( level.rescue_waypoint ) )
        return;

    level.rescue_waypoint.alpha = 1;

    if ( !isdefined( level.rescue_waypoint_locs ) || !isdefined( level.rescue_waypoint_locs[var_0] ) )
        return;

    level.rescue_waypoint.x = level.rescue_waypoint_locs[var_0][0];
    level.rescue_waypoint.y = level.rescue_waypoint_locs[var_0][1];
    level.rescue_waypoint.z = level.rescue_waypoint_locs[var_0][2];
}

escape_spawn_special_minion_wave( var_0 )
{
    level endon( "game_ended" );
    level endon( "nuke_went_off" );
    level notify( "escape_spawn_special_minion_wave" );
    level endon( "escape_spawn_special_minion_wave" );
    wait( var_0 );
    var_1 = "chaos_event_1";
    level notify( var_1 );
    maps\mp\alien\_spawn_director::activate_spawn_event( var_1 );
}

get_choke_trig_id()
{
    return int( strtok( self.targetname, "_" )[2] );
}

alien_scene_init()
{
    level.scene_trigs = getentarray( "scene_trig", "targetname" );

    foreach ( var_1 in level.scene_trigs )
        var_1 thread setup_scene();
}

setup_scene()
{
    self.scene_spawners = common_scripts\utility::getstructarray( self.target, "targetname" );

    foreach ( var_1 in self.scene_spawners )
    {
        var_2 = strtok( var_1.script_noteworthy, " " );
        var_1.types = var_2;
    }

    thread run_scene();
}

run_scene()
{
    level endon( "game_ended" );
    self endon( "death" );

    for (;;)
    {
        self waittill( "trigger", var_0 );

        if ( !isplayer( var_0 ) )
        {
            wait 0.05;
            continue;
        }

        var_1 = common_scripts\utility::array_randomize( self.scene_spawners );

        for ( var_2 = 0; var_2 < var_1.size; var_2++ )
        {
            if ( var_2 > 0 )
            {
                if ( randomint( 100 ) >= 50 )
                    continue;
            }

            var_3 = var_1[var_2];
            thread spawn_scene_alien( var_3 );
        }

        return;
    }
}

spawn_scene_alien( var_0 )
{
    if ( isdefined( var_0.script_delay ) )
        wait( var_0.script_delay );

    var_1 = "scene " + var_0.types[randomintrange( 0, var_0.types.size )];
    var_2 = var_0.angles;

    if ( !isdefined( var_2 ) )
        var_2 = ( 0, 270, 0 );

    var_3 = spawnalien( var_0.origin, var_2, var_1 );
    var_3.spawner = var_0;
}

alien_scene_behavior()
{
    self endon( "death" );
    self endon( "run_to_death" );
    maps\mp\agents\alien\_alien_think::set_alien_movemode( "run" );
    var_0 = self.moveplaybackrate;
    self.scene_moveplaybackrate = var_0 * 1.25;
    set_ignore_enemy();
    thread wakeup_to_player_damage();
    thread wakeup_to_player_distance( 256 );
    thread scene_loop();
    self waittill( "woke" );
    self.scene = undefined;
    self.moveplaybackrate = var_0;
    clear_ignore_enemy();
    self scragentsetscripted( 0 );

    if ( maps\mp\alien\_utility::get_alien_type() == "elite" )
        level thread maps\mp\alien\_music_and_dialog::handlefirstelitearrival( self );

    wait 1;
}

scene_loop()
{
    self endon( "woke" );
    self endon( "death" );
    self endon( "run_to_death" );
    wait 1;
    maps\mp\agents\alien\_alien_think::set_alien_movemode( "run" );
    var_0 = common_scripts\utility::getstructarray( self.spawner.target, "targetname" );

    for ( var_1 = var_0[randomintrange( 0, var_0.size )]; isdefined( var_1 ); var_1 = var_0[randomintrange( 0, var_0.size )] )
    {
        self scragentsetgoalpos( var_1.origin );
        self scragentsetgoalradius( 32 );
        self waittill( "goal_reached" );

        if ( isdefined( var_1.script_noteworthy ) )
        {
            wait 0.5;
            var_2 = strtok( var_1.script_noteworthy, " " );

            if ( var_2[0] == "delete" )
            {
                self suicide();
                return;
            }

            var_3 = level.players[randomintrange( 0, level.players.size )];
            maps\mp\agents\alien\_alien_anim_utils::turntowardsentity( var_3 );
            var_4 = 1;

            if ( var_2.size == 2 && int( var_2[1] ) > 1 )
                var_4 = int( var_2[1] );

            if ( var_2[0] == "posture" )
            {
                for ( var_5 = 0; var_5 < var_4; var_5++ )
                {
                    self scragentsetscripted( 1 );
                    maps\mp\alien\_utility::set_alien_emissive( 0.2, 1 );
                    self scragentsetorientmode( "face angle abs", self.angles );
                    maps\mp\agents\_scriptedagents::playanimuntilnotetrack( "posture", "posture", "end" );
                    maps\mp\alien\_utility::set_alien_emissive_default( 0.2 );
                    self scragentsetscripted( 0 );
                    self scragentsetgoalpos( self.origin );
                    wait( randomfloatrange( 0.25, 0.75 ) );
                }

                self.moveplaybackrate = self.scene_moveplaybackrate;
            }

            if ( var_2[0] == "ground_slam" )
            {
                for ( var_5 = 0; var_5 < var_4; var_5++ )
                {
                    self scragentsetscripted( 1 );
                    maps\mp\alien\_utility::set_alien_emissive( 0.2, 1 );
                    self scragentsetorientmode( "face angle abs", self.angles );
                    maps\mp\agents\_scriptedagents::playanimuntilnotetrack( "attack_melee_swipe", "attack_melee", "end" );
                    maps\mp\alien\_utility::set_alien_emissive_default( 0.2 );
                    self scragentsetscripted( 0 );
                    self scragentsetgoalpos( self.origin );
                    wait( randomfloatrange( 0.5, 1.0 ) );
                }

                self.moveplaybackrate = self.scene_moveplaybackrate;
            }
        }

        var_0 = common_scripts\utility::getstructarray( var_1.target, "targetname" );

        if ( !isdefined( var_0 ) )
            return;
    }
}

alien_lurker_init()
{
    if ( !maps\mp\alien\_utility::alien_mode_has( "lurker" ) )
        return;

    common_scripts\utility::flag_init( "lurker_active" );
    thread init_patrol_paths();
    var_0 = common_scripts\utility::getstructarray( "alien_spawn_struct", "targetname" );
    level.alien_lurkers = [];
    level.max_lurker_population = 18;

    foreach ( var_4, var_2 in level.alien_types )
    {
        var_3 = spawnstruct();
        var_3.spawn_locs = [];
        level.alien_lurkers[var_4] = var_3;
    }

    foreach ( var_6 in var_0 )
    {
        var_7 = "Spawn location at: " + var_6.origin + " ";

        if ( isdefined( var_6.script_noteworthy ) && var_6.script_noteworthy != "" )
        {
            var_8 = strtok( var_6.script_noteworthy, " " );

            if ( !issubstr( var_6.script_noteworthy, "lurker" ) )
                continue;
            else
                var_8 = common_scripts\utility::array_remove( var_8, var_8[0] );

            var_6.spawn_trigger = getent( var_6.target, "targetname" );

            foreach ( var_2 in var_8 )
            {
                if ( isdefined( level.alien_lurkers[var_2] ) )
                {
                    level.alien_lurkers[var_2].spawn_locs[level.alien_lurkers[var_2].spawn_locs.size] = var_6;
                    continue;
                }
            }

            continue;
        }

        if ( !use_spawn_director() )
        {

        }
    }

    level notify( "alien_lurkers_spawn_initialized" );
}

init_patrol_paths()
{
    level.patrol_start_nodes = common_scripts\utility::getstructarray( "patrol_start_node", "targetname" );
}

wave_spawners_init()
{
    level.alien_wave = [];

    foreach ( var_3, var_1 in level.alien_types )
    {
        var_2 = spawnstruct();
        var_2.spawn_locs = [];
        level.alien_wave[var_3] = var_2;
    }

    var_4 = common_scripts\utility::getstructarray( "alien_spawn_struct", "targetname" );

    foreach ( var_6 in var_4 )
    {
        var_7 = "Spawn location at: " + var_6.origin + " ";

        if ( isdefined( var_6.script_noteworthy ) && var_6.script_noteworthy != "" )
        {
            var_8 = strtok( var_6.script_noteworthy, " " );

            if ( issubstr( var_6.script_noteworthy, "lurker" ) )
                continue;

            foreach ( var_1 in var_8 )
            {
                if ( isdefined( level.alien_wave[var_1] ) )
                {
                    level.alien_wave[var_1].spawn_locs[level.alien_wave[var_1].spawn_locs.size] = var_6;
                    continue;
                }
            }

            continue;
        }

        if ( !use_spawn_director() )
        {

        }
    }

    level notify( "alien_wave_spawn_initialized" );
}

assign_alien_attributes( var_0 )
{
    self endon( "death" );
    var_1 = "none";
    var_2 = strtok( var_0, " " );

    if ( isdefined( var_2 ) && var_2.size == 2 )
    {
        if ( var_2[0] == "lurker" )
            var_1 = "lurker";

        if ( var_2[0] == "wave" )
            var_1 = "wave";

        if ( var_2[0] == "scene" )
            var_1 = "scene";

        var_0 = var_2[1];
    }

    if ( isdefined( level.players ) && level.players.size > 0 )
        var_3 = level.alien_types[var_0].attributes["health"] * level.alien_health_per_player_scalar[level.players.size];
    else
        var_3 = level.alien_types[var_0].attributes["health"];

    var_3 = int( level.cycle_health_scalar * var_3 );
    maps\mp\agents\_agent_common::set_agent_health( var_3 );
    self.max_health = var_3;
    self.alien_type = level.alien_types[var_0].attributes["ref"];
    self.moveplaybackrate = level.alien_types[var_0].attributes["speed"] * randomfloatrange( 0.95, 1.05 );

    if ( common_scripts\utility::flag_exist( "hives_cleared" ) && common_scripts\utility::flag( "hives_cleared" ) )
        self.moveplaybackrate = self.moveplaybackrate * 1.25;

    self.defaultmoveplaybackrate = self.moveplaybackrate;
    self.animplaybackrate = self.moveplaybackrate;
    self.xyanimscale = level.alien_types[var_0].attributes["scale"];
    self.hindlegstraceoffset = -37.0 * self.xyanimscale;
    self.defaultemissive = level.alien_types[var_0].attributes["emissive_default"];
    self.maxemissive = level.alien_types[var_0].attributes["emissive_max"];
    thread set_initial_emissive();
    self scragentsetviewheight( level.alien_types[var_0].attributes["view_height"] );

    if ( var_1 == "lurker" )
    {
        thread alien_lurker_behavior();
        self.lurker = 1;
    }

    if ( var_1 == "scene" )
    {
        thread alien_scene_behavior();
        self.scene = 1;
    }

    if ( var_1 == "wave" )
    {
        thread alien_wave_behavior();
        self.wave_spawned = 1;
    }

    if ( level.alien_types[var_0].attributes["behavior_cloak"] == 1 )
        thread maps\mp\alien\_director::alien_cloak();
}

set_initial_emissive()
{
    self endon( "death" );
    wait 1;
    maps\mp\alien\_utility::set_alien_emissive_default( 0.2 );
}

add_fire_fx()
{
    maps\mp\alien\_alien_fx::alien_fire_on();
}

stop_fire_fx()
{
    maps\mp\alien\_alien_fx::alien_fire_off();
}

remaining_alien_management()
{
    var_0 = maps\mp\agents\_agent_utility::getactiveagentsoftype( "alien" );

    foreach ( var_2 in var_0 )
    {
        if ( !isalive( var_2 ) )
            continue;

        if ( isdefined( var_2.from_previous_hive ) )
            var_2 suicide();
        else
            var_2.from_previous_hive = 1;

        if ( !isdefined( var_2.alien_type ) || var_2.alien_type == "elite" )
            continue;

        if ( var_2.health < 80 )
            continue;

        var_3 = 0.5;
        var_4 = int( var_3 * var_2.health );
        var_2.health = var_2.health - var_4;
        wait 0.05;
    }
}

get_blocker_hive( var_0 )
{
    foreach ( var_2 in level.stronghold_hive_locs )
    {
        if ( isdefined( var_2.target ) && var_2.target == var_0 )
            return var_2;
    }

    return undefined;
}

make_spitter_attack_chopper( var_0 )
{
    if ( var_0 )
        var_1 = "spitters";
    else
        var_1 = "other_aliens";

    if ( threatbiasgroupexists( var_1 ) && self getthreatbiasgroup() != var_1 )
        self setthreatbiasgroup( var_1 );

    if ( isdefined( level.hive_heli ) && var_0 )
    {
        if ( !isdefined( self.favoriteenemy ) || self.favoriteenemy != level.hive_heli )
            self.favoriteenemy = level.hive_heli;
    }
}

escape_spawning( var_0 )
{
    foreach ( var_2 in level.players )
        var_2.threatbias = 100000;

    maps\mp\alien\_spawn_director::start_cycle( var_0 );
    level thread clean_up_lagged_aliens();
    level common_scripts\utility::waittill_any( "game_ended", "nuke_went_off" );
    maps\mp\alien\_spawn_director::end_cycle();

    if ( common_scripts\utility::flag_exist( "nuke_went_off" ) && common_scripts\utility::flag( "nuke_went_off" ) )
        level common_scripts\utility::waittill_any_timeout( 10, "game_ended" );
    else
        wait 7;

    foreach ( var_5 in level.agentarray )
    {
        if ( isalive( var_5 ) && isdefined( var_5.isactive ) && var_5.isactive )
        {
            var_5 suicide();
            wait 0.1;
        }
    }
}

clean_up_lagged_aliens()
{
    level endon( "nuke_went_off" );
    level endon( "game_ended" );
    level notify( "clean_up_lagged_aliens" );
    level endon( "clean_up_lagged_aliens" );
    var_0 = 1;

    for (;;)
    {
        var_1 = [];

        foreach ( var_3 in level.agentarray )
        {
            if ( !isdefined( var_3.isactive ) || !var_3.isactive )
                continue;

            var_1[var_1.size] = var_3;
        }

        var_5 = 4;

        if ( var_1.size <= maps\mp\alien\_spawn_director::get_max_alien_count() - var_5 )
        {
            wait 1;
            continue;
        }

        foreach ( var_7 in var_1 )
        {
            if ( !isdefined( var_7.last_looked_at ) )
            {
                var_7.last_looked_at = gettime();
                var_7 thread monitor_looked_at();
                continue;
            }

            if ( !isdefined( var_7.team ) || var_7.team != "axis" )
                continue;

            var_8 = gettime() - var_7.birthtime;

            if ( var_8 / 1000 < 10 )
                continue;

            var_9 = 0;

            foreach ( var_11 in level.players )
            {
                if ( isalive( var_11 ) && distance( var_11.origin, var_7.origin ) < 1000 )
                    var_9 = 1;
            }

            if ( var_9 )
                continue;

            var_13 = gettime() - var_7.last_looked_at;

            if ( var_13 / 1000 > 2 )
            {
                var_7 suicide();
                break;
            }
        }

        wait( var_0 );
    }
}

monitor_looked_at()
{
    self endon( "death" );
    self notify( "monitoring_looked_at" );
    self endon( "monitoring_looked_at" );

    for (;;)
    {
        foreach ( var_1 in level.players )
        {
            if ( !isalive( var_1 ) )
                continue;

            var_2 = var_1 gettagangles( "tag_eye" );
            var_3 = var_1 geteye();
            var_4 = anglestoforward( var_2 );
            var_5 = vectornormalize( self.origin - var_3 );
            var_6 = 0.55;

            if ( vectordot( var_4, var_5 ) > var_6 )
                self.last_looked_at = gettime();
        }

        wait 0.25;
    }
}

port_to_player_loc( var_0, var_1 )
{
    if ( !isdefined( var_1 ) )
        var_1 = 350;

    if ( isdefined( var_0 ) && var_0 == "minion" )
        var_1 = var_1 * 1.2;

    var_2 = [];

    foreach ( var_4 in level.players )
    {
        if ( isalive( var_4 ) )
            var_2[var_2.size] = var_4;
    }

    var_6 = [];

    for ( var_7 = level.choke_trigs.size - 1; var_7 >= 0; var_7-- )
    {
        var_8 = level.choke_trigs[var_7];
        var_9 = [];

        foreach ( var_4 in var_2 )
        {
            if ( var_4 istouching( var_8 ) )
                var_9[var_9.size] = var_4;
        }

        if ( var_9.size )
        {
            var_9 = sortbydistance( var_9, var_8.choke_loc );

            for ( var_12 = 0; var_12 < var_9.size; var_12++ )
                var_6[var_6.size] = var_9[var_12];
        }
    }

    var_13 = var_6[0];

    if ( var_6.size > 1 && randomintrange( 0, 100 ) <= 66 )
        var_13 = var_6[randomintrange( 1, var_6.size )];

    var_14 = undefined;

    foreach ( var_8 in level.choke_trigs )
    {
        if ( var_13 istouching( var_8 ) )
        {
            var_14 = var_8.choke_loc;
            break;
        }
    }

    if ( !isdefined( var_14 ) )
        return undefined;

    var_17 = 3;

    if ( var_0 == "spitter" || var_0 == "seeder" )
        var_17 = 4;

    var_18 = var_13.origin + vectornormalize( var_14 - var_13.origin ) * var_1 * var_17;
    var_19 = getnodesinradius( var_18, var_1, 0, 1024, "Path" );

    if ( var_19.size == 0 )
    {
        if ( var_1 >= 2000 )
            return undefined;

        var_20 = var_1 + 250;
        return port_to_player_loc( var_0, var_20 );
    }

    var_21 = get_selected_node_for_teleport( var_19, var_14, var_13 );
    var_29 = vectortoangles( var_13.origin - var_21.origin );
    return [ var_21.origin, var_29 ];
}

port_to_escape_spitter_location()
{
    var_0 = 512;
    var_1 = level.escape_spitter_target_node.origin;
    var_2 = getnodesinradius( var_1, var_0, 0, 1024, "Path" );
    var_3 = get_selected_node_for_teleport( var_2, var_1, level.escape_spitter_target_node );
    return var_3.origin;
}

get_selected_node_for_teleport( var_0, var_1, var_2 )
{
    var_0 = sortbydistance( var_0, var_1 );
    var_3 = undefined;

    for ( var_4 = 0; var_4 < var_0.size; var_4++ )
    {
        if ( !isdefined( var_0[var_4].teleport_inuse ) || !var_0[var_4].teleport_inuse )
        {
            var_3 = var_0[var_4];
            var_3.teleport_inuse = 1;
            thread reset_teleport_inuse( var_3 );
            break;
        }
    }

    if ( !isdefined( var_3 ) )
        var_3 = var_0[randomint( var_0.size )];

    return var_3;
}

debug_circle( var_0, var_1, var_2, var_3, var_4, var_5 )
{

}

reset_teleport_inuse( var_0 )
{
    wait 5;
    var_0.teleport_inuse = undefined;
}

infinite_cycle( var_0 )
{
    maps\mp\alien\_spawn_director::start_cycle( var_0 );
    level waittill( "game_ended" );
    maps\mp\alien\_spawn_director::end_cycle();
}

lurker_loop()
{
    level endon( "game_ended" );
    common_scripts\utility::flag_set( "lurker_active" );

    for (;;)
    {
        ai_event_settings();
        var_0 = "goon";

        foreach ( var_2 in level.alien_lurkers[var_0].spawn_locs )
        {
            var_2 notify( "new_listener" );
            var_2 thread lurker_listen_trigger( var_0 );
        }

        level waittill( "alien_cycle_prespawning", var_4 );
        var_5 = 10;
        wait( max( 0, var_4 - var_5 ) );
        common_scripts\utility::flag_clear( "lurker_active" );
        level notify( "removing_lurkers" );
        ai_event_settings_reset();
        var_6 = get_alive_lurkers();

        foreach ( var_8 in var_6 )
            var_8 thread send_away_and_die();

        wait 6;

        if ( get_alive_lurkers().size > 0 )
        {
            foreach ( var_8 in get_alive_lurkers() )
                var_8 suicide();
        }

        level waittill( "alien_cycle_ended" );
        common_scripts\utility::flag_set( "lurker_active" );
    }
}

ai_event_settings()
{
    level.old_ai_eventdistgunshot = getdvarint( "ai_eventdistgunshot" );
    level.old_ai_eventdistgunshotteam = getdvarint( "ai_eventdistgunshotteam" );
    level.old_ai_eventdistnewenemy = getdvarint( "ai_eventdistnewenemy" );
    level.old_ai_eventdistdeath = getdvarint( "ai_eventdistdeath" );
    setdvar( "ai_eventdistgunshot", 512 );
    setdvar( "ai_eventdistgunshotteam", 512 );
    setdvar( "ai_eventdistnewenemy", 512 );
    setdvar( "ai_eventdistdeath", 512 );
}

ai_event_settings_reset()
{
    setdvar( "ai_eventdistgunshot", level.old_ai_eventdistgunshot );
    setdvar( "ai_eventdistgunshotteam", level.old_ai_eventdistgunshotteam );
    setdvar( "ai_eventdistnewenemy", level.old_ai_eventdistnewenemy );
    setdvar( "ai_eventdistdeath", level.old_ai_eventdistdeath );
}

remove_farthest_lurker( var_0 )
{
    var_1 = get_alive_lurkers();

    while ( var_1.size > 1 )
    {
        foreach ( var_3 in var_0 )
        {
            var_4 = common_scripts\utility::getclosest( var_3.origin, var_1 );
            var_1 = common_scripts\utility::array_remove( var_1, var_4 );

            if ( var_1.size == 1 )
                break;
        }
    }

    if ( !var_1.size )
        return 0;

    var_1[0] suicide();
}

get_alive_agents()
{
    var_0 = [];

    foreach ( var_2 in level.agentarray )
    {
        if ( isalive( var_2 ) )
            var_0[var_0.size] = var_2;
    }

    return var_0;
}

get_alive_enemies()
{
    var_0 = [];
    var_1 = [];
    var_2 = get_alive_agents();

    if ( isdefined( level.dlc_get_non_agent_enemies ) )
        var_1 = [[ level.dlc_get_non_agent_enemies ]]();

    var_0 = common_scripts\utility::array_combine( var_2, var_1 );
    return var_0;
}

get_alive_lurkers()
{
    var_0 = [];

    foreach ( var_2 in level.agentarray )
    {
        if ( isalive( var_2 ) && isdefined( var_2.lurker ) )
            var_0[var_0.size] = var_2;
    }

    return var_0;
}

lurker_listen_trigger( var_0 )
{
    level endon( "game_ended" );
    level endon( "removing_lurkers" );
    self endon( "new_listener" );
    self.cooldown = 0;
    self.spawned_lurker = undefined;
    self.spawn_trigger.reset = 0;

    for (;;)
    {
        if ( !common_scripts\utility::flag( "lurker_active" ) )
        {
            common_scripts\utility::flag_wait( "lurker_active" );
            self.cooldown = 0;
        }

        wait( self.cooldown );
        self.cooldown = 0;

        if ( isdefined( self.spawned_lurker ) && isalive( self.spawned_lurker ) )
        {
            wait 0.05;
            continue;
        }

        if ( !self.spawn_trigger.reset )
            wait_for_reset();

        self.spawn_trigger waittill( "trigger", var_1 );
        self.spawn_trigger.reset = 0;

        if ( get_alive_agents().size >= get_alive_lurkers().size )
        {
            while ( get_alive_agents().size >= level.max_lurker_population )
            {
                remove_farthest_lurker( maps\mp\alien\_utility::get_players() );
                wait 0.1;
            }
        }
        else
        {
            while ( get_alive_lurkers().size >= level.max_lurker_population )
            {
                remove_farthest_lurker( maps\mp\alien\_utility::get_players() );
                wait 0.1;
            }
        }

        self.cooldown = 10;
        self.spawned_lurker = spawn_lurker( var_0 );
        self.spawned_lurker waittill( "death" );
    }
}

wait_for_reset()
{
    level endon( "game_ended" );
    level endon( "removing_lurkers" );
    self endon( "new_listener" );
    var_0 = 1;

    while ( var_0 )
    {
        var_0 = 0;

        foreach ( var_2 in maps\mp\alien\_utility::get_players() )
        {
            if ( var_2 istouching( self.spawn_trigger ) )
                var_0 = 1;
        }

        if ( var_0 )
            wait 0.05;
    }

    self.spawn_trigger.reset = 1;
}

send_away_and_die()
{
    self endon( "death" );
    self notify( "run_to_death" );
    maps\mp\agents\alien\_alien_think::set_alien_movemode( "run" );
    set_ignore_enemy();
    self.moveplaybackrate = self.moveplaybackrate * 1.25;
    var_0 = getnodesinradiussorted( self.origin, 1000, 10 );
    self scragentsetgoalnode( var_0[var_0.size - 1] );
    self scragentsetgoalradius( 64 );
    common_scripts\utility::waittill_any_timeout( 5, "goal_reached" );
    clear_ignore_enemy();
    smoke_puff();
    wait 0.2;
    self suicide();
    return 1;
}

set_ignore_enemy()
{
    maps\mp\alien\_utility::enable_alien_scripted();

    if ( isdefined( self.enemy ) )
        self.enemy.current_attackers = [];
}

clear_ignore_enemy()
{
    maps\mp\alien\_utility::disable_alien_scripted();

    foreach ( var_1 in maps\mp\alien\_utility::get_players() )
        self getenemyinfo( var_1 );
}

smoke_puff()
{
    playfxontag( level._effect["alien_teleport"], self, "j_jaw" );
    playfxontag( level._effect["alien_teleport"], self, "j_spineupper" );
    playfxontag( level._effect["alien_teleport"], self, "j_mainroot" );
    playfxontag( level._effect["alien_teleport"], self, "j_tail_3" );
    playfxontag( level._effect["alien_teleport_dist"], self, "j_mainroot" );
}

spawn_lurker( var_0 )
{
    var_1 = self.origin;
    var_2 = ( 0, 0, 0 );

    if ( isdefined( self.angles ) )
        var_2 = self.angles;

    var_3 = "lurker";
    var_4 = var_3 + " " + var_0;
    var_5 = spawnalien( var_1, var_2, var_4 );
    return var_5;
}

alien_wave_behavior()
{
    self endon( "death" );

    foreach ( var_1 in maps\mp\alien\_utility::get_players() )
        self getenemyinfo( var_1 );

    if ( isdefined( level.bomb ) && issentient( level.bomb ) )
        self getenemyinfo( level.bomb );

    self.goalradius = 64;
    self.instandingmelee = 0;
}

alien_lurker_behavior()
{
    self endon( "death" );
    self endon( "run_to_death" );
    set_ignore_enemy();
    thread wakeup_to_player_distance();
    thread wakeup_to_player_damage();
    thread walk_patrol_loop();
    self waittill( "woke" );
    clear_ignore_enemy();
    wait 1;

    if ( self.movemode == "walk" )
        maps\mp\agents\alien\_alien_think::set_alien_movemode( "run" );
}

wakeup_to_enemy()
{
    self endon( "woke" );
    self endon( "death" );
    self endon( "run_to_death" );
    self waittill( "enemy" );
    self notify( "woke" );
}

wakeup_to_player_distance( var_0 )
{
    self endon( "woke" );
    self endon( "death" );
    self endon( "run_to_death" );

    if ( !isdefined( var_0 ) )
        var_0 = 512;

    var_1 = 0;

    while ( !var_1 )
    {
        foreach ( var_3 in maps\mp\alien\_utility::get_players() )
        {
            if ( distance( var_3.origin, self.origin ) < var_0 )
            {
                var_1 = 1;
                break;
            }
        }

        wait 0.25;
    }

    self notify( "woke" );
}

wakeup_to_player_damage()
{
    self endon( "woke" );
    self endon( "death" );
    self endon( "run_to_death" );

    for (;;)
    {
        self waittill( "damage", var_0, var_1 );

        if ( isdefined( var_1 ) && isalive( var_1 ) && isplayer( var_1 ) )
            break;
    }

    self notify( "woke" );
}

walk_patrol_loop()
{
    self endon( "woke" );
    self endon( "death" );
    self endon( "run_to_death" );
    wait 1;

    if ( isdefined( level.patrol_start_nodes ) )
    {
        var_0 = common_scripts\utility::getclosest( self.origin, level.patrol_start_nodes );
        maps\mp\agents\alien\_alien_think::set_alien_movemode( "walk" );

        for (;;)
        {
            self scragentsetgoalpos( var_0.origin );
            self scragentsetgoalradius( 32 );
            self waittill( "goal_reached" );

            if ( isdefined( var_0.script_delay ) )
                wait( var_0.script_delay );

            var_0 = common_scripts\utility::getstruct( var_0.target, "targetname" );
        }
    }
}

alien_ai_debug_print( var_0 )
{
    self endon( "death" );
    self notify( "new_name_tag" );
    self endon( "new_name_tag" );

    if ( getdvarint( "alien_debug_director" ) == 1 )
    {
        for (;;)
            wait 0.05;
    }
}

get_available_meteoroid_clip( var_0 )
{
    foreach ( var_2 in level.meteoroid_clips )
    {
        if ( !isdefined( var_2.used_by ) )
        {
            var_2.used_by = var_0;
            return var_2;
        }
    }

    return undefined;
}

setup_meteoroid_paths()
{
    level._effect["vfx_alien_lightning_bolt"] = loadfx( "vfx/gameplay/alien/vfx_alien_lightning_bolt_02" );
    level._effect["vfx_alien_lightning_impact"] = loadfx( "vfx/gameplay/alien/vfx_alien_lightning_impact_debris_01" );
    level.meteoroid_impact_nodes = [];
    level.meteoroid_impact_nodes = common_scripts\utility::getstructarray( "meteoroid_impact", "targetname" );
    level.meteoroid_clips = [];
    level.meteoroid_clips = getentarray( "meteoroid_clip", "targetname" );

    foreach ( var_1 in level.meteoroid_clips )
    {
        var_1.used_by = undefined;
        var_1.old_origin = var_1.origin;
    }

    if ( !isdefined( level.meteoroid_impact_nodes ) || level.meteoroid_impact_nodes.size == 0 )
        return;

    foreach ( var_4 in level.meteoroid_impact_nodes )
    {
        var_4.rocks = [];
        var_4.occupied = 0;
        var_5 = common_scripts\utility::getstructarray( var_4.target, "targetname" );

        foreach ( var_7 in var_5 )
        {
            if ( !isdefined( var_7.script_noteworthy ) )
                continue;

            if ( var_7.script_noteworthy == "rocks" )
                var_4.rocks[var_4.rocks.size] = var_7;

            if ( var_7.script_noteworthy == "meteoroid_final" )
            {
                var_4.meteoroid_final_pos = var_7.origin;
                var_4.meteoroid_final_angles = var_7.angles;
                var_4.meteoroid = var_7;
                var_8 = common_scripts\utility::getstruct( var_7.target, "targetname" );

                if ( isdefined( var_8 ) )
                {
                    var_4.meteoroid_start_pos = var_8.origin;
                    var_4.meteoroid_start_angles = var_8.angles;
                    var_9 = common_scripts\utility::getstruct( var_8.target, "targetname" );

                    if ( isdefined( var_9 ) )
                    {
                        var_4.meteoroid_end_pos = var_9.origin;
                        var_4.meteoroid_end_angles = var_9.angles;
                    }
                }
            }
        }
    }
}

get_meteoroid_impact_node()
{
    if ( common_scripts\utility::flag_exist( "hives_cleared" ) && common_scripts\utility::flag( "hives_cleared" ) )
        return get_meteoroid_impact_node_escape();

    var_0 = get_center_of_players();
    var_1 = 2000;
    var_2 = [];

    foreach ( var_4 in level.meteoroid_impact_nodes )
    {
        if ( isdefined( var_4.script_noteworthy ) && ( var_4.script_noteworthy == "escape_blocker_meteor" || var_4.script_noteworthy == "escape_meteor" ) )
            continue;

        if ( distance2d( var_4.origin, var_0 ) > var_1 )
            continue;

        if ( var_4.occupied == 0 )
            var_2[var_2.size] = var_4;
    }

    if ( var_2.size > 0 )
        return var_2[randomint( var_2.size )];
    else
        return undefined;
}

get_meteoroid_impact_node_escape()
{
    var_0 = "level.latest_choke_trig_active not defined during escape sequence";
    var_1 = level.latest_choke_trig_active.choke_loc;
    var_2 = 4000;
    var_3 = [];

    foreach ( var_5 in level.meteoroid_impact_nodes )
    {
        if ( !isdefined( var_5.script_noteworthy ) || var_5.script_noteworthy != "escape_blocker_meteor" && var_5.script_noteworthy != "escape_meteor" )
            continue;

        if ( distance2d( var_5.origin, var_1 ) > var_2 )
            continue;

        if ( var_5.occupied == 0 )
            var_3[var_3.size] = var_5;
    }

    if ( var_3.size > 0 )
    {
        var_7 = common_scripts\utility::getclosest( var_1, var_3 );

        if ( isdefined( var_7 ) && isdefined( var_7.script_noteworthy ) && var_7.script_noteworthy == "escape_blocker_meteor" )
        {
            return var_7;
            return;
        }

        return var_3[randomint( var_3.size )];
        return;
    }
    else
        return undefined;
}

get_center_of_players()
{
    var_0 = 0;
    var_1 = 0;
    var_2 = 0;

    foreach ( var_4 in level.players )
    {
        var_0 = var_0 + var_4.origin[0];
        var_1 = var_1 + var_4.origin[1];
        var_2 = var_2 + var_4.origin[2];
    }

    var_6 = max( 1, level.players.size );
    var_7 = ( var_0 / var_6, var_1 / var_6, var_2 / var_6 );
    return var_7;
}

spawn_alien_meteoroid( var_0, var_1, var_2, var_3, var_4 )
{
    level endon( "nuke_went_off" );

    if ( !isdefined( level.meteoroid_impact_nodes ) || level.meteoroid_impact_nodes.size == 0 )
        return 0;

    if ( !isdefined( var_2 ) )
        var_2 = 0;

    if ( !isdefined( var_1 ) )
    {
        var_1 = 4;

        foreach ( var_6 in level.meteoroid_impact_nodes )
        {
            if ( var_6.occupied )
                var_1 = var_1 + 2;
        }
    }

    if ( !isdefined( var_3 ) )
        var_3 = 60;

    if ( !isdefined( var_4 ) )
        var_4 = 20;

    var_8 = get_meteoroid_impact_node();

    if ( !isdefined( var_8 ) )
        return 0;

    var_9 = get_available_meteoroid_clip( var_8 );

    if ( !isdefined( var_9 ) )
        return 0;

    var_8.occupied = 1;
    var_8.meteoroid.ent = spawn( "script_model", var_8.meteoroid.origin );
    var_8.meteoroid.ent setmodel( "mp_ext_alien_meteor" );
    var_10 = var_8.meteoroid_start_pos;
    var_11 = var_8.meteoroid_start_angles;
    var_12 = var_8.meteoroid_final_pos;
    var_13 = var_8.meteoroid_final_angles;
    var_14 = var_8.meteoroid_end_pos;
    var_15 = var_8.meteoroid_end_angles;
    var_16 = 5;
    var_17 = 4;
    var_18 = 3;

    if ( common_scripts\utility::flag_exist( "hives_cleared" ) && common_scripts\utility::flag( "hives_cleared" ) )
    {
        var_16 = 3;
        var_17 = 1;
        var_18 = 2;
    }

    var_8.meteoroid.ent.origin = var_10;
    var_8.meteoroid.ent.angles = var_11;
    level thread maps\mp\alien\_music_and_dialog::playvoformeteor();
    var_8.meteoroid.ent moveto( var_12, var_16, var_17 );
    thread maps\mp\_utility::playsoundinspace( "alien_minion_spawn_mtr_incoming", var_12 );
    var_8.meteoroid.ent rotatevelocity( ( 0, 360, 0 ), var_16, var_17 );

    for ( var_19 = 0; var_19 < var_18; var_19++ )
    {
        playfx( level._effect["vfx_alien_lightning_bolt"], var_12 );
        thread maps\mp\_utility::playsoundinspace( "alien_minion_spawn_lightning", var_12 );
        wait( var_16 / var_18 );
    }

    var_8.meteoroid.ent.origin = var_12;
    var_8.meteoroid.ent.angles = var_13;
    playfx( level._effect["vfx_alien_lightning_impact"], var_8.origin );
    earthquake( 0.75, 1, var_8.origin, 2000 );
    thread maps\mp\_utility::playsoundinspace( "alien_meteor_impact", var_8.origin );
    playrumbleonposition( "grenade_rumble", var_8.origin );
    radiusdamage( var_8.origin, 256, 150, 10 );
    var_9.origin = var_8.origin;
    var_9 disconnectpaths();
    playfx( level._effect["vfx_alien_lightning_bolt"], var_12 );
    spawn_meteoroid_aliens( var_8, var_0, var_1, var_2, var_3, var_4 );

    if ( common_scripts\utility::flag_exist( "hives_cleared" ) && common_scripts\utility::flag( "hives_cleared" ) && isdefined( var_8.script_noteworthy ) && var_8.script_noteworthy == "escape_blocker_meteor" )
    {
        var_20 = 25;
        var_18 = 3;

        for ( var_19 = 0; var_19 < var_18; var_19++ )
        {
            playfx( level._effect["vfx_alien_lightning_bolt"], var_12 );
            thread maps\mp\_utility::playsoundinspace( "alien_minion_spawn_lightning", var_12 );
            wait( var_20 / var_18 );
        }
    }

    playfx( level._effect["vfx_alien_lightning_bolt"], var_12 );
    thread maps\mp\_utility::playsoundinspace( "alien_minion_spawn_lightning", var_12 );
    var_8.meteoroid.ent moveto( var_14, var_16 / 2, var_17 / 2 );
    var_8.meteoroid.ent rotatevelocity( ( 0, 90, 0 ), var_16 / 2, var_17 / 2 );
    playfx( level._effect["queen_ground_spawn"], var_8.origin, ( 0, 0, 1 ) );
    thread maps\mp\_utility::playsoundinspace( "alien_minion_spawn_mtr_sink", var_8.origin );
    earthquake( 0.3, var_16 / 2, var_8.origin, 512 );
    wait( var_16 / 4 );
    wait( var_16 / 4 );
    var_8.meteoroid.ent delete();
    var_9.origin = var_9.old_origin;
    var_9 connectpaths();
    var_9.used_by = undefined;
    var_8.occupied = 0;
}

spawn_meteoroid_aliens( var_0, var_1, var_2, var_3, var_4, var_5 )
{
    level endon( "nuke_went_off" );
    var_6 = var_0.origin;
    wait 1;
    var_7 = 0;
    var_8 = gettime() + var_5 * 1000.0;
    var_9 = [];

    for (;;)
    {
        if ( gettime() >= var_8 )
        {
            level notify( "meteor_aliens_spawned", var_9, var_2 );
            return;
        }

        if ( var_7 >= var_2 && !var_3 )
        {
            level notify( "meteor_aliens_spawned", var_9, var_2 );
            wait 7;
            return;
        }

        if ( !can_spawn_meteoroid_alien( var_1, var_2 ) )
        {
            wait 0.05;
            continue;
        }

        var_10 = get_center_of_players();
        var_11 = vectornormalize( var_10 - var_6 );
        var_11 = rotatevector( var_11, ( 0, 120 - randomint( 120 ), 0 ) );
        var_12 = vectortoangles( var_11 );
        var_13 = spawnalien( var_6, var_12, "wave " + var_1 );

        if ( !isdefined( var_0.script_noteworthy ) || var_0.script_noteworthy != "escape_blocker_meteor" && var_0.script_noteworthy != "escape_meteor" )
            var_13 thread crawl_out( var_6, var_11 );

        var_9[var_9.size] = var_13;
        var_7++;
        wait( randomfloatrange( 0.05, 0.25 ) );
        wait( 60 / var_4 - 0.15 );
    }
}

can_spawn_meteoroid_alien( var_0, var_1 )
{
    var_2 = 0;

    foreach ( var_4 in level.agentarray )
    {
        if ( isalive( var_4 ) )
        {
            if ( var_4 maps\mp\alien\_utility::is_alien_agent() && var_4.alien_type == var_0 )
                var_2++;
        }
    }

    var_6 = maps\mp\alien\_spawn_director::get_current_agent_count( 1 );

    if ( var_6 > 17 )
        return 0;

    if ( var_2 > var_1 )
        return 0;

    return 1;
}

crawl_out( var_0, var_1 )
{
    self endon( "death" );
    maps\mp\alien\_utility::enable_alien_scripted();
    var_2 = self.moveplaybackrate;
    self.moveplaybackrate = 0.5;
    self scragentsetgoalradius( 4000 );
    self scragentsetanimmode( "anim deltas" );
    self scragentsetorientmode( "face angle abs", self.angles );
    self scragentsetphysicsmode( "noclip" );
    self setorigin( var_0 + vectornormalize( var_1 ) * 64 );
    movetoendonground( "traverse_climb_up", 4 );
    self setanimstate( "traverse_climb_up", 4 );
    var_3 = getanimlength( self getanimentry( "traverse_climb_up", 4 ) );
    wait( var_3 / 2 );
    self scragentsetphysicsmode( "gravity" );
    wait( var_3 / 2 );
    self.moveplaybackrate = var_2;
    clear_ignore_enemy();
    var_4 = self.health;
    var_5 = self.moveplaybackrate;
    var_6 = self.animplaybackrate;

    while ( self.health > var_4 * 0.95 )
    {
        maps\mp\agents\alien\_alien_think::set_alien_movemode( "walk" );
        self.moveplaybackrate = 1.75;
        self.animplaybackrate = 1.75;
        wait 0.05;
    }

    maps\mp\agents\alien\_alien_think::set_alien_movemode( "run" );
    self.moveplaybackrate = var_5;
    self.animplaybackrate = var_6;
}

movetoendonground( var_0, var_1, var_2, var_3 )
{
    var_4 = 2;
    var_5 = 60;
    var_6 = 32;
    var_7 = self getanimentry( var_0, var_1 );
    var_8 = getanimlength( var_7 );
    var_9 = getmovedelta( var_7, 0, 1 );
    var_10 = rotatevector( var_9, self.angles );
    var_11 = self.origin + ( var_10[0], var_10[1], var_5 );
    var_12 = var_11 - ( 0, 0, 2 * var_5 );
    var_13 = self aiphysicstrace( var_11, var_12, var_6, 65 );
    var_14 = var_13 - var_10 + ( 0, 0, var_4 );
    self setorigin( var_14 );
    playfx( level._effect["drone_ground_spawn"], ( self.origin[0], self.origin[1], var_13[2] ), ( 0, 0, 1 ) );
    debug_line( var_11, var_13, ( 1, 0, 0 ), 30 );
    debug_origin( var_13, 4, ( 1, 0, 0 ), 30 );
    debug_origin( self.origin + var_10, 4, ( 1, 1, 1 ), 30 );
    debug_line( self.origin, self.origin + var_10, ( 1, 1, 1 ), 30 );
}

debug_origin( var_0, var_1, var_2, var_3 )
{

}

debug_line( var_0, var_1, var_2, var_3 )
{

}

draw_line( var_0, var_1, var_2, var_3 )
{
    if ( getdvarint( "alien_debug_director" ) > 0 )
    {
        if ( isdefined( var_3 ) )
        {
            for ( var_4 = 0; var_4 < var_3; var_4++ )
                wait 0.05;
        }
        else
        {
            for (;;)
                wait 0.05;
        }
    }
}

get_cycles( var_0 )
{
    return level.strongholds[var_0].cycles;
}

is_cycle_repeated( var_0, var_1 )
{
    var_2 = get_cycles( var_0 );
    return var_2[var_1].repeat;
}

get_waves( var_0, var_1 )
{
    var_2 = get_cycles( var_0 );
    return var_2[var_1].waves;
}

get_current_cycle()
{
    return level.alien_wave_status["cycle"];
}

get_current_wave()
{
    return level.alien_wave_status["wave"];
}

use_spawn_director()
{
    if ( isdefined( level.use_spawn_director ) && level.use_spawn_director == 1 )
        return 1;

    return 0;
}

encounter_cycle_spawn( var_0, var_1 )
{
    level endon( "game_ended" );
    level.current_cycle_started_by_timeout = undefined;

    if ( isdefined( var_1 ) )
        level endon( var_1 );

    if ( !isdefined( level.cycle_count ) )
        level.cycle_count = init_cycle_count();

    var_2 = get_cycle_spawn_delay();
    var_3 = undefined;

    if ( isdefined( var_0 ) )
        var_3 = level common_scripts\utility::waittill_any_timeout( var_2, var_0 );
    else
        wait( var_2 );

    if ( isdefined( var_3 ) && var_3 == "timeout" )
        level.current_cycle_started_by_timeout = 1;

    var_4 = level.cycle_count;

    if ( isdefined( level.get_custom_cycle_func ) )
        var_4 = [[ level.get_custom_cycle_func ]]();

    maps\mp\alien\_spawn_director::start_cycle( var_4 );
    level.cycle_count++;
}

init_cycle_count()
{
    return 1;
}

get_cycle_spawn_delay()
{
    var_0 = get_extra_spawn_delay();
    return level.cycle_data.cycle_delay_times[level.cycle_count] + var_0;
}

get_extra_spawn_delay()
{
    if ( maps\mp\alien\_utility::is_chaos_mode() )
        return 0;
    else
        return maps\mp\agents\_agent_utility::getnumactiveagents() * 3.0;
}
