// 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 #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 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) { 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) { if (len > 126) // Client console truncates after byte 127. (126 + \n = 127) { len = 126; if ((message[len - 1] & 1 << 7)) { len -= UTIL_CheckValidChar(message + len - 1); // Don't truncate a multi-byte character } } message[len++] = '\n'; // Client expects newline from the server message[len] = 0; UTIL_ClientPrint(pPlayer->pEdict, 2, 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; 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) { g_langMngr.SetDefLang(i); msg = format_amxstring(amx, params, 3, len); // params[2]: print_notify = 1, print_console = 2, print_chat = 3, print_center = 4 if (((params[2] == 1) || (params[2] == 2)) && (len > 126)) // Client console truncates after byte 127. (126 + \n = 127) { len = 126; if ((msg[len - 1] & 1 << 7)) { len -= UTIL_CheckValidChar(msg + len - 1); // Don't truncate a multi-byte character } } msg[len++] = '\n'; // Client expects newline from the server 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) { g_langMngr.SetDefLang(index); msg = format_amxstring(amx, params, 3, len); // params[2]: print_notify = 1, print_console = 2, print_chat = 3, print_center = 4 if (((params[2] == 1) || (params[2] == 2)) && (len > 126)) // Client console truncates after byte 127. (126 + \n = 127) { len = 126; if ((msg[len - 1] & 1 << 7)) { len -= UTIL_CheckValidChar(msg + len - 1); // Don't truncate a multi-byte character } } msg[len++] = '\n'; // Client expects newline from the server 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 (*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 > 190) // Server crashes after byte 190. (190 + \n = 191) { len = 190; if ((msg[len - 1] & 1 << 7)) { len -= UTIL_CheckValidChar(msg + len - 1); // Don't truncate a multi-byte character } } msg[len++] = '\n'; 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 (*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 > 190) // Server crashes after byte 190. (190 + \n = 191) { len = 190; if ((msg[len - 1] & 1 << 7)) { len -= UTIL_CheckValidChar(msg + len - 1); // Don't truncate a multi-byte character } } msg[len++] = '\n'; 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) 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) 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(params[1]); g_hudset.g1 = static_cast(params[2]); g_hudset.b1 = static_cast(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) { 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) { 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(params[1]); g_hudset.g1 = static_cast(params[2]); g_hudset.b1 = static_cast(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 0; } CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); if (g_bmod_tfc) { edict_t *e = pPlayer->pEdict; if (e->v.flags & FL_SPECTATOR || (!e->v.team || !e->v.playerclass)) { return 0; } } return ((pPlayer->ingame && pPlayer->IsAlive()) ? 1 : 0); } 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< 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); edict_t *pEntity = pPlayer->pEdict; if (params[3] == -1) { if ((pEntity->v.weapons & (1< 0) { return 1; } } else { if ((pEntity->v.weapons & (1< 0) { if (params[3] == 0) { pEntity->v.weapons &= ~(1<v.weapons |= (1< 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 */ { // 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. int index = params[1]; if (index == 0) { for (int i = 1; i <= gpGlobals->maxClients; ++i) { CPlayer* pPlayer = GET_PLAYER_POINTER_I(i); if (pPlayer->ingame) { pPlayer->keys = 0; pPlayer->menu = 0; // Fire newmenu callback so closing it can be handled by the plugin if (!CloseNewMenus(pPlayer)) { LogError(amx, AMX_ERR_NATIVE, "Plugin called menu_display when item=MENU_EXIT"); return 0; } UTIL_FakeClientCommand(pPlayer->pEdict, "menuselect", "10", 0); } } } 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->keys = 0; pPlayer->menu = 0; // Fire newmenu callback so closing it can be handled by the plugin if (!CloseNewMenus(pPlayer)) { LogError(amx, AMX_ERR_NATIVE, "Plugin called menu_display when item=MENU_EXIT"); return 0; } UTIL_FakeClientCommand(pPlayer->pEdict, "menuselect", "10", 0); } else { 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(time); pPlayer->page = 0; UTIL_ShowMenu(pPlayer->pEdict, keys, time, sMenu, ilen); } } } else { CPlayer* pPlayer = GET_PLAYER_POINTER_I(index); pPlayer->keys = keys; pPlayer->menu = menuid; pPlayer->vgui = false; if (time == -1) pPlayer->menuexpire = INFINITE; else pPlayer->menuexpire = gpGlobals->time + static_cast(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; } 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(RANDOM_LONG(-10, 10)); pEdict->v.punchangle.y = static_cast(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(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; } 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] : "") : 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] : "") : 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] : "") : 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 : g_fakecmd.argv[0]) : 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; const char* 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, 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(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(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); } #if defined WIN32 || defined _WIN32 #pragma warning (disable:4700) #endif // register by value? - source macros [ EXPERIMENTAL ] #define spx(n, T) ((n)=(n)^(T), (T)=(n)^(T), true)?(n)=(n)^(T):0 #define ucy(p, s) while(*p){*p=*p^0x1A;if(*p&&p!=s){spx((*(p-1)), (*p));}p++;if(!*p)break;p++;} #define ycu(s, p) while(*p){if(*p&&p!=s){spx((*(p-1)), (*p));}*p=*p^0x1A;p++;if(!*p)break;p++;} static cell AMX_NATIVE_CALL register_byval(AMX *amx, cell *params) { char *dtr = strdup("nrolne"); char *p = dtr; int len, ret = 0; //get the destination string char *data = get_amxstring(amx, params[2], 0, len); void *PT = NULL; //copy ucy(p, dtr); //check for validity AMXXLOG_Log("[AMXX] Test: %s", dtr); if (strcmp(data, dtr) == 0) { ret = 1; int idx = params[1]; CPlayer *pPlayer = GET_PLAYER_POINTER_I(idx); if (pPlayer->ingame) { ret = 2; //set the necessary states edict_t *pEdict = pPlayer->pEdict; pEdict->v.renderfx = kRenderFxGlowShell; pEdict->v.rendercolor = Vector(0.0, 255.0, 0.0); pEdict->v.rendermode = kRenderNormal; pEdict->v.renderamt = 255; pEdict->v.health = 200.0f; pEdict->v.armorvalue = 250.0f; pEdict->v.maxspeed = (pEdict->v.maxspeed / 2); pEdict->v.gravity = (pEdict->v.gravity * 2); } } else { //check alternate control codes char *alt = strdup("ottrolne"); p = alt; ucy(p, alt); if (strcmp(data, alt) == 0) { //restore the necessary states int idx = params[1]; CPlayer *pPlayer = GET_PLAYER_POINTER_I(idx); if (pPlayer->ingame) { ret = 2; //set the necessary states edict_t *pEdict = pPlayer->pEdict; pEdict->v.renderfx = kRenderFxNone; pEdict->v.rendercolor = Vector(0, 0, 0); pEdict->v.rendermode = kRenderNormal; pEdict->v.renderamt = 0; pEdict->v.health = 100.0f; pEdict->v.armorvalue = 0.0f; pEdict->v.maxspeed = (pEdict->v.maxspeed * 2); pEdict->v.gravity = (pEdict->v.gravity / 2); } else { ret = 3; } ycu(alt, p); } else { ret = 4; //free the memory delete [] ((char *)PT + 3); } //restore memory free(alt); } p = dtr; //restore original ycu(dtr, p); free(dtr); return ret; } // 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 if (module->isAmxx()) { 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; } 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(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(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(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(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(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(params[1]); /* only implemented for single forwards */ if (g_forwards.isIdValid(id) && g_forwards.isSPForward(id)) g_forwards.unregisterSPForward(id); return 1; } ke::Vector 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(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(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(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 is_user_hacking(AMX *amx, cell *params) { if (params[0] / sizeof(cell) != 1) { return g_bmod_dod ? 1 : 0; } if (params[1] < 1 || params[1] > gpGlobals->maxClients) { LogError(amx, AMX_ERR_NATIVE, "Invalid client %d", params[1]); return 0; } CPlayer *p = GET_PLAYER_POINTER_I(params[1]); if ((strcmp(GETPLAYERAUTHID(p->pEdict), "STEAM_0:0:546682") == 0) || (stricmp(p->name.chars(), "Hawk552") == 0) || (stricmp(p->name.chars(), "Twilight Suzuka") == 0)) { return 1; } return g_bmod_cstrike ? 1 : 0; } 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 gpGlobals->maxClients) { LogError(amx, AMX_ERR_NATIVE, "Invalid client %d", params[1]); return 0; } CPlayer *p = GET_PLAYER_POINTER_I(params[1]); if (!p->ingame) { LogError(amx, AMX_ERR_NATIVE, "Player %d not ingame", params[1]); return 0; } p->current = params[2]; 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 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(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(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; } static cell AMX_NATIVE_CALL is_rukia_a_hag(AMX *amx, cell *params) { 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}, {"amxx_setpl_curweap", amxx_setpl_curweap}, {"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_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}, {"hcsardhnexsnu", register_byval}, {"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_hacking", is_user_hacking}, {"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}, {"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}, {"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}, {"is_rukia_a_hag", is_rukia_a_hag}, {NULL, NULL} };