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