WOLAPIOB.CPP 114 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432
  1. //
  2. // Copyright 2020 Electronic Arts Inc.
  3. //
  4. // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free
  5. // software: you can redistribute it and/or modify it under the terms of
  6. // the GNU General Public License as published by the Free Software Foundation,
  7. // either version 3 of the License, or (at your option) any later version.
  8. // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
  9. // in the hope that it will be useful, but with permitted additional restrictions
  10. // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
  11. // distributed with this program. You should have received a copy of the
  12. // GNU General Public License along with permitted additional restrictions
  13. // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
  14. #ifdef WOLAPI_INTEGRATION
  15. // WolapiOb.cpp - Implementation of class WolapiObject.
  16. // ajw 07/10/98
  17. #include "WolapiOb.h"
  18. #include "RAWolapi.h"
  19. #include "WolStrng.h"
  20. #include "SEditDlg.h"
  21. #include "ToolTip.h"
  22. #include "Wol_GSup.h"
  23. #include "WolDebug.h"
  24. extern void WOL_PrintMessage( IconListClass& ILTarget, const char* szText, PlayerColorType iColorRemap = PCOLOR_NONE );
  25. extern void WOL_PrintMessage( IconListClass& ILTarget, const char* szText, RemapControlType* pColorRemap );
  26. void HostNameFromGameChannelName( char* szNameToSet, const char* szChannelName );
  27. bool WOL_Options_Dialog( WolapiObject* pWO, bool bCalledFromGame );
  28. extern bool cancel_current_msgbox;
  29. const char* Game_Registry_Key();
  30. //***********************************************************************************************
  31. WolapiObject::WolapiObject() : pChat( NULL ), pDownload( NULL ), pChatSink( NULL ), pDownloadSink( NULL ),
  32. dwChatAdvise( 0 ), dwDownloadAdvise( 0 ), pILChat( NULL ), pILUsers( NULL ),
  33. CurrentLevel( WOL_LEVEL_TOP ), bChannelOwner( false ), GameTypeInfos( NULL ),
  34. nGameTypeInfos( 0 ), bChatShownBefore( false ),
  35. pILPlayers( NULL ), pChatSaveList( NULL ), iLobbyReturnAfterGame( -1 ), iLobbyLast( -1 ),
  36. bFindEnabled( true ),
  37. bPageEnabled( true ),
  38. bLangFilter( true ),
  39. bAllGamesShown( true ),
  40. pGSupDlg( NULL ),
  41. pShpDiscon( NULL ),
  42. pShpLeave( NULL ),
  43. pShpRefresh( NULL ),
  44. pShpSquelch( NULL ),
  45. pShpBan( NULL ),
  46. pShpKick( NULL ),
  47. pShpFindpage( NULL ),
  48. pShpOptions( NULL ),
  49. pShpLadder( NULL ),
  50. pShpHelp( NULL ),
  51. pShpBtnDiscon( NULL ),
  52. pShpBtnLeave( NULL ),
  53. pShpBtnRefresh( NULL ),
  54. pShpBtnSquelch( NULL ),
  55. pShpBtnBan( NULL ),
  56. pShpBtnKick( NULL ),
  57. pShpBtnFindpage( NULL ),
  58. pShpBtnOptions( NULL ),
  59. pShpBtnLadder( NULL ),
  60. pShpBtnHelp( NULL ),
  61. bReturningAfterGame( false ),
  62. pTTipDiscon( NULL ),
  63. pTTipLeave( NULL ),
  64. pTTipRefresh( NULL ),
  65. pTTipSquelch( NULL ),
  66. pTTipBan( NULL ),
  67. pTTipKick( NULL ),
  68. pTTipFindpage( NULL ),
  69. pTTipOptions( NULL ),
  70. pTTipLadder( NULL ),
  71. pTTipHelp( NULL ),
  72. bMyRecordUpdated( false ),
  73. bChannelListTitleUpdated( false ),
  74. bInGame( false ),
  75. pStaticUsers( NULL ),
  76. bPump_In_Call_Back( false ),
  77. bFreezeExternalPager( false ),
  78. bDoingDisconnectPinging( false ),
  79. bSelfDestruct( false ),
  80. bEggSounds( true ),
  81. bEgg8Player( false ),
  82. bShowRankRA( true ),
  83. bShowRankUpdated( false )
  84. {
  85. *szMyName = 0;
  86. *szMyRecord = 0;
  87. *szMyRecordAM = 0;
  88. *szChannelListTitle = 0;
  89. *szChannelNameCurrent = 0;
  90. *szChannelReturnOnGameEnterFail = 0;
  91. dwTimeNextWolapiPump = ::timeGetTime() + WOLAPIPUMPWAIT;
  92. dwTimeNextChannelUpdate = 0;
  93. *szLadderServerHost = 0;
  94. *szGameResServerHost1 = 0;
  95. *szGameResServerHost2 = 0;
  96. strcpy( DibIconInfos[ DIBICON_OWNER ].szFile, "dib_own.bmp" );
  97. strcpy( DibIconInfos[ DIBICON_SQUELCH ].szFile, "dib_sqel.bmp" );
  98. strcpy( DibIconInfos[ DIBICON_LATENCY ].szFile, "latency.bmp" );
  99. strcpy( DibIconInfos[ DIBICON_ACCEPT ].szFile, "dib_acpt.bmp" );
  100. strcpy( DibIconInfos[ DIBICON_NOTACCEPT ].szFile, "dib_acp2.bmp" );
  101. strcpy( DibIconInfos[ DIBICON_USER ].szFile, "dib_user.bmp" );
  102. strcpy( DibIconInfos[ DIBICON_PRIVATE ].szFile, "privgame.bmp" );
  103. strcpy( DibIconInfos[ DIBICON_TOURNAMENT ].szFile, "tourgame.bmp" );
  104. strcpy( DibIconInfos[ DIBICON_VOICE ].szFile, "voice.bmp" );
  105. for( int i = 0; i != NUMDIBICONS; i++ )
  106. {
  107. DibIconInfos[ i ].hDIB = 0;
  108. DibIconInfos[ i ].pDIB = NULL;
  109. }
  110. // Determine name of executable of user's web browser.
  111. // This seems to be the "correct" way to do this, but it's bloody stupid.
  112. *szWebBrowser = 0;
  113. char szFile[] = "\\name_unlikely_to_conflict_77.html"; //"\\it is really dumb for me to have to create this file.html";
  114. HANDLE hFile = ::CreateFile( szFile, GENERIC_WRITE, NULL, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
  115. if( hFile != INVALID_HANDLE_VALUE )
  116. {
  117. ::CloseHandle( hFile );
  118. HINSTANCE hExecutable = ::FindExecutable( szFile, "", szWebBrowser );
  119. // if( (int)hExecutable <= 32 )
  120. // {
  121. // debugprint( "error %i getting browser\n", hExecutable );
  122. // }
  123. // else
  124. // debugprint( "szWebBrowser is %s\n", szWebBrowser );
  125. ::DeleteFile( szFile );
  126. }
  127. }
  128. //***********************************************************************************************
  129. WolapiObject::~WolapiObject()
  130. {
  131. DeleteSavedChat();
  132. if( nGameTypeInfos )
  133. {
  134. // Delete DIBs that were created, and the wol_gametypeinfos themselves
  135. for( unsigned int n = 0; n != nGameTypeInfos; n++ )
  136. {
  137. if( GameTypeInfos[ n ].hDIB )
  138. {
  139. GlobalUnlock( GameTypeInfos[ n ].hDIB ); // Release pDIB.
  140. DestroyDIB( GameTypeInfos[ n ].hDIB ); // Destroy mem alloc'ed for dib bits data.
  141. }
  142. }
  143. delete [] GameTypeInfos;
  144. GameTypeInfos = NULL;
  145. }
  146. for( int i = 0; i != NUMDIBICONS; i++ )
  147. {
  148. if( DibIconInfos[ i ].pDIB )
  149. {
  150. GlobalUnlock( DibIconInfos[ i ].hDIB );
  151. DestroyDIB( DibIconInfos[ i ].hDIB );
  152. }
  153. }
  154. if( pChatSink )
  155. UnsetupCOMStuff();
  156. // Delete buttons, etc., shared by dialogs.
  157. delete pShpBtnDiscon;
  158. delete pShpBtnLeave;
  159. delete pShpBtnRefresh;
  160. delete pShpBtnSquelch;
  161. delete pShpBtnBan;
  162. delete pShpBtnKick;
  163. delete pShpBtnFindpage;
  164. delete pShpBtnOptions;
  165. delete pShpBtnLadder;
  166. delete pShpBtnHelp;
  167. // Delete shared tooltips.
  168. delete pTTipDiscon;
  169. delete pTTipLeave;
  170. delete pTTipRefresh;
  171. delete pTTipSquelch;
  172. delete pTTipBan;
  173. delete pTTipKick;
  174. delete pTTipFindpage;
  175. delete pTTipOptions;
  176. delete pTTipLadder;
  177. delete pTTipHelp;
  178. }
  179. //***********************************************************************************************
  180. bool WolapiObject::bSetupCOMStuff()
  181. {
  182. // debugprint( "++++Begin WolapiObject::bSetupCOMStuff\n" );
  183. HRESULT hRes;
  184. // Grab IChat, INetUtil, set up "sinks".
  185. // debugprint( "CoCreateInstance\n" );
  186. CoCreateInstance( CLSID_Chat, NULL, CLSCTX_INPROC_SERVER, IID_IChat, (void**)&pChat );
  187. if( !pChat )
  188. return false; // Severe, essentially fatal.
  189. CoCreateInstance( CLSID_NetUtil, NULL, CLSCTX_INPROC_SERVER, IID_INetUtil, (void**)&pNetUtil );
  190. if( !pNetUtil )
  191. return false; // Severe, essentially fatal.
  192. // Set up RAChatEventSink.
  193. pChatSink = new RAChatEventSink( this );
  194. pChatSink->AddRef();
  195. // Set up RANetUtilEventSink.
  196. pNetUtilSink = new RANetUtilEventSink( this );
  197. pNetUtilSink->AddRef();
  198. // If we could use ATL stuff, this would be different. (We'd use AtlAdvise.)
  199. IConnectionPoint* pConnectionPoint = NULL;
  200. IConnectionPointContainer* pContainer = NULL;
  201. // Get a connection point from the chat class for the chatsink.
  202. // debugprint( "QueryInterface\n" );
  203. hRes = pChat->QueryInterface( IID_IConnectionPointContainer, (void**)&pContainer );
  204. if( !SUCCEEDED(hRes) )
  205. return false; // Severe, essentially fatal.
  206. // debugprint( "FindConnectionPoint\n" );
  207. hRes = pContainer->FindConnectionPoint( IID_IChatEvent, &pConnectionPoint );
  208. if( !SUCCEEDED(hRes) )
  209. return false; // Severe, essentially fatal.
  210. // Connect chat to chatsink.
  211. // debugprint( "Advise. pChatSink = %i, pConnectionPoint = %i\n", pChatSink, pConnectionPoint );
  212. hRes = pConnectionPoint->Advise( (IChatEvent*)pChatSink, &dwChatAdvise );
  213. if( !SUCCEEDED(hRes) )
  214. return false; // Severe, essentially fatal.
  215. pContainer->Release();
  216. pConnectionPoint->Release();
  217. pConnectionPoint = NULL;
  218. pContainer = NULL;
  219. // Get a connection point from the netutil class for the netutilsink.
  220. // debugprint( "QueryInterface\n" );
  221. hRes = pNetUtil->QueryInterface( IID_IConnectionPointContainer, (void**)&pContainer );
  222. if( !SUCCEEDED(hRes) )
  223. return false; // Severe, essentially fatal.
  224. // debugprint( "FindConnectionPoint\n" );
  225. hRes = pContainer->FindConnectionPoint( IID_INetUtilEvent, &pConnectionPoint );
  226. if( !SUCCEEDED(hRes) )
  227. return false; // Severe, essentially fatal.
  228. // Connect netutil to netutilsink.
  229. // debugprint( "Advise. pChatSink = %i, pConnectionPoint = %i\n", pChatSink, pConnectionPoint );
  230. hRes = pConnectionPoint->Advise( (INetUtilEvent*)pNetUtilSink, &dwNetUtilAdvise );
  231. if( !SUCCEEDED(hRes) )
  232. return false; // Severe, essentially fatal.
  233. pContainer->Release();
  234. pConnectionPoint->Release();
  235. // debugprint( "++++End WolapiObject::bSetupCOMStuff\n" );
  236. return true;
  237. }
  238. //***********************************************************************************************
  239. void WolapiObject::UnsetupCOMStuff()
  240. {
  241. // debugprint( "----Begin WolapiObject::UnsetupCOMStuff\n" );
  242. HRESULT hRes;
  243. // If we could use ATL stuff, this would be different. (We'd use AtlUnadvise.)
  244. // Unsetup RAChatEventSink and RANetUtilEventSink, release IChat.
  245. IConnectionPoint* pConnectionPoint = NULL;
  246. IConnectionPointContainer* pContainer = NULL;
  247. // debugprint( "QueryInterface\n" );
  248. hRes = pChat->QueryInterface( IID_IConnectionPointContainer, (void**)&pContainer );
  249. _ASSERTE(SUCCEEDED(hRes));
  250. // debugprint( "FindConnectionPoint\n" );
  251. hRes = pContainer->FindConnectionPoint( IID_IChatEvent, &pConnectionPoint );
  252. _ASSERTE(SUCCEEDED(hRes));
  253. // debugprint( "Unadvise: %i\n", dwChatAdvise );
  254. pConnectionPoint->Unadvise( dwChatAdvise );
  255. pContainer->Release();
  256. pConnectionPoint->Release();
  257. pConnectionPoint = NULL;
  258. pContainer = NULL;
  259. // debugprint( "QueryInterface\n" );
  260. hRes = pNetUtil->QueryInterface( IID_IConnectionPointContainer, (void**)&pContainer );
  261. _ASSERTE(SUCCEEDED(hRes));
  262. // debugprint( "FindConnectionPoint\n" );
  263. hRes = pContainer->FindConnectionPoint( IID_INetUtilEvent, &pConnectionPoint );
  264. _ASSERTE(SUCCEEDED(hRes));
  265. // debugprint( "Unadvise: %i\n", dwNetUtilAdvise );
  266. pConnectionPoint->Unadvise( dwNetUtilAdvise );
  267. pContainer->Release();
  268. pConnectionPoint->Release();
  269. // debugprint( "pChat->Release\n" );
  270. pChat->Release();
  271. // debugprint( "pChatSink->Release\n" );
  272. pChatSink->Release(); // This results in pChatSink deleting itself for us.
  273. pChatSink = NULL;
  274. // debugprint( "pNetUtil->Release\n" );
  275. pNetUtil->Release();
  276. // debugprint( "pNetUtilSink->Release\n" );
  277. pNetUtilSink->Release(); // This results in pChatSink deleting itself for us.
  278. pNetUtilSink = NULL;
  279. // debugprint( "----End WolapiObject::UnsetupCOMStuff\n" );
  280. }
  281. //***********************************************************************************************
  282. void WolapiObject::LinkToChatDlg( IconListClass* pILChat, IconListClass* pILChannels, IconListClass* pILUsers, StaticButtonClass* pStaticUsers )
  283. {
  284. // Called to initialize this before the chat dialog is shown.
  285. // Set pointers to lists in dialog.
  286. this->pILChat = pILChat;
  287. this->pILChannels = pILChannels;
  288. this->pILUsers = pILUsers;
  289. this->pStaticUsers = pStaticUsers;
  290. }
  291. //***********************************************************************************************
  292. void WolapiObject::ClearListPtrs()
  293. {
  294. // Called to clear list pointers when chat or gamesetup dialog goes away, for safety.
  295. pILChat = NULL;
  296. pILChannels = NULL;
  297. pILUsers = NULL;
  298. pILPlayers = NULL;
  299. pStaticUsers = NULL;
  300. }
  301. //***********************************************************************************************
  302. void WolapiObject::LinkToGameDlg( IconListClass* pILDisc, IconListClass* pILPlayers )
  303. {
  304. // Called to initialize this before the gamesetup dialog is shown.
  305. // Set pointers to lists in dialog.
  306. pILChat = pILDisc;
  307. this->pILPlayers = pILPlayers;
  308. }
  309. //***********************************************************************************************
  310. void WolapiObject::PrepareButtonsAndIcons()
  311. {
  312. // Load shapes for buttons. Store images in this order: up, down, disabled.
  313. //pShpDiscon = LoadShpFile( "discon.shp" ); etc
  314. pShpDiscon = (char*)MFCD::Retrieve( "discon.shp" );
  315. pShpLeave = (char*)MFCD::Retrieve( "leave.shp" );
  316. pShpRefresh = (char*)MFCD::Retrieve( "refresh.shp" );
  317. pShpSquelch = (char*)MFCD::Retrieve( "squelch.shp" );
  318. pShpBan = (char*)MFCD::Retrieve( "ban.shp" );
  319. pShpKick = (char*)MFCD::Retrieve( "kick.shp" );
  320. pShpFindpage = (char*)MFCD::Retrieve( "findpage.shp" );
  321. pShpOptions = (char*)MFCD::Retrieve( "ops.shp" );
  322. pShpLadder = (char*)MFCD::Retrieve( "ladder.shp" );
  323. pShpHelp = (char*)MFCD::Retrieve( "help.shp" );
  324. // Set up standard wol buttons, used by both main dialogs. Note hardcoded ID values: must match values in dialog.
  325. int iWolButtons_x = 34;
  326. int iWolButtons_y = 20;
  327. int iWolButtons_dx = 53;
  328. int xWolButton = iWolButtons_x;
  329. int xTTip = 10; // Offset for tooltip.
  330. int yTTip = - 5; // Offset for tooltip.
  331. pShpBtnDiscon = new ShapeButtonClass( 100, pShpDiscon, xWolButton, iWolButtons_y );
  332. pTTipDiscon = new ToolTipClass( pShpBtnDiscon, TXT_WOL_TTIP_DISCON, xWolButton + xTTip, iWolButtons_y + yTTip );
  333. xWolButton += iWolButtons_dx;
  334. pShpBtnLeave = new ShapeButtonClass( 101, pShpLeave, xWolButton, iWolButtons_y );
  335. pTTipLeave = new ToolTipClass( pShpBtnLeave, TXT_WOL_TTIP_LEAVE, xWolButton + xTTip, iWolButtons_y + yTTip );
  336. xWolButton += iWolButtons_dx;
  337. pShpBtnRefresh = new ShapeButtonClass( 102, pShpRefresh, xWolButton, iWolButtons_y );
  338. pTTipRefresh = new ToolTipClass( pShpBtnRefresh, TXT_WOL_TTIP_REFRESH, xWolButton + xTTip, iWolButtons_y + yTTip );
  339. xWolButton += iWolButtons_dx;
  340. pShpBtnSquelch = new ShapeButtonClass( 103, pShpSquelch, xWolButton, iWolButtons_y );
  341. pTTipSquelch = new ToolTipClass( pShpBtnSquelch, TXT_WOL_TTIP_SQUELCH, xWolButton + xTTip, iWolButtons_y + yTTip );
  342. xWolButton += iWolButtons_dx;
  343. pShpBtnBan = new ShapeButtonClass( 104, pShpBan, xWolButton, iWolButtons_y );
  344. pTTipBan = new ToolTipClass( pShpBtnBan, TXT_WOL_TTIP_BAN, xWolButton + xTTip, iWolButtons_y + yTTip );
  345. xWolButton += iWolButtons_dx;
  346. pShpBtnKick = new ShapeButtonClass( 105, pShpKick, xWolButton, iWolButtons_y );
  347. pTTipKick = new ToolTipClass( pShpBtnKick, TXT_WOL_TTIP_KICK, xWolButton + xTTip, iWolButtons_y + yTTip );
  348. xWolButton += iWolButtons_dx;
  349. pShpBtnFindpage = new ShapeButtonClass( 106, pShpFindpage, xWolButton, iWolButtons_y );
  350. pTTipFindpage = new ToolTipClass( pShpBtnFindpage, TXT_WOL_TTIP_FINDPAGE, xWolButton + xTTip, iWolButtons_y + yTTip );
  351. xWolButton = 452;
  352. pShpBtnOptions = new ShapeButtonClass( 107, pShpOptions, xWolButton, iWolButtons_y );
  353. pTTipOptions = new ToolTipClass( pShpBtnOptions, TXT_WOL_TTIP_OPTIONS, xWolButton + xTTip, iWolButtons_y + yTTip, true );
  354. xWolButton += iWolButtons_dx;
  355. pShpBtnLadder = new ShapeButtonClass( 108, pShpLadder, xWolButton, iWolButtons_y );
  356. pTTipLadder = new ToolTipClass( pShpBtnLadder, TXT_WOL_TTIP_LADDER, xWolButton + xTTip, iWolButtons_y + yTTip, true );
  357. xWolButton += iWolButtons_dx;
  358. pShpBtnHelp = new ShapeButtonClass( 109, pShpHelp, xWolButton, iWolButtons_y );
  359. pTTipHelp = new ToolTipClass( pShpBtnHelp, TXT_WOL_TTIP_HELP, xWolButton + xTTip, iWolButtons_y + yTTip, true );
  360. // Load standard hard-coded icons.
  361. HPALETTE hPal = GetCurrentScreenPalette();
  362. int iFileLength;
  363. const char* pFileData;
  364. for( int iDibIcon = 0; iDibIcon != NUMDIBICONS; iDibIcon++ )
  365. {
  366. //pFileData = LoadFileIntoMemory( DibIconInfos[ iDibIcon ].szFile, iFileLength );
  367. pFileData = (char*)MFCD::Retrieve( DibIconInfos[ iDibIcon ].szFile );
  368. if( pFileData )
  369. {
  370. CCFileClass ccfileDib( DibIconInfos[ iDibIcon ].szFile );
  371. iFileLength = ccfileDib.Size();
  372. //debugprint( "Loaded %s, size is %i.\n", DibIconInfos[ iDibIcon ].szFile, iFileLength );
  373. DibIconInfos[ iDibIcon ].hDIB = LoadDIB_FromMemory( (unsigned char*)pFileData, iFileLength );
  374. if( DibIconInfos[ iDibIcon ].hDIB )
  375. {
  376. DibIconInfos[ iDibIcon ].pDIB = (char*)GlobalLock( DibIconInfos[ iDibIcon ].hDIB );
  377. RemapDIBToPalette( hPal, DibIconInfos[ iDibIcon ].pDIB );
  378. }
  379. // else
  380. // debugprint( "LoadDIB_FromMemory failed!\n" );
  381. }
  382. // else
  383. // debugprint( "Couldn't find %s in mix.\n", DibIconInfos[ iDibIcon ].szFile );
  384. }
  385. if( DibIconInfos[ DIBICON_LATENCY ].pDIB )
  386. fLatencyToIconWidth = (float)DIBWidth( DibIconInfos[ DIBICON_LATENCY ].pDIB ) / 1000;
  387. else
  388. fLatencyToIconWidth = 0;
  389. // All of the following is for the list of game icons...
  390. // Load game icons from the wol api.
  391. LPCSTR szSkus;
  392. if( pChat->GetGametypeList( &szSkus ) == S_OK )
  393. {
  394. // Make two copies of szSkus because strtok insists on messing with them.
  395. char* szSkus1 = new char[ strlen( szSkus ) + 1 ];
  396. char* szSkus2 = new char[ strlen( szSkus ) + 1 ];
  397. strcpy( szSkus1, szSkus );
  398. strcpy( szSkus2, szSkus );
  399. // Count commas.
  400. char seps[] = ",";
  401. char* token;
  402. nGameTypeInfos = 0;
  403. token = strtok( szSkus1, seps );
  404. while( token != NULL )
  405. {
  406. nGameTypeInfos++;
  407. token = strtok( NULL, seps );
  408. }
  409. // There are actually 2 additional game types available in wolapi - 0 (ws icon) and -1 (wwonline icon).
  410. nGameTypeInfos += 2;
  411. // Create structs to hold infos.
  412. // debugprint( "Creating %i gametypeinfos\n", nGameTypeInfos );
  413. GameTypeInfos = new WOL_GAMETYPEINFO[ nGameTypeInfos ];
  414. int iMyIndex = 0;
  415. token = strtok( szSkus2, seps );
  416. while( token != NULL )
  417. {
  418. GetGameTypeInfo( atoi( token ), GameTypeInfos[ iMyIndex ], hPal );
  419. token = strtok( NULL, seps );
  420. iMyIndex++;
  421. }
  422. // Get the two extra game type infos...
  423. GetGameTypeInfo( -1, GameTypeInfos[ iMyIndex++ ], hPal );
  424. GetGameTypeInfo( 0, GameTypeInfos[ iMyIndex++ ], hPal );
  425. }
  426. // else
  427. // debugprint( "GetGametypeList() failed.\n" );
  428. // Load icons that we'll need to represent Red Alert GameKinds.
  429. // These are available in wolapi at their old sku number locations.
  430. GetGameTypeInfo( 2, OldRAGameTypeInfos[ 0 ], hPal ); // RA
  431. GetGameTypeInfo( 3, OldRAGameTypeInfos[ 1 ], hPal ); // CS
  432. GetGameTypeInfo( 4, OldRAGameTypeInfos[ 2 ], hPal ); // AM
  433. if( hPal )
  434. DeleteObject( hPal );
  435. }
  436. //***********************************************************************************************
  437. void WolapiObject::GetGameTypeInfo( int iGameType, WOL_GAMETYPEINFO& GameTypeInfo, HPALETTE hPal )
  438. {
  439. unsigned char* pVirtualFile;
  440. int iFileLength;
  441. // debugprint( "GetGametypeInfo, type %i\n", iGameType );
  442. LPCSTR szName;
  443. LPCSTR szURL;
  444. pChat->GetGametypeInfo( iGameType, 12, &pVirtualFile, &iFileLength, &szName, &szURL );
  445. GameTypeInfo.iGameType = iGameType;
  446. if( szName )
  447. strcpy( GameTypeInfo.szName, szName );
  448. else
  449. *GameTypeInfo.szName = 0;
  450. if( szURL )
  451. strcpy( GameTypeInfo.szURL, szURL );
  452. else
  453. *GameTypeInfo.szURL = 0;
  454. // debugprint( "LoadDIB_FromMemory( %i, %i )\n", pVirtualFile, iFileLength );
  455. // Create a DIB by "loading" (as if it was a file) the bitmap data.
  456. GameTypeInfo.hDIB = LoadDIB_FromMemory( pVirtualFile, iFileLength );
  457. // debugprint( "hDIB is %i\n", GameTypeInfo.hDIB );
  458. if( !GameTypeInfo.hDIB )
  459. {
  460. GameTypeInfo.pDIB = NULL;
  461. return; // Load failed. Should not ever happen.
  462. }
  463. GameTypeInfo.pDIB = (const char*)GlobalLock( GameTypeInfo.hDIB );
  464. // debugprint( "@@@@@ Created gametypeinfo #%i: name %s, pDIB = %i\n", iIndex, GameTypeInfo.szName, GameTypeInfo.pDIB );
  465. LPBITMAPINFOHEADER lpbi = (LPBITMAPINFOHEADER)GameTypeInfo.pDIB;
  466. if( lpbi->biBitCount != 8 )
  467. {
  468. // Do not use this loaded bmp, as it's not 256 color.
  469. GlobalUnlock( GameTypeInfo.hDIB ); // Release pDIB.
  470. GameTypeInfo.pDIB = NULL;
  471. DestroyDIB( GameTypeInfo.hDIB ); // Destroy mem alloc'ed for dib bits data.
  472. GameTypeInfo.hDIB = 0;
  473. return;
  474. }
  475. // Remap colors...
  476. RemapDIBToPalette( hPal, GameTypeInfo.pDIB );
  477. }
  478. //***********************************************************************************************
  479. void* WolapiObject::IconForGameType( int iGameType )
  480. {
  481. // Returns a GameTypeInfos entry by gametype, instead of our (potentially arbitrary) index.
  482. // Returns NULL if type not found in list, which will of course never happen...
  483. for( int i = 0; i != nGameTypeInfos; i++ )
  484. {
  485. if( GameTypeInfos[i].iGameType == iGameType )
  486. return (void*)GameTypeInfos[i].pDIB;
  487. }
  488. return NULL;
  489. }
  490. //***********************************************************************************************
  491. const char* WolapiObject::NameOfGameType( int iGameType ) const
  492. {
  493. // Returns the name of a sku by gametype, instead of our (potentially arbitrary) index.
  494. // Returns NULL if type not found in list, which will of course never happen...
  495. for( int i = 0; i != nGameTypeInfos; i++ )
  496. {
  497. if( GameTypeInfos[i].iGameType == iGameType )
  498. return GameTypeInfos[i].szName;
  499. }
  500. return NULL;
  501. }
  502. //***********************************************************************************************
  503. const char* WolapiObject::URLForGameType( int iGameType ) const
  504. {
  505. // Returns NULL if type not found in list, which will of course never happen...
  506. for( int i = 0; i != nGameTypeInfos; i++ )
  507. {
  508. if( GameTypeInfos[i].iGameType == iGameType )
  509. return GameTypeInfos[i].szURL;
  510. }
  511. return NULL;
  512. }
  513. //***********************************************************************************************
  514. void WolapiObject::PrintMessage( const char* szText, PlayerColorType iColorRemap /* = PCOLOR_NONE */ )
  515. {
  516. if( pILChat )
  517. WOL_PrintMessage( *pILChat, szText, iColorRemap );
  518. }
  519. //***********************************************************************************************
  520. void WolapiObject::PrintMessage( const char* szText, RemapControlType* pColorRemap )
  521. {
  522. if( pILChat )
  523. WOL_PrintMessage( *pILChat, szText, pColorRemap );
  524. }
  525. //***********************************************************************************************
  526. HRESULT WolapiObject::GetChatServer()
  527. {
  528. // Calls RequestServerList() to get a chat server ready for us to login to.
  529. // Returns S_OK and sets pChatSink->pServer if successful.
  530. WWMessageBox().Process( TXT_WOL_CONNECTING, TXT_NONE );
  531. //if( !( ::GetAsyncKeyState( VK_SHIFT ) & 0x8000 ) ) // ajw - allow use of test servers
  532. //{
  533. // Request chat server address from server server.
  534. pChatSink->bRequestServerListWait = true;
  535. // debugprint( "Calling RequestServerList...\n" );
  536. if( !SUCCEEDED( pChat->RequestServerList( GAME_SKU, GAME_VERSION, "unused", "unused", 5 ) ) )
  537. {
  538. // debugprint( "RequestServerList call failed\n" );
  539. return E_FAIL;
  540. }
  541. DWORD dwTimeLimit = timeGetTime(); // ajw My own extra timeout at one minute, in case wolapi chokes.
  542. // debugprint( "Called RequestServerList...\n" );
  543. DWORD dwTimeNextPump = timeGetTime() + PUMPSLEEPDURATION;
  544. ::GetAsyncKeyState( VK_ESCAPE ); // Set up for escape key checking.
  545. bool bCancel = false;
  546. hresPatchResults = 0;
  547. while( pChatSink->bRequestServerListWait && timeGetTime() - dwTimeLimit < 60000 )
  548. {
  549. while( timeGetTime() < dwTimeNextPump )
  550. {
  551. Call_Back();
  552. if( ::GetAsyncKeyState( VK_ESCAPE ) & 1 )
  553. {
  554. bCancel = true;
  555. break;
  556. }
  557. }
  558. // debugprint( "PumpMessages after RequestServerList...\n" );
  559. pChat->PumpMessages();
  560. dwTimeNextPump = timeGetTime() + PUMPSLEEPDURATION;
  561. // Sleep( PUMPSLEEPDURATION ); // Can't do because we want to Call_Back()
  562. // If an "update list" of patches has been received, instead of a server list, this flag will have been set
  563. // for us describing the results. We'll either cancel log in or trigger game exit.
  564. if( hresPatchResults )
  565. {
  566. pChatSink->bRequestServerListWait = false;
  567. return hresPatchResults;
  568. }
  569. }
  570. // debugprint( "RequestServerList wait finished\n" );
  571. if( bCancel )
  572. {
  573. Keyboard->Clear();
  574. return USERCANCELLED;
  575. }
  576. if( pChatSink->pServer )
  577. return S_OK;
  578. else
  579. return E_FAIL;
  580. /*
  581. }
  582. else
  583. {
  584. // Test using local server on LAN.
  585. // Bypass RequestServerList, as it is unnecessary and may not be possible if serverserver can't be reached.
  586. // Set SKU manually because normally RequestServerList does this for you.
  587. pChat->SetProductSKU( GAME_SKU );
  588. if( pChatSink->pServer )
  589. delete pChatSink->pServer;
  590. pChatSink->pServer = new Server;
  591. if( !( ::GetAsyncKeyState( VK_CONTROL ) & 0x8000 ) )
  592. strcpy( (char*)pChatSink->pServer->conndata, "TCP;irc.westwood.com;9000" );
  593. else
  594. // Control key down as well.
  595. strcpy( (char*)pChatSink->pServer->conndata, "TCP;10.2.20.28;4000" );
  596. strcpy( (char*)pChatSink->pServer->connlabel, "IRC" );
  597. strcpy( (char*)pChatSink->pServer->name, "Chat");
  598. return S_OK;
  599. }
  600. */
  601. }
  602. //***********************************************************************************************
  603. HRESULT WolapiObject::AttemptLogin( const char* szName, const char* szPass, bool bPassIsMangled )
  604. {
  605. // If RequestConnection() succeeds, sets pChatSink->bConnected true and returns S_OK.
  606. // Else returns RequestConnection() error result.
  607. WWMessageBox().Process( TXT_WOL_ATTEMPTLOGIN, TXT_NONE );
  608. // debugprint( "~1\n" );
  609. strcpy( (char*)pChatSink->pServer->login, szName );
  610. strcpy( (char*)pChatSink->pServer->password, szPass );
  611. /*
  612. // debugprint( "RequestConnection with:\n%s,%s,%s,%s,%s - %s\n",
  613. pChatSink->pServer->name,
  614. pChatSink->pServer->connlabel,
  615. pChatSink->pServer->conndata,
  616. pChatSink->pServer->login,
  617. pChatSink->pServer->password,
  618. bPassIsMangled ? "(mangled)" : "(unmangled)" );
  619. */
  620. pChatSink->bRequestConnectionWait = true;
  621. pChatSink->hresRequestConnectionError = 0;
  622. if( !SUCCEEDED( pChat->RequestConnection( pChatSink->pServer, 15, !bPassIsMangled ) ) )
  623. {
  624. // debugprint( "RequestConnection call failed\n" );
  625. return CHAT_E_CON_ERROR;
  626. }
  627. DWORD dwTimeStart = timeGetTime();
  628. DWORD dwTimeNextPump = timeGetTime() + PUMPSLEEPDURATION;
  629. ::GetAsyncKeyState( VK_ESCAPE ); // Set up for escape key checking.
  630. bool bCancel = false;
  631. while( pChatSink->bRequestConnectionWait && timeGetTime() - dwTimeStart < EMERGENCY_TIMEOUT )
  632. {
  633. while( timeGetTime() < dwTimeNextPump )
  634. {
  635. Call_Back();
  636. if( ::GetAsyncKeyState( VK_ESCAPE ) & 1 )
  637. {
  638. bCancel = true;
  639. break;
  640. }
  641. }
  642. if( bCancel )
  643. break;
  644. pChat->PumpMessages();
  645. dwTimeNextPump = timeGetTime() + PUMPSLEEPDURATION;
  646. // Sleep( PUMPSLEEPDURATION ); // Can't do because we want to Call_Back()
  647. }
  648. if( bCancel )
  649. {
  650. Keyboard->Clear();
  651. return USERCANCELLED;
  652. }
  653. if( pChatSink->bRequestConnectionWait )
  654. return CHAT_E_CON_ERROR;
  655. if( pChatSink->bConnected )
  656. {
  657. strcpy( szMyName, szName );
  658. strcpy( szMyRecord, szName );
  659. strcpy( szMyRecordAM, szName );
  660. return S_OK;
  661. }
  662. else
  663. return pChatSink->hresRequestConnectionError;
  664. }
  665. //***********************************************************************************************
  666. bool WolapiObject::bLoggedIn()
  667. {
  668. return pChatSink->bConnected;
  669. }
  670. //***********************************************************************************************
  671. void WolapiObject::Logout()
  672. {
  673. // Requests logout from wolapi. Doesn't return any error values, as what we would do if it
  674. // failed - force the user to stay connected?
  675. if( bSelfDestruct )
  676. WWMessageBox().Process( TXT_WOL_ERRORLOGOUT, TXT_NONE );
  677. else
  678. WWMessageBox().Process( TXT_WOL_ATTEMPTLOGOUT, TXT_NONE );
  679. // debugprint( "RequestLogout()\n" );
  680. pChatSink->bRequestLogoutWait = true;
  681. if( !SUCCEEDED( pChat->RequestLogout() ) )
  682. {
  683. // debugprint( "RequestLogout() call failed\n" );
  684. }
  685. DWORD dwTimePatience = timeGetTime(); // After 5 seconds we run out of patience and bail.
  686. DWORD dwTimeNextPump = timeGetTime() + PUMPSLEEPDURATION;
  687. while( pChatSink->bRequestLogoutWait && timeGetTime() - dwTimePatience < 5000 )
  688. {
  689. while( timeGetTime() < dwTimeNextPump )
  690. Call_Back();
  691. pChat->PumpMessages();
  692. dwTimeNextPump = timeGetTime() + PUMPSLEEPDURATION;
  693. }
  694. pChatSink->bConnected = false;
  695. *szMyName = 0;
  696. Sound_Effect( WOLSOUND_LOGOUT );
  697. }
  698. //***********************************************************************************************
  699. bool WolapiObject::UpdateChannels( int iChannelType, CHANNELFILTER ChannelFilter, bool bAutoping )
  700. {
  701. // This is now non-modal.
  702. // Sends off a request for a new channels list.
  703. // // Returns false upon total failure.
  704. // WWMessageBox().Process( TXT_WOL_WAIT, TXT_NONE );
  705. // pChatSink->bRequestChannelListWait = true;
  706. pChatSink->ChannelFilter = ChannelFilter;
  707. // debugprint( "RequestChannelList(), iChannelType = %i, filter = %i\n", iChannelType, ChannelFilter );
  708. if( !SUCCEEDED( pChat->RequestChannelList( iChannelType, bAutoping ) ) )
  709. {
  710. // debugprint( "RequestChannelList() call failed\n" );
  711. return false;
  712. }
  713. /*
  714. DWORD dwTimeStart = timeGetTime();
  715. DWORD dwTimeNextPump = timeGetTime() + PUMPSLEEPDURATION;
  716. while( pChatSink->bRequestChannelListWait && timeGetTime() - dwTimeStart < EMERGENCY_TIMEOUT )
  717. {
  718. while( timeGetTime() < dwTimeNextPump )
  719. Call_Back();
  720. pChat->PumpMessages();
  721. dwTimeNextPump = timeGetTime() + PUMPSLEEPDURATION;
  722. }
  723. if( pChatSink->bRequestChannelListWait )
  724. return false;
  725. */
  726. LastUpdateChannelCallLevel = CurrentLevel;
  727. return true;
  728. }
  729. //***********************************************************************************************
  730. void WolapiObject::OnChannelList()
  731. {
  732. // The chatsink calls this when its OnChannelList() is called, and it has remade its internal channel list.
  733. // The question here is: should we display the values now in the chatsink?
  734. // As UpdateChannels() is now non-modal, there is the danger that we have moved away from the place in
  735. // the channel heirarchy where we originally called RequestChannelList().
  736. // To help ensure we're getting this where we expect to get it, we check the value of CurrentLevel against
  737. // what it was when we called UpdateChannels().
  738. if( CurrentLevel == LastUpdateChannelCallLevel )
  739. ListChannels();
  740. }
  741. //***********************************************************************************************
  742. void WolapiObject::ListChannels()
  743. {
  744. // Show pChatSink's pChannelList in pILChannels.
  745. // The extra data ptr hidden in each list item will hold a void pointer to the channel described.
  746. // debugprint( "ListChannels(), pChannelList = %i\n", pChatSink->pChannelList );
  747. static WOL_LEVEL LevelLastListed = WOL_LEVEL_INVALID;
  748. int iListViewIndex = 0;
  749. // If redrawing the same list as before, preserve the view position.
  750. if( LevelLastListed == CurrentLevel )
  751. iListViewIndex = pILChannels->Get_View_Index();
  752. else
  753. LevelLastListed = CurrentLevel;
  754. pILChannels->Clear();
  755. switch( CurrentLevel )
  756. {
  757. case WOL_LEVEL_GAMESOFTYPE:
  758. pILChannels->Add_Item( TXT_WOL_CHANNEL_BACK, CHANNELTYPE_GAMES, NULL, ICON_SHAPE, CHANNELTYPE_GAMES );
  759. break;
  760. case WOL_LEVEL_LOBBIES:
  761. pILChannels->Add_Item( TXT_WOL_CHANNEL_BACK, CHANNELTYPE_GAMES, NULL, ICON_SHAPE, CHANNELTYPE_GAMES );
  762. break;
  763. case WOL_LEVEL_INLOBBY:
  764. pILChannels->Add_Item( TXT_WOL_CHANNEL_BACK, CHANNELTYPE_LOBBIES, NULL, ICON_SHAPE, CHANNELTYPE_LOBBIES );
  765. break;
  766. default:
  767. pILChannels->Add_Item( TXT_WOL_CHANNEL_TOP, CHANNELTYPE_TOP, NULL, ICON_SHAPE, CHANNELTYPE_TOP );
  768. break;
  769. }
  770. Channel* pChannel = pChatSink->pChannelList;
  771. while( pChannel )
  772. {
  773. if( pChannel->type == 0 )
  774. {
  775. // Show chat channel.
  776. char* pShow;
  777. int iLobby = iChannelLobbyNumber( pChannel->name );
  778. if( iLobby == - 1 )
  779. {
  780. // Regular chat channel.
  781. pShow = new char[ strlen( (char*)pChannel->name ) + 10 ];
  782. sprintf( pShow, "%s\t%-3u", (char*)pChannel->name, pChannel->currentUsers );
  783. char szHelp[ 200 ];
  784. sprintf( szHelp, TXT_WOL_TTIP_CHANLIST_CHAT, (char*)pChannel->name, pChannel->currentUsers );
  785. pILChannels->Add_Item( pShow, szHelp, (void*)DibIconInfos[ DIBICON_USER ].pDIB, ICON_DIB, CHANNELTYPE_CHATCHANNEL, (void*)pChannel );
  786. }
  787. else
  788. {
  789. // Channel is a lobby.
  790. char szLobbyName[ REASONABLELOBBYINTERPRETEDNAMELEN ];
  791. InterpretLobbyNumber( szLobbyName, iLobby );
  792. pShow = new char[ REASONABLELOBBYINTERPRETEDNAMELEN + 10 ];
  793. sprintf( pShow, "%s\t%-3u", szLobbyName, pChannel->currentUsers );
  794. char szHelp[ 200 ];
  795. sprintf( szHelp, TXT_WOL_TTIP_CHANLIST_LOBBY, szLobbyName, pChannel->currentUsers );
  796. pILChannels->Add_Item( pShow, szHelp, IconForGameType( -1 ), ICON_DIB, CHANNELTYPE_LOBBYCHANNEL, (void*)pChannel );
  797. // debugprint( ":::::added pChannel %i, name %s, as %s\n", pChannel, pChannel->name, pShow );
  798. }
  799. delete [] pShow;
  800. }
  801. else
  802. {
  803. // Show game channel.
  804. char* pShow = new char[ strlen( (char*)pChannel->name ) + 10 ];
  805. char szHelp[ 200 ];
  806. void* pGameKindIcon;
  807. if( pChannel->type == GAME_TYPE )
  808. {
  809. // Get RedAlert GameKind.
  810. CREATEGAMEINFO::GAMEKIND GameKind = (CREATEGAMEINFO::GAMEKIND)( pChannel->reserved & 0xFF000000 );
  811. switch( GameKind )
  812. {
  813. case CREATEGAMEINFO::RAGAME:
  814. pGameKindIcon = (void*)OldRAGameTypeInfos[ 0 ].pDIB; // Red Alert icon
  815. sprintf( szHelp, TXT_WOL_TTIP_CHANLIST_RAGAME, TXT_WOL_TTIP_REDALERT,
  816. pChannel->currentUsers, pChannel->maxUsers );
  817. break;
  818. case CREATEGAMEINFO::CSGAME:
  819. pGameKindIcon = (void*)OldRAGameTypeInfos[ 1 ].pDIB; // CS icon
  820. sprintf( szHelp, TXT_WOL_TTIP_CHANLIST_RAGAME, TXT_WOL_TTIP_COUNTERSTRIKE,
  821. pChannel->currentUsers, pChannel->maxUsers );
  822. break;
  823. case CREATEGAMEINFO::AMGAME:
  824. pGameKindIcon = (void*)OldRAGameTypeInfos[ 2 ].pDIB; // AM icon
  825. sprintf( szHelp, TXT_WOL_TTIP_CHANLIST_RAGAME, TXT_WOL_TTIP_AFTERMATH,
  826. pChannel->currentUsers, pChannel->maxUsers );
  827. break;
  828. default:
  829. // debugprint( "Illegal value for GameKind channel reserved field: %s\n", (char*)pChannel->name );
  830. pGameKindIcon = NULL;
  831. break;
  832. }
  833. sprintf( pShow, "%s\t%u/%u", (char*)pChannel->name, pChannel->currentUsers, pChannel->maxUsers );
  834. }
  835. else
  836. {
  837. pGameKindIcon = IconForGameType( pChannel->type );
  838. sprintf( pShow, "%s\t%-2u", (char*)pChannel->name, pChannel->currentUsers );
  839. sprintf( szHelp, TXT_WOL_TTIP_CHANLIST_GAME, NameOfGameType( pChannel->type ),
  840. pChannel->currentUsers );
  841. }
  842. void* pPrivateIcon = NULL;
  843. if( pChannel->flags & CHAN_MODE_KEY )
  844. {
  845. // Game is private.
  846. pPrivateIcon = (void*)DibIconInfos[ DIBICON_PRIVATE ].pDIB;
  847. strcat( szHelp, TXT_WOL_TTIP_PRIVATEGAME );
  848. }
  849. void* pTournamentIcon = NULL;
  850. if( pChannel->tournament )
  851. {
  852. // Game is tournament.
  853. pTournamentIcon = (void*)DibIconInfos[ DIBICON_TOURNAMENT ].pDIB;
  854. strcat( szHelp, TXT_WOL_TTIP_TOURNAMENTGAME );
  855. }
  856. int iLatencyUse = pChannel->latency;
  857. if( iLatencyUse == -1 )
  858. iLatencyUse = 0;
  859. static int iLatencyBarX = 227 - DIBWidth( DibIconInfos[ DIBICON_LATENCY ].pDIB ) - 19;
  860. pILChannels->Add_Item( pShow, szHelp, pGameKindIcon, ICON_DIB,
  861. CHANNELTYPE_GAMECHANNEL, (void*)pChannel, NULL,
  862. pPrivateIcon, ICON_DIB, pTournamentIcon, ICON_DIB,
  863. (void*)DibIconInfos[ DIBICON_LATENCY ].pDIB, ICON_DIB,
  864. iLatencyBarX, 0, iLatencyUse * fLatencyToIconWidth );
  865. delete [] pShow;
  866. }
  867. pChannel = pChannel->next;
  868. }
  869. if( iListViewIndex )
  870. pILChannels->Set_View_Index( iListViewIndex ); // Not perfect but should keep list pretty stable on updates.
  871. }
  872. //***********************************************************************************************
  873. HRESULT WolapiObject::ChannelJoin( const char* szChannelName, const char* szKey )
  874. {
  875. // Used for CHAT channels (or lobbies) only. Channel type is set to 0.
  876. Channel ChannelTemp;
  877. memset( &ChannelTemp, 0, sizeof( ChannelTemp ) );
  878. strcpy( (char*)ChannelTemp.name, szChannelName );
  879. strcpy( (char*)ChannelTemp.key, szKey );
  880. return ChannelJoin( &ChannelTemp );
  881. }
  882. //***********************************************************************************************
  883. HRESULT WolapiObject::ChannelJoin( Channel* pChannelToJoin )
  884. {
  885. // Returns an HRESULT, the meaning of which is totally customized for my own uses.
  886. WWMessageBox().Process( TXT_WOL_WAIT, TXT_NONE );
  887. pChatSink->bRequestChannelJoinWait = true;
  888. pChatSink->hresRequestJoinResult = 0;
  889. // debugprint( "RequestChannelJoin(), %s\n", pChannelToJoin->name );
  890. HRESULT hRes = pChat->RequestChannelJoin( pChannelToJoin );
  891. if( !SUCCEEDED( hRes ) )
  892. {
  893. // debugprint( "RequestChannelJoin() call failed, result %i ", hRes );
  894. DebugChatDef( hRes );
  895. return E_FAIL;
  896. }
  897. pChatSink->bIgnoreChannelLists = true; // Turn off response to channel lists.
  898. DWORD dwTimeStart = timeGetTime();
  899. DWORD dwTimeNextPump = timeGetTime() + PUMPSLEEPDURATION;
  900. while( pChatSink->bRequestChannelJoinWait && timeGetTime() - dwTimeStart < EMERGENCY_TIMEOUT )
  901. {
  902. while( timeGetTime() < dwTimeNextPump )
  903. Call_Back();
  904. pChat->PumpMessages();
  905. dwTimeNextPump = timeGetTime() + PUMPSLEEPDURATION;
  906. }
  907. pChatSink->bIgnoreChannelLists = false; // Turn on response to channel lists.
  908. if( pChatSink->bRequestChannelJoinWait )
  909. return CHAT_E_TIMEOUT;
  910. switch( pChatSink->hresRequestJoinResult )
  911. {
  912. case CHAT_E_CHANNELDOESNOTEXIST:
  913. case CHAT_E_BADCHANNELPASSWORD:
  914. case CHAT_E_BANNED:
  915. case CHAT_E_CHANNELFULL:
  916. return pChatSink->hresRequestJoinResult;
  917. }
  918. if( !pChatSink->bJoined )
  919. return E_FAIL;
  920. return S_OK;
  921. }
  922. //***********************************************************************************************
  923. bool WolapiObject::ChannelLeave()
  924. {
  925. // Returns false upon total failure.
  926. WWMessageBox().Process( TXT_WOL_WAIT, TXT_NONE );
  927. pChatSink->bRequestChannelLeaveWait = true;
  928. pChatSink->DeleteUserList();
  929. // debugprint( "RequestChannelLeave()\n" );
  930. if( !SUCCEEDED( pChat->RequestChannelLeave() ) )
  931. {
  932. // debugprint( "RequestChannelLeave() call failed\n" );
  933. return false;
  934. }
  935. pChatSink->bIgnoreChannelLists = true; // Turn off response to channel lists.
  936. DWORD dwTimeStart = timeGetTime();
  937. DWORD dwTimeNextPump = timeGetTime() + PUMPSLEEPDURATION;
  938. while( pChatSink->bRequestChannelLeaveWait && timeGetTime() - dwTimeStart < EMERGENCY_TIMEOUT )
  939. {
  940. while( timeGetTime() < dwTimeNextPump )
  941. Call_Back();
  942. pChat->PumpMessages();
  943. dwTimeNextPump = timeGetTime() + PUMPSLEEPDURATION;
  944. }
  945. pChatSink->bIgnoreChannelLists = false;
  946. if( pChatSink->bRequestChannelLeaveWait || pChatSink->bJoined )
  947. return false;
  948. return true;
  949. }
  950. /*
  951. //***********************************************************************************************
  952. bool WolapiObject::UserList()
  953. {
  954. // Returns false upon total failure.
  955. WWMessageBox().Process( TXT_WOL_WAIT, TXT_NONE );
  956. pChatSink->bRequestUserListWait = true;
  957. // I no longer request a user list, as this was being done only when entering a channel, and it turns out wolapi gives
  958. // us a user list automatically when joining. This function is used as a blocker that waits until the user list has
  959. // definitely arrived.
  960. // debugprint( "RequestUserList()\n" );
  961. // if( !SUCCEEDED( pChat->RequestUserList() ) )
  962. // {
  963. // debugprint( "RequestUserList() call failed\n" );
  964. // return false;
  965. // }
  966. DWORD dwTimeStart = timeGetTime();
  967. DWORD dwTimeNextPump = timeGetTime() + PUMPSLEEPDURATION;
  968. while( pChatSink->bRequestUserListWait && timeGetTime() - dwTimeStart < EMERGENCY_TIMEOUT )
  969. {
  970. while( timeGetTime() < dwTimeNextPump )
  971. Call_Back();
  972. pChat->PumpMessages();
  973. dwTimeNextPump = timeGetTime() + PUMPSLEEPDURATION;
  974. }
  975. if( pChatSink->bRequestUserListWait )
  976. {
  977. pChatSink->bRequestUserListWait = false;
  978. return false;
  979. }
  980. return true;
  981. }
  982. */
  983. //***********************************************************************************************
  984. //typedef char CHANNELUSERNAME[ WOL_NAME_LEN_MAX ];
  985. struct CHANNELUSERINFO
  986. {
  987. char szName[ WOL_NAME_LEN_MAX ];
  988. bool bFlagged;
  989. RemapControlType* pColorRemap;
  990. HousesType House; // Only used if game channel.
  991. bool bAccept; // Only used if game channel.
  992. char szExtra[ 50 ]; // Only used if game channel.
  993. };
  994. //***********************************************************************************************
  995. bool WolapiObject::ListChannelUsers()
  996. {
  997. // Show pChatSink's pUserList in pILUsers or pILPlayers (depending on CurrentLevel), after clearing it.
  998. // The extra data ptr hidden in each list item will hold a void pointer to the user described.
  999. // For simplicity, I destroy the old list and write a new one, even though possibly only one item
  1000. // may have changed.
  1001. // In order for the multiselect flags in the list to persist, I record the names that are flagged
  1002. // before clearing the list, then reset them (if found) in the new list.
  1003. // This is inefficient, but should be fine in this non-time-critical situation.
  1004. // (I also save item color here, and save all items. Now it's really inefficient.)
  1005. // (Oh, boy. Now I've added the persistence of house info when this is a game channel...)
  1006. // The idea was to avoid duplication of player data, and not have any dependence on the integrity of the chatsink's
  1007. // players list. Now it is a case of it working "well enough" to not require time to elegantize it.
  1008. // Extra bonus, if useful: returns true if an operator (channel owner) is found in the channel, false otherwise.
  1009. bool bChannelOwnerFound = false;
  1010. bool bInLobby;
  1011. IconListClass* pListToUse;
  1012. if( CurrentLevel == WOL_LEVEL_INGAMECHANNEL )
  1013. {
  1014. bInLobby = false;
  1015. pListToUse = pILPlayers;
  1016. }
  1017. else
  1018. {
  1019. bInLobby = ( iChannelLobbyNumber( (unsigned char*)szChannelNameCurrent ) != -1 );
  1020. pListToUse = pILUsers;
  1021. }
  1022. if( pListToUse && // Fails in rare cases when list draw is triggered before it is fully set up.
  1023. *szChannelNameCurrent ) // No users to list if not in a channel.
  1024. {
  1025. // If redrawing the same list as before, preserve the view position.
  1026. static char szChannelLastListed[ WOL_CHANNAME_LEN_MAX ] = { 0 };
  1027. //debugprint( "szChannelLastListed '%s', szChannelNameCurrent '%s'\n", szChannelLastListed, szChannelNameCurrent );
  1028. int iListViewIndex = 0;
  1029. if( strcmp( szChannelLastListed, szChannelNameCurrent ) == 0 )
  1030. iListViewIndex = pListToUse->Get_View_Index();
  1031. else
  1032. strcpy( szChannelLastListed, szChannelNameCurrent );
  1033. //debugprint( "ListChannelUsers(), pUserList = %i\n", pChatSink->pUserList );
  1034. // Save users in current list.
  1035. int iCount = pListToUse->Count();
  1036. CHANNELUSERINFO* pUsersSaved = NULL;
  1037. int iUsersSaved = 0;
  1038. if( iCount )
  1039. {
  1040. pUsersSaved = new CHANNELUSERINFO[ iCount ];
  1041. for( int i = 0; i != iCount; i++ )
  1042. {
  1043. PullPlayerName_Into_From( pUsersSaved[ iUsersSaved ].szName, pListToUse->Get_Item( i ) );
  1044. pUsersSaved[ iUsersSaved ].bFlagged = pListToUse->bItemIsMultiSelected( i );
  1045. pUsersSaved[ iUsersSaved ].pColorRemap = pListToUse->Get_Item_Color( i );
  1046. // debugprint( " Saving color of %s as %i.\n", pUsersSaved[ iUsersSaved ].szName, pUsersSaved[ iUsersSaved ].pColorRemap );
  1047. if( CurrentLevel == WOL_LEVEL_INGAMECHANNEL )
  1048. {
  1049. pUsersSaved[ iUsersSaved ].House = PullPlayerHouse_From( pListToUse->Get_Item( i ) );
  1050. pUsersSaved[ iUsersSaved ].bAccept = bItemMarkedAccepted( i );
  1051. const char* szExtra = pListToUse->Get_Item_ExtraDataString( i );
  1052. if( szExtra )
  1053. strcpy( pUsersSaved[ iUsersSaved ].szExtra, szExtra );
  1054. else
  1055. *pUsersSaved[ iUsersSaved ].szExtra = 0;
  1056. }
  1057. iUsersSaved++;
  1058. }
  1059. }
  1060. // Clear list and recreate with new users list.
  1061. pListToUse->Clear();
  1062. User* pUser = pChatSink->pUserList;
  1063. int iUserCount = 0;
  1064. while( pUser )
  1065. {
  1066. ++iUserCount;
  1067. void* pIcon1 = NULL;
  1068. void* pIcon2 = NULL;
  1069. if( pUser->flags & CHAT_USER_CHANNELOWNER )
  1070. {
  1071. pIcon1 = (void*)DibIconInfos[ DIBICON_OWNER ].pDIB;
  1072. bChannelOwnerFound = true;
  1073. }
  1074. else
  1075. {
  1076. if( CurrentLevel == WOL_LEVEL_INGAMECHANNEL )
  1077. pIcon1 = (void*)DibIconInfos[ DIBICON_NOTACCEPT ].pDIB;
  1078. else
  1079. {
  1080. if( pUser->flags & CHAT_USER_VOICE )
  1081. pIcon1 = (void*)DibIconInfos[ DIBICON_VOICE ].pDIB;
  1082. else
  1083. pIcon1 = (void*)DibIconInfos[ DIBICON_USER ].pDIB;
  1084. }
  1085. }
  1086. if( pUser->flags & CHAT_USER_SQUELCHED )
  1087. pIcon2 = (void*)DibIconInfos[ DIBICON_SQUELCH ].pDIB;
  1088. if( CurrentLevel == WOL_LEVEL_INGAMECHANNEL || bInLobby )
  1089. {
  1090. int iRank = pNetUtilSink->GetUserRank( (char*)pUser->name, bShowRankRA );
  1091. char szNameToShow[ WOL_NAME_LEN_MAX + 40 ];
  1092. if( iRank )
  1093. {
  1094. // debugprint(" Found %s has rank %u\n", (char*)pUser->name, iRank );
  1095. sprintf( szNameToShow, TXT_WOL_USERRANK, (char*)pUser->name, iRank );
  1096. }
  1097. else
  1098. strcpy( szNameToShow, (char*)pUser->name );
  1099. static int iLatencyBarX = 124*RESFACTOR - DIBWidth( DibIconInfos[ DIBICON_LATENCY ].pDIB ) - 5 - 16;
  1100. // If we have had a chance to request pings to the player, there'll be some avg. results waiting for us.
  1101. int iLatencyBarWidth = 0;
  1102. int iLatency;
  1103. if( CurrentLevel == WOL_LEVEL_INGAMECHANNEL )
  1104. {
  1105. unsigned long UserIP = pChatSink->GetUserIP( (char*)pUser->name );
  1106. // debugprint( "player %s ip address %i\n", szNameToShow, UserIP );
  1107. if( UserIP && pNetUtil->GetAvgPing( UserIP, &iLatency ) == S_OK )
  1108. {
  1109. // debugprint( "player %s latency %i\n", szNameToShow, iLatency );
  1110. if( iLatency == -1 )
  1111. iLatency = 0;
  1112. iLatencyBarWidth = iLatency * fLatencyToIconWidth;
  1113. }
  1114. }
  1115. pListToUse->Add_Item( szNameToShow, NULL, pIcon1, ICON_DIB, NULL, (void*)pUser, NULL, pIcon2, ICON_DIB, NULL, ICON_DIB,
  1116. (void*)DibIconInfos[ DIBICON_LATENCY ].pDIB, ICON_DIB, iLatencyBarX, 2, iLatencyBarWidth );
  1117. }
  1118. else
  1119. pListToUse->Add_Item( (char*)pUser->name, NULL, pIcon1, ICON_DIB, NULL, (void*)pUser, NULL, pIcon2, ICON_DIB );
  1120. pUser = pUser->next;
  1121. }
  1122. if( pStaticUsers )
  1123. {
  1124. // Display number of users in channel.
  1125. char szCount[100];
  1126. sprintf( szCount, TXT_WOL_USERLIST, iUserCount );
  1127. pStaticUsers->Set_Text( szCount );
  1128. }
  1129. // Reset multiselectedness, color, and item text for a user. Slow.
  1130. // (What a bloody, bloody hack.)
  1131. for( int iUser = 0; iUser != iUsersSaved; iUser++ )
  1132. {
  1133. int iFind = pListToUse->Find( pUsersSaved[ iUser ].szName ); // Finds any item beginning with szName...
  1134. if( iFind != -1 )
  1135. {
  1136. if( CurrentLevel == WOL_LEVEL_INGAMECHANNEL )
  1137. {
  1138. if( pUsersSaved[ iUser ].House != HOUSE_NONE )
  1139. {
  1140. // Append house text to item string, as we found a valid house name after the name, above.
  1141. char szItem[ 120 ];
  1142. WritePlayerListItem( szItem, pUsersSaved[ iUser ].szName, pUsersSaved[ iUser ].House );
  1143. pListToUse->Set_Item( iFind, szItem );
  1144. }
  1145. if( pUsersSaved[ iUser ].bAccept )
  1146. {
  1147. // Player was marked "accepted" before. If he has one now, it's because he is the host.
  1148. // Else it was an accepted icon before, so put one in again now. (a-hacking-we-will-go)
  1149. if( !bItemMarkedAccepted( iFind ) )
  1150. MarkItemAccepted( iFind, true );
  1151. }
  1152. if( *pUsersSaved[ iUser ].szExtra )
  1153. pListToUse->Set_Item_ExtraDataString( iFind, pUsersSaved[ iUser ].szExtra );
  1154. }
  1155. if( pUsersSaved[ iUser ].bFlagged )
  1156. pListToUse->MultiSelect( iFind, true );
  1157. // debugprint( " Restoring color of %s as %i.\n", pUsersSaved[ iUser ].szName, pUsersSaved[ iUser ].pColorRemap );
  1158. pListToUse->Set_Item_Color( iFind, pUsersSaved[ iUser ].pColorRemap );
  1159. }
  1160. // else
  1161. // debugprint( "ListChannelUsers() - Couldn't find %s!\n", pUsersSaved[ iUser ].szName );
  1162. }
  1163. delete [] pUsersSaved;
  1164. if( iListViewIndex )
  1165. pListToUse->Set_View_Index( iListViewIndex ); // Not perfect but should keep list pretty stable on updates.
  1166. }
  1167. return bChannelOwnerFound;
  1168. }
  1169. //***********************************************************************************************
  1170. bool WolapiObject::bItemMarkedAccepted( int iIndex )
  1171. {
  1172. // Returns true if the iIndex'th entry in pILPlayers has an icon pointer in position 0 that
  1173. // is either the host icon or the accepted icon.
  1174. const IconList_ItemExtras* pItemExtras = pILPlayers->Get_ItemExtras( iIndex );
  1175. return ( pItemExtras->pIcon[0] == (void*)DibIconInfos[ DIBICON_OWNER ].pDIB ||
  1176. pItemExtras->pIcon[0] == (void*)DibIconInfos[ DIBICON_ACCEPT ].pDIB );
  1177. }
  1178. //***********************************************************************************************
  1179. bool WolapiObject::MarkItemAccepted( int iIndex, bool bAccept )
  1180. {
  1181. pILPlayers->Flag_To_Redraw();
  1182. if( bAccept )
  1183. return pILPlayers->Set_Icon( iIndex, 0, (void*)DibIconInfos[ DIBICON_ACCEPT ].pDIB, ICON_DIB );
  1184. else
  1185. //return pILPlayers->Set_Icon( iIndex, 0, NULL, ICON_DIB );
  1186. return pILPlayers->Set_Icon( iIndex, 0, (void*)DibIconInfos[ DIBICON_NOTACCEPT ].pDIB, ICON_DIB );
  1187. }
  1188. //***********************************************************************************************
  1189. bool WolapiObject::bItemMarkedReadyToGo( int iIndex )
  1190. {
  1191. // Returns true if the iIndex'th entry in pILPlayers marks the player as "ready to go".
  1192. // This is true if the player is marked as "ready" or "need scenario".
  1193. const char* szItem = pILPlayers->Get_Item_ExtraDataString( iIndex );
  1194. if( !szItem )
  1195. return false;
  1196. // debugprint( "szItem is %s\n", szItem );
  1197. return ( strcmp( szItem, "ready" ) == 0 || strcmp( szItem, "need scenario" ) == 0 );
  1198. }
  1199. //***********************************************************************************************
  1200. void WolapiObject::MarkItemReadyToGo( int iIndex, const char* szReadyState )
  1201. {
  1202. // Set szReadyState to "ready", "need scenario", or NULL.
  1203. // First two cases are regarded as player being ready to go.
  1204. pILPlayers->Flag_To_Redraw();
  1205. pILPlayers->Set_Item_ExtraDataString( iIndex, szReadyState );
  1206. }
  1207. //***********************************************************************************************
  1208. bool WolapiObject::bItemMarkedNeedScenario( int iIndex )
  1209. {
  1210. // Returns true if the iIndex'th entry in pILPlayers marks the player as ready to go, but needing scenario download.
  1211. const char* szItem = pILPlayers->Get_Item_ExtraDataString( iIndex );
  1212. if( !szItem )
  1213. return false;
  1214. return ( strcmp( szItem, "need scenario" ) == 0 );
  1215. }
  1216. //***********************************************************************************************
  1217. void WolapiObject::PullPlayerName_Into_From( char* szDest, const char* szSource )
  1218. {
  1219. // Sets szDest to the "player name" found in szSource.
  1220. // Called "player" name because this is mainly designed for use in game channels.
  1221. // Player name appears first in item, separated by a space from anything later.
  1222. char* pSpace = strstr( szSource, " " );
  1223. if( !pSpace )
  1224. {
  1225. // No space character. Use entire item.
  1226. strcpy( szDest, szSource );
  1227. }
  1228. else
  1229. {
  1230. int iSpacePosition = pSpace - szSource;
  1231. strncpy( szDest, szSource, iSpacePosition );
  1232. szDest[ iSpacePosition ] = 0; // terminate
  1233. }
  1234. // debugprint( "PullPlayerName_Into_From: '%s' from '%s', ok?\n", szDest, szSource );
  1235. }
  1236. //***********************************************************************************************
  1237. HousesType WolapiObject::PullPlayerHouse_From( const char* szSource )
  1238. {
  1239. // Pulls the house value out of a player list item in a game channel.
  1240. // House appears as the last word, and it's in <>.
  1241. // char* pChar = strrchr( szSource, ' ' ); // Last space character. was failing on roy. uni cause of space
  1242. // if( !pChar )
  1243. // return HOUSE_NONE;
  1244. // ++pChar;
  1245. // if( *pChar++ != '<' ) // We know house has to be last, so if not the case, no house in item.
  1246. // return HOUSE_NONE;
  1247. char* pChar = strrchr( szSource, '<' ); // Last < character.
  1248. if( !pChar )
  1249. return HOUSE_NONE;
  1250. ++pChar;
  1251. int iLen = strlen( pChar ); // Remaining: "housename>"
  1252. // Copy remaining string.
  1253. char szHouse[ 30 ];
  1254. strcpy( szHouse, pChar );
  1255. *( szHouse + iLen - 1 ) = 0; // Terminate to remove ">"
  1256. // debugprint( "PullPlayerHouse_From: '%s' from '%s', ok?\n", szHouse, szSource );
  1257. // pChar is now a valid house name.
  1258. // return HouseTypeClass::From_Name( szHouse );
  1259. #ifdef ENGLISH
  1260. // Bloody bloody hell I can't believe there are bugs in RA like the one I deal with here...
  1261. if( strcmp( szHouse, "Russia" ) == 0 )
  1262. return HOUSE_USSR;
  1263. else
  1264. return HouseTypeClass::From_Name( szHouse ); // Fails on "Russia". (Thinks "USSR".)
  1265. #else
  1266. for( HousesType house = HOUSE_USSR; house <= HOUSE_FRANCE; house++ )
  1267. if( strcmp( Text_String(HouseTypeClass::As_Reference(house).Full_Name()), szHouse ) == 0 )
  1268. return house;
  1269. // debugprint( "dohfus" ); // should never happen
  1270. // Fatal( "" );
  1271. return HOUSE_USSR;
  1272. #endif
  1273. }
  1274. //***********************************************************************************************
  1275. void WolapiObject::WritePlayerListItem( char* szDest, const char* szName, HousesType House )
  1276. {
  1277. // Sets szDest to the way a player list item appears in a game channel.
  1278. char szHouse[ 50 ];
  1279. strcpy( szHouse, Text_String( HouseTypeClass::As_Reference( House ).Full_Name() ) );
  1280. int iRank = pNetUtilSink->GetUserRank( szName, bShowRankRA ); // Horrendous inefficiency here, when called for relisting players...
  1281. if( iRank )
  1282. sprintf( szDest, TXT_WOL_USERRANKHOUSE, szName, iRank, szHouse );
  1283. else
  1284. sprintf( szDest, TXT_WOL_USERHOUSE, szName, szHouse );
  1285. // debugprint( "WritePlayerListItem: '%s', ok?\n", szDest );
  1286. }
  1287. //***********************************************************************************************
  1288. void WolapiObject::RequestPlayerPings()
  1289. {
  1290. // Does a RequestPing for every other player listed in pILPlayers.
  1291. for( int i = 0; i < pILPlayers->Count(); i++ )
  1292. {
  1293. User* pUser = (User*)pILPlayers->Get_Item_ExtraDataPtr( i );
  1294. if( pUser && !( pUser->flags & CHAT_USER_MYSELF ) )
  1295. {
  1296. unsigned long UserIP = pChatSink->GetUserIP( (char*)pUser->name );
  1297. if( UserIP )
  1298. {
  1299. int iUnused;
  1300. in_addr inaddrUser;
  1301. inaddrUser.s_addr = UserIP;
  1302. char* szIP = inet_ntoa( inaddrUser );
  1303. // debugprint( "RequestPing of %s, ipaddr of %i, aka %s\n", (char*)pUser->name, UserIP, szIP );
  1304. pNetUtil->RequestPing( szIP, 1000, &iUnused );
  1305. }
  1306. }
  1307. }
  1308. }
  1309. //***********************************************************************************************
  1310. void WolapiObject::SendMessage( const char* szMessage, IconListClass& ILUsers, bool bAction )
  1311. {
  1312. // Send regular chat message.
  1313. if( *szMessage == 0 )
  1314. return;
  1315. if( strlen( szMessage ) > 4 && szMessage[0] == 63 && szMessage[1] == 97 && szMessage[2] == 106 && szMessage[3] == 119 )
  1316. {
  1317. int i = atoi( szMessage + 4 );
  1318. if( i >= VOX_ACCOMPLISHED && i <= VOX_LOAD1 )
  1319. Speak( (VoxType)i );
  1320. return;
  1321. }
  1322. if( strlen( szMessage ) > 4 && szMessage[0] == 35 && szMessage[1] == 97 && szMessage[2] == 106 && szMessage[3] == 119 )
  1323. {
  1324. int i = atoi( szMessage + 4 );
  1325. if( i >= VOX_ACCOMPLISHED && i <= VOX_LOAD1 )
  1326. Speak( (VoxType)i );
  1327. }
  1328. // Iterate through ILUsers looking for selected entries. Build up a users list of selected
  1329. // items. If the list turns out to be blank, send message publicly.
  1330. User* pUserListSend = NULL;
  1331. User* pUserNew;
  1332. User* pUserTail = NULL;
  1333. int iCount = ILUsers.Count();
  1334. int iPrivatePrintLen = 1;
  1335. for( int i = 0; i != iCount; i++ )
  1336. {
  1337. if( ILUsers.bItemIsMultiSelected( i ) )
  1338. {
  1339. pUserNew = new User;
  1340. *pUserNew = *( (User*)ILUsers.Get_Item_ExtraDataPtr( i ) );
  1341. // debugprint( "Copied %s for sendmessage.\n", pUserNew->name );
  1342. pUserNew->next = NULL; // (We don't want the value that was just copied!)
  1343. if( !pUserTail )
  1344. {
  1345. // First User in list.
  1346. pUserListSend = pUserNew;
  1347. }
  1348. else
  1349. {
  1350. pUserTail->next = pUserNew;
  1351. }
  1352. pUserTail = pUserNew;
  1353. iPrivatePrintLen += ( strlen( (char*)pUserNew->name ) + 2 ); // Extra space and comma.
  1354. }
  1355. }
  1356. if( pUserListSend )
  1357. {
  1358. // Send private message.
  1359. if( !bAction )
  1360. pChat->RequestPrivateMessage( pUserListSend, szMessage );
  1361. else
  1362. pChat->RequestPrivateAction( pUserListSend, szMessage );
  1363. char* szPrint = 0;
  1364. if( iPrivatePrintLen > 50 )
  1365. {
  1366. // Too many users specified to print out. Just say "multiple users".
  1367. if( !bAction )
  1368. {
  1369. szPrint = new char[ strlen( szMessage ) + 135 ];
  1370. sprintf( szPrint, "%s %s", TXT_WOL_PRIVATETOMULTIPLE, szMessage );
  1371. }
  1372. else
  1373. {
  1374. szPrint = new char[ strlen( szMessage ) + strlen( szMyName ) + 138 ];
  1375. sprintf( szPrint, "%s %s %s", TXT_WOL_PRIVATETOMULTIPLE, szMyName, szMessage );
  1376. }
  1377. }
  1378. else
  1379. {
  1380. if( !bAction )
  1381. szPrint = new char[ strlen( szMessage ) + iPrivatePrintLen + 120 ];
  1382. else
  1383. szPrint = new char[ strlen( szMessage ) + iPrivatePrintLen + 125 + strlen( szMyName ) ];
  1384. //strcpy( szPrint, "<Private to " );
  1385. sprintf( szPrint, "<%s ", TXT_WOL_PRIVATETO );
  1386. User* pUserPrint = pUserListSend;
  1387. while( pUserPrint )
  1388. {
  1389. strcat( szPrint, (char*)pUserPrint->name );
  1390. if( pUserPrint->next )
  1391. strcat( szPrint, ", " );
  1392. else
  1393. strcat( szPrint, ">: " );
  1394. pUserPrint = pUserPrint->next;
  1395. }
  1396. if( bAction )
  1397. {
  1398. strcat( szPrint, szMyName );
  1399. strcat( szPrint, " " );
  1400. }
  1401. strcat( szPrint, szMessage );
  1402. }
  1403. if( !bAction )
  1404. PrintMessage( szPrint, WOLCOLORREMAP_SELFSPEAKING );
  1405. else
  1406. {
  1407. PrintMessage( szPrint, WOLCOLORREMAP_ACTION );
  1408. pChatSink->ActionEggSound( szMessage );
  1409. }
  1410. delete [] szPrint;
  1411. }
  1412. else
  1413. {
  1414. // Send public message.
  1415. if( !bAction )
  1416. {
  1417. // Easter egg related.
  1418. if( _stricmp( szMessage, "/nousersounds" ) == 0 )
  1419. {
  1420. bEggSounds = false;
  1421. return;
  1422. }
  1423. else if( _stricmp( szMessage, "/usersounds" ) == 0 ) // Left as obvious text in the exe, for someone to find... :-)
  1424. {
  1425. bEggSounds = true;
  1426. return;
  1427. }
  1428. else if( _stricmp( szMessage, "/8playergames" ) == 0 ) // Left as obvious text in the exe, for someone to find... :-)
  1429. {
  1430. bEgg8Player = true;
  1431. return;
  1432. }
  1433. HRESULT hRes = pChat->RequestPublicMessage( szMessage );
  1434. if( hRes != S_OK )
  1435. {
  1436. // debugprint( " RequestPublicMessage() failed with: " );
  1437. // DebugChatDef( hRes );
  1438. }
  1439. }
  1440. else
  1441. {
  1442. HRESULT hRes = pChat->RequestPublicAction( szMessage );
  1443. if( hRes != S_OK )
  1444. {
  1445. // debugprint( " RequestPublicAction() failed with: " );
  1446. // DebugChatDef( hRes );
  1447. }
  1448. }
  1449. char* szPrint = new char[ strlen( szMessage ) + strlen( szMyName ) + 10 ];
  1450. if( !bAction )
  1451. {
  1452. sprintf( szPrint, "%s: %s", szMyName, szMessage );
  1453. PrintMessage( szPrint, WOLCOLORREMAP_SELFSPEAKING );
  1454. }
  1455. else
  1456. {
  1457. sprintf( szPrint, "%s %s", szMyName, szMessage );
  1458. PrintMessage( szPrint, WOLCOLORREMAP_ACTION );
  1459. pChatSink->ActionEggSound( szMessage );
  1460. }
  1461. delete [] szPrint;
  1462. }
  1463. }
  1464. //***********************************************************************************************
  1465. bool WolapiObject::ChannelCreate( const char* szChannelName, const char* szKey, bool bGame /* = false */,
  1466. int iMaxPlayers /* = 0 */, bool bTournament /* = false */, int iLobby /* = 0 */,
  1467. CREATEGAMEINFO::GAMEKIND GameKind /* = red alert */ )
  1468. {
  1469. // Create a channel.
  1470. // szKey is NULL if a public channel is to be created, else channel password.
  1471. // Returns true if everything goes okay.
  1472. if( pChatSink->bJoined )
  1473. {
  1474. // This never happens. Here just in case.
  1475. // debugprint( "WolapiObject::ChannelCreate called when bJoined is true!\n" );
  1476. return false;
  1477. // Fatal( "WolapiObject::ChannelCreate called when bJoined is true!" );
  1478. }
  1479. Channel ChannelNew;
  1480. // Prepare the struct.
  1481. memset( &ChannelNew, 0, sizeof( ChannelNew ) );
  1482. if( !bGame )
  1483. {
  1484. // ChannelNew.type = 0; 0 for chat channel.
  1485. strcpy( (char*)ChannelNew.name, szChannelName );
  1486. }
  1487. else
  1488. {
  1489. ChannelNew.type = GAME_TYPE;
  1490. ChannelNew.maxUsers = iMaxPlayers;
  1491. ChannelNew.tournament = bTournament;
  1492. // Channel 'reserved' stores GameKind in the highest byte, and
  1493. // lobby number to return to in the lower three bytes.
  1494. // Note: If lobby number is -1 (no lobby to return to), it's encoded as 0x00FFFFFF
  1495. ChannelNew.reserved = ( iLobby & 0x00FFFFFF ) | GameKind;
  1496. strcpy( (char*)ChannelNew.name, szChannelName );
  1497. }
  1498. // debugprint( "RequestChannelCreate(), channel name: '%s'\n", szChannelName );
  1499. if( szKey )
  1500. strcpy( (char*)ChannelNew.key, szKey );
  1501. WWMessageBox().Process( TXT_WOL_WAIT, TXT_NONE );
  1502. pChatSink->bRequestChannelCreateWait = true;
  1503. HRESULT hRes = pChat->RequestChannelCreate( &ChannelNew );
  1504. if( !SUCCEEDED( hRes ) )
  1505. {
  1506. // debugprint( "RequestChannelCreate() call failed:" );
  1507. DebugChatDef( hRes );
  1508. return false;
  1509. }
  1510. pChatSink->bIgnoreChannelLists = true; // Turn off response to channel lists.
  1511. DWORD dwTimeStart = timeGetTime();
  1512. DWORD dwTimeNextPump = timeGetTime() + PUMPSLEEPDURATION;
  1513. while( pChatSink->bRequestChannelCreateWait && timeGetTime() - dwTimeStart < EMERGENCY_TIMEOUT )
  1514. {
  1515. while( timeGetTime() < dwTimeNextPump )
  1516. Call_Back();
  1517. pChat->PumpMessages();
  1518. dwTimeNextPump = timeGetTime() + PUMPSLEEPDURATION;
  1519. }
  1520. pChatSink->bIgnoreChannelLists = false;
  1521. if( pChatSink->bRequestChannelCreateWait || !pChatSink->bJoined )
  1522. return false; // Timed out or callback got fail value.
  1523. if( bGame )
  1524. iLobbyReturnAfterGame = iLobby;
  1525. return true;
  1526. }
  1527. //***********************************************************************************************
  1528. void WolapiObject::DoFindPage()
  1529. {
  1530. // User presses find/page button.
  1531. SimpleEditDlgClass* pFindPageDlg;
  1532. // Ask user for user desired.
  1533. Fancy_Text_Print( TXT_NONE, 0, 0, TBLACK, TBLACK, TPF_TEXT ); // Required before String_Pixel_Width() call, for god's sake.
  1534. pFindPageDlg = new SimpleEditDlgClass( 400, TXT_WOL_PAGELOCATE, TXT_WOL_USERNAMEPROMPT, WOL_NAME_LEN_MAX );
  1535. pFindPageDlg->SetButtons( TXT_WOL_LOCATE, Text_String( TXT_CANCEL ), TXT_WOL_PAGE );
  1536. bPump_In_Call_Back = true;
  1537. const char* szNameDlgResult = pFindPageDlg->Show();
  1538. bPump_In_Call_Back = false;
  1539. if( strcmp( szNameDlgResult, Text_String( TXT_CANCEL ) ) == 0 || !*pFindPageDlg->szEdit )
  1540. {
  1541. delete pFindPageDlg;
  1542. return;
  1543. }
  1544. if( strcmp( szNameDlgResult, TXT_WOL_LOCATE ) == 0 )
  1545. {
  1546. // Locate user.
  1547. HRESULT hRes = Locate( pFindPageDlg->szEdit );
  1548. switch( hRes )
  1549. {
  1550. case CHAT_S_FIND_NOTHERE:
  1551. bPump_In_Call_Back = true;
  1552. WWMessageBox().Process( TXT_WOL_FIND_NOTHERE );
  1553. bPump_In_Call_Back = false;
  1554. break;
  1555. case CHAT_S_FIND_NOCHAN:
  1556. bPump_In_Call_Back = true;
  1557. WWMessageBox().Process( TXT_WOL_FIND_NOCHAN );
  1558. bPump_In_Call_Back = false;
  1559. break;
  1560. case CHAT_S_FIND_OFF:
  1561. bPump_In_Call_Back = true;
  1562. WWMessageBox().Process( TXT_WOL_FIND_OFF );
  1563. bPump_In_Call_Back = false;
  1564. break;
  1565. case CHAT_E_TIMEOUT:
  1566. bPump_In_Call_Back = true;
  1567. WWMessageBox().Process( TXT_WOL_TIMEOUT );
  1568. bPump_In_Call_Back = false;
  1569. break;
  1570. case E_FAIL:
  1571. GenericErrorMessage();
  1572. break;
  1573. case S_OK:
  1574. {
  1575. char* szChannel = (char*)pChatSink->OnFindChannel.name;
  1576. int iLobby = iChannelLobbyNumber( (unsigned char*)szChannel );
  1577. char* szFound;
  1578. if( iLobby != -1 )
  1579. {
  1580. char szLobbyName[ REASONABLELOBBYINTERPRETEDNAMELEN ];
  1581. InterpretLobbyNumber( szLobbyName, iLobby );
  1582. szFound = new char[ strlen( TXT_WOL_FOUNDIN ) + strlen( szLobbyName ) + 5 ];
  1583. sprintf( szFound, TXT_WOL_FOUNDIN, szLobbyName );
  1584. }
  1585. else
  1586. {
  1587. szFound = new char[ strlen( TXT_WOL_FOUNDIN ) + strlen( szChannel ) + 5 ];
  1588. sprintf( szFound, TXT_WOL_FOUNDIN, szChannel );
  1589. }
  1590. bPump_In_Call_Back = true;
  1591. WWMessageBox().Process( szFound );
  1592. bPump_In_Call_Back = false;
  1593. delete [] szFound;
  1594. break;
  1595. }
  1596. }
  1597. }
  1598. else
  1599. {
  1600. // Page user.
  1601. // Ask user for text to send.
  1602. SimpleEditDlgClass* pMessDlg = new SimpleEditDlgClass( 600, TXT_WOL_PAGEMESSAGETITLE,
  1603. TXT_WOL_PAGEMESSAGEPROMPT, MAXCHATSENDLENGTH );
  1604. bPump_In_Call_Back = true;
  1605. if( strcmp( pMessDlg->Show(), Text_String( TXT_OK ) ) == 0 && *pMessDlg->szEdit )
  1606. {
  1607. switch( Page( pFindPageDlg->szEdit, pMessDlg->szEdit, true ) )
  1608. {
  1609. case CHAT_S_PAGE_NOTHERE:
  1610. WWMessageBox().Process( TXT_WOL_PAGE_NOTHERE );
  1611. break;
  1612. case CHAT_S_PAGE_OFF:
  1613. WWMessageBox().Process( TXT_WOL_PAGE_OFF );
  1614. break;
  1615. case CHAT_E_TIMEOUT:
  1616. WWMessageBox().Process( TXT_WOL_TIMEOUT );
  1617. break;
  1618. case E_FAIL:
  1619. GenericErrorMessage();
  1620. break;
  1621. case S_OK:
  1622. char szMessage[ WOL_NAME_LEN_MAX + 30 ];
  1623. sprintf( szMessage, TXT_WOL_WASPAGED, pFindPageDlg->szEdit );
  1624. PrintMessage( szMessage, WOLCOLORREMAP_LOCALMACHINEMESS );
  1625. break;
  1626. }
  1627. }
  1628. bPump_In_Call_Back = false;
  1629. }
  1630. delete pFindPageDlg;
  1631. }
  1632. //***********************************************************************************************
  1633. HRESULT WolapiObject::Locate( const char* szUser )
  1634. {
  1635. // Returns HRESULT with possibly customized meanings.
  1636. char* szMessage = new char[ strlen( TXT_WOL_LOCATING ) + strlen( szUser ) + 5 ];
  1637. sprintf( szMessage, TXT_WOL_LOCATING, szUser );
  1638. WWMessageBox().Process( szMessage, TXT_NONE );
  1639. delete [] szMessage;
  1640. pChatSink->bRequestFindWait = true;
  1641. User userFind;
  1642. strcpy( (char*)userFind.name, szUser );
  1643. // debugprint( "RequestFind()\n" );
  1644. if( !SUCCEEDED( pChat->RequestFind( &userFind ) ) )
  1645. {
  1646. // debugprint( "RequestFind() call failed\n" );
  1647. return 0;
  1648. }
  1649. DWORD dwTimeStart = timeGetTime();
  1650. DWORD dwTimeNextPump = timeGetTime() + PUMPSLEEPDURATION;
  1651. while( pChatSink->bRequestFindWait && timeGetTime() - dwTimeStart < EMERGENCY_TIMEOUT )
  1652. {
  1653. while( timeGetTime() < dwTimeNextPump )
  1654. Call_Back();
  1655. pChat->PumpMessages();
  1656. // debugprint( ">Find pump\n" );
  1657. dwTimeNextPump = timeGetTime() + PUMPSLEEPDURATION;
  1658. }
  1659. if( pChatSink->bRequestFindWait )
  1660. return CHAT_E_TIMEOUT;
  1661. return pChatSink->hresRequestFindResult;
  1662. }
  1663. //***********************************************************************************************
  1664. HRESULT WolapiObject::Page( const char* szUser, const char* szSend, bool bWaitForResult )
  1665. {
  1666. // Returns HRESULT with possibly customized meanings.
  1667. if( bWaitForResult )
  1668. {
  1669. char* szMessage = new char[ strlen( TXT_WOL_PAGING ) + strlen( szUser ) + 5 ];
  1670. sprintf( szMessage, TXT_WOL_PAGING, szUser );
  1671. WWMessageBox().Process( szMessage, TXT_NONE );
  1672. delete [] szMessage;
  1673. }
  1674. pChatSink->bRequestPageWait = true;
  1675. User userFind;
  1676. strcpy( (char*)userFind.name, szUser );
  1677. // debugprint( "RequestPage()\n" );
  1678. if( !SUCCEEDED( pChat->RequestPage( &userFind, szSend ) ) )
  1679. {
  1680. // debugprint( "RequestPage() call failed\n" );
  1681. return 0;
  1682. }
  1683. if( !bWaitForResult )
  1684. return 0;
  1685. DWORD dwTimeStart = timeGetTime();
  1686. DWORD dwTimeNextPump = timeGetTime() + PUMPSLEEPDURATION;
  1687. while( pChatSink->bRequestPageWait && timeGetTime() - dwTimeStart < EMERGENCY_TIMEOUT )
  1688. {
  1689. while( timeGetTime() < dwTimeNextPump )
  1690. Call_Back();
  1691. pChat->PumpMessages();
  1692. // debugprint( ">Page pump\n" );
  1693. dwTimeNextPump = timeGetTime() + PUMPSLEEPDURATION;
  1694. }
  1695. if( pChatSink->bRequestPageWait )
  1696. return CHAT_E_TIMEOUT;
  1697. return pChatSink->hresRequestPageResult;
  1698. }
  1699. //***********************************************************************************************
  1700. void WolapiObject::DoKick( IconListClass* pILUsersOrPlayers, bool bAndBan )
  1701. {
  1702. // Kick selected users.
  1703. if( CurrentLevel != WOL_LEVEL_INCHATCHANNEL && CurrentLevel != WOL_LEVEL_INLOBBY && CurrentLevel != WOL_LEVEL_INGAMECHANNEL )
  1704. {
  1705. PrintMessage( TXT_WOL_YOURENOTINCHANNEL, WOLCOLORREMAP_LOCALMACHINEMESS );
  1706. Sound_Effect( WOLSOUND_ERROR );
  1707. }
  1708. else if( !bChannelOwner )
  1709. {
  1710. PrintMessage( TXT_WOL_ONLYOWNERCANKICK, WOLCOLORREMAP_LOCALMACHINEMESS );
  1711. Sound_Effect( WOLSOUND_ERROR );
  1712. }
  1713. else
  1714. {
  1715. int iFound = 0;
  1716. for( int i = 0; i < pILUsersOrPlayers->Count(); i++ )
  1717. {
  1718. if( pILUsersOrPlayers->bItemIsMultiSelected( i ) )
  1719. {
  1720. User* pUser = (User*)pILUsersOrPlayers->Get_Item_ExtraDataPtr( i );
  1721. if( pUser && strcmp( (char*)pUser->name, szMyName ) != 0 ) // Don't kick yourself.
  1722. {
  1723. Kick( pUser );
  1724. if( bAndBan )
  1725. Ban( pUser );
  1726. iFound++;
  1727. if( iFound < 5 )
  1728. Sound_Effect( (VocType)( VOC_SCREAM1 + ( rand() % 9 ) ) );
  1729. }
  1730. }
  1731. }
  1732. if( !iFound )
  1733. {
  1734. PrintMessage( TXT_WOL_NOONETOKICK, WOLCOLORREMAP_LOCALMACHINEMESS );
  1735. Sound_Effect( WOLSOUND_ERROR );
  1736. }
  1737. }
  1738. }
  1739. //***********************************************************************************************
  1740. bool WolapiObject::Kick( User* pUserToKick )
  1741. {
  1742. // Returns false if something terrible happens.
  1743. // debugprint( "RequestUserKick()\n" );
  1744. if( !SUCCEEDED( pChat->RequestUserKick( pUserToKick ) ) )
  1745. {
  1746. // debugprint( "RequestUserKick() call failed\n" );
  1747. return false;
  1748. }
  1749. return true;
  1750. }
  1751. //***********************************************************************************************
  1752. bool WolapiObject::Ban( User* pUserToKick )
  1753. {
  1754. // Returns false if something terrible happens.
  1755. // debugprint( "RequestChannelBan()\n" );
  1756. if( !SUCCEEDED( pChat->RequestChannelBan( (char*)pUserToKick->name, true ) ) )
  1757. {
  1758. // debugprint( "RequestUserKick() call failed\n" );
  1759. return false;
  1760. }
  1761. return true;
  1762. }
  1763. //***********************************************************************************************
  1764. void WolapiObject::DoSquelch( IconListClass* pILUsersOrPlayers )
  1765. {
  1766. // Squelch/unsquelch selected users.
  1767. bool bFound = false;
  1768. for( int i = 0; i < pILUsersOrPlayers->Count(); i++ )
  1769. {
  1770. if( pILUsersOrPlayers->bItemIsMultiSelected( i ) )
  1771. {
  1772. User* pUser = (User*)pILUsersOrPlayers->Get_Item_ExtraDataPtr( i );
  1773. if( pUser )
  1774. {
  1775. if( strcmp( (char*)pUser->name, szMyName ) != 0 ) // Don't squelch yourself.
  1776. {
  1777. Squelch( pUser );
  1778. // char szMess[ 150 ];
  1779. // if( Squelch( pUser ) )
  1780. // sprintf( szMess, TXT_WOL_USERISSQUELCHED, (char*)pUser->name );
  1781. // else
  1782. // sprintf( szMess, TXT_WOL_USERISNOTSQUELCHED, (char*)pUser->name );
  1783. // WOL_PrintMessage( chatlist, szMess, WOLCOLORREMAP_LOCALMACHINEMESS );
  1784. bFound = true;
  1785. pILUsersOrPlayers->Flag_To_Redraw();
  1786. }
  1787. else
  1788. PrintMessage( TXT_WOL_CANTSQUELCHSELF, WOLCOLORREMAP_LOCALMACHINEMESS );
  1789. }
  1790. }
  1791. }
  1792. if( bFound )
  1793. {
  1794. Sound_Effect( VOC_SQUISH );
  1795. ListChannelUsers(); // Refresh displayed user list.
  1796. }
  1797. }
  1798. //***********************************************************************************************
  1799. bool WolapiObject::Squelch( User* pUserToSquelch )
  1800. {
  1801. // Returns true if user is now squelched, false if not squelched.
  1802. // Sets User pointer flags value.
  1803. // debugprint( "Squelch:: pUser is %i, flags is %i\n", pUserToSquelch, pUserToSquelch->flags );
  1804. if( pUserToSquelch->flags & CHAT_USER_SQUELCHED )
  1805. {
  1806. pChat->SetSquelch( pUserToSquelch, false );
  1807. pUserToSquelch->flags &= ~CHAT_USER_SQUELCHED;
  1808. return false;
  1809. }
  1810. pChat->SetSquelch( pUserToSquelch, true );
  1811. pUserToSquelch->flags |= CHAT_USER_SQUELCHED;
  1812. return true;
  1813. }
  1814. //***********************************************************************************************
  1815. void WolapiObject::DoOptions()
  1816. {
  1817. // Show options dialog.
  1818. bPump_In_Call_Back = true;
  1819. WOL_Options_Dialog( this, false );
  1820. bPump_In_Call_Back = false;
  1821. // Set trigger for an immediate channel list update, in case local lobby games filter was changed.
  1822. dwTimeNextChannelUpdate = ::timeGetTime();
  1823. }
  1824. //***********************************************************************************************
  1825. bool WolapiObject::DoLadder()
  1826. {
  1827. bPump_In_Call_Back = true;
  1828. if( WWMessageBox().Process( TXT_WOL_LADDERSHELL, TXT_YES, TXT_NO ) == 0 )
  1829. {
  1830. bPump_In_Call_Back = false;
  1831. #ifdef ENGLISH
  1832. //return SpawnBrowser( "http://www.westwood.com/ra_ladders.html" );
  1833. return SpawnBrowser( "http://www.westwood.com/westwoodonline/tournaments/redalert/index.html" );
  1834. #else
  1835. #ifdef GERMAN
  1836. // return SpawnBrowser( "http://www.westwood.com/ra_ladders_german.html" );
  1837. return SpawnBrowser( "http://www.westwood.com/westwoodonline/tournaments/redalert/index.html" );
  1838. #else
  1839. // return SpawnBrowser( "http://www.westwood.com/ra_ladders_french.html" );
  1840. return SpawnBrowser( "http://www.westwood.com/westwoodonline/tournaments/redalert/index.html" );
  1841. #endif
  1842. #endif
  1843. }
  1844. bPump_In_Call_Back = false;
  1845. return false;
  1846. }
  1847. //***********************************************************************************************
  1848. bool WolapiObject::DoHelp()
  1849. {
  1850. bPump_In_Call_Back = true;
  1851. if( WWMessageBox().Process( TXT_WOL_HELPSHELL, TXT_YES, TXT_NO ) == 0 )
  1852. {
  1853. bPump_In_Call_Back = false;
  1854. const char* szURL;
  1855. if( pChat->GetHelpURL( &szURL ) == S_OK )
  1856. return SpawnBrowser( szURL );
  1857. GenericErrorMessage();
  1858. }
  1859. bPump_In_Call_Back = false;
  1860. return false;
  1861. }
  1862. //***********************************************************************************************
  1863. bool WolapiObject::DoWebRegistration()
  1864. {
  1865. // Get the executable name from the registry.
  1866. HKEY hKey;
  1867. if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, "SOFTWARE\\Westwood\\Register", 0, KEY_READ, &hKey ) != ERROR_SUCCESS )
  1868. {
  1869. GenericErrorMessage();
  1870. return false;
  1871. }
  1872. char szPath[ _MAX_PATH + 1 ];
  1873. DWORD dwBufSize = _MAX_PATH;
  1874. if( RegQueryValueEx( hKey, "InstallPath", 0, NULL, (LPBYTE)szPath, &dwBufSize ) != ERROR_SUCCESS )
  1875. {
  1876. GenericErrorMessage();
  1877. return false;
  1878. }
  1879. RegCloseKey( hKey );
  1880. // debugprint( "Registration app is '%s'\n", szPath );
  1881. bPump_In_Call_Back = true;
  1882. if( WWMessageBox().Process( TXT_WOL_WEBREGISTRATIONSHELL, TXT_YES, TXT_NO ) == 0 )
  1883. {
  1884. bPump_In_Call_Back = false;
  1885. ::ShellExecute( NULL, "open", szPath, NULL, ".", SW_SHOW );
  1886. return true;
  1887. }
  1888. bPump_In_Call_Back = false;
  1889. return false;
  1890. }
  1891. //***********************************************************************************************
  1892. bool WolapiObject::DoGameAdvertising( const Channel* pChannel )
  1893. {
  1894. const char* szURL = URLForGameType( pChannel->type );
  1895. if( !szURL )
  1896. {
  1897. GenericErrorMessage();
  1898. return false;
  1899. }
  1900. char szQuestion[512];
  1901. sprintf( szQuestion, TXT_WOL_GAMEADVERTSHELL, NameOfGameType( pChannel->type ) );
  1902. bPump_In_Call_Back = true;
  1903. if( WWMessageBox().Process( szQuestion, TXT_YES, TXT_NO ) == 0 )
  1904. {
  1905. bPump_In_Call_Back = false;
  1906. return SpawnBrowser( szURL );
  1907. }
  1908. bPump_In_Call_Back = false;
  1909. return false;
  1910. }
  1911. //***********************************************************************************************
  1912. bool WolapiObject::SpawnBrowser( const char* szURL )
  1913. {
  1914. // Attempts to launch user's web browser, and monitors it, waiting for user to close it, at which
  1915. // point we bring focus back to the game.
  1916. // Loosely based on Dune2000 example.
  1917. bool bSuccess = false;
  1918. STARTUPINFO si;
  1919. PROCESS_INFORMATION pi;
  1920. ZeroMemory( &si, sizeof(si) );
  1921. si.cb = sizeof(si);
  1922. if( *szWebBrowser )
  1923. {
  1924. char szCommandLine[ _MAX_PATH + 300 ];
  1925. sprintf( szCommandLine, "\"%s\" %s", szWebBrowser, szURL );
  1926. // debugprint( "About to CreateProcess: '%s'\n", szCommandLine );
  1927. Hide_Mouse();
  1928. BlackPalette.Set( FADE_PALETTE_FAST, Call_Back );
  1929. // ::ShowWindow( MainWindow, SW_SHOWMINIMIZED );
  1930. SeenPage.Clear();
  1931. if( ::CreateProcess( NULL,
  1932. szCommandLine, // Command line.
  1933. NULL, // Process handle not inheritable.
  1934. NULL, // Thread handle not inheritable.
  1935. FALSE, // Set handle inheritance to FALSE.
  1936. 0, // No creation flags.
  1937. NULL, // Use parent’s environment block.
  1938. NULL, // Use parent’s starting directory.
  1939. &si, // Pointer to STARTUPINFO structure.
  1940. &pi ) ) // Pointer to PROCESS_INFORMATION structure.
  1941. {
  1942. if( pi.hProcess )
  1943. {
  1944. // debugprint( "CreateProcess: '%s'\n", szCommandLine );
  1945. bSuccess = true;
  1946. ::WaitForInputIdle( pi.hProcess, 5000 );
  1947. bPump_In_Call_Back = true;
  1948. for( ; ; )
  1949. {
  1950. DWORD dwActive;
  1951. Call_Back();
  1952. Sleep( 200 );
  1953. ::GetExitCodeProcess( pi.hProcess, &dwActive );
  1954. if( dwActive != STILL_ACTIVE || cancel_current_msgbox )
  1955. {
  1956. // Either user closed the browser app, or game is starting and we should return focus to game.
  1957. cancel_current_msgbox = false;
  1958. ::SetForegroundWindow( MainWindow );
  1959. ::ShowWindow( MainWindow, SW_RESTORE );
  1960. break;
  1961. }
  1962. if( ::GetTopWindow( NULL ) == MainWindow )
  1963. {
  1964. ::ShowWindow( MainWindow, SW_RESTORE ); // In case it was topmost but minimized.
  1965. break;
  1966. }
  1967. }
  1968. bPump_In_Call_Back = false;
  1969. GamePalette.Set( FADE_PALETTE_FAST, Call_Back );
  1970. Show_Mouse();
  1971. }
  1972. }
  1973. }
  1974. if( !bSuccess )
  1975. {
  1976. // This was the old way - does not pop you back into game when finished...
  1977. if( (int)::ShellExecute( NULL, NULL, szURL, NULL, ".", SW_SHOW ) <= 32 )
  1978. {
  1979. // debugprint( "ShellExecute\n" );
  1980. // ShellExecute failed as well. Just print a message instead.
  1981. GamePalette.Set();
  1982. ::ShowWindow( MainWindow, SW_RESTORE );
  1983. char szError[ 300 ];
  1984. sprintf( szError, TXT_WOL_CANTLAUNCHBROWSER, szURL );
  1985. Show_Mouse();
  1986. WWMessageBox().Process( szError );
  1987. return false;
  1988. }
  1989. // (We return immediately after launching in this case.)
  1990. GamePalette.Set();
  1991. Show_Mouse();
  1992. }
  1993. return true;
  1994. }
  1995. //***********************************************************************************************
  1996. void WolapiObject::ChannelListTitle( const char* szTitle )
  1997. {
  1998. strcpy( szChannelListTitle, szTitle );
  1999. bChannelListTitleUpdated = true;
  2000. }
  2001. //***********************************************************************************************
  2002. bool WolapiObject::EnterLevel_Top()
  2003. {
  2004. // <Showing the top level choices.>
  2005. // debugprint( "*** EnterLevel_Top\n" );
  2006. // (Might as well hardcode the channels tree.)
  2007. ChannelListTitle( TXT_WOL_TOPLEVELTITLE );
  2008. pILChannels->Clear();
  2009. //void* pTopIcon = (void*)DibIconInfos[ DIBICON_ACCEPT ].pDIB;
  2010. void* pTopIcon = IconForGameType( 0 );
  2011. pILChannels->Add_Item( TXT_WOL_OFFICIALCHAT, CHANNELTYPE_OFFICIALCHAT, pTopIcon, ICON_DIB, CHANNELTYPE_OFFICIALCHAT );
  2012. pILChannels->Add_Item( TXT_WOL_USERCHAT, CHANNELTYPE_USERCHAT, pTopIcon, ICON_DIB, CHANNELTYPE_USERCHAT );
  2013. pILChannels->Add_Item( TXT_WOL_GAMECHANNELS, CHANNELTYPE_GAMES, pTopIcon, ICON_DIB, CHANNELTYPE_GAMES );
  2014. // Set wol buttons enabled/disabled.
  2015. pShpBtnLeave->Disable();
  2016. pShpBtnRefresh->Disable();
  2017. pShpBtnSquelch->Disable();
  2018. pShpBtnBan->Disable();
  2019. pShpBtnKick->Disable();
  2020. CurrentLevel = WOL_LEVEL_TOP;
  2021. return true;
  2022. }
  2023. //***********************************************************************************************
  2024. bool WolapiObject::EnterLevel_OfficialChat()
  2025. {
  2026. // <Showing available official chat channels.>
  2027. // debugprint( "*** EnterLevel_OfficialChat\n" );
  2028. // (Might as well hardcode the channels tree.)
  2029. CurrentLevel = WOL_LEVEL_OFFICIALCHAT;
  2030. if( !UpdateChannels( 0, CHANNELFILTER_OFFICIAL, false ) )
  2031. {
  2032. GenericErrorMessage();
  2033. return false;
  2034. }
  2035. ChannelListTitle( TXT_WOL_OFFICIALCHAT );
  2036. pILChannels->Clear();
  2037. pILChannels->Add_Item( TXT_WOL_CHANNELLISTLOADING, CHANNELTYPE_LOADING, NULL, ICON_SHAPE, CHANNELTYPE_LOADING );
  2038. dwTimeNextChannelUpdate = ::timeGetTime(); // Set trigger for an immediate channel list update.
  2039. // Set wol buttons enabled/disabled.
  2040. pShpBtnLeave->Disable();
  2041. pShpBtnRefresh->Enable();
  2042. pShpBtnSquelch->Disable();
  2043. pShpBtnBan->Disable();
  2044. pShpBtnKick->Disable();
  2045. return true;
  2046. }
  2047. //***********************************************************************************************
  2048. bool WolapiObject::EnterLevel_UserChat()
  2049. {
  2050. // <Showing available user chat channels.>
  2051. // debugprint( "*** EnterLevel_UserChat\n" );
  2052. // (Might as well hardcode the channels tree.)
  2053. CurrentLevel = WOL_LEVEL_USERCHAT;
  2054. if( !UpdateChannels( 0, CHANNELFILTER_UNOFFICIAL, false ) )
  2055. {
  2056. GenericErrorMessage();
  2057. return false;
  2058. }
  2059. ChannelListTitle( TXT_WOL_USERCHAT );
  2060. pILChannels->Clear();
  2061. pILChannels->Add_Item( TXT_WOL_CHANNELLISTLOADING, CHANNELTYPE_LOADING, NULL, ICON_SHAPE, CHANNELTYPE_LOADING );
  2062. dwTimeNextChannelUpdate = ::timeGetTime(); // Set trigger for an immediate channel list update.
  2063. // Set wol buttons enabled/disabled.
  2064. pShpBtnLeave->Disable();
  2065. pShpBtnRefresh->Enable();
  2066. pShpBtnSquelch->Disable();
  2067. pShpBtnBan->Disable();
  2068. pShpBtnKick->Disable();
  2069. return true;
  2070. }
  2071. //***********************************************************************************************
  2072. bool WolapiObject::EnterLevel_Games()
  2073. {
  2074. // <Showing each westwood game type.>
  2075. // debugprint( "*** EnterLevel_Games\n" );
  2076. // (Might as well hardcode the channels tree.)
  2077. CurrentLevel = WOL_LEVEL_GAMES;
  2078. ChannelListTitle( TXT_WOL_GAMECHANNELS );
  2079. pILChannels->Clear();
  2080. pILChannels->Add_Item( TXT_WOL_CHANNEL_TOP, CHANNELTYPE_TOP, NULL, ICON_SHAPE, CHANNELTYPE_TOP );
  2081. // Create entry for our lobbies at the top.
  2082. bool bFound = false;
  2083. // (There are actually 2 additional game types at the end of GameTypeInfos - for ws icon and wwonline icon.)
  2084. for( int i = 0; i < nGameTypeInfos - 2; i++ )
  2085. {
  2086. if( GameTypeInfos[ i ].iGameType == GAME_TYPE )
  2087. {
  2088. //pILChannels->Add_Item( GameTypeInfos[ i ].szName, CHANNELTYPE_LOBBIES, (void*)GameTypeInfos[ i ].pDIB, ICON_DIB, CHANNELTYPE_LOBBIES );
  2089. pILChannels->Add_Item( TXT_WOL_REDALERTLOBBIES, CHANNELTYPE_LOBBIES, (void*)GameTypeInfos[ i ].pDIB, ICON_DIB, CHANNELTYPE_LOBBIES );
  2090. bFound = true;
  2091. break;
  2092. }
  2093. }
  2094. if( !bFound )
  2095. {
  2096. // In the production version, this should never happen, as there should always be a gametypeinfo created that matches
  2097. // our game type. It depends on the recentness of the WOR file accompanying the wolapi.dll.
  2098. pILChannels->Add_Item( TXT_WOL_REDALERTLOBBIES, CHANNELTYPE_LOBBIES, (void*)OldRAGameTypeInfos[ 0 ].pDIB, ICON_DIB, CHANNELTYPE_LOBBIES );
  2099. }
  2100. // A pointer to the GameTypeInfos entry is stored in the item for convenience later.
  2101. for( i = 0; i < nGameTypeInfos - 2; i++ )
  2102. {
  2103. int iType = GameTypeInfos[ i ].iGameType;
  2104. if( iType != GAME_TYPE ) // Else it is our game - skip it here since we put it at the top.
  2105. {
  2106. if( iType != 2 && iType != 3 && iType != 4 ) // Hack needed for the time being, to prevent the old ra games from being seen.
  2107. {
  2108. char szHelp[ 200 ];
  2109. sprintf( szHelp, TXT_WOL_TTIP_CHANNELTYPE_GAMESOFTYPE, GameTypeInfos[ i ].szName );
  2110. pILChannels->Add_Item( GameTypeInfos[ i ].szName, szHelp, (void*)GameTypeInfos[ i ].pDIB, ICON_DIB, CHANNELTYPE_GAMESOFTYPE, (void*)&GameTypeInfos[ i ] );
  2111. }
  2112. }
  2113. }
  2114. // Set wol buttons enabled/disabled.
  2115. pShpBtnLeave->Disable();
  2116. pShpBtnRefresh->Disable();
  2117. pShpBtnSquelch->Disable();
  2118. pShpBtnBan->Disable();
  2119. pShpBtnKick->Disable();
  2120. return true;
  2121. }
  2122. //***********************************************************************************************
  2123. bool WolapiObject::EnterLevel_GamesOfType( WOL_GAMETYPEINFO* pGameTypeInfo )
  2124. {
  2125. // <Showing current game channels of a specific type - not our own game type.>
  2126. // debugprint( "*** EnterLevel_GamesOfType: pGameTypeInfo->szName %s, iGameType %i, URL %s\n", pGameTypeInfo->szName, pGameTypeInfo->iGameType, pGameTypeInfo->szURL );
  2127. CurrentLevel = WOL_LEVEL_GAMESOFTYPE;
  2128. if( !UpdateChannels( pGameTypeInfo->iGameType, CHANNELFILTER_NO, true ) )
  2129. {
  2130. GenericErrorMessage();
  2131. return false;
  2132. }
  2133. ChannelListTitle( pGameTypeInfo->szName );
  2134. pILChannels->Clear();
  2135. pILChannels->Add_Item( TXT_WOL_CHANNELLISTLOADING, CHANNELTYPE_LOADING, NULL, ICON_SHAPE, CHANNELTYPE_LOADING );
  2136. dwTimeNextChannelUpdate = ::timeGetTime(); // Set trigger for an immediate channel list update.
  2137. // Set wol buttons enabled/disabled.
  2138. pShpBtnLeave->Disable();
  2139. pShpBtnRefresh->Enable();
  2140. pShpBtnSquelch->Disable();
  2141. pShpBtnBan->Disable();
  2142. pShpBtnKick->Disable();
  2143. return true;
  2144. }
  2145. //***********************************************************************************************
  2146. bool WolapiObject::EnterLevel_Lobbies()
  2147. {
  2148. // <Showing available lobbies.>
  2149. // debugprint( "*** EnterLevel_Lobbies\n" );
  2150. CurrentLevel = WOL_LEVEL_LOBBIES;
  2151. if( !UpdateChannels( 0, CHANNELFILTER_LOBBIES, false ) )
  2152. {
  2153. GenericErrorMessage();
  2154. return false;
  2155. }
  2156. ChannelListTitle( TXT_WOL_REDALERTLOBBIES );
  2157. pILChannels->Clear();
  2158. pILChannels->Add_Item( TXT_WOL_CHANNELLISTLOADING, CHANNELTYPE_LOADING, NULL, ICON_SHAPE, CHANNELTYPE_LOADING );
  2159. dwTimeNextChannelUpdate = ::timeGetTime(); // Set trigger for an immediate channel list update.
  2160. // Set wol buttons enabled/disabled.
  2161. pShpBtnLeave->Disable();
  2162. pShpBtnRefresh->Enable();
  2163. pShpBtnSquelch->Disable();
  2164. pShpBtnBan->Disable();
  2165. pShpBtnKick->Disable();
  2166. return true;
  2167. }
  2168. //***********************************************************************************************
  2169. bool WolapiObject::OnEnteringChatChannel( const char* szChannelName, bool bICreatedChannel, int iLobby )
  2170. {
  2171. // Called when a chat channel (or lobby) has been successfully joined.
  2172. // debugprint( "*** OnEnteringChatChannel '%s'\n", szChannelName );
  2173. // // Block until we have a userlist. - Not necessary - always comes immediately following OnJoin.
  2174. // if( !UserList() )
  2175. // return false;
  2176. // Request ladders if this is a lobby.
  2177. if( iLobby != -1 )
  2178. RequestLadders( NULL );
  2179. // Set channels list.
  2180. pILChannels->Clear();
  2181. // Add a "return" choice at the top of the channel list, based on where we want to go 'back' to...
  2182. if( iLobby == -1 )
  2183. {
  2184. switch( CurrentLevel )
  2185. {
  2186. case WOL_LEVEL_OFFICIALCHAT:
  2187. pILChannels->Add_Item( TXT_WOL_CHANNEL_BACK, CHANNELTYPE_OFFICIALCHAT, NULL, ICON_SHAPE, CHANNELTYPE_OFFICIALCHAT );
  2188. break;
  2189. case WOL_LEVEL_USERCHAT:
  2190. pILChannels->Add_Item( TXT_WOL_CHANNEL_BACK, CHANNELTYPE_USERCHAT, NULL, ICON_SHAPE, CHANNELTYPE_USERCHAT );
  2191. break;
  2192. default:
  2193. // If entering a channel from anywhere else, user must have created the channel.
  2194. // Make "back" take them to user channels list.
  2195. // if( bICreatedChannel ) // ajw just verifying
  2196. pILChannels->Add_Item( TXT_WOL_CHANNEL_BACK, CHANNELTYPE_USERCHAT, NULL, ICON_SHAPE, CHANNELTYPE_USERCHAT );
  2197. /* else
  2198. {
  2199. // debugprint( "Case that should not occur in OnEnteringChatChannel. CurrentLevel %i\n", CurrentLevel );
  2200. pILChannels->Add_Item( "ERROR in OnEnteringChatChannel", NULL, NULL, ICON_SHAPE, CHANNELTYPE_TOP );
  2201. }
  2202. */
  2203. break;
  2204. }
  2205. }
  2206. else
  2207. {
  2208. pILChannels->Add_Item( TXT_WOL_CHANNEL_BACK, CHANNELTYPE_LOBBIES, NULL, ICON_SHAPE, CHANNELTYPE_LOBBIES );
  2209. }
  2210. char* szMess;
  2211. if( iLobby == -1 )
  2212. {
  2213. CurrentLevel = WOL_LEVEL_INCHATCHANNEL;
  2214. szMess = new char[ strlen( TXT_WOL_YOUJOINED ) + strlen( szChannelName ) + 5 ];
  2215. sprintf( szMess, TXT_WOL_YOUJOINED, szChannelName );
  2216. ChannelListTitle( szChannelName );
  2217. }
  2218. else
  2219. {
  2220. CurrentLevel = WOL_LEVEL_INLOBBY;
  2221. char szLobbyName[ REASONABLELOBBYINTERPRETEDNAMELEN ];
  2222. InterpretLobbyNumber( szLobbyName, iLobby );
  2223. szMess = new char[ strlen( TXT_WOL_YOUJOINEDLOBBY ) + REASONABLELOBBYINTERPRETEDNAMELEN + 10 ];
  2224. sprintf( szMess, TXT_WOL_YOUJOINEDLOBBY, szLobbyName );
  2225. ChannelListTitle( szLobbyName );
  2226. iLobbyLast = iLobby;
  2227. dwTimeNextChannelUpdate = ::timeGetTime(); // Set trigger for an immediate channel list update.
  2228. }
  2229. strcpy( szChannelNameCurrent, szChannelName );
  2230. bChannelOwner = bICreatedChannel;
  2231. // Set users list.
  2232. ListChannelUsers();
  2233. PrintMessage( szMess, WOLCOLORREMAP_LOCALMACHINEMESS );
  2234. delete [] szMess;
  2235. Sound_Effect( WOLSOUND_ENTERCHAN );
  2236. // Set wol buttons enabled/disabled.
  2237. pShpBtnLeave->Enable();
  2238. if( CurrentLevel == WOL_LEVEL_INLOBBY )
  2239. pShpBtnRefresh->Enable();
  2240. else
  2241. pShpBtnRefresh->Disable();
  2242. pShpBtnSquelch->Enable();
  2243. if( bChannelOwner )
  2244. {
  2245. pShpBtnBan->Enable();
  2246. pShpBtnKick->Enable();
  2247. }
  2248. else
  2249. {
  2250. pShpBtnBan->Disable();
  2251. pShpBtnKick->Disable();
  2252. }
  2253. return true;
  2254. }
  2255. //***********************************************************************************************
  2256. void WolapiObject::OnExitingChatChannel()
  2257. {
  2258. // Called when we successfully ExitChannel, or we get kicked out. (Lobbies included.)
  2259. // Clear users list.
  2260. pILUsers->Clear();
  2261. if( pStaticUsers )
  2262. pStaticUsers->Set_Text( TXT_WOL_NOUSERLIST );
  2263. // debugprint( "*** OnExitingChatChannel() - szChannelNameCurrent '%s', CurrentLevel %i\n", szChannelNameCurrent, CurrentLevel );
  2264. int iLobby = iChannelLobbyNumber( (unsigned char*)szChannelNameCurrent );
  2265. char* szMess;
  2266. if( iLobby == -1 )
  2267. {
  2268. szMess = new char[ strlen( TXT_WOL_YOULEFT ) + strlen( szChannelNameCurrent ) + 5 ];
  2269. sprintf( szMess, TXT_WOL_YOULEFT, szChannelNameCurrent );
  2270. }
  2271. else
  2272. {
  2273. // Channel is a lobby.
  2274. char szLobbyName[ REASONABLELOBBYINTERPRETEDNAMELEN ];
  2275. InterpretLobbyNumber( szLobbyName, iLobby );
  2276. szMess = new char[ strlen( TXT_WOL_YOULEFTLOBBY ) + REASONABLELOBBYINTERPRETEDNAMELEN + 10 ];
  2277. sprintf( szMess, TXT_WOL_YOULEFTLOBBY, szLobbyName );
  2278. }
  2279. PrintMessage( szMess, WOLCOLORREMAP_LOCALMACHINEMESS );
  2280. delete [] szMess;
  2281. *szChannelNameCurrent = 0;
  2282. CurrentLevel = WOL_LEVEL_INVALID;
  2283. Sound_Effect( WOLSOUND_EXITCHAN );
  2284. }
  2285. //***********************************************************************************************
  2286. bool WolapiObject::ExitChatChannelForGameChannel()
  2287. {
  2288. // We are about to try and join/create a game channel, and are currently in a chat channel.
  2289. // Save this channel name, so we can come back to it if game channel join/create fails.
  2290. strcpy( szChannelReturnOnGameEnterFail, szChannelNameCurrent );
  2291. if( !ChannelLeave() )
  2292. {
  2293. GenericErrorMessage();
  2294. return false;
  2295. }
  2296. return true;
  2297. }
  2298. //***********************************************************************************************
  2299. bool WolapiObject::OnEnteringGameChannel( const char* szChannelName, bool bICreatedChannel,
  2300. const CREATEGAMEINFO& CreateGameInfo )
  2301. {
  2302. // Called when a game channel has been successfully joined, while still in chat dialog,
  2303. // before game dialog has been created.
  2304. // CreateGameInfo is copied to GameInfoCurrent, so that we know what kind of a game we're in during setup.
  2305. // debugprint( "*** OnEnteringGameChannel() - %s\n", szChannelName );
  2306. CurrentLevel = WOL_LEVEL_INGAMECHANNEL;
  2307. strcpy( szChannelNameCurrent, szChannelName );
  2308. bChannelOwner = bICreatedChannel;
  2309. // GameKindCurrent = GameKind;
  2310. GameInfoCurrent = CreateGameInfo;
  2311. strcpy( GameInfoCurrent.szPassword, CreateGameInfo.szPassword );
  2312. // Remove shared buttons from wolchat's command list.
  2313. pShpBtnDiscon->Zap();
  2314. pShpBtnLeave->Zap();
  2315. pShpBtnRefresh->Zap();
  2316. pShpBtnSquelch->Zap();
  2317. pShpBtnBan->Zap();
  2318. pShpBtnKick->Zap();
  2319. pShpBtnFindpage->Zap();
  2320. pShpBtnOptions->Zap();
  2321. pShpBtnLadder->Zap();
  2322. pShpBtnHelp->Zap();
  2323. // Set wol buttons enabled/disabled.
  2324. pShpBtnLeave->Enable();
  2325. pShpBtnRefresh->Disable();
  2326. pShpBtnSquelch->Enable();
  2327. if( bChannelOwner )
  2328. {
  2329. pShpBtnBan->Enable();
  2330. pShpBtnKick->Enable();
  2331. }
  2332. else
  2333. {
  2334. pShpBtnBan->Disable();
  2335. pShpBtnKick->Disable();
  2336. }
  2337. if( CreateGameInfo.GameKind == CREATEGAMEINFO::AMGAME )
  2338. {
  2339. if( bShowRankRA )
  2340. {
  2341. // Switch to "show AM rankings" mode.
  2342. bShowRankRA = false;
  2343. bMyRecordUpdated = true;
  2344. bShowRankUpdated = true;
  2345. }
  2346. }
  2347. else
  2348. {
  2349. if( !bShowRankRA )
  2350. {
  2351. // Switch to "show RA rankings" mode.
  2352. bShowRankRA = true;
  2353. bMyRecordUpdated = true;
  2354. bShowRankUpdated = true;
  2355. }
  2356. }
  2357. return true;
  2358. }
  2359. //***********************************************************************************************
  2360. bool WolapiObject::OnEnteringGameSetup()
  2361. {
  2362. // Called when entering the game setup screen. Controls are initialized. OnEnteringGameChannel
  2363. // has just been called earlier.
  2364. // Returns false only if we find there is not host - he must have simultaneously left.
  2365. // // Block until we have a userlist. - Not necessary - always comes immediately following OnJoin.
  2366. // if( !UserList() )
  2367. // return false;
  2368. // Request ladders.
  2369. RequestLadders( NULL );
  2370. // Request IP addresses.
  2371. RequestIPs( NULL );
  2372. // Set users list.
  2373. if( !ListChannelUsers() )
  2374. {
  2375. // No host was found currently in channel!
  2376. return false;
  2377. }
  2378. if( !pGSupDlg->bHost )
  2379. {
  2380. char* szMess = new char[ strlen( TXT_WOL_YOUJOINEDGAME ) + WOL_NAME_LEN_MAX + 5 ];
  2381. char szHostName[ WOL_NAME_LEN_MAX ];
  2382. HostNameFromGameChannelName( szHostName, szChannelNameCurrent );
  2383. sprintf( szMess, TXT_WOL_YOUJOINEDGAME, szHostName );
  2384. PrintMessage( szMess, WOLCOLORREMAP_LOCALMACHINEMESS );
  2385. delete [] szMess;
  2386. }
  2387. else
  2388. PrintMessage( TXT_WOL_YOUCREATEDGAME, WOLCOLORREMAP_LOCALMACHINEMESS );
  2389. return true;
  2390. }
  2391. //***********************************************************************************************
  2392. void WolapiObject::OnFailedToEnterGameChannel()
  2393. {
  2394. if( *szChannelReturnOnGameEnterFail == 0 )
  2395. return;
  2396. // This is called when we fail to join/create a game channel.
  2397. *szChannelNameCurrent = 0;
  2398. // Because we don't save the channel key as well, assume the usual lobby password. If we fail, we'll return to top level.
  2399. HRESULT hRes = ChannelJoin( szChannelReturnOnGameEnterFail, LOBBYPASSWORD );
  2400. switch( hRes )
  2401. {
  2402. case S_OK:
  2403. OnEnteringChatChannel( szChannelReturnOnGameEnterFail, false, iChannelLobbyNumber( (unsigned char*)szChannelReturnOnGameEnterFail ) );
  2404. break;
  2405. default:
  2406. // ChannelJoin returned fail value.
  2407. // (Now only applies if you could ever enter a game channel from a non-lobby.)
  2408. // There is the possibility that the channel we were in disappeared in the instant between leaving it and
  2409. // failing to join the game channel. <sigh> Or, the channel has a password, that we didn't record. In either
  2410. // case, go back to the top level.
  2411. GenericErrorMessage();
  2412. EnterLevel_Top();
  2413. }
  2414. }
  2415. //***********************************************************************************************
  2416. void WolapiObject::OnExitingGameChannel()
  2417. {
  2418. // This is called after we leave a game channel, while still in the game setup dialog.
  2419. // Remove shared buttons from wolgsup's command list.
  2420. pShpBtnDiscon->Zap();
  2421. pShpBtnLeave->Zap();
  2422. pShpBtnRefresh->Zap();
  2423. pShpBtnSquelch->Zap();
  2424. pShpBtnBan->Zap();
  2425. pShpBtnKick->Zap();
  2426. pShpBtnFindpage->Zap();
  2427. pShpBtnOptions->Zap();
  2428. pShpBtnLadder->Zap();
  2429. pShpBtnHelp->Zap();
  2430. CurrentLevel = WOL_LEVEL_INVALID;
  2431. *szChannelNameCurrent = 0;
  2432. }
  2433. //***********************************************************************************************
  2434. void WolapiObject::RejoinLobbyAfterGame()
  2435. {
  2436. // Called to rejoin lobby after EITHER a game, or the game setup dialog.
  2437. //debugprint( "RejoinLobbyAfterGame, iLobbyReturnAfterGame is %i\n", iLobbyReturnAfterGame );
  2438. if( iLobbyReturnAfterGame == -1 )
  2439. {
  2440. // Will never happen presumably, if games are always entered via a lobby chat channel.
  2441. // We will naturally reenter the top level.
  2442. }
  2443. else
  2444. {
  2445. char szChannelToJoin[ WOL_CHANNAME_LEN_MAX ];
  2446. //sprintf( szChannelToJoin, "Lob_%i_%i", GAME_TYPE, iLobbyReturnAfterGame );
  2447. sprintf( szChannelToJoin, "%s%i", LOB_PREFIX, iLobbyReturnAfterGame );
  2448. //debugprint( "RejoinLobbyAfterGame, channel is %s\n", szChannelToJoin );
  2449. HRESULT hRes = ChannelJoin( szChannelToJoin, LOBBYPASSWORD );
  2450. switch( hRes )
  2451. {
  2452. case S_OK:
  2453. //OnEnteringChatChannel( szChannelToJoin, false ); Done automatically now in wol_chat.
  2454. break;
  2455. default:
  2456. // Something went wrong when trying to rejoin the lobby we were in.
  2457. // We'll go back to the top level instead, which happens automatically if we do this...
  2458. iLobbyReturnAfterGame = -1;
  2459. break;
  2460. }
  2461. }
  2462. }
  2463. //***********************************************************************************************
  2464. bool WolapiObject::RequestLadders( const char* szName )
  2465. {
  2466. // If szName is NULL, calls RequestLadderList() until all ladder structs for all users in pChatSink's current
  2467. // list have been asked for. Does not wait for results - these come in asynchronously. The previous list is
  2468. // erased before new results come in.
  2469. // If szName is valid, asks for specific name only. Result is appended to current ladder list.
  2470. // This function does not block.
  2471. if( szName && *szName )
  2472. {
  2473. // debugprint( "RequestLadderList( %s )\n", szName );
  2474. if( !SUCCEEDED( pNetUtil->RequestLadderList( szLadderServerHost, iLadderServerPort, szName, LADDER_CODE_RA, -1, 0, 0 ) ) )
  2475. {
  2476. // debugprint( "RequestLadderList() call failed\n" );
  2477. return false;
  2478. }
  2479. if( !SUCCEEDED( pNetUtil->RequestLadderList( szLadderServerHost, iLadderServerPort, szName, LADDER_CODE_AM, -1, 0, 0 ) ) )
  2480. {
  2481. // debugprint( "RequestLadderList() call failed\n" );
  2482. return false;
  2483. }
  2484. return true;
  2485. }
  2486. char szNames[ ( WOL_NAME_LEN_MAX + 1 ) * 30 ]; // Neal says max is actually 25 names requested at once. Do 24...
  2487. pNetUtilSink->DeleteLadderList();
  2488. // Do not request more than this number of times, to prevent overloads to ladder server.
  2489. // If we have that many people in the channel, forget about doing ladders for all of them.
  2490. // Probably this will never come into play (except while testing), because lobbies will be limited in # of users.
  2491. int iCallLimit = 4;
  2492. User* pUser = pChatSink->pUserList;
  2493. while( pUser )
  2494. {
  2495. // Reset names string.
  2496. *szNames = 0;
  2497. // Get 24 users from list and add names to string.
  2498. for( int i = 0; i != 24; ++i )
  2499. {
  2500. strcat( szNames, (char*)pUser->name );
  2501. strcat( szNames, ":" );
  2502. pUser = pUser->next;
  2503. if( !pUser )
  2504. break;
  2505. }
  2506. // Remove last colon.
  2507. szNames[ strlen( szNames ) - 1 ] = 0;
  2508. // debugprint( "RequestLadderList( %s )\n", szNames );
  2509. if( !SUCCEEDED( pNetUtil->RequestLadderList( szLadderServerHost, iLadderServerPort, szNames, LADDER_CODE_RA, -1, 0, 0 ) ) )
  2510. {
  2511. // debugprint( "RequestLadderList() call failed\n" );
  2512. return false;
  2513. }
  2514. if( !SUCCEEDED( pNetUtil->RequestLadderList( szLadderServerHost, iLadderServerPort, szNames, LADDER_CODE_AM, -1, 0, 0 ) ) )
  2515. {
  2516. // debugprint( "RequestLadderList() call failed\n" );
  2517. return false;
  2518. }
  2519. if( --iCallLimit == 0 )
  2520. return false;
  2521. }
  2522. return true;
  2523. }
  2524. //***********************************************************************************************
  2525. bool WolapiObject::RequestIPs( const char* szName )
  2526. {
  2527. // If szName is NULL, calls RequestUserIP() until IPs for all users in pChatSink's current
  2528. // list have been asked for. Does not wait for results - these come in asynchronously. The previous list is
  2529. // erased before new results come in.
  2530. // If szName is valid, asks for specific name only. Result is appended to current IP list.
  2531. // This function does not block.
  2532. if( szName && *szName )
  2533. {
  2534. User user;
  2535. strcpy( (char*)user.name, szName );
  2536. // debugprint( "RequestUserIP( %s )\n", szName );
  2537. if( !SUCCEEDED( pChat->RequestUserIP( &user ) ) )
  2538. {
  2539. // debugprint( "RequestUserIP() call failed\n" );
  2540. return false;
  2541. }
  2542. return true;
  2543. }
  2544. // Do all users in current chatsink list.
  2545. pChatSink->DeleteUserIPList(); // Clear old user IPs. (To keep searches fast, if we go in and out of game channels a lot.)
  2546. User* pUser = pChatSink->pUserList;
  2547. while( pUser )
  2548. {
  2549. if( !( pUser->flags & CHAT_USER_MYSELF ) )
  2550. {
  2551. if( !SUCCEEDED( pChat->RequestUserIP( pUser ) ) )
  2552. {
  2553. // debugprint( "RequestUserIP() call failed\n" );
  2554. return false;
  2555. }
  2556. }
  2557. pUser = pUser->next;
  2558. }
  2559. return true;
  2560. }
  2561. //***********************************************************************************************
  2562. void WolapiObject::SaveChat()
  2563. {
  2564. // Basically, a big hack to avoiding restructuring things so that the dialogs are persistent
  2565. // objects. Save the contents of the chat list in the chat dialog so that we can refresh it
  2566. // after returning from the game setup dialog (if necessary).
  2567. // This turns out to be the easiest and most straightforward way to implement this.
  2568. pChatSaveLast = pChatSaveList = NULL;
  2569. CHATSAVE* pChatSaveNew;
  2570. for( int i = 0; i != pILChat->Count(); i++ )
  2571. {
  2572. pChatSaveNew = new CHATSAVE;
  2573. const char* szItem = pILChat->Get_Item( i );
  2574. if( strlen( szItem ) < SAVECHATWIDTH )
  2575. strcpy( pChatSaveNew->szText, szItem );
  2576. const IconList_ItemExtras* pItemExtras = pILChat->Get_ItemExtras( i );
  2577. pChatSaveNew->ItemExtras.pColorRemap = pItemExtras->pColorRemap;
  2578. pChatSaveNew->next = NULL;
  2579. if( pChatSaveLast )
  2580. pChatSaveLast->next = pChatSaveNew;
  2581. else
  2582. pChatSaveList = pChatSaveNew;
  2583. pChatSaveLast = pChatSaveNew;
  2584. }
  2585. }
  2586. //***********************************************************************************************
  2587. void WolapiObject::RestoreChat()
  2588. {
  2589. // See SaveChat()...
  2590. CHATSAVE* pChatSave = pChatSaveList;
  2591. while( pChatSave )
  2592. {
  2593. PrintMessage( pChatSave->szText, pChatSave->ItemExtras.pColorRemap );
  2594. pChatSave = pChatSave->next;
  2595. }
  2596. }
  2597. //***********************************************************************************************
  2598. void WolapiObject::AddHostLeftMessageToSavedChat( const char* szName )
  2599. {
  2600. CHATSAVE* pChatSaveNew;
  2601. pChatSaveNew = new CHATSAVE;
  2602. sprintf( pChatSaveNew->szText, TXT_WOL_HOSTLEFTGAME, szName );
  2603. pChatSaveNew->ItemExtras.pColorRemap = &ColorRemaps[ WOLCOLORREMAP_LOCALMACHINEMESS ];
  2604. pChatSaveNew->next = NULL;
  2605. if( pChatSaveLast )
  2606. pChatSaveLast->next = pChatSaveNew;
  2607. else
  2608. pChatSaveList = pChatSaveNew;
  2609. pChatSaveLast = pChatSaveNew;
  2610. }
  2611. //***********************************************************************************************
  2612. void WolapiObject::AddMessageToSavedChat( const char* szMessage )
  2613. {
  2614. CHATSAVE* pChatSaveNew;
  2615. pChatSaveNew = new CHATSAVE;
  2616. strcpy( pChatSaveNew->szText, szMessage );
  2617. pChatSaveNew->ItemExtras.pColorRemap = &ColorRemaps[ WOLCOLORREMAP_LOCALMACHINEMESS ];
  2618. pChatSaveNew->next = NULL;
  2619. if( pChatSaveLast )
  2620. pChatSaveLast->next = pChatSaveNew;
  2621. else
  2622. pChatSaveList = pChatSaveNew;
  2623. pChatSaveLast = pChatSaveNew;
  2624. }
  2625. //***********************************************************************************************
  2626. void WolapiObject::DeleteSavedChat()
  2627. {
  2628. // See SaveChat()...
  2629. CHATSAVE* pChatSaveNext;
  2630. while( pChatSaveList )
  2631. {
  2632. pChatSaveNext = pChatSaveList->next;
  2633. delete pChatSaveList;
  2634. pChatSaveList = pChatSaveNext;
  2635. }
  2636. }
  2637. //***********************************************************************************************
  2638. void WolapiObject::GenericErrorMessage()
  2639. {
  2640. // Displays generic "something bad happened" error message.
  2641. bPump_In_Call_Back = true;
  2642. WWMessageBox().Process( TXT_WOL_ERRORMESSAGE );
  2643. bPump_In_Call_Back = false;
  2644. }
  2645. //***********************************************************************************************
  2646. bool WolapiObject::GetNameOfBeginningLobby( char* szNameToSet )
  2647. {
  2648. // Checks for game lobbies, sets szNameToSet to the channel name that the new user should enter and returns true if succeeds.
  2649. if( !GetLobbyChannels() )
  2650. return false;
  2651. // Chatsink should now have a list of lobbies.
  2652. int iCount = 0;
  2653. Channel* pChannel = pChatSink->pChannelList;
  2654. if( !pChannel )
  2655. // List is empty.
  2656. return false;
  2657. // Return the name of the first lobby with less than 50 users.
  2658. while( pChannel )
  2659. {
  2660. if( pChannel->currentUsers < 50 )
  2661. {
  2662. strcpy( szNameToSet, (char*)pChannel->name );
  2663. return true;
  2664. }
  2665. ++iCount;
  2666. pChannel = pChannel->next;
  2667. }
  2668. // All lobbies have 50 or more users. So just choose a random one.
  2669. int iChoice = ( rand() % iCount );
  2670. pChannel = pChatSink->pChannelList;
  2671. for( int i = 0; i != iChoice; i++ )
  2672. pChannel = pChannel->next;
  2673. strcpy( szNameToSet, (char*)pChannel->name );
  2674. return true;
  2675. }
  2676. //***********************************************************************************************
  2677. bool WolapiObject::GetLobbyChannels()
  2678. {
  2679. // Modal version of UpdateChannels, for fetching lobby names.
  2680. // // Returns false upon total failure. ajxxx do same for other calls
  2681. // WWMessageBox().Process( TXT_WOL_WAIT, TXT_NONE );
  2682. pChatSink->bRequestChannelListForLobbiesWait = true;
  2683. pChatSink->ChannelFilter = CHANNELFILTER_LOBBIES;
  2684. // debugprint( "RequestChannelList() for lobbies\n" );
  2685. if( !SUCCEEDED( pChat->RequestChannelList( 0, false ) ) )
  2686. {
  2687. // debugprint( "RequestChannelList() call failed\n" );
  2688. return false;
  2689. }
  2690. DWORD dwTimeStart = timeGetTime();
  2691. DWORD dwTimeNextPump = timeGetTime() + PUMPSLEEPDURATION;
  2692. while( pChatSink->bRequestChannelListForLobbiesWait && timeGetTime() - dwTimeStart < EMERGENCY_TIMEOUT )
  2693. {
  2694. while( timeGetTime() < dwTimeNextPump )
  2695. Call_Back();
  2696. pChat->PumpMessages();
  2697. dwTimeNextPump = timeGetTime() + PUMPSLEEPDURATION;
  2698. }
  2699. if( pChatSink->bRequestChannelListForLobbiesWait )
  2700. return false;
  2701. return true;
  2702. }
  2703. //***********************************************************************************************
  2704. const char* WolapiObject::pGameHostName()
  2705. {
  2706. // Returns a POINTER (careful - temporary!) to the name of the creator of the game channel we're in, or null.
  2707. // Uses players' list as its means of reference.
  2708. if( pILPlayers )
  2709. {
  2710. for( int i = 0; i != pILPlayers->Count(); i++ )
  2711. {
  2712. User* pUser = (User*)pILPlayers->Get_Item_ExtraDataPtr( i );
  2713. if( pUser && pUser->flags & CHAT_USER_CHANNELOWNER )
  2714. return (char*)pUser->name;
  2715. }
  2716. }
  2717. return NULL;
  2718. }
  2719. //***********************************************************************************************
  2720. User* WolapiObject::pGameHost()
  2721. {
  2722. // Returns a POINTER (careful - temporary!) to the creator of the game channel we're in, or null.
  2723. // Uses players' list as its means of reference.
  2724. if( pILPlayers )
  2725. {
  2726. for( int i = 0; i != pILPlayers->Count(); i++ )
  2727. {
  2728. User* pUser = (User*)pILPlayers->Get_Item_ExtraDataPtr( i );
  2729. if( pUser && pUser->flags & CHAT_USER_CHANNELOWNER )
  2730. return pUser;
  2731. }
  2732. }
  2733. return NULL;
  2734. }
  2735. //***********************************************************************************************
  2736. bool WolapiObject::SendGameOpt( const char* szSend, User* pUserPriv )
  2737. {
  2738. // Used during game setup to send public or private game options string.
  2739. // If pUserPriv is NULL, message is public, else private to pUserPriv.
  2740. if( !pUserPriv )
  2741. {
  2742. // debugprint( "Send public game opt: '%s'\n", szSend );
  2743. if( !SUCCEEDED( pChat->RequestPublicGameOptions( szSend ) ) )
  2744. {
  2745. // debugprint( "RequestPublicGameOptions() call failed\n" );
  2746. return false;
  2747. }
  2748. }
  2749. else
  2750. {
  2751. // debugprint( "Send private game opt to %s: '%s'\n", (char*)pUserPriv->name, szSend );
  2752. if( !SUCCEEDED( pChat->RequestPrivateGameOptions( pUserPriv, szSend ) ) )
  2753. {
  2754. // debugprint( "RequestPrivateGameOptions() call failed\n" );
  2755. return false;
  2756. }
  2757. }
  2758. return true;
  2759. }
  2760. //***********************************************************************************************
  2761. bool WolapiObject::RequestGameStart()
  2762. {
  2763. // Host is starting a game.
  2764. /*
  2765. // Block any users that join the channel in the next microsecond from becoming involved, and
  2766. // block any users that leave from being recognized as having left.
  2767. //what if someone leaves?
  2768. // This is done to preserve the integrity of the ChatSink's user list
  2769. pWO->pChatSink->bIgnoreJoin = true;
  2770. */
  2771. pChatSink->bRequestGameStartWait = true;
  2772. // debugprint( "RequestGameStart()\n" );
  2773. if( !SUCCEEDED( pChat->RequestGameStart( pChatSink->pUserList ) ) )
  2774. {
  2775. // debugprint( "RequestGameStart() call failed\n" );
  2776. return false;
  2777. }
  2778. DWORD dwTimeStart = timeGetTime();
  2779. DWORD dwTimeNextPump = timeGetTime() + PUMPSLEEPDURATION;
  2780. while( pChatSink->bRequestGameStartWait && timeGetTime() - dwTimeStart < EMERGENCY_TIMEOUT )
  2781. {
  2782. while( timeGetTime() < dwTimeNextPump )
  2783. Call_Back();
  2784. pChat->PumpMessages();
  2785. dwTimeNextPump = timeGetTime() + PUMPSLEEPDURATION;
  2786. }
  2787. if( pChatSink->bRequestGameStartWait )
  2788. {
  2789. // debugprint( "WolapiObject::RequestGameStart returning false\n" );
  2790. pChatSink->bRequestGameStartWait = false;
  2791. return false;
  2792. }
  2793. // debugprint( "WolapiObject::RequestGameStart returning true\n" );
  2794. return true;
  2795. }
  2796. //***********************************************************************************************
  2797. bool WolapiObject::SendGo( const char* szSend )
  2798. {
  2799. // Send a "GO" message to all players included in the list that came back from OnGameStart.
  2800. // (Don't just broadcast it. We don't want to include any users that may have joined the channel
  2801. // in the last microsecond.)
  2802. // debugprint( "SendGo()\n" );
  2803. User* pUser = pChatSink->pGameUserList;
  2804. while( pUser )
  2805. {
  2806. // if( !( pUser->flags & CHAT_USER_MYSELF ) ) Method changed. I now wait for go message to bounce back to me.
  2807. // {
  2808. // debugprint( "Send private game opt to %s: '%s'\n", (char*)pUser->name, szSend );
  2809. if( !SUCCEEDED( pChat->RequestPrivateGameOptions( pUser, szSend ) ) )
  2810. {
  2811. // debugprint( "RequestPrivateGameOptions() call failed\n" );
  2812. return false;
  2813. }
  2814. // }
  2815. pUser = pUser->next;
  2816. }
  2817. return true;
  2818. }
  2819. //***********************************************************************************************
  2820. void WolapiObject::Init_DisconnectPinging()
  2821. {
  2822. // Sets us up to begin "disconnect pinging" - the pinging that occurs when connection is broken
  2823. // during a tournament game. The idea is to try and figure out who is responsible for the connection
  2824. // going down. We do this by repeatedly pinging the opponent and the game results server. The number
  2825. // of successful pings is sent in the game results package.
  2826. iDisconnectPingCurrent = 0;
  2827. for( int i = 0; i != DISCONNECT_PING_COUNT; ++i )
  2828. {
  2829. DisconnectPingResult_Server[ i ] = PING_UNSTARTED;
  2830. DisconnectPingResult_Opponent[ i ] = PING_UNSTARTED;
  2831. }
  2832. bDisconnectPingingCompleted = false;
  2833. bDoingDisconnectPinging = true;
  2834. }
  2835. //***********************************************************************************************
  2836. bool WolapiObject::Pump_DisconnectPinging()
  2837. {
  2838. // Called repeatedly and continuously when it seems a tournament game connection with the opponent
  2839. // has been broken. Does PumpMessages() and requests new pings when previous results have been received.
  2840. // Returns true when the required number of pings have been completed.
  2841. if( ::timeGetTime() > dwTimeNextWolapiPump )
  2842. {
  2843. pChat->PumpMessages();
  2844. pNetUtil->PumpMessages();
  2845. dwTimeNextWolapiPump = ::timeGetTime() + WOLAPIPUMPWAIT;
  2846. }
  2847. switch( DisconnectPingResult_Server[ iDisconnectPingCurrent ] )
  2848. {
  2849. case PING_UNSTARTED:
  2850. // Pings have yet to be requested.
  2851. // Ping game results server.
  2852. int iUnused;
  2853. if( *szGameResServerHost1 )
  2854. {
  2855. // debugprint( "RequestPing ( gameres server )\n" );
  2856. if( pNetUtil->RequestPing( szGameResServerHost1, 1000, &iUnused ) != S_OK )
  2857. {
  2858. // debugprint( "RequestPing() ( gameres server ) failed\n" );
  2859. DisconnectPingResult_Server[ iDisconnectPingCurrent ] = PING_BAD;
  2860. }
  2861. DisconnectPingResult_Server[ iDisconnectPingCurrent ] = PING_WAITING;
  2862. }
  2863. else
  2864. // We never got an address for the gameresults server. Fake fail result.
  2865. DisconnectPingResult_Server[ iDisconnectPingCurrent ] = PING_BAD;
  2866. // Ping opponent.
  2867. in_addr inaddr;
  2868. char* szIP;
  2869. inaddr.s_addr = TournamentOpponentIP;
  2870. szIP = inet_ntoa( inaddr );
  2871. // debugprint( "RequestPing ( opponent )\n" );
  2872. if( pNetUtil->RequestPing( szIP, 1000, &iUnused ) != S_OK )
  2873. {
  2874. // debugprint( "RequestPing() ( opponent ) failed\n" );
  2875. DisconnectPingResult_Opponent[ iDisconnectPingCurrent ] = PING_BAD;
  2876. }
  2877. else
  2878. DisconnectPingResult_Opponent[ iDisconnectPingCurrent ] = PING_WAITING;
  2879. break;
  2880. case PING_WAITING:
  2881. // Ping results still pending. (Callback will set vars when results arrive.)
  2882. break;
  2883. default:
  2884. // Ping result for server is in.
  2885. if( DisconnectPingResult_Opponent[ iDisconnectPingCurrent ] == PING_WAITING )
  2886. break;
  2887. // Both results are in. Begin new ping, or end disconnect pinging.
  2888. iDisconnectPingCurrent++;
  2889. if( iDisconnectPingCurrent == DISCONNECT_PING_COUNT )
  2890. {
  2891. bDisconnectPingingCompleted = true;
  2892. bDoingDisconnectPinging = false;
  2893. return true;
  2894. }
  2895. break;
  2896. }
  2897. return false;
  2898. }
  2899. //***********************************************************************************************
  2900. void WolapiObject::DisconnectPingResultsString( char* szStringToSet )
  2901. {
  2902. int iGoodServerPings = 0;
  2903. int iGoodPlayerPings = 0;
  2904. for( int i = 0; i < DISCONNECT_PING_COUNT; ++i )
  2905. {
  2906. if( DisconnectPingResult_Server[ i ] == PING_GOOD ) ++iGoodServerPings;
  2907. if( DisconnectPingResult_Opponent[ i ] == PING_GOOD ) ++iGoodPlayerPings;
  2908. }
  2909. sprintf( szStringToSet, "%1u/%1u %1u/%1u", iGoodServerPings, DISCONNECT_PING_COUNT, iGoodPlayerPings, DISCONNECT_PING_COUNT );
  2910. }
  2911. //***********************************************************************************************
  2912. void WolapiObject::SetOptionDefaults()
  2913. {
  2914. // Get stored defaults for options.
  2915. HKEY hKey;
  2916. if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, Game_Registry_Key(), 0, KEY_READ, &hKey ) == ERROR_SUCCESS )
  2917. {
  2918. DWORD dwValue;
  2919. DWORD dwBufSize = sizeof( DWORD );
  2920. if( RegQueryValueEx( hKey, "WOLAPI Find Enabled", 0, NULL, (LPBYTE)&dwValue, &dwBufSize ) != ERROR_SUCCESS )
  2921. bFindEnabled = true;
  2922. else
  2923. bFindEnabled = (bool)dwValue;
  2924. if( RegQueryValueEx( hKey, "WOLAPI Page Enabled", 0, NULL, (LPBYTE)&dwValue, &dwBufSize ) != ERROR_SUCCESS )
  2925. bPageEnabled = true;
  2926. else
  2927. bPageEnabled = (bool)dwValue;
  2928. if( RegQueryValueEx( hKey, "WOLAPI Lang Filter", 0, NULL, (LPBYTE)&dwValue, &dwBufSize ) != ERROR_SUCCESS )
  2929. bLangFilter = true;
  2930. else
  2931. bLangFilter = (bool)dwValue;
  2932. if( RegQueryValueEx( hKey, "WOLAPI Show All Games", 0, NULL, (LPBYTE)&dwValue, &dwBufSize ) != ERROR_SUCCESS )
  2933. bAllGamesShown = true;
  2934. else
  2935. bAllGamesShown = (bool)dwValue;
  2936. RegCloseKey( hKey );
  2937. }
  2938. pChat->SetFindPage( bFindEnabled, bPageEnabled );
  2939. pChat->SetLangFilter( bLangFilter );
  2940. }
  2941. //***********************************************************************************************
  2942. void WolapiObject::SetOptions( bool bEnableFind, bool bEnablePage, bool bLangFilterOn, bool bShowAllGames )
  2943. {
  2944. // Set options and remember them in registry.
  2945. bFindEnabled = bEnableFind;
  2946. bPageEnabled = bEnablePage;
  2947. bLangFilter = bLangFilterOn;
  2948. bAllGamesShown = bShowAllGames;
  2949. HKEY hKey;
  2950. if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, Game_Registry_Key(), 0, KEY_WRITE, &hKey ) == ERROR_SUCCESS )
  2951. {
  2952. DWORD dwValue = bFindEnabled ? 1 : 0;
  2953. RegSetValueEx( hKey, "WOLAPI Find Enabled", 0, REG_DWORD, (LPBYTE)&dwValue, sizeof( dwValue ) );
  2954. dwValue = bPageEnabled ? 1 : 0;
  2955. RegSetValueEx( hKey, "WOLAPI Page Enabled", 0, REG_DWORD, (LPBYTE)&dwValue, sizeof( dwValue ) );
  2956. dwValue = bLangFilter ? 1 : 0;
  2957. RegSetValueEx( hKey, "WOLAPI Lang Filter", 0, REG_DWORD, (LPBYTE)&dwValue, sizeof( dwValue ) );
  2958. dwValue = bAllGamesShown ? 1 : 0;
  2959. RegSetValueEx( hKey, "WOLAPI Show All Games", 0, REG_DWORD, (LPBYTE)&dwValue, sizeof( dwValue ) );
  2960. RegCloseKey( hKey );
  2961. }
  2962. pChat->SetFindPage( bFindEnabled, bPageEnabled );
  2963. pChat->SetLangFilter( bLangFilter );
  2964. }
  2965. //***********************************************************************************************
  2966. HPALETTE GetCurrentScreenPalette()
  2967. {
  2968. // Get the palette of the current screen.
  2969. // Returns 0 if can't get palette.
  2970. // Remember to DeleteObject the HPALETTE if non-zero.
  2971. GraphicViewPortClass draw_window( LogicPage->Get_Graphic_Buffer(),
  2972. WindowList[WINDOW_MAIN][WINDOWX] + LogicPage->Get_XPos(),
  2973. WindowList[WINDOW_MAIN][WINDOWY] + LogicPage->Get_YPos(),
  2974. WindowList[WINDOW_MAIN][WINDOWWIDTH],
  2975. WindowList[WINDOW_MAIN][WINDOWHEIGHT] );
  2976. LPDIRECTDRAWSURFACE lpDDS = draw_window.Get_Graphic_Buffer()->Get_DD_Surface();
  2977. LPDIRECTDRAWPALETTE lpDDP;
  2978. HPALETTE hPal = 0;
  2979. if( lpDDS->GetPalette( &lpDDP ) == DD_OK )
  2980. {
  2981. PALETTEENTRY pe[256];
  2982. if( lpDDP->GetEntries( 0, 0, 256, pe ) == DD_OK )
  2983. {
  2984. LOGPALETTE* pLogPal = (LOGPALETTE*)new char[ sizeof( LOGPALETTE ) + sizeof( PALETTEENTRY ) * 255 ];
  2985. pLogPal->palVersion = 0x300;
  2986. pLogPal->palNumEntries = 256;
  2987. for( int i = 0; i != 256; i++ )
  2988. {
  2989. pLogPal->palPalEntry[i].peRed = pe[i].peRed;
  2990. pLogPal->palPalEntry[i].peGreen = pe[i].peGreen;
  2991. pLogPal->palPalEntry[i].peBlue = pe[i].peBlue;
  2992. pLogPal->palPalEntry[i].peFlags = 0;
  2993. // debugprint( "DD Palette %03u: %03u, %03u, %03u\n", i, pe[i].peRed, pe[i].peGreen, pe[i].peBlue );
  2994. }
  2995. hPal = CreatePalette( pLogPal );
  2996. delete [] pLogPal;
  2997. }
  2998. // else
  2999. // debugprint( "DD GetEntries failed.\n" );
  3000. }
  3001. // else
  3002. // debugprint( "DD GetPalette failed.\n" );
  3003. return hPal;
  3004. }
  3005. //***********************************************************************************************
  3006. void RemapDIBToPalette( HPALETTE hPal, const char* pDIB ) // Note: pDIB is treated as non-const.
  3007. {
  3008. // Converts pDIB's actual pixel data to proper values for a different palette (hPal).
  3009. // Obeys convention that index 0 in the DIB's palette should map to transparent. For our purposes, make it black.
  3010. // Set the values of the qNewPalette array to hold the new destination palette index we want
  3011. // a bmp palette entry to map to.
  3012. unsigned char qNewPalette[ 256 ];
  3013. LPBITMAPINFOHEADER lpbi = (LPBITMAPINFOHEADER)pDIB;
  3014. RGBQUAD* pRGBEntry = (RGBQUAD*)( (char*)lpbi + lpbi->biSize ); // This now points to the first entry in the bmp's palette table.
  3015. // debugprint( "Starting rgbquads at %i\n", pRGBEntry );
  3016. // Index zero is supposed to be transparent. In our case, that means make it black.
  3017. qNewPalette[0] = GetNearestPaletteIndex( hPal, RGB( 0, 0, 0 ) );
  3018. pRGBEntry++;
  3019. for( int i = 1; i != 256; i++ )
  3020. {
  3021. qNewPalette[i] = GetNearestPaletteIndex( hPal, RGB( pRGBEntry->rgbRed, pRGBEntry->rgbGreen, pRGBEntry->rgbBlue ) );
  3022. // if( iIndex == 1 )
  3023. // debugprint( "Remapping bmp %03u to new %03u\n", i, qNewPalette[i] );
  3024. pRGBEntry++;
  3025. }
  3026. // Convert the data to values that match game palette.
  3027. int iWidth = DIBWidth( pDIB );
  3028. int iHeight = DIBHeight( pDIB );
  3029. int iSrcPitch = ( iWidth + 3 ) & ~3;
  3030. int iLength = iSrcPitch * iHeight;
  3031. unsigned char* pBits = (unsigned char*)FindDIBBits( pDIB );
  3032. // debugprint( "First Byte value %03u will become %03u\n", *pBits, qNewPalette[ *pBits ] );
  3033. for( i = 0; i != iLength; i++ )
  3034. {
  3035. *pBits++ = qNewPalette[ *pBits ];
  3036. }
  3037. }
  3038. /*
  3039. //***********************************************************************************************
  3040. char* LoadFileIntoMemory( const char* szFileName, int& iLength )
  3041. {
  3042. // Loads a file into a buffer.
  3043. // Delete[] the pointer when you're done with the buffer.
  3044. HANDLE hFile;
  3045. hFile = CreateFile( szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
  3046. if( hFile == INVALID_HANDLE_VALUE )
  3047. return NULL;
  3048. iLength = GetFileSize( hFile, NULL );
  3049. char* pData = new char[ iLength ];
  3050. DWORD dwBytesRead;
  3051. ReadFile( hFile, pData, iLength, &dwBytesRead, NULL );
  3052. if( dwBytesRead != iLength )
  3053. // debugprint( "######LoadFileIntoMemory expected %i bytes and got %i\n", iLength, dwBytesRead );
  3054. CloseHandle( hFile );
  3055. return pData;
  3056. }
  3057. */
  3058. //***********************************************************************************************
  3059. void HostNameFromGameChannelName( char* szNameToSet, const char* szChannelName )
  3060. {
  3061. int iApostrophe = strcspn( szChannelName, "'" );
  3062. memcpy( szNameToSet, szChannelName, iApostrophe );
  3063. szNameToSet[ iApostrophe ] = 0;
  3064. }
  3065. #endif