Updated license headers on virtually all files with extremely minor changes in the name of some sort of strange consistency.
All plugin and include file headers also have been changed to say about GPL3 instead of GPL2.
(This day shall henceforth be known as the Eighty Column Massacre of '07)
3 * =============================================================================
5 * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
6 * =============================================================================
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.
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
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/>.
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>.
33 #include "sm_stringutil.h"
34 #include "MenuStyle_Base.h"
35 #include "PlayerManager.h"
36 #include "MenuManager.h"
37 #include "HandleSys.h"
38 #include "CellRecipientFilter.h"
39 #if defined MENU_DEBUG
43 BaseMenuStyle::BaseMenuStyle() : m_WatchList(256), m_hHandle(BAD_HANDLE)
47 Handle_t BaseMenuStyle::GetHandle()
49 /* Don't create the handle until we need it */
50 if (m_hHandle == BAD_HANDLE)
52 m_hHandle = g_Menus.CreateStyleHandle(this);
58 void BaseMenuStyle::AddClientToWatch(int client)
60 #if defined MENU_DEBUG
61 g_Logger.LogMessage("[SM_MENU] AddClientToWatch(%d)", client);
63 m_WatchList.push_back(client);
66 void BaseMenuStyle::RemoveClientFromWatch(int client)
68 #if defined MENU_DEBUG
69 g_Logger.LogMessage("[SM_MENU] RemoveClientFromWatch(%d)", client);
71 m_WatchList.remove(client);
74 void BaseMenuStyle::_CancelClientMenu(int client, MenuCancelReason reason, bool bAutoIgnore/* =false */)
76 #if defined MENU_DEBUG
77 g_Logger.LogMessage("[SM_MENU] _CancelClientMenu() (client %d) (bAutoIgnore %d) (reason %d)", client, bAutoIgnore, reason);
79 CBaseMenuPlayer *player = GetMenuPlayer(client);
80 menu_states_t &states = player->states;
82 bool bOldIgnore = player->bAutoIgnore;
85 player->bAutoIgnore = true;
89 IMenuHandler *mh = states.mh;
90 IBaseMenu *menu = states.menu;
93 player->bInMenu = false;
94 if (player->menuHoldTime)
96 RemoveClientFromWatch(client);
100 mh->OnMenuCancel(menu, client, reason);
102 /* Only fire end if there's a valid menu */
105 mh->OnMenuEnd(menu, MenuEnd_Cancelled);
110 player->bAutoIgnore = bOldIgnore;
114 void BaseMenuStyle::CancelMenu(CBaseMenu *menu)
116 #if defined MENU_DEBUG
117 g_Logger.LogMessage("[SM_MENU] CancelMenu() (menu %p)", menu);
119 int maxClients = g_Players.GetMaxClients();
120 for (int i=1; i<=maxClients; i++)
122 CBaseMenuPlayer *player = GetMenuPlayer(i);
125 menu_states_t &states = player->states;
126 if (states.menu == menu)
128 _CancelClientMenu(i, MenuCancel_Interrupted);
134 bool BaseMenuStyle::CancelClientMenu(int client, bool autoIgnore)
136 #if defined MENU_DEBUG
137 g_Logger.LogMessage("[SM_MENU] CancelClientMenu() (client %d) (bAutoIgnore %d)", client, autoIgnore);
139 if (client < 1 || client > g_Players.MaxClients())
144 CBaseMenuPlayer *player = GetMenuPlayer(client);
145 if (!player->bInMenu)
150 _CancelClientMenu(client, MenuCancel_Interrupted, autoIgnore);
155 MenuSource BaseMenuStyle::GetClientMenu(int client, void **object)
157 if (client < 1 || client > g_Players.GetMaxClients())
159 return MenuSource_None;
162 CBaseMenuPlayer *player = GetMenuPlayer(client);
167 if ((menu=player->states.menu) != NULL)
173 return MenuSource_BaseMenu;
176 return MenuSource_Display;
177 } else if (player->bInExternMenu) {
178 if (player->menuHoldTime != 0
179 && (gpGlobals->curtime > player->menuStartTime + player->menuHoldTime))
181 player->bInExternMenu = false;
182 return MenuSource_None;
184 return MenuSource_External;
187 return MenuSource_None;
190 void BaseMenuStyle::OnClientDisconnected(int client)
192 #if defined MENU_DEBUG
193 g_Logger.LogMessage("[SM_MENU] OnClientDisconnected(%d)", client);
195 CBaseMenuPlayer *player = GetMenuPlayer(client);
196 if (!player->bInMenu)
201 _CancelClientMenu(client, MenuCancel_Disconnected, true);
203 player->bInMenu = false;
204 player->bInExternMenu = false;
207 static int do_lookup[256];
208 void BaseMenuStyle::ProcessWatchList()
210 if (!m_WatchList.size())
215 #if defined MENU_DEBUG
216 g_Logger.LogMessage("BaseMenuStyle::ProcessWatchList(%d,%d,%d,%d,%d,%p)",
218 m_WatchList.m_FirstLink,
219 m_WatchList.m_FreeNodes,
220 m_WatchList.m_LastLink,
221 m_WatchList.m_MaxSize,
222 m_WatchList.m_Nodes);
225 unsigned int total = 0;
226 for (FastLink<int>::iterator iter=m_WatchList.begin(); iter!=m_WatchList.end(); ++iter)
228 do_lookup[total++] = (*iter);
231 #if defined MENU_DEBUG
234 g_Logger.LogMessage("[SM_MENU] ProcessWatchList() found %d clients", total);
239 CBaseMenuPlayer *player;
240 float curTime = gpGlobals->curtime;
241 for (unsigned int i=0; i<total; i++)
243 client = do_lookup[i];
244 player = GetMenuPlayer(client);
245 #if defined MENU_DEBUG
246 g_Logger.LogMessage("[SM_MENU] ProcessWatchList() (client %d) (bInMenu %d) (menuHoldTime %d) (curTime %f) (menuStartTime %f)",
249 player->menuHoldTime,
251 player->menuStartTime);
253 if (!player->bInMenu || !player->menuHoldTime)
255 #if defined MENU_DEBUG
256 g_Logger.LogMessage("[SM_MENU] ProcessWatchList() removing client %d", client);
258 m_WatchList.remove(client);
261 if (curTime > player->menuStartTime + player->menuHoldTime)
263 _CancelClientMenu(client, MenuCancel_Timeout, false);
268 void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
270 #if defined MENU_DEBUG
271 g_Logger.LogMessage("[SM_MENU] ClientPressedKey() (client %d) (key_press %d)", client, key_press);
273 CBaseMenuPlayer *player = GetMenuPlayer(client);
275 /* First question: Are we in a menu? */
276 if (!player->bInMenu)
282 unsigned int item = 0;
283 MenuCancelReason reason = MenuCancel_Exit;
284 MenuEndReason end_reason = MenuEnd_Selected;
285 menu_states_t &states = player->states;
288 IMenuHandler *mh = states.mh;
289 IBaseMenu *menu = states.menu;
296 } else if (key_press < 1 || key_press > GetMaxPageItems()) {
299 ItemSelection type = states.slots[key_press].type;
301 /* Check if we should play a sound about the type */
302 if (g_Menus.MenuSoundsEnabled() &&
303 (!menu || (menu->GetMenuOptionFlags() & MENUFLAG_NO_SOUND) != MENUFLAG_NO_SOUND))
305 CellRecipientFilter filter;
309 filter.Initialize(clients, 1);
311 const char *sound = g_Menus.GetMenuSound(type);
315 edict_t *pEdict = engine->PEntityOfEntIndex(client);
318 ICollideable *pCollideable = pEdict->GetCollideable();
322 const Vector & pos = pCollideable->GetCollisionOrigin();
324 enginesound->EmitSound(filter,
338 /* For navigational items, we're going to redisplay */
339 if (type == ItemSel_Back)
341 if (!RedoClientMenu(client, ItemOrder_Descending))
344 reason = MenuCancel_NoDisplay;
345 end_reason = MenuEnd_Cancelled;
349 } else if (type == ItemSel_Next) {
350 if (!RedoClientMenu(client, ItemOrder_Ascending))
352 cancel = true; /* I like Saltines. */
353 reason = MenuCancel_NoDisplay;
354 end_reason = MenuEnd_Cancelled;
358 } else if (type == ItemSel_Exit || type == ItemSel_None) {
360 reason = MenuCancel_Exit;
361 end_reason = MenuEnd_Exit;
362 } else if (type == ItemSel_ExitBack) {
364 reason = MenuCancel_ExitBack;
365 end_reason = MenuEnd_ExitBack;
367 item = states.slots[key_press].item;
372 player->bInMenu = false;
373 if (player->menuHoldTime)
375 RemoveClientFromWatch(client);
380 mh->OnMenuCancel(menu, client, reason);
382 mh->OnMenuSelect(menu, client, item);
385 /* Only fire end for valid menus */
388 mh->OnMenuEnd(menu, end_reason);
392 bool BaseMenuStyle::DoClientMenu(int client, IMenuPanel *menu, IMenuHandler *mh, unsigned int time)
394 #if defined MENU_DEBUG
395 g_Logger.LogMessage("[SM_MENU] DoClientMenu() (client %d) (panel %p) (mh %p) (time %d)",
401 CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
402 if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame())
407 CBaseMenuPlayer *player = GetMenuPlayer(client);
408 if (player->bAutoIgnore)
413 /* For the duration of this, we are going to totally ignore whether
414 * the player is already in a menu or not (except to cancel the old one).
415 * Instead, we are simply going to ignore any further menu displays, so
416 * this display can't be interrupted.
418 player->bAutoIgnore = true;
420 /* Cancel any old menus */
421 menu_states_t &states = player->states;
424 _CancelClientMenu(client, MenuCancel_Interrupted, true);
427 states.firstItem = 0;
431 states.apiVers = SMINTERFACE_MENUMANAGER_VERSION;
432 player->bInMenu = true;
433 player->bInExternMenu = false;
434 player->menuStartTime = gpGlobals->curtime;
435 player->menuHoldTime = time;
439 AddClientToWatch(client);
442 /* Draw the display */
443 SendDisplay(client, menu);
445 /* We can be interrupted again! */
446 player->bAutoIgnore = false;
451 bool BaseMenuStyle::DoClientMenu(int client, CBaseMenu *menu, IMenuHandler *mh, unsigned int time)
453 #if defined MENU_DEBUG
454 g_Logger.LogMessage("[SM_MENU] DoClientMenu() (client %d) (menu %p) (mh %p) (time %d)",
460 mh->OnMenuStart(menu);
462 CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
463 if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame())
465 #if defined MENU_DEBUG
466 g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Failed to display to client %d", client);
468 mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
469 mh->OnMenuEnd(menu, MenuEnd_Cancelled);
473 CBaseMenuPlayer *player = GetMenuPlayer(client);
474 if (player->bAutoIgnore)
476 #if defined MENU_DEBUG
477 g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Client %d is autoIgnoring", client);
479 mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
480 mh->OnMenuEnd(menu, MenuEnd_Cancelled);
484 /* For the duration of this, we are going to totally ignore whether
485 * the player is already in a menu or not (except to cancel the old one).
486 * Instead, we are simply going to ignore any further menu displays, so
487 * this display can't be interrupted.
489 player->bAutoIgnore = true;
491 /* Cancel any old menus */
492 menu_states_t &states = player->states;
495 #if defined MENU_DEBUG
496 g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Cancelling old menu to client %d", client);
498 _CancelClientMenu(client, MenuCancel_Interrupted, true);
501 states.firstItem = 0;
505 states.apiVers = SMINTERFACE_MENUMANAGER_VERSION;
507 IMenuPanel *display = g_Menus.RenderMenu(client, states, ItemOrder_Ascending);
510 #if defined MENU_DEBUG
511 g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Failed to render to client %d", client);
513 player->bAutoIgnore = false;
514 player->bInMenu = false;
515 mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
516 mh->OnMenuEnd(menu, MenuEnd_Cancelled);
520 /* Finally, set our states */
521 player->bInMenu = true;
522 player->bInExternMenu = false;
523 player->menuStartTime = gpGlobals->curtime;
524 player->menuHoldTime = time;
528 AddClientToWatch(client);
531 /* Draw the display */
532 SendDisplay(client, display);
534 /* Free the display pointer */
535 display->DeleteThis();
537 /* We can be interrupted again! */
538 player->bAutoIgnore = false;
540 #if defined MENU_DEBUG
541 g_Logger.LogMessage("[SM_MENU] DoClientMenu() finished successfully (client %d)", client);
547 bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order)
549 #if defined MENU_DEBUG
550 g_Logger.LogMessage("[SM_MENU] RedoClientMenu() (client %d) (order %d)", client, order);
552 CBaseMenuPlayer *player = GetMenuPlayer(client);
553 menu_states_t &states = player->states;
555 player->bAutoIgnore = true;
556 IMenuPanel *display = g_Menus.RenderMenu(client, states, order);
559 #if defined MENU_DEBUG
560 g_Logger.LogMessage("[SM_MENU] RedoClientMenu(): Failed to render menu");
562 if (player->menuHoldTime)
564 RemoveClientFromWatch(client);
566 player->bAutoIgnore = false;
570 SendDisplay(client, display);
572 display->DeleteThis();
574 player->bAutoIgnore = false;
576 #if defined MENU_DEBUG
577 g_Logger.LogMessage("[SM_MENU] RedoClientMenu(): Succeeded to client %d", client);
583 CBaseMenu::CBaseMenu(IMenuHandler *pHandler, IMenuStyle *pStyle, IdentityToken_t *pOwner) :
584 m_pStyle(pStyle), m_Strings(512), m_Pagination(7), m_bShouldDelete(false), m_bCancelling(false),
585 m_pOwner(pOwner ? pOwner : g_pCoreIdent), m_bDeleting(false), m_bWillFreeHandle(false),
586 m_hHandle(BAD_HANDLE), m_pHandler(pHandler), m_nFlags(MENUFLAG_BUTTON_EXIT)
590 CBaseMenu::~CBaseMenu()
594 Handle_t CBaseMenu::GetHandle()
598 m_hHandle = g_Menus.CreateMenuHandle(this, m_pOwner);
604 bool CBaseMenu::AppendItem(const char *info, const ItemDrawInfo &draw)
606 if (m_Pagination == (unsigned)MENU_NO_PAGINATION
607 && m_items.size() >= m_pStyle->GetMaxPageItems())
614 item.infoString = m_Strings.AddString(info);
617 item.displayString = m_Strings.AddString(draw.display);
619 item.style = draw.style;
620 item.access = draw.access;
623 m_items.push_back(item);
628 bool CBaseMenu::InsertItem(unsigned int position, const char *info, const ItemDrawInfo &draw)
630 if (m_Pagination == (unsigned)MENU_NO_PAGINATION
631 && m_items.size() >= m_pStyle->GetMaxPageItems())
636 if (position >= m_items.size())
642 item.infoString = m_Strings.AddString(info);
645 item.displayString = m_Strings.AddString(draw.display);
647 item.style = draw.style;
648 item.access = draw.access;
650 CVector<CItem>::iterator iter = m_items.iterAt(position);
651 m_items.insert(iter, item);
656 bool CBaseMenu::RemoveItem(unsigned int position)
658 if (position >= m_items.size())
663 m_items.erase(m_items.iterAt(position));
665 if (m_items.size() == 0)
673 void CBaseMenu::RemoveAllItems()
679 const char *CBaseMenu::GetItemInfo(unsigned int position, ItemDrawInfo *draw/* =NULL */)
681 if (position >= m_items.size())
688 draw->display = m_Strings.GetString(m_items[position].displayString);
689 draw->style = m_items[position].style;
692 return m_Strings.GetString(m_items[position].infoString);
695 unsigned int CBaseMenu::GetItemCount()
697 return m_items.size();
700 bool CBaseMenu::SetPagination(unsigned int itemsPerPage)
702 if (itemsPerPage > 7 || itemsPerPage == 1)
707 m_Pagination = itemsPerPage;
712 unsigned int CBaseMenu::GetPagination()
717 IMenuStyle *CBaseMenu::GetDrawStyle()
722 void CBaseMenu::SetDefaultTitle(const char *message)
724 m_Title.assign(message);
727 const char *CBaseMenu::GetDefaultTitle()
729 return m_Title.c_str();
732 void CBaseMenu::Cancel()
739 #if defined MENU_DEBUG
740 g_Logger.LogMessage("[SM_MENU] CBaseMenu::Cancel(%p) (m_bShouldDelete %d)",
745 m_bCancelling = true;
747 m_bCancelling = false;
755 void CBaseMenu::Destroy(bool releaseHandle)
757 /* Check if we shouldn't be here */
763 #if defined MENU_DEBUG
764 g_Logger.LogMessage("[SM_MENU] CBaseMenu::Destroy(%p) (release %d) (m_bCancelling %d) (m_bShouldDelete %d)",
771 /* Save the destruction hint about our handle */
772 m_bWillFreeHandle = releaseHandle;
774 /* Now actually do stuff */
775 if (!m_bCancelling || m_bShouldDelete)
780 m_bShouldDelete = true;
784 void CBaseMenu::InternalDelete()
786 if (m_bWillFreeHandle && m_hHandle != BAD_HANDLE)
788 Handle_t hndl = m_hHandle;
791 sec.pOwner = m_pOwner;
792 sec.pIdentity = g_pCoreIdent;
794 m_hHandle = BAD_HANDLE;
796 g_HandleSys.FreeHandle(hndl, &sec);
799 m_pHandler->OnMenuDestroy(this);
804 unsigned int CBaseMenu::GetMenuOptionFlags()
809 void CBaseMenu::SetMenuOptionFlags(unsigned int flags)
814 IMenuHandler *CBaseMenu::GetHandler()