- massive overhaul of the voting subsystem
- NOTE: menu API compatibility was COMPLETELY broken for C++! - cleaned up various aspects of the menu API - implemented new extended vote results callback - extended the debug reporter a tiny bit --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401275
This commit is contained in:
parent
9d0c2ea4d8
commit
6d60bd8de2
@ -33,14 +33,56 @@
|
||||
#include "DebugReporter.h"
|
||||
#include "Logger.h"
|
||||
#include "PluginSys.h"
|
||||
#include "sm_stringutil.h"
|
||||
|
||||
DebugReport g_DbgReporter;
|
||||
|
||||
/* I'm really lazy. This should probably be exported to ISourcePawnEngine someday,
|
||||
* but we need to make sure the JIT will deal with the version bump.
|
||||
*/
|
||||
extern const char *GetSourcePawnErrorMessage(int error);
|
||||
|
||||
void DebugReport::OnSourceModAllInitialized()
|
||||
{
|
||||
g_pSourcePawn->SetDebugListener(this);
|
||||
}
|
||||
|
||||
void DebugReport::GenerateError(IPluginContext *ctx, cell_t func_idx, int err, const char *message, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buffer[512];
|
||||
|
||||
va_start(ap, message);
|
||||
UTIL_FormatArgs(buffer, sizeof(buffer), message, ap);
|
||||
va_end(ap);
|
||||
|
||||
const char *plname = g_PluginSys.FindPluginByContext(ctx->GetContext())->GetFilename();
|
||||
const char *error = GetSourcePawnErrorMessage(err);
|
||||
|
||||
if (error)
|
||||
{
|
||||
g_Logger.LogError("[SM] Plugin \"%s\" encountered error %d: %s", plname, err, error);
|
||||
} else {
|
||||
g_Logger.LogError("[SM] Plugin \"%s\" encountered unknown error %d", plname, err);
|
||||
}
|
||||
|
||||
g_Logger.LogError("[SM] %s", buffer);
|
||||
|
||||
const char *func_name = NULL;
|
||||
if (func_idx != -1)
|
||||
{
|
||||
if (func_idx & 1)
|
||||
{
|
||||
func_idx >>= 1;
|
||||
sp_public_t *function;
|
||||
if (ctx->GetPublicByIndex(func_idx, &function) == SP_ERROR_NONE)
|
||||
{
|
||||
g_Logger.LogError("[SM] Unable to call function \"%s\" due to above errors.", function->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DebugReport::OnContextExecuteError(IPluginContext *ctx, IContextTrace *error)
|
||||
{
|
||||
const char *lastname;
|
||||
|
@ -44,6 +44,7 @@ public: // SMGlobalClass
|
||||
void OnSourceModAllInitialized();
|
||||
public: // IDebugListener
|
||||
void OnContextExecuteError(IPluginContext *ctx, IContextTrace *error);
|
||||
void GenerateError(IPluginContext *ctx, cell_t func_idx, int err, const char *message, ...);
|
||||
private:
|
||||
int _GetPluginIndex(IPluginContext *ctx);
|
||||
};
|
||||
|
@ -24,7 +24,7 @@ OBJECTS = AdminCache.cpp CDataPack.cpp ConCmdManager.cpp ConVarManager.cpp CoreC
|
||||
MemoryUtils.cpp PlayerManager.cpp TextParsers.cpp TimerSys.cpp Translator.cpp UserMessages.cpp \
|
||||
sm_autonatives.cpp sm_memtable.cpp sm_srvcmds.cpp sm_stringutil.cpp sm_trie.cpp \
|
||||
sourcemm_api.cpp sourcemod.cpp MenuStyle_Base.cpp MenuStyle_Valve.cpp MenuManager.cpp \
|
||||
MenuStyle_Radio.cpp ChatTriggers.cpp ADTFactory.cpp
|
||||
MenuStyle_Radio.cpp ChatTriggers.cpp ADTFactory.cpp MenuVoting.cpp
|
||||
OBJECTS += smn_admin.cpp smn_bitbuffer.cpp smn_console.cpp smn_core.cpp \
|
||||
smn_datapacks.cpp smn_entities.cpp smn_events.cpp smn_fakenatives.cpp \
|
||||
smn_filesystem.cpp smn_float.cpp smn_functions.cpp smn_gameconfigs.cpp smn_halflife.cpp smn_handles.cpp smn_keyvalues.cpp \
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include "MenuManager.h"
|
||||
#include "MenuVoting.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include "sourcemm_api.h"
|
||||
#include "PlayerManager.h"
|
||||
@ -43,220 +44,10 @@
|
||||
#include "sourcemm_api.h"
|
||||
|
||||
MenuManager g_Menus;
|
||||
VoteMenuHandler s_VoteHandler;
|
||||
|
||||
ConVar sm_menu_sounds("sm_menu_sounds", "1", 0, "Sets whether SourceMod menus play trigger sounds");
|
||||
|
||||
/*******************************
|
||||
*******************************
|
||||
******** VOTE HANDLER *********
|
||||
*******************************
|
||||
*******************************/
|
||||
|
||||
unsigned int VoteMenuHandler::GetMenuAPIVersion2()
|
||||
{
|
||||
return m_pHandler->GetMenuAPIVersion2();
|
||||
}
|
||||
|
||||
bool VoteMenuHandler::IsVoteInProgress()
|
||||
{
|
||||
return (m_pCurMenu != NULL);
|
||||
}
|
||||
|
||||
void VoteMenuHandler::InitializeVoting(IBaseMenu *menu)
|
||||
{
|
||||
m_Items = menu->GetItemCount();
|
||||
|
||||
if (m_Votes.size() < (size_t)m_Items)
|
||||
{
|
||||
/* Only clear the items we need to... */
|
||||
size_t size = m_Votes.size();
|
||||
for (size_t i=0; i<size; i++)
|
||||
{
|
||||
m_Votes[i] = 0;
|
||||
}
|
||||
m_Votes.resize(m_Items, 0);
|
||||
} else {
|
||||
for (unsigned int i=0; i<m_Items; i++)
|
||||
{
|
||||
m_Votes[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
m_pCurMenu = menu;
|
||||
|
||||
m_pHandler->OnMenuStart(m_pCurMenu);
|
||||
}
|
||||
|
||||
void VoteMenuHandler::StartVoting()
|
||||
{
|
||||
m_bStarted = true;
|
||||
|
||||
m_pHandler->OnMenuVoteStart(m_pCurMenu);
|
||||
|
||||
/* By now we know how many clients were set.
|
||||
* If there are none, we should end IMMEDIATELY.
|
||||
*/
|
||||
if (m_Clients == 0)
|
||||
{
|
||||
EndVoting();
|
||||
}
|
||||
}
|
||||
|
||||
void VoteMenuHandler::DecrementPlayerCount()
|
||||
{
|
||||
assert(m_Clients > 0);
|
||||
|
||||
m_Clients--;
|
||||
|
||||
if (m_bStarted && m_Clients == 0)
|
||||
{
|
||||
EndVoting();
|
||||
}
|
||||
}
|
||||
|
||||
void VoteMenuHandler::EndVoting()
|
||||
{
|
||||
if (m_bCancelled)
|
||||
{
|
||||
/* If we were cancelled, don't bother tabulating anything.
|
||||
* Reset just in case someone tries to redraw, which means
|
||||
* we need to save our states.
|
||||
*/
|
||||
IBaseMenu *menu = m_pCurMenu;
|
||||
InternalReset();
|
||||
m_pHandler->OnMenuVoteCancel(menu);
|
||||
m_pHandler->OnMenuEnd(menu, MenuEnd_VotingCancelled);
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int chosen = 0;
|
||||
unsigned int highest = 0;
|
||||
unsigned int dup_count = 0;
|
||||
unsigned int total = m_Votes.size() ? m_Votes[0] : 0;
|
||||
|
||||
/* If we got zero votes, take a shortcut. */
|
||||
if (m_NumVotes == 0)
|
||||
{
|
||||
/* Pick a random item and then jump far, far away. */
|
||||
srand((unsigned int)(time(NULL)));
|
||||
chosen = (unsigned int)rand() % m_Items;
|
||||
goto picked_item;
|
||||
}
|
||||
|
||||
/* We can't have more dups than this!
|
||||
* This is the max number of players.
|
||||
*/
|
||||
unsigned int dup_array[256];
|
||||
|
||||
for (size_t i=1; i<m_Items; i++)
|
||||
{
|
||||
if (m_Votes[i] > m_Votes[highest])
|
||||
{
|
||||
/* If we have a new highest count, mark it and trash the duplicate
|
||||
* list by setting the total to 0.
|
||||
*/
|
||||
highest = i;
|
||||
dup_count = 0;
|
||||
} else if (m_Votes[i] == m_Votes[highest]) {
|
||||
/* If they're equal, mark it in the duplicate list.
|
||||
* We'll add in the original later.
|
||||
*/
|
||||
dup_array[dup_count++] = i;
|
||||
}
|
||||
total += m_Votes[i];
|
||||
}
|
||||
|
||||
/* Check if we need to pick from the duplicate list */
|
||||
if (dup_count)
|
||||
{
|
||||
/* Re-add the original to the list because it's not in there. */
|
||||
dup_array[dup_count++] = highest;
|
||||
|
||||
/* Pick a random slot. */
|
||||
srand((unsigned int)(time(NULL)));
|
||||
unsigned int r = (unsigned int)rand() % dup_count;
|
||||
|
||||
/* Pick the item. */
|
||||
chosen = dup_array[r];
|
||||
} else {
|
||||
chosen = highest;
|
||||
}
|
||||
|
||||
picked_item:
|
||||
m_pHandler->OnMenuVoteEnd(m_pCurMenu, chosen, m_Votes[highest], total);
|
||||
m_pHandler->OnMenuEnd(m_pCurMenu, MenuEnd_VotingDone);
|
||||
InternalReset();
|
||||
}
|
||||
|
||||
void VoteMenuHandler::OnMenuStart(IBaseMenu *menu)
|
||||
{
|
||||
m_Clients++;
|
||||
}
|
||||
|
||||
void VoteMenuHandler::OnMenuEnd(IBaseMenu *menu, MenuEndReason reason)
|
||||
{
|
||||
DecrementPlayerCount();
|
||||
}
|
||||
|
||||
void VoteMenuHandler::OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason)
|
||||
{
|
||||
m_pHandler->OnMenuCancel(menu, client, reason);
|
||||
}
|
||||
|
||||
void VoteMenuHandler::OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display)
|
||||
{
|
||||
m_pHandler->OnMenuDisplay(menu, client, display);
|
||||
}
|
||||
|
||||
unsigned int VoteMenuHandler::OnMenuDisplayItem(IBaseMenu *menu, int client, IMenuPanel *panel, unsigned int item, const ItemDrawInfo &dr)
|
||||
{
|
||||
return m_pHandler->OnMenuDisplayItem(menu, client, panel, item, dr);
|
||||
}
|
||||
|
||||
void VoteMenuHandler::OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style)
|
||||
{
|
||||
m_pHandler->OnMenuDrawItem(menu, client, item, style);
|
||||
}
|
||||
|
||||
void VoteMenuHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int item)
|
||||
{
|
||||
/* Check by our item count, NOT the vote array size */
|
||||
if (item < m_Items)
|
||||
{
|
||||
m_Votes[item]++;
|
||||
m_NumVotes++;
|
||||
}
|
||||
|
||||
m_pHandler->OnMenuSelect(menu, client, item);
|
||||
}
|
||||
|
||||
void VoteMenuHandler::Reset(IMenuHandler *mh)
|
||||
{
|
||||
m_pHandler = mh;
|
||||
InternalReset();
|
||||
}
|
||||
|
||||
void VoteMenuHandler::InternalReset()
|
||||
{
|
||||
m_Clients = 0;
|
||||
m_Items = 0;
|
||||
m_bStarted = false;
|
||||
m_pCurMenu = NULL;
|
||||
m_NumVotes = 0;
|
||||
m_bCancelled = false;
|
||||
}
|
||||
|
||||
void VoteMenuHandler::CancelVoting()
|
||||
{
|
||||
m_bCancelled = true;
|
||||
}
|
||||
|
||||
/*******************************
|
||||
*******************************
|
||||
******** MENU MANAGER *********
|
||||
*******************************
|
||||
*******************************/
|
||||
|
||||
MenuManager::MenuManager()
|
||||
{
|
||||
m_Styles.push_back(&g_ValveMenuStyle);
|
||||
@ -283,12 +74,6 @@ void MenuManager::OnSourceModAllShutdown()
|
||||
{
|
||||
g_HandleSys.RemoveType(m_MenuType, g_pCoreIdent);
|
||||
g_HandleSys.RemoveType(m_StyleType, g_pCoreIdent);
|
||||
|
||||
while (!m_VoteHandlers.empty())
|
||||
{
|
||||
delete m_VoteHandlers.front();
|
||||
m_VoteHandlers.pop();
|
||||
}
|
||||
}
|
||||
|
||||
void MenuManager::OnHandleDestroy(HandleType_t type, void *object)
|
||||
@ -649,8 +434,8 @@ skip_search:
|
||||
if (pgn != MENU_NO_PAGINATION)
|
||||
{
|
||||
bool canDrawDisabled = display->CanDrawItem(ITEMDRAW_DISABLED|ITEMDRAW_CONTROL);
|
||||
bool exitButton = menu->GetExitButton();
|
||||
bool exitBackButton = menu->GetExitBackButton();
|
||||
bool exitButton = (menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXIT) == MENUFLAG_BUTTON_EXIT;
|
||||
bool exitBackButton = (menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXITBACK) == MENUFLAG_BUTTON_EXITBACK;
|
||||
char text[50];
|
||||
|
||||
/* Calculate how many items we are allowed for control stuff */
|
||||
@ -798,33 +583,6 @@ IMenuStyle *MenuManager::GetDefaultStyle()
|
||||
return m_pDefaultStyle;
|
||||
}
|
||||
|
||||
IVoteMenuHandler *MenuManager::CreateVoteWrapper(IMenuHandler *mh)
|
||||
{
|
||||
VoteMenuHandler *vh = NULL;
|
||||
|
||||
if (m_VoteHandlers.empty())
|
||||
{
|
||||
vh = new VoteMenuHandler;
|
||||
} else {
|
||||
vh = m_VoteHandlers.front();
|
||||
m_VoteHandlers.pop();
|
||||
}
|
||||
|
||||
vh->Reset(mh);
|
||||
|
||||
return vh;
|
||||
}
|
||||
|
||||
void MenuManager::ReleaseVoteWrapper(IVoteMenuHandler *mh)
|
||||
{
|
||||
if (mh == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_VoteHandlers.push((VoteMenuHandler *)mh);
|
||||
}
|
||||
|
||||
bool MenuManager::MenuSoundsEnabled()
|
||||
{
|
||||
return (sm_menu_sounds.GetInt() != 0);
|
||||
@ -879,7 +637,7 @@ const char *MenuManager::GetMenuSound(ItemSelection sel)
|
||||
{
|
||||
if (m_ExitSound.size() > 0)
|
||||
{
|
||||
sound= m_ExitSound.c_str();
|
||||
sound = m_ExitSound.c_str();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -907,3 +665,30 @@ void MenuManager::OnSourceModLevelChange(const char *mapName)
|
||||
enginesound->PrecacheSound(m_ExitSound.c_str(), true);
|
||||
}
|
||||
}
|
||||
|
||||
void MenuManager::CancelMenu(IBaseMenu *menu)
|
||||
{
|
||||
if (s_VoteHandler.GetCurrentMenu() == menu
|
||||
&& !s_VoteHandler.IsCancelling())
|
||||
{
|
||||
s_VoteHandler.CancelVoting();
|
||||
return;
|
||||
}
|
||||
|
||||
menu->Cancel();
|
||||
}
|
||||
|
||||
bool MenuManager::StartVote(IBaseMenu *menu, unsigned int num_clients, int clients[], unsigned int max_time, unsigned int flags)
|
||||
{
|
||||
return s_VoteHandler.StartVote(menu, num_clients, clients, max_time, flags);
|
||||
}
|
||||
|
||||
bool MenuManager::IsVoteInProgress()
|
||||
{
|
||||
return s_VoteHandler.IsVoteInProgress();
|
||||
}
|
||||
|
||||
void MenuManager::CancelVoting()
|
||||
{
|
||||
s_VoteHandler.CancelVoting();
|
||||
}
|
||||
|
@ -44,39 +44,6 @@
|
||||
using namespace SourceMod;
|
||||
using namespace SourceHook;
|
||||
|
||||
class VoteMenuHandler : public IVoteMenuHandler
|
||||
{
|
||||
public: //IMenuHandler
|
||||
unsigned int GetMenuAPIVersion2();
|
||||
void OnMenuStart(IBaseMenu *menu);
|
||||
void OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display);
|
||||
void OnMenuSelect(IBaseMenu *menu, int client, unsigned int item);
|
||||
void OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason);
|
||||
void OnMenuEnd(IBaseMenu *menu, MenuEndReason reason);
|
||||
void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style);
|
||||
unsigned int OnMenuDisplayItem(IBaseMenu *menu, int client, IMenuPanel *panel, unsigned int item, const ItemDrawInfo &dr);
|
||||
public: //IVoteMenuHandler
|
||||
bool IsVoteInProgress();
|
||||
void InitializeVoting(IBaseMenu *menu);
|
||||
void StartVoting();
|
||||
void CancelVoting();
|
||||
public:
|
||||
void Reset(IMenuHandler *mh);
|
||||
private:
|
||||
void DecrementPlayerCount();
|
||||
void EndVoting();
|
||||
void InternalReset();
|
||||
private:
|
||||
IMenuHandler *m_pHandler;
|
||||
unsigned int m_Clients;
|
||||
unsigned int m_Items;
|
||||
CVector<unsigned int> m_Votes;
|
||||
IBaseMenu *m_pCurMenu;
|
||||
bool m_bStarted;
|
||||
bool m_bCancelled;
|
||||
unsigned int m_NumVotes;
|
||||
};
|
||||
|
||||
class MenuManager :
|
||||
public IMenuManager,
|
||||
public SMGlobalClass,
|
||||
@ -114,8 +81,14 @@ public:
|
||||
void AddStyle(IMenuStyle *style);
|
||||
bool SetDefaultStyle(IMenuStyle *style);
|
||||
IMenuPanel *RenderMenu(int client, menu_states_t &states, ItemOrder order);
|
||||
IVoteMenuHandler *CreateVoteWrapper(IMenuHandler *mh);
|
||||
void ReleaseVoteWrapper(IVoteMenuHandler *mh);
|
||||
void CancelMenu(IBaseMenu *menu);
|
||||
bool StartVote(IBaseMenu *menu,
|
||||
unsigned int num_clients,
|
||||
int clients[],
|
||||
unsigned int max_time,
|
||||
unsigned int flags=0);
|
||||
bool IsVoteInProgress();
|
||||
void CancelVoting();
|
||||
public: //IHandleTypeDispatch
|
||||
void OnHandleDestroy(HandleType_t type, void *object);
|
||||
public:
|
||||
@ -130,7 +103,6 @@ protected:
|
||||
private:
|
||||
int m_ShowMenu;
|
||||
IMenuStyle *m_pDefaultStyle;
|
||||
CStack<VoteMenuHandler *> m_VoteHandlers;
|
||||
CVector<IMenuStyle *> m_Styles;
|
||||
HandleType_t m_StyleType;
|
||||
HandleType_t m_MenuType;
|
||||
|
@ -584,14 +584,12 @@ bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order)
|
||||
CBaseMenu::CBaseMenu(IMenuHandler *pHandler, IMenuStyle *pStyle, IdentityToken_t *pOwner) :
|
||||
m_pStyle(pStyle), m_Strings(512), m_Pagination(7), m_bShouldDelete(false), m_bCancelling(false),
|
||||
m_pOwner(pOwner ? pOwner : g_pCoreIdent), m_bDeleting(false), m_bWillFreeHandle(false),
|
||||
m_hHandle(BAD_HANDLE), m_pHandler(pHandler), m_pVoteHandler(NULL),
|
||||
m_nFlags(MENUFLAG_BUTTON_EXIT)
|
||||
m_hHandle(BAD_HANDLE), m_pHandler(pHandler), m_nFlags(MENUFLAG_BUTTON_EXIT)
|
||||
{
|
||||
}
|
||||
|
||||
CBaseMenu::~CBaseMenu()
|
||||
{
|
||||
g_Menus.ReleaseVoteWrapper(m_pVoteHandler);
|
||||
}
|
||||
|
||||
Handle_t CBaseMenu::GetHandle()
|
||||
@ -732,22 +730,6 @@ const char *CBaseMenu::GetDefaultTitle()
|
||||
return m_Title.c_str();
|
||||
}
|
||||
|
||||
bool CBaseMenu::GetExitButton()
|
||||
{
|
||||
return ((m_nFlags & MENUFLAG_BUTTON_EXIT) == MENUFLAG_BUTTON_EXIT);
|
||||
}
|
||||
|
||||
bool CBaseMenu::SetExitButton(bool set)
|
||||
{
|
||||
if (set)
|
||||
{
|
||||
m_nFlags |= MENUFLAG_BUTTON_EXIT;
|
||||
} else {
|
||||
m_nFlags &= ~MENUFLAG_BUTTON_EXIT;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CBaseMenu::Cancel()
|
||||
{
|
||||
if (m_bCancelling)
|
||||
@ -756,18 +738,11 @@ void CBaseMenu::Cancel()
|
||||
}
|
||||
|
||||
#if defined MENU_DEBUG
|
||||
g_Logger.LogMessage("[SM_MENU] CBaseMenu::Cancel(%p) (m_pVote %p) (inVote %d) (m_bShouldDelete %d)",
|
||||
g_Logger.LogMessage("[SM_MENU] CBaseMenu::Cancel(%p) (m_bShouldDelete %d)",
|
||||
this,
|
||||
m_pVoteHandler,
|
||||
m_pVoteHandler ? m_pVoteHandler->IsVoteInProgress() : false,
|
||||
m_bShouldDelete);
|
||||
#endif
|
||||
|
||||
if (m_pVoteHandler && m_pVoteHandler->IsVoteInProgress())
|
||||
{
|
||||
m_pVoteHandler->CancelVoting();
|
||||
}
|
||||
|
||||
m_bCancelling = true;
|
||||
Cancel_Finally();
|
||||
m_bCancelling = false;
|
||||
@ -827,58 +802,6 @@ void CBaseMenu::InternalDelete()
|
||||
delete this;
|
||||
}
|
||||
|
||||
bool CBaseMenu::BroadcastVote(int clients[],
|
||||
unsigned int numClients,
|
||||
unsigned int maxTime,
|
||||
unsigned int flags)
|
||||
{
|
||||
#if defined MENU_DEBUG
|
||||
g_Logger.LogMessage("[SM_MENU] CBaseMenu::BroadcastVote(%p) (maxTime %d) (numClients %d) (m_pVote %p) (inVote %d)",
|
||||
this,
|
||||
maxTime,
|
||||
numClients,
|
||||
m_pVoteHandler,
|
||||
m_pVoteHandler ? m_pVoteHandler->IsVoteInProgress() : false);
|
||||
#endif
|
||||
if (!m_pVoteHandler)
|
||||
{
|
||||
m_pVoteHandler = g_Menus.CreateVoteWrapper(m_pHandler);
|
||||
} else if (m_pVoteHandler->IsVoteInProgress()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_pVoteHandler->InitializeVoting(this);
|
||||
|
||||
for (unsigned int i=0; i<numClients; i++)
|
||||
{
|
||||
VoteDisplay(clients[i], maxTime);
|
||||
}
|
||||
|
||||
m_pVoteHandler->StartVoting();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBaseMenu::IsVoteInProgress()
|
||||
{
|
||||
return (m_pVoteHandler && m_pVoteHandler->IsVoteInProgress());
|
||||
}
|
||||
|
||||
bool CBaseMenu::GetExitBackButton()
|
||||
{
|
||||
return ((m_nFlags & MENUFLAG_BUTTON_EXITBACK) == MENUFLAG_BUTTON_EXITBACK);
|
||||
}
|
||||
|
||||
void CBaseMenu::SetExitBackButton(bool set)
|
||||
{
|
||||
if (set)
|
||||
{
|
||||
m_nFlags |= MENUFLAG_BUTTON_EXITBACK;
|
||||
} else {
|
||||
m_nFlags &= ~MENUFLAG_BUTTON_EXITBACK;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int CBaseMenu::GetMenuOptionFlags()
|
||||
{
|
||||
return m_nFlags;
|
||||
@ -888,3 +811,8 @@ void CBaseMenu::SetMenuOptionFlags(unsigned int flags)
|
||||
{
|
||||
m_nFlags = flags;
|
||||
}
|
||||
|
||||
IMenuHandler *CBaseMenu::GetHandler()
|
||||
{
|
||||
return m_pHandler;
|
||||
}
|
||||
|
@ -125,23 +125,13 @@ public:
|
||||
virtual IMenuStyle *GetDrawStyle();
|
||||
virtual void SetDefaultTitle(const char *message);
|
||||
virtual const char *GetDefaultTitle();
|
||||
virtual bool GetExitButton();
|
||||
virtual bool SetExitButton(bool set);
|
||||
virtual void Cancel();
|
||||
virtual void Destroy(bool releaseHandle);
|
||||
virtual void Cancel_Finally() =0;
|
||||
virtual Handle_t GetHandle();
|
||||
virtual bool BroadcastVote(int clients[],
|
||||
unsigned int numClients,
|
||||
unsigned int maxTime,
|
||||
unsigned int flags=0);
|
||||
virtual bool IsVoteInProgress();
|
||||
virtual bool GetExitBackButton();
|
||||
virtual void SetExitBackButton(bool set);
|
||||
virtual unsigned int GetMenuOptionFlags();
|
||||
virtual void SetMenuOptionFlags(unsigned int flags);
|
||||
public:
|
||||
virtual void VoteDisplay(int client, unsigned int maxTime) =0;
|
||||
virtual IMenuHandler *GetHandler();
|
||||
private:
|
||||
void InternalDelete();
|
||||
protected:
|
||||
@ -157,7 +147,6 @@ protected:
|
||||
bool m_bWillFreeHandle;
|
||||
Handle_t m_hHandle;
|
||||
IMenuHandler *m_pHandler;
|
||||
IVoteMenuHandler *m_pVoteHandler;
|
||||
unsigned int m_nFlags;
|
||||
};
|
||||
|
||||
|
@ -390,7 +390,7 @@ IMenuPanel *CRadioMenu::CreatePanel()
|
||||
return g_RadioMenuStyle.MakeRadioDisplay(this);
|
||||
}
|
||||
|
||||
bool CRadioMenu::Display(int client, unsigned int time)
|
||||
bool CRadioMenu::Display(int client, unsigned int time, IMenuHandler *alt_handler)
|
||||
{
|
||||
#if defined MENU_DEBUG
|
||||
g_Logger.LogMessage("[SM_MENU] CRadioMenu::Display(%p) (client %d) (time %d)",
|
||||
@ -403,23 +403,7 @@ bool CRadioMenu::Display(int client, unsigned int time)
|
||||
return false;
|
||||
}
|
||||
|
||||
return g_RadioMenuStyle.DoClientMenu(client, this, m_pHandler, time);
|
||||
}
|
||||
|
||||
void CRadioMenu::VoteDisplay(int client, unsigned int maxTime)
|
||||
{
|
||||
#if defined MENU_DEBUG
|
||||
g_Logger.LogMessage("[SM_MENU] CRadioMenu::VoteDisplay(%p) (client %d) (time %d)",
|
||||
this,
|
||||
client,
|
||||
maxTime);
|
||||
#endif
|
||||
if (m_bCancelling)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
g_RadioMenuStyle.DoClientMenu(client, this, m_pVoteHandler, maxTime);
|
||||
return g_RadioMenuStyle.DoClientMenu(client, this, alt_handler ? alt_handler : m_pHandler, time);
|
||||
}
|
||||
|
||||
void CRadioMenu::Cancel_Finally()
|
||||
|
@ -114,9 +114,8 @@ public:
|
||||
public:
|
||||
bool SetExtOption(MenuOption option, const void *valuePtr);
|
||||
IMenuPanel *CreatePanel();
|
||||
bool Display(int client, unsigned int time);
|
||||
bool Display(int client, unsigned int time, IMenuHandler *alt_handler=NULL);
|
||||
void Cancel_Finally();
|
||||
void VoteDisplay(int client, unsigned int maxTime);
|
||||
};
|
||||
|
||||
extern CRadioStyle g_RadioMenuStyle;
|
||||
|
@ -383,24 +383,14 @@ bool CValveMenu::SetExtOption(MenuOption option, const void *valuePtr)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CValveMenu::Display(int client, unsigned int time)
|
||||
bool CValveMenu::Display(int client, unsigned int time, IMenuHandler *alt_handler)
|
||||
{
|
||||
if (m_bCancelling)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return g_ValveMenuStyle.DoClientMenu(client, this, m_pHandler, time);
|
||||
}
|
||||
|
||||
void CValveMenu::VoteDisplay(int client, unsigned int maxTime)
|
||||
{
|
||||
if (m_bCancelling)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
g_ValveMenuStyle.DoClientMenu(client, this, m_pVoteHandler, maxTime);
|
||||
return g_ValveMenuStyle.DoClientMenu(client, this, alt_handler ? alt_handler : m_pHandler, time);
|
||||
}
|
||||
|
||||
IMenuPanel *CValveMenu::CreatePanel()
|
||||
@ -408,19 +398,9 @@ IMenuPanel *CValveMenu::CreatePanel()
|
||||
return new CValveMenuDisplay(this);
|
||||
}
|
||||
|
||||
bool CValveMenu::GetExitButton()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CValveMenu::SetExitButton(bool set)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void CValveMenu::SetMenuOptionFlags(unsigned int flags)
|
||||
{
|
||||
flags &= ~MENUFLAG_BUTTON_EXIT;
|
||||
flags |= MENUFLAG_BUTTON_EXIT;
|
||||
CBaseMenu::SetMenuOptionFlags(flags);
|
||||
}
|
||||
|
||||
|
@ -120,8 +120,7 @@ public: //IBaseMenu
|
||||
bool GetExitButton();
|
||||
bool SetExitButton(bool set);
|
||||
bool SetPagination(unsigned int itemsPerPage);
|
||||
bool Display(int client, unsigned int time);
|
||||
void VoteDisplay(int client, unsigned int maxTime);
|
||||
bool Display(int client, unsigned int time, IMenuHandler *alt_handler=NULL);
|
||||
void SetMenuOptionFlags(unsigned int flags);
|
||||
public: //CBaseMenu
|
||||
void Cancel_Finally();
|
||||
|
326
core/MenuVoting.cpp
Normal file
326
core/MenuVoting.cpp
Normal file
@ -0,0 +1,326 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ================================================================
|
||||
* SourceMod
|
||||
* 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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "MenuVoting.h"
|
||||
#include "PlayerManager.h"
|
||||
#include "sourcemm_api.h"
|
||||
|
||||
void VoteMenuHandler::OnSourceModAllInitialized()
|
||||
{
|
||||
g_Players.AddClientListener(this);
|
||||
}
|
||||
|
||||
void VoteMenuHandler::OnSourceModShutdown()
|
||||
{
|
||||
g_Players.RemoveClientListener(this);
|
||||
}
|
||||
|
||||
unsigned int VoteMenuHandler::GetMenuAPIVersion2()
|
||||
{
|
||||
return m_pHandler->GetMenuAPIVersion2();
|
||||
}
|
||||
|
||||
void VoteMenuHandler::OnClientDisconnected(int client)
|
||||
{
|
||||
if (!IsVoteInProgress())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Wipe out their vote if they had one */
|
||||
int item;
|
||||
if ((item = m_ClientVotes[client]) >= 0)
|
||||
{
|
||||
assert((unsigned)item < m_Items);
|
||||
assert(m_Votes[item] > 0);
|
||||
m_Votes[item]--;
|
||||
m_ClientVotes[client] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
bool VoteMenuHandler::IsVoteInProgress()
|
||||
{
|
||||
return (m_pCurMenu != NULL);
|
||||
}
|
||||
|
||||
bool VoteMenuHandler::StartVote(IBaseMenu *menu, unsigned int num_clients, int clients[], unsigned int max_time, unsigned int flags/* =0 */)
|
||||
{
|
||||
if (!InitializeVoting(menu, menu->GetHandler(), max_time, flags))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (unsigned int i=0; i<num_clients; i++)
|
||||
{
|
||||
menu->Display(clients[i], max_time, this);
|
||||
}
|
||||
|
||||
StartVoting();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VoteMenuHandler::InitializeVoting(IBaseMenu *menu,
|
||||
IMenuHandler *handler,
|
||||
unsigned int time,
|
||||
unsigned int flags)
|
||||
{
|
||||
if (IsVoteInProgress())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
InternalReset();
|
||||
|
||||
/* Mark all clients as not voting */
|
||||
for (int i=1; i<=gpGlobals->maxClients; i++)
|
||||
{
|
||||
m_ClientVotes[i] = -2;
|
||||
}
|
||||
|
||||
m_Items = menu->GetItemCount();
|
||||
|
||||
if (m_Votes.size() < (size_t)m_Items)
|
||||
{
|
||||
/* Only clear the items we need to... */
|
||||
size_t size = m_Votes.size();
|
||||
for (size_t i=0; i<size; i++)
|
||||
{
|
||||
m_Votes[i] = 0;
|
||||
}
|
||||
m_Votes.resize(m_Items, 0);
|
||||
} else {
|
||||
for (unsigned int i=0; i<m_Items; i++)
|
||||
{
|
||||
m_Votes[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
m_pCurMenu = menu;
|
||||
m_VoteTime = time;
|
||||
m_VoteFlags = flags;
|
||||
m_pHandler = handler;
|
||||
|
||||
m_pHandler->OnMenuStart(m_pCurMenu);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VoteMenuHandler::StartVoting()
|
||||
{
|
||||
if (!m_pCurMenu)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_bStarted = true;
|
||||
|
||||
m_pHandler->OnMenuVoteStart(m_pCurMenu);
|
||||
|
||||
/* By now we know how many clients were set.
|
||||
* If there are none, we should end IMMEDIATELY.
|
||||
*/
|
||||
if (m_Clients == 0)
|
||||
{
|
||||
EndVoting();
|
||||
}
|
||||
}
|
||||
|
||||
void VoteMenuHandler::DecrementPlayerCount()
|
||||
{
|
||||
assert(m_Clients > 0);
|
||||
|
||||
m_Clients--;
|
||||
|
||||
if (m_bStarted && m_Clients == 0)
|
||||
{
|
||||
EndVoting();
|
||||
}
|
||||
}
|
||||
|
||||
int SortVoteItems(const void *item1, const void *item2)
|
||||
{
|
||||
return ((menu_vote_result_t::menu_item_vote_t *)item2)->count
|
||||
- ((menu_vote_result_t::menu_item_vote_t *)item1)->count;
|
||||
}
|
||||
|
||||
void VoteMenuHandler::EndVoting()
|
||||
{
|
||||
if (m_bCancelled)
|
||||
{
|
||||
/* If we were cancelled, don't bother tabulating anything.
|
||||
* Reset just in case someone tries to redraw, which means
|
||||
* we need to save our states.
|
||||
*/
|
||||
IBaseMenu *menu = m_pCurMenu;
|
||||
IMenuHandler *handler = m_pHandler;
|
||||
InternalReset();
|
||||
handler->OnMenuVoteCancel(menu);
|
||||
handler->OnMenuEnd(menu, MenuEnd_VotingCancelled);
|
||||
return;
|
||||
}
|
||||
|
||||
menu_vote_result_t vote;
|
||||
menu_vote_result_t::menu_client_vote_t client_vote[256];
|
||||
menu_vote_result_t::menu_item_vote_t item_vote[256];
|
||||
|
||||
memset(&vote, 0, sizeof(vote));
|
||||
|
||||
/* Build the item list */
|
||||
for (unsigned int i=0; i<m_Items; i++)
|
||||
{
|
||||
if (m_Votes[i] > 0)
|
||||
{
|
||||
item_vote[vote.num_items].count = m_Votes[i];
|
||||
item_vote[vote.num_items].item = i;
|
||||
vote.num_votes += m_Votes[i];
|
||||
vote.num_items++;
|
||||
}
|
||||
}
|
||||
vote.item_list = item_vote;
|
||||
|
||||
if (!vote.num_votes)
|
||||
{
|
||||
IBaseMenu *menu = m_pCurMenu;
|
||||
IMenuHandler *handler = m_pHandler;
|
||||
InternalReset();
|
||||
handler->OnMenuVoteCancel(menu);
|
||||
handler->OnMenuEnd(menu, MenuEnd_NoVotes);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Build the client list */
|
||||
for (int i=1; i<=gpGlobals->maxClients; i++)
|
||||
{
|
||||
if (m_ClientVotes[i] >= -1)
|
||||
{
|
||||
client_vote[vote.num_clients].client = i;
|
||||
client_vote[vote.num_clients].item = m_ClientVotes[i];
|
||||
vote.num_clients++;
|
||||
}
|
||||
}
|
||||
vote.client_list = client_vote;
|
||||
|
||||
/* Sort the item list descending like we promised */
|
||||
qsort(item_vote,
|
||||
vote.num_items,
|
||||
sizeof(menu_vote_result_t::menu_item_vote_t),
|
||||
SortVoteItems);
|
||||
|
||||
/* Save states, then clear what we've saved.
|
||||
* This makes us re-entrant, which is always the safe way to go.
|
||||
*/
|
||||
IBaseMenu *menu = m_pCurMenu;
|
||||
IMenuHandler *handler = m_pHandler;
|
||||
InternalReset();
|
||||
|
||||
/* Send vote info */
|
||||
handler->OnMenuVoteResults(menu, &vote);
|
||||
handler->OnMenuEnd(menu, MenuEnd_VotingDone);
|
||||
}
|
||||
|
||||
void VoteMenuHandler::OnMenuStart(IBaseMenu *menu)
|
||||
{
|
||||
m_Clients++;
|
||||
}
|
||||
|
||||
void VoteMenuHandler::OnMenuEnd(IBaseMenu *menu, MenuEndReason reason)
|
||||
{
|
||||
DecrementPlayerCount();
|
||||
}
|
||||
|
||||
void VoteMenuHandler::OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason)
|
||||
{
|
||||
m_pHandler->OnMenuCancel(menu, client, reason);
|
||||
}
|
||||
|
||||
void VoteMenuHandler::OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display)
|
||||
{
|
||||
m_ClientVotes[client] = -1;
|
||||
m_pHandler->OnMenuDisplay(menu, client, display);
|
||||
}
|
||||
|
||||
unsigned int VoteMenuHandler::OnMenuDisplayItem(IBaseMenu *menu, int client, IMenuPanel *panel, unsigned int item, const ItemDrawInfo &dr)
|
||||
{
|
||||
return m_pHandler->OnMenuDisplayItem(menu, client, panel, item, dr);
|
||||
}
|
||||
|
||||
void VoteMenuHandler::OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style)
|
||||
{
|
||||
m_pHandler->OnMenuDrawItem(menu, client, item, style);
|
||||
}
|
||||
|
||||
void VoteMenuHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int item)
|
||||
{
|
||||
/* Check by our item count, NOT the vote array size */
|
||||
if (item < m_Items)
|
||||
{
|
||||
m_ClientVotes[client] = item;
|
||||
m_Votes[item]++;
|
||||
m_NumVotes++;
|
||||
}
|
||||
|
||||
m_pHandler->OnMenuSelect(menu, client, item);
|
||||
}
|
||||
|
||||
void VoteMenuHandler::InternalReset()
|
||||
{
|
||||
m_Clients = 0;
|
||||
m_Items = 0;
|
||||
m_bStarted = false;
|
||||
m_pCurMenu = NULL;
|
||||
m_NumVotes = 0;
|
||||
m_bCancelled = false;
|
||||
m_pHandler = NULL;
|
||||
}
|
||||
|
||||
void VoteMenuHandler::CancelVoting()
|
||||
{
|
||||
if (m_bCancelled || !m_pCurMenu)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_bCancelled = true;
|
||||
m_pCurMenu->Cancel();
|
||||
}
|
||||
|
||||
IBaseMenu *VoteMenuHandler::GetCurrentMenu()
|
||||
{
|
||||
return m_pCurMenu;
|
||||
}
|
||||
|
||||
bool VoteMenuHandler::IsCancelling()
|
||||
{
|
||||
return m_bCancelled;
|
||||
}
|
97
core/MenuVoting.h
Normal file
97
core/MenuVoting.h
Normal file
@ -0,0 +1,97 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ================================================================
|
||||
* SourceMod
|
||||
* 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_MENUVOTING_H_
|
||||
#define _INCLUDE_SOURCEMOD_MENUVOTING_H_
|
||||
|
||||
#include <IMenuManager.h>
|
||||
#include <IPlayerHelpers.h>
|
||||
#include <sh_vector.h>
|
||||
#include "sm_globals.h"
|
||||
|
||||
using namespace SourceHook;
|
||||
using namespace SourceMod;
|
||||
|
||||
class VoteMenuHandler :
|
||||
public IMenuHandler,
|
||||
public SMGlobalClass,
|
||||
public IClientListener
|
||||
{
|
||||
public: //SMGlobalClass
|
||||
void OnSourceModAllInitialized();
|
||||
void OnSourceModShutdown();
|
||||
public: //IClientListener
|
||||
void OnClientDisconnected(int client);
|
||||
public: //IMenuHandler
|
||||
unsigned int GetMenuAPIVersion2();
|
||||
void OnMenuStart(IBaseMenu *menu);
|
||||
void OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display);
|
||||
void OnMenuSelect(IBaseMenu *menu, int client, unsigned int item);
|
||||
void OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason);
|
||||
void OnMenuEnd(IBaseMenu *menu, MenuEndReason reason);
|
||||
void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style);
|
||||
unsigned int OnMenuDisplayItem(IBaseMenu *menu, int client, IMenuPanel *panel, unsigned int item, const ItemDrawInfo &dr);
|
||||
public:
|
||||
bool StartVote(IBaseMenu *menu,
|
||||
unsigned int num_clients,
|
||||
int clients[],
|
||||
unsigned int max_time,
|
||||
unsigned int flags=0);
|
||||
bool IsVoteInProgress();
|
||||
void CancelVoting();
|
||||
IBaseMenu *GetCurrentMenu();
|
||||
bool IsCancelling();
|
||||
private:
|
||||
void Reset(IMenuHandler *mh);
|
||||
void DecrementPlayerCount();
|
||||
void EndVoting();
|
||||
void InternalReset();
|
||||
bool InitializeVoting(IBaseMenu *menu,
|
||||
IMenuHandler *handler,
|
||||
unsigned int time,
|
||||
unsigned int flags);
|
||||
void StartVoting();
|
||||
private:
|
||||
IMenuHandler *m_pHandler;
|
||||
unsigned int m_Clients;
|
||||
unsigned int m_Items;
|
||||
CVector<unsigned int> m_Votes;
|
||||
IBaseMenu *m_pCurMenu;
|
||||
bool m_bStarted;
|
||||
bool m_bCancelled;
|
||||
unsigned int m_NumVotes;
|
||||
unsigned int m_VoteTime;
|
||||
unsigned int m_VoteFlags;
|
||||
int m_ClientVotes[256+1];
|
||||
};
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_MENUVOTING_H_
|
@ -336,6 +336,10 @@
|
||||
RelativePath="..\MenuStyle_Valve.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\MenuVoting.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\PlayerManager.cpp"
|
||||
>
|
||||
@ -474,6 +478,10 @@
|
||||
RelativePath="..\MenuStyle_Valve.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\MenuVoting.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\PlayerManager.h"
|
||||
>
|
||||
|
@ -32,6 +32,7 @@
|
||||
|
||||
#include "sm_globals.h"
|
||||
#include <sh_stack.h>
|
||||
#include "DebugReporter.h"
|
||||
#include "MenuManager.h"
|
||||
#include "MenuStyle_Valve.h"
|
||||
#include "MenuStyle_Radio.h"
|
||||
@ -93,13 +94,11 @@ public:
|
||||
void OnMenuEnd(IBaseMenu *menu, MenuEndReason reason);
|
||||
void OnMenuDestroy(IBaseMenu *menu);
|
||||
void OnMenuVoteStart(IBaseMenu *menu);
|
||||
void OnMenuVoteEnd(IBaseMenu *menu,
|
||||
unsigned int item,
|
||||
unsigned int winningVotes,
|
||||
unsigned int totalVotes);
|
||||
void OnMenuVoteResults(IBaseMenu *menu, const menu_vote_result_t *results);
|
||||
void OnMenuVoteCancel(IBaseMenu *menu);
|
||||
void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style);
|
||||
unsigned int OnMenuDisplayItem(IBaseMenu *menu, int client, IMenuPanel *panel, unsigned int item, const ItemDrawInfo &dr);
|
||||
bool OnSetHandlerOption(const char *option, const void *data);
|
||||
#if 0
|
||||
void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style);
|
||||
void OnMenuDisplayItem(IBaseMenu *menu, int client, unsigned int item, const char **display);
|
||||
@ -109,6 +108,8 @@ private:
|
||||
private:
|
||||
IPluginFunction *m_pBasic;
|
||||
int m_Flags;
|
||||
IPluginFunction *m_pVoteResults;
|
||||
cell_t m_fnVoteResult;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -221,6 +222,7 @@ public:
|
||||
m_FreeMenuHandlers.pop();
|
||||
handler->m_pBasic = pFunction;
|
||||
handler->m_Flags = flags;
|
||||
handler->m_pVoteResults = NULL;
|
||||
}
|
||||
return handler;
|
||||
}
|
||||
@ -276,7 +278,7 @@ static const ItemDrawInfo *s_CurDrawInfo = NULL;
|
||||
* MENU HANDLER WRAPPER
|
||||
*/
|
||||
CMenuHandler::CMenuHandler(IPluginFunction *pBasic, int flags) :
|
||||
m_pBasic(pBasic), m_Flags(flags)
|
||||
m_pBasic(pBasic), m_Flags(flags), m_pVoteResults(NULL)
|
||||
{
|
||||
/* :TODO: We can probably cache the handle ahead of time */
|
||||
}
|
||||
@ -334,14 +336,6 @@ void CMenuHandler::OnMenuVoteStart(IBaseMenu *menu)
|
||||
DoAction(menu, MenuAction_VoteStart, 0, 0);
|
||||
}
|
||||
|
||||
void CMenuHandler::OnMenuVoteEnd(IBaseMenu *menu,
|
||||
unsigned int item,
|
||||
unsigned int winningVotes,
|
||||
unsigned int totalVotes)
|
||||
{
|
||||
DoAction(menu, MenuAction_VoteEnd, item, (totalVotes << 16) | (winningVotes & 0xFFFF));
|
||||
}
|
||||
|
||||
void CMenuHandler::OnMenuVoteCancel(IBaseMenu *menu)
|
||||
{
|
||||
DoAction(menu, MenuAction_VoteCancel, 0, 0);
|
||||
@ -407,6 +401,145 @@ cell_t CMenuHandler::DoAction(IBaseMenu *menu, MenuAction action, cell_t param1,
|
||||
return res;
|
||||
}
|
||||
|
||||
void CMenuHandler::OnMenuVoteResults(IBaseMenu *menu, const menu_vote_result_t *results)
|
||||
{
|
||||
if (!m_pVoteResults)
|
||||
{
|
||||
/* Call MenuAction_VoteEnd instead. See if there are any extra winners. */
|
||||
unsigned int num_items = 1;
|
||||
for (unsigned int i=1; i<results->num_items; i++)
|
||||
{
|
||||
if (results->item_list[i].count != results->item_list[0].count)
|
||||
{
|
||||
break;
|
||||
}
|
||||
num_items++;
|
||||
}
|
||||
|
||||
/* See if we need to pick a random winner. */
|
||||
unsigned int winning_item;
|
||||
if (num_items > 1)
|
||||
{
|
||||
/* Yes, we do. */
|
||||
srand(time(NULL));
|
||||
winning_item = rand() % num_items;
|
||||
winning_item = results->item_list[winning_item].item;
|
||||
} else {
|
||||
/* No, take the first. */
|
||||
winning_item = results->item_list[0].item;
|
||||
}
|
||||
|
||||
unsigned int total_votes = results->num_votes;
|
||||
unsigned int winning_votes = results->item_list[0].count;
|
||||
|
||||
DoAction(menu, MenuAction_VoteEnd, winning_item, (total_votes << 16) | (winning_votes & 0xFFFF));
|
||||
} else {
|
||||
IPluginContext *pContext = m_pVoteResults->GetParentContext();
|
||||
bool no_call = false;
|
||||
int err;
|
||||
|
||||
/* First array */
|
||||
cell_t client_array_address = -1;
|
||||
cell_t *client_array_base = NULL;
|
||||
cell_t client_array_size = results->num_clients + (results->num_clients * 2);
|
||||
if (client_array_size)
|
||||
{
|
||||
if ((err = pContext->HeapAlloc(client_array_size, &client_array_address, &client_array_base))
|
||||
!= SP_ERROR_NONE)
|
||||
{
|
||||
g_DbgReporter.GenerateError(pContext, m_fnVoteResult, err, "Menu callback could not allocate %d bytes for client list.", client_array_size * sizeof(cell_t));
|
||||
no_call = true;
|
||||
} else {
|
||||
cell_t target_offs = sizeof(cell_t) * results->num_clients;
|
||||
cell_t *cur_index = client_array_base;
|
||||
cell_t *cur_array;
|
||||
for (unsigned int i=0; i<results->num_clients; i++)
|
||||
{
|
||||
/* Copy the array index */
|
||||
*cur_index = target_offs;
|
||||
/* Get the current array address */
|
||||
cur_array = (cell_t *)((char *)cur_index + target_offs);
|
||||
/* Store information */
|
||||
cur_array[0] = results->client_list[i].client;
|
||||
cur_array[1] = results->client_list[i].item;
|
||||
/* Adjust for the new target by subtracting one indirection
|
||||
* and adding one array.
|
||||
*/
|
||||
target_offs += (sizeof(cell_t) * 2) - sizeof(cell_t);
|
||||
cur_index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Second array */
|
||||
cell_t item_array_address = -1;
|
||||
cell_t *item_array_base = NULL;
|
||||
cell_t item_array_size = results->num_items + (results->num_items * 2);
|
||||
if (item_array_size)
|
||||
{
|
||||
if ((err = pContext->HeapAlloc(item_array_size, &item_array_address, &item_array_base))
|
||||
!= SP_ERROR_NONE)
|
||||
{
|
||||
g_DbgReporter.GenerateError(pContext, m_fnVoteResult, err, "Menu callback could not allocate %d bytes for item list.", item_array_size);
|
||||
no_call = true;
|
||||
} else {
|
||||
cell_t target_offs = sizeof(cell_t) * results->num_items;
|
||||
cell_t *cur_index = item_array_base;
|
||||
cell_t *cur_array;
|
||||
for (unsigned int i=0; i<results->num_items; i++)
|
||||
{
|
||||
/* Copy the array index */
|
||||
*cur_index = target_offs;
|
||||
/* Get the current array address */
|
||||
cur_array = (cell_t *)((char *)cur_index + target_offs);
|
||||
/* Store information */
|
||||
cur_array[0] = results->item_list[i].item;
|
||||
cur_array[1] = results->item_list[i].count;
|
||||
/* Adjust for the new target by subtracting one indirection
|
||||
* and adding one array.
|
||||
*/
|
||||
target_offs += (sizeof(cell_t) * 2) - sizeof(cell_t);
|
||||
cur_index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Finally, push everything */
|
||||
if (!no_call)
|
||||
{
|
||||
m_pVoteResults->PushCell(results->num_votes);
|
||||
m_pVoteResults->PushCell(results->num_clients);
|
||||
m_pVoteResults->PushCell(client_array_address);
|
||||
m_pVoteResults->PushCell(results->num_items);
|
||||
m_pVoteResults->PushCell(item_array_address);
|
||||
m_pVoteResults->Execute(NULL);
|
||||
}
|
||||
|
||||
/* Free what we allocated, in reverse order as required */
|
||||
if (item_array_address != -1)
|
||||
{
|
||||
pContext->HeapPop(item_array_address);
|
||||
}
|
||||
if (client_array_address != -1)
|
||||
{
|
||||
pContext->HeapPop(client_array_address);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CMenuHandler::OnSetHandlerOption(const char *option, const void *data)
|
||||
{
|
||||
if (strcmp(option, "set_vote_results_handler") == 0)
|
||||
{
|
||||
void **array = (void **)data;
|
||||
m_pVoteResults = (IPluginFunction *)array[0];
|
||||
m_fnVoteResult = *(cell_t *)((cell_t *)array[1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* INLINE FUNCTIONS FOR NATIVES
|
||||
*/
|
||||
@ -488,6 +621,11 @@ static cell_t DisplayMenu(IPluginContext *pContext, const cell_t *params)
|
||||
|
||||
static cell_t VoteMenu(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
if (g_Menus.IsVoteInProgress())
|
||||
{
|
||||
return pContext->ThrowNativeError("A vote is already in progress");
|
||||
}
|
||||
|
||||
Handle_t hndl = (Handle_t)params[1];
|
||||
HandleError err;
|
||||
IBaseMenu *menu;
|
||||
@ -500,7 +638,12 @@ static cell_t VoteMenu(IPluginContext *pContext, const cell_t *params)
|
||||
cell_t *addr;
|
||||
pContext->LocalToPhysAddr(params[2], &addr);
|
||||
|
||||
return menu->BroadcastVote(addr, params[3], params[4]) ? 1 : 0;
|
||||
if (!g_Menus.StartVote(menu, params[3], addr, params[4]))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t AddMenuItem(IPluginContext *pContext, const cell_t *params)
|
||||
@ -699,7 +842,7 @@ static cell_t GetMenuExitButton(IPluginContext *pContext, const cell_t *params)
|
||||
return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
|
||||
}
|
||||
|
||||
return menu->GetExitButton() ? 1 : 0;
|
||||
return ((menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXIT) == MENUFLAG_BUTTON_EXIT) ? 1 : 0;
|
||||
}
|
||||
|
||||
static cell_t GetMenuExitBackButton(IPluginContext *pContext, const cell_t *params)
|
||||
@ -713,7 +856,7 @@ static cell_t GetMenuExitBackButton(IPluginContext *pContext, const cell_t *para
|
||||
return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
|
||||
}
|
||||
|
||||
return menu->GetExitBackButton() ? 1 : 0;
|
||||
return ((menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXITBACK) == MENUFLAG_BUTTON_EXIT) ? 1 : 0;
|
||||
}
|
||||
|
||||
static cell_t SetMenuExitButton(IPluginContext *pContext, const cell_t *params)
|
||||
@ -727,7 +870,11 @@ static cell_t SetMenuExitButton(IPluginContext *pContext, const cell_t *params)
|
||||
return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
|
||||
}
|
||||
|
||||
return menu->SetExitButton(params[2] ? true : false) ? 1 : 0;
|
||||
unsigned int flags = menu->GetMenuOptionFlags();
|
||||
flags |= MENUFLAG_BUTTON_EXIT;
|
||||
menu->SetMenuOptionFlags(flags);
|
||||
flags = menu->GetMenuOptionFlags();
|
||||
return ((flags & MENUFLAG_BUTTON_EXIT) == MENUFLAG_BUTTON_EXIT) ? 1 : 0;
|
||||
}
|
||||
|
||||
static cell_t SetMenuExitBackButton(IPluginContext *pContext, const cell_t *params)
|
||||
@ -741,7 +888,9 @@ static cell_t SetMenuExitBackButton(IPluginContext *pContext, const cell_t *para
|
||||
return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
|
||||
}
|
||||
|
||||
menu->SetExitBackButton(params[2] ? true : false);
|
||||
unsigned int flags = menu->GetMenuOptionFlags();
|
||||
flags |= MENUFLAG_BUTTON_EXITBACK;
|
||||
menu->SetMenuOptionFlags(flags);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -757,23 +906,14 @@ static cell_t CancelMenu(IPluginContext *pContext, const cell_t *params)
|
||||
return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
|
||||
}
|
||||
|
||||
menu->Cancel();
|
||||
g_Menus.CancelMenu(menu);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t IsVoteInProgress(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
Handle_t hndl = (Handle_t)params[1];
|
||||
HandleError err;
|
||||
IBaseMenu *menu;
|
||||
|
||||
if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
|
||||
}
|
||||
|
||||
return menu->IsVoteInProgress() ? 1 : 0;
|
||||
return g_Menus.IsVoteInProgress() ? 1 : 0;
|
||||
}
|
||||
|
||||
static cell_t GetMenuStyle(IPluginContext *pContext, const cell_t *params)
|
||||
@ -1122,12 +1262,55 @@ static cell_t SetMenuOptionFlags(IPluginContext *pContext, const cell_t *params)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t CancelVote(IPluginContext *pContxt, const cell_t *params)
|
||||
{
|
||||
if (!g_Menus.IsVoteInProgress())
|
||||
{
|
||||
return pContxt->ThrowNativeError("No vote is in progress");
|
||||
}
|
||||
|
||||
g_Menus.CancelVoting();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t SetVoteResultCallback(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
Handle_t hndl = (Handle_t)params[1];
|
||||
HandleError err;
|
||||
IBaseMenu *menu;
|
||||
|
||||
if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
|
||||
}
|
||||
|
||||
IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
|
||||
if (!pFunction)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid function %x", params[2]);
|
||||
}
|
||||
|
||||
void *array[2];
|
||||
array[0] = pFunction;
|
||||
array[1] = (void *)¶ms[2];
|
||||
|
||||
IMenuHandler *pHandler = menu->GetHandler();
|
||||
if (!pHandler->OnSetHandlerOption("set_vote_results_handler", (const void *)array))
|
||||
{
|
||||
return pContext->ThrowNativeError("The given menu does not support this option");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
REGISTER_NATIVES(menuNatives)
|
||||
{
|
||||
{"AddMenuItem", AddMenuItem},
|
||||
{"CanPanelDrawFlags", CanPanelDrawFlags},
|
||||
{"CancelClientMenu", CancelClientMenu},
|
||||
{"CancelMenu", CancelMenu},
|
||||
{"CancelVote", CancelVote},
|
||||
{"CreateMenu", CreateMenu},
|
||||
{"CreateMenuEx", CreateMenuEx},
|
||||
{"CreatePanel", CreatePanel},
|
||||
@ -1161,6 +1344,7 @@ REGISTER_NATIVES(menuNatives)
|
||||
{"SetPanelCurrentKey", SetPanelCurrentKey},
|
||||
{"SetPanelTitle", SetPanelTitle},
|
||||
{"SetPanelKeys", SetPanelKeys},
|
||||
{"SetVoteResultCallback", SetVoteResultCallback},
|
||||
{"VoteMenu", VoteMenu},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
@ -81,6 +81,16 @@ static const char *g_ErrorMsgTable[] =
|
||||
"Call was aborted",
|
||||
};
|
||||
|
||||
const char *GetSourcePawnErrorMessage(int error)
|
||||
{
|
||||
if (error < 1 || error > ERROR_MESSAGE_MAX)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return g_ErrorMsgTable[error];
|
||||
}
|
||||
|
||||
SourcePawnEngine::SourcePawnEngine()
|
||||
{
|
||||
m_pDebugHook = NULL;
|
||||
|
@ -45,7 +45,6 @@ struct TracedCall
|
||||
unsigned int chain;
|
||||
};
|
||||
|
||||
|
||||
class CContextTrace : public IContextTrace
|
||||
{
|
||||
public:
|
||||
|
@ -68,6 +68,11 @@ enum MenuAction
|
||||
#define MENUFLAG_BUTTON_EXITBACK (1<<1) /**< Menu has an "exit back" button */
|
||||
#define MENUFLAG_NO_SOUND (1<<2) /**< Menu will not have any select sounds */
|
||||
|
||||
#define VOTEINFO_CLIENT_INDEX 0 /**< Client index */
|
||||
#define VOTEINFO_CLIENT_ITEM 1 /**< Item the client selected, or -1 for none */
|
||||
#define VOTEINFO_ITEM_INDEX 0 /**< Item index */
|
||||
#define VOTEINFO_ITEM_VOTES 1 /**< Number of votes for the item */
|
||||
|
||||
/**
|
||||
* Reasons a menu can be cancelled.
|
||||
*/
|
||||
@ -351,12 +356,20 @@ native GetMenuOptionFlags(Handle:menu);
|
||||
native SetMenuOptionFlags(Handle:menu, flags);
|
||||
|
||||
/**
|
||||
* Returns whether a vote is in progress on the given menu.
|
||||
* Returns whether a vote is in progress.
|
||||
*
|
||||
* @param menu Menu Handle.
|
||||
* @param menu Deprecated; no longer used.
|
||||
* @return True if a vote is in progress, false otherwise.
|
||||
*/
|
||||
native bool:IsVoteInProgress(Handle:menu);
|
||||
native bool:IsVoteInProgress(Handle:menu=INVALID_HANDLE);
|
||||
|
||||
/**
|
||||
* Cancels the vote in progress.
|
||||
*
|
||||
* @noreturn
|
||||
* @error If no vote is in progress.
|
||||
*/
|
||||
native CancelVote();
|
||||
|
||||
/**
|
||||
* Broadcasts a menu to a list of clients. The most selected item will be
|
||||
@ -372,7 +385,7 @@ native bool:IsVoteInProgress(Handle:menu);
|
||||
* @param time Maximum time to leave menu on the screen.
|
||||
* @return True on success, false if this menu already has a vote session
|
||||
* in progress.
|
||||
* @error Invalid Handle.
|
||||
* @error Invalid Handle, or a vote is already in progress.
|
||||
*/
|
||||
native bool:VoteMenu(Handle:menu, clients[], numClients, time);
|
||||
|
||||
@ -402,6 +415,33 @@ stock VoteMenuToAll(Handle:menu, time)
|
||||
|
||||
return VoteMenu(menu, players, total, time);
|
||||
}
|
||||
/**
|
||||
* Callback for when a vote has ended and results are available.
|
||||
*
|
||||
* @param num_votes Number of votes tallied in total.
|
||||
* @param num_clients Number of clients who could vote.
|
||||
* @param client_info Array of clients. Use VOTEINFO_CLIENT_ defines.
|
||||
* @param num_items Number of unique items that were selected.
|
||||
* @param item_info Array of items, sorted by count. Use VOTEINFO_ITEM
|
||||
* defines.
|
||||
* @noreturn
|
||||
*/
|
||||
functag VoteHandler public(num_votes,
|
||||
num_clients,
|
||||
const client_info[][2],
|
||||
num_items,
|
||||
const item_info[][2]);
|
||||
|
||||
/**
|
||||
* Sets an advanced vote handling callback. If this callback is set,
|
||||
* MenuAction_VoteEnd will not be called.
|
||||
*
|
||||
* @param menu Menu Handle.
|
||||
* @param callback Callback function.
|
||||
* @noreturn
|
||||
* @error Invalid Handle or callback.
|
||||
*/
|
||||
native SetVoteResultCallback(Handle:menu, VoteHandler:callback);
|
||||
|
||||
/**
|
||||
* Returns a style's global Handle.
|
||||
|
@ -37,7 +37,7 @@
|
||||
#include <IHandleSys.h>
|
||||
|
||||
#define SMINTERFACE_MENUMANAGER_NAME "IMenuManager"
|
||||
#define SMINTERFACE_MENUMANAGER_VERSION 8
|
||||
#define SMINTERFACE_MENUMANAGER_VERSION 9
|
||||
|
||||
/**
|
||||
* @file IMenuManager.h
|
||||
@ -117,6 +117,27 @@ namespace SourceMod
|
||||
unsigned int access; /**< Access flags required to see */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Contains information about a vote result.
|
||||
*/
|
||||
struct menu_vote_result_t
|
||||
{
|
||||
unsigned int num_clients; /**< Number of clients the menu was displayed to */
|
||||
unsigned int num_votes; /**< Number of votes received */
|
||||
struct menu_client_vote_t
|
||||
{
|
||||
int client; /**< Client index */
|
||||
int item; /**< Item # (or -1 for none) */
|
||||
} *client_list; /**< Array of size num_clients */
|
||||
unsigned int num_items; /**< Number of items voted for */
|
||||
struct menu_item_vote_t
|
||||
{
|
||||
unsigned int item; /**< Item index */
|
||||
unsigned int count; /**< Number of votes */
|
||||
} *item_list; /**< Array of size num_items, sorted by count,
|
||||
descending */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Reasons for a menu dying.
|
||||
*/
|
||||
@ -141,6 +162,7 @@ namespace SourceMod
|
||||
MenuEnd_Cancelled = -3, /**< Menu was uncleanly cancelled */
|
||||
MenuEnd_Exit = -4, /**< Menu was cleanly exited via "exit" */
|
||||
MenuEnd_ExitBack = -5, /**< Menu was cleanly exited via "back" */
|
||||
MenuEnd_NoVotes = -6, /**< No votes received */
|
||||
};
|
||||
|
||||
|
||||
@ -478,32 +500,15 @@ namespace SourceMod
|
||||
*/
|
||||
virtual IMenuPanel *CreatePanel() =0;
|
||||
|
||||
/**
|
||||
* @brief Returns whether or not the menu should have an "Exit" button for
|
||||
* paginated menus.
|
||||
*
|
||||
* @return True to have an exit button, false otherwise.
|
||||
*/
|
||||
virtual bool GetExitButton() =0;
|
||||
|
||||
/**
|
||||
* @brief Sets whether or not the menu should have an "Exit" button for
|
||||
* paginated menus.
|
||||
*
|
||||
* @param set True to enable, false to disable the exit button.
|
||||
* @return True on success, false if the exit button is
|
||||
* non-optional.
|
||||
*/
|
||||
virtual bool SetExitButton(bool set) =0;
|
||||
|
||||
/**
|
||||
* @brief Sends the menu to a client.
|
||||
*
|
||||
* @param client Client index to display to.
|
||||
* @param time Time to hold menu for.
|
||||
* @param alt_handler Alternate IMenuHandler.
|
||||
* @return True on success, false otherwise.
|
||||
*/
|
||||
virtual bool Display(int client, unsigned int time) =0;
|
||||
virtual bool Display(int client, unsigned int time, IMenuHandler *alt_handler=NULL) =0;
|
||||
|
||||
/**
|
||||
* @brief Destroys the menu and frees all associated resources.
|
||||
@ -532,46 +537,6 @@ namespace SourceMod
|
||||
*/
|
||||
virtual Handle_t GetHandle() =0;
|
||||
|
||||
/**
|
||||
* @brief Sends a menu to multiple clients as a vote menu. All callbacks
|
||||
* will be sent as normal, except two extras, OnMenuVoteStart and
|
||||
* OnMenuVoteEnd, will be called.
|
||||
*
|
||||
* @param clients Array of client indexes.
|
||||
* @param numClients Number of client indexes in the array.
|
||||
* @param maxTime Maximum amount of time to hold the vote.
|
||||
* @param flags Optional voting flags (currently unused).
|
||||
* @return True on success, false if a vote is already in
|
||||
* progress (the menu must be cancelled first).
|
||||
*/
|
||||
virtual bool BroadcastVote(int clients[],
|
||||
unsigned int numClients,
|
||||
unsigned int maxTime,
|
||||
unsigned int flags=0) =0;
|
||||
|
||||
/**
|
||||
* @brief Returns whether a vote menu is active.
|
||||
*
|
||||
* @return True if a vote menu is active, false otherwise.
|
||||
*/
|
||||
virtual bool IsVoteInProgress() =0;
|
||||
|
||||
/**
|
||||
* @brief Returns whether to draw a "Back" button on the first page.
|
||||
* ExitBack buttons are disabled by default.
|
||||
*
|
||||
* @return True if enabled, false otherwise.
|
||||
*/
|
||||
virtual bool GetExitBackButton() =0;
|
||||
|
||||
/**
|
||||
* @brief Sets whether to draw a "Back" button on the first page.
|
||||
* ExitBack buttons are disabled by default.
|
||||
*
|
||||
* @param set True to enable, false to disable.
|
||||
*/
|
||||
virtual void SetExitBackButton(bool set) =0;
|
||||
|
||||
/**
|
||||
* @brief Returns menu option flags.
|
||||
*
|
||||
@ -585,6 +550,13 @@ namespace SourceMod
|
||||
* @param flags Menu option flags.
|
||||
*/
|
||||
virtual void SetMenuOptionFlags(unsigned int flags) =0;
|
||||
|
||||
/**
|
||||
* @brief Returns the menu's handler.
|
||||
*
|
||||
* @return IMenuHandler of the menu.
|
||||
*/
|
||||
virtual IMenuHandler *GetHandler() =0;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -716,20 +688,15 @@ namespace SourceMod
|
||||
* while it is in this function.
|
||||
*
|
||||
* @param menu Menu pointer.
|
||||
* @param item Item position that was chosen by a majority.
|
||||
* @param winningVotes Number of votes from the winning item.
|
||||
* @param totalVotes Number of votes total.
|
||||
* @param results Menu vote results.
|
||||
*/
|
||||
virtual void OnMenuVoteEnd(IBaseMenu *menu,
|
||||
unsigned int item,
|
||||
unsigned int winningVotes,
|
||||
unsigned int totalVotes)
|
||||
virtual void OnMenuVoteResults(IBaseMenu *menu, const menu_vote_result_t *results)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Called when a vote is cancelled. If this is called, then
|
||||
* OnMenuVoteEnd() will not be called. In both cases, OnMenuEnd will
|
||||
* OnMenuVoteResults() will not be called. In both cases, OnMenuEnd will
|
||||
* always be called.
|
||||
*
|
||||
* @param menu Menu pointer.
|
||||
@ -737,43 +704,18 @@ namespace SourceMod
|
||||
virtual void OnMenuVoteCancel(IBaseMenu *menu)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Contains functions for managing a vote handler.
|
||||
* @brief Call to set private handler stuff.
|
||||
*
|
||||
* @param option Option name.
|
||||
* @param data Private data.
|
||||
* @return True if set, false if invalid or unrecognized.
|
||||
*/
|
||||
class IVoteMenuHandler : public IMenuHandler
|
||||
virtual bool OnSetHandlerOption(const char *option, const void *data)
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Returns whether or not a vote is in progress.
|
||||
*
|
||||
* @return True if a vote is in progress, false otherwise.
|
||||
*/
|
||||
virtual bool IsVoteInProgress() =0;
|
||||
|
||||
/**
|
||||
* @brief Use this to mark the vote as in progress (start).
|
||||
*
|
||||
* @param menu Menu pointer.
|
||||
*/
|
||||
virtual void InitializeVoting(IBaseMenu *menu) =0;
|
||||
|
||||
/**
|
||||
* @brief Use this to notify that all clients' displays have been
|
||||
* processed (i.e., there are no more clients to display to).
|
||||
*/
|
||||
virtual void StartVoting() =0;
|
||||
|
||||
/**
|
||||
* @brief Notifies the vote handler that the voting should be
|
||||
* cancelled.
|
||||
*
|
||||
* Cancellation is not immediate and will only occur once every menu
|
||||
* has been cancelled from clients. Thus this should only be called
|
||||
* from the beginning of IBaseMenu::Cancel.
|
||||
*/
|
||||
virtual void CancelVoting() =0;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -792,7 +734,7 @@ namespace SourceMod
|
||||
}
|
||||
virtual bool IsVersionCompatible(unsigned int version)
|
||||
{
|
||||
if (version < 7 || version > GetInterfaceVersion())
|
||||
if (version < 9 || version > GetInterfaceVersion())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -815,7 +757,7 @@ namespace SourceMod
|
||||
virtual IMenuStyle *GetDefaultStyle() =0;
|
||||
|
||||
/**
|
||||
* @brief Given a set of menu states, converts it to an IDisplay object.
|
||||
* @brief Given a set of menu states, converts it to an IMenuPanel object.
|
||||
*
|
||||
* The state parameter is both INPUT and OUTPUT.
|
||||
* INPUT: menu, mh, firstItem, lastItem
|
||||
@ -823,7 +765,7 @@ namespace SourceMod
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param states Menu states.
|
||||
* @return IDisplay pointer, or NULL if no items could be
|
||||
* @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
|
||||
* be freed using IMenuPanel::DeleteThis.
|
||||
@ -831,25 +773,40 @@ namespace SourceMod
|
||||
virtual IMenuPanel *RenderMenu(int client, menu_states_t &states, ItemOrder order) =0;
|
||||
|
||||
/**
|
||||
* @brief Creates a standard voting wrapper. The wrapper is not
|
||||
* re-entrant; a second menu cannot be displayed on the same handler
|
||||
* at the same time.
|
||||
* @brief Cancels a menu. Calls IBaseMenu::Cancel() after doing some preparatory
|
||||
* work. This should always be used instead of directly calling Cancel().
|
||||
*
|
||||
* @param mh Menu handler to wrap around.
|
||||
* @return An IMenuHandler pointer that is a wrapper
|
||||
* around IMenuHandler callbacks to invoke
|
||||
* voting related callbacks.
|
||||
* @param menu IBaseMenu pointer.
|
||||
*/
|
||||
virtual IVoteMenuHandler *CreateVoteWrapper(IMenuHandler *mh) =0;
|
||||
virtual void CancelMenu(IBaseMenu *menu) =0;
|
||||
|
||||
/**
|
||||
* @brief Frees a standard voting wrapper.
|
||||
* @brief Displays a menu as a vote.
|
||||
*
|
||||
* @param mh Menu handler pointer created by
|
||||
* CreateVoteWrapper(). NULL values will be
|
||||
* safely ignored.
|
||||
* @param menu IBaseMenu pointer.
|
||||
* @param num_clients Number of clients to display to.
|
||||
* @param clients Client index array.
|
||||
* @param max_time Maximum time to hold menu for.
|
||||
* @param flags Vote flags (currently unused).
|
||||
* @return True on success, false if a vote is in progress.
|
||||
*/
|
||||
virtual void ReleaseVoteWrapper(IVoteMenuHandler *mh) =0;
|
||||
virtual bool StartVote(IBaseMenu *menu,
|
||||
unsigned int num_clients,
|
||||
int clients[],
|
||||
unsigned int max_time,
|
||||
unsigned int flags=0) =0;
|
||||
|
||||
/**
|
||||
* @brief Returns whether or not a vote is in progress.
|
||||
*
|
||||
* @return True if a vote is in progress, false otherwise.
|
||||
*/
|
||||
virtual bool IsVoteInProgress() =0;
|
||||
|
||||
/**
|
||||
* @brief Cancels the vote in progress. This calls IBaseMenu::Cancel().
|
||||
*/
|
||||
virtual void CancelVoting() =0;
|
||||
};
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user