core/MenuStyle_Valve.cpp
author David Anderson <dvander@alliedmods.net>
Wed Aug 08 02:27:10 2007 +0000 (2007-08-08)
changeset 1269 27397584df9c
parent 1259 472c5e61cdc8
child 1330 ab94316bb52b
permissions -rw-r--r--
- massive overhaul of the voting subsystem
- NOTE: menu API compatibility was COMPLETELY broken for C++!
- cleaned up various aspects of the menu API
- implemented new extended vote results callback
- extended the debug reporter a tiny bit
     1 /**
     2  * vim: set ts=4 :
     3  * ================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
     6  * ================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or 
     9  * modify it under the terms of the GNU General Public License, 
    10  * version 3.0, as published by the Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful,
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15  * GNU General Public License for more details.
    16  *
    17  * You should have received a copy of the GNU General Public License
    18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to 
    21  * link the code of this program (as well as its derivative works) to 
    22  * "Half-Life 2," the "Source Engine," the "SourcePawn JIT," and any 
    23  * Game MODs that run on software by the Valve Corporation.  You must 
    24  * obey the GNU General Public License in all respects for all other 
    25  * code used. Additionally, AlliedModders LLC grants this exception 
    26  * to all derivative works. AlliedModders LLC defines further 
    27  * exceptions, found in LICENSE.txt (as of this writing, version 
    28  * JULY-31-2007), or <http://www.sourcemod.net/license.php>.
    29  *
    30  * Version: $Id$
    31  */
    32 
    33 #include "sm_stringutil.h"
    34 #include "PlayerManager.h"
    35 #include "MenuStyle_Valve.h"
    36 #include "Translator.h"
    37 #include "PlayerManager.h"
    38 #include "ConCmdManager.h"
    39 
    40 SH_DECL_HOOK4_void(IServerPluginHelpers, CreateMessage, SH_NOATTRIB, false, edict_t *, DIALOG_TYPE, KeyValues *, IServerPluginCallbacks *);
    41 
    42 ValveMenuStyle g_ValveMenuStyle;
    43 extern const char *g_OptionNumTable[];
    44 extern const char *g_OptionCmdTable[];
    45 IServerPluginCallbacks *g_pVSPHandle = NULL;
    46 CallClass<IServerPluginHelpers> *g_pSPHCC = NULL;
    47 
    48 ValveMenuStyle::ValveMenuStyle() : m_players(new CValveMenuPlayer[256+1])
    49 {
    50 }
    51 
    52 CBaseMenuPlayer *ValveMenuStyle::GetMenuPlayer(int client)
    53 {
    54 	return &m_players[client];
    55 }
    56 
    57 bool ValveMenuStyle::OnClientCommand(int client)
    58 {
    59 	const char *cmd = engine->Cmd_Argv(0);
    60 
    61 	if (strcmp(cmd, "sm_vmenuselect") == 0)
    62 	{
    63 		int key_press = atoi(engine->Cmd_Argv(1));
    64 		g_ValveMenuStyle.ClientPressedKey(client, key_press);
    65 		return true;
    66 	}
    67 
    68 	return false;
    69 }
    70 
    71 void ValveMenuStyle::OnSourceModAllInitialized()
    72 {
    73 	g_Players.AddClientListener(this);
    74 	SH_ADD_HOOK_MEMFUNC(IServerPluginHelpers, CreateMessage, serverpluginhelpers, this, &ValveMenuStyle::HookCreateMessage, false);
    75 	g_pSPHCC = SH_GET_CALLCLASS(serverpluginhelpers);
    76 }
    77 
    78 void ValveMenuStyle::OnSourceModShutdown()
    79 {
    80 	SH_RELEASE_CALLCLASS(g_pSPHCC);
    81 	SH_REMOVE_HOOK_MEMFUNC(IServerPluginHelpers, CreateMessage, serverpluginhelpers, this, &ValveMenuStyle::HookCreateMessage, false);
    82 	g_Players.RemoveClientListener(this);
    83 }
    84 
    85 void ValveMenuStyle::HookCreateMessage(edict_t *pEdict,
    86 									   DIALOG_TYPE type,
    87 									   KeyValues *kv,
    88 									   IServerPluginCallbacks *plugin)
    89 {
    90 	if (type != DIALOG_MENU)
    91 	{
    92 		return;
    93 	}
    94 
    95 	int client = engine->IndexOfEdict(pEdict);
    96 	if (client < 1 || client > 256)
    97 	{
    98 		return;
    99 	}
   100 
   101 	CValveMenuPlayer *player = &m_players[client];
   102 	
   103 	/* We don't care if the player is in a menu because, for all intents and purposes,
   104 	 * the menu is completely private.  Instead, we just figure out the level we'll need
   105 	 * in order to override it.
   106 	 */
   107 	player->curPrioLevel = kv->GetInt("level", player->curPrioLevel);
   108 
   109 	/* Oh no! What happens if we got a menu that overwrites ours?! */
   110 	if (player->bInMenu)
   111 	{
   112 		/* Okay, let the external menu survive for now.  It may live another 
   113 		 * day to avenge its grandfather, killed in the great Menu Interruption
   114 		 * battle.
   115 		 */
   116 		_CancelClientMenu(client, MenuCancel_Interrupted, true);
   117 	}
   118 }
   119 
   120 void ValveMenuStyle::OnSourceModVSPReceived(IServerPluginCallbacks *iface)
   121 {
   122 	g_pVSPHandle = iface;
   123 }
   124 
   125 IMenuPanel *ValveMenuStyle::CreatePanel()
   126 {
   127 	return new CValveMenuDisplay();
   128 }
   129 
   130 IBaseMenu *ValveMenuStyle::CreateMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner)
   131 {
   132 	return new CValveMenu(pHandler, pOwner);
   133 }
   134 
   135 const char *ValveMenuStyle::GetStyleName()
   136 {
   137 	return "valve";
   138 }
   139 
   140 unsigned int ValveMenuStyle::GetMaxPageItems()
   141 {
   142 	return 8;
   143 }
   144 
   145 void ValveMenuStyle::SendDisplay(int client, IMenuPanel *display)
   146 {
   147 	m_players[client].curPrioLevel--;
   148 	CValveMenuDisplay *vDisplay = (CValveMenuDisplay *)display;
   149 	vDisplay->SendRawDisplay(client, m_players[client].curPrioLevel, m_players[client].menuHoldTime);
   150 }
   151 
   152 bool ValveMenuStyle::DoClientMenu(int client, IMenuPanel *menu, IMenuHandler *mh, unsigned int time)
   153 {
   154 	if (!g_pVSPHandle)
   155 	{
   156 		return false;
   157 	}
   158 
   159 	return BaseMenuStyle::DoClientMenu(client, menu, mh, time);
   160 }
   161 
   162 bool ValveMenuStyle::DoClientMenu(int client, CBaseMenu *menu, IMenuHandler *mh, unsigned int time)
   163 {
   164 	if (!g_pVSPHandle)
   165 	{
   166 		mh->OnMenuStart(menu);
   167 		mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
   168 		mh->OnMenuEnd(menu, MenuEnd_Cancelled);
   169 		return false;
   170 	}
   171 
   172 	return BaseMenuStyle::DoClientMenu(client, menu, mh, time);
   173 }
   174 
   175 CValveMenuDisplay::CValveMenuDisplay()
   176 {
   177 	m_pKv = NULL;
   178 	Reset();
   179 }
   180 
   181 CValveMenuDisplay::CValveMenuDisplay(CValveMenu *pMenu)
   182 {
   183 	m_pKv = NULL;
   184 	Reset();
   185 	m_pKv->SetColor("color", pMenu->m_IntroColor);
   186 	m_pKv->SetString("title", pMenu->m_IntroMsg);
   187 }
   188 
   189 void CValveMenuDisplay::DeleteThis()
   190 {
   191 	delete this;
   192 }
   193 
   194 CValveMenuDisplay::~CValveMenuDisplay()
   195 {
   196 	m_pKv->deleteThis();
   197 }
   198 
   199 IMenuStyle *CValveMenuDisplay::GetParentStyle()
   200 {
   201 	return &g_ValveMenuStyle;
   202 }
   203 
   204 void CValveMenuDisplay::Reset()
   205 {
   206 	if (m_pKv)
   207 	{
   208 		m_pKv->deleteThis();
   209 	}
   210 	m_pKv = new KeyValues("menu");
   211 	m_NextPos = 1;
   212 	m_TitleDrawn = false;
   213 }
   214 
   215 unsigned int CValveMenuDisplay::GetCurrentKey()
   216 {
   217 	return m_NextPos;
   218 }
   219 
   220 bool CValveMenuDisplay::SetCurrentKey(unsigned int key)
   221 {
   222 	if (key < m_NextPos || key > 9)
   223 	{
   224 		return false;
   225 	}
   226 
   227 	m_NextPos = key;
   228 
   229 	return true;
   230 }
   231 
   232 bool CValveMenuDisplay::SetExtOption(MenuOption option, const void *valuePtr)
   233 {
   234 	if (option == MenuOption_IntroMessage)
   235 	{
   236 		m_pKv->SetString("title", (const char *)valuePtr);
   237 		return true;
   238 	} else if (option == MenuOption_IntroColor) {
   239 		int *array = (int *)valuePtr;
   240 		m_pKv->SetColor("color", Color(array[0], array[1], array[2], array[3]));
   241 		return true;
   242 	} else if (option == MenuOption_Priority) {
   243 		m_pKv->SetInt("level", *(int *)valuePtr);
   244 		return true;
   245 	}
   246 
   247 	return false;
   248 }
   249 
   250 bool CValveMenuDisplay::CanDrawItem(unsigned int drawFlags)
   251 {
   252 	/**
   253 	 * ITEMDRAW_RAWLINE - We can't draw random text, and this doesn't add a slot,
   254 	 *  so it's completely safe to ignore it.
   255 	 * -----------------------------------------
   256 	 */
   257 	if (drawFlags & ITEMDRAW_RAWLINE)
   258 	{
   259 		return false;
   260 	}
   261 
   262 	/**
   263 	 * Special cases, explained in DrawItem()
   264 	 */
   265 	if ((drawFlags & ITEMDRAW_NOTEXT)
   266 		|| (drawFlags & ITEMDRAW_SPACER))
   267 	{
   268 		return true;
   269 	}
   270 
   271 	/**
   272 	 * We can't draw disabled text.  We could bump the position, but we
   273 	 * want DirectDraw() to find some actual items to display.
   274 	 */
   275 	if (drawFlags & ITEMDRAW_DISABLED)
   276 	{
   277 		return false;
   278 	}
   279 
   280 	return true;
   281 }
   282 
   283 unsigned int CValveMenuDisplay::DrawItem(const ItemDrawInfo &item)
   284 {
   285 	if (m_NextPos > 9 || !CanDrawItem(item.style))
   286 	{
   287 		return 0;
   288 	}
   289 
   290 	/**
   291 	 * For these cases we can't draw anything at all, but
   292 	 * we can at least bump the position since we were explicitly asked to.
   293 	 */
   294 	if ((item.style & ITEMDRAW_NOTEXT)
   295 		|| (item.style & ITEMDRAW_SPACER))
   296 	{
   297 		return m_NextPos++;
   298 	}
   299 
   300 	char buffer[255];
   301 	UTIL_Format(buffer, sizeof(buffer), "%d. %s", m_NextPos, item.display);
   302 
   303 	KeyValues *ki = m_pKv->FindKey(g_OptionNumTable[m_NextPos], true);
   304 	ki->SetString("command", g_OptionCmdTable[m_NextPos]);
   305 	ki->SetString("msg", buffer);
   306 
   307 	return m_NextPos++;
   308 }
   309 
   310 void CValveMenuDisplay::DrawTitle(const char *text, bool onlyIfEmpty/* =false */)
   311 {
   312 	if (onlyIfEmpty && m_TitleDrawn)
   313 	{
   314 		return;
   315 	}
   316 
   317 	m_pKv->SetString("msg", text);
   318 	m_TitleDrawn = true;
   319 }
   320 
   321 bool CValveMenuDisplay::DrawRawLine(const char *rawline)
   322 {
   323 	return false;
   324 }
   325 
   326 void CValveMenuDisplay::SendRawDisplay(int client, int priority, unsigned int time)
   327 {
   328 	m_pKv->SetInt("level", priority);
   329 	m_pKv->SetInt("time", time ? time : 200);
   330 
   331 	SH_CALL(g_pSPHCC, &IServerPluginHelpers::CreateMessage)(
   332 		engine->PEntityOfEntIndex(client),
   333 		DIALOG_MENU,
   334 		m_pKv,
   335 		g_pVSPHandle);
   336 }
   337 
   338 bool CValveMenuDisplay::SendDisplay(int client, IMenuHandler *handler, unsigned int time)
   339 {
   340 	return g_ValveMenuStyle.DoClientMenu(client, this, handler, time);
   341 }
   342 
   343 bool CValveMenuDisplay::SetSelectableKeys(unsigned int keymap)
   344 {
   345 	return false;
   346 }
   347 
   348 CValveMenu::CValveMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner) : 
   349 CBaseMenu(pHandler, &g_ValveMenuStyle, pOwner), 
   350 	m_IntroColor(255, 0, 0, 255)
   351 {
   352 	strcpy(m_IntroMsg, "You have a menu, press ESC");
   353 	m_Pagination = 5;
   354 }
   355 
   356 void CValveMenu::Cancel_Finally()
   357 {
   358 	g_ValveMenuStyle.CancelMenu(this);
   359 }
   360 
   361 bool CValveMenu::SetPagination(unsigned int itemsPerPage)
   362 {
   363 	if (itemsPerPage > 5)
   364 	{
   365 		return false;
   366 	}
   367 
   368 	return CBaseMenu::SetPagination(itemsPerPage);
   369 }
   370 
   371 bool CValveMenu::SetExtOption(MenuOption option, const void *valuePtr)
   372 {
   373 	if (option == MenuOption_IntroMessage)
   374 	{
   375 		strncopy(m_IntroMsg, (const char *)valuePtr, sizeof(m_IntroMsg));
   376 		return true;
   377 	} else if (option == MenuOption_IntroColor) {
   378 		unsigned int *array = (unsigned int *)valuePtr;
   379 		m_IntroColor = Color(array[0], array[1], array[2], array[3]);
   380 		return true;
   381 	}
   382 
   383 	return false;
   384 }
   385 
   386 bool CValveMenu::Display(int client, unsigned int time, IMenuHandler *alt_handler)
   387 {
   388 	if (m_bCancelling)
   389 	{
   390 		return false;
   391 	}
   392 
   393 	return g_ValveMenuStyle.DoClientMenu(client, this, alt_handler ? alt_handler : m_pHandler, time);
   394 }
   395 
   396 IMenuPanel *CValveMenu::CreatePanel()
   397 {
   398 	return new CValveMenuDisplay(this);
   399 }
   400 
   401 void CValveMenu::SetMenuOptionFlags(unsigned int flags)
   402 {
   403 	flags |= MENUFLAG_BUTTON_EXIT;
   404 	CBaseMenu::SetMenuOptionFlags(flags);
   405 }
   406 
   407 const char *g_OptionNumTable[] = 
   408 {
   409 	"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"
   410 };
   411 
   412 const char *g_OptionCmdTable[] = 
   413 {
   414 	"sm_vmenuselect 0", /* INVALID! */
   415 	"sm_vmenuselect 1",
   416 	"sm_vmenuselect 2",
   417 	"sm_vmenuselect 3",
   418 	"sm_vmenuselect 4",
   419 	"sm_vmenuselect 5",
   420 	"sm_vmenuselect 6",
   421 	"sm_vmenuselect 7",
   422 	"sm_vmenuselect 8",
   423 	"sm_vmenuselect 9",
   424 	"sm_vmenuselect 10"
   425 };