WOLQuickMatchMenu.cpp 60 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832
  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: WOLQuickMatchMenu.cpp
  25. // Author: Chris Huybregts, November 2001
  26. // Description: Lan Lobby Menu
  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/QuickmatchPreferences.h"
  32. #include "Common/LadderPreferences.h"
  33. #include "Common/MultiplayerSettings.h"
  34. #include "Common/PlayerTemplate.h"
  35. #include "GameClient/AnimateWindowManager.h"
  36. #include "GameClient/WindowLayout.h"
  37. #include "GameClient/Gadget.h"
  38. #include "GameClient/GameText.h"
  39. #include "GameClient/InGameUI.h"
  40. #include "GameClient/Shell.h"
  41. #include "GameClient/ShellHooks.h"
  42. #include "GameClient/KeyDefs.h"
  43. #include "GameClient/GameWindowManager.h"
  44. #include "GameClient/GadgetComboBox.h"
  45. #include "GameClient/GadgetPushButton.h"
  46. #include "GameClient/GadgetListBox.h"
  47. #include "GameClient/GadgetTextEntry.h"
  48. #include "GameClient/GadgetStaticText.h"
  49. #include "GameClient/MapUtil.h"
  50. #include "GameClient/GameWindowTransitions.h"
  51. #include "GameLogic/GameLogic.h"
  52. #include "GameNetwork/NAT.h"
  53. #include "GameNetwork/GameSpyOverlay.h"
  54. #include "GameNetwork/GameSpy/BuddyDefs.h"
  55. #include "GameNetwork/GameSpy/GSConfig.h"
  56. #include "GameNetwork/GameSpy/PeerDefs.h"
  57. #include "GameNetwork/GameSpy/PeerThread.h"
  58. #include "GameNetwork/GameSpy/PersistentStorageDefs.h"
  59. #include "GameNetwork/GameSpy/PersistentStorageThread.h"
  60. #include "GameNetwork/RankPointValue.h"
  61. #include "GameNetwork/GameSpy/LadderDefs.h"
  62. #ifdef _INTERNAL
  63. // for occasional debugging...
  64. //#pragma optimize("", off)
  65. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  66. #endif
  67. #ifdef DEBUG_LOGGING
  68. #include "Common/MiniLog.h"
  69. //#define PERF_TEST
  70. static LogClass s_perfLog("QMPerf.txt");
  71. static Bool s_inQM = FALSE;
  72. #define PERF_LOG(x) s_perfLog.log x
  73. #else // DEBUG_LOGGING
  74. #define PERF_LOG(x) {}
  75. #endif // DEBUG_LOGGING
  76. // PRIVATE DATA ///////////////////////////////////////////////////////////////////////////////////
  77. // window ids ------------------------------------------------------------------------------
  78. static NameKeyType parentWOLQuickMatchID = NAMEKEY_INVALID;
  79. static NameKeyType buttonBackID = NAMEKEY_INVALID;
  80. static NameKeyType buttonStartID = NAMEKEY_INVALID;
  81. static NameKeyType buttonStopID = NAMEKEY_INVALID;
  82. static NameKeyType buttonWidenID = NAMEKEY_INVALID;
  83. static NameKeyType buttonBuddiesID = NAMEKEY_INVALID;
  84. static NameKeyType listboxQuickMatchID = NAMEKEY_INVALID;
  85. static NameKeyType listboxMapSelectID = NAMEKEY_INVALID;
  86. static NameKeyType buttonSelectAllMapsID = NAMEKEY_INVALID;
  87. static NameKeyType buttonSelectNoMapsID = NAMEKEY_INVALID;
  88. //static NameKeyType textEntryMaxDisconnectsID = NAMEKEY_INVALID;
  89. //static NameKeyType textEntryMaxPointsID = NAMEKEY_INVALID;
  90. //static NameKeyType textEntryMinPointsID = NAMEKEY_INVALID;
  91. static NameKeyType textEntryWaitTimeID = NAMEKEY_INVALID;
  92. static NameKeyType comboBoxNumPlayersID = NAMEKEY_INVALID;
  93. static NameKeyType comboBoxMaxPingID = NAMEKEY_INVALID;
  94. static NameKeyType comboBoxLadderID = NAMEKEY_INVALID;
  95. static NameKeyType comboBoxMaxDisconnectsID = NAMEKEY_INVALID;
  96. static NameKeyType staticTextNumPlayersID = NAMEKEY_INVALID;
  97. static NameKeyType comboBoxSideID = NAMEKEY_INVALID;
  98. static NameKeyType comboBoxColorID = NAMEKEY_INVALID;
  99. // Window Pointers ------------------------------------------------------------------------
  100. static GameWindow *parentWOLQuickMatch = NULL;
  101. static GameWindow *buttonBack = NULL;
  102. static GameWindow *buttonStart = NULL;
  103. static GameWindow *buttonStop = NULL;
  104. static GameWindow *buttonWiden = NULL;
  105. GameWindow *quickmatchTextWindow = NULL;
  106. static GameWindow *listboxMapSelect = NULL;
  107. //static GameWindow *textEntryMaxDisconnects = NULL;
  108. //static GameWindow *textEntryMaxPoints = NULL;
  109. //static GameWindow *textEntryMinPoints = NULL;
  110. static GameWindow *textEntryWaitTime = NULL;
  111. static GameWindow *comboBoxNumPlayers = NULL;
  112. static GameWindow *comboBoxMaxPing = NULL;
  113. static GameWindow *comboBoxLadder = NULL;
  114. static GameWindow *comboBoxDisabledLadder = NULL; // enable and disable this, but never use it. it is a stand-in for comboBoxLadder for when there are no ladders
  115. static GameWindow *comboBoxMaxDisconnects = NULL;
  116. static GameWindow *staticTextNumPlayers = NULL;
  117. static GameWindow *comboBoxSide = NULL;
  118. static GameWindow *comboBoxColor = NULL;
  119. static Bool isShuttingDown = false;
  120. static Bool buttonPushed = false;
  121. static char *nextScreen = NULL;
  122. static Bool raiseMessageBoxes = false;
  123. static Bool isInInit = FALSE;
  124. static const Image *selectedImage = NULL;
  125. static const Image *unselectedImage = NULL;
  126. static bool isPopulatingLadderBox = false;
  127. static Int maxPingEntries = 0;
  128. static Int maxPoints= 100;
  129. static Int minPoints = 0;
  130. static const LadderInfo * getLadderInfo( void );
  131. // [SKB: Jul 01 2003 @ 7:7pm] :
  132. // German2 now has fewer maps. When trying to do a QM with a Retail version
  133. // the bool string sent to the QMBot is almost always a different size. This
  134. // mapping is kept so that we now send a string of all maps instead of just
  135. // the ones that are visible to the user.
  136. #define VARIABLE_NUMBER_OF_MAPS 1
  137. #if VARIABLE_NUMBER_OF_MAPS
  138. typedef std::vector<Int> MapListboxIndex;
  139. static MapListboxIndex mapListboxIndex;
  140. #endif
  141. static Bool isInfoShown(void)
  142. {
  143. static NameKeyType parentStatsID = NAMEKEY("WOLQuickMatchMenu.wnd:ParentStats");
  144. GameWindow *parentStats = TheWindowManager->winGetWindowFromId( parentWOLQuickMatch, parentStatsID );
  145. if (parentStats)
  146. return !parentStats->winIsHidden();
  147. return FALSE;
  148. }
  149. static void hideInfoGadgets(Bool doIt)
  150. {
  151. static NameKeyType parentStatsID = NAMEKEY("WOLQuickMatchMenu.wnd:ParentStats");
  152. GameWindow *parentStats = TheWindowManager->winGetWindowFromId( parentWOLQuickMatch, parentStatsID );
  153. if (parentStats)
  154. {
  155. parentStats->winHide(doIt);
  156. }
  157. }
  158. static void hideOptionsGadgets(Bool doIt)
  159. {
  160. static NameKeyType parentOptionsID = NAMEKEY("WOLQuickMatchMenu.wnd:ParentOptions");
  161. GameWindow *parentOptions = TheWindowManager->winGetWindowFromId( parentWOLQuickMatch, parentOptionsID );
  162. if (parentOptions)
  163. {
  164. parentOptions->winHide(doIt);
  165. if (comboBoxSide)
  166. comboBoxSide->winHide(doIt);
  167. if (comboBoxColor)
  168. comboBoxColor->winHide(doIt);
  169. if (comboBoxNumPlayers)
  170. comboBoxNumPlayers->winHide(doIt);
  171. if (comboBoxLadder)
  172. comboBoxLadder->winHide(doIt);
  173. if (comboBoxDisabledLadder)
  174. comboBoxDisabledLadder->winHide(doIt);
  175. if (comboBoxMaxPing)
  176. comboBoxMaxPing->winHide(doIt);
  177. if (comboBoxMaxDisconnects)
  178. comboBoxMaxDisconnects->winHide(doIt);
  179. }
  180. }
  181. static void enableOptionsGadgets(Bool doIt)
  182. {
  183. #ifdef PERF_TEST
  184. s_inQM = !doIt;
  185. #endif // PERF_TEST
  186. static NameKeyType parentOptionsID = NAMEKEY("WOLQuickMatchMenu.wnd:ParentOptions");
  187. GameWindow *parentOptions = TheWindowManager->winGetWindowFromId( parentWOLQuickMatch, parentOptionsID );
  188. const LadderInfo *li = getLadderInfo();
  189. if (parentOptions)
  190. {
  191. parentOptions->winEnable(doIt);
  192. if (comboBoxSide)
  193. comboBoxSide->winEnable(doIt && (!li || !li->randomFactions));
  194. if (comboBoxColor)
  195. comboBoxColor->winEnable(doIt);
  196. if (comboBoxNumPlayers)
  197. comboBoxNumPlayers->winEnable(doIt);
  198. if (comboBoxLadder)
  199. comboBoxLadder->winEnable(doIt);
  200. if (comboBoxDisabledLadder)
  201. comboBoxDisabledLadder->winEnable(FALSE);
  202. if (comboBoxMaxPing)
  203. comboBoxMaxPing->winEnable(doIt);
  204. if (comboBoxMaxDisconnects)
  205. comboBoxMaxDisconnects->winEnable(doIt);
  206. }
  207. }
  208. enum
  209. {
  210. MAX_DISCONNECTS_ANY = 0,
  211. MAX_DISCONNECTS_5 = 5,
  212. MAX_DISCONNECTS_10 = 10,
  213. MAX_DISCONNECTS_25 = 25,
  214. MAX_DISCONNECTS_50 = 50,
  215. };
  216. enum{ MAX_DISCONNECTS_COUNT = 5 };
  217. static Int MAX_DISCONNECTS[MAX_DISCONNECTS_COUNT] = {MAX_DISCONNECTS_ANY, MAX_DISCONNECTS_5,
  218. MAX_DISCONNECTS_10, MAX_DISCONNECTS_25,
  219. MAX_DISCONNECTS_50};
  220. void UpdateStartButton(void)
  221. {
  222. if (!comboBoxLadder || !buttonStart || !listboxMapSelect)
  223. return;
  224. Int index;
  225. Int selected;
  226. GadgetComboBoxGetSelectedPos( comboBoxLadder, &selected );
  227. index = (Int)GadgetComboBoxGetItemData( comboBoxLadder, selected );
  228. const LadderInfo *li = TheLadderList->findLadderByIndex( index );
  229. if (li)
  230. {
  231. buttonStart->winEnable(TRUE);
  232. return;
  233. }
  234. Int numMaps = GadgetListBoxGetNumEntries(listboxMapSelect);
  235. for ( Int i=0; i<numMaps; ++i )
  236. {
  237. if ((Bool)GadgetListBoxGetItemData(listboxMapSelect, i, 0))
  238. {
  239. buttonStart->winEnable(TRUE);
  240. return;
  241. }
  242. }
  243. buttonStart->winEnable(FALSE);
  244. }
  245. // -----------------------------------------------------------------------------
  246. static void populateQMColorComboBox(QuickMatchPreferences& pref)
  247. {
  248. Int numColors = TheMultiplayerSettings->getNumColors();
  249. UnicodeString colorName;
  250. GadgetComboBoxReset(comboBoxColor);
  251. MultiplayerColorDefinition *def = TheMultiplayerSettings->getColor(PLAYERTEMPLATE_RANDOM);
  252. Int newIndex = GadgetComboBoxAddEntry(comboBoxColor, TheGameText->fetch("GUI:???"), def->getColor());
  253. GadgetComboBoxSetItemData(comboBoxColor, newIndex, (void *)-1);
  254. for (Int c=0; c<numColors; ++c)
  255. {
  256. def = TheMultiplayerSettings->getColor(c);
  257. if (!def)
  258. continue;
  259. colorName = TheGameText->fetch(def->getTooltipName().str());
  260. newIndex = GadgetComboBoxAddEntry(comboBoxColor, colorName, def->getColor());
  261. GadgetComboBoxSetItemData(comboBoxColor, newIndex, (void *)c);
  262. }
  263. GadgetComboBoxSetSelectedPos(comboBoxColor, pref.getColor());
  264. }
  265. // -----------------------------------------------------------------------------
  266. static void populateQMSideComboBox(Int favSide, const LadderInfo *li = NULL)
  267. {
  268. Int numPlayerTemplates = ThePlayerTemplateStore->getPlayerTemplateCount();
  269. UnicodeString playerTemplateName;
  270. GadgetComboBoxReset(comboBoxSide);
  271. MultiplayerColorDefinition *def = TheMultiplayerSettings->getColor(PLAYERTEMPLATE_RANDOM);
  272. Int newIndex = GadgetComboBoxAddEntry(comboBoxSide, TheGameText->fetch("GUI:Random"), def->getColor());
  273. GadgetComboBoxSetItemData(comboBoxSide, newIndex, (void *)PLAYERTEMPLATE_RANDOM);
  274. std::set<AsciiString> seenSides;
  275. Int entryToSelect = 0; // select Random by default
  276. for (Int c=0; c<numPlayerTemplates; ++c)
  277. {
  278. const PlayerTemplate *fac = ThePlayerTemplateStore->getNthPlayerTemplate(c);
  279. if (!fac)
  280. continue;
  281. if (fac->getStartingBuilding().isEmpty())
  282. continue;
  283. AsciiString side;
  284. side.format("SIDE:%s", fac->getSide().str());
  285. if (seenSides.find(side) != seenSides.end())
  286. continue;
  287. if (li)
  288. {
  289. if (std::find(li->validFactions.begin(), li->validFactions.end(), fac->getSide()) == li->validFactions.end())
  290. continue; // ladder doesn't allow it.
  291. }
  292. seenSides.insert(side);
  293. newIndex = GadgetComboBoxAddEntry(comboBoxSide, TheGameText->fetch(side), def->getColor());
  294. GadgetComboBoxSetItemData(comboBoxSide, newIndex, (void *)c);
  295. if (c == favSide)
  296. entryToSelect = newIndex;
  297. }
  298. seenSides.clear();
  299. GadgetComboBoxSetSelectedPos(comboBoxSide, entryToSelect);
  300. if (li && li->randomFactions)
  301. comboBoxSide->winEnable(FALSE);
  302. else
  303. comboBoxSide->winEnable(TRUE);
  304. }
  305. void HandleQMLadderSelection(Int ladderID)
  306. {
  307. if (!parentWOLQuickMatch)
  308. return;
  309. QuickMatchPreferences pref;
  310. if (ladderID < 1)
  311. {
  312. pref.setLastLadder(AsciiString::TheEmptyString, 0);
  313. pref.write();
  314. return;
  315. }
  316. const LadderInfo *info = TheLadderList->findLadderByIndex(ladderID);
  317. if (!info)
  318. {
  319. pref.setLastLadder(AsciiString::TheEmptyString, 0);
  320. }
  321. else
  322. {
  323. pref.setLastLadder(info->address, info->port);
  324. }
  325. pref.write();
  326. }
  327. static inline Bool isValidLadder( const LadderInfo *lad )
  328. {
  329. if (lad && lad->index > 0 && lad->validQM)
  330. {
  331. PSPlayerStats stats = TheGameSpyPSMessageQueue->findPlayerStatsByID(TheGameSpyInfo->getLocalProfileID());
  332. Int numWins = 0;
  333. PerGeneralMap::iterator it;
  334. for (it = stats.wins.begin(); it != stats.wins.end(); ++it)
  335. {
  336. numWins += it->second;
  337. }
  338. if (!lad->maxWins || lad->maxWins >=numWins)
  339. {
  340. if (!lad->minWins || lad->minWins<=numWins)
  341. {
  342. return TRUE;
  343. }
  344. }
  345. }
  346. return FALSE;
  347. }
  348. void PopulateQMLadderListBox( GameWindow *win )
  349. {
  350. if (!parentWOLQuickMatch || !comboBoxLadder)
  351. return;
  352. isPopulatingLadderBox = true;
  353. QuickMatchPreferences pref;
  354. AsciiString userPrefFilename;
  355. Int localProfile = TheGameSpyInfo->getLocalProfileID();
  356. Color specialColor = GameSpyColor[GSCOLOR_MAP_SELECTED];
  357. Color normalColor = GameSpyColor[GSCOLOR_MAP_UNSELECTED];
  358. Color favoriteColor = GameSpyColor[GSCOLOR_MAP_UNSELECTED];
  359. Int index;
  360. GadgetListBoxReset( win );
  361. std::set<const LadderInfo *> usedLadders;
  362. // start with "No Ladder"
  363. index = GadgetListBoxAddEntryText( win, TheGameText->fetch("GUI:NoLadder"), normalColor, -1 );
  364. GadgetListBoxSetItemData( win, 0, index );
  365. // add the last ladder
  366. Int selectedPos = 0;
  367. AsciiString lastLadderAddr = pref.getLastLadderAddr();
  368. UnsignedShort lastLadderPort = pref.getLastLadderPort();
  369. const LadderInfo *info = TheLadderList->findLadder( lastLadderAddr, lastLadderPort );
  370. if (isValidLadder(info))
  371. {
  372. usedLadders.insert(info);
  373. index = GadgetListBoxAddEntryText( win, info->name, favoriteColor, -1 );
  374. GadgetListBoxSetItemData( win, (void *)(info->index), index );
  375. selectedPos = index;
  376. }
  377. // our recent ladders
  378. LadderPreferences ladPref;
  379. ladPref.loadProfile( localProfile );
  380. const LadderPrefMap recentLadders = ladPref.getRecentLadders();
  381. for (LadderPrefMap::const_iterator cit = recentLadders.begin(); cit != recentLadders.end(); ++cit)
  382. {
  383. AsciiString addr = cit->second.address;
  384. UnsignedShort port = cit->second.port;
  385. if (addr == lastLadderAddr && port == lastLadderPort)
  386. continue;
  387. const LadderInfo *info = TheLadderList->findLadder( addr, port );
  388. if (isValidLadder(info) && usedLadders.find(info) == usedLadders.end())
  389. {
  390. usedLadders.insert(info);
  391. index = GadgetListBoxAddEntryText( win, info->name, favoriteColor, -1 );
  392. GadgetListBoxSetItemData( win, (void *)(info->index), index );
  393. }
  394. }
  395. // special ladders
  396. const LadderInfoList *lil = TheLadderList->getSpecialLadders();
  397. LadderInfoList::const_iterator lit;
  398. for (lit = lil->begin(); lit != lil->end(); ++lit)
  399. {
  400. const LadderInfo *info = *lit;
  401. if (isValidLadder(info) && usedLadders.find(info) == usedLadders.end())
  402. {
  403. usedLadders.insert(info);
  404. index = GadgetListBoxAddEntryText( win, info->name, specialColor, -1 );
  405. GadgetListBoxSetItemData( win, (void *)(info->index), index );
  406. }
  407. }
  408. // standard ladders
  409. lil = TheLadderList->getStandardLadders();
  410. for (lit = lil->begin(); lit != lil->end(); ++lit)
  411. {
  412. const LadderInfo *info = *lit;
  413. if (isValidLadder(info) && usedLadders.find(info) == usedLadders.end())
  414. {
  415. usedLadders.insert(info);
  416. index = GadgetListBoxAddEntryText( win, info->name, normalColor, -1 );
  417. GadgetListBoxSetItemData( win, (void *)(info->index), index );
  418. }
  419. }
  420. GadgetListBoxSetSelected( win, selectedPos );
  421. isPopulatingLadderBox = false;
  422. }
  423. static const LadderInfo * getLadderInfo( void )
  424. {
  425. Int index;
  426. Int selected;
  427. GadgetComboBoxGetSelectedPos( comboBoxLadder, &selected );
  428. index = (Int)GadgetComboBoxGetItemData( comboBoxLadder, selected );
  429. const LadderInfo *li = TheLadderList->findLadderByIndex( index );
  430. return li;
  431. }
  432. void PopulateQMLadderComboBox( void )
  433. {
  434. if (!parentWOLQuickMatch || !comboBoxLadder)
  435. return;
  436. isPopulatingLadderBox = true;
  437. QuickMatchPreferences pref;
  438. Int localProfile = TheGameSpyInfo->getLocalProfileID();
  439. Color specialColor = GameSpyColor[GSCOLOR_MAP_SELECTED];
  440. Color normalColor = GameSpyColor[GSCOLOR_MAP_UNSELECTED];
  441. Int index;
  442. GadgetComboBoxReset( comboBoxLadder );
  443. index = GadgetComboBoxAddEntry( comboBoxLadder, TheGameText->fetch("GUI:NoLadder"), normalColor );
  444. GadgetComboBoxSetItemData( comboBoxLadder, index, 0 );
  445. std::set<const LadderInfo *> usedLadders;
  446. Int selectedPos = 0;
  447. AsciiString lastLadderAddr = pref.getLastLadderAddr();
  448. UnsignedShort lastLadderPort = pref.getLastLadderPort();
  449. const LadderInfo *info = TheLadderList->findLadder( lastLadderAddr, lastLadderPort );
  450. if (isValidLadder(info))
  451. {
  452. usedLadders.insert(info);
  453. index = GadgetComboBoxAddEntry( comboBoxLadder, info->name, specialColor );
  454. GadgetComboBoxSetItemData( comboBoxLadder, index, (void *)(info->index) );
  455. selectedPos = index;
  456. // we selected a ladder? No game size choice for us...
  457. GadgetComboBoxSetSelectedPos(comboBoxNumPlayers, info->playersPerTeam-1);
  458. comboBoxNumPlayers->winEnable( FALSE );
  459. }
  460. else
  461. {
  462. comboBoxNumPlayers->winEnable( TRUE );
  463. }
  464. LadderPreferences ladPref;
  465. ladPref.loadProfile( localProfile );
  466. const LadderPrefMap recentLadders = ladPref.getRecentLadders();
  467. for (LadderPrefMap::const_iterator cit = recentLadders.begin(); cit != recentLadders.end(); ++cit)
  468. {
  469. AsciiString addr = cit->second.address;
  470. UnsignedShort port = cit->second.port;
  471. if (addr == lastLadderAddr && port == lastLadderPort)
  472. continue;
  473. const LadderInfo *info = TheLadderList->findLadder( addr, port );
  474. if (isValidLadder(info) && usedLadders.find(info) == usedLadders.end())
  475. {
  476. usedLadders.insert(info);
  477. index = GadgetComboBoxAddEntry( comboBoxLadder, info->name, normalColor );
  478. GadgetComboBoxSetItemData( comboBoxLadder, index, (void *)(info->index) );
  479. }
  480. }
  481. index = GadgetComboBoxAddEntry( comboBoxLadder, TheGameText->fetch("GUI:ChooseLadder"), normalColor );
  482. GadgetComboBoxSetItemData( comboBoxLadder, index, (void *)-1 );
  483. GadgetComboBoxSetSelectedPos( comboBoxLadder, selectedPos );
  484. isPopulatingLadderBox = false;
  485. populateQMSideComboBox(pref.getSide(), getLadderInfo()); // this will set side to random and disable if necessary
  486. }
  487. static void populateQuickMatchMapSelectListbox( QuickMatchPreferences& pref )
  488. {
  489. std::list<AsciiString> maps = TheGameSpyConfig->getQMMaps();
  490. // enable/disable box based on ladder status
  491. Int index;
  492. Int selected;
  493. GadgetComboBoxGetSelectedPos( comboBoxLadder, &selected );
  494. index = (Int)GadgetComboBoxGetItemData( comboBoxLadder, selected );
  495. const LadderInfo *li = TheLadderList->findLadderByIndex( index );
  496. //listboxMapSelect->winEnable( li == NULL || li->randomMaps == FALSE );
  497. Int numPlayers = 0;
  498. if (li)
  499. {
  500. numPlayers = li->playersPerTeam*2;
  501. maps = li->validMaps;
  502. }
  503. else
  504. {
  505. GadgetComboBoxGetSelectedPos(comboBoxNumPlayers, &selected);
  506. if (selected < 0)
  507. selected = 0;
  508. numPlayers = (selected+1)*2;
  509. }
  510. #if VARIABLE_NUMBER_OF_MAPS
  511. mapListboxIndex.clear();
  512. #endif
  513. GadgetListBoxReset(listboxMapSelect);
  514. for (std::list<AsciiString>::const_iterator it = maps.begin(); it != maps.end(); ++it)
  515. {
  516. AsciiString theMap = *it;
  517. const MapMetaData *md = TheMapCache->findMap(theMap);
  518. if (md && md->m_numPlayers >= numPlayers)
  519. {
  520. UnicodeString displayName;
  521. displayName = md->m_displayName;
  522. Bool isSelected = pref.isMapSelected(theMap);
  523. if (li && li->randomMaps)
  524. isSelected = TRUE;
  525. Int width = 10;
  526. Int height = 10;
  527. const Image *img = (isSelected)?selectedImage:unselectedImage;
  528. if ( img )
  529. {
  530. width = min(GadgetListBoxGetColumnWidth(listboxMapSelect, 0), img->getImageWidth());
  531. height = width;
  532. }
  533. Int index = GadgetListBoxAddEntryImage(listboxMapSelect, img, -1, 0, height, width);
  534. GadgetListBoxAddEntryText(listboxMapSelect, displayName, GameSpyColor[(isSelected)?GSCOLOR_MAP_SELECTED:GSCOLOR_MAP_UNSELECTED], index, 1);
  535. GadgetListBoxSetItemData(listboxMapSelect, (void *)isSelected, index);
  536. GadgetListBoxSetItemData(listboxMapSelect, (void *)md, index, 1);
  537. #if VARIABLE_NUMBER_OF_MAPS
  538. mapListboxIndex.push_back(index);
  539. #endif
  540. }
  541. else
  542. {
  543. #if VARIABLE_NUMBER_OF_MAPS
  544. // [SKB: Jul 01 2003 @ 7:9pm] :
  545. // Keep track of maps that are not visible right now so
  546. // they are added to the information sent to the QMBot.
  547. mapListboxIndex.push_back(-1);
  548. #endif
  549. }
  550. }
  551. }
  552. static void saveQuickMatchOptions( void )
  553. {
  554. if(isInInit)
  555. return;
  556. QuickMatchPreferences pref;
  557. std::list<AsciiString> maps = TheGameSpyConfig->getQMMaps();
  558. Int index;
  559. Int selected;
  560. GadgetComboBoxGetSelectedPos( comboBoxLadder, &selected );
  561. index = (Int)GadgetComboBoxGetItemData( comboBoxLadder, selected );
  562. const LadderInfo *li = TheLadderList->findLadderByIndex( index );
  563. Int numPlayers = 0;
  564. if (li)
  565. {
  566. pref.setLastLadder( li->address, li->port );
  567. numPlayers = li->playersPerTeam*2;
  568. pref.write();
  569. //return; // don't save our defaults based on the tournament's defaults
  570. }
  571. else
  572. {
  573. pref.setLastLadder( AsciiString::TheEmptyString, 0 );
  574. GadgetComboBoxGetSelectedPos(comboBoxNumPlayers, &selected);
  575. if (selected < 0)
  576. selected = 0;
  577. numPlayers = (selected+1)*2;
  578. }
  579. if (!li || !li->randomMaps) // don't save the map as selected if we couldn't choose
  580. {
  581. Int row = 0;
  582. Int entries = GadgetListBoxGetNumEntries(listboxMapSelect);
  583. while ( row < entries)
  584. {
  585. const MapMetaData *md = (const MapMetaData *)GadgetListBoxGetItemData(listboxMapSelect, row, 1);
  586. if(md)
  587. pref.setMapSelected(md->m_fileName, (Bool)GadgetListBoxGetItemData(listboxMapSelect, row));
  588. row++;
  589. }
  590. }
  591. UnicodeString u;
  592. AsciiString a;
  593. // u = GadgetTextEntryGetText(textEntryMaxDisconnects);
  594. // a.translate(u);
  595. // pref.setMaxDisconnects(atoi(a.str()));
  596. // u = GadgetTextEntryGetText(textEntryMaxPoints);
  597. // a.translate(u);
  598. // pref.setMaxPoints(max(100, atoi(a.str())));
  599. // u = GadgetTextEntryGetText(textEntryMinPoints);
  600. // a.translate(u);
  601. // pref.setMinPoints(min(100, atoi(a.str())));
  602. //u = GadgetTextEntryGetText(textEntryWaitTime);
  603. //a.translate(u);
  604. //pref.setWaitTime(atoi(a.str()));
  605. GadgetComboBoxGetSelectedPos(comboBoxNumPlayers, &selected);
  606. pref.setNumPlayers(selected);
  607. GadgetComboBoxGetSelectedPos(comboBoxMaxPing, &selected);
  608. pref.setMaxPing(selected);
  609. Int item;
  610. GadgetComboBoxGetSelectedPos(comboBoxSide, &selected);
  611. item = (Int)GadgetComboBoxGetItemData(comboBoxSide, selected);
  612. pref.setSide(max(0, item));
  613. GadgetComboBoxGetSelectedPos(comboBoxColor, &selected);
  614. pref.setColor(max(0, selected));
  615. GadgetComboBoxGetSelectedPos(comboBoxMaxDisconnects, &selected);
  616. pref.setMaxDisconnects(selected);
  617. pref.write();
  618. }
  619. //-------------------------------------------------------------------------------------------------
  620. /** Initialize the WOL Quick Match Menu */
  621. //-------------------------------------------------------------------------------------------------
  622. void WOLQuickMatchMenuInit( WindowLayout *layout, void *userData )
  623. {
  624. isInInit = TRUE;
  625. if (TheGameSpyGame && TheGameSpyGame->isGameInProgress())
  626. {
  627. TheGameSpyGame->setGameInProgress(FALSE);
  628. // check if we were disconnected
  629. Int disconReason;
  630. if (TheGameSpyInfo->isDisconnectedAfterGameStart(&disconReason))
  631. {
  632. AsciiString disconMunkee;
  633. disconMunkee.format("GUI:GSDisconReason%d", disconReason);
  634. UnicodeString title, body;
  635. title = TheGameText->fetch( "GUI:GSErrorTitle" );
  636. body = TheGameText->fetch( disconMunkee );
  637. GameSpyCloseAllOverlays();
  638. GSMessageBoxOk( title, body );
  639. TheGameSpyInfo->reset();
  640. DEBUG_LOG(("WOLQuickMatchMenuInit() - game was in progress, and we were disconnected, so pop immediate back to main menu\n"));
  641. TheShell->popImmediate();
  642. return;
  643. }
  644. }
  645. nextScreen = NULL;
  646. buttonPushed = false;
  647. isShuttingDown = false;
  648. raiseMessageBoxes = true;
  649. if (TheNAT != NULL) {
  650. delete TheNAT;
  651. TheNAT = NULL;
  652. }
  653. parentWOLQuickMatchID = NAMEKEY( "WOLQuickMatchMenu.wnd:WOLQuickMatchMenuParent" );
  654. buttonBackID = NAMEKEY( "WOLQuickMatchMenu.wnd:ButtonBack" );
  655. buttonBuddiesID = NAMEKEY( "WOLQuickMatchMenu.wnd:ButtonBuddies" );
  656. buttonStartID = NAMEKEY( "WOLQuickMatchMenu.wnd:ButtonStart" );
  657. buttonStopID = NAMEKEY( "WOLQuickMatchMenu.wnd:ButtonStop" );
  658. buttonWidenID = NAMEKEY( "WOLQuickMatchMenu.wnd:ButtonWiden" );
  659. listboxQuickMatchID = NAMEKEY( "WOLQuickMatchMenu.wnd:ListboxQuickMatch" );
  660. listboxMapSelectID = NAMEKEY( "WOLQuickMatchMenu.wnd:ListBoxMapSelect" );
  661. buttonSelectAllMapsID = NAMEKEY( "WOLQuickMatchMenu.wnd:ButtonSelectAllMaps" );
  662. buttonSelectNoMapsID = NAMEKEY( "WOLQuickMatchMenu.wnd:ButtonSelectNoMaps" );
  663. //textEntryMaxDisconnectsID = NAMEKEY( "WOLQuickMatchMenu.wnd:TextEntryMaxDisconnects" );
  664. //textEntryMaxPointsID = NAMEKEY( "WOLQuickMatchMenu.wnd:TextEntryMaxPointPercent" );
  665. //textEntryMinPointsID = NAMEKEY( "WOLQuickMatchMenu.wnd:TextEntryMinPointPercent" );
  666. textEntryWaitTimeID = NAMEKEY( "WOLQuickMatchMenu.wnd:TextEntryWaitTime" );
  667. comboBoxMaxPingID = NAMEKEY( "WOLQuickMatchMenu.wnd:ComboBoxMaxPing" );
  668. comboBoxNumPlayersID = NAMEKEY( "WOLQuickMatchMenu.wnd:ComboBoxNumPlayers" );
  669. comboBoxLadderID = NAMEKEY( "WOLQuickMatchMenu.wnd:ComboBoxLadder" );
  670. comboBoxMaxDisconnectsID = NAMEKEY( "WOLQuickMatchMenu.wnd:ComboBoxMaxDisconnects" );
  671. staticTextNumPlayersID = NAMEKEY( "WOLQuickMatchMenu.wnd:StaticTextNumPlayers" );
  672. comboBoxSideID = NAMEKEY( "WOLQuickMatchMenu.wnd:ComboBoxSide" );
  673. comboBoxColorID = NAMEKEY( "WOLQuickMatchMenu.wnd:ComboBoxColor" );
  674. parentWOLQuickMatch = TheWindowManager->winGetWindowFromId( NULL, parentWOLQuickMatchID );
  675. buttonBack = TheWindowManager->winGetWindowFromId( parentWOLQuickMatch, buttonBackID);
  676. buttonStart = TheWindowManager->winGetWindowFromId( parentWOLQuickMatch, buttonStartID);
  677. buttonStop = TheWindowManager->winGetWindowFromId( parentWOLQuickMatch, buttonStopID);
  678. buttonWiden = TheWindowManager->winGetWindowFromId( parentWOLQuickMatch, buttonWidenID);
  679. quickmatchTextWindow = TheWindowManager->winGetWindowFromId( parentWOLQuickMatch, listboxQuickMatchID);
  680. listboxMapSelect = TheWindowManager->winGetWindowFromId( parentWOLQuickMatch, listboxMapSelectID);
  681. //textEntryMaxDisconnects = TheWindowManager->winGetWindowFromId( parentWOLQuickMatch, textEntryMaxDisconnectsID );
  682. //textEntryMaxPoints = TheWindowManager->winGetWindowFromId( parentWOLQuickMatch, textEntryMaxPointsID );
  683. //textEntryMinPoints = TheWindowManager->winGetWindowFromId( parentWOLQuickMatch, textEntryMinPointsID );
  684. textEntryWaitTime = TheWindowManager->winGetWindowFromId( parentWOLQuickMatch, textEntryWaitTimeID );
  685. comboBoxMaxPing = TheWindowManager->winGetWindowFromId( parentWOLQuickMatch, comboBoxMaxPingID );
  686. comboBoxNumPlayers = TheWindowManager->winGetWindowFromId( parentWOLQuickMatch, comboBoxNumPlayersID );
  687. comboBoxLadder = TheWindowManager->winGetWindowFromId( parentWOLQuickMatch, comboBoxLadderID );
  688. comboBoxMaxDisconnects = TheWindowManager->winGetWindowFromId( parentWOLQuickMatch, comboBoxMaxDisconnectsID );
  689. TheGameSpyInfo->registerTextWindow(quickmatchTextWindow);
  690. staticTextNumPlayers = TheWindowManager->winGetWindowFromId( parentWOLQuickMatch, staticTextNumPlayersID );
  691. comboBoxSide = TheWindowManager->winGetWindowFromId( parentWOLQuickMatch, comboBoxSideID );
  692. comboBoxColor = TheWindowManager->winGetWindowFromId( parentWOLQuickMatch, comboBoxColorID );
  693. if (TheLadderList->getStandardLadders()->size() == 0
  694. && TheLadderList->getSpecialLadders()->size() == 0
  695. && TheLadderList->getLocalLadders()->size() == 0)
  696. {
  697. // no ladders, so just disable them
  698. comboBoxDisabledLadder = comboBoxLadder;
  699. comboBoxLadder = NULL;
  700. isPopulatingLadderBox = TRUE;
  701. Color normalColor = GameSpyColor[GSCOLOR_MAP_UNSELECTED];
  702. Int index;
  703. GadgetComboBoxReset( comboBoxDisabledLadder );
  704. index = GadgetComboBoxAddEntry( comboBoxDisabledLadder, TheGameText->fetch("GUI:NoLadder"), normalColor );
  705. GadgetComboBoxSetItemData( comboBoxDisabledLadder, index, 0 );
  706. GadgetComboBoxSetSelectedPos( comboBoxDisabledLadder, index );
  707. isPopulatingLadderBox = FALSE;
  708. /** This code would actually *hide* the combo box, but it doesn't look as good. Left here since someone will want to
  709. ** see it at some point. :P
  710. if (comboBoxLadder)
  711. {
  712. comboBoxLadder->winHide(TRUE);
  713. comboBoxLadder->winEnable(FALSE);
  714. }
  715. comboBoxLadder = NULL;
  716. GameWindow *staticTextLadder = TheWindowManager->winGetWindowFromId( parentWOLQuickMatch,
  717. NAMEKEY("WOLQuickMatchMenu.wnd:StaticTextLadder") );
  718. if (staticTextLadder)
  719. staticTextLadder->winHide(TRUE);
  720. */
  721. }
  722. GameWindow *buttonBuddies = TheWindowManager->winGetWindowFromId(NULL, buttonBuddiesID);
  723. if (buttonBuddies)
  724. buttonBuddies->winEnable(TRUE);
  725. GameWindow *staticTextTitle = TheWindowManager->winGetWindowFromId( parentWOLQuickMatch,
  726. NAMEKEY("WOLQuickMatchMenu.wnd:StaticTextTitle") );
  727. if (staticTextTitle)
  728. {
  729. UnicodeString tmp;
  730. tmp.format(TheGameText->fetch("GUI:QuickMatchTitle"), TheGameSpyInfo->getLocalName().str());
  731. GadgetStaticTextSetText(staticTextTitle, tmp);
  732. }
  733. // QM is not going yet, so disable the Widen Search button
  734. buttonWiden->winEnable( FALSE );
  735. buttonStop->winHide( TRUE );
  736. buttonStart->winHide( FALSE );
  737. GadgetListBoxReset(quickmatchTextWindow);
  738. enableOptionsGadgets(TRUE);
  739. // Show Menu
  740. layout->hide( FALSE );
  741. // Set Keyboard to Main Parent
  742. TheWindowManager->winSetFocus( parentWOLQuickMatch );
  743. // fill in preferences
  744. selectedImage = TheMappedImageCollection->findImageByName("CustomMatch_selected");
  745. unselectedImage = TheMappedImageCollection->findImageByName("CustomMatch_deselected");
  746. QuickMatchPreferences pref;
  747. UnicodeString s;
  748. // s.format(L"%d", pref.getMaxDisconnects());
  749. // GadgetTextEntrySetText(textEntryMaxDisconnects, s);
  750. // s.format(L"%d", pref.getMaxPoints());
  751. // GadgetTextEntrySetText(textEntryMaxPoints, s);
  752. // s.format(L"%d", pref.getMinPoints());
  753. // GadgetTextEntrySetText(textEntryMinPoints, s);
  754. //s.format(L"%d", pref.getWaitTime());
  755. //GadgetTextEntrySetText(textEntryWaitTime, s);
  756. maxPoints= pref.getMaxPoints();
  757. minPoints = pref.getMinPoints();
  758. Color c = GameSpyColor[GSCOLOR_DEFAULT];
  759. GadgetComboBoxReset( comboBoxNumPlayers );
  760. Int i;
  761. for (i=1; i<5; ++i)
  762. {
  763. s.format(TheGameText->fetch("GUI:PlayersVersusPlayers"), i, i);
  764. GadgetComboBoxAddEntry( comboBoxNumPlayers, s, c );
  765. }
  766. GadgetComboBoxSetSelectedPos( comboBoxNumPlayers, max(0, pref.getNumPlayers()) );
  767. GadgetComboBoxReset(comboBoxMaxDisconnects);
  768. GadgetComboBoxAddEntry( comboBoxMaxDisconnects, TheGameText->fetch("GUI:Any"), c);
  769. for( i = 1; i < MAX_DISCONNECTS_COUNT; ++i )
  770. {
  771. s.format(L"%d", MAX_DISCONNECTS[i]);
  772. GadgetComboBoxAddEntry( comboBoxMaxDisconnects, s, c );
  773. }
  774. Int maxDisconIndex = max(0, pref.getMaxDisconnects());
  775. GadgetComboBoxSetSelectedPos(comboBoxMaxDisconnects, maxDisconIndex);
  776. GadgetComboBoxReset( comboBoxMaxPing );
  777. maxPingEntries = (TheGameSpyConfig->getPingTimeoutInMs() - 1) / 100;
  778. maxPingEntries++; // need to add the entry for the actual timeout
  779. for (i=1; i <maxPingEntries; ++i)
  780. {
  781. s.format(TheGameText->fetch("GUI:TimeInMilliseconds"), i*100);
  782. GadgetComboBoxAddEntry( comboBoxMaxPing, s, c );
  783. }
  784. GadgetComboBoxAddEntry( comboBoxMaxPing, TheGameText->fetch("GUI:ANY"), c );
  785. i = pref.getMaxPing();
  786. if( i < 0 )
  787. i = 0;
  788. if( i >= maxPingEntries )
  789. i = maxPingEntries - 1;
  790. GadgetComboBoxSetSelectedPos( comboBoxMaxPing, i );
  791. populateQMColorComboBox(pref);
  792. populateQMSideComboBox(pref.getSide(), getLadderInfo());
  793. PopulateQMLadderComboBox();
  794. TheShell->showShellMap(TRUE);
  795. TheGameSpyGame->reset();
  796. GadgetListBoxReset(listboxMapSelect);
  797. populateQuickMatchMapSelectListbox(pref);
  798. UpdateLocalPlayerStats();
  799. UpdateStartButton();
  800. TheTransitionHandler->setGroup("WOLQuickMatchMenuFade");
  801. isInInit= FALSE;
  802. } // WOLQuickMatchMenuInit
  803. //-------------------------------------------------------------------------------------------------
  804. /** This is called when a shutdown is complete for this menu */
  805. //-------------------------------------------------------------------------------------------------
  806. static void shutdownComplete( WindowLayout *layout )
  807. {
  808. isShuttingDown = false;
  809. // hide the layout
  810. layout->hide( TRUE );
  811. // our shutdown is complete
  812. TheShell->shutdownComplete( layout, (nextScreen != NULL) );
  813. if (nextScreen != NULL)
  814. {
  815. TheShell->push(nextScreen);
  816. }
  817. nextScreen = NULL;
  818. } // end if
  819. //-------------------------------------------------------------------------------------------------
  820. /** WOL Quick Match Menu shutdown method */
  821. //-------------------------------------------------------------------------------------------------
  822. void WOLQuickMatchMenuShutdown( WindowLayout *layout, void *userData )
  823. {
  824. TheGameSpyInfo->unregisterTextWindow(quickmatchTextWindow);
  825. if (!TheGameEngine->getQuitting())
  826. saveQuickMatchOptions();
  827. parentWOLQuickMatch = NULL;
  828. buttonBack = NULL;
  829. quickmatchTextWindow = NULL;
  830. selectedImage = unselectedImage = NULL;
  831. isShuttingDown = true;
  832. // if we are shutting down for an immediate pop, skip the animations
  833. Bool popImmediate = *(Bool *)userData;
  834. if( popImmediate )
  835. {
  836. shutdownComplete( layout );
  837. return;
  838. } //end if
  839. TheShell->reverseAnimatewindow();
  840. TheTransitionHandler->reverse("WOLQuickMatchMenuFade");
  841. RaiseGSMessageBox();
  842. } // WOLQuickMatchMenuShutdown
  843. #ifdef PERF_TEST
  844. static const char* getMessageString(Int t)
  845. {
  846. switch(t)
  847. {
  848. case PeerResponse::PEERRESPONSE_LOGIN:
  849. return "login";
  850. case PeerResponse::PEERRESPONSE_DISCONNECT:
  851. return "disconnect";
  852. case PeerResponse::PEERRESPONSE_MESSAGE:
  853. return "message";
  854. case PeerResponse::PEERRESPONSE_GROUPROOM:
  855. return "group room";
  856. case PeerResponse::PEERRESPONSE_STAGINGROOM:
  857. return "staging room";
  858. case PeerResponse::PEERRESPONSE_STAGINGROOMPLAYERINFO:
  859. return "staging room player info";
  860. case PeerResponse::PEERRESPONSE_JOINGROUPROOM:
  861. return "group room join";
  862. case PeerResponse::PEERRESPONSE_CREATESTAGINGROOM:
  863. return "staging room create";
  864. case PeerResponse::PEERRESPONSE_JOINSTAGINGROOM:
  865. return "staging room join";
  866. case PeerResponse::PEERRESPONSE_PLAYERJOIN:
  867. return "player join";
  868. case PeerResponse::PEERRESPONSE_PLAYERLEFT:
  869. return "player part";
  870. case PeerResponse::PEERRESPONSE_PLAYERCHANGEDNICK:
  871. return "player nick";
  872. case PeerResponse::PEERRESPONSE_PLAYERINFO:
  873. return "player info";
  874. case PeerResponse::PEERRESPONSE_PLAYERCHANGEDFLAGS:
  875. return "player flags";
  876. case PeerResponse::PEERRESPONSE_ROOMUTM:
  877. return "room UTM";
  878. case PeerResponse::PEERRESPONSE_PLAYERUTM:
  879. return "player UTM";
  880. case PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS:
  881. return "QM status";
  882. case PeerResponse::PEERRESPONSE_GAMESTART:
  883. return "game start";
  884. case PeerResponse::PEERRESPONSE_FAILEDTOHOST:
  885. return "host failure";
  886. }
  887. return "unknown";
  888. }
  889. #endif // PERF_TEST
  890. //-------------------------------------------------------------------------------------------------
  891. /** WOL Quick Match Menu update method */
  892. //-------------------------------------------------------------------------------------------------
  893. void WOLQuickMatchMenuUpdate( WindowLayout * layout, void *userData)
  894. {
  895. if (TheGameLogic->isInShellGame() && TheGameLogic->getFrame() == 1)
  896. {
  897. SignalUIInteraction(SHELL_SCRIPT_HOOK_GENERALS_ONLINE_ENTERED_FROM_GAME);
  898. }
  899. // We'll only be successful if we've requested to
  900. if(isShuttingDown && TheShell->isAnimFinished()&& TheTransitionHandler->isFinished())
  901. shutdownComplete(layout);
  902. if (raiseMessageBoxes)
  903. {
  904. RaiseGSMessageBox();
  905. raiseMessageBoxes = false;
  906. }
  907. /// @todo: MDC handle disconnects in-game the same way as Custom Match!
  908. if (TheShell->isAnimFinished() && !buttonPushed && TheGameSpyPeerMessageQueue)
  909. {
  910. HandleBuddyResponses();
  911. HandlePersistentStorageResponses();
  912. if (TheGameSpyGame && TheGameSpyGame->isGameInProgress())
  913. {
  914. if (TheGameSpyInfo->isDisconnectedAfterGameStart(NULL))
  915. {
  916. return; // already been disconnected, so don't worry.
  917. }
  918. Int allowedMessages = TheGameSpyInfo->getMaxMessagesPerUpdate();
  919. Bool sawImportantMessage = FALSE;
  920. PeerResponse resp;
  921. while (allowedMessages-- && !sawImportantMessage && TheGameSpyPeerMessageQueue->getResponse( resp ))
  922. {
  923. switch (resp.peerResponseType)
  924. {
  925. case PeerResponse::PEERRESPONSE_DISCONNECT:
  926. {
  927. sawImportantMessage = TRUE;
  928. AsciiString disconMunkee;
  929. disconMunkee.format("GUI:GSDisconReason%d", resp.discon.reason);
  930. // check for scorescreen
  931. NameKeyType listboxChatWindowScoreScreenID = NAMEKEY("ScoreScreen.wnd:ListboxChatWindowScoreScreen");
  932. GameWindow *listboxChatWindowScoreScreen = TheWindowManager->winGetWindowFromId( NULL, listboxChatWindowScoreScreenID );
  933. if (listboxChatWindowScoreScreen)
  934. {
  935. GadgetListBoxAddEntryText(listboxChatWindowScoreScreen, TheGameText->fetch(disconMunkee),
  936. GameSpyColor[GSCOLOR_DEFAULT], -1);
  937. }
  938. else
  939. {
  940. // still ingame
  941. TheInGameUI->message(disconMunkee);
  942. }
  943. TheGameSpyInfo->markAsDisconnectedAfterGameStart(resp.discon.reason);
  944. }
  945. }
  946. }
  947. return; // if we're in game, all we care about is if we've been disconnected from the chat server
  948. }
  949. if (TheNAT != NULL) {
  950. NATStateType NATState = TheNAT->update();
  951. if (NATState == NATSTATE_DONE)
  952. {
  953. TheGameSpyGame->launchGame();
  954. if (TheGameSpyInfo) // this can be blown away by a disconnect on the map transfer screen
  955. TheGameSpyInfo->leaveStagingRoom();
  956. return; // don't do any more processing this frame, in case the screen goes away
  957. }
  958. else if (NATState == NATSTATE_FAILED)
  959. {
  960. // delete TheNAT, its no good for us anymore.
  961. delete TheNAT;
  962. TheNAT = NULL;
  963. // Just back out. This cleans up some slot list problems
  964. buttonPushed = true;
  965. GSMessageBoxOk(TheGameText->fetch("GUI:Error"), TheGameText->fetch("GUI:NATNegotiationFailed"));
  966. nextScreen = "Menus/WOLWelcomeMenu.wnd";
  967. TheShell->pop();
  968. return; // don't do any more processing this frame, in case the screen goes away
  969. }
  970. }
  971. #ifdef PERF_TEST
  972. UnsignedInt start = timeGetTime();
  973. UnsignedInt end = timeGetTime();
  974. std::list<Int> responses;
  975. Int numMessages = 0;
  976. #endif // PERF_TEST
  977. Int allowedMessages = TheGameSpyInfo->getMaxMessagesPerUpdate();
  978. Bool sawImportantMessage = FALSE;
  979. PeerResponse resp;
  980. while (allowedMessages-- && !sawImportantMessage && TheGameSpyPeerMessageQueue->getResponse( resp ))
  981. {
  982. #ifdef PERF_TEST
  983. ++numMessages;
  984. responses.push_back(resp.peerResponseType);
  985. #endif // PERF_TEST
  986. switch (resp.peerResponseType)
  987. {
  988. case PeerResponse::PEERRESPONSE_PLAYERUTM:
  989. {
  990. if (!stricmp(resp.command.c_str(), "STATS"))
  991. {
  992. DEBUG_LOG(("Saw STATS from %s, data was '%s'\n", resp.nick.c_str(), resp.commandOptions.c_str()));
  993. AsciiString data = resp.commandOptions.c_str();
  994. AsciiString idStr;
  995. data.nextToken(&idStr, " ");
  996. Int id = atoi(idStr.str());
  997. DEBUG_LOG(("data: %d(%s) - '%s'\n", id, idStr.str(), data.str()));
  998. PSPlayerStats stats = TheGameSpyPSMessageQueue->parsePlayerKVPairs(data.str());
  999. PSPlayerStats oldStats = TheGameSpyPSMessageQueue->findPlayerStatsByID(id);
  1000. stats.id = id;
  1001. DEBUG_LOG(("Parsed ID is %d, old ID is %d\n", stats.id, oldStats.id));
  1002. if (stats.id && (oldStats.id == 0))
  1003. TheGameSpyPSMessageQueue->trackPlayerStats(stats);
  1004. // now fill in the profileID in the game slot
  1005. AsciiString nick = resp.nick.c_str();
  1006. for (Int i=0; i<MAX_SLOTS; ++i)
  1007. {
  1008. GameSpyGameSlot *slot = TheGameSpyGame->getGameSpySlot(i);
  1009. if (slot && slot->isHuman() && (slot->getLoginName().compareNoCase(nick) == 0))
  1010. {
  1011. slot->setProfileID(id);
  1012. break;
  1013. }
  1014. }
  1015. }
  1016. Int slotNum = TheGameSpyGame->getSlotNum(resp.nick.c_str());
  1017. if ((slotNum >= 0) && (slotNum < MAX_SLOTS) && (!stricmp(resp.command.c_str(), "NAT"))) {
  1018. // this is a command for NAT negotiations, pass if off to TheNAT
  1019. sawImportantMessage = TRUE;
  1020. if (TheNAT != NULL) {
  1021. TheNAT->processGlobalMessage(slotNum, resp.commandOptions.c_str());
  1022. }
  1023. }
  1024. /*
  1025. else if (key == "NAT")
  1026. {
  1027. if ((val >= FirewallHelperClass::FIREWALL_TYPE_SIMPLE) &&
  1028. (val <= FirewallHelperClass::FIREWALL_TYPE_DESTINATION_PORT_DELTA))
  1029. {
  1030. slot->setNATBehavior((FirewallHelperClass::FirewallBehaviorType)val);
  1031. DEBUG_LOG(("Setting NAT behavior to %d for player %d\n", val, slotNum));
  1032. change = true;
  1033. }
  1034. else
  1035. {
  1036. DEBUG_LOG(("Rejecting invalid NAT behavior %d from player %d\n", val, slotNum));
  1037. }
  1038. }
  1039. */
  1040. }
  1041. break;
  1042. case PeerResponse::PEERRESPONSE_DISCONNECT:
  1043. {
  1044. sawImportantMessage = TRUE;
  1045. UnicodeString title, body;
  1046. AsciiString disconMunkee;
  1047. disconMunkee.format("GUI:GSDisconReason%d", resp.discon.reason);
  1048. title = TheGameText->fetch( "GUI:GSErrorTitle" );
  1049. body = TheGameText->fetch( disconMunkee );
  1050. GameSpyCloseAllOverlays();
  1051. GSMessageBoxOk( title, body );
  1052. TheGameSpyInfo->reset();
  1053. TheShell->pop();
  1054. }
  1055. case PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS:
  1056. {
  1057. sawImportantMessage = TRUE;
  1058. switch( resp.qmStatus.status )
  1059. {
  1060. case QM_IDLE:
  1061. //TheGameSpyInfo->addText(UnicodeString(L"Status: QM_IDLE"), GameSpyColor[GSCOLOR_DEFAULT], quickmatchTextWindow);
  1062. break;
  1063. case QM_JOININGQMCHANNEL:
  1064. TheGameSpyInfo->addText(TheGameText->fetch("QM:JOININGQMCHANNEL"), GameSpyColor[GSCOLOR_DEFAULT], quickmatchTextWindow);
  1065. break;
  1066. case QM_LOOKINGFORBOT:
  1067. TheGameSpyInfo->addText(TheGameText->fetch("QM:LOOKINGFORBOT"), GameSpyColor[GSCOLOR_DEFAULT], quickmatchTextWindow);
  1068. break;
  1069. case QM_SENTINFO:
  1070. TheGameSpyInfo->addText(TheGameText->fetch("QM:SENTINFO"), GameSpyColor[GSCOLOR_DEFAULT], quickmatchTextWindow);
  1071. break;
  1072. case QM_WORKING:
  1073. {
  1074. UnicodeString s;
  1075. s.format(TheGameText->fetch("QM:WORKING"), resp.qmStatus.poolSize);
  1076. TheGameSpyInfo->addText(s, GameSpyColor[GSCOLOR_DEFAULT], quickmatchTextWindow);
  1077. }
  1078. buttonWiden->winEnable( TRUE );
  1079. break;
  1080. case QM_POOLSIZE:
  1081. {
  1082. UnicodeString s;
  1083. s.format(TheGameText->fetch("QM:POOLSIZE"), resp.qmStatus.poolSize);
  1084. TheGameSpyInfo->addText(s, GameSpyColor[GSCOLOR_DEFAULT], quickmatchTextWindow);
  1085. }
  1086. break;
  1087. case QM_WIDENINGSEARCH:
  1088. TheGameSpyInfo->addText(TheGameText->fetch("QM:WIDENINGSEARCH"), GameSpyColor[GSCOLOR_DEFAULT], quickmatchTextWindow);
  1089. buttonWiden->winEnable( FALSE );
  1090. break;
  1091. case QM_MATCHED:
  1092. {
  1093. TheGameSpyInfo->addText(TheGameText->fetch("QM:MATCHED"), GameSpyColor[GSCOLOR_DEFAULT], quickmatchTextWindow);
  1094. buttonWiden->winEnable( FALSE );
  1095. TheGameSpyGame->enterGame();
  1096. TheGameSpyGame->setSeed(resp.qmStatus.seed);
  1097. TheGameSpyGame->markGameAsQM();
  1098. const LadderInfo *info = getLadderInfo();
  1099. if (!info)
  1100. {
  1101. TheGameSpyGame->setLadderIP("localhost");
  1102. TheGameSpyGame->setLadderPort(0);
  1103. }
  1104. else
  1105. {
  1106. TheGameSpyGame->setLadderIP(info->address);
  1107. TheGameSpyGame->setLadderPort(info->port);
  1108. }
  1109. Int i;
  1110. Int numPlayers = 0;
  1111. for (i=0; i<MAX_SLOTS; ++i)
  1112. {
  1113. if (!resp.stagingRoomPlayerNames[i].empty())
  1114. ++numPlayers;
  1115. }
  1116. std::list<AsciiString> maps = TheGameSpyConfig->getQMMaps();
  1117. #if VARIABLE_NUMBER_OF_MAPS
  1118. std::list<AsciiString>::const_iterator it = maps.begin();
  1119. std::advance(it, resp.qmStatus.mapIdx);
  1120. AsciiString theMap = *it;
  1121. theMap.toLower();
  1122. TheGameSpyGame->setMap(theMap);
  1123. #else
  1124. for (std::list<AsciiString>::const_iterator it = maps.begin(); it != maps.end(); ++it)
  1125. {
  1126. AsciiString theMap = *it;
  1127. theMap.toLower();
  1128. const MapMetaData *md = TheMapCache->findMap(theMap);
  1129. if (md && md->m_numPlayers >= numPlayers)
  1130. {
  1131. TheGameSpyGame->setMap(*it);
  1132. if (resp.qmStatus.mapIdx-- == 0)
  1133. break;
  1134. }
  1135. }
  1136. #endif
  1137. Int numPlayersPerTeam = numPlayers/2;
  1138. DEBUG_ASSERTCRASH(numPlayersPerTeam, ("0 players per team???"));
  1139. if (!numPlayersPerTeam)
  1140. numPlayersPerTeam = 1;
  1141. for (i=0; i<MAX_SLOTS; ++i)
  1142. {
  1143. GameSpyGameSlot *slot = TheGameSpyGame->getGameSpySlot(i);
  1144. if (resp.stagingRoomPlayerNames[i].empty())
  1145. {
  1146. slot->setState(SLOT_CLOSED);
  1147. }
  1148. else
  1149. {
  1150. AsciiString aName = resp.stagingRoomPlayerNames[i].c_str();
  1151. UnicodeString uName;
  1152. uName.translate(aName);
  1153. slot->setState(SLOT_PLAYER, uName, resp.qmStatus.IP[i]);
  1154. slot->setColor(resp.qmStatus.color[i]);
  1155. slot->setPlayerTemplate(resp.qmStatus.side[i]);
  1156. //slot->setProfileID(0);
  1157. slot->setNATBehavior((FirewallHelperClass::FirewallBehaviorType)resp.qmStatus.nat[i]);
  1158. slot->setLocale("");
  1159. slot->setTeamNumber( i/numPlayersPerTeam );
  1160. if (i==0)
  1161. TheGameSpyGame->setGameName(uName);
  1162. }
  1163. }
  1164. DEBUG_LOG(("Starting a QM game: options=[%s]\n", GameInfoToAsciiString(TheGameSpyGame).str()));
  1165. SendStatsToOtherPlayers(TheGameSpyGame);
  1166. TheGameSpyGame->startGame(0);
  1167. GameWindow *buttonBuddies = TheWindowManager->winGetWindowFromId(NULL, buttonBuddiesID);
  1168. if (buttonBuddies)
  1169. buttonBuddies->winEnable(FALSE);
  1170. GameSpyCloseOverlay(GSOVERLAY_BUDDY);
  1171. }
  1172. break;
  1173. case QM_INCHANNEL:
  1174. TheGameSpyInfo->addText(TheGameText->fetch("QM:INCHANNEL"), GameSpyColor[GSCOLOR_DEFAULT], quickmatchTextWindow);
  1175. break;
  1176. case QM_NEGOTIATINGFIREWALLS:
  1177. TheGameSpyInfo->addText(TheGameText->fetch("QM:NEGOTIATINGFIREWALLS"), GameSpyColor[GSCOLOR_DEFAULT], quickmatchTextWindow);
  1178. break;
  1179. case QM_STARTINGGAME:
  1180. TheGameSpyInfo->addText(TheGameText->fetch("QM:STARTINGGAME"), GameSpyColor[GSCOLOR_DEFAULT], quickmatchTextWindow);
  1181. break;
  1182. case QM_COULDNOTFINDBOT:
  1183. TheGameSpyInfo->addText(TheGameText->fetch("QM:COULDNOTFINDBOT"), GameSpyColor[GSCOLOR_DEFAULT], quickmatchTextWindow);
  1184. buttonWiden->winEnable( FALSE );
  1185. buttonStart->winHide( FALSE );
  1186. buttonStop->winHide( TRUE );
  1187. enableOptionsGadgets(TRUE);
  1188. break;
  1189. case QM_COULDNOTFINDCHANNEL:
  1190. TheGameSpyInfo->addText(TheGameText->fetch("QM:COULDNOTFINDCHANNEL"), GameSpyColor[GSCOLOR_DEFAULT], quickmatchTextWindow);
  1191. buttonWiden->winEnable( FALSE );
  1192. buttonStart->winHide( FALSE );
  1193. buttonStop->winHide( TRUE );
  1194. enableOptionsGadgets(TRUE);
  1195. break;
  1196. case QM_COULDNOTNEGOTIATEFIREWALLS:
  1197. TheGameSpyInfo->addText(TheGameText->fetch("QM:COULDNOTNEGOTIATEFIREWALLS"), GameSpyColor[GSCOLOR_DEFAULT], quickmatchTextWindow);
  1198. buttonWiden->winEnable( FALSE );
  1199. buttonStart->winHide( FALSE );
  1200. buttonStop->winHide( TRUE );
  1201. enableOptionsGadgets(TRUE);
  1202. break;
  1203. case QM_STOPPED:
  1204. TheGameSpyInfo->addText(TheGameText->fetch("QM:STOPPED"), GameSpyColor[GSCOLOR_DEFAULT], quickmatchTextWindow);
  1205. buttonWiden->winEnable( FALSE );
  1206. buttonStart->winHide( FALSE );
  1207. buttonStop->winHide( TRUE );
  1208. enableOptionsGadgets(TRUE);
  1209. break;
  1210. }
  1211. }
  1212. break;
  1213. }
  1214. }
  1215. #ifdef PERF_TEST
  1216. // check performance
  1217. end = timeGetTime();
  1218. UnsignedInt frameTime = end-start;
  1219. if (frameTime > 100 || responses.size() > 20)
  1220. {
  1221. UnicodeString munkee;
  1222. munkee.format(L"inQM:%d %d ms, %d messages", s_inQM, frameTime, responses.size());
  1223. TheGameSpyInfo->addText(munkee, GameSpyColor[GSCOLOR_DEFAULT], quickmatchTextWindow);
  1224. PERF_LOG(("%ls\n", munkee.str()));
  1225. std::list<Int>::const_iterator it;
  1226. for (it = responses.begin(); it != responses.end(); ++it)
  1227. {
  1228. PERF_LOG((" %s\n", getMessageString(*it)));
  1229. }
  1230. }
  1231. #endif // PERF_TEST
  1232. }
  1233. }// WOLQuickMatchMenuUpdate
  1234. //-------------------------------------------------------------------------------------------------
  1235. /** WOL Quick Match Menu input callback */
  1236. //-------------------------------------------------------------------------------------------------
  1237. WindowMsgHandledType WOLQuickMatchMenuInput( GameWindow *window, UnsignedInt msg,
  1238. WindowMsgData mData1, WindowMsgData mData2 )
  1239. {
  1240. switch( msg )
  1241. {
  1242. // --------------------------------------------------------------------------------------------
  1243. case GWM_CHAR:
  1244. {
  1245. UnsignedByte key = mData1;
  1246. UnsignedByte state = mData2;
  1247. if (buttonPushed)
  1248. break;
  1249. switch( key )
  1250. {
  1251. // ----------------------------------------------------------------------------------------
  1252. case KEY_ESC:
  1253. {
  1254. //
  1255. // send a simulated selected event to the parent window of the
  1256. // back/exit button
  1257. //
  1258. if( BitTest( state, KEY_STATE_UP ) )
  1259. {
  1260. if(!buttonBack->winIsHidden())
  1261. TheWindowManager->winSendSystemMsg( window, GBM_SELECTED,
  1262. (WindowMsgData)buttonBack, buttonBackID );
  1263. } // end if
  1264. // don't let key fall through anywhere else
  1265. return MSG_HANDLED;
  1266. } // end escape
  1267. } // end switch( key )
  1268. } // end char
  1269. } // end switch( msg )
  1270. return MSG_IGNORED;
  1271. }// WOLQuickMatchMenuInput
  1272. //-------------------------------------------------------------------------------------------------
  1273. /** WOL Quick Match Menu window system callback */
  1274. //-------------------------------------------------------------------------------------------------
  1275. WindowMsgHandledType WOLQuickMatchMenuSystem( GameWindow *window, UnsignedInt msg,
  1276. WindowMsgData mData1, WindowMsgData mData2 )
  1277. {
  1278. UnicodeString txtInput;
  1279. switch( msg )
  1280. {
  1281. case GWM_CREATE:
  1282. {
  1283. break;
  1284. } // case GWM_DESTROY:
  1285. case GWM_DESTROY:
  1286. {
  1287. break;
  1288. } // case GWM_DESTROY:
  1289. case GWM_INPUT_FOCUS:
  1290. {
  1291. // if we're givin the opportunity to take the keyboard focus we must say we want it
  1292. if( mData1 == TRUE )
  1293. *(Bool *)mData2 = TRUE;
  1294. return MSG_HANDLED;
  1295. }//case GWM_INPUT_FOCUS:
  1296. case GCM_SELECTED:
  1297. {
  1298. if (buttonPushed)
  1299. break;
  1300. GameWindow *control = (GameWindow *)mData1;
  1301. Int controlID = control->winGetWindowId();
  1302. Int pos = -1;
  1303. GadgetComboBoxGetSelectedPos(control, &pos);
  1304. saveQuickMatchOptions();
  1305. if (controlID == comboBoxLadderID && !isPopulatingLadderBox)
  1306. {
  1307. if (pos >= 0)
  1308. {
  1309. QuickMatchPreferences pref;
  1310. Int ladderID = (Int)GadgetComboBoxGetItemData(control, pos);
  1311. if (ladderID == 0)
  1312. {
  1313. // no ladder selected - enable buttons
  1314. GadgetComboBoxSetSelectedPos(comboBoxNumPlayers, max(0, pref.getNumPlayers()/2-1));
  1315. comboBoxNumPlayers->winEnable( TRUE );
  1316. populateQMSideComboBox(pref.getSide()); // this will set side to random and disable if necessary
  1317. }
  1318. else if (ladderID > 0)
  1319. {
  1320. // ladder selected - disable buttons
  1321. const LadderInfo *li = TheLadderList->findLadderByIndex(ladderID);
  1322. if (li)
  1323. GadgetComboBoxSetSelectedPos(comboBoxNumPlayers, li->playersPerTeam-1);
  1324. else
  1325. GadgetComboBoxSetSelectedPos(comboBoxNumPlayers, 0);
  1326. comboBoxNumPlayers->winEnable( FALSE );
  1327. populateQMSideComboBox(pref.getSide(), li); // this will set side to random and disable if necessary
  1328. }
  1329. else
  1330. {
  1331. // "Choose a ladder" selected - open overlay
  1332. PopulateQMLadderComboBox(); // this restores the non-"Choose a ladder" selection
  1333. GameSpyOpenOverlay( GSOVERLAY_LADDERSELECT );
  1334. }
  1335. }
  1336. }
  1337. if (!isInInit)
  1338. {
  1339. QuickMatchPreferences pref;
  1340. populateQuickMatchMapSelectListbox(pref);
  1341. UpdateStartButton();
  1342. }
  1343. break;
  1344. } // case GCM_SELECTED
  1345. case GBM_SELECTED:
  1346. {
  1347. if (buttonPushed)
  1348. break;
  1349. GameWindow *control = (GameWindow *)mData1;
  1350. Int controlID = control->winGetWindowId();
  1351. static NameKeyType buttonOptionsID = NAMEKEY("WOLQuickMatchMenu.wnd:ButtonOptions");
  1352. if ( controlID == buttonStopID )
  1353. {
  1354. PeerRequest req;
  1355. req.peerRequestType = PeerRequest::PEERREQUEST_STOPQUICKMATCH;
  1356. TheGameSpyPeerMessageQueue->addRequest(req);
  1357. buttonWiden->winEnable( FALSE );
  1358. buttonStart->winHide( FALSE );
  1359. buttonStop->winHide( TRUE );
  1360. enableOptionsGadgets(TRUE);
  1361. TheGameSpyInfo->addText(TheGameText->fetch("GUI:QMAborted"), GameSpyColor[GSCOLOR_DEFAULT], quickmatchTextWindow);
  1362. }
  1363. else if ( controlID == buttonOptionsID )
  1364. {
  1365. GameWindow *win =TheWindowManager->winGetWindowFromId(parentWOLQuickMatch,buttonOptionsID);
  1366. if (isInfoShown())
  1367. {
  1368. hideInfoGadgets(TRUE);
  1369. hideOptionsGadgets(FALSE);
  1370. GadgetButtonSetText(win, TheGameText->fetch("GUI:PlayerInfo"));
  1371. }
  1372. else
  1373. {
  1374. hideInfoGadgets(FALSE);
  1375. hideOptionsGadgets(TRUE);
  1376. GadgetButtonSetText(win, TheGameText->fetch("GUI:Setup"));
  1377. }
  1378. }
  1379. else if ( controlID == buttonWidenID )
  1380. {
  1381. PeerRequest req;
  1382. req.peerRequestType = PeerRequest::PEERREQUEST_WIDENQUICKMATCHSEARCH;
  1383. TheGameSpyPeerMessageQueue->addRequest(req);
  1384. buttonWiden->winEnable( FALSE );
  1385. }
  1386. else if ( controlID == buttonStartID )
  1387. {
  1388. PeerRequest req;
  1389. req.peerRequestType = PeerRequest::PEERREQUEST_STARTQUICKMATCH;
  1390. req.qmMaps.clear();
  1391. #if VARIABLE_NUMBER_OF_MAPS
  1392. for (MapListboxIndex::iterator idxIt = mapListboxIndex.begin(); idxIt != mapListboxIndex.end(); ++idxIt) {
  1393. Int index = (*idxIt);
  1394. if (index >= 0)
  1395. {
  1396. req.qmMaps.push_back(GadgetListBoxGetItemData(listboxMapSelect, index, 0));
  1397. }
  1398. else
  1399. {
  1400. req.qmMaps.push_back(false);
  1401. }
  1402. }
  1403. #else
  1404. Int numMaps = GadgetListBoxGetNumEntries(listboxMapSelect);
  1405. for ( Int i=0; i<numMaps; ++i )
  1406. {
  1407. req.qmMaps.push_back(GadgetListBoxGetItemData(listboxMapSelect, i, 0));
  1408. }
  1409. #endif
  1410. UnicodeString u;
  1411. AsciiString a;
  1412. // u = GadgetTextEntryGetText(textEntryMaxDisconnects);
  1413. // a.translate(u);
  1414. // req.QM.maxDiscons = atoi(a.str());
  1415. // u = GadgetTextEntryGetText(textEntryMaxPoints);
  1416. // a.translate(u);
  1417. req.QM.maxPointPercentage = max(100, maxPoints);
  1418. // u = GadgetTextEntryGetText(textEntryMinPoints);
  1419. // a.translate(u);
  1420. req.QM.minPointPercentage = min(100, minPoints);
  1421. //u = GadgetTextEntryGetText(textEntryWaitTime);
  1422. //a.translate(u);
  1423. //req.QM.widenTime = atoi(a.str());
  1424. req.QM.widenTime = 0;
  1425. Int val;
  1426. GadgetComboBoxGetSelectedPos(comboBoxMaxDisconnects, &val);
  1427. if( val < 0)
  1428. val = 0;
  1429. req.QM.maxDiscons = MAX_DISCONNECTS[val];
  1430. GadgetComboBoxGetSelectedPos(comboBoxMaxPing, &val);
  1431. if (val < 0)
  1432. val = 0;
  1433. if( val >= maxPingEntries - 1)
  1434. {
  1435. req.QM.maxPing = TheGameSpyConfig->getPingTimeoutInMs();
  1436. }
  1437. else
  1438. req.QM.maxPing = (val+1)*100;
  1439. PSPlayerStats stats = TheGameSpyPSMessageQueue->findPlayerStatsByID(TheGameSpyInfo->getLocalProfileID());
  1440. req.QM.points = CalculateRank(stats);
  1441. Int ladderIndex, index, selected;
  1442. GadgetComboBoxGetSelectedPos( comboBoxLadder, &selected );
  1443. ladderIndex = (Int)GadgetComboBoxGetItemData( comboBoxLadder, selected );
  1444. const LadderInfo *ladderInfo = NULL;
  1445. if (ladderIndex < 0)
  1446. {
  1447. ladderIndex = 0;
  1448. }
  1449. if (ladderIndex)
  1450. {
  1451. ladderInfo = TheLadderList->findLadderByIndex( ladderIndex );
  1452. if (!ladderInfo)
  1453. {
  1454. ladderIndex = 0; // sanity
  1455. }
  1456. }
  1457. req.QM.ladderID = ladderIndex;
  1458. req.QM.ladderPassCRC = 0;
  1459. index = -1;
  1460. GadgetComboBoxGetSelectedPos( comboBoxSide, &selected );
  1461. if (selected >= 0)
  1462. index = (Int)GadgetComboBoxGetItemData( comboBoxSide, selected );
  1463. req.QM.side = index;
  1464. if (ladderInfo && ladderInfo->randomFactions)
  1465. {
  1466. Int sideNum = GameClientRandomValue(0, ladderInfo->validFactions.size()-1);
  1467. DEBUG_LOG(("Looking for %d out of %d random sides\n", sideNum, ladderInfo->validFactions.size()));
  1468. AsciiStringListConstIterator cit = ladderInfo->validFactions.begin();
  1469. while (sideNum)
  1470. {
  1471. ++cit;
  1472. --sideNum;
  1473. }
  1474. if (cit != ladderInfo->validFactions.end())
  1475. {
  1476. Int numPlayerTemplates = ThePlayerTemplateStore->getPlayerTemplateCount();
  1477. AsciiString sideStr = *cit;
  1478. DEBUG_LOG(("Chose %s as our side... finding\n", sideStr.str()));
  1479. for (Int c=0; c<numPlayerTemplates; ++c)
  1480. {
  1481. const PlayerTemplate *fac = ThePlayerTemplateStore->getNthPlayerTemplate(c);
  1482. if (fac && fac->getSide() == sideStr)
  1483. {
  1484. DEBUG_LOG(("Found %s in index %d\n", sideStr.str(), c));
  1485. req.QM.side = c;
  1486. break;
  1487. }
  1488. }
  1489. }
  1490. }
  1491. index = -1;
  1492. GadgetComboBoxGetSelectedPos( comboBoxColor, &selected );
  1493. if (selected >= 0)
  1494. index = (Int)GadgetComboBoxGetItemData( comboBoxColor, selected );
  1495. req.QM.color = index;
  1496. OptionPreferences natPref;
  1497. req.QM.NAT = natPref.getFirewallBehavior();
  1498. if (ladderIndex)
  1499. {
  1500. req.QM.numPlayers = (ladderInfo)?ladderInfo->playersPerTeam*2 : 2;
  1501. }
  1502. else
  1503. {
  1504. GadgetComboBoxGetSelectedPos(comboBoxNumPlayers, &val);
  1505. if (val < 0)
  1506. val = 0;
  1507. req.QM.numPlayers = (val+1)*2;
  1508. }
  1509. Int numDiscons = 0;
  1510. PerGeneralMap::iterator it;
  1511. for(it =stats.discons.begin(); it != stats.discons.end(); ++it)
  1512. {
  1513. numDiscons += it->second;
  1514. }
  1515. for(it =stats.desyncs.begin(); it != stats.desyncs.end(); ++it)
  1516. {
  1517. numDiscons += it->second;
  1518. }
  1519. req.QM.discons = numDiscons;
  1520. strncpy(req.QM.pings, TheGameSpyInfo->getPingString().str(), 17);
  1521. req.QM.pings[16] = 0;
  1522. req.QM.botID = TheGameSpyConfig->getQMBotID();
  1523. req.QM.roomID = TheGameSpyConfig->getQMChannel();
  1524. req.QM.exeCRC = TheGlobalData->m_exeCRC;
  1525. req.QM.iniCRC = TheGlobalData->m_iniCRC;
  1526. TheGameSpyPeerMessageQueue->addRequest(req);
  1527. buttonWiden->winEnable( FALSE );
  1528. buttonStart->winHide( TRUE );
  1529. buttonStop->winHide( FALSE );
  1530. enableOptionsGadgets(FALSE);
  1531. if (ladderIndex > 0)
  1532. {
  1533. // save the ladder as being played upon even if we cancel out of matching early...
  1534. LadderPreferences ladPref;
  1535. ladPref.loadProfile( TheGameSpyInfo->getLocalProfileID() );
  1536. LadderPref p;
  1537. p.lastPlayDate = time(NULL);
  1538. p.address = ladderInfo->address;
  1539. p.port = ladderInfo->port;
  1540. p.name = ladderInfo->name;
  1541. ladPref.addRecentLadder( p );
  1542. ladPref.write();
  1543. }
  1544. }
  1545. else if ( controlID == buttonBuddiesID )
  1546. {
  1547. GameSpyToggleOverlay( GSOVERLAY_BUDDY );
  1548. }
  1549. else if ( controlID == buttonBackID )
  1550. {
  1551. buttonPushed = true;
  1552. TheGameSpyInfo->leaveGroupRoom();
  1553. nextScreen = "Menus/WOLWelcomeMenu.wnd";
  1554. TheShell->pop();
  1555. } //if ( controlID == buttonBack )
  1556. else if ( controlID == buttonSelectAllMapsID )
  1557. {
  1558. Int numMaps = GadgetListBoxGetNumEntries(listboxMapSelect);
  1559. for ( Int i=0; i<numMaps; ++i )
  1560. {
  1561. GadgetListBoxAddEntryImage(listboxMapSelect, selectedImage, i, 0);
  1562. GadgetListBoxSetItemData(listboxMapSelect, (void *)1, i);
  1563. GadgetListBoxAddEntryText(listboxMapSelect, GadgetListBoxGetText(listboxMapSelect, i, 1), GameSpyColor[GSCOLOR_MAP_SELECTED], i, 1);
  1564. }
  1565. } //if ( controlID == buttonSelectAllMapsID )
  1566. else if ( controlID == buttonSelectNoMapsID )
  1567. {
  1568. Int numMaps = GadgetListBoxGetNumEntries(listboxMapSelect);
  1569. for ( Int i=0; i<numMaps; ++i )
  1570. {
  1571. GadgetListBoxAddEntryImage(listboxMapSelect, unselectedImage, i, 0);
  1572. GadgetListBoxSetItemData(listboxMapSelect, (void *)0, i);
  1573. GadgetListBoxAddEntryText(listboxMapSelect, GadgetListBoxGetText(listboxMapSelect, i, 1), GameSpyColor[GSCOLOR_MAP_UNSELECTED], i, 1);
  1574. }
  1575. } //if ( controlID == buttonSelectNoMapsID )
  1576. break;
  1577. }// case GBM_SELECTED:
  1578. case GLM_SELECTED:
  1579. {
  1580. GameWindow *control = (GameWindow *)mData1;
  1581. Int controlID = control->winGetWindowId();
  1582. Int selected = (Int)mData2;
  1583. if ( controlID == listboxMapSelectID )
  1584. {
  1585. const LadderInfo *li = getLadderInfo();
  1586. if (selected >= 0 && (!li || !li->randomMaps))
  1587. {
  1588. Bool wasSelected = (Bool)GadgetListBoxGetItemData(control, selected, 0);
  1589. GadgetListBoxSetItemData(control, (void *)(!wasSelected), selected, 0);
  1590. Int width = 10;
  1591. Int height = 10;
  1592. const Image *img = (!wasSelected)?selectedImage:unselectedImage;
  1593. if ( img )
  1594. {
  1595. width = min(GadgetListBoxGetColumnWidth(control, 0), img->getImageWidth());
  1596. height = width;
  1597. }
  1598. GadgetListBoxAddEntryImage(control, img, selected, 0, height, width);
  1599. GadgetListBoxAddEntryText(control, GadgetListBoxGetText(control, selected, 1), GameSpyColor[(wasSelected)?GSCOLOR_MAP_UNSELECTED:GSCOLOR_MAP_SELECTED], selected, 1);
  1600. }
  1601. if (selected >= 0)
  1602. GadgetListBoxSetSelected(control, -1);
  1603. }
  1604. UpdateStartButton();
  1605. break;
  1606. }// case GLM_SELECTED
  1607. case GEM_EDIT_DONE:
  1608. {
  1609. break;
  1610. }
  1611. default:
  1612. return MSG_IGNORED;
  1613. }//Switch
  1614. return MSG_HANDLED;
  1615. }// WOLQuickMatchMenuSystem