- 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:
David Anderson 2007-10-21 20:06:30 +00:00
parent 744dbdc4c7
commit 02e8977ea0
14 changed files with 676 additions and 30 deletions

View File

@ -45,12 +45,15 @@
#include "HalfLife2.h" #include "HalfLife2.h"
#include <inetchannel.h> #include <inetchannel.h>
#include <iclient.h> #include <iclient.h>
#include "GameConfigs.h"
PlayerManager g_Players; PlayerManager g_Players;
bool g_OnMapStarted = false; bool g_OnMapStarted = false;
IForward *PreAdminCheck = NULL; IForward *PreAdminCheck = NULL;
IForward *PostAdminCheck = NULL; IForward *PostAdminCheck = NULL;
const unsigned int *g_NumPlayersToAuth = 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_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 *); 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); 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 *** *** PLAYER CODE ***
*******************/ *******************/
@ -1118,3 +1396,45 @@ void CPlayer::MarkAsBeingKicked()
{ {
m_bIsInKickQueue = true; 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;
}
}

View File

@ -44,6 +44,10 @@
using namespace SourceHook; using namespace SourceHook;
#define PLAYER_LIFE_UNKNOWN 0
#define PLAYER_LIFE_ALIVE 1
#define PLAYER_LIFE_DEAD 2
class CPlayer : public IGamePlayer class CPlayer : public IGamePlayer
{ {
friend class PlayerManager; friend class PlayerManager;
@ -70,6 +74,7 @@ public:
void DoBasicAdminChecks(); void DoBasicAdminChecks();
bool IsInKickQueue(); bool IsInKickQueue();
void MarkAsBeingKicked(); void MarkAsBeingKicked();
int GetLifeState();
private: private:
void Initialize(const char *name, const char *ip, edict_t *pEntity); void Initialize(const char *name, const char *ip, edict_t *pEntity);
void Connect(); void Connect();
@ -138,6 +143,11 @@ public: //IPlayerManager
int GetNumPlayers(); int GetNumPlayers();
int GetClientOfUserId(int userid); int GetClientOfUserId(int userid);
bool IsServerActivated(); 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: public:
inline int MaxClients() inline int MaxClients()
{ {

View File

@ -41,6 +41,7 @@
Translator g_Translator; Translator g_Translator;
CPhraseFile *g_pCorePhrases = NULL; CPhraseFile *g_pCorePhrases = NULL;
unsigned int g_pCorePhraseID = 0;
struct trans_t struct trans_t
{ {
@ -712,10 +713,13 @@ void Translator::OnSourceModAllInitialized()
if (g_LibSys.PathExists(path)) if (g_LibSys.PathExists(path))
{ {
id = FindOrAddPhraseFile("core.cfg"); id = FindOrAddPhraseFile("core.cfg");
} else { }
else
{
id = FindOrAddPhraseFile("core.phrases.txt"); id = FindOrAddPhraseFile("core.phrases.txt");
} }
g_pCorePhraseID = id;
g_pCorePhrases = GetFileByIndex(id); g_pCorePhrases = GetFileByIndex(id);
} }

View File

@ -164,6 +164,7 @@ private:
}; };
extern CPhraseFile *g_pCorePhrases; extern CPhraseFile *g_pCorePhrases;
extern unsigned int g_pCorePhraseID;
extern Translator g_Translator; extern Translator g_Translator;
#endif //_INCLUDE_SOURCEMOD_TRANSLATOR_H_ #endif //_INCLUDE_SOURCEMOD_TRANSLATOR_H_

View File

@ -154,6 +154,8 @@ try_serverlang:
if (max_params) if (max_params)
{ {
cell_t new_params[MAX_TRANSLATE_PARAMS];
/* Check if we're going to over the limit */ /* Check if we're going to over the limit */
if ((*arg) + (max_params - 1) > (size_t)params[0]) if ((*arg) + (max_params - 1) > (size_t)params[0])
{ {
@ -164,12 +166,18 @@ try_serverlang:
goto error_out; goto error_out;
} }
/* Re-order the parameters that this translation requires */ /* If we need to re-order the parameters, do so with a temporary array.
ReorderTranslationParams(&pTrans, const_cast<cell_t *>(&params[*arg])); * 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); return atcprintf(buffer, maxlen, pTrans.szPhrase, pCtx, params, arg);
}
error_out: error_out:
*error = true; *error = true;

View File

@ -408,6 +408,34 @@ static cell_t ShowVGUIPanel(IPluginContext *pContext, const cell_t *params)
return 1; 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) REGISTER_NATIVES(halflifeNatives)
{ {
{"CreateFakeClient", CreateFakeClient}, {"CreateFakeClient", CreateFakeClient},
@ -436,5 +464,6 @@ REGISTER_NATIVES(halflifeNatives)
{"PrintCenterText", PrintCenterText}, {"PrintCenterText", PrintCenterText},
{"PrintHintText", PrintHintText}, {"PrintHintText", PrintHintText},
{"ShowVGUIPanel", ShowVGUIPanel}, {"ShowVGUIPanel", ShowVGUIPanel},
{"IsPlayerAlive", smn_IsPlayerAlive},
{NULL, NULL}, {NULL, NULL},
}; };

View File

@ -881,7 +881,11 @@ static cell_t GetClientOfUserId(IPluginContext *pContext, const cell_t *params)
return g_Players.GetClientOfUserId(params[1]); 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 message[255];
char buffer[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.SetGlobalTarget(client);
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param); 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); UTIL_Format(message, sizeof(message), "%s%s\n", tag, buffer);
engine->ClientPrintf(pPlayer->GetEdict(), message); engine->ClientPrintf(pPlayer->GetEdict(), message);
display_in_chat = true; display_in_chat = true;
} }
} else { else if (mode == 2)
{
display_in_chat = true;
}
}
else
{
g_SourceMod.SetGlobalTarget(LANG_SERVER); g_SourceMod.SetGlobalTarget(LANG_SERVER);
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param); 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); UTIL_Format(message, sizeof(message), "%s%s\n", tag, buffer);
META_CONPRINT(message); META_CONPRINT(message);
} }
@ -947,15 +969,23 @@ static cell_t _ShowActivity(IPluginContext *pContext, const cell_t *params, cons
if ((value & 1) || (value & 2)) if ((value & 1) || (value & 2))
{ {
const char *newsign = sign; const char *newsign = sign;
if (value & 2) if ((value & 2) || (i == client))
{ {
newsign = name; newsign = name;
} }
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param); 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); UTIL_Format(message, sizeof(message), "%s%s: %s", tag, newsign, buffer);
g_HL2.TextMsg(i, HUD_PRINTTALK, message); g_HL2.TextMsg(i, HUD_PRINTTALK, message);
} }
} else { }
else
{
/* Treat this as an admin user */ /* Treat this as an admin user */
bool is_root = g_Admins.GetAdminFlag(id, Admin_Root, Access_Effective); bool is_root = g_Admins.GetAdminFlag(id, Admin_Root, Access_Effective);
if ((value & 4) if ((value & 4)
@ -963,11 +993,17 @@ static cell_t _ShowActivity(IPluginContext *pContext, const cell_t *params, cons
|| ((value & 16) && is_root)) || ((value & 16) && is_root))
{ {
const char *newsign = sign; const char *newsign = sign;
if ((value & 8) || ((value & 16) && is_root)) if ((value & 8) || ((value & 16) && is_root) || (i == client))
{ {
newsign = name; newsign = name;
} }
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param); 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); UTIL_Format(message, sizeof(message), "%s%s: %s", tag, newsign, buffer);
g_HL2.TextMsg(i, HUD_PRINTTALK, message); 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) 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) 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; char *str;
pContext->LocalToString(params[2], &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) 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) if (!pPlayer)
{ {
return pContext->ThrowNativeError("Client index %d is invalid", client); 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); 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) if (!pPlayer)
{ {
return pContext->ThrowNativeError("Client index %d is invalid", client); 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); 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); 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) if (!pPlayer)
{ {
return pContext->ThrowNativeError("Client index %d is invalid", client); 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); 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); 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; 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) REGISTER_NATIVES(playernatives)
{ {
{"AddUserFlags", AddUserFlags}, {"AddUserFlags", AddUserFlags},
@ -1154,10 +1243,12 @@ REGISTER_NATIVES(playernatives)
{"GetClientOfUserId", GetClientOfUserId}, {"GetClientOfUserId", GetClientOfUserId},
{"ShowActivity", ShowActivity}, {"ShowActivity", ShowActivity},
{"ShowActivityEx", ShowActivityEx}, {"ShowActivityEx", ShowActivityEx},
{"ShowActivity2", ShowActivity2},
{"KickClient", KickClient}, {"KickClient", KickClient},
{"RunAdminCacheChecks", RunAdminCacheChecks}, {"RunAdminCacheChecks", RunAdminCacheChecks},
{"NotifyPostAdminCheck", NotifyPostAdminCheck}, {"NotifyPostAdminCheck", NotifyPostAdminCheck},
{"IsClientInKickQueue", IsClientInKickQueue}, {"IsClientInKickQueue", IsClientInKickQueue},
{"ProcessTargetString", ProcessTargetString},
{NULL, NULL} {NULL, NULL}
}; };

View File

@ -45,6 +45,7 @@
#include "ConCmdManager.h" #include "ConCmdManager.h"
#include "PlayerManager.h" #include "PlayerManager.h"
#include "CoreConfig.h" #include "CoreConfig.h"
#include "Translator.h"
CPluginManager g_PluginSys; CPluginManager g_PluginSys;
HandleType_t g_PluginType = 0; 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); OnLibraryAction((*s_iter).c_str(), true, false);
} }
/* Finally, add the core language file */
pPlugin->AddLangFile(g_pCorePhraseID);
return true; return true;
} }

View File

@ -255,6 +255,17 @@ native bool:IsFakeClient(client);
*/ */
native bool:IsClientObserver(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. * Retrieves values from client replicated keys.
* *

View 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");
}
}
}

View File

@ -241,9 +241,10 @@ native bool:IsChatTrigger();
/** /**
* Displays usage of an admin command to users depending on the * Displays usage of an admin command to users depending on the
* setting of the sm_show_activity cvar. Additionally, the client * setting of the sm_show_activity cvar.
* who typed the command will receive the same text without any *
* client name prefix (as a confirmation). * 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 client Client index doing the action, or 0 for server.
* @param format Formatting rules. * @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:...); 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. * Called when a server-only command is invoked.
* *

View File

@ -142,15 +142,6 @@ native FindEntityByClassname(startEnt, const String:classname[]);
*/ */
native bool:GetClientEyeAngles(client, Float:ang[3]); 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). * 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 * If ForceEdictIndex is not -1, then it will use the edict by that index. If the index is

View File

@ -70,6 +70,7 @@ struct Plugin
#include <halflife> #include <halflife>
#include <adt> #include <adt>
#include <banning> #include <banning>
#include <commandfilters>
/** /**
* Declare this as a struct in your plugin to expose its information. * Declare this as a struct in your plugin to expose its information.

View File

@ -24,4 +24,36 @@
{ {
"en" "Previous" "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}"
}
} }