- 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 "DebugReporter.h"
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
#include "PluginSys.h"
|
#include "PluginSys.h"
|
||||||
|
#include "sm_stringutil.h"
|
||||||
|
|
||||||
DebugReport g_DbgReporter;
|
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()
|
void DebugReport::OnSourceModAllInitialized()
|
||||||
{
|
{
|
||||||
g_pSourcePawn->SetDebugListener(this);
|
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)
|
void DebugReport::OnContextExecuteError(IPluginContext *ctx, IContextTrace *error)
|
||||||
{
|
{
|
||||||
const char *lastname;
|
const char *lastname;
|
||||||
|
@ -44,6 +44,7 @@ public: // SMGlobalClass
|
|||||||
void OnSourceModAllInitialized();
|
void OnSourceModAllInitialized();
|
||||||
public: // IDebugListener
|
public: // IDebugListener
|
||||||
void OnContextExecuteError(IPluginContext *ctx, IContextTrace *error);
|
void OnContextExecuteError(IPluginContext *ctx, IContextTrace *error);
|
||||||
|
void GenerateError(IPluginContext *ctx, cell_t func_idx, int err, const char *message, ...);
|
||||||
private:
|
private:
|
||||||
int _GetPluginIndex(IPluginContext *ctx);
|
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 \
|
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 \
|
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 \
|
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 \
|
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_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 \
|
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 <stdarg.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "MenuManager.h"
|
#include "MenuManager.h"
|
||||||
|
#include "MenuVoting.h"
|
||||||
#include "sm_stringutil.h"
|
#include "sm_stringutil.h"
|
||||||
#include "sourcemm_api.h"
|
#include "sourcemm_api.h"
|
||||||
#include "PlayerManager.h"
|
#include "PlayerManager.h"
|
||||||
@ -43,220 +44,10 @@
|
|||||||
#include "sourcemm_api.h"
|
#include "sourcemm_api.h"
|
||||||
|
|
||||||
MenuManager g_Menus;
|
MenuManager g_Menus;
|
||||||
|
VoteMenuHandler s_VoteHandler;
|
||||||
|
|
||||||
ConVar sm_menu_sounds("sm_menu_sounds", "1", 0, "Sets whether SourceMod menus play trigger sounds");
|
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()
|
MenuManager::MenuManager()
|
||||||
{
|
{
|
||||||
m_Styles.push_back(&g_ValveMenuStyle);
|
m_Styles.push_back(&g_ValveMenuStyle);
|
||||||
@ -283,12 +74,6 @@ void MenuManager::OnSourceModAllShutdown()
|
|||||||
{
|
{
|
||||||
g_HandleSys.RemoveType(m_MenuType, g_pCoreIdent);
|
g_HandleSys.RemoveType(m_MenuType, g_pCoreIdent);
|
||||||
g_HandleSys.RemoveType(m_StyleType, 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)
|
void MenuManager::OnHandleDestroy(HandleType_t type, void *object)
|
||||||
@ -649,8 +434,8 @@ skip_search:
|
|||||||
if (pgn != MENU_NO_PAGINATION)
|
if (pgn != MENU_NO_PAGINATION)
|
||||||
{
|
{
|
||||||
bool canDrawDisabled = display->CanDrawItem(ITEMDRAW_DISABLED|ITEMDRAW_CONTROL);
|
bool canDrawDisabled = display->CanDrawItem(ITEMDRAW_DISABLED|ITEMDRAW_CONTROL);
|
||||||
bool exitButton = menu->GetExitButton();
|
bool exitButton = (menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXIT) == MENUFLAG_BUTTON_EXIT;
|
||||||
bool exitBackButton = menu->GetExitBackButton();
|
bool exitBackButton = (menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXITBACK) == MENUFLAG_BUTTON_EXITBACK;
|
||||||
char text[50];
|
char text[50];
|
||||||
|
|
||||||
/* Calculate how many items we are allowed for control stuff */
|
/* Calculate how many items we are allowed for control stuff */
|
||||||
@ -798,33 +583,6 @@ IMenuStyle *MenuManager::GetDefaultStyle()
|
|||||||
return m_pDefaultStyle;
|
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()
|
bool MenuManager::MenuSoundsEnabled()
|
||||||
{
|
{
|
||||||
return (sm_menu_sounds.GetInt() != 0);
|
return (sm_menu_sounds.GetInt() != 0);
|
||||||
@ -879,7 +637,7 @@ const char *MenuManager::GetMenuSound(ItemSelection sel)
|
|||||||
{
|
{
|
||||||
if (m_ExitSound.size() > 0)
|
if (m_ExitSound.size() > 0)
|
||||||
{
|
{
|
||||||
sound= m_ExitSound.c_str();
|
sound = m_ExitSound.c_str();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -907,3 +665,30 @@ void MenuManager::OnSourceModLevelChange(const char *mapName)
|
|||||||
enginesound->PrecacheSound(m_ExitSound.c_str(), true);
|
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 SourceMod;
|
||||||
using namespace SourceHook;
|
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 :
|
class MenuManager :
|
||||||
public IMenuManager,
|
public IMenuManager,
|
||||||
public SMGlobalClass,
|
public SMGlobalClass,
|
||||||
@ -114,8 +81,14 @@ public:
|
|||||||
void AddStyle(IMenuStyle *style);
|
void AddStyle(IMenuStyle *style);
|
||||||
bool SetDefaultStyle(IMenuStyle *style);
|
bool SetDefaultStyle(IMenuStyle *style);
|
||||||
IMenuPanel *RenderMenu(int client, menu_states_t &states, ItemOrder order);
|
IMenuPanel *RenderMenu(int client, menu_states_t &states, ItemOrder order);
|
||||||
IVoteMenuHandler *CreateVoteWrapper(IMenuHandler *mh);
|
void CancelMenu(IBaseMenu *menu);
|
||||||
void ReleaseVoteWrapper(IVoteMenuHandler *mh);
|
bool StartVote(IBaseMenu *menu,
|
||||||
|
unsigned int num_clients,
|
||||||
|
int clients[],
|
||||||
|
unsigned int max_time,
|
||||||
|
unsigned int flags=0);
|
||||||
|
bool IsVoteInProgress();
|
||||||
|
void CancelVoting();
|
||||||
public: //IHandleTypeDispatch
|
public: //IHandleTypeDispatch
|
||||||
void OnHandleDestroy(HandleType_t type, void *object);
|
void OnHandleDestroy(HandleType_t type, void *object);
|
||||||
public:
|
public:
|
||||||
@ -130,7 +103,6 @@ protected:
|
|||||||
private:
|
private:
|
||||||
int m_ShowMenu;
|
int m_ShowMenu;
|
||||||
IMenuStyle *m_pDefaultStyle;
|
IMenuStyle *m_pDefaultStyle;
|
||||||
CStack<VoteMenuHandler *> m_VoteHandlers;
|
|
||||||
CVector<IMenuStyle *> m_Styles;
|
CVector<IMenuStyle *> m_Styles;
|
||||||
HandleType_t m_StyleType;
|
HandleType_t m_StyleType;
|
||||||
HandleType_t m_MenuType;
|
HandleType_t m_MenuType;
|
||||||
|
@ -584,14 +584,12 @@ bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order)
|
|||||||
CBaseMenu::CBaseMenu(IMenuHandler *pHandler, IMenuStyle *pStyle, IdentityToken_t *pOwner) :
|
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_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_pOwner(pOwner ? pOwner : g_pCoreIdent), m_bDeleting(false), m_bWillFreeHandle(false),
|
||||||
m_hHandle(BAD_HANDLE), m_pHandler(pHandler), m_pVoteHandler(NULL),
|
m_hHandle(BAD_HANDLE), m_pHandler(pHandler), m_nFlags(MENUFLAG_BUTTON_EXIT)
|
||||||
m_nFlags(MENUFLAG_BUTTON_EXIT)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CBaseMenu::~CBaseMenu()
|
CBaseMenu::~CBaseMenu()
|
||||||
{
|
{
|
||||||
g_Menus.ReleaseVoteWrapper(m_pVoteHandler);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle_t CBaseMenu::GetHandle()
|
Handle_t CBaseMenu::GetHandle()
|
||||||
@ -732,22 +730,6 @@ const char *CBaseMenu::GetDefaultTitle()
|
|||||||
return m_Title.c_str();
|
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()
|
void CBaseMenu::Cancel()
|
||||||
{
|
{
|
||||||
if (m_bCancelling)
|
if (m_bCancelling)
|
||||||
@ -756,18 +738,11 @@ void CBaseMenu::Cancel()
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined MENU_DEBUG
|
#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,
|
this,
|
||||||
m_pVoteHandler,
|
|
||||||
m_pVoteHandler ? m_pVoteHandler->IsVoteInProgress() : false,
|
|
||||||
m_bShouldDelete);
|
m_bShouldDelete);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (m_pVoteHandler && m_pVoteHandler->IsVoteInProgress())
|
|
||||||
{
|
|
||||||
m_pVoteHandler->CancelVoting();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_bCancelling = true;
|
m_bCancelling = true;
|
||||||
Cancel_Finally();
|
Cancel_Finally();
|
||||||
m_bCancelling = false;
|
m_bCancelling = false;
|
||||||
@ -827,58 +802,6 @@ void CBaseMenu::InternalDelete()
|
|||||||
delete this;
|
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()
|
unsigned int CBaseMenu::GetMenuOptionFlags()
|
||||||
{
|
{
|
||||||
return m_nFlags;
|
return m_nFlags;
|
||||||
@ -888,3 +811,8 @@ void CBaseMenu::SetMenuOptionFlags(unsigned int flags)
|
|||||||
{
|
{
|
||||||
m_nFlags = flags;
|
m_nFlags = flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IMenuHandler *CBaseMenu::GetHandler()
|
||||||
|
{
|
||||||
|
return m_pHandler;
|
||||||
|
}
|
||||||
|
@ -125,23 +125,13 @@ public:
|
|||||||
virtual IMenuStyle *GetDrawStyle();
|
virtual IMenuStyle *GetDrawStyle();
|
||||||
virtual void SetDefaultTitle(const char *message);
|
virtual void SetDefaultTitle(const char *message);
|
||||||
virtual const char *GetDefaultTitle();
|
virtual const char *GetDefaultTitle();
|
||||||
virtual bool GetExitButton();
|
|
||||||
virtual bool SetExitButton(bool set);
|
|
||||||
virtual void Cancel();
|
virtual void Cancel();
|
||||||
virtual void Destroy(bool releaseHandle);
|
virtual void Destroy(bool releaseHandle);
|
||||||
virtual void Cancel_Finally() =0;
|
virtual void Cancel_Finally() =0;
|
||||||
virtual Handle_t GetHandle();
|
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 unsigned int GetMenuOptionFlags();
|
||||||
virtual void SetMenuOptionFlags(unsigned int flags);
|
virtual void SetMenuOptionFlags(unsigned int flags);
|
||||||
public:
|
virtual IMenuHandler *GetHandler();
|
||||||
virtual void VoteDisplay(int client, unsigned int maxTime) =0;
|
|
||||||
private:
|
private:
|
||||||
void InternalDelete();
|
void InternalDelete();
|
||||||
protected:
|
protected:
|
||||||
@ -157,7 +147,6 @@ protected:
|
|||||||
bool m_bWillFreeHandle;
|
bool m_bWillFreeHandle;
|
||||||
Handle_t m_hHandle;
|
Handle_t m_hHandle;
|
||||||
IMenuHandler *m_pHandler;
|
IMenuHandler *m_pHandler;
|
||||||
IVoteMenuHandler *m_pVoteHandler;
|
|
||||||
unsigned int m_nFlags;
|
unsigned int m_nFlags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -390,7 +390,7 @@ IMenuPanel *CRadioMenu::CreatePanel()
|
|||||||
return g_RadioMenuStyle.MakeRadioDisplay(this);
|
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
|
#if defined MENU_DEBUG
|
||||||
g_Logger.LogMessage("[SM_MENU] CRadioMenu::Display(%p) (client %d) (time %d)",
|
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 false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return g_RadioMenuStyle.DoClientMenu(client, this, m_pHandler, time);
|
return g_RadioMenuStyle.DoClientMenu(client, this, alt_handler ? alt_handler : 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CRadioMenu::Cancel_Finally()
|
void CRadioMenu::Cancel_Finally()
|
||||||
|
@ -114,9 +114,8 @@ public:
|
|||||||
public:
|
public:
|
||||||
bool SetExtOption(MenuOption option, const void *valuePtr);
|
bool SetExtOption(MenuOption option, const void *valuePtr);
|
||||||
IMenuPanel *CreatePanel();
|
IMenuPanel *CreatePanel();
|
||||||
bool Display(int client, unsigned int time);
|
bool Display(int client, unsigned int time, IMenuHandler *alt_handler=NULL);
|
||||||
void Cancel_Finally();
|
void Cancel_Finally();
|
||||||
void VoteDisplay(int client, unsigned int maxTime);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern CRadioStyle g_RadioMenuStyle;
|
extern CRadioStyle g_RadioMenuStyle;
|
||||||
|
@ -383,24 +383,14 @@ bool CValveMenu::SetExtOption(MenuOption option, const void *valuePtr)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CValveMenu::Display(int client, unsigned int time)
|
bool CValveMenu::Display(int client, unsigned int time, IMenuHandler *alt_handler)
|
||||||
{
|
{
|
||||||
if (m_bCancelling)
|
if (m_bCancelling)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return g_ValveMenuStyle.DoClientMenu(client, this, m_pHandler, time);
|
return g_ValveMenuStyle.DoClientMenu(client, this, alt_handler ? alt_handler : m_pHandler, time);
|
||||||
}
|
|
||||||
|
|
||||||
void CValveMenu::VoteDisplay(int client, unsigned int maxTime)
|
|
||||||
{
|
|
||||||
if (m_bCancelling)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_ValveMenuStyle.DoClientMenu(client, this, m_pVoteHandler, maxTime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IMenuPanel *CValveMenu::CreatePanel()
|
IMenuPanel *CValveMenu::CreatePanel()
|
||||||
@ -408,19 +398,9 @@ IMenuPanel *CValveMenu::CreatePanel()
|
|||||||
return new CValveMenuDisplay(this);
|
return new CValveMenuDisplay(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CValveMenu::GetExitButton()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CValveMenu::SetExitButton(bool set)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CValveMenu::SetMenuOptionFlags(unsigned int flags)
|
void CValveMenu::SetMenuOptionFlags(unsigned int flags)
|
||||||
{
|
{
|
||||||
flags &= ~MENUFLAG_BUTTON_EXIT;
|
flags |= MENUFLAG_BUTTON_EXIT;
|
||||||
CBaseMenu::SetMenuOptionFlags(flags);
|
CBaseMenu::SetMenuOptionFlags(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,8 +120,7 @@ public: //IBaseMenu
|
|||||||
bool GetExitButton();
|
bool GetExitButton();
|
||||||
bool SetExitButton(bool set);
|
bool SetExitButton(bool set);
|
||||||
bool SetPagination(unsigned int itemsPerPage);
|
bool SetPagination(unsigned int itemsPerPage);
|
||||||
bool Display(int client, unsigned int time);
|
bool Display(int client, unsigned int time, IMenuHandler *alt_handler=NULL);
|
||||||
void VoteDisplay(int client, unsigned int maxTime);
|
|
||||||
void SetMenuOptionFlags(unsigned int flags);
|
void SetMenuOptionFlags(unsigned int flags);
|
||||||
public: //CBaseMenu
|
public: //CBaseMenu
|
||||||
void Cancel_Finally();
|
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"
|
RelativePath="..\MenuStyle_Valve.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\MenuVoting.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\PlayerManager.cpp"
|
RelativePath="..\PlayerManager.cpp"
|
||||||
>
|
>
|
||||||
@ -474,6 +478,10 @@
|
|||||||
RelativePath="..\MenuStyle_Valve.h"
|
RelativePath="..\MenuStyle_Valve.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\MenuVoting.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\PlayerManager.h"
|
RelativePath="..\PlayerManager.h"
|
||||||
>
|
>
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
#include "sm_globals.h"
|
#include "sm_globals.h"
|
||||||
#include <sh_stack.h>
|
#include <sh_stack.h>
|
||||||
|
#include "DebugReporter.h"
|
||||||
#include "MenuManager.h"
|
#include "MenuManager.h"
|
||||||
#include "MenuStyle_Valve.h"
|
#include "MenuStyle_Valve.h"
|
||||||
#include "MenuStyle_Radio.h"
|
#include "MenuStyle_Radio.h"
|
||||||
@ -93,13 +94,11 @@ public:
|
|||||||
void OnMenuEnd(IBaseMenu *menu, MenuEndReason reason);
|
void OnMenuEnd(IBaseMenu *menu, MenuEndReason reason);
|
||||||
void OnMenuDestroy(IBaseMenu *menu);
|
void OnMenuDestroy(IBaseMenu *menu);
|
||||||
void OnMenuVoteStart(IBaseMenu *menu);
|
void OnMenuVoteStart(IBaseMenu *menu);
|
||||||
void OnMenuVoteEnd(IBaseMenu *menu,
|
void OnMenuVoteResults(IBaseMenu *menu, const menu_vote_result_t *results);
|
||||||
unsigned int item,
|
|
||||||
unsigned int winningVotes,
|
|
||||||
unsigned int totalVotes);
|
|
||||||
void OnMenuVoteCancel(IBaseMenu *menu);
|
void OnMenuVoteCancel(IBaseMenu *menu);
|
||||||
void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style);
|
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);
|
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
|
#if 0
|
||||||
void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style);
|
void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style);
|
||||||
void OnMenuDisplayItem(IBaseMenu *menu, int client, unsigned int item, const char **display);
|
void OnMenuDisplayItem(IBaseMenu *menu, int client, unsigned int item, const char **display);
|
||||||
@ -109,6 +108,8 @@ private:
|
|||||||
private:
|
private:
|
||||||
IPluginFunction *m_pBasic;
|
IPluginFunction *m_pBasic;
|
||||||
int m_Flags;
|
int m_Flags;
|
||||||
|
IPluginFunction *m_pVoteResults;
|
||||||
|
cell_t m_fnVoteResult;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -158,7 +159,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* It is extremely important that unloaded plugins don't crash.
|
* It is extremely important that unloaded plugins don't crash.
|
||||||
* Thus, if a plugin unloads, we run through every handler we have.
|
* Thus, if a plugin unloads, we run through every handler we have.
|
||||||
* This means we do almost no runtime work for keeping track of
|
* This means we do almost no runtime work for keeping track of
|
||||||
* our panel handlers (we don't have to store a list of the running
|
* our panel handlers (we don't have to store a list of the running
|
||||||
@ -221,6 +222,7 @@ public:
|
|||||||
m_FreeMenuHandlers.pop();
|
m_FreeMenuHandlers.pop();
|
||||||
handler->m_pBasic = pFunction;
|
handler->m_pBasic = pFunction;
|
||||||
handler->m_Flags = flags;
|
handler->m_Flags = flags;
|
||||||
|
handler->m_pVoteResults = NULL;
|
||||||
}
|
}
|
||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
@ -276,7 +278,7 @@ static const ItemDrawInfo *s_CurDrawInfo = NULL;
|
|||||||
* MENU HANDLER WRAPPER
|
* MENU HANDLER WRAPPER
|
||||||
*/
|
*/
|
||||||
CMenuHandler::CMenuHandler(IPluginFunction *pBasic, int flags) :
|
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 */
|
/* :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);
|
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)
|
void CMenuHandler::OnMenuVoteCancel(IBaseMenu *menu)
|
||||||
{
|
{
|
||||||
DoAction(menu, MenuAction_VoteCancel, 0, 0);
|
DoAction(menu, MenuAction_VoteCancel, 0, 0);
|
||||||
@ -407,6 +401,145 @@ cell_t CMenuHandler::DoAction(IBaseMenu *menu, MenuAction action, cell_t param1,
|
|||||||
return res;
|
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
|
* 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)
|
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];
|
Handle_t hndl = (Handle_t)params[1];
|
||||||
HandleError err;
|
HandleError err;
|
||||||
IBaseMenu *menu;
|
IBaseMenu *menu;
|
||||||
@ -500,7 +638,12 @@ static cell_t VoteMenu(IPluginContext *pContext, const cell_t *params)
|
|||||||
cell_t *addr;
|
cell_t *addr;
|
||||||
pContext->LocalToPhysAddr(params[2], &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)
|
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 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)
|
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 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)
|
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 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)
|
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);
|
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;
|
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);
|
return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
menu->Cancel();
|
g_Menus.CancelMenu(menu);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static cell_t IsVoteInProgress(IPluginContext *pContext, const cell_t *params)
|
static cell_t IsVoteInProgress(IPluginContext *pContext, const cell_t *params)
|
||||||
{
|
{
|
||||||
Handle_t hndl = (Handle_t)params[1];
|
return g_Menus.IsVoteInProgress() ? 1 : 0;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static cell_t GetMenuStyle(IPluginContext *pContext, const cell_t *params)
|
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;
|
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)
|
REGISTER_NATIVES(menuNatives)
|
||||||
{
|
{
|
||||||
{"AddMenuItem", AddMenuItem},
|
{"AddMenuItem", AddMenuItem},
|
||||||
{"CanPanelDrawFlags", CanPanelDrawFlags},
|
{"CanPanelDrawFlags", CanPanelDrawFlags},
|
||||||
{"CancelClientMenu", CancelClientMenu},
|
{"CancelClientMenu", CancelClientMenu},
|
||||||
{"CancelMenu", CancelMenu},
|
{"CancelMenu", CancelMenu},
|
||||||
|
{"CancelVote", CancelVote},
|
||||||
{"CreateMenu", CreateMenu},
|
{"CreateMenu", CreateMenu},
|
||||||
{"CreateMenuEx", CreateMenuEx},
|
{"CreateMenuEx", CreateMenuEx},
|
||||||
{"CreatePanel", CreatePanel},
|
{"CreatePanel", CreatePanel},
|
||||||
@ -1161,6 +1344,7 @@ REGISTER_NATIVES(menuNatives)
|
|||||||
{"SetPanelCurrentKey", SetPanelCurrentKey},
|
{"SetPanelCurrentKey", SetPanelCurrentKey},
|
||||||
{"SetPanelTitle", SetPanelTitle},
|
{"SetPanelTitle", SetPanelTitle},
|
||||||
{"SetPanelKeys", SetPanelKeys},
|
{"SetPanelKeys", SetPanelKeys},
|
||||||
|
{"SetVoteResultCallback", SetVoteResultCallback},
|
||||||
{"VoteMenu", VoteMenu},
|
{"VoteMenu", VoteMenu},
|
||||||
{NULL, NULL},
|
{NULL, NULL},
|
||||||
};
|
};
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -81,6 +81,16 @@ static const char *g_ErrorMsgTable[] =
|
|||||||
"Call was aborted",
|
"Call was aborted",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char *GetSourcePawnErrorMessage(int error)
|
||||||
|
{
|
||||||
|
if (error < 1 || error > ERROR_MESSAGE_MAX)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_ErrorMsgTable[error];
|
||||||
|
}
|
||||||
|
|
||||||
SourcePawnEngine::SourcePawnEngine()
|
SourcePawnEngine::SourcePawnEngine()
|
||||||
{
|
{
|
||||||
m_pDebugHook = NULL;
|
m_pDebugHook = NULL;
|
||||||
|
@ -45,7 +45,6 @@ struct TracedCall
|
|||||||
unsigned int chain;
|
unsigned int chain;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class CContextTrace : public IContextTrace
|
class CContextTrace : public IContextTrace
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -68,6 +68,11 @@ enum MenuAction
|
|||||||
#define MENUFLAG_BUTTON_EXITBACK (1<<1) /**< Menu has an "exit back" button */
|
#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 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.
|
* Reasons a menu can be cancelled.
|
||||||
*/
|
*/
|
||||||
@ -351,12 +356,20 @@ native GetMenuOptionFlags(Handle:menu);
|
|||||||
native SetMenuOptionFlags(Handle:menu, flags);
|
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.
|
* @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
|
* 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.
|
* @param time Maximum time to leave menu on the screen.
|
||||||
* @return True on success, false if this menu already has a vote session
|
* @return True on success, false if this menu already has a vote session
|
||||||
* in progress.
|
* in progress.
|
||||||
* @error Invalid Handle.
|
* @error Invalid Handle, or a vote is already in progress.
|
||||||
*/
|
*/
|
||||||
native bool:VoteMenu(Handle:menu, clients[], numClients, time);
|
native bool:VoteMenu(Handle:menu, clients[], numClients, time);
|
||||||
|
|
||||||
@ -402,6 +415,33 @@ stock VoteMenuToAll(Handle:menu, time)
|
|||||||
|
|
||||||
return VoteMenu(menu, players, total, 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.
|
* Returns a style's global Handle.
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
#include <IHandleSys.h>
|
#include <IHandleSys.h>
|
||||||
|
|
||||||
#define SMINTERFACE_MENUMANAGER_NAME "IMenuManager"
|
#define SMINTERFACE_MENUMANAGER_NAME "IMenuManager"
|
||||||
#define SMINTERFACE_MENUMANAGER_VERSION 8
|
#define SMINTERFACE_MENUMANAGER_VERSION 9
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file IMenuManager.h
|
* @file IMenuManager.h
|
||||||
@ -117,6 +117,27 @@ namespace SourceMod
|
|||||||
unsigned int access; /**< Access flags required to see */
|
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.
|
* @brief Reasons for a menu dying.
|
||||||
*/
|
*/
|
||||||
@ -141,6 +162,7 @@ namespace SourceMod
|
|||||||
MenuEnd_Cancelled = -3, /**< Menu was uncleanly cancelled */
|
MenuEnd_Cancelled = -3, /**< Menu was uncleanly cancelled */
|
||||||
MenuEnd_Exit = -4, /**< Menu was cleanly exited via "exit" */
|
MenuEnd_Exit = -4, /**< Menu was cleanly exited via "exit" */
|
||||||
MenuEnd_ExitBack = -5, /**< Menu was cleanly exited via "back" */
|
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;
|
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.
|
* @brief Sends the menu to a client.
|
||||||
*
|
*
|
||||||
* @param client Client index to display to.
|
* @param client Client index to display to.
|
||||||
* @param time Time to hold menu for.
|
* @param time Time to hold menu for.
|
||||||
|
* @param alt_handler Alternate IMenuHandler.
|
||||||
* @return True on success, false otherwise.
|
* @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.
|
* @brief Destroys the menu and frees all associated resources.
|
||||||
@ -531,46 +536,6 @@ namespace SourceMod
|
|||||||
* @return Handle_t handle value.
|
* @return Handle_t handle value.
|
||||||
*/
|
*/
|
||||||
virtual Handle_t GetHandle() =0;
|
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.
|
* @brief Returns menu option flags.
|
||||||
@ -585,6 +550,13 @@ namespace SourceMod
|
|||||||
* @param flags Menu option flags.
|
* @param flags Menu option flags.
|
||||||
*/
|
*/
|
||||||
virtual void SetMenuOptionFlags(unsigned int flags) =0;
|
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.
|
* while it is in this function.
|
||||||
*
|
*
|
||||||
* @param menu Menu pointer.
|
* @param menu Menu pointer.
|
||||||
* @param item Item position that was chosen by a majority.
|
* @param results Menu vote results.
|
||||||
* @param winningVotes Number of votes from the winning item.
|
|
||||||
* @param totalVotes Number of votes total.
|
|
||||||
*/
|
*/
|
||||||
virtual void OnMenuVoteEnd(IBaseMenu *menu,
|
virtual void OnMenuVoteResults(IBaseMenu *menu, const menu_vote_result_t *results)
|
||||||
unsigned int item,
|
|
||||||
unsigned int winningVotes,
|
|
||||||
unsigned int totalVotes)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Called when a vote is cancelled. If this is called, then
|
* @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.
|
* always be called.
|
||||||
*
|
*
|
||||||
* @param menu Menu pointer.
|
* @param menu Menu pointer.
|
||||||
@ -737,43 +704,18 @@ namespace SourceMod
|
|||||||
virtual void OnMenuVoteCancel(IBaseMenu *menu)
|
virtual void OnMenuVoteCancel(IBaseMenu *menu)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Contains functions for managing a vote handler.
|
|
||||||
*/
|
|
||||||
class IVoteMenuHandler : public IMenuHandler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns whether or not a vote is in progress.
|
* @brief Call to set private handler stuff.
|
||||||
*
|
*
|
||||||
* @return True if a vote is in progress, false otherwise.
|
* @param option Option name.
|
||||||
|
* @param data Private data.
|
||||||
|
* @return True if set, false if invalid or unrecognized.
|
||||||
*/
|
*/
|
||||||
virtual bool IsVoteInProgress() =0;
|
virtual bool OnSetHandlerOption(const char *option, const void *data)
|
||||||
|
{
|
||||||
/**
|
return false;
|
||||||
* @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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -792,7 +734,7 @@ namespace SourceMod
|
|||||||
}
|
}
|
||||||
virtual bool IsVersionCompatible(unsigned int version)
|
virtual bool IsVersionCompatible(unsigned int version)
|
||||||
{
|
{
|
||||||
if (version < 7 || version > GetInterfaceVersion())
|
if (version < 9 || version > GetInterfaceVersion())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -815,7 +757,7 @@ namespace SourceMod
|
|||||||
virtual IMenuStyle *GetDefaultStyle() =0;
|
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.
|
* The state parameter is both INPUT and OUTPUT.
|
||||||
* INPUT: menu, mh, firstItem, lastItem
|
* INPUT: menu, mh, firstItem, lastItem
|
||||||
@ -823,7 +765,7 @@ namespace SourceMod
|
|||||||
*
|
*
|
||||||
* @param client Client index.
|
* @param client Client index.
|
||||||
* @param states Menu states.
|
* @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
|
* found in the IBaseMenu pointer, or NULL if any
|
||||||
* other error occurred. Any valid pointer must
|
* other error occurred. Any valid pointer must
|
||||||
* be freed using IMenuPanel::DeleteThis.
|
* be freed using IMenuPanel::DeleteThis.
|
||||||
@ -831,25 +773,40 @@ namespace SourceMod
|
|||||||
virtual IMenuPanel *RenderMenu(int client, menu_states_t &states, ItemOrder order) =0;
|
virtual IMenuPanel *RenderMenu(int client, menu_states_t &states, ItemOrder order) =0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Creates a standard voting wrapper. The wrapper is not
|
* @brief Cancels a menu. Calls IBaseMenu::Cancel() after doing some preparatory
|
||||||
* re-entrant; a second menu cannot be displayed on the same handler
|
* work. This should always be used instead of directly calling Cancel().
|
||||||
* at the same time.
|
|
||||||
*
|
*
|
||||||
* @param mh Menu handler to wrap around.
|
* @param menu IBaseMenu pointer.
|
||||||
* @return An IMenuHandler pointer that is a wrapper
|
|
||||||
* around IMenuHandler callbacks to invoke
|
|
||||||
* voting related callbacks.
|
|
||||||
*/
|
*/
|
||||||
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
|
* @param menu IBaseMenu pointer.
|
||||||
* CreateVoteWrapper(). NULL values will be
|
* @param num_clients Number of clients to display to.
|
||||||
* safely ignored.
|
* @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