behold with your eyes and view upon what are MENUS

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40775
This commit is contained in:
David Anderson 2007-05-12 23:45:52 +00:00
parent 30f50e6ded
commit d7b2f9a721
11 changed files with 1994 additions and 0 deletions

View File

@ -42,6 +42,7 @@ ConCmdManager::ConCmdManager() : m_Strings(1024)
m_pExecCmd = NULL; m_pExecCmd = NULL;
m_pServerCfgFile = NULL; m_pServerCfgFile = NULL;
m_pServerCfgFwd = NULL; m_pServerCfgFwd = NULL;
m_CmdClient = 0;
} }
ConCmdManager::~ConCmdManager() ConCmdManager::~ConCmdManager()

View File

@ -111,6 +111,11 @@ private:
void RemoveConCmds(List<CmdHook *> &cmdlist, IPluginContext *pContext); void RemoveConCmds(List<CmdHook *> &cmdlist, IPluginContext *pContext);
bool CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin); bool CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin);
void OnExecCmd(); void OnExecCmd();
public:
inline int GetCommandClient()
{
return m_CmdClient;
}
private: private:
Trie *m_pCmds; /* command lookup */ Trie *m_pCmds; /* command lookup */
Trie *m_pCmdGrps; /* command group lookup */ Trie *m_pCmdGrps; /* command group lookup */

676
core/MenuManager.cpp Normal file
View File

@ -0,0 +1,676 @@
#include <stdarg.h>
#include <time.h>
#include "MenuManager.h"
#include "sm_stringutil.h"
#include "sourcemm_api.h"
#include "PlayerManager.h"
#include "MenuStyle_Valve.h"
MenuManager g_Menus;
/*************************************
*************************************
**** BROADCAST HANDLING WRAPPERS ****
*************************************
*************************************/
BroadcastHandler::BroadcastHandler(IMenuHandler *handler) : m_pHandler(handler), numClients(0)
{
}
unsigned int BroadcastHandler::GetMenuAPIVersion2()
{
return m_pHandler->GetMenuAPIVersion2();
}
void BroadcastHandler::OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason)
{
m_pHandler->OnMenuCancel(menu, client, reason);
}
void BroadcastHandler::OnMenuDisplay(IBaseMenu *menu, int client, IMenuDisplay *display)
{
numClients++;
m_pHandler->OnMenuDisplay(menu, client, display);
}
void BroadcastHandler::OnBroadcastEnd(IBaseMenu *menu)
{
g_Menus.FreeBroadcastHandler(this);
}
void BroadcastHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int item)
{
m_pHandler->OnMenuSelect(menu, client, item);
}
void BroadcastHandler::OnMenuEnd(IBaseMenu *menu)
{
assert(numClients > 0);
/* Only fire if all clients have gotten a menu end */
if (--numClients == 0)
{
IMenuHandler *pHandler = m_pHandler;
OnBroadcastEnd(menu);
pHandler->OnMenuEnd(menu);
}
}
VoteHandler::VoteHandler(IMenuVoteHandler *handler)
: BroadcastHandler(handler), m_pVoteHandler(handler)
{
}
void VoteHandler::Initialize(IBaseMenu *menu)
{
unsigned int numItems = menu->GetItemCount();
if (m_counts.size() >= numItems)
{
for (size_t i=0; i<numItems; i++)
{
m_counts[i] = 0;
}
} else {
for (size_t i=0; i<m_counts.size(); i++)
{
m_counts[i] = 0;
}
m_counts.resize(numItems, 0);
}
}
void VoteHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int item)
{
if (item < numItems)
{
m_counts[item]++;
}
BroadcastHandler::OnMenuSelect(menu, client, item);
}
void VoteHandler::OnBroadcastEnd(IBaseMenu *menu)
{
m_ties.clear();
size_t highest = 0;
for (size_t i=1; i<numItems; i++)
{
if (m_counts[i] > m_counts[highest])
{
m_ties.clear();
highest = i;
} else if (m_counts[i] == m_counts[highest]) {
m_ties.push_back(i);
}
}
if (m_ties.size())
{
m_ties.push_back(highest);
srand(static_cast<unsigned int>(time(NULL)));
highest = m_ties[rand() % m_ties.size()];
}
m_pVoteHandler->OnMenuVoteEnd(menu, highest);
g_Menus.FreeVoteHandler(this);
}
/*******************************
*******************************
******** MENU MANAGER *********
*******************************
*******************************/
MenuManager::MenuManager()
{
m_ShowMenu = -1;
m_pDefaultStyle = NULL;
}
void MenuManager::OnSourceModAllInitialized()
{
int num = g_SMAPI->GetUserMessageCount();
if (num >= 1)
{
for (int i=0; i<num; i++)
{
if (strcmp(g_SMAPI->GetUserMessage(i, NULL), "ShowMenu") == 0)
{
m_ShowMenu = i;
break;
}
}
}
/* :TODO: styles */
m_Styles.push_back(&g_ValveMenuStyle);
SetDefaultStyle(&g_ValveMenuStyle);
}
void MenuManager::OnSourceModAllShutdown()
{
while (!m_BroadcastHandlers.empty())
{
delete m_BroadcastHandlers.front();
m_BroadcastHandlers.pop();
}
while (!m_VoteHandlers.empty())
{
delete m_VoteHandlers.front();
m_VoteHandlers.pop();
}
}
bool MenuManager::SetDefaultStyle(IMenuStyle *style)
{
if (!style)
{
return false;
}
m_pDefaultStyle = style;
return true;
}
IMenuStyle *MenuManager::GetStyle(unsigned int index)
{
if (index >= GetStyleCount())
{
return NULL;
}
return m_Styles[index];
}
unsigned int MenuManager::GetStyleCount()
{
return (unsigned int)m_Styles.size();
}
IMenuStyle *MenuManager::FindStyleByName(const char *name)
{
unsigned int count = GetStyleCount();
for (unsigned int i=0; i<count; i++)
{
IMenuStyle *ptr = GetStyle(i);
if (strcasecmp(ptr->GetStyleName(), name) == 0)
{
return ptr;
}
}
return NULL;
}
inline bool IsSlotItem(IMenuDisplay *display,
unsigned int style)
{
if (!display->CanDrawItem(style))
{
return false;
}
if ((style & ITEMDRAW_IGNORE) == ITEMDRAW_IGNORE)
{
return false;
}
if (style & ITEMDRAW_RAWLINE)
{
return false;
}
return true;
}
IMenuDisplay *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder order)
{
IBaseMenu *menu = md.menu;
if (!menu)
{
return NULL;
}
struct
{
unsigned int position;
ItemDrawInfo draw;
} drawItems[10];
/* Figure out how many items to draw */
IMenuStyle *style = menu->GetDrawStyle();
unsigned int pgn = menu->GetPagination();
unsigned int maxItems = style->GetMaxPageItems();
if (pgn != MENU_NO_PAGINATION)
{
maxItems = pgn;
}
unsigned int totalItems = menu->GetItemCount();
unsigned int startItem = 0;
/* For pagination, find the starting point. */
if (pgn != MENU_NO_PAGINATION)
{
if (order == ItemOrder_Ascending)
{
startItem = md.lastItem;
/* This shouldn't happen with well-coded menus.
* If the item is out of bounds, switch the order to
* Items_Descending and make us start from the top.
*/
if (startItem >= totalItems)
{
startItem = totalItems - 1;
order = ItemOrder_Descending;
}
} else if (order == ItemOrder_Descending) {
startItem = md.firstItem;
/* This shouldn't happen with well-coded menus.
* If searching backwards doesn't give us enough room,
* start from the beginning and change to ascending.
*/
if (startItem <= maxItems)
{
startItem = 0;
order = ItemOrder_Ascending;
}
}
}
/* Get our Display pointer and initialize some crap */
IMenuDisplay *display = menu->CreateDisplay();
IMenuHandler *mh = md.mh;
bool foundExtra = false;
unsigned int extraItem = 0;
/**
* We keep searching until:
* 1) There are no more items
* 2) We reach one OVER the maximum number of slot items
* 3) We have reached maxItems and pagination is MENU_NO_PAGINATION
*/
unsigned int i = startItem;
unsigned int foundItems = 0;
while (true)
{
ItemDrawInfo &dr = drawItems[foundItems].draw;
/* Is the item valid? */
if (menu->GetItemInfo(i, &dr) != NULL)
{
/* Ask the user to change the style, if necessary */
mh->OnMenuDrawItem(menu, client, i, dr.style);
/* Check if it's renderable */
if (IsSlotItem(display, dr.style))
{
/* If we've already found the max number of items,
* This means we should just cancel out and log our
* "last item."
*/
if (foundItems >= maxItems)
{
foundExtra = true;
extraItem = i;
break;
}
drawItems[foundItems++].position = i;
}
}
/* If there's no pagination, stop once the menu is full. */
if (pgn == MENU_NO_PAGINATION)
{
/* If we've filled up, then stop */
if (foundItems >= maxItems)
{
break;
}
}
/* If we're descending and this is the first item, stop */
if (order == ItemOrder_Descending)
{
if (i == 0)
{
break;
}
i--;
}
/* If we're ascending and this is the last item, stop */
else if (order == ItemOrder_Ascending)
{
if (i >= totalItems - 1)
{
break;
}
i++;
}
}
/* There were no items to draw! */
if (!foundItems)
{
delete display;
return NULL;
}
/* Check initial buttons */
bool displayPrev = false;
bool displayNext = false;
if (foundExtra)
{
if (order == ItemOrder_Descending)
{
displayPrev = true;
md.firstItem = extraItem;
} else if (order == ItemOrder_Ascending) {
displayNext = true;
md.lastItem = extraItem;
}
}
/**
* If we're paginated, we have to find if there is another page.
* Sadly, the only way to do this is to try drawing more items!
*/
if (pgn != MENU_NO_PAGINATION)
{
unsigned int lastItem = 0;
ItemDrawInfo dr;
/* Find the last feasible item to search from. */
if (order == ItemOrder_Descending)
{
lastItem = drawItems[0].position;
if (lastItem >= totalItems - 1)
{
goto skip_search;
}
while (++lastItem < totalItems)
{
if (menu->GetItemInfo(lastItem, &dr) != NULL)
{
mh->OnMenuDrawItem(menu, client, lastItem, dr.style);
if (IsSlotItem(display, dr.style))
{
displayNext = true;
md.lastItem = lastItem;
break;
}
}
}
} else if (order == ItemOrder_Ascending) {
lastItem = drawItems[0].position;
if (lastItem == 0)
{
goto skip_search;
}
lastItem--;
while (lastItem-- != 0)
{
if (menu->GetItemInfo(lastItem, &dr) != NULL)
{
mh->OnMenuDrawItem(menu, client, lastItem, dr.style);
if (IsSlotItem(display, dr.style))
{
displayPrev = true;
md.firstItem = lastItem;
break;
}
}
}
}
}
skip_search:
/* Draw the item according to the order */
menu_slots_t *slots = md.slots;
unsigned int position = 0; /* Keep track of the last position */
if (order == ItemOrder_Ascending)
{
for (unsigned int i=0; i<foundItems; i++)
{
ItemDrawInfo &dr = drawItems[i].draw;
menu->GetItemInfo(drawItems[i].position, &dr);
mh->OnMenuDisplayItem(menu, client, drawItems[i].position, &(dr.display));
if ((position = display->DrawItem(dr)) != 0)
{
slots[position].item = drawItems[i].position;
slots[position].type = ItemSel_Item;
}
}
} else if (order == ItemOrder_Descending) {
unsigned int i = foundItems;
/* NOTE: There will always be at least one item because
* of the check earlier.
*/
while (i--)
{
ItemDrawInfo &dr = drawItems[i].draw;
menu->GetItemInfo(drawItems[i].position, &dr);
mh->OnMenuDisplayItem(menu, client, drawItems[i].position, &(dr.display));
if ((position = display->DrawItem(dr)) != 0)
{
slots[position].item = drawItems[i].position;
slots[position].type = ItemSel_Item;
}
}
}
/* Now, we need to check if we need to add anything extra */
if (pgn != MENU_NO_PAGINATION)
{
bool canDrawDisabled = display->CanDrawItem(ITEMDRAW_DISABLED);
bool exitButton = menu->GetExitButton();
char text[50];
/* Calculate how many items we are allowed for control stuff */
unsigned int padding = style->GetMaxPageItems() - maxItems;
/* Add the number of available slots */
padding += (maxItems - foundItems);
/* Someday, if we are able to re-enable this, we will be very lucky men. */
#if 0
if (!style->FeatureExists(MenuStyleFeature_ImplicitExit))
{
#endif
/* Even if we don't draw an exit button, we invalidate the slot. */
padding--;
#if 0
} else {
/* Otherwise, we don't draw anything and leave the slot available */
exitButton = false;
}
#endif
/* Subtract two slots for the displayNext/displayPrev padding */
padding -= 2;
/**
* We allow next/prev to be undrawn if neither exists.
* Thus, we only need padding if one of them will be drawn,
* or the exit button will be drawn.
*/
ItemDrawInfo padItem(NULL, ITEMDRAW_SPACER);
if (exitButton || (displayNext || displayPrev))
{
/* Add spacers so we can pad to the end */
unsigned int null_pos = 0;
for (unsigned int i=0; i<padding; i++)
{
position = display->DrawItem(padItem);
slots[position].type = ItemSel_None;
}
}
ItemDrawInfo dr(text, 0);
/* PREVIOUS */
if (displayPrev || canDrawDisabled)
{
CorePlayerTranslate(client, text, sizeof(text), "Back", NULL);
dr.style = displayPrev ? 0 : ITEMDRAW_DISABLED;
position = display->DrawItem(dr);
slots[position].type = ItemSel_Back;
} else if ((displayNext || canDrawDisabled) || exitButton) {
/* If we can't display this,
* but there is a "next" or "exit" button, we need to pad!
*/
position = display->DrawItem(padItem);
slots[position].type = ItemSel_None;
}
/* NEXT */
if (displayNext || canDrawDisabled)
{
CorePlayerTranslate(client, text, sizeof(text), "Next", NULL);
dr.style = displayNext ? 0 : ITEMDRAW_DISABLED;
position = display->DrawItem(dr);
slots[position].type = ItemSel_Next;
} else if (exitButton) {
/* If we can't display this,
* but there is an exit button, we need to pad!
*/
position = display->DrawItem(padItem);
slots[position].type = ItemSel_None;
}
/* EXIT */
if (exitButton)
{
CorePlayerTranslate(client, text, sizeof(text), "Exit", NULL);
dr.style = 0;
position = display->DrawItem(dr);
slots[position].type = ItemSel_Exit;
}
}
/* Lastly, fill in any slots we could have missed */
for (unsigned int i = position + 1; i < 10; i++)
{
slots[i].type = ItemSel_None;
}
/* Do title stuff */
mh->OnMenuDisplay(menu, client, display);
display->DrawTitle(menu->GetDefaultTitle(), true);
return display;
}
unsigned int MenuManager::BroadcastMenu(IBaseMenu *menu,
IMenuHandler *handler,
int clients[],
unsigned int numClients,
unsigned int time)
{
BroadcastHandler *bh;
if (m_BroadcastHandlers.empty())
{
bh = new BroadcastHandler(handler);
} else {
bh = m_BroadcastHandlers.front();
m_BroadcastHandlers.pop();
bh->m_pHandler = handler;
bh->numClients = 0;
}
handler->OnMenuStart(menu);
unsigned int total = 0;
for (unsigned int i=0; i<numClients; i++)
{
/* Only continue if displaying works */
if (!menu->Display(clients[i], bh, time))
{
continue;
}
/* :TODO: Allow sourcetv only, not all bots */
CPlayer *player = g_Players.GetPlayerByIndex(clients[i]);
if (player->IsFakeClient())
{
continue;
}
total++;
}
if (!total)
{
/* End the broadcast here */
handler->OnMenuEnd(menu);
FreeBroadcastHandler(bh);
}
return total;
}
unsigned int MenuManager::VoteMenu(IBaseMenu *menu,
IMenuVoteHandler *handler,
int clients[],
unsigned int numClients,
unsigned int time)
{
VoteHandler *vh;
if (m_VoteHandlers.empty())
{
vh = new VoteHandler(handler);
} else {
vh = m_VoteHandlers.front();
m_VoteHandlers.pop();
vh->m_pHandler = handler;
vh->numClients = 0;
}
vh->Initialize(menu);
handler->OnMenuStart(menu);
unsigned int total = 0;
for (unsigned int i=0; i<numClients; i++)
{
/* Only continue if displaying works */
if (!menu->Display(clients[i], vh, time))
{
continue;
}
/* :TODO: Allow sourcetv only, not all bots */
CPlayer *player = g_Players.GetPlayerByIndex(clients[i]);
if (player->IsFakeClient())
{
continue;
}
total++;
}
if (!total)
{
/* End the broadcast here */
handler->OnMenuEnd(menu);
FreeVoteHandler(vh);
}
return total;
}
void MenuManager::FreeBroadcastHandler(BroadcastHandler *bh)
{
m_BroadcastHandlers.push(bh);
}
void MenuManager::FreeVoteHandler(VoteHandler *vh)
{
m_VoteHandlers.push(vh);
}
IMenuStyle *MenuManager::GetDefaultStyle()
{
return m_pDefaultStyle;
}

110
core/MenuManager.h Normal file
View File

@ -0,0 +1,110 @@
/**
* vim: set ts=4 :
* ===============================================================
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
* ===============================================================
*
* This file is not open source and may not be copied without explicit
* written permission of AlliedModders LLC. This file may not be redistributed
* in whole or significant part.
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
*
* Version: $Id$
*/
#ifndef _INCLUDE_SOURCEMOD_MENUMANAGER_H_
#define _INCLUDE_SOURCEMOD_MENUMANAGER_H_
#include <IMenuManager.h>
#include <sh_vector.h>
#include <sh_stack.h>
#include <sh_list.h>
#include "sm_memtable.h"
#include "sm_globals.h"
using namespace SourceMod;
using namespace SourceHook;
class BroadcastHandler : public IMenuHandler
{
public:
BroadcastHandler(IMenuHandler *handler);
public: //IMenuHandler
void OnMenuDisplay(IBaseMenu *menu, int client, IMenuDisplay *display);
void OnMenuSelect(IBaseMenu *menu, int client, unsigned int item);
void OnMenuEnd(IBaseMenu *menu);
void OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason);
unsigned int GetMenuAPIVersion2();
public:
virtual void OnBroadcastEnd(IBaseMenu *menu);
public:
IMenuHandler *m_pHandler;
unsigned int numClients;
};
class VoteHandler : public BroadcastHandler
{
public:
VoteHandler(IMenuVoteHandler *handler);
public:
void Initialize(IBaseMenu *menu);
void OnMenuSelect(IBaseMenu *menu, int client, unsigned int item);
void OnBroadcastEnd(IBaseMenu *menu);
private:
CVector<unsigned int> m_counts;
CVector<unsigned int> m_ties;
unsigned int numItems;
IMenuVoteHandler *m_pVoteHandler;
};
class MenuManager :
public IMenuManager,
public SMGlobalClass
{
friend class BroadcastHandler;
friend class VoteHandler;
public:
MenuManager();
public: //SMGlobalClass
void OnSourceModAllInitialized();
void OnSourceModAllShutdown();
public: //IMenuManager
virtual const char *GetInterfaceName()
{
return SMINTERFACE_MENUMANAGER_NAME;
}
virtual unsigned int GetInterfaceVersion()
{
return SMINTERFACE_MENUMANAGER_VERSION;
}
public:
unsigned int GetStyleCount();
IMenuStyle *GetStyle(unsigned int index);
IMenuStyle *FindStyleByName(const char *name);
unsigned int BroadcastMenu(IBaseMenu *menu,
IMenuHandler *handler,
int clients[],
unsigned int numClients,
unsigned int time);
unsigned int VoteMenu(IBaseMenu *menu,
IMenuVoteHandler *handler,
int clients[],
unsigned int numClients,
unsigned int time);
IMenuStyle *GetDefaultStyle();
bool SetDefaultStyle(IMenuStyle *style);
IMenuDisplay *RenderMenu(int client, menu_states_t &states, ItemOrder order);
protected:
void FreeBroadcastHandler(BroadcastHandler *bh);
void FreeVoteHandler(VoteHandler *vh);
private:
int m_ShowMenu;
IMenuStyle *m_pDefaultStyle;
CStack<BroadcastHandler *> m_BroadcastHandlers;
CStack<VoteHandler *> m_VoteHandlers;
CVector<IMenuStyle *> m_Styles;
};
extern MenuManager g_Menus;
#endif //_INCLUDE_SOURCEMOD_MENUMANAGER_H_

162
core/MenuStyle_Base.cpp Normal file
View File

@ -0,0 +1,162 @@
/**
* vim: set ts=4 :
* ===============================================================
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
* ===============================================================
*
* This file is not open source and may not be copied without explicit
* written permission of AlliedModders LLC. This file may not be redistributed
* in whole or significant part.
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
*
* Version: $Id$
*/
#include <stdarg.h>
#include "sm_stringutil.h"
#include "MenuStyle_Base.h"
CBaseMenu::CBaseMenu(IMenuStyle *pStyle) :
m_pStyle(pStyle), m_Strings(512), m_Pagination(7), m_ExitButton(true)
{
}
CBaseMenu::~CBaseMenu()
{
}
bool CBaseMenu::AppendItem(const char *info, const ItemDrawInfo &draw)
{
if (m_Pagination == MENU_NO_PAGINATION
&& m_items.size() >= m_pStyle->GetMaxPageItems())
{
return false;
}
CItem item;
item.infoString = m_Strings.AddString(info);
if (draw.display)
{
item.displayString = m_Strings.AddString(draw.display);
}
item.style = draw.style;
m_items.push_back(item);
return true;
}
bool CBaseMenu::InsertItem(unsigned int position, const char *info, const ItemDrawInfo &draw)
{
if (m_Pagination == MENU_NO_PAGINATION
&& m_items.size() >= m_pStyle->GetMaxPageItems())
{
return false;
}
if (position >= m_items.size())
{
return false;
}
CItem item;
item.infoString = m_Strings.AddString(info);
if (draw.display)
{
item.displayString = m_Strings.AddString(draw.display);
}
item.style = draw.style;
CVector<CItem>::iterator iter = m_items.iterAt(position);
m_items.insert(iter, item);
return true;
}
bool CBaseMenu::RemoveItem(unsigned int position)
{
if (position >= m_items.size())
{
return false;
}
m_items.erase(m_items.iterAt(position));
if (m_items.size() == 0)
{
m_Strings.Reset();
}
return true;
}
void CBaseMenu::RemoveAllItems()
{
m_items.clear();
m_Strings.Reset();
}
const char *CBaseMenu::GetItemInfo(unsigned int position, ItemDrawInfo *draw/* =NULL */)
{
if (position >= m_items.size())
{
return NULL;
}
if (draw)
{
draw->display = m_Strings.GetString(m_items[position].displayString);
draw->style = m_items[position].style;
}
return m_Strings.GetString(m_items[position].infoString);
}
unsigned int CBaseMenu::GetItemCount()
{
return m_items.size();
}
bool CBaseMenu::SetPagination(unsigned int itemsPerPage)
{
if (itemsPerPage > 7)
{
return false;
}
m_Pagination = itemsPerPage;
return true;
}
unsigned int CBaseMenu::GetPagination()
{
return m_Pagination;
}
IMenuStyle *CBaseMenu::GetDrawStyle()
{
return m_pStyle;
}
void CBaseMenu::SetDefaultTitle(const char *message)
{
m_Title.assign(message);
}
const char *CBaseMenu::GetDefaultTitle()
{
return m_Title.c_str();
}
bool CBaseMenu::GetExitButton()
{
return m_ExitButton;
}
bool CBaseMenu::SetExitButton(bool set)
{
m_ExitButton = set;
return true;
}

69
core/MenuStyle_Base.h Normal file
View File

@ -0,0 +1,69 @@
/**
* vim: set ts=4 :
* ===============================================================
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
* ===============================================================
*
* This file is not open source and may not be copied without explicit
* written permission of AlliedModders LLC. This file may not be redistributed
* in whole or significant part.
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
*
* Version: $Id$
*/
#ifndef _INCLUDE_MENUSTYLE_BASE_H
#define _INCLUDE_MENUSTYLE_BASE_H
#include <IMenuManager.h>
#include <sh_string.h>
#include <sh_vector.h>
#include "sm_memtable.h"
using namespace SourceMod;
using namespace SourceHook;
class CItem
{
public:
CItem()
{
infoString = -1;
displayString = -1;
style = 0;
}
public:
int infoString;
int displayString;
unsigned int style;
};
class CBaseMenu : public IBaseMenu
{
public:
CBaseMenu(IMenuStyle *pStyle);
virtual ~CBaseMenu();
public:
virtual bool AppendItem(const char *info, const ItemDrawInfo &draw);
virtual bool InsertItem(unsigned int position, const char *info, const ItemDrawInfo &draw);
virtual bool RemoveItem(unsigned int position);
virtual void RemoveAllItems();
virtual const char *GetItemInfo(unsigned int position, ItemDrawInfo *draw=NULL);
virtual unsigned int GetItemCount();
virtual bool SetPagination(unsigned int itemsPerPage);
virtual unsigned int GetPagination();
virtual IMenuStyle *GetDrawStyle();
virtual void SetDefaultTitle(const char *message);
virtual const char *GetDefaultTitle();
virtual bool GetExitButton();
virtual bool SetExitButton(bool set);
protected:
String m_Title;
IMenuStyle *m_pStyle;
unsigned int m_Pagination;
CVector<CItem> m_items;
BaseStringTable m_Strings;
bool m_ExitButton;
};
#endif //_INCLUDE_MENUSTYLE_BASE_H

796
core/MenuStyle_Valve.cpp Normal file
View File

@ -0,0 +1,796 @@
/**
* vim: set ts=4 :
* ===============================================================
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
* ===============================================================
*
* This file is not open source and may not be copied without explicit
* written permission of AlliedModders LLC. This file may not be redistributed
* in whole or significant part.
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
*
* Version: $Id$
*/
#include "sm_stringutil.h"
#include "PlayerManager.h"
#include "MenuStyle_Valve.h"
#include "Translator.h"
#include "PlayerManager.h"
#include "ConCmdManager.h"
SH_DECL_HOOK4_void(IServerPluginHelpers, CreateMessage, SH_NOATTRIB, false, edict_t *, DIALOG_TYPE, KeyValues *, IServerPluginCallbacks *);
ValveMenuStyle g_ValveMenuStyle;
const char *g_OptionNumTable[];
const char *g_OptionCmdTable[];
IServerPluginCallbacks *g_pVSPHandle = NULL;
CallClass<IServerPluginHelpers> *g_pSPHCC = NULL;
class TestHandler : public IMenuHandler
{
public:
virtual void OnMenuEnd(IBaseMenu *menu)
{
menu->Destroy();
}
};
ValveMenuStyle::ValveMenuStyle() : m_players(new CValveMenuPlayer[256+1]), m_WatchList(256)
{
}
bool ValveMenuStyle::OnClientCommand(int client)
{
const char *cmd = engine->Cmd_Argv(0);
if (strcmp(cmd, "sm_vmenuselect") == 0)
{
int key_press = atoi(engine->Cmd_Argv(1));
g_ValveMenuStyle.ClientPressedKey(client, key_press);
return true;
}
if (strcmp(cmd, "sm_test") == 0)
{
IBaseMenu *menu = g_ValveMenuStyle.CreateMenu();
menu->AppendItem("test1", ItemDrawInfo("Test #1", 0));
menu->AppendItem("test2", ItemDrawInfo("Test #2", 0));
menu->AppendItem("test3", ItemDrawInfo("Test #3", 0));
menu->AppendItem("test4", ItemDrawInfo("Test #4", 0));
menu->AppendItem("test5", ItemDrawInfo("Test #5", 0));
menu->AppendItem("test6", ItemDrawInfo("Test #6", 0));
menu->AppendItem("test7", ItemDrawInfo("Test #7", 0));
menu->AppendItem("test8", ItemDrawInfo("Test #8", 0));
menu->AppendItem("test9", ItemDrawInfo("Test #9", 0));
menu->AppendItem("test10", ItemDrawInfo("Test #10", 0));
menu->AppendItem("test11", ItemDrawInfo("Test #11", 0));
menu->AppendItem("test12", ItemDrawInfo("Test #12", 0));
menu->AppendItem("test13", ItemDrawInfo("Test #13", 0));
menu->AppendItem("test14", ItemDrawInfo("Test #14", 0));
menu->AppendItem("test15", ItemDrawInfo("Test #15", 0));
menu->AppendItem("test16", ItemDrawInfo("Test #16", 0));
menu->AppendItem("test17", ItemDrawInfo("Test #17", 0));
menu->AppendItem("test18", ItemDrawInfo("Test #18", 0));
menu->AppendItem("test19", ItemDrawInfo("Test #19", 0));
menu->AppendItem("test20", ItemDrawInfo("Test #20", 0));
menu->Display(client, new TestHandler, 20);
return true;
} else if (strcmp(cmd, "gaben") == 0) {
KeyValues *kv = new KeyValues("menu");
kv->SetString("msg", "hi");
serverpluginhelpers->CreateMessage(engine->PEntityOfEntIndex(client), DIALOG_MENU, kv, g_pVSPHandle);
kv->deleteThis();
}
return false;
}
void ValveMenuStyle::OnSourceModAllInitialized()
{
g_Players.AddClientListener(this);
SH_ADD_HOOK_MEMFUNC(IServerPluginHelpers, CreateMessage, serverpluginhelpers, this, &ValveMenuStyle::HookCreateMessage, false);
g_pSPHCC = SH_GET_CALLCLASS(serverpluginhelpers);
}
void ValveMenuStyle::OnSourceModShutdown()
{
SH_RELEASE_CALLCLASS(g_pSPHCC);
SH_REMOVE_HOOK_MEMFUNC(IServerPluginHelpers, CreateMessage, serverpluginhelpers, this, &ValveMenuStyle::HookCreateMessage, false);
g_Players.RemoveClientListener(this);
}
void ValveMenuStyle::OnClientDisconnected(int client)
{
CValveMenuPlayer *player = &m_players[client];
if (!player->bInMenu)
{
return;
}
menu_states_t &states = player->states;
states.mh->OnMenuCancel(states.menu, client, MenuCancel_Disconnect);
states.mh->OnMenuEnd(states.menu);
if (player->menuHoldTime)
{
m_WatchList.remove(client);
}
player->bInMenu = false;
}
void ValveMenuStyle::HookCreateMessage(edict_t *pEdict,
DIALOG_TYPE type,
KeyValues *kv,
IServerPluginCallbacks *plugin)
{
if (type != DIALOG_MENU)
{
return;
}
int client = engine->IndexOfEdict(pEdict);
if (client < 1 || client > 256)
{
return;
}
CValveMenuPlayer *player = &m_players[client];
/* We don't care if the player is in a menu because, for all intents and purposes,
* the menu is completely private. Instead, we just figure out the level we'll need
* in order to override it.
*/
player->curPrioLevel = kv->GetInt("level", player->curPrioLevel);
/* Oh no! What happens if we got a menu that overwrites ours?! */
if (player->bInMenu)
{
/* Okay, let the external menu survive for now. It may live another
* day to avenge its grandfather, killed in the great Menu Interruption
* battle.
*/
_CancelMenu(client, true);
}
}
void ValveMenuStyle::OnSourceModVSPReceived(IServerPluginCallbacks *iface)
{
g_pVSPHandle = iface;
}
IMenuDisplay *ValveMenuStyle::CreateDisplay()
{
return new CValveMenuDisplay();
}
IBaseMenu *ValveMenuStyle::CreateMenu()
{
return new CValveMenu();
}
const char *ValveMenuStyle::GetStyleName()
{
return "valve";
}
unsigned int ValveMenuStyle::GetMaxPageItems()
{
return 8;
}
static int do_lookup[256];
void ValveMenuStyle::ProcessWatchList()
{
if (!m_WatchList.size())
{
return;
}
FastLink<int>::iterator iter;
unsigned int total = 0;
for (iter=m_WatchList.begin(); iter!=m_WatchList.end(); ++iter)
{
do_lookup[total++] = (*iter);
}
int client;
CValveMenuPlayer *player;
float curTime = gpGlobals->curtime;
for (unsigned int i=0; i<total; i++)
{
client = do_lookup[i];
player = &m_players[client];
if (!player->bInMenu || !player->menuHoldTime)
{
m_WatchList.remove(i);
continue;
}
if (curTime > player->menuStartTime + player->menuHoldTime)
{
_CancelMenu(i, false);
}
}
}
void ValveMenuStyle::_CancelMenu(int client, bool bAutoIgnore)
{
CValveMenuPlayer *player = &m_players[client];
menu_states_t &states = player->states;
bool bOldIgnore = player->bAutoIgnore;
if (bAutoIgnore)
{
player->bAutoIgnore = true;
}
/* Save states */
IMenuHandler *mh = states.mh;
IBaseMenu *menu = states.menu;
/* Clear menu */
player->bInMenu = false;
if (player->menuHoldTime)
{
m_WatchList.remove(client);
}
/* Fire callbacks */
mh->OnMenuCancel(menu, client, MenuCancel_Interrupt);
mh->OnMenuEnd(menu);
if (bAutoIgnore)
{
player->bAutoIgnore = bOldIgnore;
}
}
void ValveMenuStyle::CancelMenu(CValveMenu *menu)
{
int maxClients = g_Players.GetMaxClients();
for (int i=1; i<=maxClients; i++)
{
if (m_players[i].bInMenu)
{
menu_states_t &states = m_players[i].states;
if (states.menu == menu)
{
_CancelMenu(i);
}
}
}
}
bool ValveMenuStyle::CancelClientMenu(int client, bool autoIgnore)
{
if (client < 1 || client > 256 || !m_players[client].bInMenu)
{
return false;
}
_CancelMenu(client, autoIgnore);
return true;
}
void ValveMenuStyle::ClientPressedKey(int client, unsigned int key_press)
{
CValveMenuPlayer *player = &m_players[client];
/* First question: Are we in a menu? */
if (!player->bInMenu)
{
return;
}
bool cancel = false;
unsigned int item = 0;
MenuCancelReason reason = MenuCancel_Exit;
menu_states_t &states = player->states;
assert(states.mh != NULL);
if (states.menu == NULL)
{
item = key_press;
} else if (key_press < 1 || key_press > 8) {
cancel = true;
} else {
ItemSelection type = states.slots[key_press].type;
/* For navigational items, we're going to redisplay */
if (type == ItemSel_Back)
{
if (!RedoClientMenu(client, ItemOrder_Descending))
{
cancel = true;
reason = MenuCancel_NoDisplay;
} else {
return;
}
} else if (type == ItemSel_Next) {
if (!RedoClientMenu(client, ItemOrder_Ascending))
{
cancel = true; /* I like Saltines. */
reason = MenuCancel_NoDisplay;
} else {
return;
}
} else if (type == ItemSel_Exit || type == ItemSel_None) {
cancel = true;
} else {
item = states.slots[key_press].item;
}
}
/* Save variables */
IMenuHandler *mh = states.mh;
IBaseMenu *menu = states.menu;
/* Clear states */
player->bInMenu = false;
if (player->menuHoldTime)
{
m_WatchList.remove(client);
}
if (cancel)
{
mh->OnMenuCancel(menu, client, reason);
} else {
mh->OnMenuSelect(menu, client, item);
}
mh->OnMenuEnd(menu);
}
bool ValveMenuStyle::DoClientMenu(int client, CValveMenuDisplay *menu, IMenuHandler *mh, unsigned int time)
{
if (!g_pVSPHandle || !mh)
{
return false;
}
CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame())
{
return false;
}
CValveMenuPlayer *player = &m_players[client];
if (player->bAutoIgnore)
{
return false;
}
/* For the duration of this, we are going to totally ignore whether
* the player is already in a menu or not (except to cancel the old one).
* Instead, we are simply going to ignore any further menu displays, so
* this display can't be interrupted.
*/
player->bAutoIgnore = true;
/* Cancel any old menus */
menu_states_t &states = player->states;
if (player->bInMenu)
{
/* We need to cancel the old menu */
if (player->menuHoldTime)
{
m_WatchList.remove(client);
}
states.mh->OnMenuCancel(states.menu, client, MenuCancel_Interrupt);
states.mh->OnMenuEnd(states.menu);
}
states.firstItem = 0;
states.lastItem = 0;
states.menu = NULL;
states.mh = mh;
states.apiVers = SMINTERFACE_MENUMANAGER_VERSION;
player->curPrioLevel--;
player->bInMenu = true;
player->menuStartTime = gpGlobals->curtime;
player->menuHoldTime = time;
if (time)
{
m_WatchList.push_back(client);
}
/* Draw the display */
menu->SendRawDisplay(client, player->curPrioLevel, time);
/* We can be interrupted again! */
player->bAutoIgnore = false;
return true;
}
bool ValveMenuStyle::DoClientMenu(int client, CValveMenu *menu, IMenuHandler *mh, unsigned int time)
{
mh->OnMenuStart(menu);
if (!g_pVSPHandle || !mh)
{
mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
mh->OnMenuEnd(menu);
return false;
}
CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame())
{
mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
mh->OnMenuEnd(menu);
return false;
}
CValveMenuPlayer *player = &m_players[client];
if (player->bAutoIgnore)
{
mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
mh->OnMenuEnd(menu);
return false;
}
/* For the duration of this, we are going to totally ignore whether
* the player is already in a menu or not (except to cancel the old one).
* Instead, we are simply going to ignore any further menu displays, so
* this display can't be interrupted.
*/
player->bAutoIgnore = true;
/* Cancel any old menus */
menu_states_t &states = player->states;
if (player->bInMenu)
{
/* We need to cancel the old menu */
if (player->menuHoldTime)
{
m_WatchList.remove(client);
}
states.mh->OnMenuCancel(states.menu, client, MenuCancel_Interrupt);
states.mh->OnMenuEnd(states.menu);
}
states.firstItem = 0;
states.lastItem = 0;
states.menu = menu;
states.mh = mh;
states.apiVers = SMINTERFACE_MENUMANAGER_VERSION;
IMenuDisplay *display = g_Menus.RenderMenu(client, states, ItemOrder_Ascending);
if (!display)
{
player->bAutoIgnore = false;
player->bInMenu = false;
mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
mh->OnMenuEnd(menu);
return false;
}
/* Finally, set our states */
player->curPrioLevel--;
player->bInMenu = true;
player->menuStartTime = gpGlobals->curtime;
player->menuHoldTime = time;
if (time)
{
m_WatchList.push_back(client);
}
/* Draw the display */
CValveMenuDisplay *vDisplay = (CValveMenuDisplay *)display;
vDisplay->SendRawDisplay(client, player->curPrioLevel, time);
/* Free the display pointer */
delete display;
/* We can be interrupted again! */
player->bAutoIgnore = false;
return true;
}
bool ValveMenuStyle::RedoClientMenu(int client, ItemOrder order)
{
CValveMenuPlayer *player = &m_players[client];
menu_states_t &states = player->states;
player->bAutoIgnore = true;
IMenuDisplay *display = g_Menus.RenderMenu(client, states, order);
if (!display)
{
if (player->menuHoldTime)
{
m_WatchList.remove(client);
}
player->bAutoIgnore = false;
return false;
}
CValveMenuDisplay *vDisplay = (CValveMenuDisplay *)display;
vDisplay->SendRawDisplay(client, --player->curPrioLevel, player->menuHoldTime);
delete display;
player->bAutoIgnore = false;
return true;
}
MenuSource ValveMenuStyle::GetClientMenu(int client, void **object)
{
if (client < 1 || client > 256 || !m_players[client].bInMenu)
{
return MenuSource_None;
}
IBaseMenu *menu;
if ((menu=m_players[client].states.menu) != NULL)
{
if (object)
{
*object = menu;
}
return MenuSource_BaseMenu;
}
return MenuSource_Display;
}
CValveMenuDisplay::CValveMenuDisplay()
{
m_pKv = NULL;
Reset();
}
CValveMenuDisplay::CValveMenuDisplay(CValveMenu *pMenu)
{
m_pKv = NULL;
Reset();
m_pKv->SetColor("color", pMenu->m_IntroColor);
m_pKv->SetString("title", pMenu->m_IntroMsg);
}
CValveMenuDisplay::~CValveMenuDisplay()
{
m_pKv->deleteThis();
}
IMenuStyle *CValveMenuDisplay::GetParentStyle()
{
return &g_ValveMenuStyle;
}
void CValveMenuDisplay::Reset()
{
if (m_pKv)
{
m_pKv->deleteThis();
}
m_pKv = new KeyValues("menu");
m_NextPos = 1;
m_TitleDrawn = false;
}
bool CValveMenuDisplay::SetExtOption(MenuOption option, const void *valuePtr)
{
if (option == MenuOption_IntroMessage)
{
m_pKv->SetString("title", (const char *)valuePtr);
return true;
} else if (option == MenuOption_IntroColor) {
int *array = (int *)valuePtr;
m_pKv->SetColor("color", Color(array[0], array[1], array[2], array[3]));
return true;
}
return false;
}
bool CValveMenuDisplay::CanDrawItem(unsigned int drawFlags)
{
/**
* ITEMDRAW_RAWLINE - We can't draw random text, and this doesn't add a slot,
* so it's completely safe to ignore it.
* -----------------------------------------
*/
if (drawFlags & ITEMDRAW_RAWLINE)
{
return false;
}
/**
* Special cases, explained in DrawItem()
*/
if ((drawFlags & ITEMDRAW_NOTEXT)
|| (drawFlags & ITEMDRAW_SPACER))
{
return true;
}
/**
* We can't draw disabled text. We could bump the position, but we
* want DirectDraw() to find some actual items to display.
*/
if (drawFlags & ITEMDRAW_DISABLED)
{
return false;
}
return true;
}
unsigned int CValveMenuDisplay::DrawItem(const ItemDrawInfo &item)
{
if (m_NextPos > 9 || !CanDrawItem(item.style))
{
return 0;
}
/**
* For these cases we can't draw anything at all, but
* we can at least bump the position since we were explicitly asked to.
*/
if ((item.style & ITEMDRAW_NOTEXT)
|| (item.style & ITEMDRAW_SPACER))
{
return m_NextPos++;
}
char buffer[255];
UTIL_Format(buffer, sizeof(buffer), "%d. %s", m_NextPos, item.display);
KeyValues *ki = m_pKv->FindKey(g_OptionNumTable[m_NextPos], true);
ki->SetString("command", g_OptionCmdTable[m_NextPos]);
ki->SetString("msg", buffer);
return m_NextPos++;
}
void CValveMenuDisplay::DrawTitle(const char *text, bool onlyIfEmpty/* =false */)
{
if (onlyIfEmpty && m_TitleDrawn)
{
return;
}
m_pKv->SetString("msg", text);
m_TitleDrawn = true;
}
bool CValveMenuDisplay::DrawRawLine(const char *rawline)
{
return false;
}
void CValveMenuDisplay::SendRawDisplay(int client, int priority, unsigned int time)
{
m_pKv->SetInt("level", priority);
m_pKv->SetInt("time", time);
SH_CALL(g_pSPHCC, &IServerPluginHelpers::CreateMessage)(
engine->PEntityOfEntIndex(client),
DIALOG_MENU,
m_pKv,
g_pVSPHandle);
}
bool CValveMenuDisplay::SendDisplay(int client, IMenuHandler *handler, unsigned int time)
{
return g_ValveMenuStyle.DoClientMenu(client, this, handler, time);
}
CValveMenu::CValveMenu() : CBaseMenu(&g_ValveMenuStyle),
m_IntroColor(255, 0, 0, 255), m_bShouldDelete(false), m_bCancelling(false)
{
strcpy(m_IntroMsg, "You have a menu, press ESC");
m_Pagination = 5;
}
void CValveMenu::Cancel()
{
if (m_bCancelling)
{
return;
}
m_bCancelling = true;
g_ValveMenuStyle.CancelMenu(this);
m_bCancelling = false;
if (m_bShouldDelete)
{
delete this;
}
}
void CValveMenu::Destroy()
{
if (!m_bCancelling || m_bShouldDelete)
{
Cancel();
delete this;
} else {
m_bShouldDelete = true;
}
}
bool CValveMenu::SetPagination(unsigned int itemsPerPage)
{
if (itemsPerPage < 1 || itemsPerPage > 5)
{
return false;
}
CBaseMenu::SetPagination(itemsPerPage);
return true;
}
bool CValveMenu::SetExtOption(MenuOption option, const void *valuePtr)
{
if (option == MenuOption_IntroMessage)
{
strncopy(m_IntroMsg, (const char *)valuePtr, sizeof(m_IntroMsg));
return true;
} else if (option == MenuOption_IntroColor) {
unsigned int *array = (unsigned int *)valuePtr;
m_IntroColor = Color(array[0], array[1], array[2], array[3]);
return true;
}
return false;
}
bool CValveMenu::Display(int client, IMenuHandler *handler, unsigned int time)
{
if (m_bCancelling)
{
return false;
}
return g_ValveMenuStyle.DoClientMenu(client, this, handler, time);
}
IMenuDisplay *CValveMenu::CreateDisplay()
{
return new CValveMenuDisplay(this);
}
bool CValveMenu::GetExitButton()
{
return true;
}
bool CValveMenu::SetExitButton(bool set)
{
return false;
}
static const char *g_OptionNumTable[11] =
{
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"
};
static const char *g_OptionCmdTable[11] =
{
"sm_vmenuselect 0", /* INVALID! */
"sm_vmenuselect 1",
"sm_vmenuselect 2",
"sm_vmenuselect 3",
"sm_vmenuselect 4",
"sm_vmenuselect 5",
"sm_vmenuselect 6",
"sm_vmenuselect 7",
"sm_vmenuselect 8",
"sm_vmenuselect 9",
"sm_vmenuselect 10"
};

127
core/MenuStyle_Valve.h Normal file
View File

@ -0,0 +1,127 @@
/**
* vim: set ts=4 :
* ===============================================================
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
* ===============================================================
*
* This file is not open source and may not be copied without explicit
* written permission of AlliedModders LLC. This file may not be redistributed
* in whole or significant part.
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
*
* Version: $Id$
*/
#ifndef _INCLUDE_MENUSTYLE_VALVE_H
#define _INCLUDE_MENUSTYLE_VALVE_H
#include "sm_globals.h"
#include "MenuManager.h"
#include "MenuStyle_Base.h"
#include "sourcemm_api.h"
#include "KeyValues.h"
#include <IPlayerHelpers.h>
#include "sm_fastlink.h"
using namespace SourceMod;
class CValveMenuPlayer
{
public:
CValveMenuPlayer() : bInMenu(false), bAutoIgnore(false), curPrioLevel(1)
{
}
menu_states_t states;
bool bInMenu;
bool bAutoIgnore;
int curPrioLevel;
float menuStartTime;
unsigned int menuHoldTime;
};
class CValveMenu;
class CValveMenuDisplay;
class ValveMenuStyle :
public SMGlobalClass,
public IMenuStyle,
public IClientListener
{
public:
ValveMenuStyle();
bool DoClientMenu(int client, CValveMenu *menu, IMenuHandler *mh, unsigned int time);
bool DoClientMenu(int client, CValveMenuDisplay *menu, IMenuHandler *mh, unsigned int time);
void ClientPressedKey(int client, unsigned int key_press);
bool OnClientCommand(int client);
void CancelMenu(CValveMenu *menu);
void ProcessWatchList();
public: //SMGlobalClass
void OnSourceModAllInitialized();
void OnSourceModShutdown();
void OnSourceModVSPReceived(IServerPluginCallbacks *iface);
public: //IClientListener
void OnClientDisconnected(int client);
public: //IMenuStyle
const char *GetStyleName();
IMenuDisplay *CreateDisplay();
IBaseMenu *CreateMenu();
unsigned int GetMaxPageItems();
MenuSource GetClientMenu(int client, void **object);
bool CancelClientMenu(int client, bool autoIgnore=false);
private:
bool RedoClientMenu(int client, ItemOrder order);
void HookCreateMessage(edict_t *pEdict, DIALOG_TYPE type, KeyValues *kv, IServerPluginCallbacks *plugin);
void _CancelMenu(int client, bool bAutoIgnore=false);
private:
CValveMenuPlayer *m_players;
FastLink<int> m_WatchList;
};
class CValveMenu;
class CValveMenuDisplay : public IMenuDisplay
{
public:
CValveMenuDisplay();
CValveMenuDisplay(CValveMenu *pMenu);
~CValveMenuDisplay();
public:
IMenuStyle *GetParentStyle();
void Reset();
void DrawTitle(const char *text, bool onlyIfEmpty=false);
unsigned int DrawItem(const ItemDrawInfo &item);
bool DrawRawLine(const char *rawline);
bool SendDisplay(int client, IMenuHandler *handler, unsigned int time);
bool SetExtOption(MenuOption option, const void *valuePtr);
bool CanDrawItem(unsigned int drawFlags);
void SendRawDisplay(int client, int priority, unsigned int time);
private:
KeyValues *m_pKv;
unsigned int m_NextPos;
bool m_TitleDrawn;
};
class CValveMenu : public CBaseMenu
{
friend class CValveMenuDisplay;
public:
CValveMenu();
public:
bool SetExtOption(MenuOption option, const void *valuePtr);
IMenuDisplay *CreateDisplay();
bool GetExitButton();
bool SetExitButton(bool set);
bool SetPagination(unsigned int itemsPerPage);
bool Display(int client, IMenuHandler *handler, unsigned int time);
void Cancel();
void Destroy();
private:
Color m_IntroColor;
char m_IntroMsg[128];
bool m_bCancelling;
bool m_bShouldDelete;
};
extern ValveMenuStyle g_ValveMenuStyle;
#endif //_INCLUDE_MENUSTYLE_VALVE_H

View File

@ -17,6 +17,7 @@
#include "ShareSys.h" #include "ShareSys.h"
#include "AdminCache.h" #include "AdminCache.h"
#include "ConCmdManager.h" #include "ConCmdManager.h"
#include "MenuStyle_Valve.h"
PlayerManager g_Players; PlayerManager g_Players;
@ -398,6 +399,12 @@ void PlayerManager::OnClientCommand(edict_t *pEntity)
RETURN_META(MRES_SUPERCEDE); RETURN_META(MRES_SUPERCEDE);
} }
bool result = g_ValveMenuStyle.OnClientCommand(client);
if (result)
{
res = Pl_Handled;
}
res = g_ConCmds.DispatchClientCommand(client, (ResultType)res); res = g_ConCmds.DispatchClientCommand(client, (ResultType)res);
if (res >= Pl_Handled) if (res >= Pl_Handled)

View File

@ -227,6 +227,18 @@
RelativePath="..\MemoryUtils.cpp" RelativePath="..\MemoryUtils.cpp"
> >
</File> </File>
<File
RelativePath="..\MenuManager.cpp"
>
</File>
<File
RelativePath="..\MenuStyle_Base.cpp"
>
</File>
<File
RelativePath="..\MenuStyle_Valve.cpp"
>
</File>
<File <File
RelativePath="..\PlayerManager.cpp" RelativePath="..\PlayerManager.cpp"
> >
@ -333,6 +345,18 @@
RelativePath="..\MemoryUtils.h" RelativePath="..\MemoryUtils.h"
> >
</File> </File>
<File
RelativePath="..\MenuManager.h"
>
</File>
<File
RelativePath="..\MenuStyle_Base.h"
>
</File>
<File
RelativePath="..\MenuStyle_Valve.h"
>
</File>
<File <File
RelativePath="..\PlayerManager.h" RelativePath="..\PlayerManager.h"
> >
@ -341,6 +365,10 @@
RelativePath="..\sm_autonatives.h" RelativePath="..\sm_autonatives.h"
> >
</File> </File>
<File
RelativePath="..\sm_fastlink.h"
>
</File>
<File <File
RelativePath="..\sm_globals.h" RelativePath="..\sm_globals.h"
> >
@ -438,6 +466,10 @@
RelativePath="..\..\public\IMemoryUtils.h" RelativePath="..\..\public\IMemoryUtils.h"
> >
</File> </File>
<File
RelativePath="..\..\public\IMenuManager.h"
>
</File>
<File <File
RelativePath="..\..\public\IPlayerHelpers.h" RelativePath="..\..\public\IPlayerHelpers.h"
> >

View File

@ -29,6 +29,7 @@
#include "Translator.h" #include "Translator.h"
#include "ForwardSys.h" #include "ForwardSys.h"
#include "TimerSys.h" #include "TimerSys.h"
#include "MenuStyle_Valve.h"
SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool); SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool);
SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false); SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false);
@ -43,6 +44,7 @@ ISourcePawnEngine *g_pSourcePawn = &g_SourcePawn;
IVirtualMachine *g_pVM; IVirtualMachine *g_pVM;
IdentityToken_t *g_pCoreIdent = NULL; IdentityToken_t *g_pCoreIdent = NULL;
float g_LastTime = 0.0f; float g_LastTime = 0.0f;
float g_LastMenuTime = 0.0f;
float g_LastAuthCheck = 0.0f; float g_LastAuthCheck = 0.0f;
IForward *g_pOnGameFrame = NULL; IForward *g_pOnGameFrame = NULL;
IForward *g_pOnMapEnd = NULL; IForward *g_pOnMapEnd = NULL;
@ -264,6 +266,7 @@ bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, ch
m_IsMapLoading = true; m_IsMapLoading = true;
m_ExecPluginReload = true; m_ExecPluginReload = true;
g_LastTime = 0.0f; g_LastTime = 0.0f;
g_LastMenuTime = 0.0f;
g_LastAuthCheck = 0.0f; g_LastAuthCheck = 0.0f;
g_SimTicks.ticking = true; g_SimTicks.ticking = true;
g_SimTicks.tickcount = 0; g_SimTicks.tickcount = 0;
@ -384,6 +387,12 @@ void SourceModBase::GameFrame(bool simulating)
g_LastTime = curtime; g_LastTime = curtime;
} }
if (g_SimTicks.tickcount && (curtime - g_LastMenuTime >= 1.0f))
{
g_ValveMenuStyle.ProcessWatchList();
g_LastMenuTime = curtime;
}
if (g_pOnGameFrame && g_pOnGameFrame->GetFunctionCount()) if (g_pOnGameFrame && g_pOnGameFrame->GetFunctionCount())
{ {
g_pOnGameFrame->Execute(NULL); g_pOnGameFrame->Execute(NULL);