Compare commits

...

31 Commits

Author SHA1 Message Date
BotoX
178202a5b3 Add "Restart Current Map" to sm_map menu. 2019-11-01 01:17:42 +01:00
BotoX
60f3268236 Fix GetClientCount(false) 2019-10-20 12:28:44 +02:00
BotoX
64b3c8fbd8 Add damageCustom argument to SDKHooks_TakeDamage native. 2019-10-20 12:28:44 +02:00
BotoX
4c4629fca7 fix IsMapValid behavior change by a2246af121 2019-10-20 12:28:44 +02:00
BotoX
8749877c62 fix rare crash bug in SDKTools GetGameRulesProxyEnt 2019-10-20 12:28:44 +02:00
BotoX
102b01c626 Add OnEntitySpawned to SDKHooks. 2019-10-20 12:28:44 +02:00
BotoX
8e07790997 Implement per-client randomized menus with MenuShufflePerClient native.
Add MenuSetClientMapping native.
2019-10-20 12:28:44 +02:00
BotoX
a701408c71 Changes on sm_*say 2019-10-20 12:28:44 +02:00
BotoX
2d0fff79a8 Fix HookEntityOutput/HookSingleEntityOutput bugs in sdktools. 2019-10-20 12:28:44 +02:00
BotoX
9da44d67f1 Add GetClientIClient native. 2019-10-20 12:28:44 +02:00
Obuss
1847f5e2dc Logging changes to various base plugins. 2019-10-20 12:28:44 +02:00
BotoX
0dd3361050 Avoid losing console messages.
Buffers up to 16k bytes of SVC_Print if buffer would overflow, then sends chunks every frame.
Sends up to 2048 bytes per frame and does not split messages.
2019-10-20 12:28:44 +02:00
BotoX
11d12aad11 Extend function calling API for natives and allow catching exceptions.
Change sourcepawn url.
2019-10-20 12:28:44 +02:00
BotoX
8ac0c18674 Fix @spec not targeting clients in unassigned team. 2019-10-20 12:28:44 +02:00
BotoX
a0b8153f4b Added hack to make plugins open a menu with all possible targets on ReplyToTargetError COMMAND_TARGET_AMBIGUOUS.
Explanation:
There are two clients in the server, one named gene, the other one "Ene ~special characters~".
An admin issues "sm_slay Ene" and gets following error message: More than one client matched the given pattern.
What this hack will do is: Use GetCmdArg(0, ...); to get the command name "sm_slay".
Use GetCmdArgString(...); to get the arguments supplied to the command.
Use GetLastProcessTargetString(...); (which was implemented in this commit) to retrieve the arguments that were passed to the last ProcessTargetString call.
It will then pass this data to the DynamicTargeting plugin through its AmbiguousMenu native.
The plugin will open up a menu on the client and list all targets which match the pattern that was supplied to ProcessTargetString.
If the client selects a menu entry, FakeClientCommand will be used to re-execute the command with the correct target.
2019-10-20 12:28:44 +02:00
BotoX
a363587be9 Added client id to MultiTargetFilter forward. 2019-10-20 12:28:44 +02:00
BotoX
fdcce81a41 Add more macros to CDetour. 2019-10-20 12:28:44 +02:00
David Anderson
c3102c7e9f Bump version to 1.11. 2019-10-18 21:07:36 -07:00
Asher Baker
77f4ddf2c2
Fix virtual SDKCall with object params (#1104)
PR #705 made some changes for 64-bit support that required callers to
provide a buffer for object storage, but only added the required code to
the non-virtual call builder, not the virtual call builder.

Copy it over to CreateValveVCall so that ValveParamToBinParam stops
writing to a null pointer.

Fixes #1059 (Hopefully.)
2019-10-18 00:23:45 +01:00
nosoop
024ae2b9ed Use map display name for admin map chooser menu (#1097) 2019-10-07 19:15:36 +01:00
Headline
8a4295d699 NPOTB: Correct GitHub's Linguist inaccuracies (#1096) 2019-10-07 19:14:09 +01:00
David Anderson
f05e39afe1
Merge pull request #1090 from alliedmodders/update-sp
Update SourcePawn to 1.10-dev tip.
2019-10-01 09:50:25 -07:00
Headline
3b1fb85bb8
Fix quote mismatch (#1092) 2019-09-30 22:43:18 -07:00
Playa
a405f85eee Remove SourcePawn JIT license references (#1091) 2019-09-30 15:09:40 -07:00
David Anderson
78511afa4c Update SourcePawn to 1.10-dev tip. 2019-09-28 18:32:47 -07:00
David Anderson
c37c4f830f
Merge pull request #1088 from alliedmodders/update-sp
Update SourcePawn to the tip of 1.10-dev.
2019-09-26 13:14:29 -07:00
David Anderson
4fe2ae780b Update SourcePawn to the tip of 1.10-dev. 2019-09-25 21:59:32 -07:00
Einyux
e02e6bcb4f Add TR_GetHitBoxIndex() native (#1085)
Fixes #1080
2019-09-17 21:24:36 +01:00
David Anderson
c7392aeded Fully convert dynamicmenu to transitional enum structs. (#1082) 2019-09-15 14:02:46 -07:00
David Anderson
14247af323
Merge pull request #1081 from alliedmodders/enum-structs
Update SourcePawn.
2019-09-15 11:55:56 -07:00
David Anderson
32cb00a4c6 Update SourcePawn. 2019-09-15 11:38:21 -07:00
67 changed files with 1796 additions and 401 deletions

12
.gitattributes vendored Normal file
View File

@ -0,0 +1,12 @@
# GitHub views all .h files as C, let's assume it's C++
*.h linguist-language=c++
# Internal tools overriding
tools/* linguist-vendored
editor/* linguist-vendored
# Third-party overriding
extensions/curl/curl-src/* linguist-vendored
extensions/geoip/GeoIP.c linguist-vendored
extensions/geoip/GeoIP.h linguist-vendored
extensions/sqlite/sqlite-source/* linguist-vendored

2
.gitmodules vendored
View File

@ -3,4 +3,4 @@
url = https://github.com/alliedmodders/amtl
[submodule "sourcepawn"]
path = sourcepawn
url = https://github.com/alliedmodders/sourcepawn
url = https://github.com/BotoX/sourcepawn.git

View File

@ -1313,7 +1313,7 @@ bool CHalfLife2::IsMapValid(const char *map)
if (!map || !map[0])
return false;
return FindMap(map) != SMFindMapResult::NotFound;
return FindMap(map) == SMFindMapResult::Found;
}
// TODO: Add ep1 support for this. (No IServerTools available there)

View File

@ -308,7 +308,7 @@ IMenuPanel *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder ord
{
ItemDrawInfo &dr = drawItems[foundItems].draw;
/* Is the item valid? */
if (menu->GetItemInfo(i, &dr) != NULL)
if (menu->GetItemInfo(i, &dr, client) != NULL)
{
/* Ask the user to change the style, if necessary */
mh->OnMenuDrawItem(menu, client, i, dr.style);
@ -398,7 +398,7 @@ IMenuPanel *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder ord
}
while (++lastItem < totalItems)
{
if (menu->GetItemInfo(lastItem, &dr) != NULL)
if (menu->GetItemInfo(lastItem, &dr, client) != NULL)
{
mh->OnMenuDrawItem(menu, client, lastItem, dr.style);
if (IsSlotItem(panel, dr.style))
@ -420,7 +420,7 @@ IMenuPanel *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder ord
lastItem--;
while (lastItem != 0)
{
if (menu->GetItemInfo(lastItem, &dr) != NULL)
if (menu->GetItemInfo(lastItem, &dr, client) != NULL)
{
mh->OnMenuDrawItem(menu, client, lastItem, dr.style);
if (IsSlotItem(panel, dr.style))

View File

@ -633,7 +633,7 @@ bool CBaseMenu::AppendItem(const char *info, const ItemDrawInfo &draw)
return false;
}
CItem item;
CItem item(m_items.length());
item.info = info;
if (draw.display)
@ -655,7 +655,7 @@ bool CBaseMenu::InsertItem(unsigned int position, const char *info, const ItemDr
if (position >= m_items.length())
return false;
CItem item;
CItem item(position);
item.info = info;
if (draw.display)
item.display = new ke::AString(draw.display);
@ -679,11 +679,16 @@ void CBaseMenu::RemoveAllItems()
m_items.clear();
}
const char *CBaseMenu::GetItemInfo(unsigned int position, ItemDrawInfo *draw/* =NULL */)
const char *CBaseMenu::GetItemInfo(unsigned int position, ItemDrawInfo *draw/* =NULL */, int client/* =0 */)
{
if (position >= m_items.length())
return NULL;
if (client > 0 && position < m_RandomMaps[client].length())
{
position = m_RandomMaps[client][position];
}
if (draw)
{
draw->display = m_items[position].display->chars();
@ -693,6 +698,62 @@ const char *CBaseMenu::GetItemInfo(unsigned int position, ItemDrawInfo *draw/* =
return m_items[position].info.chars();
}
void CBaseMenu::ShufflePerClient(int start, int stop)
{
// limit map len to 255 items since it's using uint8
int length = MIN(GetItemCount(), 255);
if (stop >= 0)
length = MIN(length, stop);
for (int i = 1; i < SM_MAXPLAYERS + 1; i++)
{
// populate per-client map ...
m_RandomMaps[i].resize(length);
for (int j = 0; j < length; j++)
m_RandomMaps[i][j] = j;
// ... and random shuffle it
for (int j = length - 1; j > start; j--)
{
int x = rand() % (j - start + 1) + start;
uint8_t tmp = m_RandomMaps[i][x];
m_RandomMaps[i][x] = m_RandomMaps[i][j];
m_RandomMaps[i][j] = tmp;
}
}
}
void CBaseMenu::SetClientMapping(int client, int *array, int length)
{
length = MIN(length, 255);
m_RandomMaps[client].resize(length);
for (int i = 0; i < length; i++)
{
m_RandomMaps[client][i] = array[i];
}
}
bool CBaseMenu::IsPerClientShuffled()
{
for (int i = 1; i < SM_MAXPLAYERS + 1; i++)
{
if(m_RandomMaps[i].length() > 0)
return true;
}
return false;
}
unsigned int CBaseMenu::GetRealItemIndex(int client, unsigned int position)
{
if (client > 0 && position < m_RandomMaps[client].length())
{
position = m_RandomMaps[client][position];
return m_items[position].index;
}
return position;
}
unsigned int CBaseMenu::GetItemCount()
{
return m_items.length();

View File

@ -44,8 +44,9 @@ using namespace SourceMod;
class CItem
{
public:
CItem()
CItem(unsigned int index)
{
this->index = index;
style = 0;
access = 0;
}
@ -53,11 +54,13 @@ public:
: info(ke::Move(other.info)),
display(ke::Move(other.display))
{
index = other.index;
style = other.style;
access = other.access;
}
CItem & operator =(CItem &&other)
{
index = other.index;
info = ke::Move(other.info);
display = ke::Move(other.display);
style = other.style;
@ -66,6 +69,7 @@ public:
}
public:
unsigned int index;
ke::AString info;
ke::AutoPtr<ke::AString> display;
unsigned int style;
@ -138,7 +142,7 @@ public:
virtual bool InsertItem(unsigned int position, const char *info, const ItemDrawInfo &draw);
virtual bool RemoveItem(unsigned int position);
virtual void RemoveAllItems();
virtual const char *GetItemInfo(unsigned int position, ItemDrawInfo *draw=NULL);
virtual const char *GetItemInfo(unsigned int position, ItemDrawInfo *draw=NULL, int client=0);
virtual unsigned int GetItemCount();
virtual bool SetPagination(unsigned int itemsPerPage);
virtual unsigned int GetPagination();
@ -152,6 +156,10 @@ public:
virtual unsigned int GetMenuOptionFlags();
virtual void SetMenuOptionFlags(unsigned int flags);
virtual IMenuHandler *GetHandler();
virtual void ShufflePerClient(int start, int stop);
virtual void SetClientMapping(int client, int *array, int length);
virtual bool IsPerClientShuffled();
virtual unsigned int GetRealItemIndex(int client, unsigned int position);
unsigned int GetBaseMemUsage();
private:
void InternalDelete();
@ -168,6 +176,7 @@ protected:
Handle_t m_hHandle;
IMenuHandler *m_pHandler;
unsigned int m_nFlags;
ke::Vector<uint8_t> m_RandomMaps[SM_MAXPLAYERS+1];
};
#endif //_INCLUDE_MENUSTYLE_BASE_H

View File

@ -514,15 +514,16 @@ void VoteMenuHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int ite
/* Check by our item count, NOT the vote array size */
if (item < m_Items)
{
m_ClientVotes[client] = item;
m_Votes[item]++;
unsigned int index = menu->GetRealItemIndex(client, item);
m_ClientVotes[client] = index;
m_Votes[index]++;
m_NumVotes++;
if (sm_vote_chat.GetBool() || sm_vote_console.GetBool() || sm_vote_client_console.GetBool())
{
static char buffer[1024];
ItemDrawInfo dr;
menu->GetItemInfo(item, &dr);
menu->GetItemInfo(item, &dr, client);
if (sm_vote_console.GetBool())
{

View File

@ -30,6 +30,7 @@
*/
#include "PlayerManager.h"
#include "sourcemod.h"
#include "IAdminSystem.h"
#include "ConCmdManager.h"
#include "MenuStyle_Valve.h"
@ -92,6 +93,12 @@ SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &)
#else
SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
#endif
SH_DECL_HOOK2_void(IVEngineServer, ClientPrintf, SH_NOATTRIB, 0, edict_t *, const char *);
static void PrintfBuffer_FrameAction(void *data)
{
g_Players.OnPrintfFrameAction(reinterpret_cast<unsigned int>(data));
}
ConCommand *maxplayersCmd = NULL;
@ -172,6 +179,7 @@ void PlayerManager::OnSourceModAllInitialized()
#elif SOURCE_ENGINE > SE_EYE // 2013/orangebox, but not original orangebox.
SH_ADD_HOOK(IServerGameDLL, SetServerHibernation, gamedll, SH_MEMBER(this, &PlayerManager::OnServerHibernationUpdate), true);
#endif
SH_ADD_HOOK(IVEngineServer, ClientPrintf, engine, SH_MEMBER(this, &PlayerManager::OnClientPrintf), false);
sharesys->AddInterface(NULL, this);
@ -204,6 +212,9 @@ void PlayerManager::OnSourceModAllInitialized()
SH_ADD_HOOK(ConCommand, Dispatch, pCmd, SH_STATIC(CmdMaxplayersCallback), true);
maxplayersCmd = pCmd;
}
gameevents->AddListener(this, "player_connect", true);
gameevents->AddListener(this, "player_disconnect", true);
}
void PlayerManager::OnSourceModShutdown()
@ -225,6 +236,7 @@ void PlayerManager::OnSourceModShutdown()
#elif SOURCE_ENGINE > SE_EYE // 2013/orangebox, but not original orangebox.
SH_REMOVE_HOOK(IServerGameDLL, SetServerHibernation, gamedll, SH_MEMBER(this, &PlayerManager::OnServerHibernationUpdate), true);
#endif
SH_REMOVE_HOOK(IVEngineServer, ClientPrintf, engine, SH_MEMBER(this, &PlayerManager::OnClientPrintf), false);
/* Release forwards */
forwardsys->ReleaseForward(m_clconnect);
@ -250,6 +262,8 @@ void PlayerManager::OnSourceModShutdown()
{
SH_REMOVE_HOOK(ConCommand, Dispatch, maxplayersCmd, SH_STATIC(CmdMaxplayersCallback), true);
}
gameevents->RemoveListener(this);
}
ConfigResult PlayerManager::OnSourceModConfigChanged(const char *key,
@ -846,6 +860,88 @@ void PlayerManager::OnClientDisconnect_Post(edict_t *pEntity)
}
}
void PlayerManager::OnClientPrintf(edict_t *pEdict, const char *szMsg)
{
int client = IndexOfEdict(pEdict);
CPlayer &player = m_Players[client];
if (!player.IsConnected())
RETURN_META(MRES_IGNORED);
INetChannel *pNetChan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(client));
if (pNetChan == NULL)
RETURN_META(MRES_IGNORED);
size_t nMsgLen = strlen(szMsg);
#if SOURCE_ENGINE == SE_EPISODEONE
static const int nNumBitsWritten = 0;
#else
int nNumBitsWritten = pNetChan->GetNumBitsWritten(false); // SVC_Print uses unreliable netchan
#endif
// if the msg is bigger than allowed then just let it fail
if (nMsgLen + 1 >= SVC_Print_BufferSize) // +1 for NETMSG_TYPE_BITS
RETURN_META(MRES_IGNORED);
// enqueue msgs if we'd overflow the SVC_Print buffer (+7 as ceil)
if (!player.m_PrintfBuffer.empty() || (nNumBitsWritten + NETMSG_TYPE_BITS + 7) / 8 + nMsgLen >= SVC_Print_BufferSize)
{
// Don't send any more messages for this player until the buffer is empty.
// Queue up a gameframe hook to empty the buffer (if we haven't already)
if (player.m_PrintfBuffer.empty())
g_SourceMod.AddFrameAction(PrintfBuffer_FrameAction, (void *)(uintptr_t)player.GetSerial());
player.m_PrintfBuffer.append(szMsg);
RETURN_META(MRES_SUPERCEDE);
}
RETURN_META(MRES_IGNORED);
}
void PlayerManager::OnPrintfFrameAction(unsigned int serial)
{
int client = GetClientFromSerial(serial);
CPlayer &player = m_Players[client];
if (!player.IsConnected())
{
player.ClearNetchannelQueue();
return;
}
INetChannel *pNetChan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(client));
if (pNetChan == NULL)
{
player.ClearNetchannelQueue();
return;
}
while (!player.m_PrintfBuffer.empty())
{
#if SOURCE_ENGINE == SE_EPISODEONE
static const int nNumBitsWritten = 0;
#else
int nNumBitsWritten = pNetChan->GetNumBitsWritten(false); // SVC_Print uses unreliable netchan
#endif
ke::AString &string = player.m_PrintfBuffer.front();
// stop if we'd overflow the SVC_Print buffer (+7 as ceil)
if ((nNumBitsWritten + NETMSG_TYPE_BITS + 7) / 8 + string.length() >= SVC_Print_BufferSize)
break;
SH_CALL(engine, &IVEngineServer::ClientPrintf)(player.m_pEdict, string.chars());
player.m_PrintfBuffer.popFront();
}
if (!player.m_PrintfBuffer.empty())
{
// continue processing it on the next gameframe as buffer is not empty
g_SourceMod.AddFrameAction(PrintfBuffer_FrameAction, (void *)(uintptr_t)player.GetSerial());
}
}
void ClientConsolePrint(edict_t *e, const char *fmt, ...)
{
char buffer[512];
@ -1333,6 +1429,11 @@ int PlayerManager::GetNumPlayers()
return m_PlayerCount;
}
int PlayerManager::GetNumClients()
{
return m_ClientCount;
}
int PlayerManager::GetClientOfUserId(int userid)
{
if (userid < 0 || userid > USHRT_MAX)
@ -1928,6 +2029,27 @@ bool PlayerManager::HandleConVarQuery(QueryCvarCookie_t cookie, int client, EQue
}
#endif
/* IGameEventListener2::FireGameEvent */
void PlayerManager::FireGameEvent(IGameEvent *pEvent)
{
const char *name = pEvent->GetName();
if (strcmp(name, "player_connect") == 0)
{
const int client = pEvent->GetInt("index") + 1;
const int userid = pEvent->GetInt("userid");
m_ClientCount++;
}
else if (strcmp(name, "player_disconnect") == 0)
{
const int userid = pEvent->GetInt("userid");
const int client = m_UserIdLookUp[userid];
m_ClientCount--;
}
}
/*******************
*** PLAYER CODE ***
@ -2145,6 +2267,13 @@ void CPlayer::Disconnect()
#if SOURCE_ENGINE == SE_CSGO
m_LanguageCookie = InvalidQueryCvarCookie;
#endif
ClearNetchannelQueue();
}
void CPlayer::ClearNetchannelQueue(void)
{
while (!m_PrintfBuffer.empty())
m_PrintfBuffer.popFront();
}
void CPlayer::SetName(const char *name)

View File

@ -43,6 +43,7 @@
#include <sh_list.h>
#include <sh_vector.h>
#include <am-string.h>
#include <am-deque.h>
#include "ConVarManager.h"
#include <steam/steamclientpublic.h>
@ -123,6 +124,7 @@ private:
bool IsAuthStringValidated();
bool SetEngineString();
bool SetCSteamID();
void ClearNetchannelQueue(void);
private:
bool m_IsConnected = false;
bool m_IsInGame = false;
@ -152,11 +154,13 @@ private:
#if SOURCE_ENGINE == SE_CSGO
QueryCvarCookie_t m_LanguageCookie = InvalidQueryCvarCookie;
#endif
ke::Deque<ke::AString> m_PrintfBuffer;
};
class PlayerManager :
public SMGlobalClass,
public IPlayerManager
public IPlayerManager,
public IGameEventListener2
{
friend class CPlayer;
public:
@ -190,6 +194,8 @@ public:
void OnClientSettingsChanged(edict_t *pEntity);
//void OnClientSettingsChanged_Pre(edict_t *pEntity);
void OnServerHibernationUpdate(bool bHibernating);
void OnClientPrintf(edict_t *pEdict, const char *szMsg);
void OnPrintfFrameAction(unsigned int serial);
public: //IPlayerManager
void AddClientListener(IClientListener *listener);
void RemoveClientListener(IClientListener *listener);
@ -197,6 +203,7 @@ public: //IPlayerManager
IGamePlayer *GetGamePlayer(edict_t *pEdict);
int GetMaxClients();
int GetNumPlayers();
int GetNumClients();
int GetClientOfUserId(int userid);
bool IsServerActivated();
int FilterCommandTarget(IGamePlayer *pAdmin, IGamePlayer *pTarget, int flags);
@ -207,6 +214,8 @@ public: //IPlayerManager
int GetClientFromSerial(unsigned int serial);
void ClearAdminId(AdminId id);
void RecheckAnyAdmins();
public: // IGameEventListener2
void FireGameEvent(IGameEvent *pEvent);
public:
inline int MaxClients()
{
@ -267,6 +276,10 @@ private:
int m_SourceTVUserId;
int m_ReplayUserId;
bool m_bInCCKVHook;
int m_ClientCount;
private:
static const int NETMSG_TYPE_BITS = 5; // SVC_Print overhead for netmsg type
static const int SVC_Print_BufferSize = 2048 - 1; // -1 for terminating \0
};
#if SOURCE_ENGINE >= SE_ORANGEBOX

View File

@ -85,6 +85,7 @@ for arch in SM.archs:
'smn_halflife.cpp',
'FrameIterator.cpp',
'DatabaseConfBuilder.cpp',
'NativeInvoker.cpp',
]
if arch == 'x64':

View File

@ -0,0 +1,321 @@
// vim: set sts=2 ts=8 sw=2 tw=99 et:
//
// Copyright (C) 2006-2015 AlliedModders LLC
//
// This file is part of SourcePawn. SourcePawn is free software: you can
// redistribute it and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
//
// You should have received a copy of the GNU General Public License along with
// SourcePawn. If not, see http://www.gnu.org/licenses/.
//
#include <stdio.h>
#include <string.h>
#include "NativeInvoker.h"
/********************
* FUNCTION CALLING *
********************/
NativeInvoker::NativeInvoker(IPluginContext *pContext, const ke::RefPtr<Native> &native)
: context_(pContext),
m_curparam(0),
m_errorstate(SP_ERROR_NONE),
native_(native)
{
}
NativeInvoker::~NativeInvoker()
{
Cancel();
}
bool
NativeInvoker::IsRunnable()
{
return true;
}
IPluginContext *
NativeInvoker::GetParentContext()
{
return context_;
}
int NativeInvoker::PushCell(cell_t cell)
{
if (m_curparam >= SP_MAX_EXEC_PARAMS)
return SetError(SP_ERROR_PARAMS_MAX);
m_info[m_curparam].marked = false;
m_params[m_curparam] = cell;
m_curparam++;
return SP_ERROR_NONE;
}
int
NativeInvoker::PushCellByRef(cell_t *cell, int flags)
{
return PushArray(cell, 1, flags);
}
int
NativeInvoker::PushFloat(float number)
{
cell_t val = sp::FloatCellUnion(number).cell;
return PushCell(val);
}
int
NativeInvoker::PushFloatByRef(float *number, int flags)
{
return PushCellByRef((cell_t *)number, flags);
}
int
NativeInvoker::PushArray(cell_t *inarray, unsigned int cells, int copyback)
{
if (m_curparam >= SP_MAX_EXEC_PARAMS)
{
return SetError(SP_ERROR_PARAMS_MAX);
}
ParamInfo *info = &m_info[m_curparam];
info->flags = inarray ? copyback : 0;
info->marked = true;
info->size = cells;
info->str.is_sz = false;
info->orig_addr = inarray;
m_curparam++;
return SP_ERROR_NONE;
}
int
NativeInvoker::PushString(const char *string)
{
return _PushString(string, SM_PARAM_STRING_COPY, 0, strlen(string)+1);
}
int
NativeInvoker::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
{
return _PushString(buffer, sz_flags, cp_flags, length);
}
int
NativeInvoker::_PushString(const char *string, int sz_flags, int cp_flags, size_t len)
{
if (m_curparam >= SP_MAX_EXEC_PARAMS)
return SetError(SP_ERROR_PARAMS_MAX);
ParamInfo *info = &m_info[m_curparam];
info->marked = true;
info->orig_addr = (cell_t *)string;
info->flags = cp_flags;
info->size = len;
info->str.sz_flags = sz_flags;
info->str.is_sz = true;
m_curparam++;
return SP_ERROR_NONE;
}
void
NativeInvoker::Cancel()
{
if (!m_curparam)
return;
m_errorstate = SP_ERROR_NONE;
m_curparam = 0;
}
int
NativeInvoker::Execute(cell_t *result, cell_t buffer, cell_t size)
{
context_->ClearLastNativeError();
// For backward compatibility, we have to clear the exception state.
// Otherwise code like this:
//
// static cell_t native(cx, params) {
// for (auto callback : callbacks) {
// callback->Execute();
// }
// }
//
// Could unintentionally leak a pending exception back to the caller,
// which wouldn't have happened before the Great Exception Refactoring.
SourcePawn::ExceptionHandler eh(context_);
eh.Debug(!size);
if (!Invoke(result)) {
if(size)
context_->StringToLocalUTF8(buffer, size, eh.Message(), NULL);
int Err = context_->GetLastNativeError();
context_->ClearLastNativeError();
return Err;
}
return SP_ERROR_NONE;
}
bool
NativeInvoker::Invoke(cell_t *result)
{
if (!IsRunnable()) {
Cancel();
context_->ReportErrorNumber(SP_ERROR_NOT_RUNNABLE);
return false;
}
if (int err = m_errorstate) {
Cancel();
context_->ReportErrorNumber(err);
return false;
}
//This is for re-entrancy!
cell_t _temp_params[SP_MAX_EXEC_PARAMS + 1];
cell_t *temp_params = &_temp_params[1];
ParamInfo temp_info[SP_MAX_EXEC_PARAMS];
unsigned int numparams = m_curparam;
unsigned int i;
if (numparams)
{
//Save the info locally, then reset it for re-entrant calls.
memcpy(temp_info, m_info, numparams * sizeof(ParamInfo));
}
m_curparam = 0;
/* Initialize 0th parameter */
_temp_params[0] = numparams;
/* Browse the parameters and build arrays */
bool ok = true;
for (i=0; i<numparams; i++) {
/* Is this marked as an array? */
if (temp_info[i].marked) {
if (!temp_info[i].str.is_sz) {
/* Allocate a normal/generic array */
int err = context_->HeapAlloc(
temp_info[i].size,
&(temp_info[i].local_addr),
&(temp_info[i].phys_addr));
if (err != SP_ERROR_NONE) {
context_->ReportErrorNumber(err);
ok = false;
break;
}
if (temp_info[i].orig_addr)
{
memcpy(temp_info[i].phys_addr, temp_info[i].orig_addr, sizeof(cell_t) * temp_info[i].size);
}
} else {
/* Calculate cells required for the string */
size_t cells = (temp_info[i].size + sizeof(cell_t) - 1) / sizeof(cell_t);
/* Allocate the buffer */
int err = context_->HeapAlloc(
cells,
&(temp_info[i].local_addr),
&(temp_info[i].phys_addr));
if (err != SP_ERROR_NONE) {
context_->ReportErrorNumber(err);
ok = false;
break;
}
/* Copy original string if necessary */
if ((temp_info[i].str.sz_flags & SM_PARAM_STRING_COPY) && (temp_info[i].orig_addr != NULL))
{
/* Cut off UTF-8 properly */
if (temp_info[i].str.sz_flags & SM_PARAM_STRING_UTF8) {
context_->StringToLocalUTF8(
temp_info[i].local_addr,
temp_info[i].size,
(const char *)temp_info[i].orig_addr,
NULL);
}
/* Copy a binary blob */
else if (temp_info[i].str.sz_flags & SM_PARAM_STRING_BINARY)
{
memmove(temp_info[i].phys_addr, temp_info[i].orig_addr, temp_info[i].size);
}
/* Copy ASCII characters */
else
{
context_->StringToLocal(
temp_info[i].local_addr,
temp_info[i].size,
(const char *)temp_info[i].orig_addr);
}
}
} /* End array/string calculation */
/* Update the pushed parameter with the byref local address */
temp_params[i] = temp_info[i].local_addr;
} else {
/* Just copy the value normally */
temp_params[i] = m_params[i];
}
}
/* Make the call if we can */
if (ok)
{
*result = native_->func()(context_, _temp_params);
}
/* i should be equal to the last valid parameter + 1 */
bool docopies = ok;
while (i--) {
if (!temp_info[i].marked)
continue;
if (docopies && (temp_info[i].flags & SM_PARAM_COPYBACK)) {
if (temp_info[i].orig_addr) {
if (temp_info[i].str.is_sz) {
memcpy(temp_info[i].orig_addr, temp_info[i].phys_addr, temp_info[i].size);
} else {
if (temp_info[i].size == 1) {
*temp_info[i].orig_addr = *(temp_info[i].phys_addr);
} else {
memcpy(temp_info[i].orig_addr,
temp_info[i].phys_addr,
temp_info[i].size * sizeof(cell_t));
}
}
}
}
if (int err = context_->HeapPop(temp_info[i].local_addr))
context_->ReportErrorNumber(err);
}
return context_->GetLastNativeError() == SP_ERROR_NONE;
}
int
NativeInvoker::SetError(int err)
{
m_errorstate = err;
return err;
}
int NativeInvoker::CallFunction(const cell_t *params, unsigned int num_params, cell_t *result) { return 0; }
funcid_t NativeInvoker::GetFunctionID() { return 0; }
int NativeInvoker::Execute2(IPluginContext *ctx, cell_t *result) { return 0; }
int NativeInvoker::CallFunction2(IPluginContext *ctx, const cell_t *params, unsigned int num_params, cell_t *result) { return 0; }
IPluginRuntime *NativeInvoker::GetParentRuntime() { return NULL; }

View File

@ -0,0 +1,79 @@
// vim: set sts=2 ts=8 sw=2 tw=99 et:
//
// Copyright (C) 2006-2015 AlliedModders LLC
//
// This file is part of SourcePawn. SourcePawn is free software: you can
// redistribute it and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
//
// You should have received a copy of the GNU General Public License along with
// SourcePawn. If not, see http://www.gnu.org/licenses/.
//
#ifndef _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_
#define _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_
#include <sp_vm_api.h>
#include <amtl/am-autoptr.h>
#include <amtl/am-refcounting.h>
#include "Native.h"
struct ParamInfo
{
int flags; /* Copy-back flags */
bool marked; /* Whether this is marked as being used */
cell_t local_addr; /* Local address to free */
cell_t *phys_addr; /* Physical address of our copy */
cell_t *orig_addr; /* Original address to copy back to */
ucell_t size; /* Size of array in bytes */
struct {
bool is_sz; /* is a string */
int sz_flags; /* has sz flags */
} str;
};
class NativeInvoker : public IPluginFunction
{
public:
NativeInvoker(IPluginContext *pContext, const ke::RefPtr<Native> &native);
virtual ~NativeInvoker();
public:
int PushCell(cell_t cell);
int PushCellByRef(cell_t *cell, int flags);
int PushFloat(float number);
int PushFloatByRef(float *number, int flags);
int PushArray(cell_t *inarray, unsigned int cells, int copyback);
int PushString(const char *string);
int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags);
int Execute(cell_t *result, cell_t buffer=0, cell_t size=0);
void Cancel();
int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result);
IPluginContext *GetParentContext();
bool Invoke(cell_t *result);
bool IsRunnable();
funcid_t GetFunctionID();
int Execute2(IPluginContext *ctx, cell_t *result);
int CallFunction2(IPluginContext *ctx,
const cell_t *params,
unsigned int num_params,
cell_t *result);
IPluginRuntime *GetParentRuntime();
const char *DebugName() {
return native_->name();
}
private:
int _PushString(const char *string, int sz_flags, int cp_flags, size_t len);
int SetError(int err);
private:
IPluginContext *context_;
cell_t m_params[SP_MAX_EXEC_PARAMS];
ParamInfo m_info[SP_MAX_EXEC_PARAMS];
unsigned int m_curparam;
int m_errorstate;
ke::RefPtr<Native> native_;
};
#endif //_INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_

View File

@ -35,6 +35,8 @@
#include <IForwardSys.h>
#include <ISourceMod.h>
#include <amtl/am-autoptr.h>
#include "ShareSys.h"
#include "NativeInvoker.h"
HandleType_t g_GlobalFwdType = 0;
HandleType_t g_PrivateFwdType = 0;
@ -43,6 +45,7 @@ static bool s_CallStarted = false;
static ICallable *s_pCallable = NULL;
static IPluginFunction *s_pFunction = NULL;
static IForward *s_pForward = NULL;
static NativeInvoker *s_pInvoker = NULL;
class ForwardNativeHelpers :
public SMGlobalClass,
@ -102,6 +105,9 @@ inline void ResetCall()
s_pFunction = NULL;
s_pForward = NULL;
s_pCallable = NULL;
if(s_pInvoker)
delete s_pInvoker;
s_pInvoker = NULL;
}
static cell_t sm_GetFunctionByName(IPluginContext *pContext, const cell_t *params)
@ -366,6 +372,27 @@ static cell_t sm_CallStartForward(IPluginContext *pContext, const cell_t *params
return 1;
}
static cell_t sm_CallStartNative(IPluginContext *pContext, const cell_t *params)
{
ResetCall();
char *name;
pContext->LocalToString(params[1], &name);
ke::RefPtr<Native> pNative = g_ShareSys.FindNative(name);
if (!pNative)
return 0;//pContext->ThrowNativeError("Invalid native \"%s\"", name);
s_pInvoker = new NativeInvoker(pContext, pNative);
s_pCallable = static_cast<ICallable *>(s_pInvoker);
s_CallStarted = true;
return 1;
}
static cell_t sm_CallPushCell(IPluginContext *pContext, const cell_t *params)
{
int err;
@ -656,6 +683,39 @@ static cell_t sm_CallFinish(IPluginContext *pContext, const cell_t *params)
IForward *pForward = s_pForward;
ResetCall();
err = pForward->Execute(result, NULL);
} else if (s_pInvoker) {
err = s_pInvoker->Execute(result);
ResetCall();
}
return err;
}
static cell_t sm_CallFinishEx(IPluginContext *pContext, const cell_t *params)
{
int err = SP_ERROR_NOT_RUNNABLE;
cell_t *result;
if (!s_CallStarted)
{
return pContext->ThrowNativeError("Cannot finish call when there is no call in progress");
}
pContext->LocalToPhysAddr(params[1], &result);
// Note: Execute() swallows exceptions, so this is okay.
if (s_pFunction)
{
IPluginFunction *pFunction = s_pFunction;
ResetCall();
err = pFunction->Execute(result, params[2], params[3]);
} else if (s_pForward) {
IForward *pForward = s_pForward;
ResetCall();
err = pForward->Execute(result, NULL);
} else if (s_pInvoker) {
err = s_pInvoker->Execute(result, params[2], params[3]);
ResetCall();
}
return err;
@ -742,6 +802,7 @@ REGISTER_NATIVES(functionNatives)
{"RemoveAllFromForward", sm_RemoveAllFromForward},
{"Call_StartFunction", sm_CallStartFunction},
{"Call_StartForward", sm_CallStartForward},
{"Call_StartNative", sm_CallStartNative},
{"Call_PushCell", sm_CallPushCell},
{"Call_PushCellRef", sm_CallPushCellRef},
{"Call_PushFloat", sm_CallPushFloat},
@ -753,6 +814,7 @@ REGISTER_NATIVES(functionNatives)
{"Call_PushNullVector", sm_CallPushNullVector},
{"Call_PushNullString", sm_CallPushNullString},
{"Call_Finish", sm_CallFinish},
{"Call_FinishEx", sm_CallFinishEx},
{"Call_Cancel", sm_CallCancel},
{"RequestFrame", sm_AddFrameAction},

View File

@ -816,8 +816,14 @@ static cell_t GetMenuItem(IPluginContext *pContext, const cell_t *params)
ItemDrawInfo dr;
const char *info;
cell_t client = (params[0] >= 8) ? params[8] : 0;
if(!client && menu->IsPerClientShuffled())
{
return pContext->ThrowNativeError("This menu has been per-client random shuffled. "
"You have to call GetMenuItem with a client index!");
}
if ((info=menu->GetItemInfo(params[2], &dr)) == NULL)
if ((info=menu->GetItemInfo(params[2], &dr, client)) == NULL)
{
return 0;
}
@ -832,6 +838,57 @@ static cell_t GetMenuItem(IPluginContext *pContext, const cell_t *params)
return 1;
}
static cell_t MenuShufflePerClient(IPluginContext *pContext, const cell_t *params)
{
Handle_t hndl = (Handle_t)params[1];
HandleError err;
IBaseMenu *menu;
if ((err = ReadMenuHandle(params[1], &menu)) != HandleError_None)
{
return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
}
int start = params[2];
int stop = params[3];
if (stop > 0 && !(stop >= start))
{
return pContext->ThrowNativeError("Stop must be -1 or >= start!");
}
menu->ShufflePerClient(start, stop);
return 1;
}
static cell_t MenuSetClientMapping(IPluginContext *pContext, const cell_t *params)
{
Handle_t hndl = (Handle_t)params[1];
HandleError err;
IBaseMenu *menu;
if ((err = ReadMenuHandle(params[1], &menu)) != HandleError_None)
{
return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
}
int client = params[2];
if (client < 1 || client > SM_MAXPLAYERS)
{
return pContext->ThrowNativeError("Invalid client index!");
}
cell_t *array;
pContext->LocalToPhysAddr(params[3], &array);
int length = params[4];
menu->SetClientMapping(client, array, length);
return 1;
}
static cell_t SetMenuPagination(IPluginContext *pContext, const cell_t *params)
{
Handle_t hndl = (Handle_t)params[1];
@ -1645,6 +1702,8 @@ REGISTER_NATIVES(menuNatives)
{"SetPanelKeys", SetPanelKeys},
{"SetVoteResultCallback", SetVoteResultCallback},
{"VoteMenu", VoteMenu},
{"MenuShufflePerClient", MenuShufflePerClient},
{"MenuSetClientMapping", MenuSetClientMapping},
{"SetMenuNoVoteButton", SetMenuNoVoteButton},
// Transitional syntax support.
@ -1673,6 +1732,8 @@ REGISTER_NATIVES(menuNatives)
{"Menu.ToPanel", CreatePanelFromMenu},
{"Menu.Cancel", CancelMenu},
{"Menu.DisplayVote", VoteMenu},
{"Menu.ShufflePerClient", MenuShufflePerClient},
{"Menu.SetClientMapping", MenuSetClientMapping},
{"Menu.Pagination.get", GetMenuPagination},
{"Menu.Pagination.set", SetMenuPagination},
{"Menu.OptionFlags.get", GetMenuOptionFlags},

View File

@ -64,10 +64,13 @@ static const int kActivityAdmins = 4; // Show admin activity to admins anonymo
static const int kActivityAdminsNames = 8; // If 4 is specified, admin names will be shown.
static const int kActivityRootNames = 16; // Always show admin names to root users.
#define FEATURECAP_MULTITARGETFILTER_CLIENTPARAM "SourceMod MultiTargetFilter ClientParam"
class PlayerLogicHelpers :
public SMGlobalClass,
public IPluginsListener,
public ICommandTargetProcessor
public ICommandTargetProcessor,
public IFeatureProvider
{
struct SimpleMultiTargetFilter
{
@ -141,6 +144,7 @@ public: //ICommandTargetProcessor
smtf->fun->PushString(info->pattern);
smtf->fun->PushCell(ahc.getClone());
smtf->fun->PushCell(info->admin);
cell_t result = 0;
if (smtf->fun->Execute(&result) != SP_ERROR_NONE || !result)
return false;
@ -185,6 +189,7 @@ public: //SMGlobalClass
void OnSourceModAllInitialized()
{
pluginsys->AddPluginsListener(this);
sharesys->AddCapabilityProvider(NULL, this, FEATURECAP_MULTITARGETFILTER_CLIENTPARAM);
}
void OnSourceModShutdown()
@ -194,6 +199,7 @@ public: //SMGlobalClass
playerhelpers->UnregisterCommandTargetProcessor(this);
filterEnabled = false;
}
sharesys->DropCapabilityProvider(NULL, this, FEATURECAP_MULTITARGETFILTER_CLIENTPARAM);
}
public: //IPluginsListener
@ -211,6 +217,13 @@ public: //IPluginsListener
}
}
}
public: //IFeatureProvider
FeatureStatus GetFeatureStatus(FeatureType type, const char *name)
{
return FeatureStatus_Available;
}
} s_PlayerLogicHelpers;
static cell_t
@ -257,18 +270,7 @@ static cell_t sm_GetClientCount(IPluginContext *pCtx, const cell_t *params)
return playerhelpers->GetNumPlayers();
}
int maxplayers = playerhelpers->GetMaxClients();
int count = 0;
for (int i = 1; i <= maxplayers; ++i)
{
IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(i);
if ((pPlayer->IsConnected()) && !(pPlayer->IsInGame()))
{
count++;
}
}
return (playerhelpers->GetNumPlayers() + count);
return playerhelpers->GetNumClients();
}
static cell_t sm_GetMaxClients(IPluginContext *pCtx, const cell_t *params)
@ -1458,24 +1460,23 @@ static cell_t IsClientInKickQueue(IPluginContext *pContext, const cell_t *params
return pPlayer->IsInKickQueue() ? 1 : 0;
}
cmd_target_info_t g_ProcessTargetString_info;
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];
pContext->LocalToString(params[1], (char **) &g_ProcessTargetString_info.pattern);
g_ProcessTargetString_info.admin = params[2];
pContext->LocalToPhysAddr(params[3], &g_ProcessTargetString_info.targets);
g_ProcessTargetString_info.max_targets = params[4];
g_ProcessTargetString_info.flags = params[5];
pContext->LocalToString(params[6], &g_ProcessTargetString_info.target_name);
g_ProcessTargetString_info.target_name_maxlength = params[7];
cell_t *tn_is_ml;
pContext->LocalToPhysAddr(params[8], &tn_is_ml);
playerhelpers->ProcessCommandTarget(&info);
playerhelpers->ProcessCommandTarget(&g_ProcessTargetString_info);
if (info.target_name_style == COMMAND_TARGETNAME_ML)
if (g_ProcessTargetString_info.target_name_style == COMMAND_TARGETNAME_ML)
{
*tn_is_ml = 1;
}
@ -1484,16 +1485,30 @@ static cell_t ProcessTargetString(IPluginContext *pContext, const cell_t *params
*tn_is_ml = 0;
}
if (info.num_targets == 0)
if (g_ProcessTargetString_info.num_targets == 0)
{
return info.reason;
return g_ProcessTargetString_info.reason;
}
else
{
return info.num_targets;
return g_ProcessTargetString_info.num_targets;
}
}
static cell_t GetLastProcessTargetString(IPluginContext *pContext, const cell_t *params)
{
cell_t *admin, *flags;
pContext->StringToLocalUTF8(params[1], params[2], g_ProcessTargetString_info.pattern, NULL);
pContext->LocalToPhysAddr(params[3], &admin);
pContext->LocalToPhysAddr(params[4], &flags);
*admin = g_ProcessTargetString_info.admin;
*flags = g_ProcessTargetString_info.flags;
return 0;
}
static cell_t FormatActivitySource(IPluginContext *pContext, const cell_t *params)
{
int value;
@ -1645,6 +1660,7 @@ REGISTER_NATIVES(playernatives)
{ "NotifyPostAdminCheck", NotifyPostAdminCheck },
{ "IsClientInKickQueue", IsClientInKickQueue },
{ "ProcessTargetString", ProcessTargetString },
{ "GetLastProcessTargetString", GetLastProcessTargetString },
{ "FormatActivitySource", FormatActivitySource },
{ "GetClientSerial", sm_GetClientSerial },
{ "GetClientFromSerial", sm_GetClientFromSerial },

View File

@ -789,6 +789,16 @@ static cell_t sm_RegAdminCmd(IPluginContext *pContext, const cell_t *params)
return 1;
}
static cell_t sm_IsCommandCallback(IPluginContext *pContext, const cell_t *params)
{
const ICommandArgs *pCmd = g_HL2.PeekCommandStack();
if (!pCmd)
return 0;
return 1;
}
static cell_t sm_GetCmdArgs(IPluginContext *pContext, const cell_t *params)
{
const ICommandArgs *pCmd = g_HL2.PeekCommandStack();
@ -1467,6 +1477,7 @@ REGISTER_NATIVES(consoleNatives)
{"GetConVarDefault", GetConVarDefault},
{"RegServerCmd", sm_RegServerCmd},
{"RegConsoleCmd", sm_RegConsoleCmd},
{"IsCommandCallback", sm_IsCommandCallback},
{"GetCmdArgString", sm_GetCmdArgString},
{"GetCmdArgs", sm_GetCmdArgs},
{"GetCmdArg", sm_GetCmdArg},

View File

@ -356,6 +356,27 @@ static cell_t GetAvgPackets(IPluginContext *pContext, const cell_t *params)
return sp_ftoc(value);
}
static cell_t sm_GetClientIClient(IPluginContext *pContext, const cell_t *params)
{
int client = params[1];
CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
if (!pPlayer)
{
return pContext->ThrowNativeError("Client index %d is invalid", client);
}
else if (!pPlayer->IsConnected())
{
return pContext->ThrowNativeError("Client %d is not connected", client);
}
else if (pPlayer->IsFakeClient())
{
return pContext->ThrowNativeError("Client %d is a bot", client);
}
return (cell_t)pPlayer->GetIClient();
}
static cell_t RunAdminCacheChecks(IPluginContext *pContext, const cell_t *params)
{
int client = params[1];
@ -392,6 +413,7 @@ REGISTER_NATIVES(playernatives)
{"GetClientAvgChoke", GetAvgChoke},
{"GetClientAvgData", GetAvgData},
{"GetClientAvgPackets", GetAvgPackets},
{"GetClientIClient", sm_GetClientIClient },
{"RunAdminCacheChecks", RunAdminCacheChecks},
{NULL, NULL}
};

View File

@ -112,6 +112,7 @@ IServerTools *servertools = NULL;
// global hooks and forwards
IForward *g_pOnEntityCreated = NULL;
IForward *g_pOnEntitySpawned = NULL;
IForward *g_pOnEntityDestroyed = NULL;
#ifdef GAMEDESC_CAN_CHANGE
@ -252,6 +253,7 @@ bool SDKHooks::SDK_OnLoad(char *error, size_t maxlength, bool late)
plsys->AddPluginsListener(&g_Interface);
g_pOnEntityCreated = forwards->CreateForward("OnEntityCreated", ET_Ignore, 2, NULL, Param_Cell, Param_String);
g_pOnEntitySpawned = forwards->CreateForward("OnEntitySpawned", ET_Ignore, 2, NULL, Param_Cell, Param_String);
g_pOnEntityDestroyed = forwards->CreateForward("OnEntityDestroyed", ET_Ignore, 1, NULL, Param_Cell);
#ifdef GAMEDESC_CAN_CHANGE
g_pOnGetGameNameDescription = forwards->CreateForward("OnGetGameDescription", ET_Hook, 2, NULL, Param_String);
@ -344,6 +346,7 @@ void SDKHooks::SDK_OnUnload()
#endif
forwards->ReleaseForward(g_pOnEntityCreated);
forwards->ReleaseForward(g_pOnEntitySpawned);
forwards->ReleaseForward(g_pOnEntityDestroyed);
#ifdef GAMEDESC_CAN_CHANGE
forwards->ReleaseForward(g_pOnGetGameNameDescription);
@ -420,6 +423,7 @@ void SDKHooks::OnClientPutInServer(int client)
CBaseEntity *pPlayer = gamehelpers->ReferenceToEntity(client);
HandleEntityCreated(pPlayer, client, gamehelpers->EntityToReference(pPlayer));
HandleEntitySpawned(pPlayer, client, gamehelpers->EntityToReference(pPlayer));
}
void SDKHooks::OnClientDisconnecting(int client)
@ -879,6 +883,27 @@ void SDKHooks::OnEntityCreated(CBaseEntity *pEntity)
}
}
void SDKHooks::OnEntitySpawned(CBaseEntity *pEntity)
{
// Call OnEntitySpawned forward
int ref = gamehelpers->EntityToReference(pEntity);
int index = gamehelpers->ReferenceToIndex(ref);
// This can be -1 for player ents before any players have connected
if ((unsigned)index == INVALID_EHANDLE_INDEX || (index > 0 && index <= playerhelpers->GetMaxClients()))
{
return;
}
if (!IsEntityIndexInRange(index))
{
g_pSM->LogError(myself, "SDKHooks::OnEntitySpawned - Got entity index out of range (%d)", index);
return;
}
HandleEntitySpawned(pEntity, index, ref);
}
#ifdef GAMEDESC_CAN_CHANGE
const char *SDKHooks::Hook_GetGameDescription()
{
@ -1791,6 +1816,32 @@ void SDKHooks::HandleEntityCreated(CBaseEntity *pEntity, int index, cell_t ref)
m_EntityCache[index] = ref;
}
void SDKHooks::HandleEntitySpawned(CBaseEntity *pEntity, int index, cell_t ref)
{
if (g_pOnEntitySpawned->GetFunctionCount() || m_EntListeners.size())
{
cell_t bcompatRef = gamehelpers->EntityToBCompatRef(pEntity);
const char *pName = gamehelpers->GetEntityClassname(pEntity);
if (!pName)
pName = "";
// Send OnEntitySpawned to SM listeners
for (SourceHook::List<ISMEntityListener *>::iterator iter = m_EntListeners.begin(); iter != m_EntListeners.end(); iter++)
{
ISMEntityListener *pListener = (*iter);
pListener->OnEntitySpawned(pEntity, pName);
}
// Call OnEntitySpawned forward
if (g_pOnEntitySpawned->GetFunctionCount())
{
g_pOnEntitySpawned->PushCell(bcompatRef);
g_pOnEntitySpawned->PushString(pName);
g_pOnEntitySpawned->Execute(NULL);
}
}
}
void SDKHooks::HandleEntityDeleted(CBaseEntity *pEntity)
{
cell_t bcompatRef = gamehelpers->EntityToBCompatRef(pEntity);

View File

@ -238,6 +238,7 @@ public: // IFeatureProvider
public: // IEntityListener
virtual void OnEntityCreated(CBaseEntity *pEntity);
virtual void OnEntitySpawned(CBaseEntity *pEntity);
virtual void OnEntityDeleted(CBaseEntity *pEntity);
public: // IClientListener
@ -330,6 +331,7 @@ public:
private:
void HandleEntityCreated(CBaseEntity *pEntity, int index, cell_t ref);
void HandleEntitySpawned(CBaseEntity *pEntity, int index, cell_t ref);
void HandleEntityDeleted(CBaseEntity *pEntity);
void Unhook(CBaseEntity *pEntity);
void Unhook(IPluginContext *pContext);

View File

@ -175,7 +175,13 @@ cell_t Native_TakeDamage(IPluginContext *pContext, const cell_t *params)
vecDamagePosition = vec3_origin;
}
CTakeDamageInfoHack info(pInflictor, pAttacker, flDamage, iDamageType, pWeapon, vecDamageForce, vecDamagePosition);
int iDamageCustom = 0;
if (params[0] >= 9)
{
iDamageCustom = params[9];
}
CTakeDamageInfoHack info(pInflictor, pAttacker, flDamage, iDamageType, pWeapon, vecDamageForce, vecDamagePosition, iDamageCustom);
SH_MCALL(pVictim, OnTakeDamage)((CTakeDamageInfoHack &)info);
#endif

View File

@ -34,7 +34,7 @@
CTakeDamageInfo::CTakeDamageInfo(){}
CTakeDamageInfoHack::CTakeDamageInfoHack( CBaseEntity *pInflictor, CBaseEntity *pAttacker, float flDamage, int bitsDamageType, CBaseEntity *pWeapon, Vector vecDamageForce, Vector vecDamagePosition )
CTakeDamageInfoHack::CTakeDamageInfoHack( CBaseEntity *pInflictor, CBaseEntity *pAttacker, float flDamage, int bitsDamageType, CBaseEntity *pWeapon, Vector vecDamageForce, Vector vecDamagePosition, int iDamageCustom )
{
m_hInflictor = pInflictor;
if ( pAttacker )
@ -63,9 +63,9 @@ CTakeDamageInfoHack::CTakeDamageInfoHack( CBaseEntity *pInflictor, CBaseEntity *
m_iAmmoType = -1;
#if SOURCE_ENGINE < SE_ORANGEBOX
m_iCustomKillType = 0;
m_iCustomKillType = iDamageCustom;
#else
m_iDamageCustom = 0;
m_iDamageCustom = iDamageCustom;
#endif
#if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_SDK2013 \

View File

@ -58,7 +58,7 @@
class CTakeDamageInfoHack : public CTakeDamageInfo
{
public:
CTakeDamageInfoHack( CBaseEntity *pInflictor, CBaseEntity *pAttacker, float flDamage, int bitsDamageType, CBaseEntity *pWeapon, Vector vecDamageForce, Vector vecDamagePosition );
CTakeDamageInfoHack( CBaseEntity *pInflictor, CBaseEntity *pAttacker, float flDamage, int bitsDamageType, CBaseEntity *pWeapon, Vector vecDamageForce, Vector vecDamagePosition, int iDamageCustom=0);
inline int GetAttacker() const { return m_hAttacker.IsValid() ? m_hAttacker.GetEntryIndex() : -1; }
inline int GetInflictor() const { return m_hInflictor.IsValid() ? m_hInflictor.GetEntryIndex() : -1; }
#if SOURCE_ENGINE >= SE_ORANGEBOX && SOURCE_ENGINE != SE_LEFT4DEAD

View File

@ -484,7 +484,7 @@ bool SDKTools::ProcessCommandTarget(cmd_target_info_t *info)
IPlayerInfo *plinfo = player->GetPlayerInfo();
if (plinfo == NULL)
continue;
if (plinfo->GetTeamIndex() == 1 &&
if ((plinfo->GetTeamIndex() == 0 || plinfo->GetTeamIndex() == 1) &&
playerhelpers->FilterCommandTarget(pAdmin, player, info->flags) ==
COMMAND_TARGET_VALID)
{

View File

@ -53,6 +53,10 @@ static CBaseEntity *FindEntityByNetClass(int start, const char *classname)
if (network == NULL)
continue;
IHandleEntity *pHandleEnt = network->GetEntityHandle();
if (pHandleEnt == NULL)
continue;
ServerClass *sClass = network->GetServerClass();
const char *name = sClass->GetName();

View File

@ -52,7 +52,6 @@ void EntityOutputManager::Shutdown()
return;
}
EntityOutputs->Destroy();
ClassNames->Destroy();
fireOutputDetour->Destroy();
}
@ -66,7 +65,6 @@ void EntityOutputManager::Init()
return;
}
EntityOutputs = adtfactory->CreateBasicTrie();
ClassNames = adtfactory->CreateBasicTrie();
}
@ -120,45 +118,30 @@ bool EntityOutputManager::FireEventDetour(void *pOutput, CBaseEntity *pActivator
return true;
}
char sOutput[20];
ke::SafeSprintf(sOutput, sizeof(sOutput), "%p", pOutput);
// attempt to directly lookup a hook using the pOutput pointer
OutputNameStruct *pOutputName = NULL;
bool fastLookup = false;
// Fast lookup failed - check the slow way for hooks that haven't fired yet
if ((fastLookup = EntityOutputs->Retrieve(sOutput, (void **)&pOutputName)) == false)
const char *classname = gamehelpers->GetEntityClassname(pCaller);
if (!classname)
{
const char *classname = gamehelpers->GetEntityClassname(pCaller);
if (!classname)
{
return true;
}
return true;
}
const char *outputname = FindOutputName(pOutput, pCaller);
if (!outputname)
{
return true;
}
const char *outputname = FindOutputName(pOutput, pCaller);
if (!outputname)
{
return true;
}
pOutputName = FindOutputPointer(classname, outputname, false);
pOutputName = FindOutputPointer(classname, outputname, false);
if (!pOutputName)
{
return true;
}
if (!pOutputName)
{
return true;
}
if (!pOutputName->hooks.empty())
{
if (!fastLookup)
{
// hook exists on this classname and output - map it into our quick find trie
EntityOutputs->Insert(sOutput, pOutputName);
}
SourceHook::List<omg_hooks *>::iterator _iter;
omg_hooks *hook;

View File

@ -121,8 +121,6 @@ private:
const char *FindOutputName(void *pOutput, CBaseEntity *pCaller);
//Maps CEntityOutput * to a OutputNameStruct
IBasicTrie *EntityOutputs;
// Maps classname to a ClassNameStruct
IBasicTrie *ClassNames;

View File

@ -998,6 +998,22 @@ static cell_t smn_TRGetHitGroup(IPluginContext *pContext, const cell_t *params)
return tr->hitgroup;
}
static cell_t smn_TRGetHitBoxIndex(IPluginContext *pContext, const cell_t *params)
{
sm_trace_t *tr;
HandleError err;
HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
if (params[1] == BAD_HANDLE)
{
tr = &g_Trace;
} else if ((err = handlesys->ReadHandle(params[1], g_TraceHandle, &sec, (void **)&tr)) != HandleError_None) {
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err);
}
return tr->hitbox;
}
static cell_t smn_TRGetEntityIndex(IPluginContext *pContext, const cell_t *params)
{
sm_trace_t *tr;
@ -1102,6 +1118,7 @@ sp_nativeinfo_t g_TRNatives[] =
{"TR_StartSolid", smn_TRStartSolid},
{"TR_DidHit", smn_TRDidHit},
{"TR_GetHitGroup", smn_TRGetHitGroup},
{"TR_GetHitBoxIndex", smn_TRGetHitBoxIndex},
{"TR_ClipRayToEntity", smn_TRClipRayToEntity},
{"TR_ClipRayToEntityEx", smn_TRClipRayToEntityEx},
{"TR_ClipRayHullToEntity", smn_TRClipRayHullToEntity},

View File

@ -255,10 +255,12 @@ ValveCall *CreateValveVCall(unsigned int vtableIdx,
/* Get return information - encode only */
PassInfo retBuf;
ObjectField retFieldBuf[16];
size_t retBufSize = 0;
bool retbuf_needs_extra;
if (retInfo)
{
retBuf.fields = retFieldBuf;
if ((size = ValveParamToBinParam(retInfo->vtype, retInfo->type, retInfo->flags, &retBuf, retbuf_needs_extra)) == 0)
{
delete vc;
@ -269,12 +271,14 @@ ValveCall *CreateValveVCall(unsigned int vtableIdx,
/* Get parameter info */
PassInfo paramBuf[32];
ObjectField fieldBuf[32][16];
size_t sizes[32];
size_t normSize = 0;
size_t extraSize = 0;
for (unsigned int i=0; i<numParams; i++)
{
bool needs_extra;
paramBuf[i].fields = fieldBuf[i];
if ((size = ValveParamToBinParam(params[i].vtype,
params[i].type,
params[i].flags,

View File

@ -1,15 +1,14 @@
SOURCEMOD LICENSE INFORMATION
VERSION: JUNE-13-2008
VERSION: 2019-9-30
-----------------------------
SourceMod is licensed under the GNU General Public License, version 3.
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.
Engine" 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.
As an additional special exception to the GNU General Public License 3.0,
AlliedModders LLC permits dual-licensing of DERIVATIVE WORKS ONLY (that is,
@ -27,7 +26,6 @@ License version 2 (without an "or any higher version" clause) if and only if
the work was already GNU General Public License 2.0 exclusive. This clause is
provided for backwards compatibility only.
A copy of the JIT License is available in JIT.txt.
A copy of the GNU General Public License 2.0 is available in GPLv2.txt.
A copy of the GNU General Public License 3.0 is available in GPLv3.txt.
@ -35,5 +33,4 @@ SourcePawn is Copyright (C) 2006-2008 AlliedModders LLC. All rights reserved.
SourceMod is Copyright (C) 2006-2008 AlliedModders LLC. All rights reserved.
Pawn and SMALL are Copyright (C) 1997-2008 ITB CompuPhase.
Source is Copyright (C) Valve Corporation.
All trademarks are property of their respective owners in the US and other
All trademarks are property of their respective owners in the US and other countries.

View File

@ -24,7 +24,8 @@ files = [
'basecommands.sp',
'mapchooser.sp',
'randomcycle.sp',
'sql-admin-manager.sp'
'sql-admin-manager.sp',
'DynamicTargeting.sp'
]
spcomp_argv = [

266
plugins/DynamicTargeting.sp Normal file
View File

@ -0,0 +1,266 @@
#pragma semicolon 1
#define PLUGIN_VERSION "1.0"
#include <sourcemod>
#include <DynamicTargeting>
#pragma newdecls required
public Plugin myinfo =
{
name = "Dynamic Targeting",
author = "BotoX",
description = "",
version = PLUGIN_VERSION,
url = ""
}
char g_PlayerNames[MAXPLAYERS + 1][MAX_NAME_LENGTH];
Handle g_PlayerData[MAXPLAYERS + 1];
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
{
CreateNative("AmbiguousMenu", Native_AmbiguousMenu);
RegPluginLibrary("DynamicTargeting");
return APLRes_Success;
}
public void OnClientDisconnect(int client)
{
if(g_PlayerData[client] != INVALID_HANDLE)
{
CloseHandle(g_PlayerData[client]);
g_PlayerData[client] = INVALID_HANDLE;
}
}
int CreateAmbiguousMenu(int client, const char[] sCommand, const char[] sArgString, const char[] sPattern, int FilterFlags)
{
Menu menu = new Menu(MenuHandler_AmbiguousMenu, MenuAction_Select|MenuAction_Cancel|MenuAction_End|MenuAction_DrawItem|MenuAction_DisplayItem);
menu.ExitButton = true;
char sTitle[32 + MAX_TARGET_LENGTH];
FormatEx(sTitle, sizeof(sTitle), "Target \"%s\" is ambiguous.", sPattern);
menu.SetTitle(sTitle);
int Players = 0;
int[] aClients = new int[MaxClients + 1];
for(int i = 1; i <= MaxClients; i++)
{
if(!IsClientConnected(i) || i == client)
continue;
if(FilterFlags & COMMAND_FILTER_NO_BOTS && IsFakeClient(i))
continue;
if(!(FilterFlags & COMMAND_FILTER_CONNECTED) && !IsClientInGame(i))
continue;
if(FilterFlags & COMMAND_FILTER_ALIVE && !IsPlayerAlive(i))
continue;
if(FilterFlags & COMMAND_FILTER_DEAD && IsPlayerAlive(i))
continue;
// insert player names into g_PlayerNames array
GetClientName(i, g_PlayerNames[i], sizeof(g_PlayerNames[]));
if(StrContains(g_PlayerNames[i], sPattern, false) != -1)
aClients[Players++] = i;
}
// sort aClients array by player name
SortCustom1D(aClients, Players, SortByPlayerName);
// insert players sorted
char sUserId[12];
char sDisp[MAX_NAME_LENGTH + 16];
for(int i = 0; i < Players; i++)
{
IntToString(GetClientUserId(aClients[i]), sUserId, sizeof(sUserId));
FormatEx(sDisp, sizeof(sDisp), "%s (%s)", g_PlayerNames[aClients[i]], sUserId);
menu.AddItem(sUserId, sDisp);
}
DataPack pack = new DataPack();
pack.WriteString(sCommand);
pack.WriteString(sArgString);
pack.WriteString(sPattern);
pack.WriteCell(FilterFlags);
if(g_PlayerData[client] != INVALID_HANDLE)
{
CloseHandle(g_PlayerData[client]);
g_PlayerData[client] = INVALID_HANDLE;
}
CancelClientMenu(client);
g_PlayerData[client] = pack;
menu.Display(client, MENU_TIME_FOREVER);
return 0;
}
public int MenuHandler_AmbiguousMenu(Menu menu, MenuAction action, int param1, int param2)
{
switch(action)
{
case MenuAction_End:
{
CloseHandle(menu);
}
case MenuAction_Cancel:
{
if(g_PlayerData[param1] != INVALID_HANDLE)
{
CloseHandle(g_PlayerData[param1]);
g_PlayerData[param1] = INVALID_HANDLE;
}
}
case MenuAction_Select:
{
int Style;
char sItem[32];
char sDisp[MAX_NAME_LENGTH + 16];
menu.GetItem(param2, sItem, sizeof(sItem), Style, sDisp, sizeof(sDisp));
int UserId = StringToInt(sItem);
int client = GetClientOfUserId(UserId);
if(!client)
{
PrintToChat(param1, "\x04[DynamicTargeting]\x01 Player no longer available.");
menu.DisplayAt(param1, GetMenuSelectionPosition(), MENU_TIME_FOREVER);
return 0;
}
DataPack pack = view_as<DataPack>(g_PlayerData[param1]);
pack.Reset();
char sCommand[128];
pack.ReadString(sCommand, sizeof(sCommand));
char sArgString[256];
pack.ReadString(sArgString, sizeof(sArgString));
char sPattern[MAX_TARGET_LENGTH];
pack.ReadString(sPattern, sizeof(sPattern));
int Result = ReCallAmbiguous(param1, client, sCommand, sArgString, sPattern);
return Result;
}
case MenuAction_DrawItem:
{
int Style;
char sItem[32];
menu.GetItem(param2, sItem, sizeof(sItem), Style);
int UserId = StringToInt(sItem);
int client = GetClientOfUserId(UserId);
if(!client) // Player disconnected
return ITEMDRAW_DISABLED;
return Style;
}
case MenuAction_DisplayItem:
{
int Style;
char sItem[32];
char sDisp[MAX_NAME_LENGTH + 16];
menu.GetItem(param2, sItem, sizeof(sItem), Style, sDisp, sizeof(sDisp));
if(!sItem[0])
return 0;
char sBuffer[MAX_NAME_LENGTH + 16];
int UserId = StringToInt(sItem);
int client = GetClientOfUserId(UserId);
if(!client) // Player disconnected
return 0;
GetClientName(client, g_PlayerNames[client], sizeof(g_PlayerNames[]));
FormatEx(sBuffer, sizeof(sBuffer), "%s (%d)", g_PlayerNames[client], UserId);
if(!StrEqual(sDisp, sBuffer))
return RedrawMenuItem(sBuffer);
return 0;
}
}
return 0;
}
int ReCallAmbiguous(int client, int newClient, const char[] sCommand, const char[] sArgString, const char[] sPattern)
{
char sTarget[16];
FormatEx(sTarget, sizeof(sTarget), "#%d", GetClientUserId(newClient));
char sNewArgString[256];
strcopy(sNewArgString, sizeof(sNewArgString), sArgString);
char sPart[256];
int CurrentIndex = 0;
int NextIndex = 0;
while(NextIndex != -1 && CurrentIndex < sizeof(sNewArgString))
{
NextIndex = BreakString(sNewArgString[CurrentIndex], sPart, sizeof(sPart));
if(StrEqual(sPart, sPattern))
{
ReplaceStringEx(sNewArgString[CurrentIndex], sizeof(sNewArgString) - CurrentIndex, sPart, sTarget);
break;
}
CurrentIndex += NextIndex;
}
FakeClientCommandEx(client, "%s %s", sCommand, sNewArgString);
return 0;
}
public int Native_AmbiguousMenu(Handle plugin, int numParams)
{
int client = GetNativeCell(1);
if(client > MaxClients || client <= 0)
{
ThrowNativeError(SP_ERROR_NATIVE, "Client is not valid.");
return -1;
}
if(!IsClientInGame(client))
{
ThrowNativeError(SP_ERROR_NATIVE, "Client is not in-game.");
return -1;
}
if(IsFakeClient(client))
{
ThrowNativeError(SP_ERROR_NATIVE, "Client is fake-client.");
return -1;
}
char sCommand[128];
GetNativeString(2, sCommand, sizeof(sCommand));
char sArgString[256];
GetNativeString(3, sArgString, sizeof(sArgString));
char sPattern[MAX_TARGET_LENGTH];
GetNativeString(4, sPattern, sizeof(sPattern));
int FilterFlags = GetNativeCell(5);
return CreateAmbiguousMenu(client, sCommand, sArgString, sPattern, FilterFlags);
}
public int SortByPlayerName(int elem1, int elem2, const int[] array, Handle hndl)
{
return strcmp(g_PlayerNames[elem1], g_PlayerNames[elem2], false);
}

View File

@ -4,26 +4,26 @@
#define ARRAY_STRING_LENGTH 32
enum GroupCommands
enum struct GroupCommands
{
ArrayList:groupListName,
ArrayList:groupListCommand
};
ArrayList groupListName;
ArrayList groupListCommand;
}
int g_groupList[GroupCommands];
GroupCommands g_groupList;
int g_groupCount;
SMCParser g_configParser;
enum Places
enum struct Places
{
Place_Category,
Place_Item,
Place_ReplaceNum
};
int category;
int item;
int replaceNum;
}
char g_command[MAXPLAYERS+1][CMD_LENGTH];
int g_currentPlace[MAXPLAYERS+1][Places];
Places g_currentPlace[MAXPLAYERS+1];
/**
* What to put in the 'info' menu field (for PlayerList and Player_Team menus only)
@ -331,11 +331,11 @@ void ParseConfigs()
g_configParser.OnKeyValue = KeyValue;
g_configParser.OnLeaveSection = EndSection;
delete g_groupList[groupListName];
delete g_groupList[groupListCommand];
delete g_groupList.groupListName;
delete g_groupList.groupListCommand;
g_groupList[groupListName] = new ArrayList(ARRAY_STRING_LENGTH);
g_groupList[groupListCommand] = new ArrayList(ARRAY_STRING_LENGTH);
g_groupList.groupListName = new ArrayList(ARRAY_STRING_LENGTH);
g_groupList.groupListCommand = new ArrayList(ARRAY_STRING_LENGTH);
char configPath[256];
BuildPath(Path_SM, configPath, sizeof(configPath), "configs/dynamicmenu/adminmenu_grouping.txt");
@ -376,13 +376,13 @@ public SMCResult NewSection(SMCParser smc, const char[] name, bool opt_quotes)
public SMCResult KeyValue(SMCParser smc, const char[] key, const char[] value, bool key_quotes, bool value_quotes)
{
g_groupList[groupListName].PushString(key);
g_groupList[groupListCommand].PushString(value);
g_groupList.groupListName.PushString(key);
g_groupList.groupListCommand.PushString(value);
}
public SMCResult EndSection(SMCParser smc)
{
g_groupCount = g_groupList[groupListName].Length;
g_groupCount = g_groupList.groupListName.Length;
}
public void DynamicMenuCategoryHandler(TopMenu topmenu,
@ -421,8 +421,8 @@ public void DynamicMenuItemHandler(TopMenu topmenu,
strcopy(g_command[param], sizeof(g_command[]), output.cmd);
g_currentPlace[param][Place_Item] = location;
g_currentPlace[param][Place_ReplaceNum] = 1;
g_currentPlace[param].item = location;
g_currentPlace[param].replaceNum = 1;
ParamCheck(param);
}
@ -436,19 +436,19 @@ public void ParamCheck(int client)
Item outputItem;
Submenu outputSubmenu;
g_DataArray.GetArray(g_currentPlace[client][Place_Item], outputItem);
g_DataArray.GetArray(g_currentPlace[client].item, outputItem);
if (g_currentPlace[client][Place_ReplaceNum] < 1)
if (g_currentPlace[client].replaceNum < 1)
{
g_currentPlace[client][Place_ReplaceNum] = 1;
g_currentPlace[client].replaceNum = 1;
}
Format(buffer, 5, "#%i", g_currentPlace[client][Place_ReplaceNum]);
Format(buffer2, 5, "@%i", g_currentPlace[client][Place_ReplaceNum]);
Format(buffer, 5, "#%i", g_currentPlace[client].replaceNum);
Format(buffer2, 5, "@%i", g_currentPlace[client].replaceNum);
if (StrContains(g_command[client], buffer) != -1 || StrContains(g_command[client], buffer2) != -1)
{
outputItem.submenus.GetArray(g_currentPlace[client][Place_ReplaceNum] - 1, outputSubmenu);
outputItem.submenus.GetArray(g_currentPlace[client].replaceNum - 1, outputSubmenu);
Menu itemMenu = new Menu(Menu_Selection);
itemMenu.ExitBackButton = true;
@ -460,8 +460,8 @@ public void ParamCheck(int client)
for (int i = 0; i<g_groupCount; i++)
{
g_groupList[groupListName].GetString(i, nameBuffer, sizeof(nameBuffer));
g_groupList[groupListCommand].GetString(i, commandBuffer, sizeof(commandBuffer));
g_groupList.groupListName.GetString(i, nameBuffer, sizeof(nameBuffer));
g_groupList.groupListCommand.GetString(i, commandBuffer, sizeof(commandBuffer));
itemMenu.AddItem(commandBuffer, nameBuffer);
}
}
@ -591,7 +591,7 @@ public void ParamCheck(int client)
}
g_command[client][0] = '\0';
g_currentPlace[client][Place_ReplaceNum] = 1;
g_currentPlace[client].replaceNum = 1;
}
}
@ -622,16 +622,16 @@ public int Menu_Selection(Menu menu, MenuAction action, int param1, int param2)
char infobuffer[NAME_LENGTH+2];
Format(infobuffer, sizeof(infobuffer), "\"%s\"", info);
Format(buffer, 5, "#%i", g_currentPlace[param1][Place_ReplaceNum]);
Format(buffer, 5, "#%i", g_currentPlace[param1].replaceNum);
ReplaceString(g_command[param1], sizeof(g_command[]), buffer, infobuffer);
//replace #num with the selected option (quoted)
Format(buffer, 5, "@%i", g_currentPlace[param1][Place_ReplaceNum]);
Format(buffer, 5, "@%i", g_currentPlace[param1].replaceNum);
ReplaceString(g_command[param1], sizeof(g_command[]), buffer, info);
//replace @num with the selected option (unquoted)
// Increment the parameter counter.
g_currentPlace[param1][Place_ReplaceNum]++;
g_currentPlace[param1].replaceNum++;
ParamCheck(param1);
}

View File

@ -34,6 +34,7 @@
#pragma semicolon 1
#include <sourcemod>
#include <basecomm>
#pragma newdecls required
@ -80,6 +81,9 @@ public void OnPluginStart()
public Action OnClientSayCommand(int client, const char[] command, const char[] sArgs)
{
if (client <= 0 || BaseComm_IsClientGagged(client))
return Plugin_Continue;
int startidx;
if (sArgs[startidx] != CHAT_SYMBOL)
return Plugin_Continue;
@ -88,51 +92,20 @@ public Action OnClientSayCommand(int client, const char[] command, const char[]
if (strcmp(command, "say", false) == 0)
{
if (sArgs[startidx] != CHAT_SYMBOL) // sm_say alias
{
if (!CheckCommandAccess(client, "sm_say", ADMFLAG_CHAT))
{
return Plugin_Continue;
}
SendChatToAll(client, sArgs[startidx]);
LogAction(client, -1, "\"%L\" triggered sm_say (text %s)", client, sArgs[startidx]);
return Plugin_Stop;
}
startidx++;
if (sArgs[startidx] != CHAT_SYMBOL) // sm_psay alias
{
if (!CheckCommandAccess(client, "sm_psay", ADMFLAG_CHAT))
{
return Plugin_Continue;
}
char arg[64];
int len = BreakString(sArgs[startidx], arg, sizeof(arg));
int target = FindTarget(client, arg, true, false);
if (target == -1 || len == -1)
return Plugin_Stop;
SendPrivateChat(client, target, sArgs[startidx+len]);
return Plugin_Stop;
}
startidx++;
// sm_csay alias
if (!CheckCommandAccess(client, "sm_csay", ADMFLAG_CHAT))
if (!CheckCommandAccess(client, "sm_psay_chat", ADMFLAG_CHAT))
{
return Plugin_Continue;
}
DisplayCenterTextToAll(client, sArgs[startidx]);
LogAction(client, -1, "\"%L\" triggered sm_csay (text %s)", client, sArgs[startidx]);
char arg[64];
int len = BreakString(sArgs[startidx], arg, sizeof(arg));
int target = FindTarget(client, arg, true, false);
if (target == -1 || len == -1)
return Plugin_Stop;
SendPrivateChat(client, target, sArgs[startidx+len]);
return Plugin_Stop;
}

View File

@ -186,52 +186,53 @@ public int MenuHandler_GagTypes(Menu menu, MenuAction action, int param1, int pa
{
case CommType_Mute:
{
PerformMute(param1, target);
PerformMute(target);
LogAction(param1, target, "\"%L\" muted \"%L\"", param1, target);
ShowActivity2(param1, "[SM] ", "%t", "Muted target", "_s", name);
}
case CommType_UnMute:
{
PerformUnMute(param1, target);
PerformUnMute(target);
LogAction(param1, target, "\"%L\" unmuted \"%L\"", param1, target);
ShowActivity2(param1, "[SM] ", "%t", "Unmuted target", "_s", name);
}
case CommType_Gag:
{
PerformGag(param1, target);
PerformGag(target);
LogAction(param1, target, "\"%L\" gagged \"%L\"", param1, target);
ShowActivity2(param1, "[SM] ", "%t", "Gagged target", "_s", name);
}
case CommType_UnGag:
{
PerformUnGag(param1, target);
PerformUnGag(target);
LogAction(param1, target, "\"%L\" ungagged \"%L\"", param1, target);
ShowActivity2(param1, "[SM] ", "%t", "Ungagged target", "_s", name);
}
case CommType_Silence:
{
PerformSilence(param1, target);
PerformSilence(target);
LogAction(param1, target, "\"%L\" silenced \"%L\"", param1, target);
ShowActivity2(param1, "[SM] ", "%t", "Silenced target", "_s", name);
}
case CommType_UnSilence:
{
PerformUnSilence(param1, target);
PerformUnSilence(target);
LogAction(param1, target, "\"%L\" unsilenced \"%L\"", param1, target);
ShowActivity2(param1, "[SM] ", "%t", "Unsilenced target", "_s", name);
}
}
}
}
void PerformMute(int client, int target, bool silent=false)
void PerformMute(int target)
{
playerstate[target].isMuted = true;
SetClientListeningFlags(target, VOICE_MUTED);
FireOnClientMute(target, true);
if (!silent)
{
LogAction(client, target, "\"%L\" muted \"%L\"", client, target);
}
}
void PerformUnMute(int client, int target, bool silent=false)
void PerformUnMute(int target)
{
playerstate[target].isMuted = false;
if (g_Cvar_Deadtalk.IntValue == 1 && !IsPlayerAlive(target))
@ -248,36 +249,21 @@ void PerformUnMute(int client, int target, bool silent=false)
}
FireOnClientMute(target, false);
if (!silent)
{
LogAction(client, target, "\"%L\" unmuted \"%L\"", client, target);
}
}
void PerformGag(int client, int target, bool silent=false)
void PerformGag(int target)
{
playerstate[target].isGagged = true;
FireOnClientGag(target, true);
if (!silent)
{
LogAction(client, target, "\"%L\" gagged \"%L\"", client, target);
}
}
void PerformUnGag(int client, int target, bool silent=false)
void PerformUnGag(int target)
{
playerstate[target].isGagged = false;
FireOnClientGag(target, false);
if (!silent)
{
LogAction(client, target, "\"%L\" ungagged \"%L\"", client, target);
}
}
void PerformSilence(int client, int target)
void PerformSilence(int target)
{
if (!playerstate[target].isGagged)
{
@ -291,11 +277,9 @@ void PerformSilence(int client, int target)
SetClientListeningFlags(target, VOICE_MUTED);
FireOnClientMute(target, true);
}
LogAction(client, target, "\"%L\" silenced \"%L\"", client, target);
}
void PerformUnSilence(int client, int target)
void PerformUnSilence(int target)
{
if (playerstate[target].isGagged)
{
@ -321,8 +305,6 @@ void PerformUnSilence(int client, int target)
}
FireOnClientMute(target, false);
}
LogAction(client, target, "\"%L\" unsilenced \"%L\"", client, target);
}
public Action Command_Mute(int client, int args)
@ -358,16 +340,18 @@ public Action Command_Mute(int client, int args)
{
int target = target_list[i];
PerformMute(client, target);
PerformMute(target);
}
if (tn_is_ml)
{
ShowActivity2(client, "[SM] ", "%t", "Muted target", target_name);
LogAction(client, -1, "\"%L\" muted \"%s\"", client, target_name);
}
else
{
ShowActivity2(client, "[SM] ", "%t", "Muted target", "_s", target_name);
LogAction(client, target_list[0], "\"%L\" muted \"%L\"", client, target_list[0]);
}
return Plugin_Handled;
@ -406,16 +390,18 @@ public Action Command_Gag(int client, int args)
{
int target = target_list[i];
PerformGag(client, target);
PerformGag(target);
}
if (tn_is_ml)
{
ShowActivity2(client, "[SM] ", "%t", "Gagged target", target_name);
LogAction(client, -1, "\"%L\" gagged \"%s\"", client, target_name);
}
else
{
ShowActivity2(client, "[SM] ", "%t", "Gagged target", "_s", target_name);
LogAction(client, target_list[0], "\"%L\" gagged \"%L\"", client, target_list[0]);
}
return Plugin_Handled;
@ -454,16 +440,18 @@ public Action Command_Silence(int client, int args)
{
int target = target_list[i];
PerformSilence(client, target);
PerformSilence(target);
}
if (tn_is_ml)
{
ShowActivity2(client, "[SM] ", "%t", "Silenced target", target_name);
LogAction(client, -1, "\"%L\" silenced \"%s\"", client, target_name);
}
else
{
ShowActivity2(client, "[SM] ", "%t", "Silenced target", "_s", target_name);
LogAction(client, target_list[0], "\"%L\" silenced \"%L\"", client, target_list[0]);
}
return Plugin_Handled;
@ -507,9 +495,11 @@ public Action Command_Unmute(int client, int args)
continue;
}
PerformUnMute(client, target);
PerformUnMute(target);
}
LogAction(client, -1, "\"%L\" unmuted \"%s\"", client, target_name);
if (tn_is_ml)
{
ShowActivity2(client, "[SM] ", "%t", "Unmuted target", target_name);
@ -555,16 +545,18 @@ public Action Command_Ungag(int client, int args)
{
int target = target_list[i];
PerformUnGag(client, target);
PerformUnGag(target);
}
if (tn_is_ml)
{
ShowActivity2(client, "[SM] ", "%t", "Ungagged target", target_name);
LogAction(client, -1, "\"%L\" ungagged \"%s\"", client, target_name);
}
else
{
ShowActivity2(client, "[SM] ", "%t", "Ungagged target", "_s", target_name);
LogAction(client, target_list[0], "\"%L\" ungagged \"%L\"", client, target_list[0]);
}
return Plugin_Handled;
@ -603,16 +595,18 @@ public Action Command_Unsilence(int client, int args)
{
int target = target_list[i];
PerformUnSilence(client, target);
PerformUnSilence(target);
}
if (tn_is_ml)
{
ShowActivity2(client, "[SM] ", "%t", "Unsilenced target", target_name);
LogAction(client, -1, "\"%L\" unsilenced \"%s\"", client, target_name);
}
else
{
ShowActivity2(client, "[SM] ", "%t", "Unsilenced target", "_s", target_name);
LogAction(client, target_list[0], "\"%L\" unsilenced \"%L\"", client, target_list[0]);
}
return Plugin_Handled;

View File

@ -85,7 +85,7 @@ public int Native_SetClientGag(Handle hPlugin, int numParams)
return false;
}
PerformGag(-1, client, true);
PerformGag(client);
}
else
{
@ -94,7 +94,7 @@ public int Native_SetClientGag(Handle hPlugin, int numParams)
return false;
}
PerformUnGag(-1, client, true);
PerformUnGag(client);
}
return true;
@ -122,7 +122,7 @@ public int Native_SetClientMute(Handle hPlugin, int numParams)
return false;
}
PerformMute(-1, client, true);
PerformMute(client);
}
else
{
@ -131,7 +131,7 @@ public int Native_SetClientMute(Handle hPlugin, int numParams)
return false;
}
PerformUnMute(-1, client, true);
PerformUnMute(client);
}
return true;

View File

@ -31,10 +31,8 @@
* Version: $Id$
*/
void PerformKick(int client, int target, const char[] reason)
void PerformKick(int target, const char[] reason)
{
LogAction(client, target, "\"%L\" kicked \"%L\" (reason \"%s\")", client, target, reason);
if (reason[0] == '\0')
{
KickClient(target, "%t", "Kicked by admin");
@ -110,7 +108,8 @@ public int MenuHandler_Kick(Menu menu, MenuAction action, int param1, int param2
char name[MAX_NAME_LENGTH];
GetClientName(target, name, sizeof(name));
ShowActivity2(param1, "[SM] ", "%t", "Kicked target", "_s", name);
PerformKick(param1, target, "");
PerformKick(target, "");
LogAction(param1, target, "\"%L\" kicked \"%L\"", param1, target);
}
/* Re-draw the menu if they're still valid */
@ -201,13 +200,22 @@ public Action Command_Kick(int client, int args)
}
else
{
PerformKick(client, target_list[i], reason);
PerformKick(target_list[i], reason);
}
}
if (kick_self)
{
PerformKick(client, client, reason);
PerformKick(client, reason);
}
if (tn_is_ml)
{
LogAction(client, -1, "\"%L\" kicked \"%s\" (reason \"%s\")", client, target_name, reason);
}
else
{
LogAction(client, target_list[0], "\"%L\" kicked \"%L\" (reason \"%s\")", client, target_list[0], reason);
}
}
else

View File

@ -45,6 +45,11 @@ public int MenuHandler_ChangeMap(Menu menu, MenuAction action, int param1, int p
char map[PLATFORM_MAX_PATH];
menu.GetItem(param2, map, sizeof(map));
if (!map[0])
{
GetCurrentMap(map, sizeof(map));
}
ShowActivity2(param1, "[SM] ", "%t", "Changing map", map);
@ -156,11 +161,15 @@ int LoadMapList(Menu menu)
char map_name[PLATFORM_MAX_PATH];
int map_count = GetArraySize(g_map_array);
menu.AddItem("", "Restart Current Map");
for (int i = 0; i < map_count; i++)
{
char displayName[PLATFORM_MAX_PATH];
GetArrayString(g_map_array, i, map_name, sizeof(map_name));
menu.AddItem(map_name, map_name);
GetMapDisplayName(map_name, displayName, sizeof(displayName));
menu.AddItem(map_name, displayName);
}
return map_count;

View File

@ -59,18 +59,12 @@ void KillAllBeacons()
}
}
void PerformBeacon(int client, int target)
void PerformBeacon(int target)
{
if (g_BeaconSerial[target] == 0)
{
CreateBeacon(target);
LogAction(client, target, "\"%L\" set a beacon on \"%L\"", client, target);
}
else
{
KillBeacon(target);
LogAction(client, target, "\"%L\" removed a beacon on \"%L\"", client, target);
}
}
public Action Timer_Beacon(Handle timer, any value)
@ -187,8 +181,9 @@ public int MenuHandler_Beacon(Menu menu, MenuAction action, int param1, int para
char name[MAX_NAME_LENGTH];
GetClientName(target, name, sizeof(name));
PerformBeacon(param1, target);
PerformBeacon(target);
ShowActivity2(param1, "[SM] ", "%t", "Toggled beacon on target", "_s", name);
LogAction(param1, target, "\"%L\" toggled beacon on \"%L\"", param1, target);
}
/* Re-draw the menu if they're still valid */
@ -230,16 +225,18 @@ public Action Command_Beacon(int client, int args)
for (int i = 0; i < target_count; i++)
{
PerformBeacon(client, target_list[i]);
PerformBeacon(target_list[i]);
}
if (tn_is_ml)
{
ShowActivity2(client, "[SM] ", "%t", "Toggled beacon on target", target_name);
LogAction(client, -1, "\"%L\" toggled beacon on \"%s\"", client, target_name);
}
else
{
ShowActivity2(client, "[SM] ", "%t", "Toggled beacon on target", "_s", target_name);
LogAction(client, target_list[0], "\"%L\" toggled beacon on \"%L\"", client, target_list[0]);
}
return Plugin_Handled;

View File

@ -33,7 +33,7 @@
int g_BlindTarget[MAXPLAYERS+1];
void PerformBlind(int client, int target, int amount)
void PerformBlind(int target, int amount)
{
int targets[2];
targets[0] = target;
@ -75,8 +75,6 @@ void PerformBlind(int client, int target, int amount)
}
EndMessage();
LogAction(client, target, "\"%L\" set blind on \"%L\" (amount \"%d\")", client, target, amount);
}
public void AdminMenu_Blind(TopMenu topmenu,
@ -211,7 +209,8 @@ public int MenuHandler_Amount(Menu menu, MenuAction action, int param1, int para
char name[MAX_NAME_LENGTH];
GetClientName(target, name, sizeof(name));
PerformBlind(param1, target, amount);
PerformBlind(target, amount);
LogAction(param1, target, "\"%L\" set blind on \"%L\", amount %d.", param1, target, amount);
ShowActivity2(param1, "[SM] ", "%t", "Set blind on target", "_s", name, amount);
}
@ -276,16 +275,18 @@ public Action Command_Blind(int client, int args)
for (int i = 0; i < target_count; i++)
{
PerformBlind(client, target_list[i], amount);
PerformBlind(target_list[i], amount);
}
if (tn_is_ml)
{
ShowActivity2(client, "[SM] ", "%t", "Set blind on target", target_name);
LogAction(client, -1, "\"%L\" set blind on \"%s\", amount %d.", client, target_name, amount);
}
else
{
ShowActivity2(client, "[SM] ", "%t", "Set blind on target", "_s", target_name);
LogAction(client, target_list[0], "\"%L\" set blind on \"%L\", amount %d.", client, target_list[0], amount);
}
return Plugin_Handled;

View File

@ -106,7 +106,7 @@ void KillAllDrugs()
}
}
void PerformDrug(int client, int target, int toggle)
void PerformDrug(int target, int toggle)
{
switch (toggle)
{
@ -115,12 +115,10 @@ void PerformDrug(int client, int target, int toggle)
if (g_DrugTimers[target] == null)
{
CreateDrug(target);
LogAction(client, target, "\"%L\" drugged \"%L\"", client, target);
}
else
{
KillDrug(target);
LogAction(client, target, "\"%L\" undrugged \"%L\"", client, target);
}
}
@ -129,7 +127,6 @@ void PerformDrug(int client, int target, int toggle)
if (g_DrugTimers[target] == null)
{
CreateDrug(target);
LogAction(client, target, "\"%L\" drugged \"%L\"", client, target);
}
}
@ -138,7 +135,6 @@ void PerformDrug(int client, int target, int toggle)
if (g_DrugTimers[target] != null)
{
KillDrug(target);
LogAction(client, target, "\"%L\" undrugged \"%L\"", client, target);
}
}
}
@ -268,7 +264,8 @@ public int MenuHandler_Drug(Menu menu, MenuAction action, int param1, int param2
char name[MAX_NAME_LENGTH];
GetClientName(target, name, sizeof(name));
PerformDrug(param1, target, 2);
PerformDrug(target, 2);
LogAction(param1, target, "\"%L\" toggled drugs on \"%L\"", param1, target);
ShowActivity2(param1, "[SM] ", "%t", "Toggled drug on target", "_s", name);
}
@ -326,16 +323,18 @@ public Action Command_Drug(int client, int args)
for (int i = 0; i < target_count; i++)
{
PerformDrug(client, target_list[i], toggle);
PerformDrug(target_list[i], toggle);
}
if (tn_is_ml)
{
ShowActivity2(client, "[SM] ", "%t", "Toggled drug on target", target_name);
LogAction(client, -1, "\"%L\" toggled drugs on \"%s\"", client, target_name);
}
else
{
ShowActivity2(client, "[SM] ", "%t", "Toggled drug on target", "_s", target_name);
LogAction(client, target_list[0], "\"%L\" toggled drugs on \"%L\"", client, target_list[0]);
}
return Plugin_Handled;

View File

@ -64,24 +64,16 @@ void KillAllFireBombs()
}
}
void PerformBurn(int client, int target, float seconds)
{
IgniteEntity(target, seconds);
LogAction(client, target, "\"%L\" ignited \"%L\" (seconds \"%f\")", client, target, seconds);
}
void PerformFireBomb(int client, int target)
{
if (g_FireBombSerial[client] == 0)
{
CreateFireBomb(target);
LogAction(client, target, "\"%L\" set a FireBomb on \"%L\"", client, target);
}
else
{
KillFireBomb(target);
SetEntityRenderColor(client, 255, 255, 255, 255);
LogAction(client, target, "\"%L\" removed a FireBomb on \"%L\"", client, target);
}
}
@ -306,7 +298,8 @@ public int MenuHandler_Burn(Menu menu, MenuAction action, int param1, int param2
{
char name[MAX_NAME_LENGTH];
GetClientName(target, name, sizeof(name));
PerformBurn(param1, target, 20.0);
IgniteEntity(target, 20.0);
LogAction(param1, target, "\"%L\" ignited \"%L\" (seconds \"20\")", param1, target);
ShowActivity2(param1, "[SM] ", "%t", "Set target on fire", "_s", name);
}
@ -353,6 +346,7 @@ public int MenuHandler_FireBomb(Menu menu, MenuAction action, int param1, int pa
GetClientName(target, name, sizeof(name));
PerformFireBomb(param1, target);
LogAction(param1, target, "\"%L\" toggled FireBomb on \"%L\"", param1, target);
ShowActivity2(param1, "[SM] ", "%t", "Toggled FireBomb on target", "_s", name);
}
@ -408,16 +402,18 @@ public Action Command_Burn(int client, int args)
for (int i = 0; i < target_count; i++)
{
PerformBurn(client, target_list[i], seconds);
IgniteEntity(target_list[i], seconds);
}
if (tn_is_ml)
{
ShowActivity2(client, "[SM] ", "%t", "Set target on fire", target_name);
LogAction(client, -1, "\"%L\" ignited \"%s\" (seconds \"%f\")", client, target_name, seconds);
}
else
{
ShowActivity2(client, "[SM] ", "%t", "Set target on fire", "_s", target_name);
LogAction(client, target_list[0], "\"%L\" ignited \"%L\" (seconds \"%f\")", client, target_list[0], seconds);
}
return Plugin_Handled;
@ -460,10 +456,12 @@ public Action Command_FireBomb(int client, int args)
if (tn_is_ml)
{
ShowActivity2(client, "[SM] ", "%t", "Toggled FireBomb on target", target_name);
LogAction(client, -1, "\"%L\" toggled FireBomb on \"%s\"", client, target_name);
}
else
{
ShowActivity2(client, "[SM] ", "%t", "Toggled FireBomb on target", "_s", target_name);
LogAction(client, target_list[0], "\"%L\" toggled FireBomb on \"%L\"", client, target_list[0]);
}
return Plugin_Handled;
}

View File

@ -33,12 +33,6 @@
int g_GravityTarget[MAXPLAYERS+1];
void PerformGravity(int client, int target, float amount)
{
SetEntityGravity(target, amount);
LogAction(client, target, "\"%L\" set gravity on \"%L\" (amount \"%f\")", client, target, amount);
}
public void AdminMenu_Gravity(TopMenu topmenu,
TopMenuAction action,
TopMenuObject object_id,
@ -169,7 +163,8 @@ public int MenuHandler_GravityAmount(Menu menu, MenuAction action, int param1, i
char name[MAX_NAME_LENGTH];
GetClientName(target, name, sizeof(name));
PerformGravity(param1, target, amount);
SetEntityGravity(target, amount);
LogAction(param1, target, "\"%L\" set gravity on \"%L\" to %f.", param1, target, amount);
ShowActivity2(param1, "[SM] ", "%t", "Set gravity on target", "_s", name, amount);
}
@ -229,16 +224,18 @@ public Action Command_Gravity(int client, int args)
for (int i = 0; i < target_count; i++)
{
PerformGravity(client, target_list[i], amount);
SetEntityGravity(target_list[i], amount);
}
if (tn_is_ml)
{
ShowActivity2(client, "[SM] ", "%t", "Set gravity on target", target_name);
LogAction(client, -1, "\"%L\" set gravity on \"%s\" to %f.", client, target_name, amount);
}
else
{
ShowActivity2(client, "[SM] ", "%t", "Set gravity on target", "_s", target_name);
LogAction(client, target_list[0], "\"%L\" set gravity on \"%L\" to %f.", client, target_list[0], amount);
}
return Plugin_Handled;

View File

@ -125,24 +125,12 @@ void KillAllFreezes()
}
}
void PerformFreeze(int client, int target, int time)
{
FreezeClient(target, time);
LogAction(client, target, "\"%L\" froze \"%L\"", client, target);
}
void PerformFreezeBomb(int client, int target)
void PerformFreezeBomb(int target)
{
if (g_FreezeBombSerial[target] != 0)
{
KillFreezeBomb(target);
LogAction(client, target, "\"%L\" removed a FreezeBomb on \"%L\"", client, target);
}
else
{
CreateFreezeBomb(target);
LogAction(client, target, "\"%L\" set a FreezeBomb on \"%L\"", client, target);
}
}
public Action Timer_Freeze(Handle timer, any value)
@ -421,7 +409,8 @@ public int MenuHandler_Freeze(Menu menu, MenuAction action, int param1, int para
char name[MAX_NAME_LENGTH];
GetClientName(target, name, sizeof(name));
PerformFreeze(param1, target, g_Cvar_FreezeDuration.IntValue);
FreezeClient(target, g_Cvar_FreezeDuration.IntValue);
LogAction(param1, target, "\"%L\" froze \"%L\"", param1, target);
ShowActivity2(param1, "[SM] ", "%t", "Froze target", "_s", name);
}
@ -467,7 +456,8 @@ public int MenuHandler_FreezeBomb(Menu menu, MenuAction action, int param1, int
char name[MAX_NAME_LENGTH];
GetClientName(target, name, sizeof(name));
PerformFreezeBomb(param1, target);
PerformFreezeBomb(target);
LogAction(param1, target, "\"%L\" toggled FreezeBomb on \"%L\"", param1, target);
ShowActivity2(param1, "[SM] ", "%t", "Toggled FreezeBomb on target", "_s", name);
}
@ -523,16 +513,18 @@ public Action Command_Freeze(int client, int args)
for (int i = 0; i < target_count; i++)
{
PerformFreeze(client, target_list[i], seconds);
FreezeClient(target_list[i], seconds);
}
if (tn_is_ml)
{
ShowActivity2(client, "[SM] ", "%t", "Froze target", target_name);
LogAction(client, -1, "\"%L\" froze \"%s\"", client, target_name);
}
else
{
ShowActivity2(client, "[SM] ", "%t", "Froze target", "_s", target_name);
LogAction(client, target_list[0], "\"%L\" froze \"%L\"", client, target_list[0]);
}
return Plugin_Handled;
@ -569,16 +561,18 @@ public Action Command_FreezeBomb(int client, int args)
for (int i = 0; i < target_count; i++)
{
PerformFreezeBomb(client, target_list[i]);
PerformFreezeBomb(target_list[i]);
}
if (tn_is_ml)
{
ShowActivity2(client, "[SM] ", "%t", "Toggled FreezeBomb on target", target_name);
LogAction(client, -1, "\"%L\" toggled FreezeBomb on \"%s\"", client, target_name);
}
else
{
ShowActivity2(client, "[SM] ", "%t", "Toggled FreezeBomb on target", "_s", target_name);
LogAction(client, target_list[0], "\"%L\" toggled FreezeBomb on \"%L\"", client, target_list[0]);
}
return Plugin_Handled;

View File

@ -31,7 +31,7 @@
* Version: $Id$
*/
void PerformNoClip(int client, int target)
void PerformNoClip(int target)
{
MoveType movetype = GetEntityMoveType(target);
@ -43,8 +43,6 @@ void PerformNoClip(int client, int target)
{
SetEntityMoveType(target, MOVETYPE_WALK);
}
LogAction(client, target, "\"%L\" toggled noclip on \"%L\"", client, target);
}
public void AdminMenu_NoClip(TopMenu topmenu,
@ -112,7 +110,8 @@ public int MenuHandler_NoClip(Menu menu, MenuAction action, int param1, int para
char name[MAX_NAME_LENGTH];
GetClientName(target, name, sizeof(name));
PerformNoClip(param1, target);
PerformNoClip(target);
LogAction(param1, target, "\"%L\" toggled noclip on \"%L\"", param1, target);
ShowActivity2(param1, "[SM] ", "%t", "Toggled noclip on target", "_s", name);
}
@ -155,16 +154,18 @@ public Action Command_NoClip(int client, int args)
for (int i = 0; i < target_count; i++)
{
PerformNoClip(client, target_list[i]);
PerformNoClip(target_list[i]);
}
if (tn_is_ml)
{
ShowActivity2(client, "[SM] ", "%t", "Toggled noclip on target", target_name);
LogAction(client, -1, "\"%L\" toggled noclip on \"%s\"", client, target_name);
}
else
{
ShowActivity2(client, "[SM] ", "%t", "Toggled noclip on target", "_s", target_name);
LogAction(client, target_list[0], "\"%L\" toggled noclip on \"%L\"", client, target_list[0]);
}
return Plugin_Handled;

View File

@ -68,13 +68,11 @@ void PerformTimeBomb(int client, int target)
if (g_TimeBombSerial[target] == 0)
{
CreateTimeBomb(target);
LogAction(client, target, "\"%L\" set a TimeBomb on \"%L\"", client, target);
}
else
{
KillTimeBomb(target);
SetEntityRenderColor(client, 255, 255, 255, 255);
LogAction(client, target, "\"%L\" removed a TimeBomb on \"%L\"", client, target);
}
}
@ -279,6 +277,7 @@ public int MenuHandler_TimeBomb(Menu menu, MenuAction action, int param1, int pa
GetClientName(target, name, sizeof(name));
PerformTimeBomb(param1, target);
LogAction(param1, target, "\"%L\" toggled TimeBomb on \"%L\"", param1, target);
ShowActivity2(param1, "[SM] ", "%t", "Toggled TimeBomb on target", "_s", name);
}
@ -327,10 +326,12 @@ public Action Command_TimeBomb(int client, int args)
if (tn_is_ml)
{
ShowActivity2(client, "[SM] ", "%t", "Toggled TimeBomb on target", target_name);
LogAction(client, -1, "\"%L\" toggled TimeBomb on \"%s\"", client, target_name);
}
else
{
ShowActivity2(client, "[SM] ", "%t", "Toggled TimeBomb on target", "_s", target_name);
LogAction(client, target_list[0], "\"%L\" toggled TimeBomb on \"%L\"", client, target_list[0]);
}
return Plugin_Handled;

View File

@ -0,0 +1,24 @@
#if defined _DynamicTargeting_Included
#endinput
#endif
#define _DynamicTargeting_Included
native int AmbiguousMenu(int client, char[] sCommand, char[] sArgString, char[] sPattern, int FilterFlags);
public SharedPlugin __pl_DynamicTargeting =
{
name = "DynamicTargeting",
file = "DynamicTargeting.smx",
#if defined REQUIRE_PLUGIN
required = 1,
#else
required = 0,
#endif
};
#if !defined REQUIRE_PLUGIN
public __pl_DynamicTargeting_SetNTVOptional()
{
MarkNativeAsOptional("AmbiguousMenu");
}
#endif

View File

@ -741,6 +741,15 @@ native float GetClientAvgData(int client, NetFlow flow);
*/
native float GetClientAvgPackets(int client, NetFlow flow);
/**
* Returns the client's baseserver IClient pointer.
*
* @param client Player's index.
* @return IClient address.
* @error Invalid client index, client not connected, or fake client.
*/
native Address GetClientIClient(int client);
/**
* Translates an userid index to the real player index.
*

View File

@ -84,6 +84,25 @@ native int ProcessTargetString(const char[] pattern,
int tn_maxlength,
bool &tn_is_ml);
/**
* Retrieves arguments that were passed to the last ProcessTargetString call.
*
* @param pattern Buffer to store the pattern.
* @param p_maxlen Maximum length of the pattern buffer.
* @param admin OUTPUT: Admin performing the action, or 0 if the server.
* @param filter_flags OUTPUT: Filter flags.
* @noreturn
*/
native void GetLastProcessTargetString(char[] pattern,
int p_maxlen,
int &admin,
int &filter_flags);
#undef REQUIRE_PLUGIN
#include <DynamicTargeting>
#define REQUIRE_PLUGIN
/**
* Replies to a client with a given message describing a targetting
* failure reason.
@ -93,7 +112,7 @@ native int ProcessTargetString(const char[] pattern,
* @param client Client index, or 0 for server.
* @param reason COMMAND_TARGET reason.
*/
stock void ReplyToTargetError(int client, int reason)
stock void ReplyToTargetError(int client, int reason, bool dynamic=true)
{
switch (reason)
{
@ -128,20 +147,55 @@ stock void ReplyToTargetError(int client, int reason)
case COMMAND_TARGET_AMBIGUOUS:
{
ReplyToCommand(client, "[SM] %t", "More than one client matched");
if(dynamic &&
GetFeatureStatus(FeatureType_Native, "GetLastProcessTargetString") == FeatureStatus_Available &&
LibraryExists("DynamicTargeting"))
{
if(GetFeatureStatus(FeatureType_Native, "IsCommandCallback") == FeatureStatus_Available &&
!IsCommandCallback())
{
return;
}
char sCommand[128];
GetCmdArg(0, sCommand, sizeof(sCommand));
char sArgString[256];
GetCmdArgString(sArgString, sizeof(sArgString));
char pattern[MAX_TARGET_LENGTH];
int admin;
int filter_flags;
GetLastProcessTargetString(pattern, sizeof(pattern), admin, filter_flags);
if(!admin || !IsClientInGame(admin) || IsFakeClient(admin))
return;
AmbiguousMenu(admin, sCommand, sArgString, pattern, filter_flags);
}
}
}
}
#define FEATURECAP_MULTITARGETFILTER_CLIENTPARAM "SourceMod MultiTargetFilter ClientParam"
/**
* Adds clients to a multi-target filter.
*
* @param pattern Pattern name.
* @param clients Array to fill with unique, valid client indexes.
* @param client Client that triggered this filter.
* @return True if pattern was recognized, false otherwise.
*
* @note To see if the client param is available, use FeatureType_Capability and FEATURECAP_MULTITARGETFILTER_CLIENTPARAM.
*/
typeset MultiTargetFilter {
function bool (const char[] pattern, Handle clients);
function bool (const char[] pattern, ArrayList clients);
function bool (const char[] pattern, Handle clients, int client);
function bool (const char[] pattern, ArrayList clients, int client);
}
/**

View File

@ -402,7 +402,14 @@ native void RegAdminCmd(const char[] cmd,
const char[] description="",
const char[] group="",
int flags=0);
/**
* Returns whether there is a command callback available.
*
* @return True if called from inside a command callback.
*/
native bool IsCommandCallback();
/**
* Returns the number of arguments from the current console or server command.
* @note Unlike the HL2 engine call, this does not include the command itself.

View File

@ -311,6 +311,9 @@ public void __ext_core_SetNTVOptional()
MarkNativeAsOptional("Protobuf.ReadRepeatedMessage");
MarkNativeAsOptional("Protobuf.AddMessage");
MarkNativeAsOptional("IsCommandCallback");
MarkNativeAsOptional("GetLastProcessTargetString");
VerifyCoreVersion();
}

View File

@ -293,6 +293,17 @@ native void Call_StartForward(Handle fwd);
*/
native void Call_StartFunction(Handle plugin, Function func);
/**
* Starts a call to a native.
*
* @note Cannot be used during an incomplete call.
*
* @param name Name of the native.
* @return True on success, false otherwise.
* @error Invalid function, or called before another call has completed.
*/
native bool Call_StartNative(const char[] name);
/**
* Pushes a cell onto the current call.
*
@ -416,6 +427,20 @@ native void Call_PushNullString();
*/
native int Call_Finish(any &result=0);
/**
* Completes a call to a function or forward's call list.
* Catches exceptions thrown by the native.
*
* @note Cannot be used before a call has been started.
*
* @param result Return value of function or forward's call list.
* @param exception Buffer to store the exception in.
* @param maxlength Maximum length of the buffer.
* @return SP_ERROR_NONE on success, any other integer on failure.
* @error Called before a call has been started.
*/
native int Call_FinishEx(any &result=0, char[] exception, int maxlength);
/**
* Cancels a call to a function or forward's call list.
*

View File

@ -307,9 +307,23 @@ methodmap Menu < Handle
// @param style By-reference variable to store drawing flags.
// @param dispBuf Display buffer.
// @param dispBufLen Maximum length of the display buffer.
// @param client Client index. Must be specified if menu is per-client random shuffled, -1 to ignore.
// @return True on success, false if position is invalid.
public native bool GetItem(int position, char[] infoBuf, int infoBufLen,
int &style=0, char[] dispBuf="", int dispBufLen=0);
int &style=0, char[] dispBuf="", int dispBufLen=0, int client=0);
// Generates a per-client random mapping for the current vote options.
//
// @param start Menu item index to start randomizing from.
// @param stop Menu item index to stop randomizing at. -1 = infinite
public native void ShufflePerClient(int start=0, int stop=-1);
// Fills the client vote option mapping with user supplied values.
//
// @param client Client index.
// @param array Integer array with mapping.
// @param length Length of array.
public native void SetClientMapping(int client, int[] array, int length);
// Sets the menu's default title/instruction message.
//
@ -537,6 +551,7 @@ native void RemoveAllMenuItems(Handle menu);
* @param style By-reference variable to store drawing flags.
* @param dispBuf Display buffer.
* @param dispBufLen Maximum length of the display buffer.
* @param client Client index. Must be specified if menu is per-client random shuffled, -1 to ignore.
* @return True on success, false if position is invalid.
* @error Invalid Handle.
*/
@ -546,7 +561,27 @@ native bool GetMenuItem(Handle menu,
int infoBufLen,
int &style=0,
char[] dispBuf="",
int dispBufLen=0);
int dispBufLen=0,
int client=0);
/**
* Generates a per-client random mapping for the current vote options.
*
* @param menu Menu Handle.
* @param start Menu item index to start randomizing from.
* @param stop Menu item index to stop randomizing at. -1 = infinite
*/
native void MenuShufflePerClient(Handle menu, int start=0, int stop=-1);
/*
* Fills the client vote option mapping with user supplied values.
*
* @param menu Menu Handle.
* @param client Client index.
* @param array Integer array with mapping.
* @param length Length of array.
*/
native void MenuSetClientMapping(Handle menu, int client, int[] array, int length);
/**
* Returns the first item on the page of a currently selected menu.

View File

@ -333,6 +333,14 @@ typeset SDKHookCB
*/
forward void OnEntityCreated(int entity, const char[] classname);
/**
* When an entity is spawned
*
* @param entity Entity index
* @param classname Class name
*/
forward void OnEntitySpawned(int entity, const char[] classname);
/**
* When an entity is destroyed
*
@ -400,10 +408,11 @@ native void SDKUnhook(int entity, SDKHookType type, SDKHookCB callback);
* @param weapon Weapon index (orangebox and later) or -1 for unspecified
* @param damageForce Velocity of damage force
* @param damagePosition Origin of damage
* @param damageCustom User custom
*/
native void SDKHooks_TakeDamage(int entity, int inflictor, int attacker,
float damage, int damageType=DMG_GENERIC, int weapon=-1,
const float damageForce[3]=NULL_VECTOR, const float damagePosition[3]=NULL_VECTOR);
const float damageForce[3]=NULL_VECTOR, const float damagePosition[3]=NULL_VECTOR, int damageCustom=0);
/**
* Forces a client to drop the specified weapon

View File

@ -633,6 +633,18 @@ native bool TR_DidHit(Handle hndl=INVALID_HANDLE);
*/
native int TR_GetHitGroup(Handle hndl=INVALID_HANDLE);
/**
* Returns in which hitbox the trace collided if any.
*
* Note: if the entity that collided with the trace is the world entity,
* then this function doesn't return an hitbox index but a static prop index.
*
* @param hndl A trace Handle, or INVALID_HANDLE to use a global trace result.
* @return Hitbox index (Or static prop index).
* @error Invalid Handle.
*/
native int TR_GetHitBoxIndex(Handle hndl=INVALID_HANDLE);
/**
* Find the normal vector to the collision plane of a trace.
*

View File

@ -47,6 +47,92 @@ struct Plugin
public const char[] url; /**< Plugin URL */
};
/**
* Returns whether a library exists. This function should be considered
* expensive; it should only be called on plugin to determine availability
* of resources. Use OnLibraryAdded()/OnLibraryRemoved() to detect changes
* in optional resources.
*
* @param name Library name of a plugin or extension.
* @return True if exists, false otherwise.
*/
native bool LibraryExists(const char[] name);
/**
* Feature types.
*/
enum FeatureType
{
/**
* A native function call.
*/
FeatureType_Native,
/**
* A named capability. This is distinctly different from checking for a
* native, because the underlying functionality could be enabled on-demand
* to improve loading time. Thus a native may appear to exist, but it might
* be part of a set of features that are not compatible with the current game
* or version of SourceMod.
*/
FeatureType_Capability
};
/**
* Feature statuses.
*/
enum FeatureStatus
{
/**
* Feature is available for use.
*/
FeatureStatus_Available,
/**
* Feature is not available.
*/
FeatureStatus_Unavailable,
/**
* Feature is not known at all.
*/
FeatureStatus_Unknown
};
/**
* Returns whether "GetFeatureStatus" will work. Using this native
* or this function will not cause SourceMod to fail loading on older versions,
* however, GetFeatureStatus will only work if this function returns true.
*
* @return True if GetFeatureStatus will work, false otherwise.
*/
stock bool CanTestFeatures()
{
return LibraryExists("__CanTestFeatures__");
}
/**
* Returns whether a feature exists, and if so, whether it is usable.
*
* @param type Feature type.
* @param name Feature name.
* @return Feature status.
*/
native FeatureStatus GetFeatureStatus(FeatureType type, const char[] name);
/**
* Requires that a given feature is available. If it is not, SetFailState()
* is called with the given message.
*
* @param type Feature type.
* @param name Feature name.
* @param fmt Message format string, or empty to use default.
* @param ... Message format parameters, if any.
*/
native void RequireFeature(FeatureType type, const char[] name,
const char[] fmt="", any ...);
#include <core>
#include <float>
#include <vector>
@ -448,17 +534,6 @@ native void AutoExecConfig(bool autoCreate=true, const char[] name="", const cha
*/
native void RegPluginLibrary(const char[] name);
/**
* Returns whether a library exists. This function should be considered
* expensive; it should only be called on plugin to determine availability
* of resources. Use OnLibraryAdded()/OnLibraryRemoved() to detect changes
* in optional resources.
*
* @param name Library name of a plugin or extension.
* @return True if exists, false otherwise.
*/
native bool LibraryExists(const char[] name);
/**
* Returns the status of an extension, by filename.
*
@ -582,80 +657,6 @@ forward bool OnClientFloodCheck(int client);
*/
forward void OnClientFloodResult(int client, bool blocked);
/**
* Feature types.
*/
enum FeatureType
{
/**
* A native function call.
*/
FeatureType_Native,
/**
* A named capability. This is distinctly different from checking for a
* native, because the underlying functionality could be enabled on-demand
* to improve loading time. Thus a native may appear to exist, but it might
* be part of a set of features that are not compatible with the current game
* or version of SourceMod.
*/
FeatureType_Capability
};
/**
* Feature statuses.
*/
enum FeatureStatus
{
/**
* Feature is available for use.
*/
FeatureStatus_Available,
/**
* Feature is not available.
*/
FeatureStatus_Unavailable,
/**
* Feature is not known at all.
*/
FeatureStatus_Unknown
};
/**
* Returns whether "GetFeatureStatus" will work. Using this native
* or this function will not cause SourceMod to fail loading on older versions,
* however, GetFeatureStatus will only work if this function returns true.
*
* @return True if GetFeatureStatus will work, false otherwise.
*/
stock bool CanTestFeatures()
{
return LibraryExists("__CanTestFeatures__");
}
/**
* Returns whether a feature exists, and if so, whether it is usable.
*
* @param type Feature type.
* @param name Feature name.
* @return Feature status.
*/
native FeatureStatus GetFeatureStatus(FeatureType type, const char[] name);
/**
* Requires that a given feature is available. If it is not, SetFailState()
* is called with the given message.
*
* @param type Feature type.
* @param name Feature name.
* @param fmt Message format string, or empty to use default.
* @param ... Message format parameters, if any.
*/
native void RequireFeature(FeatureType type, const char[] name,
const char[] fmt="", any ...);
/**
* Represents how many bytes we can read from an address with one load
*/

View File

@ -33,10 +33,8 @@
char g_NewName[MAXPLAYERS+1][MAX_NAME_LENGTH];
void PerformRename(int client, int target)
void PerformRename(int target)
{
LogAction(client, target, "\"%L\" renamed \"%L\" (to \"%s\")", client, target, g_NewName[target]);
SetClientName(target, g_NewName[target]);
g_NewName[target][0] = '\0';
@ -109,7 +107,8 @@ public int MenuHandler_Rename(Menu menu, MenuAction action, int param1, int para
RandomizeName(target);
ShowActivity2(param1, "[SM] ", "%t", "Renamed target", "_s", name);
PerformRename(param1, target);
LogAction(param1, target, "\"%L\" renamed \"%L\" to \"%s\")", param1, target, g_NewName[target]);
PerformRename(target);
}
DisplayRenameTargetMenu(param1);
}
@ -168,12 +167,14 @@ public Action Command_Rename(int client, int args)
if (tn_is_ml)
{
ShowActivity2(client, "[SM] ", "%t", "Renamed target", target_name);
LogAction(client, -1, "\"%L\" renamed \"%s\" to \"%s\")", client, target_name, arg2);
}
else
{
ShowActivity2(client, "[SM] ", "%t", "Renamed target", "_s", target_name);
LogAction(client, target_list[0], "\"%L\" renamed \"%L\" to \"%s\")", client, target_list[0], arg2);
}
for (int i = 0; i < target_count; i++)
{
if (randomize)
@ -191,7 +192,7 @@ public Action Command_Rename(int client, int args)
Format(g_NewName[target_list[i]], MAX_NAME_LENGTH, "%s", arg2);
}
}
PerformRename(client, target_list[i]);
PerformRename(target_list[i]);
}
}
else

View File

@ -33,12 +33,6 @@
int g_SlapDamage[MAXPLAYERS+1];
void PerformSlap(int client, int target, int damage)
{
LogAction(client, target, "\"%L\" slapped \"%L\" (damage \"%d\")", client, target, damage);
SlapPlayer(target, damage, true);
}
void DisplaySlapDamageMenu(int client)
{
Menu menu = new Menu(MenuHandler_SlapDamage);
@ -151,7 +145,8 @@ public int MenuHandler_Slap(Menu menu, MenuAction action, int param1, int param2
{
char name[MAX_NAME_LENGTH];
GetClientName(target, name, sizeof(name));
PerformSlap(param1, target, g_SlapDamage[param1]);
SlapPlayer(target, g_SlapDamage[param1]);
LogAction(param1, target, "\"%L\" slapped \"%L\" (damage \"%d\")", param1, target, g_SlapDamage[param1]);
ShowActivity2(param1, "[SM] ", "%t", "Slapped target", "_s", name);
}
@ -202,16 +197,18 @@ public Action Command_Slap(int client, int args)
for (int i = 0; i < target_count; i++)
{
PerformSlap(client, target_list[i], damage);
SlapPlayer(target_list[i], damage);
}
if (tn_is_ml)
{
ShowActivity2(client, "[SM] ", "%t", "Slapped target", target_name);
LogAction(client, -1, "\"%L\" slapped \"%s\" (damage \"%d\")", client, target_name, damage);
}
else
{
ShowActivity2(client, "[SM] ", "%t", "Slapped target", "_s", target_name);
LogAction(client, target_list[0], "\"%L\" slapped \"%L\" (damage \"%d\")", client, target_list[0], damage);
}
return Plugin_Handled;

View File

@ -31,12 +31,6 @@
* Version: $Id$
*/
void PerformSlay(int client, int target)
{
LogAction(client, target, "\"%L\" slayed \"%L\"", client, target);
ForcePlayerSuicide(target);
}
void DisplaySlayMenu(int client)
{
Menu menu = new Menu(MenuHandler_Slay);
@ -105,7 +99,8 @@ public int MenuHandler_Slay(Menu menu, MenuAction action, int param1, int param2
{
char name[MAX_NAME_LENGTH];
GetClientName(target, name, sizeof(name));
PerformSlay(param1, target);
ForcePlayerSuicide(target);
LogAction(param1, target, "\"%L\" slayed \"%L\"", param1, target);
ShowActivity2(param1, "[SM] ", "%t", "Slayed target", "_s", name);
}
@ -144,16 +139,18 @@ public Action Command_Slay(int client, int args)
for (int i = 0; i < target_count; i++)
{
PerformSlay(client, target_list[i]);
ForcePlayerSuicide(target_list[i]);
}
if (tn_is_ml)
{
ShowActivity2(client, "[SM] ", "%t", "Slayed target", target_name);
LogAction(client, -1, "\"%L\" slayed \"%s\"", client, target_name);
}
else
{
ShowActivity2(client, "[SM] ", "%t", "Slayed target", "_s", target_name);
LogAction(client, target_list[0], "\"%L\" slayed \"%L\"", client, target_list[0]);
}
return Plugin_Handled;

View File

@ -107,16 +107,17 @@ public Action Command_Play(int client, int args)
for (int i = 0; i < target_count; i++)
{
ClientCommand(target_list[i], "playgamesound \"%s\"", Arguments[len]);
LogAction(client, target_list[i], "\"%L\" played sound on \"%L\" (file \"%s\")", client, target_list[i], Arguments[len]);
}
if (tn_is_ml)
{
ShowActivity2(client, "[SM] ", "%t", "Played sound to target", target_name);
LogAction(client, -1, "\"%L\" played sound on \"%s\" (file \"%s\")", client, target_name, Arguments[len]);
}
else
{
ShowActivity2(client, "[SM] ", "%t", "Played sound to target", "_s", target_name);
LogAction(client, target_list[0], "\"%L\" played sound on \"%L\" (file \"%s\")", client, target_list[0], Arguments[len]);
}
return Plugin_Handled;

View File

@ -1 +1 @@
1.10.0
1.11.0

View File

@ -48,6 +48,11 @@
#define DETOUR_MEMBER_CALL(name) (this->*name##_Actual)
#define DETOUR_STATIC_CALL(name) (name##_Actual)
#define DETOUR_MEMBER_MCALL_CALLBACK(name, classptr) \
((name##Class *)classptr->*(&name##Class::name))
#define DETOUR_MEMBER_MCALL_ORIGINAL(name, classptr) \
((name##Class *)classptr->*(name##Class::name##_Actual))
#define DETOUR_DECL_STATIC0(name, ret) \
ret (*name##_Actual)(void) = NULL; \
ret name(void)
@ -84,6 +89,14 @@ ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5na
ret (*name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type) = NULL; \
ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name)
#define DETOUR_DECL_STATIC9(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name, p6type, p6name, p7type, p7name, p8type, p8name, p9type, p9name) \
ret (*name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type, p9type) = NULL; \
ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name, p9type p9name)
#define DETOUR_DECL_STATIC10(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name, p6type, p6name, p7type, p7name, p8type, p8name, p9type, p9name, p10type, p10name) \
ret (*name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type, p9type, p10type) = NULL; \
ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name, p9type p9name, p10type p10name)
#define DETOUR_DECL_MEMBER0(name, ret) \
class name##Class \
{ \
@ -174,6 +187,65 @@ public: \
ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type) = NULL; \
ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name)
#define DETOUR_DECL_MEMBER9(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name, p6type, p6name, p7type, p7name, p8type, p8name, p9type, p9name) \
class name##Class \
{ \
public: \
ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name, p9type p9name); \
static ret (name##Class::* name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type, p9type); \
}; \
ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type, p9type) = NULL; \
ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name, p9type p9name)
#define DETOUR_DECL_MEMBER10(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name, p6type, p6name, p7type, p7name, p8type, p8name, p9type, p9name, p10type, p10name) \
class name##Class \
{ \
public: \
ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name, p9type p9name, p10type p10name); \
static ret (name##Class::* name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type, p9type, p10type); \
}; \
ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type, p9type, p10type) = NULL; \
ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name, p9type p9name, p10type p10name)
#define DETOUR_DECL_MEMBER11(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name, p6type, p6name, p7type, p7name, p8type, p8name, p9type, p9name, p10type, p10name, p11type, p11name) \
class name##Class \
{ \
public: \
ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name, p9type p9name, p10type p10name, p11type p11name); \
static ret (name##Class::* name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type, p9type, p10type, p11type); \
}; \
ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type, p9type, p10type, p11type) = NULL; \
ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name, p9type p9name, p10type p10name, p11type p11name)
#define DETOUR_DECL_MEMBER12(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name, p6type, p6name, p7type, p7name, p8type, p8name, p9type, p9name, p10type, p10name, p11type, p11name, p12type, p12name) \
class name##Class \
{ \
public: \
ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name, p9type p9name, p10type p10name, p11type p11name, p12type p12name); \
static ret (name##Class::* name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type, p9type, p10type, p11type, p12type); \
}; \
ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type, p9type, p10type, p11type, p12type) = NULL; \
ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name, p9type p9name, p10type p10name, p11type p11name, p12type p12name)
#define DETOUR_DECL_MEMBER13(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name, p6type, p6name, p7type, p7name, p8type, p8name, p9type, p9name, p10type, p10name, p11type, p11name, p12type, p12name, p13type, p13name) \
class name##Class \
{ \
public: \
ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name, p9type p9name, p10type p10name, p11type p11name, p12type p12name, p13type p13name); \
static ret (name##Class::* name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type, p9type, p10type, p11type, p12type, p13type); \
}; \
ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type, p9type, p10type, p11type, p12type, p13type) = NULL; \
ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name, p9type p9name, p10type p10name, p11type p11name, p12type p12name, p13type p13name)
#define DETOUR_DECL_MEMBER14(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name, p6type, p6name, p7type, p7name, p8type, p8name, p9type, p9name, p10type, p10name, p11type, p11name, p12type, p12name, p13type, p13name, p14type, p14name) \
class name##Class \
{ \
public: \
ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name, p9type p9name, p10type p10name, p11type p11name, p12type p12name, p13type p13name, p14type p14name); \
static ret (name##Class::* name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type, p9type, p10type, p11type, p12type, p13type, p14type); \
}; \
ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type, p7type, p8type, p9type, p10type, p11type, p12type, p13type, p14type) = NULL; \
ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name, p7type p7name, p8type p8name, p9type p9name, p10type p10name, p11type p11name, p12type p12name, p13type p13name, p14type p14name)
#define GET_MEMBER_CALLBACK(name) (void *)GetCodeAddress(&name##Class::name)
#define GET_MEMBER_TRAMPOLINE(name) (void **)(&name##Class::name##_Actual)
@ -242,7 +314,7 @@ private:
void *detour_callback;
/* The function pointer used to call our trampoline */
void **trampoline;
const char *signame;
ISourcePawnEngine *spengine;
IGameConfig *gameconf;

View File

@ -36,7 +36,7 @@
#include <IHandleSys.h>
#define SMINTERFACE_MENUMANAGER_NAME "IMenuManager"
#define SMINTERFACE_MENUMANAGER_VERSION 16
#define SMINTERFACE_MENUMANAGER_VERSION 17
/**
* @file IMenuManager.h
@ -485,9 +485,10 @@ namespace SourceMod
*
* @param position Position, starting from 0.
* @param draw Optional pointer to store a draw information.
* @param client Client index. (Important for randomized menus.)
* @return Info string pointer, or NULL if position was invalid.
*/
virtual const char *GetItemInfo(unsigned int position, ItemDrawInfo *draw) =0;
virtual const char *GetItemInfo(unsigned int position, ItemDrawInfo *draw, int client=0) =0;
/**
* @brief Returns the number of items.
@ -636,6 +637,35 @@ namespace SourceMod
* @return Approximate number of bytes being used.
*/
virtual unsigned int GetApproxMemUsage() =0;
/**
* @brief Generates a per-client random mapping for the current vote options.
* @param start Menu item index to start randomizing from.
* @param stop Menu item index to stop randomizing at. -1 = infinite
*/
virtual void ShufflePerClient(int start=0, int stop=-1) =0;
/**
* @brief Fills the client vote option mapping with user supplied values.
* @param client Client index.
* @param array Integer array with mapping.
* @param length Length of array.
*/
virtual void SetClientMapping(int client, int *array, int length) =0;
/**
* @brief Returns true if the menu has a per-client random mapping.
* @return True on success, false otherwise.
*/
virtual bool IsPerClientShuffled() =0;
/**
* @brief Returns the actual (not shuffled) item index from the client position.
* @param client Client index.
* @param position Position, starting from 0.
* @return Actual item index in menu.
*/
virtual unsigned int GetRealItemIndex(int client, unsigned int position) =0;
};
/**

View File

@ -41,7 +41,7 @@
#include <IAdminSystem.h>
#define SMINTERFACE_PLAYERMANAGER_NAME "IPlayerManager"
#define SMINTERFACE_PLAYERMANAGER_VERSION 21
#define SMINTERFACE_PLAYERMANAGER_VERSION 22
struct edict_t;
class IPlayerInfo;
@ -543,10 +543,17 @@ namespace SourceMod
/**
* @brief Returns the number of players currently connected.
*
* @return Current number of connected clients.
* @return Current number of connected players.
*/
virtual int GetNumPlayers() =0;
/**
* @brief Returns the number of clients currently connected.
*
* @return Current number of connected clients.
*/
virtual int GetNumClients() =0;
/**
* @brief Returns the client index by its userid.
*

@ -1 +1 @@
Subproject commit 2be66bdbdf965ebf19dacc2e0874f81f22fd6fa8
Subproject commit e00a845c6bc415995ddc4b7ec538d1704fdd0122

View File

@ -36,7 +36,7 @@
#include <IShareSys.h>
#define SMINTERFACE_SDKHOOKS_NAME "ISDKHooks"
#define SMINTERFACE_SDKHOOKS_VERSION 1
#define SMINTERFACE_SDKHOOKS_VERSION 2
class CBaseEntity;
@ -71,6 +71,16 @@ namespace SourceMod
virtual void OnEntityDestroyed(CBaseEntity *pEntity)
{
}
/**
* @brief When an entity is spawned
*
* @param pEntity CBaseEntity entity.
* @param classname Entity classname.
*/
virtual void OnEntitySpawned(CBaseEntity *pEntity, const char *classname)
{
}
};
/**

@ -1 +1 @@
Subproject commit a98c996b166166350e7f022d2f8db60b1ee2b53e
Subproject commit 04eafd88631e7a3ba1de6bc7228af0e3d5443f0b

View File

@ -324,6 +324,7 @@ CopyFiles('plugins', 'addons/sourcemod/scripting',
'rockthevote.sp',
'sounds.sp',
'sql-admin-manager.sp',
'DynamicTargeting.sp',
]
)
CopyFiles('plugins/include', 'addons/sourcemod/scripting/include',
@ -394,6 +395,7 @@ CopyFiles('plugins/include', 'addons/sourcemod/scripting/include',
'usermessages.inc',
'vector.inc',
'version.inc',
'DynamicTargeting.inc',
]
)
CopyFiles('translations', 'addons/sourcemod/translations',