350 lines
8.0 KiB
C++
Executable File
350 lines
8.0 KiB
C++
Executable File
/* AMX Mod X
|
|
*
|
|
* by the AMX Mod X Development Team
|
|
* originally developed by OLO
|
|
*
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation; either version 2 of the License, or (at
|
|
* your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
* In addition, as a special exception, the author gives permission to
|
|
* link the code of this program with the Half-Life Game Engine ("HL
|
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
|
* respects for all of the code used other than the HL Engine and MODs
|
|
* from Valve. If you modify this file, you may extend this exception
|
|
* to your version of the file, but you are not obligated to do so. If
|
|
* you do not wish to do so, delete this exception statement from your
|
|
* version.
|
|
*/
|
|
|
|
#include <time.h>
|
|
#include "amxmodx.h"
|
|
|
|
#ifdef __linux__
|
|
#define _vsnprintf vsnprintf
|
|
#endif
|
|
|
|
char *UTIL_VarArgs(const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
static char string[4096];
|
|
|
|
va_start(ap, fmt);
|
|
_vsnprintf(string, sizeof(string)-1, fmt, ap);
|
|
va_end(ap);
|
|
|
|
return string;
|
|
}
|
|
|
|
int UTIL_ReadFlags(const char* c)
|
|
{
|
|
int flags = 0;
|
|
|
|
while (*c)
|
|
flags |= (1<<(*c++ - 'a'));
|
|
|
|
return flags;
|
|
}
|
|
|
|
void UTIL_GetFlags(char* f, int a)
|
|
{
|
|
for (int i = 'a'; i <= 'z'; ++i)
|
|
{
|
|
if (a & 1) *f++ = i;
|
|
a >>= 1;
|
|
}
|
|
|
|
*f = 0;
|
|
}
|
|
|
|
/* warning - don't pass here const string */
|
|
void UTIL_ShowMenu(edict_t* pEdict, int slots, int time, char *menu, int mlen)
|
|
{
|
|
char *n = menu;
|
|
char c = 0;
|
|
int a;
|
|
|
|
if (!gmsgShowMenu)
|
|
return; // some games don't support ShowMenu (Firearms)
|
|
|
|
while (*n)
|
|
{
|
|
a = mlen;
|
|
if (a > 175) a = 175;
|
|
mlen -= a;
|
|
c = *(n+=a);
|
|
*n = 0;
|
|
|
|
MESSAGE_BEGIN(MSG_ONE, gmsgShowMenu, NULL, pEdict);
|
|
WRITE_SHORT(slots);
|
|
WRITE_CHAR(time);
|
|
WRITE_BYTE(c ? TRUE : FALSE);
|
|
WRITE_STRING(menu);
|
|
MESSAGE_END();
|
|
*n = c;
|
|
menu = n;
|
|
}
|
|
}
|
|
|
|
/* warning - don't pass here const string */
|
|
void UTIL_ShowMOTD(edict_t *client, char *motd, int mlen, const char *name)
|
|
{
|
|
if (!gmsgMOTD)
|
|
return; // :TODO: Maybe output a warning log?
|
|
|
|
if (gmsgServerName)
|
|
{
|
|
MESSAGE_BEGIN(MSG_ONE, gmsgServerName, NULL, client);
|
|
WRITE_STRING(name);
|
|
MESSAGE_END();
|
|
}
|
|
|
|
char *n = motd;
|
|
char c = 0;
|
|
int a;
|
|
|
|
while (*n)
|
|
{
|
|
a = mlen;
|
|
if (a > 175) a = 175;
|
|
mlen -= a;
|
|
c = *(n += a);
|
|
*n = 0;
|
|
|
|
MESSAGE_BEGIN(MSG_ONE, gmsgMOTD, NULL, client);
|
|
WRITE_BYTE(c ? FALSE : TRUE);
|
|
WRITE_STRING(motd);
|
|
MESSAGE_END();
|
|
*n = c;
|
|
motd = n;
|
|
}
|
|
|
|
if (gmsgServerName)
|
|
{
|
|
MESSAGE_BEGIN(MSG_ONE, gmsgServerName, NULL, client);
|
|
WRITE_STRING(hostname->string);
|
|
MESSAGE_END();
|
|
}
|
|
}
|
|
|
|
void UTIL_IntToString(int value, char *output)
|
|
{
|
|
static const char *words[] =
|
|
{"zero ","one ","two ","three ","four ",
|
|
"five ", "six ","seven ","eight ","nine ","ten ",
|
|
"eleven ","twelve ","thirteen ","fourteen ","fifteen ",
|
|
"sixteen ","seventeen ","eighteen ","nineteen ",
|
|
"twenty ","thirty ","fourty ", "fifty ","sixty ",
|
|
"seventy ","eighty ","ninety ",
|
|
"hundred ","thousand "};
|
|
|
|
*output = 0;
|
|
if (value < 0) value = -value;
|
|
int tho = value / 1000;
|
|
int aaa = 0;
|
|
|
|
if (tho)
|
|
{
|
|
aaa += sprintf(&output[aaa], words[tho]);
|
|
aaa += sprintf(&output[aaa], words[29]);
|
|
value = value % 1000;
|
|
}
|
|
|
|
int hun = value / 100;
|
|
|
|
if (hun)
|
|
{
|
|
aaa += sprintf(&output[aaa], words[hun]);
|
|
aaa += sprintf(&output[aaa], words[28]);
|
|
value = value % 100;
|
|
}
|
|
|
|
int ten = value / 10;
|
|
int unit = value % 10;
|
|
|
|
if (ten)
|
|
aaa += sprintf(&output[aaa], words[(ten > 1) ? (ten + 18) : (unit + 10)]);
|
|
|
|
if (ten != 1 && (unit || (!value && !hun && !tho)))
|
|
sprintf(&output[aaa], words[unit]);
|
|
}
|
|
|
|
char* UTIL_SplitHudMessage(const char *src)
|
|
{
|
|
static char message[512];
|
|
short b = 0, d = 0, e = 0, c = -1;
|
|
|
|
while (src[d] && e < 480)
|
|
{
|
|
if (src[d] == ' ')
|
|
{
|
|
c = e;
|
|
}
|
|
else if (src[d] == '\n')
|
|
{
|
|
c = -1;
|
|
b = 0;
|
|
}
|
|
|
|
message[e++] = src[d++];
|
|
|
|
if (++b == 69)
|
|
{
|
|
if (c == -1)
|
|
{
|
|
message[e++] = '\n';
|
|
b = 0;
|
|
} else {
|
|
message[c] = '\n';
|
|
b = e - c - 1;
|
|
c = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
message[e] = 0;
|
|
return message;
|
|
}
|
|
|
|
unsigned short FixedUnsigned16(float value, float scale)
|
|
{
|
|
int output = (int)(value * scale);
|
|
|
|
if (output < 0)
|
|
output = 0;
|
|
else if (output > 0xFFFF)
|
|
output = 0xFFFF;
|
|
|
|
return (unsigned short)output;
|
|
}
|
|
|
|
short FixedSigned16(float value, float scale)
|
|
{
|
|
int output = (int)(value * scale);
|
|
|
|
if (output > 32767)
|
|
output = 32767;
|
|
else if (output < -32768)
|
|
output = -32768;
|
|
|
|
return (short)output;
|
|
}
|
|
|
|
void UTIL_HudMessage(edict_t *pEntity, const hudtextparms_t &textparms, char *pMessage)
|
|
{
|
|
if (pEntity)
|
|
MESSAGE_BEGIN(MSG_ONE_UNRELIABLE, SVC_TEMPENTITY, NULL, pEntity);
|
|
else
|
|
MESSAGE_BEGIN(MSG_BROADCAST, SVC_TEMPENTITY);
|
|
|
|
WRITE_BYTE(29);
|
|
WRITE_BYTE(textparms.channel & 0xFF);
|
|
WRITE_SHORT(FixedSigned16(textparms.x, (1<<13)));
|
|
WRITE_SHORT(FixedSigned16(textparms.y, (1<<13)));
|
|
WRITE_BYTE(textparms.effect);
|
|
WRITE_BYTE(textparms.r1);
|
|
WRITE_BYTE(textparms.g1);
|
|
WRITE_BYTE(textparms.b1);
|
|
WRITE_BYTE(0);
|
|
WRITE_BYTE(255);
|
|
WRITE_BYTE(255);
|
|
WRITE_BYTE(250);
|
|
WRITE_BYTE(0);
|
|
WRITE_SHORT(FixedUnsigned16(textparms.fadeinTime, (1<<8)));
|
|
WRITE_SHORT(FixedUnsigned16(textparms.fadeoutTime, (1<<8)));
|
|
WRITE_SHORT(FixedUnsigned16(textparms.holdTime, (1<<8)));
|
|
|
|
if (textparms.effect == 2)
|
|
WRITE_SHORT(FixedUnsigned16(textparms.fxTime, (1<<8)));
|
|
|
|
WRITE_STRING(pMessage);
|
|
MESSAGE_END();
|
|
}
|
|
|
|
/* warning - buffer of msg must be longer than 190 chars!
|
|
(here in AMX it is always longer) */
|
|
void UTIL_ClientPrint(edict_t *pEntity, int msg_dest, char *msg)
|
|
{
|
|
if (!gmsgTextMsg)
|
|
return; // :TODO: Maybe output a warning log?
|
|
|
|
char c = msg[190];
|
|
msg[190] = 0; // truncate without checking with strlen()
|
|
|
|
if (pEntity)
|
|
MESSAGE_BEGIN(MSG_ONE, gmsgTextMsg, NULL, pEntity);
|
|
else
|
|
MESSAGE_BEGIN(MSG_BROADCAST, gmsgTextMsg);
|
|
|
|
WRITE_BYTE(msg_dest);
|
|
WRITE_STRING(msg);
|
|
MESSAGE_END();
|
|
msg[190] = c;
|
|
}
|
|
|
|
// UTIL_FakeClientCommand
|
|
// PURPOSE: Sends a fake client command to GameDLL
|
|
// HOW DOES IT WORK:
|
|
// 1) Stores command and arguments into a global and sets the global "fake" flag to true
|
|
// 2) Invokes ClientCommand in GameDLL
|
|
// 3) meta_api.cpp overrides Cmd_Args, Cmd_Argv, Cmd_Argc and gives them fake values if the "fake" flag is set
|
|
// 4) unsets the global "fake" flag
|
|
void UTIL_FakeClientCommand(edict_t *pEdict, const char *cmd, const char *arg1, const char *arg2)
|
|
{
|
|
if (!cmd)
|
|
return; // no command
|
|
|
|
// store command
|
|
g_fakecmd.argv[0] = cmd;
|
|
// if only arg2 is passed, swap the arguments
|
|
if (!arg1 && arg2)
|
|
{
|
|
arg1 = arg2;
|
|
arg2 = NULL;
|
|
}
|
|
|
|
// store arguments
|
|
if (arg2)
|
|
{ // both arguments passed
|
|
g_fakecmd.argc = 3; // 2 arguments + 1 command
|
|
// store arguments
|
|
g_fakecmd.argv[1] = arg1;
|
|
g_fakecmd.argv[2] = arg2;
|
|
// build argument line
|
|
snprintf(g_fakecmd.args, 255, "%s %s", arg1, arg2);
|
|
// if snprintf reached 255 chars limit, this will make sure there will be no access violation
|
|
g_fakecmd.args[255] = 0;
|
|
}
|
|
else if (arg1)
|
|
{ // only one argument passed
|
|
g_fakecmd.argc = 2; // 1 argument + 1 command
|
|
// store argument
|
|
g_fakecmd.argv[1] = arg1;
|
|
// build argument line
|
|
snprintf(g_fakecmd.args, 255, "%s", arg1);
|
|
// if snprintf reached 255 chars limit, this will make sure there will be no access violation
|
|
g_fakecmd.args[255] = 0;
|
|
}
|
|
else
|
|
g_fakecmd.argc = 1; // no argmuents -> only one command
|
|
|
|
// set the global "fake" flag so the Cmd_Arg* functions will be superceded
|
|
g_fakecmd.fake = true;
|
|
// tell the GameDLL that the client sent a command
|
|
MDLL_ClientCommand(pEdict);
|
|
// unset the global "fake" flag
|
|
g_fakecmd.fake = false;
|
|
}
|