WOLGameSetupMenu.cpp 85 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689
  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: WOLGameSetupMenu.cpp
  25. // Author: Matt Campbell, December 2001
  26. // Description: WOL Game Options Menu
  27. ///////////////////////////////////////////////////////////////////////////////////////
  28. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  29. #include "Common/GameEngine.h"
  30. #include "Common/GameState.h"
  31. #include "GameClient/GameText.h"
  32. #include "Common/MultiplayerSettings.h"
  33. #include "Common/PlayerTemplate.h"
  34. #include "Common/CustomMatchPreferences.h"
  35. #include "GameClient/AnimateWindowManager.h"
  36. #include "GameClient/InGameUI.h"
  37. #include "GameClient/WindowLayout.h"
  38. #include "GameClient/Mouse.h"
  39. #include "GameClient/Gadget.h"
  40. #include "GameClient/Shell.h"
  41. #include "GameClient/KeyDefs.h"
  42. #include "GameClient/GameWindowManager.h"
  43. #include "GameClient/GadgetComboBox.h"
  44. #include "GameClient/GadgetListBox.h"
  45. #include "GameClient/GadgetTextEntry.h"
  46. #include "GameClient/GadgetPushButton.h"
  47. #include "GameClient/GadgetStaticText.h"
  48. #include "GameClient/MapUtil.h"
  49. #include "GameClient/EstablishConnectionsMenu.h"
  50. #include "GameClient/GameWindowTransitions.h"
  51. #include "GameNetwork/GameSpy/BuddyDefs.h"
  52. #include "GameNetwork/GameSpy/PeerDefs.h"
  53. #include "GameNetwork/GameSpy/PeerThread.h"
  54. #include "GameNetwork/GameSpy/PersistentStorageDefs.h"
  55. #include "GameNetwork/GameSpy/PersistentStorageThread.h"
  56. #include "GameNetwork/GameSpyOverlay.h"
  57. #include "GameNetwork/NAT.h"
  58. #include "GameNetwork/GUIUtil.h"
  59. #include "GameNetwork/GameSpy/GSConfig.h"
  60. void WOLDisplaySlotList( void );
  61. #ifdef _INTERNAL
  62. // for occasional debugging...
  63. //#pragma optimize("", off)
  64. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  65. #endif
  66. extern std::list<PeerResponse> TheLobbyQueuedUTMs;
  67. extern void MapSelectorTooltip(GameWindow *window, WinInstanceData *instData, UnsignedInt mouse);
  68. #if defined(_DEBUG) || defined(_INTERNAL)
  69. extern Bool g_debugSlots;
  70. void slotListDebugLog(const char *fmt, ...)
  71. {
  72. static char buf[1024];
  73. va_list va;
  74. va_start( va, fmt );
  75. _vsnprintf(buf, 1024, fmt, va );
  76. va_end( va );
  77. buf[1023] = 0;
  78. DEBUG_LOG(("%s", buf));
  79. if (g_debugSlots)
  80. {
  81. UnicodeString msg;
  82. msg.translate(buf);
  83. TheGameSpyInfo->addText(msg, GameSpyColor[GSCOLOR_DEFAULT], NULL);
  84. }
  85. }
  86. #define SLOTLIST_DEBUG_LOG(x) slotListDebugLog x
  87. #else
  88. #define SLOTLIST_DEBUG_LOG(x) DEBUG_LOG(x)
  89. #endif
  90. void SendStatsToOtherPlayers(const GameInfo *game)
  91. {
  92. PeerRequest req;
  93. req.peerRequestType = PeerRequest::PEERREQUEST_UTMPLAYER;
  94. req.UTM.isStagingRoom = TRUE;
  95. req.id = "STATS/";
  96. AsciiString fullStr;
  97. PSPlayerStats fullStats = TheGameSpyPSMessageQueue->findPlayerStatsByID(TheGameSpyInfo->getLocalProfileID());
  98. PSPlayerStats subStats;
  99. subStats.id = fullStats.id;
  100. subStats.wins = fullStats.wins;
  101. subStats.losses = fullStats.losses;
  102. subStats.discons = fullStats.discons;
  103. subStats.desyncs = fullStats.desyncs;
  104. subStats.games = fullStats.games;
  105. subStats.locale = fullStats.locale;
  106. subStats.gamesAsRandom = fullStats.gamesAsRandom;
  107. GetAdditionalDisconnectsFromUserFile(&subStats);
  108. fullStr.format("%d %s", TheGameSpyInfo->getLocalProfileID(), TheGameSpyPSMessageQueue->formatPlayerKVPairs( subStats ));
  109. req.options = fullStr.str();
  110. Int localIndex = game->getLocalSlotNum();
  111. for (Int i=0; i<MAX_SLOTS; ++i)
  112. {
  113. const GameSlot *slot = game->getConstSlot(i);
  114. if (slot->isHuman() && i != localIndex)
  115. {
  116. AsciiString hostName;
  117. hostName.translate(slot->getName());
  118. req.nick = hostName.str();
  119. DEBUG_LOG(("SendStatsToOtherPlayers() - sending to '%s', data of\n\t'%s'\n", hostName.str(), req.options.c_str()));
  120. TheGameSpyPeerMessageQueue->addRequest(req);
  121. }
  122. }
  123. }
  124. // PRIVATE DATA ///////////////////////////////////////////////////////////////////////////////////
  125. static Bool isShuttingDown = false;
  126. static Bool buttonPushed = false;
  127. static char *nextScreen = NULL;
  128. static Bool raiseMessageBoxes = false;
  129. static Bool launchGameNext = FALSE;
  130. // window ids ------------------------------------------------------------------------------
  131. static NameKeyType parentWOLGameSetupID = NAMEKEY_INVALID;
  132. static NameKeyType comboBoxPlayerID[MAX_SLOTS] = { NAMEKEY_INVALID,NAMEKEY_INVALID,
  133. NAMEKEY_INVALID,NAMEKEY_INVALID,
  134. NAMEKEY_INVALID,NAMEKEY_INVALID,
  135. NAMEKEY_INVALID,NAMEKEY_INVALID };
  136. static NameKeyType staticTextPlayerID[MAX_SLOTS] = { NAMEKEY_INVALID,NAMEKEY_INVALID,
  137. NAMEKEY_INVALID,NAMEKEY_INVALID,
  138. NAMEKEY_INVALID,NAMEKEY_INVALID,
  139. NAMEKEY_INVALID,NAMEKEY_INVALID };
  140. static NameKeyType buttonAcceptID[MAX_SLOTS] = { NAMEKEY_INVALID,NAMEKEY_INVALID,
  141. NAMEKEY_INVALID,NAMEKEY_INVALID,
  142. NAMEKEY_INVALID,NAMEKEY_INVALID,
  143. NAMEKEY_INVALID,NAMEKEY_INVALID };
  144. static NameKeyType comboBoxColorID[MAX_SLOTS] = { NAMEKEY_INVALID,NAMEKEY_INVALID,
  145. NAMEKEY_INVALID,NAMEKEY_INVALID,
  146. NAMEKEY_INVALID,NAMEKEY_INVALID,
  147. NAMEKEY_INVALID,NAMEKEY_INVALID };
  148. static NameKeyType comboBoxPlayerTemplateID[MAX_SLOTS] = { NAMEKEY_INVALID,NAMEKEY_INVALID,
  149. NAMEKEY_INVALID,NAMEKEY_INVALID,
  150. NAMEKEY_INVALID,NAMEKEY_INVALID,
  151. NAMEKEY_INVALID,NAMEKEY_INVALID };
  152. static NameKeyType comboBoxTeamID[MAX_SLOTS] = { NAMEKEY_INVALID,NAMEKEY_INVALID,
  153. NAMEKEY_INVALID,NAMEKEY_INVALID,
  154. NAMEKEY_INVALID,NAMEKEY_INVALID,
  155. NAMEKEY_INVALID,NAMEKEY_INVALID };
  156. //static NameKeyType buttonStartPositionID[MAX_SLOTS] = { NAMEKEY_INVALID,NAMEKEY_INVALID,
  157. // NAMEKEY_INVALID,NAMEKEY_INVALID,
  158. // NAMEKEY_INVALID,NAMEKEY_INVALID,
  159. // NAMEKEY_INVALID,NAMEKEY_INVALID };
  160. static NameKeyType buttonMapStartPositionID[MAX_SLOTS] = { NAMEKEY_INVALID,NAMEKEY_INVALID,
  161. NAMEKEY_INVALID,NAMEKEY_INVALID,
  162. NAMEKEY_INVALID,NAMEKEY_INVALID,
  163. NAMEKEY_INVALID,NAMEKEY_INVALID };
  164. static NameKeyType genericPingWindowID[MAX_SLOTS] = { NAMEKEY_INVALID,NAMEKEY_INVALID,
  165. NAMEKEY_INVALID,NAMEKEY_INVALID,
  166. NAMEKEY_INVALID,NAMEKEY_INVALID,
  167. NAMEKEY_INVALID,NAMEKEY_INVALID };
  168. static NameKeyType textEntryChatID = NAMEKEY_INVALID;
  169. static NameKeyType textEntryMapDisplayID = NAMEKEY_INVALID;
  170. static NameKeyType buttonBackID = NAMEKEY_INVALID;
  171. static NameKeyType buttonStartID = NAMEKEY_INVALID;
  172. static NameKeyType buttonEmoteID = NAMEKEY_INVALID;
  173. static NameKeyType buttonSelectMapID = NAMEKEY_INVALID;
  174. static NameKeyType windowMapID = NAMEKEY_INVALID;
  175. static NameKeyType windowMapSelectMapID = NAMEKEY_INVALID;
  176. // Window Pointers ------------------------------------------------------------------------
  177. static GameWindow *parentWOLGameSetup = NULL;
  178. static GameWindow *buttonBack = NULL;
  179. static GameWindow *buttonStart = NULL;
  180. static GameWindow *buttonSelectMap = NULL;
  181. static GameWindow *buttonEmote = NULL;
  182. static GameWindow *textEntryChat = NULL;
  183. static GameWindow *textEntryMapDisplay = NULL;
  184. static GameWindow *windowMap = NULL;
  185. static GameWindow *comboBoxPlayer[MAX_SLOTS] = {NULL,NULL,NULL,NULL,
  186. NULL,NULL,NULL,NULL };
  187. static GameWindow *staticTextPlayer[MAX_SLOTS] = {NULL,NULL,NULL,NULL,
  188. NULL,NULL,NULL,NULL };
  189. static GameWindow *buttonAccept[MAX_SLOTS] = {NULL,NULL,NULL,NULL,
  190. NULL,NULL,NULL,NULL };
  191. static GameWindow *comboBoxColor[MAX_SLOTS] = {NULL,NULL,NULL,NULL,
  192. NULL,NULL,NULL,NULL };
  193. static GameWindow *comboBoxPlayerTemplate[MAX_SLOTS] = {NULL,NULL,NULL,NULL,
  194. NULL,NULL,NULL,NULL };
  195. static GameWindow *comboBoxTeam[MAX_SLOTS] = {NULL,NULL,NULL,NULL,
  196. NULL,NULL,NULL,NULL };
  197. //static GameWindow *buttonStartPosition[MAX_SLOTS] = {NULL,NULL,NULL,NULL,
  198. // NULL,NULL,NULL,NULL };
  199. //
  200. static GameWindow *buttonMapStartPosition[MAX_SLOTS] = {NULL,NULL,NULL,NULL,
  201. NULL,NULL,NULL,NULL };
  202. static GameWindow *genericPingWindow[MAX_SLOTS] = {NULL,NULL,NULL,NULL,
  203. NULL,NULL,NULL,NULL };
  204. static const Image *pingImages[3] = { NULL, NULL, NULL };
  205. WindowLayout *WOLMapSelectLayout = NULL;
  206. void PopBackToLobby( void )
  207. {
  208. // delete TheNAT, its no good for us anymore.
  209. delete TheNAT;
  210. TheNAT = NULL;
  211. if (TheGameSpyInfo) // this can be blown away by a disconnect on the map transfer screen
  212. {
  213. TheGameSpyInfo->getCurrentStagingRoom()->reset();
  214. TheGameSpyInfo->leaveStagingRoom();
  215. //TheGameSpyInfo->joinBestGroupRoom();
  216. }
  217. DEBUG_LOG(("PopBackToLobby() - parentWOLGameSetup is %X\n", parentWOLGameSetup));
  218. if (parentWOLGameSetup)
  219. {
  220. nextScreen = "Menus/WOLCustomLobby.wnd";
  221. TheShell->pop();
  222. }
  223. }
  224. void updateMapStartSpots( GameInfo *myGame, GameWindow *buttonMapStartPositions[], Bool onLoadScreen = FALSE );
  225. void positionStartSpots( GameInfo *myGame, GameWindow *buttonMapStartPositions[], GameWindow *mapWindow);
  226. void positionStartSpots(AsciiString mapName, GameWindow *buttonMapStartPositions[], GameWindow *mapWindow);
  227. void WOLPositionStartSpots( void )
  228. {
  229. GameWindow *win = windowMap;
  230. if (WOLMapSelectLayout != NULL) {
  231. win = TheWindowManager->winGetWindowFromId(NULL, windowMapSelectMapID);
  232. // get the controls.
  233. NameKeyType listboxMapID = TheNameKeyGenerator->nameToKey( AsciiString("WOLMapSelectMenu.wnd:ListboxMap") );
  234. GameWindow *listboxMap = TheWindowManager->winGetWindowFromId( NULL, listboxMapID );
  235. if (listboxMap != NULL) {
  236. Int selected;
  237. UnicodeString map;
  238. // get the selected index
  239. GadgetListBoxGetSelected( listboxMap, &selected );
  240. if( selected != -1 )
  241. {
  242. // get text of the map to load
  243. map = GadgetListBoxGetText( listboxMap, selected, 0 );
  244. // set the map name in the global data map name
  245. AsciiString asciiMap;
  246. const char *mapFname = (const char *)GadgetListBoxGetItemData( listboxMap, selected );
  247. DEBUG_ASSERTCRASH(mapFname, ("No map item data"));
  248. if (mapFname) {
  249. asciiMap = mapFname;
  250. } else {
  251. asciiMap.translate( map );
  252. }
  253. positionStartSpots(asciiMap, buttonMapStartPosition, win);
  254. }
  255. }
  256. } else {
  257. DEBUG_ASSERTCRASH(win != NULL, ("no map preview window"));
  258. positionStartSpots( TheGameSpyInfo->getCurrentStagingRoom(), buttonMapStartPosition, win);
  259. }
  260. }
  261. static void savePlayerInfo( void )
  262. {
  263. if (TheGameSpyGame)
  264. {
  265. Int slotNum = TheGameSpyGame->getLocalSlotNum();
  266. if (slotNum >= 0)
  267. {
  268. GameSpyGameSlot *slot = TheGameSpyGame->getGameSpySlot(slotNum);
  269. if (slot)
  270. {
  271. // save off some prefs
  272. CustomMatchPreferences pref;
  273. pref.setPreferredColor(slot->getColor());
  274. pref.setPreferredFaction(slot->getPlayerTemplate());
  275. if (TheGameSpyGame->amIHost())
  276. {
  277. pref.setPreferredMap(TheGameSpyGame->getMap());
  278. }
  279. pref.write();
  280. }
  281. }
  282. }
  283. }
  284. // Tooltips -------------------------------------------------------------------------------
  285. static void playerTooltip(GameWindow *window,
  286. WinInstanceData *instData,
  287. UnsignedInt mouse)
  288. {
  289. Int slotIdx = -1;
  290. for (Int i=0; i<MAX_SLOTS; ++i)
  291. {
  292. if (window == comboBoxPlayer[i] || window == staticTextPlayer[i])
  293. {
  294. slotIdx = i;
  295. break;
  296. }
  297. }
  298. if (slotIdx < 0)
  299. {
  300. TheMouse->setCursorTooltip( UnicodeString::TheEmptyString, -1, NULL, 1.5f );
  301. return;
  302. }
  303. GameSpyStagingRoom *game = TheGameSpyInfo->getCurrentStagingRoom();
  304. if (!game)
  305. {
  306. TheMouse->setCursorTooltip( UnicodeString::TheEmptyString, -1, NULL, 1.5f );
  307. return;
  308. }
  309. GameSpyGameSlot *slot = game->getGameSpySlot(slotIdx);
  310. if (!slot || !slot->isHuman())
  311. {
  312. TheMouse->setCursorTooltip( UnicodeString::TheEmptyString, -1, NULL, 1.5f );
  313. return;
  314. }
  315. // for tooltip, we want:
  316. // * player name
  317. // * ping
  318. // * locale
  319. // * win/loss history
  320. // * discons/desyncs as one var
  321. // * favorite army
  322. // in that order. got it? good.
  323. UnicodeString uName = slot->getName();
  324. AsciiString aName;
  325. aName.translate(uName);
  326. PlayerInfoMap::iterator pmIt = TheGameSpyInfo->getPlayerInfoMap()->find(aName);
  327. if (pmIt == TheGameSpyInfo->getPlayerInfoMap()->end())
  328. {
  329. TheMouse->setCursorTooltip( uName, -1, NULL, 1.5f );
  330. return;
  331. }
  332. Int profileID = pmIt->second.m_profileID;
  333. PSPlayerStats stats = TheGameSpyPSMessageQueue->findPlayerStatsByID(profileID);
  334. if (stats.id == 0)
  335. {
  336. TheMouse->setCursorTooltip( uName, -1, NULL, 1.5f );
  337. return;
  338. }
  339. Bool isLocalPlayer = slot == game->getGameSpySlot(game->getLocalSlotNum());
  340. AsciiString localeIdentifier;
  341. localeIdentifier.format("WOL:Locale%2.2d", stats.locale);
  342. UnicodeString playerInfo;
  343. Int totalWins = 0, totalLosses = 0, totalDiscons = 0;
  344. PerGeneralMap::iterator it;
  345. for (it = stats.wins.begin(); it != stats.wins.end(); ++it)
  346. {
  347. totalWins += it->second;
  348. }
  349. for (it = stats.losses.begin(); it != stats.losses.end(); ++it)
  350. {
  351. totalLosses += it->second;
  352. }
  353. for (it = stats.discons.begin(); it != stats.discons.end(); ++it)
  354. {
  355. totalDiscons += it->second;
  356. }
  357. for (it = stats.desyncs.begin(); it != stats.desyncs.end(); ++it)
  358. {
  359. totalDiscons += it->second;
  360. }
  361. UnicodeString favoriteSide;
  362. Int numGames = 0;
  363. Int favorite = 0;
  364. for(it = stats.games.begin(); it != stats.games.end(); ++it)
  365. {
  366. if(it->second >= numGames)
  367. {
  368. numGames = it->second;
  369. favorite = it->first;
  370. }
  371. }
  372. if(numGames == 0)
  373. favoriteSide = TheGameText->fetch("GUI:None");
  374. else if( stats.gamesAsRandom >= numGames )
  375. favoriteSide = TheGameText->fetch("GUI:Random");
  376. else
  377. {
  378. const PlayerTemplate *fac = ThePlayerTemplateStore->getNthPlayerTemplate(favorite);
  379. if (fac)
  380. {
  381. AsciiString side;
  382. side.format("SIDE:%s", fac->getSide().str());
  383. favoriteSide = TheGameText->fetch(side);
  384. }
  385. }
  386. playerInfo.format(TheGameText->fetch("TOOLTIP:StagingPlayerInfo"),
  387. TheGameText->fetch(localeIdentifier).str(),
  388. slot->getPingAsInt(),
  389. totalWins, totalLosses, totalDiscons,
  390. favoriteSide.str());
  391. UnicodeString tooltip = UnicodeString::TheEmptyString;
  392. if (isLocalPlayer)
  393. {
  394. tooltip.format(TheGameText->fetch("TOOLTIP:LocalPlayer"), uName.str());
  395. }
  396. else
  397. {
  398. // not us
  399. if (TheGameSpyInfo->getBuddyMap()->find(profileID) != TheGameSpyInfo->getBuddyMap()->end())
  400. {
  401. // buddy
  402. tooltip.format(TheGameText->fetch("TOOLTIP:BuddyPlayer"), uName.str());
  403. }
  404. else
  405. {
  406. if (profileID)
  407. {
  408. // non-buddy profiled player
  409. tooltip.format(TheGameText->fetch("TOOLTIP:ProfiledPlayer"), uName.str());
  410. }
  411. else
  412. {
  413. // non-profiled player
  414. tooltip.format(TheGameText->fetch("TOOLTIP:GenericPlayer"), uName.str());
  415. }
  416. }
  417. }
  418. tooltip.concat(playerInfo);
  419. TheMouse->setCursorTooltip( tooltip, -1, NULL, 1.5f ); // the text and width are the only params used. the others are the default values.
  420. }
  421. void gameAcceptTooltip(GameWindow *window, WinInstanceData *instData, UnsignedInt mouse)
  422. {
  423. Int x, y;
  424. x = LOLONGTOSHORT(mouse);
  425. y = HILONGTOSHORT(mouse);
  426. Int winPosX, winPosY, winWidth, winHeight;
  427. window->winGetScreenPosition(&winPosX, &winPosY);
  428. window->winGetSize(&winWidth, &winHeight);
  429. if ((x > winPosX && x < (winPosX + winWidth)) && (y > winPosY && y < (winPosY + winHeight)))
  430. {
  431. TheMouse->setCursorTooltip(TheGameText->fetch("TOOLTIP:GameAcceptance"), -1, NULL);
  432. }
  433. }
  434. void pingTooltip(GameWindow *window, WinInstanceData *instData, UnsignedInt mouse)
  435. {
  436. Int x, y;
  437. x = LOLONGTOSHORT(mouse);
  438. y = HILONGTOSHORT(mouse);
  439. Int winPosX, winPosY, winWidth, winHeight;
  440. window->winGetScreenPosition(&winPosX, &winPosY);
  441. window->winGetSize(&winWidth, &winHeight);
  442. if ((x > winPosX && x < (winPosX + winWidth)) && (y > winPosY && y < (winPosY + winHeight)))
  443. {
  444. TheMouse->setCursorTooltip(TheGameText->fetch("TOOLTIP:ConnectionSpeed"), -1, NULL);
  445. }
  446. }
  447. //external declarations of the Gadgets the callbacks can use
  448. GameWindow *listboxGameSetupChat = NULL;
  449. NameKeyType listboxGameSetupChatID = NAMEKEY_INVALID;
  450. static void handleColorSelection(int index)
  451. {
  452. GameWindow *combo = comboBoxColor[index];
  453. Int color, selIndex;
  454. GadgetComboBoxGetSelectedPos(combo, &selIndex);
  455. color = (Int)GadgetComboBoxGetItemData(combo, selIndex);
  456. GameInfo *myGame = TheGameSpyInfo->getCurrentStagingRoom();
  457. if (myGame)
  458. {
  459. GameSlot * slot = myGame->getSlot(index);
  460. if (color == slot->getColor())
  461. return;
  462. if (color >= -1 && color < TheMultiplayerSettings->getNumColors())
  463. {
  464. Bool colorAvailable = TRUE;
  465. if(color != -1 )
  466. {
  467. for(Int i=0; i <MAX_SLOTS; i++)
  468. {
  469. GameSlot *checkSlot = myGame->getSlot(i);
  470. if(color == checkSlot->getColor() && slot != checkSlot)
  471. {
  472. colorAvailable = FALSE;
  473. break;
  474. }
  475. }
  476. }
  477. if(!colorAvailable)
  478. return;
  479. }
  480. slot->setColor(color);
  481. if (TheGameSpyInfo->amIHost())
  482. {
  483. // send around a new slotlist
  484. TheGameSpyInfo->setGameOptions();
  485. WOLDisplaySlotList();
  486. }
  487. else
  488. {
  489. // request the color from the host
  490. if (!slot->isPlayer(TheGameSpyInfo->getLocalName()))
  491. return;
  492. AsciiString options;
  493. options.format("Color=%d", color);
  494. AsciiString hostName;
  495. hostName.translate(myGame->getSlot(0)->getName());
  496. PeerRequest req;
  497. req.peerRequestType = PeerRequest::PEERREQUEST_UTMPLAYER;
  498. req.UTM.isStagingRoom = TRUE;
  499. req.id = "REQ/";
  500. req.nick = hostName.str();
  501. req.options = options.str();
  502. TheGameSpyPeerMessageQueue->addRequest(req);
  503. }
  504. }
  505. }
  506. static void handlePlayerTemplateSelection(int index)
  507. {
  508. GameWindow *combo = comboBoxPlayerTemplate[index];
  509. Int playerTemplate, selIndex;
  510. GadgetComboBoxGetSelectedPos(combo, &selIndex);
  511. playerTemplate = (Int)GadgetComboBoxGetItemData(combo, selIndex);
  512. GameInfo *myGame = TheGameSpyInfo->getCurrentStagingRoom();
  513. if (myGame)
  514. {
  515. GameSlot * slot = myGame->getSlot(index);
  516. if (playerTemplate == slot->getPlayerTemplate())
  517. return;
  518. Int oldTemplate = slot->getPlayerTemplate();
  519. slot->setPlayerTemplate(playerTemplate);
  520. if (oldTemplate == PLAYERTEMPLATE_OBSERVER)
  521. {
  522. // was observer, so populate color & team with all, and enable
  523. GadgetComboBoxSetSelectedPos(comboBoxColor[index], 0);
  524. GadgetComboBoxSetSelectedPos(comboBoxTeam[index], 0);
  525. slot->setStartPos(-1);
  526. }
  527. else if (playerTemplate == PLAYERTEMPLATE_OBSERVER)
  528. {
  529. // is becoming observer, so populate color & team with random only, and disable
  530. GadgetComboBoxSetSelectedPos(comboBoxColor[index], 0);
  531. GadgetComboBoxSetSelectedPos(comboBoxTeam[index], 0);
  532. slot->setStartPos(-1);
  533. }
  534. if (TheGameSpyInfo->amIHost())
  535. {
  536. // send around a new slotlist
  537. myGame->resetAccepted();
  538. TheGameSpyInfo->setGameOptions();
  539. WOLDisplaySlotList();
  540. }
  541. else
  542. {
  543. // request the playerTemplate from the host
  544. AsciiString options;
  545. options.format("PlayerTemplate=%d", playerTemplate);
  546. AsciiString hostName;
  547. hostName.translate(myGame->getSlot(0)->getName());
  548. PeerRequest req;
  549. req.peerRequestType = PeerRequest::PEERREQUEST_UTMPLAYER;
  550. req.UTM.isStagingRoom = TRUE;
  551. req.id = "REQ/";
  552. req.nick = hostName.str();
  553. req.options = options.str();
  554. TheGameSpyPeerMessageQueue->addRequest(req);
  555. }
  556. }
  557. }
  558. static void handleStartPositionSelection(Int player, int startPos)
  559. {
  560. GameSpyStagingRoom *myGame = TheGameSpyInfo->getCurrentStagingRoom();
  561. if (myGame)
  562. {
  563. GameSpyGameSlot * slot = myGame->getGameSpySlot(player);
  564. if (!slot)
  565. return;
  566. if (startPos == slot->getStartPos())
  567. return;
  568. Bool skip = FALSE;
  569. if (startPos < 0)
  570. {
  571. skip = TRUE;
  572. }
  573. if(!skip)
  574. {
  575. Bool isAvailable = TRUE;
  576. for(Int i = 0; i < MAX_SLOTS; ++i)
  577. {
  578. if(i != player && myGame->getSlot(i)->getStartPos() == startPos)
  579. {
  580. isAvailable = FALSE;
  581. break;
  582. }
  583. }
  584. if( !isAvailable )
  585. return;
  586. }
  587. slot->setStartPos(startPos);
  588. if (myGame->amIHost())
  589. {
  590. // send around a new slotlist
  591. myGame->resetAccepted();
  592. TheGameSpyInfo->setGameOptions();
  593. WOLDisplaySlotList();
  594. }
  595. else
  596. {
  597. // request the color from the host
  598. if (AreSlotListUpdatesEnabled())
  599. {
  600. // request the playerTemplate from the host
  601. AsciiString options;
  602. options.format("StartPos=%d", slot->getStartPos());
  603. AsciiString hostName;
  604. hostName.translate(myGame->getSlot(0)->getName());
  605. PeerRequest req;
  606. req.peerRequestType = PeerRequest::PEERREQUEST_UTMPLAYER;
  607. req.UTM.isStagingRoom = TRUE;
  608. req.id = "REQ/";
  609. req.nick = hostName.str();
  610. req.options = options.str();
  611. TheGameSpyPeerMessageQueue->addRequest(req);
  612. }
  613. }
  614. }
  615. }
  616. static void handleTeamSelection(int index)
  617. {
  618. GameWindow *combo = comboBoxTeam[index];
  619. Int team, selIndex;
  620. GadgetComboBoxGetSelectedPos(combo, &selIndex);
  621. team = (Int)GadgetComboBoxGetItemData(combo, selIndex);
  622. GameInfo *myGame = TheGameSpyInfo->getCurrentStagingRoom();
  623. if (myGame)
  624. {
  625. GameSlot * slot = myGame->getSlot(index);
  626. if (team == slot->getTeamNumber())
  627. return;
  628. slot->setTeamNumber(team);
  629. if (TheGameSpyInfo->amIHost())
  630. {
  631. // send around a new slotlist
  632. myGame->resetAccepted();
  633. TheGameSpyInfo->setGameOptions();
  634. WOLDisplaySlotList();
  635. }
  636. else
  637. {
  638. // request the team from the host
  639. AsciiString options;
  640. options.format("Team=%d", team);
  641. AsciiString hostName;
  642. hostName.translate(myGame->getSlot(0)->getName());
  643. PeerRequest req;
  644. req.peerRequestType = PeerRequest::PEERREQUEST_UTMPLAYER;
  645. req.UTM.isStagingRoom = TRUE;
  646. req.id = "REQ/";
  647. req.nick = hostName.str();
  648. req.options = options.str();
  649. TheGameSpyPeerMessageQueue->addRequest(req);
  650. }
  651. }
  652. }
  653. static void StartPressed(void)
  654. {
  655. Bool isReady = TRUE;
  656. Bool allHaveMap = TRUE;
  657. Int playerCount = 0;
  658. Int humanCount = 0;
  659. GameSpyStagingRoom *myGame = TheGameSpyInfo->getCurrentStagingRoom();
  660. if (!myGame)
  661. return;
  662. // see if everyone's accepted and count the number of players in the game
  663. UnicodeString mapDisplayName;
  664. const MapMetaData *mapData = TheMapCache->findMap( myGame->getMap() );
  665. Bool willTransfer = TRUE;
  666. if (mapData)
  667. {
  668. mapDisplayName.format(L"%ls", mapData->m_displayName.str());
  669. willTransfer = !mapData->m_isOfficial;
  670. }
  671. else
  672. {
  673. mapDisplayName.format(L"%hs", myGame->getMap().str());
  674. willTransfer = WouldMapTransfer(myGame->getMap());
  675. }
  676. for( int i = 0; i < MAX_SLOTS; i++ )
  677. {
  678. if ((myGame->getSlot(i)->isAccepted() == FALSE) && (myGame->getSlot(i)->isHuman() == TRUE))
  679. {
  680. isReady = FALSE;
  681. if (!myGame->getSlot(i)->hasMap() && !willTransfer)
  682. {
  683. UnicodeString msg;
  684. msg.format(TheGameText->fetch("GUI:PlayerNoMap"), myGame->getSlot(i)->getName().str(), mapDisplayName.str());
  685. TheGameSpyInfo->addText(msg, GameSpyColor[GSCOLOR_DEFAULT], listboxGameSetupChat);
  686. allHaveMap = FALSE;
  687. }
  688. }
  689. if(myGame->getSlot(i)->isOccupied() && myGame->getSlot(i)->getPlayerTemplate() != PLAYERTEMPLATE_OBSERVER)
  690. {
  691. if (myGame->getSlot(i)->isHuman())
  692. humanCount++;
  693. playerCount++;
  694. }
  695. }
  696. // Check for too many players
  697. const MapMetaData *md = TheMapCache->findMap( myGame->getMap() );
  698. if (!md || md->m_numPlayers < playerCount)
  699. {
  700. if (myGame->amIHost())
  701. {
  702. UnicodeString text;
  703. text.format(TheGameText->fetch("LAN:TooManyPlayers"), (md)?md->m_numPlayers:0);
  704. TheGameSpyInfo->addText(text, GameSpyColor[GSCOLOR_DEFAULT], listboxGameSetupChat);
  705. }
  706. return;
  707. }
  708. // Check for observer + AI players
  709. if (TheGlobalData->m_netMinPlayers && !humanCount)
  710. {
  711. if (myGame->amIHost())
  712. {
  713. UnicodeString text = TheGameText->fetch("GUI:NeedHumanPlayers");
  714. TheGameSpyInfo->addText(text, GameSpyColor[GSCOLOR_DEFAULT], listboxGameSetupChat);
  715. }
  716. return;
  717. }
  718. // Check for too few players
  719. if (playerCount < TheGlobalData->m_netMinPlayers)
  720. {
  721. if (myGame->amIHost())
  722. {
  723. UnicodeString text;
  724. text.format(TheGameText->fetch("LAN:NeedMorePlayers"),playerCount);
  725. TheGameSpyInfo->addText(text, GameSpyColor[GSCOLOR_DEFAULT], listboxGameSetupChat);
  726. }
  727. return;
  728. }
  729. // Check for too few teams
  730. int numRandom = 0;
  731. std::set<Int> teams;
  732. for (i=0; i<MAX_SLOTS; ++i)
  733. {
  734. GameSlot *slot = myGame->getSlot(i);
  735. if (slot && slot->isOccupied() && slot->getPlayerTemplate() != PLAYERTEMPLATE_OBSERVER)
  736. {
  737. if (slot->getTeamNumber() >= 0)
  738. {
  739. teams.insert(slot->getTeamNumber());
  740. }
  741. else
  742. {
  743. ++numRandom;
  744. }
  745. }
  746. }
  747. if (numRandom + teams.size() < TheGlobalData->m_netMinPlayers)
  748. {
  749. if (myGame->amIHost())
  750. {
  751. UnicodeString text;
  752. text.format(TheGameText->fetch("LAN:NeedMoreTeams"));
  753. TheGameSpyInfo->addText(text, GameSpyColor[GSCOLOR_DEFAULT], listboxGameSetupChat);
  754. }
  755. return;
  756. }
  757. if (numRandom + teams.size() < 2)
  758. {
  759. UnicodeString text;
  760. text.format(TheGameText->fetch("GUI:SandboxMode"));
  761. TheGameSpyInfo->addText(text, GameSpyColor[GSCOLOR_DEFAULT], listboxGameSetupChat);
  762. }
  763. if(isReady)
  764. {
  765. PeerRequest req;
  766. req.peerRequestType = PeerRequest::PEERREQUEST_STARTGAME;
  767. TheGameSpyPeerMessageQueue->addRequest(req);
  768. SendStatsToOtherPlayers(myGame);
  769. // we've started, there's no going back
  770. // i.e. disable the back button.
  771. buttonBack->winEnable(FALSE);
  772. GameWindow *buttonBuddy = TheWindowManager->winGetWindowFromId(NULL, NAMEKEY("GameSpyGameOptionsMenu.wnd:ButtonCommunicator"));
  773. if (buttonBuddy)
  774. buttonBuddy->winEnable(FALSE);
  775. GameSpyCloseOverlay(GSOVERLAY_BUDDY);
  776. *TheGameSpyGame = *myGame;
  777. TheGameSpyGame->startGame(0);
  778. }
  779. else if (allHaveMap)
  780. {
  781. TheGameSpyInfo->addText(TheGameText->fetch("GUI:NotifiedStartIntent"), GameSpyColor[GSCOLOR_DEFAULT], listboxGameSetupChat);
  782. PeerRequest req;
  783. req.peerRequestType = PeerRequest::PEERREQUEST_UTMROOM;
  784. req.UTM.isStagingRoom = TRUE;
  785. req.id = "HWS/";
  786. req.options = "true";
  787. TheGameSpyPeerMessageQueue->addRequest(req);
  788. }
  789. }//void StartPressed(void)
  790. //-------------------------------------------------------------------------------------------------
  791. /** Update options on screen */
  792. //-------------------------------------------------------------------------------------------------
  793. void WOLDisplayGameOptions( void )
  794. {
  795. GameSpyStagingRoom *theGame = TheGameSpyInfo->getCurrentStagingRoom();
  796. if (!parentWOLGameSetup || !theGame)
  797. return;
  798. const GameSlot *localSlot = NULL;
  799. if (theGame->getLocalSlotNum() >= 0)
  800. localSlot = theGame->getConstSlot(theGame->getLocalSlotNum());
  801. const MapMetaData *md = TheMapCache->findMap(TheGameSpyInfo->getCurrentStagingRoom()->getMap());
  802. if (md && localSlot && localSlot->hasMap())
  803. {
  804. GadgetStaticTextSetText(textEntryMapDisplay, md->m_displayName);
  805. }
  806. else
  807. {
  808. AsciiString s = TheGameSpyInfo->getCurrentStagingRoom()->getMap();
  809. if (s.reverseFind('\\'))
  810. {
  811. s = s.reverseFind('\\') + 1;
  812. }
  813. UnicodeString mapDisplay;
  814. mapDisplay.translate(s);
  815. GadgetStaticTextSetText(textEntryMapDisplay, mapDisplay);
  816. }
  817. WOLPositionStartSpots();
  818. updateMapStartSpots(TheGameSpyInfo->getCurrentStagingRoom(), buttonMapStartPosition);
  819. }
  820. // -----------------------------------------------------------------------------------------
  821. // The Bad munkee slot list displaying function
  822. //-------------------------------------------------------------------------------------------------
  823. void WOLDisplaySlotList( void )
  824. {
  825. if (!parentWOLGameSetup || !TheGameSpyInfo->getCurrentStagingRoom())
  826. return;
  827. GameSpyStagingRoom *game = TheGameSpyInfo->getCurrentStagingRoom();
  828. if (!game->isInGame())
  829. return;
  830. DEBUG_ASSERTCRASH(!game->getConstSlot(0)->isOpen(), ("Open host!"));
  831. UpdateSlotList( game, comboBoxPlayer, comboBoxColor,
  832. comboBoxPlayerTemplate, comboBoxTeam, buttonAccept, buttonStart, buttonMapStartPosition );
  833. WOLDisplayGameOptions();
  834. for (Int i=0; i<MAX_SLOTS; ++i)
  835. {
  836. GameSpyGameSlot *slot = game->getGameSpySlot(i);
  837. if (slot && slot->isHuman())
  838. {
  839. if (i == game->getLocalSlotNum())
  840. {
  841. // set up my own ping...
  842. slot->setPingString(TheGameSpyInfo->getPingString());
  843. }
  844. if (genericPingWindow[i])
  845. {
  846. genericPingWindow[i]->winHide(FALSE);
  847. Int ping = slot->getPingAsInt();
  848. if (ping < TheGameSpyConfig->getPingCutoffGood())
  849. {
  850. genericPingWindow[i]->winSetEnabledImage(0, pingImages[0]);
  851. }
  852. else if (ping < TheGameSpyConfig->getPingCutoffBad())
  853. {
  854. genericPingWindow[i]->winSetEnabledImage(0, pingImages[1]);
  855. }
  856. else
  857. {
  858. genericPingWindow[i]->winSetEnabledImage(0, pingImages[2]);
  859. }
  860. }
  861. }
  862. else
  863. {
  864. if (genericPingWindow[i])
  865. genericPingWindow[i]->winHide(TRUE);
  866. }
  867. }
  868. }
  869. //-------------------------------------------------------------------------------------------------
  870. /** Initialize the Gadgets Options Menu */
  871. //-------------------------------------------------------------------------------------------------
  872. void InitWOLGameGadgets( void )
  873. {
  874. GameSpyStagingRoom *theGameInfo = TheGameSpyInfo->getCurrentStagingRoom();
  875. pingImages[0] = TheMappedImageCollection->findImageByName("Ping03");
  876. pingImages[1] = TheMappedImageCollection->findImageByName("Ping02");
  877. pingImages[2] = TheMappedImageCollection->findImageByName("Ping01");
  878. DEBUG_ASSERTCRASH(pingImages[0], ("Can't find ping image!"));
  879. DEBUG_ASSERTCRASH(pingImages[1], ("Can't find ping image!"));
  880. DEBUG_ASSERTCRASH(pingImages[2], ("Can't find ping image!"));
  881. //Initialize the gadget IDs
  882. parentWOLGameSetupID = TheNameKeyGenerator->nameToKey( AsciiString( "GameSpyGameOptionsMenu.wnd:GameSpyGameOptionsMenuParent" ) );
  883. buttonBackID = TheNameKeyGenerator->nameToKey( AsciiString( "GameSpyGameOptionsMenu.wnd:ButtonBack" ) );
  884. buttonStartID = TheNameKeyGenerator->nameToKey( AsciiString( "GameSpyGameOptionsMenu.wnd:ButtonStart" ) );
  885. textEntryChatID = TheNameKeyGenerator->nameToKey( AsciiString( "GameSpyGameOptionsMenu.wnd:TextEntryChat" ) );
  886. textEntryMapDisplayID = TheNameKeyGenerator->nameToKey( AsciiString( "GameSpyGameOptionsMenu.wnd:TextEntryMapDisplay" ) );
  887. listboxGameSetupChatID = TheNameKeyGenerator->nameToKey( AsciiString( "GameSpyGameOptionsMenu.wnd:ListboxChatWindowGameSpyGameSetup" ) );
  888. buttonEmoteID = TheNameKeyGenerator->nameToKey( AsciiString( "GameSpyGameOptionsMenu.wnd:ButtonEmote" ) );
  889. buttonSelectMapID = TheNameKeyGenerator->nameToKey( AsciiString( "GameSpyGameOptionsMenu.wnd:ButtonSelectMap" ) );
  890. windowMapID = TheNameKeyGenerator->nameToKey( AsciiString( "GameSpyGameOptionsMenu.wnd:MapWindow" ) );
  891. windowMapSelectMapID = TheNameKeyGenerator->nameToKey(AsciiString("WOLMapSelectMenu.wnd:WinMapPreview"));
  892. NameKeyType staticTextTitleID = NAMEKEY("GameSpyGameOptionsMenu.wnd:StaticTextGameName");
  893. // Initialize the pointers to our gadgets
  894. parentWOLGameSetup = TheWindowManager->winGetWindowFromId( NULL, parentWOLGameSetupID );
  895. buttonEmote = TheWindowManager->winGetWindowFromId( parentWOLGameSetup,buttonEmoteID );
  896. buttonSelectMap = TheWindowManager->winGetWindowFromId( parentWOLGameSetup,buttonSelectMapID );
  897. buttonStart = TheWindowManager->winGetWindowFromId( parentWOLGameSetup,buttonStartID );
  898. buttonBack = TheWindowManager->winGetWindowFromId( parentWOLGameSetup, buttonBackID);
  899. listboxGameSetupChat = TheWindowManager->winGetWindowFromId( parentWOLGameSetup, listboxGameSetupChatID );
  900. textEntryChat = TheWindowManager->winGetWindowFromId( parentWOLGameSetup, textEntryChatID );
  901. textEntryMapDisplay = TheWindowManager->winGetWindowFromId( parentWOLGameSetup, textEntryMapDisplayID );
  902. windowMap = TheWindowManager->winGetWindowFromId( parentWOLGameSetup,windowMapID );
  903. DEBUG_ASSERTCRASH(windowMap, ("Could not find the parentWOLGameSetup.wnd:MapWindow" ));
  904. //Added By Sadullah Nader
  905. //Tooltip Function set
  906. windowMap->winSetTooltipFunc(MapSelectorTooltip);
  907. //
  908. GameWindow *staticTextTitle = TheWindowManager->winGetWindowFromId( parentWOLGameSetup, staticTextTitleID );
  909. if (staticTextTitle)
  910. {
  911. GadgetStaticTextSetText(staticTextTitle, TheGameSpyGame->getGameName());
  912. }
  913. if (!theGameInfo)
  914. {
  915. DEBUG_CRASH(("No staging room!"));
  916. return;
  917. }
  918. for (Int i = 0; i < MAX_SLOTS; i++)
  919. {
  920. AsciiString tmpString;
  921. tmpString.format("GameSpyGameOptionsMenu.wnd:ComboBoxPlayer%d", i);
  922. comboBoxPlayerID[i] = TheNameKeyGenerator->nameToKey( tmpString );
  923. comboBoxPlayer[i] = TheWindowManager->winGetWindowFromId( parentWOLGameSetup, comboBoxPlayerID[i] );
  924. GadgetComboBoxReset(comboBoxPlayer[i]);
  925. comboBoxPlayer[i]->winSetTooltipFunc(playerTooltip);
  926. tmpString.format("GameSpyGameOptionsMenu.wnd:StaticTextPlayer%d", i);
  927. staticTextPlayerID[i] = TheNameKeyGenerator->nameToKey( tmpString );
  928. staticTextPlayer[i] = TheWindowManager->winGetWindowFromId( parentWOLGameSetup, staticTextPlayerID[i] );
  929. staticTextPlayer[i]->winSetTooltipFunc(playerTooltip);
  930. if (TheGameSpyInfo->amIHost())
  931. staticTextPlayer[i]->winHide(TRUE);
  932. if(i==0 && TheGameSpyInfo->amIHost())
  933. {
  934. UnicodeString uName;
  935. uName.translate(TheGameSpyInfo->getLocalName());
  936. GadgetComboBoxAddEntry(comboBoxPlayer[i],uName,GameSpyColor[GSCOLOR_PLAYER_OWNER]);
  937. GadgetComboBoxSetSelectedPos(comboBoxPlayer[0],0);
  938. }
  939. else
  940. {
  941. GadgetComboBoxAddEntry(comboBoxPlayer[i],TheGameText->fetch("GUI:Open"),GameSpyColor[GSCOLOR_PLAYER_NORMAL]);
  942. GadgetComboBoxAddEntry(comboBoxPlayer[i],TheGameText->fetch("GUI:Closed"),GameSpyColor[GSCOLOR_PLAYER_NORMAL]);
  943. GadgetComboBoxAddEntry(comboBoxPlayer[i],TheGameText->fetch("GUI:EasyAI"),GameSpyColor[GSCOLOR_PLAYER_NORMAL]);
  944. GadgetComboBoxAddEntry(comboBoxPlayer[i],TheGameText->fetch("GUI:MediumAI"),GameSpyColor[GSCOLOR_PLAYER_NORMAL]);
  945. GadgetComboBoxAddEntry(comboBoxPlayer[i],TheGameText->fetch("GUI:HardAI"),GameSpyColor[GSCOLOR_PLAYER_NORMAL]);
  946. GadgetComboBoxSetSelectedPos(comboBoxPlayer[i],0);
  947. }
  948. tmpString.format("GameSpyGameOptionsMenu.wnd:ComboBoxColor%d", i);
  949. comboBoxColorID[i] = TheNameKeyGenerator->nameToKey( tmpString );
  950. comboBoxColor[i] = TheWindowManager->winGetWindowFromId( parentWOLGameSetup, comboBoxColorID[i] );
  951. DEBUG_ASSERTCRASH(comboBoxColor[i], ("Could not find the comboBoxColor[%d]",i ));
  952. PopulateColorComboBox(i, comboBoxColor, theGameInfo);
  953. GadgetComboBoxSetSelectedPos(comboBoxColor[i], 0);
  954. tmpString.format("GameSpyGameOptionsMenu.wnd:ComboBoxPlayerTemplate%d", i);
  955. comboBoxPlayerTemplateID[i] = TheNameKeyGenerator->nameToKey( tmpString );
  956. comboBoxPlayerTemplate[i] = TheWindowManager->winGetWindowFromId( parentWOLGameSetup, comboBoxPlayerTemplateID[i] );
  957. DEBUG_ASSERTCRASH(comboBoxPlayerTemplate[i], ("Could not find the comboBoxPlayerTemplate[%d]",i ));
  958. PopulatePlayerTemplateComboBox(i, comboBoxPlayerTemplate, theGameInfo, theGameInfo->getAllowObservers());
  959. tmpString.format("GameSpyGameOptionsMenu.wnd:ComboBoxTeam%d", i);
  960. comboBoxTeamID[i] = TheNameKeyGenerator->nameToKey( tmpString );
  961. comboBoxTeam[i] = TheWindowManager->winGetWindowFromId( parentWOLGameSetup, comboBoxTeamID[i] );
  962. DEBUG_ASSERTCRASH(comboBoxTeam[i], ("Could not find the comboBoxTeam[%d]",i ));
  963. PopulateTeamComboBox(i, comboBoxTeam, theGameInfo);
  964. tmpString.format("GameSpyGameOptionsMenu.wnd:ButtonAccept%d", i);
  965. buttonAcceptID[i] = TheNameKeyGenerator->nameToKey( tmpString );
  966. buttonAccept[i] = TheWindowManager->winGetWindowFromId( parentWOLGameSetup, buttonAcceptID[i] );
  967. DEBUG_ASSERTCRASH(buttonAccept[i], ("Could not find the buttonAccept[%d]",i ));
  968. buttonAccept[i]->winSetTooltipFunc(gameAcceptTooltip);
  969. tmpString.format("GameSpyGameOptionsMenu.wnd:GenericPing%d", i);
  970. genericPingWindowID[i] = TheNameKeyGenerator->nameToKey( tmpString );
  971. genericPingWindow[i] = TheWindowManager->winGetWindowFromId( parentWOLGameSetup, genericPingWindowID[i] );
  972. DEBUG_ASSERTCRASH(genericPingWindow[i], ("Could not find the genericPingWindow[%d]",i ));
  973. genericPingWindow[i]->winSetTooltipFunc(pingTooltip);
  974. // tmpString.format("GameSpyGameOptionsMenu.wnd:ButtonStartPosition%d", i);
  975. // buttonStartPositionID[i] = TheNameKeyGenerator->nameToKey( tmpString );
  976. // buttonStartPosition[i] = TheWindowManager->winGetWindowFromId( parentWOLGameSetup, buttonStartPositionID[i] );
  977. // DEBUG_ASSERTCRASH(buttonStartPosition[i], ("Could not find the ButtonStartPosition[%d]",i ));
  978. tmpString.format("GameSpyGameOptionsMenu.wnd:ButtonMapStartPosition%d", i);
  979. buttonMapStartPositionID[i] = TheNameKeyGenerator->nameToKey( tmpString );
  980. buttonMapStartPosition[i] = TheWindowManager->winGetWindowFromId( parentWOLGameSetup, buttonMapStartPositionID[i] );
  981. DEBUG_ASSERTCRASH(buttonMapStartPosition[i], ("Could not find the ButtonMapStartPosition[%d]",i ));
  982. // if (buttonStartPosition[i])
  983. // buttonStartPosition[i]->winHide(TRUE);
  984. if(i !=0 && buttonAccept[i])
  985. buttonAccept[i]->winHide(TRUE);
  986. }
  987. if( buttonAccept[0] )
  988. buttonAccept[0]->winEnable(TRUE);
  989. if (buttonBack != NULL)
  990. {
  991. buttonBack->winEnable(TRUE);
  992. }
  993. //GadgetButtonSetEnabledColor(buttonAccept[0], GameSpyColor[GSCOLOR_ACCEPT_TRUE]);
  994. }
  995. void DeinitWOLGameGadgets( void )
  996. {
  997. parentWOLGameSetup = NULL;
  998. buttonEmote = NULL;
  999. buttonSelectMap = NULL;
  1000. buttonStart = NULL;
  1001. buttonBack = NULL;
  1002. listboxGameSetupChat = NULL;
  1003. textEntryChat = NULL;
  1004. textEntryMapDisplay = NULL;
  1005. windowMap = NULL;
  1006. // GameWindow *staticTextTitle = NULL;
  1007. for (Int i = 0; i < MAX_SLOTS; i++)
  1008. {
  1009. comboBoxPlayer[i] = NULL;
  1010. staticTextPlayer[i] = NULL;
  1011. comboBoxColor[i] = NULL;
  1012. comboBoxPlayerTemplate[i] = NULL;
  1013. comboBoxTeam[i] = NULL;
  1014. buttonAccept[i] = NULL;
  1015. // buttonStartPosition[i] = NULL;
  1016. buttonMapStartPosition[i] = NULL;
  1017. genericPingWindow[i] = NULL;
  1018. }
  1019. }
  1020. static Bool initDone = false;
  1021. UnsignedInt lastSlotlistTime = 0;
  1022. UnsignedInt enterTime = 0;
  1023. Bool initialAcceptEnable = FALSE;
  1024. //-------------------------------------------------------------------------------------------------
  1025. /** Initialize the Lan Game Options Menu */
  1026. //-------------------------------------------------------------------------------------------------
  1027. void WOLGameSetupMenuInit( WindowLayout *layout, void *userData )
  1028. {
  1029. if (TheGameSpyGame && TheGameSpyGame->isGameInProgress())
  1030. {
  1031. TheGameSpyGame->setGameInProgress(FALSE);
  1032. // check if we were disconnected
  1033. Int disconReason;
  1034. if (TheGameSpyInfo->isDisconnectedAfterGameStart(&disconReason))
  1035. {
  1036. AsciiString disconMunkee;
  1037. disconMunkee.format("GUI:GSDisconReason%d", disconReason);
  1038. UnicodeString title, body;
  1039. title = TheGameText->fetch( "GUI:GSErrorTitle" );
  1040. body = TheGameText->fetch( disconMunkee );
  1041. GameSpyCloseAllOverlays();
  1042. GSMessageBoxOk( title, body );
  1043. TheGameSpyInfo->reset();
  1044. DEBUG_LOG(("WOLGameSetupMenuInit() - game was in progress, and we were disconnected, so pop immediate back to main menu\n"));
  1045. TheShell->popImmediate();
  1046. return;
  1047. }
  1048. // If we init while the game is in progress, we are really returning to the menu
  1049. // after the game. So, we pop the menu and go back to the lobby. Whee!
  1050. DEBUG_LOG(("WOLGameSetupMenuInit() - game was in progress, so pop immediate back to lobby\n"));
  1051. TheShell->popImmediate();
  1052. if (TheGameSpyPeerMessageQueue && TheGameSpyPeerMessageQueue->isConnected())
  1053. {
  1054. DEBUG_LOG(("We're still connected, so pushing back on the lobby\n"));
  1055. TheShell->push("Menus/WOLCustomLobby.wnd", TRUE);
  1056. }
  1057. return;
  1058. }
  1059. TheGameSpyInfo->setCurrentGroupRoom(0);
  1060. if (TheNAT != NULL) {
  1061. delete TheNAT;
  1062. TheNAT = NULL;
  1063. }
  1064. nextScreen = NULL;
  1065. buttonPushed = false;
  1066. isShuttingDown = false;
  1067. launchGameNext = FALSE;
  1068. //initialize the gadgets
  1069. EnableSlotListUpdates(FALSE);
  1070. InitWOLGameGadgets();
  1071. EnableSlotListUpdates(TRUE);
  1072. TheGameSpyInfo->registerTextWindow(listboxGameSetupChat);
  1073. //The dialog needs to react differently depending on whether it's the host or not.
  1074. TheMapCache->updateCache();
  1075. GameSpyStagingRoom *game = TheGameSpyInfo->getCurrentStagingRoom();
  1076. GameSpyGameSlot *hostSlot = game->getGameSpySlot(0);
  1077. hostSlot->setAccept();
  1078. if (TheGameSpyInfo->amIHost())
  1079. {
  1080. OptionPreferences natPref;
  1081. CustomMatchPreferences customPref;
  1082. hostSlot->setColor( customPref.getPreferredColor() );
  1083. hostSlot->setPlayerTemplate( customPref.getPreferredFaction() );
  1084. hostSlot->setNATBehavior((FirewallHelperClass::FirewallBehaviorType)natPref.getFirewallBehavior());
  1085. hostSlot->setPingString(TheGameSpyInfo->getPingString());
  1086. game->setMap(customPref.getPreferredMap());
  1087. for (Int i=1; i<MAX_SLOTS; ++i)
  1088. {
  1089. GameSpyGameSlot *slot = game->getGameSpySlot(i);
  1090. slot->setState( SLOT_OPEN );
  1091. }
  1092. AsciiString lowerMap = customPref.getPreferredMap();
  1093. lowerMap.toLower();
  1094. std::map<AsciiString, MapMetaData>::iterator it = TheMapCache->find(lowerMap);
  1095. if (it != TheMapCache->end())
  1096. {
  1097. hostSlot->setMapAvailability(TRUE);
  1098. game->setMapCRC( it->second.m_CRC );
  1099. game->setMapSize( it->second.m_filesize );
  1100. game->adjustSlotsForMap(); // BGC- adjust the slots for the new map.
  1101. }
  1102. WOLDisplaySlotList();
  1103. WOLDisplayGameOptions();
  1104. }
  1105. else
  1106. {
  1107. OptionPreferences natPref;
  1108. CustomMatchPreferences customPref;
  1109. AsciiString options;
  1110. PeerRequest req;
  1111. UnicodeString uName = hostSlot->getName();
  1112. AsciiString aName;
  1113. aName.translate(uName);
  1114. req.peerRequestType = PeerRequest::PEERREQUEST_UTMPLAYER;
  1115. req.UTM.isStagingRoom = TRUE;
  1116. req.id = "REQ/";
  1117. req.nick = aName.str();
  1118. options.format("PlayerTemplate=%d", customPref.getPreferredFaction());
  1119. req.options = options.str();
  1120. TheGameSpyPeerMessageQueue->addRequest(req);
  1121. options.format("Color=%d", customPref.getPreferredColor());
  1122. req.options = options.str();
  1123. TheGameSpyPeerMessageQueue->addRequest(req);
  1124. options.format("NAT=%d", natPref.getFirewallBehavior());
  1125. req.options = options.str();
  1126. TheGameSpyPeerMessageQueue->addRequest(req);
  1127. options.format("Ping=%s", TheGameSpyInfo->getPingString().str());
  1128. req.options = options.str();
  1129. TheGameSpyPeerMessageQueue->addRequest(req);
  1130. game->setMapCRC( game->getMapCRC() ); // force a recheck
  1131. game->setMapSize( game->getMapSize() ); // of if we have the map
  1132. for (Int i = 0; i < MAX_SLOTS; ++i)
  1133. {
  1134. //I'm a client, disable the controls I can't touch.
  1135. comboBoxPlayer[i]->winEnable(FALSE);
  1136. comboBoxColor[i]->winEnable(FALSE);
  1137. comboBoxPlayerTemplate[i]->winEnable(FALSE);
  1138. comboBoxTeam[i]->winEnable(FALSE);
  1139. // buttonStartPosition[i]->winEnable(FALSE);
  1140. buttonMapStartPosition[i]->winEnable(FALSE);
  1141. }
  1142. buttonStart->winSetText(TheGameText->fetch("GUI:Accept"));
  1143. buttonStart->winEnable( FALSE );
  1144. buttonSelectMap->winEnable( FALSE );
  1145. initialAcceptEnable = FALSE;
  1146. }
  1147. // Show the Menu
  1148. layout->hide( FALSE );
  1149. // Make sure the text fields are clear
  1150. GadgetListBoxReset( listboxGameSetupChat );
  1151. GadgetTextEntrySetText(textEntryChat, UnicodeString::TheEmptyString);
  1152. initDone = true;
  1153. TheGameSpyInfo->setGameOptions();
  1154. //TheShell->registerWithAnimateManager(parentWOLGameSetup, WIN_ANIMATION_SLIDE_TOP, TRUE);
  1155. WOLPositionStartSpots();
  1156. lastSlotlistTime = 0;
  1157. enterTime = timeGetTime();
  1158. // Set Keyboard to chat entry
  1159. TheWindowManager->winSetFocus( textEntryChat );
  1160. raiseMessageBoxes = true;
  1161. TheTransitionHandler->setGroup("GameSpyGameOptionsMenuFade");
  1162. }// void WOLGameSetupMenuInit( WindowLayout *layout, void *userData )
  1163. //-------------------------------------------------------------------------------------------------
  1164. /** This is called when a shutdown is complete for this menu */
  1165. //-------------------------------------------------------------------------------------------------
  1166. static void shutdownComplete( WindowLayout *layout )
  1167. {
  1168. isShuttingDown = false;
  1169. // hide the layout
  1170. layout->hide( TRUE );
  1171. // our shutdown is complete
  1172. TheShell->shutdownComplete( layout, (nextScreen != NULL) );
  1173. if (nextScreen != NULL)
  1174. {
  1175. if (!TheGameSpyPeerMessageQueue || !TheGameSpyPeerMessageQueue->isConnected())
  1176. {
  1177. DEBUG_LOG(("GameSetup shutdownComplete() - skipping push because we're disconnected\n"));
  1178. }
  1179. else
  1180. {
  1181. TheShell->push(nextScreen);
  1182. }
  1183. }
  1184. /*
  1185. if (launchGameNext)
  1186. {
  1187. TheGameSpyGame->launchGame();
  1188. TheGameSpyInfo->leaveStagingRoom();
  1189. }
  1190. */
  1191. nextScreen = NULL;
  1192. } // end if
  1193. //-------------------------------------------------------------------------------------------------
  1194. /** GameSpy Game Options menu shutdown method */
  1195. //-------------------------------------------------------------------------------------------------
  1196. void WOLGameSetupMenuShutdown( WindowLayout *layout, void *userData )
  1197. {
  1198. TheGameSpyInfo->unregisterTextWindow(listboxGameSetupChat);
  1199. if( WOLMapSelectLayout )
  1200. {
  1201. WOLMapSelectLayout->destroyWindows();
  1202. WOLMapSelectLayout->deleteInstance();
  1203. WOLMapSelectLayout = NULL;
  1204. }
  1205. parentWOLGameSetup = NULL;
  1206. EnableSlotListUpdates(FALSE);
  1207. DeinitWOLGameGadgets();
  1208. if (TheEstablishConnectionsMenu != NULL)
  1209. {
  1210. TheEstablishConnectionsMenu->endMenu();
  1211. }
  1212. initDone = false;
  1213. isShuttingDown = true;
  1214. // if we are shutting down for an immediate pop, skip the animations
  1215. Bool popImmediate = *(Bool *)userData;
  1216. if( popImmediate )
  1217. {
  1218. shutdownComplete( layout );
  1219. return;
  1220. } //end if
  1221. TheShell->reverseAnimatewindow();
  1222. RaiseGSMessageBox();
  1223. TheTransitionHandler->reverse("GameSpyGameOptionsMenuFade");
  1224. } // void WOLGameSetupMenuShutdown( WindowLayout *layout, void *userData )
  1225. static void fillPlayerInfo(const PeerResponse *resp, PlayerInfo *info)
  1226. {
  1227. info->m_name = resp->nick.c_str();
  1228. info->m_profileID = resp->player.profileID;
  1229. info->m_flags = resp->player.flags;
  1230. info->m_wins = resp->player.wins;
  1231. info->m_losses = resp->player.losses;
  1232. info->m_locale = resp->locale.c_str();
  1233. info->m_rankPoints= resp->player.rankPoints;
  1234. info->m_side = resp->player.side;
  1235. info->m_preorder = resp->player.preorder;
  1236. }
  1237. //-------------------------------------------------------------------------------------------------
  1238. /** Lan Game Options menu update method */
  1239. //-------------------------------------------------------------------------------------------------
  1240. void WOLGameSetupMenuUpdate( WindowLayout * layout, void *userData)
  1241. {
  1242. // We'll only be successful if we've requested to
  1243. if(isShuttingDown && TheShell->isAnimFinished() && TheTransitionHandler->isFinished())
  1244. {
  1245. shutdownComplete(layout);
  1246. return;
  1247. }
  1248. if (raiseMessageBoxes)
  1249. {
  1250. RaiseGSMessageBox();
  1251. raiseMessageBoxes = false;
  1252. }
  1253. if (TheShell->isAnimFinished() && !buttonPushed && TheGameSpyPeerMessageQueue)
  1254. {
  1255. HandleBuddyResponses();
  1256. HandlePersistentStorageResponses();
  1257. if (TheGameSpyGame && TheGameSpyGame->isGameInProgress())
  1258. {
  1259. if (TheGameSpyInfo->isDisconnectedAfterGameStart(NULL))
  1260. {
  1261. return; // already been disconnected, so don't worry.
  1262. }
  1263. Int allowedMessages = TheGameSpyInfo->getMaxMessagesPerUpdate();
  1264. Bool sawImportantMessage = FALSE;
  1265. PeerResponse resp;
  1266. while (allowedMessages-- && !sawImportantMessage && TheGameSpyPeerMessageQueue->getResponse( resp ))
  1267. {
  1268. switch (resp.peerResponseType)
  1269. {
  1270. case PeerResponse::PEERRESPONSE_DISCONNECT:
  1271. {
  1272. sawImportantMessage = TRUE;
  1273. AsciiString disconMunkee;
  1274. disconMunkee.format("GUI:GSDisconReason%d", resp.discon.reason);
  1275. // check for scorescreen
  1276. NameKeyType listboxChatWindowScoreScreenID = NAMEKEY("ScoreScreen.wnd:ListboxChatWindowScoreScreen");
  1277. GameWindow *listboxChatWindowScoreScreen = TheWindowManager->winGetWindowFromId( NULL, listboxChatWindowScoreScreenID );
  1278. if (listboxChatWindowScoreScreen)
  1279. {
  1280. GadgetListBoxAddEntryText(listboxChatWindowScoreScreen, TheGameText->fetch(disconMunkee),
  1281. GameSpyColor[GSCOLOR_DEFAULT], -1);
  1282. }
  1283. else
  1284. {
  1285. // still ingame
  1286. TheInGameUI->message(disconMunkee);
  1287. }
  1288. TheGameSpyInfo->markAsDisconnectedAfterGameStart(resp.discon.reason);
  1289. }
  1290. }
  1291. }
  1292. return; // if we're in game, all we care about is if we've been disconnected from the chat server
  1293. }
  1294. Bool isHosting = TheGameSpyInfo->amIHost(); // only while in game setup screen
  1295. isHosting = isHosting || (TheGameSpyGame && TheGameSpyGame->isInGame() && TheGameSpyGame->amIHost()); // while in game
  1296. if (!isHosting && !lastSlotlistTime && timeGetTime() > enterTime + 10000)
  1297. {
  1298. // don't do this if we're disconnected
  1299. if (TheGameSpyPeerMessageQueue->isConnected())
  1300. {
  1301. // haven't seen ourselves
  1302. buttonPushed = true;
  1303. DEBUG_LOG(("Haven't seen ourselves in slotlist\n"));
  1304. if (TheGameSpyGame)
  1305. TheGameSpyGame->reset();
  1306. TheGameSpyInfo->leaveStagingRoom();
  1307. //TheGameSpyInfo->joinBestGroupRoom();
  1308. GSMessageBoxOk(TheGameText->fetch("GUI:HostLeftTitle"), TheGameText->fetch("GUI:HostLeft"));
  1309. nextScreen = "Menus/WOLCustomLobby.wnd";
  1310. TheShell->pop();
  1311. }
  1312. return;
  1313. }
  1314. if (TheNAT != NULL) {
  1315. NATStateType NATState = TheNAT->update();
  1316. if (NATState == NATSTATE_DONE)
  1317. {
  1318. //launchGameNext = TRUE;
  1319. //TheShell->pop();
  1320. TheGameSpyGame->launchGame();
  1321. if (TheGameSpyInfo) // this can be blown away by a disconnect on the map transfer screen
  1322. TheGameSpyInfo->leaveStagingRoom();
  1323. return;
  1324. }
  1325. else if (NATState == NATSTATE_FAILED)
  1326. {
  1327. // Just back out. This cleans up some slot list problems
  1328. buttonPushed = true;
  1329. // delete TheNAT, its no good for us anymore.
  1330. delete TheNAT;
  1331. TheNAT = NULL;
  1332. TheGameSpyInfo->getCurrentStagingRoom()->reset();
  1333. TheGameSpyInfo->leaveStagingRoom();
  1334. //TheGameSpyInfo->joinBestGroupRoom();
  1335. GSMessageBoxOk(TheGameText->fetch("GUI:Error"), TheGameText->fetch("GUI:NATNegotiationFailed"));
  1336. nextScreen = "Menus/WOLCustomLobby.wnd";
  1337. TheShell->pop();
  1338. return;
  1339. }
  1340. }
  1341. PeerResponse resp;
  1342. Int allowedMessages = TheGameSpyInfo->getMaxMessagesPerUpdate();
  1343. Bool sawImportantMessage = FALSE;
  1344. while (allowedMessages-- && !sawImportantMessage)
  1345. {
  1346. if (!TheLobbyQueuedUTMs.empty())
  1347. {
  1348. DEBUG_LOG(("Got response from queued lobby UTM list\n"));
  1349. resp = TheLobbyQueuedUTMs.front();
  1350. TheLobbyQueuedUTMs.pop_front();
  1351. }
  1352. else if (TheGameSpyPeerMessageQueue->getResponse( resp ))
  1353. {
  1354. DEBUG_LOG(("Got response from message queue\n"));
  1355. }
  1356. else
  1357. {
  1358. break;
  1359. }
  1360. switch (resp.peerResponseType)
  1361. {
  1362. case PeerResponse::PEERRESPONSE_FAILEDTOHOST:
  1363. {
  1364. // oops - we've not heard from the qr server. bail.
  1365. TheGameSpyInfo->addText(TheGameText->fetch("GUI:GSFailedToHost"), GameSpyColor[GSCOLOR_DEFAULT], NULL);
  1366. }
  1367. break;
  1368. case PeerResponse::PEERRESPONSE_GAMESTART:
  1369. {
  1370. sawImportantMessage = TRUE;
  1371. GameSpyStagingRoom *myGame = TheGameSpyInfo->getCurrentStagingRoom();
  1372. if (!myGame || !myGame->isInGame())
  1373. break;
  1374. if (!TheGameSpyGame)
  1375. break;
  1376. SendStatsToOtherPlayers(TheGameSpyGame);
  1377. // we've started, there's no going back
  1378. // i.e. disable the back button.
  1379. buttonBack->winEnable(FALSE);
  1380. GameWindow *buttonBuddy = TheWindowManager->winGetWindowFromId(NULL, NAMEKEY("GameSpyGameOptionsMenu.wnd:ButtonCommunicator"));
  1381. if (buttonBuddy)
  1382. buttonBuddy->winEnable(FALSE);
  1383. GameSpyCloseOverlay(GSOVERLAY_BUDDY);
  1384. *TheGameSpyGame = *myGame;
  1385. TheGameSpyGame->startGame(0);
  1386. }
  1387. break;
  1388. case PeerResponse::PEERRESPONSE_PLAYERCHANGEDFLAGS:
  1389. {
  1390. PlayerInfo p;
  1391. fillPlayerInfo(&resp, &p);
  1392. TheGameSpyInfo->updatePlayerInfo(p);
  1393. WOLDisplaySlotList();
  1394. }
  1395. break;
  1396. case PeerResponse::PEERRESPONSE_PLAYERINFO:
  1397. {
  1398. PlayerInfo p;
  1399. fillPlayerInfo(&resp, &p);
  1400. TheGameSpyInfo->updatePlayerInfo(p);
  1401. WOLDisplaySlotList();
  1402. // send out new slotlist if I'm host
  1403. TheGameSpyInfo->setGameOptions();
  1404. }
  1405. break;
  1406. case PeerResponse::PEERRESPONSE_PLAYERJOIN:
  1407. {
  1408. if (resp.player.roomType != StagingRoom)
  1409. {
  1410. break;
  1411. }
  1412. sawImportantMessage = TRUE;
  1413. PlayerInfo p;
  1414. fillPlayerInfo(&resp, &p);
  1415. TheGameSpyInfo->updatePlayerInfo(p);
  1416. if (p.m_profileID)
  1417. {
  1418. if (TheGameSpyPSMessageQueue->findPlayerStatsByID(p.m_profileID).id == 0)
  1419. {
  1420. PSRequest req;
  1421. req.requestType = PSRequest::PSREQUEST_READPLAYERSTATS;
  1422. req.player.id = p.m_profileID;
  1423. TheGameSpyPSMessageQueue->addRequest(req);
  1424. }
  1425. }
  1426. // check if we have room for the dude
  1427. GameInfo *game = TheGameSpyInfo->getCurrentStagingRoom();
  1428. if (TheGameSpyInfo->amIHost() && game)
  1429. {
  1430. if (TheNAT)
  1431. {
  1432. // ditch him
  1433. PeerRequest req;
  1434. req.peerRequestType = PeerRequest::PEERREQUEST_UTMPLAYER;
  1435. req.UTM.isStagingRoom = TRUE;
  1436. req.id = "KICK/";
  1437. req.nick = p.m_name.str();
  1438. req.options = "GameStarted";
  1439. TheGameSpyPeerMessageQueue->addRequest(req);
  1440. }
  1441. else
  1442. {
  1443. // look for room for him
  1444. // See if there's room
  1445. // First get the number of players currently in the room.
  1446. Int numPlayers = 0;
  1447. for (Int player = 0; player < MAX_SLOTS; ++player)
  1448. {
  1449. if (game->getSlot(player)->isOccupied() &&
  1450. game->getSlot(player)->getPlayerTemplate() != PLAYERTEMPLATE_OBSERVER)
  1451. {
  1452. ++numPlayers;
  1453. }
  1454. }
  1455. // now get the number of starting spots on the map.
  1456. Int numStartingSpots = MAX_SLOTS;
  1457. const MapMetaData *md = TheMapCache->findMap(game->getMap());
  1458. if (md != NULL)
  1459. {
  1460. numStartingSpots = md->m_numPlayers;
  1461. }
  1462. Int openSlotIndex = -1;
  1463. for (Int i=0; i<MAX_SLOTS; ++i)
  1464. {
  1465. const GameSlot *slot = game->getConstSlot(i);
  1466. if (slot && slot->isOpen())
  1467. {
  1468. openSlotIndex = i;
  1469. break;
  1470. }
  1471. }
  1472. if (openSlotIndex >= 0)
  1473. {
  1474. // add him
  1475. GameSlot newSlot;
  1476. UnicodeString uName;
  1477. uName.translate(p.m_name);
  1478. newSlot.setState(SLOT_PLAYER, uName);
  1479. newSlot.setIP(ntohl(resp.player.IP));
  1480. game->setSlot( openSlotIndex, newSlot );
  1481. game->resetAccepted(); // BGC - need to unaccept everyone if someone joins the game.
  1482. }
  1483. else
  1484. {
  1485. // ditch him
  1486. PeerRequest req;
  1487. req.peerRequestType = PeerRequest::PEERREQUEST_UTMPLAYER;
  1488. req.UTM.isStagingRoom = TRUE;
  1489. req.id = "KICK/";
  1490. req.nick = p.m_name.str();
  1491. req.options = "GameFull";
  1492. TheGameSpyPeerMessageQueue->addRequest(req);
  1493. }
  1494. // send out new slotlist if I'm host
  1495. TheGameSpyInfo->setGameOptions();
  1496. }
  1497. }
  1498. WOLDisplaySlotList();
  1499. }
  1500. break;
  1501. case PeerResponse::PEERRESPONSE_PLAYERLEFT:
  1502. {
  1503. sawImportantMessage = TRUE;
  1504. PlayerInfo p;
  1505. fillPlayerInfo(&resp, &p);
  1506. TheGameSpyInfo->playerLeftGroupRoom(resp.nick.c_str());
  1507. if (TheGameSpyGame && TheGameSpyGame->isGameInProgress())
  1508. {
  1509. break;
  1510. }
  1511. if (TheNAT == NULL) // don't update slot list if we're trying to start a game
  1512. {
  1513. GameInfo *game = TheGameSpyInfo->getCurrentStagingRoom();
  1514. if (game && TheGameSpyInfo->amIHost())
  1515. {
  1516. Int idx = game->getSlotNum(resp.nick.c_str());
  1517. if (idx >= 0)
  1518. {
  1519. game->getSlot(idx)->setState(SLOT_OPEN);
  1520. game->resetAccepted(); // BGC - need to unaccept everyone if someone leaves the game.
  1521. }
  1522. }
  1523. // send out new slotlist if I'm host
  1524. TheGameSpyInfo->setGameOptions();
  1525. WOLDisplaySlotList();
  1526. if (game && !TheGameSpyInfo->amIHost())
  1527. {
  1528. Int idx = game->getSlotNum(resp.nick.c_str());
  1529. if (idx == 0)
  1530. {
  1531. // host left
  1532. buttonPushed = true;
  1533. TheGameSpyInfo->getCurrentStagingRoom()->reset();
  1534. TheGameSpyInfo->leaveStagingRoom();
  1535. //TheGameSpyInfo->joinBestGroupRoom();
  1536. GSMessageBoxOk(TheGameText->fetch("GUI:HostLeftTitle"), TheGameText->fetch("GUI:HostLeft"));
  1537. nextScreen = "Menus/WOLCustomLobby.wnd";
  1538. TheShell->pop();
  1539. }
  1540. }
  1541. }
  1542. }
  1543. break;
  1544. case PeerResponse::PEERRESPONSE_MESSAGE:
  1545. {
  1546. TheGameSpyInfo->addChat(resp.nick.c_str(), resp.message.profileID,
  1547. UnicodeString(resp.text.c_str()), !resp.message.isPrivate, resp.message.isAction, listboxGameSetupChat);
  1548. }
  1549. break;
  1550. case PeerResponse::PEERRESPONSE_DISCONNECT:
  1551. {
  1552. sawImportantMessage = TRUE;
  1553. UnicodeString title, body;
  1554. AsciiString disconMunkee;
  1555. disconMunkee.format("GUI:GSDisconReason%d", resp.discon.reason);
  1556. title = TheGameText->fetch( "GUI:GSErrorTitle" );
  1557. body = TheGameText->fetch( disconMunkee );
  1558. GameSpyCloseAllOverlays();
  1559. GSMessageBoxOk( title, body );
  1560. TheGameSpyInfo->reset();
  1561. TheShell->pop();
  1562. }
  1563. case PeerResponse::PEERRESPONSE_ROOMUTM:
  1564. {
  1565. sawImportantMessage = TRUE;
  1566. #if defined(_DEBUG) || defined(_INTERNAL)
  1567. if (g_debugSlots)
  1568. {
  1569. DEBUG_LOG(("About to process a room UTM. Command is '%s', command options is '%s'\n",
  1570. resp.command.c_str(), resp.commandOptions.c_str()));
  1571. }
  1572. #endif
  1573. if (!strcmp(resp.command.c_str(), "SL"))
  1574. {
  1575. // slotlist
  1576. GameSpyStagingRoom *game = TheGameSpyInfo->getCurrentStagingRoom();
  1577. Bool isValidSlotList = game && game->getSlot(0) && game->getSlot(0)->isPlayer( resp.nick.c_str() ) && !TheGameSpyInfo->amIHost();
  1578. if (!isValidSlotList)
  1579. {
  1580. SLOTLIST_DEBUG_LOG(("Not a valid slotlist\n"));
  1581. if (!game)
  1582. {
  1583. SLOTLIST_DEBUG_LOG(("No game!\n"));
  1584. }
  1585. else
  1586. {
  1587. if (!game->getSlot(0))
  1588. {
  1589. SLOTLIST_DEBUG_LOG(("No slot 0!\n"));
  1590. }
  1591. else
  1592. {
  1593. if (TheGameSpyInfo->amIHost())
  1594. {
  1595. SLOTLIST_DEBUG_LOG(("I'm the host!\n"));
  1596. }
  1597. else
  1598. {
  1599. SLOTLIST_DEBUG_LOG(("Not from the host! isHuman:%d, name:'%ls', sender:'%s'\n",
  1600. game->getSlot(0)->isHuman(), game->getSlot(0)->getName().str(),
  1601. resp.nick.c_str()));
  1602. }
  1603. }
  1604. }
  1605. }
  1606. else // isValidSlotList
  1607. {
  1608. Int oldLocalSlotNum = (game->isInGame()) ? game->getLocalSlotNum() : -1;
  1609. Bool wasInGame = oldLocalSlotNum >= 0;
  1610. AsciiString oldMap = game->getMap();
  1611. UnsignedInt oldMapCRC, newMapCRC;
  1612. oldMapCRC = game->getMapCRC();
  1613. AsciiString options = resp.commandOptions.c_str();
  1614. options.trim();
  1615. UnsignedShort ports[MAX_SLOTS];
  1616. UnsignedInt ips[MAX_SLOTS];
  1617. Int i;
  1618. for (i=0; i<MAX_SLOTS; ++i)
  1619. {
  1620. if (game && game->getConstSlot(i))
  1621. {
  1622. ips[i] = game->getConstSlot(i)->getIP();
  1623. ports[i] = game->getConstSlot(i)->getPort();
  1624. }
  1625. else
  1626. {
  1627. ips[i] = 0;
  1628. ports[i] = 0;
  1629. }
  1630. }
  1631. Bool optionsOK = ParseAsciiStringToGameInfo(game, options.str());
  1632. if (TheNAT)
  1633. {
  1634. for (i=0; i<MAX_SLOTS; ++i)
  1635. {
  1636. if (game && game->getSlot(i))
  1637. {
  1638. #ifdef DEBUG_LOGGING
  1639. UnsignedShort newPort = game->getConstSlot(i)->getPort();
  1640. UnsignedInt newIP = game->getConstSlot(i)->getIP();
  1641. DEBUG_ASSERTLOG(newIP == ips[i], ("IP was different for player %d (%X --> %X)\n",
  1642. i, ips[i], newIP));
  1643. DEBUG_ASSERTLOG(newPort == ports[i], ("Port was different for player %d (%d --> %d)\n",
  1644. i, ports[i], newPort));
  1645. #endif
  1646. game->getSlot(i)->setPort(ports[i]);
  1647. game->getSlot(i)->setIP(ips[i]);
  1648. }
  1649. }
  1650. }
  1651. Int newLocalSlotNum = (game->isInGame()) ? game->getLocalSlotNum() : -1;
  1652. Bool isInGame = newLocalSlotNum >= 0;
  1653. if (!optionsOK)
  1654. {
  1655. SLOTLIST_DEBUG_LOG(("Options are bad! bailing!\n"));
  1656. break;
  1657. }
  1658. else
  1659. {
  1660. SLOTLIST_DEBUG_LOG(("Options are good, local slot is %d\n", newLocalSlotNum));
  1661. if (!isInGame)
  1662. {
  1663. SLOTLIST_DEBUG_LOG(("Not in game; players are:\n"));
  1664. for (Int i=0; i<MAX_SLOTS; ++i)
  1665. {
  1666. const GameSpyGameSlot *slot = game->getGameSpySlot(i);
  1667. if (slot && slot->isHuman())
  1668. {
  1669. UnicodeString munkee;
  1670. munkee.format(L"\t%d: %ls", i, slot->getName().str());
  1671. SLOTLIST_DEBUG_LOG(("%ls\n", munkee.str()));
  1672. }
  1673. }
  1674. }
  1675. }
  1676. WOLDisplaySlotList();
  1677. // if I changed map availability, send it across
  1678. newMapCRC = game->getMapCRC();
  1679. if (isInGame)
  1680. {
  1681. lastSlotlistTime = timeGetTime();
  1682. if ( (oldMapCRC ^ newMapCRC) || (!wasInGame && isInGame) )
  1683. {
  1684. // it changed. send it
  1685. UnicodeString hostName = TheGameSpyInfo->getCurrentStagingRoom()->getSlot(0)->getName();
  1686. AsciiString asciiName;
  1687. asciiName.translate(hostName);
  1688. PeerRequest req;
  1689. req.peerRequestType = PeerRequest::PEERREQUEST_UTMPLAYER;
  1690. req.UTM.isStagingRoom = TRUE;
  1691. req.id = "MAP";
  1692. req.nick = asciiName.str();
  1693. req.options = (game->getSlot(newLocalSlotNum)->hasMap())?"1":"0";
  1694. TheGameSpyPeerMessageQueue->addRequest(req);
  1695. if (!game->getSlot(newLocalSlotNum)->hasMap())
  1696. {
  1697. UnicodeString text;
  1698. UnicodeString mapDisplayName;
  1699. const MapMetaData *mapData = TheMapCache->findMap( game->getMap() );
  1700. Bool willTransfer = TRUE;
  1701. if (mapData)
  1702. {
  1703. mapDisplayName.format(L"%ls", mapData->m_displayName.str());
  1704. willTransfer = !mapData->m_isOfficial;
  1705. }
  1706. else
  1707. {
  1708. mapDisplayName.format(L"%hs", TheGameState->getMapLeafName(game->getMap()).str());
  1709. willTransfer = WouldMapTransfer(game->getMap());
  1710. }
  1711. if (willTransfer)
  1712. text.format(TheGameText->fetch("GUI:LocalPlayerNoMapWillTransfer"), mapDisplayName.str());
  1713. else
  1714. text.format(TheGameText->fetch("GUI:LocalPlayerNoMap"), mapDisplayName.str());
  1715. TheGameSpyInfo->addText(text, GameSpyColor[GSCOLOR_DEFAULT], listboxGameSetupChat);
  1716. }
  1717. }
  1718. if (!initialAcceptEnable)
  1719. {
  1720. buttonStart->winEnable( TRUE );
  1721. initialAcceptEnable = TRUE;
  1722. }
  1723. }
  1724. else
  1725. {
  1726. if (lastSlotlistTime)
  1727. {
  1728. // can't see ourselves
  1729. buttonPushed = true;
  1730. DEBUG_LOG(("Can't see ourselves in slotlist %s\n", options.str()));
  1731. TheGameSpyInfo->getCurrentStagingRoom()->reset();
  1732. TheGameSpyInfo->leaveStagingRoom();
  1733. //TheGameSpyInfo->joinBestGroupRoom();
  1734. GSMessageBoxOk(TheGameText->fetch("GUI:GSErrorTitle"), TheGameText->fetch("GUI:GSKicked"));
  1735. nextScreen = "Menus/WOLCustomLobby.wnd";
  1736. TheShell->pop();
  1737. }
  1738. }
  1739. }
  1740. }
  1741. else if (!strcmp(resp.command.c_str(), "HWS"))
  1742. {
  1743. // host wants to start
  1744. GameInfo *game = TheGameSpyInfo->getCurrentStagingRoom();
  1745. if (game && game->isInGame() && game->getSlot(0) && game->getSlot(0)->isPlayer( resp.nick.c_str() ))
  1746. {
  1747. Int slotNum = game->getLocalSlotNum();
  1748. GameSlot *slot = game->getSlot(slotNum);
  1749. if (slot && (slot->isAccepted() == false))
  1750. {
  1751. TheGameSpyInfo->addText(TheGameText->fetch("GUI:HostWantsToStart"), GameSpyColor[GSCOLOR_DEFAULT], listboxGameSetupChat);
  1752. }
  1753. }
  1754. }
  1755. else if (!stricmp(resp.command.c_str(), "NAT"))
  1756. {
  1757. if (TheNAT != NULL) {
  1758. TheNAT->processGlobalMessage(-1, resp.commandOptions.c_str());
  1759. }
  1760. }
  1761. else if (!stricmp(resp.command.c_str(), "Pings"))
  1762. {
  1763. if (!TheGameSpyInfo->amIHost())
  1764. {
  1765. AsciiString pings = resp.commandOptions.c_str();
  1766. AsciiString token;
  1767. for (Int i=0; i<MAX_SLOTS; ++i)
  1768. {
  1769. GameSpyGameSlot *slot = TheGameSpyInfo->getCurrentStagingRoom()->getGameSpySlot(i);
  1770. if (pings.nextToken(&token, ","))
  1771. {
  1772. token.trim();
  1773. slot->setPingString(token);
  1774. }
  1775. else
  1776. {
  1777. slot->setPingString("");
  1778. }
  1779. }
  1780. }
  1781. }
  1782. }
  1783. break;
  1784. case PeerResponse::PEERRESPONSE_PLAYERUTM:
  1785. {
  1786. sawImportantMessage = TRUE;
  1787. if (!strcmp(resp.command.c_str(), "STATS"))
  1788. {
  1789. PSPlayerStats stats = TheGameSpyPSMessageQueue->parsePlayerKVPairs(resp.commandOptions.c_str());
  1790. if (stats.id && (TheGameSpyPSMessageQueue->findPlayerStatsByID(stats.id).id == 0))
  1791. TheGameSpyPSMessageQueue->trackPlayerStats(stats);
  1792. break;
  1793. }
  1794. GameSpyStagingRoom *game = TheGameSpyInfo->getCurrentStagingRoom();
  1795. if (game)
  1796. {
  1797. Int slotNum = game->getSlotNum(resp.nick.c_str());
  1798. if ((slotNum >= 0) && (slotNum < MAX_SLOTS) && (!stricmp(resp.command.c_str(), "NAT"))) {
  1799. // this is a command for NAT negotiations, pass if off to TheNAT
  1800. if (TheNAT != NULL) {
  1801. TheNAT->processGlobalMessage(slotNum, resp.commandOptions.c_str());
  1802. }
  1803. }
  1804. if (slotNum == 0 && !TheGameSpyInfo->amIHost())
  1805. {
  1806. if (!strcmp(resp.command.c_str(), "KICK"))
  1807. {
  1808. // oops - we've been kicked. bail.
  1809. buttonPushed = true;
  1810. TheGameSpyInfo->getCurrentStagingRoom()->reset();
  1811. TheGameSpyInfo->leaveStagingRoom();
  1812. //TheGameSpyInfo->joinBestGroupRoom();
  1813. UnicodeString message = TheGameText->fetch("GUI:GSKicked");
  1814. AsciiString commandMessage = resp.commandOptions.c_str();
  1815. commandMessage.trim();
  1816. DEBUG_LOG(("We were kicked: reason was '%s'\n", resp.commandOptions.c_str()));
  1817. if (commandMessage == "GameStarted")
  1818. {
  1819. message = TheGameText->fetch("GUI:GSKickedGameStarted");
  1820. }
  1821. else if (commandMessage == "GameFull")
  1822. {
  1823. message = TheGameText->fetch("GUI:GSKickedGameFull");
  1824. }
  1825. GSMessageBoxOk(TheGameText->fetch("GUI:GSErrorTitle"), message);
  1826. nextScreen = "Menus/WOLCustomLobby.wnd";
  1827. TheShell->pop();
  1828. }
  1829. }
  1830. else if (slotNum > 0 && TheGameSpyInfo->amIHost())
  1831. {
  1832. if (!strcmp(resp.command.c_str(), "accept"))
  1833. {
  1834. game->getSlot(slotNum)->setAccept();
  1835. TheGameSpyInfo->setGameOptions();
  1836. WOLDisplaySlotList();
  1837. }
  1838. else if (!strcmp(resp.command.c_str(), "MAP"))
  1839. {
  1840. Bool hasMap = atoi(resp.commandOptions.c_str());
  1841. game->getSlot(slotNum)->setMapAvailability(hasMap);
  1842. if (!hasMap)
  1843. {
  1844. // tell the host the user doesn't have the map
  1845. UnicodeString mapDisplayName;
  1846. const MapMetaData *mapData = TheMapCache->findMap( game->getMap() );
  1847. Bool willTransfer = TRUE;
  1848. if (mapData)
  1849. {
  1850. mapDisplayName.format(L"%ls", mapData->m_displayName.str());
  1851. willTransfer = !mapData->m_isOfficial;
  1852. }
  1853. else
  1854. {
  1855. mapDisplayName.format(L"%hs", game->getMap().str());
  1856. willTransfer = WouldMapTransfer(game->getMap());
  1857. }
  1858. UnicodeString text;
  1859. if (willTransfer)
  1860. text.format(TheGameText->fetch("GUI:PlayerNoMapWillTransfer"), game->getSlot(slotNum)->getName().str(), mapDisplayName.str());
  1861. else
  1862. text.format(TheGameText->fetch("GUI:PlayerNoMap"), game->getSlot(slotNum)->getName().str(), mapDisplayName.str());
  1863. TheGameSpyInfo->addText(text, GameSpyColor[GSCOLOR_DEFAULT], listboxGameSetupChat);
  1864. }
  1865. WOLDisplaySlotList();
  1866. }
  1867. else if (!strcmp(resp.command.c_str(), "REQ"))
  1868. {
  1869. AsciiString options = resp.commandOptions.c_str();
  1870. options.trim();
  1871. Bool change = false;
  1872. Bool shouldUnaccept = false;
  1873. AsciiString key;
  1874. options.nextToken(&key, "=");
  1875. Int val = atoi(options.str()+1);
  1876. UnsignedInt uVal = atoi(options.str()+1);
  1877. DEBUG_LOG(("GameOpt request: key=%s, val=%s from player %d\n", key.str(), options.str()+1, slotNum));
  1878. GameSpyGameSlot *slot = game->getGameSpySlot(slotNum);
  1879. if (!slot)
  1880. break;
  1881. if (key == "Color")
  1882. {
  1883. if (val >= -1 && val < TheMultiplayerSettings->getNumColors() && val != slot->getColor() && slot->getPlayerTemplate() != PLAYERTEMPLATE_OBSERVER)
  1884. {
  1885. Bool colorAvailable = TRUE;
  1886. if(val != -1 )
  1887. {
  1888. for(Int i=0; i <MAX_SLOTS; i++)
  1889. {
  1890. GameSlot *checkSlot = game->getSlot(i);
  1891. if(val == checkSlot->getColor() && slot != checkSlot)
  1892. {
  1893. colorAvailable = FALSE;
  1894. break;
  1895. }
  1896. }
  1897. }
  1898. if(colorAvailable)
  1899. slot->setColor(val);
  1900. change = true;
  1901. }
  1902. else
  1903. {
  1904. DEBUG_LOG(("Rejecting invalid color %d\n", val));
  1905. }
  1906. }
  1907. else if (key == "PlayerTemplate")
  1908. {
  1909. if (val >= PLAYERTEMPLATE_MIN && val < ThePlayerTemplateStore->getPlayerTemplateCount() && val != slot->getPlayerTemplate())
  1910. {
  1911. slot->setPlayerTemplate(val);
  1912. if (val == PLAYERTEMPLATE_OBSERVER)
  1913. {
  1914. slot->setColor(-1);
  1915. slot->setStartPos(-1);
  1916. slot->setTeamNumber(-1);
  1917. }
  1918. change = true;
  1919. shouldUnaccept = true;
  1920. }
  1921. else
  1922. {
  1923. DEBUG_LOG(("Rejecting invalid PlayerTemplate %d\n", val));
  1924. }
  1925. }
  1926. else if (key == "StartPos")
  1927. {
  1928. if (val >= -1 && val < MAX_SLOTS && val != slot->getStartPos() && slot->getPlayerTemplate() != PLAYERTEMPLATE_OBSERVER)
  1929. {
  1930. Bool startPosAvailable = TRUE;
  1931. if(val != -1)
  1932. {
  1933. for(Int i=0; i <MAX_SLOTS; i++)
  1934. {
  1935. GameSlot *checkSlot = game->getSlot(i);
  1936. if(val == checkSlot->getStartPos() && slot != checkSlot)
  1937. {
  1938. startPosAvailable = FALSE;
  1939. break;
  1940. }
  1941. }
  1942. }
  1943. if(startPosAvailable)
  1944. slot->setStartPos(val);
  1945. change = true;
  1946. shouldUnaccept = true;
  1947. }
  1948. else
  1949. {
  1950. DEBUG_LOG(("Rejecting invalid startPos %d\n", val));
  1951. }
  1952. }
  1953. else if (key == "Team")
  1954. {
  1955. if (val >= -1 && val < MAX_SLOTS/2 && val != slot->getTeamNumber() && slot->getPlayerTemplate() != PLAYERTEMPLATE_OBSERVER)
  1956. {
  1957. slot->setTeamNumber(val);
  1958. change = true;
  1959. shouldUnaccept = true;
  1960. }
  1961. else
  1962. {
  1963. DEBUG_LOG(("Rejecting invalid team %d\n", val));
  1964. }
  1965. }
  1966. else if (key == "IP")
  1967. {
  1968. if (uVal != slot->getIP())
  1969. {
  1970. DEBUG_LOG(("setting IP of player %ls from 0x%08x to be 0x%08x", slot->getName().str(), slot->getIP(), uVal));
  1971. slot->setIP(uVal);
  1972. change = true;
  1973. shouldUnaccept = true;
  1974. }
  1975. else
  1976. {
  1977. DEBUG_LOG(("Rejecting invalid IP %d\n", uVal));
  1978. }
  1979. }
  1980. else if (key == "NAT")
  1981. {
  1982. if ((val >= FirewallHelperClass::FIREWALL_MIN) &&
  1983. (val <= FirewallHelperClass::FIREWALL_MAX))
  1984. {
  1985. slot->setNATBehavior((FirewallHelperClass::FirewallBehaviorType)val);
  1986. DEBUG_LOG(("Setting NAT behavior to %d for player %d\n", val, slotNum));
  1987. change = true;
  1988. }
  1989. else
  1990. {
  1991. DEBUG_LOG(("Rejecting invalid NAT behavior %d from player %d\n", val, slotNum));
  1992. }
  1993. }
  1994. else if (key == "Ping")
  1995. {
  1996. slot->setPingString(options.str()+1);
  1997. TheGameSpyInfo->setGameOptions();
  1998. DEBUG_LOG(("Setting ping string to %s for player %d\n", options.str()+1, slotNum));
  1999. }
  2000. if (change)
  2001. {
  2002. if (shouldUnaccept)
  2003. game->resetAccepted();
  2004. TheGameSpyInfo->setGameOptions();
  2005. WOLDisplaySlotList();
  2006. DEBUG_LOG(("Slot value is color=%d, PlayerTemplate=%d, startPos=%d, team=%d, IP=0x%8.8X\n",
  2007. slot->getColor(), slot->getPlayerTemplate(), slot->getStartPos(), slot->getTeamNumber(), slot->getIP()));
  2008. DEBUG_LOG(("Slot list updated to %s\n", GameInfoToAsciiString(game).str()));
  2009. }
  2010. }
  2011. }
  2012. }
  2013. }
  2014. break;
  2015. }
  2016. }
  2017. }
  2018. }// void WOLGameSetupMenuUpdate( WindowLayout * layout, void *userData)
  2019. //-------------------------------------------------------------------------------------------------
  2020. /** Lan Game Options menu input callback */
  2021. //-------------------------------------------------------------------------------------------------
  2022. WindowMsgHandledType WOLGameSetupMenuInput( GameWindow *window, UnsignedInt msg,
  2023. WindowMsgData mData1, WindowMsgData mData2 )
  2024. {
  2025. /*
  2026. switch( msg )
  2027. {
  2028. //-------------------------------------------------------------------------------------------------
  2029. case GWM_RIGHT_UP:
  2030. {
  2031. if (buttonPushed)
  2032. break;
  2033. GameWindow *control = (GameWindow *)mData1;
  2034. NameKeyType controlID = (NameKeyType)control->winGetWindowId();
  2035. DEBUG_LOG(("GWM_RIGHT_UP for control %d(%s)\n", controlID, TheNameKeyGenerator->keyToName(controlID).str()));
  2036. break;
  2037. }
  2038. // --------------------------------------------------------------------------------------------
  2039. case GWM_CHAR:
  2040. {
  2041. UnsignedByte key = mData1;
  2042. UnsignedByte state = mData2;
  2043. if (buttonPushed)
  2044. break;
  2045. switch( key )
  2046. {
  2047. // ----------------------------------------------------------------------------------------
  2048. case KEY_ESC:
  2049. {
  2050. //
  2051. // send a simulated selected event to the parent window of the
  2052. // back/exit button
  2053. //
  2054. if( BitTest( state, KEY_STATE_UP ) )
  2055. {
  2056. TheWindowManager->winSendSystemMsg( window, GBM_SELECTED,
  2057. (WindowMsgData)buttonBack, buttonBackID );
  2058. } // end if
  2059. // don't let key fall through anywhere else
  2060. return MSG_HANDLED;
  2061. } // end escape
  2062. } // end switch( key )
  2063. } // end char
  2064. } // end switch( msg )
  2065. */
  2066. return MSG_IGNORED;
  2067. }//WindowMsgHandledType WOLGameSetupMenuInput( GameWindow *window, UnsignedInt msg,
  2068. // Slash commands -------------------------------------------------------------------------
  2069. extern "C" {
  2070. int getQR2HostingStatus(void);
  2071. }
  2072. extern int isThreadHosting;
  2073. Bool handleGameSetupSlashCommands(UnicodeString uText)
  2074. {
  2075. AsciiString message;
  2076. message.translate(uText);
  2077. if (message.getCharAt(0) != '/')
  2078. {
  2079. return FALSE; // not a slash command
  2080. }
  2081. AsciiString remainder = message.str() + 1;
  2082. AsciiString token;
  2083. remainder.nextToken(&token);
  2084. token.toLower();
  2085. if (token == "host")
  2086. {
  2087. UnicodeString s;
  2088. s.format(L"Hosting qr2:%d thread:%d", getQR2HostingStatus(), isThreadHosting);
  2089. TheGameSpyInfo->addText(s, GameSpyColor[GSCOLOR_DEFAULT], NULL);
  2090. return TRUE; // was a slash command
  2091. }
  2092. else if (token == "me" && uText.getLength()>4)
  2093. {
  2094. TheGameSpyInfo->sendChat(UnicodeString(uText.str()+4), TRUE, NULL);
  2095. return TRUE; // was a slash command
  2096. }
  2097. #if defined(_DEBUG) || defined(_INTERNAL)
  2098. else if (token == "slots")
  2099. {
  2100. g_debugSlots = !g_debugSlots;
  2101. TheGameSpyInfo->addText(UnicodeString(L"Toggled SlotList debug"), GameSpyColor[GSCOLOR_DEFAULT], NULL);
  2102. return TRUE; // was a slash command
  2103. }
  2104. else if (token == "discon")
  2105. {
  2106. PeerRequest req;
  2107. req.peerRequestType = PeerRequest::PEERREQUEST_LOGOUT;
  2108. TheGameSpyPeerMessageQueue->addRequest( req );
  2109. return TRUE;
  2110. }
  2111. #endif // defined(_DEBUG) || defined(_INTERNAL)
  2112. return FALSE; // not a slash command
  2113. }
  2114. static Int getNextSelectablePlayer(Int start)
  2115. {
  2116. GameSpyStagingRoom *game = TheGameSpyInfo->getCurrentStagingRoom();
  2117. if (!game->amIHost())
  2118. return -1;
  2119. for (Int j=start; j<MAX_SLOTS; ++j)
  2120. {
  2121. GameSpyGameSlot *slot = game->getGameSpySlot(j);
  2122. if (slot && slot->getStartPos() == -1 &&
  2123. ( (j==game->getLocalSlotNum() && game->getConstSlot(j)->getPlayerTemplate()!=PLAYERTEMPLATE_OBSERVER)
  2124. || slot->isAI()))
  2125. {
  2126. return j;
  2127. }
  2128. }
  2129. return -1;
  2130. }
  2131. static Int getFirstSelectablePlayer(const GameInfo *game)
  2132. {
  2133. const GameSlot *slot = game->getConstSlot(game->getLocalSlotNum());
  2134. if (!game->amIHost() || slot && slot->getPlayerTemplate() != PLAYERTEMPLATE_OBSERVER)
  2135. return game->getLocalSlotNum();
  2136. for (Int i=0; i<MAX_SLOTS; ++i)
  2137. {
  2138. slot = game->getConstSlot(i);
  2139. if (slot && slot->isAI())
  2140. return i;
  2141. }
  2142. return game->getLocalSlotNum();
  2143. }
  2144. //-------------------------------------------------------------------------------------------------
  2145. /** WOL Game Options menu window system callback */
  2146. //-------------------------------------------------------------------------------------------------
  2147. WindowMsgHandledType WOLGameSetupMenuSystem( GameWindow *window, UnsignedInt msg,
  2148. WindowMsgData mData1, WindowMsgData mData2 )
  2149. {
  2150. UnicodeString txtInput;
  2151. static buttonCommunicatorID = NAMEKEY_INVALID;
  2152. switch( msg )
  2153. {
  2154. //-------------------------------------------------------------------------------------------------
  2155. case GWM_CREATE:
  2156. {
  2157. buttonCommunicatorID = NAMEKEY("GameSpyGameOptionsMenu.wnd:ButtonCommunicator");
  2158. break;
  2159. } // case GWM_DESTROY:
  2160. //-------------------------------------------------------------------------------------------------
  2161. case GWM_DESTROY:
  2162. {
  2163. break;
  2164. } // case GWM_DESTROY:
  2165. //-------------------------------------------------------------------------------------------------
  2166. case GWM_INPUT_FOCUS:
  2167. {
  2168. // if we're givin the opportunity to take the keyboard focus we must say we want it
  2169. if( mData1 == TRUE )
  2170. *(Bool *)mData2 = TRUE;
  2171. return MSG_HANDLED;
  2172. }//case GWM_INPUT_FOCUS:
  2173. //-------------------------------------------------------------------------------------------------
  2174. case GCM_SELECTED:
  2175. {
  2176. if (!initDone)
  2177. break;
  2178. if (buttonPushed)
  2179. break;
  2180. GameWindow *control = (GameWindow *)mData1;
  2181. Int controlID = control->winGetWindowId();
  2182. GameSpyStagingRoom *myGame = TheGameSpyInfo->getCurrentStagingRoom();
  2183. for (Int i = 0; i < MAX_SLOTS; i++)
  2184. {
  2185. if (controlID == comboBoxColorID[i])
  2186. {
  2187. handleColorSelection(i);
  2188. }
  2189. else if (controlID == comboBoxPlayerTemplateID[i])
  2190. {
  2191. handlePlayerTemplateSelection(i);
  2192. }
  2193. else if (controlID == comboBoxTeamID[i])
  2194. {
  2195. handleTeamSelection(i);
  2196. }
  2197. else if( controlID == comboBoxPlayerID[i] && TheGameSpyInfo->amIHost() )
  2198. {
  2199. // We don't have anything that'll happen if we click on ourselves
  2200. if(i == myGame->getLocalSlotNum())
  2201. break;
  2202. // Get
  2203. Int pos = -1;
  2204. GadgetComboBoxGetSelectedPos(comboBoxPlayer[i], &pos);
  2205. if( pos != SLOT_PLAYER && pos >= 0)
  2206. {
  2207. if( myGame->getSlot(i)->getState() == SLOT_PLAYER )
  2208. {
  2209. PeerRequest req;
  2210. req.peerRequestType = PeerRequest::PEERREQUEST_UTMPLAYER;
  2211. req.UTM.isStagingRoom = TRUE;
  2212. AsciiString aName;
  2213. aName.translate(myGame->getSlot(i)->getName());
  2214. req.nick = aName.str();
  2215. req.id = "KICK/";
  2216. req.options = "true";
  2217. TheGameSpyPeerMessageQueue->addRequest(req);
  2218. UnicodeString name = myGame->getSlot(i)->getName();
  2219. myGame->getSlot(i)->setState(SlotState(pos));
  2220. myGame->resetAccepted();
  2221. TheGameSpyInfo->setGameOptions();
  2222. WOLDisplaySlotList();
  2223. //TheLAN->OnPlayerLeave(name);
  2224. }
  2225. else if( myGame->getSlot(i)->getState() != pos )
  2226. {
  2227. Bool wasAI = (myGame->getSlot(i)->isAI());
  2228. myGame->getSlot(i)->setState(SlotState(pos));
  2229. Bool isAI = (myGame->getSlot(i)->isAI());
  2230. myGame->resetAccepted();
  2231. if (wasAI ^ isAI)
  2232. PopulatePlayerTemplateComboBox(i, comboBoxPlayerTemplate, myGame, wasAI && myGame->getAllowObservers());
  2233. TheGameSpyInfo->setGameOptions();
  2234. WOLDisplaySlotList();
  2235. }
  2236. }
  2237. break;
  2238. }
  2239. }
  2240. }// case GCM_SELECTED:
  2241. //-------------------------------------------------------------------------------------------------
  2242. case GBM_SELECTED:
  2243. {
  2244. if (buttonPushed)
  2245. break;
  2246. GameWindow *control = (GameWindow *)mData1;
  2247. Int controlID = control->winGetWindowId();
  2248. static buttonCommunicatorID = NAMEKEY("GameSpyGameOptionsMenu.wnd:ButtonCommunicator");
  2249. if ( controlID == buttonBackID )
  2250. {
  2251. savePlayerInfo();
  2252. if( WOLMapSelectLayout )
  2253. {
  2254. WOLMapSelectLayout->destroyWindows();
  2255. WOLMapSelectLayout->deleteInstance();
  2256. WOLMapSelectLayout = NULL;
  2257. }
  2258. TheGameSpyInfo->getCurrentStagingRoom()->reset();
  2259. //peerLeaveRoom(TheGameSpyChat->getPeer(), StagingRoom, NULL);
  2260. TheGameSpyInfo->leaveStagingRoom();
  2261. buttonPushed = true;
  2262. nextScreen = "Menus/WOLCustomLobby.wnd";
  2263. TheShell->pop();
  2264. } //if ( controlID == buttonBack )
  2265. else if ( controlID == buttonCommunicatorID )
  2266. {
  2267. GameSpyToggleOverlay( GSOVERLAY_BUDDY );
  2268. }
  2269. else if ( controlID == buttonEmoteID )
  2270. {
  2271. // read the user's input
  2272. txtInput.set(GadgetTextEntryGetText( textEntryChat ));
  2273. // Clear the text entry line
  2274. GadgetTextEntrySetText(textEntryChat, UnicodeString::TheEmptyString);
  2275. // Clean up the text (remove leading/trailing chars, etc)
  2276. txtInput.trim();
  2277. // Echo the user's input to the chat window
  2278. if (!txtInput.isEmpty())
  2279. TheGameSpyInfo->sendChat(txtInput, FALSE, NULL); // 'emote' button is now carriage-return
  2280. } //if ( controlID == buttonEmote )
  2281. else if ( controlID == buttonSelectMapID )
  2282. {
  2283. WOLMapSelectLayout = TheWindowManager->winCreateLayout( "Menus/WOLMapSelectMenu.wnd" );
  2284. WOLMapSelectLayout->runInit();
  2285. WOLMapSelectLayout->hide( FALSE );
  2286. WOLMapSelectLayout->bringForward();
  2287. }
  2288. else if ( controlID == buttonStartID )
  2289. {
  2290. savePlayerInfo();
  2291. if (TheGameSpyInfo->amIHost())
  2292. {
  2293. StartPressed();
  2294. }
  2295. else
  2296. {
  2297. //I'm the Client... send an accept message to the host.
  2298. GameSlot *localSlot = TheGameSpyInfo->getCurrentStagingRoom()->getSlot(TheGameSpyInfo->getCurrentStagingRoom()->getLocalSlotNum());
  2299. if (localSlot)
  2300. {
  2301. localSlot->setAccept();
  2302. }
  2303. UnicodeString hostName = TheGameSpyInfo->getCurrentStagingRoom()->getSlot(0)->getName();
  2304. AsciiString asciiName;
  2305. asciiName.translate(hostName);
  2306. PeerRequest req;
  2307. req.peerRequestType = PeerRequest::PEERREQUEST_UTMPLAYER;
  2308. req.UTM.isStagingRoom = TRUE;
  2309. req.id = "accept";
  2310. req.nick = asciiName.str();
  2311. req.options = "true";
  2312. TheGameSpyPeerMessageQueue->addRequest(req);
  2313. //peerSetReady( PEER, PEERTrue );
  2314. WOLDisplaySlotList();
  2315. }
  2316. }
  2317. else
  2318. {
  2319. for (Int i = 0; i < MAX_SLOTS; i++)
  2320. {
  2321. if (controlID == buttonMapStartPositionID[i])
  2322. {
  2323. GameSpyStagingRoom *game = TheGameSpyInfo->getCurrentStagingRoom();
  2324. Int playerIdxInPos = -1;
  2325. for (Int j=0; j<MAX_SLOTS; ++j)
  2326. {
  2327. GameSpyGameSlot *slot = game->getGameSpySlot(j);
  2328. if (slot && slot->getStartPos() == i)
  2329. {
  2330. playerIdxInPos = j;
  2331. break;
  2332. }
  2333. }
  2334. if (playerIdxInPos >= 0)
  2335. {
  2336. GameSpyGameSlot *slot = game->getGameSpySlot(playerIdxInPos);
  2337. if (playerIdxInPos == game->getLocalSlotNum() || (game->amIHost() && slot && slot->isAI()))
  2338. {
  2339. // it's one of my type. Try to change it.
  2340. Int nextPlayer = getNextSelectablePlayer(playerIdxInPos+1);
  2341. handleStartPositionSelection(playerIdxInPos, -1);
  2342. if (nextPlayer >= 0)
  2343. {
  2344. handleStartPositionSelection(nextPlayer, i);
  2345. }
  2346. }
  2347. }
  2348. else
  2349. {
  2350. // nobody in the slot - put us in
  2351. Int nextPlayer = getNextSelectablePlayer(0);
  2352. if (nextPlayer < 0)
  2353. nextPlayer = getFirstSelectablePlayer(game);
  2354. handleStartPositionSelection(nextPlayer, i);
  2355. }
  2356. }
  2357. }
  2358. }
  2359. break;
  2360. }// case GBM_SELECTED:
  2361. //-------------------------------------------------------------------------------------------------
  2362. case GBM_SELECTED_RIGHT:
  2363. {
  2364. if (buttonPushed)
  2365. break;
  2366. GameWindow *control = (GameWindow *)mData1;
  2367. Int controlID = control->winGetWindowId();
  2368. for (Int i = 0; i < MAX_SLOTS; i++)
  2369. {
  2370. if (controlID == buttonMapStartPositionID[i])
  2371. {
  2372. GameSpyStagingRoom *game = TheGameSpyInfo->getCurrentStagingRoom();
  2373. Int playerIdxInPos = -1;
  2374. for (Int j=0; j<MAX_SLOTS; ++j)
  2375. {
  2376. GameSpyGameSlot *slot = game->getGameSpySlot(j);
  2377. if (slot && slot->getStartPos() == i)
  2378. {
  2379. playerIdxInPos = j;
  2380. break;
  2381. }
  2382. }
  2383. if (playerIdxInPos >= 0)
  2384. {
  2385. GameSpyGameSlot *slot = game->getGameSpySlot(playerIdxInPos);
  2386. if (playerIdxInPos == game->getLocalSlotNum() || (game->amIHost() && slot && slot->isAI()))
  2387. {
  2388. // it's one of my type. Remove it.
  2389. handleStartPositionSelection(playerIdxInPos, -1);
  2390. }
  2391. }
  2392. }
  2393. }
  2394. break;
  2395. }
  2396. //-------------------------------------------------------------------------------------------------
  2397. case GEM_EDIT_DONE:
  2398. {
  2399. GameWindow *control = (GameWindow *)mData1;
  2400. Int controlID = control->winGetWindowId();
  2401. // Take the user's input and echo it into the chat window as well as
  2402. // send it to the other clients on the lan
  2403. if ( controlID == textEntryChatID )
  2404. {
  2405. // read the user's input
  2406. txtInput.set(GadgetTextEntryGetText( textEntryChat ));
  2407. // Clear the text entry line
  2408. GadgetTextEntrySetText(textEntryChat, UnicodeString::TheEmptyString);
  2409. // Clean up the text (remove leading/trailing chars, etc)
  2410. txtInput.trim();
  2411. // Echo the user's input to the chat window
  2412. if (!txtInput.isEmpty())
  2413. {
  2414. if (!handleGameSetupSlashCommands(txtInput))
  2415. {
  2416. TheGameSpyInfo->sendChat(txtInput, false, NULL);
  2417. }
  2418. }
  2419. }// if ( controlID == textEntryChatID )
  2420. break;
  2421. }
  2422. //-------------------------------------------------------------------------------------------------
  2423. default:
  2424. return MSG_IGNORED;
  2425. }//Switch
  2426. return MSG_HANDLED;
  2427. }//WindowMsgHandledType WOLGameSetupMenuSystem( GameWindow *window, UnsignedInt msg,