Raised This Month: $12 Target: $400
 3% 

[L4D & L4D2] Target Override (2.29) [25-Mar-2024]


Post New Thread Reply   
 
Thread Tools Display Modes
Author
Silvers
SourceMod Plugin Approver
Join Date: Aug 2010
Location: SpaceX
Plugin ID:
6996
Plugin Version:
2.29
Plugin Category:
Gameplay
Plugin Game:
Left 4 Dead
Plugin Dependencies:
Servers with this Plugin:
69 
Plugin Description:
Overrides Special Infected targeting of Survivors
Old 03-23-2020 , 10:20   [L4D & L4D2] Target Override (2.29) [25-Mar-2024]
Reply With Quote #1

About:
  • This overrides the ChooseVictim function for each Special Infected according to your preferences.
  • Prioritize who to attack first, vomited survivors, vomited specials, incapped, pinned etc.
  • Can prevent specific Special Infected from targeting incapacitated survivors.
  • Can restore L4D1 game behaviour in L4D2 so the Hunter and Tank can attack incapacitated and vomited players.
  • Forward and natives provided to extend the plugins functionality to 3rd party plugins (version 2.21 and newer).
  • Benchmarking shows the function/plugin is highly optimized and extremely quick (0.058 ms think time).


Thanks:
  • Sev - For the idea and request.
  • BlackSabbarh - Also for the request.
  • Lux - For fixing God Frames detour which is similar to this, and would not be possible without.
  • hoanganh81097 - For testing version 2.0.
  • morzlee - Lots of help testing version 2.21.


Example Data Config:

Saved to l4d_target_override.cfg in your servers \addons\sourcemod\data\ folder.

PHP Code:
// Rearrange order to your preference for each Special Infected class.
// You can set any number of "order" values, all are not required to be entered.
// When no order value is matched, the Special Infected will default to using the games internal targeting logic.
//
// Order:     Prioritize who to attack first:
//            1    = Normal Survivor.
//            2    = Vomited Survivor.
//            3    = Incapacitated Survivor.
//            4    = Survivor Pinned (by Smoker, Hunter, Charger, Jockey).
//            5    = Ledge hanging Survivor.
//            6    = Vomited Special Infected (Tanks will not attack other Special Infected).
//            7    = Last Attacker. Set after most/all other order priorities since there will always be a last attacker.
//            8    = Lowest Health Survivor.
//            9    = Highest Health Survivor.
//            10   = Survivor being Pummelled by Charger.
//            11   = Survivor mounted on a Mini Gun.
//            12   = Survivor reviving someone.
//            13   = Survivor furthest ahead (requires Left4DHooks plugin).
//            14   = Survivor self healing when health is below the "survivor_limp_health" cvar value.
//            15   = Survivor furthest behind in flow distance (requires Left4DHooks plugin).
//            16   = Survivor with their Flashlight on.
//            17   = Survivor running (not crouched or walking).
//            18   = Survivor who dealt the highest damage.
//            19   = Survivor inside the saferom (requires Left4DHooks plugin).
//            20   = Survivor being attacked by a Witch (requires Actions extension: https://forums.alliedmods.net/showthread.php?t=336374).
//            21   = Survivor whose health is below the "survivor_limp_health" cvar value.
//
// pinned:    Ignore attacking target when they're pinned by: 1=Smoker. 2=Hunter. 4=Jockey. 8=Charger. 15=All. Add numbers together.
// incap:     0=Ignore incapacitated players. 1=Allow attacking incapacitated players. 2=Only attack incapacitated players when they are vomited. 3=Only attack incapacitated when everyone is incapacitated.
// minigun:   0=Ignore Survivors on a minigun unless using order "11" to target them. 1=Survivors on a minigun can be targeted if they match the selected order priority.
// voms:      0=Off. 1=Allow attacking vomited Special Infected (order number 6).
// voms2:     0=Ignore attacking if target is currently covered in bile. 1=Allow attacking vomited incapacitated Survivors.
// range:     0.0=No limit. The maximum range to target someone, otherwise the plugin defaults to the games internal mechanics for targeting someone.
// dist:      How close the Special Infected must be to a target to prevent changing target.
// wait:      How many seconds to target someone before being allowed to switch to another target. They will switch before if the player is no longer valid or allowed to be targeted.
// last:      0=Off. 1=Allow targeting the last attacker using order value 7.
// time:      When using the "last" order "7", how many seconds since the last attacker hurt the Special Infected before being able to change target.
// safe:      0=Allow attacking players in the saferoom. 1=Don't attack players in the saferoom.
// targeted:  0=Ignored. Total number of Special Infected allowed to attack someone at the same time.

"target_patch"
{
    
"tank"
    
{
        
"order"      "2,3,18" // Preference: Vomited Survivors, then Incapped, then Survivor who dealt the highest damage.
        
"pinned"     "15"
        "incap"      "1"
        "minigun"    "1"
        "voms"       "1"
        "voms2"      "1"
        "range"      "0.0"
        "dist"       "250.0"
        "wait"       "2.0"
        "last"       "1"
        "time"       "2.0"
        "safe"       "1"
        "targeted"   "0"
    
}



Forward and Natives:
See the include/l4d_target_override.inc include file for details.

Spoiler


Admin Commands: (requires "z" flag)

PHP Code:
sm_to_reload   // Reloads the data config
sm_to_stats    // Displays benchmarking stats (min/avg/max). (Requires plugin recompile with DEBUG_BENCHMARK set to 1 or 2). 


Cvars:

Saved to l4d_target_override.cfg in your servers \cfg\sourcemod\ folder.

PHP Code:
// 0=Plugin off, 1=Plugin on.
l4d_target_override_allow "1"

// Turn on the plugin in these game modes, separate by commas (no spaces). (Empty = all).
l4d_target_override_modes ""

// Turn off the plugin in these game modes, separate by commas (no spaces). (Empty = none).
l4d_target_override_modes_off ""

// Turn on the plugin in these game modes. 0=All, 1=Coop, 2=Survival, 4=Versus, 8=Scavenge. Add numbers together.
l4d_target_override_modes_tog "0"

// 0=Off. 1=On. Forward used for 3rd party plugins when someone is being targeted, triggers every frame or so.
l4d_target_override_forward "0"

// L4D1: Override these Specials target function: 1=Smoker, 2=Boomer, 4=Hunter, 8=Tank. 15=All. Add numbers together.
l4d_target_override_specials "15"

// L4D2: Override these Specials target function: 1=Smoker, 2=Boomer, 4=Hunter, 8=Spitter, 16=Jockey, 32=Charger, 64=Tank. 127=All. Add numbers together.
l4d_target_override_specials "127"

// Which Survivor teams should be targeted. 2=Default Survivors. 4=Holding and Passing bots. 6=Both.
l4d_target_override_team "2"

// How should the plugin search through Survivors. 1=Nearest visible (defaults to games method on fail). 2=All Survivors from the nearest. 3=Nearest by flow distance (requires Left4DHooks plugin, defaults to type 2).
l4d_target_override_type "1"

// Target Override plugin version.
l4d_target_override_version 


Changes:
Code:
2.29 (25-Mar-2024)
    - Plugin now follows the "nb_blind" cvar and prevents attacking if set to "1".
    - Added option "21" to target a Survivor whose health is below "survivor_limp_health" cvar value. Requested by "jimmycm123".

2.28 (20-Jan-2024)
    - Added option "minigun" to the data config to choose whether to ignore players on a minigun or treat them as normal players. Requested by "Morning".

2.27 (05-Sep-2023)
    - Added option "20" to target a Survivor who is being chased by a Witch. Requested by "Xenorvya".
    - This requires the Actions extension. Thanks to "ForgeTest" for providing the method and code.

2.26 (27-Jul-2023)
    - Added option "19" to target a Survivor who is inside the saferoom. Requested by "SpannerV2".

2.25 (19-Jun-2023)
    - Added option "18" to target the Survivor who caused the highest damage.
    - Fixed issues with the "time" option and resetting the last attacker.
    - Thanks to "Kanashimi" and "kooper990" for helping test.

2.24 (24-Nov-2022)
    - Fixed plugin not accounting for idle or disconnected players being replaced by bots. Thanks to "HarryPotter" for help.

2.23 (28-Oct-2022)
    - Fixed Special Infected not being able to target other SI. Tank vs SI is still not capable. Thanks to "Tonblader" for reporting.
    - Fixed the "voms" and "voms2" options not working correctly.
    - Plugin now prevents the Tank attempting to attack vomited Special Infected, since the Tank will just stand there.

2.22 (20-Oct-2022)
    - Fixed various issues with the "pinned" option breaking targeting. Thanks to "morzlee" for reporting and lots of help testing.

2.21 (08-Oct-2022)
    - Added option "15" to target the Survivor furthest behind in flow distance. Requested by "gabuch2"
    - Added option "16" to target a Survivor with their flashlight on. Requested by "gabuch2"
    - Added option "17" to target a Survivor who is running (not crouched or walking). Requested by "gabuch2"

    - Added new include file for 3rd party plugins to use the forward and natives.
    - Added natives "L4D_TargetOverride_GetOption" and "L4D_TargetOverride_SetOption" for 3rd party plugins to get or set some option values. Requested by "morzlee".
    - Added native "L4D_TargetOverride_GetValue" for 3rd party plugins to get or set client values. Requested by "morzlee".
    - Added forward "L4D_OnTargetOverride" for 3rd party plugins to trigger every frame or whenever someone is being targeted. Requested by "morzlee".
    - Added cvar "l4d_target_override_forward" to enable or disabled the forward. Disabled by default to save CPU cycles.

    - Changed "targeted" option to use the set value as a maximum number of Special Infected allowed to target someone. Requested by "morzlee".
    - Fixed option "14" not working in L4D1. Thanks to "axelnieves2012" for fixing.
    - Increased string buffer and maximum orders in case all options are used in a single "order" data key value string.

2.20 (03-Oct-2022)
    - Added option "14" to target someone healing whose health is below "survivor_limp_health" cvar value. Added by "axelnieves2012".
    - Fixed order "12" and "13" being switched. Thanks to "axelnieves2012" for reporting.

2.19 (22-Sep-2022)
    - Added option "13" to "order" to target the Survivor furthest ahead in flow distance. Requested by "axelnieves2012".
    - Added option "targeted" to the data config to prevent targeting someone that's already targeted by another Special Infected. Requested by "axelnieves2012".

2.18 (10-Aug-2022)
    - Added cvar "l4d_target_override_team" to specify which Survivor teams can be targeted.
    - Added option "dist" to the data config to set how close the Special Infected must be to a target to prevent changing target.
    - Added option "time" to the data config to set the duration of targeting the last attacker before being allowed to change target.
    - Fixed the wait time and last attacker interfering with selecting a new target. Thanks to "moschinovac" for reporting.

2.17 (30-Jul-2022)
    - Added option "12" to "order" to target the Survivor furthest ahead in flow distance. Requested by "yzybb".

2.16 (09-Sep-2021)
    - Fixed not reading the entire data configs "order" value when the string was longer than 15 characters.

2.15a (09-Jul-2021)
    - L4D2: Fixed GameData file from the "2.2.2.0" game update.

2.15 (06-Jul-2021)
    - Limited the patch from last update to L4D2 only.

2.14 (03-Jul-2021)
    - L4D2: Fixed plugin not ignoring players using a minigun. Thanks to "ProjectSky" for reporting.
    - L4D2: GameData .txt file updated.

2.13 (04-Jun-2021)
    - Fixed the plugin not working without the optional "Left 4 DHooks Direct" plugin being installed. Thanks to "spaghettipastaman" for reporting.

2.12 (20-Apr-2021)
    - Changed cvar "l4d_target_override_type" adding type "3" to order range by nav flow distance.
    - This requires the "Left4DHooks" plugin and used only when the plugin is detected. Maybe unreliable due to unreachable flow areas.

    - Fixed "Highest Health" and "Highest Health" orders not validating the clients correctly, Thanks to "larrybrains" for reporting.
    - Fixed "Highest Health" and "Highest Health" config orders description being flipped.

2.11 (12-Apr-2021)
    - Added priority order option "11" to target players using a Mini Gun.

2.10 (15-Feb-2021)
    - Added option "safe" to control if Survivors can be attacked when in a saferoom. Requested by "axelnieves2012".

2.9 (18-Sep-2020)
    - Added option "range" to set how near a Survivor must be to target. Defaults to 0.0 for no range check.
    - Added option "voms2" to control if Survivors can be attacked when incapacitated and vomited.
    - Data config "data/l4d_target_override.cfg" updated to reflect changes.
    - Thanks to "XDglory" for requesting and testing.

2.8 (17-May-2020)
    - Fixed "normal" order test affecting ledge hanging players. Thanks to "tRololo312312" for reporting.
    - Optimized the order test loop by exiting when order is 0, unavailable.

2.7 (15-May-2020)
    - Fixed not resetting variables on clients spawning causing issues e.g. thinking someone's ledge hanging.
    - Thanks to "tRololo312312" for reporting.

2.6 (10-May-2020)
    - Added option "8" to "order" to choose targeting the survivor with highest health.
    - Added option "9" to "order" to choose targeting the survivor with lowest health.
    - Added option "10" to "order" to choose targeting a survivor being pummelled by the Charger (L4D2 only).
    - Extra checks to prevent "IsAllowedGameMode" throwing errors.
    - Fixed "incap" option not working correctly. Thanks to "login101" for reporting.
    - Fixed not resetting the last attacker on special infected spawning.
    - Gamedata changed to wildcard first few bytes due to Left4DHooks using as a detour.

2.5 (07-Apr-2020)
    - Added cvar "l4d_target_override_type" to select which method to search for survivors.
    - Fixed "Invalid index 0" when no valid targets are available. Thanks to "tRololo312312".

2.4 (01-Apr-2020)
    - Fixed "IsAllowedGameMode" from throwing errors when the "_tog" cvar was changed before MapStart.

2.3 (26-Mar-2020)
    - Added option "last" to the config to enable targeting the last attacker using order value 7.
    - Added option "7" to "order" to choose targeting the last attacker.
    - This option won't change target if one is already very close (250 units).
    - Thanks to "xZk" for requesting.

2.2 (24-Mar-2020)
    - Fixed memory leak. Thanks to "sorallll" for reporting. Thanks to "Lux" for adding the fix.

2.1 (23-Mar-2020)
    - Fixed only using the first 5 priority order values and never checking the 6th when the first 5 fail.

2.0 (23-Mar-2020)
    - Initial Release.

    - Combined L4D1 and L4D2 versions into 1 plugin.
    - Major changes to how the plugin works. 
    - Now has a data config to choose preferences for each Special Infected.

    - Renamed plugin (delete the old .smx - added check to prevent duplicate plugins).
    - Removed cvar "l4d2_target_patch_special", now part part of data config settings.
    - Removed cvar "l4d2_target_patch_targets", now part part of data config settings.
    - Removed cvar "l4d2_target_patch_wait", now part part of data config settings.
    - Removed cvar "l4d2_target_patch_incap", now part part of data config settings.
    - Removed cvar "l4d_target_patch_incap", now part part of data config settings.


Requirements:

Updating from 2.20 or older:
  • New cvars have been added: use the Cvar Configs Updater, or delete the old cvars config or manually add them.


Installation:
  • Download the .zip and extract the files to their respective folders in your servers \addons\sourcemod\ folder.
Attached Files
File Type: zip l4d_target_override.zip (46.4 KB, 21 views)
__________________

Last edited by Silvers; 03-25-2024 at 18:48.
Silvers is offline
sorallll
Senior Member
Join Date: Oct 2018
Old 03-24-2020 , 01:14   Re: [L4D & L4D2] Target Override (2.1) [23-Mar-2020]
Reply With Quote #2

L 03/24/2020 - 078:14: [SM] MEMORY LEAK DETECTED IN PLUGIN (file "optional/coop/l4d_target_override.smx")
L 03/24/2020 - 078:14: [SM] Unloading plugin to free 31530 handles.
L 03/24/2020 - 078:14: [SM] Contact the author(s) of this plugin to correct this error.
L 03/24/2020 - 078:14: --------------------------------------------------------------------------
L 03/24/2020 - 078:14: Type CellArray | Count 31527
L 03/24/2020 - 078:14: Type HookSetup | Count 1
L 03/24/2020 - 078:14: Type HookParams | Count 1
L 03/24/2020 - 078:14: Type HookReturn | Count 1
L 03/24/2020 - 078:14: -- Approximately 3652812 bytes of memory are in use by (31530) Handles.

L 03/24/2020 - 078:14: [SM] Exception reported: Memory leak
L 03/24/2020 - 078:14: [SM] Blaming: optional/coop/l4d_target_override.smx
L 03/24/2020 - 078:14: [SM] Call stack trace:
L 03/24/2020 - 078:14: [SM] [0] ArrayList.ArrayList
L 03/24/2020 - 078:14: [SM] [1] Line 699, l4d_target_override.sp::ChooseVictim
L 03/24/2020 - 07:45:07: Error log file session closed.
sorallll is offline
Lux
Veteran Member
Join Date: Jan 2015
Location: Cat
Old 03-24-2020 , 02:18   Re: [L4D & L4D2] Target Override (2.1) [23-Mar-2020]
Reply With Quote #3

Quote:
Originally Posted by sorallll View Post
L 03/24/2020 - 078:14: [SM] MEMORY LEAK DETECTED IN PLUGIN (file "optional/coop/l4d_target_override.smx")
L 03/24/2020 - 078:14: [SM] Unloading plugin to free 31530 handles.
L 03/24/2020 - 078:14: [SM] Contact the author(s) of this plugin to correct this error.
L 03/24/2020 - 078:14: --------------------------------------------------------------------------
L 03/24/2020 - 078:14: Type CellArray | Count 31527
L 03/24/2020 - 078:14: Type HookSetup | Count 1
L 03/24/2020 - 078:14: Type HookParams | Count 1
L 03/24/2020 - 078:14: Type HookReturn | Count 1
L 03/24/2020 - 078:14: -- Approximately 3652812 bytes of memory are in use by (31530) Handles.

L 03/24/2020 - 078:14: [SM] Exception reported: Memory leak
L 03/24/2020 - 078:14: [SM] Blaming: optional/coop/l4d_target_override.smx
L 03/24/2020 - 078:14: [SM] Call stack trace:
L 03/24/2020 - 078:14: [SM] [0] ArrayList.ArrayList
L 03/24/2020 - 078:14: [SM] [1] Line 699, l4d_target_override.sp::ChooseVictim
L 03/24/2020 - 07:45:07: Error log file session closed.
From quick skim don't really understand the code much but the error should fix after you put
PHP Code:
delete aTargets 
Just before the function returns.


Here did it below replace the whole function with this one.
PHP Code:
public MRESReturn ChooseVictim(int attackerHandle hReturn)
{
    
#if DEBUG_BENCHMARK == 1 || DEBUG_BENCHMARK == 2
    
StartProfiling(g_Prof);
    
#endif

    #if DEBUG_BENCHMARK == 3
    
PrintToServer("");
    
PrintToServer("");
    
PrintToServer("ENTRY %d (%N)"attackerattacker);
    
#endif



    // =========================
    // VALIDATE SPECIAL ALLOWED CHANGE TARGET
    // =========================
    // 1=Smoker, 2=Boomer, 3=Hunter, 4=Spitter, 5=Jockey, 6=Charger, 5 (L4D1) / 8 (L4D2)=Tank
    
int class = GetEntProp(attackerProp_Send"m_zombieClass");
    if( class == (
g_bLeft4Dead2 5) ) class -= 1;
    if( 
g_iCvarSpecials & (<< class - 1) == )
    {
        
#if DEBUG_BENCHMARK == 1 || DEBUG_BENCHMARK == 2
        
StopProfiling(g_Prof);
        
float speed GetProfilerTime(g_Prof);
        if( 
speed g_fBenchMin g_fBenchMin speed;
        if( 
speed g_fBenchMax g_fBenchMax speed;
        
g_fBenchAvg += speed;
        
g_iBenchTicks++;
        
#endif

        #if DEBUG_BENCHMARK == 2
        
PrintToServer("ChooseVictim End 1 in %f (Min %f. Avg %f. Max %f)"speedg_fBenchMing_fBenchAvg g_iBenchTicksg_fBenchMax);
        
#endif

        
return MRES_Ignored;
    }

    
// Change tank class for use as index
    
if( class == (g_bLeft4Dead2 4) )
    {
        class = 
0;
    }



    
// =========================
    // VALIDATE OLD TARGET, WAIT
    // =========================
    
int newVictim;
    
int lastVictim g_iLastVictim[attacker];
    if( 
lastVictim )
    {
        
// Player disconnected or player dead, otherwise validate last selected order still applies
        
if( IsClientInGame(lastVictim) == true && IsPlayerAlive(lastVictim) )
        {
            
#if DEBUG_BENCHMARK == 3
            
PrintToServer("=== Test Last: Order: %d. newVictim %d (%N)"g_iLastOrders[attacker], lastVictimlastVictim);
            
#endif

            
newVictim OrderTest(attackerlastVictimGetClientTeam(lastVictim), g_iLastOrders[attacker]);

            
#if DEBUG_BENCHMARK == 3
            
PrintToServer("=== Test Last: newVictim %d (%N)"lastVictimlastVictim);
            
#endif
        
}

        
// Not reached delay time
        
if( newVictim && GetGameTime() <= g_fLastSwitch[attacker] )
        {
            
#if DEBUG_BENCHMARK == 3
            
PrintToServer("=== Test Last: wait delay.");
            
#endif

            // CONTINUE OVERRIDE LAST
            
DHookSetReturn(hReturnnewVictim);
            return 
MRES_Supercede;
        }
        else
        {
            
#if DEBUG_BENCHMARK == 3
            
PrintToServer("=== Test Last: wait reset.");
            
#endif

            
g_iLastOrders[attacker] = 0;
            
g_iLastVictim[attacker] = 0;
            
g_fLastSwitch[attacker] = 0.0;
        }
    }



    
// =========================
    // FIND NEAREST SURVIVORS
    // =========================
    // Visible near
    
float vPos[3];
    
int targets[MAXPLAYERS+1];
    
ArrayList aTargets = new ArrayList(3);

    
GetClientEyePosition(attackervPos);
    
int numClients GetClientsInRange(vPosRangeType_VisibilitytargetsMAXPLAYERS);
    if( 
numClients == )
    {
        
#if DEBUG_BENCHMARK == 1 || DEBUG_BENCHMARK == 2
        
StopProfiling(g_Prof);
        
float speed GetProfilerTime(g_Prof);
        if( 
speed g_fBenchMin g_fBenchMin speed;
        if( 
speed g_fBenchMax g_fBenchMax speed;
        
g_fBenchAvg += speed;
        
g_iBenchTicks++;
        
#endif

        #if DEBUG_BENCHMARK == 2
        
PrintToServer("ChooseVictim End 2 in %f (Min %f. Avg %f. Max %f)"speedg_fBenchMing_fBenchAvg g_iBenchTicksg_fBenchMax);
        
#endif
        
        
delete aTargets;
        return 
MRES_Ignored;
    }



    
// =========================
    // GET DISTANCE
    // =========================
    
float vTarg[3];
    
float dist;
    
int team;
    
int index;
    
int victim;

    for( 
int i 0numClientsi++ )
    {
        
victim targets[i];

        if( 
victim && IsPlayerAlive(victim) )
        {
            
// Option "voms" then allow choosing team 3
            
team GetClientTeam(victim);
            if( 
team == || (team == && g_iVomsOption[class] == 1) )
            {
                
GetClientAbsOrigin(victimvTarg);
                
dist GetVectorDistance(vPosvTarg);

                
index aTargets.Push(dist);
                
aTargets.Set(indexvictim1);
                
aTargets.Set(indexteam2);
            }
        }
    }

    
// Sort by nearest
    
SortADTArray(aTargetsSort_AscendingSort_Float);



    
// =========================
    // ALL INCAPPED CHECK
    // OPTION: "incap" "3"
    // =========================
    // 3=Only attack incapacitated when everyones incapacitated.
    
bool allIncap;
    if( 
g_iIncapOption[class] == )
    {
        
allIncap true;

        for( 
int i 1<= MaxClientsi++ )
        {
            if( 
IsClientInGame(i) && GetClientTeam(i) == && IsPlayerAlive(i) )
            {
                if( 
g_bIncapped[i] == false )
                {
                    
allIncap false;
                    break;
                }
            }
        }
    }



    
// =========================
    // ORDER VALIDATION
    // =========================
    // Loop through all orders progressing to the next on fail, and each time loop through all survivors from nearest to test the order preference
    
bool allPinned true;
    
int order;

    
int len aTargets.Length;
    
int orders;
    for( ; 
orders MAX_ORDERSorders++ )
    {
        
// Found someone, exit loop
        #if DEBUG_BENCHMARK == 3
        
PrintToServer("=== ORDER LOOP %d. newVictim %d (%N)"ordersnewVictimnewVictim);
        
#endif

        
if( newVictim ) break;



        
// =========================
        // OPTION: "order"
        // =========================
        
switch( class )
        {
            case 
INDEX_TANK:        order g_iOrderTank[orders];
            case 
INDEX_SMOKER:        order g_iOrderSmoker[orders];
            case 
INDEX_BOOMER:        order g_iOrderBoomer[orders];
            case 
INDEX_HUNTER:        order g_iOrderHunter[orders];
            case 
INDEX_SPITTER:        order g_iOrderSpitter[orders];
            case 
INDEX_JOCKEY:        order g_iOrderJockeys[orders];
            case 
INDEX_CHARGER:        order g_iOrderCharger[orders];
        }



        
// =========================
        // LOOP SURVIVORS
        // =========================
        
for( int i 0leni++ )
        {
            
victim aTargets.Get(i1);



            
// All incapped, target nearest
            
if( allIncap )
            {
                
#if DEBUG_BENCHMARK == 3
                
PrintToServer("Break allIncap");
                
#endif

                
newVictim victim;
                break;
            }



            
team aTargets.Get(i2);
            
// dist = aTargets.Get(i, 0);



            // =========================
            // OPTION: "incap"
            // =========================
            // 0=Ignore incapacitated players.
            // 1=Allow attacking incapacitated players.
            // 2=Only attack incapacitated players when they are vomited.
            // 3=Only attack incapacitated when everyones incapacitated.
            // 3 is already checked above.
            
if( team == &&
                
g_bIncapped[victim] == true &&
                
g_bIncapped[victim] == false
            
)
            {
                switch( 
g_iIncapOption[class] )
                {
                    case 
0: continue;
                    case 
2: if( g_bPinBoomer[victim] == false ) continue;
                }
            }



            
// =========================
            // OPTION: "pinned"
            // =========================
            // Validate pinned and allowed
            // 1=Smoker. 2=Hunter. 4=Jockey. 8=Charger.
            
if( team == )
            {
                if( 
g_iPinnedOption[class] & && g_bPinSmoker[victim] ) continue;
                if( 
g_iPinnedOption[class] & && g_bPinHunter[victim] ) continue;
                if( 
g_bLeft4Dead2 )
                {
                    if( 
g_iPinnedOption[class] & && g_bPinJockey[victim] ) continue;
                    if( 
g_iPinnedOption[class] & && g_bPinCharger[victim] ) continue;
                }

                
allPinned false;
            }



            
// =========================
            // OPTION: "order"
            // =========================
            
newVictim OrderTest(attackervictimteamorder);

            
#if DEBUG_BENCHMARK == 3
            
PrintToServer("Order %d newVictim %d (%N)"ordernewVictimnewVictim);
            
#endif

            
if( newVictim ) break;
        }
    }



    
// All pinned and not allowed to target, target self to avoid attacking pinned.
    
if( allPinned && g_iPinnedOption[class] == )
    {
        
newVictim attacker;
    }



    
// =========================
    // NEW TARGET
    // =========================
    
if( newVictim != g_iLastVictim[attacker] )
    {
        
g_iLastOrders[attacker] = orders;
        
g_iLastVictim[attacker] = newVictim;
        
g_fLastSwitch[attacker] = GetGameTime() + g_fWaitOption[class];
    }



    
// =========================
    // OVERRIDE VICTIM
    // =========================
    
if( newVictim )
    {
        
DHookSetReturn(hReturnnewVictim);

        
#if DEBUG_BENCHMARK == 1 || DEBUG_BENCHMARK == 2
        
StopProfiling(g_Prof);
        
float speed GetProfilerTime(g_Prof);
        if( 
speed g_fBenchMin g_fBenchMin speed;
        if( 
speed g_fBenchMax g_fBenchMax speed;
        
g_fBenchAvg += speed;
        
g_iBenchTicks++;
        
#endif

        #if DEBUG_BENCHMARK == 2
        
PrintToServer("ChooseVictim End 3 in %f (Min %f. Avg %f. Max %f)"speedg_fBenchMing_fBenchAvg g_iBenchTicksg_fBenchMax);
        
#endif
        
        
delete aTargets;
        return 
MRES_Supercede;
    }

    
#if DEBUG_BENCHMARK == 1 || DEBUG_BENCHMARK == 2
    
StopProfiling(g_Prof);
    
float speed GetProfilerTime(g_Prof);
    if( 
speed g_fBenchMin g_fBenchMin speed;
    if( 
speed g_fBenchMax g_fBenchMax speed;
    
g_fBenchAvg += speed;
    
g_iBenchTicks++;
    
#endif

    #if DEBUG_BENCHMARK == 2
    
PrintToServer("ChooseVictim End 4 in %f (Min %f. Avg %f. Max %f)"speedg_fBenchMing_fBenchAvg g_iBenchTicksg_fBenchMax);
    
#endif
    
    
delete aTargets;
    return 
MRES_Ignored;

Also it looks like you edited the code somewhat line 699 has nothing but a comment.
__________________
Connect
My Plugins: KlickME
[My GitHub]

Commission me for L4D
Lux is offline
sorallll
Senior Member
Join Date: Oct 2018
Old 03-24-2020 , 04:40   Re: [L4D & L4D2] Target Override (2.1) [23-Mar-2020]
Reply With Quote #4

Quote:
Originally Posted by Lux View Post
From quick skim don't really understand the code much but the error should fix after you put
PHP Code:
delete aTargets 
Just before the function returns.


Here did it below replace the whole function with this one.
PHP Code:
public MRESReturn ChooseVictim(int attackerHandle hReturn)
{
    
#if DEBUG_BENCHMARK == 1 || DEBUG_BENCHMARK == 2
    
StartProfiling(g_Prof);
    
#endif

    #if DEBUG_BENCHMARK == 3
    
PrintToServer("");
    
PrintToServer("");
    
PrintToServer("ENTRY %d (%N)"attackerattacker);
    
#endif



    // =========================
    // VALIDATE SPECIAL ALLOWED CHANGE TARGET
    // =========================
    // 1=Smoker, 2=Boomer, 3=Hunter, 4=Spitter, 5=Jockey, 6=Charger, 5 (L4D1) / 8 (L4D2)=Tank
    
int class = GetEntProp(attackerProp_Send"m_zombieClass");
    if( class == (
g_bLeft4Dead2 5) ) class -= 1;
    if( 
g_iCvarSpecials & (<< class - 1) == )
    {
        
#if DEBUG_BENCHMARK == 1 || DEBUG_BENCHMARK == 2
        
StopProfiling(g_Prof);
        
float speed GetProfilerTime(g_Prof);
        if( 
speed g_fBenchMin g_fBenchMin speed;
        if( 
speed g_fBenchMax g_fBenchMax speed;
        
g_fBenchAvg += speed;
        
g_iBenchTicks++;
        
#endif

        #if DEBUG_BENCHMARK == 2
        
PrintToServer("ChooseVictim End 1 in %f (Min %f. Avg %f. Max %f)"speedg_fBenchMing_fBenchAvg g_iBenchTicksg_fBenchMax);
        
#endif

        
return MRES_Ignored;
    }

    
// Change tank class for use as index
    
if( class == (g_bLeft4Dead2 4) )
    {
        class = 
0;
    }



    
// =========================
    // VALIDATE OLD TARGET, WAIT
    // =========================
    
int newVictim;
    
int lastVictim g_iLastVictim[attacker];
    if( 
lastVictim )
    {
        
// Player disconnected or player dead, otherwise validate last selected order still applies
        
if( IsClientInGame(lastVictim) == true && IsPlayerAlive(lastVictim) )
        {
            
#if DEBUG_BENCHMARK == 3
            
PrintToServer("=== Test Last: Order: %d. newVictim %d (%N)"g_iLastOrders[attacker], lastVictimlastVictim);
            
#endif

            
newVictim OrderTest(attackerlastVictimGetClientTeam(lastVictim), g_iLastOrders[attacker]);

            
#if DEBUG_BENCHMARK == 3
            
PrintToServer("=== Test Last: newVictim %d (%N)"lastVictimlastVictim);
            
#endif
        
}

        
// Not reached delay time
        
if( newVictim && GetGameTime() <= g_fLastSwitch[attacker] )
        {
            
#if DEBUG_BENCHMARK == 3
            
PrintToServer("=== Test Last: wait delay.");
            
#endif

            // CONTINUE OVERRIDE LAST
            
DHookSetReturn(hReturnnewVictim);
            return 
MRES_Supercede;
        }
        else
        {
            
#if DEBUG_BENCHMARK == 3
            
PrintToServer("=== Test Last: wait reset.");
            
#endif

            
g_iLastOrders[attacker] = 0;
            
g_iLastVictim[attacker] = 0;
            
g_fLastSwitch[attacker] = 0.0;
        }
    }



    
// =========================
    // FIND NEAREST SURVIVORS
    // =========================
    // Visible near
    
float vPos[3];
    
int targets[MAXPLAYERS+1];
    
ArrayList aTargets = new ArrayList(3);

    
GetClientEyePosition(attackervPos);
    
int numClients GetClientsInRange(vPosRangeType_VisibilitytargetsMAXPLAYERS);
    if( 
numClients == )
    {
        
#if DEBUG_BENCHMARK == 1 || DEBUG_BENCHMARK == 2
        
StopProfiling(g_Prof);
        
float speed GetProfilerTime(g_Prof);
        if( 
speed g_fBenchMin g_fBenchMin speed;
        if( 
speed g_fBenchMax g_fBenchMax speed;
        
g_fBenchAvg += speed;
        
g_iBenchTicks++;
        
#endif

        #if DEBUG_BENCHMARK == 2
        
PrintToServer("ChooseVictim End 2 in %f (Min %f. Avg %f. Max %f)"speedg_fBenchMing_fBenchAvg g_iBenchTicksg_fBenchMax);
        
#endif
        
        
delete aTargets;
        return 
MRES_Ignored;
    }



    
// =========================
    // GET DISTANCE
    // =========================
    
float vTarg[3];
    
float dist;
    
int team;
    
int index;
    
int victim;

    for( 
int i 0numClientsi++ )
    {
        
victim targets[i];

        if( 
victim && IsPlayerAlive(victim) )
        {
            
// Option "voms" then allow choosing team 3
            
team GetClientTeam(victim);
            if( 
team == || (team == && g_iVomsOption[class] == 1) )
            {
                
GetClientAbsOrigin(victimvTarg);
                
dist GetVectorDistance(vPosvTarg);

                
index aTargets.Push(dist);
                
aTargets.Set(indexvictim1);
                
aTargets.Set(indexteam2);
            }
        }
    }

    
// Sort by nearest
    
SortADTArray(aTargetsSort_AscendingSort_Float);



    
// =========================
    // ALL INCAPPED CHECK
    // OPTION: "incap" "3"
    // =========================
    // 3=Only attack incapacitated when everyones incapacitated.
    
bool allIncap;
    if( 
g_iIncapOption[class] == )
    {
        
allIncap true;

        for( 
int i 1<= MaxClientsi++ )
        {
            if( 
IsClientInGame(i) && GetClientTeam(i) == && IsPlayerAlive(i) )
            {
                if( 
g_bIncapped[i] == false )
                {
                    
allIncap false;
                    break;
                }
            }
        }
    }



    
// =========================
    // ORDER VALIDATION
    // =========================
    // Loop through all orders progressing to the next on fail, and each time loop through all survivors from nearest to test the order preference
    
bool allPinned true;
    
int order;

    
int len aTargets.Length;
    
int orders;
    for( ; 
orders MAX_ORDERSorders++ )
    {
        
// Found someone, exit loop
        #if DEBUG_BENCHMARK == 3
        
PrintToServer("=== ORDER LOOP %d. newVictim %d (%N)"ordersnewVictimnewVictim);
        
#endif

        
if( newVictim ) break;



        
// =========================
        // OPTION: "order"
        // =========================
        
switch( class )
        {
            case 
INDEX_TANK:        order g_iOrderTank[orders];
            case 
INDEX_SMOKER:        order g_iOrderSmoker[orders];
            case 
INDEX_BOOMER:        order g_iOrderBoomer[orders];
            case 
INDEX_HUNTER:        order g_iOrderHunter[orders];
            case 
INDEX_SPITTER:        order g_iOrderSpitter[orders];
            case 
INDEX_JOCKEY:        order g_iOrderJockeys[orders];
            case 
INDEX_CHARGER:        order g_iOrderCharger[orders];
        }



        
// =========================
        // LOOP SURVIVORS
        // =========================
        
for( int i 0leni++ )
        {
            
victim aTargets.Get(i1);



            
// All incapped, target nearest
            
if( allIncap )
            {
                
#if DEBUG_BENCHMARK == 3
                
PrintToServer("Break allIncap");
                
#endif

                
newVictim victim;
                break;
            }



            
team aTargets.Get(i2);
            
// dist = aTargets.Get(i, 0);



            // =========================
            // OPTION: "incap"
            // =========================
            // 0=Ignore incapacitated players.
            // 1=Allow attacking incapacitated players.
            // 2=Only attack incapacitated players when they are vomited.
            // 3=Only attack incapacitated when everyones incapacitated.
            // 3 is already checked above.
            
if( team == &&
                
g_bIncapped[victim] == true &&
                
g_bIncapped[victim] == false
            
)
            {
                switch( 
g_iIncapOption[class] )
                {
                    case 
0: continue;
                    case 
2: if( g_bPinBoomer[victim] == false ) continue;
                }
            }



            
// =========================
            // OPTION: "pinned"
            // =========================
            // Validate pinned and allowed
            // 1=Smoker. 2=Hunter. 4=Jockey. 8=Charger.
            
if( team == )
            {
                if( 
g_iPinnedOption[class] & && g_bPinSmoker[victim] ) continue;
                if( 
g_iPinnedOption[class] & && g_bPinHunter[victim] ) continue;
                if( 
g_bLeft4Dead2 )
                {
                    if( 
g_iPinnedOption[class] & && g_bPinJockey[victim] ) continue;
                    if( 
g_iPinnedOption[class] & && g_bPinCharger[victim] ) continue;
                }

                
allPinned false;
            }



            
// =========================
            // OPTION: "order"
            // =========================
            
newVictim OrderTest(attackervictimteamorder);

            
#if DEBUG_BENCHMARK == 3
            
PrintToServer("Order %d newVictim %d (%N)"ordernewVictimnewVictim);
            
#endif

            
if( newVictim ) break;
        }
    }



    
// All pinned and not allowed to target, target self to avoid attacking pinned.
    
if( allPinned && g_iPinnedOption[class] == )
    {
        
newVictim attacker;
    }



    
// =========================
    // NEW TARGET
    // =========================
    
if( newVictim != g_iLastVictim[attacker] )
    {
        
g_iLastOrders[attacker] = orders;
        
g_iLastVictim[attacker] = newVictim;
        
g_fLastSwitch[attacker] = GetGameTime() + g_fWaitOption[class];
    }



    
// =========================
    // OVERRIDE VICTIM
    // =========================
    
if( newVictim )
    {
        
DHookSetReturn(hReturnnewVictim);

        
#if DEBUG_BENCHMARK == 1 || DEBUG_BENCHMARK == 2
        
StopProfiling(g_Prof);
        
float speed GetProfilerTime(g_Prof);
        if( 
speed g_fBenchMin g_fBenchMin speed;
        if( 
speed g_fBenchMax g_fBenchMax speed;
        
g_fBenchAvg += speed;
        
g_iBenchTicks++;
        
#endif

        #if DEBUG_BENCHMARK == 2
        
PrintToServer("ChooseVictim End 3 in %f (Min %f. Avg %f. Max %f)"speedg_fBenchMing_fBenchAvg g_iBenchTicksg_fBenchMax);
        
#endif
        
        
delete aTargets;
        return 
MRES_Supercede;
    }

    
#if DEBUG_BENCHMARK == 1 || DEBUG_BENCHMARK == 2
    
StopProfiling(g_Prof);
    
float speed GetProfilerTime(g_Prof);
    if( 
speed g_fBenchMin g_fBenchMin speed;
    if( 
speed g_fBenchMax g_fBenchMax speed;
    
g_fBenchAvg += speed;
    
g_iBenchTicks++;
    
#endif

    #if DEBUG_BENCHMARK == 2
    
PrintToServer("ChooseVictim End 4 in %f (Min %f. Avg %f. Max %f)"speedg_fBenchMing_fBenchAvg g_iBenchTicksg_fBenchMax);
    
#endif
    
    
delete aTargets;
    return 
MRES_Ignored;

Also it looks like you edited the code somewhat line 699 has nothing but a comment.
Thanks,lux:眨眼:
sorallll is offline
Silvers
SourceMod Plugin Approver
Join Date: Aug 2010
Location: SpaceX
Old 03-24-2020 , 09:56   Re: [L4D & L4D2] Target Override (2.2) [24-Mar-2020]
Reply With Quote #5

Oversight, didn't review close enough before posting. Thanks. Updated 1st post.
__________________
Silvers is offline
Silvers
SourceMod Plugin Approver
Join Date: Aug 2010
Location: SpaceX
Old 03-26-2020 , 01:01   Re: [L4D & L4D2] Target Override (2.3) [26-Mar-2020]
Reply With Quote #6

Code:
2.3 (26-Mar-2020)
    - Added option "last" to the config to enable targeting the last attacker using order value 7.
    - Added option "7" to "order" to choose targeting the last attacker.
    - This option won't change target if one is already very close (250 units).
    - Thanks to "xZk" for requesting.
__________________
Silvers is offline
tRololo312312
Senior Member
Join Date: Apr 2015
Old 04-05-2020 , 18:28   Re: [L4D & L4D2] Target Override (2.4) [01-Apr-2020]
Reply With Quote #7

Can you add order value for closest survivor?
tRololo312312 is offline
Silvers
SourceMod Plugin Approver
Join Date: Aug 2010
Location: SpaceX
Old 04-05-2020 , 18:59   Re: [L4D & L4D2] Target Override (2.4) [01-Apr-2020]
Reply With Quote #8

Quote:
Originally Posted by tRololo312312 View Post
Can you add order value for closest survivor?
They all use closest survivor, except 7=Last Attacker.
__________________
Silvers is offline
sxslmk
Member
Join Date: Dec 2017
Location: CN
Old 04-06-2020 , 00:43   Re: [L4D & L4D2] Target Override (2.4) [01-Apr-2020]
Reply With Quote #9

Excuse me, I tested this plugin but it doesn't fix this problem:

IMG
I'm using Auto Infected Spawner
to spawn lot of SIs. Like image above, the problem is some SIs stuck at spawn point and don't attack survivors until any survivor close to them. I tried to set
Code:
sm_cvar z_finale_spawn_safety_range  0
sm_cvar z_finale_spawn_tank_safety_range 0
sm_cvar z_safe_spawn_range 7
It doesn't fix. This problem only appears in the final game. Infected Bots Control is same problem as AutoIS. Could you help me how to fix this? Thanks for your attention.

Last edited by sxslmk; 04-06-2020 at 00:51.
sxslmk is offline
Silvers
SourceMod Plugin Approver
Join Date: Aug 2010
Location: SpaceX
Old 04-06-2020 , 00:51   Re: [L4D & L4D2] Target Override (2.4) [01-Apr-2020]
Reply With Quote #10

Quote:
Originally Posted by sxslmk View Post
Excuse me, I tested this plugin but it doesn't fix this problem:

IMG
I'm using Auto Infected Spawner
to spawn lot of SIs. Like image above, the problem is some SIs stuck at spawn point and don't attack survivors until any survivor close to them. I tried to set
Code:
sm_cvar z_finale_spawn_safety_range  0
sm_cvar z_finale_spawn_tank_safety_range 0
sm_cvar z_safe_spawn_range 7
It doesn't fix. This problem only appears in the final game. Infected Bots Control is same problem as AutoIS.
This plugin checks for nearby (supposed to be nearby visible but seems it might catch those also not visible) survivors, then sets the target according to the preferences specified. If none of those criteria match it defaults to the games own choose victim system. If that bug occurs without the plugin then theres nothing wrong on my end. Maybe I can add an option to search through all survivors from the nearest and not just visible ones.

Edit: sent PM with link to test version with above mentioned option.
__________________

Last edited by Silvers; 04-06-2020 at 01:00.
Silvers is offline
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 05:54.


Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Theme made by Freecode