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:
		
							parent
							
								
									30f50e6ded
								
							
						
					
					
						commit
						d7b2f9a721
					
				| @ -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() | ||||||
|  | |||||||
| @ -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
									
								
							
							
						
						
									
										676
									
								
								core/MenuManager.cpp
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										110
									
								
								core/MenuManager.h
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										162
									
								
								core/MenuStyle_Base.cpp
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										69
									
								
								core/MenuStyle_Base.h
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										796
									
								
								core/MenuStyle_Valve.cpp
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										127
									
								
								core/MenuStyle_Valve.h
									
									
									
									
									
										Normal 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
 | ||||||
| @ -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) | ||||||
|  | |||||||
| @ -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" | ||||||
| 				> | 				> | ||||||
|  | |||||||
| @ -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); | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user