merged trunk back into 1.1.0 branch for "safety"
--HG-- branch : sourcemod-1.1.0 extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/branches/sourcemod-1.1.0%401721
This commit is contained in:
parent
0601988e80
commit
3f49d29274
@ -38,7 +38,7 @@
|
||||
// Examples: (do not put // in front of real lines, as // means 'comment')
|
||||
//
|
||||
// "STEAM_0:1:16" "bce" //kick, ban, slay for this steam ID, no immunity
|
||||
// "127.0.0.1" "99:z" //all permissions for this ip, immunity value is 99
|
||||
// "!127.0.0.1" "99:z" //all permissions for this ip, immunity value is 99
|
||||
// "BAILOPAN" "abc" "Gab3n" //name BAILOPAN, password "Gab3n": gets reservation, kick, ban
|
||||
//
|
||||
////////////////////////////////
|
||||
|
@ -93,13 +93,6 @@ sm_hide_slots 0
|
||||
// Default: 1
|
||||
sm_chat_mode 1
|
||||
|
||||
// Specifies whether or not non-admins can send private messages to each other
|
||||
// using say @@<target> <message>. Valid values are 0 (disabled) or 1 (enabled)
|
||||
// --
|
||||
// Required: basechat.smx
|
||||
// Default: 1
|
||||
sm_psay_mode 0
|
||||
|
||||
// Specifies whether or not "timeleft" will automaticly be triggered every
|
||||
// x seconds. Valid values are 0 (disabled) to 1800 seconds.
|
||||
// --
|
||||
|
@ -32,6 +32,8 @@
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
|
||||
extern HandleType_t htCellArray;
|
||||
|
||||
class CellArray
|
||||
{
|
||||
public:
|
||||
@ -149,6 +151,11 @@ public:
|
||||
return array;
|
||||
}
|
||||
|
||||
cell_t *base()
|
||||
{
|
||||
return m_Data;
|
||||
}
|
||||
|
||||
private:
|
||||
bool GrowIfNeeded(size_t count)
|
||||
{
|
||||
|
@ -46,7 +46,7 @@ public: //IRecipientFilter
|
||||
int GetRecipientCount() const;
|
||||
int GetRecipientIndex(int slot) const;
|
||||
public:
|
||||
void Initialize(cell_t *ptr, size_t count);
|
||||
void Initialize(const cell_t *ptr, size_t count);
|
||||
void SetToReliable(bool isreliable);
|
||||
void SetToInit(bool isinitmsg);
|
||||
void Reset();
|
||||
@ -98,7 +98,7 @@ inline void CellRecipientFilter::SetToReliable(bool isreliable)
|
||||
m_IsReliable = isreliable;
|
||||
}
|
||||
|
||||
inline void CellRecipientFilter::Initialize(cell_t *ptr, size_t count)
|
||||
inline void CellRecipientFilter::Initialize(const cell_t *ptr, size_t count)
|
||||
{
|
||||
memcpy(m_Players, ptr, count * sizeof(cell_t));
|
||||
m_Size = count;
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "UserMessages.h"
|
||||
#include "PlayerManager.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include "GameConfigs.h"
|
||||
#include <compat_wrappers.h>
|
||||
|
||||
CHalfLife2 g_HL2;
|
||||
@ -308,7 +309,11 @@ bool CHalfLife2::HintTextMsg(int client, const char *msg)
|
||||
return false;
|
||||
}
|
||||
|
||||
pBitBuf->WriteByte(1);
|
||||
const char *pre_byte = g_pGameConf->GetKeyValue("HintTextPreByte");
|
||||
if (pre_byte != NULL && strcmp(pre_byte, "yes") == 0)
|
||||
{
|
||||
pBitBuf->WriteByte(1);
|
||||
}
|
||||
pBitBuf->WriteString(msg);
|
||||
g_UserMsgs.EndMessage();
|
||||
|
||||
|
@ -380,7 +380,9 @@ void Logger::LogError(const char *vafmt, ...)
|
||||
LogToOpenFileEx(fp, vafmt, ap);
|
||||
va_end(ap);
|
||||
fclose(fp);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
char error[255];
|
||||
g_LibSys.GetPlatformError(error, sizeof(error));
|
||||
LogFatal("[SM] Unexpected fatal logging error (file \"%s\")", m_NrmFileName.c_str());
|
||||
|
@ -42,9 +42,15 @@ extern const char *g_RadioNumTable[];
|
||||
CRadioStyle g_RadioMenuStyle;
|
||||
int g_ShowMenuId = -1;
|
||||
bool g_bRadioInit = false;
|
||||
unsigned int g_RadioMenuTimeout = 0;
|
||||
|
||||
CRadioStyle::CRadioStyle() : m_players(new CBaseMenuPlayer[256+1])
|
||||
CRadioStyle::CRadioStyle()
|
||||
{
|
||||
m_players = new CRadioMenuPlayer[256+1];
|
||||
for (size_t i = 0; i < 256+1; i++)
|
||||
{
|
||||
m_players[i].Radio_SetIndex(i);
|
||||
}
|
||||
}
|
||||
|
||||
void CRadioStyle::OnSourceModAllInitialized()
|
||||
@ -73,6 +79,16 @@ void CRadioStyle::OnSourceModLevelChange(const char *mapName)
|
||||
return;
|
||||
}
|
||||
|
||||
const char *val = g_pGameConf->GetKeyValue("RadioMenuTimeout");
|
||||
if (val != NULL)
|
||||
{
|
||||
g_RadioMenuTimeout = atoi(val);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_RadioMenuTimeout = 0;
|
||||
}
|
||||
|
||||
g_Menus.AddStyle(this);
|
||||
g_Menus.SetDefaultStyle(this);
|
||||
|
||||
@ -190,7 +206,9 @@ CRadioDisplay *CRadioStyle::MakeRadioDisplay(CRadioMenu *menu)
|
||||
if (m_FreeDisplays.empty())
|
||||
{
|
||||
display = new CRadioDisplay();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
display = m_FreeDisplays.front();
|
||||
m_FreeDisplays.pop();
|
||||
display->Reset();
|
||||
@ -198,11 +216,51 @@ CRadioDisplay *CRadioStyle::MakeRadioDisplay(CRadioMenu *menu)
|
||||
return display;
|
||||
}
|
||||
|
||||
IMenuPanel *CRadioStyle::MakeRadioDisplay(const char *str, int keys)
|
||||
{
|
||||
CRadioDisplay *pPanel = MakeRadioDisplay(NULL);
|
||||
|
||||
pPanel->DirectSet(str, keys);
|
||||
|
||||
return pPanel;
|
||||
}
|
||||
|
||||
void CRadioStyle::FreeRadioDisplay(CRadioDisplay *display)
|
||||
{
|
||||
m_FreeDisplays.push(display);
|
||||
}
|
||||
|
||||
CRadioMenuPlayer *CRadioStyle::GetRadioMenuPlayer(int client)
|
||||
{
|
||||
return &m_players[client];
|
||||
}
|
||||
|
||||
void CRadioStyle::ProcessWatchList()
|
||||
{
|
||||
if (!g_RadioMenuTimeout)
|
||||
{
|
||||
BaseMenuStyle::ProcessWatchList();
|
||||
return;
|
||||
}
|
||||
|
||||
BaseMenuStyle::ProcessWatchList();
|
||||
|
||||
CRadioMenuPlayer *pPlayer;
|
||||
unsigned int max_clients = g_Players.GetMaxClients();
|
||||
for (unsigned int i = 1; i <= max_clients; i++)
|
||||
{
|
||||
pPlayer = GetRadioMenuPlayer(i);
|
||||
if (!pPlayer->bInMenu || pPlayer->bInExternMenu)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (pPlayer->Radio_NeedsRefresh())
|
||||
{
|
||||
pPlayer->Radio_Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CRadioDisplay::CRadioDisplay()
|
||||
{
|
||||
Reset();
|
||||
@ -228,6 +286,13 @@ void CRadioDisplay::Reset()
|
||||
keys = 0;
|
||||
}
|
||||
|
||||
void CRadioDisplay::DirectSet(const char *str, int keymap)
|
||||
{
|
||||
m_Title.clear();
|
||||
m_BufferText.assign(str);
|
||||
keys = keymap;
|
||||
}
|
||||
|
||||
unsigned int CRadioDisplay::GetCurrentKey()
|
||||
{
|
||||
return m_NextPos;
|
||||
@ -326,17 +391,60 @@ bool CRadioDisplay::CanDrawItem(unsigned int drawFlags)
|
||||
|
||||
void CRadioDisplay::SendRawDisplay(int client, unsigned int time)
|
||||
{
|
||||
char buffer[4096];
|
||||
size_t len;
|
||||
|
||||
len = UTIL_Format(buffer, sizeof(buffer), "%s\n%s", m_Title.c_str(), m_BufferText.c_str());
|
||||
|
||||
cell_t players[1] = {client};
|
||||
|
||||
int _sel_keys = (keys == 0) ? (1<<9) : keys;
|
||||
CRadioMenuPlayer *pPlayer = g_RadioMenuStyle.GetRadioMenuPlayer(client);
|
||||
pPlayer->Radio_Init(_sel_keys, m_Title.c_str(), m_BufferText.c_str());
|
||||
pPlayer->Radio_Refresh();
|
||||
}
|
||||
|
||||
char *ptr = buffer;
|
||||
void CRadioMenuPlayer::Radio_SetIndex(unsigned int index)
|
||||
{
|
||||
m_index = index;
|
||||
}
|
||||
|
||||
bool CRadioMenuPlayer::Radio_NeedsRefresh()
|
||||
{
|
||||
return (gpGlobals->curtime - display_last_refresh >= g_RadioMenuTimeout);
|
||||
}
|
||||
|
||||
void CRadioMenuPlayer::Radio_Init(int keys, const char *title, const char *text)
|
||||
{
|
||||
if (title[0] != '\0')
|
||||
{
|
||||
display_len = UTIL_Format(display_pkt,
|
||||
sizeof(display_pkt),
|
||||
"%s\n%s",
|
||||
title,
|
||||
text);
|
||||
}
|
||||
else
|
||||
{
|
||||
display_len = UTIL_Format(display_pkt,
|
||||
sizeof(display_pkt),
|
||||
"%s",
|
||||
text);
|
||||
}
|
||||
display_keys = keys;
|
||||
}
|
||||
|
||||
void CRadioMenuPlayer::Radio_Refresh()
|
||||
{
|
||||
cell_t players[1] = {m_index};
|
||||
char *ptr = display_pkt;
|
||||
char save = 0;
|
||||
size_t len = display_len;
|
||||
unsigned int time;
|
||||
|
||||
/* Compute the new time */
|
||||
if (menuHoldTime == 0)
|
||||
{
|
||||
time = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
time = menuHoldTime - (unsigned int)(gpGlobals->curtime - menuStartTime);
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (len > 240)
|
||||
@ -345,7 +453,7 @@ void CRadioDisplay::SendRawDisplay(int client, unsigned int time)
|
||||
ptr[240] = '\0';
|
||||
}
|
||||
bf_write *buffer = g_UserMsgs.StartMessage(g_ShowMenuId, players, 1, USERMSG_BLOCKHOOKS);
|
||||
buffer->WriteWord(_sel_keys);
|
||||
buffer->WriteWord(display_keys);
|
||||
buffer->WriteChar(time ? time : -1);
|
||||
buffer->WriteByte( (len > 240) ? 1 : 0 );
|
||||
buffer->WriteString(ptr);
|
||||
@ -355,10 +463,14 @@ void CRadioDisplay::SendRawDisplay(int client, unsigned int time)
|
||||
ptr[240] = save;
|
||||
ptr = &ptr[240];
|
||||
len -= 240;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
display_last_refresh = gpGlobals->curtime;
|
||||
}
|
||||
|
||||
int CRadioDisplay::GetAmountRemaining()
|
||||
|
@ -47,6 +47,21 @@ using namespace SourceMod;
|
||||
class CRadioDisplay;
|
||||
class CRadioMenu;
|
||||
|
||||
class CRadioMenuPlayer : public CBaseMenuPlayer
|
||||
{
|
||||
public:
|
||||
void Radio_Init(int keys, const char *title, const char *buffer);
|
||||
bool Radio_NeedsRefresh();
|
||||
void Radio_Refresh();
|
||||
void Radio_SetIndex(unsigned int index);
|
||||
private:
|
||||
unsigned int m_index;
|
||||
size_t display_len;
|
||||
char display_pkt[512];
|
||||
int display_keys;
|
||||
float display_last_refresh;
|
||||
};
|
||||
|
||||
class CRadioStyle :
|
||||
public BaseMenuStyle,
|
||||
public SMGlobalClass,
|
||||
@ -61,6 +76,7 @@ public: //SMGlobalClass
|
||||
public: //BaseMenuStyle
|
||||
CBaseMenuPlayer *GetMenuPlayer(int client);
|
||||
void SendDisplay(int client, IMenuPanel *display);
|
||||
void ProcessWatchList();
|
||||
public: //IMenuStyle
|
||||
const char *GetStyleName();
|
||||
IMenuPanel *CreatePanel();
|
||||
@ -75,8 +91,10 @@ public:
|
||||
public:
|
||||
CRadioDisplay *MakeRadioDisplay(CRadioMenu *menu=NULL);
|
||||
void FreeRadioDisplay(CRadioDisplay *display);
|
||||
CRadioMenuPlayer *GetRadioMenuPlayer(int client);
|
||||
IMenuPanel *MakeRadioDisplay(const char *str, int keys);
|
||||
private:
|
||||
CBaseMenuPlayer *m_players;
|
||||
CRadioMenuPlayer *m_players;
|
||||
CStack<CRadioDisplay *> m_FreeDisplays;
|
||||
};
|
||||
|
||||
@ -101,6 +119,8 @@ public: //IMenuPanel
|
||||
unsigned int GetCurrentKey();
|
||||
bool SetCurrentKey(unsigned int key);
|
||||
int GetAmountRemaining();
|
||||
public:
|
||||
void DirectSet(const char *str, int keymap);
|
||||
private:
|
||||
String m_BufferText;
|
||||
String m_Title;
|
||||
|
@ -1295,12 +1295,32 @@ void CPlayer::Authorize_Post()
|
||||
|
||||
void CPlayer::DoPostConnectAuthorization()
|
||||
{
|
||||
bool delay = false;
|
||||
|
||||
List<IClientListener *>::iterator iter;
|
||||
for (iter = g_Players.m_hooks.begin();
|
||||
iter != g_Players.m_hooks.end();
|
||||
iter++)
|
||||
{
|
||||
IClientListener *pListener = (*iter);
|
||||
#if defined MIN_API_FOR_ADMINCALLS
|
||||
if (pListener->GetClientListenerVersion() < MIN_API_FOR_ADMINCALLS)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if (!pListener->OnClientPreAdminCheck(m_iIndex))
|
||||
{
|
||||
delay = true;
|
||||
}
|
||||
}
|
||||
|
||||
cell_t result = 0;
|
||||
PreAdminCheck->PushCell(m_iIndex);
|
||||
PreAdminCheck->Execute(&result);
|
||||
|
||||
/* Defer, for better or worse */
|
||||
if ((ResultType)result >= Pl_Handled)
|
||||
if (delay || (ResultType)result >= Pl_Handled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -1318,6 +1338,15 @@ void CPlayer::DoPostConnectAuthorization()
|
||||
NotifyPostAdminChecks();
|
||||
}
|
||||
|
||||
bool CPlayer::RunAdminCacheChecks()
|
||||
{
|
||||
AdminId old_id = GetAdminId();
|
||||
|
||||
DoBasicAdminChecks();
|
||||
|
||||
return (GetAdminId() != old_id);
|
||||
}
|
||||
|
||||
void CPlayer::NotifyPostAdminChecks()
|
||||
{
|
||||
if (m_bAdminCheckSignalled)
|
||||
@ -1328,6 +1357,21 @@ void CPlayer::NotifyPostAdminChecks()
|
||||
/* Block beforehand so they can't double-call */
|
||||
m_bAdminCheckSignalled = true;
|
||||
|
||||
List<IClientListener *>::iterator iter;
|
||||
for (iter = g_Players.m_hooks.begin();
|
||||
iter != g_Players.m_hooks.end();
|
||||
iter++)
|
||||
{
|
||||
IClientListener *pListener = (*iter);
|
||||
#if defined MIN_API_FOR_ADMINCALLS
|
||||
if (pListener->GetClientListenerVersion() < MIN_API_FOR_ADMINCALLS)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
pListener->OnClientPostAdminCheck(m_iIndex);
|
||||
}
|
||||
|
||||
PostAdminCheck->PushCell(m_iIndex);
|
||||
PostAdminCheck->Execute(NULL);
|
||||
}
|
||||
|
@ -48,6 +48,8 @@ using namespace SourceHook;
|
||||
#define PLAYER_LIFE_ALIVE 1
|
||||
#define PLAYER_LIFE_DEAD 2
|
||||
|
||||
#define MIN_API_FOR_ADMINCALLS 7
|
||||
|
||||
class CPlayer : public IGamePlayer
|
||||
{
|
||||
friend class PlayerManager;
|
||||
@ -69,8 +71,9 @@ public:
|
||||
IPlayerInfo *GetPlayerInfo();
|
||||
unsigned int GetLanguageId();
|
||||
int GetUserId();
|
||||
public:
|
||||
bool RunAdminCacheChecks();
|
||||
void NotifyPostAdminChecks();
|
||||
public:
|
||||
void DoBasicAdminChecks();
|
||||
bool IsInKickQueue();
|
||||
void MarkAsBeingKicked();
|
||||
@ -108,6 +111,7 @@ class PlayerManager :
|
||||
public SMGlobalClass,
|
||||
public IPlayerManager
|
||||
{
|
||||
friend class CPlayer;
|
||||
public:
|
||||
PlayerManager();
|
||||
~PlayerManager();
|
||||
|
@ -48,16 +48,16 @@ SH_DECL_HOOK2_void(ICvar, CallGlobalChangeCallbacks, SH_NOATTRIB, false, ConVar
|
||||
#endif
|
||||
|
||||
TimerSystem g_Timers;
|
||||
float g_fUniversalTime = 0.0f;
|
||||
double g_fUniversalTime = 0.0f;
|
||||
float g_fGameStartTime = 0.0f; /* Game game start time, non-universal */
|
||||
float g_fTimerThink = 0.0f; /* Timer's next think time */
|
||||
const float *g_pUniversalTime = &g_fUniversalTime;
|
||||
double g_fTimerThink = 0.0f; /* Timer's next think time */
|
||||
const double *g_pUniversalTime = &g_fUniversalTime;
|
||||
ConVar *mp_timelimit = NULL;
|
||||
int g_TimeLeftMode = 0;
|
||||
|
||||
ConVar sm_time_adjustment("sm_time_adjustment", "0", 0, "Adjusts the server time in seconds");
|
||||
|
||||
inline float GetSimulatedTime()
|
||||
inline double GetSimulatedTime()
|
||||
{
|
||||
return g_fUniversalTime;
|
||||
}
|
||||
@ -159,7 +159,7 @@ private:
|
||||
* that a drastic jump in time will continue acting normally. Users
|
||||
* may not expect this, but... I think it is the best solution.
|
||||
*/
|
||||
inline float CalcNextThink(float last, float interval)
|
||||
inline double CalcNextThink(double last, float interval)
|
||||
{
|
||||
if (g_fUniversalTime - last - interval <= TIMER_MIN_ACCURACY)
|
||||
{
|
||||
@ -274,7 +274,7 @@ void TimerSystem::RunFrame()
|
||||
ITimer *pTimer;
|
||||
TimerIter iter;
|
||||
|
||||
float curtime = GetSimulatedTime();
|
||||
double curtime = GetSimulatedTime();
|
||||
for (iter=m_SingleTimers.begin(); iter!=m_SingleTimers.end(); )
|
||||
{
|
||||
pTimer = (*iter);
|
||||
|
@ -51,7 +51,7 @@ public:
|
||||
ITimedEvent *m_Listener;
|
||||
void *m_pData;
|
||||
float m_Interval;
|
||||
float m_ToExec;
|
||||
double m_ToExec;
|
||||
int m_Flags;
|
||||
bool m_InExec;
|
||||
bool m_KillMe;
|
||||
@ -103,7 +103,7 @@ private:
|
||||
|
||||
time_t GetAdjustedTime(time_t *buf = NULL);
|
||||
|
||||
extern const float *g_pUniversalTime;
|
||||
extern const double *g_pUniversalTime;
|
||||
extern TimerSystem g_Timers;
|
||||
extern int g_TimeLeftMode;
|
||||
|
||||
|
@ -135,7 +135,7 @@ bool UserMessages::GetMessageName(int msgid, char *buffer, size_t maxlength) con
|
||||
return false;
|
||||
}
|
||||
|
||||
bf_write *UserMessages::StartMessage(int msg_id, cell_t players[], unsigned int playersNum, int flags)
|
||||
bf_write *UserMessages::StartMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags)
|
||||
{
|
||||
bf_write *buffer;
|
||||
|
||||
|
@ -69,7 +69,7 @@ public: //IUserMessages
|
||||
bool GetMessageName(int msgid, char *buffer, size_t maxlength) const;
|
||||
bool HookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept=false);
|
||||
bool UnhookUserMessage(int msg_id, IUserMessageListener *pListener, bool intercept=false);
|
||||
bf_write *StartMessage(int msg_id, cell_t players[], unsigned int playersNum, int flags);
|
||||
bf_write *StartMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags);
|
||||
bool EndMessage();
|
||||
public:
|
||||
bf_write *OnStartMessage_Pre(IRecipientFilter *filter, int msg_type);
|
||||
|
@ -290,6 +290,34 @@ CON_COMMAND(sm, "SourceMod Menu")
|
||||
g_RootMenu.GotRootCmd(args);
|
||||
}
|
||||
|
||||
FILE *g_pHndlLog = NULL;
|
||||
|
||||
void write_handles_to_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(g_pHndlLog, fmt, ap);
|
||||
fprintf(g_pHndlLog, "\n");
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void write_handles_to_game(const char *fmt, ...)
|
||||
{
|
||||
size_t len;
|
||||
va_list ap;
|
||||
char buffer[1024];
|
||||
|
||||
va_start(ap, fmt);
|
||||
len = UTIL_FormatArgs(buffer, sizeof(buffer)-2, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
buffer[len] = '\n';
|
||||
buffer[len+1] = '\0';
|
||||
|
||||
engine->LogPrint(buffer);
|
||||
}
|
||||
|
||||
CON_COMMAND(sm_dump_handles, "Dumps Handle usage to a file for finding Handle leaks")
|
||||
{
|
||||
#if !defined ORANGEBOX_BUILD
|
||||
@ -297,19 +325,28 @@ CON_COMMAND(sm_dump_handles, "Dumps Handle usage to a file for finding Handle le
|
||||
#endif
|
||||
if (args.ArgC() < 2)
|
||||
{
|
||||
g_RootMenu.ConsolePrint("Usage: sm_dump_handles <file>");
|
||||
g_RootMenu.ConsolePrint("Usage: sm_dump_handles <file> or <log> for game logs");
|
||||
return;
|
||||
}
|
||||
|
||||
const char *arg = args.Arg(1);
|
||||
FILE *fp = fopen(arg, "wt");
|
||||
if (!fp)
|
||||
if (strcmp(args.Arg(1), "log") != 0)
|
||||
{
|
||||
g_RootMenu.ConsolePrint("Could not find file \"%s\"", arg);
|
||||
return;
|
||||
const char *arg = args.Arg(1);
|
||||
FILE *fp = fopen(arg, "wt");
|
||||
if (!fp)
|
||||
{
|
||||
g_RootMenu.ConsolePrint("Could not find file \"%s\"", arg);
|
||||
return;
|
||||
}
|
||||
|
||||
g_pHndlLog = fp;
|
||||
g_HandleSys.Dump(write_handles_to_log);
|
||||
g_pHndlLog = NULL;
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_HandleSys.Dump(write_handles_to_game);
|
||||
}
|
||||
|
||||
g_HandleSys.Dump(fp);
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
@ -207,7 +207,9 @@ void AddString(char **buf_p, size_t &maxlen, const char *string, int width, int
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
while (string[size++]);
|
||||
size--;
|
||||
}
|
||||
@ -234,78 +236,125 @@ void AddString(char **buf_p, size_t &maxlen, const char *string, int width, int
|
||||
*buf_p = buf;
|
||||
}
|
||||
|
||||
void AddFloat(char **buf_p, size_t &maxlen, double fval, int width, int prec)
|
||||
void AddFloat(char **buf_p, size_t &maxlen, double fval, int width, int prec, int flags)
|
||||
{
|
||||
char text[32];
|
||||
int digits;
|
||||
double signedVal;
|
||||
char *buf;
|
||||
int val;
|
||||
|
||||
// get the sign
|
||||
signedVal = fval;
|
||||
if (fval < 0)
|
||||
{
|
||||
fval = -fval;
|
||||
}
|
||||
|
||||
// write the float number
|
||||
digits = 0;
|
||||
val = (int)fval;
|
||||
do
|
||||
{
|
||||
text[digits++] = '0' + val % 10;
|
||||
val /= 10;
|
||||
} while (val);
|
||||
|
||||
if (signedVal < 0)
|
||||
{
|
||||
text[digits++] = '-';
|
||||
}
|
||||
|
||||
buf = *buf_p;
|
||||
|
||||
while ((digits < width) && maxlen)
|
||||
{
|
||||
*buf++ = ' ';
|
||||
width--;
|
||||
maxlen--;
|
||||
}
|
||||
|
||||
while ((digits--) && maxlen)
|
||||
{
|
||||
*buf++ = text[digits];
|
||||
maxlen--;
|
||||
}
|
||||
|
||||
*buf_p = buf;
|
||||
int digits; // non-fraction part digits
|
||||
double tmp; // temporary
|
||||
char *buf = *buf_p; // output buffer pointer
|
||||
int val; // temporary
|
||||
int sign = 0; // 0: positive, 1: negative
|
||||
int fieldlength; // for padding
|
||||
int significant_digits = 0; // number of significant digits written
|
||||
const int MAX_SIGNIFICANT_DIGITS = 16;
|
||||
|
||||
// default precision
|
||||
if (prec < 0)
|
||||
{
|
||||
prec = 6;
|
||||
}
|
||||
// write the fraction
|
||||
digits = 0;
|
||||
while (digits < prec)
|
||||
|
||||
// get the sign
|
||||
if (fval < 0)
|
||||
{
|
||||
fval -= (int)fval;
|
||||
fval *= 10.0;
|
||||
val = (int)fval;
|
||||
text[digits++] = '0' + val % 10;
|
||||
fval = -fval;
|
||||
sign = 1;
|
||||
}
|
||||
|
||||
if ((digits > 0) && maxlen)
|
||||
// compute whole-part digits count
|
||||
digits = (int)log10(fval) + 1;
|
||||
|
||||
// Only print 0.something if 0 < fval < 1
|
||||
if (digits < 1)
|
||||
{
|
||||
buf = *buf_p;
|
||||
*buf++ = '.';
|
||||
digits = 1;
|
||||
}
|
||||
|
||||
// compute the field length
|
||||
fieldlength = digits + prec + ((prec > 0) ? 1 : 0) + sign;
|
||||
|
||||
// minus sign BEFORE left padding if padding with zeros
|
||||
if (sign && maxlen && (flags & ZEROPAD))
|
||||
{
|
||||
*buf++ = '-';
|
||||
maxlen--;
|
||||
for (prec = 0; maxlen && (prec < digits); prec++)
|
||||
}
|
||||
|
||||
// right justify if required
|
||||
if ((flags & LADJUST) == 0)
|
||||
{
|
||||
while ((fieldlength < width) && maxlen)
|
||||
{
|
||||
*buf++ = text[prec];
|
||||
*buf++ = (flags & ZEROPAD) ? '0' : ' ';
|
||||
width--;
|
||||
maxlen--;
|
||||
}
|
||||
*buf_p = buf;
|
||||
}
|
||||
|
||||
// minus sign AFTER left padding if padding with spaces
|
||||
if (sign && maxlen && !(flags & ZEROPAD))
|
||||
{
|
||||
*buf++ = '-';
|
||||
maxlen--;
|
||||
}
|
||||
|
||||
// write the whole part
|
||||
tmp = pow(10.0, digits-1);
|
||||
while ((digits--) && maxlen)
|
||||
{
|
||||
if (++significant_digits > MAX_SIGNIFICANT_DIGITS)
|
||||
{
|
||||
*buf++ = '0';
|
||||
}
|
||||
else
|
||||
{
|
||||
val = (int)(fval / tmp);
|
||||
*buf++ = '0' + val;
|
||||
fval -= val * tmp;
|
||||
tmp *= 0.1;
|
||||
}
|
||||
maxlen--;
|
||||
}
|
||||
|
||||
// write the fraction part
|
||||
if (maxlen)
|
||||
{
|
||||
*buf++ = '.';
|
||||
maxlen--;
|
||||
}
|
||||
|
||||
tmp = pow(10.0, prec);
|
||||
|
||||
fval *= tmp;
|
||||
while (prec-- && maxlen)
|
||||
{
|
||||
if (++significant_digits > MAX_SIGNIFICANT_DIGITS)
|
||||
{
|
||||
*buf++ = '0';
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp *= 0.1;
|
||||
val = (int)(fval / tmp);
|
||||
*buf++ = '0' + val;
|
||||
fval -= val * tmp;
|
||||
}
|
||||
maxlen--;
|
||||
}
|
||||
|
||||
// left justify if required
|
||||
if (flags & LADJUST)
|
||||
{
|
||||
while ((fieldlength < width) && maxlen)
|
||||
{
|
||||
// right-padding only with spaces, ZEROPAD is ignored
|
||||
*buf++ = ' ';
|
||||
width--;
|
||||
maxlen--;
|
||||
}
|
||||
}
|
||||
|
||||
// update parent's buffer pointer
|
||||
*buf_p = buf;
|
||||
}
|
||||
|
||||
void AddUInt(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
|
||||
@ -366,9 +415,12 @@ void AddInt(char **buf_p, size_t &maxlen, int val, int width, int flags)
|
||||
{
|
||||
/* we want the unsigned version */
|
||||
unsignedVal = abs(val);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
unsignedVal = val;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
text[digits++] = '0' + unsignedVal % 10;
|
||||
@ -422,7 +474,9 @@ void AddHex(char **buf_p, size_t &maxlen, unsigned int val, int width, int flags
|
||||
if (flags & UPPERDIGITS)
|
||||
{
|
||||
hexadjust = 'A' - '9' - 1;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
hexadjust = 'a' - '9' - 1;
|
||||
}
|
||||
|
||||
@ -587,7 +641,7 @@ reswitch:
|
||||
case 'f':
|
||||
{
|
||||
float *value = (float *)args[arg];
|
||||
AddFloat(&buf_p, llen, *value, width, prec);
|
||||
AddFloat(&buf_p, llen, *value, width, prec, flags);
|
||||
arg++;
|
||||
break;
|
||||
}
|
||||
@ -779,7 +833,7 @@ reswitch:
|
||||
CHECK_ARGS(0);
|
||||
cell_t *value;
|
||||
pCtx->LocalToPhysAddr(params[arg], &value);
|
||||
AddFloat(&buf_p, llen, sp_ctof(*value), width, prec);
|
||||
AddFloat(&buf_p, llen, sp_ctof(*value), width, prec, flags);
|
||||
arg++;
|
||||
break;
|
||||
}
|
||||
@ -808,7 +862,9 @@ reswitch:
|
||||
player->GetName(),
|
||||
userid,
|
||||
auth);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
UTIL_Format(buffer,
|
||||
sizeof(buffer),
|
||||
"Console<0><Console><Console>");
|
||||
@ -964,7 +1020,9 @@ const char *stristr(const char *str, const char *substr)
|
||||
{
|
||||
return prevloc;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
haystack = ++prevloc;
|
||||
needle = (char *)substr;
|
||||
}
|
||||
@ -1001,7 +1059,9 @@ size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
|
||||
{
|
||||
buffer[maxlength - 1] = '\0';
|
||||
return (maxlength - 1);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return len;
|
||||
}
|
||||
}
|
||||
@ -1014,7 +1074,9 @@ size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list
|
||||
{
|
||||
buffer[maxlength - 1] = '\0';
|
||||
return (maxlength - 1);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return len;
|
||||
}
|
||||
}
|
||||
@ -1117,7 +1179,9 @@ char *UTIL_ReplaceEx(char *subject, size_t maxLen, const char *search, size_t se
|
||||
replaceLen = maxLen - browsed;
|
||||
/* Note, we add one to the final result for the null terminator */
|
||||
strncopy(ptr, replace, replaceLen+1);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* EXAMPLE CASE:
|
||||
* Subject: AABBBCCC
|
||||
* Buffer : 12 bytes
|
||||
@ -1138,7 +1202,9 @@ char *UTIL_ReplaceEx(char *subject, size_t maxLen, const char *search, size_t se
|
||||
/* Now, do our replacement. */
|
||||
memcpy(ptr, replace, replaceLen);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* EXAMPLE CASE:
|
||||
* Subject: AABBBCCC
|
||||
* Buffer : 12 bytes
|
||||
@ -1158,7 +1224,9 @@ char *UTIL_ReplaceEx(char *subject, size_t maxLen, const char *search, size_t se
|
||||
/* Now do our replacement. */
|
||||
memcpy(ptr, replace, replaceLen);
|
||||
}
|
||||
} else if (replaceLen < searchLen) {
|
||||
}
|
||||
else if (replaceLen < searchLen)
|
||||
{
|
||||
/* EXAMPLE CASE:
|
||||
* Subject: AABBBCCC
|
||||
* Buffer : 12 bytes
|
||||
@ -1184,7 +1252,9 @@ char *UTIL_ReplaceEx(char *subject, size_t maxLen, const char *search, size_t se
|
||||
|
||||
/* Move the rest of the string down */
|
||||
memmove(moveTo, moveFrom, bytesToCopy);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* EXAMPLE CASE:
|
||||
* Subject: AABBBCCC
|
||||
* Buffer : 12 bytes
|
||||
|
@ -406,6 +406,33 @@ static cell_t smn_KvJumpToKey(IPluginContext *pCtx, const cell_t *params)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t smn_KvJumpToKeySymbol(IPluginContext *pCtx, const cell_t *params)
|
||||
{
|
||||
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
||||
HandleError herr;
|
||||
HandleSecurity sec;
|
||||
KeyValueStack *pStk;
|
||||
|
||||
sec.pOwner = NULL;
|
||||
sec.pIdentity = g_pCoreIdent;
|
||||
|
||||
if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
|
||||
}
|
||||
|
||||
KeyValues *pSubKey = pStk->pCurRoot.front();
|
||||
pSubKey = pSubKey->FindKey(params[2]);
|
||||
if (!pSubKey)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
pStk->pCurRoot.push(pSubKey);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t smn_KvGotoFirstSubKey(IPluginContext *pCtx, const cell_t *params)
|
||||
{
|
||||
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
||||
@ -921,6 +948,36 @@ static cell_t smn_FindKeyById(IPluginContext *pContext, const cell_t *params)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t smn_KvGetSectionSymbol(IPluginContext *pCtx, const cell_t *params)
|
||||
{
|
||||
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
||||
HandleError herr;
|
||||
HandleSecurity sec;
|
||||
KeyValueStack *pStk;
|
||||
cell_t *val;
|
||||
|
||||
sec.pOwner = NULL;
|
||||
sec.pIdentity = g_pCoreIdent;
|
||||
|
||||
if ((herr=g_HandleSys.ReadHandle(hndl, g_KeyValueType, &sec, (void **)&pStk))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
|
||||
}
|
||||
|
||||
KeyValues *pSection = pStk->pCurRoot.front();
|
||||
|
||||
pCtx->LocalToPhysAddr(params[2], &val);
|
||||
*val = pSection->GetNameSymbol();
|
||||
|
||||
if (!*val)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static KeyValueNatives s_KeyValueNatives;
|
||||
|
||||
REGISTER_NATIVES(keyvaluenatives)
|
||||
@ -937,6 +994,7 @@ REGISTER_NATIVES(keyvaluenatives)
|
||||
{"KvGetUInt64", smn_KvGetUInt64},
|
||||
{"CreateKeyValues", smn_CreateKeyValues},
|
||||
{"KvJumpToKey", smn_KvJumpToKey},
|
||||
{"KvJumpToKeySymbol", smn_KvJumpToKeySymbol},
|
||||
{"KvGotoNextKey", smn_KvGotoNextKey},
|
||||
{"KvJumpFirstSubKey", smn_KvGotoFirstSubKey}, /* BACKWARDS COMPAT SHIM */
|
||||
{"KvGotoFirstSubKey", smn_KvGotoFirstSubKey},
|
||||
@ -956,5 +1014,6 @@ REGISTER_NATIVES(keyvaluenatives)
|
||||
{"KvCopySubkeys", smn_CopySubkeys},
|
||||
{"KvFindKeyById", smn_FindKeyById},
|
||||
{"KvGetNameSymbol", smn_GetNameSymbol},
|
||||
{"KvGetSectionSymbol", smn_KvGetSectionSymbol},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "MenuStyle_Radio.h"
|
||||
#include "HandleSys.h"
|
||||
#include "PluginSys.h"
|
||||
#include "PlayerManager.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include "sourcemm_api.h"
|
||||
#if defined MENU_DEBUG
|
||||
@ -1398,6 +1399,73 @@ static cell_t GetMenuSelectionPosition(IPluginContext *pContext, const cell_t *p
|
||||
return *s_CurSelectPosition;
|
||||
}
|
||||
|
||||
class EmptyMenuHandler : public IMenuHandler
|
||||
{
|
||||
public:
|
||||
} s_EmptyMenuHandler;
|
||||
|
||||
static cell_t InternalShowMenu(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
int client = params[1];
|
||||
CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
|
||||
|
||||
if (pPlayer == NULL)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid client index %d", client);
|
||||
}
|
||||
else if (!pPlayer->IsInGame())
|
||||
{
|
||||
return pContext->ThrowNativeError("Client %d is not in game", client);
|
||||
}
|
||||
|
||||
if (!g_RadioMenuStyle.IsSupported())
|
||||
{
|
||||
return pContext->ThrowNativeError("Radio menus are not supported on this mod");
|
||||
}
|
||||
|
||||
char *str;
|
||||
pContext->LocalToString(params[2], &str);
|
||||
|
||||
IMenuPanel *pPanel = g_RadioMenuStyle.MakeRadioDisplay(str, params[4]);
|
||||
|
||||
if (pPanel == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
IMenuHandler *pHandler;
|
||||
CPanelHandler *pActualHandler = NULL;
|
||||
if (params[5] != -1)
|
||||
{
|
||||
IPluginFunction *pFunction = pContext->GetFunctionById(params[5]);
|
||||
if (pFunction == NULL)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid function index %x", params[5]);
|
||||
}
|
||||
pActualHandler = g_MenuHelpers.GetPanelHandler(pFunction);
|
||||
}
|
||||
|
||||
if (pActualHandler == NULL)
|
||||
{
|
||||
pHandler = &s_EmptyMenuHandler;
|
||||
}
|
||||
else
|
||||
{
|
||||
pHandler = pActualHandler;
|
||||
}
|
||||
|
||||
bool bSuccess = pPanel->SendDisplay(client, pHandler, params[3]);
|
||||
|
||||
pPanel->DeleteThis();
|
||||
|
||||
if (!bSuccess && pActualHandler != NULL)
|
||||
{
|
||||
g_MenuHelpers.FreePanelHandler(pActualHandler);
|
||||
}
|
||||
|
||||
return bSuccess ? 1 : 0;
|
||||
}
|
||||
|
||||
REGISTER_NATIVES(menuNatives)
|
||||
{
|
||||
{"AddMenuItem", AddMenuItem},
|
||||
@ -1430,6 +1498,7 @@ REGISTER_NATIVES(menuNatives)
|
||||
{"GetPanelCurrentKey", GetPanelCurrentKey},
|
||||
{"GetPanelStyle", GetPanelStyle},
|
||||
{"InsertMenuItem", InsertMenuItem},
|
||||
{"InternalShowMenu", InternalShowMenu},
|
||||
{"IsVoteInProgress", IsVoteInProgress},
|
||||
{"RedrawMenuItem", RedrawMenuItem},
|
||||
{"RemoveAllMenuItems", RemoveAllMenuItems},
|
||||
|
@ -259,7 +259,7 @@ static cell_t SetUserAdmin(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
return pContext->ThrowNativeError("Client %d is not connected", client);
|
||||
}
|
||||
if (!g_Admins.IsValidAdmin(params[2]))
|
||||
if (!g_Admins.IsValidAdmin(params[2]) && params[2] != INVALID_ADMIN_ID)
|
||||
{
|
||||
return pContext->ThrowNativeError("AdminId %x is invalid", params[2]);
|
||||
}
|
||||
|
@ -33,6 +33,8 @@
|
||||
#include <IHandleSys.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "HandleSys.h"
|
||||
#include "CellArray.h"
|
||||
|
||||
/***********************************
|
||||
* About the double array hack *
|
||||
@ -373,6 +375,139 @@ static cell_t sm_SortCustom2D(IPluginContext *pContext, const cell_t *params)
|
||||
return 1;
|
||||
}
|
||||
|
||||
enum SortType
|
||||
{
|
||||
Sort_Integer = 0,
|
||||
Sort_Float,
|
||||
Sort_String,
|
||||
};
|
||||
|
||||
int sort_adtarray_strings_asc(const void *str1, const void *str2)
|
||||
{
|
||||
return strcmp((char *) str1, (char *) str2);
|
||||
}
|
||||
|
||||
int sort_adtarray_strings_desc(const void *str1, const void *str2)
|
||||
{
|
||||
return strcmp((char *) str2, (char *) str1);
|
||||
}
|
||||
|
||||
static cell_t sm_SortADTArray(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
CellArray *cArray;
|
||||
HandleError err;
|
||||
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
|
||||
|
||||
if ((err = g_HandleSys.ReadHandle(params[1], htCellArray, &sec, (void **)&cArray))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
cell_t order = params[2];
|
||||
cell_t type = params[3];
|
||||
size_t arraysize = cArray->size();
|
||||
size_t blocksize = cArray->blocksize();
|
||||
cell_t *array = cArray->base();
|
||||
|
||||
if (type == Sort_Integer)
|
||||
{
|
||||
if (order == Sort_Ascending)
|
||||
{
|
||||
qsort(array, arraysize, blocksize * sizeof(cell_t), sort_ints_asc);
|
||||
}
|
||||
else
|
||||
{
|
||||
qsort(array, arraysize, blocksize * sizeof(cell_t), sort_ints_desc);
|
||||
}
|
||||
}
|
||||
else if (type == Sort_Float)
|
||||
{
|
||||
if (order == Sort_Ascending)
|
||||
{
|
||||
qsort(array, arraysize, blocksize * sizeof(cell_t), sort_floats_asc);
|
||||
}
|
||||
else
|
||||
{
|
||||
qsort(array, arraysize, blocksize * sizeof(cell_t), sort_floats_desc);
|
||||
}
|
||||
}
|
||||
else if (type == Sort_String)
|
||||
{
|
||||
if (order == Sort_Ascending)
|
||||
{
|
||||
qsort(array, arraysize, blocksize * sizeof(cell_t), sort_adtarray_strings_asc);
|
||||
}
|
||||
else
|
||||
{
|
||||
qsort(array, arraysize, blocksize * sizeof(cell_t), sort_adtarray_strings_desc);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct sort_infoADT
|
||||
{
|
||||
IPluginFunction *pFunc;
|
||||
cell_t *array_base;
|
||||
cell_t array_bsize;
|
||||
Handle_t array_hndl;
|
||||
Handle_t hndl;
|
||||
};
|
||||
|
||||
sort_infoADT g_SortInfoADT;
|
||||
|
||||
int sort_adtarray_custom(const void *elem1, const void *elem2)
|
||||
{
|
||||
cell_t result = 0;
|
||||
IPluginFunction *pf = g_SortInfoADT.pFunc;
|
||||
pf->PushCell(((cell_t) ((cell_t *) elem1 - g_SortInfoADT.array_base)) / g_SortInfoADT.array_bsize);
|
||||
pf->PushCell(((cell_t) ((cell_t *) elem2 - g_SortInfoADT.array_base)) / g_SortInfoADT.array_bsize);
|
||||
pf->PushCell(g_SortInfoADT.array_hndl);
|
||||
pf->PushCell(g_SortInfoADT.hndl);
|
||||
pf->Execute(&result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static cell_t sm_SortADTArrayCustom(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
CellArray *cArray;
|
||||
HandleError err;
|
||||
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
|
||||
|
||||
if ((err = g_HandleSys.ReadHandle(params[1], htCellArray, &sec, (void **)&cArray))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
|
||||
if (!pFunction)
|
||||
{
|
||||
return pContext->ThrowNativeError("Function %x is not a valid function", params[2]);
|
||||
}
|
||||
|
||||
size_t arraysize = cArray->size();
|
||||
size_t blocksize = cArray->blocksize();
|
||||
cell_t *array = cArray->base();
|
||||
|
||||
sort_infoADT oldinfo = g_SortInfoADT;
|
||||
|
||||
g_SortInfoADT.pFunc = pFunction;
|
||||
g_SortInfoADT.array_base = array;
|
||||
g_SortInfoADT.array_bsize = (cell_t) blocksize;
|
||||
g_SortInfoADT.array_hndl = params[1];
|
||||
g_SortInfoADT.hndl = params[3];
|
||||
|
||||
qsort(array, arraysize, blocksize * sizeof(cell_t), sort_adtarray_custom);
|
||||
|
||||
g_SortInfoADT = oldinfo;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
REGISTER_NATIVES(sortNatives)
|
||||
{
|
||||
{"SortIntegers", sm_SortIntegers},
|
||||
@ -380,5 +515,7 @@ REGISTER_NATIVES(sortNatives)
|
||||
{"SortStrings", sm_SortStrings},
|
||||
{"SortCustom1D", sm_SortCustom1D},
|
||||
{"SortCustom2D", sm_SortCustom2D},
|
||||
{"SortADTArray", sm_SortADTArray},
|
||||
{"SortADTArrayCustom", sm_SortADTArrayCustom},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
@ -586,9 +586,11 @@ const char *SourceModBase::GetGamePath() const
|
||||
return g_BaseDir.c_str();
|
||||
}
|
||||
|
||||
void SourceModBase::SetGlobalTarget(unsigned int index)
|
||||
unsigned int SourceModBase::SetGlobalTarget(unsigned int index)
|
||||
{
|
||||
unsigned int old = m_target;
|
||||
m_target = index;
|
||||
return old;
|
||||
}
|
||||
|
||||
unsigned int SourceModBase::GetGlobalTarget() const
|
||||
|
@ -83,7 +83,7 @@ public:
|
||||
/**
|
||||
* @brief Stores the global target index.
|
||||
*/
|
||||
void SetGlobalTarget(unsigned int index);
|
||||
unsigned int SetGlobalTarget(unsigned int index);
|
||||
|
||||
/**
|
||||
* @brief Returns the global target index.
|
||||
|
@ -285,7 +285,22 @@ void CExtension::RemovePlugin(IPlugin *pPlugin)
|
||||
if ((*iter).pl == pPlugin)
|
||||
{
|
||||
iter = m_WeakNatives.erase(iter);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
iter = m_ReplacedNatives.begin();
|
||||
while (iter != m_ReplacedNatives.end())
|
||||
{
|
||||
if ((*iter).pl == pPlugin)
|
||||
{
|
||||
iter = m_ReplacedNatives.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
@ -703,6 +718,7 @@ void CExtensionManager::BindAllNativesToPlugin(IPlugin *pPlugin)
|
||||
uint32_t natives = pContext->GetNativesNum();
|
||||
sp_native_t *native;
|
||||
sm_extnative_t *x_native;
|
||||
sm_repnative_t *r_native;
|
||||
for (uint32_t i=0; i<natives; i++)
|
||||
{
|
||||
/* Make sure the native is valid */
|
||||
@ -710,11 +726,26 @@ void CExtensionManager::BindAllNativesToPlugin(IPlugin *pPlugin)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Make sure the native is not already bound */
|
||||
if (native->status == SP_NATIVE_BOUND)
|
||||
{
|
||||
/* If it is bound, see if there is a replacement. */
|
||||
if ((r_native = m_RepNatives.retrieve(native->name)) == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Rewrite the address. Whee! */
|
||||
native->pfn = r_native->info.func;
|
||||
|
||||
/* Make sure this will unload safely */
|
||||
WeakNative wn((CPlugin *)pPlugin, i);
|
||||
r_native->owner->m_ReplacedNatives.push_back(wn);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* See if we've got this native in our cache */
|
||||
if ((x_native = m_ExtNatives.retrieve(native->name)) == NULL)
|
||||
{
|
||||
@ -789,7 +820,7 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
|
||||
g_PluginSys.OnLibraryAction((*s_iter).c_str(), false, true);
|
||||
}
|
||||
|
||||
/* Unbound weak natives */
|
||||
/* Unbind weak natives */
|
||||
List<WeakNative>::iterator wkn_iter;
|
||||
for (wkn_iter=pExt->m_WeakNatives.begin(); wkn_iter!=pExt->m_WeakNatives.end(); wkn_iter++)
|
||||
{
|
||||
@ -798,6 +829,21 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
|
||||
ctx->natives[wkn.idx].status = SP_NATIVE_UNBOUND;
|
||||
}
|
||||
|
||||
/* Unbind replacement natives, link them back to their originals */
|
||||
for (wkn_iter = pExt->m_ReplacedNatives.begin();
|
||||
wkn_iter != pExt->m_ReplacedNatives.end();
|
||||
wkn_iter++)
|
||||
{
|
||||
WeakNative & wkn = (*wkn_iter);
|
||||
sp_context_t *ctx = wkn.pl->GetContext();
|
||||
sm_repnative_t *r_native = m_RepNatives.retrieve(ctx->natives[wkn.idx].name);
|
||||
if (r_native == NULL || ctx->natives[wkn.idx].pfn != r_native->info.func)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
ctx->natives[wkn.idx].pfn = r_native->original;
|
||||
}
|
||||
|
||||
/* Notify and/or unload all dependencies */
|
||||
List<CExtension *>::iterator c_iter;
|
||||
CExtension *pDep;
|
||||
@ -871,6 +917,22 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
|
||||
}
|
||||
}
|
||||
|
||||
/* Unbind our replacement natives */
|
||||
List<sm_repnative_t>::iterator rep_iter = m_RepNativeList.begin();
|
||||
while (rep_iter != m_RepNativeList.end())
|
||||
{
|
||||
sm_repnative_t & r_native = (*rep_iter);
|
||||
if (r_native.owner == pExt)
|
||||
{
|
||||
m_RepNatives.remove(r_native.info.name);
|
||||
rep_iter = m_RepNativeList.erase(rep_iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
rep_iter++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Tell it to unload */
|
||||
pAPI = pExt->GetAPI();
|
||||
pAPI->OnExtensionUnload();
|
||||
@ -919,6 +981,25 @@ void CExtensionManager::AddNatives(IExtension *pOwner, const sp_nativeinfo_t *na
|
||||
}
|
||||
}
|
||||
|
||||
void CExtensionManager::OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives)
|
||||
{
|
||||
SPVM_NATIVE_FUNC orig;
|
||||
|
||||
for (unsigned int i = 0; natives[i].func != NULL && natives[i].name != NULL; i++)
|
||||
{
|
||||
if ((orig = g_PluginSys.FindCoreNative(natives[i].name)) == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
sm_repnative_t rep;
|
||||
rep.info = natives[i];
|
||||
rep.owner = (CExtension *)myself;
|
||||
rep.original = orig;
|
||||
m_RepNativeList.push_back(rep);
|
||||
m_RepNatives.insert(natives[i].name, rep);
|
||||
}
|
||||
}
|
||||
|
||||
void CExtensionManager::MarkAllLoaded()
|
||||
{
|
||||
List<CExtension *>::iterator iter;
|
||||
|
@ -55,6 +55,14 @@ struct sm_extnative_t
|
||||
const sp_nativeinfo_t *info;
|
||||
};
|
||||
|
||||
/* Replacement native */
|
||||
struct sm_repnative_t
|
||||
{
|
||||
CExtension *owner;
|
||||
sp_nativeinfo_t info;
|
||||
SPVM_NATIVE_FUNC original;
|
||||
};
|
||||
|
||||
class CExtension : public IExtension
|
||||
{
|
||||
friend class CExtensionManager;
|
||||
@ -98,6 +106,7 @@ protected:
|
||||
List<IPlugin *> m_Plugins;
|
||||
List<const sp_nativeinfo_t *> m_Natives;
|
||||
List<WeakNative> m_WeakNatives;
|
||||
List<WeakNative> m_ReplacedNatives;
|
||||
List<String> m_Libraries;
|
||||
unsigned int unload_code;
|
||||
bool m_bFullyLoaded;
|
||||
@ -168,6 +177,7 @@ public:
|
||||
void TryAutoload();
|
||||
void AddLibrary(IExtension *pSource, const char *library);
|
||||
bool LibraryExists(const char *library);
|
||||
void OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives);
|
||||
public:
|
||||
CExtension *GetExtensionFromIdent(IdentityToken_t *ptr);
|
||||
void Shutdown();
|
||||
@ -175,6 +185,8 @@ private:
|
||||
CExtension *FindByOrder(unsigned int num);
|
||||
private:
|
||||
List<CExtension *> m_Libs;
|
||||
List<sm_repnative_t> m_RepNativeList;
|
||||
KTrie<sm_repnative_t> m_RepNatives;
|
||||
KTrie<sm_extnative_t> m_ExtNatives;
|
||||
};
|
||||
|
||||
|
@ -994,10 +994,10 @@ bool HandleSystem::TryAndFreeSomeHandles()
|
||||
return g_PluginSys.UnloadPlugin(highest_owner);
|
||||
}
|
||||
|
||||
void HandleSystem::Dump(FILE *fp)
|
||||
void HandleSystem::Dump(HANDLE_REPORTER rep)
|
||||
{
|
||||
fprintf(fp, "%-10.10s\t%-20.20s\t%-20.20s\n", "Handle", "Owner", "Type");
|
||||
fprintf(fp, "---------------------------------------------\n");
|
||||
rep("%-10.10s\t%-20.20s\t%-20.20s", "Handle", "Owner", "Type");
|
||||
rep("---------------------------------------------");
|
||||
for (unsigned int i = 1; i <= m_HandleTail; i++)
|
||||
{
|
||||
if (m_Handles[i].set != HandleSet_Used)
|
||||
@ -1046,7 +1046,7 @@ void HandleSystem::Dump(FILE *fp)
|
||||
{
|
||||
type = m_strtab->GetString(pType->nameIdx);
|
||||
}
|
||||
fprintf(fp, "0x%08x\t%-20.20s\t%-20.20s\n", index, owner, type);
|
||||
rep("0x%08x\t%-20.20s\t%-20.20s", index, owner, type);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,6 +105,8 @@ struct QHandleType
|
||||
int nameIdx;
|
||||
};
|
||||
|
||||
typedef void (HANDLE_REPORTER)(const char *str, ...);
|
||||
|
||||
class HandleSystem :
|
||||
public IHandleSys
|
||||
{
|
||||
@ -155,7 +157,7 @@ public: //IHandleSystem
|
||||
const HandleAccess *pAccess,
|
||||
HandleError *err);
|
||||
|
||||
void Dump(FILE *fp);
|
||||
void Dump(HANDLE_REPORTER rep);
|
||||
protected:
|
||||
/**
|
||||
* Decodes a handle with sanity and security checking.
|
||||
|
@ -1440,6 +1440,18 @@ void CPluginManager::AddCoreNativesToPlugin(CPlugin *pPlugin)
|
||||
}
|
||||
}
|
||||
|
||||
SPVM_NATIVE_FUNC CPluginManager::FindCoreNative(const char *name)
|
||||
{
|
||||
SPVM_NATIVE_FUNC pfn;
|
||||
|
||||
if (!sm_trie_retrieve(m_pCoreNatives, name, (void **)&pfn))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pfn;
|
||||
}
|
||||
|
||||
void CPluginManager::TryRefreshDependencies(CPlugin *pPlugin)
|
||||
{
|
||||
assert(pPlugin->GetBaseContext() != NULL);
|
||||
|
@ -489,6 +489,7 @@ public:
|
||||
}
|
||||
public:
|
||||
bool AddFakeNative(IPluginFunction *pFunction, const char *name, SPVM_FAKENATIVE_FUNC func);
|
||||
SPVM_NATIVE_FUNC FindCoreNative(const char *name);
|
||||
private:
|
||||
void AddFakeNativesToPlugin(CPlugin *pPlugin);
|
||||
void TryRefreshDependencies(CPlugin *pOther);
|
||||
|
@ -243,3 +243,8 @@ void ShareSystem::RegisterLibrary(IExtension *myself, const char *name)
|
||||
{
|
||||
g_Extensions.AddLibrary(myself, name);
|
||||
}
|
||||
|
||||
void ShareSystem::OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives)
|
||||
{
|
||||
g_Extensions.OverrideNatives(myself, natives);
|
||||
}
|
||||
|
@ -81,6 +81,7 @@ public: //IShareSys
|
||||
void DestroyIdentity(IdentityToken_t *identity);
|
||||
void AddDependency(IExtension *myself, const char *filename, bool require, bool autoload);
|
||||
void RegisterLibrary(IExtension *myself, const char *name);
|
||||
void OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives);
|
||||
public: //SMGlobalClass
|
||||
/* Pre-empt in case anything tries to register idents early */
|
||||
void OnSourceModStartup(bool late);
|
||||
|
@ -13,7 +13,7 @@ HL2SDK = ../../../hl2sdk
|
||||
PROJECT = game.cstrike
|
||||
|
||||
#Uncomment for SourceMM-enabled extensions
|
||||
#LINK_HL2 = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so
|
||||
LINK_HL2 = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so
|
||||
|
||||
OBJECTS = sdk/smsdk_ext.cpp extension.cpp natives.cpp RegNatives.cpp timeleft.cpp
|
||||
|
||||
|
@ -13,7 +13,7 @@ HL2SDK = ../../../hl2sdk-ob
|
||||
PROJECT = game.cstrike
|
||||
|
||||
#Uncomment for SourceMM-enabled extensions
|
||||
#LINK_HL2 = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so
|
||||
LINK_HL2 = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so
|
||||
|
||||
OBJECTS = sdk/smsdk_ext.cpp extension.cpp natives.cpp RegNatives.cpp timeleft.cpp
|
||||
|
||||
|
@ -13,7 +13,7 @@ HL2SDK = ../../../hl2sdk
|
||||
PROJECT = game.cstrike
|
||||
|
||||
#Uncomment for SourceMM-enabled extensions
|
||||
#LINK_HL2 = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so
|
||||
LINK_HL2 = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so
|
||||
|
||||
OBJECTS = sdk/smsdk_ext.cpp extension.cpp natives.cpp RegNatives.cpp timeleft.cpp
|
||||
|
||||
|
@ -45,6 +45,7 @@ IBinTools *g_pBinTools = NULL;
|
||||
IGameConfig *g_pGameConf = NULL;
|
||||
IGameEventManager2 *gameevents = NULL;
|
||||
bool hooked_everything = false;
|
||||
int g_msgHintText = -1;
|
||||
|
||||
SMEXT_LINK(&g_CStrike);
|
||||
|
||||
@ -67,6 +68,11 @@ bool CStrike::SDK_OnLoad(char *error, size_t maxlength, bool late)
|
||||
sharesys->AddNatives(myself, g_CSNatives);
|
||||
sharesys->RegisterLibrary(myself, "cstrike");
|
||||
|
||||
if ((g_msgHintText = usermsgs->GetMessageIndex("HintText")) != -1)
|
||||
{
|
||||
sharesys->OverrideNatives(myself, g_CS_PrintHintText);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -122,5 +122,7 @@ public:
|
||||
/* Interfaces from SourceMod */
|
||||
extern IBinTools *g_pBinTools;
|
||||
extern IGameConfig *g_pGameConf;
|
||||
extern int g_msgHintText;
|
||||
extern sp_nativeinfo_t g_CS_PrintHintText[];
|
||||
|
||||
#endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
|
||||
|
@ -69,6 +69,45 @@ inline CBaseEntity *GetCBaseEntity(int num, bool isplayer)
|
||||
return pUnk->GetBaseEntity();
|
||||
}
|
||||
|
||||
static cell_t CS_PrintHintText(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
int client = params[1];
|
||||
IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(params[1]);
|
||||
|
||||
if (!pPlayer)
|
||||
{
|
||||
return pContext->ThrowNativeError("Client index %d is invalid", client);
|
||||
}
|
||||
|
||||
if (!pPlayer->IsInGame())
|
||||
{
|
||||
return pContext->ThrowNativeError("Client %d is not in game", client);
|
||||
}
|
||||
|
||||
g_pSM->SetGlobalTarget(client);
|
||||
|
||||
char buffer[192];
|
||||
g_pSM->FormatString(buffer, sizeof(buffer), pContext, params, 2);
|
||||
|
||||
/* Check for an error before printing to the client */
|
||||
if (pContext->GetContext()->n_err != SP_ERROR_NONE)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bf_write *pBitBuf = usermsgs->StartMessage(g_msgHintText, ¶ms[1], 1, USERMSG_RELIABLE);
|
||||
if (pBitBuf == NULL)
|
||||
{
|
||||
return pContext->ThrowNativeError("Could not send a usermessage");
|
||||
}
|
||||
pBitBuf->WriteByte(1);
|
||||
pBitBuf->WriteString(buffer);
|
||||
usermsgs->EndMessage();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static cell_t CS_RespawnPlayer(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
static ICallWrapper *pWrapper = NULL;
|
||||
@ -124,3 +163,9 @@ sp_nativeinfo_t g_CSNatives[] =
|
||||
{"CS_SwitchTeam", CS_SwitchTeam},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
sp_nativeinfo_t g_CS_PrintHintText[] =
|
||||
{
|
||||
{"PrintHintText", CS_PrintHintText},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
@ -71,5 +71,6 @@
|
||||
#define SMEXT_ENABLE_TIMERSYS
|
||||
//#define SMEXT_ENABLE_THREADER
|
||||
//#define SMEXT_ENABLE_LIBSYS
|
||||
#define SMEXT_ENABLE_USERMSGS
|
||||
|
||||
#endif // _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_
|
||||
|
@ -79,6 +79,9 @@ IThreader *threader = NULL;
|
||||
#if defined SMEXT_ENABLE_LIBSYS
|
||||
ILibrarySys *libsys = NULL;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_USERMSGS
|
||||
IUserMessages *usermsgs = NULL;
|
||||
#endif
|
||||
|
||||
/** Exports the main interface */
|
||||
PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI()
|
||||
@ -149,6 +152,9 @@ bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error,
|
||||
#if defined SMEXT_ENABLE_LIBSYS
|
||||
SM_GET_IFACE(LIBRARYSYS, libsys);
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_USERMSGS
|
||||
SM_GET_IFACE(USERMSGS, usermsgs);
|
||||
#endif
|
||||
|
||||
if (SDK_OnLoad(error, maxlength, late))
|
||||
{
|
||||
|
@ -73,6 +73,9 @@
|
||||
#if defined SMEXT_ENABLE_LIBSYS
|
||||
#include <ILibrarySys.h>
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_USERMSGS
|
||||
#include <IUserMessages.h>
|
||||
#endif
|
||||
|
||||
#if defined SMEXT_CONF_METAMOD
|
||||
#include <ISmmPlugin.h>
|
||||
@ -260,6 +263,9 @@ extern IThreader *threader;
|
||||
#if defined SMEXT_ENABLE_LIBSYS
|
||||
extern ILibrarySys *libsys;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_USERMSGS
|
||||
extern IUserMessages *usermsgs;
|
||||
#endif
|
||||
|
||||
#if defined SMEXT_CONF_METAMOD
|
||||
PLUGIN_GLOBALVARS();
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,178 +1,179 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod Sample Extension
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_TOP_MENU_H_
|
||||
#define _INCLUDE_SOURCEMOD_TOP_MENU_H_
|
||||
|
||||
#include <sh_list.h>
|
||||
#include <sh_vector.h>
|
||||
#include <sm_trie_tpl.h>
|
||||
#include <ITopMenus.h>
|
||||
#include "smsdk_ext.h"
|
||||
#include "sm_memtable.h"
|
||||
|
||||
using namespace SourceHook;
|
||||
using namespace SourceMod;
|
||||
|
||||
struct config_category_t
|
||||
{
|
||||
int name;
|
||||
CVector<int> commands;
|
||||
};
|
||||
|
||||
struct config_root_t
|
||||
{
|
||||
config_root_t() : strings(1024)
|
||||
{
|
||||
}
|
||||
BaseStringTable strings;
|
||||
CVector<config_category_t *> cats;
|
||||
};
|
||||
|
||||
struct topmenu_object_t
|
||||
{
|
||||
char name[64]; /** Name */
|
||||
char cmdname[64]; /** Command name */
|
||||
FlagBits flags; /** Admin flags */
|
||||
ITopMenuObjectCallbacks *callbacks; /** Callbacks */
|
||||
IdentityToken_t *owner; /** Owner */
|
||||
unsigned int object_id; /** Object ID */
|
||||
topmenu_object_t *parent; /** Parent, if any */
|
||||
TopMenuObjectType type; /** Object Type */
|
||||
bool is_free; /** Free or not? */
|
||||
char info[255]; /** Info string */
|
||||
};
|
||||
|
||||
struct topmenu_category_t
|
||||
{
|
||||
CVector<topmenu_object_t *> obj_list; /** Full object list */
|
||||
CVector<topmenu_object_t *> sorted; /** Sorted items */
|
||||
CVector<topmenu_object_t *> unsorted; /** Unsorted items */
|
||||
topmenu_object_t *obj; /** Bound object */
|
||||
unsigned int serial; /** Serial number */
|
||||
bool reorder; /** Whether ordering needs updating */
|
||||
};
|
||||
|
||||
struct topmenu_player_category_t
|
||||
{
|
||||
IBaseMenu *menu; /** menu pointer */
|
||||
unsigned int serial; /** last known serial */
|
||||
};
|
||||
|
||||
struct topmenu_player_t
|
||||
{
|
||||
int user_id; /** userid on server */
|
||||
unsigned int menu_serial; /** menu serial no */
|
||||
IBaseMenu *root; /** root menu display */
|
||||
topmenu_player_category_t *cats; /** category display */
|
||||
unsigned int cat_count; /** number of categories */
|
||||
unsigned int last_category; /** last category they selected */
|
||||
unsigned int last_position; /** last position in that category */
|
||||
unsigned int last_root_pos; /** last page in the root menu */
|
||||
};
|
||||
|
||||
class TopMenu :
|
||||
public ITopMenu,
|
||||
public IMenuHandler,
|
||||
public ITextListener_SMC
|
||||
{
|
||||
friend class TopMenuManager;
|
||||
public:
|
||||
TopMenu(ITopMenuObjectCallbacks *callbacks);
|
||||
~TopMenu();
|
||||
public: //ITopMenu
|
||||
virtual unsigned int AddToMenu(const char *name,
|
||||
TopMenuObjectType type,
|
||||
ITopMenuObjectCallbacks *callbacks,
|
||||
IdentityToken_t *owner,
|
||||
const char *cmdname,
|
||||
FlagBits flags,
|
||||
unsigned int parent);
|
||||
unsigned int AddToMenu2(const char *name,
|
||||
TopMenuObjectType type,
|
||||
ITopMenuObjectCallbacks *callbacks,
|
||||
IdentityToken_t *owner,
|
||||
const char *cmdname,
|
||||
FlagBits flags,
|
||||
unsigned int parent,
|
||||
const char *info_string);
|
||||
virtual void RemoveFromMenu(unsigned int object_id);
|
||||
virtual bool DisplayMenu(int client,
|
||||
unsigned int hold_time,
|
||||
TopMenuPosition position);
|
||||
virtual bool LoadConfiguration(const char *file, char *error, size_t maxlength);
|
||||
virtual unsigned int FindCategory(const char *name);
|
||||
const char *GetObjectInfoString(unsigned int object_id);
|
||||
public: //IMenuHandler
|
||||
virtual void OnMenuSelect2(IBaseMenu *menu, int client, unsigned int item, unsigned int item_on_page);
|
||||
virtual void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style);
|
||||
virtual unsigned int OnMenuDisplayItem(IBaseMenu *menu,
|
||||
int client,
|
||||
IMenuPanel *panel,
|
||||
unsigned int item,
|
||||
const ItemDrawInfo &dr);
|
||||
virtual void OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason);
|
||||
public: //ITextListener_SMC
|
||||
void ReadSMC_ParseStart();
|
||||
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
|
||||
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
|
||||
SMCResult ReadSMC_LeavingSection(const SMCStates *states);
|
||||
private:
|
||||
void SortCategoriesIfNeeded();
|
||||
void SortCategoryIfNeeded(unsigned int category);
|
||||
private:
|
||||
bool DisplayCategory(int client, unsigned int category, unsigned int hold_time, bool last_position);
|
||||
void CreatePlayers(int max_clients);
|
||||
void UpdateClientRoot(int client, IGamePlayer *pGamePlayer=NULL);
|
||||
void UpdateClientCategory(int client, unsigned int category);
|
||||
void TearDownClient(topmenu_player_t *player);
|
||||
private:
|
||||
void OnClientConnected(int client);
|
||||
void OnClientDisconnected(int client);
|
||||
void OnServerActivated(int max_clients);
|
||||
bool OnIdentityRemoval(IdentityToken_t *owner);
|
||||
private:
|
||||
config_root_t m_Config; /* Configuration from file */
|
||||
topmenu_player_t *m_clients; /* Client array */
|
||||
CVector<unsigned int> m_SortedCats; /* Sorted categories */
|
||||
CVector<unsigned int> m_UnsortedCats; /* Un-sorted categories */
|
||||
CVector<topmenu_category_t *> m_Categories; /* Category array */
|
||||
CVector<topmenu_object_t *> m_Objects; /* Object array */
|
||||
KTrie<topmenu_object_t *> m_ObjLookup; /* Object lookup trie */
|
||||
unsigned int m_SerialNo; /* Serial number for updating */
|
||||
ITopMenuObjectCallbacks *m_pTitle; /* Title callbacks */
|
||||
int m_max_clients; /* Maximum number of clients */
|
||||
bool m_bCatsNeedResort; /* True if categories need a resort */
|
||||
};
|
||||
|
||||
unsigned int strncopy(char *dest, const char *src, size_t count);
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_TOP_MENU_H_
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod Sample Extension
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_TOP_MENU_H_
|
||||
#define _INCLUDE_SOURCEMOD_TOP_MENU_H_
|
||||
|
||||
#include <sh_list.h>
|
||||
#include <sh_vector.h>
|
||||
#include <sm_trie_tpl.h>
|
||||
#include <ITopMenus.h>
|
||||
#include "smsdk_ext.h"
|
||||
#include "sm_memtable.h"
|
||||
|
||||
using namespace SourceHook;
|
||||
using namespace SourceMod;
|
||||
|
||||
struct config_category_t
|
||||
{
|
||||
int name;
|
||||
CVector<int> commands;
|
||||
};
|
||||
|
||||
struct config_root_t
|
||||
{
|
||||
config_root_t() : strings(1024)
|
||||
{
|
||||
}
|
||||
BaseStringTable strings;
|
||||
CVector<config_category_t *> cats;
|
||||
};
|
||||
|
||||
struct topmenu_object_t
|
||||
{
|
||||
char name[64]; /** Name */
|
||||
char cmdname[64]; /** Command name */
|
||||
FlagBits flags; /** Admin flags */
|
||||
ITopMenuObjectCallbacks *callbacks; /** Callbacks */
|
||||
IdentityToken_t *owner; /** Owner */
|
||||
unsigned int object_id; /** Object ID */
|
||||
topmenu_object_t *parent; /** Parent, if any */
|
||||
TopMenuObjectType type; /** Object Type */
|
||||
bool is_free; /** Free or not? */
|
||||
char info[255]; /** Info string */
|
||||
};
|
||||
|
||||
struct topmenu_category_t
|
||||
{
|
||||
CVector<topmenu_object_t *> obj_list; /** Full object list */
|
||||
CVector<topmenu_object_t *> sorted; /** Sorted items */
|
||||
CVector<topmenu_object_t *> unsorted; /** Unsorted items */
|
||||
topmenu_object_t *obj; /** Bound object */
|
||||
unsigned int serial; /** Serial number */
|
||||
bool reorder; /** Whether ordering needs updating */
|
||||
};
|
||||
|
||||
struct topmenu_player_category_t
|
||||
{
|
||||
IBaseMenu *menu; /** menu pointer */
|
||||
unsigned int serial; /** last known serial */
|
||||
};
|
||||
|
||||
struct topmenu_player_t
|
||||
{
|
||||
int user_id; /** userid on server */
|
||||
unsigned int menu_serial; /** menu serial no */
|
||||
IBaseMenu *root; /** root menu display */
|
||||
topmenu_player_category_t *cats; /** category display */
|
||||
unsigned int cat_count; /** number of categories */
|
||||
unsigned int last_category; /** last category they selected */
|
||||
unsigned int last_position; /** last position in that category */
|
||||
unsigned int last_root_pos; /** last page in the root menu */
|
||||
};
|
||||
|
||||
class TopMenu :
|
||||
public ITopMenu,
|
||||
public IMenuHandler,
|
||||
public ITextListener_SMC
|
||||
{
|
||||
friend class TopMenuManager;
|
||||
public:
|
||||
TopMenu(ITopMenuObjectCallbacks *callbacks);
|
||||
~TopMenu();
|
||||
public: //ITopMenu
|
||||
virtual unsigned int AddToMenu(const char *name,
|
||||
TopMenuObjectType type,
|
||||
ITopMenuObjectCallbacks *callbacks,
|
||||
IdentityToken_t *owner,
|
||||
const char *cmdname,
|
||||
FlagBits flags,
|
||||
unsigned int parent);
|
||||
unsigned int AddToMenu2(const char *name,
|
||||
TopMenuObjectType type,
|
||||
ITopMenuObjectCallbacks *callbacks,
|
||||
IdentityToken_t *owner,
|
||||
const char *cmdname,
|
||||
FlagBits flags,
|
||||
unsigned int parent,
|
||||
const char *info_string);
|
||||
virtual void RemoveFromMenu(unsigned int object_id);
|
||||
virtual bool DisplayMenu(int client,
|
||||
unsigned int hold_time,
|
||||
TopMenuPosition position);
|
||||
virtual bool LoadConfiguration(const char *file, char *error, size_t maxlength);
|
||||
virtual unsigned int FindCategory(const char *name);
|
||||
const char *GetObjectInfoString(unsigned int object_id);
|
||||
const char *GetObjectName(unsigned int object_id);
|
||||
public: //IMenuHandler
|
||||
virtual void OnMenuSelect2(IBaseMenu *menu, int client, unsigned int item, unsigned int item_on_page);
|
||||
virtual void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style);
|
||||
virtual unsigned int OnMenuDisplayItem(IBaseMenu *menu,
|
||||
int client,
|
||||
IMenuPanel *panel,
|
||||
unsigned int item,
|
||||
const ItemDrawInfo &dr);
|
||||
virtual void OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason);
|
||||
public: //ITextListener_SMC
|
||||
void ReadSMC_ParseStart();
|
||||
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
|
||||
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
|
||||
SMCResult ReadSMC_LeavingSection(const SMCStates *states);
|
||||
private:
|
||||
void SortCategoriesIfNeeded();
|
||||
void SortCategoryIfNeeded(unsigned int category);
|
||||
private:
|
||||
bool DisplayCategory(int client, unsigned int category, unsigned int hold_time, bool last_position);
|
||||
void CreatePlayers(int max_clients);
|
||||
void UpdateClientRoot(int client, IGamePlayer *pGamePlayer=NULL);
|
||||
void UpdateClientCategory(int client, unsigned int category);
|
||||
void TearDownClient(topmenu_player_t *player);
|
||||
private:
|
||||
void OnClientConnected(int client);
|
||||
void OnClientDisconnected(int client);
|
||||
void OnServerActivated(int max_clients);
|
||||
bool OnIdentityRemoval(IdentityToken_t *owner);
|
||||
private:
|
||||
config_root_t m_Config; /* Configuration from file */
|
||||
topmenu_player_t *m_clients; /* Client array */
|
||||
CVector<unsigned int> m_SortedCats; /* Sorted categories */
|
||||
CVector<unsigned int> m_UnsortedCats; /* Un-sorted categories */
|
||||
CVector<topmenu_category_t *> m_Categories; /* Category array */
|
||||
CVector<topmenu_object_t *> m_Objects; /* Object array */
|
||||
KTrie<topmenu_object_t *> m_ObjLookup; /* Object lookup trie */
|
||||
unsigned int m_SerialNo; /* Serial number for updating */
|
||||
ITopMenuObjectCallbacks *m_pTitle; /* Title callbacks */
|
||||
int m_max_clients; /* Maximum number of clients */
|
||||
bool m_bCatsNeedResort; /* True if categories need a resort */
|
||||
};
|
||||
|
||||
unsigned int strncopy(char *dest, const char *src, size_t count);
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_TOP_MENU_H_
|
||||
|
@ -1,358 +1,383 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod Sample Extension
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include "extension.h"
|
||||
#include "TopMenuManager.h"
|
||||
#include "TopMenu.h"
|
||||
|
||||
HandleType_t hTopMenuType;
|
||||
|
||||
class TopMenuHandle : public IHandleTypeDispatch
|
||||
{
|
||||
public:
|
||||
void OnHandleDestroy(HandleType_t type, void *object)
|
||||
{
|
||||
ITopMenu *pTopMenu = (ITopMenu *)object;
|
||||
g_TopMenus.DestroyTopMenu(pTopMenu);
|
||||
}
|
||||
} s_TopMenuHandle;
|
||||
|
||||
void Initialize_Natives()
|
||||
{
|
||||
hTopMenuType = handlesys->CreateType("ITopMenu",
|
||||
&s_TopMenuHandle,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
myself->GetIdentity(),
|
||||
NULL);
|
||||
}
|
||||
|
||||
void Shutdown_Natives()
|
||||
{
|
||||
handlesys->RemoveType(hTopMenuType, myself->GetIdentity());
|
||||
}
|
||||
|
||||
enum TopMenuAction
|
||||
{
|
||||
TopMenuAction_DisplayOption = 0,
|
||||
TopMenuAction_DisplayTitle = 1,
|
||||
TopMenuAction_SelectOption = 2,
|
||||
TopMenuAction_DrawOption = 3,
|
||||
TopMenuAction_RemoveObject = 4,
|
||||
};
|
||||
|
||||
class TopMenuCallbacks : public ITopMenuObjectCallbacks
|
||||
{
|
||||
public:
|
||||
TopMenuCallbacks(IPluginFunction *pFunction) : m_pFunction(pFunction)
|
||||
{
|
||||
}
|
||||
|
||||
unsigned int OnTopMenuDrawOption(ITopMenu *menu,
|
||||
int client,
|
||||
unsigned int object_id)
|
||||
{
|
||||
char buffer[2] = {ITEMDRAW_DEFAULT, 0x0};
|
||||
m_pFunction->PushCell(m_hMenuHandle);
|
||||
m_pFunction->PushCell(TopMenuAction_DrawOption);
|
||||
m_pFunction->PushCell(object_id);
|
||||
m_pFunction->PushCell(client);
|
||||
m_pFunction->PushStringEx(buffer, sizeof(buffer), SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
|
||||
m_pFunction->PushCell(sizeof(buffer));
|
||||
m_pFunction->Execute(NULL);
|
||||
return (unsigned int)buffer[0];
|
||||
}
|
||||
|
||||
void OnTopMenuDisplayOption(ITopMenu *menu,
|
||||
int client,
|
||||
unsigned int object_id,
|
||||
char buffer[],
|
||||
size_t maxlength)
|
||||
{
|
||||
m_pFunction->PushCell(m_hMenuHandle);
|
||||
m_pFunction->PushCell(TopMenuAction_DisplayOption);
|
||||
m_pFunction->PushCell(object_id);
|
||||
m_pFunction->PushCell(client);
|
||||
m_pFunction->PushStringEx(buffer, maxlength, 0, SM_PARAM_COPYBACK);
|
||||
m_pFunction->PushCell(maxlength);
|
||||
m_pFunction->Execute(NULL);
|
||||
}
|
||||
|
||||
void OnTopMenuDisplayTitle(ITopMenu *menu,
|
||||
int client,
|
||||
unsigned int object_id,
|
||||
char buffer[],
|
||||
size_t maxlength)
|
||||
{
|
||||
m_pFunction->PushCell(m_hMenuHandle);
|
||||
m_pFunction->PushCell(TopMenuAction_DisplayTitle);
|
||||
m_pFunction->PushCell(object_id);
|
||||
m_pFunction->PushCell(client);
|
||||
m_pFunction->PushStringEx(buffer, maxlength, 0, SM_PARAM_COPYBACK);
|
||||
m_pFunction->PushCell(maxlength);
|
||||
m_pFunction->Execute(NULL);
|
||||
}
|
||||
|
||||
void OnTopMenuSelectOption(ITopMenu *menu,
|
||||
int client,
|
||||
unsigned int object_id)
|
||||
{
|
||||
unsigned int old_reply = playerhelpers->SetReplyTo(SM_REPLY_CHAT);
|
||||
m_pFunction->PushCell(m_hMenuHandle);
|
||||
m_pFunction->PushCell(TopMenuAction_SelectOption);
|
||||
m_pFunction->PushCell(object_id);
|
||||
m_pFunction->PushCell(client);
|
||||
m_pFunction->PushString("");
|
||||
m_pFunction->PushCell(0);
|
||||
m_pFunction->Execute(NULL);
|
||||
playerhelpers->SetReplyTo(old_reply);
|
||||
}
|
||||
|
||||
void OnTopMenuObjectRemoved(ITopMenu *menu, unsigned int object_id)
|
||||
{
|
||||
m_pFunction->PushCell(m_hMenuHandle);
|
||||
m_pFunction->PushCell(TopMenuAction_RemoveObject);
|
||||
m_pFunction->PushCell(object_id);
|
||||
m_pFunction->PushCell(0);
|
||||
m_pFunction->PushString("");
|
||||
m_pFunction->PushCell(0);
|
||||
m_pFunction->Execute(NULL);
|
||||
|
||||
delete this;
|
||||
}
|
||||
|
||||
Handle_t m_hMenuHandle;
|
||||
IPluginFunction *m_pFunction;
|
||||
};
|
||||
|
||||
static cell_t CreateTopMenu(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IPluginFunction *func = pContext->GetFunctionById(params[1]);
|
||||
if (func == NULL)
|
||||
{
|
||||
return pContext ->ThrowNativeError("Invalid function specified");
|
||||
}
|
||||
|
||||
TopMenuCallbacks *cb = new TopMenuCallbacks(func);
|
||||
|
||||
ITopMenu *pMenu = g_TopMenus.CreateTopMenu(cb);
|
||||
|
||||
if (!pMenu)
|
||||
{
|
||||
delete cb;
|
||||
return BAD_HANDLE;
|
||||
}
|
||||
|
||||
Handle_t hndl = handlesys->CreateHandle(hTopMenuType,
|
||||
pMenu,
|
||||
pContext->GetIdentity(),
|
||||
myself->GetIdentity(),
|
||||
NULL);
|
||||
if (hndl == 0)
|
||||
{
|
||||
g_TopMenus.DestroyTopMenu(pMenu);
|
||||
return BAD_HANDLE;
|
||||
}
|
||||
|
||||
cb->m_hMenuHandle = hndl;
|
||||
|
||||
return hndl;
|
||||
}
|
||||
|
||||
static cell_t LoadTopMenuConfig(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
HandleError err;
|
||||
ITopMenu *pMenu;
|
||||
HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
|
||||
|
||||
if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
char *file, *err_buf;
|
||||
pContext->LocalToString(params[2], &file);
|
||||
pContext->LocalToString(params[3], &err_buf);
|
||||
|
||||
char path[PLATFORM_MAX_PATH];
|
||||
g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file);
|
||||
|
||||
return pMenu->LoadConfiguration(path, err_buf, params[4]) ? 1 : 0;
|
||||
}
|
||||
|
||||
static cell_t AddToTopMenu(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
HandleError err;
|
||||
ITopMenu *pMenu;
|
||||
HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
|
||||
|
||||
if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
IPluginFunction *func = pContext->GetFunctionById(params[4]);
|
||||
if (func == NULL)
|
||||
{
|
||||
return pContext ->ThrowNativeError("Invalid function specified");
|
||||
}
|
||||
|
||||
TopMenuCallbacks *cb = new TopMenuCallbacks(func);
|
||||
|
||||
char *name, *cmdname, *info_string = NULL;
|
||||
pContext->LocalToString(params[2], &name);
|
||||
pContext->LocalToString(params[6], &cmdname);
|
||||
|
||||
if (params[0] >= 8)
|
||||
{
|
||||
pContext->LocalToString(params[8], &info_string);
|
||||
}
|
||||
|
||||
TopMenuObjectType obj_type = (TopMenuObjectType)params[3];
|
||||
|
||||
unsigned int object_id;
|
||||
if ((object_id = pMenu->AddToMenu2(name,
|
||||
obj_type,
|
||||
cb,
|
||||
pContext->GetIdentity(),
|
||||
cmdname,
|
||||
params[7],
|
||||
params[5],
|
||||
info_string)) == 0)
|
||||
{
|
||||
delete cb;
|
||||
return 0;
|
||||
}
|
||||
|
||||
cb->m_hMenuHandle = params[1];
|
||||
|
||||
return object_id;
|
||||
}
|
||||
|
||||
static cell_t RemoveFromTopMenu(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
HandleError err;
|
||||
ITopMenu *pMenu;
|
||||
HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
|
||||
|
||||
if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
pMenu->RemoveFromMenu(params[2]);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t FindTopMenuCategory(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
HandleError err;
|
||||
ITopMenu *pMenu;
|
||||
HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
|
||||
|
||||
if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
char *name;
|
||||
pContext->LocalToString(params[2], &name);
|
||||
|
||||
return pMenu->FindCategory(name);
|
||||
}
|
||||
|
||||
static cell_t DisplayTopMenu(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
HandleError err;
|
||||
ITopMenu *pMenu;
|
||||
HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
|
||||
|
||||
if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
int client = params[2];
|
||||
IGamePlayer *player = playerhelpers->GetGamePlayer(client);
|
||||
if (!player)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid client index %d", client);
|
||||
}
|
||||
else if (!player->IsInGame())
|
||||
{
|
||||
return pContext->ThrowNativeError("Client %d is not in game", client);
|
||||
}
|
||||
|
||||
return pMenu->DisplayMenu(client, 0, (TopMenuPosition)params[3]);
|
||||
}
|
||||
|
||||
static cell_t GetTopMenuInfoString(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
HandleError err;
|
||||
ITopMenu *pMenu;
|
||||
HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
|
||||
|
||||
if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
const char *str;
|
||||
if ((str = pMenu->GetObjectInfoString(params[2])) == NULL)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid menu object %d", params[2]);
|
||||
}
|
||||
|
||||
char *buffer;
|
||||
pContext->LocalToString(params[3], &buffer);
|
||||
|
||||
return strncopy(buffer, str, params[4]);
|
||||
}
|
||||
|
||||
sp_nativeinfo_t g_TopMenuNatives[] =
|
||||
{
|
||||
{"AddToTopMenu", AddToTopMenu},
|
||||
{"CreateTopMenu", CreateTopMenu},
|
||||
{"DisplayTopMenu", DisplayTopMenu},
|
||||
{"LoadTopMenuConfig", LoadTopMenuConfig},
|
||||
{"RemoveFromTopMenu", RemoveFromTopMenu},
|
||||
{"FindTopMenuCategory", FindTopMenuCategory},
|
||||
{"GetTopMenuInfoString", GetTopMenuInfoString},
|
||||
{NULL, NULL},
|
||||
};
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod Sample Extension
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include "extension.h"
|
||||
#include "TopMenuManager.h"
|
||||
#include "TopMenu.h"
|
||||
|
||||
HandleType_t hTopMenuType;
|
||||
|
||||
class TopMenuHandle : public IHandleTypeDispatch
|
||||
{
|
||||
public:
|
||||
void OnHandleDestroy(HandleType_t type, void *object)
|
||||
{
|
||||
ITopMenu *pTopMenu = (ITopMenu *)object;
|
||||
g_TopMenus.DestroyTopMenu(pTopMenu);
|
||||
}
|
||||
} s_TopMenuHandle;
|
||||
|
||||
void Initialize_Natives()
|
||||
{
|
||||
hTopMenuType = handlesys->CreateType("ITopMenu",
|
||||
&s_TopMenuHandle,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
myself->GetIdentity(),
|
||||
NULL);
|
||||
}
|
||||
|
||||
void Shutdown_Natives()
|
||||
{
|
||||
handlesys->RemoveType(hTopMenuType, myself->GetIdentity());
|
||||
}
|
||||
|
||||
enum TopMenuAction
|
||||
{
|
||||
TopMenuAction_DisplayOption = 0,
|
||||
TopMenuAction_DisplayTitle = 1,
|
||||
TopMenuAction_SelectOption = 2,
|
||||
TopMenuAction_DrawOption = 3,
|
||||
TopMenuAction_RemoveObject = 4,
|
||||
};
|
||||
|
||||
class TopMenuCallbacks : public ITopMenuObjectCallbacks
|
||||
{
|
||||
public:
|
||||
TopMenuCallbacks(IPluginFunction *pFunction) : m_pFunction(pFunction)
|
||||
{
|
||||
}
|
||||
|
||||
unsigned int OnTopMenuDrawOption(ITopMenu *menu,
|
||||
int client,
|
||||
unsigned int object_id)
|
||||
{
|
||||
char buffer[2] = {ITEMDRAW_DEFAULT, 0x0};
|
||||
m_pFunction->PushCell(m_hMenuHandle);
|
||||
m_pFunction->PushCell(TopMenuAction_DrawOption);
|
||||
m_pFunction->PushCell(object_id);
|
||||
m_pFunction->PushCell(client);
|
||||
m_pFunction->PushStringEx(buffer, sizeof(buffer), SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
|
||||
m_pFunction->PushCell(sizeof(buffer));
|
||||
m_pFunction->Execute(NULL);
|
||||
return (unsigned int)buffer[0];
|
||||
}
|
||||
|
||||
void OnTopMenuDisplayOption(ITopMenu *menu,
|
||||
int client,
|
||||
unsigned int object_id,
|
||||
char buffer[],
|
||||
size_t maxlength)
|
||||
{
|
||||
m_pFunction->PushCell(m_hMenuHandle);
|
||||
m_pFunction->PushCell(TopMenuAction_DisplayOption);
|
||||
m_pFunction->PushCell(object_id);
|
||||
m_pFunction->PushCell(client);
|
||||
m_pFunction->PushStringEx(buffer, maxlength, 0, SM_PARAM_COPYBACK);
|
||||
m_pFunction->PushCell(maxlength);
|
||||
m_pFunction->Execute(NULL);
|
||||
}
|
||||
|
||||
void OnTopMenuDisplayTitle(ITopMenu *menu,
|
||||
int client,
|
||||
unsigned int object_id,
|
||||
char buffer[],
|
||||
size_t maxlength)
|
||||
{
|
||||
m_pFunction->PushCell(m_hMenuHandle);
|
||||
m_pFunction->PushCell(TopMenuAction_DisplayTitle);
|
||||
m_pFunction->PushCell(object_id);
|
||||
m_pFunction->PushCell(client);
|
||||
m_pFunction->PushStringEx(buffer, maxlength, 0, SM_PARAM_COPYBACK);
|
||||
m_pFunction->PushCell(maxlength);
|
||||
m_pFunction->Execute(NULL);
|
||||
}
|
||||
|
||||
void OnTopMenuSelectOption(ITopMenu *menu,
|
||||
int client,
|
||||
unsigned int object_id)
|
||||
{
|
||||
unsigned int old_reply = playerhelpers->SetReplyTo(SM_REPLY_CHAT);
|
||||
m_pFunction->PushCell(m_hMenuHandle);
|
||||
m_pFunction->PushCell(TopMenuAction_SelectOption);
|
||||
m_pFunction->PushCell(object_id);
|
||||
m_pFunction->PushCell(client);
|
||||
m_pFunction->PushString("");
|
||||
m_pFunction->PushCell(0);
|
||||
m_pFunction->Execute(NULL);
|
||||
playerhelpers->SetReplyTo(old_reply);
|
||||
}
|
||||
|
||||
void OnTopMenuObjectRemoved(ITopMenu *menu, unsigned int object_id)
|
||||
{
|
||||
m_pFunction->PushCell(m_hMenuHandle);
|
||||
m_pFunction->PushCell(TopMenuAction_RemoveObject);
|
||||
m_pFunction->PushCell(object_id);
|
||||
m_pFunction->PushCell(0);
|
||||
m_pFunction->PushString("");
|
||||
m_pFunction->PushCell(0);
|
||||
m_pFunction->Execute(NULL);
|
||||
|
||||
delete this;
|
||||
}
|
||||
|
||||
Handle_t m_hMenuHandle;
|
||||
IPluginFunction *m_pFunction;
|
||||
};
|
||||
|
||||
static cell_t CreateTopMenu(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IPluginFunction *func = pContext->GetFunctionById(params[1]);
|
||||
if (func == NULL)
|
||||
{
|
||||
return pContext ->ThrowNativeError("Invalid function specified");
|
||||
}
|
||||
|
||||
TopMenuCallbacks *cb = new TopMenuCallbacks(func);
|
||||
|
||||
ITopMenu *pMenu = g_TopMenus.CreateTopMenu(cb);
|
||||
|
||||
if (!pMenu)
|
||||
{
|
||||
delete cb;
|
||||
return BAD_HANDLE;
|
||||
}
|
||||
|
||||
Handle_t hndl = handlesys->CreateHandle(hTopMenuType,
|
||||
pMenu,
|
||||
pContext->GetIdentity(),
|
||||
myself->GetIdentity(),
|
||||
NULL);
|
||||
if (hndl == 0)
|
||||
{
|
||||
g_TopMenus.DestroyTopMenu(pMenu);
|
||||
return BAD_HANDLE;
|
||||
}
|
||||
|
||||
cb->m_hMenuHandle = hndl;
|
||||
|
||||
return hndl;
|
||||
}
|
||||
|
||||
static cell_t LoadTopMenuConfig(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
HandleError err;
|
||||
ITopMenu *pMenu;
|
||||
HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
|
||||
|
||||
if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
char *file, *err_buf;
|
||||
pContext->LocalToString(params[2], &file);
|
||||
pContext->LocalToString(params[3], &err_buf);
|
||||
|
||||
char path[PLATFORM_MAX_PATH];
|
||||
g_pSM->BuildPath(Path_Game, path, sizeof(path), "%s", file);
|
||||
|
||||
return pMenu->LoadConfiguration(path, err_buf, params[4]) ? 1 : 0;
|
||||
}
|
||||
|
||||
static cell_t AddToTopMenu(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
HandleError err;
|
||||
ITopMenu *pMenu;
|
||||
HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
|
||||
|
||||
if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
IPluginFunction *func = pContext->GetFunctionById(params[4]);
|
||||
if (func == NULL)
|
||||
{
|
||||
return pContext ->ThrowNativeError("Invalid function specified");
|
||||
}
|
||||
|
||||
TopMenuCallbacks *cb = new TopMenuCallbacks(func);
|
||||
|
||||
char *name, *cmdname, *info_string = NULL;
|
||||
pContext->LocalToString(params[2], &name);
|
||||
pContext->LocalToString(params[6], &cmdname);
|
||||
|
||||
if (params[0] >= 8)
|
||||
{
|
||||
pContext->LocalToString(params[8], &info_string);
|
||||
}
|
||||
|
||||
TopMenuObjectType obj_type = (TopMenuObjectType)params[3];
|
||||
|
||||
unsigned int object_id;
|
||||
if ((object_id = pMenu->AddToMenu2(name,
|
||||
obj_type,
|
||||
cb,
|
||||
pContext->GetIdentity(),
|
||||
cmdname,
|
||||
params[7],
|
||||
params[5],
|
||||
info_string)) == 0)
|
||||
{
|
||||
delete cb;
|
||||
return 0;
|
||||
}
|
||||
|
||||
cb->m_hMenuHandle = params[1];
|
||||
|
||||
return object_id;
|
||||
}
|
||||
|
||||
static cell_t RemoveFromTopMenu(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
HandleError err;
|
||||
ITopMenu *pMenu;
|
||||
HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
|
||||
|
||||
if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
pMenu->RemoveFromMenu(params[2]);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t FindTopMenuCategory(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
HandleError err;
|
||||
ITopMenu *pMenu;
|
||||
HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
|
||||
|
||||
if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
char *name;
|
||||
pContext->LocalToString(params[2], &name);
|
||||
|
||||
return pMenu->FindCategory(name);
|
||||
}
|
||||
|
||||
static cell_t DisplayTopMenu(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
HandleError err;
|
||||
ITopMenu *pMenu;
|
||||
HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
|
||||
|
||||
if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
int client = params[2];
|
||||
IGamePlayer *player = playerhelpers->GetGamePlayer(client);
|
||||
if (!player)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid client index %d", client);
|
||||
}
|
||||
else if (!player->IsInGame())
|
||||
{
|
||||
return pContext->ThrowNativeError("Client %d is not in game", client);
|
||||
}
|
||||
|
||||
return pMenu->DisplayMenu(client, 0, (TopMenuPosition)params[3]);
|
||||
}
|
||||
|
||||
static cell_t GetTopMenuInfoString(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
HandleError err;
|
||||
ITopMenu *pMenu;
|
||||
HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
|
||||
|
||||
if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
const char *str;
|
||||
if ((str = pMenu->GetObjectInfoString(params[2])) == NULL)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid menu object %d", params[2]);
|
||||
}
|
||||
|
||||
char *buffer;
|
||||
pContext->LocalToString(params[3], &buffer);
|
||||
|
||||
return strncopy(buffer, str, params[4]);
|
||||
}
|
||||
|
||||
static cell_t GetTopMenuName(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
HandleError err;
|
||||
ITopMenu *pMenu;
|
||||
HandleSecurity sec(pContext->GetIdentity(), myself->GetIdentity());
|
||||
|
||||
if ((err = handlesys->ReadHandle(params[1], hTopMenuType, &sec, (void **)&pMenu))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
const char *str;
|
||||
if ((str = pMenu->GetObjectName(params[2])) == NULL)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid menu object %d", params[2]);
|
||||
}
|
||||
|
||||
char *buffer;
|
||||
pContext->LocalToString(params[3], &buffer);
|
||||
|
||||
return strncopy(buffer, str, params[4]);
|
||||
}
|
||||
|
||||
sp_nativeinfo_t g_TopMenuNatives[] =
|
||||
{
|
||||
{"AddToTopMenu", AddToTopMenu},
|
||||
{"CreateTopMenu", CreateTopMenu},
|
||||
{"DisplayTopMenu", DisplayTopMenu},
|
||||
{"LoadTopMenuConfig", LoadTopMenuConfig},
|
||||
{"RemoveFromTopMenu", RemoveFromTopMenu},
|
||||
{"FindTopMenuCategory", FindTopMenuCategory},
|
||||
{"GetTopMenuInfoString", GetTopMenuInfoString},
|
||||
{"GetTopMenuObjName", GetTopMenuName},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
@ -62,6 +62,24 @@
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Which games use an extra byte in the HintText
|
||||
* message? Even though it's in the SDK, apparently
|
||||
* only CS:S does this right now.
|
||||
*/
|
||||
"#default"
|
||||
{
|
||||
"#supported"
|
||||
{
|
||||
"game" "cstrike"
|
||||
}
|
||||
|
||||
"Keys"
|
||||
{
|
||||
"HintTextPreByte" "yes"
|
||||
}
|
||||
}
|
||||
|
||||
"cstrike"
|
||||
{
|
||||
"Keys"
|
||||
@ -69,4 +87,12 @@
|
||||
"GameExtension" "game.cstrike"
|
||||
}
|
||||
}
|
||||
|
||||
"tf"
|
||||
{
|
||||
"Keys"
|
||||
{
|
||||
"RadioMenuTimeout" "4"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,6 @@ new String:g_ColorNames[13][10] = {"White", "Red", "Green", "Blue", "Yellow", "P
|
||||
new g_Colors[13][3] = {{255,255,255},{255,0,0},{0,255,0},{0,0,255},{255,255,0},{255,0,255},{0,255,255},{255,128,0},{255,0,128},{128,255,0},{0,255,128},{128,0,255},{0,128,255}};
|
||||
|
||||
new Handle:g_Cvar_Chatmode = INVALID_HANDLE;
|
||||
new Handle:g_Cvar_Psaymode = INVALID_HANDLE;
|
||||
|
||||
new bool:g_DoColor = true;
|
||||
|
||||
@ -59,7 +58,6 @@ public OnPluginStart()
|
||||
LoadTranslations("common.phrases");
|
||||
|
||||
g_Cvar_Chatmode = CreateConVar("sm_chat_mode", "1", "Allows player's to send messages to admin chat.", 0, true, 0.0, true, 1.0);
|
||||
g_Cvar_Psaymode = CreateConVar("sm_psay_mode", "0", "Allows player's to use psay 'say @@' alias.", 0, true, 0.0, true, 1.0);
|
||||
|
||||
RegConsoleCmd("say", Command_SayChat);
|
||||
RegConsoleCmd("say_team", Command_SayAdmin);
|
||||
@ -114,17 +112,17 @@ public Action:Command_SayChat(client, args)
|
||||
decl String:name[64];
|
||||
GetClientName(client, name, sizeof(name));
|
||||
|
||||
if (msgStart == 1 && CheckAdminForChat(client)) // sm_say alias
|
||||
if (msgStart == 1 && CheckCommandAccess(client, "sm_say", ADMFLAG_CHAT)) // sm_say alias
|
||||
{
|
||||
SendChatToAll(name, message);
|
||||
LogAction(client, -1, "%L triggered sm_say (text %s)", client, message);
|
||||
}
|
||||
else if (msgStart == 3 && CheckAdminForChat(client)) // sm_csay alias
|
||||
else if (msgStart == 3 && CheckCommandAccess(client, "sm_csay", ADMFLAG_CHAT)) // sm_csay alias
|
||||
{
|
||||
PrintCenterTextAll("%s: %s", name, message);
|
||||
LogAction(client, -1, "%L triggered sm_csay (text %s)", client, text);
|
||||
}
|
||||
else if (msgStart == 2 && (CheckAdminForChat(client) || GetConVarBool(g_Cvar_Psaymode))) // sm_psay alias
|
||||
else if (msgStart == 2 && CheckCommandAccess(client, "sm_psay", ADMFLAG_CHAT)) // sm_psay alias
|
||||
{
|
||||
decl String:arg[64];
|
||||
|
||||
@ -158,7 +156,7 @@ public Action:Command_SayChat(client, args)
|
||||
|
||||
public Action:Command_SayAdmin(client, args)
|
||||
{
|
||||
if (!CheckAdminForChat(client) && !GetConVarBool(g_Cvar_Chatmode))
|
||||
if (!CheckCommandAccess(client, "sm_chat", ADMFLAG_CHAT) && !GetConVarBool(g_Cvar_Chatmode))
|
||||
{
|
||||
return Plugin_Continue;
|
||||
}
|
||||
@ -359,16 +357,6 @@ public Action:Command_SmMsay(client, args)
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
bool:CheckAdminForChat(client)
|
||||
{
|
||||
if (client == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return CheckCommandAccess(client, "sm_chat", ADMFLAG_CHAT);
|
||||
}
|
||||
|
||||
FindColor(String:color[])
|
||||
{
|
||||
for (new i = 0; i < 13; i++)
|
||||
@ -400,7 +388,7 @@ SendChatToAdmins(String:name[], String:message[])
|
||||
{
|
||||
if (IsClientInGame(i))
|
||||
{
|
||||
if (CheckAdminForChat(i))
|
||||
if (CheckCommandAccess(i, "sm_chat", ADMFLAG_CHAT))
|
||||
{
|
||||
if (g_DoColor)
|
||||
{
|
||||
|
@ -58,7 +58,7 @@ DisplayGagPlayerMenu(client)
|
||||
SetMenuTitle(menu, title);
|
||||
SetMenuExitBackButton(menu, true);
|
||||
|
||||
AddTargetsToMenu(menu, client, false, false);
|
||||
AddTargetsToMenu(menu, client, true, false);
|
||||
|
||||
DisplayMenu(menu, client, MENU_TIME_FOREVER);
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ DisplayBurnMenu(client)
|
||||
SetMenuTitle(menu, title);
|
||||
SetMenuExitBackButton(menu, true);
|
||||
|
||||
AddTargetsToMenu(menu, client, false, true);
|
||||
AddTargetsToMenu(menu, client, true, true);
|
||||
|
||||
DisplayMenu(menu, client, MENU_TIME_FOREVER);
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ DisplaySlapTargetMenu(client)
|
||||
SetMenuTitle(menu, title);
|
||||
SetMenuExitBackButton(menu, true);
|
||||
|
||||
AddTargetsToMenu(menu, client, false, true);
|
||||
AddTargetsToMenu(menu, client, true, true);
|
||||
|
||||
DisplayMenu(menu, client, MENU_TIME_FOREVER);
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ DisplaySlayMenu(client)
|
||||
SetMenuTitle(menu, title);
|
||||
SetMenuExitBackButton(menu, true);
|
||||
|
||||
AddTargetsToMenu(menu, client, false, true);
|
||||
AddTargetsToMenu(menu, client, true, true);
|
||||
|
||||
DisplayMenu(menu, client, MENU_TIME_FOREVER);
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ DisplayBurnTargetMenu(client)
|
||||
SetMenuTitle(menu, title);
|
||||
SetMenuExitBackButton(menu, true);
|
||||
|
||||
AddTargetsToMenu(menu, client, false, true);
|
||||
AddTargetsToMenu(menu, client, true, true);
|
||||
|
||||
DisplayMenu(menu, client, MENU_TIME_FOREVER);
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ DisplaySlayTargetMenu(client)
|
||||
SetMenuTitle(menu, title);
|
||||
SetMenuExitBackButton(menu, true);
|
||||
|
||||
AddTargetsToMenu(menu, client, false, true);
|
||||
AddTargetsToMenu(menu, client, true, true);
|
||||
|
||||
DisplayMenu(menu, client, MENU_TIME_FOREVER);
|
||||
}
|
||||
|
@ -51,8 +51,6 @@ public Plugin:myinfo =
|
||||
|
||||
new Handle:g_hVoteMenu = INVALID_HANDLE;
|
||||
|
||||
new Handle:g_hBanForward = INVALID_HANDLE;
|
||||
|
||||
new Handle:g_Cvar_Limits[3] = {INVALID_HANDLE, ...};
|
||||
//new Handle:g_Cvar_VoteSay = INVALID_HANDLE;
|
||||
|
||||
@ -111,8 +109,6 @@ public OnPluginStart()
|
||||
g_Cvar_Limits[1] = CreateConVar("sm_vote_kick", "0.60", "percent required for successful kick vote.", 0, true, 0.05, true, 1.0);
|
||||
g_Cvar_Limits[2] = CreateConVar("sm_vote_ban", "0.60", "percent required for successful ban vote.", 0, true, 0.05, true, 1.0);
|
||||
|
||||
g_hBanForward = CreateGlobalForward("OnClientBanned", ET_Ignore, Param_Cell, Param_Cell, Param_Cell, Param_String);
|
||||
|
||||
/* Account for late loading */
|
||||
new Handle:topmenu;
|
||||
if (LibraryExists("adminmenu") && ((topmenu = GetAdminTopMenu()) != INVALID_HANDLE))
|
||||
@ -350,14 +346,6 @@ public Handler_VoteCallback(Handle:menu, MenuAction:action, param1, param2)
|
||||
|
||||
case (voteType:ban):
|
||||
{
|
||||
/* Fire the ban forward */
|
||||
Call_StartForward(g_hBanForward);
|
||||
Call_PushCell(0);
|
||||
Call_PushCell(g_voteClient[VOTE_USERID]);
|
||||
Call_PushCell(30);
|
||||
Call_PushString(g_voteArg);
|
||||
Call_Finish();
|
||||
|
||||
if (g_voteArg[0] == '\0')
|
||||
{
|
||||
strcopy(g_voteArg, sizeof(g_voteArg), "Votebanned");
|
||||
@ -365,9 +353,13 @@ public Handler_VoteCallback(Handle:menu, MenuAction:action, param1, param2)
|
||||
|
||||
PrintToChatAll("[SM] %t", "Banned player", g_voteInfo[VOTE_NAME], 30);
|
||||
LogAction(-1, g_voteClient[VOTE_CLIENTID], "Vote ban successful, banned \"%L\" (minutes \"30\") (reason \"%s\")", g_voteClient[VOTE_CLIENTID], g_voteArg);
|
||||
|
||||
ServerCommand("banid %d %s", 30, g_voteClient[VOTE_AUTHID]);
|
||||
ServerCommand("kickid %d \"%s\"", g_voteClient[VOTE_USERID], g_voteArg);
|
||||
|
||||
BanClient(g_voteClient[VOTE_CLIENTID],
|
||||
30,
|
||||
BANFLAG_AUTO,
|
||||
g_voteArg,
|
||||
"Banned by vote",
|
||||
"sm_voteban");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ public MenuHandler_Map(Handle:menu, MenuAction:action, param1, param2)
|
||||
|
||||
GetMenuItem(menu, param2, info, sizeof(info), _, name, sizeof(name));
|
||||
|
||||
if (IsStringInArray(g_SelectedMaps, info))
|
||||
if (FindStringInArray(g_SelectedMaps, info) != -1)
|
||||
{
|
||||
return ITEMDRAW_IGNORE;
|
||||
}
|
||||
|
@ -266,8 +266,8 @@ native SwapArrayItems(Handle:array, index1, index2);
|
||||
*
|
||||
* @param array Array Handle.
|
||||
* @param item String to search for
|
||||
* @return Array index, or -1 on failure
|
||||
* @error Invalid Handle
|
||||
* @return Array index, or -1 on failure
|
||||
* @error Invalid Handle
|
||||
*/
|
||||
native FindStringInArray(Handle:array, const String:item[]);
|
||||
|
||||
@ -277,8 +277,8 @@ native FindStringInArray(Handle:array, const String:item[]);
|
||||
*
|
||||
* @param array Array Handle.
|
||||
* @param item Value to search for
|
||||
* @return Array index, or -1 on failure
|
||||
* @error Invalid Handle
|
||||
* @return Array index, or -1 on failure
|
||||
* @error Invalid Handle
|
||||
*/
|
||||
native FindValueInArray(Handle:array, item);
|
||||
|
||||
@ -290,4 +290,4 @@ native FindValueInArray(Handle:array, item);
|
||||
stock bool:IsStringInArray(Handle:array, const String:item[])
|
||||
{
|
||||
return (FindStringInArray(array, item) != -1);
|
||||
}
|
||||
}
|
||||
|
@ -191,6 +191,15 @@ native KvGetUInt64(Handle:kv, const String:key[], value[2], defvalue[2]={0,0});
|
||||
*/
|
||||
native bool:KvJumpToKey(Handle:kv, const String:key[], bool:create=false);
|
||||
|
||||
/**
|
||||
* Sets the current position in the KeyValues tree to the given key.
|
||||
*
|
||||
* @param kv KeyValues Handle.
|
||||
* @param id KeyValues id.
|
||||
* @return True if the key exists, false if it does not.
|
||||
*/
|
||||
native bool:KvJumpToKeySymbol(Handle:kv, id);
|
||||
|
||||
/**
|
||||
* Sets the current position in the KeyValues tree to the first sub key.
|
||||
* This native adds to the internal traversal stack.
|
||||
@ -385,3 +394,13 @@ native bool:KvFindKeyById(Handle:kv, id, String:name[], maxlength);
|
||||
* @error Invalid Handle.
|
||||
*/
|
||||
native bool:KvGetNameSymbol(Handle:kv, const String:key[], &id);
|
||||
|
||||
/**
|
||||
* Retrieves the current section id.
|
||||
*
|
||||
* @param kv KeyValues Handle.
|
||||
* @param id Id of the current section.
|
||||
* @return True on success, false on failure.
|
||||
* @error Invalid Handle.
|
||||
*/
|
||||
native bool:KvGetSectionSymbol(Handle:kv, &id);
|
||||
|
@ -732,6 +732,26 @@ native bool:SetPanelCurrentKey(Handle:panel, key);
|
||||
*/
|
||||
native RedrawMenuItem(const String:text[]);
|
||||
|
||||
/**
|
||||
* This function is provided for legacy code only. Some older plugins may use
|
||||
* network messages instead of the panel API. This function wraps the panel
|
||||
* API for eased portability into the SourceMod menu system.
|
||||
*
|
||||
* This function is only usable with the Radio Menu style. You do not need to
|
||||
* split up your menu into multiple packets; SourceMod will break the string
|
||||
* up internally.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param str Full menu string as would be passed over the network.
|
||||
* @param time Time to hold the menu for.
|
||||
* @param keys Selectable key bitstring.
|
||||
* @param handler Optional handler function, with the same rules as
|
||||
* SendPanelToClient().
|
||||
* @return True on success, false on failure.
|
||||
* @error Invalid client index, or radio menus not supported.
|
||||
*/
|
||||
native bool:InternalShowMenu(client, const String:str[], time, keys=-1, MenuHandler:handler=MenuHandler:-1);
|
||||
|
||||
/**
|
||||
* Retrieves voting information from MenuAction_VoteEnd.
|
||||
*
|
||||
|
@ -45,6 +45,16 @@ enum SortOrder
|
||||
Sort_Descending = 1, /**< Descending order */
|
||||
};
|
||||
|
||||
/**
|
||||
* Data types for ADT Array Sorts
|
||||
*/
|
||||
enum SortType
|
||||
{
|
||||
Sort_Integer = 0,
|
||||
Sort_Float,
|
||||
Sort_String,
|
||||
};
|
||||
|
||||
/**
|
||||
* Sorts an array of integers.
|
||||
*
|
||||
@ -128,3 +138,38 @@ funcenum SortFunc2D
|
||||
* @noreturn
|
||||
*/
|
||||
native SortCustom2D(array[][], array_size, SortFunc2D:sortfunc, Handle:hndl=INVALID_HANDLE);
|
||||
|
||||
/**
|
||||
* Sort an ADT Array. Specify the type as Integer, Float, or String.
|
||||
*
|
||||
* @param array Array Handle to sort
|
||||
* @param order Sort order to use, same as other sorts.
|
||||
* @param type Data type stored in the ADT Array
|
||||
* @noreturn
|
||||
*/
|
||||
native SortADTArray(Handle:array, SortOrder:order = Sort_Ascending, SortType:type = Sort_Integer);
|
||||
|
||||
/**
|
||||
* Sort comparison function for ADT Array elements. Function provides you with
|
||||
* indexes currently being sorted, use ADT Array functions to retrieve the
|
||||
* index values and compare.
|
||||
*
|
||||
* @param index1 First index to compare.
|
||||
* @param index2 Second index to compare.
|
||||
* @param array Array that is being sorted (order is undefined).
|
||||
* @param hndl Handle optionally passed in while sorting.
|
||||
* @return -1 if first should go before second
|
||||
* 0 if first is equal to second
|
||||
* 1 if first should go after second
|
||||
*/
|
||||
functag SortFuncADTArray public(index1, index2, Handle:array, Handle:hndl);
|
||||
|
||||
/**
|
||||
* Custom sorts an ADT Array. You must pass in a comparison function.
|
||||
*
|
||||
* @param array Array Handle to sort
|
||||
* @param sortfunc Sort comparision function to use
|
||||
* @param hndl Optional Handle to pass through the comparison calls.
|
||||
* @noreturn
|
||||
*/
|
||||
native SortADTArrayCustom(Handle:array, SortFuncADTArray:sortfunc, Handle:hndl=INVALID_HANDLE);
|
@ -1,277 +1,290 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This file is part of the SourceMod/SourcePawn SDK.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#if defined _topmenus_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _topmenus_included
|
||||
|
||||
#include <menus>
|
||||
|
||||
/**
|
||||
* Actions a top menu will take on an object.
|
||||
*/
|
||||
enum TopMenuAction
|
||||
{
|
||||
/**
|
||||
* An option is being drawn for a menu (or for sorting purposes).
|
||||
*
|
||||
* INPUT : TopMenu Handle, object ID, client index.
|
||||
* OUTPUT: Buffer for rendering, maxlength of buffer.
|
||||
*/
|
||||
TopMenuAction_DisplayOption = 0,
|
||||
|
||||
/**
|
||||
* The title of a menu is being drawn for a given object.
|
||||
*
|
||||
* Note: The Object ID will be INVALID_TOPMENUOBJECT if drawing the
|
||||
* root title. Otherwise, the Object ID is a category.
|
||||
*
|
||||
* INPUT : TopMenu Handle, object ID, client index.
|
||||
* OUTPUT: Buffer for rendering, maxlength of buffer.
|
||||
*/
|
||||
TopMenuAction_DisplayTitle = 1,
|
||||
|
||||
/**
|
||||
* A menu option has been selected.
|
||||
*
|
||||
* The Object ID will always be an item (not a category).
|
||||
*
|
||||
* INPUT : TopMenu Handle, object ID, client index.
|
||||
*/
|
||||
TopMenuAction_SelectOption = 2,
|
||||
|
||||
/**
|
||||
* A menu option is being drawn and its flags can be overridden.
|
||||
*
|
||||
* INPUT : TopMenu Handle, object ID, client index.
|
||||
* OUTPUT: The first byte of the 'buffer' string should be set
|
||||
* to the desired flags. By default, it will contain
|
||||
* ITEMDRAW_DEFAULT.
|
||||
*/
|
||||
TopMenuAction_DrawOption = 3,
|
||||
|
||||
/**
|
||||
* Called when an object is being removed from the menu.
|
||||
* This can be used to clean up data stored in the info string.
|
||||
*
|
||||
* INPUT : TopMenu Handle, object ID.
|
||||
*/
|
||||
TopMenuAction_RemoveObject = 4,
|
||||
};
|
||||
|
||||
/**
|
||||
* Top menu object types.
|
||||
*/
|
||||
enum TopMenuObjectType
|
||||
{
|
||||
TopMenuObject_Category = 0, /**< Category (sub-menu branching from root) */
|
||||
TopMenuObject_Item = 1 /**< Item on a sub-menu */
|
||||
};
|
||||
|
||||
/**
|
||||
* Top menu starting positions for display.
|
||||
*/
|
||||
enum TopMenuPosition
|
||||
{
|
||||
TopMenuPosition_Start = 0, /**< Start/root of the menu */
|
||||
TopMenuPosition_LastRoot = 1, /**< Last position in the root menu */
|
||||
TopMenuPosition_LastCategory = 3, /**< Last position in their last category */
|
||||
};
|
||||
|
||||
/**
|
||||
* Top menu object tag for type checking.
|
||||
*/
|
||||
enum TopMenuObject
|
||||
{
|
||||
INVALID_TOPMENUOBJECT = 0,
|
||||
}
|
||||
|
||||
/**
|
||||
* TopMenu callback prototype.
|
||||
*
|
||||
* @param topmenu Handle to the TopMenu.
|
||||
* @param action TopMenuAction being performed.
|
||||
* @param object_id The object ID (if used).
|
||||
* @param param Extra parameter (if used).
|
||||
* @param buffer Output buffer (if used).
|
||||
* @param maxlength Output buffer (if used).
|
||||
* @noreturn
|
||||
*/
|
||||
functag TopMenuHandler public(Handle:topmenu,
|
||||
TopMenuAction:action,
|
||||
TopMenuObject:object_id,
|
||||
param,
|
||||
String:buffer[],
|
||||
maxlength);
|
||||
|
||||
/**
|
||||
* Creates a TopMenu.
|
||||
*
|
||||
* @param handler Handler to use for drawing the root title.
|
||||
* @return A new TopMenu Handle, or INVALID_HANDLE on failure.
|
||||
*/
|
||||
native Handle:CreateTopMenu(TopMenuHandler:handler);
|
||||
|
||||
/**
|
||||
* Re-sorts the items in a TopMenu via a configuration file.
|
||||
*
|
||||
* The format of the configuration file should be a Valve Key-Values
|
||||
* formatted file that SourceMod can parse. There should be one root
|
||||
* section, and one sub-section for each category. Each sub-section's
|
||||
* name should match the category name.
|
||||
*
|
||||
* Each sub-section may only contain key/value pairs in the form of:
|
||||
* key: "item"
|
||||
* value: Name of the item as passed to AddToTopMenu().
|
||||
*
|
||||
* The TopMenu will draw items in the order declared in the configuration
|
||||
* file. If items do not appear in the configuration file, they are sorted
|
||||
* per-player based on how the handler function renders for that player.
|
||||
* These items appear after the configuration sorted items.
|
||||
*
|
||||
* @param topmenu TopMenu Handle.
|
||||
* @param file File path.
|
||||
* @param error Error buffer.
|
||||
* @param maxlength Maximum size of the error buffer.
|
||||
* Error buffer will be filled with a
|
||||
* zero-terminated string if false is
|
||||
* returned.
|
||||
* @return True on success, false on failure.
|
||||
* @error Invalid TopMenu Handle.
|
||||
*/
|
||||
native bool:LoadTopMenuConfig(Handle:topmenu, const String:file[], String:error[], maxlength);
|
||||
|
||||
/**
|
||||
* Adds an object to a TopMenu.
|
||||
*
|
||||
* @param topmenu TopMenu Handle.
|
||||
* @param name Object name (MUST be unique).
|
||||
* @param type Object type.
|
||||
* @param handler Handler for object.
|
||||
* @param cmdname Command name (for access overrides).
|
||||
* @param flags Default access flags.
|
||||
* @param parent Parent object ID, or INVALID_TOPMENUOBJECT for none.
|
||||
* Items must have a category parent.
|
||||
* Categories must not have a parent.
|
||||
* @param info_string Arbitrary storage (max 255 bytes).
|
||||
* @return A new TopMenuObject ID, or INVALID_TOPMENUOBJECT on
|
||||
* failure.
|
||||
* @error Invalid TopMenu Handle.
|
||||
*/
|
||||
native TopMenuObject:AddToTopMenu(Handle:topmenu,
|
||||
const String:name[],
|
||||
TopMenuObjectType:type,
|
||||
TopMenuHandler:handler,
|
||||
TopMenuObject:parent,
|
||||
const String:cmdname[]="",
|
||||
flags=0,
|
||||
const String:info_string[]="");
|
||||
|
||||
/**
|
||||
* Retrieves the info string of a top menu item.
|
||||
*
|
||||
* @param topmenu TopMenu Handle.
|
||||
* @param object TopMenuObject ID.
|
||||
* @param buffer Buffer to store info string.
|
||||
* @param maxlength Maximum size of info string.
|
||||
* @return Number of bytes written, not including the
|
||||
* null terminator.
|
||||
* @error Invalid TopMenu Handle or TopMenuObject ID.
|
||||
*/
|
||||
native GetTopMenuInfoString(Handle:topmenu, TopMenuObject:parent, String:buffer[], maxlength);
|
||||
|
||||
/**
|
||||
* Removes an object from a TopMenu.
|
||||
*
|
||||
* Plugins' objects are automatically removed all TopMenus when the given
|
||||
* plugin unloads or pauses. In the case of unpausing, all items are restored.
|
||||
*
|
||||
* @param topmenu TopMenu Handle.
|
||||
* @param object TopMenuObject ID.
|
||||
* @noreturn
|
||||
* @error Invalid TopMenu Handle.
|
||||
*/
|
||||
native RemoveFromTopMenu(Handle:topmenu, TopMenuObject:object);
|
||||
|
||||
/**
|
||||
* Displays a TopMenu to a client.
|
||||
*
|
||||
* @param topmenu TopMenu Handle.
|
||||
* @param client Client index.
|
||||
* @param position Position to display from.
|
||||
* @return True on success, false on failure.
|
||||
* @error Invalid TopMenu Handle or client not in game.
|
||||
*/
|
||||
native bool:DisplayTopMenu(Handle:topmenu, client, TopMenuPosition:position);
|
||||
|
||||
/**
|
||||
* Finds a category's object ID in a TopMenu.
|
||||
*
|
||||
* @param topmenu TopMenu Handle.
|
||||
* @param name Object's unique name.
|
||||
* @return TopMenuObject ID on success, or
|
||||
* INVALID_TOPMENUOBJECT on failure.
|
||||
* @error Invalid TopMenu Handle.
|
||||
*/
|
||||
native TopMenuObject:FindTopMenuCategory(Handle:topmenu, const String:name[]);
|
||||
|
||||
/**
|
||||
* Do not edit below this line!
|
||||
*/
|
||||
public Extension:__ext_topmenus =
|
||||
{
|
||||
name = "TopMenus",
|
||||
file = "topmenus.ext",
|
||||
#if defined AUTOLOAD_EXTENSIONS
|
||||
autoload = 1,
|
||||
#else
|
||||
autoload = 0,
|
||||
#endif
|
||||
#if defined REQUIRE_EXTENSIONS
|
||||
required = 1,
|
||||
#else
|
||||
required = 0,
|
||||
#endif
|
||||
};
|
||||
|
||||
#if !defined REQUIRE_EXTENSIONS
|
||||
public __ext_topmenus_SetNTVOptional()
|
||||
{
|
||||
MarkNativeAsOptional("CreateTopMenu");
|
||||
MarkNativeAsOptional("LoadTopMenuConfig");
|
||||
MarkNativeAsOptional("AddToTopMenu");
|
||||
MarkNativeAsOptional("RemoveFromTopMenu");
|
||||
MarkNativeAsOptional("DisplayTopMenu");
|
||||
MarkNativeAsOptional("FindTopMenuCategory");
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This file is part of the SourceMod/SourcePawn SDK.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#if defined _topmenus_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _topmenus_included
|
||||
|
||||
#include <menus>
|
||||
|
||||
/**
|
||||
* Actions a top menu will take on an object.
|
||||
*/
|
||||
enum TopMenuAction
|
||||
{
|
||||
/**
|
||||
* An option is being drawn for a menu (or for sorting purposes).
|
||||
*
|
||||
* INPUT : TopMenu Handle, object ID, client index.
|
||||
* OUTPUT: Buffer for rendering, maxlength of buffer.
|
||||
*/
|
||||
TopMenuAction_DisplayOption = 0,
|
||||
|
||||
/**
|
||||
* The title of a menu is being drawn for a given object.
|
||||
*
|
||||
* Note: The Object ID will be INVALID_TOPMENUOBJECT if drawing the
|
||||
* root title. Otherwise, the Object ID is a category.
|
||||
*
|
||||
* INPUT : TopMenu Handle, object ID, client index.
|
||||
* OUTPUT: Buffer for rendering, maxlength of buffer.
|
||||
*/
|
||||
TopMenuAction_DisplayTitle = 1,
|
||||
|
||||
/**
|
||||
* A menu option has been selected.
|
||||
*
|
||||
* The Object ID will always be an item (not a category).
|
||||
*
|
||||
* INPUT : TopMenu Handle, object ID, client index.
|
||||
*/
|
||||
TopMenuAction_SelectOption = 2,
|
||||
|
||||
/**
|
||||
* A menu option is being drawn and its flags can be overridden.
|
||||
*
|
||||
* INPUT : TopMenu Handle, object ID, client index.
|
||||
* OUTPUT: The first byte of the 'buffer' string should be set
|
||||
* to the desired flags. By default, it will contain
|
||||
* ITEMDRAW_DEFAULT.
|
||||
*/
|
||||
TopMenuAction_DrawOption = 3,
|
||||
|
||||
/**
|
||||
* Called when an object is being removed from the menu.
|
||||
* This can be used to clean up data stored in the info string.
|
||||
*
|
||||
* INPUT : TopMenu Handle, object ID.
|
||||
*/
|
||||
TopMenuAction_RemoveObject = 4,
|
||||
};
|
||||
|
||||
/**
|
||||
* Top menu object types.
|
||||
*/
|
||||
enum TopMenuObjectType
|
||||
{
|
||||
TopMenuObject_Category = 0, /**< Category (sub-menu branching from root) */
|
||||
TopMenuObject_Item = 1 /**< Item on a sub-menu */
|
||||
};
|
||||
|
||||
/**
|
||||
* Top menu starting positions for display.
|
||||
*/
|
||||
enum TopMenuPosition
|
||||
{
|
||||
TopMenuPosition_Start = 0, /**< Start/root of the menu */
|
||||
TopMenuPosition_LastRoot = 1, /**< Last position in the root menu */
|
||||
TopMenuPosition_LastCategory = 3, /**< Last position in their last category */
|
||||
};
|
||||
|
||||
/**
|
||||
* Top menu object tag for type checking.
|
||||
*/
|
||||
enum TopMenuObject
|
||||
{
|
||||
INVALID_TOPMENUOBJECT = 0,
|
||||
}
|
||||
|
||||
/**
|
||||
* TopMenu callback prototype.
|
||||
*
|
||||
* @param topmenu Handle to the TopMenu.
|
||||
* @param action TopMenuAction being performed.
|
||||
* @param object_id The object ID (if used).
|
||||
* @param param Extra parameter (if used).
|
||||
* @param buffer Output buffer (if used).
|
||||
* @param maxlength Output buffer (if used).
|
||||
* @noreturn
|
||||
*/
|
||||
functag TopMenuHandler public(Handle:topmenu,
|
||||
TopMenuAction:action,
|
||||
TopMenuObject:object_id,
|
||||
param,
|
||||
String:buffer[],
|
||||
maxlength);
|
||||
|
||||
/**
|
||||
* Creates a TopMenu.
|
||||
*
|
||||
* @param handler Handler to use for drawing the root title.
|
||||
* @return A new TopMenu Handle, or INVALID_HANDLE on failure.
|
||||
*/
|
||||
native Handle:CreateTopMenu(TopMenuHandler:handler);
|
||||
|
||||
/**
|
||||
* Re-sorts the items in a TopMenu via a configuration file.
|
||||
*
|
||||
* The format of the configuration file should be a Valve Key-Values
|
||||
* formatted file that SourceMod can parse. There should be one root
|
||||
* section, and one sub-section for each category. Each sub-section's
|
||||
* name should match the category name.
|
||||
*
|
||||
* Each sub-section may only contain key/value pairs in the form of:
|
||||
* key: "item"
|
||||
* value: Name of the item as passed to AddToTopMenu().
|
||||
*
|
||||
* The TopMenu will draw items in the order declared in the configuration
|
||||
* file. If items do not appear in the configuration file, they are sorted
|
||||
* per-player based on how the handler function renders for that player.
|
||||
* These items appear after the configuration sorted items.
|
||||
*
|
||||
* @param topmenu TopMenu Handle.
|
||||
* @param file File path.
|
||||
* @param error Error buffer.
|
||||
* @param maxlength Maximum size of the error buffer.
|
||||
* Error buffer will be filled with a
|
||||
* zero-terminated string if false is
|
||||
* returned.
|
||||
* @return True on success, false on failure.
|
||||
* @error Invalid TopMenu Handle.
|
||||
*/
|
||||
native bool:LoadTopMenuConfig(Handle:topmenu, const String:file[], String:error[], maxlength);
|
||||
|
||||
/**
|
||||
* Adds an object to a TopMenu.
|
||||
*
|
||||
* @param topmenu TopMenu Handle.
|
||||
* @param name Object name (MUST be unique).
|
||||
* @param type Object type.
|
||||
* @param handler Handler for object.
|
||||
* @param cmdname Command name (for access overrides).
|
||||
* @param flags Default access flags.
|
||||
* @param parent Parent object ID, or INVALID_TOPMENUOBJECT for none.
|
||||
* Items must have a category parent.
|
||||
* Categories must not have a parent.
|
||||
* @param info_string Arbitrary storage (max 255 bytes).
|
||||
* @return A new TopMenuObject ID, or INVALID_TOPMENUOBJECT on
|
||||
* failure.
|
||||
* @error Invalid TopMenu Handle.
|
||||
*/
|
||||
native TopMenuObject:AddToTopMenu(Handle:topmenu,
|
||||
const String:name[],
|
||||
TopMenuObjectType:type,
|
||||
TopMenuHandler:handler,
|
||||
TopMenuObject:parent,
|
||||
const String:cmdname[]="",
|
||||
flags=0,
|
||||
const String:info_string[]="");
|
||||
|
||||
/**
|
||||
* Retrieves the info string of a top menu item.
|
||||
*
|
||||
* @param topmenu TopMenu Handle.
|
||||
* @param object TopMenuObject ID.
|
||||
* @param buffer Buffer to store info string.
|
||||
* @param maxlength Maximum size of info string.
|
||||
* @return Number of bytes written, not including the
|
||||
* null terminator.
|
||||
* @error Invalid TopMenu Handle or TopMenuObject ID.
|
||||
*/
|
||||
native GetTopMenuInfoString(Handle:topmenu, TopMenuObject:parent, String:buffer[], maxlength);
|
||||
|
||||
/**
|
||||
* Retrieves the name string of a top menu item.
|
||||
*
|
||||
* @param topmenu TopMenu Handle.
|
||||
* @param object TopMenuObject ID.
|
||||
* @param buffer Buffer to store info string.
|
||||
* @param maxlength Maximum size of info string.
|
||||
* @return Number of bytes written, not including the
|
||||
* null terminator.
|
||||
* @error Invalid TopMenu Handle or TopMenuObject ID.
|
||||
*/
|
||||
native GetTopMenuObjName(Handle:topmenu, TopMenuObject:object, String:buffer[], maxlength);
|
||||
|
||||
/**
|
||||
* Removes an object from a TopMenu.
|
||||
*
|
||||
* Plugins' objects are automatically removed all TopMenus when the given
|
||||
* plugin unloads or pauses. In the case of unpausing, all items are restored.
|
||||
*
|
||||
* @param topmenu TopMenu Handle.
|
||||
* @param object TopMenuObject ID.
|
||||
* @noreturn
|
||||
* @error Invalid TopMenu Handle.
|
||||
*/
|
||||
native RemoveFromTopMenu(Handle:topmenu, TopMenuObject:object);
|
||||
|
||||
/**
|
||||
* Displays a TopMenu to a client.
|
||||
*
|
||||
* @param topmenu TopMenu Handle.
|
||||
* @param client Client index.
|
||||
* @param position Position to display from.
|
||||
* @return True on success, false on failure.
|
||||
* @error Invalid TopMenu Handle or client not in game.
|
||||
*/
|
||||
native bool:DisplayTopMenu(Handle:topmenu, client, TopMenuPosition:position);
|
||||
|
||||
/**
|
||||
* Finds a category's object ID in a TopMenu.
|
||||
*
|
||||
* @param topmenu TopMenu Handle.
|
||||
* @param name Object's unique name.
|
||||
* @return TopMenuObject ID on success, or
|
||||
* INVALID_TOPMENUOBJECT on failure.
|
||||
* @error Invalid TopMenu Handle.
|
||||
*/
|
||||
native TopMenuObject:FindTopMenuCategory(Handle:topmenu, const String:name[]);
|
||||
|
||||
/**
|
||||
* Do not edit below this line!
|
||||
*/
|
||||
public Extension:__ext_topmenus =
|
||||
{
|
||||
name = "TopMenus",
|
||||
file = "topmenus.ext",
|
||||
#if defined AUTOLOAD_EXTENSIONS
|
||||
autoload = 1,
|
||||
#else
|
||||
autoload = 0,
|
||||
#endif
|
||||
#if defined REQUIRE_EXTENSIONS
|
||||
required = 1,
|
||||
#else
|
||||
required = 0,
|
||||
#endif
|
||||
};
|
||||
|
||||
#if !defined REQUIRE_EXTENSIONS
|
||||
public __ext_topmenus_SetNTVOptional()
|
||||
{
|
||||
MarkNativeAsOptional("CreateTopMenu");
|
||||
MarkNativeAsOptional("LoadTopMenuConfig");
|
||||
MarkNativeAsOptional("AddToTopMenu");
|
||||
MarkNativeAsOptional("RemoveFromTopMenu");
|
||||
MarkNativeAsOptional("DisplayTopMenu");
|
||||
MarkNativeAsOptional("FindTopMenuCategory");
|
||||
}
|
||||
#endif
|
||||
|
@ -74,6 +74,7 @@ new Handle:g_NextMapList = INVALID_HANDLE;
|
||||
new Handle:g_TeamScores = INVALID_HANDLE;
|
||||
new Handle:g_VoteMenu = INVALID_HANDLE;
|
||||
|
||||
new g_TotalRounds;
|
||||
new bool:g_HasVoteStarted;
|
||||
new g_mapFileTime;
|
||||
|
||||
@ -87,7 +88,6 @@ public OnPluginStart()
|
||||
g_MapList = CreateArray(arraySize);
|
||||
g_OldMapList = CreateArray(arraySize);
|
||||
g_NextMapList = CreateArray(arraySize);
|
||||
g_TeamScores = CreateArray(2);
|
||||
|
||||
g_Cvar_StartTime = CreateConVar("sm_mapvote_start", "3.0", "Specifies when to start the vote based on time remaining.", _, true, 1.0);
|
||||
g_Cvar_StartRounds = CreateConVar("sm_mapvote_startround", "2.0", "Specifies when to start the vote based on rounds remaining.", _, true, 1.0);
|
||||
@ -139,6 +139,14 @@ public OnConfigsExecuted()
|
||||
SetupTimeleftTimer();
|
||||
SetConVarString(g_Cvar_Nextmap, "Pending Vote");
|
||||
}
|
||||
|
||||
if (g_TeamScores != INVALID_HANDLE)
|
||||
{
|
||||
CloseHandle(g_TeamScores);
|
||||
}
|
||||
|
||||
g_TeamScores = CreateArray(2);
|
||||
g_TotalRounds = 0;
|
||||
}
|
||||
|
||||
public OnMapEnd()
|
||||
@ -225,8 +233,7 @@ public Event_RoundEnd(Handle:event, const String:name[], bool:dontBroadcast)
|
||||
return;
|
||||
}
|
||||
|
||||
static total;
|
||||
total++;
|
||||
g_TotalRounds++;
|
||||
|
||||
new team[2], teamPos = -1;
|
||||
for (new i; i < GetArraySize(g_TeamScores); i++)
|
||||
@ -268,7 +275,7 @@ public Event_RoundEnd(Handle:event, const String:name[], bool:dontBroadcast)
|
||||
new maxrounds = GetConVarInt(g_Cvar_Maxrounds);
|
||||
if (maxrounds)
|
||||
{
|
||||
if (total >= (maxrounds - GetConVarInt(g_Cvar_StartRounds)))
|
||||
if (g_TotalRounds >= (maxrounds - GetConVarInt(g_Cvar_StartRounds)))
|
||||
{
|
||||
InitiateVote();
|
||||
}
|
||||
|
@ -90,10 +90,8 @@ public OnConfigsExecuted()
|
||||
}
|
||||
}
|
||||
|
||||
public Action:OnTimedKick(Handle:timer, any:value)
|
||||
{
|
||||
new client = GetClientOfUserId(value);
|
||||
|
||||
public Action:OnTimedKick(Handle:timer, any:client)
|
||||
{
|
||||
if (!client || !IsClientInGame(client))
|
||||
{
|
||||
return Plugin_Handled;
|
||||
@ -101,6 +99,11 @@ public Action:OnTimedKick(Handle:timer, any:value)
|
||||
|
||||
KickClient(client, "%T", "Slot reserved", client);
|
||||
|
||||
if (GetConVarBool(sm_hide_slots))
|
||||
{
|
||||
SetVisibleMaxSlots(GetClientCount(false), g_MaxClients - GetConVarInt(sm_reserved_slots));
|
||||
}
|
||||
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
@ -113,32 +116,45 @@ public OnClientPostAdminCheck(client)
|
||||
new clients = GetClientCount(false);
|
||||
new limit = g_MaxClients - reserved;
|
||||
new flags = GetUserFlagBits(client);
|
||||
|
||||
if (clients <= limit || IsFakeClient(client) || flags & ADMFLAG_ROOT || flags & ADMFLAG_RESERVATION)
|
||||
|
||||
new type = GetConVarInt(sm_reserve_type);
|
||||
|
||||
if (type == 0)
|
||||
{
|
||||
if (GetConVarBool(sm_hide_slots))
|
||||
if (clients <= limit || IsFakeClient(client) || flags & ADMFLAG_ROOT || flags & ADMFLAG_RESERVATION)
|
||||
{
|
||||
SetVisibleMaxSlots(clients, limit);
|
||||
if (GetConVarBool(sm_hide_slots))
|
||||
{
|
||||
SetVisibleMaxSlots(clients, limit);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
new type = GetConVarInt(sm_reserve_type);
|
||||
|
||||
if (type == 1)
|
||||
{
|
||||
new target = SelectKickClient();
|
||||
|
||||
if (target)
|
||||
/* Kick player because there are no public slots left */
|
||||
CreateTimer(0.1, OnTimedKick, client);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (clients > limit)
|
||||
{
|
||||
if (flags & ADMFLAG_ROOT || flags & ADMFLAG_RESERVATION)
|
||||
{
|
||||
/* Kick public player to free the reserved slot again */
|
||||
CreateTimer(0.1, OnTimedKick, GetClientUserId(target));
|
||||
new target = SelectKickClient();
|
||||
|
||||
if (target)
|
||||
{
|
||||
/* Kick public player to free the reserved slot again */
|
||||
CreateTimer(0.1, OnTimedKick, target);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Kick player because there are no public slots left */
|
||||
CreateTimer(0.1, OnTimedKick, client);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Kick player because there are no public slots left */
|
||||
CreateTimer(0.1, OnTimedKick, GetClientUserId(client));
|
||||
}
|
||||
}
|
||||
|
||||
@ -161,7 +177,7 @@ public SlotsChanged(Handle:convar, const String:oldValue[], const String:newValu
|
||||
|
||||
SetVisibleMaxSlots(clients, limit)
|
||||
{
|
||||
new num = clients + 1;
|
||||
new num = clients;
|
||||
|
||||
if (clients == g_MaxClients)
|
||||
{
|
||||
@ -186,7 +202,7 @@ SelectKickClient()
|
||||
new Float:latency;
|
||||
|
||||
for (new i=1; i<=g_MaxClients; i++)
|
||||
{
|
||||
{
|
||||
if (!IsClientConnected(i))
|
||||
{
|
||||
continue;
|
||||
@ -198,13 +214,17 @@ SelectKickClient()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
latency = 0.0;
|
||||
|
||||
if (IsClientInGame(i))
|
||||
{
|
||||
latency = GetClientAvgLatency(i, NetFlow_Both);
|
||||
{
|
||||
latency = GetClientAvgLatency(i, NetFlow_Outgoing);
|
||||
|
||||
LogMessage("Latency : %f",latency);
|
||||
|
||||
if (IsClientObserver(i))
|
||||
{
|
||||
{
|
||||
specFound = true;
|
||||
|
||||
if (latency > highestSpecLatency)
|
||||
@ -214,12 +234,8 @@ SelectKickClient()
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
latency = 0.0;
|
||||
}
|
||||
|
||||
if (latency > highestLatency)
|
||||
if (latency >= highestLatency)
|
||||
{
|
||||
highestLatency = latency;
|
||||
highestLatencyId = i;
|
||||
|
@ -88,27 +88,15 @@ public OnPluginStart()
|
||||
|
||||
AutoExecConfig(true, "rtv");
|
||||
}
|
||||
|
||||
public OnConfigsExecuted()
|
||||
{
|
||||
if (g_RTVMapList != INVALID_HANDLE)
|
||||
{
|
||||
ClearArray(g_RTVMapList);
|
||||
}
|
||||
|
||||
g_Voters = 0;
|
||||
g_Votes = 0;
|
||||
g_VotesNeeded = 0;
|
||||
g_RTVStarted = false;
|
||||
g_RTVEnded = false;
|
||||
|
||||
if (LoadMaps(g_MapList, g_mapFileTime, g_Cvar_File))
|
||||
{
|
||||
BuildMapMenu();
|
||||
g_CanRTV = true;
|
||||
CreateTimer(30.0, Timer_DelayRTV);
|
||||
}
|
||||
}
|
||||
|
||||
public OnMapStart()
|
||||
{
|
||||
g_Voters = 0;
|
||||
g_Votes = 0;
|
||||
g_VotesNeeded = 0;
|
||||
g_RTVStarted = false;
|
||||
g_RTVEnded = false;
|
||||
}
|
||||
|
||||
public OnMapEnd()
|
||||
{
|
||||
@ -116,10 +104,24 @@ public OnMapEnd()
|
||||
g_RTVAllowed = false;
|
||||
}
|
||||
|
||||
public OnConfigsExecuted()
|
||||
{
|
||||
if (g_RTVMapList != INVALID_HANDLE)
|
||||
{
|
||||
ClearArray(g_RTVMapList);
|
||||
}
|
||||
|
||||
if (LoadMaps(g_MapList, g_mapFileTime, g_Cvar_File))
|
||||
{
|
||||
BuildMapMenu();
|
||||
g_CanRTV = true;
|
||||
CreateTimer(30.0, Timer_DelayRTV);
|
||||
}
|
||||
}
|
||||
|
||||
public bool:OnClientConnect(client, String:rejectmsg[], maxlen)
|
||||
{
|
||||
if(IsFakeClient(client))
|
||||
if(!g_CanRTV || IsFakeClient(client))
|
||||
return true;
|
||||
|
||||
g_Voted[client] = false;
|
||||
@ -133,7 +135,7 @@ public bool:OnClientConnect(client, String:rejectmsg[], maxlen)
|
||||
|
||||
public OnClientDisconnect(client)
|
||||
{
|
||||
if(IsFakeClient(client))
|
||||
if(!g_CanRTV || IsFakeClient(client))
|
||||
return;
|
||||
|
||||
if(g_Voted[client])
|
||||
@ -145,8 +147,9 @@ public OnClientDisconnect(client)
|
||||
|
||||
g_VotesNeeded = RoundToFloor(float(g_Voters) * GetConVarFloat(g_Cvar_Needed));
|
||||
|
||||
if (g_Votes && g_Voters && g_Votes >= g_VotesNeeded && g_RTVAllowed)
|
||||
{
|
||||
if (g_Votes && g_Voters && g_Votes >= g_VotesNeeded && g_RTVAllowed && !g_RTVStarted)
|
||||
{
|
||||
g_RTVStarted = true;
|
||||
CreateTimer(2.0, Timer_StartRTV, TIMER_FLAG_NO_MAPCHANGE);
|
||||
}
|
||||
}
|
||||
@ -157,6 +160,12 @@ public Action:Command_Addmap(client, args)
|
||||
{
|
||||
ReplyToCommand(client, "[SM] Usage: sm_rtv_addmap <mapname>");
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
if (!g_CanRTV)
|
||||
{
|
||||
ReplyToCommand(client, "[SM] RockTheVote is not available.");
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
decl String:mapname[64];
|
||||
@ -208,8 +217,10 @@ public Action:Command_Addmap(client, args)
|
||||
|
||||
public Action:Command_Say(client, args)
|
||||
{
|
||||
if (!g_CanRTV || !client)
|
||||
return Plugin_Continue;
|
||||
if (!g_CanRTV || !client)
|
||||
{
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
decl String:text[192];
|
||||
if (!GetCmdArgString(text, sizeof(text)))
|
||||
@ -265,7 +276,8 @@ public Action:Command_Say(client, args)
|
||||
PrintToChatAll("[SM] %t", "RTV Requested", name, g_Votes, g_VotesNeeded);
|
||||
|
||||
if (g_Votes >= g_VotesNeeded)
|
||||
{
|
||||
{
|
||||
g_RTVStarted = true;
|
||||
CreateTimer(2.0, Timer_StartRTV, TIMER_FLAG_NO_MAPCHANGE);
|
||||
}
|
||||
}
|
||||
@ -318,8 +330,6 @@ public Action:Timer_StartRTV(Handle:timer)
|
||||
return;
|
||||
}
|
||||
|
||||
g_RTVStarted = true;
|
||||
|
||||
if (IsVoteInProgress())
|
||||
{
|
||||
// Can't start a vote, try again in 5 seconds.
|
||||
@ -429,7 +439,8 @@ public Handler_MapMapVoteMenu(Handle:menu, MenuAction:action, param1, param2)
|
||||
{
|
||||
if (param1 == VoteCancel_NoVotes)
|
||||
{
|
||||
PrintToChatAll("[SM] %t", "No Votes");
|
||||
PrintToChatAll("[SM] %t", "No Votes");
|
||||
g_RTVEnded = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,13 +9,17 @@ public Plugin:myinfo =
|
||||
url = "http://www.sourcemod.net/"
|
||||
};
|
||||
|
||||
public OnPluginStart(Handle:myself)
|
||||
public OnPluginStart()
|
||||
{
|
||||
RegServerCmd("test_sort_ints", Command_TestSortInts)
|
||||
RegServerCmd("test_sort_floats", Command_TestSortFloats)
|
||||
RegServerCmd("test_sort_strings", Command_TestSortStrings)
|
||||
RegServerCmd("test_sort_1d", Command_TestSort1D)
|
||||
RegServerCmd("test_sort_2d", Command_TestSort2D)
|
||||
RegServerCmd("test_adtsort_ints", Command_TestSortADTInts)
|
||||
RegServerCmd("test_adtsort_floats", Command_TestSortADTFloats)
|
||||
RegServerCmd("test_adtsort_strings", Command_TestSortADTStrings)
|
||||
RegServerCmd("test_adtsort_custom", Command_TestSortADTCustom)
|
||||
}
|
||||
|
||||
/*****************
|
||||
@ -138,7 +142,7 @@ public Action:Command_TestSortStrings(args)
|
||||
|
||||
public Custom2DSort(String:elem1[], String:elem2[], String:array[][], Handle:hndl)
|
||||
{
|
||||
return StrCompare(elem1, elem2)
|
||||
return strcmp(elem1, elem2)
|
||||
}
|
||||
|
||||
public Action:Command_TestSort2D(args)
|
||||
@ -162,3 +166,142 @@ public Action:Command_TestSort2D(args)
|
||||
|
||||
return Plugin_Handled
|
||||
}
|
||||
|
||||
/*******************
|
||||
* ADT ARRAY TESTS *
|
||||
*******************/
|
||||
// Int and floats work the same as normal comparisions. Strings are direct
|
||||
// comparisions with no hacky memory stuff like Pawn arrays.
|
||||
|
||||
PrintADTArrayIntegers(Handle:array)
|
||||
{
|
||||
new size = GetArraySize(array);
|
||||
for (new i=0; i<size;i++)
|
||||
{
|
||||
PrintToServer("array[%d] = %d", i, GetArrayCell(array, i));
|
||||
}
|
||||
}
|
||||
|
||||
public Action:Command_TestSortADTInts(args)
|
||||
{
|
||||
new Handle:array = CreateArray();
|
||||
PushArrayCell(array, 6);
|
||||
PushArrayCell(array, 7);
|
||||
PushArrayCell(array, 3);
|
||||
PushArrayCell(array, 2);
|
||||
PushArrayCell(array, 8);
|
||||
PushArrayCell(array, 5);
|
||||
PushArrayCell(array, 0);
|
||||
PushArrayCell(array, 1);
|
||||
PushArrayCell(array, 4);
|
||||
PushArrayCell(array, 9);
|
||||
|
||||
PrintToServer("Testing ascending sort:")
|
||||
SortADTArray(array, Sort_Ascending, Sort_Integer)
|
||||
PrintADTArrayIntegers(array)
|
||||
|
||||
PrintToServer("Testing descending sort:")
|
||||
SortADTArray(array, Sort_Descending, Sort_Integer)
|
||||
PrintADTArrayIntegers(array)
|
||||
|
||||
return Plugin_Handled
|
||||
|
||||
}
|
||||
|
||||
PrintADTArrayFloats(Handle:array)
|
||||
{
|
||||
new size = GetArraySize(array);
|
||||
for (new i=0; i<size;i++)
|
||||
{
|
||||
PrintToServer("array[%d] = %f", i, float:GetArrayCell(array, i));
|
||||
}
|
||||
}
|
||||
|
||||
public Action:Command_TestSortADTFloats(args)
|
||||
{
|
||||
new Handle:array = CreateArray();
|
||||
PushArrayCell(array, 6.0);
|
||||
PushArrayCell(array, 7.0);
|
||||
PushArrayCell(array, 3.0);
|
||||
PushArrayCell(array, 2.0);
|
||||
PushArrayCell(array, 8.0);
|
||||
PushArrayCell(array, 5.0);
|
||||
PushArrayCell(array, 0.0);
|
||||
PushArrayCell(array, 1.0);
|
||||
PushArrayCell(array, 4.0);
|
||||
PushArrayCell(array, 9.0);
|
||||
|
||||
PrintToServer("Testing ascending sort:")
|
||||
SortADTArray(array, Sort_Ascending, Sort_Float)
|
||||
PrintADTArrayFloats(array)
|
||||
|
||||
PrintToServer("Testing descending sort:")
|
||||
SortADTArray(array, Sort_Descending, Sort_Float)
|
||||
PrintADTArrayFloats(array)
|
||||
|
||||
return Plugin_Handled
|
||||
}
|
||||
|
||||
PrintADTArrayStrings(Handle:array)
|
||||
{
|
||||
new size = GetArraySize(array);
|
||||
decl String:buffer[64];
|
||||
for (new i=0; i<size;i++)
|
||||
{
|
||||
GetArrayString(array, i, buffer, sizeof(buffer));
|
||||
PrintToServer("array[%d] = %s", i, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public Action:Command_TestSortADTStrings(args)
|
||||
{
|
||||
new Handle:array = CreateArray(ByteCountToCells(64));
|
||||
PushArrayString(array, "faluco");
|
||||
PushArrayString(array, "bailopan");
|
||||
PushArrayString(array, "pm onoto");
|
||||
PushArrayString(array, "damaged soul");
|
||||
PushArrayString(array, "sniperbeamer");
|
||||
PushArrayString(array, "sidluke");
|
||||
PushArrayString(array, "johnny got his gun");
|
||||
PushArrayString(array, "gabe newell");
|
||||
PushArrayString(array, "hello");
|
||||
PushArrayString(array, "WHAT?!");
|
||||
|
||||
PrintToServer("Testing ascending sort:")
|
||||
SortADTArray(array, Sort_Ascending, Sort_String)
|
||||
PrintADTArrayStrings(array)
|
||||
|
||||
PrintToServer("Testing descending sort:")
|
||||
SortADTArray(array, Sort_Descending, Sort_String)
|
||||
PrintADTArrayStrings(array)
|
||||
|
||||
return Plugin_Handled
|
||||
}
|
||||
|
||||
public ArrayADTCustomCallback(index1, index2, Handle:array, Handle:hndl)
|
||||
{
|
||||
decl String:buffer1[64], String:buffer2[64];
|
||||
GetArrayString(array, index1, buffer1, sizeof(buffer1));
|
||||
GetArrayString(array, index2, buffer2, sizeof(buffer2));
|
||||
|
||||
return strcmp(buffer1, buffer2);
|
||||
}
|
||||
|
||||
public Action:Command_TestSortADTCustom(args)
|
||||
{
|
||||
new Handle:array = CreateArray(ByteCountToCells(64));
|
||||
PushArrayString(array, "faluco");
|
||||
PushArrayString(array, "bailopan");
|
||||
PushArrayString(array, "pm onoto");
|
||||
PushArrayString(array, "damaged soul");
|
||||
PushArrayString(array, "sniperbeamer");
|
||||
PushArrayString(array, "sidluke");
|
||||
PushArrayString(array, "johnny got his gun");
|
||||
PushArrayString(array, "gabe newell");
|
||||
PushArrayString(array, "hello");
|
||||
PushArrayString(array, "WHAT?!");
|
||||
|
||||
PrintToServer("Testing custom sort:")
|
||||
SortADTArrayCustom(array, ArrayADTCustomCallback)
|
||||
PrintADTArrayStrings(array);
|
||||
}
|
||||
|
@ -624,7 +624,7 @@ namespace SourceMod
|
||||
/**
|
||||
* @brief Reads a single character as a flag.
|
||||
*
|
||||
* @param flag Flag character.
|
||||
* @param c Flag character.
|
||||
* @param pAdmFlag Pointer to store the admin flag.
|
||||
* @return True on success, false if invalid.
|
||||
*/
|
||||
@ -707,7 +707,7 @@ namespace SourceMod
|
||||
* @brief Computers access to an override.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param override Override name.
|
||||
* @param cmd Override name.
|
||||
* @param flags Default flags.
|
||||
* @param override_only If false, if a command matches the override,
|
||||
* then its flags will override the default.
|
||||
|
@ -36,6 +36,11 @@
|
||||
#include <IHandleSys.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* @file IDBDriver.h
|
||||
* @brief Defines interfaces for interacting with relational databases.
|
||||
*/
|
||||
|
||||
#define SMINTERFACE_DBI_NAME "IDBI"
|
||||
#define SMINTERFACE_DBI_VERSION 5
|
||||
|
||||
@ -784,7 +789,7 @@ namespace SourceMod
|
||||
* @param type A DBHandleType value.
|
||||
* @param ptr A pointer corrresponding to a DBHandleType
|
||||
* object.
|
||||
* @param token Identity pointer of the owning identity.
|
||||
* @param pToken Identity pointer of the owning identity.
|
||||
* @return A new Handle_t handle, or 0 on failure.
|
||||
*/
|
||||
virtual Handle_t CreateHandle(DBHandleType type, void *ptr, IdentityToken_t *pToken) =0;
|
||||
@ -814,7 +819,7 @@ namespace SourceMod
|
||||
* @brief Given a driver name, attempts to find it. If it is not found, SourceMod
|
||||
* will attempt to load it. This function is not thread safe.
|
||||
*
|
||||
* @param name Driver identifier name.
|
||||
* @param driver Driver identifier name.
|
||||
* @return IDBDriver pointer on success, NULL otherwise.
|
||||
*/
|
||||
virtual IDBDriver *FindOrLoadDriver(const char *driver) =0;
|
||||
|
@ -127,8 +127,11 @@ namespace SourceMod
|
||||
|
||||
/**
|
||||
* @brief Version code of the IExtensionInterface API itself.
|
||||
*
|
||||
* Note: This is bumped when IShareSys is changed, because IShareSys
|
||||
* itself is not versioned.
|
||||
*/
|
||||
#define SMINTERFACE_EXTENSIONAPI_VERSION 2
|
||||
#define SMINTERFACE_EXTENSIONAPI_VERSION 3
|
||||
|
||||
/**
|
||||
* @brief The interface an extension must expose.
|
||||
@ -337,7 +340,6 @@ namespace SourceMod
|
||||
*
|
||||
* @param path Path to extension file, relative to the
|
||||
* extensions folder.
|
||||
* @param lifetime Lifetime of the extension (currently ignored).
|
||||
* @param error Error buffer.
|
||||
* @param maxlength Maximum error buffer length.
|
||||
* @return New IExtension on success, NULL on failure.
|
||||
|
@ -37,6 +37,11 @@
|
||||
#define SMINTERFACE_MEMORYUTILS_NAME "IMemoryUtils"
|
||||
#define SMINTERFACE_MEMORYUTILS_VERSION 1
|
||||
|
||||
/**
|
||||
* @file IMemoryUtils.h
|
||||
* @brief Interface for finding patterns in memory.
|
||||
*/
|
||||
|
||||
namespace SourceMod
|
||||
{
|
||||
class IMemoryUtils : public SMInterface
|
||||
|
@ -265,7 +265,7 @@ namespace SourceMod
|
||||
* @brief Returns whether the display is capable of rendering an item
|
||||
* with the given flags.
|
||||
*
|
||||
* @param flags ITEMDRAW flags.
|
||||
* @param drawFlags ITEMDRAW flags.
|
||||
* @return True if renderable, false otherwise.
|
||||
*/
|
||||
virtual bool CanDrawItem(unsigned int drawFlags) =0;
|
||||
@ -289,7 +289,7 @@ namespace SourceMod
|
||||
* @brief Sets the selectable key map. Returns false if the function
|
||||
* is not supported.
|
||||
*
|
||||
* @param keys A bit string where each bit N-1 specifies
|
||||
* @param keymap A bit string where each bit N-1 specifies
|
||||
* that key N is selectable (key 0 is bit 9).
|
||||
* If the selectable key map is 0, it will be
|
||||
* automatically set to allow 0.
|
||||
@ -662,6 +662,7 @@ namespace SourceMod
|
||||
* @brief A display/selection cycle has ended.
|
||||
*
|
||||
* @param menu Menu pointer.
|
||||
* @param reason MenuEndReason reason.
|
||||
*/
|
||||
virtual void OnMenuEnd(IBaseMenu *menu, MenuEndReason reason)
|
||||
{
|
||||
@ -740,6 +741,7 @@ namespace SourceMod
|
||||
* always be called.
|
||||
*
|
||||
* @param menu Menu pointer.
|
||||
* @param reason VoteCancelReason reason.
|
||||
*/
|
||||
virtual void OnMenuVoteCancel(IBaseMenu *menu, VoteCancelReason reason)
|
||||
{
|
||||
@ -823,6 +825,7 @@ namespace SourceMod
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param states Menu states.
|
||||
* @param order Order to search for items.
|
||||
* @return IMenuPanel pointer, or NULL if no items could be
|
||||
* found in the IBaseMenu pointer, or NULL if any
|
||||
* other error occurred. Any valid pointer must
|
||||
|
@ -41,7 +41,7 @@
|
||||
#include <IAdminSystem.h>
|
||||
|
||||
#define SMINTERFACE_PLAYERMANAGER_NAME "IPlayerManager"
|
||||
#define SMINTERFACE_PLAYERMANAGER_VERSION 6
|
||||
#define SMINTERFACE_PLAYERMANAGER_VERSION 7
|
||||
|
||||
struct edict_t;
|
||||
class IPlayerInfo;
|
||||
@ -147,6 +147,42 @@ namespace SourceMod
|
||||
* @return IPlayerInfo pointer, or NULL if none.
|
||||
*/
|
||||
virtual IPlayerInfo *GetPlayerInfo() =0;
|
||||
|
||||
/**
|
||||
* @brief Runs through Core's admin authorization checks. If the
|
||||
* client is already an admin, no checks are performed.
|
||||
*
|
||||
* Note that this function operates solely against the in-memory admin
|
||||
* cache. It will check steamids, IPs, names, and verify a password
|
||||
* if one exists. To implement other authentication schemes, simply
|
||||
* don't call this function and use IGamePlayer::SetAdminId() instead.
|
||||
*
|
||||
* @return True if access changed, false otherwise.
|
||||
*/
|
||||
virtual bool RunAdminCacheChecks() =0;
|
||||
|
||||
/**
|
||||
* @brief Notifies all listeners that the client has completed
|
||||
* all of your post-connection (in-game, auth, admin) checks.
|
||||
*
|
||||
* If you returned "false" from OnClientPreAdminCheck(), you must
|
||||
* ALWAYS manually invoke this function, even if RunAdminCacheChecks()
|
||||
* failed or you did not assign an AdminId. Failure to call this
|
||||
* function could result in plugins (such as reservedslots) not
|
||||
* working properly.
|
||||
*
|
||||
* If you are implementing asynchronous fetches, and the client
|
||||
* disconnects during your fetching process, you should make sure to
|
||||
* recognize that case and not call this function. That is, do not
|
||||
* call this function on mismatched PreCheck calls, or on disconnected
|
||||
* clients. A good way to check this is to pass userids around, which
|
||||
* are unique per client connection.
|
||||
*
|
||||
* Calling this has no effect if it has already been called on the
|
||||
* given client (thus it is safe for multiple asynchronous plugins to
|
||||
* call it at various times).
|
||||
*/
|
||||
virtual void NotifyPostAdminChecks() =0;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -230,6 +266,41 @@ namespace SourceMod
|
||||
virtual void OnServerActivated(int max_clients)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Called once a client is authorized and fully in-game, but
|
||||
* before admin checks are done. This can be used to override the
|
||||
* default admin checks for a client.
|
||||
*
|
||||
* By default, this function allows the authentication process to
|
||||
* continue as normal. If you need to delay the cache searching
|
||||
* process in order to get asynchronous data, then return false here.
|
||||
*
|
||||
* If you return false, you must call IPlayerManager::NotifyPostAdminCheck
|
||||
* for the same client, or else the OnClientPostAdminCheck callback will
|
||||
* never be called.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @return True to continue normally, false to override
|
||||
* the authentication process.
|
||||
*/
|
||||
virtual bool OnClientPreAdminCheck(int client)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Called once a client is authorized and fully in-game, and
|
||||
* after all post-connection authorizations have been passed. If the
|
||||
* client does not have an AdminId by this stage, it means that no
|
||||
* admin entry was in the cache that matched, and the user could not
|
||||
* be authenticated as an admin.
|
||||
*
|
||||
* @param client Client index.
|
||||
*/
|
||||
virtual void OnClientPostAdminCheck(int client)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#define COMMAND_FILTER_ALIVE (1<<0) /**< Only allow alive players */
|
||||
|
@ -200,6 +200,29 @@ namespace SourceMod
|
||||
* @param name Library name.
|
||||
*/
|
||||
virtual void RegisterLibrary(IExtension *myself, const char *name) =0;
|
||||
|
||||
/**
|
||||
* @brief Adds a list of natives to the global native pool, to be
|
||||
* bound on plugin load.
|
||||
*
|
||||
* Unlike AddNatives(), this function implements natives that are
|
||||
* ALWAYS bound, regardless of whether a previous function is bound.
|
||||
* That means extensions can override Core natives.
|
||||
*
|
||||
* A Core version of each native must exist. If one does not, then
|
||||
* Core will simply ignore that entry.
|
||||
*
|
||||
* Override natives represent a weak coupling. If the extension is
|
||||
* unloaded, the native will be re-bound to the Core version.
|
||||
*
|
||||
* @param myself Identity token of parent object.
|
||||
* @param natives Array of natives to add. The last entry in
|
||||
* the array must be filled with NULLs to
|
||||
* terminate the array. The array must be static
|
||||
* as Core will cache the pointer for the
|
||||
* lifetime of the extension.
|
||||
*/
|
||||
virtual void OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives) =0;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,7 @@
|
||||
#include <time.h>
|
||||
|
||||
#define SMINTERFACE_SOURCEMOD_NAME "ISourceMod"
|
||||
#define SMINTERFACE_SOURCEMOD_VERSION 3
|
||||
#define SMINTERFACE_SOURCEMOD_VERSION 4
|
||||
|
||||
/**
|
||||
* @brief Forward declaration of the KeyValues class.
|
||||
@ -199,6 +199,23 @@ namespace SourceMod
|
||||
* @return Adjusted server time.
|
||||
*/
|
||||
virtual time_t GetAdjustedTime() =0;
|
||||
|
||||
/**
|
||||
* @brief Sets the global client SourceMod will use for assisted
|
||||
* translations (that is, %t).
|
||||
*
|
||||
* @param index Client index.
|
||||
* @return Old global client value.
|
||||
*/
|
||||
virtual unsigned int SetGlobalTarget(unsigned int index) =0;
|
||||
|
||||
/**
|
||||
* @brief Returns the global client SourceMod is currently using
|
||||
* for assisted translations (that is, %t).
|
||||
*
|
||||
* @return Global client value.
|
||||
*/
|
||||
virtual unsigned int GetGlobalTarget() const =0;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -280,7 +280,6 @@ namespace SourceMod
|
||||
* @param key Key string.
|
||||
* @param value Value string. If no quotes were specified, this will be NULL,
|
||||
* and key will contain the entire string.
|
||||
* @param Number of line in file.
|
||||
* @return SMCResult directive.
|
||||
*/
|
||||
virtual SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
|
||||
@ -291,7 +290,7 @@ namespace SourceMod
|
||||
/**
|
||||
* @brief Called when leaving the current section.
|
||||
*
|
||||
* @param Parsing states.
|
||||
* @param states Parsing states.
|
||||
* @return SMCResult directive.
|
||||
*/
|
||||
virtual SMCResult ReadSMC_LeavingSection(const SMCStates *states)
|
||||
|
@ -144,7 +144,7 @@ namespace SourceMod
|
||||
* @param flags Flags to use for sending the message.
|
||||
* @return bf_write structure to write message with, or NULL on failure.
|
||||
*/
|
||||
virtual bf_write *StartMessage(int msg_id, cell_t players[], unsigned int playersNum, int flags) =0;
|
||||
virtual bf_write *StartMessage(int msg_id, const cell_t players[], unsigned int playersNum, int flags) =0;
|
||||
|
||||
/**
|
||||
* @brief Wrapper around UserMessageEnd for use with StartMessage().
|
||||
|
@ -43,7 +43,7 @@
|
||||
*/
|
||||
|
||||
#define SMINTERFACE_TOPMENUS_NAME "ITopMenus"
|
||||
#define SMINTERFACE_TOPMENUS_VERSION 3
|
||||
#define SMINTERFACE_TOPMENUS_VERSION 4
|
||||
|
||||
namespace SourceMod
|
||||
{
|
||||
@ -268,6 +268,14 @@ namespace SourceMod
|
||||
* @return Object's info string, or NULL if none.
|
||||
*/
|
||||
virtual const char *GetObjectInfoString(unsigned int object_id) =0;
|
||||
|
||||
/**
|
||||
* @brief Returns an object's name string.
|
||||
*
|
||||
* @param object_id Object ID.
|
||||
* @return Object's name string, or NULL if none.
|
||||
*/
|
||||
virtual const char *GetObjectName(unsigned int object_id) =0;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -74,5 +74,6 @@
|
||||
//#define SMEXT_ENABLE_PLUGINSYS
|
||||
//#define SMEXT_ENABLE_ADMINSYS
|
||||
//#define SMEXT_ENABLE_TEXTPARSERS
|
||||
#define SMEXT_ENABLE_USERMSGS
|
||||
|
||||
#endif // _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_
|
||||
|
@ -91,6 +91,9 @@ IAdminSystem *adminsys = NULL;
|
||||
#if defined SMEXT_ENABLE_TEXTPARSERS
|
||||
ITextParsers *textparsers = NULL;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_USERMSGS
|
||||
IUserMessages *usermsgs = NULL;
|
||||
#endif
|
||||
|
||||
/** Exports the main interface */
|
||||
PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI()
|
||||
@ -173,6 +176,9 @@ bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error,
|
||||
#if defined SMEXT_ENABLE_TEXTPARSERS
|
||||
SM_GET_IFACE(TEXTPARSERS, textparsers);
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_USERMSGS
|
||||
SM_GET_IFACE(USERMSGS, usermsgs);
|
||||
#endif
|
||||
|
||||
if (SDK_OnLoad(error, maxlength, late))
|
||||
{
|
||||
|
@ -85,6 +85,9 @@
|
||||
#if defined SMEXT_ENABLE_TEXTPARSERS
|
||||
#include <ITextParsers.h>
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_USERMSGS
|
||||
#include <IUserMessages.h>
|
||||
#endif
|
||||
|
||||
#if defined SMEXT_CONF_METAMOD
|
||||
#include <ISmmPlugin.h>
|
||||
@ -277,6 +280,9 @@ extern IMenuManager *menus;
|
||||
#if defined SMEXT_ENABLE_ADMINSYS
|
||||
extern IAdminSystem *adminsys;
|
||||
#endif
|
||||
#if defined SMEXT_ENABLE_USERMSGS
|
||||
extern IUserMessages *usermsgs;
|
||||
#endif
|
||||
|
||||
#if defined SMEXT_CONF_METAMOD
|
||||
PLUGIN_GLOBALVARS();
|
||||
|
Loading…
Reference in New Issue
Block a user