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

init()
{
    if ( !isdefined( level.alien_cycle_table ) )
        level.alien_cycle_table = "mp/alien/default_cycle_spawn.csv";

    if ( !isdefined( level.alien_cycle_table_hardcore ) )
        level.alien_cycle_table_hardcore = "mp/alien/default_cycle_spawn_hardcore.csv";

    if ( maps\mp\alien\_utility::is_hardcore_mode() )
        level.alien_cycle_table = level.alien_cycle_table_hardcore;

    if ( !isdefined( level.base_player_count_multiplier ) )
    {
        level.base_player_count_multiplier = 0.49;
        level.additional_player_count_multiplier = 0.17;
    }

    if ( !isdefined( level.hardcore_spawn_multiplier ) )
        level.hardcore_spawn_multiplier = 1.0;

    if ( !isdefined( level.hardcore_damage_scalar ) )
        level.hardcore_damage_scalar = 1.0;

    if ( !isdefined( level.hardcore_health_scalar ) )
        level.hardcore_health_scalar = 1.0;

    if ( !isdefined( level.hardcore_reward_scalar ) )
        level.hardcore_reward_scalar = 1.0;

    if ( !isdefined( level.hardcore_score_scalar ) )
        level.hardcore_score_scalar = 1.0;

    if ( !isdefined( level.casual_spawn_multiplier ) )
        level.casual_spawn_multiplier = 1.0;

    if ( !isdefined( level.casual_damage_scalar ) )
        level.casual_damage_scalar = 0.5;

    if ( !isdefined( level.casual_health_scalar ) )
        level.casual_health_scalar = 0.5;

    if ( !isdefined( level.casual_reward_scalar ) )
        level.casual_reward_scalar = 1.0;

    if ( !isdefined( level.casual_score_scalar ) )
        level.casual_score_scalar = 0.5;

    level.cycle_data = spawnstruct();
    level.lanes = [];
    load_cycles_from_table( level.cycle_data );
    init_spawn_node_info( level.cycle_data );
    build_spawn_zones( level.cycle_data );
    load_spawn_events_from_table( level.cycle_data );
    load_variables_from_table( level.cycle_data );
    load_cycle_scalars_from_table( level.cycle_data );
    load_cycle_drill_layer_from_table( level.cycle_data );
    load_random_hives_from_table();
    load_encounter_lanes_from_table();
    populate_lane_spawners();
    level.cycle_data.current_wave_types = create_wave_types_array();
    level.cycle_data.current_spawn_event_wave_types = create_wave_types_array();
    level thread spawn_type_vo_monitor();
    level thread monitor_meteor_spawn();
    level thread monitor_ground_spawn();
    level.pending_meteor_spawns = 0;
    level.pending_ground_spawns = 0;
    level.pending_custom_spawns = 0;
    level.cycle_spawning_active = 0;

    if ( maps\mp\alien\_utility::isplayingsolo() )
        level.cycle_data.max_alien_count = int( ceil( 18 * level.base_player_count_multiplier ) );
    else
        level.cycle_data.max_alien_count = 18;
}

load_variables_from_table( var_0 )
{
    var_0.min_spawn_interval = float( tablelookup( level.alien_cycle_table, 0, 400, 2 ) );
    var_1 = float( tablelookup( level.alien_cycle_table, 0, 401, 2 ) );
    var_0.safe_spawn_distance_sq = var_1 * var_1;
    var_0.spawn_point_last_used_duration = float( tablelookup( level.alien_cycle_table, 0, 402, 2 ) ) * 1000.0;
    var_2 = float( tablelookup( level.alien_cycle_table, 0, 403, 2 ) );
    var_0.group_break_away_distance_sq = var_2 * var_2;
    var_0.player_in_zone_score_modifier = float( tablelookup( level.alien_cycle_table, 0, 404, 2 ) );
    var_0.current_attacker_in_zone_score_modifier = float( tablelookup( level.alien_cycle_table, 0, 405, 2 ) );
    var_0.recently_used_spawn_zone_score_modifier = float( tablelookup( level.alien_cycle_table, 0, 406, 2 ) );
    var_0.max_break_away_zone_score_increase = float( tablelookup( level.alien_cycle_table, 0, 407, 2 ) );
    var_0.spawn_event_min_activation_time = float( tablelookup( level.alien_cycle_table, 0, 408, 2 ) );
    var_0.spawn_event_per_alien_activation_increase = float( tablelookup( level.alien_cycle_table, 0, 409, 2 ) );
    var_0.spawn_event_max_activation_increase = float( tablelookup( level.alien_cycle_table, 0, 410, 2 ) );
}

load_encounter_lanes_from_table()
{
    level.encounter_lanes = [];

    for ( var_0 = 700; var_0 <= 799; var_0++ )
    {
        var_1 = tablelookup( level.alien_cycle_table, 0, var_0, 1 );

        if ( var_1 == "" )
            break;

        if ( !isdefined( level.encounter_lanes[var_1] ) )
            level.encounter_lanes[var_1] = [];

        var_2 = strtok( tablelookup( level.alien_cycle_table, 0, var_0, 2 ), ", " );
        var_3 = strtok( tablelookup( level.alien_cycle_table, 0, var_0, 3 ), " ,()" );
        var_4 = get_lanes_from_names( var_3 );
        var_5 = tolower( var_3[0] ) == "random_sequence" && var_3.size > 1;
        var_6 = 0;

        foreach ( var_8 in var_2 )
        {
            var_9 = [];

            if ( var_5 )
            {
                var_9[0] = var_4[var_6];
                var_6++;

                if ( var_6 >= var_4.size )
                    var_6 = 0;
            }
            else
                var_9 = var_4;

            add_new_encounter_lane( var_1, var_9, var_8 );
        }

        foreach ( var_12 in var_4 )
        {
            if ( isdefined( level.lanes[var_12] ) )
                continue;

            level.lanes[var_12] = [];
        }
    }

    foreach ( var_16, var_15 in level.encounter_lanes )
        level.encounter_lanes[var_16] = sort_array( level.encounter_lanes[var_16], ::sort_encounter_level_activation_time_func );
}

add_new_encounter_lane( var_0, var_1, var_2 )
{
    var_3 = spawnstruct();
    var_3.lanes = var_1;
    var_3.activation_time = int( var_2 ) * 1000.0;
    var_4 = level.encounter_lanes[var_0].size;
    level.encounter_lanes[var_0][var_4] = var_3;
}

get_lanes_from_names( var_0 )
{
    var_1 = tolower( var_0[0] ) == "random_sequence" && var_0.size > 1;
    var_2 = tolower( var_0[0] ) == "random" && var_0.size > 1;
    var_3 = [];

    if ( var_1 )
    {
        var_3 = maps\mp\alien\_utility::array_remove_index( var_0, 0 );
        var_3 = common_scripts\utility::array_randomize( var_3 );
    }
    else if ( var_2 )
    {
        var_4 = randomintrange( 1, var_0.size );
        var_3[0] = var_0[var_4];
    }
    else
        var_3 = var_0;

    return var_3;
}

populate_lane_spawners()
{
    foreach ( var_8, var_1 in level.lanes )
    {
        var_2 = common_scripts\utility::getstruct( var_8, "targetname" );
        var_3 = var_2 common_scripts\utility::get_links();

        foreach ( var_5 in var_3 )
        {
            var_6 = find_spawners_by_script_name( var_5 );
            level.lanes[var_8] = common_scripts\utility::array_combine( level.lanes[var_8], var_6 );
        }
    }
}

find_spawners_by_script_name( var_0 )
{
    var_1 = [];

    for ( var_2 = 0; var_2 < level.cycle_data.spawner_list.size; var_2++ )
    {
        if ( !isdefined( level.cycle_data.spawner_list[var_2]["location"].script_linkname ) )
            continue;

        if ( level.cycle_data.spawner_list[var_2]["location"].script_linkname == var_0 )
            var_1[var_1.size] = var_2;
    }

    return var_1;
}

load_spawn_events_from_table( var_0 )
{
    var_0.generic_spawn_events = [];

    for ( var_1 = 2000; var_1 <= 2099; var_1++ )
    {
        var_2 = tablelookup( level.alien_cycle_table, 0, var_1, 1 );

        if ( var_2 == "" )
            break;

        var_3 = int( var_2 ) - 1;
        var_4 = spawnstruct();
        var_4.activation_notify = tablelookup( level.alien_cycle_table, 0, var_1, 2 );
        var_4.id = strtok( tablelookup( level.alien_cycle_table, 0, var_1, 3 ), " ," );
        var_4.time_limit = float( tablelookup( level.alien_cycle_table, 0, var_1, 4 ) );
        var_5 = strtok( tablelookup( level.alien_cycle_table, 0, var_1, 5 ), " ," );

        if ( var_5.size > 0 )
        {
            var_6 = get_lanes_from_names( var_5 );
            var_4.lanes = var_6;

            foreach ( var_8 in var_6 )
            {
                if ( isdefined( level.lanes[var_8] ) )
                    continue;

                level.lanes[var_8] = [];
            }
        }

        if ( var_3 == -1 )
        {
            var_4.allow_initial_delay = 0;
            var_10 = var_0.generic_spawn_events.size;
            var_0.generic_spawn_events[var_10] = var_4;
            continue;
        }

        var_4.allow_initial_delay = 1;
        var_10 = var_0.spawn_cycles[var_3].spawn_events.size;
        var_0.spawn_cycles[var_3].spawn_events[var_10] = var_4;
    }

    load_spawn_event_waves_from_table();
}

load_spawn_event_waves_from_table()
{
    level.spawn_event_waves = [];

    for ( var_0 = 3000; var_0 <= 3099; var_0++ )
    {
        var_1 = tablelookup( level.alien_cycle_table, 0, var_0, 1 );

        if ( var_1 == "" )
            break;

        if ( !isdefined( level.spawn_event_waves[var_1] ) )
            level.spawn_event_waves[var_1] = [];

        var_2 = spawnstruct();
        var_2.blocking = get_spawn_event_wave_blocking_by_index( var_0 );
        var_2.spawn_delay = float( tablelookup( level.alien_cycle_table, 0, var_0, 3 ) );
        var_2.entry_index = var_0;
        var_3 = level.spawn_event_waves[var_1].size;
        level.spawn_event_waves[var_1][var_3] = var_2;
    }
}

get_spawn_event_wave_blocking_by_index( var_0 )
{
    var_1 = tablelookup( level.alien_cycle_table, 0, var_0, 2 );
    return var_1 == "yes";
}

clear_spawn_event_wave_types()
{
    foreach ( var_1 in level.cycle_data.current_spawn_event_wave_types )
    {
        var_1.type_name = undefined;
        var_1.min_spawned = undefined;
        var_1.max_spawned = undefined;
        var_1.max_of_type = undefined;
    }
}

get_spawn_event_types_array( var_0 )
{
    clear_spawn_event_wave_types();
    get_type_data( get_available_type_data( level.cycle_data.current_spawn_event_wave_types ), var_0, 4, 5 );
    get_type_data( get_available_type_data( level.cycle_data.current_spawn_event_wave_types ), var_0, 6, 7 );
    get_type_data( get_available_type_data( level.cycle_data.current_spawn_event_wave_types ), var_0, 8, 9 );
    get_type_data( get_available_type_data( level.cycle_data.current_spawn_event_wave_types ), var_0, 10, 11 );
    get_type_data( get_available_type_data( level.cycle_data.current_spawn_event_wave_types ), var_0, 12, 13 );
    level.cycle_data.current_spawn_event_wave_types = sort_array( level.cycle_data.current_spawn_event_wave_types, ::sort_priority_levels_func );
    return level.cycle_data.current_spawn_event_wave_types;
}

set_intensity( var_0 )
{
    level.current_intensity = clamp( var_0, 0.0, 1.0 );
}

force_intensity( var_0, var_1 )
{
    if ( var_0 )
        level.forced_current_intensity = clamp( var_1, 0.0, 1.0 );
    else if ( isdefined( level.forced_current_intensity ) )
        level.forced_current_intensity = undefined;
}

load_cycles_from_table( var_0 )
{
    var_0.spawn_cycles = [];
    var_1 = 0;
    var_2 = 399;

    if ( level.script == "mp_alien_last" && !maps\mp\alien\_utility::is_chaos_mode() )
    {
        var_1 = 1000;
        var_2 = 1999;
    }

    for ( var_3 = var_1; var_3 <= var_2; var_3++ )
    {
        var_4 = get_cycle_by_index( var_3 );

        if ( var_4 == "" )
            break;

        var_5 = int( var_4 ) - 1;

        if ( !isdefined( var_0.spawn_cycles[var_5] ) )
        {
            var_6 = spawnstruct();
            var_6.intensitylevels = [];
            var_6.spawn_events = [];
            var_6.lanes = [];
            var_6.type_max_counts = [];
            var_0.spawn_cycles[var_5] = var_6;
        }
        else
            var_6 = var_0.spawn_cycles[var_5];

        var_7 = spawnstruct();
        var_7.intensitythreshold = get_intensity_threshold_by_index( var_3 );
        var_7.tableindex = var_3;
        var_6.intensitylevels[var_6.intensitylevels.size] = var_7;
    }

    foreach ( var_6 in var_0.spawn_cycles )
    {
        var_6.intensitylevels = sort_array( var_6.intensitylevels, ::sort_intensity_levels_func );

        if ( var_6.intensitylevels.size > 0 )
        {
            var_9 = var_6.intensitylevels[var_6.intensitylevels.size - 1].intensitythreshold;

            foreach ( var_11 in var_6.intensitylevels )
            {
                if ( var_9 <= 0.0 )
                {
                    var_11.intensitythreshold = 0.0;
                    continue;
                }

                var_11.intensitythreshold = var_11.intensitythreshold / var_9;
            }

            var_6.fullintensitytime = var_9 * 1000.0;
        }
    }
}

sort_array( var_0, var_1, var_2, var_3 )
{
    if ( !isdefined( var_2 ) )
        var_2 = 0;

    for ( var_4 = var_2 + 1; var_4 < var_0.size; var_4++ )
    {
        var_5 = var_0[var_4];

        for ( var_6 = var_4 - 1; var_6 >= var_2 && [[ var_1 ]]( var_0[var_6], var_5, var_3 ); var_6-- )
            var_0[var_6 + 1] = var_0[var_6];

        var_0[var_6 + 1] = var_5;
    }

    return var_0;
}

sort_intensity_levels_func( var_0, var_1, var_2 )
{
    return var_0.intensitythreshold > var_1.intensitythreshold;
}

sort_encounter_level_activation_time_func( var_0, var_1, var_2 )
{
    return var_0.activation_time > var_1.activation_time;
}

sort_priority_levels_func( var_0, var_1, var_2 )
{
    if ( !isdefined( var_1.type_name ) )
        return 0;

    if ( !isdefined( var_0.type_name ) )
        return 1;

    var_3 = get_translated_ai_type( var_0.type_name );
    var_4 = get_translated_ai_type( var_1.type_name );
    var_5 = level.alien_types[var_3].attributes["attacker_priority"];
    var_6 = level.alien_types[var_4].attributes["attacker_priority"];
    return var_5 > var_6;
}

sort_closest_distance_to_players_func( var_0, var_1, var_2 )
{
    var_3 = get_average_distance_to_players( var_0["location"].origin );
    var_4 = get_average_distance_to_players( var_1["location"].origin );
    return var_3 > var_4;
}

sort_player_view_direction_func( var_0, var_1, var_2 )
{
    var_3 = var_2[0];
    var_4 = var_2[1];
    var_5 = get_player_to_node_dot( var_3, var_4, var_1["location"] );
    var_6 = get_player_to_node_dot( var_3, var_4, var_0["location"] );
    return var_6 < var_5;
}

get_player_to_node_dot( var_0, var_1, var_2 )
{
    var_3 = vectornormalize( var_2.origin - var_0 );
    return vectordot( var_3, var_1 );
}

get_average_distance_to_players( var_0 )
{
    var_1 = level.players.size;

    if ( var_1 == 0 )
        return 0;

    var_2 = 0;

    foreach ( var_4 in level.players )
        var_2 = var_2 + distancesquared( var_4.origin, var_0 );

    return var_2 / var_1;
}

build_spawn_zones( var_0 )
{
    var_1 = common_scripts\utility::getstructarray( "alien_spawn_struct", "targetname" );
    var_2 = getentarray( "spawn_zone", "targetname" );
    var_0.spawn_zones = [];

    foreach ( var_4 in var_2 )
    {
        var_5 = spawnstruct();
        var_5.zone_name = var_4.script_linkname;
        var_5.volume = var_4;
        var_5.spawn_nodes = [];
        var_0.spawn_zones[var_4.script_linkname] = var_5;
    }

    var_0.spawner_list = [];
    put_spawnlocations_into_cycle_data( var_1, var_0 );
}

put_spawnlocations_into_cycle_data( var_0, var_1 )
{
    foreach ( var_3 in var_0 )
    {
        var_4 = [];

        if ( isdefined( level.adjust_spawnlocation_func ) )
            var_3 = [[ level.adjust_spawnlocation_func ]]( var_3 );

        if ( isdefined( var_3.script_noteworthy ) )
            var_4 = strtok( var_1.spawn_node_info[var_3.script_noteworthy].validtype, " " );

        var_5 = [];
        var_5["types"] = var_4;
        var_5["location"] = var_3;
        var_1.spawner_list[var_1.spawner_list.size] = var_5;

        if ( !isdefined( var_3.script_linkto ) )
            continue;

        var_6 = var_3 common_scripts\utility::get_links();

        foreach ( var_8 in var_6 )
        {
            var_9 = var_1.spawn_zones[var_8].spawn_nodes.size;
            var_1.spawn_zones[var_8].spawn_nodes[var_9] = var_5;
        }
    }
}

spawn_zone_exists( var_0, var_1 )
{
    foreach ( var_4, var_3 in var_1.spawn_zones )
    {
        if ( var_4 == var_0 )
            return 1;
    }

    return 0;
}

can_spawn_type( var_0 )
{
    if ( !isdefined( level.current_cycle ) || !isdefined( level.current_cycle.type_max_counts[var_0] ) )
        return get_max_alien_count() - get_current_agent_count() > 0;

    return level.current_cycle.type_max_counts[var_0] - get_current_agent_count_of_type( var_0 ) > 0;
}

reserve_custom_spawn_space( var_0, var_1, var_2 )
{
    if ( !isdefined( var_1 ) )
        var_1 = 0;

    var_3 = get_current_agent_count();

    if ( var_1 )
    {
        if ( isdefined( var_2 ) && isdefined( level.current_cycle ) && isdefined( level.current_cycle.type_max_counts[var_2] ) )
            var_0 = clamp( level.current_cycle.type_max_counts[var_2] - get_current_agent_count_of_type( var_2 ), 0, var_0 );

        var_4 = clamp( get_max_alien_count() - var_3, 0, var_0 );
    }
    else if ( var_3 + var_0 <= get_max_alien_count() )
        var_4 = var_0;
    else
        var_4 = 0;

    level.pending_custom_spawns = level.pending_custom_spawns + var_4;
    return var_4;
}

process_custom_spawn( var_0, var_1, var_2 )
{
    var_3 = get_current_agent_count( 1, 0, 1 );

    if ( var_3 >= get_max_alien_count() )
        var_4 = undefined;
    else
        var_4 = process_spawn( var_0, var_1, var_2 );

    level.pending_custom_spawns = max( 0, level.pending_custom_spawns - 1 );
    return var_4;
}

release_custom_spawn_space( var_0 )
{
    level.pending_custom_spawns = max( 0, level.pending_custom_spawns - var_0 );
}

get_cycle_by_index( var_0 )
{
    return tablelookup( level.alien_cycle_table, 0, var_0, 1 );
}

get_intensity_level_by_index( var_0 )
{
    return tablelookup( level.alien_cycle_table, 0, var_0, 2 );
}

get_respawn_threshold_by_index( var_0 )
{
    var_1 = tablelookup( level.alien_cycle_table, 0, var_0, 4 );

    if ( var_1 == "" || var_1 == " " )
        return undefined;

    return int( var_1 );
}

get_respawn_delay_by_index( var_0 )
{
    var_1 = tablelookup( level.alien_cycle_table, 0, var_0, 5 );

    if ( var_1 == "" || var_1 == " " )
        return undefined;

    return float( var_1 );
}

get_intensity_threshold_by_index( var_0 )
{
    return float( tablelookup( level.alien_cycle_table, 0, var_0, 3 ) );
}

get_types_array( var_0 )
{
    get_type_data( get_available_type_data( level.cycle_data.current_wave_types ), var_0, 7, 8 );
    get_type_data( get_available_type_data( level.cycle_data.current_wave_types ), var_0, 9, 10 );
    get_type_data( get_available_type_data( level.cycle_data.current_wave_types ), var_0, 11, 12 );
    get_type_data( get_available_type_data( level.cycle_data.current_wave_types ), var_0, 13, 14 );
    get_type_data( get_available_type_data( level.cycle_data.current_wave_types ), var_0, 15, 16 );
    get_type_data( get_available_type_data( level.cycle_data.current_wave_types ), var_0, 17, 18 );
    get_type_data( get_available_type_data( level.cycle_data.current_wave_types ), var_0, 19, 20 );
    get_type_data( get_available_type_data( level.cycle_data.current_wave_types ), var_0, 21, 22 );
    get_type_data( get_available_type_data( level.cycle_data.current_wave_types ), var_0, 23, 24 );
    level.cycle_data.current_wave_types = sort_array( level.cycle_data.current_wave_types, ::sort_priority_levels_func );
}

get_available_type_data( var_0 )
{
    for ( var_1 = 0; var_1 < var_0.size; var_1++ )
    {
        if ( !isdefined( var_0[var_1].type_name ) )
            return var_0[var_1];
    }

    return undefined;
}

get_type_data( var_0, var_1, var_2, var_3 )
{
    if ( !isdefined( var_0 ) )
        return undefined;

    var_4 = tablelookup( level.alien_cycle_table, 0, var_1, var_2 );

    if ( var_4 == "" )
        return undefined;

    var_5 = strtok( tablelookup( level.alien_cycle_table, 0, var_1, var_3 ), " " );
    var_0.type_name = var_4;
    var_5[0] = int( var_5[0] );
    var_5[1] = int( var_5[1] );

    if ( var_5.size == 0 )
        var_0.min_spawned = 0;
    else if ( var_5.size == 1 )
        var_0.min_spawned = var_5[0];
    else
    {
        if ( var_5[0] < var_5[1] )
        {
            var_0.min_spawned = var_5[0];
            var_0.max_spawned = var_5[1];
        }
        else if ( var_5[1] > var_5[0] )
        {
            var_0.min_spawned = var_5[1];
            var_0.max_spawned = var_5[0];
        }
        else
            var_0.min_spawned = var_5[0];

        if ( var_5.size == 3 )
            var_0.max_of_type = int( var_5[2] );
    }

    return var_0;
}

remove_spawn_location( var_0 )
{
    foreach ( var_2 in level.cycle_data.spawn_zones )
    {
        for ( var_3 = 0; var_3 < var_2.spawn_nodes.size; var_3++ )
        {
            var_4 = var_2.spawn_nodes[var_3]["location"];

            if ( !isdefined( var_4.script_linkname ) )
                continue;

            if ( var_4.script_linkname == var_0 )
            {
                var_2.spawn_nodes = maps\mp\alien\_utility::array_remove_index( var_2.spawn_nodes, var_3 );
                break;
            }
        }
    }
}

start_cycle( var_0 )
{
    set_cycle_scalars( var_0 );
    level.cycle_spawning_active = 1;
    level thread spawn_director_loop( var_0 - 1 );
    level notify( "alien_cycle_started" );
}

end_cycle()
{
    level notify( "end_cycle" );
    level.cycle_spawning_active = 0;
    level notify( "alien_cycle_ended" );
}

pause_cycle( var_0 )
{
    if ( !level.cycle_spawning_active )
        return;

    level thread pause_cycle_internal( var_0 );
}

pause_cycle_internal( var_0 )
{
    level.intensity_spawning_paused_count++;
    wait( var_0 );
    level.intensity_spawning_paused_count = int( max( 0, level.intensity_spawning_paused_count - 1 ) );
}

activate_spawn_event( var_0, var_1 )
{
    if ( !isdefined( var_1 ) )
        var_1 = 0;

    var_2 = find_spawn_event( var_0 );

    if ( !isdefined( var_2 ) )
    {
        if ( isdefined( level.current_cycle_num ) )
            var_3 = level.current_cycle_num + 1;
        else
            var_3 = 0;
    }
    else
    {
        if ( var_1 )
        {
            level run_spawn_event( var_2, var_0 );
            return;
        }

        level thread run_spawn_event( var_2, var_0 );
    }
}

find_spawn_event( var_0 )
{
    if ( isdefined( level.current_cycle ) )
    {
        foreach ( var_2 in level.current_cycle.spawn_events )
        {
            if ( var_2.activation_notify == var_0 )
                return var_2;
        }
    }

    foreach ( var_2 in level.cycle_data.generic_spawn_events )
    {
        if ( var_2.activation_notify == var_0 )
            return var_2;
    }

    return undefined;
}

wait_for_spawn_event_delay()
{
    while ( level.pending_meteor_spawns > 0 || level.pending_ground_spawns > 0 )
        wait 0.05;

    var_0 = level.cycle_data.spawn_event_min_activation_time + level.cycle_data.spawn_event_per_alien_activation_increase * get_current_agent_count();
    var_0 = min( level.cycle_data.spawn_event_max_activation_increase, var_0 );
    wait( var_0 );
}

run_spawn_event( var_0, var_1 )
{
    level endon( "end_cycle" );
    level endon( "nuke_went_off" );
    level endon( "game_ended" );

    if ( level.cycle_spawning_active )
        level.intensity_spawning_paused_count++;

    if ( var_0.allow_initial_delay )
        wait_for_spawn_event_delay();

    level thread spawn_event_time_limit_monitor( var_0.time_limit, var_0.activation_notify );
    level thread process_spawn_event_spawning( var_0 );
    common_scripts\utility::waittill_any( "spawn_event_complete" + var_0.activation_notify, "spawn_event_time_limit_reached" + var_0.activation_notify );

    if ( level.cycle_spawning_active )
        level.intensity_spawning_paused_count = int( max( 0, level.intensity_spawning_paused_count - 1 ) );
}

process_spawn_event_spawning( var_0 )
{
    var_1 = [];
    var_2 = randomint( var_0.id.size );
    var_3 = var_0.id[var_2];
    level.override_lane_index = 0;

    foreach ( var_5 in level.spawn_event_waves[var_3] )
    {
        if ( var_5.spawn_delay > 0.0 )
            wait( var_5.spawn_delay );

        if ( isdefined( var_0.lanes ) )
            var_6 = var_0.lanes;
        else
            var_6 = undefined;

        var_5.types = get_spawn_event_types_array( var_5.entry_index );

        if ( wave_has_delayed_spawn_type( var_5 ) )
            var_7 = spawn_event_delayed_wave_spawn( var_5, var_0.activation_notify, var_6 );
        else
            var_7 = spawn_event_wave_spawn( var_5, var_0.activation_notify, var_6 );

        var_1 = common_scripts\utility::array_combine( var_1, var_7 );
    }

    wait_for_all_aliens_killed( var_1, var_0.activation_notify );
    level notify( "spawn_event_complete" + var_0.activation_notify );
}

wave_has_delayed_spawn_type( var_0 )
{
    if ( wave_has_type( var_0, "minion" ) )
        return 1;

    if ( wave_has_type( var_0, "elite" ) )
        return 1;

    return 0;
}

wave_has_type( var_0, var_1 )
{
    foreach ( var_3 in var_0.types )
    {
        if ( !isdefined( var_3.type_name ) )
            continue;

        if ( var_3.type_name == var_1 )
            return 1;
    }

    return 0;
}

spawn_event_wave_spawn( var_0, var_1, var_2 )
{
    var_3 = spawn_wave( var_0.types, "event", var_2 );

    if ( var_0.blocking )
        spawn_event_wave_block( var_3, var_1 );

    return var_3;
}

spawn_event_wave_block( var_0, var_1 )
{
    wait_for_all_aliens_killed( var_0, var_1 );
}

spawn_event_delayed_wave_spawn( var_0, var_1, var_2 )
{
    var_3 = spawn_wave( var_0.types, "event", var_2 );

    if ( level.pending_meteor_spawns > 0 )
        level thread spawn_event_minion_wave_spawn();

    if ( level.pending_ground_spawns > 0 )
        level thread spawn_event_elite_wave_spawn();

    while ( level.pending_meteor_spawns > 0 || level.pending_ground_spawns > 0 )
    {
        level waittill( "spawn_event_delayed_spawn_complete", var_4 );
        var_3 = common_scripts\utility::array_combine( var_3, var_4 );
        wait 0.05;
    }

    if ( var_0.blocking )
        spawn_event_wave_block( var_3, var_1 );

    return var_3;
}

spawn_event_minion_wave_spawn()
{
    var_0 = [];

    while ( level.pending_meteor_spawns > 0 )
    {
        level waittill( "meteor_aliens_spawned", var_1, var_2 );
        var_0 = common_scripts\utility::array_combine( var_0, var_1 );
        wait 0.05;
    }

    level notify( "spawn_event_delayed_spawn_complete", var_0 );
}

spawn_event_elite_wave_spawn()
{
    var_0 = [];

    while ( level.pending_ground_spawns > 0 )
    {
        level waittill( "ground_alien_spawned", var_1 );
        var_0[var_0.size] = var_1;
        wait 0.05;
    }

    level notify( "spawn_event_delayed_spawn_complete", var_0 );
}

spawn_event_time_limit_monitor( var_0, var_1 )
{
    level endon( "spawn_event_complete" + var_1 );
    wait( var_0 );
    level notify( "spawn_event_time_limit_reached" + var_1 );
}

wait_for_all_aliens_killed( var_0, var_1 )
{
    level endon( "spawn_event_complete" + var_1 );

    for (;;)
    {
        wait 0.05;
        var_2 = 0;

        foreach ( var_4 in var_0 )
        {
            if ( isalive( var_4 ) )
            {
                var_2 = 1;
                break;
            }
        }

        if ( !var_2 )
            break;
    }
}

create_wave_types_array()
{
    var_0 = 9;
    var_1 = [];

    for ( var_2 = 0; var_2 < var_0; var_2++ )
    {
        var_3 = spawnstruct();
        var_3.type_name = undefined;
        var_1[var_1.size] = var_3;
    }

    return var_1;
}

spawn_director_loop( var_0 )
{
    level endon( "end_cycle" );
    level endon( "nuke_went_off" );
    level endon( "game_ended" );
    level.spawn_node_traces_this_frame = 0;
    level.spawn_node_traces_frame_time = gettime();
    level.intensity_spawning_paused_count = 0;
    level.current_cycle_num = var_0;
    level.current_cycle = level.cycle_data.spawn_cycles[var_0];
    cycle_begin_intensity_monitor();
    level.pending_meteor_spawns = 0;
    level.pending_ground_spawns = 0;
    activate_current_lane_monitor();

    if ( !isdefined( level.debug_spawn_director_active ) || !level.debug_spawn_director_active )
        initial_spawn();

    for (;;)
    {
        var_1 = respawn_threshold_monitor();
        respawn( var_1 );
    }
}

activate_current_lane_monitor()
{
    if ( maps\mp\alien\_utility::is_chaos_mode() )
        return;

    level thread current_lane_monitor();
}

cycle_begin_intensity_monitor()
{
    level.current_intensity_level = -1;
    level.current_intensity = 0.0;
    level thread intensity_monitor_update_loop();
}

intensity_monitor_update_loop()
{
    level endon( "end_cycle" );
    level endon( "nuke_went_off" );
    level endon( "game_ended" );
    var_0 = gettime();

    for (;;)
    {
        var_1 = gettime();

        if ( level.intensity_spawning_paused_count == 0 )
        {
            if ( isdefined( level.forced_current_intensity ) )
                level.current_intensity = level.forced_current_intensity;
            else if ( level.current_cycle.fullintensitytime == 0.0 )
                level.current_intensity = 1.0;
            else
            {
                var_2 = ( var_1 - var_0 ) / level.current_cycle.fullintensitytime;
                level.current_intensity = clamp( level.current_intensity + var_2, 0.0, 1.0 );
            }

            var_0 = var_1;
            var_3 = calculate_current_intensity_level();

            if ( level.current_intensity_level != var_3 )
                level notify( "intensity_level_changed" );

            level.current_intensity_level = var_3;
        }
        else
            var_0 = var_1;

        wait 0.1;
    }
}

current_lane_monitor()
{
    level endon( "end_cycle" );
    level endon( "nuke_went_off" );
    level endon( "game_ended" );
    level.cycle_data.current_lane = undefined;

    for ( var_0 = get_current_encounter(); !isdefined( var_0 ); var_0 = get_current_encounter() )
        wait 0.2;

    if ( !isdefined( level.encounter_lanes[var_0] ) || level.encounter_lanes[var_0].size == 0 )
        return;

    for (;;)
    {
        var_1 = undefined;

        foreach ( var_5, var_3 in level.encounter_lanes[var_0] )
        {
            var_4 = var_3.activation_time / level.current_cycle.fullintensitytime;

            if ( var_4 > level.current_intensity )
                break;

            var_1 = var_5;
        }

        if ( isdefined( var_1 ) )
        {
            var_6 = level.encounter_lanes[var_0][var_1];

            if ( !isdefined( level.cycle_data.current_lane ) || var_6 != level.cycle_data.current_lane )
            {
                level.cycle_data.current_lane = var_6;
                play_lane_change_sound();
            }
        }

        wait 0.5;
    }
}

play_lane_change_sound()
{
    var_0 = get_random_entry( level.cycle_data.current_lane.lanes );
    var_1 = level.lanes[var_0][randomint( level.lanes[var_0].size )];
    var_2 = level.cycle_data.spawner_list[var_1]["location"].origin;
    playsoundatpos( var_2, "alien_distant" );
}

calculate_current_intensity_level()
{
    for ( var_0 = 0; var_0 < level.current_cycle.intensitylevels.size; var_0++ )
    {
        if ( level.current_cycle.intensitylevels[var_0].intensitythreshold > level.current_intensity )
            break;
    }

    return var_0 - 1;
}

initial_spawn()
{
    while ( level.current_intensity_level < 0 )
        wait 0.05;

    var_0 = get_current_wave_ai_types();
    spawn_wave( var_0, "spawn" );
}

get_current_wave_ai_types()
{
    foreach ( var_1 in level.cycle_data.current_wave_types )
    {
        var_1.type_name = undefined;
        var_1.max_of_type = undefined;
        var_1.min_spawned = undefined;
        var_1.max_spawned = undefined;
    }

    var_3 = level.current_cycle.intensitylevels[level.current_intensity_level].tableindex;
    get_types_array( var_3 );
    level.cycle_data.current_respawn_threshold = get_respawn_threshold_by_index( var_3 );
    level.cycle_data.current_respawn_delay = get_respawn_delay_by_index( var_3 );
    return level.cycle_data.current_wave_types;
}

respawn( var_0 )
{
    if ( isdefined( var_0 ) && var_0 )
    {
        var_1 = level.cycle_data.current_wave_types;
        var_2 = "respawn";
    }
    else
    {
        var_1 = get_current_wave_ai_types();
        var_2 = "spawn";
    }

    spawn_wave( var_1, var_2 );
}

spawn_wave( var_0, var_1, var_2 )
{
    var_3 = [];

    for ( var_4 = 0; var_4 < var_0.size; var_4++ )
    {
        if ( isdefined( var_0[var_4].type_name ) )
            var_3 = common_scripts\utility::array_combine( spawn_type( var_0[var_4], var_1, var_2 ), var_3 );
    }

    return var_3;
}

respawn_threshold_monitor()
{
    level endon( "end cycle" );
    level endon( "intensity_level_changed" );

    for (;;)
    {
        if ( level.current_intensity_level >= 0 && level.intensity_spawning_paused_count == 0 )
        {
            if ( isdefined( level.cycle_data.current_respawn_threshold ) && level.cycle_data.current_respawn_threshold >= 0 )
            {
                var_0 = get_current_agent_count();
                var_1 = get_scaled_alien_amount( level.cycle_data.current_respawn_threshold );

                if ( var_0 <= var_1 )
                    break;
            }
        }

        wait 0.1;
    }

    if ( isdefined( level.cycle_data.current_respawn_delay ) )
    {
        if ( level.current_intensity_level >= 0 && level.cycle_data.current_respawn_delay >= 0 )
            wait( level.cycle_data.current_respawn_delay * get_current_spawn_count_multiplier() );
    }

    return 1;
}

get_current_spawn_count_multiplier()
{
    var_0 = level.base_player_count_multiplier + level.additional_player_count_multiplier * ( level.players.size - 1 );

    if ( maps\mp\alien\_utility::is_hardcore_mode() )
        var_0 = var_0 * level.hardcore_spawn_multiplier;

    return var_0;
}

spawn_type_vo_monitor()
{
    level endon( "game_ended" );
    level endon( "nuke_went_off" );
    var_0 = gettime();
    var_1 = var_0;
    var_2 = var_0;
    var_3 = 40000;
    var_4 = 30000;

    for (;;)
    {
        level waittill( "spawned_alien", var_5 );

        if ( !isdefined( var_5.alien_type ) )
            continue;

        if ( common_scripts\utility::flag_exist( "escape_conditions_met" ) && common_scripts\utility::flag( "escape_conditions_met" ) )
            return;

        switch ( var_5.alien_type )
        {
            case "spitter":
                var_0 = gettime();

                if ( var_0 >= var_1 )
                {
                    level thread maps\mp\alien\_music_and_dialog::playvoforspitterspawn( var_5 );
                    var_1 = var_0 + var_3;
                }

                break;
            case "elite":
                var_0 = gettime();

                if ( var_0 >= var_2 )
                {
                    level thread maps\mp\alien\_music_and_dialog::playvoforqueenspawn( var_5 );
                    var_2 = var_0 + var_4;
                }

                break;
            case "seeder":
                level notify( "dlc_vo_notify", "inbound_seeder", var_5 );
                break;
            case "brute":
                level notify( "dlc_vo_notify", "inbound_brute", var_5 );
                break;
            case "mammoth":
                level notify( "dlc_vo_notify", "inbound_mammoth", var_5 );
                break;
            case "gargoyle":
                level notify( "dlc_vo_notify", "inbound_gargoyle", var_5 );
                break;
            case "bomber":
                level notify( "dlc_vo_notify", "inbound_bomber", var_5 );
                break;
            default:
                break;
        }
    }
}

get_scaled_alien_amount( var_0 )
{
    var_1 = var_0 * get_current_spawn_count_multiplier();
    return max( 1, int( var_1 + 0.5 ) );
}

get_modified_alien_amount( var_0, var_1, var_2 )
{
    var_3 = get_scaled_alien_amount( var_0 );
    return get_max_type_count( var_1, var_3 );
}

spawn_type( var_0, var_1, var_2 )
{
    if ( !isdefined( var_0.max_spawned ) )
        var_3 = var_0.min_spawned;
    else
        var_3 = randomintrange( var_0.min_spawned, var_0.max_spawned );

    var_4 = get_modified_alien_amount( var_3, var_0, var_1 );
    var_5 = [];

    if ( !isdefined( level.cycle_data.current_lane ) && !isdefined( level.cycle_data.non_lane_spawn_started ) )
    {
        level thread maps\mp\alien\_music_and_dialog::play2dspawnsound();
        level.cycle_data.non_lane_spawn_started = 1;
    }

    switch ( var_0.type_name )
    {
        case "minion":
            spawn_minions( var_4 );
            break;
        case "elite":
            spawn_elite( var_4 );
            break;
        default:
            var_5 = spawn_aliens( var_4, var_0.type_name, var_2 );
            break;
    }

    return var_5;
}

get_max_alien_count()
{
    return level.cycle_data.max_alien_count;
}

get_max_type_count( var_0, var_1 )
{
    if ( !isdefined( level.current_cycle ) )
        return var_1;

    var_2 = get_translated_ai_type( var_0.type_name );

    if ( isdefined( var_0.max_of_type ) )
    {
        if ( var_0.max_of_type <= 0 )
            level.current_cycle.type_max_counts[var_2] = undefined;
        else
            level.current_cycle.type_max_counts[var_2] = var_0.max_of_type;
    }

    if ( !isdefined( level.current_cycle.type_max_counts[var_2] ) )
        return var_1;

    var_3 = get_scaled_alien_amount( level.current_cycle.type_max_counts[var_2] );
    var_3 = max( 0, var_3 - get_current_agent_count_of_type( var_2 ) );
    return min( var_1, var_3 );
}

at_max_alien_count()
{
    return get_current_agent_count() >= get_max_alien_count();
}

get_translated_ai_type( var_0 )
{
    switch ( var_0 )
    {
        case "minion_nometeor":
            return "minion";
    }

    return var_0;
}

spawn_aliens( var_0, var_1, var_2 )
{
    var_1 = get_translated_ai_type( var_1 );
    var_3 = [];

    for ( var_4 = 0; var_4 < var_0; var_4++ )
    {
        if ( at_max_alien_count() )
            break;

        var_6 = undefined;

        if ( maps\mp\alien\_utility::is_chaos_mode() )
            var_6 = ::sort_player_view_direction;

        var_7 = spawn_alien( var_1, var_2, undefined, var_6 );
        var_3[var_3.size] = var_7;
        wait( level.cycle_data.min_spawn_interval );
    }

    return var_3;
}

spawn_minions( var_0 )
{
    level thread spawn_meteor_aliens( var_0, "minion" );
    wait( level.cycle_data.min_spawn_interval );
}

spawn_elite( var_0 )
{
    level thread spawn_ground_aliens( var_0, "elite", ::elite_monitor );
    wait( level.cycle_data.min_spawn_interval );
}

elite_monitor()
{
    if ( !isdefined( level.cycle_data.elite_count ) || level.cycle_data.elite_count == 0 )
    {
        level thread maps\mp\alien\_music_and_dialog::handlefirstelitearrival( self );
        level.cycle_data.elite_count = 1;
    }
    else
        level.cycle_data.elite_count++;

    self waittill( "death" );
    level.cycle_data.elite_count--;

    if ( level.cycle_data.elite_count == 0 )
        level thread maps\mp\alien\_music_and_dialog::handlelastelitedeath( self );
}

is_spawn_debug_info_requested()
{
    return getdvarint( "scr_alienspawninfo", 0 ) == 1 || getdvarint( "scr_alienspawneventinfo" ) == 1;
}

spawn_meteor_aliens( var_0, var_1 )
{
    level endon( "game_ended" );
    level endon( "nuke_went_off" );

    if ( var_0 >= 9 )
        var_2 = int( var_0 / 3 );
    else
        var_2 = 4;

    level.pending_meteor_spawns = level.pending_meteor_spawns + var_0;

    while ( var_0 > 0 )
    {
        var_3 = var_2;

        if ( var_0 < var_2 )
            var_3 = var_0;

        var_4 = level thread maps\mp\alien\_spawnlogic::spawn_alien_meteoroid( var_1, var_3 );

        if ( isdefined( var_4 ) )
        {
            level.pending_meteor_spawns = level.pending_meteor_spawns - var_0;
            return;
        }

        var_0 = var_0 - var_3;
        wait( randomintrange( 5, 10 ) );
        level thread maps\mp\alien\_music_and_dialog::playvoforminions();
    }
}

spawn_ground_aliens( var_0, var_1, var_2 )
{
    level endon( "game_ended" );
    level endon( "nuke_went_off" );
    var_3 = 2.0;
    var_4 = 3.5;

    while ( var_0 > 0 )
    {
        var_5 = level thread spawn_ground_alien( var_1, 1, var_2 );

        if ( isdefined( var_5 ) )
            return;

        level.pending_ground_spawns++;
        var_0 = var_0 - 1;
        wait( randomfloatrange( var_3, var_4 ) );
    }
}

spawn_ground_alien( var_0, var_1, var_2 )
{
    var_3 = 10000;
    var_4 = [];
    var_5 = spawn_alien( var_0, var_4, var_3, ::sort_closest_to_players );
    var_5 thread [[ var_2 ]]();
    level notify( "ground_alien_spawned", var_5 );
}

monitor_meteor_spawn()
{
    level endon( "game_ended" );
    level endon( "nuke_went_off" );

    for (;;)
    {
        level waittill( "meteor_aliens_spawned", var_0, var_1 );
        level.pending_meteor_spawns = level.pending_meteor_spawns - var_1;

        if ( level.pending_meteor_spawns < 0 )
            level.pending_meteor_spawns = 0;
    }
}

monitor_ground_spawn()
{
    level endon( "game_ended" );
    level endon( "nuke_went_off" );

    for (;;)
    {
        level waittill( "ground_alien_spawned", var_0 );
        var_1 = var_0 maps\mp\alien\_utility::get_alien_type();

        if ( !isalive( var_0 ) )
            continue;

        level.pending_ground_spawns--;

        if ( level.pending_ground_spawns < 0 )
            level.pending_ground_spawns = 0;
    }
}

get_current_agent_count( var_0, var_1, var_2 )
{
    var_3 = maps\mp\agents\_agent_utility::getnumactiveagents();

    if ( !isdefined( var_0 ) || !var_0 )
        var_3 = var_3 + level.pending_meteor_spawns;

    if ( !isdefined( var_1 ) || !var_1 )
        var_3 = var_3 + level.pending_ground_spawns;

    if ( !isdefined( var_2 ) || !var_2 )
        var_3 = var_3 + level.pending_custom_spawns;

    return var_3;
}

get_current_agent_count_of_type( var_0 )
{
    var_1 = maps\mp\agents\_agent_utility::getactiveagentsoftype( "alien" );
    var_2 = 0;

    foreach ( var_4 in var_1 )
    {
        if ( isdefined( var_4.pet ) && var_4.pet )
            continue;

        if ( var_4 maps\mp\alien\_utility::get_alien_type() == var_0 )
            var_2++;
    }

    return var_2;
}

spawn_alien( var_0, var_1, var_2, var_3 )
{
    var_4 = find_safe_spawn_point_info( var_0, var_1, var_2, var_3 );
    var_5 = var_4["node"];
    var_6 = 0;

    if ( var_0 == "spitter" && isdefined( level.hive_heli ) && level.hive_heli.health > 0 && threatbiasgroupexists( "spitters" ) )
    {
        var_7 = 0;
        var_8 = 0;

        foreach ( var_10 in level.agentarray )
        {
            if ( !isdefined( var_10.isactive ) || !var_10.isactive || !isalive( var_10 ) || !isdefined( var_10.alien_type ) || var_10.alien_type != "spitter" )
                continue;

            if ( var_10 getthreatbiasgroup() == "spitters" )
            {
                var_8++;
                continue;
            }

            var_7++;
        }

        var_12 = int( max( 1, var_8 + var_7 ) );
        level.spitters_against_players_ratio = var_7 / var_12;
        var_13 = 0;

        foreach ( var_15 in level.players )
            var_13 = var_13 + distance2d( var_15.origin, level.hive_heli.origin );

        var_17 = var_13 / int( min( 1, level.players.size ) );
        var_18 = 0.32;

        if ( var_17 > 1500 )
            var_18 = 0.1;

        if ( level.spitters_against_players_ratio >= var_18 )
            var_6 = 1;
    }

    var_19 = process_intro_vignette_ai_type( var_0 );

    if ( isdefined( var_5.script_noteworthy ) )
        var_20 = level.cycle_data.spawn_node_info[var_5.script_noteworthy].vignetteinfo[var_19];
    else
        var_20 = undefined;

    var_21 = process_spawn( var_0, var_5, var_20 );

    if ( ( var_0 == "spitter" || var_0 == "seeder" ) && isdefined( level.hive_heli ) && level.hive_heli.health > 0 && threatbiasgroupexists( "spitters" ) )
    {
        if ( var_6 )
            var_21 maps\mp\alien\_spawnlogic::make_spitter_attack_chopper( 1 );
        else
            var_21 maps\mp\alien\_spawnlogic::make_spitter_attack_chopper( 0 );
    }

    if ( ( var_0 == "spitter" || var_0 == "seeder" || var_0 == "gargoyle" ) && common_scripts\utility::flag_exist( "player_using_vanguard" ) && common_scripts\utility::flag( "player_using_vanguard" ) && threatbiasgroupexists( "spitters" ) )
    {
        var_21 setthreatbiasgroup( "spitters" );
        var_21.favoriteenemy = level.alien_vanguard;
    }

    if ( isdefined( var_5.script_noteworthy ) )
    {
        if ( issubstr( var_5.script_noteworthy, "vent" ) )
            level notify( "dlc_vo_notify", "direction_vo", "spawn_vent" );

        if ( issubstr( var_5.script_noteworthy, "duct" ) )
            level notify( "dlc_vo_notify", "direction_vo", "spawn_vent" );

        if ( issubstr( var_5.script_noteworthy, "grate" ) )
            level notify( "dlc_vo_notify", "direction_vo", "spawn_grate" );
    }

    level notify( "spawned_alien", var_21 );
    return var_21;
}

process_intro_vignette_ai_type( var_0 )
{
    switch ( var_0 )
    {
        case "leper":
        case "locust":
            return "brute";
        case "mammoth":
            return "elite";
    }

    return var_0;
}

process_spawn( var_0, var_1, var_2 )
{
    var_3 = ( 0, 0, 0 );

    if ( isdefined( var_1.angles ) )
        var_3 = var_1.angles;

    var_1.last_used_time = gettime();
    var_4 = "wave " + var_0;
    var_5 = maps\mp\gametypes\aliens::addalienagent( "axis", var_1.origin, var_3, var_4, var_2 );
    return var_5;
}

find_safe_spawn_point_info( var_0, var_1, var_2, var_3 )
{
    if ( should_lane_spawn( var_1, var_0 ) )
        return find_lane_spawn_node( var_1 );

    var_4 = get_current_player_volumes();

    if ( var_4.size == 0 )
    {
        var_5 = find_random_spawn_node( level.cycle_data.spawner_list, var_0, var_2, ::filter_spawn_point_by_distance_from_player, undefined, var_3 );
        return var_5;
    }
    else if ( var_4.size == 1 )
    {
        foreach ( var_8, var_7 in var_4 )
        {
            if ( level.cycle_data.spawn_zones[var_8].spawn_nodes.size == 0 )
                continue;

            var_5 = find_random_spawn_node( level.cycle_data.spawn_zones[var_8].spawn_nodes, var_0, var_2, undefined, undefined, var_3 );
            return var_5;
        }
    }

    return find_safe_spawn_spot_with_volumes( var_4, var_0, var_2, var_3 );
}

get_current_encounter()
{
    return level.encounter_name;
}

should_lane_spawn( var_0, var_1 )
{
    var_2 = 1024;

    if ( maps\mp\alien\_utility::is_chaos_mode() )
        return 0;

    if ( isdefined( var_0 ) && var_0.size == 0 )
        return 0;

    if ( !can_spawn_at_any_node( var_1 ) )
        return 0;

    if ( isdefined( level.blocker_hive_active ) && level.blocker_hive_active )
        return 1;

    var_3 = get_current_drill_state();

    if ( !isdefined( var_0 ) )
    {
        if ( !isdefined( level.cycle_data.current_lane ) )
            return 0;

        if ( var_3 == "idle" )
            return 0;
    }

    if ( var_3 == "offline" )
    {
        var_4 = 0;
        var_5 = 0;

        foreach ( var_7 in level.players )
        {
            if ( isdefined( var_7 ) && isalive( var_7 ) )
            {
                var_5++;
                var_4 = var_4 + distance2d( var_7.origin, level.drill.origin );
            }
        }

        if ( var_5 > 0 )
        {
            if ( var_4 / var_5 > var_2 )
                return 0;
        }
    }

    return 1;
}

get_current_drill_state()
{
    if ( !isdefined( level.drill ) || !isdefined( level.drill.state ) )
        return "undefined";

    return level.drill.state;
}

get_override_lane_entry( var_0 )
{
    if ( !isdefined( level.override_lane_index ) )
        return get_random_entry( var_0 );

    if ( level.override_lane_index >= var_0.size )
        level.override_lane_index = 0;

    var_1 = level.override_lane_index;
    level.override_lane_index++;
    return var_0[var_1];
}

find_lane_spawn_node( var_0 )
{
    if ( isdefined( var_0 ) && var_0.size > 0 )
    {
        var_1 = get_random_entry( var_0 );
        var_2 = get_override_lane_entry( level.lanes[var_1] );
    }
    else
    {
        var_1 = get_random_entry( level.cycle_data.current_lane.lanes );
        var_2 = level.lanes[var_1][randomint( level.lanes[var_1].size )];
    }

    var_3 = [];
    var_3["node"] = level.cycle_data.spawner_list[var_2]["location"];
    var_3["validNode"] = 1;
    return var_3;
}

get_current_encounter_lane_index()
{
    var_0 = undefined;
    var_1 = get_current_encounter();

    if ( !isdefined( var_1 ) )
        return undefined;

    foreach ( var_5, var_3 in level.encounter_lanes[var_1] )
    {
        var_4 = var_3.activation_time / level.current_cycle.fullintensitytime;

        if ( var_4 > level.current_intensity )
            break;

        var_0 = var_5;
    }

    return level.encounter_lanes[var_1][var_0];
}

get_random_entry( var_0 )
{
    var_1 = -1;
    var_2 = randomint( var_0.size );

    foreach ( var_5, var_4 in var_0 )
    {
        var_1++;

        if ( var_1 == var_2 )
            return var_0[var_5];
    }

    return undefined;
}

filter_spawn_point_by_distance_from_player( var_0, var_1 )
{
    if ( var_1 == "elite" )
        return 1;

    var_2 = level.players[0].origin;
    return distancesquared( var_2, var_0.origin ) > level.cycle_data.safe_spawn_distance_sq;
}

sort_closest_to_players( var_0 )
{
    return sort_array( var_0, ::sort_closest_distance_to_players_func, 0 );
}

sort_player_view_direction( var_0 )
{
    var_1 = level.players[randomint( level.players.size )];
    var_2 = anglestoforward( var_1 getplayerangles() );
    return sort_array( var_0, ::sort_player_view_direction_func, 0, [ var_1.origin, var_2 ] );
}

find_random_spawn_node( var_0, var_1, var_2, var_3, var_4, var_5 )
{
    if ( isdefined( var_2 ) )
        var_6 = var_2;
    else
        var_6 = level.cycle_data.spawn_point_last_used_duration;

    if ( !isdefined( var_5 ) )
        var_5 = common_scripts\utility::array_randomize;

    var_0 = [[ var_5 ]]( var_0 );
    var_7 = 0;
    var_8 = randomfloatrange( var_6 * 0.5, var_6 * 0.75 );
    var_9 = 0.0;
    var_10 = 0;

    for ( var_11 = 0; var_11 < var_0.size; var_11++ )
    {
        var_12 = var_0[var_11]["location"];

        if ( isdefined( var_3 ) && !passes_spawn_node_filter( var_12, var_1, var_3, var_4 ) )
            continue;

        if ( isdefined( var_0[var_11]["location"].script_linkname ) )
            var_13 = var_0[var_11]["location"].script_linkname;
        else
            var_13 = undefined;

        if ( !is_valid_spawn_node_for_type( var_0[var_11]["types"], var_1, var_13 ) )
            continue;

        if ( !isdefined( var_12.last_used_time ) )
        {
            var_10 = 1;
            var_7 = var_11;
            break;
        }

        var_14 = gettime() - var_12.last_used_time;

        if ( var_14 > var_8 )
        {
            var_10 = 1;
            var_7 = var_11;
            break;
        }

        if ( var_14 > var_9 )
        {
            var_9 = var_14;
            var_7 = var_11;
        }
    }

    var_15 = [];
    var_15["node"] = var_0[var_7]["location"];
    var_15["validNode"] = var_10;
    return var_15;
}

is_valid_spawn_node_for_type( var_0, var_1, var_2 )
{
    if ( var_0.size == 0 )
        return can_spawn_at_any_node( var_1 );

    foreach ( var_4 in var_0 )
    {
        if ( var_4 == var_1 )
            return 1;
    }

    return 0;
}

can_spawn_at_any_node( var_0 )
{
    if ( isdefined( level.dlc_alien_type_node_match_override_func ) )
    {
        var_1 = self [[ level.dlc_alien_type_node_match_override_func ]]( var_0 );

        if ( isdefined( var_1 ) )
            return var_1;
    }

    switch ( var_0 )
    {
        case "elite":
            return 0;
        default:
            return 1;
    }
}

passes_spawn_node_filter( var_0, var_1, var_2, var_3 )
{
    if ( isdefined( var_3 ) )
        return [[ var_2 ]]( var_0, var_1, var_3 );

    return [[ var_2 ]]( var_0, var_1 );
}

find_safe_spawn_spot_with_volumes( var_0, var_1, var_2, var_3 )
{
    var_4 = score_and_sort_spawn_zones( var_0 );

    foreach ( var_6 in var_4 )
    {
        if ( level.cycle_data.spawn_zones[var_6.name].spawn_nodes.size == 0 )
            continue;

        var_7 = [];

        foreach ( var_10, var_9 in var_0 )
        {
            if ( var_10 != var_6.name )
                var_7 = common_scripts\utility::array_combine( var_7, var_9.players );
        }

        var_11 = find_random_spawn_node( level.cycle_data.spawn_zones[var_6.name].spawn_nodes, var_1, var_2, ::is_safe_spawn_location, var_7, var_3 );

        if ( var_11["validNode"] )
            return var_11;
    }

    var_11 = find_random_spawn_node( level.cycle_data.spawner_list, var_1, var_2, ::filter_spawn_point_by_distance_from_player, undefined, var_3 );
    return var_11;
}

score_and_sort_spawn_zones( var_0 )
{
    var_1 = calculate_player_proximity_scores();

    foreach ( var_3 in var_0 )
    {
        var_4 = 0.0;

        foreach ( var_6 in var_3.players )
        {
            var_4 = var_4 + level.cycle_data.player_in_zone_score_modifier;

            if ( isdefined( var_6.current_attackers ) )
                var_4 = var_4 - var_6.current_attackers.size * level.cycle_data.current_attacker_in_zone_score_modifier;

            if ( isdefined( var_1[var_6.name] ) && var_1[var_6.name] > level.cycle_data.group_break_away_distance_sq )
                var_4 = var_4 + min( level.cycle_data.max_break_away_zone_score_increase, var_1[var_6.name] / level.cycle_data.group_break_away_distance_sq );
        }

        var_4 = var_4 - get_number_of_recently_used_spawn_points_in_zone( var_3 ) * level.cycle_data.recently_used_spawn_zone_score_modifier;
        var_3.zone_score = var_4;
    }

    var_9 = [];

    foreach ( var_3 in var_0 )
        var_9[var_9.size] = var_3;

    return sort_array( var_9, ::sort_zone_score_func );
}

calculate_player_proximity_scores()
{
    var_0 = [];

    if ( level.players.size <= 2 )
        return var_0;

    for ( var_1 = 0; var_1 < level.players.size; var_1++ )
    {
        var_2 = level.players[var_1].name;

        if ( !isdefined( var_0[var_2] ) )
            var_0[var_2] = 100000000.0;

        for ( var_3 = var_1 + 1; var_3 < level.players.size; var_3++ )
        {
            var_4 = distancesquared( level.players[var_1].origin, level.players[var_3].origin );

            if ( var_4 < var_0[var_2] )
                var_0[var_2] = var_4;

            var_5 = level.players[var_3].name;

            if ( !isdefined( var_0[var_5] ) || var_4 < var_0[var_5] )
                var_0[var_5] = var_4;
        }
    }

    return var_0;
}

get_number_of_recently_used_spawn_points_in_zone( var_0 )
{
    var_1 = 0;
    var_2 = gettime();

    for ( var_3 = 0; var_3 < level.cycle_data.spawn_zones[var_0.name].spawn_nodes.size; var_3++ )
    {
        var_4 = level.cycle_data.spawn_zones[var_0.name].spawn_nodes[var_3]["location"];

        if ( isdefined( var_4.last_used_time ) )
        {
            var_5 = var_2 - var_4.last_used_time;

            if ( var_5 < level.cycle_data.spawn_point_last_used_duration )
                var_1++;
        }
    }

    return var_1;
}

sort_zone_score_func( var_0, var_1, var_2 )
{
    return var_0.zone_score > var_1.zone_score;
}

is_safe_spawn_location( var_0, var_1, var_2 )
{
    if ( var_1 == "elite" )
        return 1;

    foreach ( var_4 in var_2 )
    {
        if ( distancesquared( var_0.origin, var_4.origin ) > level.cycle_data.safe_spawn_distance_sq )
            continue;

        if ( has_line_of_sight( var_0.origin, var_4.origin ) )
            return 0;
    }

    return 1;
}

has_line_of_sight( var_0, var_1 )
{
    while ( max_traces_reached() )
        wait 0.05;

    level.spawn_node_traces_this_frame++;
    return bullettracepassed( var_0, var_1, 0, undefined );
}

get_current_player_volumes()
{
    if ( isdefined( level.dlc_get_current_player_volumes_override_func ) )
        return level [[ level.dlc_get_current_player_volumes_override_func ]]();

    var_0 = [];
    var_1 = [];

    foreach ( var_3 in level.cycle_data.spawn_zones )
        var_0[var_0.size] = var_3.volume;

    foreach ( var_6 in level.players )
    {
        if ( !isalive( var_6 ) || var_6.sessionstate == "spectator" )
            continue;

        var_7 = var_6 getistouchingentities( var_0 );

        foreach ( var_9 in var_7 )
        {
            var_10 = 0;

            if ( !isdefined( var_1[var_9.script_linkname] ) )
            {
                var_11 = var_9.script_linkname;
                var_1[var_11] = spawnstruct();
                var_1[var_11].players = [];
                var_1[var_11].origin = var_9.origin;
                var_1[var_11].name = var_11;
            }

            var_10 = var_1[var_9.script_linkname].players.size;
            var_1[var_9.script_linkname].players[var_10] = var_6;
        }
    }

    return var_1;
}

max_traces_reached()
{
    var_0 = 5;

    if ( gettime() > level.spawn_node_traces_frame_time )
    {
        level.spawn_node_traces_frame_time = gettime();
        level.spawn_node_traces_this_frame = 0;
    }

    return level.spawn_node_traces_this_frame >= var_0;
}

load_cycle_scalars_from_table( var_0 )
{
    var_0.cycle_scalars = [];

    if ( maps\mp\alien\_utility::is_casual_mode() )
    {
        level.cycle_health_scalar = level.casual_health_scalar;
        level.cycle_damage_scalar = level.casual_damage_scalar;
        level.cycle_reward_scalar = level.casual_reward_scalar;
        level.cycle_score_scalar = level.casual_score_scalar;
    }
    else if ( maps\mp\alien\_utility::is_hardcore_mode() )
    {
        level.cycle_health_scalar = level.hardcore_health_scalar;
        level.cycle_damage_scalar = level.hardcore_damage_scalar;
        level.cycle_reward_scalar = level.hardcore_reward_scalar;
        level.cycle_score_scalar = level.hardcore_score_scalar;
    }
    else
    {
        level.cycle_health_scalar = 1.0;
        level.cycle_damage_scalar = 1.0;
        level.cycle_reward_scalar = 1.0;
        level.cycle_score_scalar = 1.0;
    }

    for ( var_1 = 500; var_1 <= 599; var_1++ )
    {
        var_2 = tablelookup( level.alien_cycle_table, 0, var_1, 1 );

        if ( var_2 == "" )
            break;

        var_2 = int( var_2 );
        var_3 = spawnstruct();
        var_3.health = float( tablelookup( level.alien_cycle_table, 0, var_1, 2 ) );
        var_3.damage = float( tablelookup( level.alien_cycle_table, 0, var_1, 3 ) );
        var_3.reward = float( tablelookup( level.alien_cycle_table, 0, var_1, 4 ) );
        var_3.score = float( tablelookup( level.alien_cycle_table, 0, var_1, 5 ) );
        add_cycle_scalar( int( var_2 ), var_3, var_0 );
    }
}

add_cycle_scalar( var_0, var_1, var_2 )
{
    var_2.cycle_scalars[var_0] = var_1;
}

set_cycle_scalars( var_0 )
{
    if ( maps\mp\alien\_utility::is_hardcore_mode() )
    {
        level.cycle_health_scalar = level.cycle_data.cycle_scalars[var_0].health * level.hardcore_health_scalar;
        level.cycle_damage_scalar = level.cycle_data.cycle_scalars[var_0].damage * level.hardcore_damage_scalar;
        level.cycle_reward_scalar = level.cycle_data.cycle_scalars[var_0].reward * level.hardcore_reward_scalar;
        level.cycle_score_scalar = level.cycle_data.cycle_scalars[var_0].score * level.hardcore_score_scalar;
    }
    else if ( maps\mp\alien\_utility::is_casual_mode() )
    {
        level.cycle_health_scalar = level.cycle_data.cycle_scalars[var_0].health * level.casual_health_scalar;
        level.cycle_damage_scalar = level.cycle_data.cycle_scalars[var_0].damage * level.casual_damage_scalar;
        level.cycle_reward_scalar = level.cycle_data.cycle_scalars[var_0].reward * level.casual_reward_scalar;
        level.cycle_score_scalar = level.cycle_data.cycle_scalars[var_0].score * level.casual_score_scalar;
    }
    else
    {
        level.cycle_health_scalar = level.cycle_data.cycle_scalars[var_0].health;
        level.cycle_damage_scalar = level.cycle_data.cycle_scalars[var_0].damage;
        level.cycle_reward_scalar = level.cycle_data.cycle_scalars[var_0].reward;
        level.cycle_score_scalar = level.cycle_data.cycle_scalars[var_0].score;
    }
}

init_spawn_node_info( var_0 )
{
    var_0.spawn_node_info = [];
    init_spawn_node_info_from_table( var_0 );
}

init_spawn_node_info_from_table( var_0 )
{
    if ( !isdefined( level.spawn_node_info_table ) )
        level.spawn_node_info_table = "mp/alien/spawn_node_info.csv";

    for ( var_1 = 1; var_1 <= 100; var_1++ )
    {
        var_2 = tablelookup( level.spawn_node_info_table, 0, var_1, 1 );

        if ( var_2 == "" )
            break;

        var_3 = spawnstruct();
        var_3.validtype = tablelookup( level.spawn_node_info_table, 0, var_1, 2 );
        var_3.scriptablestatus = getscriptablestatus( var_1 );
        var_4 = [];
        var_4["goon"] = grabvignetteinfo( var_2, var_1, 4, 5, 6, 7, 8, 9, 10 );
        var_4["brute"] = grabvignetteinfo( var_2, var_1, 11, 12, 13, 14, 15, 16, 17 );
        var_4["spitter"] = grabvignetteinfo( var_2, var_1, 18, 19, 20, 21, 22, 23, 24 );
        var_4["seeder"] = grabvignetteinfo( var_2, var_1, 18, 19, 20, 21, 22, 23, 24 );
        var_4["elite"] = grabvignetteinfo( var_2, var_1, 25, 26, 27, 28, 29, 30, 31 );
        var_4["minion"] = grabvignetteinfo( var_2, var_1, 32, 33, 34, 35, 36, 37, 38 );
        var_3.vignetteinfo = var_4;
        var_0.spawn_node_info[var_2] = var_3;
    }
}

grabvignetteinfo( var_0, var_1, var_2, var_3, var_4, var_5, var_6, var_7, var_8 )
{
    var_9 = ";";
    var_10 = replaceemptystringwithnone( tablelookup( level.spawn_node_info_table, 0, var_1, var_2 ) );
    var_11 = replaceemptystringwithnone( tablelookup( level.spawn_node_info_table, 0, var_1, var_3 ) );
    var_12 = replaceemptystringwithnone( tablelookup( level.spawn_node_info_table, 0, var_1, var_4 ) );
    var_13 = replaceemptystringwithnone( tablelookup( level.spawn_node_info_table, 0, var_1, var_5 ) );
    var_6 = replaceemptystringwithnone( tablelookup( level.spawn_node_info_table, 0, var_1, var_6 ) );
    var_7 = replaceemptystringwithnone( tablelookup( level.spawn_node_info_table, 0, var_1, var_7 ) );
    var_8 = replaceemptystringwithnone( tablelookup( level.spawn_node_info_table, 0, var_1, var_8 ) );
    return var_10 + var_9 + var_11 + var_9 + var_12 + var_9 + var_13 + var_9 + var_6 + var_9 + var_7 + var_9 + var_8 + var_9 + var_0;
}

getscriptablestatus( var_0 )
{
    var_1 = tablelookup( level.spawn_node_info_table, 0, var_0, 3 );

    if ( maps\mp\agents\alien\_alien_agents::is_empty_string( var_1 ) )
        return "always_on";
    else
        return "one_off";
}

replaceemptystringwithnone( var_0 )
{
    if ( maps\mp\agents\alien\_alien_agents::is_empty_string( var_0 ) )
        return "NONE";

    return var_0;
}

load_cycle_drill_layer_from_table( var_0 )
{
    var_0.cycle_drill_layers = [];
    var_0.cycle_delay_times = [];

    for ( var_1 = 600; var_1 <= 699; var_1++ )
    {
        var_2 = tablelookup( level.alien_cycle_table, 0, var_1, 1 );

        if ( var_2 == "" )
            break;

        var_3 = tablelookup( level.alien_cycle_table, 0, var_1, 2 );
        var_3 = strtok( var_3, " " );

        for ( var_4 = 0; var_4 < var_3.size; var_4++ )
            var_3[var_4] = int( var_3[var_4] );

        var_0.cycle_drill_layers[int( var_2 )] = var_3;
        var_5 = tablelookup( level.alien_cycle_table, 0, var_1, 3 );
        var_0.cycle_delay_times[int( var_2 )] = float( var_5 );
    }
}

load_random_hives_from_table()
{
    var_0 = [];

    for ( var_1 = 900; var_1 <= 999; var_1++ )
    {
        var_2 = tablelookup( level.alien_cycle_table, 0, var_1, 1 );

        if ( var_2 == "" )
            break;

        var_3 = tablelookup( level.alien_cycle_table, 0, var_1, 2 );
        var_3 = strtok( var_3, " " );
        var_0 = common_scripts\utility::array_combine( var_0, get_hives_to_remove( int( var_2 ), var_3 ) );
    }

    level.removed_hives = var_0;
}

get_hives_to_remove( var_0, var_1 )
{
    var_2 = var_1.size - var_0;

    if ( var_2 == 0 )
        return [];

    var_1 = common_scripts\utility::array_randomize( var_1 );
    var_3 = [];

    for ( var_4 = 0; var_4 < var_2; var_4++ )
        var_3[var_3.size] = var_1[var_4];

    return var_3;
}
