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_pServerCfgFile = NULL; | ||||
| 	m_pServerCfgFwd = NULL; | ||||
| 	m_CmdClient = 0; | ||||
| } | ||||
| 
 | ||||
| ConCmdManager::~ConCmdManager() | ||||
|  | ||||
| @ -111,6 +111,11 @@ private: | ||||
| 	void RemoveConCmds(List<CmdHook *> &cmdlist, IPluginContext *pContext); | ||||
| 	bool CheckAccess(int client, const char *cmd, AdminCmdInfo *pAdmin); | ||||
| 	void OnExecCmd(); | ||||
| public: | ||||
| 	inline int GetCommandClient() | ||||
| 	{ | ||||
| 		return m_CmdClient; | ||||
| 	} | ||||
| private: | ||||
| 	Trie *m_pCmds;					/* command 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 "AdminCache.h" | ||||
| #include "ConCmdManager.h" | ||||
| #include "MenuStyle_Valve.h" | ||||
| 
 | ||||
| PlayerManager g_Players; | ||||
| 
 | ||||
| @ -398,6 +399,12 @@ void PlayerManager::OnClientCommand(edict_t *pEntity) | ||||
| 		RETURN_META(MRES_SUPERCEDE); | ||||
| 	} | ||||
| 
 | ||||
| 	bool result = g_ValveMenuStyle.OnClientCommand(client); | ||||
| 	if (result) | ||||
| 	{ | ||||
| 		res = Pl_Handled; | ||||
| 	} | ||||
| 
 | ||||
| 	res = g_ConCmds.DispatchClientCommand(client, (ResultType)res); | ||||
| 
 | ||||
| 	if (res >= Pl_Handled) | ||||
|  | ||||
| @ -227,6 +227,18 @@ | ||||
| 				RelativePath="..\MemoryUtils.cpp" | ||||
| 				> | ||||
| 			</File> | ||||
| 			<File | ||||
| 				RelativePath="..\MenuManager.cpp" | ||||
| 				> | ||||
| 			</File> | ||||
| 			<File | ||||
| 				RelativePath="..\MenuStyle_Base.cpp" | ||||
| 				> | ||||
| 			</File> | ||||
| 			<File | ||||
| 				RelativePath="..\MenuStyle_Valve.cpp" | ||||
| 				> | ||||
| 			</File> | ||||
| 			<File | ||||
| 				RelativePath="..\PlayerManager.cpp" | ||||
| 				> | ||||
| @ -333,6 +345,18 @@ | ||||
| 				RelativePath="..\MemoryUtils.h" | ||||
| 				> | ||||
| 			</File> | ||||
| 			<File | ||||
| 				RelativePath="..\MenuManager.h" | ||||
| 				> | ||||
| 			</File> | ||||
| 			<File | ||||
| 				RelativePath="..\MenuStyle_Base.h" | ||||
| 				> | ||||
| 			</File> | ||||
| 			<File | ||||
| 				RelativePath="..\MenuStyle_Valve.h" | ||||
| 				> | ||||
| 			</File> | ||||
| 			<File | ||||
| 				RelativePath="..\PlayerManager.h" | ||||
| 				> | ||||
| @ -341,6 +365,10 @@ | ||||
| 				RelativePath="..\sm_autonatives.h" | ||||
| 				> | ||||
| 			</File> | ||||
| 			<File | ||||
| 				RelativePath="..\sm_fastlink.h" | ||||
| 				> | ||||
| 			</File> | ||||
| 			<File | ||||
| 				RelativePath="..\sm_globals.h" | ||||
| 				> | ||||
| @ -438,6 +466,10 @@ | ||||
| 				RelativePath="..\..\public\IMemoryUtils.h" | ||||
| 				> | ||||
| 			</File> | ||||
| 			<File | ||||
| 				RelativePath="..\..\public\IMenuManager.h" | ||||
| 				> | ||||
| 			</File> | ||||
| 			<File | ||||
| 				RelativePath="..\..\public\IPlayerHelpers.h" | ||||
| 				> | ||||
|  | ||||
| @ -29,6 +29,7 @@ | ||||
| #include "Translator.h" | ||||
| #include "ForwardSys.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_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false); | ||||
| @ -43,6 +44,7 @@ ISourcePawnEngine *g_pSourcePawn = &g_SourcePawn; | ||||
| IVirtualMachine *g_pVM; | ||||
| IdentityToken_t *g_pCoreIdent = NULL; | ||||
| float g_LastTime = 0.0f; | ||||
| float g_LastMenuTime = 0.0f; | ||||
| float g_LastAuthCheck = 0.0f; | ||||
| IForward *g_pOnGameFrame = NULL; | ||||
| IForward *g_pOnMapEnd = NULL; | ||||
| @ -264,6 +266,7 @@ bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, ch | ||||
| 	m_IsMapLoading = true; | ||||
| 	m_ExecPluginReload = true; | ||||
| 	g_LastTime = 0.0f; | ||||
| 	g_LastMenuTime = 0.0f; | ||||
| 	g_LastAuthCheck = 0.0f; | ||||
| 	g_SimTicks.ticking = true; | ||||
| 	g_SimTicks.tickcount = 0; | ||||
| @ -384,6 +387,12 @@ void SourceModBase::GameFrame(bool simulating) | ||||
| 		g_LastTime = curtime; | ||||
| 	} | ||||
| 
 | ||||
| 	if (g_SimTicks.tickcount && (curtime - g_LastMenuTime >= 1.0f)) | ||||
| 	{ | ||||
| 		g_ValveMenuStyle.ProcessWatchList(); | ||||
| 		g_LastMenuTime = curtime; | ||||
| 	} | ||||
| 
 | ||||
| 	if (g_pOnGameFrame && g_pOnGameFrame->GetFunctionCount()) | ||||
| 	{ | ||||
| 		g_pOnGameFrame->Execute(NULL); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user