WOLGameSetupMenu.cpp 93 KB

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