Compare commits

...

36 Commits

Author SHA1 Message Date
BotoX
0546426157 Add "Restart Current Map" to sm_map menu. 2019-12-05 18:56:28 +01:00
BotoX
2837dd77a5 Fix GetClientCount(false) 2019-12-05 18:56:28 +01:00
BotoX
30d8882833 Add damageCustom argument to SDKHooks_TakeDamage native. 2019-12-05 18:56:28 +01:00
BotoX
e2990c5e05 fix IsMapValid behavior change by a2246af121 2019-12-05 18:56:28 +01:00
BotoX
5fdb24c6c1 Add OnEntitySpawned to SDKHooks. 2019-12-05 18:56:28 +01:00
BotoX
2c8071995d Implement per-client randomized menus with MenuShufflePerClient native.
Add MenuSetClientMapping native.
2019-12-05 18:56:28 +01:00
BotoX
7ed4e88915 Changes on sm_*say 2019-12-05 18:56:28 +01:00
BotoX
453001ae9c Fix HookEntityOutput/HookSingleEntityOutput bugs in sdktools. 2019-12-05 18:56:28 +01:00
BotoX
b71a98f174 Add GetClientIClient native. 2019-12-05 18:56:28 +01:00
Obuss
6b3ca53a92 Logging changes to various base plugins. 2019-12-05 18:56:28 +01:00
BotoX
da2c643675 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-12-05 18:56:28 +01:00
BotoX
2e0beed7c9 Extend function calling API for natives and allow catching exceptions.
Change sourcepawn url.
2019-12-05 18:56:24 +01:00
BotoX
182da464cd Fix @spec not targeting clients in unassigned team. 2019-11-28 14:48:31 +01:00
BotoX
e42ff417b1 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-11-28 14:48:31 +01:00
BotoX
0c147446d5 Added client id to MultiTargetFilter forward. 2019-11-28 14:48:31 +01:00
BotoX
86fbf20a85 Add more macros to CDetour. 2019-11-28 14:48:31 +01:00
David Anderson
cd1a296e4f
Merge pull request #1131 from alliedmodders/update-sp
Update SourcePawn.
2019-11-24 20:57:06 -08:00
David Anderson
3ddf9f8a0d Update SourcePawn. 2019-11-24 20:41:59 -08:00
komashchenko
82df6087af Update CScore and MVP CSGO gamedata (#1127) 2019-11-19 21:31:54 -08:00
PerfectLaugh
bef8562de5 Fix CSGO Update crash (11/19/2019) (#1125)
* Fix CSGO Update crash (11/19/2019)

We know what happened when Valve do something big.
Not tested on Linux

* Fix RoundRespawn on Windows

* Fix TerminateRound on Linux x86

* Comment out Linux x64 part of TerminateRound

Better leave blank here.
2019-11-18 22:18:28 -05:00
Nicholas Hastings
1000d419fc Throw configuration error on unsupported compilers (#1029) 2019-11-15 16:40:39 -08:00
Einyux
2a9deb6a64 Add missing const to origin parameters (#1079) 2019-11-13 00:33:00 -08:00
42
351e406f85 Fix ArrayStack.Pop documentation (#1099) 2019-11-13 00:26:36 -08:00
David Anderson
d6e518838f
Merge pull request #1053 from nosoop/remote-ext-filename-check
Check short name for remote extensions
2019-11-12 11:45:02 +09:00
hydrogen-mvm
9e39f18230 Fix OpenFile files.inc example (#1120)
"rb" = binary file for *reading* (not writing, that would be "wb").
2019-11-11 16:24:12 -08:00
BotoX
3dd1e5a318 Validate GetEntityHandle in FindEntityByNetClass (#1089) 2019-11-05 22:25:18 -08:00
Bara
23e1c0b71e Add slot define for healthshot/shield and tablet (#1114) 2019-11-04 12:36:17 +00:00
JoinedSenses
a1436cd205 Add windows supported SDKs to powershell checkout-deps (#1116)
.sh version has this bit:

```
if [ $ismac -eq 0 ]; then
  # Add these SDKs for Windows or Linux
  sdks+=( orangebox blade episode1 bms )

  # Add more SDKs for Windows only
  if [ $iswin -eq 1 ]; then
    sdks+=( darkm swarm bgt eye contagion )
  fi
fi
```

Added these to the SDK list.
2019-11-04 12:34:56 +00:00
David Anderson
0d320b7922
Merge pull request #1115 from alliedmodders/update-sp
Update SourcePawn.
2019-11-02 12:32:35 -07:00
David Anderson
b2a0d0e4da Update SourcePawn.
Bug: alliedmodders/sourcepawn#400
Bug: alliedmodders/sourcepawn#401
Bug: alliedmodders/sourcepawn#402
2019-11-02 12:16:04 -07:00
Bara
273f058da9 Add classic knife to CSWeaponID (#1111) 2019-10-31 13:50:29 -07:00
Headline
c6f751bb67
Return DBDriver instead of Handle in DBI (#1109) 2019-10-31 01:53:50 -07:00
Headline
00b7ac5a39
Add bounds check for userid reset on disconnect (#1108) 2019-10-30 17:17:53 -07:00
David Anderson
c0686dc4f9
Merge pull request #1106 from alliedmodders/update-sp
Update SourcePawn to master.
2019-10-28 22:51:30 -07:00
David Anderson
7ab3a3cfd9 Update SourcePawn to master.
This turns on the new expression parser by default.
2019-10-28 21:19:22 -07:00
nosoop
5293815bf6 Check other filename sources on remote extensions 2019-07-29 04:00:18 -07:00
72 changed files with 1784 additions and 399 deletions

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

@ -214,6 +214,16 @@ class SMConfig(object):
if cxx.like('msvc') and len(self.archs) > 1:
raise Exception('Building multiple archs with MSVC is not currently supported')
if cxx.family == 'msvc':
if cxx.version < 1900:
raise Exception('Only MSVC 2015 and later are supported, c++14 support is required.')
if cxx.family == 'gcc':
if cxx.version < 'gcc-4.9':
raise Exception('Only GCC versions 4.9 or greater are supported, c++14 support is required.')
if cxx.family == 'clang':
if cxx.version < 'clang-3.4':
raise Exception('Only clang versions 3.4 or greater are supported, c++14 support is required.')
if cxx.like('gcc'):
self.configure_gcc(cxx)
elif cxx.family == 'msvc':
@ -379,6 +389,16 @@ class SMConfig(object):
def configure_windows(self, cxx):
cxx.defines += ['WIN32', '_WINDOWS']
def add_libamtl(self):
# Add libamtl.
self.libamtl = {}
for arch in self.archs:
def get_configure_fn(arch):
return lambda builder, name: self.StaticLibrary(builder, name, arch)
extra_vars = {'Configure': get_configure_fn(arch)}
libamtl = builder.Build('public/amtl/amtl/AMBuilder', extra_vars)
self.libamtl[arch] = libamtl.binary
def AddVersioning(self, binary, arch):
if builder.target.platform == 'windows':
binary.sources += ['version.rc']
@ -498,8 +518,7 @@ class SMConfig(object):
if compiler.like('msvc'):
compiler.defines += ['COMPILER_MSVC', 'COMPILER_MSVC32']
if compiler.version >= 1900:
compiler.linkflags += ['legacy_stdio_definitions.lib']
compiler.linkflags += ['legacy_stdio_definitions.lib']
else:
compiler.defines += ['COMPILER_GCC']
@ -613,6 +632,7 @@ SM = SMConfig()
SM.detectProductVersion()
SM.detectSDKs()
SM.configure()
SM.add_libamtl()
if SM.use_auto_versioning():
SM.generated_headers = builder.Build(

View File

@ -84,9 +84,7 @@ for sdk_name in SM.sdks:
elif builder.target.platform == 'windows':
msvc_ver = compiler.version
vs_year = ''
if msvc_ver == 1800:
vs_year = '2013'
elif 1900 <= msvc_ver < 2000:
if 1900 <= msvc_ver < 2000:
vs_year = '2015'
else:
raise Exception('Cannot find libprotobuf for MSVC version "' + str(compiler.version) + '"')

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)
@ -1474,7 +1575,10 @@ void PlayerManager::InvalidatePlayer(CPlayer *pPlayer)
}
}
m_UserIdLookUp[engine->GetPlayerUserId(pPlayer->m_pEdict)] = 0;
auto userid = engine->GetPlayerUserId(pPlayer->m_pEdict);
if (userid != -1)
m_UserIdLookUp[userid] = 0;
pPlayer->Disconnect();
}
@ -1928,6 +2032,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 +2270,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

@ -1364,7 +1364,7 @@ bool CLocalExtension::IsSameFile(const char *file)
bool CRemoteExtension::IsSameFile(const char *file)
{
/* :TODO: this could be better, but no one uses this API anyway. */
return strcmp(file, m_Path.c_str()) == 0;
/* Check full path and name passed in from LoadExternal */
return strcmp(file, m_Path.c_str()) == 0 || strcmp(file, m_File.c_str()) == 0;
}

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

@ -244,10 +244,10 @@
{
"GiveNamedItem"
{
"windows" "456"
"linux" "457"
"linux64" "457"
"mac64" "457"
"windows" "457"
"linux" "458"
"linux64" "458"
"mac64" "458"
}
"RemovePlayerItem"
{
@ -286,10 +286,10 @@
}
"CommitSuicide"
{
"windows" "506"
"linux" "506"
"linux64" "506"
"mac64" "506"
"windows" "507"
"linux" "507"
"linux64" "507"
"mac64" "507"
}
"GetVelocity"
{
@ -335,10 +335,10 @@
}
"PlayerRunCmd"
{
"windows" "476"
"linux" "477"
"linux64" "477"
"mac64" "477"
"windows" "477"
"linux" "478"
"linux64" "478"
"mac64" "478"
}
"GiveAmmo"
{

View File

@ -107,7 +107,7 @@
"RoundRespawn"
{
"library" "server"
"windows" "\x55\x8B\xEC\x83\xEC\x0C\x53\x56\x8B\xF1\x8B\x0D\x2A\x2A\x2A\x2A\x57\x8B\x01"
"windows" "\x55\x8B\xEC\x83\xEC\x0C\x53\x56\x57\x8B\xF9\x8B\x0D\x2A\x2A\x2A\x2A\x8B\x01"
"linux" "\x55\x89\xE5\x57\x56\x53\x83\xEC\x4C\xA1\x2A\x2A\x2A\x2A\x8B\x5D\x08\x89\x04\x24"
"linux64" "\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x41\x54\x53\x48\x89\xFB\x48\x83\xEC\x18\x4C\x8B\x25\x85\x17\xB4\x00"
"mac64" "\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x54\x53\x48\x83\xEC\x10\x49\x89\xFC\x4C\x8D\x3D\xD7\xB9\x90\x00"
@ -140,8 +140,8 @@
{
"library" "server"
"windows" "\x55\x8B\xEC\x83\xE4\xF8\x83\xEC\x2A\x53\x8B\xD9\xF3\x0F\x2A\x2A\x2A\x2A\x56\x57\x89\x2A\x2A\x2A\x83\xBB"
"linux" "\x55\x89\xE5\x57\x56\x53\x81\xEC\xBC\x00\x00\x00\x8B\x7D\x08\x8B\x9F"
"linux64" "\x55\x48\x89\xE5\x41\x57\x41\x56\x49\x89\xFE\x41\x55\x41\x54\x53\x48\x81\xEC\x98\x00\x00\x00\x89\xB5\x68\xFF\xFF\xFF"
"linux" "\x55\x89\xE5\x57\x56\x53\x81\xEC\xBC\x00\x00\x00\x8B\x7D\x08\x8B\x87\xB4\x0B\x00\x00"
//"linux64" "\x55\x48\x89\xE5\x41\x57\x41\x56\x49\x89\xFE\x41\x55\x41\x54\x53\x48\x81\xEC\x98\x00\x00\x00\x89\xB5\x68\xFF\xFF\xFF"
"mac64" "\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x41\x54\x53\x48\x81\xEC\x08\x01\x00\x00\x41\x89\xF6"
}
//In CS:GO this is actually CCSGameRules::CheckRestartRound(void) but to keep same gamedata as cs:s.
@ -204,10 +204,10 @@
{
"CScore"
{
"windows" "63"
"linux" "63"
"linux64" "63"
"mac64" "63"
"windows" "59"
"linux" "59"
"linux64" "59"
"mac64" "59"
}
}
}
@ -223,10 +223,10 @@
{
"MVPs"
{
"windows" "15"
"linux" "15"
"linux64" "15"
"mac64" "15"
"windows" "11"
"linux" "11"
"linux64" "11"
"mac64" "11"
}
}
}

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

@ -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,6 +161,8 @@ 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++)
{

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

@ -84,7 +84,7 @@ methodmap ArrayStack < Handle
// @param block Optionally specify which block to read from
// (useful if the blocksize > 0).
// @param asChar Optionally read as a byte instead of a cell.
// @return True on success, false if the stack is empty.
// @return Value popped from the stack.
// @error The stack is empty.
public native any Pop(int block=0, bool asChar=false);
@ -92,7 +92,7 @@ methodmap ArrayStack < Handle
//
// @param buffer Buffer to store string.
// @param maxlength Maximum size of the buffer.
// @oaram written Number of characters written to buffer, not including
// @param written Number of characters written to buffer, not including
// the null terminator.
// @error The stack is empty.
public native void PopString(char[] buffer, int maxlength, int &written = 0);

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

@ -45,6 +45,8 @@
#define CS_SLOT_KNIFE 2 /**< Knife slot. */
#define CS_SLOT_GRENADE 3 /**< Grenade slot (will only return one grenade). */
#define CS_SLOT_C4 4 /**< C4 slot. */
#define CS_SLOT_BOOST 11 /**< Slot for healthshot and shield (will only return one weapon/item). */
#define CS_SLOT_UTILITY 12 /**< Slot for tablet. */
#define CS_DMG_HEADSHOT (1 << 30) /**< Headshot */
@ -156,6 +158,7 @@ enum CSWeaponID
CSWeapon_BUMPMINE = 85,
CSWeapon_MAX_WEAPONS_NO_KNIFES, // Max without the knife item defs, useful when treating all knives as a regular knife.
CSWeapon_BAYONET = 500,
CSWeapon_KNIFE_CLASSIC = 503,
CSWeapon_KNIFE_FLIP = 505,
CSWeapon_KNIFE_GUT = 506,
CSWeapon_KNIFE_KARAMBIT = 507,

View File

@ -547,7 +547,7 @@ native bool SQL_CheckConfig(const char[] name);
* string to return the default driver.
* @return Driver Handle, or INVALID_HANDLE on failure.
*/
native Handle SQL_GetDriver(const char[] name="");
native DBDriver SQL_GetDriver(const char[] name="");
/**
* Reads the driver of an opened database.
@ -557,7 +557,7 @@ native Handle SQL_GetDriver(const char[] name="");
* @param ident_length Maximum length of the buffer.
* @return Driver Handle.
*/
native Handle SQL_ReadDriver(Handle database, char[] ident="", int ident_length=0);
native DBDriver SQL_ReadDriver(Handle database, char[] ident="", int ident_length=0);
/**
* Retrieves a driver's identification string.

View File

@ -314,7 +314,7 @@ native bool ReadDirEntry(Handle dir, char[] buffer, int maxlength, FileType &typ
* Mac, this has no distinction from binary mode. On Windows, it causes the '\n'
* character (0xA) to be written as "\r\n" (0xD, 0xA).
*
* Example: "rb" opens a binary file for writing; "at" opens a text file for
* Example: "rb" opens a binary file for reading; "at" opens a text file for
* appending.
*
* @param file File to open.

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

@ -682,7 +682,7 @@ enum ClientRangeType
* @param size Maximum size of clients array.
* @return Number of client indexes written to clients array.
*/
native int GetClientsInRange(float origin[3], ClientRangeType rangeType, int[] clients, int size);
native int GetClientsInRange(const float origin[3], ClientRangeType rangeType, int[] clients, int size);
/**
* Retrieves the server's authentication string (SteamID).

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

@ -224,7 +224,7 @@ stock void TE_SendToClient(int client, float delay=0.0)
* @param rangeType Range type to use for filtering clients.
* @param delay Delay in seconds to send the TE.
*/
stock void TE_SendToAllInRange(float origin[3], ClientRangeType rangeType, float delay=0.0)
stock void TE_SendToAllInRange(const float origin[3], ClientRangeType rangeType, float delay=0.0)
{
int[] clients = new int[MaxClients];
int total = GetClientsInRange(origin, rangeType, clients, MaxClients);

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

@ -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 e00a845c6bc415995ddc4b7ec538d1704fdd0122
Subproject commit eb7b6ba084e13c50f7c2c53b285e6e6af44accd9

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 7ba3e384e29ccdb5dbd3ac4a0fda16fd0a0144a8
Subproject commit a496cf77528e976bfc5a665dc87cb59acab59133

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',

View File

@ -18,7 +18,17 @@ param(
'tf2',
'insurgency',
'sdk2013',
'dota'
'dota',
'orangebox',
'blade',
'episode1',
'bms',
'darkm',
'swarm',
'bgt',
'eye',
'contagion',
'doi'
)
)
@ -78,4 +88,4 @@ Checkout-Repo -Name "ambuild" -Branch "master" -Repo "https://github.com/alliedm
Set-Location ambuild
& python setup.py install
Set-Location ..
Set-Location ..