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

Solved [TF2] Problem with Bot Creation Plugin


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
ThatKidWhoGames
Veteran Member
Join Date: Jun 2013
Location: IsValidClient()
Old 01-16-2021 , 13:27   [TF2] Problem with Bot Creation Plugin
Reply With Quote #1

Hello,

I am currently writing a plugin where admins can create bots (fake clients) using the command sm_bot. If no arguments are supplied, it creates a bot and sets their team to a random team and their class to a random class. If arguments are given, it sets the bots team and class accordingly. However, I am having a strange issue when it comes to setting the bots team and class to be random when no arguments are given. Using the command creating a bot for the first time without arguments initially works perfectly fine, and creates the bot correctly with a random team and class. However, every time after that, it sets their team to red and their class to engineer. I am certain that there are no other conflicting plugins and I have tried restarting my server and changing the map. When arguments are given for the command, the bot is created correctly and there are never issues with it. Here is my code:
PHP Code:
#include <sourcemod>
#include <tf2_stocks>

public void OnPluginStart()
{
    
RegAdminCmd("sm_bot"Command_BotADMFLAG_CHEATS"Create a bot");
}

public 
Action Command_Bot(int iClientint iArgs)
{
    
TFTeam team TF2_GetRandomTeam();
    
TFClassType class = TF2_GetRandomClass();
    if (
iArgs 0)
    {
        
/* Get the first argument */
        
char sArg1[32];
        
GetCmdArg(1sArg1sizeof(sArg1));
        
team TF2_GetTeamFromString(sArg1);
        if (
team TFTeam_Red)
        {
            
ReplyToCommand(iClient"[SM] Invalid team specified!");
            return 
Plugin_Handled;
        }

        if (
iArgs 1)
        {
            
/* Get the second argument */
            
char sArg2[32];
            
GetCmdArg(2sArg2sizeof(sArg2));
            class = 
TF2_GetClassFromString(sArg2);
            if (class == 
TFClass_Unknown)
            {
                
ReplyToCommand(iClient"[SM] Invalid class specified!");
                return 
Plugin_Handled;
            }
        }
    }

    
ReplyToCommand(iClient"[SM] team == %d"team);
    
ReplyToCommand(iClient"[SM] class == %d", class);

    
char sTeam[32], sClass[32];
    
TF2_GetTeamName(teamsTeamsizeof(sTeam));
    
TF2_GetClassName(class, sClasssizeof(sClass));

    
CapitalizeFirstLetter(sTeam);
    
CapitalizeFirstLetter(sClass);

    
char sName[MAX_NAME_LENGTH];
    
Format(sNamesizeof(sName), "%s %s #%i"sTeamsClassTF2_GetBotCount(team, class));
    if (!
TF2_CreateBot(sNameteam, class))
    {
        
ReplyToCommand(iClient"[SM] Failure creating bot!");
        return 
Plugin_Handled;
    }

    
ReplyToCommand(iClient"[SM] Successfully created bot!");
    return 
Plugin_Handled;
}

stock TFTeam TF2_GetRandomTeam()
{
    return 
view_as<TFTeam>(GetRandomInt(23));
}

stock TFClassType TF2_GetRandomClass()
{
    return 
view_as<TFClassType>(GetRandomInt(19));
}

stock TFTeam TF2_GetTeamFromString(const char[] sBuffer)
{
    if (
StrEqual(sBuffer"1"false) || StrEqual(sBuffer"spectator"false))
    {
        return 
TFTeam_Spectator;
    }

    if (
StrEqual(sBuffer"2"false) || StrEqual(sBuffer"red"false))
    {
        return 
TFTeam_Red;
    }

    if (
StrEqual(sBuffer"3"false) || StrEqual(sBuffer"blue"false))
    {
        return 
TFTeam_Blue;
    }

    return 
TFTeam_Unassigned;
}

stock void TF2_GetTeamName(TFTeam teamchar[] sBufferint iMaxlength)
{
    switch (
team)
    {
        case 
TFTeam_Unassigned:
        {
            
Format(sBufferiMaxlength"unassigned");
        }

        case 
TFTeam_Spectator:
        {
            
Format(sBufferiMaxlength"spectator");
        }

        case 
TFTeam_Red:
        {
            
Format(sBufferiMaxlength"red");
        }

        case 
TFTeam_Blue:
        {
            
Format(sBufferiMaxlength"blue");
        }
    }
}

// This is basically TF2_GetClass() but it works better
stock TFClassType TF2_GetClassFromString(const char[] sBuffer)
{
    if (
StrEqual(sBuffer"scout"false))
    {
        return 
TFClass_Scout;
    }

    if (
StrEqual(sBuffer"soldier"false))
    {
        return 
TFClass_Soldier;
    }

    if (
StrEqual(sBuffer"pyro"false))
    {
        return 
TFClass_Pyro;
    }

    if (
StrEqual(sBuffer"demoman"false))
    {
        return 
TFClass_DemoMan;
    }

    if (
StrEqual(sBuffer"heavy"false))
    {
        return 
TFClass_Heavy;
    }

    if (
StrEqual(sBuffer"engineer"false))
    {
        return 
TFClass_Engineer;
    }

    if (
StrEqual(sBuffer"medic"false))
    {
        return 
TFClass_Medic;
    }

    if (
StrEqual(sBuffer"sniper"false))
    {
        return 
TFClass_Sniper;
    }

    if (
StrEqual(sBuffer"spy"false))
    {
        return 
TFClass_Spy;
    }

    return 
TFClass_Unknown;
}

stock void TF2_GetClassName(TFClassType class, char[] sBufferint iMaxlength)
{
    switch (class)
    {
        case 
TFClass_Scout:
        {
            
Format(sBufferiMaxlength"scout");
        }

        case 
TFClass_Soldier:
        {
            
Format(sBufferiMaxlength"soldier");
        }

        case 
TFClass_Pyro:
        {
            
Format(sBufferiMaxlength"pyro");
        }

        case 
TFClass_DemoMan:
        {
            
Format(sBufferiMaxlength"demoman");
        }

        case 
TFClass_Heavy:
        {
            
Format(sBufferiMaxlength"heavy");
        }

        case 
TFClass_Engineer:
        {
            
Format(sBufferiMaxlength"engineer");
        }

        case 
TFClass_Medic:
        {
            
Format(sBufferiMaxlength"medic");
        }

        case 
TFClass_Sniper:
        {
            
Format(sBufferiMaxlength"sniper");
        }

        case 
TFClass_Spy:
        {
            
Format(sBufferiMaxlength"spy");
        }

        case 
TFClass_Unknown:
        {
            
Format(sBufferiMaxlength"unknown");
        }
    }
}

stock int TF2_GetBotCount(TFTeam teamTFClassType class)
{
    
int iCount 1;
    for (
int i 1<= MaxClientsi++)
    {
        if (
IsClientInGame(i) && IsFakeClient(i) && TF2_GetClientTeam(i) == team && TF2_GetPlayerClass(i) == class)
        {
            
iCount++;
        }
    }

    return 
iCount;
}

stock bool TF2_CreateBot(const char[] sNameTFTeam teamTFClassType class)
{
    
int iBot CreateFakeClient(sName);
    if (
iBot != 0)
    {
        
TF2_ChangeClientTeam(iBotteam);
        
TF2_SetPlayerClass(iBot, class);
        
TF2_RespawnPlayer(iBot);
        return 
true;
    }

    return 
false;
}

stock void CapitalizeFirstLetter(char[] sBuffer)
{
    
sBuffer[0] = CharToUpper(sBuffer[0]);

Thank you,
Grant

Last edited by ThatKidWhoGames; 01-17-2021 at 13:50.
ThatKidWhoGames is offline
PC Gamer
Veteran Member
Join Date: Mar 2014
Old 01-17-2021 , 12:33   Re: [TF2] Problem with Bot Creation Plugin
Reply With Quote #2

Are you trying to create Puppet Bots? I'm already running Bots on my server. When I use the code above the new Bot is created and it just stands there without moving. The server console will display "Cannot verify load for invalid steam ID [A:1415:1]".

Anyway... I was able to reproduce and correct the Engineer error. I'm certainly no expert but I believe the SourceMod GetRandomInt function is to blame in this case. It started working correctly when I replaced it with GetRandomUInt. The invalid steam ID problem still exists.

Edited code:
PHP Code:
#include <sourcemod>
#include <tf2_stocks>

public void OnPluginStart()
{
    
RegAdminCmd("sm_bot"Command_BotADMFLAG_CHEATS"Create a bot");
}

public 
Action Command_Bot(int iClientint iArgs)
{
    
TFTeam team TF2_GetRandomTeam();
    
TFClassType class = TF2_GetRandomClass();
    if (
iArgs 0)
    {
        
/* Get the first argument */
        
char sArg1[32];
        
GetCmdArg(1sArg1sizeof(sArg1));
        
team TF2_GetTeamFromString(sArg1);
        if (
team TFTeam_Red)
        {
            
ReplyToCommand(iClient"[SM] Invalid team specified!");
            return 
Plugin_Handled;
        }

        if (
iArgs 1)
        {
            
/* Get the second argument */
            
char sArg2[32];
            
GetCmdArg(2sArg2sizeof(sArg2));
            class = 
TF2_GetClassFromString(sArg2);
            if (class == 
TFClass_Unknown)
            {
                
ReplyToCommand(iClient"[SM] Invalid class specified!");
                return 
Plugin_Handled;
            }
        }
    }

    
ReplyToCommand(iClient"[SM] team == %d"team);
    
ReplyToCommand(iClient"[SM] class == %d", class);

    
char sTeam[32], sClass[32];
    
TF2_GetTeamName(teamsTeamsizeof(sTeam));
    
TF2_GetClassName(class, sClasssizeof(sClass));

    
CapitalizeFirstLetter(sTeam);
    
CapitalizeFirstLetter(sClass);

    
char sName[MAX_NAME_LENGTH];
    
Format(sNamesizeof(sName), "%s %s #%i"sTeamsClassTF2_GetBotCount(team, class));
    if (!
TF2_CreateBot(sNameteam, class))
    {
        
ReplyToCommand(iClient"[SM] Failure creating bot!");
        return 
Plugin_Handled;
    }

    
ReplyToCommand(iClient"[SM] Successfully created bot!");
    return 
Plugin_Handled;
}

stock TFTeam TF2_GetRandomTeam()
{
    return 
view_as<TFTeam>(GetRandomUInt(23));
}

stock TFClassType TF2_GetRandomClass()
{
    return 
view_as<TFClassType>(GetRandomUInt(19));
}

stock TFTeam TF2_GetTeamFromString(const char[] sBuffer)
{
    if (
StrEqual(sBuffer"1"false) || StrEqual(sBuffer"spectator"false))
    {
        return 
TFTeam_Spectator;
    }

    if (
StrEqual(sBuffer"2"false) || StrEqual(sBuffer"red"false))
    {
        return 
TFTeam_Red;
    }

    if (
StrEqual(sBuffer"3"false) || StrEqual(sBuffer"blue"false))
    {
        return 
TFTeam_Blue;
    }

    return 
TFTeam_Unassigned;
}

stock void TF2_GetTeamName(TFTeam teamchar[] sBufferint iMaxlength)
{
    switch (
team)
    {
    case 
TFTeam_Unassigned:
        {
            
Format(sBufferiMaxlength"unassigned");
        }

    case 
TFTeam_Spectator:
        {
            
Format(sBufferiMaxlength"spectator");
        }

    case 
TFTeam_Red:
        {
            
Format(sBufferiMaxlength"red");
        }

    case 
TFTeam_Blue:
        {
            
Format(sBufferiMaxlength"blue");
        }
    }
}

// This is basically TF2_GetClass() but it works better
stock TFClassType TF2_GetClassFromString(const char[] sBuffer)
{
    if (
StrEqual(sBuffer"scout"false))
    {
        return 
TFClass_Scout;
    }

    if (
StrEqual(sBuffer"soldier"false))
    {
        return 
TFClass_Soldier;
    }

    if (
StrEqual(sBuffer"pyro"false))
    {
        return 
TFClass_Pyro;
    }

    if (
StrEqual(sBuffer"demoman"false))
    {
        return 
TFClass_DemoMan;
    }

    if (
StrEqual(sBuffer"heavy"false))
    {
        return 
TFClass_Heavy;
    }

    if (
StrEqual(sBuffer"engineer"false))
    {
        return 
TFClass_Engineer;
    }

    if (
StrEqual(sBuffer"medic"false))
    {
        return 
TFClass_Medic;
    }

    if (
StrEqual(sBuffer"sniper"false))
    {
        return 
TFClass_Sniper;
    }

    if (
StrEqual(sBuffer"spy"false))
    {
        return 
TFClass_Spy;
    }

    return 
TFClass_Unknown;
}

stock void TF2_GetClassName(TFClassType class, char[] sBufferint iMaxlength)
{
    switch (class)
    {
    case 
TFClass_Scout:
        {
            
Format(sBufferiMaxlength"scout");
        }

    case 
TFClass_Soldier:
        {
            
Format(sBufferiMaxlength"soldier");
        }

    case 
TFClass_Pyro:
        {
            
Format(sBufferiMaxlength"pyro");
        }

    case 
TFClass_DemoMan:
        {
            
Format(sBufferiMaxlength"demoman");
        }

    case 
TFClass_Heavy:
        {
            
Format(sBufferiMaxlength"heavy");
        }

    case 
TFClass_Engineer:
        {
            
Format(sBufferiMaxlength"engineer");
        }

    case 
TFClass_Medic:
        {
            
Format(sBufferiMaxlength"medic");
        }

    case 
TFClass_Sniper:
        {
            
Format(sBufferiMaxlength"sniper");
        }

    case 
TFClass_Spy:
        {
            
Format(sBufferiMaxlength"spy");
        }

    case 
TFClass_Unknown:
        {
            
Format(sBufferiMaxlength"unknown");
        }
    }
}

stock int TF2_GetBotCount(TFTeam teamTFClassType class)
{
    
int iCount 1;
    for (
int i 1<= MaxClientsi++)
    {
        if (
IsClientInGame(i) && IsFakeClient(i) && TF2_GetClientTeam(i) == team && TF2_GetPlayerClass(i) == class)
        {
            
iCount++;
        }
    }

    return 
iCount;
}

stock bool TF2_CreateBot(const char[] sNameTFTeam teamTFClassType class)
{
    
int iBot CreateFakeClient(sName);
    
PrintToChatAll("Debug: Creating %s, %s, %s"sNameteam, class);
    if (
iBot != 0)
    {
        
TF2_ChangeClientTeam(iBotteam);
        
TF2_SetPlayerClass(iBot, class);
        
TF2_RespawnPlayer(iBot);
        return 
true;
    }

    return 
false;
}

stock void CapitalizeFirstLetter(char[] sBuffer)
{
    
sBuffer[0] = CharToUpper(sBuffer[0]);


int GetRandomUInt(int minint max)
{
    return 
RoundToFloor(GetURandomFloat() * (max min 1)) + min;


Last edited by PC Gamer; 01-17-2021 at 12:35.
PC Gamer is offline
ThatKidWhoGames
Veteran Member
Join Date: Jun 2013
Location: IsValidClient()
Old 01-17-2021 , 13:49   Re: [TF2] Problem with Bot Creation Plugin
Reply With Quote #3

Quote:
Originally Posted by PC Gamer View Post
Are you trying to create Puppet Bots? I'm already running Bots on my server. When I use the code above the new Bot is created and it just stands there without moving. The server console will display "Cannot verify load for invalid steam ID [A:1415:1]".

Anyway... I was able to reproduce and correct the Engineer error. I'm certainly no expert but I believe the SourceMod GetRandomInt function is to blame in this case. It started working correctly when I replaced it with GetRandomUInt. The invalid steam ID problem still exists.

Edited code:
PHP Code:
#include <sourcemod>
#include <tf2_stocks>

public void OnPluginStart()
{
    
RegAdminCmd("sm_bot"Command_BotADMFLAG_CHEATS"Create a bot");
}

public 
Action Command_Bot(int iClientint iArgs)
{
    
TFTeam team TF2_GetRandomTeam();
    
TFClassType class = TF2_GetRandomClass();
    if (
iArgs 0)
    {
        
/* Get the first argument */
        
char sArg1[32];
        
GetCmdArg(1sArg1sizeof(sArg1));
        
team TF2_GetTeamFromString(sArg1);
        if (
team TFTeam_Red)
        {
            
ReplyToCommand(iClient"[SM] Invalid team specified!");
            return 
Plugin_Handled;
        }

        if (
iArgs 1)
        {
            
/* Get the second argument */
            
char sArg2[32];
            
GetCmdArg(2sArg2sizeof(sArg2));
            class = 
TF2_GetClassFromString(sArg2);
            if (class == 
TFClass_Unknown)
            {
                
ReplyToCommand(iClient"[SM] Invalid class specified!");
                return 
Plugin_Handled;
            }
        }
    }

    
ReplyToCommand(iClient"[SM] team == %d"team);
    
ReplyToCommand(iClient"[SM] class == %d", class);

    
char sTeam[32], sClass[32];
    
TF2_GetTeamName(teamsTeamsizeof(sTeam));
    
TF2_GetClassName(class, sClasssizeof(sClass));

    
CapitalizeFirstLetter(sTeam);
    
CapitalizeFirstLetter(sClass);

    
char sName[MAX_NAME_LENGTH];
    
Format(sNamesizeof(sName), "%s %s #%i"sTeamsClassTF2_GetBotCount(team, class));
    if (!
TF2_CreateBot(sNameteam, class))
    {
        
ReplyToCommand(iClient"[SM] Failure creating bot!");
        return 
Plugin_Handled;
    }

    
ReplyToCommand(iClient"[SM] Successfully created bot!");
    return 
Plugin_Handled;
}

stock TFTeam TF2_GetRandomTeam()
{
    return 
view_as<TFTeam>(GetRandomUInt(23));
}

stock TFClassType TF2_GetRandomClass()
{
    return 
view_as<TFClassType>(GetRandomUInt(19));
}

stock TFTeam TF2_GetTeamFromString(const char[] sBuffer)
{
    if (
StrEqual(sBuffer"1"false) || StrEqual(sBuffer"spectator"false))
    {
        return 
TFTeam_Spectator;
    }

    if (
StrEqual(sBuffer"2"false) || StrEqual(sBuffer"red"false))
    {
        return 
TFTeam_Red;
    }

    if (
StrEqual(sBuffer"3"false) || StrEqual(sBuffer"blue"false))
    {
        return 
TFTeam_Blue;
    }

    return 
TFTeam_Unassigned;
}

stock void TF2_GetTeamName(TFTeam teamchar[] sBufferint iMaxlength)
{
    switch (
team)
    {
    case 
TFTeam_Unassigned:
        {
            
Format(sBufferiMaxlength"unassigned");
        }

    case 
TFTeam_Spectator:
        {
            
Format(sBufferiMaxlength"spectator");
        }

    case 
TFTeam_Red:
        {
            
Format(sBufferiMaxlength"red");
        }

    case 
TFTeam_Blue:
        {
            
Format(sBufferiMaxlength"blue");
        }
    }
}

// This is basically TF2_GetClass() but it works better
stock TFClassType TF2_GetClassFromString(const char[] sBuffer)
{
    if (
StrEqual(sBuffer"scout"false))
    {
        return 
TFClass_Scout;
    }

    if (
StrEqual(sBuffer"soldier"false))
    {
        return 
TFClass_Soldier;
    }

    if (
StrEqual(sBuffer"pyro"false))
    {
        return 
TFClass_Pyro;
    }

    if (
StrEqual(sBuffer"demoman"false))
    {
        return 
TFClass_DemoMan;
    }

    if (
StrEqual(sBuffer"heavy"false))
    {
        return 
TFClass_Heavy;
    }

    if (
StrEqual(sBuffer"engineer"false))
    {
        return 
TFClass_Engineer;
    }

    if (
StrEqual(sBuffer"medic"false))
    {
        return 
TFClass_Medic;
    }

    if (
StrEqual(sBuffer"sniper"false))
    {
        return 
TFClass_Sniper;
    }

    if (
StrEqual(sBuffer"spy"false))
    {
        return 
TFClass_Spy;
    }

    return 
TFClass_Unknown;
}

stock void TF2_GetClassName(TFClassType class, char[] sBufferint iMaxlength)
{
    switch (class)
    {
    case 
TFClass_Scout:
        {
            
Format(sBufferiMaxlength"scout");
        }

    case 
TFClass_Soldier:
        {
            
Format(sBufferiMaxlength"soldier");
        }

    case 
TFClass_Pyro:
        {
            
Format(sBufferiMaxlength"pyro");
        }

    case 
TFClass_DemoMan:
        {
            
Format(sBufferiMaxlength"demoman");
        }

    case 
TFClass_Heavy:
        {
            
Format(sBufferiMaxlength"heavy");
        }

    case 
TFClass_Engineer:
        {
            
Format(sBufferiMaxlength"engineer");
        }

    case 
TFClass_Medic:
        {
            
Format(sBufferiMaxlength"medic");
        }

    case 
TFClass_Sniper:
        {
            
Format(sBufferiMaxlength"sniper");
        }

    case 
TFClass_Spy:
        {
            
Format(sBufferiMaxlength"spy");
        }

    case 
TFClass_Unknown:
        {
            
Format(sBufferiMaxlength"unknown");
        }
    }
}

stock int TF2_GetBotCount(TFTeam teamTFClassType class)
{
    
int iCount 1;
    for (
int i 1<= MaxClientsi++)
    {
        if (
IsClientInGame(i) && IsFakeClient(i) && TF2_GetClientTeam(i) == team && TF2_GetPlayerClass(i) == class)
        {
            
iCount++;
        }
    }

    return 
iCount;
}

stock bool TF2_CreateBot(const char[] sNameTFTeam teamTFClassType class)
{
    
int iBot CreateFakeClient(sName);
    
PrintToChatAll("Debug: Creating %s, %s, %s"sNameteam, class);
    if (
iBot != 0)
    {
        
TF2_ChangeClientTeam(iBotteam);
        
TF2_SetPlayerClass(iBot, class);
        
TF2_RespawnPlayer(iBot);
        return 
true;
    }

    return 
false;
}

stock void CapitalizeFirstLetter(char[] sBuffer)
{
    
sBuffer[0] = CharToUpper(sBuffer[0]);


int GetRandomUInt(int minint max)
{
    return 
RoundToFloor(GetURandomFloat() * (max min 1)) + min;

Hello,

Thank you for the reply! That did the trick, thanks! Yeah, the bots are intended to not be able to move. Out of curiosity, what made the issue occur with the GetRandomInt() function? Is it something to do with caching or along those lines?

Thank you,
Grant

Last edited by ThatKidWhoGames; 01-17-2021 at 13:50.
ThatKidWhoGames 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 03:39.


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