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

bot_defend_get_random_entrance_point_for_current_area()
{
    var_0 = bot_defend_get_precalc_entrances_for_current_area( self.cur_defend_stance );

    if ( isdefined( var_0 ) && var_0.size > 0 )
        return common_scripts\utility::random( var_0 ).origin;

    return undefined;
}

bot_defend_get_precalc_entrances_for_current_area( var_0 )
{
    if ( isdefined( self.defend_entrance_index ) )
        return maps\mp\bots\_bots_util::bot_get_entrances_for_stance_and_index( var_0, self.defend_entrance_index );

    return [];
}

bot_setup_bombzone_bottargets()
{
    wait 1.0;
    bot_setup_bot_targets( level.bombzones );
    level.bot_set_bombzone_bottargets = 1;
}

bot_setup_radio_bottargets()
{
    bot_setup_bot_targets( level.radios );
}

bot_setup_bot_targets( var_0 )
{
    foreach ( var_2 in var_0 )
    {
        if ( !isdefined( var_2.bottargets ) )
        {
            var_2.bottargets = [];
            var_3 = gettnodesintrigger( var_2.trigger );

            foreach ( var_5 in var_3 )
            {
                if ( !var_5 nodeisdisconnected() )
                    var_2.bottargets = common_scripts\utility::array_add( var_2.bottargets, var_5 );
            }
        }
    }
}

bot_get_ambush_trap_item( var_0, var_1, var_2 )
{
    var_3 = [];
    var_4 = [];
    var_4[var_4.size] = var_0;

    if ( isdefined( var_1 ) )
        var_4[var_4.size] = var_1;

    if ( isdefined( var_1 ) )
        var_4[var_4.size] = var_2;

    foreach ( var_6 in var_4 )
    {
        var_3["purpose"] = var_6;
        var_3["item_action"] = maps\mp\bots\_bots_util::bot_get_grenade_for_purpose( var_6 );

        if ( isdefined( var_3["item_action"] ) )
            return var_3;
    }
}

bot_set_ambush_trap( var_0, var_1, var_2, var_3, var_4 )
{
    self notify( "bot_set_ambush_trap" );
    self endon( "bot_set_ambush_trap" );

    if ( !isdefined( var_0 ) )
        return 0;

    var_5 = undefined;

    if ( !isdefined( var_4 ) && isdefined( var_1 ) && var_1.size > 0 )
    {
        if ( !isdefined( var_2 ) )
            return 0;

        var_6 = [];
        var_7 = undefined;

        if ( isdefined( var_3 ) )
            var_7 = anglestoforward( ( 0, var_3, 0 ) );

        foreach ( var_9 in var_1 )
        {
            if ( !isdefined( var_7 ) )
            {
                var_6[var_6.size] = var_9;
                continue;
            }

            if ( distancesquared( var_9.origin, var_2.origin ) > 90000 )
            {
                if ( vectordot( var_7, vectornormalize( var_9.origin - var_2.origin ) ) < 0.4 )
                    var_6[var_6.size] = var_9;
            }
        }

        if ( var_6.size > 0 )
        {
            var_5 = common_scripts\utility::random( var_6 );
            var_11 = getnodesinradius( var_5.origin, 300, 50 );
            var_12 = [];

            foreach ( var_14 in var_11 )
            {
                if ( !isdefined( var_14.bot_ambush_end ) )
                    var_12[var_12.size] = var_14;
            }

            var_11 = var_12;
            var_4 = self botnodepick( var_11, min( var_11.size, 3 ), "node_trap", var_2, var_5 );
        }
    }

    if ( isdefined( var_4 ) )
    {
        var_16 = undefined;

        if ( var_0["purpose"] == "trap_directional" && isdefined( var_5 ) )
        {
            var_17 = vectortoangles( var_5.origin - var_4.origin );
            var_16 = var_17[1];
        }

        if ( self bothasscriptgoal() && self botgetscriptgoaltype() != "critical" && self botgetscriptgoaltype() != "tactical" )
            self botclearscriptgoal();

        var_18 = self botsetscriptgoalnode( var_4, "guard", var_16 );

        if ( var_18 )
        {
            var_19 = maps\mp\bots\_bots_util::bot_waittill_goal_or_fail();

            if ( var_19 == "goal" )
            {
                thread maps\mp\bots\_bots_util::bot_force_stance_for_time( "stand", 5.0 );

                if ( !isdefined( self.enemy ) || 0 == self botcanseeentity( self.enemy ) )
                {
                    if ( isdefined( var_16 ) )
                        self botthrowgrenade( var_5.origin, var_0["item_action"] );
                    else
                        self botthrowgrenade( self.origin + anglestoforward( self.angles ) * 50, var_0["item_action"] );

                    self.ambush_trap_ent = undefined;
                    thread bot_set_ambush_trap_wait_fire( "grenade_fire" );
                    thread bot_set_ambush_trap_wait_fire( "missile_fire" );
                    var_20 = 3.0;

                    if ( var_0["purpose"] == "tacticalinsertion" )
                        var_20 = 6.0;

                    common_scripts\utility::waittill_any_timeout( var_20, "missile_fire", "grenade_fire" );
                    wait 0.05;
                    self notify( "ambush_trap_ent" );

                    if ( isdefined( self.ambush_trap_ent ) && var_0["purpose"] == "c4" )
                        thread bot_watch_manual_detonate( self.ambush_trap_ent, var_0["item_action"], 300 );

                    self.ambush_trap_ent = undefined;
                    wait( randomfloat( 0.25 ) );
                    self botsetstance( "none" );
                }
            }

            return 1;
        }
    }

    return 0;
}

bot_set_ambush_trap_wait_fire( var_0 )
{
    self endon( "death" );
    self endon( "disconnect" );
    self endon( "bot_set_ambush_trap" );
    self endon( "ambush_trap_ent" );
    level endon( "game_ended" );
    self waittill( var_0, var_1 );
    self.ambush_trap_ent = var_1;
}

bot_watch_manual_detonate( var_0, var_1, var_2 )
{
    self endon( "death" );
    self endon( "disconnect" );
    var_0 endon( "death" );
    level endon( "game_ended" );
    var_3 = var_2 * var_2;

    for (;;)
    {
        if ( isdefined( var_0.origin ) && distancesquared( self.origin, var_0.origin ) > var_3 )
        {
            var_4 = self getclosestenemysqdist( var_0.origin, 1.0 );

            if ( var_4 < var_3 )
            {
                self botpressbutton( var_1 );
                return;
            }
        }

        wait( randomfloatrange( 0.25, 1.0 ) );
    }
}

bot_capture_point( var_0, var_1, var_2 )
{
    thread bot_defend_think( var_0, var_1, "capture", var_2 );
}

bot_capture_zone( var_0, var_1, var_2, var_3 )
{
    var_3["capture_trigger"] = var_2;
    thread bot_defend_think( var_0, var_1, "capture_zone", var_3 );
}

bot_protect_point( var_0, var_1, var_2 )
{
    if ( !isdefined( var_2 ) || !isdefined( var_2["min_goal_time"] ) )
        var_2["min_goal_time"] = 12;

    if ( !isdefined( var_2 ) || !isdefined( var_2["max_goal_time"] ) )
        var_2["max_goal_time"] = 18;

    thread bot_defend_think( var_0, var_1, "protect", var_2 );
}

bot_patrol_area( var_0, var_1, var_2 )
{
    if ( !isdefined( var_2 ) || !isdefined( var_2["min_goal_time"] ) )
        var_2["min_goal_time"] = 0.0;

    if ( !isdefined( var_2 ) || !isdefined( var_2["max_goal_time"] ) )
        var_2["max_goal_time"] = 0.01;

    thread bot_defend_think( var_0, var_1, "patrol", var_2 );
}

bot_guard_player( var_0, var_1, var_2 )
{
    if ( !isdefined( var_2 ) || !isdefined( var_2["min_goal_time"] ) )
        var_2["min_goal_time"] = 15;

    if ( !isdefined( var_2 ) || !isdefined( var_2["max_goal_time"] ) )
        var_2["max_goal_time"] = 20;

    thread bot_defend_think( var_0, var_1, "bodyguard", var_2 );
}

bot_defend_think( var_0, var_1, var_2, var_3 )
{
    self notify( "started_bot_defend_think" );
    self endon( "started_bot_defend_think" );
    self endon( "death" );
    self endon( "disconnect" );
    level endon( "game_ended" );
    self endon( "defend_stop" );
    thread defense_death_monitor();

    if ( isdefined( self.bot_defending ) || self botgetscriptgoaltype() == "camp" )
        self botclearscriptgoal();

    self.bot_defending = 1;
    self.bot_defending_type = var_2;

    if ( var_2 == "capture_zone" )
    {
        self.bot_defending_radius = undefined;
        self.bot_defending_nodes = var_1;
        self.bot_defending_trigger = var_3["capture_trigger"];
    }
    else
    {
        self.bot_defending_radius = var_1;
        self.bot_defending_nodes = undefined;
        self.bot_defending_trigger = undefined;
    }

    if ( maps\mp\_utility::isgameparticipant( var_0 ) )
    {
        self.bot_defend_player_guarding = var_0;
        childthread monitor_defend_player();
    }
    else
    {
        self.bot_defend_player_guarding = undefined;
        self.bot_defending_center = var_0;
    }

    self botsetstance( "none" );
    var_4 = undefined;
    var_5 = 6;
    var_6 = 10;

    if ( isdefined( var_3 ) )
    {
        self.defend_entrance_index = var_3["entrance_points_index"];
        self.defense_score_flags = var_3["score_flags"];
        self.bot_defending_override_origin_node = var_3["override_origin_node"];

        if ( isdefined( var_3["override_goal_type"] ) )
            var_4 = var_3["override_goal_type"];

        if ( isdefined( var_3["min_goal_time"] ) )
            var_5 = var_3["min_goal_time"];

        if ( isdefined( var_3["max_goal_time"] ) )
            var_6 = var_3["max_goal_time"];

        if ( isdefined( var_3["override_entrances"] ) && var_3["override_entrances"].size > 0 )
        {
            self.defense_override_entrances = var_3["override_entrances"];
            self.defend_entrance_index = self.name + " " + gettime();

            foreach ( var_8 in self.defense_override_entrances )
            {
                var_8.prone_visible_from[self.defend_entrance_index] = maps\mp\bots\_bots_util::entrance_visible_from( var_8.origin, maps\mp\bots\_bots_util::defend_valid_center(), "prone" );
                wait 0.05;
                var_8.crouch_visible_from[self.defend_entrance_index] = maps\mp\bots\_bots_util::entrance_visible_from( var_8.origin, maps\mp\bots\_bots_util::defend_valid_center(), "crouch" );
                wait 0.05;
            }
        }
    }

    if ( !isdefined( self.bot_defend_player_guarding ) )
    {
        var_10 = undefined;

        if ( isdefined( var_3 ) && isdefined( var_3["nearest_node_to_center"] ) )
            var_10 = var_3["nearest_node_to_center"];

        if ( !isdefined( var_10 ) && isdefined( self.bot_defending_override_origin_node ) )
            var_10 = self.bot_defending_override_origin_node;

        if ( !isdefined( var_10 ) && isdefined( self.bot_defending_trigger ) && isdefined( self.bot_defending_trigger.nearest_node ) )
            var_10 = self.bot_defending_trigger.nearest_node;

        if ( !isdefined( var_10 ) )
            var_10 = getclosestnodeinsight( maps\mp\bots\_bots_util::defend_valid_center() );

        if ( !isdefined( var_10 ) )
        {
            var_11 = maps\mp\bots\_bots_util::defend_valid_center();
            var_12 = getnodesinradiussorted( var_11, 256, 0 );

            for ( var_13 = 0; var_13 < var_12.size; var_13++ )
            {
                var_14 = vectornormalize( var_12[var_13].origin - var_11 );
                var_15 = var_11 + var_14 * 15;

                if ( sighttracepassed( var_15, var_12[var_13].origin, 0, undefined ) )
                {
                    var_10 = var_12[var_13];
                    break;
                }

                wait 0.05;

                if ( sighttracepassed( var_15 + ( 0, 0, 55 ), var_12[var_13].origin + ( 0, 0, 55 ), 0, undefined ) )
                {
                    var_10 = var_12[var_13];
                    break;
                }

                wait 0.05;
            }
        }

        self.node_closest_to_defend_center = var_10;
    }

    var_16 = level.bot_find_defend_node_func[var_2];

    if ( !isdefined( var_4 ) )
    {
        var_4 = "guard";

        if ( var_2 == "capture" || var_2 == "capture_zone" )
            var_4 = "objective";
    }

    var_17 = maps\mp\bots\_bots_util::bot_is_capturing();

    if ( var_2 == "protect" )
        childthread protect_watch_allies();

    for (;;)
    {
        self.prev_defend_node = self.cur_defend_node;
        self.cur_defend_node = undefined;
        self.cur_defend_angle_override = undefined;
        self.cur_defend_point_override = undefined;
        self.cur_defend_stance = calculate_defend_stance( var_17 );
        var_18 = self botgetscriptgoaltype();
        var_19 = maps\mp\bots\_bots_util::bot_goal_can_override( var_4, var_18 );

        if ( !var_19 )
        {
            wait 0.25;
            continue;
        }

        var_20 = var_5;
        var_21 = var_6;
        var_22 = 1;

        if ( isdefined( self.defense_investigate_specific_point ) )
        {
            self.cur_defend_point_override = self.defense_investigate_specific_point;
            self.defense_investigate_specific_point = undefined;
            var_22 = 0;
            var_20 = 1.0;
            var_21 = 2.0;
        }
        else if ( isdefined( self.defense_force_next_node_goal ) )
        {
            self.cur_defend_node = self.defense_force_next_node_goal;
            self.defense_force_next_node_goal = undefined;
        }
        else
            self [[ var_16 ]]();

        self botclearscriptgoal();
        var_23 = "";

        if ( isdefined( self.cur_defend_node ) || isdefined( self.cur_defend_point_override ) )
        {
            if ( var_22 && maps\mp\bots\_bots_util::bot_is_protecting() && !isplayer( var_0 ) && isdefined( self.defend_entrance_index ) )
            {
                var_24 = bot_get_ambush_trap_item( "trap_directional", "trap", "c4" );

                if ( isdefined( var_24 ) )
                {
                    var_25 = maps\mp\bots\_bots_util::bot_get_entrances_for_stance_and_index( undefined, self.defend_entrance_index );
                    bot_set_ambush_trap( var_24, var_25, self.node_closest_to_defend_center );
                }
            }

            if ( isdefined( self.cur_defend_point_override ) )
            {
                var_26 = undefined;

                if ( isdefined( self.cur_defend_angle_override ) )
                    var_26 = self.cur_defend_angle_override[1];

                self botsetscriptgoal( self.cur_defend_point_override, 0, var_4, var_26 );
            }
            else if ( !isdefined( self.cur_defend_angle_override ) )
                self botsetscriptgoalnode( self.cur_defend_node, var_4 );
            else
                self botsetscriptgoalnode( self.cur_defend_node, var_4, self.cur_defend_angle_override[1] );

            if ( var_17 )
            {
                if ( !isdefined( self.prev_defend_node ) || !isdefined( self.cur_defend_node ) || self.prev_defend_node != self.cur_defend_node )
                    self botsetstance( "none" );
            }

            var_27 = self botgetscriptgoal();
            self notify( "new_defend_goal" );
            maps\mp\bots\_bots_util::watch_nodes_stop();

            if ( var_4 == "objective" )
            {
                defense_cautious_approach();
                self botsetawareness( 1.0 );
                self botsetflag( "cautious", 0 );
            }

            if ( self bothasscriptgoal() )
            {
                var_28 = self botgetscriptgoal();

                if ( maps\mp\bots\_bots_util::bot_vectors_are_equal( var_28, var_27 ) )
                    var_23 = maps\mp\bots\_bots_util::bot_waittill_goal_or_fail( 20, "defend_force_node_recalculation" );
            }

            if ( var_23 == "goal" )
            {
                if ( var_17 )
                    self botsetstance( self.cur_defend_stance );

                childthread defense_watch_entrances_at_goal();
            }
        }

        if ( var_23 != "goal" )
        {
            wait 0.25;
            continue;
        }

        var_29 = randomfloatrange( var_20, var_21 );
        var_23 = common_scripts\utility::waittill_any_timeout( var_29, "node_relinquished", "goal_changed", "script_goal_changed", "defend_force_node_recalculation", "bad_path" );

        if ( ( var_23 == "node_relinquished" || var_23 == "bad_path" || var_23 == "goal_changed" || var_23 == "script_goal_changed" ) && ( self.cur_defend_stance == "crouch" || self.cur_defend_stance == "prone" ) )
            self botsetstance( "none" );
    }
}

calculate_defend_stance( var_0 )
{
    var_1 = "stand";

    if ( var_0 )
    {
        var_2 = 100;
        var_3 = 0;
        var_4 = 0;
        var_5 = self botgetdifficultysetting( "strategyLevel" );

        if ( var_5 == 1 )
        {
            var_2 = 20;
            var_3 = 25;
            var_4 = 55;
        }
        else if ( var_5 >= 2 )
        {
            var_2 = 10;
            var_3 = 20;
            var_4 = 70;
        }

        var_6 = randomint( 100 );

        if ( var_6 < var_3 )
            var_1 = "crouch";
        else if ( var_6 < var_3 + var_4 )
            var_1 = "prone";

        if ( var_1 == "prone" )
        {
            var_7 = bot_defend_get_precalc_entrances_for_current_area( "prone" );
            var_8 = defend_get_ally_bots_at_zone_for_stance( "prone" );

            if ( var_8.size >= var_7.size )
                var_1 = "crouch";
        }

        if ( var_1 == "crouch" )
        {
            var_9 = bot_defend_get_precalc_entrances_for_current_area( "crouch" );
            var_10 = defend_get_ally_bots_at_zone_for_stance( "crouch" );

            if ( var_10.size >= var_9.size )
                var_1 = "stand";
        }
    }

    return var_1;
}

should_start_cautious_approach_default( var_0 )
{
    var_1 = 1250;
    var_2 = var_1 * var_1;

    if ( var_0 )
    {
        if ( self botgetdifficultysetting( "strategyLevel" ) == 0 )
            return 0;

        if ( self.bot_defending_type == "capture_zone" && self istouching( self.bot_defending_trigger ) )
            return 0;

        return distancesquared( self.origin, self.bot_defending_center ) > var_2 * 0.75 * 0.75;
    }
    else if ( self botpursuingscriptgoal() && distancesquared( self.origin, self.bot_defending_center ) < var_2 )
    {
        var_3 = self botgetpathdist();
        return 0 <= var_3 && var_3 <= var_1;
    }
    else
        return 0;
}

setup_investigate_location( var_0, var_1 )
{
    var_2 = spawnstruct();

    if ( isdefined( var_1 ) )
        var_2.origin = var_1;
    else
        var_2.origin = var_0.origin;

    var_2.node = var_0;
    var_2.frames_visible = 0;
    return var_2;
}

defense_cautious_approach()
{
    self notify( "defense_cautious_approach" );
    self endon( "defense_cautious_approach" );
    level endon( "game_ended" );
    self endon( "defend_force_node_recalculation" );
    self endon( "death" );
    self endon( "disconnect" );
    self endon( "defend_stop" );
    self endon( "started_bot_defend_think" );

    if ( ![[ level.bot_funcs["should_start_cautious_approach"] ]]( 1 ) )
        return;

    var_0 = self botgetscriptgoal();
    var_1 = self botgetscriptgoalnode();
    var_2 = 1;
    var_3 = 0.2;

    while ( var_2 )
    {
        wait 0.25;

        if ( !self bothasscriptgoal() )
            return;

        var_4 = self botgetscriptgoal();

        if ( !maps\mp\bots\_bots_util::bot_vectors_are_equal( var_0, var_4 ) )
            return;

        var_3 = var_3 + 0.25;

        if ( var_3 >= 0.5 )
        {
            var_3 = 0.0;

            if ( [[ level.bot_funcs["should_start_cautious_approach"] ]]( 0 ) )
                var_2 = 0;
        }
    }

    self botsetawareness( 1.8 );
    self botsetflag( "cautious", 1 );
    var_5 = self botgetnodesonpath();

    if ( !isdefined( var_5 ) || var_5.size <= 2 )
        return;

    self.locations_to_investigate = [];
    var_6 = 1000;

    if ( isdefined( level.protect_radius ) )
        var_6 = level.protect_radius;

    var_7 = var_6 * var_6;
    var_8 = getnodesinradius( self.bot_defending_center, var_6, 0, 500 );

    if ( var_8.size <= 0 )
        return;

    var_9 = 5 + self botgetdifficultysetting( "strategyLevel" ) * 2;
    var_10 = int( min( var_9, var_8.size ) );
    var_11 = self botnodepickmultiple( var_8, 15, var_10, "node_protect", maps\mp\bots\_bots_util::defend_valid_center(), "ignore_occupancy" );

    for ( var_12 = 0; var_12 < var_11.size; var_12++ )
    {
        var_13 = setup_investigate_location( var_11[var_12] );
        self.locations_to_investigate = common_scripts\utility::array_add( self.locations_to_investigate, var_13 );
    }

    var_14 = botgetmemoryevents( 0, gettime() - 60000, 1, "death", 0, self );

    foreach ( var_16 in var_14 )
    {
        if ( distancesquared( var_16, self.bot_defending_center ) < var_7 )
        {
            var_17 = getclosestnodeinsight( var_16 );

            if ( isdefined( var_17 ) )
            {
                var_13 = setup_investigate_location( var_17, var_16 );
                self.locations_to_investigate = common_scripts\utility::array_add( self.locations_to_investigate, var_13 );
            }
        }
    }

    if ( isdefined( self.defend_entrance_index ) )
    {
        var_19 = maps\mp\bots\_bots_util::bot_get_entrances_for_stance_and_index( "stand", self.defend_entrance_index );

        for ( var_12 = 0; var_12 < var_19.size; var_12++ )
        {
            var_13 = setup_investigate_location( var_19[var_12] );
            self.locations_to_investigate = common_scripts\utility::array_add( self.locations_to_investigate, var_13 );
        }
    }

    if ( self.locations_to_investigate.size == 0 )
        return;

    childthread monitor_cautious_approach_dangerous_locations();
    var_20 = self botgetscriptgoaltype();
    var_21 = self botgetscriptgoalradius();
    var_22 = self botgetscriptgoalyaw();
    wait 0.05;

    for ( var_23 = 1; var_23 < var_5.size - 2; var_23++ )
    {
        maps\mp\bots\_bots_util::bot_waittill_out_of_combat_or_time();
        var_24 = getlinkednodes( var_5[var_23] );

        if ( var_24.size == 0 )
            continue;

        var_25 = [];

        for ( var_12 = 0; var_12 < var_24.size; var_12++ )
        {
            if ( !common_scripts\utility::within_fov( self.origin, self.angles, var_24[var_12].origin, 0 ) )
                continue;

            for ( var_26 = 0; var_26 < self.locations_to_investigate.size; var_26++ )
            {
                var_16 = self.locations_to_investigate[var_26];

                if ( nodesvisible( var_16.node, var_24[var_12], 1 ) )
                {
                    var_25 = common_scripts\utility::array_add( var_25, var_24[var_12] );
                    var_26 = self.locations_to_investigate.size;
                }
            }
        }

        if ( var_25.size == 0 )
            continue;

        var_27 = self botnodepick( var_25, 1 + var_25.size * 0.15, "node_hide" );

        if ( isdefined( var_27 ) )
        {
            var_28 = [];

            for ( var_12 = 0; var_12 < self.locations_to_investigate.size; var_12++ )
            {
                if ( nodesvisible( self.locations_to_investigate[var_12].node, var_27, 1 ) )
                    var_28 = common_scripts\utility::array_add( var_28, self.locations_to_investigate[var_12] );
            }

            self botclearscriptgoal();
            self botsetscriptgoalnode( var_27, "critical" );
            childthread monitor_cautious_approach_early_out();
            var_29 = maps\mp\bots\_bots_util::bot_waittill_goal_or_fail( undefined, "cautious_approach_early_out" );
            self notify( "stop_cautious_approach_early_out_monitor" );

            if ( var_29 == "cautious_approach_early_out" )
                break;

            if ( var_29 == "goal" )
            {
                for ( var_12 = 0; var_12 < var_28.size; var_12++ )
                {
                    for ( var_30 = 0; var_28[var_12].frames_visible < 18 && var_30 < 3.6; var_30 = var_30 + 0.25 )
                    {
                        self botlookatpoint( var_28[var_12].origin + ( 0, 0, self getplayerviewheight() ), 0.25, "script_search" );
                        wait 0.25;
                    }
                }
            }
        }

        wait 0.05;
    }

    self notify( "stop_location_monitoring" );
    self botclearscriptgoal();

    if ( isdefined( var_1 ) )
        self botsetscriptgoalnode( var_1, var_20, var_22 );
    else
        self botsetscriptgoal( self.cur_defend_point_override, var_21, var_20, var_22 );
}

monitor_cautious_approach_early_out()
{
    self endon( "cautious_approach_early_out" );
    self endon( "stop_cautious_approach_early_out_monitor" );
    var_0 = undefined;

    if ( isdefined( self.bot_defending_radius ) )
        var_0 = self.bot_defending_radius * self.bot_defending_radius;
    else if ( isdefined( self.bot_defending_nodes ) )
    {
        var_1 = bot_capture_zone_get_furthest_distance();
        var_0 = var_1 * var_1;
    }

    wait 0.05;

    for (;;)
    {
        if ( distancesquared( self.origin, self.bot_defending_center ) < var_0 )
            self notify( "cautious_approach_early_out" );

        wait 0.05;
    }
}

monitor_cautious_approach_dangerous_locations()
{
    self endon( "stop_location_monitoring" );
    var_0 = 10000;

    for (;;)
    {
        var_1 = self getnearestnode();

        if ( isdefined( var_1 ) )
        {
            var_2 = self botgetfovdot();

            for ( var_3 = 0; var_3 < self.locations_to_investigate.size; var_3++ )
            {
                if ( nodesvisible( var_1, self.locations_to_investigate[var_3].node, 1 ) )
                {
                    var_4 = common_scripts\utility::within_fov( self.origin, self.angles, self.locations_to_investigate[var_3].origin, var_2 );
                    var_5 = !var_4 || self.locations_to_investigate[var_3].frames_visible < 17;

                    if ( var_5 && distancesquared( self.origin, self.locations_to_investigate[var_3].origin ) < var_0 )
                    {
                        var_4 = 1;
                        self.locations_to_investigate[var_3].frames_visible = 18;
                    }

                    if ( var_4 )
                    {
                        self.locations_to_investigate[var_3].frames_visible++;

                        if ( self.locations_to_investigate[var_3].frames_visible >= 18 )
                        {
                            self.locations_to_investigate[var_3] = self.locations_to_investigate[self.locations_to_investigate.size - 1];
                            self.locations_to_investigate[self.locations_to_investigate.size - 1] = undefined;
                            var_3--;
                        }
                    }
                }
            }
        }

        wait 0.05;
    }
}

protect_watch_allies()
{
    self notify( "protect_watch_allies" );
    self endon( "protect_watch_allies" );
    var_0 = [];
    var_1 = 1050;
    var_2 = var_1 * var_1;
    var_3 = 900;

    if ( isdefined( level.protect_radius ) )
        var_3 = level.protect_radius;

    for (;;)
    {
        var_4 = gettime();
        var_5 = bot_get_teammates_in_radius( self.bot_defending_center, var_3 );

        foreach ( var_7 in var_5 )
        {
            var_8 = var_7.entity_number;

            if ( !isdefined( var_8 ) )
                var_8 = var_7 getentitynumber();

            if ( !isdefined( var_0[var_8] ) )
                var_0[var_8] = var_4 - 1;

            if ( !isdefined( var_7.last_investigation_time ) )
                var_7.last_investigation_time = var_4 - 10001;

            if ( var_7.health == 0 && isdefined( var_7.deathtime ) && var_4 - var_7.deathtime < 5000 )
            {
                if ( var_4 - var_7.last_investigation_time > 10000 && var_4 > var_0[var_8] )
                {
                    if ( isdefined( var_7.lastattacker ) && isdefined( var_7.lastattacker.team ) && var_7.lastattacker.team == common_scripts\utility::get_enemy_team( self.team ) )
                    {
                        if ( distancesquared( var_7.origin, self.origin ) < var_2 )
                        {
                            self botgetimperfectenemyinfo( var_7.lastattacker, var_7.origin );
                            var_9 = getclosestnodeinsight( var_7.origin );

                            if ( isdefined( var_9 ) )
                            {
                                self.defense_investigate_specific_point = var_9.origin;
                                self notify( "defend_force_node_recalculation" );
                            }

                            var_7.last_investigation_time = var_4;
                        }

                        var_0[var_8] = var_4 + 10000;
                    }
                }
            }
        }

        wait( ( randomint( 5 ) + 1 ) * 0.05 );
    }
}

defense_get_initial_entrances()
{
    if ( isdefined( self.defense_override_entrances ) )
        return self.defense_override_entrances;
    else if ( maps\mp\bots\_bots_util::bot_is_capturing() )
        return bot_defend_get_precalc_entrances_for_current_area( self.cur_defend_stance );
    else if ( maps\mp\bots\_bots_util::bot_is_protecting() || maps\mp\bots\_bots_util::bot_is_bodyguarding() )
    {
        var_0 = findentrances( self.origin );
        return var_0;
    }
}

defense_watch_entrances_at_goal()
{
    self notify( "defense_watch_entrances_at_goal" );
    self endon( "defense_watch_entrances_at_goal" );
    self endon( "new_defend_goal" );
    self endon( "script_goal_changed" );
    var_0 = self getnearestnode();
    var_1 = undefined;

    if ( maps\mp\bots\_bots_util::bot_is_capturing() )
    {
        var_2 = defense_get_initial_entrances();
        var_1 = [];

        if ( isdefined( var_0 ) )
        {
            foreach ( var_4 in var_2 )
            {
                if ( nodesvisible( var_0, var_4, 1 ) )
                    var_1 = common_scripts\utility::array_add( var_1, var_4 );
            }
        }
    }
    else if ( maps\mp\bots\_bots_util::bot_is_protecting() || maps\mp\bots\_bots_util::bot_is_bodyguarding() )
    {
        var_1 = defense_get_initial_entrances();

        if ( isdefined( var_0 ) && !issubstr( self getcurrentweapon(), "riotshield" ) )
        {
            if ( nodesvisible( var_0, self.node_closest_to_defend_center, 1 ) )
                var_1 = common_scripts\utility::array_add( var_1, self.node_closest_to_defend_center );
        }
    }

    if ( isdefined( var_1 ) )
    {
        childthread maps\mp\bots\_bots_util::bot_watch_nodes( var_1 );

        if ( maps\mp\bots\_bots_util::bot_is_bodyguarding() )
            childthread bot_monitor_watch_entrances_bodyguard();
        else
            childthread bot_monitor_watch_entrances_at_goal();
    }
}

bot_monitor_watch_entrances_at_goal()
{
    self notify( "bot_monitor_watch_entrances_at_goal" );
    self endon( "bot_monitor_watch_entrances_at_goal" );
    self notify( "bot_monitor_watch_entrances" );
    self endon( "bot_monitor_watch_entrances" );

    while ( !isdefined( self.watch_nodes ) )
        wait 0.05;

    var_0 = level.bot_funcs["get_watch_node_chance"];

    for (;;)
    {
        foreach ( var_2 in self.watch_nodes )
        {
            if ( var_2 == self.node_closest_to_defend_center )
            {
                var_2.watch_node_chance[self.entity_number] = 0.8;
                continue;
            }

            var_2.watch_node_chance[self.entity_number] = 1.0;
        }

        var_4 = isdefined( var_0 );

        if ( !var_4 )
            prioritize_watch_nodes_toward_enemies( 0.5 );

        foreach ( var_2 in self.watch_nodes )
        {
            if ( var_4 )
            {
                var_6 = self [[ var_0 ]]( var_2 );
                var_2.watch_node_chance[self.entity_number] = var_2.watch_node_chance[self.entity_number] * var_6;
            }

            if ( entrance_watched_by_ally( var_2 ) )
                var_2.watch_node_chance[self.entity_number] = var_2.watch_node_chance[self.entity_number] * 0.5;
        }

        wait( randomfloatrange( 0.5, 0.75 ) );
    }
}

bot_monitor_watch_entrances_bodyguard()
{
    self notify( "bot_monitor_watch_entrances_bodyguard" );
    self endon( "bot_monitor_watch_entrances_bodyguard" );
    self notify( "bot_monitor_watch_entrances" );
    self endon( "bot_monitor_watch_entrances" );

    while ( !isdefined( self.watch_nodes ) )
        wait 0.05;

    for (;;)
    {
        var_0 = anglestoforward( self.bot_defend_player_guarding.angles ) * ( 1, 1, 0 );
        var_0 = vectornormalize( var_0 );

        foreach ( var_2 in self.watch_nodes )
        {
            var_2.watch_node_chance[self.entity_number] = 1.0;
            var_3 = var_2.origin - self.bot_defend_player_guarding.origin;
            var_3 = vectornormalize( var_3 );
            var_4 = vectordot( var_0, var_3 );

            if ( var_4 > 0.6 )
                var_2.watch_node_chance[self.entity_number] = var_2.watch_node_chance[self.entity_number] * 0.33;
            else if ( var_4 > 0 )
                var_2.watch_node_chance[self.entity_number] = var_2.watch_node_chance[self.entity_number] * 0.66;

            if ( !entrance_to_enemy_zone( var_2 ) )
                var_2.watch_node_chance[self.entity_number] = var_2.watch_node_chance[self.entity_number] * 0.5;
        }

        wait( randomfloatrange( 0.4, 0.6 ) );
    }
}

entrance_to_enemy_zone( var_0 )
{
    var_1 = getnodezone( var_0 );
    var_2 = vectornormalize( var_0.origin - self.origin );

    for ( var_3 = 0; var_3 < level.zonecount; var_3++ )
    {
        if ( botzonegetcount( var_3, self.team, "enemy_predict" ) > 0 )
        {
            if ( isdefined( var_1 ) && var_3 == var_1 )
                return 1;
            else
            {
                var_4 = vectornormalize( getzoneorigin( var_3 ) - self.origin );
                var_5 = vectordot( var_2, var_4 );

                if ( var_5 > 0.2 )
                    return 1;
            }
        }
    }

    return 0;
}

prioritize_watch_nodes_toward_enemies( var_0 )
{
    if ( self.watch_nodes.size <= 0 )
        return;

    var_1 = self.watch_nodes;

    for ( var_2 = 0; var_2 < level.zonecount; var_2++ )
    {
        if ( botzonegetcount( var_2, self.team, "enemy_predict" ) <= 0 )
            continue;

        if ( var_1.size == 0 )
            break;

        var_3 = vectornormalize( getzoneorigin( var_2 ) - self.origin );

        for ( var_4 = 0; var_4 < var_1.size; var_4++ )
        {
            var_5 = getnodezone( var_1[var_4] );
            var_6 = 0;

            if ( isdefined( var_5 ) && var_2 == var_5 )
                var_6 = 1;
            else
            {
                var_7 = vectornormalize( var_1[var_4].origin - self.origin );
                var_8 = vectordot( var_7, var_3 );

                if ( var_8 > 0.2 )
                    var_6 = 1;
            }

            if ( var_6 )
            {
                var_1[var_4].watch_node_chance[self.entity_number] = var_1[var_4].watch_node_chance[self.entity_number] * var_0;
                var_1[var_4] = var_1[var_1.size - 1];
                var_1[var_1.size - 1] = undefined;
                var_4--;
            }
        }
    }
}

entrance_watched_by_ally( var_0 )
{
    var_1 = bot_get_teammates_currently_defending_point( self.bot_defending_center );

    foreach ( var_3 in var_1 )
    {
        if ( entrance_watched_by_player( var_3, var_0 ) )
            return 1;
    }

    return 0;
}

entrance_watched_by_player( var_0, var_1 )
{
    var_2 = anglestoforward( var_0.angles );
    var_3 = vectornormalize( var_1.origin - var_0.origin );
    var_4 = vectordot( var_2, var_3 );

    if ( var_4 > 0.6 )
        return 1;

    return 0;
}

bot_get_teammates_currently_defending_point( var_0, var_1 )
{
    if ( !isdefined( var_1 ) )
    {
        if ( isdefined( level.protect_radius ) )
            var_1 = level.protect_radius;
        else
            var_1 = 900;
    }

    var_2 = [];
    var_3 = bot_get_teammates_in_radius( var_0, var_1 );

    foreach ( var_5 in var_3 )
    {
        if ( !isai( var_5 ) || var_5 maps\mp\bots\_bots_util::bot_is_defending_point( var_0 ) )
            var_2 = common_scripts\utility::array_add( var_2, var_5 );
    }

    return var_2;
}

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

    for ( var_4 = 0; var_4 < level.participants.size; var_4++ )
    {
        var_5 = level.participants[var_4];

        if ( var_5 != self && isdefined( var_5.team ) && var_5.team == self.team && maps\mp\_utility::isteamparticipant( var_5 ) )
        {
            if ( distancesquared( var_0, var_5.origin ) < var_2 )
                var_3 = common_scripts\utility::array_add( var_3, var_5 );
        }
    }

    return var_3;
}

defense_death_monitor()
{
    level endon( "game_ended" );
    self endon( "started_bot_defend_think" );
    self endon( "defend_stop" );
    self endon( "disconnect" );
    self waittill( "death" );

    if ( isdefined( self ) )
        thread bot_defend_stop();
}

bot_defend_stop()
{
    self notify( "defend_stop" );
    self.bot_defending = undefined;
    self.bot_defending_center = undefined;
    self.bot_defending_radius = undefined;
    self.bot_defending_nodes = undefined;
    self.bot_defending_type = undefined;
    self.bot_defending_trigger = undefined;
    self.bot_defending_override_origin_node = undefined;
    self.bot_defend_player_guarding = undefined;
    self.defense_score_flags = undefined;
    self.node_closest_to_defend_center = undefined;
    self.defense_investigate_specific_point = undefined;
    self.defense_force_next_node_goal = undefined;
    self.prev_defend_node = undefined;
    self.cur_defend_node = undefined;
    self.cur_defend_angle_override = undefined;
    self.cur_defend_point_override = undefined;
    self.defend_entrance_index = undefined;
    self.defense_override_entrances = undefined;
    self botclearscriptgoal();
    self botsetstance( "none" );
}

defend_get_ally_bots_at_zone_for_stance( var_0 )
{
    var_1 = [];

    foreach ( var_3 in level.participants )
    {
        if ( !isdefined( var_3.team ) )
            continue;

        if ( var_3.team == self.team && var_3 != self && isai( var_3 ) && var_3 maps\mp\bots\_bots_util::bot_is_defending() && var_3.cur_defend_stance == var_0 )
        {
            if ( var_3.bot_defending_type == self.bot_defending_type && maps\mp\bots\_bots_util::bot_is_defending_point( var_3.bot_defending_center ) )
                var_1 = common_scripts\utility::array_add( var_1, var_3 );
        }
    }

    return var_1;
}

monitor_defend_player()
{
    var_0 = 0;
    var_1 = 175;
    var_2 = self.bot_defend_player_guarding.origin;
    var_3 = 0;
    var_4 = 0;

    for (;;)
    {
        if ( !isdefined( self.bot_defend_player_guarding ) )
            thread bot_defend_stop();

        if ( self.bot_defend_player_guarding islinked() )
        {
            wait 0.05;
            continue;
        }

        self.bot_defending_center = self.bot_defend_player_guarding.origin;
        self.node_closest_to_defend_center = self.bot_defend_player_guarding getnearestnode();

        if ( !isdefined( self.node_closest_to_defend_center ) )
            self.node_closest_to_defend_center = self getnearestnode();

        if ( self botgetscriptgoaltype() != "none" )
        {
            var_5 = self botgetscriptgoal();
            var_6 = self.bot_defend_player_guarding getvelocity();
            var_7 = lengthsquared( var_6 );

            if ( var_7 > 100 )
            {
                var_0 = 0;

                if ( distancesquared( var_2, self.bot_defend_player_guarding.origin ) > var_1 * var_1 )
                {
                    var_2 = self.bot_defend_player_guarding.origin;
                    var_4 = 1;
                    var_8 = vectornormalize( var_5 - self.bot_defend_player_guarding.origin );
                    var_9 = vectornormalize( var_6 );

                    if ( vectordot( var_8, var_9 ) < 0.1 )
                    {
                        self notify( "defend_force_node_recalculation" );
                        wait 0.25;
                    }
                }
            }
            else
            {
                var_0 = var_0 + 0.05;

                if ( var_3 > 100 && var_4 )
                {
                    var_2 = self.bot_defend_player_guarding.origin;
                    var_4 = 0;
                }

                if ( var_0 > 0.5 )
                {
                    var_10 = distancesquared( var_5, self.bot_defending_center );

                    if ( var_10 > self.bot_defending_radius * self.bot_defending_radius )
                    {
                        self notify( "defend_force_node_recalculation" );
                        wait 0.25;
                    }
                }
            }

            var_3 = var_7;

            if ( abs( self.bot_defend_player_guarding.origin[2] - var_5[2] ) >= 50 )
            {
                self notify( "defend_force_node_recalculation" );
                wait 0.25;
            }
        }

        wait 0.05;
    }
}

find_defend_node_capture()
{
    var_0 = bot_defend_get_random_entrance_point_for_current_area();
    var_1 = maps\mp\bots\_bots_util::bot_find_node_to_capture_point( maps\mp\bots\_bots_util::defend_valid_center(), self.bot_defending_radius, var_0 );

    if ( isdefined( var_1 ) )
    {
        if ( isdefined( var_0 ) )
        {
            var_2 = vectornormalize( var_0 - var_1.origin );
            self.cur_defend_angle_override = vectortoangles( var_2 );
        }
        else
        {
            var_3 = vectornormalize( var_1.origin - maps\mp\bots\_bots_util::defend_valid_center() );
            self.cur_defend_angle_override = vectortoangles( var_3 );
        }

        self.cur_defend_node = var_1;
    }
    else if ( isdefined( var_0 ) )
        bot_handle_no_valid_defense_node( var_0, undefined );
    else
        bot_handle_no_valid_defense_node( undefined, maps\mp\bots\_bots_util::defend_valid_center() );
}

find_defend_node_capture_zone()
{
    var_0 = bot_defend_get_random_entrance_point_for_current_area();
    var_1 = maps\mp\bots\_bots_util::bot_find_node_to_capture_zone( self.bot_defending_nodes, var_0 );

    if ( isdefined( var_1 ) )
    {
        if ( isdefined( var_0 ) )
        {
            var_2 = vectornormalize( var_0 - var_1.origin );
            self.cur_defend_angle_override = vectortoangles( var_2 );
        }
        else
        {
            var_3 = vectornormalize( var_1.origin - maps\mp\bots\_bots_util::defend_valid_center() );
            self.cur_defend_angle_override = vectortoangles( var_3 );
        }

        self.cur_defend_node = var_1;
    }
    else if ( isdefined( var_0 ) )
        bot_handle_no_valid_defense_node( var_0, undefined );
    else
        bot_handle_no_valid_defense_node( undefined, maps\mp\bots\_bots_util::defend_valid_center() );
}

find_defend_node_protect()
{
    var_0 = maps\mp\bots\_bots_util::bot_find_node_that_protects_point( maps\mp\bots\_bots_util::defend_valid_center(), self.bot_defending_radius );

    if ( isdefined( var_0 ) )
    {
        var_1 = vectornormalize( maps\mp\bots\_bots_util::defend_valid_center() - var_0.origin );
        self.cur_defend_angle_override = vectortoangles( var_1 );
        self.cur_defend_node = var_0;
    }
    else
        bot_handle_no_valid_defense_node( maps\mp\bots\_bots_util::defend_valid_center(), undefined );
}

find_defend_node_bodyguard()
{
    var_0 = maps\mp\bots\_bots_util::bot_find_node_to_guard_player( maps\mp\bots\_bots_util::defend_valid_center(), self.bot_defending_radius );

    if ( isdefined( var_0 ) )
        self.cur_defend_node = var_0;
    else
    {
        var_1 = self getnearestnode();

        if ( isdefined( var_1 ) )
            self.cur_defend_node = var_1;
        else
            self.cur_defend_point_override = self.origin;
    }
}

find_defend_node_patrol()
{
    var_0 = undefined;
    var_1 = getnodesinradius( maps\mp\bots\_bots_util::defend_valid_center(), self.bot_defending_radius, 0 );

    if ( isdefined( var_1 ) && var_1.size > 0 )
        var_0 = self botnodepick( var_1, 1 + var_1.size * 0.5, "node_traffic" );

    if ( isdefined( var_0 ) )
        self.cur_defend_node = var_0;
    else
        bot_handle_no_valid_defense_node( undefined, maps\mp\bots\_bots_util::defend_valid_center() );
}

bot_handle_no_valid_defense_node( var_0, var_1 )
{
    if ( self.bot_defending_type == "capture_zone" )
        self.cur_defend_point_override = maps\mp\bots\_bots_util::bot_pick_random_point_from_set( maps\mp\bots\_bots_util::defend_valid_center(), self.bot_defending_nodes, ::bot_can_use_point_in_defend );
    else
        self.cur_defend_point_override = maps\mp\bots\_bots_util::bot_pick_random_point_in_radius( maps\mp\bots\_bots_util::defend_valid_center(), self.bot_defending_radius, ::bot_can_use_point_in_defend, 0.15, 0.9 );

    if ( isdefined( var_0 ) )
    {
        var_2 = vectornormalize( var_0 - self.cur_defend_point_override );
        self.cur_defend_angle_override = vectortoangles( var_2 );
    }
    else if ( isdefined( var_1 ) )
    {
        var_2 = vectornormalize( self.cur_defend_point_override - var_1 );
        self.cur_defend_angle_override = vectortoangles( var_2 );
    }
}

bot_can_use_point_in_defend( var_0 )
{
    if ( bot_check_team_is_using_position( var_0, 1, 1, 1 ) )
        return 0;

    return 1;
}

bot_check_team_is_using_position( var_0, var_1, var_2, var_3 )
{
    for ( var_4 = 0; var_4 < level.participants.size; var_4++ )
    {
        var_5 = level.participants[var_4];

        if ( var_5.team == self.team && var_5 != self )
        {
            if ( isai( var_5 ) )
            {
                if ( var_2 )
                {
                    if ( distancesquared( var_0, var_5.origin ) < 441 )
                        return 1;
                }

                if ( var_3 && var_5 bothasscriptgoal() )
                {
                    var_6 = var_5 botgetscriptgoal();

                    if ( distancesquared( var_0, var_6 ) < 441 )
                        return 1;
                }

                continue;
            }

            if ( var_1 )
            {
                if ( distancesquared( var_0, var_5.origin ) < 441 )
                    return 1;
            }
        }
    }

    return 0;
}

bot_capture_zone_get_furthest_distance()
{
    var_0 = 0;

    if ( isdefined( self.bot_defending_nodes ) )
    {
        foreach ( var_2 in self.bot_defending_nodes )
        {
            var_3 = distance( self.bot_defending_center, var_2.origin );
            var_0 = max( var_3, var_0 );
        }
    }

    return var_0;
}

bot_think_tactical_goals()
{
    self notify( "bot_think_tactical_goals" );
    self endon( "bot_think_tactical_goals" );
    self endon( "death" );
    self endon( "disconnect" );
    level endon( "game_ended" );
    self.tactical_goals = [];

    for (;;)
    {
        if ( self.tactical_goals.size > 0 && !maps\mp\bots\_bots_util::bot_is_remote_or_linked() )
        {
            var_0 = self.tactical_goals[0];

            if ( !isdefined( var_0.abort ) )
            {
                self notify( "start_tactical_goal" );

                if ( isdefined( var_0.start_thread ) )
                    self [[ var_0.start_thread ]]( var_0 );

                childthread watch_goal_aborted( var_0 );
                var_1 = "tactical";

                if ( isdefined( var_0.goal_type ) )
                    var_1 = var_0.goal_type;

                self botsetscriptgoal( var_0.goal_position, var_0.goal_radius, var_1, var_0.goal_yaw, var_0.objective_radius );
                var_2 = maps\mp\bots\_bots_util::bot_waittill_goal_or_fail( undefined, "stop_tactical_goal" );
                self notify( "stop_goal_aborted_watch" );

                if ( var_2 == "goal" )
                {
                    if ( isdefined( var_0.action_thread ) )
                        self [[ var_0.action_thread ]]( var_0 );
                }

                if ( var_2 != "script_goal_changed" )
                    self botclearscriptgoal();

                if ( isdefined( var_0.end_thread ) )
                    self [[ var_0.end_thread ]]( var_0 );
            }

            self.tactical_goals = common_scripts\utility::array_remove( self.tactical_goals, var_0 );
        }

        wait 0.05;
    }
}

watch_goal_aborted( var_0 )
{
    self endon( "stop_tactical_goal" );
    self endon( "stop_goal_aborted_watch" );
    wait 0.05;

    for (;;)
    {
        if ( isdefined( var_0.abort ) || isdefined( var_0.should_abort ) && self [[ var_0.should_abort ]]( var_0 ) )
            self notify( "stop_tactical_goal" );

        wait 0.05;
    }
}

bot_new_tactical_goal( var_0, var_1, var_2, var_3 )
{
    var_4 = spawnstruct();
    var_4.type = var_0;
    var_4.goal_position = var_1;

    if ( isdefined( self.only_allowable_tactical_goals ) )
    {
        if ( !common_scripts\utility::array_contains( self.only_allowable_tactical_goals, var_0 ) )
            return;
    }

    var_4.priority = var_2;
    var_4.object = var_3.object;
    var_4.goal_type = var_3.script_goal_type;
    var_4.goal_yaw = var_3.script_goal_yaw;
    var_4.goal_radius = 0;

    if ( isdefined( var_3.script_goal_radius ) )
        var_4.goal_radius = var_3.script_goal_radius;

    var_4.start_thread = var_3.start_thread;
    var_4.end_thread = var_3.end_thread;
    var_4.should_abort = var_3.should_abort;
    var_4.action_thread = var_3.action_thread;
    var_4.objective_radius = var_3.objective_radius;

    for ( var_5 = 0; var_5 < self.tactical_goals.size; var_5++ )
    {
        if ( var_4.priority > self.tactical_goals[var_5].priority )
            break;
    }

    for ( var_6 = self.tactical_goals.size - 1; var_6 >= var_5; var_6-- )
        self.tactical_goals[var_6 + 1] = self.tactical_goals[var_6];

    self.tactical_goals[var_5] = var_4;
}

bot_has_tactical_goal( var_0, var_1 )
{
    if ( !isdefined( self.tactical_goals ) )
        return 0;

    if ( isdefined( var_0 ) )
    {
        foreach ( var_3 in self.tactical_goals )
        {
            if ( var_3.type == var_0 )
            {
                if ( isdefined( var_1 ) && isdefined( var_3.object ) )
                    return var_3.object == var_1;
                else
                    return 1;
            }
        }

        return 0;
    }
    else
        return self.tactical_goals.size > 0;
}

bot_abort_tactical_goal( var_0, var_1 )
{
    if ( !isdefined( self.tactical_goals ) )
        return;

    foreach ( var_3 in self.tactical_goals )
    {
        if ( var_3.type == var_0 )
        {
            if ( isdefined( var_1 ) )
            {
                if ( isdefined( var_3.object ) && var_3.object == var_1 )
                    var_3.abort = 1;

                continue;
            }

            var_3.abort = 1;
        }
    }
}

bot_disable_tactical_goals()
{
    self.only_allowable_tactical_goals[0] = "map_interactive_object";

    foreach ( var_1 in self.tactical_goals )
    {
        if ( var_1.type != "map_interactive_object" )
            var_1.abort = 1;
    }
}

bot_enable_tactical_goals()
{
    self.only_allowable_tactical_goals = undefined;
}

bot_melee_tactical_insertion_check()
{
    var_0 = gettime();

    if ( !isdefined( self.last_melee_ti_check ) || var_0 - self.last_melee_ti_check > 1000 )
    {
        self.last_melee_ti_check = var_0;
        var_1 = bot_get_ambush_trap_item( "tacticalinsertion" );

        if ( !isdefined( var_1 ) )
            return 0;

        if ( isdefined( self.enemy ) && self botcanseeentity( self.enemy ) )
            return 0;

        var_2 = getzonenearest( self.origin );

        if ( !isdefined( var_2 ) )
            return 0;

        var_3 = botzonenearestcount( var_2, self.team, 1, "enemy_predict", ">", 0 );

        if ( !isdefined( var_3 ) )
            return 0;

        var_4 = getnodesinradius( self.origin, 500, 0 );

        if ( var_4.size <= 0 )
            return 0;

        var_5 = self botnodepick( var_4, var_4.size * 0.15, "node_hide" );

        if ( !isdefined( var_5 ) )
            return 0;

        return bot_set_ambush_trap( var_1, undefined, undefined, undefined, var_5 );
    }

    return 0;
}
