WOLAPIOB.CPP 114 KB

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