FL_FAKECLIENT
flag which we need to detect which players are bots. This flag is used to distinguish real players from bots.
Change this:pev->flags &= FL_PROXY | FL_FAKECLIENT; // keep proxy and fakeclient flags set by engine
pev->flags |= FL_CLIENT;
If you are making an Opposing Force mod you will need to update a few other places:CBasePlayer::Menu_Char_Input
there is code to reset players that are going from observer mode to joining a time. This line is part of that:
pev->flags = FL_CLIENT;
Change this to:
pev->flags &= FL_FAKECLIENT;
pev->flags |= FL_CLIENT;
Much like the code above this keeps the fake client flag and sets the client flag as originally intended. The proxy flag isn't needed here because it only applies to HLTV spectators, who can't participate in gameplay.CDisplacerBall::BallTouch
there is code to teleport players hit by Displacer balls. This line is part of that:
pPlayer->pev->flags = FL_CLIENT;
Change this to:
//Clear any flags set on player (onground, using grapple, etc).
pPlayer->pev->flags &= FL_FAKECLIENT;
pPlayer->pev->flags |= FL_CLIENT;
You should check for any other occurrences of the pev->flags
variable (search for ->flags
and .flags
as well to be sure) being changed to catch cases where the flag is removed.
BOOL IsNetClient() override { return (pev->flags & FL_FAKECLIENT) == 0; }
This is required mainly to make certain entities ignore bots.
/**
* @brief True if the player is currently connected to the server.
* Should only be false in multiplayer games, for players that have disconnected.
*/
bool m_bIsConnected = true;
Before this line:auto pPlayer = reinterpret_cast<CBasePlayer*>(GET_PRIVATE(pEntity));
if (pPlayer)
{
pPlayer->m_bIsConnected = false;
}
This will let us check m_bIsConnected
to see if the player is connected.
game.cpp
.#include "client.h"
We're going to need some of the functions declared in that header.g_engfuncs.pfnAddServerCommand("sv_addbot", []()
{
if (CMD_ARGC() != 2)
{
g_engfuncs.pfnServerPrint("Usage: sv_addbot <bot_name>");
}
const char* name = CMD_ARGV(1);
//The engine will validate the name and change it to "unnamed" if it's not valid.
//Any duplicates will be disambiguated by prepending a (%d) where %d is a number.
const auto fakeClient = g_engfuncs.pfnCreateFakeClient(name);
if (!fakeClient)
{
return;
}
//Use the netname variable here in case the engine changed it for some reason (usually duplicate names).
//Use localhost as the IP address.
char reject[128];
if (0 == ClientConnect(fakeClient, STRING(fakeClient->v.netname), "127.0.0.1", reject))
{
//Bot was refused connection, kick it from the server to free the slot.
SERVER_COMMAND(UTIL_VarArgs("kick %s\n", STRING(fakeClient->v.netname)));
return;
}
//Finish connecting, create player.
ClientPutInServer(fakeClient);
//Do remaining logic at least one frame later to avoid race conditions.
});
Compile your mod, run it and start a multiplayer server. You can now run the console command sv_addbot foo
to add a bot with the name foo
.client.cpp
and scroll to this function:static float g_LastBotUpdateTime = 0;
Add this code to the end of the function:
// Handle level changes and other problematic time changes.
float frametime = gpGlobals->time - g_LastBotUpdateTime;
if (frametime > 0.25f || frametime < 0)
{
frametime = 0;
}
const byte msec = byte(frametime * 1000);
g_LastBotUpdateTime = gpGlobals->time;
for (int i = 1; i <= gpGlobals->maxClients; ++i)
{
auto player = static_cast<CBasePlayer*>(UTIL_PlayerByIndex(i));
if (!player)
{
continue;
}
if (!player->m_bIsConnected)
{
continue;
}
if ((player->pev->flags & FL_FAKECLIENT) == 0)
{
continue;
}
//If bot is newly created finish setup here.
//Run bot think here.
//Now update the bot.
g_engfuncs.pfnRunPlayerMove(player->edict(), player->pev->angles, 0, 0, 0, player->pev->button, player->pev->impulse, msec);
}
This for loop enumerates all player slots and filters out slots that aren't in use and that aren't bots.g_engfuncs.pfnRunPlayerMove
tells the engine to run the player movement code using the given angles, forward, side and up movement speeds, button bit mask and impulse value, and the frametime.sv_addbot foo
to add a bot with the name foo
.kick "bot_name"
.
StartFrame
, preferably in a separate function called from there. If you try to make the bot join a team immediately the server will send messages to the client before the client has received information about the bot. This will cause glitches like the bot not appearing on the scoreboard.You must log in to post a comment. You can login or register a new account.