Compare commits
	
		
			34 Commits
		
	
	
		
			feature-ge
			...
			1.10-fork
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					178202a5b3 | ||
| 
						 | 
					60f3268236 | ||
| 
						 | 
					64b3c8fbd8 | ||
| 
						 | 
					4c4629fca7 | ||
| 
						 | 
					8749877c62 | ||
| 
						 | 
					102b01c626 | ||
| 
						 | 
					8e07790997 | ||
| 
						 | 
					a701408c71 | ||
| 
						 | 
					2d0fff79a8 | ||
| 
						 | 
					9da44d67f1 | ||
| 
						 | 
					1847f5e2dc | ||
| 
						 | 
					0dd3361050 | ||
| 
						 | 
					11d12aad11 | ||
| 
						 | 
					8ac0c18674 | ||
| 
						 | 
					a0b8153f4b | ||
| 
						 | 
					a363587be9 | ||
| 
						 | 
					fdcce81a41 | ||
| 
						 | 
					c3102c7e9f | ||
| 
						 | 
					77f4ddf2c2 | ||
| 
						 | 
					024ae2b9ed | ||
| 
						 | 
					8a4295d699 | ||
| 
						 | 
					f05e39afe1 | ||
| 
						 | 
					3b1fb85bb8 | ||
| 
						 | 
					a405f85eee | ||
| 
						 | 
					78511afa4c | ||
| 
						 | 
					c37c4f830f | ||
| 
						 | 
					4fe2ae780b | ||
| 
						 | 
					e02e6bcb4f | ||
| 
						 | 
					c7392aeded | ||
| 
						 | 
					14247af323 | ||
| 
						 | 
					32cb00a4c6 | ||
| 
						 | 
					d93f6984cc | ||
| 
						 | 
					207584818f | ||
| 
						 | 
					7a42d6b564 | 
							
								
								
									
										12
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
# GitHub views all .h files as C, let's assume it's C++
 | 
			
		||||
*.h linguist-language=c++
 | 
			
		||||
 | 
			
		||||
# Internal tools overriding
 | 
			
		||||
tools/* linguist-vendored
 | 
			
		||||
editor/* linguist-vendored
 | 
			
		||||
 | 
			
		||||
# Third-party overriding 
 | 
			
		||||
extensions/curl/curl-src/* linguist-vendored
 | 
			
		||||
extensions/geoip/GeoIP.c linguist-vendored
 | 
			
		||||
extensions/geoip/GeoIP.h linguist-vendored
 | 
			
		||||
extensions/sqlite/sqlite-source/* linguist-vendored
 | 
			
		||||
							
								
								
									
										2
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							@ -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
 | 
			
		||||
 | 
			
		||||
@ -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)
 | 
			
		||||
 | 
			
		||||
@ -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))
 | 
			
		||||
 | 
			
		||||
@ -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();
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -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())
 | 
			
		||||
			{
 | 
			
		||||
 | 
			
		||||
@ -30,6 +30,7 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "PlayerManager.h"
 | 
			
		||||
#include "sourcemod.h"
 | 
			
		||||
#include "IAdminSystem.h"
 | 
			
		||||
#include "ConCmdManager.h"
 | 
			
		||||
#include "MenuStyle_Valve.h"
 | 
			
		||||
@ -92,6 +93,12 @@ SH_DECL_EXTERN1_void(ConCommand, Dispatch, SH_NOATTRIB, false, const CCommand &)
 | 
			
		||||
#else
 | 
			
		||||
SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
 | 
			
		||||
#endif
 | 
			
		||||
SH_DECL_HOOK2_void(IVEngineServer, ClientPrintf, SH_NOATTRIB, 0, edict_t *, const char *);
 | 
			
		||||
 | 
			
		||||
static void PrintfBuffer_FrameAction(void *data)
 | 
			
		||||
{
 | 
			
		||||
	g_Players.OnPrintfFrameAction(reinterpret_cast<unsigned int>(data));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ConCommand *maxplayersCmd = NULL;
 | 
			
		||||
 | 
			
		||||
@ -172,6 +179,7 @@ void PlayerManager::OnSourceModAllInitialized()
 | 
			
		||||
#elif SOURCE_ENGINE > SE_EYE // 2013/orangebox, but not original orangebox.
 | 
			
		||||
	SH_ADD_HOOK(IServerGameDLL, SetServerHibernation, gamedll, SH_MEMBER(this, &PlayerManager::OnServerHibernationUpdate), true);
 | 
			
		||||
#endif
 | 
			
		||||
	SH_ADD_HOOK(IVEngineServer, ClientPrintf, engine, SH_MEMBER(this, &PlayerManager::OnClientPrintf), false);
 | 
			
		||||
 | 
			
		||||
	sharesys->AddInterface(NULL, this);
 | 
			
		||||
 | 
			
		||||
@ -204,6 +212,9 @@ void PlayerManager::OnSourceModAllInitialized()
 | 
			
		||||
		SH_ADD_HOOK(ConCommand, Dispatch, pCmd, SH_STATIC(CmdMaxplayersCallback), true);
 | 
			
		||||
		maxplayersCmd = pCmd;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gameevents->AddListener(this, "player_connect", true);
 | 
			
		||||
	gameevents->AddListener(this, "player_disconnect", true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PlayerManager::OnSourceModShutdown()
 | 
			
		||||
@ -225,6 +236,7 @@ void PlayerManager::OnSourceModShutdown()
 | 
			
		||||
#elif SOURCE_ENGINE > SE_EYE // 2013/orangebox, but not original orangebox.
 | 
			
		||||
	SH_REMOVE_HOOK(IServerGameDLL, SetServerHibernation, gamedll, SH_MEMBER(this, &PlayerManager::OnServerHibernationUpdate), true);
 | 
			
		||||
#endif
 | 
			
		||||
	SH_REMOVE_HOOK(IVEngineServer, ClientPrintf, engine, SH_MEMBER(this, &PlayerManager::OnClientPrintf), false);
 | 
			
		||||
 | 
			
		||||
	/* Release forwards */
 | 
			
		||||
	forwardsys->ReleaseForward(m_clconnect);
 | 
			
		||||
@ -250,6 +262,8 @@ void PlayerManager::OnSourceModShutdown()
 | 
			
		||||
	{
 | 
			
		||||
		SH_REMOVE_HOOK(ConCommand, Dispatch, maxplayersCmd, SH_STATIC(CmdMaxplayersCallback), true);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gameevents->RemoveListener(this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ConfigResult PlayerManager::OnSourceModConfigChanged(const char *key, 
 | 
			
		||||
@ -846,6 +860,88 @@ void PlayerManager::OnClientDisconnect_Post(edict_t *pEntity)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PlayerManager::OnClientPrintf(edict_t *pEdict, const char *szMsg)
 | 
			
		||||
{
 | 
			
		||||
	int client = IndexOfEdict(pEdict);
 | 
			
		||||
 | 
			
		||||
	CPlayer &player = m_Players[client];
 | 
			
		||||
	if (!player.IsConnected())
 | 
			
		||||
		RETURN_META(MRES_IGNORED);
 | 
			
		||||
 | 
			
		||||
	INetChannel *pNetChan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(client));
 | 
			
		||||
	if (pNetChan == NULL)
 | 
			
		||||
		RETURN_META(MRES_IGNORED);
 | 
			
		||||
 | 
			
		||||
	size_t nMsgLen = strlen(szMsg);
 | 
			
		||||
#if SOURCE_ENGINE == SE_EPISODEONE
 | 
			
		||||
	static const int nNumBitsWritten = 0;
 | 
			
		||||
#else
 | 
			
		||||
	int nNumBitsWritten = pNetChan->GetNumBitsWritten(false); // SVC_Print uses unreliable netchan
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	// if the msg is bigger than allowed then just let it fail
 | 
			
		||||
	if (nMsgLen + 1 >= SVC_Print_BufferSize) // +1 for NETMSG_TYPE_BITS
 | 
			
		||||
		RETURN_META(MRES_IGNORED);
 | 
			
		||||
 | 
			
		||||
	// enqueue msgs if we'd overflow the SVC_Print buffer (+7 as ceil)
 | 
			
		||||
	if (!player.m_PrintfBuffer.empty() || (nNumBitsWritten + NETMSG_TYPE_BITS + 7) / 8 + nMsgLen >= SVC_Print_BufferSize)
 | 
			
		||||
	{
 | 
			
		||||
		// Don't send any more messages for this player until the buffer is empty.
 | 
			
		||||
		// Queue up a gameframe hook to empty the buffer (if we haven't already)
 | 
			
		||||
		if (player.m_PrintfBuffer.empty())
 | 
			
		||||
			g_SourceMod.AddFrameAction(PrintfBuffer_FrameAction, (void *)(uintptr_t)player.GetSerial());
 | 
			
		||||
 | 
			
		||||
		player.m_PrintfBuffer.append(szMsg);
 | 
			
		||||
 | 
			
		||||
		RETURN_META(MRES_SUPERCEDE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	RETURN_META(MRES_IGNORED);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PlayerManager::OnPrintfFrameAction(unsigned int serial)
 | 
			
		||||
{
 | 
			
		||||
	int client = GetClientFromSerial(serial);
 | 
			
		||||
	CPlayer &player = m_Players[client];
 | 
			
		||||
	if (!player.IsConnected())
 | 
			
		||||
	{
 | 
			
		||||
		player.ClearNetchannelQueue();
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	INetChannel *pNetChan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(client));
 | 
			
		||||
	if (pNetChan == NULL)
 | 
			
		||||
	{
 | 
			
		||||
		player.ClearNetchannelQueue();
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	while (!player.m_PrintfBuffer.empty())
 | 
			
		||||
	{
 | 
			
		||||
#if SOURCE_ENGINE == SE_EPISODEONE
 | 
			
		||||
		static const int nNumBitsWritten = 0;
 | 
			
		||||
#else
 | 
			
		||||
		int nNumBitsWritten = pNetChan->GetNumBitsWritten(false); // SVC_Print uses unreliable netchan
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		ke::AString &string = player.m_PrintfBuffer.front();
 | 
			
		||||
 | 
			
		||||
		// stop if we'd overflow the SVC_Print buffer  (+7 as ceil)
 | 
			
		||||
		if ((nNumBitsWritten + NETMSG_TYPE_BITS + 7) / 8 + string.length() >= SVC_Print_BufferSize)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		SH_CALL(engine, &IVEngineServer::ClientPrintf)(player.m_pEdict, string.chars());
 | 
			
		||||
 | 
			
		||||
		player.m_PrintfBuffer.popFront();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!player.m_PrintfBuffer.empty())
 | 
			
		||||
	{
 | 
			
		||||
		// continue processing it on the next gameframe as buffer is not empty
 | 
			
		||||
		g_SourceMod.AddFrameAction(PrintfBuffer_FrameAction, (void *)(uintptr_t)player.GetSerial());
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ClientConsolePrint(edict_t *e, const char *fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
	char buffer[512];
 | 
			
		||||
@ -1333,6 +1429,11 @@ int PlayerManager::GetNumPlayers()
 | 
			
		||||
	return m_PlayerCount;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int PlayerManager::GetNumClients()
 | 
			
		||||
{
 | 
			
		||||
	return m_ClientCount;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int PlayerManager::GetClientOfUserId(int userid)
 | 
			
		||||
{
 | 
			
		||||
	if (userid < 0 || userid > USHRT_MAX)
 | 
			
		||||
@ -1928,6 +2029,27 @@ bool PlayerManager::HandleConVarQuery(QueryCvarCookie_t cookie, int client, EQue
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* IGameEventListener2::FireGameEvent */
 | 
			
		||||
void PlayerManager::FireGameEvent(IGameEvent *pEvent)
 | 
			
		||||
{
 | 
			
		||||
	const char *name = pEvent->GetName();
 | 
			
		||||
 | 
			
		||||
	if (strcmp(name, "player_connect") == 0)
 | 
			
		||||
	{
 | 
			
		||||
		const int client = pEvent->GetInt("index") + 1;
 | 
			
		||||
		const int userid = pEvent->GetInt("userid");
 | 
			
		||||
 | 
			
		||||
		m_ClientCount++;
 | 
			
		||||
	}
 | 
			
		||||
	else if (strcmp(name, "player_disconnect") == 0)
 | 
			
		||||
	{
 | 
			
		||||
		const int userid = pEvent->GetInt("userid");
 | 
			
		||||
		const int client = m_UserIdLookUp[userid];
 | 
			
		||||
 | 
			
		||||
		m_ClientCount--;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*******************
 | 
			
		||||
 *** PLAYER CODE ***
 | 
			
		||||
@ -2145,6 +2267,13 @@ void CPlayer::Disconnect()
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO
 | 
			
		||||
	m_LanguageCookie = InvalidQueryCvarCookie;
 | 
			
		||||
#endif
 | 
			
		||||
	ClearNetchannelQueue();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CPlayer::ClearNetchannelQueue(void)
 | 
			
		||||
{
 | 
			
		||||
	while (!m_PrintfBuffer.empty())
 | 
			
		||||
		m_PrintfBuffer.popFront();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CPlayer::SetName(const char *name)
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -36,7 +36,11 @@
 | 
			
		||||
 | 
			
		||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
 | 
			
		||||
SH_DECL_HOOK1_void(ICvar, UnregisterConCommand, SH_NOATTRIB, 0, ConCommandBase *);
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO
 | 
			
		||||
SH_DECL_HOOK2_void(ICvar, RegisterConCommand, SH_NOATTRIB, 0, ConCommandBase *, bool);
 | 
			
		||||
#else
 | 
			
		||||
SH_DECL_HOOK1_void(ICvar, RegisterConCommand, SH_NOATTRIB, 0, ConCommandBase *);
 | 
			
		||||
#endif
 | 
			
		||||
#else
 | 
			
		||||
SH_DECL_HOOK1_void(ICvar, RegisterConCommandBase, SH_NOATTRIB, 0, ConCommandBase *);
 | 
			
		||||
#endif
 | 
			
		||||
@ -78,7 +82,11 @@ public:
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#if SOURCE_ENGINE == SE_CSGO
 | 
			
		||||
	void LinkConCommandBase(ConCommandBase *pBase, bool unknown)
 | 
			
		||||
#else
 | 
			
		||||
	void LinkConCommandBase(ConCommandBase *pBase)
 | 
			
		||||
#endif
 | 
			
		||||
	{
 | 
			
		||||
		IConCommandLinkListener *listener = IConCommandLinkListener::head;
 | 
			
		||||
		while (listener)
 | 
			
		||||
 | 
			
		||||
@ -85,6 +85,7 @@ for arch in SM.archs:
 | 
			
		||||
    'smn_halflife.cpp',
 | 
			
		||||
    'FrameIterator.cpp',
 | 
			
		||||
    'DatabaseConfBuilder.cpp',
 | 
			
		||||
    'NativeInvoker.cpp',
 | 
			
		||||
  ]
 | 
			
		||||
 | 
			
		||||
  if arch == 'x64':
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										321
									
								
								core/logic/NativeInvoker.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										321
									
								
								core/logic/NativeInvoker.cpp
									
									
									
									
									
										Normal 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; }
 | 
			
		||||
							
								
								
									
										79
									
								
								core/logic/NativeInvoker.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								core/logic/NativeInvoker.h
									
									
									
									
									
										Normal 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_
 | 
			
		||||
@ -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},
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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},
 | 
			
		||||
 | 
			
		||||
@ -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 },
 | 
			
		||||
 | 
			
		||||
@ -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},
 | 
			
		||||
 | 
			
		||||
@ -51,6 +51,7 @@ IGameConfig *g_pGameConf = NULL;
 | 
			
		||||
IGameEventManager2 *gameevents = NULL;
 | 
			
		||||
bool hooked_everything = false;
 | 
			
		||||
int g_msgHintText = -1;
 | 
			
		||||
CGlobalVars *gpGlobals;
 | 
			
		||||
 | 
			
		||||
SMEXT_LINK(&g_CStrike);
 | 
			
		||||
 | 
			
		||||
@ -107,6 +108,7 @@ bool CStrike::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool
 | 
			
		||||
{
 | 
			
		||||
	GET_V_IFACE_CURRENT(GetEngineFactory, gameevents, IGameEventManager2, INTERFACEVERSION_GAMEEVENTSMANAGER2);
 | 
			
		||||
	GET_V_IFACE_CURRENT(GetEngineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER);
 | 
			
		||||
	gpGlobals = ismm->GetCGlobals();
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -166,6 +166,7 @@ private:
 | 
			
		||||
extern IBinTools *g_pBinTools;
 | 
			
		||||
extern IGameConfig *g_pGameConf;
 | 
			
		||||
extern ISDKTools *g_pSDKTools;
 | 
			
		||||
extern CGlobalVars *gpGlobals;
 | 
			
		||||
extern int g_msgHintText;
 | 
			
		||||
extern bool g_pIgnoreTerminateDetour;
 | 
			
		||||
extern bool g_pIgnoreCSWeaponDropDetour;
 | 
			
		||||
 | 
			
		||||
@ -58,7 +58,19 @@ void TimeLeftEvents::FireGameEvent(IGameEvent *event)
 | 
			
		||||
		if (get_new_timeleft_offset || !round_end_found)
 | 
			
		||||
		{
 | 
			
		||||
			get_new_timeleft_offset = false;
 | 
			
		||||
			timersys->NotifyOfGameStart();
 | 
			
		||||
 | 
			
		||||
			float flGameStartTime = gpGlobals->curtime;
 | 
			
		||||
			uintptr_t gamerules = (uintptr_t)g_pSDKTools->GetGameRules();
 | 
			
		||||
			if (gamerules)
 | 
			
		||||
			{
 | 
			
		||||
				sm_sendprop_info_t info;
 | 
			
		||||
				if (gamehelpers->FindSendPropInfo("CCSGameRulesProxy", "m_flGameStartTime", &info))
 | 
			
		||||
				{
 | 
			
		||||
					flGameStartTime = *(float *)(gamerules + info.actual_offset);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			timersys->NotifyOfGameStart(flGameStartTime - gpGlobals->curtime);
 | 
			
		||||
			timersys->MapTimeLeftChanged();
 | 
			
		||||
		}
 | 
			
		||||
		round_end_found = false;
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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 \
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -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)
 | 
			
		||||
			{
 | 
			
		||||
 | 
			
		||||
@ -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();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -998,6 +998,22 @@ static cell_t smn_TRGetHitGroup(IPluginContext *pContext, const cell_t *params)
 | 
			
		||||
	return tr->hitgroup;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static cell_t smn_TRGetHitBoxIndex(IPluginContext *pContext, const cell_t *params)
 | 
			
		||||
{
 | 
			
		||||
	sm_trace_t *tr;
 | 
			
		||||
	HandleError err;
 | 
			
		||||
	HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
 | 
			
		||||
 | 
			
		||||
	if (params[1] == BAD_HANDLE)
 | 
			
		||||
	{
 | 
			
		||||
		tr = &g_Trace;
 | 
			
		||||
	} else if ((err = handlesys->ReadHandle(params[1], g_TraceHandle, &sec, (void **)&tr)) != HandleError_None) {
 | 
			
		||||
		return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return tr->hitbox;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static cell_t smn_TRGetEntityIndex(IPluginContext *pContext, const cell_t *params)
 | 
			
		||||
{
 | 
			
		||||
	sm_trace_t *tr;
 | 
			
		||||
@ -1102,6 +1118,7 @@ sp_nativeinfo_t g_TRNatives[] =
 | 
			
		||||
	{"TR_StartSolid",				smn_TRStartSolid},
 | 
			
		||||
	{"TR_DidHit",					smn_TRDidHit},
 | 
			
		||||
	{"TR_GetHitGroup",				smn_TRGetHitGroup},
 | 
			
		||||
	{"TR_GetHitBoxIndex",			smn_TRGetHitBoxIndex},
 | 
			
		||||
	{"TR_ClipRayToEntity",			smn_TRClipRayToEntity},
 | 
			
		||||
	{"TR_ClipRayToEntityEx",		smn_TRClipRayToEntityEx},
 | 
			
		||||
	{"TR_ClipRayHullToEntity",		smn_TRClipRayHullToEntity},
 | 
			
		||||
 | 
			
		||||
@ -255,10 +255,12 @@ ValveCall *CreateValveVCall(unsigned int vtableIdx,
 | 
			
		||||
 | 
			
		||||
	/* Get return information - encode only */
 | 
			
		||||
	PassInfo retBuf;
 | 
			
		||||
	ObjectField retFieldBuf[16];
 | 
			
		||||
	size_t retBufSize = 0;
 | 
			
		||||
	bool retbuf_needs_extra;
 | 
			
		||||
	if (retInfo)
 | 
			
		||||
	{
 | 
			
		||||
		retBuf.fields = retFieldBuf;
 | 
			
		||||
		if ((size = ValveParamToBinParam(retInfo->vtype, retInfo->type, retInfo->flags, &retBuf, retbuf_needs_extra)) == 0)
 | 
			
		||||
		{
 | 
			
		||||
			delete vc;
 | 
			
		||||
@ -269,12 +271,14 @@ ValveCall *CreateValveVCall(unsigned int vtableIdx,
 | 
			
		||||
 | 
			
		||||
	/* Get parameter info */
 | 
			
		||||
	PassInfo paramBuf[32];
 | 
			
		||||
	ObjectField fieldBuf[32][16];
 | 
			
		||||
	size_t sizes[32];
 | 
			
		||||
	size_t normSize = 0;
 | 
			
		||||
	size_t extraSize = 0;
 | 
			
		||||
	for (unsigned int i=0; i<numParams; i++)
 | 
			
		||||
	{
 | 
			
		||||
		bool needs_extra;
 | 
			
		||||
		paramBuf[i].fields = fieldBuf[i];
 | 
			
		||||
		if ((size = ValveParamToBinParam(params[i].vtype, 
 | 
			
		||||
										params[i].type,
 | 
			
		||||
										params[i].flags,
 | 
			
		||||
 | 
			
		||||
@ -1,15 +1,14 @@
 | 
			
		||||
SOURCEMOD LICENSE INFORMATION
 | 
			
		||||
VERSION: JUNE-13-2008
 | 
			
		||||
VERSION: 2019-9-30
 | 
			
		||||
-----------------------------
 | 
			
		||||
 | 
			
		||||
SourceMod is licensed under the GNU General Public License, version 3.  
 | 
			
		||||
 | 
			
		||||
As a special exception, AlliedModders LLC gives you permission to link the code
 | 
			
		||||
of this program (as well as its derivative works) to "Half-Life 2," the "Source 
 | 
			
		||||
Engine," the "SourcePawn JIT," and any Game MODs that run on software by the 
 | 
			
		||||
Valve Corporation.  You must obey the GNU General Public License in all 
 | 
			
		||||
respects for all other code used. Additionally, AlliedModders LLC grants this 
 | 
			
		||||
exception to all derivative works.
 | 
			
		||||
Engine" and any Game MODs that run on software by the Valve Corporation.
 | 
			
		||||
You must obey the GNU General Public License in all respects for all other code used.
 | 
			
		||||
Additionally, AlliedModders LLC grants this exception to all derivative works.
 | 
			
		||||
 | 
			
		||||
As an additional special exception to the GNU General Public License 3.0, 
 | 
			
		||||
AlliedModders LLC permits dual-licensing of DERIVATIVE WORKS ONLY (that is, 
 | 
			
		||||
@ -27,7 +26,6 @@ License version 2 (without an "or any higher version" clause) if and only if
 | 
			
		||||
the work was already GNU General Public License 2.0 exclusive.  This clause is 
 | 
			
		||||
provided for backwards compatibility only.
 | 
			
		||||
 | 
			
		||||
A copy of the JIT License is available in JIT.txt.
 | 
			
		||||
A copy of the GNU General Public License 2.0 is available in GPLv2.txt.
 | 
			
		||||
A copy of the GNU General Public License 3.0 is available in GPLv3.txt.
 | 
			
		||||
 | 
			
		||||
@ -35,5 +33,4 @@ SourcePawn is Copyright (C) 2006-2008 AlliedModders LLC.  All rights reserved.
 | 
			
		||||
SourceMod is Copyright (C) 2006-2008 AlliedModders LLC.  All rights reserved.
 | 
			
		||||
Pawn and SMALL are Copyright (C) 1997-2008 ITB CompuPhase.
 | 
			
		||||
Source is Copyright (C) Valve Corporation.
 | 
			
		||||
All trademarks are property of their respective owners in the US and other 
 | 
			
		||||
 | 
			
		||||
All trademarks are property of their respective owners in the US and other countries.
 | 
			
		||||
 | 
			
		||||
@ -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
									
								
							
							
						
						
									
										266
									
								
								plugins/DynamicTargeting.sp
									
									
									
									
									
										Normal 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);
 | 
			
		||||
}
 | 
			
		||||
@ -4,26 +4,26 @@
 | 
			
		||||
 | 
			
		||||
#define ARRAY_STRING_LENGTH 32
 | 
			
		||||
 | 
			
		||||
enum GroupCommands
 | 
			
		||||
enum struct GroupCommands
 | 
			
		||||
{
 | 
			
		||||
	ArrayList:groupListName,
 | 
			
		||||
	ArrayList:groupListCommand	
 | 
			
		||||
};
 | 
			
		||||
	ArrayList groupListName;
 | 
			
		||||
	ArrayList groupListCommand;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int g_groupList[GroupCommands];
 | 
			
		||||
GroupCommands g_groupList;
 | 
			
		||||
int g_groupCount;
 | 
			
		||||
 | 
			
		||||
SMCParser g_configParser;
 | 
			
		||||
 | 
			
		||||
enum Places
 | 
			
		||||
enum struct Places
 | 
			
		||||
{
 | 
			
		||||
	Place_Category,
 | 
			
		||||
	Place_Item,
 | 
			
		||||
	Place_ReplaceNum
 | 
			
		||||
};
 | 
			
		||||
	int category;
 | 
			
		||||
	int item;
 | 
			
		||||
	int replaceNum;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char g_command[MAXPLAYERS+1][CMD_LENGTH];
 | 
			
		||||
int g_currentPlace[MAXPLAYERS+1][Places];
 | 
			
		||||
Places g_currentPlace[MAXPLAYERS+1];
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * What to put in the 'info' menu field (for PlayerList and Player_Team menus only)
 | 
			
		||||
@ -331,11 +331,11 @@ void ParseConfigs()
 | 
			
		||||
	g_configParser.OnKeyValue = KeyValue;
 | 
			
		||||
	g_configParser.OnLeaveSection = EndSection;
 | 
			
		||||
	
 | 
			
		||||
	delete g_groupList[groupListName];
 | 
			
		||||
	delete g_groupList[groupListCommand];
 | 
			
		||||
	delete g_groupList.groupListName;
 | 
			
		||||
	delete g_groupList.groupListCommand;
 | 
			
		||||
	
 | 
			
		||||
	g_groupList[groupListName] = new ArrayList(ARRAY_STRING_LENGTH);
 | 
			
		||||
	g_groupList[groupListCommand] = new ArrayList(ARRAY_STRING_LENGTH);
 | 
			
		||||
	g_groupList.groupListName = new ArrayList(ARRAY_STRING_LENGTH);
 | 
			
		||||
	g_groupList.groupListCommand = new ArrayList(ARRAY_STRING_LENGTH);
 | 
			
		||||
	
 | 
			
		||||
	char configPath[256];
 | 
			
		||||
	BuildPath(Path_SM, configPath, sizeof(configPath), "configs/dynamicmenu/adminmenu_grouping.txt");
 | 
			
		||||
@ -376,13 +376,13 @@ public SMCResult NewSection(SMCParser smc, const char[] name, bool opt_quotes)
 | 
			
		||||
 | 
			
		||||
public SMCResult KeyValue(SMCParser smc, const char[] key, const char[] value, bool key_quotes, bool value_quotes)
 | 
			
		||||
{
 | 
			
		||||
	g_groupList[groupListName].PushString(key);
 | 
			
		||||
	g_groupList[groupListCommand].PushString(value);
 | 
			
		||||
	g_groupList.groupListName.PushString(key);
 | 
			
		||||
	g_groupList.groupListCommand.PushString(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public SMCResult EndSection(SMCParser smc)
 | 
			
		||||
{
 | 
			
		||||
	g_groupCount = g_groupList[groupListName].Length;
 | 
			
		||||
	g_groupCount = g_groupList.groupListName.Length;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public void DynamicMenuCategoryHandler(TopMenu topmenu, 
 | 
			
		||||
@ -421,8 +421,8 @@ public void DynamicMenuItemHandler(TopMenu topmenu,
 | 
			
		||||
		
 | 
			
		||||
		strcopy(g_command[param], sizeof(g_command[]), output.cmd);
 | 
			
		||||
					
 | 
			
		||||
		g_currentPlace[param][Place_Item] = location;
 | 
			
		||||
		g_currentPlace[param][Place_ReplaceNum] = 1;
 | 
			
		||||
		g_currentPlace[param].item = location;
 | 
			
		||||
		g_currentPlace[param].replaceNum = 1;
 | 
			
		||||
		
 | 
			
		||||
		ParamCheck(param);
 | 
			
		||||
	}
 | 
			
		||||
@ -436,19 +436,19 @@ public void ParamCheck(int client)
 | 
			
		||||
	Item outputItem;
 | 
			
		||||
	Submenu outputSubmenu;
 | 
			
		||||
	
 | 
			
		||||
	g_DataArray.GetArray(g_currentPlace[client][Place_Item], outputItem);
 | 
			
		||||
	g_DataArray.GetArray(g_currentPlace[client].item, outputItem);
 | 
			
		||||
		
 | 
			
		||||
	if (g_currentPlace[client][Place_ReplaceNum] < 1)
 | 
			
		||||
	if (g_currentPlace[client].replaceNum < 1)
 | 
			
		||||
	{
 | 
			
		||||
		g_currentPlace[client][Place_ReplaceNum] = 1;
 | 
			
		||||
		g_currentPlace[client].replaceNum = 1;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	Format(buffer, 5, "#%i", g_currentPlace[client][Place_ReplaceNum]);
 | 
			
		||||
	Format(buffer2, 5, "@%i", g_currentPlace[client][Place_ReplaceNum]);
 | 
			
		||||
	Format(buffer, 5, "#%i", g_currentPlace[client].replaceNum);
 | 
			
		||||
	Format(buffer2, 5, "@%i", g_currentPlace[client].replaceNum);
 | 
			
		||||
	
 | 
			
		||||
	if (StrContains(g_command[client], buffer) != -1 || StrContains(g_command[client], buffer2) != -1)
 | 
			
		||||
	{
 | 
			
		||||
		outputItem.submenus.GetArray(g_currentPlace[client][Place_ReplaceNum] - 1, outputSubmenu);
 | 
			
		||||
		outputItem.submenus.GetArray(g_currentPlace[client].replaceNum - 1, outputSubmenu);
 | 
			
		||||
		
 | 
			
		||||
		Menu itemMenu = new Menu(Menu_Selection);
 | 
			
		||||
		itemMenu.ExitBackButton = true;
 | 
			
		||||
@ -460,8 +460,8 @@ public void ParamCheck(int client)
 | 
			
		||||
		
 | 
			
		||||
			for (int i = 0; i<g_groupCount; i++)
 | 
			
		||||
			{			
 | 
			
		||||
				g_groupList[groupListName].GetString(i, nameBuffer, sizeof(nameBuffer));
 | 
			
		||||
				g_groupList[groupListCommand].GetString(i, commandBuffer, sizeof(commandBuffer));
 | 
			
		||||
				g_groupList.groupListName.GetString(i, nameBuffer, sizeof(nameBuffer));
 | 
			
		||||
				g_groupList.groupListCommand.GetString(i, commandBuffer, sizeof(commandBuffer));
 | 
			
		||||
				itemMenu.AddItem(commandBuffer, nameBuffer);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@ -591,7 +591,7 @@ public void ParamCheck(int client)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		g_command[client][0] = '\0';
 | 
			
		||||
		g_currentPlace[client][Place_ReplaceNum] = 1;
 | 
			
		||||
		g_currentPlace[client].replaceNum = 1;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -622,16 +622,16 @@ public int Menu_Selection(Menu menu, MenuAction action, int param1, int param2)
 | 
			
		||||
		char infobuffer[NAME_LENGTH+2];
 | 
			
		||||
		Format(infobuffer, sizeof(infobuffer), "\"%s\"", info);
 | 
			
		||||
		
 | 
			
		||||
		Format(buffer, 5, "#%i", g_currentPlace[param1][Place_ReplaceNum]);
 | 
			
		||||
		Format(buffer, 5, "#%i", g_currentPlace[param1].replaceNum);
 | 
			
		||||
		ReplaceString(g_command[param1], sizeof(g_command[]), buffer, infobuffer);
 | 
			
		||||
		//replace #num with the selected option (quoted)
 | 
			
		||||
		
 | 
			
		||||
		Format(buffer, 5, "@%i", g_currentPlace[param1][Place_ReplaceNum]);
 | 
			
		||||
		Format(buffer, 5, "@%i", g_currentPlace[param1].replaceNum);
 | 
			
		||||
		ReplaceString(g_command[param1], sizeof(g_command[]), buffer, info);
 | 
			
		||||
		//replace @num with the selected option (unquoted)
 | 
			
		||||
		
 | 
			
		||||
		// Increment the parameter counter.
 | 
			
		||||
		g_currentPlace[param1][Place_ReplaceNum]++;
 | 
			
		||||
		g_currentPlace[param1].replaceNum++;
 | 
			
		||||
		
 | 
			
		||||
		ParamCheck(param1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -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;	
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -45,6 +45,11 @@ public int MenuHandler_ChangeMap(Menu menu, MenuAction action, int param1, int p
 | 
			
		||||
		char map[PLATFORM_MAX_PATH];
 | 
			
		||||
		
 | 
			
		||||
		menu.GetItem(param2, map, sizeof(map));
 | 
			
		||||
 | 
			
		||||
		if (!map[0])
 | 
			
		||||
		{
 | 
			
		||||
			GetCurrentMap(map, sizeof(map));
 | 
			
		||||
		}
 | 
			
		||||
	
 | 
			
		||||
		ShowActivity2(param1, "[SM] ", "%t", "Changing map", map);
 | 
			
		||||
 | 
			
		||||
@ -156,11 +161,15 @@ int LoadMapList(Menu menu)
 | 
			
		||||
	
 | 
			
		||||
	char map_name[PLATFORM_MAX_PATH];
 | 
			
		||||
	int map_count = GetArraySize(g_map_array);
 | 
			
		||||
 | 
			
		||||
	menu.AddItem("", "Restart Current Map");
 | 
			
		||||
	
 | 
			
		||||
	for (int i = 0; i < map_count; i++)
 | 
			
		||||
	{
 | 
			
		||||
		char displayName[PLATFORM_MAX_PATH];
 | 
			
		||||
		GetArrayString(g_map_array, i, map_name, sizeof(map_name));
 | 
			
		||||
		menu.AddItem(map_name, map_name);
 | 
			
		||||
		GetMapDisplayName(map_name, displayName, sizeof(displayName));
 | 
			
		||||
		menu.AddItem(map_name, displayName);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return map_count;
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										24
									
								
								plugins/include/DynamicTargeting.inc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								plugins/include/DynamicTargeting.inc
									
									
									
									
									
										Normal 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
 | 
			
		||||
@ -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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 | 
			
		||||
@ -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.
 | 
			
		||||
 | 
			
		||||
@ -311,6 +311,9 @@ public void __ext_core_SetNTVOptional()
 | 
			
		||||
	MarkNativeAsOptional("Protobuf.ReadRepeatedMessage");
 | 
			
		||||
	MarkNativeAsOptional("Protobuf.AddMessage");
 | 
			
		||||
 | 
			
		||||
	MarkNativeAsOptional("IsCommandCallback");
 | 
			
		||||
	MarkNativeAsOptional("GetLastProcessTargetString");
 | 
			
		||||
 | 
			
		||||
	VerifyCoreVersion();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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.
 | 
			
		||||
 *
 | 
			
		||||
@ -615,7 +640,10 @@ native int FormatNativeString(int out_param,
 | 
			
		||||
 *
 | 
			
		||||
 * @param data          Data passed to the RequestFrame native.
 | 
			
		||||
 */
 | 
			
		||||
typedef RequestFrameCallback = function void (any data);
 | 
			
		||||
typeset RequestFrameCallback {
 | 
			
		||||
	function void ();
 | 
			
		||||
	function void (any data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Creates a single use Next Frame hook.
 | 
			
		||||
 | 
			
		||||
@ -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.
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -633,6 +633,18 @@ native bool TR_DidHit(Handle hndl=INVALID_HANDLE);
 | 
			
		||||
 */
 | 
			
		||||
native int TR_GetHitGroup(Handle hndl=INVALID_HANDLE);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns in which hitbox the trace collided if any. 
 | 
			
		||||
 *
 | 
			
		||||
 * Note: if the entity that collided with the trace is the world entity, 
 | 
			
		||||
 * then this function doesn't return an hitbox index but a static prop index.
 | 
			
		||||
 *
 | 
			
		||||
 * @param hndl          A trace Handle, or INVALID_HANDLE to use a global trace result.
 | 
			
		||||
 * @return              Hitbox index (Or static prop index).
 | 
			
		||||
 * @error               Invalid Handle.
 | 
			
		||||
 */
 | 
			
		||||
native int TR_GetHitBoxIndex(Handle hndl=INVALID_HANDLE);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Find the normal vector to the collision plane of a trace.
 | 
			
		||||
 *
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
@ -1 +1 @@
 | 
			
		||||
1.10.0
 | 
			
		||||
1.11.0
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	/** 
 | 
			
		||||
 | 
			
		||||
@ -41,7 +41,7 @@
 | 
			
		||||
#include <IAdminSystem.h>
 | 
			
		||||
 | 
			
		||||
#define SMINTERFACE_PLAYERMANAGER_NAME		"IPlayerManager"
 | 
			
		||||
#define SMINTERFACE_PLAYERMANAGER_VERSION	21
 | 
			
		||||
#define SMINTERFACE_PLAYERMANAGER_VERSION	22
 | 
			
		||||
 | 
			
		||||
struct edict_t;
 | 
			
		||||
class IPlayerInfo;
 | 
			
		||||
@ -543,10 +543,17 @@ namespace SourceMod
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Returns the number of players currently connected.
 | 
			
		||||
		 *
 | 
			
		||||
		 * @return				Current number of connected clients.
 | 
			
		||||
		 * @return				Current number of connected players.
 | 
			
		||||
		 */
 | 
			
		||||
		virtual int GetNumPlayers() =0;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Returns the number of clients currently connected.
 | 
			
		||||
		 *
 | 
			
		||||
		 * @return				Current number of connected clients.
 | 
			
		||||
		 */
 | 
			
		||||
		virtual int GetNumClients() =0;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Returns the client index by its userid.
 | 
			
		||||
		 *
 | 
			
		||||
 | 
			
		||||
@ -1 +1 @@
 | 
			
		||||
Subproject commit 2be66bdbdf965ebf19dacc2e0874f81f22fd6fa8
 | 
			
		||||
Subproject commit e00a845c6bc415995ddc4b7ec538d1704fdd0122
 | 
			
		||||
@ -36,7 +36,7 @@
 | 
			
		||||
#include <IShareSys.h>
 | 
			
		||||
 | 
			
		||||
#define SMINTERFACE_SDKHOOKS_NAME		"ISDKHooks"
 | 
			
		||||
#define SMINTERFACE_SDKHOOKS_VERSION	1
 | 
			
		||||
#define SMINTERFACE_SDKHOOKS_VERSION	2
 | 
			
		||||
 | 
			
		||||
class CBaseEntity;
 | 
			
		||||
 | 
			
		||||
@ -71,6 +71,16 @@ namespace SourceMod
 | 
			
		||||
		virtual void OnEntityDestroyed(CBaseEntity *pEntity)
 | 
			
		||||
		{
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief	When an entity is spawned
 | 
			
		||||
		 *
 | 
			
		||||
		 * @param	pEntity		CBaseEntity entity.
 | 
			
		||||
		 * @param	classname	Entity classname.
 | 
			
		||||
		 */
 | 
			
		||||
		virtual void OnEntitySpawned(CBaseEntity *pEntity, const char *classname)
 | 
			
		||||
		{
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
 | 
			
		||||
@ -1 +1 @@
 | 
			
		||||
Subproject commit a98c996b166166350e7f022d2f8db60b1ee2b53e
 | 
			
		||||
Subproject commit 04eafd88631e7a3ba1de6bc7228af0e3d5443f0b
 | 
			
		||||
@ -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',
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user