15a14a0a43
* Fix newlines for TextMsg * Fix newlines for SayText * Adjust comments * Replace hardcoded detination value with HUD_* constants * Make sure only official mods can use format string * Fix typos * Split condition for readability * CS only: Fix newlines in TextMsg and with print_center
4850 lines
113 KiB
C++
Executable File
4850 lines
113 KiB
C++
Executable File
// vim: set ts=4 sw=4 tw=99 noet:
|
|
//
|
|
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
// Copyright (C) The AMX Mod X Development Team.
|
|
//
|
|
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
// https://alliedmods.net/amxmodx-license
|
|
|
|
#include <time.h>
|
|
#include <amtl/am-utility.h>
|
|
#include "amxmodx.h"
|
|
#include "CMenu.h"
|
|
#include "newmenus.h"
|
|
#include "natives.h"
|
|
#include "debugger.h"
|
|
#include "binlog.h"
|
|
#include "libraries.h"
|
|
#include "CFlagManager.h"
|
|
#include "nongpl_matches.h"
|
|
#include "format.h"
|
|
|
|
extern CFlagManager FlagMan;
|
|
ke::Vector<CAdminData *> DynamicAdmins;
|
|
|
|
static cell AMX_NATIVE_CALL get_xvar_id(AMX *amx, cell *params)
|
|
{
|
|
int len;
|
|
char* sName = get_amxstring(amx, params[1], 0, len);
|
|
cell ptr;
|
|
|
|
if (!strcmp(sName, "MaxClients") || !strcmp(sName, "NULL_STRING") || !strcmp(sName, "NULL_VECTOR"))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
for (CPluginMngr::iterator a = g_plugins.begin(); a ; ++a)
|
|
{
|
|
if ((*a).isValid() && amx_FindPubVar((*a).getAMX(), sName, &ptr) == AMX_ERR_NONE)
|
|
return g_xvars.put((*a).getAMX(), get_amxaddr((*a).getAMX(), ptr));
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_xvar_num(AMX *amx, cell *params)
|
|
{
|
|
return g_xvars.getValue(params[1]);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL set_xvar_num(AMX *amx, cell *params)
|
|
{
|
|
if (g_xvars.setValue(params[1], params[2]))
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid xvar id");
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL xvar_exists(AMX *amx, cell *params)
|
|
{
|
|
return (get_xvar_id(amx, params) != -1) ? 1 : 0;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL emit_sound(AMX *amx, cell *params) /* 7 param */
|
|
{
|
|
int len;
|
|
char* szSample = get_amxstring(amx, params[3], 0, len);
|
|
REAL vol = amx_ctof(params[4]);
|
|
REAL att = amx_ctof(params[5]);
|
|
int channel = params[2];
|
|
int pitch = params[7];
|
|
int flags = params[6];
|
|
|
|
if (params[1] == 0)
|
|
{
|
|
for (int i = 1; i <= gpGlobals->maxClients ; ++i)
|
|
{
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(i);
|
|
|
|
if (pPlayer->ingame)
|
|
EMIT_SOUND_DYN2(pPlayer->pEdict, channel, szSample, vol, att, flags, pitch);
|
|
}
|
|
} else {
|
|
edict_t* pEdict = TypeConversion.id_to_edict(params[1]);
|
|
|
|
if (!FNullEnt(pEdict))
|
|
EMIT_SOUND_DYN2(pEdict, channel, szSample, vol, att, flags, pitch);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL server_print(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
int len;
|
|
g_langMngr.SetDefLang(LANG_SERVER); // Default language = server
|
|
char* message = format_amxstring(amx, params, 1, len);
|
|
|
|
if (len > 254)
|
|
len = 254;
|
|
|
|
message[len++] = '\n';
|
|
message[len] = 0;
|
|
SERVER_PRINT(message);
|
|
|
|
return len;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL engclient_print(AMX *amx, cell *params) /* 3 param */
|
|
{
|
|
int len = 0;
|
|
char *msg;
|
|
PRINT_TYPE type = (PRINT_TYPE)params[2];
|
|
|
|
if (params[1] == 0)
|
|
{
|
|
for (int i = 1; i <= gpGlobals->maxClients; ++i)
|
|
{
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(i);
|
|
|
|
if ((type == print_console && pPlayer->initialized) || pPlayer->ingame)
|
|
{
|
|
g_langMngr.SetDefLang(i);
|
|
msg = format_amxstring(amx, params, 3, len);
|
|
msg[len++] = '\n';
|
|
msg[len] = 0;
|
|
CLIENT_PRINT(pPlayer->pEdict, type, msg);
|
|
}
|
|
}
|
|
} else {
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid player id %d", index);
|
|
return 0;
|
|
}
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
if ((type == print_console && pPlayer->initialized) || pPlayer->ingame)
|
|
{
|
|
g_langMngr.SetDefLang(index);
|
|
msg = format_amxstring(amx, params, 3, len);
|
|
msg[len++] = '\n';
|
|
msg[len] = 0;
|
|
CLIENT_PRINT(pPlayer->pEdict, type, msg);
|
|
}
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL console_cmd(AMX *amx, cell *params) /* 2 param */
|
|
{
|
|
int index = params[1];
|
|
g_langMngr.SetDefLang(index);
|
|
int len;
|
|
char* cmd = format_amxstring(amx, params, 2, len);
|
|
|
|
cmd[len++] = '\n';
|
|
cmd[len] = 0;
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
{
|
|
SERVER_COMMAND(cmd);
|
|
} else {
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
if (!pPlayer->IsBot() && pPlayer->initialized)
|
|
CLIENT_COMMAND(pPlayer->pEdict, "%s", cmd);
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
// The server console is limited to 255 bytes, including the newline.
|
|
// The client console is limited to 127 bytes, including the newline.
|
|
static cell AMX_NATIVE_CALL console_print(AMX *amx, cell *params) /* 2 param */
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
{
|
|
g_langMngr.SetDefLang(LANG_SERVER);
|
|
}
|
|
else
|
|
{
|
|
g_langMngr.SetDefLang(index);
|
|
}
|
|
|
|
int len;
|
|
char* message = format_amxstring(amx, params, 2, len);
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients) // Server console
|
|
{
|
|
if (len > 254) // Server console truncates after byte 255. (254 + \n = 255)
|
|
{
|
|
len = 254;
|
|
if ((message[len - 1] & 1 << 7))
|
|
{
|
|
len -= UTIL_CheckValidChar(message + len - 1); // Don't truncate a multi-byte character
|
|
}
|
|
}
|
|
message[len++] = '\n';
|
|
message[len] = 0;
|
|
|
|
SERVER_PRINT(message);
|
|
}
|
|
else // A specific player's console
|
|
{
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
if (pPlayer->ingame && !pPlayer->IsBot())
|
|
{
|
|
if (len > 125) // Client console truncates after byte 127. (125 + \n\n = 127)
|
|
{
|
|
len = 125;
|
|
if ((message[len - 1] & 1 << 7))
|
|
{
|
|
len -= UTIL_CheckValidChar(message + len - 1); // Don't truncate a multi-byte character
|
|
}
|
|
}
|
|
message[len++] = '\n';
|
|
|
|
const auto canUseFormatString = g_official_mod && !g_bmod_dod; // Temporary exclusion for DoD until officially supported
|
|
|
|
if (canUseFormatString)
|
|
{
|
|
message[len++] = '\n'; // Double newline is required when pre-formatted string in TextMsg is passed as argument.
|
|
}
|
|
|
|
message[len] = 0;
|
|
|
|
UTIL_ClientPrint(pPlayer->pEdict, HUD_PRINTCONSOLE, message);
|
|
}
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
// print_notify and print_console are limited to 127 bytes, including the newline.
|
|
// print_chat and print_center are not limited by *this* function.
|
|
static cell AMX_NATIVE_CALL client_print(AMX *amx, cell *params) /* 3 param */
|
|
{
|
|
int len = 0;
|
|
char *msg;
|
|
|
|
const auto canUseFormatString = g_official_mod && !g_bmod_dod; // Temporary exclusion for DoD until officially supported
|
|
|
|
if (params[1] == 0) // 0 = All players
|
|
{
|
|
for (int i = 1; i <= gpGlobals->maxClients; ++i)
|
|
{
|
|
CPlayer *pPlayer = GET_PLAYER_POINTER_I(i);
|
|
|
|
if (pPlayer->ingame && !pPlayer->IsBot())
|
|
{
|
|
g_langMngr.SetDefLang(i);
|
|
msg = format_amxstring(amx, params, 3, len);
|
|
|
|
// Client console truncates after byte 127.
|
|
// If format string is used, limit includes double new lines (125 + \n\n), otherwise one new line (126 + \n).
|
|
const auto bytesLimit = canUseFormatString ? 125 : 126;
|
|
|
|
if (g_bmod_cstrike && params[2] == HUD_PRINTCENTER) // Likely a temporary fix.
|
|
{
|
|
for (int j = 0; j < len; ++j)
|
|
{
|
|
if (msg[j] == '\n')
|
|
{
|
|
msg[j] = '\r';
|
|
}
|
|
}
|
|
}
|
|
else if (((params[2] == HUD_PRINTNOTIFY) || (params[2] == HUD_PRINTCONSOLE)) && (len > bytesLimit))
|
|
{
|
|
len = bytesLimit;
|
|
if ((msg[len - 1] & 1 << 7))
|
|
{
|
|
len -= UTIL_CheckValidChar(msg + len - 1); // Don't truncate a multi-byte character
|
|
}
|
|
}
|
|
msg[len++] = '\n';
|
|
|
|
if (canUseFormatString)
|
|
{
|
|
if (!g_bmod_cstrike || params[2] == HUD_PRINTNOTIFY || params[2] == HUD_PRINTCONSOLE)
|
|
{
|
|
msg[len++] = '\n'; // Double newline is required when pre-formatted string in TextMsg is passed as argument.
|
|
}
|
|
}
|
|
|
|
msg[len] = 0;
|
|
|
|
UTIL_ClientPrint(pPlayer->pEdict, params[2], msg);
|
|
}
|
|
}
|
|
}
|
|
else // A specific player
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid player id %d", index);
|
|
return 0;
|
|
}
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
if (pPlayer->ingame && !pPlayer->IsBot())
|
|
{
|
|
g_langMngr.SetDefLang(index);
|
|
|
|
msg = format_amxstring(amx, params, 3, len);
|
|
|
|
// Client console truncates after byte 127.
|
|
// If format string is used, limit includes double new lines (125 + \n\n), otherwise one new line (126 + \n).
|
|
const auto bytesLimit = canUseFormatString ? 125 : 126;
|
|
|
|
if (g_bmod_cstrike && params[2] == HUD_PRINTCENTER) // Likely a temporary fix.
|
|
{
|
|
for (int j = 0; j < len; ++j)
|
|
{
|
|
if (msg[j] == '\n')
|
|
{
|
|
msg[j] = '\r';
|
|
}
|
|
}
|
|
}
|
|
else if (((params[2] == HUD_PRINTNOTIFY) || (params[2] == HUD_PRINTCONSOLE)) && (len > bytesLimit)) // Client console truncates after byte 127. (125 + \n\n = 127)
|
|
{
|
|
len = bytesLimit;
|
|
if ((msg[len - 1] & 1 << 7))
|
|
{
|
|
len -= UTIL_CheckValidChar(msg + len - 1); // Don't truncate a multi-byte character
|
|
}
|
|
}
|
|
msg[len++] = '\n';
|
|
|
|
if (canUseFormatString)
|
|
{
|
|
if (!g_bmod_cstrike || params[2] == HUD_PRINTNOTIFY || params[2] == HUD_PRINTCONSOLE)
|
|
{
|
|
msg[len++] = '\n'; // Double newline is required when pre-formatted string in TextMsg is passed as argument.
|
|
}
|
|
}
|
|
|
|
msg[len] = 0;
|
|
|
|
UTIL_ClientPrint(pPlayer->pEdict, params[2], msg);
|
|
}
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL client_print_color(AMX *amx, cell *params) /* 3 param */
|
|
{
|
|
if (!g_bmod_cstrike)
|
|
{
|
|
params[2] = print_chat;
|
|
return client_print(amx, params);
|
|
}
|
|
|
|
int len = 0;
|
|
char *msg;
|
|
int index = params[1];
|
|
int sender = params[2];
|
|
|
|
if (sender < print_team_blue || sender > gpGlobals->maxClients)
|
|
{
|
|
sender = print_team_default;
|
|
}
|
|
else if (sender < print_team_default)
|
|
{
|
|
sender = abs(sender) + 32; // align indexes to the TeamInfo ones.
|
|
}
|
|
|
|
if (!index)
|
|
{
|
|
for (int i = 1; i <= gpGlobals->maxClients; ++i)
|
|
{
|
|
CPlayer *pPlayer = GET_PLAYER_POINTER_I(i);
|
|
|
|
if (pPlayer->ingame && !pPlayer->IsBot())
|
|
{
|
|
g_langMngr.SetDefLang(i);
|
|
msg = format_amxstring(amx, params, 3, len);
|
|
|
|
if (static_cast<byte>(*msg) > 4) // Insert default color code at the start if not present, otherwise message will not be colored.
|
|
{
|
|
memmove(msg + 1, msg, ke::Min(len++, 191));
|
|
*msg = 1;
|
|
}
|
|
|
|
if (len > 187) // Max available bytes: 188
|
|
{
|
|
len = 187;
|
|
if ((msg[len - 1] & 1 << 7))
|
|
{
|
|
len -= UTIL_CheckValidChar(msg + len - 1); // Don't truncate a multi-byte character
|
|
}
|
|
}
|
|
|
|
msg[len] = 0;
|
|
|
|
UTIL_ClientSayText(pPlayer->pEdict, sender ? sender : i, msg);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid player id %d", index);
|
|
return 0;
|
|
}
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
if (pPlayer->ingame && !pPlayer->IsBot())
|
|
{
|
|
g_langMngr.SetDefLang(index);
|
|
|
|
msg = format_amxstring(amx, params, 3, len);
|
|
|
|
if (static_cast<byte>(*msg) > 4) // Insert default color code at the start if not present, otherwise message will not be colored.
|
|
{
|
|
memmove(msg + 1, msg, ke::Min(len++, 191));
|
|
*msg = 1;
|
|
}
|
|
|
|
if (len > 187) // Max available bytes: 188
|
|
{
|
|
len = 187;
|
|
if ((msg[len - 1] & 1 << 7))
|
|
{
|
|
len -= UTIL_CheckValidChar(msg + len - 1); // Don't truncate a multi-byte character
|
|
}
|
|
}
|
|
|
|
msg[len] = 0;
|
|
|
|
UTIL_ClientSayText(pPlayer->pEdict, sender ? sender : index, msg);
|
|
}
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL show_motd(AMX *amx, cell *params) /* 3 param */
|
|
{
|
|
int ilen;
|
|
const char* szHead = get_amxstring(amx, params[3], 0, ilen);
|
|
|
|
if (!ilen)
|
|
szHead = hostname->string;
|
|
|
|
char* szBody = get_amxstring(amx, params[2], 1, ilen);
|
|
int iFile = 0;
|
|
char* sToShow = NULL; // = szBody;
|
|
|
|
if (ilen < 128)
|
|
sToShow = (char*)LOAD_FILE_FOR_ME(szBody, &iFile);
|
|
|
|
if (!iFile)
|
|
sToShow = szBody;
|
|
else
|
|
ilen = iFile;
|
|
|
|
if (params[1] == 0)
|
|
{
|
|
for (int i = 1; i <= gpGlobals->maxClients; ++i)
|
|
{
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(i);
|
|
|
|
if (pPlayer->ingame && !pPlayer->IsBot())
|
|
UTIL_ShowMOTD(pPlayer->pEdict, sToShow, ilen, szHead);
|
|
}
|
|
} else {
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid player id %d", index);
|
|
if (iFile)
|
|
FREE_FILE(sToShow);
|
|
|
|
return 0;
|
|
}
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
if (pPlayer->ingame && !pPlayer->IsBot())
|
|
UTIL_ShowMOTD(pPlayer->pEdict, sToShow, ilen, szHead);
|
|
}
|
|
|
|
if (iFile)
|
|
FREE_FILE(sToShow);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL next_hudchannel(AMX *amx, cell *params)
|
|
{
|
|
int index = params[1];
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid player %d", index);
|
|
return 0;
|
|
}
|
|
|
|
CPlayer *pPlayer = GET_PLAYER_POINTER_I(index);
|
|
if (!pPlayer->ingame)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Player %d not in game", index);
|
|
return 0;
|
|
}
|
|
|
|
return pPlayer->NextHUDChannel();
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL set_hudmessage(AMX *amx, cell *params) /* 11 param */
|
|
{
|
|
g_hudset.a1 = 0;
|
|
g_hudset.a2 = 0;
|
|
g_hudset.r2 = 255;
|
|
g_hudset.g2 = 255;
|
|
g_hudset.b2 = 250;
|
|
g_hudset.r1 = static_cast<byte>(params[1]);
|
|
g_hudset.g1 = static_cast<byte>(params[2]);
|
|
g_hudset.b1 = static_cast<byte>(params[3]);
|
|
g_hudset.x = amx_ctof(params[4]);
|
|
g_hudset.y = amx_ctof(params[5]);
|
|
g_hudset.effect = params[6];
|
|
g_hudset.fxTime = amx_ctof(params[7]);
|
|
g_hudset.holdTime = amx_ctof(params[8]);
|
|
g_hudset.fadeinTime = amx_ctof(params[9]);
|
|
g_hudset.fadeoutTime = amx_ctof(params[10]);
|
|
g_hudset.channel = params[11];
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL show_hudmessage(AMX *amx, cell *params) /* 2 param */
|
|
{
|
|
int len = 0;
|
|
g_langMngr.SetDefLang(params[1]);
|
|
char* message = NULL;
|
|
|
|
/**
|
|
* Earlier versions would ignore invalid bounds.
|
|
* Now, bounds are only checked for internal operations.
|
|
* "channel" stores the valid channel that core uses.
|
|
* "g_hudset.channel" stores the direct channel passed to the engine.
|
|
*/
|
|
|
|
bool aut = (g_hudset.channel == -1) ? true : false;
|
|
int channel = -1;
|
|
if (!aut)
|
|
{
|
|
/**
|
|
* guarantee this to be between 0-4
|
|
* if it's not auto, we don't care
|
|
*/
|
|
channel = abs(g_hudset.channel % 5);
|
|
}
|
|
if (params[1] == 0)
|
|
{
|
|
for (int i = 1; i <= gpGlobals->maxClients; ++i)
|
|
{
|
|
CPlayer *pPlayer = GET_PLAYER_POINTER_I(i);
|
|
|
|
if (pPlayer->ingame && !pPlayer->IsBot())
|
|
{
|
|
g_langMngr.SetDefLang(i);
|
|
message = UTIL_SplitHudMessage(format_amxstring(amx, params, 2, len));
|
|
if (aut)
|
|
{
|
|
channel = pPlayer->NextHUDChannel();
|
|
pPlayer->channels[channel] = gpGlobals->time;
|
|
g_hudset.channel = channel;
|
|
}
|
|
//don't need to set g_hudset!
|
|
pPlayer->hudmap[channel] = 0;
|
|
UTIL_HudMessage(pPlayer->pEdict, g_hudset, message);
|
|
}
|
|
}
|
|
} else {
|
|
message = UTIL_SplitHudMessage(format_amxstring(amx, params, 2, len));
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid player id %d", index);
|
|
return 0;
|
|
}
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
if (pPlayer->ingame && !pPlayer->IsBot())
|
|
{
|
|
if (aut)
|
|
{
|
|
channel = pPlayer->NextHUDChannel();
|
|
pPlayer->channels[channel] = gpGlobals->time;
|
|
g_hudset.channel = channel;
|
|
}
|
|
pPlayer->hudmap[channel] = 0;
|
|
UTIL_HudMessage(pPlayer->pEdict, g_hudset, message);
|
|
}
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL set_dhudmessage(AMX *amx, cell *params) /* 10 param */
|
|
{
|
|
g_hudset.a1 = 0;
|
|
g_hudset.a2 = 0;
|
|
g_hudset.r2 = 255;
|
|
g_hudset.g2 = 255;
|
|
g_hudset.b2 = 250;
|
|
g_hudset.r1 = static_cast<byte>(params[1]);
|
|
g_hudset.g1 = static_cast<byte>(params[2]);
|
|
g_hudset.b1 = static_cast<byte>(params[3]);
|
|
g_hudset.x = amx_ctof(params[4]);
|
|
g_hudset.y = amx_ctof(params[5]);
|
|
g_hudset.effect = params[6];
|
|
g_hudset.fxTime = amx_ctof(params[7]);
|
|
g_hudset.holdTime = amx_ctof(params[8]);
|
|
g_hudset.fadeinTime = amx_ctof(params[9]);
|
|
g_hudset.fadeoutTime = amx_ctof(params[10]);
|
|
g_hudset.channel = -1;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL show_dhudmessage(AMX *amx, cell *params) /* 2 param */
|
|
{
|
|
int len = 0;
|
|
int index = params[1];
|
|
char *message;
|
|
|
|
if (!index)
|
|
{
|
|
for (int i = 1; i <= gpGlobals->maxClients; ++i)
|
|
{
|
|
CPlayer *pPlayer = GET_PLAYER_POINTER_I(i);
|
|
|
|
if (pPlayer->ingame && !pPlayer->IsBot())
|
|
{
|
|
g_langMngr.SetDefLang(i);
|
|
message = format_amxstring(amx, params, 2, len);
|
|
|
|
if (len > 127) // Client truncates after byte 127.
|
|
{
|
|
len = 127;
|
|
|
|
// Don't truncate a double-byte character
|
|
if (((message[len - 1] & 0xFF) >= 0xC2) && ((message[len - 1] & 0xFF) <= 0xEF))
|
|
{
|
|
len--;
|
|
}
|
|
|
|
message[len] = 0;
|
|
}
|
|
|
|
UTIL_DHudMessage(pPlayer->pEdict, g_hudset, message, len);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid player id %d", index);
|
|
return 0;
|
|
}
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
if (pPlayer->ingame && !pPlayer->IsBot())
|
|
{
|
|
g_langMngr.SetDefLang(index);
|
|
message = format_amxstring(amx, params, 2, len);
|
|
|
|
if (len > 127) // Client truncates after byte 127.
|
|
{
|
|
len = 127;
|
|
|
|
// Don't truncate a double-byte character
|
|
if (((message[len - 1] & 0xFF) >= 0xC2) && ((message[len - 1] & 0xFF) <= 0xEF))
|
|
{
|
|
--len;
|
|
}
|
|
|
|
message[len] = 0;
|
|
}
|
|
|
|
UTIL_DHudMessage(pPlayer->pEdict, g_hudset, message, len);
|
|
}
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_user_name(AMX *amx, cell *params) /* 3 param */
|
|
{
|
|
int index = params[1];
|
|
int maxlen = params[3];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
return set_amxstring_utf8(amx, params[2], hostname->string, strlen(hostname->string), maxlen);
|
|
else
|
|
return set_amxstring_utf8(amx, params[2], g_players[index].name.chars(), g_players[index].name.length(), maxlen);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_user_index(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
int i;
|
|
char* sptemp = get_amxstring(amx, params[1], 0, i);
|
|
|
|
for (i = 1; i <= gpGlobals->maxClients; ++i)
|
|
{
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(i);
|
|
|
|
if (strcmp(pPlayer->name.chars(), sptemp) == 0)
|
|
return i;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL is_dedicated_server(AMX *amx, cell *params)
|
|
{
|
|
return (IS_DEDICATED_SERVER() ? 1 : 0);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL is_linux_server(AMX *amx, cell *params)
|
|
{
|
|
#if defined(__linux__) || defined(__APPLE__)
|
|
return 1;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL is_amd64_server(AMX *amx, cell *params)
|
|
{
|
|
#if PAWN_CELL_SIZE==64
|
|
return 1;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL is_jit_enabled(AMX *amx, cell *params) // PM: Useless ;P
|
|
{
|
|
#ifdef JIT
|
|
return 1;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL is_map_valid(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
int ilen;
|
|
return (IS_MAP_VALID(get_amxstring(amx, params[1], 0, ilen)) ? 1 : 0);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL is_user_connected(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
return 0;
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
return (pPlayer->ingame ? 1 : 0);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL is_user_connecting(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
return 0;
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
return (!pPlayer->ingame && pPlayer->initialized && (GETPLAYERUSERID(pPlayer->pEdict) > 0)) ? 1 : 0;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL is_user_bot(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
return 0;
|
|
|
|
return (GET_PLAYER_POINTER_I(index)->IsBot() ? 1 : 0);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL is_user_hltv(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
return 0;
|
|
|
|
CPlayer *pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
if (!pPlayer->initialized)
|
|
return 0;
|
|
|
|
if (pPlayer->pEdict->v.flags & FL_PROXY)
|
|
return 1;
|
|
|
|
const char *authid = GETPLAYERAUTHID(pPlayer->pEdict);
|
|
|
|
if (authid && stricmp(authid, "HLTV") == 0)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
extern bool g_bmod_tfc;
|
|
static cell AMX_NATIVE_CALL is_user_alive(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
if (!pPlayer->ingame)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (g_bmod_tfc)
|
|
{
|
|
edict_t *e = pPlayer->pEdict;
|
|
if (e->v.flags & FL_SPECTATOR ||
|
|
(!e->v.team || !e->v.playerclass))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return pPlayer->IsAlive() ? TRUE : FALSE;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_amxx_verstring(AMX *amx, cell *params) /* 2 params */
|
|
{
|
|
return set_amxstring(amx, params[1], AMXX_VERSION, params[2]);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_user_frags(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
return 0;
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
return (cell)(pPlayer->ingame ? pPlayer->pEdict->v.frags : 0);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_user_deaths(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
return 0;
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
return (cell)(pPlayer->ingame ? pPlayer->deaths : 0);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_user_armor(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
return 0;
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
return (cell)(pPlayer->ingame ? pPlayer->pEdict->v.armorvalue : 0);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_user_health(AMX *amx, cell *params) /* param */
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
return 0;
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
return (cell)(pPlayer->ingame ? pPlayer->pEdict->v.health : 0);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_user_userid(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
return 0;
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
return pPlayer->initialized ? GETPLAYERUSERID(pPlayer->pEdict) : -1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_user_authid(AMX *amx, cell *params) /* 3 param */
|
|
{
|
|
int index = params[1];
|
|
const char* authid = 0;
|
|
|
|
if (index > 0 && index <= gpGlobals->maxClients)
|
|
authid = GETPLAYERAUTHID(g_players[index].pEdict);
|
|
|
|
return set_amxstring(amx, params[2], authid ? authid : "", params[3]);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL is_user_authorized(AMX *amx, cell *params)
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
return 0;
|
|
|
|
return GET_PLAYER_POINTER_I(index)->authorized;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_weaponname(AMX *amx, cell *params) /* 3 param */
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index >= MAX_WEAPONS)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid weapon id %d", index);
|
|
return 0;
|
|
}
|
|
|
|
return set_amxstring(amx, params[2], g_weaponsData[index].fullName.chars(), params[3]);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_weaponid(AMX *amx, cell *params)
|
|
{
|
|
int ilen;
|
|
const char *name = get_amxstring(amx, params[1], 0, ilen);
|
|
|
|
for (int i = 1; i < MAX_WEAPONS; i++)
|
|
{
|
|
if (!strcmp(g_weaponsData[i].fullName.chars(), name))
|
|
return g_weaponsData[i].iId;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_user_weapons(AMX *amx, cell *params) /* 3 param */
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid player id %d", index);
|
|
return 0;
|
|
}
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
if (pPlayer->ingame)
|
|
{
|
|
cell *cpNum = get_amxaddr(amx, params[3]);
|
|
cell *cpIds = get_amxaddr(amx, params[2]);
|
|
*cpIds = 0;
|
|
|
|
int weapons = pPlayer->pEdict->v.weapons & ~(1<<31); // don't count last element
|
|
|
|
if (g_bmod_dod)
|
|
{
|
|
// Don't ignore that last element for dod
|
|
weapons = pPlayer->pEdict->v.weapons;
|
|
}
|
|
|
|
for (int i = 1; i < MAX_WEAPONS; ++i)
|
|
{
|
|
if (weapons & (1<<i))
|
|
{
|
|
*(cpIds+(*cpNum)) = i;
|
|
(*cpNum)++;
|
|
}
|
|
}
|
|
return weapons;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_user_origin(AMX *amx, cell *params) /* 3 param */
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid player id %d", index);
|
|
return 0;
|
|
}
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
if (pPlayer->ingame)
|
|
{
|
|
int mode = params[3];
|
|
cell *cpOrigin = get_amxaddr(amx, params[2]);
|
|
|
|
if (mode == 4)
|
|
{
|
|
cpOrigin[0] = (long int)pPlayer->lastHit.x;
|
|
cpOrigin[1] = (long int)pPlayer->lastHit.y;
|
|
cpOrigin[2] = (long int)pPlayer->lastHit.z;
|
|
return 1;
|
|
}
|
|
|
|
edict_t* edict = pPlayer->pEdict;
|
|
Vector pos = edict->v.origin;
|
|
|
|
if (mode && mode != 2)
|
|
pos = pos + edict->v.view_ofs;
|
|
|
|
if (mode > 1)
|
|
{
|
|
Vector vec;
|
|
Vector v_angle = edict->v.v_angle;
|
|
float v_vec[3];
|
|
|
|
v_vec[0] = v_angle.x;
|
|
v_vec[1] = v_angle.y;
|
|
v_vec[2] = v_angle.z;
|
|
|
|
ANGLEVECTORS(v_vec, vec, NULL, NULL);
|
|
TraceResult trEnd;
|
|
Vector v_dest = pos + vec * 9999;
|
|
|
|
float f_pos[3];
|
|
f_pos[0] = pos.x;
|
|
f_pos[1] = pos.y;
|
|
f_pos[2] = pos.z;
|
|
|
|
float f_dest[3];
|
|
f_dest[0] = v_dest.x;
|
|
f_dest[1] = v_dest.y;
|
|
f_dest[2] = v_dest.z;
|
|
|
|
TRACE_LINE(f_pos, f_dest, 0, edict, &trEnd);
|
|
pos = (trEnd.flFraction < 1.0) ? trEnd.vecEndPos : Vector(0, 0, 0);
|
|
}
|
|
cpOrigin[0] = (long int)pos.x;
|
|
cpOrigin[1] = (long int)pos.y;
|
|
cpOrigin[2] = (long int)pos.z;
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_user_ip(AMX *amx, cell *params) /* 3 param */
|
|
{
|
|
int index = params[1];
|
|
char *ptr;
|
|
char szIp[32];
|
|
strcpy(szIp, (index < 1 || index > gpGlobals->maxClients) ? CVAR_GET_STRING("net_address") : g_players[index].ip.chars());
|
|
|
|
if (params[4] && (ptr = strstr(szIp, ":")) != 0)
|
|
*ptr = '\0';
|
|
|
|
return set_amxstring(amx, params[2], szIp, params[3]);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_user_attacker(AMX *amx, cell *params) /* 2 param */
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid player id %d", index);
|
|
return 0;
|
|
}
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
edict_t *enemy = NULL;
|
|
|
|
if (pPlayer->ingame)
|
|
{
|
|
enemy = pPlayer->pEdict->v.dmg_inflictor;
|
|
if (!FNullEnt(enemy))
|
|
{
|
|
int weapon = 0;
|
|
|
|
if (enemy->v.flags & (FL_CLIENT | FL_FAKECLIENT))
|
|
{
|
|
pPlayer = GET_PLAYER_POINTER(enemy);
|
|
weapon = pPlayer->current;
|
|
} else if (g_grenades.find(enemy, &pPlayer, weapon)) {
|
|
enemy = pPlayer->pEdict;
|
|
} else {
|
|
enemy = enemy->v.owner;
|
|
if (!FNullEnt(enemy) && (enemy->v.flags & (FL_CLIENT | FL_FAKECLIENT)))
|
|
{
|
|
pPlayer = GET_PLAYER_POINTER(enemy);
|
|
weapon = pPlayer->current;
|
|
} else {
|
|
switch (*params / sizeof(cell))
|
|
{
|
|
case 3: *get_amxaddr(amx, params[3]) = 0;
|
|
case 2: *get_amxaddr(amx, params[2]) = 0;
|
|
}
|
|
return ENTINDEX(pPlayer->pEdict->v.dmg_inflictor);
|
|
}
|
|
}
|
|
|
|
if (enemy)
|
|
{
|
|
switch (*params / sizeof(cell))
|
|
{
|
|
case 3: *get_amxaddr(amx, params[3]) = pPlayer->aiming;
|
|
case 2: *get_amxaddr(amx, params[2]) = weapon;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return (enemy ? pPlayer->index : 0);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL user_has_weapon(AMX *amx, cell *params)
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid player id %d", index);
|
|
return 0;
|
|
}
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
if (!pPlayer->ingame)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
edict_t *pEntity = pPlayer->pEdict;
|
|
|
|
if (params[3] == -1)
|
|
{
|
|
if ((pEntity->v.weapons & (1<<params[2])) > 0)
|
|
{
|
|
return 1;
|
|
}
|
|
} else {
|
|
if ((pEntity->v.weapons & (1<<params[2])) > 0)
|
|
{
|
|
if (params[3] == 0)
|
|
{
|
|
pEntity->v.weapons &= ~(1<<params[2]);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
} else {
|
|
if (params[3] == 1)
|
|
{
|
|
pEntity->v.weapons |= (1<<params[2]);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_user_weapon(AMX *amx, cell *params) /* 3 param */
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid player id %d", index);
|
|
return 0;
|
|
}
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
if (pPlayer->ingame)
|
|
{
|
|
int wpn = pPlayer->current;
|
|
|
|
cell *cpTemp = get_amxaddr(amx, params[2]);
|
|
*cpTemp = pPlayer->weapons[wpn].clip;
|
|
cpTemp = get_amxaddr(amx, params[3]);
|
|
*cpTemp = pPlayer->weapons[wpn].ammo;
|
|
|
|
return wpn;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_user_ammo(AMX *amx, cell *params) /* 4 param */
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid player id %d", index);
|
|
return 0;
|
|
}
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
if (pPlayer->ingame)
|
|
{
|
|
int wpn = params[2];
|
|
|
|
if (wpn < 1 || wpn >= MAX_WEAPONS)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid weapon id %d", wpn);
|
|
return 0;
|
|
}
|
|
|
|
cell *cpTemp = get_amxaddr(amx, params[3]);
|
|
*cpTemp = pPlayer->weapons[wpn].clip;
|
|
cpTemp = get_amxaddr(amx, params[4]);
|
|
*cpTemp = pPlayer->weapons[wpn].ammo;
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_user_team(AMX *amx, cell *params) /* 3 param */
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
return -1;
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
if (pPlayer->ingame)
|
|
{
|
|
// SidLuke, DoD fix
|
|
if (g_bmod_dod)
|
|
{
|
|
int iTeam = pPlayer->pEdict->v.team;
|
|
|
|
if (params[3])
|
|
{
|
|
const char *szTeam = "";
|
|
|
|
switch (iTeam)
|
|
{
|
|
case 1:
|
|
szTeam = "Allies";
|
|
break;
|
|
case 2:
|
|
szTeam = "Axis";
|
|
break;
|
|
}
|
|
|
|
set_amxstring(amx, params[2], szTeam, params[3]);
|
|
}
|
|
return iTeam;
|
|
}
|
|
//
|
|
if (params[3])
|
|
{
|
|
set_amxstring(amx, params[2], pPlayer->team.chars(), params[3]);
|
|
}
|
|
|
|
return pPlayer->teamId;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL show_menu(AMX *amx, cell *params) /* 3 param */
|
|
{
|
|
auto closeMenu = [amx](int index) -> int
|
|
{
|
|
auto pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
if (!pPlayer->ingame)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
pPlayer->keys = 0;
|
|
pPlayer->menu = 0;
|
|
|
|
// Fire newmenu callback so closing it can be handled by the plugin
|
|
if (!CloseNewMenus(pPlayer))
|
|
{
|
|
return 2;
|
|
}
|
|
|
|
if (g_bmod_cstrike)
|
|
{
|
|
enum JoinState { Joined = 0 };
|
|
enum MenuState { Menu_OFF = 0, Menu_ChooseTeam = 1, Menu_ChooseAppearance = 3 };
|
|
|
|
GET_OFFSET("CBasePlayer", m_iJoiningState);
|
|
GET_OFFSET("CBasePlayer", m_iMenu);
|
|
|
|
if (get_pdata<int>(pPlayer->pEdict, m_iJoiningState) == Joined || (get_pdata<int>(pPlayer->pEdict, m_iMenu) != Menu_ChooseTeam && get_pdata<int>(pPlayer->pEdict, m_iMenu) != Menu_ChooseAppearance))
|
|
{
|
|
set_pdata<int>(pPlayer->pEdict, m_iMenu, Menu_OFF);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
};
|
|
|
|
int index = params[1];
|
|
|
|
// If show_menu is called from within a newmenu callback upon receiving MENU_EXIT
|
|
// it is possible for this native to recurse. We need to close newmenus right away
|
|
// because the recursive call would otherwise modify/corrupt the static get_amxstring
|
|
// buffer mid execution. This will either display incorrect text or result in UTIL_ShowMenu
|
|
// running into an infinite loop.
|
|
if (index == 0)
|
|
{
|
|
for (int i = 1; i <= gpGlobals->maxClients; ++i)
|
|
{
|
|
if (closeMenu(i) == 2)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid player id %d", index);
|
|
return 0;
|
|
}
|
|
|
|
if (closeMenu(index) == 2)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int ilen = 0, ilen2 = 0;
|
|
char *sMenu = get_amxstring(amx, params[3], 0, ilen);
|
|
char *lMenu = get_amxstring(amx, params[5], 1, ilen2);
|
|
int menuid = 0;
|
|
|
|
if (ilen2 && lMenu)
|
|
{
|
|
menuid = g_menucmds.findMenuId(lMenu, amx);
|
|
} else {
|
|
menuid = g_menucmds.findMenuId(sMenu, amx);
|
|
}
|
|
|
|
int keys = params[2];
|
|
int time = params[4];
|
|
|
|
if (index == 0)
|
|
{
|
|
for (int i = 1; i <= gpGlobals->maxClients; ++i)
|
|
{
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(i);
|
|
|
|
if (pPlayer->ingame)
|
|
{
|
|
pPlayer->keys = keys;
|
|
pPlayer->menu = menuid;
|
|
pPlayer->vgui = false;
|
|
|
|
if (time == -1)
|
|
pPlayer->menuexpire = INFINITE;
|
|
else
|
|
pPlayer->menuexpire = gpGlobals->time + static_cast<float>(time);
|
|
|
|
pPlayer->page = 0;
|
|
UTIL_ShowMenu(pPlayer->pEdict, keys, time, sMenu, ilen);
|
|
}
|
|
}
|
|
} else {
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
if (pPlayer->ingame)
|
|
{
|
|
pPlayer->keys = keys;
|
|
pPlayer->menu = menuid;
|
|
pPlayer->vgui = false;
|
|
|
|
if (time == -1)
|
|
pPlayer->menuexpire = INFINITE;
|
|
else
|
|
pPlayer->menuexpire = gpGlobals->time + static_cast<float>(time);
|
|
|
|
pPlayer->page = 0;
|
|
UTIL_ShowMenu(pPlayer->pEdict, keys, time, sMenu, ilen);
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL register_plugin(AMX *amx, cell *params) /* 3 param */
|
|
{
|
|
CPluginMngr::CPlugin* a = g_plugins.findPluginFast(amx);
|
|
int i;
|
|
|
|
char *title = get_amxstring(amx, params[1], 0, i);
|
|
char *vers = get_amxstring(amx, params[2], 1, i);
|
|
char *author = get_amxstring(amx, params[3], 2, i);
|
|
|
|
#if defined BINLOG_ENABLED
|
|
g_BinLog.WriteOp(BinLog_Registered, a->getId(), title, vers);
|
|
#endif
|
|
|
|
a->setTitle(title);
|
|
a->setVersion(vers);
|
|
a->setAuthor(author);
|
|
|
|
/* Check if we need to add fail counters */
|
|
i = 0;
|
|
unsigned int counter = 0;
|
|
while (NONGPL_PLUGIN_LIST[i].author != NULL)
|
|
{
|
|
if (strcmp(NONGPL_PLUGIN_LIST[i].author, author) == 0)
|
|
{
|
|
counter++;
|
|
}
|
|
if (stricmp(NONGPL_PLUGIN_LIST[i].filename, a->getName()) == 0)
|
|
{
|
|
counter++;
|
|
}
|
|
if (stricmp(NONGPL_PLUGIN_LIST[i].title, title) == 0)
|
|
{
|
|
counter++;
|
|
}
|
|
if (counter)
|
|
{
|
|
a->AddToFailCounter(counter);
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
return a->getId();
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL register_menucmd(AMX *amx, cell *params) /* 3 param */
|
|
{
|
|
CPluginMngr::CPlugin* plugin = g_plugins.findPluginFast(amx);
|
|
int ilen, idx;
|
|
char* sptemp = get_amxstring(amx, params[3], 0, ilen);
|
|
|
|
idx = registerSPForwardByName(amx, sptemp, FP_CELL, FP_CELL, FP_CELL, FP_DONE);
|
|
|
|
if (idx == -1)
|
|
{
|
|
LogError(amx, AMX_ERR_NOTFOUND, "Function \"%s\" was not found", sptemp);
|
|
return 0;
|
|
}
|
|
|
|
g_menucmds.registerMenuCmd(plugin, params[1], params[2], idx);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_plugin(AMX *amx, cell *params) /* 11 param */
|
|
{
|
|
CPluginMngr::CPlugin* a;
|
|
|
|
if (params[1] < 0)
|
|
a = g_plugins.findPluginFast(amx);
|
|
else
|
|
a = g_plugins.findPlugin((int)params[1]);
|
|
|
|
if (a)
|
|
{
|
|
set_amxstring(amx, params[2], a->getName(), params[3]);
|
|
set_amxstring(amx, params[4], a->getTitle(), params[5]);
|
|
set_amxstring(amx, params[6], a->getVersion(), params[7]);
|
|
set_amxstring(amx, params[8], a->getAuthor(), params[9]);
|
|
set_amxstring(amx, params[10], a->getStatus(), params[11]);
|
|
|
|
if (params[0] / sizeof(cell) >= 12)
|
|
{
|
|
cell *jit_info = get_amxaddr(amx, params[12]);
|
|
#if defined AMD64 || !defined JIT
|
|
*jit_info = 0;
|
|
#else
|
|
*jit_info = a->isDebug() ? 0 : 1;
|
|
#endif
|
|
}
|
|
|
|
return a->getId();
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL amx_md5(AMX *amx, cell *params)
|
|
{
|
|
int len;
|
|
char *str = get_amxstring(amx, params[1], 0, len);
|
|
const char *hash = hashString((const char *)str, len, Hash_Md5);
|
|
|
|
return set_amxstring(amx, params[2], hash, 32);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL amx_md5_file(AMX *amx, cell *params)
|
|
{
|
|
int len;
|
|
char *str = get_amxstring(amx, params[1], 0, len);
|
|
char file[PLATFORM_MAX_PATH];
|
|
|
|
build_pathname_r(file, sizeof(file), "%s", str);
|
|
|
|
const char *hash = hashFile((const char *)file, Hash_Md5);
|
|
if (!hash)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Cant open file \"%s\"", file);
|
|
return 0;
|
|
}
|
|
|
|
return set_amxstring(amx, params[2], hash, 32);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL amx_hash_string(AMX *amx, cell *params)
|
|
{
|
|
int len;
|
|
char *str = get_amxstring(amx, params[1], 0, len);
|
|
HashType type = (HashType)params[2];
|
|
|
|
const char *hash = hashString((const char *)str, len, type);
|
|
if (!hash)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Cant hash string \"%s\"", str);
|
|
return 0;
|
|
}
|
|
|
|
return set_amxstring(amx, params[3], hash, params[4]);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL amx_hash_file(AMX *amx, cell *params)
|
|
{
|
|
int len;
|
|
char *str = get_amxstring(amx, params[1], 0, len);
|
|
char file[PLATFORM_MAX_PATH];
|
|
build_pathname_r(file, sizeof(file), "%s", str);
|
|
|
|
HashType type = (HashType)params[2];
|
|
|
|
const char *hash = hashFile((const char *)file, type);
|
|
if (!hash)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Cant open file \"%s\"", file);
|
|
return 0;
|
|
}
|
|
|
|
return set_amxstring(amx, params[3], hash, params[4]);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_pluginsnum(AMX *amx, cell *params)
|
|
{
|
|
return g_plugins.getPluginsNum();
|
|
}
|
|
|
|
// native register_concmd(const cmd[], const function[], flags = -1, const info[] = "", FlagManager = -1, bool:info_ml = false);
|
|
static cell AMX_NATIVE_CALL register_concmd(AMX *amx, cell *params)
|
|
{
|
|
CPluginMngr::CPlugin* plugin = g_plugins.findPluginFast(amx);
|
|
int i, idx = 0;
|
|
char* temp = get_amxstring(amx, params[2], 0, i);
|
|
|
|
idx = registerSPForwardByName(amx, temp, FP_CELL, FP_CELL, FP_CELL, FP_DONE);
|
|
|
|
if (idx == -1)
|
|
{
|
|
LogError(amx, AMX_ERR_NOTFOUND, "Function \"%s\" was not found", temp);
|
|
return 0;
|
|
}
|
|
|
|
temp = get_amxstring(amx, params[1], 0, i);
|
|
char* info = get_amxstring(amx, params[4], 1, i);
|
|
CmdMngr::Command* cmd;
|
|
int access = params[3];
|
|
bool listable = true;
|
|
bool info_ml = *params / sizeof(cell) >= 6 && params[6] != 0 && i;
|
|
|
|
if (access < 0) // is access is -1 then hide from listing
|
|
{
|
|
access = 0;
|
|
listable = false;
|
|
}
|
|
|
|
if (FlagMan.ShouldIAddThisCommand(amx,params,temp)==1)
|
|
{
|
|
FlagMan.LookupOrAdd(temp,access,amx);
|
|
}
|
|
|
|
if ((cmd = g_commands.registerCommand(plugin, idx, temp, info, access, listable, info_ml)) == NULL)
|
|
return 0;
|
|
|
|
if (CheckBadConList(temp, 1))
|
|
{
|
|
plugin->AddToFailCounter(1);
|
|
}
|
|
|
|
cmd->setCmdType(CMD_ConsoleCommand);
|
|
REG_SVR_COMMAND((char*)cmd->getCommand(), plugin_srvcmd);
|
|
|
|
return cmd->getId();
|
|
}
|
|
|
|
// native register_clcmd(const client_cmd[], const function[], flags = -1, const info[] = "", FlagManager = -1, bool:info_ml = false);
|
|
static cell AMX_NATIVE_CALL register_clcmd(AMX *amx, cell *params)
|
|
{
|
|
CPluginMngr::CPlugin* plugin = g_plugins.findPluginFast(amx);
|
|
int i, idx = 0;
|
|
char* temp = get_amxstring(amx, params[2], 0, i);
|
|
|
|
idx = registerSPForwardByName(amx, temp, FP_CELL, FP_CELL, FP_CELL, FP_DONE);
|
|
|
|
if (idx == -1)
|
|
{
|
|
LogError(amx, AMX_ERR_NOTFOUND, "Function \"%s\" was not found", temp);
|
|
return 0;
|
|
}
|
|
|
|
temp = get_amxstring(amx, params[1], 0, i);
|
|
const char* info = get_amxstring(amx, params[4], 1, i);
|
|
CmdMngr::Command* cmd;
|
|
int access = params[3];
|
|
bool listable = true;
|
|
bool info_ml = *params / sizeof(cell) >= 6 && params[6] != 0 && i;
|
|
|
|
if (access < 0) // is access is -1 then hide from listing
|
|
{
|
|
access = 0;
|
|
listable = false;
|
|
}
|
|
|
|
if (FlagMan.ShouldIAddThisCommand(amx,params,temp)==1)
|
|
{
|
|
FlagMan.LookupOrAdd(temp,access,amx);
|
|
}
|
|
|
|
if ((cmd = g_commands.registerCommand(plugin, idx, temp, info, access, listable, info_ml)) == NULL)
|
|
return 0;
|
|
|
|
cmd->setCmdType(CMD_ClientCommand);
|
|
|
|
return cmd->getId();
|
|
}
|
|
|
|
// native register_srvcmd(const server_cmd[], const function[], flags = -1, const info[] = "", bool:info_ml = false);
|
|
static cell AMX_NATIVE_CALL register_srvcmd(AMX *amx, cell *params)
|
|
{
|
|
CPluginMngr::CPlugin* plugin = g_plugins.findPluginFast(amx);
|
|
int i, idx = 0;
|
|
char* temp = get_amxstring(amx, params[2], 0, i);
|
|
|
|
idx = registerSPForwardByName(amx, temp, FP_CELL, FP_CELL, FP_CELL, FP_DONE);
|
|
|
|
if (idx == -1)
|
|
{
|
|
LogError(amx, AMX_ERR_NOTFOUND, "Function \"%s\" was not found", temp);
|
|
return 0;
|
|
}
|
|
|
|
temp = get_amxstring(amx, params[1], 0, i);
|
|
const char* info = get_amxstring(amx, params[4], 1, i);
|
|
CmdMngr::Command* cmd;
|
|
int access = params[3];
|
|
bool listable = true;
|
|
bool info_ml = *params / sizeof(cell) >= 5 && params[5] != 0 && i;
|
|
|
|
if (access < 0) // is access is -1 then hide from listing
|
|
{
|
|
access = 0;
|
|
listable = false;
|
|
}
|
|
|
|
if ((cmd = g_commands.registerCommand(plugin, idx, temp, info, access, listable, info_ml)) == NULL)
|
|
return 0;
|
|
|
|
cmd->setCmdType(CMD_ServerCommand);
|
|
REG_SVR_COMMAND((char*)cmd->getCommand(), plugin_srvcmd);
|
|
|
|
return cmd->getId();
|
|
}
|
|
|
|
// native get_concmd(index, cmd[], len1, &flags, info[], len2, flag, id = -1, &bool:info_ml = false);
|
|
static cell AMX_NATIVE_CALL get_concmd(AMX *amx, cell *params)
|
|
{
|
|
int who = params[8];
|
|
|
|
if (who > 0) // id of player - client command
|
|
who = CMD_ClientCommand;
|
|
else if (who == 0) // server
|
|
who = CMD_ServerCommand;
|
|
else // -1 parameter - all commands
|
|
who = CMD_ConsoleCommand;
|
|
|
|
CmdMngr::Command* cmd = g_commands.getCmd(params[1], who, params[7]);
|
|
|
|
if (cmd == 0)
|
|
return 0;
|
|
|
|
set_amxstring_utf8(amx, params[2], cmd->getCmdLine(), strlen(cmd->getCmdLine()), params[3]);
|
|
set_amxstring_utf8(amx, params[5], cmd->getCmdInfo(), strlen(cmd->getCmdInfo()), params[6]);
|
|
cell *cpFlags = get_amxaddr(amx, params[4]);
|
|
*cpFlags = cmd->getFlags();
|
|
|
|
if (*params / sizeof(cell) >= 9)
|
|
{
|
|
*get_amxaddr(amx, params[9]) = cmd->isInfoML();
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_concmd_plid(AMX *amx, cell *params)
|
|
{
|
|
int who = params[3];
|
|
if (who > 0)
|
|
{
|
|
who = CMD_ClientCommand;
|
|
} else if (who == 0) {
|
|
who = CMD_ServerCommand;
|
|
} else {
|
|
who = CMD_ConsoleCommand;
|
|
}
|
|
|
|
CmdMngr::Command *cmd = g_commands.getCmd(params[1], who, params[2]);
|
|
|
|
if (cmd == NULL)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
return cmd->getPlugin()->getId();
|
|
}
|
|
|
|
// native get_clcmd(index, command[], len1, &flags, info[], len2, flag, &bool:info_ml = false);
|
|
static cell AMX_NATIVE_CALL get_clcmd(AMX *amx, cell *params)
|
|
{
|
|
CmdMngr::Command* cmd = g_commands.getCmd(params[1], CMD_ClientCommand, params[7]);
|
|
|
|
if (cmd == 0)
|
|
return 0;
|
|
|
|
set_amxstring_utf8(amx, params[2], cmd->getCmdLine(), strlen(cmd->getCmdLine()), params[3]);
|
|
set_amxstring_utf8(amx, params[5], cmd->getCmdInfo(), strlen(cmd->getCmdInfo()), params[6]);
|
|
|
|
cell *cpFlags = get_amxaddr(amx, params[4]);
|
|
*cpFlags = cmd->getFlags();
|
|
|
|
if (*params / sizeof(cell) >= 8)
|
|
{
|
|
*get_amxaddr(amx, params[8]) = cmd->isInfoML();
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
// native get_srvcmd(index, server_cmd[], len1, &flags, info[], len2, flag, &bool:info_ml = false);
|
|
static cell AMX_NATIVE_CALL get_srvcmd(AMX *amx, cell *params)
|
|
{
|
|
CmdMngr::Command* cmd = g_commands.getCmd(params[1], CMD_ServerCommand, params[7]);
|
|
|
|
if (cmd == 0)
|
|
return 0;
|
|
|
|
set_amxstring_utf8(amx, params[2], cmd->getCmdLine(), strlen(cmd->getCmdLine()), params[3]);
|
|
set_amxstring_utf8(amx, params[5], cmd->getCmdInfo(), strlen(cmd->getCmdInfo()), params[6]);
|
|
cell *cpFlags = get_amxaddr(amx, params[4]);
|
|
*cpFlags = cmd->getFlags();
|
|
|
|
if (*params / sizeof(cell) >= 8)
|
|
{
|
|
*get_amxaddr(amx, params[8]) = cmd->isInfoML();
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_srvcmdsnum(AMX *amx, cell *params)
|
|
{
|
|
return g_commands.getCmdNum(CMD_ServerCommand, params[1]);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_clcmdsnum(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
return g_commands.getCmdNum(CMD_ClientCommand, params[1]);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_concmdsnum(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
int who = params[2];
|
|
|
|
if (who > 0)
|
|
return g_commands.getCmdNum(CMD_ClientCommand, params[1]);
|
|
if (who == 0)
|
|
return g_commands.getCmdNum(CMD_ServerCommand, params[1]);
|
|
|
|
return g_commands.getCmdNum(CMD_ConsoleCommand, params[1]);
|
|
}
|
|
|
|
// native register_event(const event[], const function[], const flags[], const cond[] = "", ...);
|
|
static cell AMX_NATIVE_CALL register_event(AMX *amx, cell *params)
|
|
{
|
|
CPluginMngr::CPlugin* plugin = g_plugins.findPluginFast(amx);
|
|
|
|
int len, eventId, forwardId;
|
|
|
|
const char* eventName = get_amxstring(amx, params[1], 0, len);
|
|
|
|
if ((eventId = g_events.getEventId(eventName)) == 0)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid event (name \"%s\") (plugin \"%s\")", eventName, plugin->getName());
|
|
return 0;
|
|
}
|
|
|
|
const char* callback = get_amxstring(amx, params[2], 0, len);
|
|
|
|
forwardId = registerSPForwardByName(amx, callback, FP_CELL, FP_DONE);
|
|
|
|
if (forwardId == -1)
|
|
{
|
|
LogError(amx, AMX_ERR_NOTFOUND, "Function \"%s\" was not found", callback);
|
|
return 0;
|
|
}
|
|
|
|
int numparam = *params / sizeof(cell);
|
|
int flags = 0;
|
|
|
|
if (numparam > 2)
|
|
{
|
|
flags = UTIL_ReadFlags(get_amxstring(amx, params[3], 0, len));
|
|
}
|
|
|
|
int handle = g_events.registerEvent(plugin, forwardId, flags, eventId);
|
|
|
|
if (!handle)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
auto event = EventHandles.lookup(handle)->m_event;
|
|
|
|
for (int i = 4; i <= numparam; ++i)
|
|
{
|
|
event->registerFilter(get_amxstring(amx, params[i], 0, len));
|
|
}
|
|
|
|
return handle;
|
|
}
|
|
|
|
// native register_event_ex(const event[], const function[], RegisterEventFlags:flags, const cond[] = "", ...);
|
|
static cell AMX_NATIVE_CALL register_event_ex(AMX *amx, cell *params)
|
|
{
|
|
cell amx_addr;
|
|
cell *phys_addr;
|
|
char strFlags[8];
|
|
|
|
amx_Allot(amx, ARRAY_LENGTH(strFlags), &amx_addr, &phys_addr);
|
|
UTIL_GetFlags(strFlags, params[3]);
|
|
set_amxstring(amx, amx_addr, strFlags, ARRAY_LENGTH(strFlags) - 1);
|
|
|
|
params[3] = amx_addr;
|
|
cell ret = register_event(amx, params);
|
|
amx_Release(amx, amx_addr);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL enable_event(AMX *amx, cell *params)
|
|
{
|
|
auto handle = EventHandles.lookup(params[1]);
|
|
|
|
if (!handle)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid event handle %d", params[1]);
|
|
return 0;
|
|
}
|
|
|
|
handle->m_event->setForwardState(FSTATE_ACTIVE);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL disable_event(AMX *amx, cell *params)
|
|
{
|
|
auto handle = EventHandles.lookup(params[1]);
|
|
|
|
if (!handle)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid event handle: %d", params[1]);
|
|
return 0;
|
|
}
|
|
|
|
handle->m_event->setForwardState(FSTATE_STOP);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL user_kill(AMX *amx, cell *params) /* 2 param */
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
return 0;
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
if (pPlayer->ingame && pPlayer->IsAlive())
|
|
{
|
|
float bef = pPlayer->pEdict->v.frags;
|
|
MDLL_ClientKill(pPlayer->pEdict);
|
|
|
|
if (params[2])
|
|
pPlayer->pEdict->v.frags = bef;
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL user_slap(AMX *amx, cell *params) /* 2 param */
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
return 0;
|
|
|
|
int power = (int)params[2];
|
|
|
|
if (power < 0)
|
|
power = 0;
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
if (pPlayer->ingame && pPlayer->IsAlive())
|
|
{
|
|
if (pPlayer->pEdict->v.health <= power)
|
|
{
|
|
float bef = pPlayer->pEdict->v.frags;
|
|
MDLL_ClientKill(pPlayer->pEdict);
|
|
pPlayer->pEdict->v.frags = bef;
|
|
} else {
|
|
edict_t *pEdict = pPlayer->pEdict;
|
|
int numparam = *params / sizeof(cell);
|
|
|
|
if (numparam < 3 || params[3])
|
|
{
|
|
pEdict->v.velocity.x += RANDOM_LONG(-600, 600);
|
|
pEdict->v.velocity.y += RANDOM_LONG(-180, 180);
|
|
pEdict->v.velocity.z += RANDOM_LONG(100, 200);
|
|
} else {
|
|
Vector v_forward, v_right;
|
|
Vector vang = pEdict->v.angles;
|
|
float fang[3];
|
|
fang[0] = vang.x;
|
|
fang[1] = vang.y;
|
|
fang[2] = vang.z;
|
|
ANGLEVECTORS(fang, v_forward, v_right, NULL);
|
|
pEdict->v.velocity = pEdict->v.velocity + v_forward * 220 + Vector(0, 0, 200);
|
|
}
|
|
|
|
pEdict->v.punchangle.x = static_cast<vec_t>(RANDOM_LONG(-10, 10));
|
|
pEdict->v.punchangle.y = static_cast<vec_t>(RANDOM_LONG(-10, 10));
|
|
pEdict->v.health -= power;
|
|
|
|
int armor = (int)pEdict->v.armorvalue;
|
|
armor -= power;
|
|
|
|
if (armor < 0)
|
|
armor = 0;
|
|
|
|
pEdict->v.armorvalue = static_cast<float>(armor);
|
|
pEdict->v.dmg_inflictor = pEdict;
|
|
|
|
if (g_bmod_cstrike)
|
|
{
|
|
static const char *cs_sound[4] =
|
|
{
|
|
"player/bhit_flesh-3.wav",
|
|
"player/bhit_flesh-2.wav",
|
|
"player/pl_die1.wav",
|
|
"player/pl_pain6.wav"
|
|
};
|
|
EMIT_SOUND_DYN2(pEdict, CHAN_VOICE, cs_sound[RANDOM_LONG(0, 3)], 1.0, ATTN_NORM, 0, PITCH_NORM);
|
|
} else{
|
|
static const char *bit_sound[3] =
|
|
{
|
|
"weapons/cbar_hitbod1.wav",
|
|
"weapons/cbar_hitbod2.wav",
|
|
"weapons/cbar_hitbod3.wav"
|
|
};
|
|
EMIT_SOUND_DYN2(pEdict, CHAN_VOICE, bit_sound[RANDOM_LONG(0, 2)], 1.0, ATTN_NORM, 0, PITCH_NORM);
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL server_cmd(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
int len;
|
|
g_langMngr.SetDefLang(LANG_SERVER);
|
|
char* cmd = format_amxstring(amx, params, 1, len);
|
|
|
|
cmd[len++] = '\n';
|
|
cmd[len] = 0;
|
|
|
|
SERVER_COMMAND(cmd);
|
|
|
|
CoreCfg.CheckLegacyBufferedCommand(cmd);
|
|
|
|
return len;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL client_cmd(AMX *amx, cell *params) /* 2 param */
|
|
{
|
|
int len;
|
|
char* cmd = format_amxstring(amx, params, 2, len);
|
|
cmd[len++] = '\n';
|
|
cmd[len] = 0;
|
|
|
|
if (params[1] == 0)
|
|
{
|
|
for (int i = 1; i <= gpGlobals->maxClients; ++i)
|
|
{
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(i);
|
|
if (!pPlayer->IsBot() && pPlayer->initialized /*&& pPlayer->ingame*/)
|
|
CLIENT_COMMAND(pPlayer->pEdict, "%s", cmd);
|
|
}
|
|
} else {
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid player id %d", index);
|
|
return 0;
|
|
}
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
if (!pPlayer->IsBot() && pPlayer->initialized /*&& pPlayer->ingame*/)
|
|
CLIENT_COMMAND(pPlayer->pEdict, "%s", cmd);
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL log_message(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
int len;
|
|
g_langMngr.SetDefLang(LANG_SERVER);
|
|
char* message = format_amxstring(amx, params, 1, len);
|
|
|
|
message[len++] = '\n';
|
|
message[len] = 0;
|
|
|
|
ALERT(at_logged, "%s", message);
|
|
|
|
return len;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL elog_message(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
int len;
|
|
g_langMngr.SetDefLang(LANG_SERVER);
|
|
char* message = format_amxstring(amx, params, 1, len);
|
|
|
|
message[len++] = '\n';
|
|
message[len] = 0;
|
|
|
|
g_pEngTable->pfnAlertMessage(at_logged, "%s", message);
|
|
return len;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL log_to_file(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
int ilen;
|
|
char* szFile = get_amxstring(amx, params[1], 0, ilen);
|
|
FILE*fp;
|
|
char file[PLATFORM_MAX_PATH];
|
|
|
|
if (strchr(szFile, '/') || strchr(szFile, '\\'))
|
|
{
|
|
build_pathname_r(file, sizeof(file), "%s", szFile);
|
|
} else {
|
|
build_pathname_r(file, sizeof(file), "%s/%s", g_log_dir.chars(), szFile);
|
|
}
|
|
|
|
bool first_time = true;
|
|
|
|
if ((fp = fopen(file, "r")) != NULL)
|
|
{
|
|
first_time = false;
|
|
fclose(fp);
|
|
}
|
|
|
|
if ((fp = fopen(file, "a")) == NULL)
|
|
{
|
|
//amx_RaiseError(amx, AMX_ERR_NATIVE);
|
|
//would cause too much troubles in old plugins
|
|
return 0;
|
|
}
|
|
|
|
char date[32];
|
|
time_t td; time(&td);
|
|
strftime(date, 31, "%m/%d/%Y - %H:%M:%S", localtime(&td));
|
|
int len;
|
|
g_langMngr.SetDefLang(LANG_SERVER);
|
|
char* message = format_amxstring(amx, params, 2, len);
|
|
|
|
message[len++] = '\n';
|
|
message[len] = 0;
|
|
|
|
if (first_time)
|
|
{
|
|
fprintf(fp, "L %s: Log file started (file \"%s\") (game \"%s\") (amx \"%s\")\n", date, file, g_mod_name.chars(), Plugin_info.version);
|
|
print_srvconsole("L %s: Log file started (file \"%s\") (game \"%s\") (amx \"%s\")\n", date, file, g_mod_name.chars(), Plugin_info.version);
|
|
}
|
|
|
|
fprintf(fp, "L %s: %s", date, message);
|
|
print_srvconsole("L %s: %s", date, message);
|
|
fclose(fp);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL num_to_word(AMX *amx, cell *params) /* 3 param */
|
|
{
|
|
char sptemp[512];
|
|
UTIL_IntToString(params[1], sptemp);
|
|
|
|
return set_amxstring(amx, params[2], sptemp, params[3]);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_timeleft(AMX *amx, cell *params)
|
|
{
|
|
float flCvarTimeLimit = mp_timelimit->value;
|
|
|
|
if (flCvarTimeLimit)
|
|
{
|
|
int iReturn = (int)((g_game_timeleft + flCvarTimeLimit * 60.0) - gpGlobals->time);
|
|
return (iReturn < 0) ? 0 : iReturn;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_time(AMX *amx, cell *params) /* 3 param */
|
|
{
|
|
int ilen;
|
|
char* sptemp = get_amxstring(amx, params[1], 0, ilen);
|
|
time_t td = time(NULL);
|
|
tm* lt = localtime(&td);
|
|
|
|
char szDate[512];
|
|
strftime(szDate, 511, sptemp, lt);
|
|
|
|
return set_amxstring(amx, params[2], szDate, params[3]);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL format_time(AMX *amx, cell *params) /* 3 param */
|
|
{
|
|
int ilen;
|
|
char* sptemp = get_amxstring(amx, params[3], 0, ilen);
|
|
time_t tim = params[4];
|
|
time_t td = (tim != -1) ? tim : time(NULL);
|
|
tm* lt = localtime(&td);
|
|
|
|
if (lt == 0)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Couldn't get localtime");
|
|
return 0;
|
|
}
|
|
|
|
char szDate[512];
|
|
ilen = strftime(szDate, 511, sptemp, lt);
|
|
|
|
return set_amxstring_utf8(amx, params[1], szDate, ilen, params[2]);
|
|
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL parse_time(AMX *amx, cell *params) /* 3 param */
|
|
{
|
|
int ilen;
|
|
char* sTime = get_amxstring(amx, params[1], 1, ilen);
|
|
char* sFormat = get_amxstring(amx, params[2], 0, ilen);
|
|
tm* mytime;
|
|
time_t td;
|
|
|
|
if (params[3] == -1)
|
|
{
|
|
td = time(NULL);
|
|
mytime = localtime(&td);
|
|
|
|
if (mytime == 0)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Couldn't get localtime");
|
|
return 0;
|
|
}
|
|
|
|
strptime(sTime, sFormat, mytime, 0);
|
|
} else {
|
|
td = params[3];
|
|
mytime = localtime(&td);
|
|
|
|
if (mytime == 0)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Couldn't get localtime");
|
|
return 0;
|
|
}
|
|
|
|
strptime(sTime, sFormat, mytime, 1);
|
|
}
|
|
|
|
return mktime(mytime);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_systime(AMX *amx, cell *params) /* 3 param */
|
|
{
|
|
time_t td = time(NULL);
|
|
td += params[1];
|
|
|
|
return td;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL read_datanum(AMX *amx, cell *params) /* 0 param */
|
|
{
|
|
return g_events.getArgNum();
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL read_data(AMX *amx, cell *params) /* 3 param */
|
|
{
|
|
if (params[0] == 0)
|
|
{
|
|
return g_events.getCurrentMsgType();
|
|
}
|
|
|
|
switch (*params / sizeof(cell))
|
|
{
|
|
case 1:
|
|
return g_events.getArgInteger(params[1]);
|
|
case 3:
|
|
return set_amxstring_utf8(amx, params[2], g_events.getArgString(params[1]),
|
|
strlen(g_events.getArgString(params[1])),*get_amxaddr(amx, params[3]));
|
|
default:
|
|
cell *fCell = get_amxaddr(amx, params[2]);
|
|
REAL fparam = (REAL)g_events.getArgFloat(params[1]);
|
|
fCell[0] = amx_ftoc(fparam);
|
|
return (int)fparam;
|
|
}
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL read_datatype(AMX *amx, cell *params) /* 0 param */
|
|
{
|
|
return g_events.getCurrentMsgType();
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_playersnum(AMX *amx, cell *params)
|
|
{
|
|
if (!params[1])
|
|
return g_players_num;
|
|
|
|
int a = 0;
|
|
|
|
for (int i = 1; i <= gpGlobals->maxClients; ++i)
|
|
{
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(i);
|
|
|
|
if (pPlayer->initialized && (GETPLAYERUSERID(pPlayer->pEdict) > 0))
|
|
++a;
|
|
}
|
|
|
|
return a;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_players(AMX *amx, cell *params) /* 4 param */
|
|
{
|
|
int iNum = 0;
|
|
int ilen;
|
|
char* sptemp = get_amxstring(amx, params[3], 0, ilen);
|
|
int flags = UTIL_ReadFlags(sptemp);
|
|
|
|
cell *aPlayers = get_amxaddr(amx, params[1]);
|
|
cell *iMax = get_amxaddr(amx, params[2]);
|
|
|
|
int team = 0;
|
|
|
|
if (flags & 48)
|
|
{
|
|
sptemp = get_amxstring(amx, params[4], 0, ilen);
|
|
|
|
if (flags & 16)
|
|
{
|
|
if (flags & 64)
|
|
team = g_teamsIds.findTeamId(sptemp);
|
|
else
|
|
team = g_teamsIds.findTeamIdCase(sptemp);
|
|
}
|
|
}
|
|
|
|
for (int i = 1; i <= gpGlobals->maxClients; ++i)
|
|
{
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(i);
|
|
if (pPlayer->ingame || ((flags & 256) && pPlayer->initialized))
|
|
{
|
|
if (pPlayer->IsAlive() ? (flags & 2) : (flags & 1))
|
|
continue;
|
|
if (pPlayer->IsBot() ? (flags & 4) : (flags & 8))
|
|
continue;
|
|
if ((flags & 16) && (pPlayer->teamId != team))
|
|
continue;
|
|
if ((flags & 128) && (pPlayer->pEdict->v.flags & FL_PROXY))
|
|
continue;
|
|
if (flags & 32)
|
|
{
|
|
if (flags & 64)
|
|
{
|
|
if (utf8stristr(pPlayer->name.chars(), sptemp) == NULL)
|
|
continue;
|
|
}
|
|
else if (strstr(pPlayer->name.chars(), sptemp) == NULL)
|
|
continue;
|
|
}
|
|
aPlayers[iNum++] = i;
|
|
}
|
|
}
|
|
|
|
*iMax = iNum;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL find_player(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
typedef int (*STRCOMPARE)(const char*, const char*);
|
|
STRCOMPARE func;
|
|
|
|
int ilen, userid = 0;
|
|
char* sptemp = get_amxstring(amx, params[1], 0, ilen);
|
|
int flags = UTIL_ReadFlags(sptemp);
|
|
|
|
if (flags & 31)
|
|
sptemp = get_amxstring(amx, params[2], 0, ilen);
|
|
else if (flags & 1024)
|
|
userid = *get_amxaddr(amx, params[2]);
|
|
|
|
// a b c d e f g h i j k l
|
|
int result = 0;
|
|
|
|
// Switch for the l flag
|
|
if (flags & 2048)
|
|
func = utf8strcasecmp;
|
|
else
|
|
func = strcmp;
|
|
|
|
for (int i = 1; i <= gpGlobals->maxClients; ++i)
|
|
{
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(i);
|
|
|
|
if (pPlayer->ingame || ((flags & 4096) && pPlayer->initialized))
|
|
{
|
|
if (pPlayer->IsAlive() ? (flags & 64) : (flags & 32))
|
|
continue;
|
|
|
|
if (pPlayer->IsBot() ? (flags & 128) : (flags & 256))
|
|
continue;
|
|
|
|
if (flags & 1)
|
|
{
|
|
if ((func)(pPlayer->name.chars(), sptemp))
|
|
continue;
|
|
}
|
|
|
|
if (flags & 2)
|
|
{
|
|
if (flags & 2048)
|
|
{
|
|
if (utf8stristr(pPlayer->name.chars(), sptemp) == NULL)
|
|
continue;
|
|
}
|
|
else if (strstr(pPlayer->name.chars(), sptemp) == NULL)
|
|
continue;
|
|
}
|
|
|
|
if (flags & 4)
|
|
{
|
|
const char* authid = GETPLAYERAUTHID(pPlayer->pEdict);
|
|
|
|
if (!authid || (func)(authid, sptemp))
|
|
continue;
|
|
}
|
|
|
|
if (flags & 1024)
|
|
{
|
|
if (userid != GETPLAYERUSERID(pPlayer->pEdict))
|
|
continue;
|
|
}
|
|
|
|
if (flags & 8)
|
|
{
|
|
if (strncmp(pPlayer->ip.chars(), sptemp, ilen))
|
|
continue;
|
|
}
|
|
|
|
if (flags & 16)
|
|
{
|
|
if ((func)(pPlayer->team.chars(), sptemp))
|
|
continue;
|
|
}
|
|
|
|
result = i;
|
|
|
|
if ((flags & 512) == 0)
|
|
break;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// native find_player_ex(FindPlayerFlags:flags, ...);
|
|
static cell AMX_NATIVE_CALL find_player_ex(AMX *amx, cell *params)
|
|
{
|
|
cell amx_addr;
|
|
cell *phys_addr;
|
|
char strFlags[14];
|
|
|
|
amx_Allot(amx, ARRAY_LENGTH(strFlags), &amx_addr, &phys_addr);
|
|
UTIL_GetFlags(strFlags, params[1]);
|
|
set_amxstring(amx, amx_addr, strFlags, ARRAY_LENGTH(strFlags) - 1);
|
|
|
|
params[1] = amx_addr;
|
|
cell ret = find_player(amx, params);
|
|
amx_Release(amx, amx_addr);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_maxplayers(AMX *amx, cell *params)
|
|
{
|
|
return gpGlobals->maxClients;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_gametime(AMX *amx, cell *params)
|
|
{
|
|
REAL pFloat = (REAL)gpGlobals->time;
|
|
return amx_ftoc(pFloat);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_mapname(AMX *amx, cell *params) /* 2 param */
|
|
{
|
|
return set_amxstring(amx, params[1], STRING(gpGlobals->mapname), params[2]);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_modname(AMX *amx, cell *params) /* 2 param */
|
|
{
|
|
return set_amxstring(amx, params[1], g_mod_name.chars(), params[2]);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_localinfo(AMX *amx, cell *params) /* 3 param */
|
|
{
|
|
int ilen;
|
|
char* sptemp = get_amxstring(amx, params[1], 0, ilen);
|
|
|
|
char *value = LOCALINFO(sptemp);
|
|
return set_amxstring_utf8(amx, params[2], value, strlen(value), params[3]);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL set_localinfo(AMX *amx, cell *params) /* 2 param */
|
|
{
|
|
int ilen;
|
|
char* sptemp = get_amxstring(amx, params[1], 0, ilen);
|
|
char* szValue = get_amxstring(amx, params[2], 1, ilen);
|
|
|
|
SET_LOCALINFO(sptemp, szValue);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_user_info(AMX *amx, cell *params) /* 4 param */
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid player id %d", index);
|
|
return 0;
|
|
}
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
if (!pPlayer->pEdict)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Player %d is not connected", index);
|
|
return 0;
|
|
}
|
|
|
|
int ilen;
|
|
char* sptemp = get_amxstring(amx, params[2], 0, ilen);
|
|
|
|
return set_amxstring(amx, params[3], ENTITY_KEYVALUE(pPlayer->pEdict, sptemp), params[4]);
|
|
return 1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL set_user_info(AMX *amx, cell *params) /* 3 param */
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid player id %d", index);
|
|
return 0;
|
|
}
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
if (!pPlayer->pEdict)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Player %d is not connected", index);
|
|
return 0;
|
|
}
|
|
|
|
int ilen;
|
|
char* sptemp = get_amxstring(amx, params[2], 0, ilen);
|
|
char* szValue = get_amxstring(amx, params[3], 1, ilen);
|
|
|
|
ENTITY_SET_KEYVALUE(pPlayer->pEdict, sptemp, szValue);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL read_argc(AMX *amx, cell *params)
|
|
{
|
|
return g_fakecmd.notify ? g_fakecmd.argc : CMD_ARGC();
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL read_argv(AMX *amx, cell *params) /* 3 param */
|
|
{
|
|
int argc = params[1];
|
|
|
|
const char *value = g_fakecmd.notify ? ((argc >= 0 && argc < 3 && g_fakecmd.argv[argc] != nullptr) ? g_fakecmd.argv[argc] : "") : CMD_ARGV(argc);
|
|
return set_amxstring_utf8(amx, params[2], value, strlen(value), params[3]);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL read_argv_int(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
int argc = params[1];
|
|
|
|
if (argc <= 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
const char *value = g_fakecmd.notify ? ((argc >= 1 && argc < 3 && g_fakecmd.argv[argc] != nullptr) ? g_fakecmd.argv[argc] : "") : CMD_ARGV(argc);
|
|
|
|
return atoi(value);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL read_argv_float(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
int argc = params[1];
|
|
|
|
if (argc <= 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
const char *value = g_fakecmd.notify ? ((argc >= 1 && argc < 3 && g_fakecmd.argv[argc] != nullptr) ? g_fakecmd.argv[argc] : "") : CMD_ARGV(argc);
|
|
float flValue = atof(value);
|
|
|
|
return amx_ftoc(flValue);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL read_args(AMX *amx, cell *params) /* 2 param */
|
|
{
|
|
const char* sValue = g_fakecmd.notify ? (g_fakecmd.argc > 1 ? g_fakecmd.args : "") : CMD_ARGS();
|
|
return set_amxstring_utf8(amx, params[1], sValue ? sValue : "", sValue ? strlen(sValue) : 0, params[2]);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_user_msgid(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
int ilen;
|
|
char* sptemp = get_amxstring(amx, params[1], 0, ilen);
|
|
|
|
return GET_USER_MSG_ID(PLID, sptemp, NULL);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_user_msgname(AMX *amx, cell *params) /* get_user_msgname(msg, str[], len) = 3 params */
|
|
{
|
|
const char* STRING = GET_USER_MSG_NAME(PLID, params[1], NULL);
|
|
if (STRING)
|
|
return set_amxstring(amx, params[2], STRING, params[3]);
|
|
|
|
// Comes here if GET_USER_MSG_NAME failed (ie, invalid msg id)
|
|
return 0;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL set_task(AMX *amx, cell *params) /* 2 param */
|
|
{
|
|
|
|
CPluginMngr::CPlugin *plugin = g_plugins.findPluginFast(amx);
|
|
|
|
int a, iFunc;
|
|
|
|
char* stemp = get_amxstring(amx, params[2], 1, a);
|
|
|
|
if (params[5])
|
|
{
|
|
iFunc = registerSPForwardByName(amx, stemp, FP_ARRAY, FP_CELL, FP_DONE);
|
|
} else {
|
|
iFunc = registerSPForwardByName(amx, stemp, FP_CELL, FP_DONE);
|
|
}
|
|
|
|
if (iFunc == -1)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Function is not present (function \"%s\") (plugin \"%s\")", stemp, plugin->getName());
|
|
return 0;
|
|
}
|
|
|
|
float base = amx_ctof(params[1]);
|
|
|
|
if (base < 0.1f)
|
|
base = 0.1f;
|
|
|
|
char* temp = get_amxstring(amx, params[6], 0, a);
|
|
|
|
g_tasksMngr.registerTask(plugin, iFunc, UTIL_ReadFlags(temp), params[3], base, params[5], get_amxaddr(amx, params[4]), params[7]);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL remove_task(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
return g_tasksMngr.removeTasks(params[1], params[2] ? 0 : amx);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL change_task(AMX *amx, cell *params)
|
|
{
|
|
REAL flNewTime = amx_ctof(params[2]);
|
|
return g_tasksMngr.changeTasks(params[1], params[3] ? 0 : amx, flNewTime);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL engine_changelevel(AMX *amx, cell *params)
|
|
{
|
|
int length;
|
|
ke::AString new_map(get_amxstring(amx, params[1], 0, length));
|
|
|
|
// Same as calling "changelevel" command but will trigger "server_changelevel" AMXX forward as well.
|
|
// Filling second param will call "changelevel2" command, but this is not usable in multiplayer game.
|
|
g_pEngTable->pfnChangeLevel(new_map.chars(), NULL);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL task_exists(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
return g_tasksMngr.taskExists(params[1], params[2] ? 0 : amx);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_user_ping(AMX *amx, cell *params) /* 3 param */
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
return 0;
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
if (pPlayer->ingame)
|
|
{
|
|
cell *cpPing = get_amxaddr(amx, params[2]);
|
|
cell *cpLoss = get_amxaddr(amx, params[3]);
|
|
int ping, loss;
|
|
PLAYER_CNX_STATS(pPlayer->pEdict, &ping, &loss);
|
|
*cpPing = ping;
|
|
*cpLoss = loss;
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_user_time(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
return 0;
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
if (pPlayer->ingame)
|
|
{
|
|
int time = (int)(gpGlobals->time - (params[2] ? pPlayer->playtime : pPlayer->time));
|
|
return time;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL server_exec(AMX *amx, cell *params)
|
|
{
|
|
SERVER_EXECUTE();
|
|
return 1;
|
|
}
|
|
|
|
int sendFakeCommand(AMX *amx, cell *params, bool send_forward = false)
|
|
{
|
|
enum args { arg_count, arg_index, arg_command, arg_argument1, arg_argument2 };
|
|
|
|
char command[128 * 2];
|
|
auto command_length = strncopy(command, get_amxaddr(amx, params[arg_command]), sizeof(command));
|
|
|
|
if (!command_length)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
char argument1[128];
|
|
char argument2[128];
|
|
auto argument1_length = strncopy(argument1, get_amxaddr(amx, params[arg_argument1]), sizeof(argument1));
|
|
auto argument2_length = strncopy(argument2, get_amxaddr(amx, params[arg_argument2]), sizeof(argument2));
|
|
|
|
const char *pArgument1 = argument1_length ? argument1 : nullptr;
|
|
const char *pArgument2 = argument2_length ? argument2 : nullptr;
|
|
|
|
int index = params[arg_index];
|
|
|
|
if (index == 0)
|
|
{
|
|
for (int i = 1; i <= gpGlobals->maxClients; ++i)
|
|
{
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(i);
|
|
|
|
if (pPlayer->ingame /*&& pPlayer->initialized */)
|
|
UTIL_FakeClientCommand(pPlayer->pEdict, command, pArgument1, pArgument2, send_forward);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid player id %d", index);
|
|
return 0;
|
|
}
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
if (/*pPlayer->initialized && */pPlayer->ingame)
|
|
UTIL_FakeClientCommand(pPlayer->pEdict, command, pArgument1, pArgument2, send_forward);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
// native engclient_cmd(index, const command[], const arg1[] = "", const arg2[] = "");
|
|
static cell AMX_NATIVE_CALL engclient_cmd(AMX *amx, cell *params)
|
|
{
|
|
return sendFakeCommand(amx, params);
|
|
}
|
|
|
|
// native amxclient_cmd(index, const command[], const arg1[] = "", const arg2[] = "");
|
|
static cell AMX_NATIVE_CALL amxclient_cmd(AMX *amx, cell *params)
|
|
{
|
|
return sendFakeCommand(amx, params, true);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL pause(AMX *amx, cell *params) /* 3 param */
|
|
{
|
|
int ilen;
|
|
char* temp = get_amxstring(amx, params[1], 0, ilen);
|
|
int flags = UTIL_ReadFlags(temp);
|
|
|
|
CPluginMngr::CPlugin *plugin = 0;
|
|
|
|
if (flags & 2) // pause function
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "This usage of the native pause() has been deprecated!");
|
|
return 1;
|
|
}
|
|
else if (flags & 4)
|
|
{
|
|
temp = get_amxstring(amx, params[2], 0, ilen);
|
|
plugin = g_plugins.findPlugin(temp);
|
|
}
|
|
else
|
|
plugin = g_plugins.findPluginFast(amx);
|
|
|
|
if (plugin && plugin->isValid())
|
|
{
|
|
if (flags & 8)
|
|
plugin->setStatus(ps_stopped);
|
|
/*else if (flags & 16)
|
|
plugin->setStatus(ps_locked);*/
|
|
else
|
|
plugin->pausePlugin();
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL unpause(AMX *amx, cell *params) /* 3 param */
|
|
{
|
|
|
|
int ilen;
|
|
char* sptemp = get_amxstring(amx, params[1], 0, ilen);
|
|
int flags = UTIL_ReadFlags(sptemp);
|
|
CPluginMngr::CPlugin *plugin = 0;
|
|
|
|
if (flags & 2)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "This usage of the native pause() has been deprecated!");
|
|
return 1;
|
|
}
|
|
else if (flags & 4)
|
|
{
|
|
sptemp = get_amxstring(amx, params[2], 0, ilen);
|
|
plugin = g_plugins.findPlugin(sptemp);
|
|
}
|
|
else
|
|
plugin = g_plugins.findPluginFast(amx);
|
|
|
|
if (plugin && plugin->isValid() && plugin->isPaused() && !plugin->isStopped())
|
|
{
|
|
plugin->unpausePlugin();
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL read_flags(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
int ilen;
|
|
char* sptemp = get_amxstring(amx, params[1], 0, ilen);
|
|
|
|
return UTIL_ReadFlags(sptemp);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_flags(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
char flags[32];
|
|
UTIL_GetFlags(flags, params[1]);
|
|
|
|
return set_amxstring(amx, params[2], flags, params[3]);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_user_flags(AMX *amx, cell *params) /* 2 param */
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 0 || index > gpGlobals->maxClients)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid player id %d", index);
|
|
return 0;
|
|
}
|
|
|
|
int id = params[2];
|
|
|
|
if (id < 0)
|
|
id = 0;
|
|
|
|
if (id > 31)
|
|
id = 31;
|
|
|
|
return GET_PLAYER_POINTER_I(index)->flags[id];
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL set_user_flags(AMX *amx, cell *params) /* 3 param */
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 0 || index > gpGlobals->maxClients)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid player id %d", index);
|
|
return 0;
|
|
}
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
int flag = params[2];
|
|
int id = params[3];
|
|
|
|
if (id < 0)
|
|
id = 0;
|
|
|
|
if (id > 31)
|
|
id = 31;
|
|
|
|
pPlayer->flags[id] |= flag;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL remove_user_flags(AMX *amx, cell *params) /* 3 param */
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 0 || index > gpGlobals->maxClients)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid player id %d", index);
|
|
return 0;
|
|
}
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
int flag = params[2];
|
|
int id = params[3];
|
|
|
|
if (id < 0)
|
|
id = 0;
|
|
|
|
if (id > 31)
|
|
id = 31;
|
|
|
|
pPlayer->flags[id] &= ~flag;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL register_menuid(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
int i;
|
|
char* temp = get_amxstring(amx, params[1], 0, i);
|
|
AMX* a = (*params / sizeof(cell) < 2 || params[2]) ? 0 : amx;
|
|
|
|
return g_menucmds.registerMenuId(temp, a);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_user_menu(AMX *amx, cell *params) /* 3 param */
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid player id %d", index);
|
|
return 0;
|
|
}
|
|
|
|
cell *cpMenu = get_amxaddr(amx, params[2]);
|
|
cell *cpKeys = get_amxaddr(amx, params[3]);
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
if (pPlayer->ingame)
|
|
{
|
|
if (gpGlobals->time > pPlayer->menuexpire)
|
|
{
|
|
if (Menu *pMenu = get_menu_by_id(pPlayer->newmenu))
|
|
pMenu->Close(pPlayer->index);
|
|
else
|
|
pPlayer->menu = 0;
|
|
|
|
*cpMenu = 0;
|
|
*cpKeys = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
*cpMenu = pPlayer->menu;
|
|
*cpKeys = pPlayer->keys;
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL precache_sound(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
if (g_dontprecache)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Precaching not allowed");
|
|
return 0;
|
|
}
|
|
|
|
int len;
|
|
char* sptemp = get_amxstring(amx, params[1], 0, len);
|
|
|
|
return PRECACHE_SOUND((char*)STRING(ALLOC_STRING(sptemp)));
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL precache_model(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
if (g_dontprecache)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Precaching not allowed");
|
|
return 0;
|
|
}
|
|
|
|
int len;
|
|
char* sptemp = get_amxstring(amx, params[1], 0, len);
|
|
|
|
return PRECACHE_MODEL((char*)STRING(ALLOC_STRING(sptemp)));
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL precache_generic(AMX *amx, cell *params)
|
|
{
|
|
if (g_dontprecache)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Precaching not allowed");
|
|
return 0;
|
|
}
|
|
|
|
int len;
|
|
char* sptemp = get_amxstring(amx, params[1], 0, len);
|
|
|
|
return PRECACHE_GENERIC((char*)STRING(ALLOC_STRING(sptemp)));
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL precache_event(AMX *amx, cell *params)
|
|
{
|
|
int len;
|
|
char *sptemp = format_amxstring(amx, params, 2, len);
|
|
|
|
return PRECACHE_EVENT(params[1], (char*)STRING(ALLOC_STRING(sptemp)));
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL random_float(AMX *amx, cell *params) /* 2 param */
|
|
{
|
|
float one = amx_ctof(params[1]);
|
|
float two = amx_ctof(params[2]);
|
|
REAL fRnd = RANDOM_FLOAT(one, two);
|
|
|
|
return amx_ftoc(fRnd);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL random_num(AMX *amx, cell *params) /* 2 param */
|
|
{
|
|
return RANDOM_LONG(params[1], params[2]);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL remove_quotes(AMX *amx, cell *params) /* 1 param */
|
|
{
|
|
cell *text = get_amxaddr(amx, params[1]);
|
|
|
|
if (*text == '\"')
|
|
{
|
|
register cell *temp = text;
|
|
int len = 0;
|
|
|
|
while (*temp++)
|
|
++len; // get length
|
|
|
|
cell *src = text;
|
|
|
|
if (src[len-1] == '\r')
|
|
src[--len] = 0;
|
|
|
|
if (src[--len] == '\"')
|
|
{
|
|
src[len] = 0;
|
|
temp = src + 1;
|
|
while ((*src++ = *temp++));
|
|
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_user_aiming(AMX *amx, cell *params) /* 4 param */
|
|
{
|
|
int index = params[1];
|
|
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid player id %d", index);
|
|
return 0;
|
|
}
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
cell *cpId = get_amxaddr(amx, params[2]);
|
|
cell *cpBody = get_amxaddr(amx, params[3]);
|
|
|
|
REAL pfloat = 0.0f;
|
|
|
|
if (pPlayer->ingame)
|
|
{
|
|
edict_t* edict = pPlayer->pEdict;
|
|
|
|
Vector v_forward;
|
|
Vector v_src = edict->v.origin + edict->v.view_ofs;
|
|
|
|
ANGLEVECTORS(edict->v.v_angle, v_forward, NULL, NULL);
|
|
TraceResult trEnd;
|
|
Vector v_dest = v_src + v_forward * static_cast<float>(params[4]);
|
|
TRACE_LINE(v_src, v_dest, 0, edict, &trEnd);
|
|
|
|
*cpId = FNullEnt(trEnd.pHit) ? 0 : ENTINDEX(trEnd.pHit);
|
|
*cpBody = trEnd.iHitgroup;
|
|
|
|
if (trEnd.flFraction < 1.0)
|
|
{
|
|
pfloat = (trEnd.vecEndPos - v_src).Length();
|
|
}
|
|
} else {
|
|
*cpId = 0;
|
|
*cpBody = 0;
|
|
}
|
|
|
|
return amx_ftoc(pfloat);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL force_unmodified(AMX *amx, cell *params)
|
|
{
|
|
int a;
|
|
|
|
cell *cpVec1 = get_amxaddr(amx, params[2]);
|
|
cell *cpVec2 = get_amxaddr(amx, params[3]);
|
|
|
|
Vector vec1 = Vector((float)cpVec1[0], (float)cpVec1[1], (float)cpVec1[2]);
|
|
Vector vec2 = Vector((float)cpVec2[0], (float)cpVec2[1], (float)cpVec2[2]);
|
|
|
|
char* filename = get_amxstring(amx, params[4], 0, a);
|
|
|
|
auto object = ke::AutoPtr<ForceObject>(new ForceObject(filename, (FORCE_TYPE)((int)(params[1])), vec1, vec2, amx));
|
|
|
|
if (object)
|
|
{
|
|
auto forceObjVec = &g_forcegeneric;
|
|
|
|
if (stristr(filename, ".wav"))
|
|
forceObjVec = &g_forcesounds;
|
|
else if (stristr(filename, ".mdl"))
|
|
forceObjVec = &g_forcemodels;
|
|
|
|
forceObjVec->append(ke::Move(object));
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL read_logdata(AMX *amx, cell *params)
|
|
{
|
|
const char *value = g_logevents.getLogString();
|
|
return set_amxstring_utf8(amx, params[1], value, strlen(value), params[2]);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL read_logargc(AMX *amx, cell *params)
|
|
{
|
|
return g_logevents.getLogArgNum();
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL read_logargv(AMX *amx, cell *params)
|
|
{
|
|
const char *value = g_logevents.getLogArg(params[1]);
|
|
return set_amxstring_utf8(amx, params[2], value, strlen(value), params[3]);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL parse_loguser(AMX *amx, cell *params)
|
|
{
|
|
int len;
|
|
char *text = get_amxstring(amx, params[1], 0, len);
|
|
|
|
if (len < 6) // no user to parse!?
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "No user name specified");
|
|
return 0;
|
|
}
|
|
|
|
/******** GET TEAM **********/
|
|
char* end = text + --len;
|
|
*end = 0;
|
|
|
|
while (*end != '<' && len--)
|
|
--end;
|
|
|
|
++end;
|
|
cell *cPtr = get_amxaddr(amx, params[7]);
|
|
int max = params[8]; // get TEAM
|
|
// print_srvconsole("Got team: %s (Len %d)\n", end, len);
|
|
|
|
while (max-- && *end)
|
|
*cPtr++ = *end++;
|
|
|
|
*cPtr = 0;
|
|
|
|
/******** GET AUTHID **********/
|
|
if (len <= 0)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "No Authid found");
|
|
return 0;
|
|
}
|
|
|
|
end = text + --len;
|
|
*end = 0;
|
|
|
|
while (*end != '<' && len--)
|
|
--end;
|
|
|
|
++end;
|
|
cPtr = get_amxaddr(amx, params[5]);
|
|
max = params[6]; // get AUTHID
|
|
// print_srvconsole("Got auth: %s (Len %d)\n", end, len);
|
|
|
|
while (max-- && *end)
|
|
*cPtr++ = *end++;
|
|
|
|
*cPtr = 0;
|
|
|
|
/******** GET USERID **********/
|
|
if (len <= 0)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "No Userid found");
|
|
return 0;
|
|
}
|
|
|
|
end = text + --len;
|
|
*end = 0;
|
|
|
|
while (*end != '<' && len--)
|
|
--end;
|
|
|
|
// print_srvconsole("Got userid: %s (Len %d)\n", end + 1, len);
|
|
if (*(cPtr = get_amxaddr(amx, params[4])) != -2)
|
|
*cPtr = atoi(end + 1);
|
|
|
|
/******** GET NAME **********/
|
|
*end = 0;
|
|
cPtr = get_amxaddr(amx, params[2]);
|
|
max = params[3]; // get NAME
|
|
// print_srvconsole("Got name: %s (Len %d)\n", text, len);
|
|
|
|
while (max-- && *text)
|
|
*cPtr++ = *text++;
|
|
|
|
*cPtr = 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
// native register_logevent(const function[], argsnum, ...);
|
|
static cell AMX_NATIVE_CALL register_logevent(AMX *amx, cell *params)
|
|
{
|
|
int length;
|
|
auto callback = get_amxstring(amx, params[1], 0, length);
|
|
|
|
auto forwardId = registerSPForwardByName(amx, callback, FP_DONE);
|
|
|
|
if (forwardId == -1)
|
|
{
|
|
LogError(amx, AMX_ERR_NOTFOUND, "Function \"%s\" was not found", callback);
|
|
return 0;
|
|
}
|
|
|
|
auto handle = g_logevents.registerLogEvent(g_plugins.findPluginFast(amx), forwardId, params[2]);
|
|
|
|
if (!handle)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
auto logevent = LogEventHandles.lookup(handle)->m_logevent;
|
|
auto numparam = *params / sizeof(cell);
|
|
|
|
for (auto i = 3U; i <= numparam; ++i)
|
|
{
|
|
logevent->registerFilter(get_amxstring(amx, params[i], 0, length));
|
|
}
|
|
|
|
return handle;
|
|
}
|
|
|
|
// native enable_logevent(handle);
|
|
static cell AMX_NATIVE_CALL enable_logevent(AMX *amx, cell *params)
|
|
{
|
|
auto handle = LogEventHandles.lookup(params[1]);
|
|
|
|
if (!handle)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid log event handle %d", params[1]);
|
|
return 0;
|
|
}
|
|
|
|
handle->m_logevent->setForwardState(FSTATE_ACTIVE);
|
|
|
|
return 1;
|
|
}
|
|
|
|
// native disable_logevent(handle);
|
|
static cell AMX_NATIVE_CALL disable_logevent(AMX *amx, cell *params)
|
|
{
|
|
auto handle = LogEventHandles.lookup(params[1]);
|
|
|
|
if (!handle)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid log event handle: %d", params[1]);
|
|
return 0;
|
|
}
|
|
|
|
handle->m_logevent->setForwardState(FSTATE_STOP);
|
|
|
|
return 1;
|
|
}
|
|
|
|
// native is_module_loaded(const name[]);
|
|
static cell AMX_NATIVE_CALL is_module_loaded(AMX *amx, cell *params)
|
|
{
|
|
// param1: name
|
|
int len;
|
|
char *name = get_amxstring(amx, params[1], 0, len);
|
|
int id = 0;
|
|
|
|
for (auto module : g_modules)
|
|
{
|
|
if (!stricmp(module->getName(), name))
|
|
return id;
|
|
|
|
++id;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// native is_plugin_loaded(const name[]);
|
|
// 1.8 changed to: is_plugin_loaded(const name[], bool:usefilename=false);
|
|
static cell AMX_NATIVE_CALL is_plugin_loaded(AMX *amx, cell *params)
|
|
{
|
|
// param1: name
|
|
int len;
|
|
char *name = get_amxstring(amx, params[1], 0, len);
|
|
int id = 0;
|
|
|
|
if (params[0] / sizeof(cell) == 1 || // compiled pre-1.8 - assume plugin's registered name
|
|
params[2] == 0) // compiled post 1.8 - wants plugin's registered name
|
|
{
|
|
// searching for registered plugin name
|
|
for (CPluginMngr::iterator iter = g_plugins.begin(); iter; ++iter)
|
|
{
|
|
if (stricmp((*iter).getTitle(), name) == 0)
|
|
return id;
|
|
|
|
++id;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// searching for filename
|
|
// filename search is case sensitive
|
|
for (CPluginMngr::iterator iter = g_plugins.begin(); iter; ++iter)
|
|
{
|
|
if (strcmp((*iter).getName(), name) == 0)
|
|
return id;
|
|
|
|
++id;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// native get_modulesnum();
|
|
static cell AMX_NATIVE_CALL get_modulesnum(AMX *amx, cell *params)
|
|
{
|
|
return (cell)countModules(CountModules_All);
|
|
}
|
|
|
|
// native get_module(id, name[], nameLen, author[], authorLen, version[], versionLen, &status);
|
|
static cell AMX_NATIVE_CALL get_module(AMX *amx, cell *params)
|
|
{
|
|
// find the module
|
|
int i = params[1];
|
|
|
|
for (auto module : g_modules)
|
|
{
|
|
if (i--)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// set name, author, version
|
|
const amxx_module_info_s *info = module->getInfoNew();
|
|
const char *name = info && info->name ? info->name : "unk";
|
|
const char *author = info && info->author ? info->author : "unk";
|
|
const char *version = info && info->version ? info->version : "unk";
|
|
|
|
set_amxstring_utf8(amx, params[2], name, strlen(name), params[3]);
|
|
set_amxstring_utf8(amx, params[4], author, strlen(author), params[5]);
|
|
set_amxstring_utf8(amx, params[6], version, strlen(version), params[7]);
|
|
|
|
// compatibility problem possible
|
|
int numParams = params[0] / sizeof(cell);
|
|
|
|
if (numParams < 8)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Call to incompatible version");
|
|
return 0;
|
|
}
|
|
|
|
// set status
|
|
cell *addr;
|
|
if (amx_GetAddr(amx, params[8], &addr) != AMX_ERR_NONE)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid reference plugin");
|
|
return 0;
|
|
}
|
|
|
|
*addr = (cell)module->getStatusValue();
|
|
return params[1];
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// native log_amx(const msg[], ...);
|
|
static cell AMX_NATIVE_CALL log_amx(AMX *amx, cell *params)
|
|
{
|
|
CPluginMngr::CPlugin *plugin = g_plugins.findPluginFast(amx);
|
|
int len;
|
|
|
|
g_langMngr.SetDefLang(LANG_SERVER);
|
|
AMXXLOG_Log("[%s] %s", plugin->getName(), format_amxstring(amx, params, 1, len));
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*********************************************************************/
|
|
|
|
CPluginMngr::CPlugin *g_CallFunc_Plugin = NULL; // The plugin
|
|
int g_CallFunc_Func = 0; // The func
|
|
|
|
struct CallFunc_ParamInfo
|
|
{
|
|
unsigned char flags; // flags
|
|
cell byrefAddr; // byref address in caller plugin
|
|
cell size; // byref size
|
|
cell *alloc; // allocated block
|
|
bool copyback; // copy back?
|
|
};
|
|
|
|
#if !defined CALLFUNC_MAXPARAMS
|
|
#define CALLFUNC_MAXPARAMS 64 /* Maximal params number */
|
|
#endif
|
|
|
|
cell g_CallFunc_Params[CALLFUNC_MAXPARAMS] = {0}; // Params
|
|
CallFunc_ParamInfo g_CallFunc_ParamInfo[CALLFUNC_MAXPARAMS] = {{0}}; // Flags
|
|
int g_CallFunc_CurParam = 0; // Current param id
|
|
|
|
#define CALLFUNC_FLAG_BYREF 1 /* Byref flag so that mem is released */
|
|
#define CALLFUNC_FLAG_BYREF_REUSED 2 /* Reused byref */
|
|
|
|
// native callfunc_begin(const func[], const plugin[]="");
|
|
static cell AMX_NATIVE_CALL callfunc_begin(AMX *amx, cell *params)
|
|
{
|
|
CPluginMngr::CPlugin *curPlugin = g_plugins.findPluginFast(amx);
|
|
|
|
if (g_CallFunc_Plugin)
|
|
{
|
|
// scripter's fault
|
|
LogError(amx, AMX_ERR_NATIVE, "callfunc_begin called without callfunc_end");
|
|
return 0;
|
|
}
|
|
|
|
int len;
|
|
char *pluginStr = get_amxstring(amx, params[2], 0, len);
|
|
char *funcStr = get_amxstring(amx, params[1], 1, len);
|
|
CPluginMngr::CPlugin *plugin = NULL;
|
|
|
|
if (!pluginStr || !*pluginStr)
|
|
plugin = curPlugin;
|
|
else
|
|
plugin = g_plugins.findPlugin(pluginStr);
|
|
|
|
if (!plugin)
|
|
{
|
|
return -1; // plugin not found: -1
|
|
}
|
|
|
|
int func;
|
|
|
|
if (amx_FindPublic(plugin->getAMX(), funcStr, &func) != AMX_ERR_NONE)
|
|
{
|
|
return -2; // func not found: -2
|
|
}
|
|
|
|
// set globals
|
|
g_CallFunc_Plugin = plugin;
|
|
g_CallFunc_Func = func;
|
|
g_CallFunc_CurParam = 0;
|
|
|
|
return 1; // success: 1
|
|
}
|
|
|
|
// native callfunc_begin_i(funcId, pluginId = -1)
|
|
static cell AMX_NATIVE_CALL callfunc_begin_i(AMX *amx, cell *params)
|
|
{
|
|
CPluginMngr::CPlugin *plugin;
|
|
|
|
if (params[2] < 0)
|
|
plugin = g_plugins.findPluginFast(amx);
|
|
else
|
|
plugin = g_plugins.findPlugin(params[2]);
|
|
|
|
if (!plugin)
|
|
return -1;
|
|
|
|
if (g_CallFunc_Plugin)
|
|
{
|
|
// scripter's fault
|
|
LogError(amx, AMX_ERR_NATIVE, "callfunc_begin called without callfunc_end");
|
|
return 0;
|
|
}
|
|
|
|
if (params[1] < 0)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Public function %d is invalid", params[1]);
|
|
return -1;
|
|
}
|
|
|
|
if (!plugin->isExecutable(params[1]))
|
|
return -2;
|
|
|
|
g_CallFunc_Plugin = plugin;
|
|
g_CallFunc_Func = params[1];
|
|
g_CallFunc_CurParam = 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
// native get_func_id(funcName[], pluginId = -1)
|
|
static cell AMX_NATIVE_CALL get_func_id(AMX *amx, cell *params)
|
|
{
|
|
CPluginMngr::CPlugin *plugin;
|
|
|
|
if (params[2] < 0)
|
|
{
|
|
plugin = g_plugins.findPluginFast(amx);
|
|
} else {
|
|
plugin = g_plugins.findPlugin(params[2]);
|
|
}
|
|
|
|
if (!plugin)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if (!plugin->isValid())
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
int len;
|
|
const char *funcName = get_amxstring(amx, params[1], 0, len);
|
|
int index, err;
|
|
|
|
if ((err = amx_FindPublic(plugin->getAMX(), funcName, &index)) != AMX_ERR_NONE)
|
|
{
|
|
index = -1;
|
|
}
|
|
|
|
return index;
|
|
}
|
|
|
|
// native callfunc_end();
|
|
static cell AMX_NATIVE_CALL callfunc_end(AMX *amx, cell *params)
|
|
{
|
|
CPluginMngr::CPlugin *curPlugin = g_plugins.findPluginFast(amx);
|
|
|
|
if (!g_CallFunc_Plugin)
|
|
{
|
|
// scripter's fault
|
|
LogError(amx, AMX_ERR_NATIVE, "callfunc_end called without callfunc_begin");
|
|
return 0;
|
|
}
|
|
|
|
// call the func
|
|
cell retVal;
|
|
int err;
|
|
|
|
// copy the globs so the called func can also use callfunc
|
|
cell gparams[CALLFUNC_MAXPARAMS];
|
|
CallFunc_ParamInfo gparamInfo[CALLFUNC_MAXPARAMS];
|
|
|
|
CPluginMngr::CPlugin *plugin = g_CallFunc_Plugin;
|
|
int func = g_CallFunc_Func;
|
|
int curParam = g_CallFunc_CurParam;
|
|
|
|
memcpy(gparams, g_CallFunc_Params, sizeof(cell) * curParam);
|
|
memcpy(gparamInfo, g_CallFunc_ParamInfo, sizeof(CallFunc_ParamInfo) * curParam);
|
|
|
|
// cleanup
|
|
g_CallFunc_Plugin = NULL;
|
|
g_CallFunc_CurParam = 0;
|
|
|
|
AMX *pAmx = plugin->getAMX();
|
|
|
|
Debugger *pDebugger = (Debugger *)pAmx->userdata[UD_DEBUGGER];
|
|
|
|
if (pDebugger)
|
|
{
|
|
pDebugger->BeginExec();
|
|
}
|
|
|
|
// first pass over byref things
|
|
for (int i = curParam - 1; i >= 0; i--)
|
|
{
|
|
if (gparamInfo[i].flags & CALLFUNC_FLAG_BYREF)
|
|
{
|
|
cell amx_addr, *phys_addr;
|
|
amx_Allot(pAmx, gparamInfo[i].size, &amx_addr, &phys_addr);
|
|
memcpy(phys_addr, gparamInfo[i].alloc, gparamInfo[i].size * sizeof(cell));
|
|
gparams[i] = amx_addr;
|
|
delete [] gparamInfo[i].alloc;
|
|
gparamInfo[i].alloc = NULL;
|
|
}
|
|
}
|
|
|
|
// second pass, link in reused byrefs
|
|
for (int i = curParam - 1; i >= 0; i--)
|
|
{
|
|
if (gparamInfo[i].flags & CALLFUNC_FLAG_BYREF_REUSED)
|
|
{
|
|
gparams[i] = gparams[gparams[i]];
|
|
}
|
|
}
|
|
|
|
// actual call
|
|
// Pawn - push parameters in reverse order
|
|
for (int i = curParam - 1; i >= 0; i--)
|
|
{
|
|
amx_Push(pAmx, gparams[i]);
|
|
}
|
|
|
|
err = amx_Exec(pAmx, &retVal, func);
|
|
|
|
if (err != AMX_ERR_NONE)
|
|
{
|
|
if (pDebugger && pDebugger->ErrorExists())
|
|
{
|
|
//already handled
|
|
} else {
|
|
LogError(amx, err, NULL);
|
|
}
|
|
}
|
|
|
|
if (pDebugger)
|
|
{
|
|
pDebugger->EndExec();
|
|
}
|
|
|
|
// process byref params (not byref_reused)
|
|
for (int i = 0; i < curParam; ++i)
|
|
{
|
|
if (gparamInfo[i].flags & CALLFUNC_FLAG_BYREF)
|
|
{
|
|
// copy back so that references work
|
|
AMX *amxCalled = plugin->getAMX();
|
|
|
|
if (gparamInfo[i].copyback)
|
|
{
|
|
AMX *amxCaller = curPlugin->getAMX();
|
|
AMX_HEADER *hdrCaller = (AMX_HEADER *)amxCaller->base;
|
|
AMX_HEADER *hdrCalled = (AMX_HEADER *)amxCalled->base;
|
|
memcpy( /** DEST ADDR **/
|
|
(amxCaller->data ? amxCaller->data : (amxCaller->base + hdrCaller->dat)) + gparamInfo[i].byrefAddr,
|
|
/** SOURCE ADDR **/
|
|
(amxCalled->data ? amxCalled->data : (amxCalled->base + hdrCalled->dat)) + gparams[i],
|
|
/** SIZE **/
|
|
gparamInfo[i].size * sizeof(cell));
|
|
}
|
|
|
|
// free memory used for params passed by reference
|
|
amx_Release(amxCalled, gparams[i]);
|
|
}
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
// native callfunc_push_int(value);
|
|
// native callfunc_push_float(Float: value);
|
|
static cell AMX_NATIVE_CALL callfunc_push_byval(AMX *amx, cell *params)
|
|
{
|
|
if (!g_CallFunc_Plugin)
|
|
{
|
|
// scripter's fault
|
|
LogError(amx, AMX_ERR_NATIVE, "callfunc_push_xxx called without callfunc_begin");
|
|
return 0;
|
|
}
|
|
|
|
if (g_CallFunc_CurParam == CALLFUNC_MAXPARAMS)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Callfunc_push_xxx: maximal parameters num: %d", CALLFUNC_MAXPARAMS);
|
|
return 0;
|
|
}
|
|
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].flags = 0;
|
|
g_CallFunc_Params[g_CallFunc_CurParam++] = params[1];
|
|
|
|
return 0;
|
|
}
|
|
|
|
// native callfunc_push_intref(&value);
|
|
// native callfunc_push_floatref(Float: &value);
|
|
static cell AMX_NATIVE_CALL callfunc_push_byref(AMX *amx, cell *params)
|
|
{
|
|
CPluginMngr::CPlugin *curPlugin = g_plugins.findPluginFast(amx);
|
|
|
|
if (!g_CallFunc_Plugin)
|
|
{
|
|
// scripter's fault
|
|
LogError(amx, AMX_ERR_NATIVE, "callfunc_push_xxx called without callfunc_begin");
|
|
return 0;
|
|
}
|
|
|
|
if (g_CallFunc_CurParam == CALLFUNC_MAXPARAMS)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "callfunc_push_xxx: maximal parameters num: %d", CALLFUNC_MAXPARAMS);
|
|
return 0;
|
|
}
|
|
|
|
// search for the address; if it is found, dont create a new copy
|
|
for (int i = 0; i < g_CallFunc_CurParam; ++i)
|
|
{
|
|
if ((g_CallFunc_ParamInfo[i].flags & CALLFUNC_FLAG_BYREF) && (g_CallFunc_ParamInfo[i].byrefAddr == params[1]))
|
|
{
|
|
// the byrefAddr and size params should not be used; set them anyways...
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].flags = CALLFUNC_FLAG_BYREF_REUSED;
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].byrefAddr = params[1];
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].size = 1;
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].alloc = NULL;
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].copyback = true;
|
|
g_CallFunc_Params[g_CallFunc_CurParam++] = i; /* referenced parameter */
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
cell *phys_addr = new cell[1];
|
|
|
|
// copy the value to the allocated memory
|
|
cell *phys_addr2;
|
|
amx_GetAddr(curPlugin->getAMX(), params[1], &phys_addr2);
|
|
*phys_addr = *phys_addr2;
|
|
|
|
// push the address and set the reference flag so that memory is released after function call.
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].flags = CALLFUNC_FLAG_BYREF;
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].byrefAddr = params[1];
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].size = 1;
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].alloc = phys_addr;
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].copyback = true;
|
|
g_CallFunc_Params[g_CallFunc_CurParam++] = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// native callfunc_push_array(array[], size, [copyback])
|
|
static cell AMX_NATIVE_CALL callfunc_push_array(AMX *amx, cell *params)
|
|
{
|
|
if (!g_CallFunc_Plugin)
|
|
{
|
|
// scripter's fault
|
|
LogError(amx, AMX_ERR_NATIVE, "callfunc_push_xxx called without callfunc_begin");
|
|
return 0;
|
|
}
|
|
|
|
if (g_CallFunc_CurParam == CALLFUNC_MAXPARAMS)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "callfunc_push_xxx: maximal parameters num: %d", CALLFUNC_MAXPARAMS);
|
|
return 0;
|
|
}
|
|
|
|
// search for the address; if it is found, dont create a new copy
|
|
for (int i = 0; i < g_CallFunc_CurParam; ++i)
|
|
{
|
|
if ((g_CallFunc_ParamInfo[i].flags & CALLFUNC_FLAG_BYREF) && (g_CallFunc_ParamInfo[i].byrefAddr == params[1]))
|
|
{
|
|
// the byrefAddr and size params should not be used; set them anyways...
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].flags = CALLFUNC_FLAG_BYREF_REUSED;
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].byrefAddr = params[1];
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].size = 1;
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].alloc = NULL;
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].copyback = g_CallFunc_ParamInfo[i].copyback;
|
|
g_CallFunc_Params[g_CallFunc_CurParam++] = i; /* referenced parameter */
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// not found; create an own copy
|
|
// get the string and its length
|
|
cell *pArray = get_amxaddr(amx, params[1]);
|
|
cell array_size = params[2];
|
|
|
|
// allocate enough memory for the array
|
|
cell *phys_addr = new cell[array_size];
|
|
|
|
memcpy(phys_addr, pArray, array_size * sizeof(cell));
|
|
|
|
// push the address and set the reference flag so that memory is released after function call.
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].flags = CALLFUNC_FLAG_BYREF;
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].byrefAddr = params[1];
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].size = array_size;
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].alloc = phys_addr;
|
|
|
|
if (params[0] / sizeof(cell) >= 3)
|
|
{
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].copyback = params[3] ? true : false;
|
|
} else {
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].copyback = true;
|
|
}
|
|
|
|
g_CallFunc_Params[g_CallFunc_CurParam++] = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// native callfunc_push_str(value[]);
|
|
static cell AMX_NATIVE_CALL callfunc_push_str(AMX *amx, cell *params)
|
|
{
|
|
if (!g_CallFunc_Plugin)
|
|
{
|
|
// scripter's fault
|
|
LogError(amx, AMX_ERR_NATIVE, "callfunc_push_xxx called without callfunc_begin");
|
|
return 0;
|
|
}
|
|
|
|
if (g_CallFunc_CurParam == CALLFUNC_MAXPARAMS)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "callfunc_push_xxx: maximal parameters num: %d", CALLFUNC_MAXPARAMS);
|
|
return 0;
|
|
}
|
|
|
|
// search for the address; if it is found, dont create a new copy
|
|
for (int i = 0; i < g_CallFunc_CurParam; ++i)
|
|
{
|
|
if ((g_CallFunc_ParamInfo[i].flags & CALLFUNC_FLAG_BYREF) && (g_CallFunc_ParamInfo[i].byrefAddr == params[1]))
|
|
{
|
|
// the byrefAddr and size params should not be used; set them anyways...
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].flags = CALLFUNC_FLAG_BYREF_REUSED;
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].byrefAddr = params[1];
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].size = 1;
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].alloc = NULL;
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].copyback = g_CallFunc_ParamInfo[i].copyback;
|
|
g_CallFunc_Params[g_CallFunc_CurParam++] = i;
|
|
// we are done
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// not found; create an own copy
|
|
// get the string and its length
|
|
int len;
|
|
char *str = get_amxstring(amx, params[1], 0, len);
|
|
|
|
// allocate enough memory for the string
|
|
cell *phys_addr = new cell[len+1];
|
|
|
|
// copy it to the allocated memory
|
|
// we assume it's unpacked
|
|
// :NOTE: 4th parameter use_wchar since Small Abstract Machine 2.5.0
|
|
amx_SetStringOld(phys_addr, str, 0, 0);
|
|
|
|
// push the address and set the reference flag so that memory is released after function call.
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].flags = CALLFUNC_FLAG_BYREF;
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].byrefAddr = params[1];
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].size = len + 1;
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].alloc = phys_addr;
|
|
|
|
if (params[0] / sizeof(cell) >= 3)
|
|
{
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].copyback = params[3] ? true : false;
|
|
} else {
|
|
g_CallFunc_ParamInfo[g_CallFunc_CurParam].copyback = true;
|
|
}
|
|
|
|
g_CallFunc_Params[g_CallFunc_CurParam++] = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// get_langsnum();
|
|
static cell AMX_NATIVE_CALL get_langsnum(AMX *amx, cell *params)
|
|
{
|
|
return g_langMngr.GetLangsNum();
|
|
}
|
|
|
|
// get_lang(id, name[(at least 3)]);
|
|
static cell AMX_NATIVE_CALL get_lang(AMX *amx, cell *params)
|
|
{
|
|
set_amxstring(amx, params[2], g_langMngr.GetLangName(params[1]), 2);
|
|
return 0;
|
|
}
|
|
|
|
// register_dictionary(const filename[]);
|
|
static cell AMX_NATIVE_CALL register_dictionary(AMX *amx, cell *params)
|
|
{
|
|
int len;
|
|
static char file[PLATFORM_MAX_PATH];
|
|
int result = g_langMngr.MergeDefinitionFile(build_pathname_r(file, sizeof(file), "%s/lang/%s", get_localinfo("amxx_datadir", "addons/amxmodx/data"), get_amxstring(amx, params[1], 1, len)));
|
|
|
|
return result;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL plugin_flags(AMX *amx, cell *params)
|
|
{
|
|
if ((params[0] / sizeof(cell)) == 1 || // compiled with old include file
|
|
params[2] < 0) // specifically want calling plugin's flags
|
|
{
|
|
if (params[1])
|
|
{
|
|
AMX_HEADER *hdr;
|
|
hdr = (AMX_HEADER *)amx->base;
|
|
return hdr->flags;
|
|
}
|
|
|
|
return amx->flags;
|
|
}
|
|
else
|
|
{
|
|
CPluginMngr::CPlugin* a = g_plugins.findPlugin((int)params[2]);
|
|
|
|
if (a == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
if (params[1])
|
|
{
|
|
AMX_HEADER *hdr;
|
|
hdr = (AMX_HEADER *)a->getAMX()->base;
|
|
return hdr->flags;
|
|
}
|
|
|
|
return a->getAMX()->flags;
|
|
}
|
|
}
|
|
|
|
// lang_exists(const name[]);
|
|
static cell AMX_NATIVE_CALL lang_exists(AMX *amx, cell *params)
|
|
{
|
|
int len = 0;
|
|
return g_langMngr.LangExists(get_amxstring(amx, params[1], 1, len)) ? 1 : 0;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL require_module(AMX *amx, cell *params)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL find_plugin_byfile(AMX *amx, cell *params)
|
|
{
|
|
typedef int (*STRCOMPARE)(const char*, const char*);
|
|
|
|
STRCOMPARE func;
|
|
|
|
if (params[2])
|
|
{
|
|
func = strcasecmp;
|
|
} else {
|
|
func = strcmp;
|
|
}
|
|
|
|
int len, i = 0;
|
|
char *file = get_amxstring(amx, params[1], 0, len);
|
|
|
|
for (CPluginMngr::iterator iter = g_plugins.begin(); iter; ++iter)
|
|
{
|
|
if ((func)((*iter).getName(), file) == 0)
|
|
return i;
|
|
i++;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL int3(AMX *amx, cell *params)
|
|
{
|
|
#if defined _DEBUG || defined DEBUG
|
|
#if defined WIN32
|
|
__asm
|
|
{
|
|
int 3;
|
|
};
|
|
#else
|
|
asm("int $3");
|
|
#endif //WIN32
|
|
#endif //DEBUG
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*********************************************************************/
|
|
|
|
static cell AMX_NATIVE_CALL amx_abort(AMX *amx, cell *params)
|
|
{
|
|
int err = params[1];
|
|
|
|
int len;
|
|
char *fmt = format_amxstring(amx, params, 2, len);
|
|
|
|
if (fmt[0] == '\0')
|
|
fmt = NULL;
|
|
|
|
const char *filename = "";
|
|
CPluginMngr::CPlugin *pPlugin = g_plugins.findPluginFast(amx);
|
|
|
|
if (pPlugin)
|
|
filename = pPlugin->getName();
|
|
|
|
//we were in a callfunc?
|
|
if (g_CallFunc_Plugin == pPlugin)
|
|
g_CallFunc_Plugin = NULL;
|
|
|
|
if (fmt)
|
|
LogError(amx, err, "[%s] %s", filename, fmt);
|
|
else
|
|
LogError(amx, err, NULL);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL module_exists(AMX *amx, cell *params)
|
|
{
|
|
int len;
|
|
char *module = get_amxstring(amx, params[1], 0, len);
|
|
|
|
if (!FindLibrary(module, LibType_Library))
|
|
return FindLibrary(module, LibType_Class);
|
|
|
|
return true;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL LibraryExists(AMX *amx, cell *params)
|
|
{
|
|
int len;
|
|
char *library = get_amxstring(amx, params[1], 0, len);
|
|
|
|
return FindLibrary(library, static_cast<LibType>(params[2]));
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL set_fail_state(AMX *amx, cell *params)
|
|
{
|
|
int len;
|
|
char* str;
|
|
|
|
g_langMngr.SetDefLang(LANG_SERVER); // Default language = server
|
|
|
|
if (params[0] / sizeof(cell) > 1)
|
|
str = format_amxstring(amx, params, 1, len);
|
|
else
|
|
str = get_amxstring(amx, params[1], 0, len);
|
|
|
|
CPluginMngr::CPlugin *pPlugin = g_plugins.findPluginFast(amx);
|
|
|
|
pPlugin->setStatus(ps_error);
|
|
pPlugin->setError(str);
|
|
|
|
AMXXLOG_Error("[AMXX] Plugin (\"%s\") is setting itself as failed.", pPlugin->getName());
|
|
AMXXLOG_Error("[AMXX] Plugin says: %s", str);
|
|
|
|
LogError(amx, AMX_ERR_EXIT, NULL);
|
|
|
|
//plugin dies once amx_Exec concludes
|
|
return 0;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_var_addr(AMX *amx, cell *params)
|
|
{
|
|
if (params[0] / sizeof(cell) > 0)
|
|
{
|
|
return params[1];
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL get_addr_val(AMX *amx, cell *params)
|
|
{
|
|
cell *addr;
|
|
int err;
|
|
|
|
if ( (err=amx_GetAddr(amx, params[1], &addr)) != AMX_ERR_NONE )
|
|
{
|
|
LogError(amx, err, "Bad reference %d supplied", params[1]);
|
|
return 0;
|
|
}
|
|
|
|
return addr ? *addr : 0;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL set_addr_val(AMX *amx, cell *params)
|
|
{
|
|
cell *addr;
|
|
int err;
|
|
|
|
if ( (err=amx_GetAddr(amx, params[1], &addr)) != AMX_ERR_NONE )
|
|
{
|
|
LogError(amx, err, "Bad reference %d supplied", params[1]);
|
|
return 0;
|
|
}
|
|
|
|
if (addr)
|
|
*addr = params[2];
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL CreateMultiForward(AMX *amx, cell *params)
|
|
{
|
|
int len;
|
|
char *funcname = get_amxstring(amx, params[1], 0, len);
|
|
|
|
cell ps[FORWARD_MAX_PARAMS];
|
|
cell count = params[0] / sizeof(cell);
|
|
for (cell i=3; i<=count; i++)
|
|
{
|
|
ps[i-3] = *get_amxaddr(amx, params[i]);
|
|
}
|
|
|
|
return registerForwardC(funcname, static_cast<ForwardExecType>(params[2]), ps, count-2);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL CreateOneForward(AMX *amx, cell *params)
|
|
{
|
|
CPluginMngr::CPlugin *p = g_plugins.findPlugin(params[1]);
|
|
|
|
if (!p)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid plugin id: %d", params[1]);
|
|
return -1;
|
|
} else if (!p->isExecutable(0)) {
|
|
return -1;
|
|
}
|
|
|
|
int len;
|
|
char *funcname = get_amxstring(amx, params[2], 0, len);
|
|
|
|
cell ps[FORWARD_MAX_PARAMS];
|
|
cell count = params[0] / sizeof(cell);
|
|
for (cell i=3; i<=count; i++)
|
|
{
|
|
ps[i-3] = *get_amxaddr(amx, params[i]);
|
|
}
|
|
|
|
return registerSPForwardByNameC(p->getAMX(), funcname, ps, count-2);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL PrepareArray(AMX *amx, cell *params)
|
|
{
|
|
cell *addr = get_amxaddr(amx, params[1]);
|
|
unsigned int len = static_cast<unsigned int>(params[2]);
|
|
bool copyback = params[3] ? true : false;
|
|
|
|
return prepareCellArray(addr, len, copyback);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL ExecuteForward(AMX *amx, cell *params)
|
|
{
|
|
int id = static_cast<int>(params[1]);
|
|
int len, err;
|
|
cell *addr = get_amxaddr(amx, params[2]);
|
|
|
|
if (!g_forwards.isIdValid(id))
|
|
return 0;
|
|
|
|
struct allot_info
|
|
{
|
|
cell amx_addr;
|
|
cell *phys_addr;
|
|
};
|
|
|
|
cell ps[FORWARD_MAX_PARAMS];
|
|
allot_info allots[FORWARD_MAX_PARAMS];
|
|
cell count = params[0] / sizeof(cell);
|
|
if (count - 2 != g_forwards.getParamsNum(id))
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Expected %d parameters, got %d", g_forwards.getParamsNum(id), count-2);
|
|
return 0;
|
|
}
|
|
|
|
ForwardParam param_type;
|
|
|
|
for (cell i=3; i<=count; i++)
|
|
{
|
|
param_type = g_forwards.getParamType(id, i-3);
|
|
if (param_type == FP_STRING)
|
|
{
|
|
char *tmp = get_amxstring(amx, params[i], 0, len);
|
|
cell num = len / sizeof(cell) + 1;
|
|
if ((err=amx_Allot(amx, num, &allots[i-3].amx_addr, &allots[i-3].phys_addr)) != AMX_ERR_NONE)
|
|
{
|
|
LogError(amx, err, NULL);
|
|
return 0;
|
|
}
|
|
strcpy((char *)allots[i-3].phys_addr, tmp);
|
|
ps[i-3] = (cell)allots[i-3].phys_addr;
|
|
}
|
|
else if (param_type == FP_CELL_BYREF)
|
|
{
|
|
cell *temp = get_amxaddr(amx, params[i]);
|
|
ps[i-3] = reinterpret_cast<cell>(temp);
|
|
}
|
|
else
|
|
{
|
|
ps[i-3] = *get_amxaddr(amx, params[i]);
|
|
}
|
|
}
|
|
|
|
*addr = g_forwards.executeForwards(id, ps);
|
|
|
|
for (cell i=3; i<=count; i++)
|
|
{
|
|
if (g_forwards.getParamType(id, i-3) == FP_STRING)
|
|
{
|
|
amx_Release(amx, allots[i-3].amx_addr);
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL DestroyForward(AMX *amx, cell *params)
|
|
{
|
|
int id = static_cast<int>(params[1]);
|
|
|
|
/* only implemented for single forwards */
|
|
if (g_forwards.isIdValid(id) && g_forwards.isSPForward(id))
|
|
g_forwards.unregisterSPForward(id);
|
|
|
|
return 1;
|
|
}
|
|
|
|
ke::Vector<cell *> g_hudsync;
|
|
|
|
static cell AMX_NATIVE_CALL CreateHudSyncObj(AMX *amx, cell *params)
|
|
{
|
|
cell *p = new cell[gpGlobals->maxClients+1];
|
|
memset(p, 0, sizeof(cell) * (gpGlobals->maxClients + 1));
|
|
g_hudsync.append(p);
|
|
|
|
return static_cast<cell>(g_hudsync.length());
|
|
}
|
|
|
|
void CheckAndClearPlayerHUD(CPlayer *player, int &channel, unsigned int sync_obj)
|
|
{
|
|
/**
|
|
* player and channel should be guaranteed to be good to go.
|
|
*/
|
|
//get the sync object's hud list
|
|
cell *plist = g_hudsync[sync_obj];
|
|
//get the last channel this message class was displayed on.
|
|
cell last_channel = plist[player->index];
|
|
//check if the last sync on this channel was this sync obj
|
|
if ((unsigned int)player->hudmap[last_channel] == sync_obj + 1)
|
|
{
|
|
//if so, we can safely REUSE it
|
|
channel = (int)last_channel;
|
|
}
|
|
|
|
//set the new states
|
|
plist[player->index] = channel;
|
|
player->hudmap[channel] = sync_obj + 1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL ClearSyncHud(AMX *amx, cell *params)
|
|
{
|
|
int len = 0;
|
|
int index = params[1];
|
|
unsigned int sync_obj = static_cast<unsigned int>(params[2]) - 1;
|
|
|
|
if (sync_obj >= g_hudsync.length())
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "HudSyncObject %d is invalid", sync_obj);
|
|
return 0;
|
|
}
|
|
|
|
g_langMngr.SetDefLang(params[1]);
|
|
|
|
if (index == 0)
|
|
{
|
|
for (int i = 1; i <= gpGlobals->maxClients; ++i)
|
|
{
|
|
CPlayer *pPlayer = GET_PLAYER_POINTER_I(i);
|
|
|
|
int channel;
|
|
if (pPlayer->ingame)
|
|
{
|
|
g_langMngr.SetDefLang(i);
|
|
channel = pPlayer->NextHUDChannel();
|
|
CheckAndClearPlayerHUD(pPlayer, channel, sync_obj);
|
|
pPlayer->channels[channel] = gpGlobals->time;
|
|
g_hudset.channel = channel;
|
|
UTIL_HudMessage(pPlayer->pEdict, g_hudset, "");
|
|
}
|
|
}
|
|
} else {
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid player id %d", index);
|
|
return 0;
|
|
}
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
if (pPlayer->ingame)
|
|
{
|
|
int channel = pPlayer->NextHUDChannel();
|
|
CheckAndClearPlayerHUD(pPlayer, channel, sync_obj);
|
|
pPlayer->channels[channel] = gpGlobals->time;
|
|
g_hudset.channel = channel;
|
|
UTIL_HudMessage(pPlayer->pEdict, g_hudset, "");
|
|
}
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
//params[1] - target
|
|
//params[2] - HudSyncObj
|
|
//params[3] - hud message
|
|
static cell AMX_NATIVE_CALL ShowSyncHudMsg(AMX *amx, cell *params)
|
|
{
|
|
int len = 0;
|
|
char* message = NULL;
|
|
int index = params[1];
|
|
unsigned int sync_obj = static_cast<unsigned int>(params[2]) - 1;
|
|
|
|
if (sync_obj >= g_hudsync.length())
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "HudSyncObject %d is invalid", sync_obj);
|
|
return 0;
|
|
}
|
|
|
|
g_langMngr.SetDefLang(params[1]);
|
|
|
|
if (index == 0)
|
|
{
|
|
for (int i = 1; i <= gpGlobals->maxClients; ++i)
|
|
{
|
|
CPlayer *pPlayer = GET_PLAYER_POINTER_I(i);
|
|
|
|
int channel;
|
|
if (pPlayer->ingame)
|
|
{
|
|
g_langMngr.SetDefLang(i);
|
|
channel = pPlayer->NextHUDChannel();
|
|
CheckAndClearPlayerHUD(pPlayer, channel, sync_obj);
|
|
pPlayer->channels[channel] = gpGlobals->time;
|
|
g_hudset.channel = channel;
|
|
message = UTIL_SplitHudMessage(format_amxstring(amx, params, 3, len));
|
|
UTIL_HudMessage(pPlayer->pEdict, g_hudset, message);
|
|
}
|
|
}
|
|
} else {
|
|
if (index < 1 || index > gpGlobals->maxClients)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Invalid player id %d", index);
|
|
return 0;
|
|
}
|
|
|
|
CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
|
|
|
|
if (pPlayer->ingame)
|
|
{
|
|
int channel = pPlayer->NextHUDChannel();
|
|
CheckAndClearPlayerHUD(pPlayer, channel, sync_obj);
|
|
pPlayer->channels[channel] = gpGlobals->time;
|
|
g_hudset.channel = channel;
|
|
message = UTIL_SplitHudMessage(format_amxstring(amx, params, 3, len));
|
|
UTIL_HudMessage(pPlayer->pEdict, g_hudset, message);
|
|
}
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL arrayset(AMX *amx, cell *params)
|
|
{
|
|
cell value = params[2];
|
|
|
|
if (!value)
|
|
{
|
|
memset(get_amxaddr(amx, params[1]), 0, params[3] * sizeof(cell));
|
|
} else {
|
|
int size = params[3];
|
|
cell *addr = get_amxaddr(amx, params[1]);
|
|
for (int i=0; i<size; i++)
|
|
{
|
|
addr[i] = value;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL CreateLangKey(AMX *amx, cell *params)
|
|
{
|
|
int len;
|
|
const char *key = get_amxstring(amx, params[1], 0, len);
|
|
int key_index = g_langMngr.GetKeyEntry(key);
|
|
|
|
if (key_index != -1)
|
|
{
|
|
return key_index;
|
|
}
|
|
|
|
return g_langMngr.AddKeyEntry(key);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL AddTranslation(AMX *amx, cell *params)
|
|
{
|
|
int len;
|
|
const char *lang = get_amxstring(amx, params[1], 0, len);
|
|
int key_index = params[2];
|
|
const char *phrase = get_amxstring(amx, params[3], 1, len);
|
|
|
|
ke::Vector<sKeyDef> queue;
|
|
sKeyDef def;
|
|
|
|
def.definition = new ke::AutoString(phrase);
|
|
def.key = key_index;
|
|
|
|
queue.append(def);
|
|
|
|
g_langMngr.MergeDefinitions(lang, queue);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL GetLangTransKey(AMX *amx, cell *params)
|
|
{
|
|
int len;
|
|
const char *key = get_amxstring(amx, params[1], 0, len);
|
|
|
|
return g_langMngr.GetKeyEntry(key);
|
|
}
|
|
|
|
static cell AMX_NATIVE_CALL admins_push(AMX *amx, cell *params)
|
|
{
|
|
// admins_push("SteamID","password",access,flags);
|
|
CAdminData *TempData=new CAdminData;
|
|
|
|
TempData->SetAuthID(get_amxaddr(amx,params[1]));
|
|
TempData->SetPass(get_amxaddr(amx,params[2]));
|
|
TempData->SetAccess(params[3]);
|
|
TempData->SetFlags(params[4]);
|
|
|
|
DynamicAdmins.append(TempData);
|
|
|
|
return 0;
|
|
};
|
|
static cell AMX_NATIVE_CALL admins_flush(AMX *amx, cell *params)
|
|
{
|
|
// admins_flush();
|
|
|
|
size_t iter=DynamicAdmins.length();
|
|
|
|
while (iter--)
|
|
{
|
|
delete DynamicAdmins[iter];
|
|
}
|
|
|
|
DynamicAdmins.clear();
|
|
|
|
return 0;
|
|
|
|
};
|
|
static cell AMX_NATIVE_CALL admins_num(AMX *amx, cell *params)
|
|
{
|
|
// admins_num();
|
|
|
|
return static_cast<cell>(DynamicAdmins.length());
|
|
};
|
|
static cell AMX_NATIVE_CALL admins_lookup(AMX *amx, cell *params)
|
|
{
|
|
// admins_lookup(Num, Property, Buffer[]={0}, BufferSize=-1);
|
|
|
|
if (params[1]>=static_cast<int>(DynamicAdmins.length()))
|
|
{
|
|
LogError(amx,AMX_ERR_NATIVE,"Invalid admins num");
|
|
return 1;
|
|
};
|
|
|
|
int BufferSize;
|
|
cell *Buffer;
|
|
const cell *Input;
|
|
|
|
switch(params[2])
|
|
{
|
|
case Admin_Auth:
|
|
BufferSize=params[4];
|
|
Buffer=get_amxaddr(amx, params[3]);
|
|
Input=DynamicAdmins[params[1]]->GetAuthID();
|
|
|
|
while (BufferSize-->0)
|
|
{
|
|
if ((*Buffer++=*Input++)==0)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
// hit max buffer size, terminate string
|
|
*Buffer=0;
|
|
return 0;
|
|
break;
|
|
case Admin_Password:
|
|
BufferSize=params[4];
|
|
Buffer=get_amxaddr(amx, params[3]);
|
|
Input=DynamicAdmins[params[1]]->GetPass();
|
|
|
|
while (BufferSize-->0)
|
|
{
|
|
if ((*Buffer++=*Input++)==0)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
// hit max buffer size, terminate string
|
|
*Buffer=0;
|
|
return 0;
|
|
break;
|
|
case Admin_Access:
|
|
return DynamicAdmins[params[1]]->GetAccess();
|
|
break;
|
|
case Admin_Flags:
|
|
return DynamicAdmins[params[1]]->GetFlags();
|
|
break;
|
|
};
|
|
|
|
// unknown property
|
|
return 0;
|
|
};
|
|
// LookupLangKey(Output[], OutputSize, const Key[], const &id)
|
|
static cell AMX_NATIVE_CALL LookupLangKey(AMX *amx, cell *params)
|
|
{
|
|
int len;
|
|
char *key=get_amxstring(amx,params[3],0,len);
|
|
const char *def=translate(amx, playerlang(*get_amxaddr(amx, params[4])),key);
|
|
|
|
if (def==NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
set_amxstring(amx,params[1],def,params[2]);
|
|
return 1;
|
|
};
|
|
|
|
// SetGlobalTransTarget(client)
|
|
static cell AMX_NATIVE_CALL SetGlobalTransTarget(AMX *amx, cell *params)
|
|
{
|
|
g_langMngr.SetDefLang(params[1]);
|
|
|
|
return 1;
|
|
};
|
|
|
|
// has_map_ent_class(const classname[])
|
|
static cell AMX_NATIVE_CALL has_map_ent_class(AMX *amx, cell *params)
|
|
{
|
|
int len;
|
|
char *name = get_amxstring(amx, params[1], 0, len);
|
|
|
|
return len && !FNullEnt(FIND_ENTITY_BY_STRING(NULL, "classname", name));
|
|
};
|
|
|
|
static cell AMX_NATIVE_CALL AutoExecConfig(AMX *amx, cell *params)
|
|
{
|
|
int length;
|
|
bool autocreate = params[1] != 0;
|
|
const char *name = get_amxstring(amx, params[2], 0, length);
|
|
const char *folder = get_amxstring(amx, params[3], 1, length);
|
|
|
|
auto plugin = g_plugins.findPluginFast(amx);
|
|
|
|
if (*name == '\0')
|
|
{
|
|
char pluginName[PLATFORM_MAX_PATH];
|
|
strncopy(pluginName, plugin->getName(), sizeof(pluginName));
|
|
|
|
char *ptr;
|
|
|
|
if ((ptr = strstr(pluginName, ".amxx")))
|
|
{
|
|
*ptr = '\0';
|
|
}
|
|
|
|
static char newName[PLATFORM_MAX_PATH];
|
|
ke::SafeSprintf(newName, sizeof(newName), "plugin-%s", pluginName);
|
|
|
|
name = newName;
|
|
}
|
|
|
|
plugin->AddConfig(autocreate, name, folder);
|
|
|
|
return 1;
|
|
}
|
|
|
|
//native RequestFrame(const callback[], any:data);
|
|
static cell AMX_NATIVE_CALL RequestFrame(AMX *amx, cell *params)
|
|
{
|
|
int len;
|
|
const char *funcName = get_amxstring(amx, params[1], 0, len);
|
|
|
|
int func = registerSPForwardByName(amx, funcName, FP_CELL, FP_DONE);
|
|
if (func < 0)
|
|
{
|
|
LogError(amx, AMX_ERR_NATIVE, "Function \"%s\" was not found", funcName);
|
|
return 0;
|
|
}
|
|
|
|
g_frameActionMngr.AddFrameAction(func, params[2]);
|
|
|
|
return 1;
|
|
}
|
|
|
|
AMX_NATIVE_INFO amxmodx_Natives[] =
|
|
{
|
|
{"abort", amx_abort},
|
|
{"admins_flush", admins_flush},
|
|
{"admins_lookup", admins_lookup},
|
|
{"admins_num", admins_num},
|
|
{"admins_push", admins_push},
|
|
{"amxclient_cmd", amxclient_cmd},
|
|
{"arrayset", arrayset},
|
|
{"get_addr_val", get_addr_val},
|
|
{"get_var_addr", get_var_addr},
|
|
{"set_addr_val", set_addr_val},
|
|
{"callfunc_begin", callfunc_begin},
|
|
{"callfunc_begin_i", callfunc_begin_i},
|
|
{"callfunc_end", callfunc_end},
|
|
{"callfunc_push_int", callfunc_push_byval},
|
|
{"callfunc_push_float", callfunc_push_byval},
|
|
{"callfunc_push_intrf", callfunc_push_byref},
|
|
{"callfunc_push_floatrf", callfunc_push_byref},
|
|
{"callfunc_push_str", callfunc_push_str},
|
|
{"callfunc_push_array", callfunc_push_array},
|
|
{"change_task", change_task},
|
|
{"engine_changelevel", engine_changelevel},
|
|
{"client_cmd", client_cmd},
|
|
{"client_print", client_print},
|
|
{"client_print_color", client_print_color},
|
|
{"console_cmd", console_cmd},
|
|
{"console_print", console_print},
|
|
{"emit_sound", emit_sound},
|
|
{"engclient_cmd", engclient_cmd},
|
|
{"engclient_print", engclient_print},
|
|
{"find_player", find_player},
|
|
{"find_player_ex", find_player_ex},
|
|
{"find_plugin_byfile", find_plugin_byfile},
|
|
{"force_unmodified", force_unmodified},
|
|
{"format_time", format_time},
|
|
{"get_clcmd", get_clcmd},
|
|
{"get_clcmdsnum", get_clcmdsnum},
|
|
{"get_concmd", get_concmd},
|
|
{"get_concmdsnum", get_concmdsnum},
|
|
{"get_concmd_plid", get_concmd_plid},
|
|
{"get_flags", get_flags},
|
|
{"get_func_id", get_func_id},
|
|
{"get_gametime", get_gametime},
|
|
{"get_lang", get_lang},
|
|
{"get_langsnum", get_langsnum},
|
|
{"get_localinfo", get_localinfo},
|
|
{"get_mapname", get_mapname},
|
|
{"get_maxplayers", get_maxplayers},
|
|
{"get_modname", get_modname},
|
|
{"get_module", get_module},
|
|
{"get_modulesnum", get_modulesnum},
|
|
{"get_players", get_players},
|
|
{"get_playersnum", get_playersnum},
|
|
{"get_plugin", get_plugin},
|
|
{"get_pluginsnum", get_pluginsnum},
|
|
{"get_srvcmd", get_srvcmd},
|
|
{"get_srvcmdsnum", get_srvcmdsnum},
|
|
{"get_systime", get_systime},
|
|
{"get_time", get_time},
|
|
{"get_timeleft", get_timeleft},
|
|
{"get_amxx_verstring", get_amxx_verstring},
|
|
{"get_user_aiming", get_user_aiming},
|
|
{"get_user_ammo", get_user_ammo},
|
|
{"get_user_armor", get_user_armor},
|
|
{"get_user_attacker", get_user_attacker},
|
|
{"get_user_authid", get_user_authid},
|
|
{"get_user_flags", get_user_flags},
|
|
{"get_user_frags", get_user_frags},
|
|
{"get_user_deaths", get_user_deaths},
|
|
{"get_user_health", get_user_health},
|
|
{"get_user_index", get_user_index},
|
|
{"get_user_info", get_user_info},
|
|
{"get_user_ip", get_user_ip},
|
|
{"get_user_menu", get_user_menu},
|
|
{"get_user_msgid", get_user_msgid},
|
|
{"get_user_msgname", get_user_msgname},
|
|
{"get_user_name", get_user_name},
|
|
{"get_user_origin", get_user_origin},
|
|
{"get_user_ping", get_user_ping},
|
|
{"get_user_team", get_user_team},
|
|
{"get_user_time", get_user_time},
|
|
{"get_user_userid", get_user_userid},
|
|
{"get_user_weapon", get_user_weapon},
|
|
{"get_user_weapons", get_user_weapons},
|
|
{"get_weaponid", get_weaponid},
|
|
{"get_weaponname", get_weaponname},
|
|
{"get_xvar_float", get_xvar_num},
|
|
{"get_xvar_id", get_xvar_id},
|
|
{"get_xvar_num", get_xvar_num},
|
|
{"has_map_ent_class", has_map_ent_class},
|
|
{"int3", int3},
|
|
{"is_amd64_server", is_amd64_server},
|
|
{"is_dedicated_server", is_dedicated_server},
|
|
{"is_jit_enabled", is_jit_enabled},
|
|
{"is_linux_server", is_linux_server},
|
|
{"is_map_valid", is_map_valid},
|
|
{"is_module_loaded", is_module_loaded},
|
|
{"is_plugin_loaded", is_plugin_loaded},
|
|
{"is_user_alive", is_user_alive},
|
|
{"is_user_authorized", is_user_authorized},
|
|
{"is_user_bot", is_user_bot},
|
|
{"is_user_connected", is_user_connected},
|
|
{"is_user_connecting", is_user_connecting},
|
|
{"is_user_hltv", is_user_hltv},
|
|
{"lang_exists", lang_exists},
|
|
{"log_amx", log_amx},
|
|
{"log_message", log_message},
|
|
{"elog_message", elog_message},
|
|
{"log_to_file", log_to_file},
|
|
{"md5", amx_md5},
|
|
{"md5_file", amx_md5_file},
|
|
{"hash_string", amx_hash_string},
|
|
{"hash_file", amx_hash_file},
|
|
{"module_exists", module_exists},
|
|
{"next_hudchannel", next_hudchannel},
|
|
{"num_to_word", num_to_word},
|
|
{"parse_loguser", parse_loguser},
|
|
{"parse_time", parse_time},
|
|
{"pause", pause},
|
|
{"plugin_flags", plugin_flags},
|
|
{"precache_model", precache_model},
|
|
{"precache_sound", precache_sound},
|
|
{"precache_generic", precache_generic},
|
|
{"precache_event", precache_event},
|
|
{"random_float", random_float},
|
|
{"random_num", random_num},
|
|
{"read_argc", read_argc},
|
|
{"read_args", read_args},
|
|
{"read_argv", read_argv},
|
|
{"read_argv_int", read_argv_int},
|
|
{"read_argv_float", read_argv_float},
|
|
{"read_data", read_data},
|
|
{"read_datanum", read_datanum},
|
|
{"read_datatype", read_datatype},
|
|
{"read_flags", read_flags},
|
|
{"read_logargc", read_logargc},
|
|
{"read_logargv", read_logargv},
|
|
{"read_logdata", read_logdata},
|
|
{"register_clcmd", register_clcmd},
|
|
{"register_concmd", register_concmd},
|
|
{"register_dictionary", register_dictionary},
|
|
{"register_event", register_event},
|
|
{"register_event_ex", register_event_ex},
|
|
{"enable_event", enable_event},
|
|
{"disable_event", disable_event},
|
|
{"register_logevent", register_logevent},
|
|
{"enable_logevent", enable_logevent},
|
|
{"disable_logevent", disable_logevent},
|
|
{"register_menucmd", register_menucmd},
|
|
{"register_menuid", register_menuid},
|
|
{"register_plugin", register_plugin},
|
|
{"register_srvcmd", register_srvcmd},
|
|
{"require_module", require_module},
|
|
{"remove_quotes", remove_quotes},
|
|
{"remove_task", remove_task},
|
|
{"remove_user_flags", remove_user_flags},
|
|
{"server_cmd", server_cmd},
|
|
{"server_exec", server_exec},
|
|
{"server_print", server_print},
|
|
{"set_fail_state", set_fail_state},
|
|
{"set_dhudmessage", set_dhudmessage},
|
|
{"set_hudmessage", set_hudmessage},
|
|
{"set_localinfo", set_localinfo},
|
|
{"set_task", set_task},
|
|
{"set_user_flags", set_user_flags},
|
|
{"set_user_info", set_user_info},
|
|
{"set_xvar_float", set_xvar_num},
|
|
{"set_xvar_num", set_xvar_num},
|
|
{"show_dhudmessage", show_dhudmessage},
|
|
{"show_hudmessage", show_hudmessage},
|
|
{"show_menu", show_menu},
|
|
{"show_motd", show_motd},
|
|
{"task_exists", task_exists},
|
|
{"unpause", unpause},
|
|
{"user_has_weapon", user_has_weapon},
|
|
{"user_kill", user_kill},
|
|
{"user_slap", user_slap},
|
|
{"xvar_exists", xvar_exists},
|
|
{"AddTranslation", AddTranslation},
|
|
{"ClearSyncHud", ClearSyncHud},
|
|
{"CreateHudSyncObj", CreateHudSyncObj},
|
|
{"CreateLangKey", CreateLangKey},
|
|
{"CreateMultiForward", CreateMultiForward},
|
|
{"CreateOneForward", CreateOneForward},
|
|
{"DestroyForward", DestroyForward},
|
|
{"ExecuteForward", ExecuteForward},
|
|
{"GetLangTransKey", GetLangTransKey},
|
|
{"LibraryExists", LibraryExists},
|
|
{"LookupLangKey", LookupLangKey},
|
|
{"SetGlobalTransTarget", SetGlobalTransTarget},
|
|
{"PrepareArray", PrepareArray},
|
|
{"ShowSyncHudMsg", ShowSyncHudMsg},
|
|
{"AutoExecConfig", AutoExecConfig},
|
|
{"RequestFrame", RequestFrame},
|
|
{NULL, NULL}
|
|
};
|