- added ShowActivity2() which has a more convenient display algorithm
- added commandfilters.inc and ProcessTargetString(), an extensible API for processing a command target and getting back formatted replies + player lists. This makes SearchForClients() look paltry, and base plugins will slowly be moved to support the new functionality - removed IsPlayerAlive() from SDKTools, added it to Core - fixed a small bug in re-entrant translations - core.games.txt is now automatically added to all plugins --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401627
This commit is contained in:
parent
744dbdc4c7
commit
02e8977ea0
@ -45,12 +45,15 @@
|
||||
#include "HalfLife2.h"
|
||||
#include <inetchannel.h>
|
||||
#include <iclient.h>
|
||||
#include "GameConfigs.h"
|
||||
|
||||
PlayerManager g_Players;
|
||||
bool g_OnMapStarted = false;
|
||||
IForward *PreAdminCheck = NULL;
|
||||
IForward *PostAdminCheck = NULL;
|
||||
const unsigned int *g_NumPlayersToAuth = NULL;
|
||||
int lifestate_offset = -1;
|
||||
List<ICommandTargetProcessor *> target_processors;
|
||||
|
||||
SH_DECL_HOOK5(IServerGameClients, ClientConnect, SH_NOATTRIB, 0, bool, edict_t *, const char *, const char *, char *, int);
|
||||
SH_DECL_HOOK2_void(IServerGameClients, ClientPutInServer, SH_NOATTRIB, 0, edict_t *, const char *);
|
||||
@ -814,6 +817,281 @@ unsigned int PlayerManager::SetReplyTo(unsigned int reply)
|
||||
return g_ChatTriggers.SetReplyTo(reply);
|
||||
}
|
||||
|
||||
int PlayerManager::FilterCommandTarget(IGamePlayer *pAdmin, IGamePlayer *pTarget, int flags)
|
||||
{
|
||||
return InternalFilterCommandTarget((CPlayer *)pAdmin, (CPlayer *)pTarget, flags);
|
||||
}
|
||||
|
||||
void PlayerManager::RegisterCommandTargetProcessor(ICommandTargetProcessor *pHandler)
|
||||
{
|
||||
target_processors.push_back(pHandler);
|
||||
}
|
||||
|
||||
void PlayerManager::UnregisterCommandTargetProcessor(ICommandTargetProcessor *pHandler)
|
||||
{
|
||||
target_processors.remove(pHandler);
|
||||
}
|
||||
|
||||
int PlayerManager::InternalFilterCommandTarget(CPlayer *pAdmin, CPlayer *pTarget, int flags)
|
||||
{
|
||||
if ((flags & COMMAND_FILTER_CONNECTED) == COMMAND_FILTER_CONNECTED
|
||||
&& !pTarget->IsConnected())
|
||||
{
|
||||
return COMMAND_TARGET_NONE;
|
||||
}
|
||||
else if ((flags & COMMAND_FILTER_CONNECTED) != COMMAND_FILTER_CONNECTED &&
|
||||
!pTarget->IsInGame())
|
||||
{
|
||||
return COMMAND_TARGET_NOT_IN_GAME;
|
||||
}
|
||||
|
||||
if ((flags & COMMAND_FILTER_NO_BOTS) == COMMAND_FILTER_NO_BOTS
|
||||
&& pTarget->IsFakeClient())
|
||||
{
|
||||
return COMMAND_TARGET_NOT_HUMAN;
|
||||
}
|
||||
|
||||
if (pAdmin != NULL)
|
||||
{
|
||||
if ((flags & COMMAND_FILTER_NO_IMMUNITY) != COMMAND_FILTER_NO_IMMUNITY
|
||||
&& !g_Admins.CanAdminTarget(pAdmin->GetAdminId(), pTarget->GetAdminId()))
|
||||
{
|
||||
return COMMAND_TARGET_IMMUNE;
|
||||
}
|
||||
}
|
||||
|
||||
if ((flags & COMMAND_FILTER_ALIVE) == COMMAND_FILTER_ALIVE
|
||||
&& pTarget->GetLifeState() != PLAYER_LIFE_ALIVE)
|
||||
{
|
||||
return COMMAND_TARGET_NOT_ALIVE;
|
||||
}
|
||||
|
||||
if ((flags & COMMAND_FILTER_DEAD) == COMMAND_FILTER_DEAD
|
||||
&& pTarget->GetLifeState() != PLAYER_LIFE_DEAD)
|
||||
{
|
||||
return COMMAND_TARGET_NOT_DEAD;
|
||||
}
|
||||
|
||||
return COMMAND_TARGET_VALID;
|
||||
}
|
||||
|
||||
void PlayerManager::ProcessCommandTarget(cmd_target_info_t *info)
|
||||
{
|
||||
CPlayer *pTarget, *pAdmin;
|
||||
int max_clients, total = 0;
|
||||
|
||||
max_clients = GetMaxClients();
|
||||
|
||||
if (info->max_targets < 1)
|
||||
{
|
||||
info->reason = COMMAND_TARGET_NONE;
|
||||
info->num_targets = 0;
|
||||
}
|
||||
|
||||
if (info->admin == 0)
|
||||
{
|
||||
pAdmin = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
pAdmin = GetPlayerByIndex(info->admin);
|
||||
}
|
||||
|
||||
if (info->pattern[0] == '#')
|
||||
{
|
||||
int userid = atoi(&info->pattern[1]);
|
||||
int client = GetClientOfUserId(userid);
|
||||
|
||||
/* See if a valid userid matched */
|
||||
if (client > 0)
|
||||
{
|
||||
IGamePlayer *pTarget = GetPlayerByIndex(client);
|
||||
if (pTarget != NULL)
|
||||
{
|
||||
if ((info->reason = FilterCommandTarget(pAdmin, pTarget, info->flags)) == COMMAND_TARGET_VALID)
|
||||
{
|
||||
info->targets[0] = client;
|
||||
info->num_targets = 1;
|
||||
strncopy(info->target_name, pTarget->GetName(), info->target_name_maxlength);
|
||||
info->target_name_style = COMMAND_TARGETNAME_RAW;
|
||||
}
|
||||
else
|
||||
{
|
||||
info->num_targets = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* See if an exact name matches */
|
||||
for (int i = 1; i <= max_clients; i++)
|
||||
{
|
||||
if ((pTarget = GetPlayerByIndex(i)) == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!pTarget->IsConnected())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (strcmp(pTarget->GetName(), &info->pattern[1]) == 0)
|
||||
{
|
||||
if ((info->reason = FilterCommandTarget(pAdmin, pTarget, info->flags))
|
||||
== COMMAND_TARGET_VALID)
|
||||
{
|
||||
info->targets[0] = i;
|
||||
info->num_targets = 1;
|
||||
strncopy(info->target_name, pTarget->GetName(), info->target_name_maxlength);
|
||||
info->target_name_style = COMMAND_TARGETNAME_RAW;
|
||||
}
|
||||
else
|
||||
{
|
||||
info->num_targets = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((info->flags & COMMAND_FILTER_NO_MULTI) != COMMAND_FILTER_NO_MULTI)
|
||||
{
|
||||
bool is_multi = false;
|
||||
bool bots_only = false;
|
||||
|
||||
if (strcmp(info->pattern, "@all") == 0)
|
||||
{
|
||||
is_multi = true;
|
||||
strncopy(info->target_name, "all players", info->target_name_maxlength);
|
||||
info->target_name_style = COMMAND_TARGETNAME_ML;
|
||||
}
|
||||
else if (strcmp(info->pattern, "@dead") == 0)
|
||||
{
|
||||
is_multi = true;
|
||||
if ((info->flags & COMMAND_FILTER_ALIVE) == COMMAND_FILTER_ALIVE)
|
||||
{
|
||||
info->num_targets = 0;
|
||||
info->reason = COMMAND_TARGET_NOT_ALIVE;
|
||||
return;
|
||||
}
|
||||
info->flags |= COMMAND_FILTER_DEAD;
|
||||
strncopy(info->target_name, "all dead players", info->target_name_maxlength);
|
||||
info->target_name_style = COMMAND_TARGETNAME_ML;
|
||||
}
|
||||
else if (strcmp(info->pattern, "@alive") == 0)
|
||||
{
|
||||
is_multi = true;
|
||||
if ((info->flags & COMMAND_FILTER_DEAD) == COMMAND_FILTER_DEAD)
|
||||
{
|
||||
info->num_targets = 0;
|
||||
info->reason = COMMAND_TARGET_NOT_DEAD;
|
||||
return;
|
||||
}
|
||||
strncopy(info->target_name, "all alive players", info->target_name_maxlength);
|
||||
info->target_name_style = COMMAND_TARGETNAME_ML;
|
||||
info->flags |= COMMAND_FILTER_ALIVE;
|
||||
}
|
||||
else if (strcmp(info->pattern, "@bots") == 0)
|
||||
{
|
||||
is_multi = true;
|
||||
if ((info->flags & COMMAND_FILTER_NO_BOTS) == COMMAND_FILTER_NO_BOTS)
|
||||
{
|
||||
info->num_targets = 0;
|
||||
info->reason = COMMAND_FILTER_NO_BOTS;
|
||||
return;
|
||||
}
|
||||
strncopy(info->target_name, "all bots", info->target_name_maxlength);
|
||||
info->target_name_style = COMMAND_TARGETNAME_ML;
|
||||
bots_only = true;
|
||||
}
|
||||
else if (strcmp(info->pattern, "@humans") == 0)
|
||||
{
|
||||
is_multi = true;
|
||||
strncopy(info->target_name, "all humans", info->target_name_maxlength);
|
||||
info->target_name_style = COMMAND_TARGETNAME_ML;
|
||||
info->flags |= COMMAND_FILTER_NO_BOTS;
|
||||
}
|
||||
|
||||
if (is_multi)
|
||||
{
|
||||
for (int i = 1; i <= max_clients && total < info->max_targets; i++)
|
||||
{
|
||||
if ((pTarget = GetPlayerByIndex(i)) == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (FilterCommandTarget(pAdmin, pTarget, info->flags) > 0)
|
||||
{
|
||||
if (!bots_only || pTarget->IsFakeClient())
|
||||
{
|
||||
info->targets[total++] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info->num_targets = total;
|
||||
info->reason = (info->num_targets) ? COMMAND_TARGET_VALID : COMMAND_TARGET_EMPTY_FILTER;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
List<ICommandTargetProcessor *>::iterator iter;
|
||||
for (iter = target_processors.begin(); iter != target_processors.end(); iter++)
|
||||
{
|
||||
ICommandTargetProcessor *pProcessor = (*iter);
|
||||
if (pProcessor->ProcessCommandTarget(info))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check partial names */
|
||||
int found_client = 0;
|
||||
CPlayer *pFoundClient = NULL;
|
||||
for (int i = 1; i <= max_clients; i++)
|
||||
{
|
||||
if ((pTarget = GetPlayerByIndex(i)) == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (stristr(pTarget->GetName(), info->pattern) != NULL)
|
||||
{
|
||||
if (found_client)
|
||||
{
|
||||
info->num_targets = 0;
|
||||
info->reason = COMMAND_TARGET_AMBIGUOUS;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
found_client = i;
|
||||
pFoundClient = pTarget;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found_client)
|
||||
{
|
||||
if ((info->reason = FilterCommandTarget(pAdmin, pFoundClient, info->flags))
|
||||
== COMMAND_TARGET_VALID)
|
||||
{
|
||||
info->targets[0] = found_client;
|
||||
info->num_targets = 1;
|
||||
strncopy(info->target_name, pFoundClient->GetName(), info->target_name_maxlength);
|
||||
info->target_name_style = COMMAND_TARGETNAME_RAW;
|
||||
}
|
||||
else
|
||||
{
|
||||
info->num_targets = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
info->num_targets = 0;
|
||||
info->reason = COMMAND_TARGET_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************
|
||||
*** PLAYER CODE ***
|
||||
*******************/
|
||||
@ -1118,3 +1396,45 @@ void CPlayer::MarkAsBeingKicked()
|
||||
{
|
||||
m_bIsInKickQueue = true;
|
||||
}
|
||||
|
||||
int CPlayer::GetLifeState()
|
||||
{
|
||||
if (lifestate_offset == -1)
|
||||
{
|
||||
if (!g_pGameConf->GetOffset("m_lifeState", &lifestate_offset))
|
||||
{
|
||||
lifestate_offset = -2;
|
||||
}
|
||||
}
|
||||
|
||||
if (lifestate_offset < 0)
|
||||
{
|
||||
IPlayerInfo *info = GetPlayerInfo();
|
||||
if (info == NULL)
|
||||
{
|
||||
return PLAYER_LIFE_UNKNOWN;
|
||||
}
|
||||
return info->IsDead() ? PLAYER_LIFE_DEAD : PLAYER_LIFE_ALIVE;
|
||||
}
|
||||
|
||||
if (m_pEdict == NULL)
|
||||
{
|
||||
return PLAYER_LIFE_UNKNOWN;
|
||||
}
|
||||
|
||||
CBaseEntity *pEntity;
|
||||
IServerUnknown *pUnknown = m_pEdict->GetUnknown();
|
||||
if (pUnknown == NULL || (pEntity = pUnknown->GetBaseEntity()) == NULL)
|
||||
{
|
||||
return PLAYER_LIFE_UNKNOWN;
|
||||
}
|
||||
|
||||
if (*((uint8_t *)pEntity + lifestate_offset) == LIFE_ALIVE)
|
||||
{
|
||||
return PLAYER_LIFE_ALIVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return PLAYER_LIFE_DEAD;
|
||||
}
|
||||
}
|
||||
|
@ -44,6 +44,10 @@
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
#define PLAYER_LIFE_UNKNOWN 0
|
||||
#define PLAYER_LIFE_ALIVE 1
|
||||
#define PLAYER_LIFE_DEAD 2
|
||||
|
||||
class CPlayer : public IGamePlayer
|
||||
{
|
||||
friend class PlayerManager;
|
||||
@ -70,6 +74,7 @@ public:
|
||||
void DoBasicAdminChecks();
|
||||
bool IsInKickQueue();
|
||||
void MarkAsBeingKicked();
|
||||
int GetLifeState();
|
||||
private:
|
||||
void Initialize(const char *name, const char *ip, edict_t *pEntity);
|
||||
void Connect();
|
||||
@ -138,6 +143,11 @@ public: //IPlayerManager
|
||||
int GetNumPlayers();
|
||||
int GetClientOfUserId(int userid);
|
||||
bool IsServerActivated();
|
||||
int FilterCommandTarget(IGamePlayer *pAdmin, IGamePlayer *pTarget, int flags);
|
||||
int InternalFilterCommandTarget(CPlayer *pAdmin, CPlayer *pTarget, int flags);
|
||||
void RegisterCommandTargetProcessor(ICommandTargetProcessor *pHandler);
|
||||
void UnregisterCommandTargetProcessor(ICommandTargetProcessor *pHandler);
|
||||
void ProcessCommandTarget(cmd_target_info_t *info);
|
||||
public:
|
||||
inline int MaxClients()
|
||||
{
|
||||
|
@ -41,6 +41,7 @@
|
||||
|
||||
Translator g_Translator;
|
||||
CPhraseFile *g_pCorePhrases = NULL;
|
||||
unsigned int g_pCorePhraseID = 0;
|
||||
|
||||
struct trans_t
|
||||
{
|
||||
@ -712,10 +713,13 @@ void Translator::OnSourceModAllInitialized()
|
||||
if (g_LibSys.PathExists(path))
|
||||
{
|
||||
id = FindOrAddPhraseFile("core.cfg");
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
id = FindOrAddPhraseFile("core.phrases.txt");
|
||||
}
|
||||
|
||||
g_pCorePhraseID = id;
|
||||
g_pCorePhrases = GetFileByIndex(id);
|
||||
}
|
||||
|
||||
|
@ -164,6 +164,7 @@ private:
|
||||
};
|
||||
|
||||
extern CPhraseFile *g_pCorePhrases;
|
||||
extern unsigned int g_pCorePhraseID;
|
||||
extern Translator g_Translator;
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_TRANSLATOR_H_
|
||||
|
@ -154,6 +154,8 @@ try_serverlang:
|
||||
|
||||
if (max_params)
|
||||
{
|
||||
cell_t new_params[MAX_TRANSLATE_PARAMS];
|
||||
|
||||
/* Check if we're going to over the limit */
|
||||
if ((*arg) + (max_params - 1) > (size_t)params[0])
|
||||
{
|
||||
@ -164,12 +166,18 @@ try_serverlang:
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
/* Re-order the parameters that this translation requires */
|
||||
ReorderTranslationParams(&pTrans, const_cast<cell_t *>(¶ms[*arg]));
|
||||
}
|
||||
/* If we need to re-order the parameters, do so with a temporary array.
|
||||
* Otherwise, we could run into trouble with continual formats, a la ShowActivity().
|
||||
*/
|
||||
memcpy(new_params, params, sizeof(cell_t) * (params[0] + 1));
|
||||
ReorderTranslationParams(&pTrans, &new_params[*arg]);
|
||||
|
||||
/* Now, call back into atcprintf() which is re-entrant */
|
||||
return atcprintf(buffer, maxlen, pTrans.szPhrase, pCtx, new_params, arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
return atcprintf(buffer, maxlen, pTrans.szPhrase, pCtx, params, arg);
|
||||
}
|
||||
|
||||
error_out:
|
||||
*error = true;
|
||||
|
@ -408,6 +408,34 @@ static cell_t ShowVGUIPanel(IPluginContext *pContext, const cell_t *params)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t smn_IsPlayerAlive(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
CPlayer *player = g_Players.GetPlayerByIndex(params[1]);
|
||||
if (player == NULL)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid client index %d", params[1]);
|
||||
}
|
||||
else if (!player->IsInGame())
|
||||
{
|
||||
return pContext->ThrowNativeError("Client %d is not in game", params[1]);
|
||||
}
|
||||
|
||||
unsigned int state = player->GetLifeState();
|
||||
|
||||
if (state == PLAYER_LIFE_UNKNOWN)
|
||||
{
|
||||
return pContext->ThrowNativeError("\"IsPlayerAlive\" not supported by this mod");
|
||||
}
|
||||
else if (state == PLAYER_LIFE_ALIVE)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_NATIVES(halflifeNatives)
|
||||
{
|
||||
{"CreateFakeClient", CreateFakeClient},
|
||||
@ -436,5 +464,6 @@ REGISTER_NATIVES(halflifeNatives)
|
||||
{"PrintCenterText", PrintCenterText},
|
||||
{"PrintHintText", PrintHintText},
|
||||
{"ShowVGUIPanel", ShowVGUIPanel},
|
||||
{"IsPlayerAlive", smn_IsPlayerAlive},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
@ -881,7 +881,11 @@ static cell_t GetClientOfUserId(IPluginContext *pContext, const cell_t *params)
|
||||
return g_Players.GetClientOfUserId(params[1]);
|
||||
}
|
||||
|
||||
static cell_t _ShowActivity(IPluginContext *pContext, const cell_t *params, const char *tag, cell_t fmt_param)
|
||||
static cell_t _ShowActivity(IPluginContext *pContext,
|
||||
const cell_t *params,
|
||||
const char *tag,
|
||||
cell_t fmt_param,
|
||||
unsigned int mode)
|
||||
{
|
||||
char message[255];
|
||||
char buffer[255];
|
||||
@ -912,13 +916,31 @@ static cell_t _ShowActivity(IPluginContext *pContext, const cell_t *params, cons
|
||||
{
|
||||
g_SourceMod.SetGlobalTarget(client);
|
||||
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param);
|
||||
|
||||
if (pContext->GetContext()->n_err != SP_ERROR_NONE)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
UTIL_Format(message, sizeof(message), "%s%s\n", tag, buffer);
|
||||
engine->ClientPrintf(pPlayer->GetEdict(), message);
|
||||
display_in_chat = true;
|
||||
}
|
||||
} else {
|
||||
else if (mode == 2)
|
||||
{
|
||||
display_in_chat = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_SourceMod.SetGlobalTarget(LANG_SERVER);
|
||||
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param);
|
||||
|
||||
if (pContext->GetContext()->n_err != SP_ERROR_NONE)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
UTIL_Format(message, sizeof(message), "%s%s\n", tag, buffer);
|
||||
META_CONPRINT(message);
|
||||
}
|
||||
@ -947,15 +969,23 @@ static cell_t _ShowActivity(IPluginContext *pContext, const cell_t *params, cons
|
||||
if ((value & 1) || (value & 2))
|
||||
{
|
||||
const char *newsign = sign;
|
||||
if (value & 2)
|
||||
if ((value & 2) || (i == client))
|
||||
{
|
||||
newsign = name;
|
||||
}
|
||||
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param);
|
||||
|
||||
if (pContext->GetContext()->n_err != SP_ERROR_NONE)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
UTIL_Format(message, sizeof(message), "%s%s: %s", tag, newsign, buffer);
|
||||
g_HL2.TextMsg(i, HUD_PRINTTALK, message);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Treat this as an admin user */
|
||||
bool is_root = g_Admins.GetAdminFlag(id, Admin_Root, Access_Effective);
|
||||
if ((value & 4)
|
||||
@ -963,11 +993,17 @@ static cell_t _ShowActivity(IPluginContext *pContext, const cell_t *params, cons
|
||||
|| ((value & 16) && is_root))
|
||||
{
|
||||
const char *newsign = sign;
|
||||
if ((value & 8) || ((value & 16) && is_root))
|
||||
if ((value & 8) || ((value & 16) && is_root) || (i == client))
|
||||
{
|
||||
newsign = name;
|
||||
}
|
||||
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param);
|
||||
|
||||
if (pContext->GetContext()->n_err != SP_ERROR_NONE)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
UTIL_Format(message, sizeof(message), "%s%s: %s", tag, newsign, buffer);
|
||||
g_HL2.TextMsg(i, HUD_PRINTTALK, message);
|
||||
}
|
||||
@ -979,7 +1015,7 @@ static cell_t _ShowActivity(IPluginContext *pContext, const cell_t *params, cons
|
||||
|
||||
static cell_t ShowActivity(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
return _ShowActivity(pContext, params, "[SM] ", 2);
|
||||
return _ShowActivity(pContext, params, "[SM] ", 2, 1);
|
||||
}
|
||||
|
||||
static cell_t ShowActivityEx(IPluginContext *pContext, const cell_t *params)
|
||||
@ -987,7 +1023,15 @@ static cell_t ShowActivityEx(IPluginContext *pContext, const cell_t *params)
|
||||
char *str;
|
||||
pContext->LocalToString(params[2], &str);
|
||||
|
||||
return _ShowActivity(pContext, params, str, 3);
|
||||
return _ShowActivity(pContext, params, str, 3, 1);
|
||||
}
|
||||
|
||||
static cell_t ShowActivity2(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
char *str;
|
||||
pContext->LocalToString(params[2], &str);
|
||||
|
||||
return _ShowActivity(pContext, params, str, 3, 2);
|
||||
}
|
||||
|
||||
static cell_t KickClient(IPluginContext *pContext, const cell_t *params)
|
||||
@ -1036,7 +1080,9 @@ static cell_t ChangeClientTeam(IPluginContext *pContext, const cell_t *params)
|
||||
if (!pPlayer)
|
||||
{
|
||||
return pContext->ThrowNativeError("Client index %d is invalid", client);
|
||||
} else if (!pPlayer->IsInGame()) {
|
||||
}
|
||||
else if (!pPlayer->IsInGame())
|
||||
{
|
||||
return pContext->ThrowNativeError("Client %d is not in game", client);
|
||||
}
|
||||
|
||||
@ -1059,9 +1105,13 @@ static cell_t RunAdminCacheChecks(IPluginContext *pContext, const cell_t *params
|
||||
if (!pPlayer)
|
||||
{
|
||||
return pContext->ThrowNativeError("Client index %d is invalid", client);
|
||||
} else if (!pPlayer->IsInGame()) {
|
||||
}
|
||||
else if (!pPlayer->IsInGame())
|
||||
{
|
||||
return pContext->ThrowNativeError("Client %d is not in game", client);
|
||||
} else if (!pPlayer->IsAuthorized()) {
|
||||
}
|
||||
else if (!pPlayer->IsAuthorized())
|
||||
{
|
||||
return pContext->ThrowNativeError("Client %d is not authorized", client);
|
||||
}
|
||||
|
||||
@ -1079,9 +1129,12 @@ static cell_t NotifyPostAdminCheck(IPluginContext *pContext, const cell_t *param
|
||||
if (!pPlayer)
|
||||
{
|
||||
return pContext->ThrowNativeError("Client index %d is invalid", client);
|
||||
} else if (!pPlayer->IsInGame()) {
|
||||
}
|
||||
else if (!pPlayer->IsInGame()) {
|
||||
return pContext->ThrowNativeError("Client %d is not in game", client);
|
||||
} else if (!pPlayer->IsAuthorized()) {
|
||||
}
|
||||
else if (!pPlayer->IsAuthorized())
|
||||
{
|
||||
return pContext->ThrowNativeError("Client %d is not authorized", client);
|
||||
}
|
||||
|
||||
@ -1108,6 +1161,42 @@ static cell_t IsClientInKickQueue(IPluginContext *pContext, const cell_t *params
|
||||
return pPlayer->IsInKickQueue() ? 1 : 0;
|
||||
}
|
||||
|
||||
static cell_t ProcessTargetString(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
cmd_target_info_t info;
|
||||
|
||||
pContext->LocalToString(params[1], (char **)&info.pattern);
|
||||
info.admin = params[2];
|
||||
pContext->LocalToPhysAddr(params[3], &info.targets);
|
||||
info.max_targets = params[4];
|
||||
info.flags = params[5];
|
||||
pContext->LocalToString(params[6], &info.target_name);
|
||||
info.target_name_maxlength = params[7];
|
||||
|
||||
cell_t *tn_is_ml;
|
||||
pContext->LocalToPhysAddr(params[8], &tn_is_ml);
|
||||
|
||||
g_Players.ProcessCommandTarget(&info);
|
||||
|
||||
if (info.target_name_style == COMMAND_TARGETNAME_ML)
|
||||
{
|
||||
*tn_is_ml = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
*tn_is_ml = 0;
|
||||
}
|
||||
|
||||
if (info.num_targets == 0)
|
||||
{
|
||||
return info.reason;
|
||||
}
|
||||
else
|
||||
{
|
||||
return info.num_targets;
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_NATIVES(playernatives)
|
||||
{
|
||||
{"AddUserFlags", AddUserFlags},
|
||||
@ -1154,10 +1243,12 @@ REGISTER_NATIVES(playernatives)
|
||||
{"GetClientOfUserId", GetClientOfUserId},
|
||||
{"ShowActivity", ShowActivity},
|
||||
{"ShowActivityEx", ShowActivityEx},
|
||||
{"ShowActivity2", ShowActivity2},
|
||||
{"KickClient", KickClient},
|
||||
{"RunAdminCacheChecks", RunAdminCacheChecks},
|
||||
{"NotifyPostAdminCheck", NotifyPostAdminCheck},
|
||||
{"IsClientInKickQueue", IsClientInKickQueue},
|
||||
{"ProcessTargetString", ProcessTargetString},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "ConCmdManager.h"
|
||||
#include "PlayerManager.h"
|
||||
#include "CoreConfig.h"
|
||||
#include "Translator.h"
|
||||
|
||||
CPluginManager g_PluginSys;
|
||||
HandleType_t g_PluginType = 0;
|
||||
@ -1379,6 +1380,9 @@ bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxleng
|
||||
OnLibraryAction((*s_iter).c_str(), true, false);
|
||||
}
|
||||
|
||||
/* Finally, add the core language file */
|
||||
pPlugin->AddLangFile(g_pCorePhraseID);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -255,6 +255,17 @@ native bool:IsFakeClient(client);
|
||||
*/
|
||||
native bool:IsClientObserver(client);
|
||||
|
||||
/**
|
||||
* Returns if the client is alive or dead.
|
||||
*
|
||||
* Note: This function was originally in SDKTools and was moved to core.
|
||||
*
|
||||
* @param client Player's index.
|
||||
* @return True if the client is alive, false otherwise.
|
||||
* @error Invalid client index, client not in game, or no mod support.
|
||||
*/
|
||||
native bool:IsPlayerAlive(client);
|
||||
|
||||
/**
|
||||
* Retrieves values from client replicated keys.
|
||||
*
|
||||
|
130
plugins/include/commandfilters.inc
Normal file
130
plugins/include/commandfilters.inc
Normal file
@ -0,0 +1,130 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This file is part of the SourceMod/SourcePawn SDK.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#if defined _commandfilters_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _commandfilters_included
|
||||
|
||||
#define MAX_TARGET_LENGTH 64
|
||||
|
||||
#define COMMAND_FILTER_ALIVE (1<<0) /* Only allow alive players */
|
||||
#define COMMAND_FILTER_DEAD (1<<1) /* Only filter dead players */
|
||||
#define COMMAND_FILTER_CONNECTED (1<<2) /* Allow players not fully in-game */
|
||||
#define COMMAND_FILTER_NO_IMMUNITY (1<<3) /* Ignore immunity rules */
|
||||
#define COMMAND_FILTER_NO_MULTI (1<<4) /* Do not allow multiple target patterns */
|
||||
#define COMMAND_FILTER_NO_BOTS (1<<5) /* Do not allow bots to be targetted */
|
||||
|
||||
#define COMMAND_TARGET_NONE 0 /* No target was found */
|
||||
#define COMMAND_TARGET_NOT_ALIVE -1 /* Single client is not alive */
|
||||
#define COMMAND_TARGET_NOT_DEAD -2 /* Single client is not dead */
|
||||
#define COMMAND_TARGET_NOT_IN_GAME -3 /* Single client is not in game */
|
||||
#define COMMAND_TARGET_IMMUNE -4 /* Single client is immune */
|
||||
#define COMMAND_TARGET_EMPTY_FILTER -5 /* A multi-filter (such as @all) had no targets */
|
||||
#define COMMAND_TARGET_NOT_HUMAN -6 /* Target was not human */
|
||||
#define COMMAND_TARGET_AMBIGUOUS -7 /* Partial name had too many targets */
|
||||
|
||||
/**
|
||||
* Processes a generic command target string, and resolves it to a list
|
||||
* of clients or one client, based on filtering rules and a pattern.
|
||||
*
|
||||
* @param pattern Pattern to find clients against.
|
||||
* @param admin Admin performing the action, or 0 if the server.
|
||||
* @param targets Array to hold targets.
|
||||
* @param max_targets Maximum size of the targets array.
|
||||
* @param filter_flags Filter flags.
|
||||
* @param target_name Buffer to store the target name.
|
||||
* @param tn_maxlength Maximum length of the target name buffer.
|
||||
* @param tn_is_ml Set to true if the target name buffer is an ML phrase,
|
||||
* false if it is a normal string.
|
||||
* @return If a multi-target pattern was used, the number of clients found
|
||||
* is returned. If a single-target pattern was used, 1 is returned
|
||||
* if one valid client is found. Otherwise, a CLIENT_TARGET reason
|
||||
* for failure is returned.
|
||||
*/
|
||||
native ProcessTargetString(const String:pattern[],
|
||||
admin,
|
||||
targets[],
|
||||
max_targets,
|
||||
filter_flags,
|
||||
String:target_name[],
|
||||
tn_maxlength,
|
||||
&bool:tn_is_ml);
|
||||
|
||||
/**
|
||||
* Replies to a client with a given message describing a targetting
|
||||
* failure reason.
|
||||
*
|
||||
* Note: The translation phrases are found in common.phrases.txt.
|
||||
*
|
||||
* @param client Client index, or 0 for server.
|
||||
* @param reason COMMAND_TARGET reason.
|
||||
* @noreturn
|
||||
*/
|
||||
stock ReplyToTargetError(client, reason)
|
||||
{
|
||||
switch (reason)
|
||||
{
|
||||
case COMMAND_TARGET_NONE:
|
||||
{
|
||||
ReplyToCommand(client, "[SM] %t", "No matching client");
|
||||
}
|
||||
case COMMAND_TARGET_NOT_ALIVE:
|
||||
{
|
||||
ReplyToCommand(client, "[SM] %t", "Target must be alive");
|
||||
}
|
||||
case COMMAND_TARGET_NOT_DEAD:
|
||||
{
|
||||
ReplyToCommand(client, "[SM] %t", "Target must be dead");
|
||||
}
|
||||
case COMMAND_TARGET_NOT_IN_GAME:
|
||||
{
|
||||
ReplyToCommand(client, "[SM] %t", "Target is not in game");
|
||||
}
|
||||
case COMMAND_TARGET_IMMUNE:
|
||||
{
|
||||
ReplyToCommand(client, "[SM] %t", "Unable to target");
|
||||
}
|
||||
case COMMAND_TARGET_EMPTY_FILTER:
|
||||
{
|
||||
ReplyToCommand(client, "[SM] %t", "No matching clients");
|
||||
}
|
||||
case COMMAND_TARGET_NOT_HUMAN:
|
||||
{
|
||||
ReplyToCommand(client, "[SM] %t", "Cannot target bot");
|
||||
}
|
||||
case COMMAND_TARGET_AMBIGUOUS:
|
||||
{
|
||||
ReplyToCommand(client, "[SM] %t", "More than one client matched");
|
||||
}
|
||||
}
|
||||
}
|
@ -241,9 +241,10 @@ native bool:IsChatTrigger();
|
||||
|
||||
/**
|
||||
* Displays usage of an admin command to users depending on the
|
||||
* setting of the sm_show_activity cvar. Additionally, the client
|
||||
* who typed the command will receive the same text without any
|
||||
* client name prefix (as a confirmation).
|
||||
* setting of the sm_show_activity cvar.
|
||||
*
|
||||
* If the original client did not use a console command, they will
|
||||
* not see the public display in their chat.
|
||||
*
|
||||
* @param client Client index doing the action, or 0 for server.
|
||||
* @param format Formatting rules.
|
||||
@ -266,6 +267,19 @@ native ShowActivity(client, const String:format[], any:...);
|
||||
*/
|
||||
native ShowActivityEx(client, const String:tag[], const String:format[], any:...);
|
||||
|
||||
/**
|
||||
* Same as ShowActivityEx(), except the text will always be mirrored to the
|
||||
* client's chat (and console, if the reply source specifies as such).
|
||||
*
|
||||
* @param client Client index doing the action, or 0 for server.
|
||||
* @param tag Tag to display with.
|
||||
* @param format Formatting rules.
|
||||
* @param ... Variable number of format parameters.
|
||||
* @noreturn
|
||||
* @error
|
||||
*/
|
||||
native ShowActivity2(client, const String:tag[], const String:format[], any:...);
|
||||
|
||||
/**
|
||||
* Called when a server-only command is invoked.
|
||||
*
|
||||
|
@ -142,15 +142,6 @@ native FindEntityByClassname(startEnt, const String:classname[]);
|
||||
*/
|
||||
native bool:GetClientEyeAngles(client, Float:ang[3]);
|
||||
|
||||
/**
|
||||
* Returns if the client is alive or dead.
|
||||
*
|
||||
* @param client Player's index.
|
||||
* @return True if the client is alive, false otherwise.
|
||||
* @error Invalid client index, client not in game, or no mod support.
|
||||
*/
|
||||
native bool:IsPlayerAlive(client);
|
||||
|
||||
/**
|
||||
* Creates an entity by string name, but does not spawn it (see DispatchSpawn).
|
||||
* If ForceEdictIndex is not -1, then it will use the edict by that index. If the index is
|
||||
|
@ -70,6 +70,7 @@ struct Plugin
|
||||
#include <halflife>
|
||||
#include <adt>
|
||||
#include <banning>
|
||||
#include <commandfilters>
|
||||
|
||||
/**
|
||||
* Declare this as a struct in your plugin to expose its information.
|
||||
|
@ -24,4 +24,36 @@
|
||||
{
|
||||
"en" "Previous"
|
||||
}
|
||||
|
||||
"all players"
|
||||
{
|
||||
"en" "all players"
|
||||
}
|
||||
|
||||
"all humans"
|
||||
{
|
||||
"en" "all humans"
|
||||
}
|
||||
|
||||
"all bots"
|
||||
{
|
||||
"en" "all bots"
|
||||
}
|
||||
|
||||
"all dead players"
|
||||
{
|
||||
"en" "all dead players"
|
||||
}
|
||||
|
||||
"all alive players"
|
||||
{
|
||||
"en" "all alive players"
|
||||
}
|
||||
|
||||
/* This is a special "pass-thru" translation */
|
||||
"_S"
|
||||
{
|
||||
"#format" "{1:s}"
|
||||
"en" "{1}"
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user