core/MenuStyle_Valve.cpp
author Scott Ehlert <ds@alliedmods.net>
Mon May 14 21:29:17 2007 +0000 (2007-05-14)
changeset 794 5947b0ee60bb
parent 790 9b1474d03470
child 819 a2f2353049b9
permissions -rw-r--r--
Implemented amb286 - .smx extension no longer required with "sm plugins load"
     1 /**
     2  * vim: set ts=4 :
     3  * ===============================================================
     4  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     5  * ===============================================================
     6  *
     7  * This file is not open source and may not be copied without explicit
     8  * written permission of AlliedModders LLC.  This file may not be redistributed 
     9  * in whole or significant part.
    10  * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    11  *
    12  * Version: $Id$
    13  */
    14 
    15 #include "sm_stringutil.h"
    16 #include "PlayerManager.h"
    17 #include "MenuStyle_Valve.h"
    18 #include "Translator.h"
    19 #include "PlayerManager.h"
    20 #include "ConCmdManager.h"
    21 
    22 SH_DECL_HOOK4_void(IServerPluginHelpers, CreateMessage, SH_NOATTRIB, false, edict_t *, DIALOG_TYPE, KeyValues *, IServerPluginCallbacks *);
    23 
    24 ValveMenuStyle g_ValveMenuStyle;
    25 extern const char *g_OptionNumTable[];
    26 extern const char *g_OptionCmdTable[];
    27 IServerPluginCallbacks *g_pVSPHandle = NULL;
    28 CallClass<IServerPluginHelpers> *g_pSPHCC = NULL;
    29 
    30 ValveMenuStyle::ValveMenuStyle() : m_players(new CValveMenuPlayer[256+1])
    31 {
    32 }
    33 
    34 CBaseMenuPlayer *ValveMenuStyle::GetMenuPlayer(int client)
    35 {
    36 	return &m_players[client];
    37 }
    38 
    39 bool ValveMenuStyle::OnClientCommand(int client)
    40 {
    41 	const char *cmd = engine->Cmd_Argv(0);
    42 
    43 	if (strcmp(cmd, "sm_vmenuselect") == 0)
    44 	{
    45 		int key_press = atoi(engine->Cmd_Argv(1));
    46 		g_ValveMenuStyle.ClientPressedKey(client, key_press);
    47 		return true;
    48 	}
    49 
    50 	return false;
    51 }
    52 
    53 void ValveMenuStyle::OnSourceModAllInitialized()
    54 {
    55 	g_Players.AddClientListener(this);
    56 	SH_ADD_HOOK_MEMFUNC(IServerPluginHelpers, CreateMessage, serverpluginhelpers, this, &ValveMenuStyle::HookCreateMessage, false);
    57 	g_pSPHCC = SH_GET_CALLCLASS(serverpluginhelpers);
    58 }
    59 
    60 void ValveMenuStyle::OnSourceModShutdown()
    61 {
    62 	SH_RELEASE_CALLCLASS(g_pSPHCC);
    63 	SH_REMOVE_HOOK_MEMFUNC(IServerPluginHelpers, CreateMessage, serverpluginhelpers, this, &ValveMenuStyle::HookCreateMessage, false);
    64 	g_Players.RemoveClientListener(this);
    65 }
    66 
    67 void ValveMenuStyle::HookCreateMessage(edict_t *pEdict,
    68 									   DIALOG_TYPE type,
    69 									   KeyValues *kv,
    70 									   IServerPluginCallbacks *plugin)
    71 {
    72 	if (type != DIALOG_MENU)
    73 	{
    74 		return;
    75 	}
    76 
    77 	int client = engine->IndexOfEdict(pEdict);
    78 	if (client < 1 || client > 256)
    79 	{
    80 		return;
    81 	}
    82 
    83 	CValveMenuPlayer *player = &m_players[client];
    84 	
    85 	/* We don't care if the player is in a menu because, for all intents and purposes,
    86 	 * the menu is completely private.  Instead, we just figure out the level we'll need
    87 	 * in order to override it.
    88 	 */
    89 	player->curPrioLevel = kv->GetInt("level", player->curPrioLevel);
    90 
    91 	/* Oh no! What happens if we got a menu that overwrites ours?! */
    92 	if (player->bInMenu)
    93 	{
    94 		/* Okay, let the external menu survive for now.  It may live another 
    95 		 * day to avenge its grandfather, killed in the great Menu Interruption
    96 		 * battle.
    97 		 */
    98 		_CancelClientMenu(client, true);
    99 	}
   100 }
   101 
   102 void ValveMenuStyle::OnSourceModVSPReceived(IServerPluginCallbacks *iface)
   103 {
   104 	g_pVSPHandle = iface;
   105 }
   106 
   107 IMenuPanel *ValveMenuStyle::CreatePanel()
   108 {
   109 	return new CValveMenuDisplay();
   110 }
   111 
   112 IBaseMenu *ValveMenuStyle::CreateMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner)
   113 {
   114 	return new CValveMenu(pHandler, pOwner);
   115 }
   116 
   117 const char *ValveMenuStyle::GetStyleName()
   118 {
   119 	return "valve";
   120 }
   121 
   122 unsigned int ValveMenuStyle::GetMaxPageItems()
   123 {
   124 	return 8;
   125 }
   126 
   127 void ValveMenuStyle::SendDisplay(int client, IMenuPanel *display)
   128 {
   129 	m_players[client].curPrioLevel--;
   130 	CValveMenuDisplay *vDisplay = (CValveMenuDisplay *)display;
   131 	vDisplay->SendRawDisplay(client, m_players[client].curPrioLevel, m_players[client].menuHoldTime);
   132 }
   133 
   134 bool ValveMenuStyle::DoClientMenu(int client, IMenuPanel *menu, IMenuHandler *mh, unsigned int time)
   135 {
   136 	if (!g_pVSPHandle)
   137 	{
   138 		return false;
   139 	}
   140 
   141 	return BaseMenuStyle::DoClientMenu(client, menu, mh, time);
   142 }
   143 
   144 bool ValveMenuStyle::DoClientMenu(int client, CBaseMenu *menu, IMenuHandler *mh, unsigned int time)
   145 {
   146 	if (!g_pVSPHandle)
   147 	{
   148 		mh->OnMenuStart(menu);
   149 		mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
   150 		mh->OnMenuEnd(menu);
   151 		return false;
   152 	}
   153 
   154 	return BaseMenuStyle::DoClientMenu(client, menu, mh, time);
   155 }
   156 
   157 CValveMenuDisplay::CValveMenuDisplay()
   158 {
   159 	m_pKv = NULL;
   160 	Reset();
   161 }
   162 
   163 CValveMenuDisplay::CValveMenuDisplay(CValveMenu *pMenu)
   164 {
   165 	m_pKv = NULL;
   166 	Reset();
   167 	m_pKv->SetColor("color", pMenu->m_IntroColor);
   168 	m_pKv->SetString("title", pMenu->m_IntroMsg);
   169 }
   170 
   171 void CValveMenuDisplay::DeleteThis()
   172 {
   173 	delete this;
   174 }
   175 
   176 CValveMenuDisplay::~CValveMenuDisplay()
   177 {
   178 	m_pKv->deleteThis();
   179 }
   180 
   181 IMenuStyle *CValveMenuDisplay::GetParentStyle()
   182 {
   183 	return &g_ValveMenuStyle;
   184 }
   185 
   186 void CValveMenuDisplay::Reset()
   187 {
   188 	if (m_pKv)
   189 	{
   190 		m_pKv->deleteThis();
   191 	}
   192 	m_pKv = new KeyValues("menu");
   193 	m_NextPos = 1;
   194 	m_TitleDrawn = false;
   195 }
   196 
   197 bool CValveMenuDisplay::SetExtOption(MenuOption option, const void *valuePtr)
   198 {
   199 	if (option == MenuOption_IntroMessage)
   200 	{
   201 		m_pKv->SetString("title", (const char *)valuePtr);
   202 		return true;
   203 	} else if (option == MenuOption_IntroColor) {
   204 		int *array = (int *)valuePtr;
   205 		m_pKv->SetColor("color", Color(array[0], array[1], array[2], array[3]));
   206 		return true;
   207 	} else if (option == MenuOption_Priority) {
   208 		m_pKv->SetInt("level", *(int *)valuePtr);
   209 		return true;
   210 	}
   211 
   212 	return false;
   213 }
   214 
   215 bool CValveMenuDisplay::CanDrawItem(unsigned int drawFlags)
   216 {
   217 	/**
   218 	 * ITEMDRAW_RAWLINE - We can't draw random text, and this doesn't add a slot,
   219 	 *  so it's completely safe to ignore it.
   220 	 * -----------------------------------------
   221 	 */
   222 	if (drawFlags & ITEMDRAW_RAWLINE)
   223 	{
   224 		return false;
   225 	}
   226 
   227 	/**
   228 	 * Special cases, explained in DrawItem()
   229 	 */
   230 	if ((drawFlags & ITEMDRAW_NOTEXT)
   231 		|| (drawFlags & ITEMDRAW_SPACER))
   232 	{
   233 		return true;
   234 	}
   235 
   236 	/**
   237 	 * We can't draw disabled text.  We could bump the position, but we
   238 	 * want DirectDraw() to find some actual items to display.
   239 	 */
   240 	if (drawFlags & ITEMDRAW_DISABLED)
   241 	{
   242 		return false;
   243 	}
   244 
   245 	return true;
   246 }
   247 
   248 unsigned int CValveMenuDisplay::DrawItem(const ItemDrawInfo &item)
   249 {
   250 	if (m_NextPos > 9 || !CanDrawItem(item.style))
   251 	{
   252 		return 0;
   253 	}
   254 
   255 	/**
   256 	 * For these cases we can't draw anything at all, but
   257 	 * we can at least bump the position since we were explicitly asked to.
   258 	 */
   259 	if ((item.style & ITEMDRAW_NOTEXT)
   260 		|| (item.style & ITEMDRAW_SPACER))
   261 	{
   262 		return m_NextPos++;
   263 	}
   264 
   265 	char buffer[255];
   266 	UTIL_Format(buffer, sizeof(buffer), "%d. %s", m_NextPos, item.display);
   267 
   268 	KeyValues *ki = m_pKv->FindKey(g_OptionNumTable[m_NextPos], true);
   269 	ki->SetString("command", g_OptionCmdTable[m_NextPos]);
   270 	ki->SetString("msg", buffer);
   271 
   272 	return m_NextPos++;
   273 }
   274 
   275 void CValveMenuDisplay::DrawTitle(const char *text, bool onlyIfEmpty/* =false */)
   276 {
   277 	if (onlyIfEmpty && m_TitleDrawn)
   278 	{
   279 		return;
   280 	}
   281 
   282 	m_pKv->SetString("msg", text);
   283 	m_TitleDrawn = true;
   284 }
   285 
   286 bool CValveMenuDisplay::DrawRawLine(const char *rawline)
   287 {
   288 	return false;
   289 }
   290 
   291 void CValveMenuDisplay::SendRawDisplay(int client, int priority, unsigned int time)
   292 {
   293 	m_pKv->SetInt("level", priority);
   294 	m_pKv->SetInt("time", time ? time : 200);
   295 
   296 	SH_CALL(g_pSPHCC, &IServerPluginHelpers::CreateMessage)(
   297 		engine->PEntityOfEntIndex(client),
   298 		DIALOG_MENU,
   299 		m_pKv,
   300 		g_pVSPHandle);
   301 }
   302 
   303 bool CValveMenuDisplay::SendDisplay(int client, IMenuHandler *handler, unsigned int time)
   304 {
   305 	return g_ValveMenuStyle.DoClientMenu(client, this, handler, time);
   306 }
   307 
   308 CValveMenu::CValveMenu(IMenuHandler *pHandler, IdentityToken_t *pOwner) : 
   309 CBaseMenu(pHandler, &g_ValveMenuStyle, pOwner), 
   310 	m_IntroColor(255, 0, 0, 255)
   311 {
   312 	strcpy(m_IntroMsg, "You have a menu, press ESC");
   313 	m_Pagination = 5;
   314 }
   315 
   316 void CValveMenu::Cancel_Finally()
   317 {
   318 	g_ValveMenuStyle.CancelMenu(this);
   319 }
   320 
   321 bool CValveMenu::SetPagination(unsigned int itemsPerPage)
   322 {
   323 	if (itemsPerPage < 1 || itemsPerPage > 5)
   324 	{
   325 		return false;
   326 	}
   327 
   328 	CBaseMenu::SetPagination(itemsPerPage);
   329 
   330 	return true;
   331 }
   332 
   333 bool CValveMenu::SetExtOption(MenuOption option, const void *valuePtr)
   334 {
   335 	if (option == MenuOption_IntroMessage)
   336 	{
   337 		strncopy(m_IntroMsg, (const char *)valuePtr, sizeof(m_IntroMsg));
   338 		return true;
   339 	} else if (option == MenuOption_IntroColor) {
   340 		unsigned int *array = (unsigned int *)valuePtr;
   341 		m_IntroColor = Color(array[0], array[1], array[2], array[3]);
   342 		return true;
   343 	}
   344 
   345 	return false;
   346 }
   347 
   348 bool CValveMenu::Display(int client, unsigned int time)
   349 {
   350 	if (m_bCancelling)
   351 	{
   352 		return false;
   353 	}
   354 
   355 	return g_ValveMenuStyle.DoClientMenu(client, this, m_pHandler, time);
   356 }
   357 
   358 IMenuPanel *CValveMenu::CreatePanel()
   359 {
   360 	return new CValveMenuDisplay(this);
   361 }
   362 
   363 bool CValveMenu::GetExitButton()
   364 {
   365 	return true;
   366 }
   367 
   368 bool CValveMenu::SetExitButton(bool set)
   369 {
   370 	return false;
   371 }
   372 
   373 const char *g_OptionNumTable[] = 
   374 {
   375 	"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"
   376 };
   377 
   378 const char *g_OptionCmdTable[] = 
   379 {
   380 	"sm_vmenuselect 0", /* INVALID! */
   381 	"sm_vmenuselect 1",
   382 	"sm_vmenuselect 2",
   383 	"sm_vmenuselect 3",
   384 	"sm_vmenuselect 4",
   385 	"sm_vmenuselect 5",
   386 	"sm_vmenuselect 6",
   387 	"sm_vmenuselect 7",
   388 	"sm_vmenuselect 8",
   389 	"sm_vmenuselect 9",
   390 	"sm_vmenuselect 10"
   391 };