LobbyUtils.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. ///////////////////////////////////////////////////////////////////////////////////////
  24. // FILE: LobbyUtils.cpp
  25. // Author: Matthew D. Campbell, Sept 2002
  26. // Description: GameSpy lobby utils
  27. ///////////////////////////////////////////////////////////////////////////////////////
  28. // INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
  29. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  30. #include "Common/GameEngine.h"
  31. #include "Common/MultiplayerSettings.h"
  32. #include "Common/PlayerTemplate.h"
  33. #include "Common/Version.h"
  34. #include "GameClient/AnimateWindowManager.h"
  35. #include "GameClient/WindowLayout.h"
  36. #include "GameClient/Gadget.h"
  37. #include "GameClient/Image.h"
  38. #include "GameClient/Shell.h"
  39. #include "GameClient/KeyDefs.h"
  40. #include "GameClient/GameWindowManager.h"
  41. #include "GameClient/GadgetComboBox.h"
  42. #include "GameClient/GadgetListBox.h"
  43. #include "GameClient/GadgetTextEntry.h"
  44. #include "GameClient/GameText.h"
  45. #include "GameClient/MapUtil.h"
  46. #include "GameClient/MessageBox.h"
  47. #include "GameClient/Mouse.h"
  48. #include "GameNetwork/GameSpyOverlay.h"
  49. #include "GameClient/LanguageFilter.h"
  50. #include "GameNetwork/GameSpy/BuddyDefs.h"
  51. #include "GameNetwork/GameSpy/LadderDefs.h"
  52. #include "GameNetwork/GameSpy/LobbyUtils.h"
  53. #include "GameNetwork/GameSpy/PeerDefs.h"
  54. #include "GameNetwork/GameSpy/PeerThread.h"
  55. #include "GameNetwork/GameSpy/PersistentStorageDefs.h"
  56. #include "GameNetwork/GameSpy/GSConfig.h"
  57. #include "Common/STLTypedefs.h"
  58. #ifdef _INTERNAL
  59. // for occasional debugging...
  60. //#pragma optimize("", off)
  61. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  62. #endif
  63. // PRIVATE DATA ///////////////////////////////////////////////////////////////////////////////////
  64. static enum {
  65. COLUMN_NAME = 0,
  66. COLUMN_MAP,
  67. COLUMN_LADDER,
  68. COLUMN_NUMPLAYERS,
  69. COLUMN_PASSWORD,
  70. COLUMN_OBSERVER,
  71. COLUMN_PING,
  72. };
  73. static NameKeyType buttonSortAlphaID = NAMEKEY_INVALID;
  74. static NameKeyType buttonSortPingID = NAMEKEY_INVALID;
  75. static NameKeyType buttonSortBuddiesID = NAMEKEY_INVALID;
  76. static NameKeyType windowSortAlphaID = NAMEKEY_INVALID;
  77. static NameKeyType windowSortPingID = NAMEKEY_INVALID;
  78. static NameKeyType windowSortBuddiesID = NAMEKEY_INVALID;
  79. static GameWindow *buttonSortAlpha = NULL;
  80. static GameWindow *buttonSortPing = NULL;
  81. static GameWindow *buttonSortBuddies = NULL;
  82. static GameWindow *windowSortAlpha = NULL;
  83. static GameWindow *windowSortPing = NULL;
  84. static GameWindow *windowSortBuddies = NULL;
  85. static GameSortType theGameSortType = GAMESORT_ALPHA_ASCENDING;
  86. static Bool sortBuddies = TRUE;
  87. static void showSortIcons(void)
  88. {
  89. if (windowSortAlpha && windowSortPing)
  90. {
  91. switch(theGameSortType)
  92. {
  93. case GAMESORT_ALPHA_ASCENDING:
  94. windowSortAlpha->winHide(FALSE);
  95. windowSortAlpha->winEnable(TRUE);
  96. windowSortPing->winHide(TRUE);
  97. break;
  98. case GAMESORT_ALPHA_DESCENDING:
  99. windowSortAlpha->winHide(FALSE);
  100. windowSortAlpha->winEnable(FALSE);
  101. windowSortPing->winHide(TRUE);
  102. break;
  103. case GAMESORT_PING_ASCENDING:
  104. windowSortPing->winHide(FALSE);
  105. windowSortPing->winEnable(TRUE);
  106. windowSortAlpha->winHide(TRUE);
  107. break;
  108. case GAMESORT_PING_DESCENDING:
  109. windowSortPing->winHide(FALSE);
  110. windowSortPing->winEnable(FALSE);
  111. windowSortAlpha->winHide(TRUE);
  112. break;
  113. }
  114. }
  115. if (sortBuddies)
  116. {
  117. if (windowSortBuddies)
  118. {
  119. windowSortBuddies->winHide(FALSE);
  120. }
  121. }
  122. else
  123. {
  124. if (windowSortBuddies)
  125. {
  126. windowSortBuddies->winHide(TRUE);
  127. }
  128. }
  129. }
  130. void setSortMode( GameSortType sortType ) { theGameSortType = sortType; showSortIcons(); RefreshGameListBoxes(); }
  131. void sortByBuddies( Bool doSort ) { sortBuddies = doSort; showSortIcons(); RefreshGameListBoxes(); }
  132. Bool HandleSortButton( NameKeyType sortButton )
  133. {
  134. if (sortButton == buttonSortBuddiesID)
  135. {
  136. sortByBuddies( !sortBuddies );
  137. return TRUE;
  138. }
  139. else if (sortButton == buttonSortAlphaID)
  140. {
  141. if (theGameSortType == GAMESORT_ALPHA_ASCENDING)
  142. {
  143. setSortMode(GAMESORT_ALPHA_DESCENDING);
  144. }
  145. else
  146. {
  147. setSortMode(GAMESORT_ALPHA_ASCENDING);
  148. }
  149. return TRUE;
  150. }
  151. else if (sortButton == buttonSortPingID)
  152. {
  153. if (theGameSortType == GAMESORT_PING_ASCENDING)
  154. {
  155. setSortMode(GAMESORT_PING_DESCENDING);
  156. }
  157. else
  158. {
  159. setSortMode(GAMESORT_PING_ASCENDING);
  160. }
  161. return TRUE;
  162. }
  163. return FALSE;
  164. }
  165. // window ids ------------------------------------------------------------------------------
  166. static NameKeyType parentID = NAMEKEY_INVALID;
  167. //static NameKeyType parentGameListSmallID = NAMEKEY_INVALID;
  168. static NameKeyType parentGameListLargeID = NAMEKEY_INVALID;
  169. static NameKeyType listboxLobbyGamesSmallID = NAMEKEY_INVALID;
  170. static NameKeyType listboxLobbyGamesLargeID = NAMEKEY_INVALID;
  171. //static NameKeyType listboxLobbyGameInfoID = NAMEKEY_INVALID;
  172. // Window Pointers ------------------------------------------------------------------------
  173. static GameWindow *parent = NULL;
  174. //static GameWindow *parentGameListSmall = NULL;
  175. static GameWindow *parentGameListLarge = NULL;
  176. //GameWindow *listboxLobbyGamesSmall = NULL;
  177. GameWindow *listboxLobbyGamesLarge = NULL;
  178. //GameWindow *listboxLobbyGameInfo = NULL;
  179. static const Image *pingImages[3] = { NULL, NULL, NULL };
  180. static void gameTooltip(GameWindow *window,
  181. WinInstanceData *instData,
  182. UnsignedInt mouse)
  183. {
  184. Int x, y, row, col;
  185. x = LOLONGTOSHORT(mouse);
  186. y = HILONGTOSHORT(mouse);
  187. GadgetListBoxGetEntryBasedOnXY(window, x, y, row, col);
  188. if (row == -1 || col == -1)
  189. {
  190. TheMouse->setCursorTooltip( UnicodeString::TheEmptyString);//TheGameText->fetch("TOOLTIP:GamesBeingFormed") );
  191. return;
  192. }
  193. Int gameID = (Int)GadgetListBoxGetItemData(window, row, 0);
  194. GameSpyStagingRoom *room = TheGameSpyInfo->findStagingRoomByID(gameID);
  195. if (!room)
  196. {
  197. TheMouse->setCursorTooltip( TheGameText->fetch("TOOLTIP:UnknownGame") );
  198. return;
  199. }
  200. if (col == COLUMN_PING)
  201. {
  202. #ifdef DEBUG_LOGGING
  203. UnicodeString s;
  204. s.format(L"Ping is %d ms (cutoffs are %d ms and %d ms\n%hs local pings\n%hs remote pings",
  205. room->getPingAsInt(), TheGameSpyConfig->getPingCutoffGood(), TheGameSpyConfig->getPingCutoffBad(),
  206. TheGameSpyInfo->getPingString().str(), room->getPingString().str()
  207. );
  208. TheMouse->setCursorTooltip( s, 10, NULL, 2.0f ); // the text and width are the only params used. the others are the default values.
  209. #else
  210. TheMouse->setCursorTooltip( TheGameText->fetch("TOOLTIP:PingInfo"), 10, NULL, 2.0f ); // the text and width are the only params used. the others are the default values.
  211. #endif
  212. return;
  213. }
  214. if (col == COLUMN_NUMPLAYERS)
  215. {
  216. TheMouse->setCursorTooltip( TheGameText->fetch("TOOLTIP:NumberOfPlayers"), 10, NULL, 2.0f ); // the text and width are the only params used. the others are the default values.
  217. return;
  218. }
  219. if (col == COLUMN_PASSWORD)
  220. {
  221. if (room->getHasPassword())
  222. {
  223. UnicodeString checkTooltip =TheGameText->fetch("TOOTIP:Password");
  224. if(!checkTooltip.compare(L"Password required to joing game"))
  225. checkTooltip.set(L"Password required to join game");
  226. TheMouse->setCursorTooltip( checkTooltip, 10, NULL, 2.0f ); // the text and width are the only params used. the others are the default values.
  227. }
  228. else
  229. TheMouse->setCursorTooltip( UnicodeString::TheEmptyString );
  230. return;
  231. }
  232. UnicodeString tooltip;
  233. UnicodeString mapName;
  234. const MapMetaData *md = TheMapCache->findMap(room->getMap());
  235. if (md)
  236. {
  237. mapName = md->m_displayName;
  238. }
  239. else
  240. {
  241. const char *start = room->getMap().reverseFind('\\');
  242. if (start)
  243. {
  244. ++start;
  245. }
  246. else
  247. {
  248. start = room->getMap().str();
  249. }
  250. mapName.translate( start );
  251. }
  252. UnicodeString tmp;
  253. tooltip.format(TheGameText->fetch("TOOLTIP:GameInfoGameName"), room->getGameName().str());
  254. if (room->getLadderPort() != 0)
  255. {
  256. const LadderInfo *linfo = TheLadderList->findLadder(room->getLadderIP(), room->getLadderPort());
  257. if (linfo)
  258. {
  259. tmp.format(TheGameText->fetch("TOOLTIP:GameInfoLadderName"), linfo->name.str());
  260. tooltip.concat(tmp);
  261. }
  262. }
  263. if (room->getExeCRC() != TheGlobalData->m_exeCRC || room->getIniCRC() != TheGlobalData->m_iniCRC)
  264. {
  265. tmp.format(TheGameText->fetch("TOOLTIP:InvalidGameVersion"), mapName.str());
  266. tooltip.concat(tmp);
  267. }
  268. tmp.format(TheGameText->fetch("TOOLTIP:GameInfoMap"), mapName.str());
  269. tooltip.concat(tmp);
  270. AsciiString aPlayer;
  271. UnicodeString player;
  272. Int numPlayers = 0;
  273. for (Int i=0; i<MAX_SLOTS; ++i)
  274. {
  275. GameSpyGameSlot *slot = room->getGameSpySlot(i);
  276. if (i == 0 && (!slot || !slot->isHuman()))
  277. {
  278. DEBUG_CRASH(("About to tooltip a non-hosted game!\n"));
  279. }
  280. if (slot && slot->isHuman())
  281. {
  282. tmp.format(TheGameText->fetch("TOOLTIP:GameInfoPlayer"), slot->getName().str(), slot->getWins(), slot->getLosses());
  283. tooltip.concat(tmp);
  284. ++numPlayers;
  285. }
  286. else if (slot && slot->isAI())
  287. {
  288. ++numPlayers;
  289. switch(slot->getState())
  290. {
  291. case SLOT_EASY_AI:
  292. tooltip.concat(L'\n');
  293. tooltip.concat(TheGameText->fetch("GUI:EasyAI"));
  294. break;
  295. case SLOT_MED_AI:
  296. tooltip.concat(L'\n');
  297. tooltip.concat(TheGameText->fetch("GUI:MediumAI"));
  298. break;
  299. case SLOT_BRUTAL_AI:
  300. tooltip.concat(L'\n');
  301. tooltip.concat(TheGameText->fetch("GUI:HardAI"));
  302. break;
  303. }
  304. }
  305. }
  306. DEBUG_ASSERTCRASH(numPlayers, ("Tooltipping a 0-player game!\n"));
  307. TheMouse->setCursorTooltip( tooltip, 10, NULL, 2.0f ); // the text and width are the only params used. the others are the default values.
  308. }
  309. static Bool isSmall = TRUE;
  310. GameWindow *GetGameListBox( void )
  311. {
  312. return listboxLobbyGamesLarge;
  313. }
  314. GameWindow *GetGameInfoListBox( void )
  315. {
  316. return NULL;
  317. }
  318. NameKeyType GetGameListBoxID( void )
  319. {
  320. return listboxLobbyGamesLargeID;
  321. }
  322. NameKeyType GetGameInfoListBoxID( void )
  323. {
  324. return NAMEKEY_INVALID;
  325. }
  326. void GrabWindowInfo( void )
  327. {
  328. isSmall = TRUE;
  329. parentID = NAMEKEY( "WOLCustomLobby.wnd:WOLLobbyMenuParent" );
  330. parent = TheWindowManager->winGetWindowFromId(NULL, parentID);
  331. pingImages[0] = TheMappedImageCollection->findImageByName("Ping03");
  332. pingImages[1] = TheMappedImageCollection->findImageByName("Ping02");
  333. pingImages[2] = TheMappedImageCollection->findImageByName("Ping01");
  334. DEBUG_ASSERTCRASH(pingImages[0], ("Can't find ping image!"));
  335. DEBUG_ASSERTCRASH(pingImages[1], ("Can't find ping image!"));
  336. DEBUG_ASSERTCRASH(pingImages[2], ("Can't find ping image!"));
  337. // parentGameListSmallID = NAMEKEY( "WOLCustomLobby.wnd:ParentGameListSmall" );
  338. // parentGameListSmall = TheWindowManager->winGetWindowFromId(NULL, parentGameListSmallID);
  339. parentGameListLargeID = NAMEKEY( "WOLCustomLobby.wnd:ParentGameListLarge" );
  340. parentGameListLarge = TheWindowManager->winGetWindowFromId(NULL, parentGameListLargeID);
  341. listboxLobbyGamesSmallID = NAMEKEY( "WOLCustomLobby.wnd:ListboxGames" );
  342. // listboxLobbyGamesSmall = TheWindowManager->winGetWindowFromId(NULL, listboxLobbyGamesSmallID);
  343. // listboxLobbyGamesSmall->winSetTooltipFunc(gameTooltip);
  344. listboxLobbyGamesLargeID = NAMEKEY( "WOLCustomLobby.wnd:ListboxGamesLarge" );
  345. listboxLobbyGamesLarge = TheWindowManager->winGetWindowFromId(NULL, listboxLobbyGamesLargeID);
  346. listboxLobbyGamesLarge->winSetTooltipFunc(gameTooltip);
  347. //
  348. // listboxLobbyGameInfoID = NAMEKEY( "WOLCustomLobby.wnd:ListboxGameInfo" );
  349. // listboxLobbyGameInfo = TheWindowManager->winGetWindowFromId(NULL, listboxLobbyGameInfoID);
  350. buttonSortAlphaID = NAMEKEY("WOLCustomLobby.wnd:ButtonSortAlpha");
  351. buttonSortPingID = NAMEKEY("WOLCustomLobby.wnd:ButtonSortPing");
  352. buttonSortBuddiesID = NAMEKEY("WOLCustomLobby.wnd:ButtonSortBuddies");
  353. windowSortAlphaID = NAMEKEY("WOLCustomLobby.wnd:WindowSortAlpha");
  354. windowSortPingID = NAMEKEY("WOLCustomLobby.wnd:WindowSortPing");
  355. windowSortBuddiesID = NAMEKEY("WOLCustomLobby.wnd:WindowSortBuddies");
  356. buttonSortAlpha = TheWindowManager->winGetWindowFromId(parent, buttonSortAlphaID);
  357. buttonSortPing = TheWindowManager->winGetWindowFromId(parent, buttonSortPingID);
  358. buttonSortBuddies = TheWindowManager->winGetWindowFromId(parent, buttonSortBuddiesID);
  359. windowSortAlpha = TheWindowManager->winGetWindowFromId(parent, windowSortAlphaID);
  360. windowSortPing = TheWindowManager->winGetWindowFromId(parent, windowSortPingID);
  361. windowSortBuddies = TheWindowManager->winGetWindowFromId(parent, windowSortBuddiesID);
  362. showSortIcons();
  363. }
  364. void ReleaseWindowInfo( void )
  365. {
  366. isSmall = TRUE;
  367. parent = NULL;
  368. // parentGameListSmall = NULL;
  369. parentGameListLarge = NULL;
  370. // listboxLobbyGamesSmall = NULL;
  371. listboxLobbyGamesLarge = NULL;
  372. // listboxLobbyGameInfo = NULL;
  373. buttonSortAlpha = NULL;
  374. buttonSortPing = NULL;
  375. buttonSortBuddies = NULL;
  376. windowSortAlpha = NULL;
  377. windowSortPing = NULL;
  378. windowSortBuddies = NULL;
  379. }
  380. typedef std::set<GameSpyStagingRoom *> BuddyGameSet;
  381. static BuddyGameSet *theBuddyGames = NULL;
  382. static void populateBuddyGames(void)
  383. {
  384. BuddyInfoMap *m = TheGameSpyInfo->getBuddyMap();
  385. theBuddyGames = NEW BuddyGameSet;
  386. if (!m)
  387. {
  388. return;
  389. }
  390. for (BuddyInfoMap::const_iterator bit = m->begin(); bit != m->end(); ++bit)
  391. {
  392. BuddyInfo info = bit->second;
  393. if (info.m_status == GP_STAGING)
  394. {
  395. StagingRoomMap *srm = TheGameSpyInfo->getStagingRoomList();
  396. for (StagingRoomMap::iterator srmIt = srm->begin(); srmIt != srm->end(); ++srmIt)
  397. {
  398. GameSpyStagingRoom *game = srmIt->second;
  399. game->cleanUpSlotPointers();
  400. const GameSpyGameSlot *slot = game->getGameSpySlot(0);
  401. if (slot && slot->getName() == info.m_locationString)
  402. {
  403. theBuddyGames->insert(game);
  404. break;
  405. }
  406. }
  407. }
  408. }
  409. }
  410. static void clearBuddyGames(void)
  411. {
  412. if (theBuddyGames)
  413. delete theBuddyGames;
  414. theBuddyGames = NULL;
  415. }
  416. struct GameSortStruct
  417. {
  418. bool operator()(GameSpyStagingRoom *g1, GameSpyStagingRoom *g2)
  419. {
  420. // sort CRC mismatches to the bottom
  421. Bool g1Good = (g1->getExeCRC() != TheGlobalData->m_exeCRC || g1->getIniCRC() != TheGlobalData->m_iniCRC);
  422. Bool g2Good = (g1->getExeCRC() != TheGlobalData->m_exeCRC || g1->getIniCRC() != TheGlobalData->m_iniCRC);
  423. if ( g1Good ^ g2Good )
  424. {
  425. return g1Good;
  426. }
  427. // sort games with private ladders to the bottom
  428. Bool g1UnknownLadder = (g1->getLadderPort() && TheLadderList->findLadder(g1->getLadderIP(), g1->getLadderPort()) == NULL);
  429. Bool g2UnknownLadder = (g2->getLadderPort() && TheLadderList->findLadder(g2->getLadderIP(), g2->getLadderPort()) == NULL);
  430. if ( g1UnknownLadder ^ g2UnknownLadder )
  431. {
  432. return g2UnknownLadder;
  433. }
  434. // sort full games to the bottom
  435. Bool g1Full = (g1->getNumNonObserverPlayers() == g1->getMaxPlayers() || g1->getNumPlayers() == MAX_SLOTS);
  436. Bool g2Full = (g2->getNumNonObserverPlayers() == g2->getMaxPlayers() || g2->getNumPlayers() == MAX_SLOTS);
  437. if ( g1Full ^ g2Full )
  438. {
  439. return g2Full;
  440. }
  441. if (sortBuddies)
  442. {
  443. Bool g1HasBuddies = (theBuddyGames->find(g1) != theBuddyGames->end());
  444. Bool g2HasBuddies = (theBuddyGames->find(g2) != theBuddyGames->end());
  445. if ( g1HasBuddies ^ g2HasBuddies )
  446. {
  447. return g1HasBuddies;
  448. }
  449. }
  450. switch(theGameSortType)
  451. {
  452. case GAMESORT_ALPHA_ASCENDING:
  453. return wcsicmp(g1->getGameName().str(), g2->getGameName().str()) < 0;
  454. break;
  455. case GAMESORT_ALPHA_DESCENDING:
  456. return wcsicmp(g1->getGameName().str(),g2->getGameName().str()) > 0;
  457. break;
  458. case GAMESORT_PING_ASCENDING:
  459. return g1->getPingAsInt() < g2->getPingAsInt();
  460. break;
  461. case GAMESORT_PING_DESCENDING:
  462. return g1->getPingAsInt() > g2->getPingAsInt();
  463. break;
  464. }
  465. return false;
  466. }
  467. };
  468. static Int insertGame( GameWindow *win, GameSpyStagingRoom *game, Bool showMap )
  469. {
  470. game->cleanUpSlotPointers();
  471. Color gameColor = GameSpyColor[GSCOLOR_GAME];
  472. if (game->getNumNonObserverPlayers() == game->getMaxPlayers() || game->getNumPlayers() == MAX_SLOTS)
  473. {
  474. gameColor = GameSpyColor[GSCOLOR_GAME_FULL];
  475. }
  476. if (game->getExeCRC() != TheGlobalData->m_exeCRC || game->getIniCRC() != TheGlobalData->m_iniCRC)
  477. {
  478. gameColor = GameSpyColor[GSCOLOR_GAME_CRCMISMATCH];
  479. }
  480. UnicodeString gameName = game->getGameName();
  481. if(TheGameSpyInfo->getDisallowAsianText())
  482. {
  483. const WideChar *buff = gameName.str();
  484. Int length = gameName.getLength();
  485. for(Int i = 0; i < length; ++i)
  486. {
  487. if(buff[i] >= 256)
  488. return -1;
  489. }
  490. }
  491. else if(TheGameSpyInfo->getDisallowNonAsianText())
  492. {
  493. const WideChar *buff = gameName.str();
  494. Int length = gameName.getLength();
  495. Bool hasUnicode = FALSE;
  496. for(Int i = 0; i < length; ++i)
  497. {
  498. if(buff[i] >= 256)
  499. {
  500. hasUnicode = TRUE;
  501. break;
  502. }
  503. }
  504. if(!hasUnicode)
  505. return -1;
  506. }
  507. Int index = GadgetListBoxAddEntryText(win, game->getGameName(), gameColor, -1, COLUMN_NAME);
  508. GadgetListBoxSetItemData(win, (void *)game->getID(), index);
  509. UnicodeString s;
  510. if (showMap)
  511. {
  512. UnicodeString mapName;
  513. const MapMetaData *md = TheMapCache->findMap(game->getMap());
  514. if (md)
  515. {
  516. mapName = md->m_displayName;
  517. }
  518. else
  519. {
  520. const char *start = game->getMap().reverseFind('\\');
  521. if (start)
  522. {
  523. ++start;
  524. }
  525. else
  526. {
  527. start = game->getMap().str();
  528. }
  529. mapName.translate( start );
  530. }
  531. GadgetListBoxAddEntryText(win, mapName, gameColor, index, COLUMN_MAP);
  532. const LadderInfo * li = TheLadderList->findLadder(game->getLadderIP(), game->getLadderPort());
  533. if (li)
  534. {
  535. GadgetListBoxAddEntryText(win, li->name, gameColor, index, COLUMN_LADDER);
  536. }
  537. else if (game->getLadderPort())
  538. {
  539. GadgetListBoxAddEntryText(win, TheGameText->fetch("GUI:UnknownLadder"), gameColor, index, COLUMN_LADDER);
  540. }
  541. else
  542. {
  543. GadgetListBoxAddEntryText(win, TheGameText->fetch("GUI:NoLadder"), gameColor, index, COLUMN_LADDER);
  544. }
  545. }
  546. else
  547. {
  548. GadgetListBoxAddEntryText(win, UnicodeString(L" "), gameColor, index, COLUMN_MAP);
  549. GadgetListBoxAddEntryText(win, UnicodeString(L" "), gameColor, index, COLUMN_LADDER);
  550. }
  551. s.format(L"%d/%d", game->getReportedNumPlayers(), game->getReportedMaxPlayers());
  552. GadgetListBoxAddEntryText(win, s, gameColor, index, COLUMN_NUMPLAYERS);
  553. if (game->getHasPassword())
  554. {
  555. const Image *img = TheMappedImageCollection->findImageByName("Password");
  556. Int width = 10, height = 10;
  557. if (img)
  558. {
  559. width = img->getImageWidth();
  560. height = img->getImageHeight();
  561. }
  562. GadgetListBoxAddEntryImage(win, img, index, COLUMN_PASSWORD, width, height);
  563. }
  564. else
  565. {
  566. GadgetListBoxAddEntryText(win, UnicodeString(L" "), gameColor, index, COLUMN_PASSWORD);
  567. }
  568. if (game->getAllowObservers())
  569. {
  570. const Image *img = TheMappedImageCollection->findImageByName("Observer");
  571. GadgetListBoxAddEntryImage(win, img, index, COLUMN_OBSERVER);
  572. }
  573. else
  574. {
  575. GadgetListBoxAddEntryText(win, UnicodeString(L" "), gameColor, index, COLUMN_OBSERVER);
  576. }
  577. s.format(L"%d", game->getPingAsInt());
  578. GadgetListBoxAddEntryText(win, s, gameColor, index, COLUMN_PING);
  579. Int ping = game->getPingAsInt();
  580. Int width = 10, height = 10;
  581. if (pingImages[0])
  582. {
  583. width = pingImages[0]->getImageWidth();
  584. height = pingImages[0]->getImageHeight();
  585. }
  586. // CLH picking an arbitrary number for our ping display
  587. if (ping < TheGameSpyConfig->getPingCutoffGood())
  588. {
  589. GadgetListBoxAddEntryImage(win, pingImages[0], index, COLUMN_PING, width, height);
  590. }
  591. else if (ping < TheGameSpyConfig->getPingCutoffBad())
  592. {
  593. GadgetListBoxAddEntryImage(win, pingImages[1], index, COLUMN_PING, width, height);
  594. }
  595. else
  596. {
  597. GadgetListBoxAddEntryImage(win, pingImages[2], index, COLUMN_PING, width, height);
  598. }
  599. return index;
  600. }
  601. void RefreshGameListBox( GameWindow *win, Bool showMap )
  602. {
  603. if (!win)
  604. return;
  605. // save off selection
  606. Int selectedIndex = -1;
  607. Int indexToSelect = -1;
  608. Int selectedID = 0;
  609. GadgetListBoxGetSelected(win, &selectedIndex);
  610. if (selectedIndex != -1 )
  611. {
  612. selectedID = (Int)GadgetListBoxGetItemData(win, selectedIndex);
  613. }
  614. int prevPos = GadgetListBoxGetTopVisibleEntry( win );
  615. // empty listbox
  616. GadgetListBoxReset(win);
  617. // sort our games
  618. typedef std::multiset<GameSpyStagingRoom *, GameSortStruct> SortedGameList;
  619. SortedGameList sgl;
  620. StagingRoomMap *srm = TheGameSpyInfo->getStagingRoomList();
  621. populateBuddyGames();
  622. for (StagingRoomMap::iterator srmIt = srm->begin(); srmIt != srm->end(); ++srmIt)
  623. {
  624. sgl.insert(srmIt->second);
  625. }
  626. // populate listbox
  627. for (SortedGameList::iterator sglIt = sgl.begin(); sglIt != sgl.end(); ++sglIt)
  628. {
  629. GameSpyStagingRoom *game = *sglIt;
  630. if (game)
  631. {
  632. Int index = insertGame(win, game, showMap);
  633. if (game->getID() == selectedID)
  634. {
  635. indexToSelect = index;
  636. }
  637. }
  638. }
  639. clearBuddyGames();
  640. // restore selection
  641. GadgetListBoxSetSelected(win, indexToSelect); // even for -1, so we can disable the 'Join Game' button
  642. // if(prevPos > 10)
  643. GadgetListBoxSetTopVisibleEntry( win, prevPos );//+ 1
  644. if (indexToSelect < 0 && selectedID)
  645. {
  646. TheWindowManager->winSetLoneWindow(NULL);
  647. }
  648. }
  649. void RefreshGameInfoListBox( GameWindow *mainWin, GameWindow *win )
  650. {
  651. // if (!mainWin || !win)
  652. // return;
  653. //
  654. // GadgetListBoxReset(win);
  655. //
  656. // Int selected = -1;
  657. // GadgetListBoxGetSelected(mainWin, &selected);
  658. // if (selected < 0)
  659. // {
  660. // return;
  661. // }
  662. //
  663. // Int selectedID = (Int)GadgetListBoxGetItemData(mainWin, selected);
  664. // if (selectedID < 0)
  665. // {
  666. // return;
  667. // }
  668. //
  669. // StagingRoomMap *srm = TheGameSpyInfo->getStagingRoomList();
  670. // StagingRoomMap::iterator srmIt = srm->find(selectedID);
  671. // if (srmIt != srm->end())
  672. // {
  673. // GameSpyStagingRoom *theRoom = srmIt->second;
  674. // theRoom->cleanUpSlotPointers();
  675. //
  676. // // game name
  677. //// GadgetListBoxAddEntryText(listboxLobbyGameInfo, theRoom->getGameName(), GameSpyColor[GSCOLOR_DEFAULT], -1);
  678. //
  679. // const LadderInfo * li = TheLadderList->findLadder(theRoom->getLadderIP(), theRoom->getLadderPort());
  680. // if (li)
  681. // {
  682. // UnicodeString tmp;
  683. // tmp.format(TheGameText->fetch("TOOLTIP:LadderName"), li->name.str());
  684. // GadgetListBoxAddEntryText(listboxLobbyGameInfo, tmp, GameSpyColor[GSCOLOR_DEFAULT], -1);
  685. // }
  686. // else if (theRoom->getLadderPort())
  687. // {
  688. // GadgetListBoxAddEntryText(listboxLobbyGameInfo, TheGameText->fetch("TOOLTIP:UnknownLadder"), GameSpyColor[GSCOLOR_DEFAULT], -1);
  689. // }
  690. // else
  691. // {
  692. // GadgetListBoxAddEntryText(listboxLobbyGameInfo, TheGameText->fetch("TOOLTIP:NoLadder"), GameSpyColor[GSCOLOR_DEFAULT], -1);
  693. // }
  694. //
  695. // if (theRoom->getExeCRC() != TheGlobalData->m_exeCRC || theRoom->getIniCRC() != TheGlobalData->m_iniCRC)
  696. // {
  697. // GadgetListBoxAddEntryText(listboxLobbyGameInfo, TheGameText->fetch("TOOLTIP:InvalidGameVersionSingleLine"), GameSpyColor[GSCOLOR_DEFAULT], -1);
  698. // }
  699. //
  700. // // map name
  701. // UnicodeString mapName;
  702. // const MapMetaData *md = TheMapCache->findMap(theRoom->getMap());
  703. // if (md)
  704. // {
  705. // mapName = md->m_displayName;
  706. // }
  707. // else
  708. // {
  709. // const char *start = theRoom->getMap().reverseFind('\\');
  710. // if (start)
  711. // {
  712. // ++start;
  713. // }
  714. // else
  715. // {
  716. // start = theRoom->getMap().str();
  717. // }
  718. // mapName.translate( start );
  719. // }
  720. //
  721. // GadgetListBoxAddEntryText(listboxLobbyGameInfo, mapName, GameSpyColor[GSCOLOR_DEFAULT], -1);
  722. //
  723. // // player list (rank, win/loss, side)
  724. // for (Int i=0; i<MAX_SLOTS; ++i)
  725. // {
  726. // const GameSpyGameSlot *slot = theRoom->getGameSpySlot(i);
  727. // if (slot && slot->isHuman())
  728. // {
  729. // UnicodeString theName, theRating, thePlayerTemplate;
  730. // Int colorIdx = slot->getColor();
  731. // theName = slot->getName();
  732. // theRating.format(L" (%d-%d)", slot->getWins(), slot->getLosses());
  733. // const PlayerTemplate * pt = ThePlayerTemplateStore->getNthPlayerTemplate(slot->getPlayerTemplate());
  734. // if (pt)
  735. // {
  736. // thePlayerTemplate = pt->getDisplayName();
  737. // }
  738. // else
  739. // {
  740. // thePlayerTemplate = TheGameText->fetch("GUI:Random");
  741. // }
  742. //
  743. // UnicodeString theText;
  744. // theText.format(L"%ls - %ls - %ls", theName.str(), thePlayerTemplate.str(), theRating.str());
  745. //
  746. // Int theColor = GameSpyColor[GSCOLOR_DEFAULT];
  747. // const MultiplayerColorDefinition *mcd = TheMultiplayerSettings->getColor(colorIdx);
  748. // if (mcd)
  749. // {
  750. // theColor = mcd->getColor();
  751. // }
  752. //
  753. // GadgetListBoxAddEntryText(listboxLobbyGameInfo, theText, theColor, -1);
  754. // }
  755. // }
  756. // }
  757. }
  758. void RefreshGameListBoxes( void )
  759. {
  760. GameWindow *main = GetGameListBox();
  761. GameWindow *info = GetGameInfoListBox();
  762. RefreshGameListBox( main, (info == NULL) );
  763. if (info)
  764. {
  765. RefreshGameInfoListBox( main, info );
  766. }
  767. }
  768. void ToggleGameListType( void )
  769. {
  770. isSmall = !isSmall;
  771. if(isSmall)
  772. {
  773. parentGameListLarge->winHide(TRUE);
  774. // parentGameListSmall->winHide(FALSE);
  775. }
  776. else
  777. {
  778. parentGameListLarge->winHide(FALSE);
  779. // parentGameListSmall->winHide(TRUE);
  780. }
  781. RefreshGameListBoxes();
  782. }