Code:
void CGeneral::FakeClientCommand(CClient *pClient, const char *fmt, ...)
{
if (!pClient->Valid())
return; // reliability check
edict_t *pFakeClient = pClient->edict();
va_list argptr;
char command[256];
int length, fieldstart, fieldstop, i, index, stringindex = 0;
// concatenate all the arguments in one string
va_start(argptr, fmt);
_vsnprintf(command, sizeof(command), fmt, argptr);
va_end(argptr);
if (*command == 0)
return; // if nothing in the command buffer, return
m_bIsFakeClientCommand = TRUE; // set the "fakeclient command" flag
length = strlen(command); // get the total length of the command string
// process all individual commands (separated by a semicolon) one each a time
while (stringindex < length) {
fieldstart = stringindex; // save field start position (first character)
while (stringindex < length && command[stringindex] != ';')
stringindex++; // reach end of field
if (command[stringindex - 1] == '\n')
fieldstop = stringindex - 2; // discard any trailing '\n' if needed
else
fieldstop = stringindex - 1; // save field stop position (last character before semicolon or end)
for (i = fieldstart; i <= fieldstop; i++)
m_szCmdArgv[i - fieldstart] = command[i]; // store the field value in the g_argv global string
m_szCmdArgv[i - fieldstart] = 0; // terminate the string
stringindex++; // move the overall string index one step further to bypass the semicolon
index = 0;
m_iCmdArgc = 0; // let's now parse that command and count the different arguments
+ m_pszCmdArgs = "";
// count the number of arguments
while (index < i - fieldstart) {
while (index < i - fieldstart && m_szCmdArgv[index] == ' ')
index++; // ignore spaces
+ if (m_iCmdArgc == 1) {
+ m_pszCmdArgs = &m_szCmdArgv[index];
+ }
// is this field a group of words between quotes or a single word ?
if (m_szCmdArgv[index] == '"') {
index++; // move one step further to bypass the quote
while (index < i - fieldstart && m_szCmdArgv[index] != '"')
index++; // reach end of field
index++; // move one step further to bypass the quote
} else {
while (index < i - fieldstart && m_szCmdArgv[index] != ' ')
index++; // this is a single word, so reach the end of field
}
m_iCmdArgc++; // we have processed one argument more
}
ClientCommand(pFakeClient); // tell now the MOD DLL to execute this ClientCommand...
}
m_szCmdArgv[0] = 0; // when it's done, reset the g_argv field
m_bIsFakeClientCommand = FALSE; // reset the "fakeclient command" flag
m_iCmdArgc = 0; // and the argument count
}
...and:
Code:
const char *pfnCmd_Args(void)
{
if (g_General.IsFakeClientCommand())
return g_General.m_pszArgs;
return (*g_engfuncs.pfnCmd_Args)();
}
m_pszCmdArgs is (char *m_pszCmdArgs
Note that the pfnCmd_Args() isn't supposed to return the command name (not only "say" "say_team" but also
whatever command name). It isn't "bug in HL engine". You can look at the cmd.c file in Quake1 source code to find it out.
PS, This is PMB's code, however botman's original one also has this bug. It won't affect too much to CS, but if some MOD use pfnCmd_Args() to do something this will cause problem for bots.