dlgmpwolgamelist.cpp 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516
  1. /*
  2. ** Command & Conquer Renegade(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. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Combat *
  23. * *
  24. * $Archive:: /Commando/Code/Commando/dlgmpwolgamelist.cpp $*
  25. * *
  26. * Author:: Patrick Smith *
  27. * *
  28. * $Modtime:: 11/24/02 4:52p $*
  29. * *
  30. * $Revision:: 76 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "DlgMPWOLGameList.h"
  36. #include "specialbuilds.h"
  37. #include "cNetwork.h"
  38. #include "BandwidthCheck.h"
  39. #include "UserOptions.h"
  40. #include "GameInitMgr.h"
  41. #include "DlgMPWOLPageBuddy.h"
  42. #include "DlgMessageBox.h"
  43. #include "DlgPasswordPrompt.h"
  44. #include <Combat\PlayerType.h>
  45. #include "WOLJoinGame.h"
  46. #include "WOLLogonMgr.h"
  47. #include <WWOnline\WOLServer.h>
  48. #include <WWOnline\WOLChannel.h>
  49. #include <WWUI\DialogMgr.h>
  50. #include <WWUI\ShortcutBarCtrl.h>
  51. #include <WWUI\ButtonCtrl.h>
  52. #include <WWUI\CheckBoxCtrl.h>
  53. #include <WWUI\ListCtrl.h>
  54. #include "String_IDs.h"
  55. #include <WWTranslateDB\TranslateDB.h>
  56. #include "dlgmplanhostoptions.h"
  57. #include "debug.h"
  58. #include "init.h"
  59. using namespace WWOnline;
  60. // Game List columns
  61. static enum
  62. {
  63. COL_ICON = 0,
  64. COL_HOST_NAME,
  65. COL_GAME_TITLE,
  66. COL_GAME_MAP,
  67. COL_PLAYERS,
  68. COL_PING
  69. };
  70. #define CLAN_ENTRY_MARKER 0x0C1A0C1A
  71. #define PING_GREEN_THRESHOLD 655
  72. #define PING_YELLOW_THRESHOLD 2621
  73. // Sorting flags for game attributes
  74. #define FLAGSORT_DEDICATED 0x01
  75. #define FLAGSORT_LADDERED 0x02
  76. #define FLAGSORT_PASSWORDED 0x04
  77. #define FLAGSORT_CLAN 0x08
  78. static void SetGameTypeFlags(ListCtrlClass* list, int itemIndex, const WOLGameInfo& gameInfo);
  79. static void SetPingTimeIcon(ListCtrlClass* list, int itemIndex, long pingTime);
  80. static int CALLBACK FlagsSortCallback(ListCtrlClass* list, int item1, int item2, uint32 param);
  81. static int CALLBACK NumericSortCallback(ListCtrlClass* list, int item1, int item2, uint32 param);
  82. static int CALLBACK AlphaSortCallback(ListCtrlClass* list, int index1, int index2, uint32 param);
  83. MPWolGameListMenuClass* MPWolGameListMenuClass::_mInstance = NULL;
  84. /******************************************************************************
  85. *
  86. * NAME
  87. * MPWolGameListMenuClass::DoDialog
  88. *
  89. * DESCRIPTION
  90. * Display the Westwood Online advanced game listings dialog.
  91. *
  92. * INPUTS
  93. * NONE
  94. *
  95. * RESULT
  96. * NONE
  97. *
  98. ******************************************************************************/
  99. void MPWolGameListMenuClass::DoDialog(void)
  100. {
  101. // Create the dialog if necessary, otherwise simply bring it to the front
  102. if (_mInstance == NULL)
  103. {
  104. MPWolGameListMenuClass* dialog = new MPWolGameListMenuClass;
  105. WWASSERT(dialog != NULL && "Failed to create WOL GameList dialog");
  106. if (dialog)
  107. {
  108. dialog->Start_Dialog();
  109. dialog->Release_Ref();
  110. }
  111. }
  112. else
  113. {
  114. if (_mInstance->Is_Active_Menu() == false)
  115. {
  116. DialogMgrClass::Rollback(_mInstance);
  117. }
  118. }
  119. }
  120. /******************************************************************************
  121. *
  122. * NAME
  123. * MPWolGameListMenuClass::MPWolGameListMenuClass
  124. *
  125. * DESCRIPTION
  126. * Constructor
  127. *
  128. * INPUTS
  129. * NONE
  130. *
  131. * RESULT
  132. * NONE
  133. *
  134. ******************************************************************************/
  135. MPWolGameListMenuClass::MPWolGameListMenuClass(void) :
  136. MenuDialogClass(IDD_MP_WOL_GAME_LIST),
  137. mChannelListPending(false),
  138. mSortColumn(COL_HOST_NAME),
  139. mIsSortAscending(true),
  140. mSortFlags(0)
  141. {
  142. WWDEBUG_SAY(("MPWolGameListMenuClass Instantiated\n"));
  143. WWASSERT(_mInstance == NULL);
  144. _mInstance = this;
  145. mWOLSession = Session::GetInstance(false);
  146. WWASSERT_PRINT(mWOLSession.IsValid(), "WOLSession not instantiated!");
  147. }
  148. /******************************************************************************
  149. *
  150. * NAME
  151. * MPWolGameListMenuClass::~MPWolGameListMenuClass
  152. *
  153. * DESCRIPTION
  154. * Destructor
  155. *
  156. * INPUTS
  157. * NONE
  158. *
  159. * RESULT
  160. * NONE
  161. *
  162. ******************************************************************************/
  163. MPWolGameListMenuClass::~MPWolGameListMenuClass(void)
  164. {
  165. WWDEBUG_SAY(("MPWolGameListMenuClass Destroyed\n"));
  166. _mInstance = NULL;
  167. }
  168. /******************************************************************************
  169. *
  170. * NAME
  171. * MPWolGameListMenuClass::On_Init_Dialog
  172. *
  173. * DESCRIPTION
  174. * One time dialog initialization
  175. *
  176. * INPUTS
  177. * NONE
  178. *
  179. * RESULT
  180. * NONE
  181. *
  182. ******************************************************************************/
  183. void MPWolGameListMenuClass::On_Init_Dialog(void)
  184. {
  185. #ifdef FREEDEDICATEDSERVER
  186. Enable_Dlg_Item(IDC_JOIN_GAME_BUTTON, false);
  187. #endif // FREEDEDICATEDSERVER
  188. //---------------------------------------------------------------------------
  189. // Configure the shortcut bar
  190. //---------------------------------------------------------------------------
  191. ShortcutBarCtrlClass* bar = (ShortcutBarCtrlClass*)Get_Dlg_Item(IDC_SHORTCUT_BAR);
  192. if (bar)
  193. {
  194. bar->Add_Button(IDC_MP_SHORTCUT_CHAT, TRANSLATE(IDS_MP_SHORTCUT_CHAT));
  195. bar->Add_Button(IDC_MP_SHORTCUT_BUDDIES, TRANSLATE(IDS_MP_SHORTCUT_BUDDIES));
  196. bar->Add_Button(IDC_MP_SHORTCUT_INTERNET_OPTIONS, TRANSLATE(IDS_INTERNET_OPTIONS));
  197. bar->Add_Button(IDC_MP_SHORTCUT_NEWS, TRANSLATE(IDS_MP_SHORTCUT_NEWS));
  198. bar->Add_Button(IDC_MP_SHORTCUT_CLANS, TRANSLATE(IDS_MP_SHORTCUT_CLANS));
  199. bar->Add_Button(IDC_MP_SHORTCUT_RANKINGS, TRANSLATE(IDS_MP_SHORTCUT_RANKINGS));
  200. bar->Add_Button(IDC_MP_SHORTCUT_NET_STATUS, TRANSLATE(IDS_MP_SHORTCUT_NET_STATUS));
  201. }
  202. //---------------------------------------------------------------------------
  203. // Show the current login and server
  204. //---------------------------------------------------------------------------
  205. WideStringClass serverName(64, true);
  206. WOLLogonMgr::GetServerName(serverName);
  207. WideStringClass string(128, true);
  208. string.Format(TRANSLATE (IDS_MENU_CONNECTED_TO_FORMAT), serverName);
  209. Set_Dlg_Item_Text(IDC_SERVERNAME, string);
  210. WideStringClass loginName(64, true);
  211. WOLLogonMgr::GetLoginName(loginName);
  212. string.Format(TRANSLATE (IDS_MENU_LOGIN_NAME_FORMAT), loginName);
  213. Set_Dlg_Item_Text(IDC_LOGINNAME, string);
  214. WideStringClass conn(BandwidthCheckerClass::Get_Bandwidth_As_String(), true);
  215. string.Format(TRANSLATE (IDS_MENU_SPEED_FORMAT), conn);
  216. Set_Dlg_Item_Text(IDC_CONNECTIONSPEED, string);
  217. //---------------------------------------------------------------------------
  218. // Configure sorting buttons
  219. //---------------------------------------------------------------------------
  220. ButtonCtrlClass* button = (ButtonCtrlClass*)Get_Dlg_Item(IDC_SORT_DEDICATED_BUTTON);
  221. if (button)
  222. {
  223. button->Set_Bitmap("mul_spec.tga", "mul_nopts.tga");
  224. button->Set_Tooltip_Text(TRANSLATE (IDS_MENU_TOOLTIP_SORT_01));
  225. }
  226. button = (ButtonCtrlClass*)Get_Dlg_Item(IDC_SORT_PASSWORD_BUTTON);
  227. if (button)
  228. {
  229. button->Set_Bitmap("mul_pswrd.tga", "mul_nopts.tga");
  230. button->Set_Tooltip_Text(TRANSLATE (IDS_MENU_TOOLTIP_SORT_02));
  231. }
  232. button = (ButtonCtrlClass*)Get_Dlg_Item(IDC_SORT_LADDERED_BUTTON);
  233. if (button)
  234. {
  235. button->Set_Bitmap("mul_pts.tga", "mul_nopts.tga");
  236. button->Set_Tooltip_Text(TRANSLATE (IDS_MENU_TOOLTIP_SORT_03));
  237. }
  238. button = (ButtonCtrlClass*)Get_Dlg_Item(IDC_SORT_CLAN_BUTTON);
  239. if (button)
  240. {
  241. button->Set_Bitmap("mul_btlcln.tga", "mul_nopts.tga");
  242. button->Set_Tooltip_Text(TRANSLATE (IDS_MENU_TOOLTIP_SORT_04));
  243. }
  244. //---------------------------------------------------------------------------
  245. // Configure game listing control
  246. //---------------------------------------------------------------------------
  247. ListCtrlClass* list_ctrl = (ListCtrlClass*)Get_Dlg_Item(IDC_GAME_LIST_CTRL);
  248. if (list_ctrl)
  249. {
  250. Vector3 color(1,1,1);
  251. list_ctrl->Add_Column(TRANSLATE(IDS_MP_GAME_LIST_HEADER_ICON), 0.1F, color);
  252. list_ctrl->Add_Column(TRANSLATE(IDS_MP_GAME_LIST_HEADER_HOST_NAME), 0.175F, color);
  253. list_ctrl->Add_Column(TRANSLATE(IDS_MP_GAME_LIST_HEADER_GAME_NAME), 0.325F, color);
  254. list_ctrl->Add_Column(TRANSLATE(IDS_MP_GAME_LIST_HEADER_GAME_MAP), 0.2F, color);
  255. list_ctrl->Add_Column(TRANSLATE(IDS_MP_GAME_LIST_HEADER_PLAYERS), 0.1F, color);
  256. list_ctrl->Add_Column(TRANSLATE(IDS_MP_GAME_LIST_HEADER_PING), 0.1F, color);
  257. list_ctrl->Allow_NoSelection(true);
  258. Observer<ChannelListEvent>::NotifyMe(*mWOLSession);
  259. Observer<ServerError>::NotifyMe(*mWOLSession);
  260. Observer<SquadEvent>::NotifyMe(*mWOLSession);
  261. RequestGameList();
  262. }
  263. //---------------------------------------------------------------------------
  264. // Configure game details list control
  265. //---------------------------------------------------------------------------
  266. list_ctrl = (ListCtrlClass*)Get_Dlg_Item(IDC_DETAILS_LIST);
  267. if (list_ctrl)
  268. {
  269. list_ctrl->Allow_Selection(false);
  270. list_ctrl->Set_Tabstop(20.0f);
  271. }
  272. MenuDialogClass::On_Init_Dialog();
  273. }
  274. /******************************************************************************
  275. *
  276. * NAME
  277. * MPWolGameListMenuClass::On_Command
  278. *
  279. * DESCRIPTION
  280. * Respond to command messages from UI controls
  281. *
  282. * INPUTS
  283. * ID - ID of control originating the message
  284. * Msg - Message identifier
  285. * Param - Message specific parameter
  286. *
  287. * RESULT
  288. * NONE
  289. *
  290. ******************************************************************************/
  291. void MPWolGameListMenuClass::On_Command(int id, int msg, DWORD param)
  292. {
  293. switch (id)
  294. {
  295. case IDC_PAGE_BUDDY_BUTTON:
  296. START_DIALOG(MPWolPageBuddyPopupClass);
  297. break;
  298. case IDC_REFRESH_GAME_LIST:
  299. RequestGameList();
  300. break;
  301. case IDC_SORT_DEDICATED_BUTTON:
  302. SortGameChannels(COL_ICON, true, FLAGSORT_DEDICATED);
  303. break;
  304. case IDC_SORT_PASSWORD_BUTTON:
  305. SortGameChannels(COL_ICON, true, FLAGSORT_PASSWORDED);
  306. break;
  307. case IDC_SORT_LADDERED_BUTTON:
  308. SortGameChannels(COL_ICON, true, FLAGSORT_LADDERED);
  309. break;
  310. case IDC_SORT_CLAN_BUTTON:
  311. SortGameChannels(COL_ICON, true, FLAGSORT_CLAN);
  312. break;
  313. case IDC_JOIN_GAME_BUTTON:
  314. Join_Game();
  315. break;
  316. case IDC_MENU_MP_LAN_HOST_BUTTON:
  317. // Return to the game list on exit
  318. GameInitMgrClass::Set_WOL_Return_Dialog(RenegadeDialogMgrClass::LOC_INTERNET_GAME_LIST);
  319. // Create the new game data
  320. if ( PTheGameData != NULL ) {
  321. delete PTheGameData;
  322. PTheGameData = NULL;
  323. }
  324. PTheGameData = cGameData::Create_Game_Of_Type(cGameData::GAME_TYPE_CNC);
  325. WWASSERT(PTheGameData != NULL);
  326. // WOL games default as quickmatch servers
  327. The_Game()->Set_QuickMatch_Server(true);
  328. // Load server preferences.
  329. The_Game()->Load_From_Server_Config();
  330. // Move to the next menu
  331. DialogBaseClass* dialog = new MPLanHostOptionsMenuClass;
  332. dialog->Start_Dialog();
  333. REF_PTR_RELEASE(dialog);
  334. break;
  335. }
  336. MenuDialogClass::On_Command(id, msg, param);
  337. }
  338. /******************************************************************************
  339. *
  340. * NAME
  341. * MPWolGameListMenuClass::On_Key_Down
  342. *
  343. * DESCRIPTION
  344. *
  345. * INPUTS
  346. *
  347. * RESULT
  348. *
  349. ******************************************************************************/
  350. bool MPWolGameListMenuClass::On_Key_Down(uint32 key_id, uint32 key_data)
  351. {
  352. if (VK_F5 == key_id)
  353. {
  354. RequestGameList();
  355. return true;
  356. }
  357. return MenuDialogClass::On_Key_Down(key_id, key_data);
  358. }
  359. /******************************************************************************
  360. *
  361. * NAME
  362. * MPWolGameListMenuClass::Join_Game
  363. *
  364. * DESCRIPTION
  365. * Join the currently selected game
  366. *
  367. * INPUTS
  368. * NONE
  369. *
  370. * RESULT
  371. * NONE
  372. *
  373. ******************************************************************************/
  374. void MPWolGameListMenuClass::Join_Game(void)
  375. {
  376. ListCtrlClass* list = (ListCtrlClass*)Get_Dlg_Item(IDC_GAME_LIST_CTRL);
  377. if (list)
  378. {
  379. // Get the currently selected index
  380. int index = list->Get_Curr_Sel();
  381. if (index >= 0)
  382. {
  383. RefPtr<ChannelData> channel = (ChannelData*)list->Get_Entry_Data(index, COL_HOST_NAME);
  384. // If the channel is invalid then do not proceed
  385. if (!channel.IsValid())
  386. {
  387. return;
  388. }
  389. WOLGameInfo selectedGame(channel);
  390. // If the channel data is invalid then do not proceed
  391. if (!selectedGame.IsDataValid())
  392. {
  393. return;
  394. }
  395. // If the user cannot join this game then do not proceed.
  396. if (!selectedGame.CanUserJoin(mWOLSession->GetCurrentUser()))
  397. {
  398. return;
  399. }
  400. // Return to the game list on exit
  401. GameInitMgrClass::Set_WOL_Return_Dialog(RenegadeDialogMgrClass::LOC_INTERNET_GAME_LIST);
  402. // If the game to join is passworded then it is necessary for the user to
  403. // supply the correct password. Therefore prompt the user to enter the
  404. // password. We will attempt to connect to the game when we receive a
  405. // signal from the dialog that the user has entered a password.
  406. if (channel->IsPassworded())
  407. {
  408. mGameToJoin = channel;
  409. DlgPasswordPrompt::DoDialog(this);
  410. }
  411. else
  412. {
  413. // No password require
  414. WOLJoinGame::JoinTheGame(channel->GetName(), L"", true);
  415. }
  416. }
  417. }
  418. }
  419. /******************************************************************************
  420. *
  421. * NAME
  422. * MPWolGameListMenuClass::ReceiveSignal
  423. *
  424. * DESCRIPTION
  425. * Handle receipt of password entered signal from the password prompt dialog.
  426. *
  427. * INPUTS
  428. * Signal - Signal that the user has entered a password.
  429. *
  430. * RESULT
  431. * NONE
  432. *
  433. ******************************************************************************/
  434. void MPWolGameListMenuClass::ReceiveSignal(DlgPasswordPrompt& passwordDialog)
  435. {
  436. if (mGameToJoin.IsValid())
  437. {
  438. WOLJoinGame::JoinTheGame(mGameToJoin->GetName(), passwordDialog.GetPassword(), true);
  439. mGameToJoin.Release();
  440. }
  441. }
  442. /******************************************************************************
  443. *
  444. * NAME
  445. * MPWolGameListMenuClass::RequestGameList
  446. *
  447. * DESCRIPTION
  448. * Submit a request for an updated game list.
  449. *
  450. * INPUTS
  451. * NONE
  452. *
  453. * RESULT
  454. * NONE
  455. *
  456. ******************************************************************************/
  457. void MPWolGameListMenuClass::RequestGameList(void)
  458. {
  459. if (mChannelListPending == false)
  460. {
  461. if (mWOLSession->RequestGameChannelList())
  462. {
  463. mChannelListPending = true;
  464. Enable_Dlg_Item(IDC_REFRESH_GAME_LIST, false);
  465. ListCtrlClass* list = (ListCtrlClass*)Get_Dlg_Item(IDC_DETAILS_LIST);
  466. if (list)
  467. {
  468. list->Delete_All_Entries();
  469. list->Add_Column(L"", 1.0F, Vector3(1, 1, 1));
  470. list->Insert_Entry(0, TRANSLATE (IDS_MENU_REQUESTING_NEW_CHANNELS));
  471. }
  472. }
  473. }
  474. }
  475. /******************************************************************************
  476. *
  477. * NAME
  478. * MPWolGameListMenuClass::UpdateChannels
  479. *
  480. * DESCRIPTION
  481. * Update the list of game channels.
  482. *
  483. * INPUTS
  484. * List - List control to view channels.
  485. * Channels - List of channels
  486. *
  487. * RESULT
  488. * True if the list changed.
  489. *
  490. ******************************************************************************/
  491. void MPWolGameListMenuClass::UpdateChannels(ListCtrlClass* list, const ChannelList& chanList)
  492. {
  493. // Get current selection so we can reselect it.
  494. WideStringClass selectedGameName(64, true);
  495. int selIndex = list->Get_Curr_Sel();
  496. if (selIndex >= 0)
  497. {
  498. selectedGameName = list->Get_Entry_Text(selIndex, COL_HOST_NAME);
  499. }
  500. selIndex = -1;
  501. int listIndex = list->Get_Entry_Count();
  502. ChannelList::const_iterator chanIter = chanList.begin();
  503. while (chanIter != chanList.end())
  504. {
  505. RefPtr<ChannelData> channel = (*chanIter);
  506. if (channel.IsValid())
  507. {
  508. WOLGameInfo gameInfo(channel);
  509. // Only show the channel if it is a valid game channel
  510. if (gameInfo.IsDataValid())
  511. {
  512. bool newlyAdded = false;
  513. // Check if the channel entry is already in the listbox.
  514. int itemIndex = list->Find_Entry(COL_HOST_NAME, channel->GetName());
  515. // If the channel was not found then add it now.
  516. if (itemIndex == -1)
  517. {
  518. itemIndex = list->Insert_Entry(listIndex, L"");
  519. newlyAdded = true;
  520. }
  521. // Update the channel in the listbox
  522. if (itemIndex >= 0)
  523. {
  524. // Associate the channel data inside with the entry
  525. if (newlyAdded)
  526. {
  527. ChannelData* rawChannel = channel.ReferencedObject();
  528. rawChannel->AddReference();
  529. list->Set_Entry_Data(itemIndex, COL_HOST_NAME, (unsigned long)rawChannel);
  530. // Show the game channel name
  531. list->Set_Entry_Text(itemIndex, COL_HOST_NAME, channel->GetName());
  532. }
  533. WideStringClass title(0, true);
  534. title.Convert_From(gameInfo.Title());
  535. list->Set_Entry_Text(itemIndex, COL_GAME_TITLE, title);
  536. // Show the game type icons
  537. SetGameTypeFlags(list, itemIndex, gameInfo);
  538. // Show the map name
  539. WideStringClass mapName(64, true);
  540. //
  541. // If this is a mod'd game, then display the mod_name\map_name...
  542. //
  543. if (gameInfo.ModName() != NULL && gameInfo.ModName()[0] != 0) {
  544. //
  545. // Strip off the extension for both the map and the mod package
  546. //
  547. char map_name[_MAX_FNAME] = { 0 };
  548. char mod_name[_MAX_FNAME] = { 0 };
  549. ::_splitpath (gameInfo.MapName(), NULL, NULL, map_name, NULL);
  550. ::_splitpath (gameInfo.ModName(), NULL, NULL, mod_name, NULL);
  551. //
  552. // Create the map name from the aggregate of the mod and map
  553. //
  554. StringClass ascii_map_name;
  555. ascii_map_name.Format ("%s\\%s", mod_name, map_name);
  556. mapName.Convert_From (ascii_map_name);
  557. } else {
  558. mapName = gameInfo.MapName();
  559. }
  560. list->Set_Entry_Text(itemIndex, COL_GAME_MAP, mapName);
  561. // Show the number of current / max players
  562. list->Set_Entry_Data(itemIndex, COL_PLAYERS, MAKELONG(gameInfo.NumPlayers(), gameInfo.MaxPlayers()));
  563. WideStringClass playersString(64, true);
  564. playersString.Format(L"%u/%u", gameInfo.NumPlayers(), gameInfo.MaxPlayers());
  565. list->Set_Entry_Text(itemIndex, COL_PLAYERS, playersString);
  566. // Show the ping time ranking
  567. SetPingTimeIcon(list, itemIndex, gameInfo.PingTime());
  568. if ((selIndex == -1) && (selectedGameName.Compare_No_Case(channel->GetName()) == 0))
  569. {
  570. selIndex = itemIndex;
  571. }
  572. if (gameInfo.Version() != (unsigned long)cNetwork::Get_Exe_Key() || !gameInfo.IsMapValid())
  573. {
  574. ChannelData* rawChannel = (ChannelData*)list->Get_Entry_Data(itemIndex, COL_HOST_NAME);
  575. if (rawChannel)
  576. {
  577. rawChannel->ReleaseReference();
  578. }
  579. list->Set_Entry_Data(itemIndex, COL_HOST_NAME, 0);
  580. if (gameInfo.IsMapValid()) {
  581. list->Set_Entry_Text(itemIndex, COL_GAME_TITLE, TRANSLATE(IDS_MENU_VERSION_MISMATCH));
  582. }
  583. /*
  584. WideStringClass diagnostic;
  585. diagnostic.Format(L"Version Mismatch (v. %u.%u)",
  586. HIWORD(gameInfo.Version()), LOWORD(gameInfo.Version()));
  587. list->Set_Entry_Text(itemIndex, COL_GAME_TITLE, diagnostic);
  588. */
  589. Vector3 grey(0.5F, 0.5F, 0.5F);
  590. list->Set_Entry_Color(itemIndex, COL_ICON, grey);
  591. list->Set_Entry_Color(itemIndex, COL_HOST_NAME, grey);
  592. list->Set_Entry_Color(itemIndex, COL_GAME_TITLE, grey);
  593. list->Set_Entry_Color(itemIndex, COL_GAME_MAP, grey);
  594. list->Set_Entry_Color(itemIndex, COL_PLAYERS, grey);
  595. list->Set_Entry_Color(itemIndex, COL_PING, grey);
  596. list->Set_Entry_Data(itemIndex, 0, 0);
  597. }
  598. }
  599. }
  600. ++listIndex;
  601. }
  602. ++chanIter;
  603. }
  604. // Select the previously selected entry
  605. if ((selIndex != -1) && (list->Get_Entry_Count() > 0))
  606. {
  607. list->Set_Curr_Sel(selIndex);
  608. }
  609. }
  610. /******************************************************************************
  611. *
  612. * NAME
  613. * MPWolGameListMenuClass::HandleNotification(ChannelListEvent)
  614. *
  615. * DESCRIPTION
  616. * Process the receipt of a game channel list.
  617. *
  618. * INPUTS
  619. * Channels - List of channels
  620. *
  621. * RESULT
  622. * NONE
  623. *
  624. ******************************************************************************/
  625. void MPWolGameListMenuClass::HandleNotification(ChannelListEvent& event)
  626. {
  627. // Ignore chat channels
  628. if (event.GetChannelType() == 0)
  629. {
  630. return;
  631. }
  632. // Update the channel listbox
  633. ListCtrlClass* list = (ListCtrlClass*)Get_Dlg_Item(IDC_GAME_LIST_CTRL);
  634. if (list)
  635. {
  636. bool sort = false;
  637. switch (event.GetEvent())
  638. {
  639. default:
  640. case ChannelListEvent::Error:
  641. case ChannelListEvent::NewList:
  642. {
  643. ChannelList& chanList = event.Subject();
  644. bool listEmpty = chanList.empty();
  645. ListCtrlClass* details = (ListCtrlClass*)Get_Dlg_Item(IDC_DETAILS_LIST);
  646. if (details)
  647. {
  648. details->Delete_All_Entries();
  649. if (listEmpty)
  650. {
  651. details->Insert_Entry(0, TRANSLATE(IDS_MENU_NO_GAME_SERVERS_FOUND));
  652. }
  653. }
  654. Enable_Dlg_Item(IDC_JOIN_GAME_BUTTON, !listEmpty);
  655. Enable_Dlg_Item(IDC_REFRESH_GAME_LIST, true);
  656. mChannelListPending = false;
  657. }
  658. break;
  659. case ChannelListEvent::Update:
  660. UpdateChannels(list, event.Subject());
  661. sort = true;
  662. break;
  663. case ChannelListEvent::Remove:
  664. {
  665. ChannelList& chanList = event.Subject();
  666. ChannelList::iterator chanIter = chanList.begin();
  667. while (chanIter != chanList.end())
  668. {
  669. RefPtr<ChannelData> channel = (*chanIter);
  670. int index = list->Find_Entry(COL_HOST_NAME, channel->GetName());
  671. if (index >= 0)
  672. {
  673. list->Delete_Entry(index);
  674. sort = true;
  675. }
  676. ++chanIter;
  677. }
  678. }
  679. break;
  680. }
  681. if (sort)
  682. {
  683. SortGameChannels(mSortColumn, mIsSortAscending, mSortFlags);
  684. }
  685. }
  686. }
  687. /******************************************************************************
  688. *
  689. * NAME
  690. * MPWolGameListMenuClass::On_ListCtrl_Delete_Entry
  691. *
  692. * DESCRIPTION
  693. * Handle the deletion of a listbox entry
  694. *
  695. * INPUTS
  696. * List - Pointer to list control originating notification.
  697. * ID - Identifier of list control originating notification.
  698. * Index - Index of entry being deleted
  699. *
  700. * RESULT
  701. * NONE
  702. *
  703. ******************************************************************************/
  704. void MPWolGameListMenuClass::On_ListCtrl_Delete_Entry(ListCtrlClass* list, int id, int index)
  705. {
  706. if (IDC_GAME_LIST_CTRL == id)
  707. {
  708. ChannelData* rawChannel = (ChannelData*)list->Get_Entry_Data(index, COL_HOST_NAME);
  709. if (rawChannel)
  710. {
  711. rawChannel->ReleaseReference();
  712. }
  713. }
  714. }
  715. /******************************************************************************
  716. *
  717. * NAME
  718. * MPWolGameListMenuClass::On_ListCtrl_Sel_Change
  719. *
  720. * DESCRIPTION
  721. * Handle user selecting a game entry.
  722. *
  723. * INPUTS
  724. * List - Pointer to list control originating notification.
  725. * ID - Identifier of list control originating notification.
  726. * OldSel - Index of previous selection
  727. * NewSel - Index of new selection
  728. *
  729. * RESULT
  730. * NONE
  731. *
  732. ******************************************************************************/
  733. void MPWolGameListMenuClass::On_ListCtrl_Sel_Change(ListCtrlClass* list, int id, int oldIndex, int newIndex)
  734. {
  735. if (IDC_GAME_LIST_CTRL == id)
  736. {
  737. Enable_Dlg_Item(IDC_JOIN_GAME_BUTTON, false);
  738. mSelectedGame.Reset();
  739. // Clear any detailed game information.
  740. ListCtrlClass* detailsList = (ListCtrlClass*)Get_Dlg_Item(IDC_DETAILS_LIST);
  741. detailsList->Delete_All_Entries();
  742. if (newIndex >= 0)
  743. {
  744. RefPtr<ChannelData> channel = (ChannelData*)list->Get_Entry_Data(newIndex, COL_HOST_NAME);
  745. if (channel.IsValid())
  746. {
  747. mSelectedGame.ImportFromChannel(channel);
  748. if (mSelectedGame.IsDataValid())
  749. {
  750. WideStringClass text(255, true);
  751. // Show host name and exe version
  752. // Denzil 02/14/02 The version encoded in the channel is NOT the printable version.
  753. // Just show the EXE version until we can work this out.
  754. #if(0)
  755. text.Format(TRANSLATE(IDS_MENU_HOST_INFO_FORMAT), (const WCHAR*)channel->GetName(),
  756. mSelectedGame.Title(), HIWORD(mSelectedGame.Version()), LOWORD(mSelectedGame.Version()));
  757. #else
  758. unsigned long verMajor = 0;
  759. unsigned long verMinor = 0;
  760. Get_Version_Number(&verMajor,&verMinor);
  761. text.Format(TRANSLATE(IDS_MENU_HOST_INFO_FORMAT), (const WCHAR*)channel->GetName(),
  762. mSelectedGame.Title(), HIWORD(verMajor), LOWORD(verMajor));
  763. #endif
  764. detailsList->Insert_Entry(0, text);
  765. // If this is a clan game then show the opposing clans
  766. if (mSelectedGame.IsClanGame()) {
  767. GetClanVSClanString(mSelectedGame, text);
  768. int entryIndex = detailsList->Insert_Entry(detailsList->Get_Entry_Count(), text);
  769. detailsList->Set_Entry_Data(entryIndex, 0, CLAN_ENTRY_MARKER);
  770. }
  771. // Show server settings
  772. text.Format(TRANSLATE(IDS_MENU_HOST_OPTIONS_INFO_FORMAT),
  773. mSelectedGame.IsDedicated() ? TRANSLATE(IDS_MENU_TEXT463) : TRANSLATE(IDS_MENU_TEXT464),
  774. mSelectedGame.IsPassworded() ? TRANSLATE(IDS_MENU_TEXT463) : TRANSLATE(IDS_MENU_TEXT464),
  775. mSelectedGame.IsLaddered() ? TRANSLATE(IDS_MENU_TEXT463) : TRANSLATE(IDS_MENU_TEXT464),
  776. mSelectedGame.IsQuickmatch() ? TRANSLATE(IDS_MENU_TEXT463) : TRANSLATE(IDS_MENU_TEXT464));
  777. detailsList->Insert_Entry(detailsList->Get_Entry_Count(), text);
  778. text.Format(TRANSLATE(IDS_MENU_HOST_OPTIONS_INFO2_FORMAT),
  779. mSelectedGame.IsClanGame() ? TRANSLATE (IDS_MENU_ON) : TRANSLATE(IDS_MENU_OFF),
  780. mSelectedGame.IsTeamChange() ? TRANSLATE (IDS_MENU_ON) : TRANSLATE(IDS_MENU_OFF),
  781. mSelectedGame.IsTeamRemix() ? TRANSLATE (IDS_MENU_ON) : TRANSLATE(IDS_MENU_OFF),
  782. mSelectedGame.IsFriendlyFire() ? TRANSLATE (IDS_MENU_ON) : TRANSLATE(IDS_MENU_OFF));
  783. detailsList->Insert_Entry(detailsList->Get_Entry_Count(), text);
  784. text.Format(TRANSLATE(IDS_MENU_HOST_OPTIONS_INFO3_FORMAT),
  785. mSelectedGame.IsDriverGunner() ? TRANSLATE(IDS_MENU_ON) : TRANSLATE(IDS_MENU_OFF),
  786. mSelectedGame.IsSpawnWeapons() ? TRANSLATE(IDS_MENU_ON) : TRANSLATE(IDS_MENU_OFF),
  787. mSelectedGame.IsRepairBuildings() ? TRANSLATE(IDS_MENU_ON) : TRANSLATE(IDS_MENU_OFF));
  788. detailsList->Insert_Entry(detailsList->Get_Entry_Count(), text);
  789. }
  790. bool canJoin = mSelectedGame.CanUserJoin(mWOLSession->GetCurrentUser());
  791. Enable_Dlg_Item(IDC_JOIN_GAME_BUTTON, canJoin);
  792. }
  793. }
  794. }
  795. }
  796. /******************************************************************************
  797. *
  798. * NAME
  799. * MPWolGameListMenuClass::
  800. *
  801. * DESCRIPTION
  802. *
  803. * INPUTS
  804. *
  805. * RESULT
  806. * NONE
  807. *
  808. ******************************************************************************/
  809. void MPWolGameListMenuClass::GetClanVSClanString(WOLGameInfo& gameInfo, WideStringClass& text)
  810. {
  811. const char* clan1Name = "____";
  812. const char* clan2Name = "____";
  813. RefPtr<SquadData> clan = SquadData::FindByID(gameInfo.ClanID1());
  814. if (clan.IsValid())
  815. {
  816. clan1Name = clan->GetName();
  817. }
  818. else if (gameInfo.ClanID1() != 0)
  819. {
  820. clan1Name = "????";
  821. mWOLSession->RequestSquadInfoByID(gameInfo.ClanID1());
  822. }
  823. clan = SquadData::FindByID(gameInfo.ClanID2());
  824. if (clan.IsValid())
  825. {
  826. clan2Name = clan->GetName();
  827. }
  828. else if (gameInfo.ClanID2() != 0)
  829. {
  830. clan2Name = "????";
  831. mWOLSession->RequestSquadInfoByID(gameInfo.ClanID2());
  832. }
  833. text.Format(L"%S -VS- %S", clan1Name, clan2Name);
  834. }
  835. /******************************************************************************
  836. *
  837. * NAME
  838. * MPWolGameListMenuClass::On_ListCtrl_Column_Click
  839. *
  840. * DESCRIPTION
  841. * Respond to user clicking on a column header of a list control.
  842. *
  843. * INPUTS
  844. * List - Pointer to list control originating notification.
  845. * ID - Identifier of list control originating notification.
  846. * Column - Number of column clicked.
  847. *
  848. * RESULT
  849. * NONE
  850. *
  851. ******************************************************************************/
  852. void MPWolGameListMenuClass::On_ListCtrl_Column_Click(ListCtrlClass* list, int id, int column)
  853. {
  854. if (IDC_GAME_LIST_CTRL == id)
  855. {
  856. // If clicking the same column then toggle ascending / descending
  857. if (mSortColumn == column)
  858. {
  859. SortGameChannels(column, !mIsSortAscending, mSortFlags);
  860. }
  861. else
  862. {
  863. SortGameChannels(column, true, mSortFlags);
  864. }
  865. }
  866. }
  867. /******************************************************************************
  868. *
  869. * NAME
  870. * MPWolGameListMenuClass::On_ListCtrl_DblClk
  871. *
  872. * DESCRIPTION
  873. * Automatically attempt to join a game if the user double-clicks on the
  874. * game entry.
  875. *
  876. * INPUTS
  877. * List - List control
  878. * ID - Identifier of list control
  879. * Index - Entry index double-clicked
  880. *
  881. * RESULT
  882. * NONE
  883. *
  884. ******************************************************************************/
  885. void MPWolGameListMenuClass::On_ListCtrl_DblClk(ListCtrlClass* list, int id, int index)
  886. {
  887. if (IDC_GAME_LIST_CTRL == id)
  888. {
  889. Join_Game();
  890. }
  891. }
  892. /******************************************************************************
  893. *
  894. * NAME
  895. * On_Last_Menu_Ending
  896. *
  897. * DESCRIPTION
  898. * Callback from menu class signifying the close of the last menu
  899. *
  900. * INPUTS
  901. *
  902. * RESULT
  903. *
  904. ******************************************************************************/
  905. void MPWolGameListMenuClass::On_Last_Menu_Ending (void)
  906. {
  907. RenegadeDialogMgrClass::Goto_Location(RenegadeDialogMgrClass::LOC_INTERNET_MAIN);
  908. }
  909. /******************************************************************************
  910. *
  911. * NAME
  912. * MPWolGameListMenuClass::HandleNotification(ServerError)
  913. *
  914. * DESCRIPTION
  915. * Handle server error notifications from WWOnline session.
  916. *
  917. * INPUTS
  918. * Error - Server error
  919. *
  920. * RESULT
  921. * NONE
  922. *
  923. ******************************************************************************/
  924. void MPWolGameListMenuClass::HandleNotification(ServerError& error)
  925. {
  926. if (CHAT_E_BANNED == error.GetErrorCode())
  927. {
  928. // DlgMsgBox::DoDialog(TRANSLATE(IDS_WOL_SERVERMESSAGE), TRANSLATE(IDS_WOL_BANNED));
  929. DlgMsgBox::DoDialog(TRANSLATE (IDS_MENU_SERVER_MESSAGE_TITLE), TRANSLATE (IDS_MENU_WOL_BAN_USER_MESSAGE));
  930. End_Dialog();
  931. }
  932. }
  933. /******************************************************************************
  934. *
  935. * NAME
  936. * MPWolGameListMenuClass::HandleNotification(SquadEvent)
  937. *
  938. * DESCRIPTION
  939. *
  940. * INPUTS
  941. *
  942. * RESULT
  943. * NONE
  944. *
  945. ******************************************************************************/
  946. void MPWolGameListMenuClass::HandleNotification(WWOnline::SquadEvent& event)
  947. {
  948. if (!mSelectedGame.IsDataValid() && mSelectedGame.IsClanGame())
  949. {
  950. return;
  951. }
  952. RefPtr<SquadData> squad = event.GetSquadData();
  953. if (squad.IsValid())
  954. {
  955. unsigned long squadID = squad->GetID();
  956. if (mSelectedGame.ClanID1() == squadID || mSelectedGame.ClanID2() == squadID)
  957. {
  958. ListCtrlClass* detailsList = (ListCtrlClass*)Get_Dlg_Item(IDC_DETAILS_LIST);
  959. if (detailsList)
  960. {
  961. // Find entry with marker indicating clan vs clan
  962. const int count = detailsList->Get_Entry_Count();
  963. for (int index = 0; index < count; ++index)
  964. {
  965. int marker = detailsList->Get_Entry_Data(index, 0);
  966. if (CLAN_ENTRY_MARKER == marker)
  967. {
  968. WideStringClass text(0, true);
  969. GetClanVSClanString(mSelectedGame, text);
  970. detailsList->Set_Entry_Text(index, 0, text);
  971. break;
  972. }
  973. }
  974. }
  975. }
  976. }
  977. }
  978. /******************************************************************************
  979. *
  980. * NAME
  981. * SetGameTypeFlags
  982. *
  983. * DESCRIPTION
  984. * Setup the game type flags in the icon column of the game listings.
  985. *
  986. * INPUTS
  987. * List - Pointer to list control to work with.
  988. * Index - Entry index to set type flags for.
  989. * GameInfo - Game information
  990. *
  991. * RESULT
  992. *
  993. ******************************************************************************/
  994. void SetGameTypeFlags(ListCtrlClass* list, int itemIndex, const WOLGameInfo& gameInfo)
  995. {
  996. WWASSERT(list != NULL);
  997. list->Reset_Icons(itemIndex, COL_ICON);
  998. uint32 flags = 0;
  999. if (gameInfo.IsLaddered())
  1000. {
  1001. list->Add_Icon(itemIndex, COL_ICON, "MUL_pts.tga");
  1002. flags |= FLAGSORT_LADDERED;
  1003. }
  1004. else
  1005. {
  1006. list->Add_Icon(itemIndex, COL_ICON, "MUL_NoPts.tga");
  1007. }
  1008. if (gameInfo.IsDedicated())
  1009. {
  1010. list->Add_Icon(itemIndex, COL_ICON, "MUL_Spec.tga");
  1011. flags |= FLAGSORT_DEDICATED;
  1012. }
  1013. if (gameInfo.IsPassworded())
  1014. {
  1015. list->Add_Icon(itemIndex, COL_ICON, "MUL_Pswrd.tga");
  1016. flags |= FLAGSORT_PASSWORDED;
  1017. }
  1018. if (gameInfo.IsClanGame())
  1019. {
  1020. list->Add_Icon(itemIndex, COL_ICON, "MUL_Btlcln.tga");
  1021. flags |= FLAGSORT_CLAN;
  1022. }
  1023. list->Set_Entry_Data(itemIndex, COL_ICON, flags);
  1024. }
  1025. /******************************************************************************
  1026. *
  1027. * NAME
  1028. * SetPingTimeIcon
  1029. *
  1030. * DESCRIPTION
  1031. * Set an icon reflecting the latency for this game.
  1032. *
  1033. * INPUTS
  1034. * List - List control
  1035. * Index - Entry index
  1036. * Time - Latency
  1037. *
  1038. * RESULT
  1039. * NONE
  1040. *
  1041. ******************************************************************************/
  1042. void SetPingTimeIcon(ListCtrlClass* list, int itemIndex, long pingTime)
  1043. {
  1044. const char* pingIcon = NULL;
  1045. if (pingTime <= PING_GREEN_THRESHOLD)
  1046. {
  1047. pingIcon = "mul_statg.tga";
  1048. }
  1049. else if (pingTime <= PING_YELLOW_THRESHOLD)
  1050. {
  1051. pingIcon = "mul_staty.tga";
  1052. }
  1053. else
  1054. {
  1055. pingIcon = "mul_statr.tga";
  1056. }
  1057. list->Reset_Icons(itemIndex, COL_PING);
  1058. list->Add_Icon(itemIndex, COL_PING, pingIcon);
  1059. unsigned long displayPing = (unsigned long)((1000.0 / 256.0) * (sqrt(double(pingTime))));
  1060. list->Set_Entry_Data(itemIndex, COL_PING, displayPing);
  1061. WideStringClass text(32, true);
  1062. text.Format(L" (%lu)", displayPing);
  1063. list->Set_Entry_Text(itemIndex, COL_PING, text);
  1064. }
  1065. /******************************************************************************
  1066. *
  1067. * NAME
  1068. * MPWolGameListMenuClass::SortGameChannels
  1069. *
  1070. * DESCRIPTION
  1071. * Sort the game channels
  1072. *
  1073. * INPUTS
  1074. * Column - Number of column to sort by.
  1075. * Ascending - True to sort ascending; false to sort descending
  1076. * Flags - Game flags to sort by if column is COL_ICON
  1077. *
  1078. * RESULT
  1079. * NONE
  1080. *
  1081. ******************************************************************************/
  1082. void MPWolGameListMenuClass::SortGameChannels(int column, bool isAscending, unsigned long param)
  1083. {
  1084. mSortColumn = column;
  1085. mIsSortAscending = isAscending;
  1086. mSortFlags = param;
  1087. ListCtrlClass* list = (ListCtrlClass*)Get_Dlg_Item(IDC_GAME_LIST_CTRL);
  1088. if (list)
  1089. {
  1090. ListCtrlClass::SORT_TYPE sortDirection = ListCtrlClass::SORT_DESCENDING;
  1091. if (isAscending)
  1092. {
  1093. sortDirection = ListCtrlClass::SORT_ASCENDING;
  1094. }
  1095. if (COL_ICON == column)
  1096. {
  1097. list->Sort(FlagsSortCallback, mSortFlags);
  1098. }
  1099. else if (COL_PLAYERS == column || COL_PING == column)
  1100. {
  1101. list->Sort(NumericSortCallback, MAKELONG(column, sortDirection));
  1102. }
  1103. else
  1104. {
  1105. list->Sort(AlphaSortCallback, MAKELONG(column, sortDirection));
  1106. }
  1107. list->Set_Sort_Designator(column, sortDirection);
  1108. }
  1109. }
  1110. /******************************************************************************
  1111. *
  1112. * NAME
  1113. * FlagSortCallback
  1114. *
  1115. * DESCRIPTION
  1116. * Sort list entries by game type flags.
  1117. *
  1118. * INPUTS
  1119. * List - List control performing sort.
  1120. * Index1 - First entry to compare
  1121. * Index2 - Second entry to compare
  1122. *
  1123. * RESULT
  1124. * 0 - Items are equal
  1125. * -1 - Item1 is less than item2
  1126. * 1 - Item1 is greater than item2
  1127. *
  1128. ******************************************************************************/
  1129. int CALLBACK FlagsSortCallback(ListCtrlClass* list, int index1, int index2, uint32 mask)
  1130. {
  1131. uint32 flags1 = list->Get_Entry_Data(index1, COL_ICON);
  1132. flags1 &= mask;
  1133. uint32 flags2 = list->Get_Entry_Data(index2, COL_ICON);
  1134. flags2 &= mask;
  1135. if (flags1 && !flags2)
  1136. {
  1137. return -1;
  1138. }
  1139. else if (!flags1 && flags2)
  1140. {
  1141. return 1;
  1142. }
  1143. else if (flags1 && flags2)
  1144. {
  1145. // Secondary sort by ping time
  1146. int ping1 = list->Get_Entry_Data(index1, COL_PING);
  1147. int ping2 = list->Get_Entry_Data(index2, COL_PING);
  1148. int delta = (ping1 - ping2);
  1149. if (delta < 0)
  1150. {
  1151. return -1;
  1152. }
  1153. else if (delta > 0)
  1154. {
  1155. return 1;
  1156. }
  1157. const WCHAR* name1 = list->Get_Entry_Text(index1, COL_HOST_NAME);
  1158. const WCHAR* name2 = list->Get_Entry_Text(index2, COL_HOST_NAME);
  1159. return wcsicmp(name1, name2);
  1160. }
  1161. return 0;
  1162. }
  1163. /******************************************************************************
  1164. *
  1165. * NAME
  1166. * NumericSortCallback
  1167. *
  1168. * DESCRIPTION
  1169. * Sort list entries numerically from the numbers contained in the entries
  1170. * data field.
  1171. *
  1172. * INPUTS
  1173. * List - List control performing sort.
  1174. * Index1 - First entry to compare
  1175. * Index2 - Second entry to compare
  1176. *
  1177. * RESULT
  1178. * -1 - Item1 is less than item2
  1179. * 0 - Items are equal
  1180. * 1 - Item1 is greater than item2
  1181. *
  1182. ******************************************************************************/
  1183. int CALLBACK NumericSortCallback(ListCtrlClass* list, int index1, int index2, uint32 param)
  1184. {
  1185. // Sort by numeric value stored in entry data field
  1186. int column = LOWORD(param);
  1187. uint32 data1 = list->Get_Entry_Data(index1, column);
  1188. uint32 data2 = list->Get_Entry_Data(index2, column);
  1189. int retval = (data1 - data2);
  1190. if (retval < 0)
  1191. {
  1192. retval = -1;
  1193. }
  1194. else if (retval > 0)
  1195. {
  1196. retval = 1;
  1197. }
  1198. else
  1199. {
  1200. if (column != COL_PING)
  1201. {
  1202. // Secondary sort by ping time
  1203. data1 = list->Get_Entry_Data(index1, COL_PING);
  1204. data2 = list->Get_Entry_Data(index2, COL_PING);
  1205. retval = (data1 - data2);
  1206. if (retval < 0)
  1207. {
  1208. retval = -1;
  1209. }
  1210. else if (retval > 0)
  1211. {
  1212. retval = 1;
  1213. }
  1214. }
  1215. if (retval == 0)
  1216. {
  1217. const WCHAR* name1 = list->Get_Entry_Text(index1, COL_HOST_NAME);
  1218. const WCHAR* name2 = list->Get_Entry_Text(index2, COL_HOST_NAME);
  1219. retval = wcsicmp(name1, name2);
  1220. }
  1221. }
  1222. // Invert the return value if we are sorting descendingly
  1223. ListCtrlClass::SORT_TYPE sortType = (ListCtrlClass::SORT_TYPE)HIWORD(param);
  1224. if (ListCtrlClass::SORT_DESCENDING == sortType)
  1225. {
  1226. return -retval;
  1227. }
  1228. return retval;
  1229. }
  1230. /******************************************************************************
  1231. *
  1232. * NAME
  1233. * NumericSortCallback
  1234. *
  1235. * DESCRIPTION
  1236. * Sort list entries alphbetically then by ping time.
  1237. *
  1238. * INPUTS
  1239. * List - List control performing sort.
  1240. * Index1 - First entry to compare
  1241. * Index2 - Second entry to compare
  1242. *
  1243. * RESULT
  1244. * -1 - Item1 is less than item2
  1245. * 0 - Items are equal
  1246. * 1 - Item1 is greater than item2
  1247. *
  1248. ******************************************************************************/
  1249. int CALLBACK AlphaSortCallback(ListCtrlClass* list, int index1, int index2, uint32 param)
  1250. {
  1251. // Sort by numeric value stored in entry data field
  1252. int column = LOWORD(param);
  1253. const WCHAR* text1 = list->Get_Entry_Text(index1, column);
  1254. const WCHAR* text2 = list->Get_Entry_Text(index2, column);
  1255. int retval = wcsicmp(text1, text2);
  1256. // If the strings match then secondary sort by ping time.
  1257. if (retval == 0)
  1258. {
  1259. uint32 data1 = list->Get_Entry_Data(index1, COL_PING);
  1260. uint32 data2 = list->Get_Entry_Data(index2, COL_PING);
  1261. retval = (data1 - data2);
  1262. if (retval < 0)
  1263. {
  1264. retval = -1;
  1265. }
  1266. else if (retval > 0)
  1267. {
  1268. retval = 1;
  1269. }
  1270. }
  1271. // Invert the return value if we are sorting descendingly
  1272. ListCtrlClass::SORT_TYPE sortType = (ListCtrlClass::SORT_TYPE)HIWORD(param);
  1273. if (ListCtrlClass::SORT_DESCENDING == sortType)
  1274. {
  1275. return -retval;
  1276. }
  1277. return retval;
  1278. }