WOL_GSUP.CPP 128 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500
  1. /*
  2. ** Command & Conquer Red Alert(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. #ifdef WOLAPI_INTEGRATION // Now implies also WINSOCK_IPX, WIN32, and FIXIT_CSII must be true
  19. #include "wol_gsup.h"
  20. #include "function.h"
  21. #include "IconList.h"
  22. #include <time.h>
  23. #include "WolStrng.h"
  24. #include "wsproto.h"
  25. #include "BigCheck.h"
  26. #include "ToolTip.h"
  27. extern char const* EngMisStr[];
  28. bool Is_Mission_126x126 (char *file_name);
  29. bool Is_Mission_Aftermath (char *file_name);
  30. bool Is_Mission_Counterstrike (char *file_name);
  31. bool Force_Scenario_Available( const char* szName );
  32. int ScenarioIndex_From_Filename( const char* szScenarioFilename );
  33. bool bSpecialAftermathScenario( const char* szScenarioDescription );
  34. #include "WolDebug.h"
  35. #define PARAMREFRESHWAIT 2000
  36. #define PING_AND_DISPLAY_WAIT 5000
  37. void WOL_PrintMessage( IconListClass& ILTarget, const char* szText, PlayerColorType iColorRemap = PCOLOR_NONE );
  38. void WOL_PrintMessage( IconListClass& ILTarget, const char* szText, RemapControlType* pColorRemap );
  39. void CC_Draw_DIB( const char* pDIB, int xDest, int yDest, int iWidth, WindowNumberType window );
  40. bool operator==( const GAMEPARAMS& gp1, const GAMEPARAMS& gp2 );
  41. bool operator==( const GlobalPacketType& gp1, const GlobalPacketType& gp2 );
  42. PlayerColorType PlayerColorTypeOf( RemapControlType* pColorRemap );
  43. extern unsigned long PlanetWestwoodStartTime; //Time that game was started
  44. extern bool cancel_current_msgbox;
  45. extern bool disable_current_msgbox;
  46. void Debug_GlobalPacketType( const GlobalPacketType& gp1 );
  47. //***********************************************************************************************
  48. /* Game startup logic:
  49. When a guest joins the channel, the host sends all current setup info.
  50. When a guest changes house, he tells the host, who informs everyone. A house change can't be denied.
  51. When a guest changes color, he asks the host for the new color, and assumes the request will go through. If it doesn't, the
  52. host sends the guest a messages setting him back to the old color, otherwise, everyone gets the new color for the guest.
  53. When the host changes a game param, the change will be noticed within PARAMREFRESHWAIT milliseconds and then transmitted to
  54. all guests.
  55. All player specific information is stored within the players list (IconListClass), and nowhere else. Though this storage
  56. method got a bit inelegant, it gets the job done.
  57. All "informs" (messages sent from host to guest) except color changes (WOL_GAMEOPT_INFCOLOR) and player "accept" status
  58. changes (WOL_GAMEOPT_INFACCEPT) are assigned a ID, which
  59. increments on each send. Color informs are: a) not a condition for removing a guest's "accept" status, and b) sent out to
  60. individual guests in certain cases, and would thus complicate the ID tracking scheme.
  61. When a guest "accepts" the game setup (with a WOL_GAMEOPT_REQACCEPT), the latest received ID is included in the message.
  62. If the host receives a WOL_GAMEOPT_REQACCEPT with an out-of-date ID, the accept is ignored. Though the guest sets himself to
  63. "accepted" when he sends the WOL_GAMEOPT_REQACCEPT, if it gets ignored by the host it is because a new inform is already on its
  64. way, which will reset the guest's own status to "not accepted" when it arrives.
  65. Host clears all accepteds when params are changed, player joins or leaves, or house change message arrives. Though a
  66. WOL_GAMEOPT_INFACCEPT is sent out when a guest accepts, there is no corresponding "unaccept all" message sent out at this point,
  67. as all guests will naturally clear their recorded accept status for everyone when the change arrives there.
  68. Guest clears own accepted when an inform from the server other than color change arrives, player joins or leaves, or own
  69. house is directly changed.
  70. When all players are "accepted", and the host says "start", a WOL_GAMEOPT_INFSTART is sent to all guests and the host goes into
  71. "waiting to start" mode. If a house change or other arrives in this phase, host clears waiting mode and (naturally) marks guests
  72. unaccepted and sends out the house change to the guests. (The same applies to player joins/leaves.)
  73. While in this mode, the host user is locked out of making any changes to game params.
  74. If a change does come in during this phase, a WOL_GAMEOPT_INFCANCELSTART is sent to the guests, and the waiting mode cancelled.
  75. When a guest receives WOL_GAMEOPT_INFSTART: If he does not see himself as accepted, it is because a change has just been sent
  76. to the host, or some other event occurred that the host will learn about, so the guest can simply ignore the WOL_GAMEOPT_INFSTART.
  77. If the guest does see himself as accepted when WOL_GAMEOPT_INFSTART arrives, he responds with WOL_GAMEOPT_REQSTART and goes into
  78. "waiting to start" mode. When in this mode, the user is locked out of making any changes.
  79. Note that the host is not really asking for any sort of "confirmation that it's ok" to start from the guest here. (Hence no
  80. "cancel" response is possible.) It's really just a way of telling the guests not to make any more changes to the setup; it's
  81. like we're making sure we've "flushed the queue" of game changes.
  82. If a guest receives a WOL_GAMEOPT_INFCANCELSTART, he cancels out of "waiting to start" mode. Note that while in the waiting
  83. mode, normal processing of messages is allowed to take place - the user is simply blocked from doing anything.
  84. Presumably (hopefully) this phase will last less than a second.
  85. When the host receives a WOL_GAMEOPT_REQSTART from everyone, he tells everyone to start with a WOL_GAMEOPT_INFGO.
  86. Because there is a chance of color changes being out of sync, all player colors are sent to all guests at this point.
  87. There is no chance of other data being out of sync.
  88. */
  89. //--------------------------------------------------------------------------
  90. // Pieced together from Net_New_Dialog() and Net_Join_Dialog().
  91. //--------------------------------------------------------------------------
  92. //***********************************************************************************************
  93. WOL_GameSetupDialog::WOL_GameSetupDialog( WolapiObject* pWO, bool bHost ) : pWO( pWO ), bHost( bHost ),
  94. HousePrevious( HOUSE_NONE ),
  95. pILPlayers( NULL ),
  96. pILScens( NULL ),
  97. pILDisc( NULL ),
  98. pEditSend( NULL ),
  99. pGaugeCount( NULL ),
  100. pGaugeLevel( NULL ),
  101. pGaugeCredits( NULL ),
  102. pGaugeAIPlayers( NULL ),
  103. pCheckListOptions( NULL ),
  104. // pTextBtnOk( NULL ),
  105. pTextBtnCancel( NULL ),
  106. pTextBtnAcceptStart( NULL ),
  107. pTextBtnAction( NULL ),
  108. pStaticDescrip( NULL ),
  109. pStaticUnit( NULL ),
  110. pStaticLevel( NULL ),
  111. pStaticCredits( NULL ),
  112. pStaticAIPlayers( NULL ),
  113. pDropListHouse( NULL ),
  114. pCheckAftermathUnits( NULL ),
  115. nHostLastParamID( 0 ),
  116. nGuestLastParamID( 0 ),
  117. bWaitingToStart( false ),
  118. bParamsReceived( false ),
  119. bHostSayGo( false ),
  120. bExitForGameTrigger( false ),
  121. pToolTipHead( NULL ),
  122. pToolTipHitLast( NULL ),
  123. pTTipAcceptStart( NULL ),
  124. pTTipCancel( NULL ),
  125. pTTipAction( NULL ),
  126. ScenKindCurrent( SCENARIO_UNINITIALIZED ),
  127. pShpBtnScenarioRA( NULL ),
  128. pShpBtnScenarioCS( NULL ),
  129. pShpBtnScenarioAM( NULL ),
  130. pShpBtnScenarioUser( NULL ),
  131. bLeaveDueToRulesMismatchTrigger( false ),
  132. bHostWaitingForGoTrigger( false )
  133. {
  134. *szSendBuffer = 0;
  135. *szHouseBuffer = 0;
  136. memset( &GParamsLastSent, 0, sizeof( GAMEPARAMS ) );
  137. *szNameOfHostWhoJustBailedOnUs = 0;
  138. *szTriggerGameStartInfo = 0;
  139. }
  140. //***********************************************************************************************
  141. WOL_GameSetupDialog::~WOL_GameSetupDialog()
  142. {
  143. delete pILPlayers;
  144. delete pILScens;
  145. delete pILDisc;
  146. delete pEditSend;
  147. delete pGaugeCount;
  148. delete pGaugeLevel;
  149. delete pGaugeCredits;
  150. delete pGaugeAIPlayers;
  151. delete pCheckListOptions;
  152. // delete pTextBtnOk;
  153. delete pTextBtnCancel;
  154. delete pTextBtnAcceptStart;
  155. delete pTextBtnAction;
  156. // delete pStaticDescrip;
  157. delete pStaticUnit;
  158. delete pStaticLevel;
  159. delete pStaticCredits;
  160. delete pStaticAIPlayers;
  161. delete pDropListHouse;
  162. delete pCheckAftermathUnits;
  163. delete pTTipAcceptStart;
  164. delete pTTipCancel;
  165. delete pTTipAction;
  166. delete pShpBtnScenarioRA;
  167. delete pShpBtnScenarioCS;
  168. delete pShpBtnScenarioAM;
  169. delete pShpBtnScenarioUser;
  170. }
  171. //***********************************************************************************************
  172. RESULT_WOLGSUP WOL_GameSetupDialog::Run()
  173. {
  174. Initialize();
  175. return Show();
  176. }
  177. //***********************************************************************************************
  178. void WOL_GameSetupDialog::Initialize()
  179. {
  180. //------------------------------------------------------------------------
  181. // Dialog & button dimensions
  182. //------------------------------------------------------------------------
  183. d_dialog_w = 640; // dialog width
  184. d_dialog_h = 400; // dialog height
  185. d_dialog_x = 0;
  186. d_dialog_y = 0;
  187. d_dialog_cx = d_dialog_x + (d_dialog_w / 2); // center x-coord
  188. d_txt6_h = 6*RESFACTOR+1; // ht of 6-pt text
  189. int d_text_h = 12;
  190. d_margin1 = 34; // large margin
  191. d_color_w = 10 *RESFACTOR;
  192. d_color_h = 9 *RESFACTOR;
  193. d_color_x = 294; //54; //d_dialog_x + ((d_dialog_w / 4) * 3) - (d_color_w * 3);
  194. d_color_y = 89; //142; //d_house_y;
  195. d_house_w = 60 *RESFACTOR;
  196. d_house_h = (8 * 5 *RESFACTOR);
  197. d_house_x = 466; //65; //d_color_x; //d_dialog_cx - (d_house_w / 2);
  198. d_house_y = d_color_y; // + 36; //d_dialog_y + ( 7 * RESFACTOR ) + d_txt6_h + (2*RESFACTOR);
  199. if( bHost )
  200. d_disc_w = 365; //d_dialog_w - (d_margin1 * 2) - 20*RESFACTOR;
  201. else
  202. d_disc_w = d_dialog_w - ( d_margin1 * 2 );
  203. d_disc_x = d_dialog_x + d_margin1;
  204. d_disc_y = 205; //d_dialog_y + d_dialog_h - ( 65 + d_disc_h );
  205. d_disc_h = 337 - d_disc_y;
  206. d_playerlist_w = 124*RESFACTOR;
  207. d_playerlist_h = d_text_h * 4 + 4;
  208. d_playerlist_x = d_dialog_x + d_margin1;
  209. d_playerlist_y = 75; //d_dialog_y + d_margin1 + d_txt6_h + 3*RESFACTOR + 18 * RESFACTOR;
  210. int d_tab_h = 19;
  211. d_scenariolist_w = 200;
  212. // d_scenariolist_h = (4 * d_txt6_h) + 3*RESFACTOR; // 4 rows high
  213. d_scenariolist_x = d_dialog_x + d_dialog_w - d_margin1 - d_scenariolist_w;
  214. d_scenariolist_y = d_disc_y + d_tab_h;
  215. d_scenariolist_h = d_disc_y + d_disc_h - d_scenariolist_y;
  216. d_gamekind_w = 182;
  217. d_gamekind_h = 30;
  218. d_gamekind_x = 52; // 370;
  219. d_gamekind_y = 153; // d_playerlist_y + d_text_h + 3; // + d_playerlist_h - d_text_h;
  220. d_count_w = 25*RESFACTOR;
  221. d_count_h = d_txt6_h;
  222. d_count_x = 310;
  223. d_count_y = 138; //d_playerlist_y + d_playerlist_h + d_margin2 + 9*RESFACTOR;
  224. d_level_w = 25*RESFACTOR;
  225. d_level_h = d_txt6_h;
  226. d_level_x = d_count_x;
  227. d_level_y = d_count_y + d_count_h;
  228. d_credits_w = 25*RESFACTOR;
  229. d_credits_h = d_txt6_h;
  230. d_credits_x = d_count_x;
  231. d_credits_y = d_level_y + d_level_h;
  232. d_aiplayers_w = 25*RESFACTOR;
  233. d_aiplayers_h = d_txt6_h;
  234. d_aiplayers_x = d_count_x;
  235. d_aiplayers_y = d_credits_y + d_credits_h;
  236. #ifdef GERMAN
  237. d_options_w = 186;
  238. #else
  239. d_options_w = 180;
  240. #endif
  241. d_options_h = ((6 * 6) + 4)*RESFACTOR + 1;
  242. d_options_x = d_dialog_x + d_dialog_w - d_options_w - d_margin1;
  243. d_options_y = 127 - d_txt6_h + 2;
  244. d_send_w = d_dialog_w - ( d_margin1 * 2 );
  245. d_send_h = 9*RESFACTOR;
  246. d_send_x = d_dialog_x + d_margin1;
  247. d_send_y = d_disc_y + d_disc_h + 5;
  248. // d_ok_w = 50*RESFACTOR;
  249. // d_ok_h = 9*RESFACTOR;
  250. // d_ok_x = d_dialog_x + (d_dialog_w / 6) - (d_ok_w / 2);
  251. // d_ok_y = d_dialog_y + d_dialog_h - d_ok_h - d_margin1 - 3*RESFACTOR;
  252. d_cancel_w = 100;
  253. d_cancel_h = 9*RESFACTOR;
  254. d_cancel_x = d_dialog_x + 100; //d_dialog_cx - (d_cancel_w / 2);
  255. d_cancel_y = 365; //d_dialog_y + d_dialog_h - d_cancel_h - d_margin1 - 3*RESFACTOR;
  256. d_accept_w = 100;
  257. d_accept_h = 9 *RESFACTOR;
  258. d_accept_x = d_dialog_x + 210;
  259. d_accept_y = d_cancel_y; //d_dialog_y + d_dialog_h - 17*RESFACTOR;
  260. d_action_w = 100;
  261. d_action_h = 9 *RESFACTOR;
  262. d_action_x = d_dialog_x + 500;
  263. d_action_y = d_cancel_y;
  264. /* int d_load_w = 50*RESFACTOR;
  265. int d_load_h = 9*RESFACTOR;
  266. int d_load_x = d_dialog_x + ((d_dialog_w * 5) / 6) - (d_load_w / 2);
  267. int d_load_y = d_dialog_y + d_dialog_h - d_load_h - d_margin1 - 3*RESFACTOR;
  268. */
  269. d_amunits_w = 160;
  270. d_amunits_h = 18;
  271. d_amunits_x = d_dialog_x + (d_dialog_w / 6) - (d_amunits_w / 2);
  272. d_amunits_y = 365;
  273. ToolTipClass* pToolTip = pToolTipHead = pWO->pTTipDiscon;
  274. pToolTip->next = pWO->pTTipLeave;
  275. pToolTip = pToolTip->next;
  276. pToolTip->next = pWO->pTTipRefresh;
  277. pToolTip = pToolTip->next;
  278. pToolTip->next = pWO->pTTipSquelch;
  279. pToolTip = pToolTip->next;
  280. pToolTip->next = pWO->pTTipBan;
  281. pToolTip = pToolTip->next;
  282. pToolTip->next = pWO->pTTipKick;
  283. pToolTip = pToolTip->next;
  284. pToolTip->next = pWO->pTTipFindpage;
  285. pToolTip = pToolTip->next;
  286. pToolTip->next = pWO->pTTipOptions;
  287. pToolTip = pToolTip->next;
  288. pToolTip->next = pWO->pTTipLadder;
  289. pToolTip = pToolTip->next;
  290. pToolTip->next = pWO->pTTipHelp;
  291. pILPlayers = new IconListClass( BUTTON_PLAYERLIST, d_playerlist_x, d_playerlist_y, d_playerlist_w, d_playerlist_h, TPF_TYPE, MFCD::Retrieve("BTN-UP.SHP"), MFCD::Retrieve("BTN-DN.SHP"), true, 2 );
  292. // ListClass scenariolist(BUTTON_SCENARIOLIST, d_scenariolist_x, d_scenariolist_y, d_scenariolist_w, d_scenariolist_h, TPF_TEXT, MFCD::Retrieve("BTN-UP.SHP"), MFCD::Retrieve("BTN-DN.SHP"));
  293. pILScens = new IconListClass( BUTTON_SCENARIOLIST, d_scenariolist_x, d_scenariolist_y, d_scenariolist_w, d_scenariolist_h, TPF_TYPE, MFCD::Retrieve("BTN-UP.SHP"), MFCD::Retrieve("BTN-DN.SHP"), true, 1 );
  294. pILDisc = new IconListClass( BUTTON_DISCLIST, d_disc_x, d_disc_y, d_disc_w, d_disc_h, TPF_TYPE, MFCD::Retrieve("BTN-UP.SHP"), MFCD::Retrieve("BTN-DN.SHP"), true, 0, 300 );
  295. pEditSend = new EditClass( BUTTON_SENDEDIT, szSendBuffer, MAXCHATSENDLENGTH, TPF_TEXT, d_send_x, d_send_y, d_send_w, d_send_h );
  296. // TextButtonClass rejectbtn( BUTTON_REJECT, TXT_REJECT, TPF_BUTTON, d_reject_x, d_reject_y );
  297. pGaugeCount = new GaugeClass( BUTTON_COUNT, d_count_x, d_count_y, d_count_w, d_count_h );
  298. pGaugeLevel = new GaugeClass( BUTTON_LEVEL, d_level_x, d_level_y, d_level_w, d_level_h );
  299. pGaugeCredits = new GaugeClass( BUTTON_CREDITS, d_credits_x, d_credits_y, d_credits_w, d_credits_h );
  300. pGaugeAIPlayers = new GaugeClass( BUTTON_AIPLAYERS, d_aiplayers_x, d_aiplayers_y, d_aiplayers_w, d_aiplayers_h );
  301. pCheckListOptions = new CheckListClass( BUTTON_PARAMS, d_options_x, d_options_y, d_options_w, d_options_h, TPF_TEXT, MFCD::Retrieve("BTN-UP.SHP"), MFCD::Retrieve("BTN-DN.SHP") );
  302. // pTextBtnOk = new TextButtonClass( BUTTON_OK, TXT_OK, TPF_BUTTON, d_ok_x, d_ok_y, 60*RESFACTOR );
  303. // TextButtonClass loadbtn(BUTTON_LOAD, TXT_LOAD_BUTTON, TPF_BUTTON, d_load_x, d_load_y, 60*RESFACTOR);
  304. pTextBtnCancel = new TextButtonClass( BUTTON_CANCEL, TXT_WOL_CANCELGAME, TPF_BUTTON, d_cancel_x, d_cancel_y, d_cancel_w );
  305. pTTipCancel = new ToolTipClass( pTextBtnCancel, TXT_WOL_TTIP_CANCELGAME, d_cancel_x + d_cancel_w/2, d_cancel_y - 6 );
  306. if( bHost )
  307. {
  308. pTextBtnAcceptStart = new TextButtonClass( BUTTON_ACCEPTSTART, TXT_WOL_STARTBUTTON, TPF_BUTTON, d_accept_x, d_accept_y, d_accept_w );
  309. pTTipAcceptStart = new ToolTipClass( pTextBtnAcceptStart, TXT_WOL_TTIP_START, d_accept_x + d_accept_w/2, d_accept_y - 6 );
  310. }
  311. else
  312. {
  313. pTextBtnAcceptStart = new TextButtonClass( BUTTON_ACCEPTSTART, TXT_WOL_ACCEPTBUTTON, TPF_BUTTON, d_accept_x, d_accept_y, d_accept_w );
  314. pTTipAcceptStart = new ToolTipClass( pTextBtnAcceptStart, TXT_WOL_TTIP_ACCEPT, d_accept_x + d_accept_w/2, d_accept_y - 6 );
  315. }
  316. pTextBtnAction = new TextButtonClass( BUTTON_ACTION, TXT_WOL_ACTION, TPF_BUTTON, d_action_x, d_action_y, d_action_w );
  317. pTTipAction = new ToolTipClass( pTextBtnAction, TXT_WOL_TTIP_ACTION, d_action_x + d_action_w/2, d_action_y - 6, true );
  318. pToolTip = pToolTip->next;
  319. pToolTip->next = pTTipCancel;
  320. pToolTip = pToolTip->next;
  321. pToolTip->next = pTTipAcceptStart;
  322. pToolTip = pToolTip->next;
  323. pToolTip->next = pTTipAction;
  324. pToolTip = pToolTip->next;
  325. pToolTip->next = NULL;
  326. if( bHost )
  327. pTextBtnAcceptStart->Disable();
  328. // pStaticDescrip is no longer used - can't get the bloody thing to clip text. You'd think a StaticButton control would.
  329. // pStaticDescrip = new StaticButtonClass( 0, "", TPF_TYPE, d_gamekind_x, d_gamekind_y, d_gamekind_w, d_gamekind_h );
  330. pStaticUnit = new StaticButtonClass( 0, " ", TPF_TEXT, d_count_x + d_count_w + 2*RESFACTOR, d_count_y );
  331. pStaticLevel = new StaticButtonClass( 0, " ", TPF_TEXT, d_level_x + d_level_w + 2*RESFACTOR, d_level_y );
  332. pStaticCredits = new StaticButtonClass( 0, " ", TPF_TEXT, d_credits_x + d_credits_w + 2*RESFACTOR, d_credits_y );
  333. pStaticAIPlayers = new StaticButtonClass( 0, " ", TPF_TEXT, d_aiplayers_x + d_aiplayers_w + 2*RESFACTOR, d_aiplayers_y );
  334. Fancy_Text_Print("", 0, 0, 0, 0, TPF_TEXT);
  335. pDropListHouse = new DropListClass( BUTTON_HOUSE, szHouseBuffer, sizeof( szHouseBuffer ),
  336. TPF_TEXT,
  337. d_house_x, d_house_y, d_house_w, d_house_h,
  338. MFCD::Retrieve("BTN-UP.SHP"),
  339. MFCD::Retrieve("BTN-DN.SHP") );
  340. // ajw - This checkbox is not used. Could be turned on, though.
  341. pCheckAftermathUnits = new BigCheckBoxClass( BUTTON_AFTERMATHUNITS, d_amunits_x, d_amunits_y, d_amunits_w, d_amunits_h,
  342. "Aftermath units enabled", TPF_TEXT, false );
  343. if( pWO->GameInfoCurrent.GameKind == CREATEGAMEINFO::AMGAME )
  344. {
  345. bAftermathUnits = true;
  346. int current_drive = CCFileClass::Get_CD_Drive();
  347. int cd_index = Get_CD_Index(current_drive, 1*60);
  348. if( cd_index != 3 && cd_index != 5 )
  349. {
  350. WOL_PrintMessage( *pILDisc, TXT_WOL_AMDISCNEEDED, WOLCOLORREMAP_LOCALMACHINEMESS );
  351. }
  352. }
  353. else
  354. {
  355. bAftermathUnits = false;
  356. pCheckAftermathUnits->Disable();
  357. }
  358. bSlowUnitBuildRate = true;
  359. #define TABSPACING 38
  360. pShpBtnScenarioRA = new ShapeButtonClass( BUTTON_SCENARIO_RA, MFCD::Retrieve( "tabra.shp" ), d_scenariolist_x, d_scenariolist_y - d_tab_h );
  361. pShpBtnScenarioCS = new ShapeButtonClass( BUTTON_SCENARIO_CS, MFCD::Retrieve( "tabcs.shp" ), d_scenariolist_x + TABSPACING, d_scenariolist_y - d_tab_h );
  362. pShpBtnScenarioAM = new ShapeButtonClass( BUTTON_SCENARIO_AM, MFCD::Retrieve( "tabam.shp" ), d_scenariolist_x + TABSPACING, d_scenariolist_y - d_tab_h );
  363. int iScenarioUserTabPos;
  364. if( pWO->GameInfoCurrent.GameKind == CREATEGAMEINFO::CSGAME || pWO->GameInfoCurrent.GameKind == CREATEGAMEINFO::AMGAME ||
  365. ( pWO->GameInfoCurrent.GameKind == CREATEGAMEINFO::RAGAME && Is_Aftermath_Installed() && !pWO->GameInfoCurrent.bTournament ) )
  366. // Place user tab in the third tab position. (It may still not be present.)
  367. iScenarioUserTabPos = d_scenariolist_x + TABSPACING * 2;
  368. else
  369. iScenarioUserTabPos = d_scenariolist_x + TABSPACING;
  370. pShpBtnScenarioUser = new ShapeButtonClass( BUTTON_SCENARIO_USER, MFCD::Retrieve( "tabus.shp" ), iScenarioUserTabPos, d_scenariolist_y - d_tab_h );
  371. // Change draw behavior of tab buttons.
  372. pShpBtnScenarioRA->ReflectButtonState = true;
  373. pShpBtnScenarioCS->ReflectButtonState = true;
  374. pShpBtnScenarioAM->ReflectButtonState = true;
  375. pShpBtnScenarioUser->ReflectButtonState = true;
  376. if( !bHost )
  377. {
  378. pILScens->Disable();
  379. pGaugeCount->Disable();
  380. pGaugeLevel->Disable();
  381. pGaugeCredits->Disable();
  382. pGaugeAIPlayers->Disable();
  383. pCheckListOptions->Disable();
  384. pCheckAftermathUnits->Disable();
  385. }
  386. pWO->LinkToGameDlg( pILDisc, pILPlayers );
  387. pWO->pGSupDlg = this;
  388. dwTimeNextParamRefresh = ::timeGetTime();
  389. }
  390. //***********************************************************************************************
  391. RESULT_WOLGSUP WOL_GameSetupDialog::Show()
  392. {
  393. // Returns: -1 == return to chat dialog.
  394. //------------------------------------------------------------------------
  395. // Dialog variables
  396. //------------------------------------------------------------------------
  397. bool bHackFocus = true;
  398. display = REDRAW_ALL; // redraw level
  399. bProcess = true; // process while true
  400. KeyNumType input;
  401. DWORD timeWaitingToStartTimeout;
  402. char szScenarioNameDisplay[ 300 ];
  403. bool bInformParamChange;
  404. long ok_timer = 0; // for timing OK button
  405. int i;
  406. int tabs[] = {77*RESFACTOR}; // tabs for player list box
  407. int optiontabs[] = {8*RESFACTOR}; // tabs for option list box
  408. CCFileClass loadfile ("SAVEGAME.NET");
  409. int load_game = 0; // 1 = load a saved game
  410. RemapControlType * scheme = GadgetClass::Get_Color_Scheme();
  411. int cbox_x[] = {
  412. d_color_x,
  413. d_color_x + d_color_w,
  414. d_color_x + (d_color_w * 2),
  415. d_color_x + (d_color_w * 3),
  416. d_color_x + (d_color_w * 4),
  417. d_color_x + (d_color_w * 5),
  418. d_color_x + (d_color_w * 6),
  419. d_color_x + (d_color_w * 7),
  420. };
  421. bool bRetractHouseDropDown = false;
  422. if( !pWO->OnEnteringGameSetup() ) // Gets a userlist setup, among other things.
  423. strcpy( szNameOfHostWhoJustBailedOnUs, TXT_WOL_THEGAMEHOST ); // Will cause immediate exit.
  424. // If I'm not already listed with a color, give myself a color.
  425. // (I may have already received my assigned color from the game host.)
  426. int iItem = pILPlayers->Find( pWO->szMyName ); // (I must be in the list I just got.)
  427. _ASSERTE( iItem != -1 );
  428. RemapControlType* pColorRemap = pILPlayers->Get_Item_Color( iItem );
  429. PlayerColorType Color = PlayerColorTypeOf( pColorRemap );
  430. // debugprint( "Starting up, I see myself as color %i\n", Color );
  431. if( Color == PCOLOR_NONE )
  432. SetPlayerColor( pWO->szMyName, ColorNextAvailable() ); // Unless I'm host, this will be changed quite immediately,
  433. // but nice to have it be a valid value until then.
  434. DWORD dwTimeNextPlayerPing = ::timeGetTime() + PING_AND_DISPLAY_WAIT;
  435. DWORD dwTimeNextPingDisplay = dwTimeNextPlayerPing + 1500; // Stagger ping and ping display periods.
  436. //------------------------------------------------------------------------
  437. // Build the button list
  438. //------------------------------------------------------------------------
  439. BindControls( true );
  440. pILPlayers->Set_Tabs(tabs);
  441. // If we have not already received a param update from a host, set default param values.
  442. if( !bParamsReceived )
  443. {
  444. if( !bHost )
  445. // Accept button disabled until first params arrive.
  446. pTextBtnAcceptStart->Disable();
  447. Special.IsCaptureTheFlag = Rule.IsMPCaptureTheFlag; // Ugh. Use of "Special" global.
  448. if( bHost ) {
  449. Session.Options.Credits = Rule.MPDefaultMoney; // init credits & credit buffer
  450. Session.Options.Bases = Rule.IsMPBasesOn; // init scenario parameters
  451. Session.Options.Tiberium = Rule.IsMPTiberiumGrow;
  452. Session.Options.Goodies = Rule.IsMPCrates;
  453. Session.Options.AIPlayers = 0;
  454. Session.Options.UnitCount = (SessionClass::CountMax[Session.Options.Bases] + SessionClass::CountMin[Session.Options.Bases]) / 2;
  455. //first_time = 0;
  456. }
  457. //------------------------------------------------------------------------
  458. // Init other scenario parameters
  459. //------------------------------------------------------------------------
  460. Special.IsTGrowth = Session.Options.Tiberium; // Ugh. Use of "Special" global.
  461. Rule.IsTGrowth = Session.Options.Tiberium;
  462. Special.IsTSpread = Session.Options.Tiberium; // Ugh. Use of "Special" global.
  463. Rule.IsTSpread = Session.Options.Tiberium;
  464. if( bHost )
  465. {
  466. //------------------------------------------------------------------------
  467. // Set up array of lists of available scenarios.
  468. //------------------------------------------------------------------------
  469. for( i = 0; i < Session.Scenarios.Count(); i++ )
  470. {
  471. // Reworking of the loop previously used for language translation. (What a hack I have inherited...)
  472. MultiMission* pMMission = Session.Scenarios[ i ];
  473. const char* szScenarioNameShow = pMMission->Description();
  474. #if defined( GERMAN ) || defined( FRENCH )
  475. for( int j = 0; EngMisStr[j] != NULL; j++ )
  476. {
  477. if( !strcmp( szScenarioNameShow, EngMisStr[j] ) )
  478. {
  479. // Found description in translation array that matches mission.
  480. szScenarioNameShow = EngMisStr[ j + 1 ];
  481. break;
  482. }
  483. }
  484. // (If no match found, defaults to English description.)
  485. #endif
  486. // Place scenario name in a specific scenario list.
  487. if( pMMission->Get_Official() )
  488. {
  489. if( Is_Mission_Counterstrike( (char*)( Session.Scenarios[i]->Get_Filename() ) ) )
  490. {
  491. // debugprint( " ---------------- Adding scenario %s as CS\n", szScenarioNameShow );
  492. ar_szScenarios[ SCENARIO_CS ].Add( szScenarioNameShow );
  493. ar_szScenIndexes[ SCENARIO_CS ].Add( (void*)i );
  494. }
  495. else if( Is_Mission_Aftermath( (char*)( Session.Scenarios[i]->Get_Filename() ) ) )
  496. {
  497. // debugprint( " ---------------- Adding scenario %s as AM\n", szScenarioNameShow );
  498. // If this is not an Aftermath game channel, we must filter out any AM maps that have
  499. // special AM units on them.
  500. if( pWO->GameInfoCurrent.GameKind == CREATEGAMEINFO::AMGAME ||
  501. !bSpecialAftermathScenario( pMMission->Description() ) )
  502. {
  503. ar_szScenarios[ SCENARIO_AM ].Add( szScenarioNameShow );
  504. ar_szScenIndexes[ SCENARIO_AM ].Add( (void*)i );
  505. }
  506. }
  507. else
  508. {
  509. // debugprint( " ---------------- Adding scenario %s as RA\n", szScenarioNameShow );
  510. ar_szScenarios[ SCENARIO_RA ].Add( szScenarioNameShow );
  511. ar_szScenIndexes[ SCENARIO_RA ].Add( (void*)i );
  512. }
  513. }
  514. else
  515. {
  516. // debugprint( " ---------------- Adding scenario %s as User\n", szScenarioNameShow );
  517. ar_szScenarios[ SCENARIO_USER ].Add( szScenarioNameShow );
  518. ar_szScenIndexes[ SCENARIO_USER ].Add( (void*)i );
  519. }
  520. }
  521. // Set default scenario list viewing mode and prepare tab buttons.
  522. /* switch( pWO->GameInfoCurrent.GameKind )
  523. {
  524. case CREATEGAMEINFO::RAGAME:
  525. ScenarioDisplayMode( SCENARIO_RA );
  526. break;
  527. case CREATEGAMEINFO::CSGAME:
  528. ScenarioDisplayMode( SCENARIO_CS );
  529. break;
  530. case CREATEGAMEINFO::AMGAME:
  531. ScenarioDisplayMode( SCENARIO_AM );
  532. break;
  533. default:
  534. // debugprint( "Illegal GameInfoCurrent value." );
  535. Fatal( "Illegal GameInfoCurrent value." );
  536. }
  537. */
  538. Session.Options.ScenarioIndex = 0; // 1st scenario is selected
  539. ScenarioDisplayMode( SCENARIO_RA ); // Always start on RedAlert tab. Next line depends on selected item in
  540. // list matching selected scenario.
  541. // pStaticDescrip->Set_Text( pILScens->Get_Item( pILScens->Current_Index() ), false );
  542. strcpy( szScenarioNameDisplay, pILScens->Get_Item( pILScens->Current_Index() ) );
  543. }
  544. Seed = rand();
  545. }
  546. //------------------------------------------------------------------------
  547. // Init button states
  548. //------------------------------------------------------------------------
  549. pCheckListOptions->Set_Tabs(optiontabs);
  550. pCheckListOptions->Set_Read_Only(0);
  551. pCheckListOptions->Add_Item(Text_String(TXT_BASES));
  552. pCheckListOptions->Add_Item(Text_String(TXT_ORE_SPREADS));
  553. pCheckListOptions->Add_Item(Text_String(TXT_CRATES));
  554. pCheckListOptions->Add_Item(Text_String(TXT_CAPTURE_THE_FLAG));
  555. pCheckListOptions->Add_Item(Text_String(TXT_SHADOW_REGROWS));
  556. pCheckListOptions->Add_Item(TXT_WOL_SLOWUNITBUILD);
  557. SetSpecialControlStates();
  558. //........................................................................
  559. // House buttons
  560. //........................................................................
  561. for (HousesType house = HOUSE_USSR; house <= HOUSE_FRANCE; house++) {
  562. pDropListHouse->Add_Item(Text_String(HouseTypeClass::As_Reference(house).Full_Name()));
  563. }
  564. pDropListHouse->Set_Selected_Index(Session.House - HOUSE_USSR);
  565. pDropListHouse->Set_Read_Only (true);
  566. bInformParamChange = false;
  567. // PlayingAgainstVersion = VerNum.Version_Number();
  568. //------------------------------------------------------------------------
  569. // Init random-number generator, & create a seed to be used for all random
  570. // numbers from here on out
  571. //------------------------------------------------------------------------
  572. srand(time(NULL));
  573. //------------------------------------------------------------------------
  574. // Init the version-clipping system
  575. //------------------------------------------------------------------------
  576. VerNum.Init_Clipping();
  577. // Load_Title_Page(true);
  578. // CCPalette.Set(); //GamePalette.Set();
  579. //
  580. // Now init the max range of the AI players slider.
  581. //
  582. // pGaugeAIPlayers->Set_Maximum(Rule.MaxPlayers-Session.Players.Count());
  583. // pGaugeAIPlayers->Set_Value(Session.Options.AIPlayers);
  584. Sound_Effect( WOLSOUND_ENTERGAME );
  585. //------------------------------------------------------------------------
  586. // Processing loop
  587. //------------------------------------------------------------------------
  588. while (bProcess) {
  589. #if(SHOW_MONO)
  590. Ipx.Mono_Debug_Print(-1,0);
  591. #endif
  592. // Check for change of house. Occurs on first loop and when user changes house.
  593. if( HousePrevious != Session.House )
  594. {
  595. if( bHost )
  596. {
  597. // Host changed house.
  598. // Do processing as if we'd received a message from a guest.
  599. // Set house in our own list.
  600. SetPlayerHouse( pWO->szMyName, Session.House );
  601. // Tell guests.
  602. nHostLastParamID++;
  603. InformAboutPlayerHouse( pWO->szMyName, Session.House, NULL );
  604. HousePrevious = Session.House;
  605. ClearAllAccepts();
  606. }
  607. else
  608. {
  609. User* pUserHost = pWO->pGameHost();
  610. if( pUserHost ) // Else we have not received the user list yet and don't know who the host is.
  611. // We'll keep trying this until we get a host - HousePrevious keeps us triggering until then.
  612. {
  613. // debugprint( "Session.House changed.\n" );
  614. // Tell host we changed our house.
  615. char szSend[ 20 ];
  616. sprintf( szSend, "%02u %02u", WOL_GAMEOPT_REQHOUSE, Session.House );
  617. pWO->SendGameOpt( szSend, pUserHost );
  618. // Set house in our own list. This is fine because we know that the change must be affirmed by the host.
  619. SetPlayerHouse( pWO->szMyName, Session.House );
  620. HousePrevious = Session.House;
  621. }
  622. }
  623. }
  624. // Regularly ping other players to assess latencies.
  625. // Display of ping results is on a parallel timer, slightly behind the ping so that we'll be likely to have
  626. // a fresh average to show. Not too big a deal if OnPings haven't arrived by then (though they should have).
  627. if( ::timeGetTime() > dwTimeNextPlayerPing )
  628. {
  629. pWO->RequestPlayerPings();
  630. dwTimeNextPlayerPing = ::timeGetTime() + PING_AND_DISPLAY_WAIT;
  631. }
  632. if( ::timeGetTime() > dwTimeNextPingDisplay )
  633. {
  634. pWO->ListChannelUsers();
  635. dwTimeNextPingDisplay = ::timeGetTime() + PING_AND_DISPLAY_WAIT;
  636. }
  637. if( pWO->bShowRankUpdated )
  638. {
  639. pWO->bShowRankUpdated = false;
  640. pWO->ListChannelUsers();
  641. }
  642. // Regularly check for incoming messages from wolapi.
  643. if( ::timeGetTime() > pWO->dwTimeNextWolapiPump )
  644. {
  645. pWO->pChat->PumpMessages();
  646. pWO->pNetUtil->PumpMessages();
  647. // Special post-callback processing...
  648. if( pWO->pChatSink->bGotKickedTrigger )
  649. {
  650. // We got kicked out of the channel.
  651. pWO->OnExitingGameChannel();
  652. pWO->RejoinLobbyAfterGame();
  653. bProcess = false;
  654. ResultReturn = RESULT_WOLGSUP_BACKTOCHAT; // Return to chat.
  655. // Leave the bGotKickedTrigger flag so we can react to it upon reentering the chat dialog.
  656. //pWO->pChatSink->bGotKickedTrigger = false;
  657. display = REDRAW_ALL;
  658. }
  659. pWO->dwTimeNextWolapiPump = ::timeGetTime() + WOLAPIPUMPWAIT;
  660. }
  661. if( bHostSayGo )
  662. {
  663. // debugprint( "bHostSayGo trigger\n" );
  664. // We are the host, now ready to tell everyone to GO and start our game.
  665. HostSaysGo();
  666. /* Part of old method of game start.
  667. bProcess = false;
  668. ResultReturn = RESULT_WOLGSUP_STARTGAMEHOST;
  669. // debugprint( "Host about to exit game setup dialog for game.\n" );
  670. if( !ExitGameChannel() )
  671. ResultReturn = RESULT_WOLGSUP_FATALERROR; // Return with an error value.
  672. break;
  673. */
  674. }
  675. else if( *szNameOfHostWhoJustBailedOnUs ) // Host left channel - cancel setup.
  676. {
  677. // debugprint( "Guest about to exit game setup dialog because host bailed on us.\n" );
  678. if( ExitGameChannel() )
  679. {
  680. pWO->RejoinLobbyAfterGame();
  681. bProcess = false;
  682. ResultReturn = RESULT_WOLGSUP_HOSTLEFT; // Return to chat.
  683. // Add a message explaining what happened to the saved chat that will be restored in the chat dialog.
  684. pWO->AddHostLeftMessageToSavedChat( szNameOfHostWhoJustBailedOnUs );
  685. }
  686. else
  687. {
  688. bProcess = false;
  689. ResultReturn = RESULT_WOLGSUP_FATALERROR; // Return with an error value.
  690. }
  691. break;
  692. }
  693. else if( bLeaveDueToRulesMismatchTrigger )
  694. {
  695. // debugprint( "Guest about to exit game setup dialog because of rules.ini mismatch.\n" );
  696. if( ExitGameChannel() )
  697. {
  698. pWO->RejoinLobbyAfterGame();
  699. bProcess = false;
  700. ResultReturn = RESULT_WOLGSUP_RULESMISMATCH; // Return to chat.
  701. // Add a message explaining what happened to the saved chat that will be restored in the chat dialog.
  702. pWO->AddMessageToSavedChat( TXT_WOL_RULESMISMATCH );
  703. }
  704. else
  705. {
  706. bProcess = false;
  707. ResultReturn = RESULT_WOLGSUP_FATALERROR; // Return with an error value.
  708. }
  709. break;
  710. }
  711. else if( *szTriggerGameStartInfo )
  712. {
  713. // debugprint( "About to trigger game start.\n" );
  714. TriggerGameStart( szTriggerGameStartInfo );
  715. }
  716. else if( pWO->bSelfDestruct )
  717. {
  718. if( pWO->pChatSink->bConnected )
  719. pWO->Logout();
  720. bProcess = false;
  721. ResultReturn = RESULT_WOLGSUP_LOGOUT; // As if the user logged himself out.
  722. }
  723. if( bExitForGameTrigger )
  724. {
  725. // We are now exiting to go into a game.
  726. bProcess = false;
  727. if( bHost )
  728. ResultReturn = RESULT_WOLGSUP_STARTGAMEHOST;
  729. else
  730. ResultReturn = RESULT_WOLGSUP_STARTGAME;
  731. // debugprint( "About to exit game setup dialog for game.\n" );
  732. if( !ExitGameChannel() )
  733. ResultReturn = RESULT_WOLGSUP_FATALERROR; // Return with an error value.
  734. break;
  735. }
  736. if( bHost && bWaitingToStart && !bExitForGameTrigger && timeGetTime() > timeWaitingToStartTimeout )
  737. {
  738. ClearAllAccepts(); // Results in all required steps to cancel game start.
  739. WOL_PrintMessage( *pILDisc, TXT_WOL_STARTTIMEOUT, WOLCOLORREMAP_LOCALMACHINEMESS );
  740. Sound_Effect( WOLSOUND_ERROR );
  741. }
  742. // Regularly send game param changes if I'm the host.
  743. if( bHost && !bHostSayGo && !bExitForGameTrigger && ::timeGetTime() > dwTimeNextParamRefresh )
  744. {
  745. if( bParamsUnfresh() )
  746. {
  747. nHostLastParamID++;
  748. SendParams();
  749. ClearAllAccepts();
  750. }
  751. dwTimeNextParamRefresh = ::timeGetTime() + PARAMREFRESHWAIT;
  752. }
  753. if( !bProcess ) // Avoid redrawing if we're about to bail.
  754. break;
  755. //
  756. // If we have just received input focus again after running in the background then
  757. // we need to redraw.
  758. //
  759. if (AllSurfaces.SurfacesRestored) {
  760. AllSurfaces.SurfacesRestored=FALSE;
  761. display = REDRAW_ALL;
  762. }
  763. //.....................................................................
  764. // Refresh display if needed
  765. //.....................................................................
  766. if( bRetractHouseDropDown ) //|| pCheckListOptions->Is_To_Redraw() )
  767. {
  768. bRetractHouseDropDown = false;
  769. if( pDropListHouse->IsDropped )
  770. {
  771. pDropListHouse->Collapse();
  772. if (display < REDRAW_BACKGROUND) display = REDRAW_BACKGROUND;
  773. }
  774. }
  775. // if( pILDisc->Is_To_Redraw() )
  776. // {
  777. // pDropListHouse->Flag_To_Redraw();
  778. // }
  779. if( display )
  780. {
  781. Hide_Mouse();
  782. /*
  783. ** Collapse the country list if we are going to redraw the game list
  784. */
  785. // if (pILScens->Is_To_Redraw() && pDropListHouse->IsDropped) {
  786. // pDropListHouse->Collapse();
  787. // if (display < REDRAW_BACKGROUND) display = REDRAW_BACKGROUND;
  788. // }
  789. //..................................................................
  790. // Redraw backgound & dialog box
  791. //..................................................................
  792. if (display >= REDRAW_BACKGROUND) {
  793. if( pToolTipHitLast && pToolTipHitLast->bShowing )
  794. pToolTipHitLast->Unshow();
  795. if( pDropListHouse->IsDropped )
  796. pDropListHouse->Collapse();
  797. Dialog_Box(d_dialog_x, d_dialog_y, d_dialog_w, d_dialog_h);
  798. //...............................................................
  799. // Dialog & Field labels
  800. //...............................................................
  801. Fancy_Text_Print(TXT_PLAYERS, d_playerlist_x + (d_playerlist_w / 2), d_playerlist_y - d_txt6_h, scheme, TBLACK, TPF_TEXT | TPF_CENTER);
  802. if( bHost )
  803. Fancy_Text_Print( TXT_SCENARIOS, d_scenariolist_x + d_scenariolist_w, d_scenariolist_y - 12, scheme, TBLACK, TPF_TYPE | TPF_RIGHT );
  804. // else
  805. // Fancy_Text_Print( TXT_SCENARIO_COLON, d_scenariolist_x + (d_scenariolist_w / 2), d_scenariolist_y - d_txt6_h, scheme, TBLACK, TPF_TEXT | TPF_CENTER);
  806. Fancy_Text_Print(TXT_COUNT, d_count_x - 2*RESFACTOR, d_count_y, scheme, TBLACK, TPF_TEXT | TPF_RIGHT);
  807. Fancy_Text_Print(TXT_LEVEL, d_level_x - 2*RESFACTOR, d_level_y, scheme, TBLACK, TPF_TEXT | TPF_RIGHT);
  808. Fancy_Text_Print(TXT_CREDITS_COLON, d_credits_x - 2*RESFACTOR, d_credits_y, scheme, TBLACK, TPF_TEXT | TPF_RIGHT);
  809. Fancy_Text_Print(TXT_AI_PLAYERS_COLON, d_aiplayers_x - 2*RESFACTOR, d_aiplayers_y, scheme, TBLACK, TPF_TEXT | TPF_RIGHT);
  810. Fancy_Text_Print(TXT_SIDE_COLON,
  811. // d_house_x + (d_house_w / 2),
  812. d_house_x + ( ( d_house_w + 16 ) / 2 ),
  813. d_house_y - d_txt6_h,
  814. scheme, TBLACK,
  815. TPF_CENTER | TPF_TEXT);
  816. Fancy_Text_Print(TXT_COLOR_COLON,
  817. d_color_x + d_color_w * 4,
  818. d_color_y - d_txt6_h,
  819. scheme, TBLACK,
  820. TPF_CENTER | TPF_TEXT);
  821. const char* szGameKind;
  822. const char* pDIB;
  823. switch( pWO->GameInfoCurrent.GameKind )
  824. {
  825. case CREATEGAMEINFO::RAGAME:
  826. szGameKind = TXT_WOL_CG_RAGAME;
  827. pDIB = pWO->OldRAGameTypeInfos[ 0 ].pDIB;
  828. break;
  829. case CREATEGAMEINFO::CSGAME:
  830. szGameKind = TXT_WOL_CG_CSGAME;
  831. pDIB = pWO->OldRAGameTypeInfos[ 1 ].pDIB;
  832. break;
  833. case CREATEGAMEINFO::AMGAME:
  834. szGameKind = TXT_WOL_CG_AMGAME;
  835. pDIB = pWO->OldRAGameTypeInfos[ 2 ].pDIB;
  836. break;
  837. default:
  838. // debugprint( "Illegal GameInfoCurrent value." );
  839. //Fatal( "Illegal GameInfoCurrent value." );
  840. szGameKind = TXT_WOL_CG_AMGAME;
  841. pDIB = NULL;
  842. pWO->bSelfDestruct = true;
  843. break;
  844. }
  845. int iGameInfoSpacingY = 14;
  846. int iGameInfoSecondColumnX = 0; //170;
  847. // Game kind.
  848. Fancy_Text_Print( szGameKind, d_gamekind_x, d_gamekind_y - iGameInfoSpacingY * 1, scheme, TBLACK, TPF_TYPE );
  849. // Game kind icon.
  850. CC_Draw_DIB( pDIB, d_gamekind_x - 16, d_gamekind_y - iGameInfoSpacingY * 1 - 2, 100, WINDOW_MAIN );
  851. // "Tournament."
  852. if( pWO->GameInfoCurrent.bTournament )
  853. {
  854. Fancy_Text_Print( TXT_WOL_CG_TOURNAMENT, d_gamekind_x + iGameInfoSecondColumnX,
  855. d_gamekind_y + iGameInfoSpacingY * 1, scheme, TBLACK, TPF_TYPE );
  856. CC_Draw_DIB( pWO->DibIconInfos[ DIBICON_TOURNAMENT ].pDIB, d_gamekind_x + iGameInfoSecondColumnX - 16,
  857. d_gamekind_y + iGameInfoSpacingY * 1 - 2, 100, WINDOW_MAIN );
  858. }
  859. // "Password: ..."
  860. if( pWO->GameInfoCurrent.bPrivate )
  861. {
  862. char szPrivatePassword[ 100 ];
  863. sprintf( szPrivatePassword, TXT_WOL_PRIVATEPASSWORD, pWO->GameInfoCurrent.szPassword );
  864. Fancy_Text_Print( szPrivatePassword, d_gamekind_x + iGameInfoSecondColumnX,
  865. d_gamekind_y + iGameInfoSpacingY * 2, scheme, TBLACK, TPF_TYPE );
  866. CC_Draw_DIB( pWO->DibIconInfos[ DIBICON_PRIVATE ].pDIB, d_gamekind_x + iGameInfoSecondColumnX - 16,
  867. d_gamekind_y + iGameInfoSpacingY * 2 - 2, 100, WINDOW_MAIN );
  868. }
  869. // "Scenario:" - scenario name is drawn separately.
  870. //Fancy_Text_Print( TXT_SCENARIO_COLON, d_gamekind_x, d_gamekind_y - iGameInfoSpacingY, scheme, TBLACK, TPF_TYPE );
  871. }
  872. //..................................................................
  873. // Redraw buttons
  874. //..................................................................
  875. if (display >= REDRAW_BUTTONS) {
  876. commands->Draw_All();
  877. }
  878. //..................................................................
  879. // Draw the color boxes
  880. //..................................................................
  881. if (display >= REDRAW_COLORS ) {
  882. for (i = 0; i < MAX_MPLAYER_COLORS; i++) {
  883. LogicPage->Fill_Rect (cbox_x[i] + 1, d_color_y + 1,
  884. cbox_x[i] + 1 + d_color_w - 2 *RESFACTOR, d_color_y + 1 + d_color_h - 2,
  885. ColorRemaps[i].Box);
  886. if (i == Session.ColorIdx) {
  887. Draw_Box(cbox_x[i], d_color_y, d_color_w, d_color_h, BOXSTYLE_DOWN, false);
  888. } else {
  889. Draw_Box(cbox_x[i], d_color_y, d_color_w, d_color_h, BOXSTYLE_RAISED, false);
  890. }
  891. }
  892. }
  893. //..................................................................
  894. // Draw the messages:
  895. // - Erase an old message first
  896. // - If we're in a game, print the game options (if they've been
  897. // received)
  898. // - If we've been rejected from a game, print that message
  899. //..................................................................
  900. if (display >= REDRAW_MESSAGE) {
  901. // Draw_Box(d_disc_x, d_disc_y, d_disc_w, d_disc_h, BOXSTYLE_BOX, true);
  902. // Draw_Box(d_send_x, d_send_y, d_send_w, d_send_h, BOXSTYLE_BOX, true);
  903. // Session.Messages.Draw();
  904. }
  905. //..................................................................
  906. // Update game parameter labels
  907. //..................................................................
  908. if (display >= REDRAW_PARMS)
  909. {
  910. char txt[80];
  911. char* szScenarioDesc;
  912. bool bOfficial;
  913. char* szScenarioFileName;
  914. if( !bHost )
  915. {
  916. szScenarioDesc = Session.Options.ScenarioDescription;
  917. bOfficial = Session.ScenarioIsOfficial;
  918. szScenarioFileName = Session.ScenarioFileName;
  919. }
  920. else
  921. {
  922. szScenarioDesc = (char*)Session.Scenarios[ Session.Options.ScenarioIndex ]->Description();
  923. bOfficial = Session.Scenarios[ Session.Options.ScenarioIndex ]->Get_Official();
  924. szScenarioFileName = (char*)Session.Scenarios[ Session.Options.ScenarioIndex ]->Get_Filename();
  925. }
  926. if( *szScenarioDesc )
  927. {
  928. // Language translation.
  929. for (int ii = 0; EngMisStr[ii] != NULL; ii++) {
  930. if (!strcmp( szScenarioDesc, EngMisStr[ii]) ) {
  931. #if defined(GERMAN) || defined(FRENCH)
  932. //sprintf(txt, "%s %s", Text_String(TXT_SCENARIO_COLON), EngMisStr[ii+1]);
  933. sprintf(txt, "%s", EngMisStr[ii+1]);
  934. #else
  935. //sprintf(txt, "%s %s", Text_String(TXT_SCENARIO_COLON), Session.Options.ScenarioDescription);
  936. sprintf(txt, "%s", szScenarioDesc);
  937. #endif
  938. break;
  939. }
  940. }
  941. if (EngMisStr[ii] == NULL) {
  942. sprintf(txt, "%s", szScenarioDesc);
  943. }
  944. // pStaticDescrip->Set_Text( txt, false );
  945. strcpy( szScenarioNameDisplay, txt );
  946. // Show icon for gamekind of scenario.
  947. const char* pDIB;
  948. if( bOfficial )
  949. {
  950. if( Is_Mission_Counterstrike( szScenarioFileName ) )
  951. pDIB = pWO->OldRAGameTypeInfos[ 1 ].pDIB;
  952. else if( Is_Mission_Aftermath( szScenarioFileName ) )
  953. pDIB = pWO->OldRAGameTypeInfos[ 2 ].pDIB;
  954. else
  955. pDIB = pWO->OldRAGameTypeInfos[ 0 ].pDIB;
  956. }
  957. else
  958. pDIB = pWO->DibIconInfos[ DIBICON_USER ].pDIB;
  959. DrawScenarioDescripIcon( pDIB );
  960. }
  961. else
  962. {
  963. //sprintf(txt, "%s %s", Text_String(TXT_SCENARIO_COLON), Text_String(TXT_NOT_FOUND));
  964. sprintf(txt, "%s", TXT_WOL_SCENARIONAMEWAIT );
  965. // pStaticDescrip->Set_Text( txt, false );
  966. strcpy( szScenarioNameDisplay, txt );
  967. }
  968. // Print scenario name.
  969. Conquer_Clip_Text_Print( szScenarioNameDisplay, d_gamekind_x, d_gamekind_y, scheme, TBLACK, TPF_TYPE, d_gamekind_w );
  970. // pStaticDescrip->Draw_Me();
  971. sprintf(txt,"%d",Session.Options.UnitCount);
  972. pStaticUnit->Set_Text(txt);
  973. pStaticUnit->Draw_Me();
  974. if (BuildLevel <= MPLAYER_BUILD_LEVEL_MAX) {
  975. sprintf(txt,"%d",BuildLevel);
  976. } else {
  977. sprintf(txt, "**");
  978. }
  979. pStaticLevel->Set_Text(txt);
  980. pStaticLevel->Draw_Me();
  981. sprintf(txt,"%d",Session.Options.Credits);
  982. pStaticCredits->Set_Text(txt);
  983. pStaticCredits->Draw_Me();
  984. sprintf(txt,"%d",Session.Options.AIPlayers);
  985. pStaticAIPlayers->Set_Text(txt);
  986. pStaticAIPlayers->Draw_Me();
  987. }
  988. Show_Mouse();
  989. display = REDRAW_NONE;
  990. }
  991. // Force mouse visible, as some beta testers report unexplicable disappearing cursors.
  992. while( Get_Mouse_State() )
  993. Show_Mouse();
  994. // Be nice to other apps.
  995. Sleep( 50 );
  996. //.....................................................................
  997. // Get user input
  998. //.....................................................................
  999. if( ( ::GetAsyncKeyState( KN_LMOUSE ) & 0x8000 ) || ( ::GetAsyncKeyState( KN_RMOUSE ) & 0x8000 ) )
  1000. {
  1001. timeToolTipAppear = ::timeGetTime() + TOOLTIPDELAY;
  1002. if( pToolTipHitLast && pToolTipHitLast->bShowing )
  1003. pToolTipHitLast->Unshow();
  1004. }
  1005. input = commands->Input();
  1006. if( bHackFocus )
  1007. {
  1008. pEditSend->Set_Focus();
  1009. pEditSend->Flag_To_Redraw();
  1010. input = commands->Input();
  1011. bHackFocus = false;
  1012. }
  1013. // Tooltips...
  1014. if( pToolTipHead )
  1015. {
  1016. ToolTipClass* pToolTipHit = pToolTipHead->GetToolTipHit();
  1017. if( pToolTipHit == pToolTipHitLast )
  1018. {
  1019. if( pToolTipHit && !pToolTipHit->bShowing && ::timeGetTime() > timeToolTipAppear && !( ( ::GetAsyncKeyState( KN_LMOUSE ) & 0x8000 ) || ( ::GetAsyncKeyState( KN_RMOUSE ) & 0x8000 ) ) )
  1020. {
  1021. pToolTipHit->Show();
  1022. }
  1023. }
  1024. else
  1025. {
  1026. if( pToolTipHitLast && pToolTipHitLast->bShowing )
  1027. pToolTipHitLast->Unshow();
  1028. pToolTipHitLast = pToolTipHit;
  1029. timeToolTipAppear = ::timeGetTime() + TOOLTIPDELAY;
  1030. }
  1031. }
  1032. // Yummy special hack. Luv' that UI system.
  1033. if( input == 2049 ) // Left mouse released, not on control that captured it.
  1034. {
  1035. // Redraw the tabs in case they were what were pressed down on.
  1036. pShpBtnScenarioRA->Flag_To_Redraw();
  1037. pShpBtnScenarioCS->Flag_To_Redraw();
  1038. pShpBtnScenarioAM->Flag_To_Redraw();
  1039. pShpBtnScenarioUser->Flag_To_Redraw();
  1040. }
  1041. //.....................................................................
  1042. // Process input
  1043. //.....................................................................
  1044. switch( input )
  1045. {
  1046. case KN_LMOUSE:
  1047. if( !bWaitingToStart )
  1048. {
  1049. // Check for mouse down on a control when player is not host.
  1050. if( !bHost )
  1051. {
  1052. if ( (
  1053. Get_Mouse_X() >= d_count_x &&
  1054. Get_Mouse_X() <= d_count_x + d_count_w &&
  1055. Get_Mouse_Y() >= d_count_y &&
  1056. Get_Mouse_Y() <= d_aiplayers_y + d_aiplayers_h
  1057. ) || (
  1058. Get_Mouse_X() >= d_options_x &&
  1059. Get_Mouse_X() <= d_options_x + d_options_w &&
  1060. Get_Mouse_Y() >= d_options_y &&
  1061. Get_Mouse_Y() <= d_options_y + d_options_h
  1062. ) || (
  1063. Get_Mouse_X() >= d_scenariolist_x &&
  1064. Get_Mouse_X() <= d_scenariolist_x + d_scenariolist_w &&
  1065. Get_Mouse_Y() >= d_scenariolist_y &&
  1066. Get_Mouse_Y() <= d_scenariolist_y + d_scenariolist_h
  1067. ) )
  1068. {
  1069. //Session.Messages.Add_Message(NULL, 0, (char *)Text_String(TXT_ONLY_HOST_CAN_MODIFY), PCOLOR_BROWN, TPF_TEXT, 1200);
  1070. WOL_PrintMessage( *pILDisc, Text_String( TXT_ONLY_HOST_CAN_MODIFY ), WOLCOLORREMAP_LOCALMACHINEMESS );
  1071. Sound_Effect( WOLSOUND_ERROR );
  1072. if (display < REDRAW_MESSAGE) display = REDRAW_MESSAGE;
  1073. break;
  1074. }
  1075. }
  1076. if (Keyboard->MouseQX > cbox_x[0] &&
  1077. Keyboard->MouseQX < (cbox_x[MAX_MPLAYER_COLORS - 1] + d_color_w) &&
  1078. Keyboard->MouseQY > d_color_y &&
  1079. Keyboard->MouseQY < (d_color_y + d_color_h))
  1080. {
  1081. Session.PrefColor = (PlayerColorType)
  1082. ((Keyboard->MouseQX - cbox_x[0]) / d_color_w);
  1083. // Ensure that no one is using this color (to our knowledge).
  1084. if( pILPlayers->FindColor( &ColorRemaps[ Session.PrefColor == PCOLOR_DIALOG_BLUE ? PCOLOR_REALLY_BLUE : Session.PrefColor ] ) == -1 )
  1085. {
  1086. // Show me as the new color.
  1087. // debugprint( "Color box pressed - " );
  1088. SetPlayerColor( pWO->szMyName, Session.PrefColor );
  1089. if( bHost )
  1090. {
  1091. // Tell all guests about the color change.
  1092. InformAboutPlayerColor( pWO->szMyName, Session.PrefColor, NULL );
  1093. }
  1094. else
  1095. {
  1096. RequestPlayerColor( Session.PrefColor );
  1097. }
  1098. }
  1099. }
  1100. }
  1101. break;
  1102. case ( BUTTON_DISCONNECT | KN_BUTTON ):
  1103. if( WWMessageBox().Process( TXT_WOL_CONFIRMLOGOUT, TXT_YES, TXT_NO ) == 0 )
  1104. {
  1105. // debugprint( "Logging out from gsup.\n" );
  1106. ExitGameChannel();
  1107. pWO->Logout();
  1108. bProcess = false;
  1109. ResultReturn = RESULT_WOLGSUP_LOGOUT;
  1110. }
  1111. display = REDRAW_ALL;
  1112. bHackFocus = true;
  1113. break;
  1114. case ( BUTTON_REFRESH | KN_BUTTON ): // Always disabled.
  1115. break;
  1116. case ( BUTTON_SQUELCH | KN_BUTTON ):
  1117. pWO->DoSquelch( pILPlayers );
  1118. break;
  1119. case ( BUTTON_BAN | KN_BUTTON ):
  1120. pWO->DoKick( pILPlayers, true );
  1121. // display = REDRAW_ALL;
  1122. break;
  1123. case ( BUTTON_KICK | KN_BUTTON ):
  1124. pWO->DoKick( pILPlayers, false );
  1125. // display = REDRAW_ALL;
  1126. break;
  1127. case ( BUTTON_FINDPAGE | KN_BUTTON ):
  1128. pWO->DoFindPage();
  1129. display = REDRAW_ALL;
  1130. bHackFocus = true;
  1131. break;
  1132. case ( BUTTON_OPTIONS | KN_BUTTON ):
  1133. pWO->DoOptions();
  1134. display = REDRAW_ALL;
  1135. bHackFocus = true;
  1136. break;
  1137. case ( BUTTON_LADDER | KN_BUTTON ):
  1138. pWO->DoLadder();
  1139. display = REDRAW_ALL;
  1140. bHackFocus = true;
  1141. break;
  1142. case ( BUTTON_HELP | KN_BUTTON ):
  1143. pWO->DoHelp();
  1144. display = REDRAW_ALL;
  1145. bHackFocus = true;
  1146. break;
  1147. case ( BUTTON_HOUSE | KN_BUTTON ):
  1148. Session.House = (HousesType)( pDropListHouse->Current_Index() + HOUSE_USSR );
  1149. /*
  1150. // Bloody bloody hell I can't believe there are bugs in RA like the one I deal with here...
  1151. if( strcmp( pDropListHouse->Current_Item(), "Russia" ) == 0 )
  1152. Session.House = HOUSE_USSR;
  1153. else
  1154. {
  1155. Session.House = HouseTypeClass::From_Name( pDropListHouse->Current_Item() ); // Fails on "Russia". (Thinks "USSR".)
  1156. if( Session.House == HOUSE_NONE )
  1157. {
  1158. // debugprint( "Couldn't find house from selected '%s'.\n", pDropListHouse->Current_Item() );
  1159. }
  1160. }
  1161. */
  1162. if( pDropListHouse->IsDropped )
  1163. bRetractHouseDropDown = true;
  1164. else
  1165. if (display < REDRAW_BACKGROUND) display = REDRAW_BACKGROUND; // Droplist already got contracted.
  1166. Sound_Effect(VOC_OPTIONS_CHANGED);
  1167. break;
  1168. case ( BUTTON_AFTERMATHUNITS | KN_BUTTON ):
  1169. bAftermathUnits = pCheckAftermathUnits->IsOn;
  1170. break;
  1171. case ( BUTTON_SENDEDIT | KN_BUTTON ):
  1172. // Enter has been pressed - was caught by pEditSend control.
  1173. pWO->SendMessage( pEditSend->Get_Text(), *pILPlayers, false );
  1174. // Clear pEditSend, reset focus.
  1175. szSendBuffer[0] = 0;
  1176. pEditSend->Set_Focus();
  1177. // Mark for redraw.
  1178. pEditSend->Flag_To_Redraw();
  1179. break;
  1180. case ( BUTTON_ACTION | KN_BUTTON ):
  1181. // Enter has been pressed - was caught by pEditSend control.
  1182. pWO->SendMessage( pEditSend->Get_Text(), *pILPlayers, true );
  1183. // Clear pEditSend, reset focus.
  1184. szSendBuffer[0] = 0;
  1185. pEditSend->Set_Focus();
  1186. // Mark for redraw.
  1187. pEditSend->Flag_To_Redraw();
  1188. break;
  1189. //..................................................................
  1190. // New Scenario selected.
  1191. //..................................................................
  1192. case (BUTTON_SCENARIOLIST | KN_BUTTON):
  1193. {
  1194. if( pILScens->Count() )
  1195. {
  1196. int iSelectedScenIndex = (int)pILScens->Get_Item_ExtraDataPtr( pILScens->Current_Index() );
  1197. if( iSelectedScenIndex != Session.Options.ScenarioIndex )
  1198. {
  1199. Session.Options.ScenarioIndex = iSelectedScenIndex;
  1200. bInformParamChange = true;
  1201. if( !pILScens->SetSelectType( 1 ) ) // Hack to deal with ListClass "highlighting nothing" problem.
  1202. // SelectType was 0 before call.
  1203. pILScens->Flag_To_Redraw();
  1204. // pStaticDescrip->Set_Text( pILScens->Get_Item( pILScens->Current_Index() ), false );
  1205. strcpy( szScenarioNameDisplay, pILScens->Get_Item( pILScens->Current_Index() ) );
  1206. //if (display < REDRAW_PARMS) display = REDRAW_PARMS;
  1207. display = REDRAW_ALL;
  1208. Sound_Effect(VOC_OPTIONS_CHANGED);
  1209. }
  1210. }
  1211. break;
  1212. }
  1213. //..................................................................
  1214. // User adjusts max # units
  1215. //..................................................................
  1216. case (BUTTON_COUNT | KN_BUTTON):
  1217. Session.Options.UnitCount = pGaugeCount->Get_Value() +
  1218. SessionClass::CountMin[Session.Options.Bases];
  1219. bInformParamChange = true;
  1220. if (display < REDRAW_PARMS) display = REDRAW_PARMS;
  1221. Sound_Effect(VOC_OPTIONS_CHANGED);
  1222. break;
  1223. //..................................................................
  1224. // User adjusts build level
  1225. //..................................................................
  1226. case (BUTTON_LEVEL | KN_BUTTON):
  1227. BuildLevel = pGaugeLevel->Get_Value() + 1;
  1228. if (BuildLevel > MPLAYER_BUILD_LEVEL_MAX) // if it's pegged, max it out
  1229. BuildLevel = MPLAYER_BUILD_LEVEL_MAX;
  1230. bInformParamChange = true;
  1231. if (display < REDRAW_PARMS) display = REDRAW_PARMS;
  1232. Sound_Effect(VOC_OPTIONS_CHANGED);
  1233. break;
  1234. //..................................................................
  1235. // User edits the credits value; retransmit new game options
  1236. // Round the credits to the nearest 500.
  1237. //..................................................................
  1238. case (BUTTON_CREDITS | KN_BUTTON):
  1239. Session.Options.Credits = pGaugeCredits->Get_Value();
  1240. Session.Options.Credits =
  1241. ((Session.Options.Credits + 250) / 500) * 500;
  1242. bInformParamChange = true;
  1243. if (display < REDRAW_PARMS) display = REDRAW_PARMS;
  1244. Sound_Effect(VOC_OPTIONS_CHANGED);
  1245. break;
  1246. //..................................................................
  1247. // User adjusts # of AI players
  1248. //..................................................................
  1249. case (BUTTON_AIPLAYERS | KN_BUTTON):
  1250. Session.Options.AIPlayers = pGaugeAIPlayers->Get_Value();
  1251. // if (Session.Options.AIPlayers+Session.Players.Count() > Rule.MaxPlayers) { // if it's pegged, max it out
  1252. if (Session.Options.AIPlayers + pWO->GameInfoCurrent.iPlayerMax > Rule.MaxPlayers) { // if it's pegged, max it out
  1253. Session.Options.AIPlayers = Rule.MaxPlayers - pWO->GameInfoCurrent.iPlayerMax;
  1254. pGaugeAIPlayers->Set_Value(Session.Options.AIPlayers);
  1255. }
  1256. bInformParamChange = true;
  1257. if (display < REDRAW_PARMS) display = REDRAW_PARMS;
  1258. Sound_Effect(VOC_OPTIONS_CHANGED);
  1259. break;
  1260. //..................................................................
  1261. // Toggle-able options:
  1262. // If 'Bases' gets toggled, we have to change the range of the
  1263. // UnitCount slider.
  1264. // Also, if Tiberium gets toggled, we have to set the flags
  1265. // in SpecialClass.
  1266. //..................................................................
  1267. case ( BUTTON_PARAMS | KN_BUTTON ):
  1268. bRetractHouseDropDown = true;
  1269. if (Special.IsCaptureTheFlag != pCheckListOptions->Is_Checked(3) && !Special.IsCaptureTheFlag) {
  1270. pCheckListOptions->Check_Item(0, true);
  1271. }
  1272. if (Session.Options.Bases != pCheckListOptions->Is_Checked(0)) {
  1273. Session.Options.Bases = pCheckListOptions->Is_Checked(0);
  1274. if (Session.Options.Bases) {
  1275. Session.Options.UnitCount = Fixed_To_Cardinal (
  1276. SessionClass::CountMax[1] -
  1277. SessionClass::CountMin[1],
  1278. Cardinal_To_Fixed(
  1279. SessionClass::CountMax[0]-SessionClass::CountMin[0],
  1280. Session.Options.UnitCount-SessionClass::CountMin[0])) +
  1281. SessionClass::CountMin[1];
  1282. } else {
  1283. pCheckListOptions->Check_Item(3, false);
  1284. Session.Options.UnitCount = Fixed_To_Cardinal (
  1285. SessionClass::CountMax[0] -
  1286. SessionClass::CountMin[0],
  1287. Cardinal_To_Fixed(
  1288. SessionClass::CountMax[1]-SessionClass::CountMin[1],
  1289. Session.Options.UnitCount - SessionClass::CountMin[1])) +
  1290. SessionClass::CountMin[0];
  1291. }
  1292. pGaugeCount->Set_Maximum(
  1293. SessionClass::CountMax[Session.Options.Bases] -
  1294. SessionClass::CountMin[Session.Options.Bases]);
  1295. pGaugeCount->Set_Value(Session.Options.UnitCount -
  1296. SessionClass::CountMin[Session.Options.Bases]);
  1297. }
  1298. Session.Options.Tiberium = pCheckListOptions->Is_Checked(1);
  1299. Special.IsTGrowth = Session.Options.Tiberium; // Ugh. Use of "Special" global.
  1300. Rule.IsTGrowth = Session.Options.Tiberium;
  1301. Special.IsTSpread = Session.Options.Tiberium; // Ugh. Use of "Special" global.
  1302. Rule.IsTSpread = Session.Options.Tiberium;
  1303. Session.Options.Goodies = pCheckListOptions->Is_Checked(2);
  1304. Special.IsCaptureTheFlag = pCheckListOptions->Is_Checked(3); // Ugh. Use of "Special" global.
  1305. Special.IsShadowGrow = pCheckListOptions->Is_Checked(4); // Ugh. Use of "Special" global.
  1306. bSlowUnitBuildRate = pCheckListOptions->Is_Checked(5);
  1307. bInformParamChange = true;
  1308. if (display < REDRAW_PARMS) display = REDRAW_PARMS;
  1309. Sound_Effect(VOC_OPTIONS_CHANGED);
  1310. break;
  1311. case ( BUTTON_ACCEPTSTART | KN_BUTTON ): // 'Accept' or 'Start Game' button.
  1312. if( !bHost )
  1313. {
  1314. // Guest wishes to accept game params.
  1315. User* pUserHost = pWO->pGameHost();
  1316. if( pUserHost ) // Else it's too early to even be thinking about accepting, anyway.
  1317. {
  1318. // Set ourself as accepted. We want to do this immediately so the user has feedback for pressing button.
  1319. // Besides, the host is guaranteed to allow this and set us to "accepted", unless it is simultaneously
  1320. // sending us a new update we haven't received yet. If this is the case, we will get that update in a
  1321. // second and will set ourselves to unaccepted, which will match the unaccepted state on the server.
  1322. // Upshot - We can ignore messages from the server telling us that we, ourself, accepted.
  1323. if( pToolTipHitLast && pToolTipHitLast->bShowing )
  1324. pToolTipHitLast->Unshow();
  1325. pTextBtnAcceptStart->Disable();
  1326. if( SetPlayerAccepted( pWO->szMyName, true ) ) // Else we didn't find ourself in list!
  1327. {
  1328. // debugprint( "Sending accept.\n" );
  1329. // Tell host we accept.
  1330. char szSend[ 20 ];
  1331. sprintf( szSend, "%02u %06u", WOL_GAMEOPT_REQACCEPT, nGuestLastParamID );
  1332. pWO->SendGameOpt( szSend, pUserHost );
  1333. }
  1334. }
  1335. }
  1336. else
  1337. {
  1338. // Host says start the game.
  1339. // If we have changes just made and not yet sent, don't say start, because we're about to send changes
  1340. // that will unaccept everyone.
  1341. if( !bParamsUnfresh() )
  1342. {
  1343. // Force user to put the correct disk in before proceeding. (Not crucial, but can lead to ugly
  1344. // timeouts if the scenario has to be downloaded before game start.)
  1345. if( !Session.Scenarios[ Session.Options.ScenarioIndex ]->Get_Official() ||
  1346. Force_Scenario_Available( Session.Scenarios[ Session.Options.ScenarioIndex ]->Get_Filename() ) )
  1347. {
  1348. // Go into "waiting to start" mode, tell guests to, and wait for responses.
  1349. bWaitingToStart = true;
  1350. timeWaitingToStartTimeout = ::timeGetTime() + 30000;
  1351. nHostLastParamID++;
  1352. InformAboutStart();
  1353. WWMessageBox().Process( TXT_WOL_WAITINGTOSTART, TXT_NONE );
  1354. BindControls( false );
  1355. SetPlayerReadyToGo( pWO->szMyName, "ready" );
  1356. Sound_Effect( VOC_GAME_CLOSED );
  1357. }
  1358. }
  1359. }
  1360. break;
  1361. case ( BUTTON_SCENARIO_RA | KN_BUTTON ):
  1362. ScenarioDisplayMode( SCENARIO_RA );
  1363. break;
  1364. case ( BUTTON_SCENARIO_CS | KN_BUTTON ):
  1365. ScenarioDisplayMode( SCENARIO_CS );
  1366. break;
  1367. case ( BUTTON_SCENARIO_AM | KN_BUTTON ):
  1368. ScenarioDisplayMode( SCENARIO_AM );
  1369. break;
  1370. case ( BUTTON_SCENARIO_USER | KN_BUTTON ):
  1371. ScenarioDisplayMode( SCENARIO_USER );
  1372. break;
  1373. // case (BUTTON_LOAD | KN_BUTTON):
  1374. // case (BUTTON_OK | KN_BUTTON):
  1375. // break;
  1376. case (KN_ESC):
  1377. if( pDropListHouse->IsDropped )
  1378. bRetractHouseDropDown = true;
  1379. break;
  1380. case ( BUTTON_LEAVE | KN_BUTTON ):
  1381. case ( BUTTON_CANCEL | KN_BUTTON ):
  1382. if( ExitGameChannel() )
  1383. {
  1384. pWO->RejoinLobbyAfterGame();
  1385. bProcess = false;
  1386. ResultReturn = RESULT_WOLGSUP_BACKTOCHAT; // Return to chat.
  1387. }
  1388. else
  1389. {
  1390. bProcess = false;
  1391. ResultReturn = RESULT_WOLGSUP_FATALERROR; // Return with an error value.
  1392. }
  1393. break;
  1394. }
  1395. Call_Back();
  1396. }
  1397. if( pToolTipHitLast && pToolTipHitLast->bShowing )
  1398. pToolTipHitLast->Unshow();
  1399. pWO->ClearListPtrs();
  1400. pWO->pGSupDlg = NULL;
  1401. return ResultReturn;
  1402. }
  1403. //***********************************************************************************************
  1404. void WOL_GameSetupDialog::SetSpecialControlStates()
  1405. {
  1406. // Set gauges and checklist.
  1407. pCheckListOptions->Check_Item(0, Session.Options.Bases);
  1408. pCheckListOptions->Check_Item(1, Session.Options.Tiberium);
  1409. pCheckListOptions->Check_Item(2, Session.Options.Goodies);
  1410. pCheckListOptions->Check_Item(3, Special.IsCaptureTheFlag); // Ugh. Use of "Special" global.
  1411. pCheckListOptions->Check_Item(4, Special.IsShadowGrow); // Ugh. Use of "Special" global.
  1412. pCheckListOptions->Check_Item(5, bSlowUnitBuildRate); // Ugh. Use of "Special" global.
  1413. pGaugeCount->Set_Maximum(SessionClass::CountMax[Session.Options.Bases] - SessionClass::CountMin[Session.Options.Bases]);
  1414. pGaugeCount->Set_Value(Session.Options.UnitCount - SessionClass::CountMin[Session.Options.Bases]);
  1415. pGaugeLevel->Set_Maximum(MPLAYER_BUILD_LEVEL_MAX - 1);
  1416. pGaugeLevel->Set_Value(BuildLevel - 1);
  1417. pGaugeCredits->Set_Maximum(Rule.MPMaxMoney);
  1418. pGaugeCredits->Set_Value(Session.Options.Credits);
  1419. if( pWO->GameInfoCurrent.bTournament )
  1420. {
  1421. pGaugeAIPlayers->Set_Maximum( 0 );
  1422. }
  1423. else
  1424. {
  1425. // Note dependency of AIPlayers on number of human players.
  1426. // pGaugeAIPlayers->Set_Maximum(Rule.MaxPlayers-Session.Players.Count());
  1427. pGaugeAIPlayers->Set_Maximum( Rule.MaxPlayers - pWO->GameInfoCurrent.iPlayerMax );
  1428. }
  1429. pGaugeAIPlayers->Set_Value(Session.Options.AIPlayers);
  1430. if( bAftermathUnits )
  1431. pCheckAftermathUnits->Turn_On();
  1432. else
  1433. pCheckAftermathUnits->Turn_Off();
  1434. }
  1435. #define DRAWTABDOWN Turn_On()
  1436. #define DRAWTABUP Turn_Off()
  1437. //***********************************************************************************************
  1438. void WOL_GameSetupDialog::BindControls( bool bBind )
  1439. {
  1440. if( bBind )
  1441. {
  1442. commands = pWO->pShpBtnDiscon;
  1443. pWO->pShpBtnLeave->Add_Tail(*commands);
  1444. pWO->pShpBtnRefresh->Add_Tail(*commands);
  1445. pWO->pShpBtnSquelch->Add_Tail(*commands);
  1446. pWO->pShpBtnBan->Add_Tail(*commands);
  1447. pWO->pShpBtnKick->Add_Tail(*commands);
  1448. pWO->pShpBtnFindpage->Add_Tail(*commands);
  1449. pWO->pShpBtnOptions->Add_Tail(*commands);
  1450. pWO->pShpBtnLadder->Add_Tail(*commands);
  1451. pWO->pShpBtnHelp->Add_Tail(*commands);
  1452. pILPlayers->Add_Tail(*commands);
  1453. if( bHost )
  1454. {
  1455. // Draw order of tabs depends on which one is selected, as we want them to overlap appropriately.
  1456. // Also, the selected tab must appear over the scenario list, while the unselected tabs are below it.
  1457. // This assures that that bottom of the tab overlaps the scenario list border, making it look connected.
  1458. // ajw I could make all maps always available now that they're downloadable. Playing CS map with AM rules
  1459. // would mean switching CDs, though.
  1460. // Would mean no difference between RA and CS games.
  1461. switch( ScenKindCurrent )
  1462. {
  1463. case SCENARIO_RA:
  1464. if( !pWO->GameInfoCurrent.bTournament )
  1465. {
  1466. pShpBtnScenarioUser->Add_Tail(*commands);
  1467. pShpBtnScenarioUser->DRAWTABDOWN;
  1468. }
  1469. if( pWO->GameInfoCurrent.GameKind == CREATEGAMEINFO::CSGAME )
  1470. {
  1471. pShpBtnScenarioCS->Add_Tail(*commands);
  1472. pShpBtnScenarioCS->DRAWTABDOWN;
  1473. }
  1474. else if( pWO->GameInfoCurrent.GameKind == CREATEGAMEINFO::AMGAME ||
  1475. ( pWO->GameInfoCurrent.GameKind == CREATEGAMEINFO::RAGAME && Is_Aftermath_Installed() && !pWO->GameInfoCurrent.bTournament ) )
  1476. {
  1477. pShpBtnScenarioAM->Add_Tail(*commands);
  1478. pShpBtnScenarioAM->DRAWTABDOWN;
  1479. }
  1480. pILScens->Add_Tail(*commands);
  1481. pShpBtnScenarioRA->Add_Tail(*commands);
  1482. pShpBtnScenarioRA->DRAWTABUP;
  1483. break;
  1484. case SCENARIO_CS: // pWO->GameInfoCurrent.GameKind must be CREATEGAMEINFO::CSGAME.
  1485. if( !pWO->GameInfoCurrent.bTournament )
  1486. {
  1487. pShpBtnScenarioUser->Add_Tail(*commands);
  1488. pShpBtnScenarioUser->DRAWTABDOWN;
  1489. }
  1490. pShpBtnScenarioRA->Add_Tail(*commands);
  1491. pShpBtnScenarioRA->DRAWTABDOWN;
  1492. pILScens->Add_Tail(*commands);
  1493. pShpBtnScenarioCS->Add_Tail(*commands);
  1494. pShpBtnScenarioCS->DRAWTABUP;
  1495. break;
  1496. case SCENARIO_AM: // pWO->GameInfoCurrent.GameKind must be CREATEGAMEINFO::AMGAME, or RAGAME with AM installed.
  1497. if( !pWO->GameInfoCurrent.bTournament )
  1498. {
  1499. pShpBtnScenarioUser->Add_Tail(*commands);
  1500. pShpBtnScenarioUser->DRAWTABDOWN;
  1501. }
  1502. pShpBtnScenarioRA->Add_Tail(*commands);
  1503. pShpBtnScenarioRA->DRAWTABDOWN;
  1504. pILScens->Add_Tail(*commands);
  1505. pShpBtnScenarioAM->Add_Tail(*commands);
  1506. pShpBtnScenarioAM->DRAWTABUP;
  1507. break;
  1508. case SCENARIO_USER: // pWO->GameInfoCurrent.bTournament must be false.
  1509. pShpBtnScenarioRA->Add_Tail(*commands);
  1510. pShpBtnScenarioRA->DRAWTABDOWN;
  1511. if( pWO->GameInfoCurrent.GameKind == CREATEGAMEINFO::CSGAME )
  1512. {
  1513. pShpBtnScenarioCS->Add_Tail(*commands);
  1514. pShpBtnScenarioCS->DRAWTABDOWN;
  1515. }
  1516. else if( pWO->GameInfoCurrent.GameKind == CREATEGAMEINFO::AMGAME ||
  1517. ( pWO->GameInfoCurrent.GameKind == CREATEGAMEINFO::RAGAME && Is_Aftermath_Installed() && !pWO->GameInfoCurrent.bTournament ) )
  1518. {
  1519. pShpBtnScenarioAM->Add_Tail(*commands);
  1520. pShpBtnScenarioAM->DRAWTABDOWN;
  1521. }
  1522. pILScens->Add_Tail(*commands);
  1523. pShpBtnScenarioUser->Add_Tail(*commands);
  1524. pShpBtnScenarioUser->DRAWTABUP;
  1525. break;
  1526. }
  1527. }
  1528. // pStaticDescrip->Add_Tail(*commands);
  1529. pEditSend->Add_Tail(*commands);
  1530. pStaticUnit->Add_Tail(*commands);
  1531. pStaticLevel->Add_Tail(*commands);
  1532. pStaticCredits->Add_Tail(*commands);
  1533. pStaticAIPlayers->Add_Tail(*commands);
  1534. pGaugeCount->Add_Tail(*commands);
  1535. pGaugeCredits->Add_Tail(*commands);
  1536. pGaugeAIPlayers->Add_Tail(*commands);
  1537. pGaugeLevel->Add_Tail(*commands);
  1538. pCheckListOptions->Add_Tail(*commands);
  1539. pTextBtnCancel->Add_Tail(*commands);
  1540. pTextBtnAcceptStart->Add_Tail(*commands);
  1541. pTextBtnAction->Add_Tail(*commands);
  1542. pILDisc->Add_Tail(*commands);
  1543. pDropListHouse->Add_Tail(*commands);
  1544. // pCheckAftermathUnits->Add_Tail(*commands);
  1545. }
  1546. else
  1547. {
  1548. pWO->pShpBtnDiscon->Zap();
  1549. pWO->pShpBtnLeave->Zap();
  1550. pWO->pShpBtnRefresh->Zap();
  1551. pWO->pShpBtnSquelch->Zap();
  1552. pWO->pShpBtnBan->Zap();
  1553. pWO->pShpBtnKick->Zap();
  1554. pWO->pShpBtnFindpage->Zap();
  1555. pWO->pShpBtnOptions->Zap();
  1556. pWO->pShpBtnLadder->Zap();
  1557. pWO->pShpBtnHelp->Zap();
  1558. pILPlayers->Zap();
  1559. if( bHost )
  1560. {
  1561. pShpBtnScenarioRA->Zap();
  1562. if( !pWO->GameInfoCurrent.bTournament )
  1563. {
  1564. pShpBtnScenarioUser->Zap();
  1565. }
  1566. if( pWO->GameInfoCurrent.GameKind == CREATEGAMEINFO::CSGAME )
  1567. pShpBtnScenarioCS->Zap();
  1568. else if( pWO->GameInfoCurrent.GameKind == CREATEGAMEINFO::AMGAME ||
  1569. ( pWO->GameInfoCurrent.GameKind == CREATEGAMEINFO::RAGAME && Is_Aftermath_Installed() && !pWO->GameInfoCurrent.bTournament ) )
  1570. pShpBtnScenarioAM->Zap();
  1571. pILScens->Zap();
  1572. }
  1573. // pStaticDescrip->Zap();
  1574. pEditSend->Zap();
  1575. pStaticUnit->Zap();
  1576. pStaticLevel->Zap();
  1577. pStaticCredits->Zap();
  1578. pStaticAIPlayers->Zap();
  1579. pGaugeCount->Zap();
  1580. pGaugeCredits->Zap();
  1581. pGaugeAIPlayers->Zap();
  1582. pGaugeLevel->Zap();
  1583. pCheckListOptions->Zap();
  1584. pTextBtnCancel->Zap();
  1585. pTextBtnAcceptStart->Zap();
  1586. pTextBtnAction->Zap();
  1587. pILDisc->Zap();
  1588. pDropListHouse->Zap();
  1589. // pCheckAftermathUnits->Zap();
  1590. }
  1591. }
  1592. //***********************************************************************************************
  1593. void WOL_GameSetupDialog::ScenarioDisplayMode( SCENARIO_GAMEKIND ScenKind )
  1594. {
  1595. // debugprint( "ScenarioDisplayMode, from %i going into %i mode.\n", ScenKindCurrent, ScenKind );
  1596. // Puts us into mode where we are viewing a particular gamekind of scenario list.
  1597. if( ScenKindCurrent == ScenKind )
  1598. return;
  1599. // Reorder tab buttons.
  1600. BindControls( false );
  1601. ScenKindCurrent = ScenKind;
  1602. BindControls( true );
  1603. // Reset list items.
  1604. pILScens->Clear();
  1605. // debugprint( " * * * * * * ScenKind %i has %i items.\n", ScenKind, ar_szScenarios[ ScenKind ].Count() );
  1606. // Check for the currently selected scenario.
  1607. bool bFoundCurrentSelection = false;
  1608. int iSelect;
  1609. for( int i = 0; i != ar_szScenarios[ ScenKind ].Count(); i++ )
  1610. {
  1611. // Put ScenarioIndex in as extradata to list item.
  1612. int iScenIndex = (int)ar_szScenIndexes[ ScenKind ][ i ];
  1613. int iIndexNew = pILScens->Add_Item( ar_szScenarios[ ScenKind ][ i ], NULL, NULL, ICON_DIB, NULL, (void*)iScenIndex );
  1614. if( iScenIndex == Session.Options.ScenarioIndex && !bFoundCurrentSelection )
  1615. {
  1616. // (Choose first line of what can be multiline description of currently selected scenario.)
  1617. bFoundCurrentSelection = true;
  1618. iSelect = i;
  1619. }
  1620. }
  1621. // If the current scenario selection is in this list, enable the list to show the selection, otherwise,
  1622. // make the listclass selection invisible, because it doesn't indicate the real scenario selection.
  1623. // Basically, problem is that I can't have no selection in ListClass, and I don't want to risk changing
  1624. // it as I'll affect the rest of the code. So I do this horrible hack.
  1625. if( bFoundCurrentSelection )
  1626. {
  1627. pILScens->SetSelectType( 1 ); // Regular selection.
  1628. pILScens->Set_Selected_Index( iSelect );
  1629. }
  1630. else
  1631. pILScens->SetSelectType( 0 ); // Invisible selection.
  1632. // display = REDRAW_ALL;
  1633. pILScens->Flag_To_Redraw();
  1634. pShpBtnScenarioRA->Flag_To_Redraw();
  1635. pShpBtnScenarioCS->Flag_To_Redraw();
  1636. pShpBtnScenarioAM->Flag_To_Redraw();
  1637. pShpBtnScenarioUser->Flag_To_Redraw();
  1638. }
  1639. //***********************************************************************************************
  1640. bool WOL_GameSetupDialog::ExitGameChannel()
  1641. {
  1642. // debugprint( "ExitGameChannel \n" );
  1643. if( pDropListHouse->IsDropped )
  1644. {
  1645. pDropListHouse->Collapse();
  1646. if (display < REDRAW_BACKGROUND) display = REDRAW_BACKGROUND;
  1647. }
  1648. if( !pWO->ChannelLeave() )
  1649. {
  1650. pWO->GenericErrorMessage();
  1651. return false;
  1652. }
  1653. pWO->OnExitingGameChannel();
  1654. return true;
  1655. }
  1656. //***********************************************************************************************
  1657. void WOL_GameSetupDialog::DrawScenarioDescripIcon( const char* pDIB ) const
  1658. {
  1659. CC_Draw_DIB( pDIB, d_gamekind_x - 16, d_gamekind_y - 2, 100, WINDOW_MAIN );
  1660. }
  1661. //***********************************************************************************************
  1662. void WOL_GameSetupDialog::SetPlayerColor( const char* szName, PlayerColorType Color )
  1663. {
  1664. // Sets player color - does not verify if it is "okay" to do so.
  1665. // debugprint( "SetPlayerColor %s to %i\n", szName, Color );
  1666. int iItem = pILPlayers->Find( szName );
  1667. if( iItem == -1 )
  1668. {
  1669. // Player name was not found in list.
  1670. // This can happen when player color Informs arrive from the host before I have gotten a userlist.
  1671. // Insert an entry for user - color will be maintained when the userlist arrives.
  1672. // "early insertion"
  1673. // debugprint( "SetPlayerColor could not find name '%s'! Inserting...\n", szName );
  1674. iItem = pILPlayers->Add_Item( szName );
  1675. }
  1676. if( strcmp( pWO->szMyName, szName ) == 0 )
  1677. {
  1678. // I am the player involved.
  1679. Session.ColorIdx = Color;
  1680. if( display < REDRAW_COLORS ) display = REDRAW_COLORS;
  1681. }
  1682. pILPlayers->Set_Item_Color( iItem, &ColorRemaps[ Color == PCOLOR_DIALOG_BLUE ? PCOLOR_REALLY_BLUE : Color ] );
  1683. pILPlayers->Flag_To_Redraw();
  1684. }
  1685. //***********************************************************************************************
  1686. PlayerColorType WOL_GameSetupDialog::GetPlayerColor( const char* szName )
  1687. {
  1688. // Returns player color, if player is found in list, else PCOLOR_NONE.
  1689. int iItem = pILPlayers->Find( szName );
  1690. if( iItem == -1 )
  1691. {
  1692. // Player name was not found in list.
  1693. return PCOLOR_NONE;
  1694. }
  1695. RemapControlType* pRemap = pILPlayers->Get_Item_Color( iItem );
  1696. return PlayerColorTypeOf( pRemap );
  1697. }
  1698. //***********************************************************************************************
  1699. void WOL_GameSetupDialog::SetPlayerHouse( const char* szName, HousesType House )
  1700. {
  1701. // Sets player house - does not verify if it is "okay" to do so.
  1702. // debugprint( "SetPlayerHouse %s to %i\n", szName, House );
  1703. int iItem = pILPlayers->Find( szName );
  1704. if( iItem == -1 )
  1705. {
  1706. // Player name was not found in list.
  1707. // This can happen when player house Informs arrive from the host before I have gotten a userlist.
  1708. // Insert an entry for user - house will be maintained when the userlist arrives.
  1709. // "early insertion"
  1710. // debugprint( "SetPlayerHouse could not find name '%s'! Inserting...\n", szName );
  1711. iItem = pILPlayers->Add_Item( szName );
  1712. }
  1713. // Reset item text.
  1714. char szItem[ 100 ];
  1715. pWO->WritePlayerListItem( szItem, szName, House );
  1716. // debugprint ( "%i, %s\n", iItem, szItem );
  1717. pILPlayers->Set_Item( iItem, szItem );
  1718. pILPlayers->Flag_To_Redraw();
  1719. }
  1720. //***********************************************************************************************
  1721. HousesType WOL_GameSetupDialog::GetPlayerHouse( const char* szName )
  1722. {
  1723. // Returns player house for user if found in list, else HOUSE_NONE.
  1724. int iItem = pILPlayers->Find( szName );
  1725. if( iItem == -1 )
  1726. {
  1727. // Player name was not found in list.
  1728. return HOUSE_NONE;
  1729. }
  1730. return pWO->PullPlayerHouse_From( pILPlayers->Get_Item( iItem ) );
  1731. }
  1732. //***********************************************************************************************
  1733. bool WOL_GameSetupDialog::SetPlayerAccepted( const char* szName, bool bAccepted )
  1734. {
  1735. // Sets player's 'accepted' state to true or false.
  1736. // Value is stored in the player list: if there is an accepted icon, player has accepted.
  1737. int iItem = pILPlayers->Find( szName );
  1738. if( iItem == -1 )
  1739. {
  1740. // Player name was not found in list.
  1741. // debugprint( "SetPlayerAccepted() - could not find '%s'.\n", szName );
  1742. return false;
  1743. }
  1744. // debugprint( "SetPlayerAccepted() - set '%s' to %s.\n", szName, bAccepted ? "accepted" : "NOT accepted" );
  1745. return pWO->MarkItemAccepted( iItem, bAccepted );
  1746. }
  1747. //***********************************************************************************************
  1748. bool WOL_GameSetupDialog::IveAccepted()
  1749. {
  1750. // Returns true if I am marked as "accepted".
  1751. int iItem = pILPlayers->Find( pWO->szMyName );
  1752. if( iItem == -1 )
  1753. return false;
  1754. return pWO->bItemMarkedAccepted( iItem );
  1755. }
  1756. //***********************************************************************************************
  1757. bool WOL_GameSetupDialog::SetPlayerReadyToGo( const char* szName, const char* szReadyState )
  1758. {
  1759. // Sets player's 'ready to go' state.
  1760. // Set szReadyState to "ready", "need scenario", or NULL.
  1761. // First two cases are regarded as player being ready to go.
  1762. // Value is stored in the player list in the hidden string field.
  1763. int iItem = pILPlayers->Find( szName );
  1764. if( iItem == -1 )
  1765. {
  1766. // Player name was not found in list.
  1767. // debugprint( "SetPlayerReadyToGo() - could not find '%s'.\n", szName );
  1768. return false;
  1769. }
  1770. // debugprint( "SetPlayerReadyToGo() - set '%s' to %s.\n", szName, szReadyState );
  1771. pWO->MarkItemReadyToGo( iItem, szReadyState );
  1772. return true;
  1773. }
  1774. //***********************************************************************************************
  1775. void WOL_GameSetupDialog::ResetReadyToGo()
  1776. {
  1777. // Resets all users to "not ready to go".
  1778. for( int i = 0; i < pILPlayers->Count(); i++ )
  1779. {
  1780. pWO->MarkItemReadyToGo( i, NULL );
  1781. }
  1782. }
  1783. //***********************************************************************************************
  1784. bool WOL_GameSetupDialog::bPlayerReadyToGo( const char* szName )
  1785. {
  1786. // Returns true if player is marked as "ready to go".
  1787. int iItem = pILPlayers->Find( szName );
  1788. if( iItem == -1 )
  1789. return false;
  1790. return pWO->bItemMarkedReadyToGo( iItem );
  1791. }
  1792. //***********************************************************************************************
  1793. bool WOL_GameSetupDialog::bAllPlayersReadyToGo()
  1794. {
  1795. // Returns true if all players are marked as "ready to go".
  1796. // debugprint( "Checking for all players ready - there are %i\n", pILPlayers->Count() );
  1797. for( int i = 0; i < pILPlayers->Count(); i++ )
  1798. {
  1799. if( !pWO->bItemMarkedReadyToGo( i ) )
  1800. {
  1801. // debugprint( "Item %i NOT ready\n", i );
  1802. return false;
  1803. }
  1804. // debugprint( "Item %i is ready\n", i );
  1805. }
  1806. // debugprint( "Return true\n" );
  1807. return true;
  1808. }
  1809. //***********************************************************************************************
  1810. void WOL_GameSetupDialog::ProcessGuestRequest( User* pUser, const char* szRequest )
  1811. {
  1812. // Game host processes a request that arrived as a privategameopt from one of the guests.
  1813. // WOL_GAMEOPT_REQCOLOR format:
  1814. // 2 WOL_GAMEOPT
  1815. // 1 space
  1816. // 2 color
  1817. // 1 null-terminator
  1818. // debugprint( "ProcessGuestRequest. szRequest is '%s', len %i.\n", szRequest, strlen( szRequest ) );
  1819. WOL_GAMEOPT opt = (WOL_GAMEOPT)atoi( szRequest );
  1820. szRequest += 3;
  1821. switch( opt )
  1822. {
  1823. case WOL_GAMEOPT_REQCOLOR:
  1824. {
  1825. PlayerColorType ColorDesired = (PlayerColorType)( atoi( szRequest ) );
  1826. if( pILPlayers->FindColor( &ColorRemaps[ ColorDesired == PCOLOR_DIALOG_BLUE ? PCOLOR_REALLY_BLUE : ColorDesired ] ) == -1 )
  1827. {
  1828. // Color is available.
  1829. SetPlayerColor( (char*)pUser->name, ColorDesired );
  1830. // Tell all guests about the color change.
  1831. InformAboutPlayerColor( (char*)pUser->name, ColorDesired, NULL );
  1832. }
  1833. else
  1834. {
  1835. // Color is not available.
  1836. // debugprint( "Color %i denied to %s\n", ColorDesired, (char*)pUser->name );
  1837. // Tell requestor that his color is still the same.
  1838. RemapControlType* pColorRemapCurrent = pILPlayers->Get_Item_Color( pILPlayers->Find( (char*)pUser->name ) );
  1839. InformAboutPlayerColor( (char*)pUser->name, PlayerColorTypeOf( pColorRemapCurrent ), pUser );
  1840. }
  1841. break;
  1842. }
  1843. case WOL_GAMEOPT_REQHOUSE:
  1844. {
  1845. HousesType HouseChoice = (HousesType)( atoi( szRequest ) );
  1846. // debugprint( "Host received: '%s' changed house to %u.\n", (char*)pUser->name, HouseChoice );
  1847. SetPlayerHouse( (char*)pUser->name, HouseChoice );
  1848. nHostLastParamID++;
  1849. InformAboutPlayerHouse( (char*)pUser->name, HouseChoice, NULL );
  1850. ClearAllAccepts();
  1851. break;
  1852. }
  1853. case WOL_GAMEOPT_REQACCEPT:
  1854. // Does Param ID of accept request match the last param change ID sent? See notes at top.
  1855. if( atoi( szRequest ) == nHostLastParamID )
  1856. {
  1857. // debugprint( "Host received valid accept from '%s'.\n", (char*)pUser->name );
  1858. SetPlayerAccepted( (char*)pUser->name, true );
  1859. InformAboutPlayerAccept( (char*)pUser->name, NULL );
  1860. // We may be ready to start a game now.
  1861. if( bAllGuestsAccept() )
  1862. {
  1863. if( pToolTipHitLast && pToolTipHitLast->bShowing )
  1864. pToolTipHitLast->Unshow();
  1865. pTextBtnAcceptStart->Enable();
  1866. }
  1867. }
  1868. else
  1869. {
  1870. // debugprint( "______________Host received invalid accept from '%s'. ID = %i when it should be %i.\n", (char*)pUser->name,
  1871. // atoi( szRequest ), nHostLastParamID );
  1872. }
  1873. break;
  1874. case WOL_GAMEOPT_REQSTART:
  1875. // Does Param ID of accept request match the last param change ID sent? See notes at top.
  1876. if( atoi( szRequest ) == nHostLastParamID ) // Otherwise ignore - it's old and we don't care. (Incredibly unlikely to happen, actually.)
  1877. {
  1878. // debugprint( "Host received valid WOL_GAMEOPT_REQSTART from '%s'.\n", (char*)pUser->name );
  1879. // WOL_PrintMessage( *pILDisc, "WOL_GAMEOPT_REQSTART response", WOLCOLORREMAP_LOCALMACHINEMESS );
  1880. // WOL_PrintMessage( *pILDisc, (char*)pUser->name, WOLCOLORREMAP_LOCALMACHINEMESS );
  1881. if( bWaitingToStart )
  1882. // If all responses are in, start the game!
  1883. GuestIsReadyToPlay( (char*)pUser->name, "ready" );
  1884. // else
  1885. // debugprint( "Ignoring - I am no longer waiting to start a game.\n" );
  1886. }
  1887. break;
  1888. case WOL_GAMEOPT_REQSTART_BUTNEEDSCENARIO:
  1889. // Does Param ID of accept request match the last param change ID sent? See notes at top.
  1890. if( atoi( szRequest ) == nHostLastParamID ) // Otherwise ignore - it's old and we don't care. (Incredibly unlikely to happen, actually.)
  1891. {
  1892. // debugprint( "Host received valid WOL_GAMEOPT_REQSTART_BUTNEEDSCENARIO from '%s'.\n", (char*)pUser->name );
  1893. if( bWaitingToStart )
  1894. // If all responses are in, start the game!
  1895. GuestIsReadyToPlay( (char*)pUser->name, "need scenario" );
  1896. // else
  1897. // debugprint( "Ignoring - I am no longer waiting to start a game.\n" );
  1898. }
  1899. break;
  1900. case WOL_GAMEOPT_INFGO:
  1901. // I have told myself to start game right now.
  1902. // This is the new method. Avoids apparent "private messages/gameopts are getting delayed" problem in chatserver...
  1903. // (I don't want to end up leaving the channel before guests get my go message.)
  1904. strcpy( szTriggerGameStartInfo, szRequest );
  1905. break;
  1906. default:
  1907. // debugprint( "Unhandled value of %i in ProcessGuestRequest!!!\n", opt );
  1908. break;
  1909. }
  1910. }
  1911. //***********************************************************************************************
  1912. void WOL_GameSetupDialog::ProcessInform( char* szInform )
  1913. {
  1914. // Process inform message arriving from game host.
  1915. // debugprint( "ProcessInform: '%s'\n", szInform );
  1916. if( !bHost )
  1917. {
  1918. WOL_GAMEOPT opt = (WOL_GAMEOPT)atoi( szInform );
  1919. szInform += 3;
  1920. switch( opt )
  1921. {
  1922. case WOL_GAMEOPT_INFCOLOR:
  1923. {
  1924. // WOL_GAMEOPT_INFCOLOR format:
  1925. // 2 WOL_GAMEOPT
  1926. // 1 space
  1927. // 2 color
  1928. // 1 space
  1929. // string name of player
  1930. PlayerColorType Color = (PlayerColorType)( atoi( szInform ) );
  1931. szInform += 3;
  1932. SetPlayerColor( szInform, Color ); // (szInform is now sitting at the start of the name string.)
  1933. Sound_Effect(VOC_OPTIONS_CHANGED);
  1934. break;
  1935. }
  1936. case WOL_GAMEOPT_INFHOUSE: // Note: In theory, I could ignore this if it refers to me. I've already set my own house.
  1937. {
  1938. nGuestLastParamID = atoi( szInform );
  1939. szInform += 7;
  1940. HousesType House = (HousesType)( atoi( szInform ) );
  1941. szInform += 3;
  1942. SetPlayerHouse( szInform, House ); // (szInform is now sitting at the start of the name string.)
  1943. ClearAllAccepts();
  1944. Sound_Effect(VOC_OPTIONS_CHANGED);
  1945. break;
  1946. }
  1947. case WOL_GAMEOPT_INFACCEPT: // Note: In theory, I could ignore this if it refers to me.
  1948. // A guest has accepted.
  1949. SetPlayerAccepted( szInform, true ); // (szInform is now sitting at the start of the name string.)
  1950. break;
  1951. case WOL_GAMEOPT_INFPARAMS:
  1952. // Game params have changed.
  1953. bParamsReceived = true;
  1954. if( !AcceptParams( szInform ) )
  1955. bLeaveDueToRulesMismatchTrigger = true;
  1956. SetSpecialControlStates();
  1957. //pILScens->Set_Selected_Index( Session.Options.ScenarioIndex );
  1958. display = REDRAW_ALL;
  1959. ClearAllAccepts();
  1960. Sound_Effect(VOC_OPTIONS_CHANGED);
  1961. break;
  1962. case WOL_GAMEOPT_INFNEWGUESTPLAYERINFO:
  1963. // I have just joined and have received a message with info on all players in game.
  1964. AcceptNewGuestPlayerInfo( szInform );
  1965. Sound_Effect(VOC_OPTIONS_CHANGED);
  1966. break;
  1967. case WOL_GAMEOPT_INFSTART:
  1968. {
  1969. // Host tells us to wait for start of game.
  1970. // debugprint( "Guest received WOL_GAMEOPT_INFSTART.\n" );
  1971. nGuestLastParamID = atoi( szInform );
  1972. // The following check is not necessary. Rules.ini, if manually replaced by a cheater, is not reloaded.
  1973. // So prior checks (that occur on game params receives) are sufficient.
  1974. // szInform += 7;
  1975. // // Check rules.ini compatibility.
  1976. // int iRulesID = atoi( szInform );
  1977. // if( RuleINI.Get_Unique_ID() != iRulesID )
  1978. // {
  1979. // // Rules.ini incompatible. Don't respond to call for start.
  1980. // bLeaveDueToRulesMismatchTrigger = true;
  1981. // break;
  1982. // }
  1983. User* pUserHost = pWO->pGameHost();
  1984. if( pUserHost ) // This better'd be true.
  1985. {
  1986. // Send ack back to host.
  1987. char szSend[ 20 ];
  1988. // Make sure we have the scenario.
  1989. if( !bNeedScenarioDownload() )
  1990. sprintf( szSend, "%02u %06u", WOL_GAMEOPT_REQSTART, nGuestLastParamID );
  1991. else
  1992. sprintf( szSend, "%02u %06u", WOL_GAMEOPT_REQSTART_BUTNEEDSCENARIO, nGuestLastParamID );
  1993. pWO->SendGameOpt( szSend, pUserHost );
  1994. // Enter waiting mode.
  1995. bWaitingToStart = true;
  1996. WWMessageBox().Process( TXT_WOL_WAITINGTOSTART, TXT_NONE );
  1997. BindControls( false );
  1998. // If we are in a modal dialog, we must have arrived here through Call_Back()'s PumpMessages.
  1999. // Set global that will force edit dialogs to stop accepting characters.
  2000. // This is to fix a minor glitch: guests can keep typing into a "page" dialog editbox after the
  2001. // "Launching game..." message has appeared on top of it.
  2002. if( pWO->bPump_In_Call_Back )
  2003. disable_current_msgbox = true;
  2004. }
  2005. else
  2006. {
  2007. // debugprint( "Impossible arose on WOL_GAMEOPT_INFSTART.\n" );
  2008. Fatal( "Impossible arose on WOL_GAMEOPT_INFSTART.\n" );
  2009. }
  2010. Sound_Effect( VOC_GAME_CLOSED );
  2011. break;
  2012. }
  2013. case WOL_GAMEOPT_INFCANCELSTART:
  2014. // Host tells us to cancel waiting for start of game.
  2015. bWaitingToStart = false;
  2016. ClearAllAccepts();
  2017. BindControls( true );
  2018. WOL_PrintMessage( *pILDisc, TXT_WOL_STARTCANCELLED, WOLCOLORREMAP_LOCALMACHINEMESS );
  2019. Sound_Effect( VOC_SYS_ERROR );
  2020. display = REDRAW_ALL;
  2021. // If we are in a modal dialog, we must have arrived here through Call_Back()'s PumpMessages. Set global that will
  2022. // force a cancel out of the dialog.
  2023. if( pWO->bPump_In_Call_Back )
  2024. cancel_current_msgbox = true;
  2025. break;
  2026. case WOL_GAMEOPT_INFGO:
  2027. // Host says start game right now.
  2028. strcpy( szTriggerGameStartInfo, szInform );
  2029. // If we are in a modal dialog, we must have arrived here through Call_Back()'s PumpMessages. Set global that will
  2030. // force a cancel out of the dialog.
  2031. if( pWO->bPump_In_Call_Back )
  2032. cancel_current_msgbox = true;
  2033. break;
  2034. default:
  2035. // debugprint( "Unhandled value of %i in ProcessInform!!!\n", opt );
  2036. //WOL_PrintMessage( *pILDisc, "Error - Unhandled value in ProcessInform!!!", WOLCOLORREMAP_LOCALMACHINEMESS );
  2037. Fatal( "Error - Unhandled value in ProcessInform!" );
  2038. break;
  2039. }
  2040. }
  2041. // debugprint( "* END of ProcessInform: '%s'\n", szInform );
  2042. }
  2043. //***********************************************************************************************
  2044. bool WOL_GameSetupDialog::bParamsUnfresh()
  2045. {
  2046. // Returns true if game setup parameters do not match what they were last time they were sent.
  2047. GAMEPARAMS GParamsNow;
  2048. SetGParamsToCurrent( GParamsNow );
  2049. // if( !( GParamsNow == GParamsLastSent ) )
  2050. // {
  2051. // debugprint( "---- Params Unfresh: OLD...\n" );
  2052. // Debug_GlobalPacketType( GParamsLastSent.GPacket );
  2053. // debugprint( "------------------- NEW...\n" );
  2054. // Debug_GlobalPacketType( GParamsNow.GPacket );
  2055. // debugprint( "old bAftermathUnits = %i\n", GParamsLastSent.bAftermathUnits );
  2056. // debugprint( "new bAftermathUnits = %i\n", GParamsNow.bAftermathUnits );
  2057. // }
  2058. return !( GParamsNow == GParamsLastSent );
  2059. }
  2060. //***********************************************************************************************
  2061. void WOL_GameSetupDialog::SendParams()
  2062. {
  2063. // Host only.
  2064. SetGParamsToCurrent( GParamsLastSent );
  2065. char szSend[ 130 + DESCRIP_MAX + 12 + 32 + 100 ];
  2066. sprintf( szSend,
  2067. "%01u "
  2068. "%06u "
  2069. "%03u "
  2070. "%s "
  2071. "%u "
  2072. "%s "
  2073. "%01u "
  2074. "%.32s " // No null-terminator on digest. There may be nothing at all inserted here.
  2075. "%u "
  2076. "%u "
  2077. "%u "
  2078. "%u "
  2079. "%u "
  2080. "%u "
  2081. "%u "
  2082. "%u "
  2083. "%u "
  2084. "%u "
  2085. "%u "
  2086. "%u "
  2087. "%u "
  2088. "%u "
  2089. "%u "
  2090. "%u "
  2091. "%u "
  2092. "%u "
  2093. "%u "
  2094. "%u "
  2095. "%u "
  2096. "%u "
  2097. ,
  2098. WOL_GAMEOPT_INFPARAMS,
  2099. nHostLastParamID,
  2100. strlen( GParamsLastSent.GPacket.ScenarioInfo.Scenario ),
  2101. GParamsLastSent.GPacket.ScenarioInfo.Scenario,
  2102. GParamsLastSent.GPacket.ScenarioInfo.FileLength,
  2103. GParamsLastSent.GPacket.ScenarioInfo.ShortFileName,
  2104. // strlen( (char*)GParamsLastSent.GPacket.ScenarioInfo.FileDigest ), not null-terminated!
  2105. GParamsLastSent.GPacket.ScenarioInfo.FileDigest[0] ? 1 : 0,
  2106. GParamsLastSent.GPacket.ScenarioInfo.FileDigest,
  2107. GParamsLastSent.GPacket.ScenarioInfo.OfficialScenario,
  2108. GParamsLastSent.GPacket.ScenarioInfo.Credits,
  2109. GParamsLastSent.GPacket.ScenarioInfo.IsBases,
  2110. GParamsLastSent.GPacket.ScenarioInfo.IsTiberium,
  2111. GParamsLastSent.GPacket.ScenarioInfo.IsGoodies,
  2112. GParamsLastSent.GPacket.ScenarioInfo.BuildLevel,
  2113. GParamsLastSent.GPacket.ScenarioInfo.UnitCount,
  2114. GParamsLastSent.GPacket.ScenarioInfo.AIPlayers,
  2115. GParamsLastSent.GPacket.ScenarioInfo.Seed,
  2116. GParamsLastSent.GPacket.ScenarioInfo.Special.IsShadowGrow,
  2117. GParamsLastSent.GPacket.ScenarioInfo.Special.IsSpeedBuild,
  2118. GParamsLastSent.GPacket.ScenarioInfo.Special.IsFromInstall,
  2119. GParamsLastSent.GPacket.ScenarioInfo.Special.IsCaptureTheFlag,
  2120. GParamsLastSent.GPacket.ScenarioInfo.Special.IsInert,
  2121. GParamsLastSent.GPacket.ScenarioInfo.Special.IsThreePoint,
  2122. GParamsLastSent.GPacket.ScenarioInfo.Special.IsTGrowth,
  2123. GParamsLastSent.GPacket.ScenarioInfo.Special.IsTSpread,
  2124. GParamsLastSent.GPacket.ScenarioInfo.GameSpeed,
  2125. GParamsLastSent.GPacket.ScenarioInfo.Version,
  2126. GParamsLastSent.bAftermathUnits, // Not currently used.
  2127. GParamsLastSent.bSlowUnitBuildRate,
  2128. RuleINI.Get_Unique_ID() // Used to verify rules.ini files match.
  2129. );
  2130. pWO->SendGameOpt( szSend, NULL );
  2131. }
  2132. //***********************************************************************************************
  2133. bool WOL_GameSetupDialog::AcceptParams( char* szParams )
  2134. {
  2135. // Reverse of SendParams() process. szParams has already been stripped of 2 bytes header. Guest only.
  2136. // Returns false if rules.ini doesn't match that of the host.
  2137. // (Or if an error occurs due to the packet being incorrect - which happened once in test...)
  2138. char szDelimiter[] = " ";
  2139. char* szToken;
  2140. char* szRemaining;
  2141. szToken = strtok( szParams, szDelimiter );
  2142. nGuestLastParamID = atoi( szToken );
  2143. // Read in length of following string.
  2144. szToken = strtok( NULL, szDelimiter );
  2145. if( !szToken ) return false;
  2146. int iLen = atoi( szToken );
  2147. // Set string pointer to start of string (length is 3 digits).
  2148. szRemaining = szToken + 4;
  2149. // Read in string.
  2150. memcpy( Session.Options.ScenarioDescription, szRemaining, iLen );
  2151. // Null-terminate.
  2152. Session.Options.ScenarioDescription[ iLen ] = 0;
  2153. // Advance string pointer to next param.
  2154. szRemaining += iLen + 1;
  2155. //debugprint( "scenario description is '%s'\n", Session.Options.ScenarioDescription );
  2156. //debugprint( "remaining: '%s'\n", szRemaining );
  2157. szToken = strtok( szRemaining, szDelimiter );
  2158. if( !szToken ) return false;
  2159. Session.ScenarioFileLength = atoi( szToken );
  2160. szToken = strtok( NULL, szDelimiter );
  2161. if( !szToken ) return false;
  2162. strcpy( Session.ScenarioFileName, szToken );
  2163. // // Read in length of following string.
  2164. // szToken = strtok( NULL, szDelimiter );
  2165. // iLen = atoi( szToken );
  2166. // // Set string pointer to start of string (length is 3 digits).
  2167. // szRemaining = szToken + 4;
  2168. // Method changed.
  2169. // Check if there is a digest.
  2170. szToken = strtok( NULL, szDelimiter );
  2171. if( !szToken ) return false;
  2172. iLen = atoi( szToken ); // 1 or 0, indicating if there is a digest following.
  2173. if( iLen )
  2174. {
  2175. // // Set string pointer to start of string (previous field is 1 digit).
  2176. // szRemaining = szToken + 2;
  2177. // iLen = sizeof( Session.ScenarioDigest );
  2178. // // Read in string.
  2179. // memcpy( Session.ScenarioDigest, szRemaining, iLen );
  2180. // // // Null-terminate.
  2181. // // Session.ScenarioDigest[ iLen ] = 0; Digest has no null-terminator!
  2182. // // Advance string pointer to next param.
  2183. // szRemaining += iLen + 1;
  2184. // There is a digest.
  2185. szToken = strtok( NULL, szDelimiter ); // (Digests can't have spaces in the them.)
  2186. //debugprint( "digest: '%s'\n", szToken );
  2187. if( !szToken ) return false;
  2188. strncpy( Session.ScenarioDigest, szToken, sizeof( Session.ScenarioDigest ) );
  2189. }
  2190. szToken = strtok( NULL, szDelimiter );
  2191. if( !szToken ) return false;
  2192. Session.ScenarioIsOfficial = (bool)atoi( szToken );
  2193. szToken = strtok( NULL, szDelimiter );
  2194. if( !szToken ) return false;
  2195. Session.Options.Credits = atoi( szToken );
  2196. szToken = strtok( NULL, szDelimiter );
  2197. if( !szToken ) return false;
  2198. Session.Options.Bases = atoi( szToken );
  2199. szToken = strtok( NULL, szDelimiter );
  2200. if( !szToken ) return false;
  2201. Session.Options.Tiberium = atoi( szToken );
  2202. szToken = strtok( NULL, szDelimiter );
  2203. if( !szToken ) return false;
  2204. Session.Options.Goodies = atoi( szToken );
  2205. szToken = strtok( NULL, szDelimiter );
  2206. if( !szToken ) return false;
  2207. BuildLevel = atoi( szToken );
  2208. szToken = strtok( NULL, szDelimiter );
  2209. if( !szToken ) return false;
  2210. Session.Options.UnitCount = atoi( szToken );
  2211. szToken = strtok( NULL, szDelimiter );
  2212. if( !szToken ) return false;
  2213. Session.Options.AIPlayers = atoi( szToken );
  2214. szToken = strtok( NULL, szDelimiter );
  2215. if( !szToken ) return false;
  2216. Seed = atoi( szToken );
  2217. szToken = strtok( NULL, szDelimiter );
  2218. if( !szToken ) return false;
  2219. Special.IsShadowGrow = ( atoi( szToken ) == 0 ) ? 0 : 1;
  2220. szToken = strtok( NULL, szDelimiter );
  2221. if( !szToken ) return false;
  2222. Special.IsSpeedBuild = ( atoi( szToken ) == 0 ) ? 0 : 1;
  2223. szToken = strtok( NULL, szDelimiter );
  2224. if( !szToken ) return false;
  2225. Special.IsFromInstall = ( atoi( szToken ) == 0 ) ? 0 : 1;
  2226. szToken = strtok( NULL, szDelimiter );
  2227. if( !szToken ) return false;
  2228. Special.IsCaptureTheFlag = ( atoi( szToken ) == 0 ) ? 0 : 1;
  2229. szToken = strtok( NULL, szDelimiter );
  2230. if( !szToken ) return false;
  2231. Special.IsInert = ( atoi( szToken ) == 0 ) ? 0 : 1;
  2232. szToken = strtok( NULL, szDelimiter );
  2233. if( !szToken ) return false;
  2234. Special.IsThreePoint = ( atoi( szToken ) == 0 ) ? 0 : 1;
  2235. szToken = strtok( NULL, szDelimiter );
  2236. if( !szToken ) return false;
  2237. Special.IsTGrowth = ( atoi( szToken ) == 0 ) ? 0 : 1;
  2238. szToken = strtok( NULL, szDelimiter );
  2239. if( !szToken ) return false;
  2240. Special.IsTSpread = ( atoi( szToken ) == 0 ) ? 0 : 1;
  2241. szToken = strtok( NULL, szDelimiter );
  2242. if( !szToken ) return false;
  2243. Options.GameSpeed = atoi( szToken );
  2244. szToken = strtok( NULL, szDelimiter );
  2245. if( !szToken ) return false;
  2246. // "Version" = atoi( szToken );
  2247. szToken = strtok( NULL, szDelimiter );
  2248. if( !szToken ) return false;
  2249. bAftermathUnits = (bool)atoi( szToken );
  2250. szToken = strtok( NULL, szDelimiter );
  2251. if( !szToken ) return false;
  2252. bSlowUnitBuildRate = (bool)atoi( szToken );
  2253. szToken = strtok( NULL, szDelimiter );
  2254. if( !szToken ) return false;
  2255. int iRulesID = atoi( szToken );
  2256. szToken = strtok( NULL, szDelimiter );
  2257. // if( szToken )
  2258. // debugprint( "szToken should be NULL!!!!!!!!\n" );
  2259. return ( RuleINI.Get_Unique_ID() == iRulesID );
  2260. }
  2261. //***********************************************************************************************
  2262. void WOL_GameSetupDialog::SetGParamsToCurrent( GAMEPARAMS& GParams )
  2263. {
  2264. // Sets values in a GAMEPARAMS to the current game settings.
  2265. strcpy( GParams.GPacket.ScenarioInfo.Scenario, Session.Scenarios[ Session.Options.ScenarioIndex ]->Description() );
  2266. CCFileClass file( Session.Scenarios[ Session.Options.ScenarioIndex ]->Get_Filename() );
  2267. GParams.GPacket.ScenarioInfo.FileLength = file.Size();
  2268. strcpy( GParams.GPacket.ScenarioInfo.ShortFileName, Session.Scenarios[ Session.Options.ScenarioIndex ]->Get_Filename() );
  2269. // Digest is not null-terminated.
  2270. strncpy( (char*)GParams.GPacket.ScenarioInfo.FileDigest, Session.Scenarios[ Session.Options.ScenarioIndex ]->Get_Digest(), sizeof( GParams.GPacket.ScenarioInfo.FileDigest ) );
  2271. GParams.GPacket.ScenarioInfo.OfficialScenario = Session.Scenarios[ Session.Options.ScenarioIndex ]->Get_Official();
  2272. GParams.GPacket.ScenarioInfo.Credits = Session.Options.Credits;
  2273. GParams.GPacket.ScenarioInfo.IsBases = Session.Options.Bases;
  2274. GParams.GPacket.ScenarioInfo.IsTiberium = Session.Options.Tiberium;
  2275. GParams.GPacket.ScenarioInfo.IsGoodies = Session.Options.Goodies;
  2276. GParams.GPacket.ScenarioInfo.BuildLevel = BuildLevel;
  2277. GParams.GPacket.ScenarioInfo.UnitCount = Session.Options.UnitCount;
  2278. GParams.GPacket.ScenarioInfo.AIPlayers = Session.Options.AIPlayers;
  2279. GParams.GPacket.ScenarioInfo.Seed = Seed;
  2280. GParams.GPacket.ScenarioInfo.Special = Special;
  2281. GParams.GPacket.ScenarioInfo.GameSpeed = Options.GameSpeed;
  2282. GParams.GPacket.ScenarioInfo.Version = VerNum.Get_Clipped_Version();
  2283. GParams.bAftermathUnits = bAftermathUnits;
  2284. GParams.bSlowUnitBuildRate = bSlowUnitBuildRate;
  2285. }
  2286. //***********************************************************************************************
  2287. bool operator==( const GAMEPARAMS& gp1, const GAMEPARAMS& gp2 )
  2288. {
  2289. return gp1.GPacket == gp2.GPacket &&
  2290. gp1.bAftermathUnits == gp2.bAftermathUnits && gp1.bSlowUnitBuildRate == gp2.bSlowUnitBuildRate;
  2291. }
  2292. //***********************************************************************************************
  2293. bool operator==( const GlobalPacketType& gp1, const GlobalPacketType& gp2 )
  2294. {
  2295. if( strcmp( gp1.ScenarioInfo.Scenario, gp2.ScenarioInfo.Scenario ) != 0 ) return false;
  2296. if( strcmp( gp1.ScenarioInfo.ShortFileName, gp2.ScenarioInfo.ShortFileName ) != 0 ) return false;
  2297. // Digest is not null-terminated...
  2298. if( strncmp( (const char*)gp1.ScenarioInfo.FileDigest, (const char*)gp2.ScenarioInfo.FileDigest, sizeof( gp1.ScenarioInfo.FileDigest ) ) != 0 ) return false;
  2299. if( gp1.ScenarioInfo.FileLength == gp2.ScenarioInfo.FileLength &&
  2300. gp1.ScenarioInfo.OfficialScenario == gp2.ScenarioInfo.OfficialScenario &&
  2301. gp1.ScenarioInfo.Credits == gp2.ScenarioInfo.Credits &&
  2302. gp1.ScenarioInfo.IsBases == gp2.ScenarioInfo.IsBases &&
  2303. gp1.ScenarioInfo.IsTiberium == gp2.ScenarioInfo.IsTiberium &&
  2304. gp1.ScenarioInfo.IsGoodies == gp2.ScenarioInfo.IsGoodies &&
  2305. gp1.ScenarioInfo.BuildLevel == gp2.ScenarioInfo.BuildLevel &&
  2306. gp1.ScenarioInfo.UnitCount == gp2.ScenarioInfo.UnitCount &&
  2307. gp1.ScenarioInfo.AIPlayers == gp2.ScenarioInfo.AIPlayers &&
  2308. gp1.ScenarioInfo.Seed == gp2.ScenarioInfo.Seed &&
  2309. gp1.ScenarioInfo.Special.IsShadowGrow == gp2.ScenarioInfo.Special.IsShadowGrow &&
  2310. gp1.ScenarioInfo.Special.IsSpeedBuild == gp2.ScenarioInfo.Special.IsSpeedBuild &&
  2311. gp1.ScenarioInfo.Special.IsFromInstall == gp2.ScenarioInfo.Special.IsFromInstall &&
  2312. gp1.ScenarioInfo.Special.IsCaptureTheFlag == gp2.ScenarioInfo.Special.IsCaptureTheFlag &&
  2313. gp1.ScenarioInfo.Special.IsInert == gp2.ScenarioInfo.Special.IsInert &&
  2314. gp1.ScenarioInfo.Special.IsThreePoint == gp2.ScenarioInfo.Special.IsThreePoint &&
  2315. gp1.ScenarioInfo.Special.IsTGrowth == gp2.ScenarioInfo.Special.IsTGrowth &&
  2316. gp1.ScenarioInfo.Special.IsTSpread == gp2.ScenarioInfo.Special.IsTSpread &&
  2317. gp1.ScenarioInfo.GameSpeed == gp2.ScenarioInfo.GameSpeed &&
  2318. gp1.ScenarioInfo.Version == gp2.ScenarioInfo.Version )
  2319. return true;
  2320. return false;
  2321. }
  2322. //***********************************************************************************************
  2323. /*
  2324. void Debug_GlobalPacketType( const GlobalPacketType& gp1 ) // ajw debugging
  2325. {
  2326. if( *gp1.ScenarioInfo.Scenario )
  2327. // debugprint( "Scenario = %s\n", (char*)gp1.ScenarioInfo.Scenario );
  2328. else
  2329. // debugprint( "!Scenario string is null\n" );
  2330. if( *gp1.ScenarioInfo.ShortFileName )
  2331. // debugprint( "ShortFileName = %s\n", (char*)gp1.ScenarioInfo.ShortFileName );
  2332. else
  2333. // debugprint( "!ShortFileName string is null\n" );
  2334. // Remember ShortFileName is not null-terminated...
  2335. if( *gp1.ScenarioInfo.FileDigest )
  2336. // debugprint( "FileDigest = %.32s\n", (char*)gp1.ScenarioInfo.FileDigest );
  2337. else
  2338. // debugprint( "!FileDigest string is null\n" );
  2339. // debugprint( "FileLength = %i\n"
  2340. "OfficialScenario = %i\n"
  2341. "Credits = %i\n"
  2342. "IsBases = %i\n"
  2343. "IsTiberium = %i\n"
  2344. "IsGoodies = %i\n"
  2345. "BuildLevel = %i\n"
  2346. "UnitCount = %i\n"
  2347. "AIPlayers = %i\n"
  2348. "Seed = %i\n"
  2349. "Special.IsShadowGrow = %i\n"
  2350. "Special.IsSpeedBuild = %i\n"
  2351. "Special.IsFromInstall = %i\n"
  2352. "Special.IsCaptureTheFlag = %i\n"
  2353. "Special.IsInert = %i\n"
  2354. "Special.IsThreePoint = %i\n"
  2355. "Special.IsTGrowth = %i\n"
  2356. "Special.IsTSpread = %i\n"
  2357. "GameSpeed = %i\n"
  2358. "Version = %i\n",
  2359. gp1.ScenarioInfo.FileLength,
  2360. gp1.ScenarioInfo.OfficialScenario,
  2361. gp1.ScenarioInfo.Credits,
  2362. gp1.ScenarioInfo.IsBases,
  2363. gp1.ScenarioInfo.IsTiberium,
  2364. gp1.ScenarioInfo.IsGoodies,
  2365. gp1.ScenarioInfo.BuildLevel,
  2366. gp1.ScenarioInfo.UnitCount,
  2367. gp1.ScenarioInfo.AIPlayers,
  2368. gp1.ScenarioInfo.Seed,
  2369. gp1.ScenarioInfo.Special.IsShadowGrow,
  2370. gp1.ScenarioInfo.Special.IsSpeedBuild,
  2371. gp1.ScenarioInfo.Special.IsFromInstall,
  2372. gp1.ScenarioInfo.Special.IsCaptureTheFlag,
  2373. gp1.ScenarioInfo.Special.IsInert,
  2374. gp1.ScenarioInfo.Special.IsThreePoint,
  2375. gp1.ScenarioInfo.Special.IsTGrowth,
  2376. gp1.ScenarioInfo.Special.IsTSpread,
  2377. gp1.ScenarioInfo.GameSpeed,
  2378. gp1.ScenarioInfo.Version );
  2379. }
  2380. */
  2381. //***********************************************************************************************
  2382. PlayerColorType PlayerColorTypeOf( RemapControlType* pColorRemap )
  2383. {
  2384. for( PlayerColorType pcolor = PCOLOR_FIRST; pcolor < PCOLOR_COUNT; pcolor++ )
  2385. {
  2386. if( &ColorRemaps[ pcolor ] == pColorRemap )
  2387. return pcolor;
  2388. }
  2389. return PCOLOR_NONE;
  2390. }
  2391. //***********************************************************************************************
  2392. bool WOL_GameSetupDialog::RequestPlayerColor( PlayerColorType Color )
  2393. {
  2394. // Local player sends a request to the game host asking for a particular color.
  2395. char szSend[ 20 ];
  2396. // WOL_GAMEOPT_REQCOLOR format:
  2397. // 2 WOL_GAMEOPT
  2398. // 1 space
  2399. // 2 color
  2400. sprintf( szSend, "%02u %02u", WOL_GAMEOPT_REQCOLOR, Color );
  2401. _ASSERTE( pWO->pGameHost() );
  2402. return pWO->SendGameOpt( szSend, pWO->pGameHost() );
  2403. }
  2404. //***********************************************************************************************
  2405. bool WOL_GameSetupDialog::InformAboutPlayerColor( const char* szName, PlayerColorType Color, User* pUserPriv )
  2406. {
  2407. // Game host tells guests about a player color assignment.
  2408. // If pUserPriv is not null, indicates user to send message as private to.
  2409. char szSend[ 20 + WOL_NAME_LEN_MAX ];
  2410. // WOL_GAMEOPT_INFCOLOR format:
  2411. // 2 WOL_GAMEOPT
  2412. // 1 space
  2413. // 2 color
  2414. // 1 space
  2415. // string name of player
  2416. if( Color == PCOLOR_NONE )
  2417. {
  2418. // debugprint( "Bad Color for %s in InformAboutPlayerColor.\n", szName );
  2419. *szSend = 0;
  2420. }
  2421. else
  2422. sprintf( szSend, "%02u %02u %s", WOL_GAMEOPT_INFCOLOR, Color, szName );
  2423. return pWO->SendGameOpt( szSend, pUserPriv );
  2424. }
  2425. //***********************************************************************************************
  2426. bool WOL_GameSetupDialog::InformAboutPlayerHouse( const char* szName, HousesType House, User* pUserPriv )
  2427. {
  2428. // Game host tells guests about a player house assignment.
  2429. // If pUserPriv is not null, indicates user to send message as private to.
  2430. char szSend[ 28 + WOL_NAME_LEN_MAX ];
  2431. // WOL_GAMEOPT_INFHOUSE format:
  2432. // 2 WOL_GAMEOPT
  2433. // 1 space
  2434. // 6 param ID
  2435. // 1 space
  2436. // 2 house
  2437. // 1 space
  2438. // string name of player
  2439. if( House == HOUSE_NONE )
  2440. {
  2441. // debugprint( "Bad House for %s in InformAboutPlayerHouse.\n", szName );
  2442. *szSend = 0;
  2443. }
  2444. else
  2445. sprintf( szSend, "%02u %06u %02u %s", WOL_GAMEOPT_INFHOUSE, nHostLastParamID, (short)House, szName );
  2446. return pWO->SendGameOpt( szSend, pUserPriv );
  2447. }
  2448. //***********************************************************************************************
  2449. bool WOL_GameSetupDialog::InformAboutPlayerAccept( const char* szName, User* pUserPriv )
  2450. {
  2451. // Game host tells guests about player accepting game params.
  2452. // If pUserPriv is not null, indicates user to send message as private to.
  2453. char szSend[ 6 + WOL_NAME_LEN_MAX ];
  2454. sprintf( szSend, "%02u %s", WOL_GAMEOPT_INFACCEPT, szName );
  2455. return pWO->SendGameOpt( szSend, pUserPriv );
  2456. }
  2457. //***********************************************************************************************
  2458. bool WOL_GameSetupDialog::InformAboutStart()
  2459. {
  2460. // Game host tells all guests that he wants to start the game.
  2461. // Note that nHostLastParamID is involved here. We want to make sure that guest responses apply
  2462. // to the latest WOL_GAMEOPT_INFSTART, and not to an earlier one we canceled out of.
  2463. char szSend[ 10 ];
  2464. sprintf( szSend, "%02u %06u", WOL_GAMEOPT_INFSTART, nHostLastParamID );
  2465. return pWO->SendGameOpt( szSend, NULL );
  2466. }
  2467. //***********************************************************************************************
  2468. bool WOL_GameSetupDialog::InformAboutCancelStart()
  2469. {
  2470. // Game host tells all guests that he wants to start the game.
  2471. // Note that nHostLastParamID is involved here. We want to make sure that guest responses apply
  2472. // to the latest WOL_GAMEOPT_INFSTART, and not to an earlier one we canceled out of.
  2473. // debugprint( "InformAboutCancelStart!\n" );
  2474. char szSend[ 10 ];
  2475. sprintf( szSend, "%02u", WOL_GAMEOPT_INFCANCELSTART );
  2476. return pWO->SendGameOpt( szSend, NULL );
  2477. }
  2478. //***********************************************************************************************
  2479. void WOL_GameSetupDialog::OnGuestJoin( User* pUser )
  2480. {
  2481. // A guest (not myself) has entered the game channel.
  2482. // debugprint( "OnGuestJoin()\n" );
  2483. char* szPrint = new char[ strlen( TXT_WOL_PLAYERJOINEDGAME ) + strlen( (char*)pUser->name ) + 5 ];
  2484. sprintf( szPrint, TXT_WOL_PLAYERJOINEDGAME, (char*)pUser->name );
  2485. WOL_PrintMessage( *pILDisc, szPrint, WOLCOLORREMAP_LOCALMACHINEMESS );
  2486. delete [] szPrint;
  2487. ClearAllAccepts();
  2488. if( bHost )
  2489. {
  2490. // Send the new guest the current setup. Note that nHostLastParamID doesn't change here.
  2491. // Assign color to new guest.
  2492. PlayerColorType Color = ColorNextAvailable();
  2493. SetPlayerColor( (char*)pUser->name, Color );
  2494. // Previously, I was sending an individual color, house, and acceptedstate message for each other guest.
  2495. // Though convenient code-wise, this causes the initial info to arrive at the new guest in a very slow
  2496. // manner. This is because of the wonderful "anti-flood" feature of the chat server, which prevents a
  2497. // series of messages from a client from being passed on faster than a certain rate.
  2498. // For this reason, a new message that contains all of the info about all of the other guests has been
  2499. // created (WOL_GAMEOPT_INFNEWGUESTPLAYERINFO).
  2500. // WOL_GAMEOPT_INFNEWGUESTPLAYERINFO format (items separated by spaces):
  2501. // WOL_GAMEOPT
  2502. // number of players
  2503. // for each player {
  2504. // length of player name string
  2505. // player name
  2506. // color
  2507. // bool - is there a house field following?
  2508. // (house)
  2509. // // (removed) acceptedness - true for set player accepted, false for do nothing
  2510. // }
  2511. // Build up a big WOL_GAMEOPT_INFNEWGUESTPLAYERINFO message.
  2512. char szSend[ 500 ];
  2513. sprintf( szSend, "%02u %02u", WOL_GAMEOPT_INFNEWGUESTPLAYERINFO, pILPlayers->Count() );
  2514. // Send color and house of all players (including himself) to the new guest.
  2515. for( int i = 0; i < pILPlayers->Count(); i++ )
  2516. {
  2517. char szSendPiece[ 100 ];
  2518. char szPlayerName[ WOL_NAME_LEN_MAX ];
  2519. pWO->PullPlayerName_Into_From( szPlayerName, pILPlayers->Get_Item( i ) );
  2520. // InformAboutPlayerColor( szPlayerName, PlayerColorTypeOf( pILPlayers->Get_Item_Color( i ) ), pUser );
  2521. sprintf( szSendPiece, " %02u %s %02u", strlen( szPlayerName ), szPlayerName,
  2522. PlayerColorTypeOf( pILPlayers->Get_Item_Color( i ) ) );
  2523. if( strcmp( szPlayerName, (char*)pUser->name ) != 0 )
  2524. {
  2525. HousesType House = pWO->PullPlayerHouse_From( pILPlayers->Get_Item( i ) );
  2526. if( House != HOUSE_NONE )
  2527. {
  2528. // InformAboutPlayerHouse( szPlayerName, House, pUser );
  2529. char szSendHouse[ 50 ];
  2530. sprintf( szSendHouse, " 1 %02u", (short)House );
  2531. strcat( szSendPiece, szSendHouse );
  2532. }
  2533. else
  2534. {
  2535. // Player must not have told me what house he is yet. Don't send house value.
  2536. strcat( szSendPiece, " 0" );
  2537. }
  2538. }
  2539. else
  2540. {
  2541. // Player is the new guest himself. Don't send house value.
  2542. strcat( szSendPiece, " 0" );
  2543. }
  2544. // Acceptedness must be false! No need to send.
  2545. // // Send "accepted" status of player. Ignore myself, as I'm the host.
  2546. // if( strcmp( szPlayerName, pWO->szMyName ) != 0 && pWO->bItemMarkedAccepted( i ) )
  2547. // strcat( szSendPiece, " 1" );
  2548. // else
  2549. // strcat( szSendPiece, " 0" );
  2550. strcat( szSend, szSendPiece );
  2551. }
  2552. pWO->SendGameOpt( szSend, pUser );
  2553. // Send everyone the color of the new guest.
  2554. InformAboutPlayerColor( (char*)pUser->name, Color, NULL );
  2555. // Send game params.
  2556. // This is done last because it contains a param ID value, and we need to ensure that the new guest has
  2557. // received everything we are sending him here before he tries to send me an accept.
  2558. // If game params were sent first, he could theoretically receive them, then send an accept, even though he
  2559. // has not received the WOL_GAMEOPT_INFNEWGUESTPLAYERINFO.
  2560. // By doing this I avoid having to have a param ID in WOL_GAMEOPT_INFNEWGUESTPLAYERINFO, which would be hard,
  2561. // since it is a private message.
  2562. // For simplicity, send public.
  2563. SendParams();
  2564. }
  2565. }
  2566. //***********************************************************************************************
  2567. void WOL_GameSetupDialog::AcceptNewGuestPlayerInfo( char* szMsg )
  2568. {
  2569. // Process a received WOL_GAMEOPT_INFNEWGUESTPLAYERINFO message.
  2570. // szMsg has already been stripped of 2 bytes header.
  2571. char szDelimiter[] = " ";
  2572. char* szToken;
  2573. char* szRemaining;
  2574. szToken = strtok( szMsg, szDelimiter );
  2575. unsigned int nPlayers = atoi( szToken );
  2576. // We have to assist strtok a bit because of calls below that may also call strtok()...
  2577. szRemaining = szMsg + 3;
  2578. for( unsigned int nPlayer = 0; nPlayer != nPlayers; ++nPlayer )
  2579. {
  2580. // Read in length of following string.
  2581. szToken = strtok( szRemaining, szDelimiter );
  2582. int iLen = atoi( szToken );
  2583. // Set string pointer to start of string (length is 2 digits).
  2584. szRemaining = szToken + 3;
  2585. // Read in string.
  2586. char szPlayerName[ 50 ];
  2587. memcpy( szPlayerName, szRemaining, iLen );
  2588. // Null-terminate.
  2589. szPlayerName[ iLen ] = 0;
  2590. // Advance string pointer to next param.
  2591. szRemaining += iLen + 1;
  2592. // Read color.
  2593. szToken = strtok( szRemaining, szDelimiter );
  2594. PlayerColorType Color = (PlayerColorType)atoi( szToken );
  2595. SetPlayerColor( szPlayerName, Color );
  2596. // SetPlayerColor may call strtok, so we can't use the strtok( NULL, option... in the next call.
  2597. szRemaining += 3;
  2598. // Read whether there is a house field.
  2599. szToken = strtok( szRemaining, szDelimiter );
  2600. bool bHouseField = (bool)atoi( szToken );
  2601. if( bHouseField )
  2602. {
  2603. // Read house.
  2604. szToken = strtok( NULL, szDelimiter );
  2605. HousesType House = (HousesType)atoi( szToken );
  2606. SetPlayerHouse( szPlayerName, House );
  2607. // SetPlayerHouse may call strtok, so we can't use the strtok( NULL, option... in the next call.
  2608. szRemaining += 5;
  2609. }
  2610. else
  2611. szRemaining += 2; // Advance past "0 ".
  2612. // Acceptedness must be false. No need for it in message.
  2613. // // Read acceptedness.
  2614. // szToken = strtok( NULL, szDelimiter );
  2615. // bool bAccepted = (bool)atoi( szToken );
  2616. // if( bAccepted )
  2617. // SetPlayerAccepted( szPlayerName, true );
  2618. }
  2619. szToken = strtok( NULL, szDelimiter );
  2620. // if( szToken )
  2621. // debugprint( "szToken should be NULL!!!!!!!!\n" );
  2622. ClearAllAccepts(); // Most likely a pointless precaution.
  2623. }
  2624. //***********************************************************************************************
  2625. void WOL_GameSetupDialog::OnGuestLeave( User* pUser )
  2626. {
  2627. // pUser is about to leave but is still in our player list.
  2628. if( pUser->flags & CHAT_USER_CHANNELOWNER )
  2629. {
  2630. // Host is leaving the channel. We must be a guest, and so must leave also. This will trigger exit.
  2631. strcpy( szNameOfHostWhoJustBailedOnUs, (char*)pUser->name );
  2632. }
  2633. else
  2634. {
  2635. ClearAllAccepts();
  2636. }
  2637. }
  2638. //***********************************************************************************************
  2639. void WOL_GameSetupDialog::ClearAllAccepts()
  2640. {
  2641. // Clears all "player has accepted" marks.
  2642. //debugprint( "ClearAllAccepts()\n" );
  2643. for( int i = 0; i < pILPlayers->Count(); i++ )
  2644. {
  2645. User* pUser = (User*)pILPlayers->Get_Item_ExtraDataPtr( i );
  2646. if( pUser && !( pUser->flags & CHAT_USER_CHANNELOWNER ) ) // pUser null if this is an "early insertion" entry on startup
  2647. pWO->MarkItemAccepted( i, false );
  2648. }
  2649. if( pToolTipHitLast && pToolTipHitLast->bShowing )
  2650. pToolTipHitLast->Unshow();
  2651. if( bHost )
  2652. {
  2653. pTextBtnAcceptStart->Disable();
  2654. if( bWaitingToStart )
  2655. {
  2656. // Something has happened that makes starting a game not possible now.
  2657. // Cancel out of waiting mode and tell guests to do the same.
  2658. bWaitingToStart = false;
  2659. InformAboutCancelStart();
  2660. BindControls( true );
  2661. ResetReadyToGo();
  2662. display = REDRAW_ALL;
  2663. }
  2664. else
  2665. pTextBtnAcceptStart->Flag_To_Redraw();
  2666. }
  2667. else
  2668. {
  2669. pTextBtnAcceptStart->Enable();
  2670. pTextBtnAcceptStart->Flag_To_Redraw();
  2671. }
  2672. }
  2673. //***********************************************************************************************
  2674. bool WOL_GameSetupDialog::bAllGuestsAccept()
  2675. {
  2676. for( int i = 0; i < pILPlayers->Count(); i++ )
  2677. {
  2678. if( !pWO->bItemMarkedAccepted( i ) )
  2679. return false;
  2680. }
  2681. return true;
  2682. }
  2683. //***********************************************************************************************
  2684. PlayerColorType WOL_GameSetupDialog::ColorNextAvailable()
  2685. {
  2686. // Returns the first free player color available.
  2687. // (Totally unoptimized, but hardly ever called.)
  2688. for( int i = 0; i < MAX_MPLAYER_COLORS; i++ )
  2689. {
  2690. if( pILPlayers->FindColor( &ColorRemaps[ i ] ) == -1 )
  2691. {
  2692. return (PlayerColorType)i;
  2693. }
  2694. }
  2695. // debugprint( "ColorNextAvailable is NONE!\n" );
  2696. return PCOLOR_NONE;
  2697. }
  2698. //***********************************************************************************************
  2699. void WOL_GameSetupDialog::GuestIsReadyToPlay( const char* szName, const char* szReadyState )
  2700. {
  2701. // A guest has responded to a game start request.
  2702. SetPlayerReadyToGo( szName, szReadyState );
  2703. if( bAllPlayersReadyToGo() )
  2704. {
  2705. // debugprint( "All players ready to go.\n" );
  2706. // We can start the game.
  2707. bHostSayGo = true; // Set trigger to fire function after we're out of callback.
  2708. }
  2709. }
  2710. //***********************************************************************************************
  2711. bool WOL_GameSetupDialog::bNeedScenarioDownload()
  2712. {
  2713. // Returns true if we don't have the scenario and it is allowable as a download.
  2714. if( !bHost )
  2715. {
  2716. if( Find_Local_Scenario( Session.Options.ScenarioDescription,
  2717. Session.ScenarioFileName,
  2718. Session.ScenarioFileLength,
  2719. Session.ScenarioDigest,
  2720. Session.ScenarioIsOfficial ) )
  2721. {
  2722. // debugprint( "bNeedScenarioDownload() returning false.\n" );
  2723. bRequestedScenarioDownload = false;
  2724. return false;
  2725. }
  2726. else
  2727. {
  2728. /* if( !Session.ScenarioIsOfficial )
  2729. {
  2730. bRequestedScenarioDownload = true;
  2731. return true;
  2732. }
  2733. else
  2734. {
  2735. // debugprint( "bNeedScenarioDownload fatal\n" );
  2736. Fatal( "" );
  2737. }
  2738. */
  2739. // debugprint( "Requesting download\n" ); // ajw Shouldn't be happening with am maps when i have am...?
  2740. bRequestedScenarioDownload = true; // All maps are downloadable.
  2741. return true;
  2742. }
  2743. }
  2744. bRequestedScenarioDownload = false;
  2745. return false;
  2746. }
  2747. //***********************************************************************************************
  2748. void WOL_GameSetupDialog::HostSaysGo()
  2749. {
  2750. bHostSayGo = false;
  2751. bHostWaitingForGoTrigger = true;
  2752. // debugprint( "HostSaysGo()\n" );
  2753. if( !pWO->RequestGameStart() )
  2754. {
  2755. // debugprint( "Call to RequestGameStart() failed.\n" );
  2756. //Fatal( "Call to RequestGameStart() failed.\n" );
  2757. pWO->bSelfDestruct = true;
  2758. return;
  2759. }
  2760. // Tell guests to start game.
  2761. // debugprint( "Telling guests to start game.\n" );
  2762. // Create WOL_GAMEOPT_INFGO message.
  2763. // This contains the color for each player, which can change about haphazardly at the end of setup,
  2764. // without causing "unacceptedness". This means that the colors everyone thinks everyone else is might not
  2765. // be sync'ed. Host sets everyone straight here.
  2766. char szSend[ ( WOL_NAME_LEN_MAX + 10 ) * 4 + 50 ] = "";
  2767. sprintf( szSend, "%02u", WOL_GAMEOPT_INFGO );
  2768. User* pUser = pWO->pChatSink->pGameUserList;
  2769. while( pUser )
  2770. {
  2771. char szUser[ WOL_NAME_LEN_MAX + 10 ];
  2772. PlayerColorType Color = GetPlayerColor( (char*)pUser->name );
  2773. sprintf( szUser, " %s %02u", (char*)pUser->name, Color ); // What if player left just now, and got removed from list. Ok to continue and fail on game start?
  2774. strcat( szSend, szUser );
  2775. pUser = pUser->next;
  2776. }
  2777. if( !pWO->SendGo( szSend ) )
  2778. {
  2779. // debugprint( "Call to SendGo() failed.\n" );
  2780. //Fatal( "Call to SendGo() failed.\n" );
  2781. pWO->bSelfDestruct = true;
  2782. return;
  2783. }
  2784. /* ...Method changed. It appears that my channelleave may appear to guests before the "go" privategameopt.
  2785. For this reason, I'll wait until I receive a copy of the "go" message sent to myself, before proceeding.
  2786. pWO->pChat->PumpMessages(); // Flush the send out.
  2787. // (ajw - Note: An apparent bug in wolapi means that this pump does not necessarily flush the go gameopts.
  2788. // This is ok in practice, because the host hits pumps later that will flush them.)
  2789. // Pretend we just received szSend, and processed it like a guest would.
  2790. char* szFakeGoMessage = szSend + 3;
  2791. TriggerGameStart( szFakeGoMessage );
  2792. */
  2793. }
  2794. //***********************************************************************************************
  2795. void WOL_GameSetupDialog::TriggerGameStart( char* szGoMessage )
  2796. {
  2797. // Last function before dialog is exited for game start. (Which must occur now.)
  2798. // Host or guest is about to start a game using final data in szGoMessage.
  2799. // debugprint( "TriggerGameStart( %s )\n", szGoMessage );
  2800. // If we are in a modal dialog, we must have arrived here through Call_Back()'s PumpMessages. Set global that will
  2801. // force a cancel out of the dialog.
  2802. if( pWO->bPump_In_Call_Back )
  2803. cancel_current_msgbox = true;
  2804. bHostWaitingForGoTrigger = false;
  2805. bExitForGameTrigger = true;
  2806. // The following is based on Read_Game_Options()...
  2807. // WWGetPrivateProfileString("Options", "Handle", "Noname", Session.Handle, sizeof(Session.Handle), buffer);
  2808. strcpy( Session.Handle, pWO->szMyName );
  2809. // GameName will be the host's name...
  2810. strcpy( Session.GameName, pWO->pGameHostName() );
  2811. // debugprint( "Session.GameName is %s\n", Session.GameName );
  2812. // gotit Session.ColorIdx = (PlayerColorType) WWGetPrivateProfileInt("Options", "Color", 0, buffer);
  2813. // gotit Session.PrefColor = Session.ColorIdx;
  2814. // gotit int temp = WWGetPrivateProfileInt("Options", "Side", 0, buffer);
  2815. // gotit Session.House = (HousesType) ((int)HOUSE_USSR + temp);
  2816. // gotit Session.Options.Credits = WWGetPrivateProfileInt("Options", "Credits", 0, buffer);
  2817. // gotit Session.Options.Bases = WWGetPrivateProfileInt("Options", "Bases", 0, buffer);
  2818. // gotit Session.Options.Tiberium = WWGetPrivateProfileInt("Options", "Tiberium", 0, buffer);
  2819. // gotit Session.Options.Goodies = WWGetPrivateProfileInt("Options", "Crates", 0, buffer);
  2820. // gotit Special.IsShadowGrow = WWGetPrivateProfileInt ("Options", "Shadow", 0, buffer);
  2821. // gotit BuildLevel = WWGetPrivateProfileInt("Options", "BuildLevel", 0, buffer);
  2822. // gotit Session.Options.UnitCount = WWGetPrivateProfileInt("Options", "UnitCount", 0, buffer);
  2823. // gotit Seed = WWGetPrivateProfileInt("Options", "Seed", 0, buffer);
  2824. // gotit Special.IsCaptureTheFlag = WWGetPrivateProfileInt("Options", "CapFlag", 0, buffer);
  2825. // UnitBuildPenalty = WWGetPrivateProfileInt ("Options", "BuildRate", 100, buffer);
  2826. if( bSlowUnitBuildRate )
  2827. UnitBuildPenalty = 250;
  2828. else
  2829. UnitBuildPenalty = 100;
  2830. //PlanetWestwoodGameID = WWGetPrivateProfileInt("Internet", "GameID", 0, buffer);
  2831. PlanetWestwoodGameID = pWO->pChatSink->iGameID;
  2832. // Reset ChatSink's iGameID.
  2833. pWO->pChatSink->iGameID = 0;
  2834. //PlanetWestwoodStartTime = WWGetPrivateProfileInt ("Internet", "StartTime", 0, buffer);
  2835. PlanetWestwoodStartTime = time( NULL );
  2836. //WChatHWND = (HWND) WWGetPrivateProfileInt("Internet", "HWND", (int)FindWindow("OWL_Window", "Westwood Chat"), buffer);
  2837. // gotit Session.Options.AIPlayers = WWGetPrivateProfileInt("Options", "AI", 0, buffer); //Number of AI players
  2838. if (Session.Options.AIPlayers){
  2839. Session.Options.Ghosts = 1;
  2840. }
  2841. if (Session.Options.Tiberium) {
  2842. Special.IsTGrowth = 1;
  2843. Special.IsTSpread = 1;
  2844. } else {
  2845. Special.IsTGrowth = 0;
  2846. Special.IsTSpread = 0;
  2847. }
  2848. // The preceding was based on Read_Game_Options()...
  2849. // Now do whatever we've left out that the horrific Net_Fake_New_Dialog() and Net_Fake_Join_Dialog() used to do for us...
  2850. // Set up the Session.Players list.
  2851. // I think there is dependence on the local player being first, so put him there.
  2852. // Else put them in order listed in the szGoMessage.
  2853. // I will set "ID" based on a player's color, though it seems unclear if this is even used in the game, or what it should be.
  2854. Clear_Vector( &Session.Players );
  2855. // Make the pILPlayers a valid list of players in the game.
  2856. // Players might (incredibly rarely) have joined in the last split-second, and we only want the players listed in
  2857. // the szGoMessage. To test for whether they're in this list, first wipe the colors from all list items.
  2858. // Then we fill them in from info in szGoMessage.
  2859. // We can ignore any list items then that have no color assigned.
  2860. // Also, we'll know that the colors assigned to valid players indeed match up with what every other client has.
  2861. // Remember, all other data should already be sync'ed because it has been implemented in such a way that changes would
  2862. // cause "unacceptedness" of guests to occur.
  2863. // Clear colors in list.
  2864. for( int iItem = 0; iItem < pILPlayers->Count(); iItem++ )
  2865. pILPlayers->Set_Item_Color( iItem, &ColorRemaps[ PCOLOR_NONE ] );
  2866. // Parse szGoMessage to iterate through players.
  2867. char szDelimiter[] = " ";
  2868. char* szToken;
  2869. char szPlayerName[ WOL_NAME_LEN_MAX ];
  2870. szToken = strtok( szGoMessage, szDelimiter );
  2871. while( szToken )
  2872. {
  2873. strcpy( szPlayerName, szToken );
  2874. szToken = strtok( NULL, szDelimiter );
  2875. PlayerColorType Color = (PlayerColorType)atoi( szToken );
  2876. SetPlayerColor( szPlayerName, Color ); // ajw note: inserts if not found.
  2877. szToken = strtok( NULL, szDelimiter );
  2878. }
  2879. // Add myself to Session.Players list.
  2880. _ASSERTE( pILPlayers->Find( pWO->szMyName ) != -1 );
  2881. NodeNameType* pPlayerNew = new NodeNameType;
  2882. strcpy( pPlayerNew->Name, pWO->szMyName ); // "Name" is 12 chars max.
  2883. //pPlayerNew->Address = Session.GAddress;
  2884. pPlayerNew->Player.House = GetPlayerHouse( pWO->szMyName );
  2885. //debugprint( "ME: pPlayerNew->Player.House = %i\n", pPlayerNew->Player.House );
  2886. pPlayerNew->Player.Color = GetPlayerColor( pWO->szMyName );
  2887. // This gets done later.
  2888. // pPlayerNew->Player.ID = (HousesType)( pPlayerNew->Player.Color + HOUSE_MULTI1 );
  2889. Session.Players.Add( pPlayerNew );
  2890. char szHostName[ WOL_NAME_LEN_MAX ] = "Game host";
  2891. // Add all other players to Session.Players list (if they have a valid color - see just above).
  2892. // Also in this step - build the scenario download requests array (used by hosts only).
  2893. memset( Session.ScenarioRequests, 0, sizeof( Session.ScenarioRequests ) );
  2894. Session.RequestCount = 0;
  2895. for( iItem = 0; iItem < pILPlayers->Count(); iItem++ )
  2896. {
  2897. // The following is not very efficient, but doesn't have to be. Better in this case to keep it clear and simple.
  2898. pWO->PullPlayerName_Into_From( szPlayerName, pILPlayers->Get_Item( iItem ) );
  2899. if( strcmp( szPlayerName, pWO->szMyName ) != 0 && GetPlayerColor( szPlayerName ) != PCOLOR_NONE )
  2900. {
  2901. // debugprint( "Creating player node '%s'\n", szPlayerName );
  2902. pPlayerNew = new NodeNameType;
  2903. strcpy( pPlayerNew->Name, szPlayerName );
  2904. // Get player's IP address from pChatSink...
  2905. unsigned long lAddress = ( pWO->pChatSink->GetPlayerGameIP( szPlayerName ) ); //ntohl(
  2906. // debugprint( "IP address is %i, or 0x%x\n", lAddress, lAddress );
  2907. if( pWO->GameInfoCurrent.bTournament )
  2908. {
  2909. // This is a tournament game, and I therefore have only one opponent: this one.
  2910. // for convenience, save a copy of his IP address in case I need it later for disconnect pinging.
  2911. pWO->TournamentOpponentIP = lAddress;
  2912. pWO->bDisconnectPingingCompleted = false;
  2913. }
  2914. NetNumType net;
  2915. NetNodeType node;
  2916. memset( net, 0, 4 );
  2917. memset( node, 0, 6 );
  2918. memcpy( node, &lAddress, 4 );
  2919. //memcpy( node + 2, &lAddress, 4 );
  2920. pPlayerNew->Address.Set_Address( net, node );
  2921. //pPlayerNew->Address = Session.GAddress;
  2922. pPlayerNew->Player.House = GetPlayerHouse( szPlayerName );
  2923. //debugprint( "Player %i: pPlayerNew->Player.House = %i\n", iItem, pPlayerNew->Player.House );
  2924. pPlayerNew->Player.Color = GetPlayerColor( szPlayerName );
  2925. // This gets done later.
  2926. //pPlayerNew->Player.ID = (HousesType)( pPlayerNew->Player.Color + HOUSE_MULTI1 );
  2927. Session.Players.Add( pPlayerNew );
  2928. // If player is the game host, set HostAddress. This global is used when downloading scenarios; who knows where else.
  2929. User* pUser = (User*)pILPlayers->Get_Item_ExtraDataPtr( iItem );
  2930. if( pUser && pUser->flags & CHAT_USER_CHANNELOWNER )
  2931. {
  2932. Session.HostAddress = pPlayerNew->Address;
  2933. strcpy( szHostName, (char*)pUser->name );
  2934. /*
  2935. // debugging
  2936. NetNumType netxxx;
  2937. NetNodeType nodexxx;
  2938. Session.HostAddress.Get_Address( netxxx, nodexxx );
  2939. // debugprint( "Host, ip %i.%i.%i.%i.%i.%i\n", nodexxx[0], nodexxx[1], nodexxx[2], nodexxx[3], nodexxx[4], nodexxx[5] );
  2940. */
  2941. }
  2942. /*
  2943. else
  2944. {
  2945. NetNumType netxxx;
  2946. NetNodeType nodexxx;
  2947. pPlayerNew->Address.Get_Address( netxxx, nodexxx );
  2948. // debugprint( "Player ip %i.%i.%i.%i.%i.%i\n", nodexxx[0], nodexxx[1], nodexxx[2], nodexxx[3], nodexxx[4], nodexxx[5] );
  2949. }
  2950. */
  2951. if( bHost && pWO->bItemMarkedNeedScenario( iItem ) )
  2952. {
  2953. // debugprint( "%s has requested scenario download.\n", szPlayerName );
  2954. Session.ScenarioRequests[ Session.RequestCount++ ] = Session.Players.Count() - 1;
  2955. }
  2956. }
  2957. // else
  2958. // debugprint( "%s excluded from Session.Players\n", szPlayerName );
  2959. }
  2960. // From Init...
  2961. // debugprint( "About to call Open_Socket().\n");
  2962. PacketTransport->Open_Socket( 0 );
  2963. // debugprint( "RA95 - About to call Start_Listening.\n" );
  2964. PacketTransport->Start_Listening();
  2965. /*
  2966. ** Flush out any pending packets from a previous game.
  2967. */
  2968. PacketTransport->Discard_In_Buffers();
  2969. PacketTransport->Discard_Out_Buffers();
  2970. WWDebugString ("RA95 - About to call Init_Network.\n");
  2971. Init_Network();
  2972. Ipx.Set_Timing ( 30, // retry 2 times per second
  2973. -1, // ignore max retries
  2974. 600); // give up after 10 seconds
  2975. // debugprint( "Session.ScenarioFileName is %s.\n", Session.ScenarioFileName );
  2976. /*
  2977. ** Read the scenario name from the .INI and try to match it with a scenario file in our list.
  2978. */
  2979. // gotit WWGetPrivateProfileString("Options", "Scenario", "SCM01EA.INI",
  2980. // Session.Options.ScenarioDescription,
  2981. // sizeof (Session.Options.ScenarioDescription),
  2982. // buffer);
  2983. //WWDebugString ("RA95I - Scenario is ");
  2984. //WWDebugString (Session.Options.ScenarioDescription);
  2985. //WWDebugString ("\n");
  2986. if( !bHost ) // Else ScenarioIndex is already set.
  2987. {
  2988. if( bRequestedScenarioDownload )
  2989. {
  2990. Session.Options.ScenarioIndex = 1;
  2991. if( bSpecialAftermathScenario( Session.Options.ScenarioDescription ) )
  2992. {
  2993. // Shouldn't ever happen. We should never have the opportunity to ask for one of these maps to be downloaded.
  2994. bExitForGameTrigger = false;
  2995. *szTriggerGameStartInfo = 0;
  2996. // Trigger the "our host just left the channel" code...
  2997. strcpy( szNameOfHostWhoJustBailedOnUs, szHostName );
  2998. return;
  2999. }
  3000. // Wait for download from game host.
  3001. //debugprint( "Wait for download from game host.\n" );
  3002. if( !Get_Scenario_File_From_Host( Session.ScenarioFileName, 1 ) )
  3003. {
  3004. // debugprint( "Get_Scenario_File_From_Host failed!\n" );
  3005. bExitForGameTrigger = false;
  3006. *szTriggerGameStartInfo = 0;
  3007. // Trigger the "our host just left the channel" code...
  3008. strcpy( szNameOfHostWhoJustBailedOnUs, szHostName );
  3009. return;
  3010. }
  3011. Scen.Scenario = Session.Options.ScenarioIndex;
  3012. // debugprint( "Scen.Scenario = %i\n", Scen.Scenario );
  3013. strcpy( Scen.ScenarioName, Session.ScenarioFileName );
  3014. // debugprint( "Scen.ScenarioName = %s\n", Scen.ScenarioName );
  3015. }
  3016. else
  3017. {
  3018. // Match ScenarioDescription to a ScenarioIndex.
  3019. /* This is how the same code existed previously. Insufficient because Description may match on many scenarios.
  3020. Session.Options.ScenarioIndex = -1;
  3021. for (int i = 0; i < Session.Scenarios.Count(); i++) {
  3022. if (!strcmp (Session.Scenarios[i]->Description(), Session.Options.ScenarioDescription) ){
  3023. Session.Options.ScenarioIndex = i;
  3024. break;
  3025. }
  3026. }
  3027. */
  3028. // (We have already done the lookup, in Find_Local_Scenario, above.)
  3029. Session.Options.ScenarioIndex = ScenarioIndex_From_Filename( Session.ScenarioFileName );
  3030. _ASSERTE( Session.Options.ScenarioIndex != -1 );
  3031. Scen.Scenario = Session.Options.ScenarioIndex;
  3032. // debugprint( "Scen.Scenario = %i\n", Scen.Scenario );
  3033. strcpy( Scen.ScenarioName, Session.Scenarios[ Session.Options.ScenarioIndex ]->Get_Filename() );
  3034. // debugprint( "Scen.ScenarioName = %s\n", Scen.ScenarioName );
  3035. }
  3036. }
  3037. else // bHost
  3038. {
  3039. Scen.Scenario = Session.Options.ScenarioIndex;
  3040. // debugprint( "Scen.Scenario = %i\n", Scen.Scenario );
  3041. strcpy( Scen.ScenarioName, Session.Scenarios[ Session.Options.ScenarioIndex ]->Get_Filename() );
  3042. // debugprint( "Scen.ScenarioName = %s\n", Scen.ScenarioName );
  3043. strcpy( Session.Options.ScenarioDescription, (char*)Session.Scenarios[ Session.Options.ScenarioIndex ]->Description() );
  3044. }
  3045. Options.GameSpeed = 0;
  3046. //Session.MaxAhead = WChatMaxAhead = WWGetPrivateProfileInt("Timing", "MaxAhead", 9, buffer);
  3047. //Session.FrameSendRate = WChatSendRate = WWGetPrivateProfileInt("Timing", "SendRate", 3, buffer);
  3048. Session.MaxAhead = 15; //9;
  3049. //Session.FrameSendRate = 5; //3;
  3050. Session.FrameSendRate = 3; //3;
  3051. // This is from NETDLG processing...
  3052. Session.NumPlayers = Session.Players.Count();
  3053. pWO->GameInfoCurrent.iPlayerCount = Session.Players.Count();
  3054. Ipx.Set_Timing (25, (unsigned long) -1, 1000);
  3055. if( bHost )
  3056. {
  3057. if( Session.Scenarios[ Session.Options.ScenarioIndex ]->Get_Official() )
  3058. {
  3059. if( !Force_Scenario_Available( Scen.ScenarioName ) )
  3060. {
  3061. bExitForGameTrigger = false;
  3062. *szTriggerGameStartInfo = 0;
  3063. pWO->bSelfDestruct = true;
  3064. return;
  3065. }
  3066. }
  3067. if( Session.RequestCount )
  3068. {
  3069. // Send the scenario to any guests that requested a download.
  3070. //debugprint( "Send the scenario to any guests that requested a download.\n" );
  3071. Send_Remote_File( Scen.ScenarioName, 1 );
  3072. }
  3073. }
  3074. Session.CommProtocol = COMM_PROTOCOL_MULTI_E_COMP;
  3075. Ipx.Set_Timing (30, (unsigned long) -1, 600);
  3076. pWO->bEnableNewAftermathUnits = bAftermathUnits;
  3077. bAftermathMultiplayer = bAftermathUnits;
  3078. *pWO->szExternalPager = 0;
  3079. pWO->bDoingDisconnectPinging = false; // Pointlessly making sure.
  3080. *szTriggerGameStartInfo = 0; // This was set in order to trigger my coming here.
  3081. }
  3082. #endif
  3083. //***********************************************************************************************
  3084. bool bSpecialAftermathScenario( const char* szScenarioDescription )
  3085. {
  3086. // Returns true if szScenarioDescription matches one of the descriptions for Aftermath multiplayer
  3087. // scenarios that have special Aftermath-only units *embedded* within them.
  3088. if( strcmp( szScenarioDescription, "Booby Traps (Mega 8 players)" ) == 0 ||
  3089. strcmp( szScenarioDescription, "Central Conflict Extreme (Mega 8 players)" ) == 0 ||
  3090. strcmp( szScenarioDescription, "Circles of Death (Mega 8 players)" ) == 0 ||
  3091. strcmp( szScenarioDescription, "Holy Grounds (Mega 8 players)" ) == 0 ||
  3092. strcmp( szScenarioDescription, "Island Wars Extreme (Mega 8 players)" ) == 0 ||
  3093. strcmp( szScenarioDescription, "King of the Hills Extreme (Mega 8 players)" ) == 0 ||
  3094. strcmp( szScenarioDescription, "The Hills Have Eyes (Mega 8 players)" ) == 0 )
  3095. return true;
  3096. return false;
  3097. }
  3098. //***********************************************************************************************
  3099. int ScenarioIndex_From_Filename( const char* szScenarioFilename )
  3100. {
  3101. // Returns the scenario index that matches the scenario filename, or -1 if no match found.
  3102. for( int index = 0; index < Session.Scenarios.Count(); index++ )
  3103. {
  3104. if( _stricmp( szScenarioFilename, Session.Scenarios[index]->Get_Filename() ) == 0 )
  3105. return index;
  3106. }
  3107. return -1;
  3108. }