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

remote_vehicle_setup()
{
    while ( !isdefined( level.bot_variables_initialized ) )
        wait 0.05;

    if ( isdefined( level.bot_initialized_remote_vehicles ) )
        return;

    level.bot_ks_heli_offset["heli_pilot"] = ( 0, 0, 350 );
    level.bot_ks_heli_offset["heli_sniper"] = ( 0, 0, 228 );
    level.bot_ks_funcs["isUsing"]["odin_assault"] = maps\mp\_utility::isusingremote;
    level.bot_ks_funcs["isUsing"]["odin_support"] = maps\mp\_utility::isusingremote;
    level.bot_ks_funcs["isUsing"]["heli_pilot"] = maps\mp\_utility::isusingremote;
    level.bot_ks_funcs["isUsing"]["heli_sniper"] = maps\mp\killstreaks\_killstreaks::isusinghelisniper;
    level.bot_ks_funcs["isUsing"]["switchblade_cluster"] = maps\mp\_utility::isusingremote;
    level.bot_ks_funcs["isUsing"]["vanguard"] = ::isusingvanguard;
    level.bot_ks_funcs["waittill_initial_goal"]["heli_pilot"] = ::heli_pilot_waittill_initial_goal;
    level.bot_ks_funcs["waittill_initial_goal"]["heli_sniper"] = ::heli_sniper_waittill_initial_goal;
    level.bot_ks_funcs["control_aiming"]["heli_pilot"] = ::heli_pilot_control_heli_aiming;
    level.bot_ks_funcs["control_aiming"]["heli_sniper"] = common_scripts\utility::empty_init_func;
    level.bot_ks_funcs["control_aiming"]["vanguard"] = ::vanguard_control_aiming;
    level.bot_ks_funcs["control_other"]["heli_pilot"] = ::heli_pilot_monitor_flares;
    level.bot_ks_funcs["heli_pick_node"]["heli_pilot"] = ::heli_pilot_pick_node;
    level.bot_ks_funcs["heli_pick_node"]["heli_sniper"] = ::heli_sniper_pick_node;
    level.bot_ks_funcs["heli_pick_node"]["vanguard"] = ::vanguard_pick_node;
    level.bot_ks_funcs["heli_node_get_origin"]["heli_pilot"] = ::heli_get_node_origin;
    level.bot_ks_funcs["heli_node_get_origin"]["heli_sniper"] = ::heli_get_node_origin;
    level.bot_ks_funcs["heli_node_get_origin"]["vanguard"] = ::vanguard_get_node_origin;
    level.bot_ks_funcs["odin_perform_action"]["odin_assault"] = ::odin_assault_perform_action;
    level.bot_ks_funcs["odin_perform_action"]["odin_support"] = ::odin_support_perform_action;
    level.bot_ks_funcs["odin_get_target"]["odin_assault"] = ::odin_assault_get_target;
    level.bot_ks_funcs["odin_get_target"]["odin_support"] = ::odin_support_get_target;
    var_0 = common_scripts\utility::getstructarray( "so_chopper_boss_path_struct", "script_noteworthy" );
    level.bot_heli_nodes = [];

    foreach ( var_2 in var_0 )
    {
        if ( isdefined( var_2.script_linkname ) )
            level.bot_heli_nodes = common_scripts\utility::array_add( level.bot_heli_nodes, var_2 );
    }

    level.bot_heli_pilot_traceoffset = maps\mp\_utility::gethelipilottraceoffset();

    foreach ( var_5 in level.bot_heli_nodes )
    {
        var_5.vanguard_origin = var_5.origin;
        var_6 = var_5.origin + ( 0, 0, 50 );

        for ( var_5.valid_for_vanguard = 1; !origin_is_valid_for_vanguard( var_6 ) && var_6[2] > var_5.origin[2] - 1000; var_6 = var_6 - ( 0, 0, 25 ) )
        {

        }

        if ( var_6[2] <= var_5.origin[2] - 1000 )
            var_5.valid_for_vanguard = 0;

        var_6 = var_6 - ( 0, 0, 50 );
        var_5.vanguard_origin = var_6;
    }

    var_8 = -99999999;

    foreach ( var_5 in level.bot_heli_nodes )
        var_8 = max( var_8, var_5.origin[2] );

    level.bot_vanguard_height_trace_size = var_8 - level.bot_map_min_z + 100;
    level.odin_large_rod_radius = getweaponexplosionradius( "odin_projectile_large_rod_mp" );
    level.odin_small_rod_radius = getweaponexplosionradius( "odin_projectile_small_rod_mp" );
    level.vanguard_missile_radius = getweaponexplosionradius( "remote_tank_projectile_mp" );
    level.heli_pilot_missile_radius = getdvarfloat( "bg_bulletExplRadius" );

    while ( !isdefined( level.odin_marking_flash_radius_max ) || !isdefined( level.odin_marking_flash_radius_min ) )
        wait 0.05;

    level.odin_flash_radius = ( level.odin_marking_flash_radius_max + level.odin_marking_flash_radius_min ) / 2;
    level.outside_zones = [];

    if ( isdefined( level.teleportgetactivepathnodezonesfunc ) )
        var_11 = [[ level.teleportgetactivepathnodezonesfunc ]]();
    else
    {
        var_11 = [];

        for ( var_12 = 0; var_12 < level.zonecount; var_12++ )
            var_11[var_11.size] = var_12;
    }

    foreach ( var_14 in var_11 )
    {
        if ( botzonegetindoorpercent( var_14 ) < 0.25 )
            level.outside_zones = common_scripts\utility::array_add( level.outside_zones, var_14 );
    }

    level.bot_odin_time_to_move["recruit"] = 1.0;
    level.bot_odin_time_to_move["regular"] = 0.7;
    level.bot_odin_time_to_move["hardened"] = 0.4;
    level.bot_odin_time_to_move["veteran"] = 0.05;
    level.bot_initialized_remote_vehicles = 1;
}

bot_killstreak_remote_control( var_0, var_1, var_2, var_3, var_4 )
{
    if ( !isdefined( var_3 ) )
        return 0;

    var_5 = 1;
    var_6 = 1;
    var_7 = undefined;

    if ( isdefined( self.node_ambushing_from ) )
    {
        var_8 = self botgetscriptgoalradius();
        var_9 = distancesquared( self.origin, self.node_ambushing_from.origin );

        if ( var_9 < squared( var_8 ) )
        {
            var_5 = 0;
            var_6 = 0;
        }
        else if ( var_9 < squared( 200 ) )
            var_5 = 0;
    }

    var_10 = var_0.streakname == "vanguard" && is_indoor_map();

    if ( var_10 || var_5 )
    {
        var_11 = getnodesinradius( self.origin, 500, 0, 512 );

        if ( isdefined( var_11 ) && var_11.size > 0 )
        {
            if ( isdefined( var_4 ) && var_4 )
            {
                var_12 = var_11;
                var_11 = [];

                foreach ( var_14 in var_12 )
                {
                    if ( nodeexposedtosky( var_14 ) )
                    {
                        var_15 = getlinkednodes( var_14 );
                        var_16 = 0;

                        foreach ( var_18 in var_15 )
                        {
                            if ( nodeexposedtosky( var_18 ) )
                                var_16++;
                        }

                        if ( var_16 / var_15.size > 0.5 )
                            var_11 = common_scripts\utility::array_add( var_11, var_14 );
                    }
                }
            }

            if ( var_10 )
            {
                var_21 = self botnodescoremultiple( var_11, "node_exposed" );

                foreach ( var_14 in var_21 )
                {
                    if ( bullettracepassed( var_14.origin + ( 0, 0, 30 ), var_14.origin + ( 0, 0, 400 ), 0, self ) )
                    {
                        var_7 = var_14;
                        break;
                    }

                    wait 0.05;
                }
            }
            else if ( var_11.size > 0 )
                var_7 = self botnodepick( var_11, min( 3, var_11.size ), "node_hide" );

            if ( !isdefined( var_7 ) )
                return 0;

            self botsetscriptgoalnode( var_7, "tactical" );
        }
    }

    if ( var_6 )
    {
        var_24 = maps\mp\bots\_bots_util::bot_waittill_goal_or_fail();

        if ( var_24 != "goal" )
        {
            try_clear_hide_goal( var_7 );
            return 1;
        }
    }

    if ( isdefined( var_2 ) && !self [[ var_2 ]]() )
    {
        try_clear_hide_goal( var_7 );
        return 0;
    }

    if ( !maps\mp\bots\_bots_util::bot_allowed_to_use_killstreaks() )
    {
        try_clear_hide_goal( var_7 );
        return 1;
    }

    if ( !isdefined( var_7 ) )
    {
        if ( self getstance() == "prone" )
            self botsetstance( "prone" );
        else if ( self getstance() == "crouch" )
            self botsetstance( "crouch" );
    }
    else if ( self botgetdifficultysetting( "strategyLevel" ) > 0 )
    {
        if ( randomint( 100 ) > 50 )
            self botsetstance( "prone" );
        else
            self botsetstance( "crouch" );
    }

    maps\mp\bots\_bots_ks::bot_switch_to_killstreak_weapon( var_0, var_1, var_0.weapon );
    self.vehicle_controlling = undefined;
    self thread [[ var_3 ]]();
    thread bot_end_control_on_respawn();
    thread bot_end_control_watcher( var_7 );
    self waittill( "control_func_done" );
    return 1;
}

bot_end_control_on_respawn()
{
    self endon( "disconnect" );
    self endon( "control_func_done" );
    level endon( "game_ended" );
    self waittill( "spawned_player" );
    self notify( "control_func_done" );
}

bot_end_control_watcher( var_0 )
{
    self endon( "disconnect" );
    self waittill( "control_func_done" );
    try_clear_hide_goal( var_0 );
    self botsetstance( "none" );
    self botsetscriptmove( 0, 0 );
    self botsetflag( "disable_movement", 0 );
    self botsetflag( "disable_rotation", 0 );
    self.vehicle_controlling = undefined;
}

try_clear_hide_goal( var_0 )
{
    if ( isdefined( var_0 ) && self bothasscriptgoal() && isdefined( self botgetscriptgoalnode() ) && self botgetscriptgoalnode() == var_0 )
        self botclearscriptgoal();
}

bot_end_control_on_vehicle_death( var_0 )
{
    var_0 waittill( "death" );
    self notify( "control_func_done" );
}

bot_waittill_using_vehicle( var_0 )
{
    var_1 = gettime();

    while ( !self [[ level.bot_ks_funcs["isUsing"][var_0] ]]() )
    {
        wait 0.05;

        if ( gettime() - var_1 > 5000 )
            return 0;
    }

    return 1;
}

bot_control_switchblade_cluster()
{
    self endon( "spawned_player" );
    self endon( "disconnect" );
    self endon( "control_func_done" );
    level endon( "game_ended" );
    childthread handle_disable_rotation();
    var_0 = bot_waittill_using_vehicle( "switchblade_cluster" );

    if ( !var_0 )
        self notify( "control_func_done" );

    thread switchblade_handle_awareness();
    var_1 = find_cluster_rocket_for_bot( self );
    wait 0.1;
    self.oldmaxsightdistsqrd = self.maxsightdistsqrd;
    self.maxsightdistsqrd = 256000000;
    thread watch_end_switchblade();
    var_2 = undefined;
    var_3 = 0;
    var_4 = 0;
    var_5 = [];
    var_6 = undefined;
    var_7 = 0;
    var_8 = 0;
    var_9 = undefined;
    var_10 = undefined;
    var_11 = 0;
    var_12 = is_indoor_map();

    while ( self [[ level.bot_ks_funcs["isUsing"]["switchblade_cluster"] ]]() && isdefined( var_1 ) )
    {
        foreach ( var_14 in level.rockets )
        {
            if ( isdefined( var_14 ) && var_14.owner == self && var_14.weapon_name == "switch_blade_child_mp" )
            {
                var_15 = 1;

                foreach ( var_17 in var_5 )
                {
                    if ( var_17.rocket == var_14 )
                        var_15 = 0;
                }

                if ( var_15 )
                {
                    var_19 = spawnstruct();
                    var_19.rocket = var_14;
                    var_19.target = var_6;
                    var_6 = undefined;
                    var_5 = common_scripts\utility::array_add( var_5, var_19 );
                }
            }
        }

        for ( var_21 = 0; var_21 < var_5.size; var_21++ )
        {
            var_17 = var_5[var_21];

            if ( isdefined( var_17 ) && isdefined( var_17.rocket ) && !common_scripts\utility::array_contains( level.rockets, var_17.rocket ) )
            {
                var_5[var_21] = var_5[var_5.size - 1];
                var_5[var_5.size - 1] = undefined;
                var_21--;
            }
        }

        if ( var_11 )
        {
            wait 0.05;
            continue;
        }

        var_22 = undefined;

        if ( isdefined( var_10 ) )
        {
            var_22 = var_10;

            if ( !isalive( var_10 ) || !self botcanseeentity( var_22 ) )
            {
                if ( !isalive( var_10 ) )
                    var_11 = 1;

                wait 0.05;
                continue;
            }
        }

        var_23 = [];

        if ( !isdefined( var_22 ) )
        {
            var_24 = bot_killstreak_get_all_outside_enemies( 0 );
            var_25 = [];

            foreach ( var_17 in var_5 )
            {
                if ( isdefined( var_17.target ) )
                    var_25 = common_scripts\utility::array_add( var_25, var_17.target );
            }

            var_24 = common_scripts\utility::array_remove_array( var_24, var_25 );

            foreach ( var_29 in var_24 )
            {
                if ( var_29 maps\mp\_utility::_hasperk( "specialty_noplayertarget" ) )
                    continue;

                if ( self botcanseeentity( var_29 ) || var_12 && common_scripts\utility::within_fov( self geteye(), var_1.angles, var_29.origin, self botgetfovdot() ) )
                {
                    if ( !bot_body_is_dead() && distancesquared( var_29.origin, self.origin ) < 40000 )
                        continue;

                    var_23 = common_scripts\utility::array_add( var_23, var_29 );

                    if ( !isdefined( var_22 ) )
                    {
                        var_22 = var_29;
                        continue;
                    }

                    var_30 = vectornormalize( var_22.origin - var_1.origin );
                    var_31 = vectornormalize( var_29.origin - var_1.origin );
                    var_32 = anglestoforward( var_1.angles );
                    var_33 = vectordot( var_30, var_32 );
                    var_34 = vectordot( var_31, var_32 );

                    if ( var_34 > var_33 )
                        var_22 = var_29;
                }
            }
        }

        if ( isdefined( var_22 ) )
        {
            var_2 = undefined;
            var_36 = var_1.origin[2] - var_22.origin[2];
            var_37 = self botgetdifficulty();

            if ( var_37 == "recruit" )
                var_9 = var_22.origin;
            else if ( var_36 < 5000 )
                var_9 = var_22.origin;
            else if ( length( var_22 getentityvelocity() ) < 25 )
                var_9 = var_22.origin;
            else if ( gettime() - var_8 > 500 )
            {
                var_8 = gettime();
                var_38 = 3.0;

                if ( var_37 == "regular" )
                    var_38 = 1.0;

                var_9 = getpredictedentityposition( var_22, var_38 );
            }

            var_39 = missile_get_desired_angles_to_target( var_1, var_9 );
            var_40 = missile_get_distance_to_target( var_1, var_9 );

            if ( var_40 < 30 )
                var_41 = 0.0;
            else if ( var_40 < 100 )
                var_41 = 0.15;
            else if ( var_40 < 200 )
                var_41 = 0.3;
            else if ( var_40 < 400 )
                var_41 = 0.6;
            else
                var_41 = 1.0;

            if ( var_7 )
                var_41 = min( var_41 * 3, 1.0 );

            if ( var_41 > 0 )
                self botsetscriptmove( var_39[1], 0.05, var_41, 1, 1 );
            else if ( gettime() > var_4 )
            {
                if ( var_3 < 2 )
                {
                    self botpressbutton( "attack" );
                    var_3++;
                    var_4 = gettime() + 200;

                    if ( var_37 == "regular" && var_3 == 2 || var_37 == "hardened" || var_37 == "veteran" )
                    {
                        var_42 = var_3 == 1 && var_23.size == 1;

                        if ( !var_42 )
                        {
                            var_6 = var_22;
                            var_4 = var_4 + 800;
                        }
                    }
                }
                else if ( !var_7 && ( var_36 < 5000 || var_37 == "recruit" ) )
                {
                    var_7 = 1;
                    self botpressbutton( "attack" );

                    if ( var_37 == "recruit" )
                        var_10 = var_22;
                }
            }
        }
        else
        {
            if ( !isdefined( var_2 ) )
                var_2 = common_scripts\utility::random( level.outside_zones );

            var_43 = getzonenodeforindex( var_2 ).origin;

            if ( missile_get_distance_to_target( var_1, var_43 ) < 200 )
            {
                var_2 = common_scripts\utility::random( level.outside_zones );
                var_43 = getzonenodeforindex( var_2 ).origin;
            }

            var_39 = missile_get_desired_angles_to_target( var_1, var_43 );
            self botsetscriptmove( var_39[1], 0.05, 0.75, 1, 1 );
        }

        wait 0.05;
    }

    self notify( "control_func_done" );
}

missile_get_desired_angles_to_target( var_0, var_1 )
{
    var_2 = missile_find_ground_target( var_0, var_1[2] );
    var_3 = vectornormalize( var_1 - var_2 );
    return vectortoangles( var_3 );
}

missile_get_distance_to_target( var_0, var_1 )
{
    var_2 = missile_find_ground_target( var_0, var_1[2] );
    return distance( var_2, var_1 );
}

handle_disable_rotation()
{
    self botsetflag( "disable_rotation", 1 );
    self botsetflag( "disable_movement", 1 );
    find_cluster_rocket_for_bot( self );
    self botsetflag( "disable_rotation", 0 );
    self botsetflag( "disable_movement", 0 );
}

switchblade_handle_awareness()
{
    self endon( "disconnect" );
    self botsetawareness( 2.5 );
    self waittill( "control_func_done" );
    self botsetawareness( 1.0 );
}

missile_find_ground_target( var_0, var_1 )
{
    var_2 = anglestoforward( var_0.angles );
    var_3 = ( var_1 - var_0.origin[2] ) / var_2[2];
    var_4 = var_0.origin + var_2 * var_3;
    return var_4;
}

watch_end_switchblade()
{
    self endon( "disconnect" );
    self waittill( "control_func_done" );
    self.maxsightdistsqrd = self.oldmaxsightdistsqrd;
}

find_cluster_rocket_for_bot( var_0 )
{
    for (;;)
    {
        foreach ( var_2 in level.rockets )
        {
            if ( isdefined( var_2 ) && var_2.owner == var_0 )
                return var_2;
        }

        wait 0.05;
    }
}

vanguard_allowed()
{
    if ( !maps\mp\bots\_bots_ks::aerial_vehicle_allowed() )
        return 0;

    if ( maps\mp\killstreaks\_vanguard::exceededmaxvanguards( self.team ) || level.littlebirds.size >= 4 )
        return 0;

    if ( maps\mp\bots\_bots_ks::iskillstreakblockedforbots( "vanguard" ) )
        return 0;

    return 1;
}

bot_killstreak_vanguard_start( var_0, var_1, var_2, var_3 )
{
    bot_killstreak_remote_control( var_0, var_1, var_2, var_3, 1 );
}

isusingvanguard()
{
    return maps\mp\_utility::isusingremote() && self.usingremote == "vanguard" && isdefined( self.remoteuav );
}

bot_control_vanguard()
{
    self endon( "spawned_player" );
    self endon( "disconnect" );
    self endon( "control_func_done" );
    level endon( "game_ended" );
    var_0 = bot_waittill_using_vehicle( "vanguard" );

    if ( !var_0 )
        self notify( "control_func_done" );

    self.vehicle_controlling = self.remoteuav;
    childthread bot_end_control_on_vehicle_death( self.vehicle_controlling );
    self.vehicle_controlling endon( "death" );
    wait 0.5;
    var_1 = 0;
    var_2 = !self.vehicle_controlling vanguard_is_outside();
    var_3 = undefined;
    var_4 = 0;
    var_5 = is_indoor_map();

    while ( var_2 && !var_5 )
    {
        var_6 = getnodesinradiussorted( self.vehicle_controlling.origin, 1024, 64, 512, "path" );

        if ( isdefined( var_3 ) )
            var_6 = common_scripts\utility::array_remove( var_6, var_3 );

        foreach ( var_8 in var_6 )
        {
            if ( node_is_valid_outside_for_vanguard( var_8 ) )
            {
                var_3 = var_8;
                break;
            }

            wait 0.05;
            var_1 = var_1 + 0.05;
        }

        if ( var_1 < 1.0 )
            wait( 1.0 - var_1 );

        if ( !isdefined( var_3 ) )
        {
            self botpressbutton( "use", 4.0 );
            wait 4.0;
        }

        var_10 = maps\mp\bots\_bots_util::bot_queued_process( "GetNodesOnPathVanguard", maps\mp\bots\_bots_util::func_get_nodes_on_path, self.vehicle_controlling.origin, var_3.origin );

        if ( !isdefined( var_10 ) )
        {
            if ( var_4 == 0 )
            {
                var_4++;
                wait 0.05;
                continue;
            }
            else
            {
                self botpressbutton( "use", 4.0 );
                wait 4.0;
            }
        }

        for ( var_11 = 0; var_11 < var_10.size; var_11++ )
        {
            var_12 = var_10[var_11];

            if ( var_11 == 0 && distancesquared( self.origin, var_12.origin ) < 1600 )
                continue;

            var_13 = 32;

            if ( var_11 == var_10.size - 1 )
                var_13 = 16;

            var_14 = self.vehicle_controlling.origin;
            var_15 = gettime() + 2500;

            while ( distance2dsquared( var_12.origin, self.vehicle_controlling.origin ) > var_13 * var_13 )
            {
                if ( self.vehicle_controlling vanguard_is_outside() )
                {
                    var_11 = var_10.size;
                    break;
                }

                if ( gettime() > var_15 )
                {
                    var_15 = gettime() + 2500;
                    var_16 = distancesquared( self.vehicle_controlling.origin, var_14 );

                    if ( var_16 < 1.0 )
                    {
                        var_11++;
                        break;
                    }

                    var_14 = self.vehicle_controlling.origin;
                }

                var_17 = vectornormalize( var_12.origin - self.vehicle_controlling.origin );
                self botsetscriptmove( vectortoangles( var_17 )[1], 0.2 );
                self botlookatpoint( var_12.origin, 0.2, "script_forced" );
                var_18 = var_12.origin[2] + 64;
                var_19 = var_18 - self.vehicle_controlling.origin[2];

                if ( var_19 > 10 )
                    self botpressbutton( "lethal" );
                else if ( var_19 < -10 )
                    self botpressbutton( "tactical" );

                wait 0.05;
            }
        }

        var_2 = 0;

        if ( !self.vehicle_controlling vanguard_is_outside() )
            var_2 = 1;
    }

    self botsetscriptmove( 0, 0 );
    self botlookatpoint( undefined );
    self childthread [[ level.bot_ks_funcs["control_aiming"]["vanguard"] ]]();
    var_21 = self.vehicle_controlling.origin[2];
    var_22 = undefined;
    var_23 = gettime() + 2000;
    var_24 = [];
    var_24[0] = ( 1, 0, 0 );
    var_24[1] = ( -1, 0, 0 );
    var_24[2] = ( 0, 1, 0 );
    var_24[3] = ( 0, -1, 0 );
    var_24[4] = ( 1, 1, 0 );
    var_24[5] = ( 1, -1, 0 );
    var_24[6] = ( -1, 1, 0 );
    var_24[7] = ( -1, -1, 0 );
    var_25 = find_closest_heli_node_2d( self.vehicle_controlling.origin, "vanguard" );

    while ( var_25.vanguard_origin[2] - self.vehicle_controlling.origin[2] > 20 )
    {
        if ( !self.vehicle_controlling maps\mp\killstreaks\_vanguard::vanguard_in_range() )
            break;

        if ( gettime() > var_23 )
        {
            var_23 = gettime() + 2000;

            if ( isdefined( var_22 ) )
                var_22 = undefined;
            else
            {
                var_19 = self.vehicle_controlling.origin[2] - var_21;

                if ( var_19 < 20 && !var_5 )
                {
                    var_26 = common_scripts\utility::array_randomize( var_24 );

                    foreach ( var_28 in var_26 )
                    {
                        if ( pos_passes_sky_trace( self.vehicle_controlling.origin + var_28 * 64 ) )
                        {
                            if ( !bullettracepassed( self.vehicle_controlling.origin, self.vehicle_controlling.origin + var_28 * 64, 0, self.vehicle_controlling ) )
                            {
                                wait 0.05;
                                continue;
                            }

                            var_22 = var_28;
                            break;
                        }

                        wait 0.05;
                    }
                }
            }

            var_21 = self.vehicle_controlling.origin[2];
        }

        if ( isdefined( var_22 ) )
        {
            self botsetscriptmove( vectortoangles( var_22 )[1], 0.05 );

            if ( common_scripts\utility::cointoss() )
                self botpressbutton( "tactical" );
        }
        else
            self botpressbutton( "lethal" );

        wait 0.05;
    }

    wait 1.0;

    while ( !self.vehicle_controlling maps\mp\killstreaks\_vanguard::vanguard_in_range() )
    {
        self botpressbutton( "tactical" );
        wait 0.1;
    }

    wait 1.0;
    self botsetflag( "disable_movement", 0 );
    bot_control_heli_main_move_loop( "vanguard", 0 );
    self notify( "control_func_done" );
}

pos_is_valid_outside_for_vanguard( var_0 )
{
    var_1 = getclosestnodeinsight( var_0 );

    if ( isdefined( var_1 ) )
        return node_is_valid_outside_for_vanguard( var_1 );

    return 0;
}

node_is_valid_outside_for_vanguard( var_0 )
{
    if ( nodeexposedtosky( var_0 ) )
        return pos_passes_sky_trace( var_0.origin );

    return 0;
}

pos_passes_sky_trace( var_0 )
{
    var_1 = var_0;

    for ( var_2 = var_0 + ( 0, 0, level.bot_vanguard_height_trace_size ); !origin_is_valid_for_vanguard( var_2 ) && var_2[2] > var_1[2]; var_2 = var_2 - ( 0, 0, 50 ) )
    {

    }

    if ( var_2[2] <= var_1[2] )
        return 0;

    var_3 = bullettracepassed( var_1, var_2, 0, undefined );
    return var_3;
}

vanguard_is_outside()
{
    var_0 = getclosestnodeinsight( self.origin );

    if ( isdefined( var_0 ) && !nodeexposedtosky( var_0 ) )
        return 0;

    wait 0.05;

    if ( !pos_passes_sky_trace( self.origin + ( 18, 0, 25 ) ) )
        return 0;

    wait 0.05;

    if ( !pos_passes_sky_trace( self.origin + ( -18, 0, 25 ) ) )
        return 0;

    wait 0.05;

    if ( !pos_passes_sky_trace( self.origin + ( 0, 18, 25 ) ) )
        return 0;

    wait 0.05;

    if ( !pos_passes_sky_trace( self.origin + ( 0, -18, 25 ) ) )
        return 0;

    return 1;
}

vanguard_control_aiming()
{
    self notify( "vanguard_control_aiming" );
    self endon( "vanguard_control_aiming" );
    var_0 = undefined;
    var_1 = 0;
    var_2 = gettime();
    var_3 = 0;
    var_4 = undefined;
    var_5 = 0;

    while ( self [[ level.bot_ks_funcs["isUsing"]["vanguard"] ]]() )
    {
        var_6 = undefined;
        var_7 = self geteye();
        var_8 = self getplayerangles();
        var_9 = self botgetfovdot();

        if ( isalive( self.enemy ) && self botcanseeentity( self.enemy ) )
        {
            var_10 = 1;
            var_6 = self.enemy;
            var_5 = 0;
        }
        else if ( var_5 < 10.0 )
        {
            foreach ( var_12 in level.characters )
            {
                if ( var_12 == self || !isalive( var_12 ) )
                    continue;

                if ( var_12 maps\mp\_utility::_hasperk( "specialty_noplayertarget" ) )
                    continue;

                if ( !isdefined( var_12.team ) )
                    continue;

                if ( !level.teambased || self.team != var_12.team )
                {
                    if ( common_scripts\utility::within_fov( var_7, var_8, var_12.origin, var_9 ) )
                    {
                        var_5 = var_5 + 0.05;

                        if ( isdefined( var_6 ) )
                        {
                            var_13 = distancesquared( self.vehicle_controlling.origin, var_6.origin );
                            var_14 = distancesquared( self.vehicle_controlling.origin, var_12.origin );

                            if ( var_14 < var_13 )
                                var_6 = var_12;

                            continue;
                        }

                        var_6 = var_12;
                    }
                }
            }
        }

        if ( isdefined( var_6 ) )
        {
            if ( ( isai( var_6 ) || isplayer( var_6 ) ) && length( var_6 getentityvelocity() ) < 25 )
                var_0 = var_6.origin;
            else if ( gettime() - var_3 < 500 )
            {
                if ( var_4 != var_6 )
                    var_0 = var_6.origin;
            }
            else if ( gettime() - var_3 > 500 )
            {
                var_3 = gettime();
                var_0 = getpredictedentityposition( var_6, 3.0 );
                var_4 = var_6;
            }

            var_16 = 165;

            if ( gettime() - var_2 > 10000 )
                var_16 = 200;

            if ( distancesquared( self.vehicle_controlling.attackarrow.origin, var_0 ) < level.vanguard_missile_radius * level.vanguard_missile_radius )
            {
                if ( bot_body_is_dead() || distancesquared( self.vehicle_controlling.attackarrow.origin, self.origin ) > level.vanguard_missile_radius * level.vanguard_missile_radius )
                {
                    var_2 = gettime();
                    self botpressbutton( "attack" );
                }
            }
        }
        else if ( gettime() > var_1 )
        {
            var_1 = gettime() + randomintrange( 1000, 2000 );
            var_0 = get_random_outside_target();
            self.next_goal_time = gettime();
        }

        if ( length( var_0 ) == 0 )
            var_0 = ( 0, 0, 10 );

        self botlookatpoint( var_0, 0.2, "script_forced" );
        wait 0.05;
    }
}

vanguard_pick_node( var_0 )
{
    var_0.bot_visited_times[self.entity_number]++;
    var_1 = [[ level.bot_ks_funcs["heli_node_get_origin"]["vanguard"] ]]( var_0 );
    var_2 = bot_vanguard_find_unvisited_nodes( var_0 );
    var_3 = var_2;
    var_2 = [];

    foreach ( var_5 in var_3 )
    {
        if ( var_5.valid_for_vanguard )
        {
            if ( var_0.origin[2] != var_0.vanguard_origin[2] || var_5.origin[2] != var_5.vanguard_origin[2] )
            {
                var_6 = [[ level.bot_ks_funcs["heli_node_get_origin"]["vanguard"] ]]( var_5 );
                var_7 = playerphysicstrace( var_1, var_6 );

                if ( distancesquared( var_7, var_6 ) < 1 )
                    var_2 = common_scripts\utility::array_add( var_2, var_5 );

                wait 0.05;
                continue;
            }

            var_2 = common_scripts\utility::array_add( var_2, var_5 );
        }
    }

    if ( var_2.size == 0 && var_3.size > 0 )
    {
        foreach ( var_5 in var_3 )
            var_5.bot_visited_times[self.entity_number]++;
    }

    return heli_pick_node_furthest_from_center( var_2, "vanguard" );
}

bot_vanguard_find_unvisited_nodes( var_0 )
{
    var_1 = 99;
    var_2 = [];

    foreach ( var_4 in var_0.neighbors )
    {
        if ( isdefined( var_4.script_linkname ) && var_4.valid_for_vanguard )
        {
            var_5 = var_4.bot_visited_times[self.entity_number];

            if ( var_5 < var_1 )
            {
                var_2 = [];
                var_2[0] = var_4;
                var_1 = var_5;
            }
            else if ( var_5 == var_1 )
                var_2[var_2.size] = var_4;
        }
    }

    return var_2;
}

vanguard_get_node_origin( var_0 )
{
    return var_0.vanguard_origin;
}

origin_is_valid_for_vanguard( var_0 )
{
    var_1 = common_scripts\utility::spawn_tag_origin();
    var_1.origin = var_0;
    var_2 = var_1 maps\mp\killstreaks\_vanguard::vanguard_in_range();
    var_1 delete();
    return var_2;
}

heli_sniper_allowed()
{
    if ( !maps\mp\bots\_bots_ks::aerial_vehicle_allowed() )
        return 0;

    if ( maps\mp\killstreaks\_helisniper::exceededmaxhelisnipers() )
        return 0;

    return 1;
}

heli_sniper_waittill_initial_goal()
{
    self.vehicle_controlling waittill( "near_goal" );
}

bot_control_heli_sniper()
{
    thread heli_sniper_clear_script_goal_on_ride();
    bot_control_heli( "heli_sniper" );
}

heli_sniper_clear_script_goal_on_ride()
{
    self endon( "spawned_player" );
    self endon( "disconnect" );
    self endon( "control_func_done" );
    level endon( "game_ended" );

    while ( !( maps\mp\killstreaks\_killstreaks::isusinghelisniper() && self islinked() ) )
        wait 0.05;

    self botclearscriptgoal();
}

heli_sniper_pick_node( var_0 )
{
    var_0.bot_visited_times[self.entity_number]++;
    var_1 = bot_heli_find_unvisited_nodes( var_0 );
    return heli_pick_node_furthest_from_center( var_1, "heli_sniper" );
}

heli_pilot_allowed()
{
    if ( !maps\mp\bots\_bots_ks::aerial_vehicle_allowed() )
        return 0;

    if ( maps\mp\killstreaks\_helicopter_pilot::exceededmaxhelipilots( self.team ) )
        return 0;

    return 1;
}

heli_pilot_waittill_initial_goal()
{
    self.vehicle_controlling waittill( "goal_reached" );
}

bot_control_heli_pilot()
{
    bot_control_heli( "heli_pilot" );
}

heli_pilot_pick_node( var_0 )
{
    var_0.bot_visited_times[self.entity_number]++;
    var_1 = bot_heli_find_unvisited_nodes( var_0 );
    var_2 = common_scripts\utility::random( var_1 );
    return var_2;
}

heli_pilot_monitor_flares()
{
    self notify( "heli_pilot_monitor_flares" );
    self endon( "heli_pilot_monitor_flares" );
    var_0 = [];

    while ( self [[ level.bot_ks_funcs["isUsing"]["heli_pilot"] ]]() )
    {
        self.vehicle_controlling waittill( "targeted_by_incoming_missile", var_1 );

        if ( !maps\mp\killstreaks\_flares::flares_areavailable( self.vehicle_controlling ) )
            break;

        var_2 = 1;

        foreach ( var_4 in var_1 )
        {
            if ( isdefined( var_4 ) && !common_scripts\utility::array_contains( var_0, var_4 ) )
                var_2 = 0;
        }

        if ( !var_2 )
        {
            var_6 = clamp( 0.34 * self botgetdifficultysetting( "strategyLevel" ), 0.0, 1.0 );

            if ( randomfloat( 1.0 ) < var_6 )
                self notify( "manual_flare_popped" );

            var_0 = common_scripts\utility::array_combine( var_0, var_1 );
            var_0 = common_scripts\utility::array_removeundefined( var_0 );
            wait 3.0;
        }
    }
}

heli_pilot_control_heli_aiming()
{
    self notify( "heli_pilot_control_heli_aiming" );
    self endon( "heli_pilot_control_heli_aiming" );
    var_0 = undefined;
    var_1 = undefined;
    var_2 = undefined;
    var_3 = 0;
    var_4 = 0;
    var_5 = undefined;
    var_6 = ( self botgetdifficultysetting( "minInaccuracy" ) + self botgetdifficultysetting( "maxInaccuracy" ) ) / 2;
    var_7 = 0;

    while ( self [[ level.bot_ks_funcs["isUsing"]["heli_pilot"] ]]() )
    {
        var_8 = 0;
        var_9 = 0;

        if ( isdefined( var_1 ) && var_1.health <= 0 && gettime() - var_1.deathtime < 2000 )
        {
            var_8 = 1;
            var_9 = 1;
        }
        else if ( isalive( self.enemy ) && ( self botcanseeentity( self.enemy ) || gettime() - self lastknowntime( self.enemy ) <= 300 ) )
        {
            var_8 = 1;
            var_1 = self.enemy;
            var_0 = self.enemy.origin;

            if ( self botcanseeentity( self.enemy ) )
            {
                var_7 = 0;
                var_9 = 1;
                var_10 = gettime();
            }
            else
            {
                var_7 = var_7 + 0.05;

                if ( var_7 > 5.0 )
                    var_8 = 0;
            }
        }

        if ( var_8 )
        {
            var_2 = var_0 - ( 0, 0, 50 );

            if ( var_9 && ( bot_body_is_dead() || distancesquared( var_2, self.origin ) > level.heli_pilot_missile_radius * level.heli_pilot_missile_radius ) )
                self botpressbutton( "attack" );

            if ( gettime() > var_4 + 500 )
            {
                var_11 = randomfloatrange( -1 * var_6 / 2, var_6 / 2 );
                var_12 = randomfloatrange( -1 * var_6 / 2, var_6 / 2 );
                var_13 = randomfloatrange( -1 * var_6 / 2, var_6 / 2 );
                var_5 = ( 150 * var_11, 150 * var_12, 150 * var_13 );
                var_4 = gettime();
            }

            var_2 = var_2 + var_5;
            var_14 = self.vehicle_controlling gettagorigin( "tag_player" );
            var_15 = vectornormalize( var_2 - var_14 );
            var_16 = anglestoforward( self getplayerangles() );
            var_17 = vectordot( var_15, var_16 );

            if ( var_17 > 0.5 )
                self botpressbutton( "ads", 0.1 );
        }
        else if ( gettime() > var_3 )
        {
            var_3 = gettime() + randomintrange( 1000, 2000 );
            var_2 = get_random_outside_target();
            self.next_goal_time = gettime();
        }

        var_18 = var_2 - self.vehicle_controlling.origin;
        var_19 = length( var_18 );
        var_20 = vectortoangles( var_18 );
        var_21 = angleclamp( self.vehicle_controlling.angles[0] );
        var_22 = angleclamp( var_20[0] );
        var_23 = int( var_21 - var_22 ) % 360;

        if ( var_23 > 180 )
            var_23 = 360 - var_23;
        else if ( var_23 < -180 )
            var_23 = -360 + var_23;

        if ( var_23 > 15 )
            var_22 = var_21 - 15;
        else if ( var_23 < -15 )
            var_22 = var_21 + 15;

        var_20 = ( var_22, var_20[1], var_20[2] );
        var_18 = anglestoforward( var_20 );
        var_2 = self.vehicle_controlling.origin + var_18 * var_19;

        if ( length( var_2 ) == 0 )
            var_2 = ( 0, 0, 10 );

        self botlookatpoint( var_2, 0.2, "script_forced" );
        wait 0.05;
    }
}

bot_control_odin_assault()
{
    bot_control_odin( "odin_assault" );
}

odin_assault_perform_action()
{
    if ( bot_odin_try_spawn_juggernaut() )
        return 1;

    if ( bot_odin_try_rods() )
        return 1;

    if ( bot_odin_try_airdrop() )
        return 1;

    return 0;
}

odin_assault_get_target()
{
    return bot_odin_find_target_for_rods();
}

bot_odin_find_target_for_rods()
{
    var_0 = undefined;

    if ( isdefined( self.last_large_rod_target ) && gettime() - self.last_large_rod_time < 5000 )
        var_0 = self.last_large_rod_target;

    return bot_odin_get_closest_visible_outside_player( "enemy", 1, var_0 );
}

bot_odin_try_rods()
{
    var_0 = bot_odin_should_fire_rod_at_marker();

    if ( var_0 == "large" )
    {
        self notify( "large_rod_action" );
        return 1;
    }

    if ( var_0 == "small" )
    {
        self notify( "small_rod_action" );
        return 1;
    }

    return 0;
}

bot_odin_should_fire_rod_at_marker()
{
    var_0 = gettime() >= self.odin.odin_largerodusetime;
    var_1 = gettime() >= self.odin.odin_smallrodusetime;

    if ( var_0 || var_1 )
    {
        var_2 = bot_odin_get_visible_outside_players( "enemy", 0 );
        var_3 = [];
        var_4 = distancesquared( self.origin, self.odin.targeting_marker.origin );

        for ( var_5 = 0; var_5 < var_2.size; var_5++ )
        {
            var_6 = bot_odin_get_player_target_point( var_2[var_5] );
            var_3[var_5] = distancesquared( self.odin.targeting_marker.origin, var_6 );
        }

        if ( var_0 )
        {
            if ( !bot_body_is_dead() && var_4 < level.odin_large_rod_radius * level.odin_large_rod_radius )
                return "none";

            for ( var_5 = 0; var_5 < var_2.size; var_5++ )
            {
                if ( var_3[var_5] < squared( level.odin_large_rod_radius ) )
                {
                    self.last_large_rod_target = var_2[var_5];
                    self.last_large_rod_time = gettime();
                    return "large";
                }
            }
        }

        if ( var_1 )
        {
            if ( !bot_body_is_dead() && var_4 < level.odin_small_rod_radius * level.odin_small_rod_radius )
                return "none";

            for ( var_5 = 0; var_5 < var_2.size; var_5++ )
            {
                if ( var_3[var_5] < squared( level.odin_small_rod_radius ) )
                {
                    if ( isdefined( self.last_large_rod_target ) && self.last_large_rod_target == var_2[var_5] && gettime() - self.last_large_rod_time < 5000 )
                        continue;

                    return "small";
                }
            }
        }
    }

    return "none";
}

bot_control_odin_support()
{
    bot_control_odin( "odin_support" );
}

odin_support_perform_action()
{
    if ( bot_odin_try_spawn_juggernaut() )
        return 1;

    if ( bot_odin_try_airdrop() )
        return 1;

    if ( bot_odin_try_smoke() )
        return 1;

    if ( bot_odin_try_flash() )
        return 1;

    return 0;
}

bot_odin_try_flash()
{
    if ( bot_odin_should_fire_flash_at_marker() )
    {
        self notify( "marking_action" );
        return 1;
    }

    return 0;
}

bot_odin_should_fire_flash_at_marker()
{
    if ( gettime() < self.odin.odin_markingusetime )
        return 0;

    var_0 = bot_odin_get_visible_outside_players( "enemy", 0 );
    var_1 = [];

    for ( var_2 = 0; var_2 < var_0.size; var_2++ )
    {
        var_3 = bot_odin_get_player_target_point( var_0[var_2] );
        var_1[var_2] = distancesquared( self.odin.targeting_marker.origin, var_3 );

        if ( var_1[var_2] < squared( level.odin_flash_radius / 2 ) )
            return 1;
    }

    return 0;
}

bot_odin_try_smoke()
{
    if ( bot_odin_should_drop_smoke_at_marker() )
    {
        self notify( "smoke_action" );
        return 1;
    }

    return 0;
}

bot_odin_should_drop_smoke_at_marker()
{
    if ( gettime() < self.odin.odin_smokeusetime )
        return 0;

    var_0 = bot_odin_get_high_priority_smoke_locations();

    foreach ( var_2 in var_0 )
    {
        if ( distancesquared( var_2, self.odin.targeting_marker.origin ) < 2500 )
            return 1;
    }

    var_4 = undefined;

    if ( isdefined( self.odin.targeting_marker.nearest_node ) )
        var_4 = getnodezone( self.odin.targeting_marker.nearest_node );

    if ( !isdefined( var_4 ) )
        return 0;

    var_5 = bot_killstreak_get_zone_enemies_outside( 1 );
    var_6 = var_5[var_4].size;

    if ( var_6 >= 2 )
        return 1;

    return 0;
}

bot_odin_get_high_priority_smoke_locations()
{
    var_0 = [];

    if ( gettime() < self.odin.odin_smokeusetime )
        return var_0;

    foreach ( var_2 in level.carepackages )
    {
        if ( maps\mp\bots\_bots::crate_landed_and_on_path_grid( var_2 ) )
        {
            var_3[0] = self;
            var_4 = common_scripts\utility::get_array_of_closest( var_2.origin, level.players, var_3 );

            if ( var_4.size > 0 && var_4[0].team == self.team )
                var_0 = common_scripts\utility::array_add( var_0, var_2.origin );
        }
    }

    var_6 = bot_odin_get_visible_outside_players( "ally", 0 );

    foreach ( var_8 in var_6 )
    {
        if ( isai( var_8 ) && var_8 maps\mp\bots\_bots_util::bot_is_capturing() )
            var_0 = common_scripts\utility::array_add( var_0, var_8.origin );
    }

    return var_0;
}

odin_support_get_target()
{
    var_0 = bot_odin_get_high_priority_smoke_locations();

    if ( var_0.size > 0 )
        return var_0[0];

    return bot_odin_get_closest_visible_outside_player( "enemy", 1 );
}

monitor_odin_marker()
{
    for (;;)
    {
        self.odin.targeting_marker.nearest_node = getclosestnodeinsight( self.odin.targeting_marker.origin );

        if ( maps\mp\bots\_bots_util::bot_point_is_on_pathgrid( self.odin.targeting_marker.origin, 200 ) )
            self.odin.targeting_marker.nearest_point_on_pathgrid = self.odin.targeting_marker.origin;
        else
            self.odin.targeting_marker.nearest_point_on_pathgrid = undefined;

        wait 0.25;
    }
}

bot_control_odin( var_0 )
{
    self endon( "spawned_player" );
    self endon( "disconnect" );
    self endon( "control_func_done" );
    level endon( "game_ended" );
    var_1 = bot_waittill_using_vehicle( var_0 );

    if ( !var_1 )
        self notify( "control_func_done" );

    self.vehicle_controlling = self.odin;
    childthread bot_end_control_on_vehicle_death( self.odin );
    self.odin endon( "death" );
    wait 1.4;
    self botsetawareness( 0.7 );
    thread bot_end_odin_watcher();
    self.odin_predicted_loc_for_player = [];
    self.odin_predicted_loc_time_for_player = [];
    self.odin_last_predict_position_time = 0;
    var_2 = undefined;
    var_3 = 0;
    var_4 = undefined;
    childthread monitor_odin_marker();
    var_5 = self.odin.targeting_marker.origin;
    var_6 = gettime();

    while ( self [[ level.bot_ks_funcs["isUsing"][var_0] ]]() )
    {
        var_7 = self [[ level.bot_ks_funcs["odin_perform_action"][var_0] ]]();

        if ( gettime() > var_6 + 2000 )
        {
            var_6 = gettime();
            var_8 = distance( var_5, self.odin.targeting_marker.origin );
            var_5 = self.odin.targeting_marker.origin;

            if ( var_8 < 100 )
            {
                var_4 = undefined;
                var_2 = undefined;
            }
        }

        if ( gettime() > var_3 || !isdefined( var_4 ) )
        {
            var_9 = level.bot_odin_time_to_move[self botgetdifficulty()];
            var_3 = gettime() + var_9 * 1000;
            var_10 = self [[ level.bot_ks_funcs["odin_get_target"][var_0] ]]();

            if ( isdefined( var_10 ) )
            {
                var_2 = undefined;

                if ( isplayer( var_10 ) )
                    var_4 = bot_odin_get_player_target_point( var_10 );
                else
                    var_4 = var_10;
            }
            else
            {
                if ( !isdefined( var_2 ) )
                    var_2 = common_scripts\utility::random( level.outside_zones );

                var_11 = getzonenodeforindex( var_2 ).origin;

                if ( distance2dsquared( self.odin.targeting_marker.origin, var_11 ) < 10000 )
                {
                    var_2 = common_scripts\utility::random( level.outside_zones );
                    var_11 = getzonenodeforindex( var_2 ).origin;
                    var_6 = gettime();
                }

                var_4 = var_11;
            }
        }

        var_12 = var_4 - self.odin.targeting_marker.origin;

        if ( lengthsquared( var_12 ) > 100 )
        {
            var_13 = vectortoangles( var_12 );
            self botsetscriptmove( var_13[1], 0.05 );
            self botlookatpoint( var_4, 0.1, "script_forced" );
        }
        else
            var_6 = gettime();

        wait 0.05;
    }

    self notify( "control_func_done" );
}

bot_end_odin_watcher( var_0 )
{
    self endon( "disconnect" );
    self waittill( "control_func_done" );
    self.odin_predicted_loc_for_player = undefined;
    self.odin_predicted_loc_time_for_player = undefined;
    self.odin_last_predict_position_time = undefined;
    self botsetawareness( 1.0 );
}

bot_odin_get_player_target_point( var_0 )
{
    if ( level.teambased && self.team == var_0.team )
        return var_0.origin;
    else
    {
        if ( length( var_0 getentityvelocity() ) < 25 )
            return var_0.origin;

        var_1 = var_0 getentitynumber();

        if ( !isdefined( self.odin_predicted_loc_time_for_player[var_1] ) )
            self.odin_predicted_loc_time_for_player[var_1] = 0;

        var_2 = gettime();
        var_3 = var_2 - self.odin_predicted_loc_time_for_player[var_1];

        if ( var_3 <= 400 )
        {
            var_4 = vectornormalize( var_0 getentityvelocity() );
            var_5 = vectornormalize( self.odin_predicted_loc_for_player[var_1] - var_0.origin );

            if ( vectordot( var_4, var_5 ) < -0.5 )
                return var_0.origin;
        }

        if ( var_3 > 400 )
        {
            if ( var_2 == self.odin_last_predict_position_time )
            {
                if ( var_3 > 1000 )
                    return var_0.origin;
            }
            else
            {
                self.odin_predicted_loc_for_player[var_1] = getpredictedentityposition( var_0, 1.5 );
                self.odin_predicted_loc_time_for_player[var_1] = var_2;
                self.odin_last_predict_position_time = var_2;
            }
        }

        return self.odin_predicted_loc_for_player[var_1];
    }
}

bot_odin_get_closest_visible_outside_player( var_0, var_1, var_2 )
{
    var_3 = bot_odin_get_visible_outside_players( var_0, var_1 );

    if ( isdefined( var_2 ) )
        var_3 = common_scripts\utility::array_remove( var_3, var_2 );

    if ( var_3.size > 0 )
    {
        var_4 = common_scripts\utility::get_array_of_closest( self.odin.targeting_marker.origin, var_3 );
        return var_4[0];
    }

    return undefined;
}

bot_odin_try_spawn_juggernaut()
{
    if ( gettime() >= self.odin.odin_juggernautusetime )
    {
        if ( !isdefined( self.odin.targeting_marker.nearest_node ) )
            return 0;

        var_0 = maps\mp\killstreaks\_odin::getjuggstartingpathnode( self.odin.targeting_marker.origin );

        if ( isdefined( var_0 ) )
        {
            self notify( "juggernaut_action" );
            return 1;
        }
    }

    return 0;
}

bot_odin_find_target_for_airdrop()
{
    return bot_odin_get_closest_visible_outside_player( "ally", 0 );
}

bot_odin_try_airdrop()
{
    if ( bot_odin_should_airdrop_at_marker() )
    {
        self notify( "airdrop_action" );
        self notify( "juggernaut_action" );
        return 1;
    }

    return 0;
}

bot_odin_should_airdrop_at_marker()
{
    if ( gettime() < self.odin.odin_airdropusetime )
        return 0;

    if ( !isdefined( self.odin.targeting_marker.nearest_node ) )
        return 0;

    if ( bot_odin_get_num_valid_care_packages() > 2 )
        return 0;

    if ( !isdefined( self.odin.targeting_marker.nearest_point_on_pathgrid ) )
        return 0;

    var_0 = getnodezone( self.odin.targeting_marker.nearest_node );

    if ( !isdefined( var_0 ) )
        return 0;

    var_1 = bot_killstreak_get_zone_allies_outside( 1 );
    var_2 = var_1[var_0].size;
    var_3 = bot_killstreak_get_zone_enemies_outside( 1 );
    var_4 = var_3[var_0].size;

    if ( var_2 == 0 )
        return 0;

    if ( var_4 == 0 )
    {
        var_5 = 0;
        var_6 = bot_odin_get_visible_outside_players( "enemy", 1 );

        foreach ( var_8 in var_6 )
        {
            if ( distancesquared( var_8.origin, self.odin.targeting_marker.origin ) < 14400 )
                var_5 = 1;
        }

        if ( !var_5 )
            return 1;
    }

    if ( var_2 - var_4 >= 2 )
    {
        var_10 = common_scripts\utility::get_array_of_closest( self.odin.targeting_marker.origin, var_1[var_0] );
        var_11 = common_scripts\utility::get_array_of_closest( self.odin.targeting_marker.origin, var_3[var_0] );
        var_12 = distance( self.odin.targeting_marker.origin, var_10[0].origin );
        var_13 = distance( self.odin.targeting_marker.origin, var_11[0].origin );

        if ( var_12 + 120 < var_13 )
            return 1;
    }

    return 0;
}

bot_odin_get_num_valid_care_packages()
{
    var_0 = 0;

    foreach ( var_2 in level.carepackages )
    {
        if ( isdefined( var_2 ) && maps\mp\bots\_bots::crate_landed_and_on_path_grid( var_2 ) )
            var_0++;
    }

    return var_0;
}

bot_odin_get_visible_outside_players( var_0, var_1, var_2 )
{
    var_3 = bot_killstreak_get_outside_players( self.team, var_0, var_1 );
    var_4 = self botgetfovdot();
    var_5 = [];

    foreach ( var_7 in var_3 )
    {
        var_8 = 0;
        var_9 = var_4;

        if ( var_0 == "enemy" )
        {
            if ( maps\mp\killstreaks\_odin::enemynotaffectedbyodinoutline( var_7 ) )
                var_8 = 1;
            else
                var_9 = var_9 * 0.9;
        }

        if ( common_scripts\utility::within_fov( self.vehicle_controlling.origin, self getplayerangles(), var_7.origin, var_9 ) )
        {
            if ( !var_8 || self botcanseeentity( var_7 ) )
                var_5 = common_scripts\utility::array_add( var_5, var_7 );
        }
    }

    return var_5;
}

is_indoor_map()
{
    return level.script == "mp_sovereign";
}

bot_body_is_dead()
{
    return isdefined( self.fauxdead ) && self.fauxdead;
}

heli_pick_node_furthest_from_center( var_0, var_1 )
{
    var_2 = undefined;
    var_3 = 0;

    foreach ( var_5 in var_0 )
    {
        var_6 = distancesquared( level.bot_map_center, [[ level.bot_ks_funcs["heli_node_get_origin"][var_1] ]]( var_5 ) );

        if ( var_6 > var_3 )
        {
            var_3 = var_6;
            var_2 = var_5;
        }
    }

    if ( isdefined( var_2 ) )
        return var_2;
    else
        return common_scripts\utility::random( var_0 );
}

heli_get_node_origin( var_0 )
{
    return var_0.origin;
}

find_closest_heli_node_2d( var_0, var_1 )
{
    var_2 = undefined;
    var_3 = 99999999;

    foreach ( var_5 in level.bot_heli_nodes )
    {
        var_6 = distance2dsquared( var_0, [[ level.bot_ks_funcs["heli_node_get_origin"][var_1] ]]( var_5 ) );

        if ( var_6 < var_3 )
        {
            var_2 = var_5;
            var_3 = var_6;
        }
    }

    return var_2;
}

bot_killstreak_get_zone_allies_outside( var_0 )
{
    var_1 = bot_killstreak_get_all_outside_allies( var_0 );
    var_2 = [];

    for ( var_3 = 0; var_3 < level.zonecount; var_3++ )
        var_2[var_3] = [];

    foreach ( var_5 in var_1 )
    {
        var_6 = var_5 getnearestnode();
        var_7 = getnodezone( var_6 );

        if ( isdefined( var_7 ) )
            var_2[var_7] = common_scripts\utility::array_add( var_2[var_7], var_5 );
    }

    return var_2;
}

bot_killstreak_get_zone_enemies_outside( var_0 )
{
    var_1 = bot_killstreak_get_all_outside_enemies( var_0 );
    var_2 = [];

    for ( var_3 = 0; var_3 < level.zonecount; var_3++ )
        var_2[var_3] = [];

    foreach ( var_5 in var_1 )
    {
        var_6 = var_5 getnearestnode();
        var_7 = getnodezone( var_6 );
        var_2[var_7] = common_scripts\utility::array_add( var_2[var_7], var_5 );
    }

    return var_2;
}

bot_killstreak_get_all_outside_enemies( var_0 )
{
    return bot_killstreak_get_outside_players( self.team, "enemy", var_0 );
}

bot_killstreak_get_all_outside_allies( var_0 )
{
    return bot_killstreak_get_outside_players( self.team, "ally", var_0 );
}

bot_killstreak_get_outside_players( var_0, var_1, var_2 )
{
    var_3 = [];
    var_4 = level.participants;

    if ( isdefined( var_2 ) && var_2 )
        var_4 = level.players;

    foreach ( var_6 in var_4 )
    {
        if ( var_6 == self || !isalive( var_6 ) )
            continue;

        var_7 = 0;

        if ( var_1 == "ally" )
            var_7 = level.teambased && var_0 == var_6.team;
        else if ( var_1 == "enemy" )
            var_7 = !level.teambased || var_0 != var_6.team;

        if ( var_7 )
        {
            var_8 = var_6 getnearestnode();

            if ( isdefined( var_8 ) && nodeexposedtosky( var_8 ) )
                var_3 = common_scripts\utility::array_add( var_3, var_6 );
        }
    }

    var_3 = common_scripts\utility::array_remove( var_3, self );
    return var_3;
}

bot_heli_find_unvisited_nodes( var_0 )
{
    var_1 = 99;
    var_2 = [];

    foreach ( var_4 in var_0.neighbors )
    {
        if ( isdefined( var_4.script_linkname ) )
        {
            var_5 = var_4.bot_visited_times[self.entity_number];

            if ( var_5 < var_1 )
            {
                var_2 = [];
                var_2[0] = var_4;
                var_1 = var_5;
            }
            else if ( var_5 == var_1 )
                var_2[var_2.size] = var_4;
        }
    }

    return var_2;
}

bot_control_heli( var_0 )
{
    self endon( "spawned_player" );
    self endon( "disconnect" );
    self endon( "control_func_done" );
    level endon( "game_ended" );
    var_1 = bot_waittill_using_vehicle( var_0 );

    if ( !var_1 )
        self notify( "control_func_done" );

    foreach ( var_3 in level.littlebirds )
    {
        if ( var_3.owner == self )
            self.vehicle_controlling = var_3;
    }

    childthread bot_end_control_on_vehicle_death( self.vehicle_controlling );
    self.vehicle_controlling endon( "death" );

    if ( isdefined( level.bot_ks_funcs["control_other"][var_0] ) )
        self childthread [[ level.bot_ks_funcs["control_other"][var_0] ]]();

    self [[ level.bot_ks_funcs["waittill_initial_goal"][var_0] ]]();
    self childthread [[ level.bot_ks_funcs["control_aiming"][var_0] ]]();
    bot_control_heli_main_move_loop( var_0, 1 );
    self notify( "control_func_done" );
}

bot_get_heli_goal_dist_sq( var_0 )
{
    if ( var_0 )
        return squared( 100 );
    else
        return squared( 30 );
}

bot_get_heli_slowdown_dist_sq( var_0 )
{
    if ( var_0 )
        return squared( 300 );
    else
        return squared( 90 );
}

bot_control_heli_main_move_loop( var_0, var_1 )
{
    foreach ( var_3 in level.bot_heli_nodes )
        var_3.bot_visited_times[self.entity_number] = 0;

    var_5 = find_closest_heli_node_2d( self.vehicle_controlling.origin, var_0 );
    var_6 = undefined;
    self.next_goal_time = 0;
    var_7 = "needs_new_goal";
    var_8 = undefined;
    var_9 = self.vehicle_controlling.origin;
    var_10 = 3.0;
    var_11 = 0.05;

    while ( self [[ level.bot_ks_funcs["isUsing"][var_0] ]]() )
    {
        if ( gettime() > self.next_goal_time && var_7 == "needs_new_goal" )
        {
            var_12 = var_5;
            var_5 = [[ level.bot_ks_funcs["heli_pick_node"][var_0] ]]( var_5 );
            var_6 = undefined;

            if ( isdefined( var_5 ) )
            {
                var_13 = [[ level.bot_ks_funcs["heli_node_get_origin"][var_0] ]]( var_5 );

                if ( var_1 )
                {
                    var_14 = var_5.origin + ( maps\mp\_utility::gethelipilotmeshoffset() + level.bot_heli_pilot_traceoffset );
                    var_15 = var_5.origin + ( maps\mp\_utility::gethelipilotmeshoffset() - level.bot_heli_pilot_traceoffset );
                    var_16 = bullettrace( var_14, var_15, 0, undefined, 0, 0, 1 );
                    var_6 = var_16["position"] - maps\mp\_utility::gethelipilotmeshoffset() + level.bot_ks_heli_offset[var_0];
                }
                else
                    var_6 = var_13;
            }

            if ( isdefined( var_6 ) )
            {
                self botsetflag( "disable_movement", 0 );
                var_7 = "waiting_till_goal";
                var_10 = 3.0;
                var_9 = self.vehicle_controlling.origin;
            }
            else
            {
                var_5 = var_12;
                self.next_goal_time = gettime() + 2000;
            }
        }
        else if ( var_7 == "waiting_till_goal" )
        {
            if ( !var_1 )
            {
                var_17 = var_6[2] - self.vehicle_controlling.origin[2];

                if ( var_17 > 10 )
                    self botpressbutton( "lethal" );
                else if ( var_17 < -10 )
                    self botpressbutton( "tactical" );
            }

            var_18 = var_6 - self.vehicle_controlling.origin;

            if ( var_1 )
                var_8 = length2dsquared( var_18 );
            else
                var_8 = lengthsquared( var_18 );

            if ( var_8 < bot_get_heli_goal_dist_sq( var_1 ) )
            {
                self botsetscriptmove( 0, 0 );
                self botsetflag( "disable_movement", 1 );

                if ( self botgetdifficulty() == "recruit" )
                    self.next_goal_time = gettime() + randomintrange( 5000, 7000 );
                else
                    self.next_goal_time = gettime() + randomintrange( 3000, 5000 );

                var_7 = "needs_new_goal";
            }
            else
            {
                var_18 = var_6 - self.vehicle_controlling.origin;
                var_19 = vectortoangles( var_18 );
                var_20 = common_scripts\utility::ter_op( var_8 < bot_get_heli_slowdown_dist_sq( var_1 ), 0.5, 1.0 );
                self botsetscriptmove( var_19[1], var_11, var_20 );
                var_10 = var_10 - var_11;

                if ( var_10 <= 0.0 )
                {
                    if ( distancesquared( self.vehicle_controlling.origin, var_9 ) < 225 )
                    {
                        var_5.bot_visited_times[self.entity_number]++;
                        var_7 = "needs_new_goal";
                    }

                    var_9 = self.vehicle_controlling.origin;
                    var_10 = 3.0;
                }
            }
        }

        wait( var_11 );
    }
}

get_random_outside_target()
{
    var_0 = [];

    foreach ( var_2 in level.outside_zones )
    {
        var_3 = botzonegetcount( var_2, self.team, "enemy_predict" );

        if ( var_3 > 0 )
            var_0 = common_scripts\utility::array_add( var_0, var_2 );
    }

    var_5 = undefined;

    if ( var_0.size > 0 )
    {
        var_6 = common_scripts\utility::random( var_0 );
        var_7 = common_scripts\utility::random( getzonenodes( var_6 ) );
        var_5 = var_7.origin;
    }
    else
    {
        if ( isdefined( level.teleportgetactivenodesfunc ) )
            var_8 = [[ level.teleportgetactivenodesfunc ]]();
        else
            var_8 = getallnodes();

        var_9 = 0;

        while ( var_9 < 10 )
        {
            var_9++;
            var_10 = var_8[randomint( var_8.size )];
            var_5 = var_10.origin;

            if ( nodeexposedtosky( var_10 ) && distance2dsquared( var_10.origin, self.vehicle_controlling.origin ) > 62500 )
                break;
        }
    }

    return var_5;
}
