WOL_CHAT.CPP 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581
  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. // wol_chat.cpp
  20. // ajw 7/8/98
  21. #include "function.h"
  22. #include "iconlist.h"
  23. #include "WolapiOb.h"
  24. #include "SEditDlg.h"
  25. #include "WolStrng.h"
  26. #include "ToolTip.h"
  27. //#include "WolDebug.h"
  28. void WOL_PrintMessage( IconListClass& ILTarget, const char* szText, PlayerColorType iColorRemap = PCOLOR_NONE );
  29. void WOL_PrintMessage( IconListClass& ILTarget, const char* szText, RemapControlType* pColorRemap );
  30. bool EnterChannel( WolapiObject* pWO, IconListClass& chatlist, Channel* pChannel, char* szChannelName, bool bGame );
  31. bool EnterChannel( WolapiObject* pWO, IconListClass& chatlist, IconListClass& chanlist, int iIndex, bool bGame );
  32. bool ExitChatChannel( WolapiObject* pWO );
  33. void CreateChatChannel( WolapiObject* pWO );
  34. bool CreateGameChannel( WolapiObject* pWO, const CREATEGAMEINFO& cgi );
  35. bool ProcessChannelListSelection( WolapiObject* pWO, IconListClass& chatlist, IconListClass& chanlist, int iIndex );
  36. enum LIST_EXPAND_STATE
  37. {
  38. LES_NORMAL,
  39. LES_CHANNELS_EXPANDED,
  40. LES_USERS_EXPANDED,
  41. };
  42. static LIST_EXPAND_STATE lesCurrent = LES_NORMAL;
  43. bool OnExpandChannelList( IconListClass& chanlist, IconListClass& userlist );
  44. bool OnExpandUserList( IconListClass& chanlist, IconListClass& userlist );
  45. void ResizeChannelList( IconListClass& chanlist, bool bExpand );
  46. void ResizeUserList( IconListClass& userlist, bool bExpand );
  47. bool bLinkInList( const LinkClass* pListHead, const LinkClass* pLinkToFind );
  48. extern CREATEGAMEINFO WOL_CreateGame_Dialog( WolapiObject* pWO );
  49. static int d_chanlist_w;
  50. static int d_chanlist_h;
  51. static int d_chanlist_x;
  52. static int d_chanlist_y;
  53. static int d_userlist_w;
  54. static int d_userlist_h;
  55. static int d_userlist_x;
  56. static int d_userlist_y;
  57. #define DRAWTOGDOWN Turn_Off()
  58. #define DRAWTOGUP Turn_On()
  59. //***********************************************************************************************
  60. int WOL_Chat_Dialog( WolapiObject* pWO )
  61. {
  62. int rc;
  63. bool bFirsttime = true;
  64. bool bHackFocus = true;
  65. //------------------------------------------------------------------------
  66. // Dialog & button dimensions
  67. //------------------------------------------------------------------------
  68. int d_dialog_w = 320 *RESFACTOR; // dialog width
  69. int d_dialog_h = 200 *RESFACTOR; // dialog height
  70. int d_dialog_x = ((320*RESFACTOR - d_dialog_w) / 2); // dialog x-coord
  71. int d_dialog_y = ((200*RESFACTOR - d_dialog_h) / 2); // centered y-coord
  72. int d_dialog_cx = d_dialog_x + (d_dialog_w / 2); // center x-coord
  73. int d_text_h = 12;
  74. int d_margin1 = 34; // large margin
  75. int d_margin2 = 14; // small margin
  76. int d_chatlist_w = 340;
  77. int d_chatlist_x = d_dialog_x + d_margin1;
  78. int d_chatlist_y = d_dialog_y + d_margin2 + d_margin1 + 27;
  79. int d_chatlist_h = 337 - d_chatlist_y;
  80. d_chanlist_w = 227;
  81. d_chanlist_h = 50 * RESFACTOR;
  82. d_chanlist_x = d_dialog_x + d_dialog_w - (d_margin1 + d_chanlist_w);
  83. d_chanlist_y = d_chatlist_y;
  84. d_userlist_w = d_chanlist_w;
  85. // int d_userlist_h = ((10 * 6) + 3) *RESFACTOR;
  86. d_userlist_x = d_chanlist_x;
  87. d_userlist_y = d_chanlist_y + d_chanlist_h + 14 + 5;
  88. d_userlist_h = d_chatlist_y + d_chatlist_h - d_userlist_y;
  89. int d_action_w = 100;
  90. int d_action_h = 9 *RESFACTOR;
  91. int d_action_x = d_dialog_x + 500;
  92. int d_action_y = 365;
  93. // int d_chanpriv_w = 60;
  94. // int d_chanpriv_h = 9 *RESFACTOR;
  95. // int d_chanpriv_x = d_dialog_x + 150;
  96. // int d_chanpriv_y = d_action_y;
  97. // int d_cgame_w = 60;
  98. // int d_cgame_h = 9 *RESFACTOR;
  99. // int d_cgame_x = d_dialog_x + 390; //d_dialog_cx - d_cgame_w / 2;
  100. // int d_cgame_y = d_action_y;
  101. int d_back_w = 100;
  102. int d_back_h = 9 *RESFACTOR;
  103. int d_back_x = d_dialog_x + 100;
  104. int d_back_y = d_action_y;
  105. int d_join_w = 100;
  106. int d_join_h = 9 *RESFACTOR;
  107. int d_join_x = d_dialog_x + 210;
  108. int d_join_y = d_action_y;
  109. int d_create_w = 100;
  110. int d_create_h = 9 *RESFACTOR;
  111. int d_create_x = d_dialog_x + 320; //((d_dialog_w * 5) / 6) - (d_create_w / 2);
  112. int d_create_y = d_action_y;
  113. int d_send_w = d_chanlist_x + d_chanlist_w - d_chatlist_x;
  114. int d_send_h = 9 *RESFACTOR;
  115. int d_send_x = d_chatlist_x;
  116. int d_send_y = d_chatlist_y + d_chatlist_h + 5;
  117. //------------------------------------------------------------------------
  118. // Button Enumerations
  119. //------------------------------------------------------------------------
  120. enum
  121. {
  122. BUTTON_DISCONNECT = 100, // Note: standard WOL button IDs must match values in WolapiObject::PrepareButtonsAndIcons().
  123. BUTTON_LEAVE,
  124. BUTTON_REFRESH,
  125. BUTTON_SQUELCH,
  126. BUTTON_BAN,
  127. BUTTON_KICK,
  128. BUTTON_FINDPAGE,
  129. BUTTON_OPTIONS,
  130. BUTTON_LADDER,
  131. BUTTON_HELP,
  132. BUTTON_CHATLIST,
  133. BUTTON_CHANLIST,
  134. BUTTON_USERLIST,
  135. BUTTON_SENDEDIT,
  136. BUTTON_ACTION,
  137. // BUTTON_CGAME,
  138. BUTTON_CREATE,
  139. BUTTON_JOIN,
  140. BUTTON_BACK,
  141. BUTTON_EXPANDCHANNELS,
  142. BUTTON_EXPANDUSERS,
  143. BUTTON_RANKRA,
  144. BUTTON_RANKAM
  145. };
  146. //------------------------------------------------------------------------
  147. // Redraw values: in order from "top" to "bottom" layer of the dialog
  148. //------------------------------------------------------------------------
  149. typedef enum {
  150. REDRAW_NONE = 0,
  151. REDRAW_BACKGROUND,
  152. REDRAW_ALL = REDRAW_BACKGROUND
  153. } RedrawType;
  154. //------------------------------------------------------------------------
  155. // Dialog variables
  156. //------------------------------------------------------------------------
  157. RedrawType display = REDRAW_ALL; // redraw level
  158. bool process = true; // process while true
  159. KeyNumType input;
  160. TTimerClass<SystemTimerClass> lastclick_timer;
  161. int lastclick_idx = 0; // index of item last clicked on
  162. RemapControlType * scheme = GadgetClass::Get_Color_Scheme();
  163. //------------------------------------------------------------------------
  164. // Buttons
  165. //------------------------------------------------------------------------
  166. GadgetClass *commands; // button list
  167. char* pShpExpand = (char*)MFCD::Retrieve( "exp.shp" );
  168. char* pShpUnexpand = (char*)MFCD::Retrieve( "unexp.shp" );
  169. IconListClass chatlist( BUTTON_CHATLIST, d_chatlist_x, d_chatlist_y, d_chatlist_w, d_chatlist_h, TPF_TYPE, MFCD::Retrieve("BTN-UP.SHP"), MFCD::Retrieve("BTN-DN.SHP"), true, 0, 500 );
  170. ShapeButtonClass ExpandChanBtn( BUTTON_EXPANDCHANNELS, pShpExpand, d_chanlist_x + d_chanlist_w - 17, d_chanlist_y - 14 );
  171. IconListClass chanlist( BUTTON_CHANLIST, d_chanlist_x, d_chanlist_y, d_chanlist_w, d_chanlist_h, TPF_TYPE, MFCD::Retrieve("BTN-UP.SHP"), MFCD::Retrieve("BTN-DN.SHP"), true, 1 );
  172. ShapeButtonClass ExpandUserBtn( BUTTON_EXPANDUSERS, pShpExpand, d_userlist_x + d_userlist_w - 17, d_userlist_y - 14 );
  173. IconListClass userlist( BUTTON_USERLIST, d_userlist_x, d_userlist_y, d_userlist_w, d_userlist_h, TPF_TYPE, MFCD::Retrieve("BTN-UP.SHP"), MFCD::Retrieve("BTN-DN.SHP"), true, 2 );
  174. TextButtonClass ActionBtn( BUTTON_ACTION, TXT_WOL_ACTION, TPF_BUTTON, d_action_x, d_action_y, d_action_w );
  175. TextButtonClass CreateBtn( BUTTON_CREATE, TXT_WOL_NEWSOMETHING, TPF_BUTTON, d_create_x, d_create_y, d_create_w );
  176. TextButtonClass JoinBtn( BUTTON_JOIN, TXT_WOL_JOIN, TPF_BUTTON, d_join_x, d_join_y, d_join_w );
  177. TextButtonClass BackBtn( BUTTON_BACK, TXT_WOL_BACK, TPF_BUTTON, d_back_x, d_back_y, d_back_w );
  178. char* szRecordToStartWith;
  179. if( pWO->bShowRankRA )
  180. szRecordToStartWith = pWO->szMyRecord;
  181. else
  182. szRecordToStartWith = pWO->szMyRecordAM;
  183. StaticButtonClass chatlistTitle( 0, szRecordToStartWith, TPF_TYPE, d_chatlist_x + 2, d_chatlist_y - 13, d_chatlist_w - 4, 12 );
  184. StaticButtonClass chanlistTitle( 0, "", TPF_TYPE, d_chanlist_x + 2, d_chanlist_y - 16 + 4, d_chanlist_w - 4 - 16, 12 );
  185. StaticButtonClass userlistTitle( 0, TXT_WOL_NOUSERLIST, TPF_TYPE, d_userlist_x + 2, d_userlist_y - 16 + 4, d_userlist_w - 4 - 16 * 4, 12 );
  186. char szSendBuffer[MAXCHATSENDLENGTH] = "";
  187. EditClass sendedit( BUTTON_SENDEDIT, szSendBuffer, MAXCHATSENDLENGTH, TPF_TEXT, d_send_x, d_send_y, d_send_w, d_send_h );
  188. char* pShpRankRA = (char*)MFCD::Retrieve( "rank_ra.shp" );
  189. char* pShpRankAM = (char*)MFCD::Retrieve( "rank_am.shp" );
  190. ShapeButtonClass RankRABtn( BUTTON_RANKRA, pShpRankRA, d_userlist_x + d_userlist_w - ( 16 * 4 + 1 ), d_userlist_y - 14 );
  191. ShapeButtonClass RankAMBtn( BUTTON_RANKAM, pShpRankAM, d_userlist_x + d_userlist_w - ( 16 * 3 + 1 ), d_userlist_y - 14 );
  192. // Change draw behavior of toggle buttons.
  193. RankRABtn.ReflectButtonState = true;
  194. RankAMBtn.ReflectButtonState = true;
  195. // Build the button list.
  196. commands = pWO->pShpBtnDiscon;
  197. pWO->pShpBtnLeave->Add_Tail(*commands);
  198. pWO->pShpBtnRefresh->Add_Tail(*commands);
  199. pWO->pShpBtnSquelch->Add_Tail(*commands);
  200. pWO->pShpBtnBan->Add_Tail(*commands);
  201. pWO->pShpBtnKick->Add_Tail(*commands);
  202. pWO->pShpBtnFindpage->Add_Tail(*commands);
  203. pWO->pShpBtnOptions->Add_Tail(*commands);
  204. pWO->pShpBtnLadder->Add_Tail(*commands);
  205. pWO->pShpBtnHelp->Add_Tail(*commands);
  206. chatlist.Add_Tail(*commands);
  207. ExpandChanBtn.Add_Tail(*commands);
  208. chanlist.Add_Tail(*commands);
  209. ExpandUserBtn.Add_Tail(*commands);
  210. userlist.Add_Tail(*commands);
  211. ActionBtn.Add_Tail(*commands);
  212. CreateBtn.Add_Tail(*commands);
  213. // CreatePrivBtn.Add_Tail(*commands);
  214. JoinBtn.Add_Tail(*commands);
  215. BackBtn.Add_Tail(*commands);
  216. // CGameBtn.Add_Tail(*commands);
  217. chatlistTitle.Add_Tail(*commands);
  218. chanlistTitle.Add_Tail(*commands);
  219. userlistTitle.Add_Tail(*commands);
  220. sendedit.Add_Tail(*commands);
  221. // Tooltips...
  222. DWORD timeToolTipAppear;
  223. ToolTipClass* pToolTipHead = NULL; // Head of list of ToolTips that parallels gadget list.
  224. ToolTipClass* pToolTipHitLast = NULL; // ToolTip the mouse was last over, or null.
  225. ToolTipClass* pToolTip = pToolTipHead = pWO->pTTipDiscon;
  226. pToolTip->next = pWO->pTTipLeave;
  227. pToolTip = pToolTip->next;
  228. pToolTip->next = pWO->pTTipRefresh;
  229. pToolTip = pToolTip->next;
  230. pToolTip->next = pWO->pTTipSquelch;
  231. pToolTip = pToolTip->next;
  232. pToolTip->next = pWO->pTTipBan;
  233. pToolTip = pToolTip->next;
  234. pToolTip->next = pWO->pTTipKick;
  235. pToolTip = pToolTip->next;
  236. pToolTip->next = pWO->pTTipFindpage;
  237. pToolTip = pToolTip->next;
  238. pToolTip->next = pWO->pTTipOptions;
  239. pToolTip = pToolTip->next;
  240. pToolTip->next = pWO->pTTipLadder;
  241. pToolTip = pToolTip->next;
  242. pToolTip->next = pWO->pTTipHelp;
  243. pToolTip = pToolTip->next;
  244. ToolTipClass TTipChanExpand( &ExpandChanBtn, TXT_WOL_TTIP_EXPANDLIST, ExpandChanBtn.X + 8, ExpandChanBtn.Y - 9, true );
  245. pToolTip->next = &TTipChanExpand;
  246. pToolTip = pToolTip->next;
  247. ToolTipClass TTipUserExpand( &ExpandUserBtn, TXT_WOL_TTIP_EXPANDLIST, ExpandUserBtn.X + 8, ExpandUserBtn.Y - 9, true );
  248. pToolTip->next = &TTipUserExpand;
  249. pToolTip = pToolTip->next;
  250. ToolTipClass TTipChanList( &chanlist, 0, chanlist.X + 1, chanlist.Y + 1, true, true );
  251. pToolTip->next = &TTipChanList;
  252. pToolTip = pToolTip->next;
  253. ToolTipClass TTipJoin( &JoinBtn, TXT_WOL_TTIP_JOIN, d_join_x + d_join_w/2, d_join_y - 6 );
  254. pToolTip->next = &TTipJoin;
  255. pToolTip = pToolTip->next;
  256. ToolTipClass TTipBack( &BackBtn, TXT_WOL_TTIP_BACK, d_back_x + d_back_w/2, d_back_y - 6 );
  257. pToolTip->next = &TTipBack;
  258. pToolTip = pToolTip->next;
  259. ToolTipClass TTipCreate( &CreateBtn, TXT_WOL_TTIP_CREATE, d_create_x + d_create_w/2, d_create_y - 6 );
  260. pToolTip->next = &TTipCreate;
  261. pToolTip = pToolTip->next;
  262. ToolTipClass TTipAction( &ActionBtn, TXT_WOL_TTIP_ACTION, d_action_x + d_action_w/2, d_action_y - 6, true );
  263. pToolTip->next = &TTipAction;
  264. pToolTip = pToolTip->next;
  265. ToolTipClass TTipRankRA( &RankRABtn, TXT_WOL_TTIP_RANKRA, RankRABtn.X + 8, RankRABtn.Y - 9, true );
  266. pToolTip->next = &TTipRankRA;
  267. pToolTip = pToolTip->next;
  268. ToolTipClass TTipRankAM( &RankAMBtn, TXT_WOL_TTIP_RANKAM, RankAMBtn.X + 8, RankAMBtn.Y - 9, true );
  269. pToolTip->next = &TTipRankAM;
  270. pToolTip = pToolTip->next;
  271. pToolTip->next = NULL;
  272. //........................................................................
  273. // List boxes
  274. //........................................................................
  275. int tabs[] = { 150 }; // tabs for channel list
  276. chanlist.Set_Tabs( tabs );
  277. // Fancy_Text_Print("", 0, 0, scheme, TBLACK, TPF_TEXT);
  278. lastclick_timer = 0;
  279. // Tell WolapiObject about lists to use for output.
  280. // (Sure wish I'd gone against the grain and made this dialog a class...)
  281. pWO->LinkToChatDlg( &chatlist, &chanlist, &userlist, &userlistTitle );
  282. if( !pWO->bChatShownBefore )
  283. {
  284. // Print message of the day.
  285. chatlist.Add_Item( pWO->pChatSink->szMotd, NULL, NULL, ICON_SHAPE );
  286. }
  287. else
  288. {
  289. // We have returned to the chat dialog after being in either game setup or an actual game.
  290. pWO->RestoreChat();
  291. pWO->DeleteSavedChat();
  292. if( pWO->bReturningAfterGame )
  293. pWO->RejoinLobbyAfterGame();
  294. else
  295. {
  296. if( pWO->pChatSink->bGotKickedTrigger )
  297. {
  298. // We got kicked out of a game setup.
  299. WOL_PrintMessage( chatlist, TXT_WOL_YOUWEREKICKEDFROMGAME, WOLCOLORREMAP_KICKORBAN );
  300. pWO->pChatSink->bGotKickedTrigger = false;
  301. }
  302. }
  303. if( pWO->iLobbyReturnAfterGame != -1 )
  304. {
  305. char szChannelToJoin[ WOL_CHANNAME_LEN_MAX ];
  306. //sprintf( szChannelToJoin, "Lob_%i_%i", GAME_TYPE, pWO->iLobbyReturnAfterGame );
  307. sprintf( szChannelToJoin, "%s%i", LOB_PREFIX, pWO->iLobbyReturnAfterGame );
  308. pWO->OnEnteringChatChannel( szChannelToJoin, false, iChannelLobbyNumber( (unsigned char*)szChannelToJoin ) );
  309. }
  310. else
  311. // Will never happen presumably, if games are always entered via a lobby chat channel.
  312. pWO->EnterLevel_Top();
  313. pWO->iLobbyReturnAfterGame = -1;
  314. if( pWO->bReturningAfterGame )
  315. {
  316. Sound_Effect( WOLSOUND_LOGIN );
  317. pWO->bReturningAfterGame = false;
  318. }
  319. else
  320. Sound_Effect( WOLSOUND_EXITGAME );
  321. }
  322. // Cause a refresh of szMyRecord, the string showing my win/loss record.
  323. pWO->RequestLadders( pWO->szMyName );
  324. //------------------------------------------------------------------------
  325. // Init Mono Output
  326. //------------------------------------------------------------------------
  327. #if(SHOW_MONO)
  328. Ipx.Configure_Debug(-1, sizeof (GlobalHeaderType), sizeof(NetCommandType), GlobalPacketNames, 0, 13);
  329. Ipx.Mono_Debug_Print(-1,1);
  330. #endif
  331. //------------------------------------------------------------------------
  332. // Processing loop
  333. //------------------------------------------------------------------------
  334. while (process)
  335. {
  336. #if(SHOW_MONO)
  337. Ipx.Mono_Debug_Print(-1,0);
  338. #endif
  339. // Regularly check for incoming messages from wolapi.
  340. if( ::timeGetTime() > pWO->dwTimeNextWolapiPump )
  341. {
  342. /*
  343. if( pToolTipHitLast && pToolTipHitLast->bShowing ) // Lame hack. Problem is draws that occur in callbacks.
  344. {
  345. pToolTipHitLast->Unshow();
  346. pWO->pChat->PumpMessages();
  347. pWO->pNetUtil->PumpMessages();
  348. pToolTipHitLast->Show();
  349. }
  350. else
  351. {
  352. pWO->pChat->PumpMessages();
  353. pWO->pNetUtil->PumpMessages();
  354. }
  355. */
  356. pWO->pChat->PumpMessages();
  357. pWO->pNetUtil->PumpMessages();
  358. // Special post-callback processing...
  359. if( pWO->bSelfDestruct )
  360. {
  361. if( pWO->pChatSink->bConnected )
  362. pWO->Logout();
  363. rc = -1; // As if the user logged himself out.
  364. process = false;
  365. break;
  366. }
  367. if( pWO->pChatSink->bGotKickedTrigger )
  368. {
  369. if( pWO->CurrentLevel == WOL_LEVEL_INCHATCHANNEL )
  370. {
  371. pWO->OnExitingChatChannel();
  372. pWO->EnterLevel_UserChat();
  373. }
  374. else if( pWO->CurrentLevel == WOL_LEVEL_INLOBBY )
  375. {
  376. pWO->OnExitingChatChannel();
  377. pWO->EnterLevel_Lobbies();
  378. }
  379. else // Must be WOL_LEVEL_INOFFICIALCHATCHANNEL.
  380. {
  381. pWO->OnExitingChatChannel();
  382. pWO->EnterLevel_OfficialChat();
  383. }
  384. pWO->pChatSink->bGotKickedTrigger = false;
  385. display = REDRAW_ALL;
  386. }
  387. if( pWO->bMyRecordUpdated )
  388. {
  389. if( pWO->bShowRankRA )
  390. chatlistTitle.Set_Text( pWO->szMyRecord );
  391. else
  392. chatlistTitle.Set_Text( pWO->szMyRecordAM );
  393. pWO->bMyRecordUpdated = false;
  394. }
  395. if( pWO->bChannelListTitleUpdated )
  396. {
  397. chanlistTitle.Set_Text( pWO->szChannelListTitle );
  398. pWO->bChannelListTitleUpdated = false;
  399. }
  400. pWO->dwTimeNextWolapiPump = ::timeGetTime() + WOLAPIPUMPWAIT;
  401. }
  402. // Synch rank toggle buttons state.
  403. if( BackBtn.Get_Prev() == &RankAMBtn )
  404. {
  405. if( pWO->CurrentLevel != WOL_LEVEL_INLOBBY )
  406. {
  407. // Rank buttons are there and shouldn't be.
  408. RankRABtn.Remove();
  409. RankAMBtn.Remove();
  410. display = REDRAW_ALL;
  411. }
  412. else
  413. {
  414. if( pWO->bShowRankUpdated )
  415. {
  416. if( pWO->bShowRankRA )
  417. {
  418. RankRABtn.DRAWTOGDOWN;
  419. RankAMBtn.DRAWTOGUP;
  420. }
  421. else
  422. {
  423. RankRABtn.DRAWTOGUP;
  424. RankAMBtn.DRAWTOGDOWN;
  425. }
  426. // Buttons have been refreshed.
  427. pWO->bShowRankUpdated = false;
  428. // Cause my own record to get refreshed.
  429. pWO->bMyRecordUpdated = true;
  430. // Refresh list to show different rankings type.
  431. pWO->ListChannelUsers();
  432. }
  433. }
  434. }
  435. else
  436. {
  437. if( pWO->CurrentLevel == WOL_LEVEL_INLOBBY )
  438. {
  439. // Rank buttons aren't there and should be.
  440. RankRABtn.Add( JoinBtn );
  441. RankAMBtn.Add( RankRABtn );
  442. RankRABtn.Flag_To_Redraw();
  443. RankAMBtn.Flag_To_Redraw();
  444. if( pWO->bShowRankRA )
  445. {
  446. RankRABtn.DRAWTOGDOWN;
  447. RankAMBtn.DRAWTOGUP;
  448. }
  449. else
  450. {
  451. RankRABtn.DRAWTOGUP;
  452. RankAMBtn.DRAWTOGDOWN;
  453. }
  454. // Buttons have been refreshed.
  455. pWO->bShowRankUpdated = false;
  456. }
  457. }
  458. // Regularly update the channels list in certain cases.
  459. if( ( pWO->CurrentLevel == WOL_LEVEL_OFFICIALCHAT || pWO->CurrentLevel == WOL_LEVEL_USERCHAT ||
  460. pWO->CurrentLevel == WOL_LEVEL_LOBBIES || pWO->CurrentLevel == WOL_LEVEL_INLOBBY ) &&
  461. ::timeGetTime() > pWO->dwTimeNextChannelUpdate )
  462. {
  463. switch( pWO->CurrentLevel )
  464. {
  465. case WOL_LEVEL_OFFICIALCHAT:
  466. pWO->UpdateChannels( 0, CHANNELFILTER_OFFICIAL, false );
  467. break;
  468. case WOL_LEVEL_USERCHAT:
  469. pWO->UpdateChannels( 0, CHANNELFILTER_UNOFFICIAL, false );
  470. break;
  471. case WOL_LEVEL_LOBBIES: // Overkill in this case to update so often...
  472. pWO->UpdateChannels( 0, CHANNELFILTER_LOBBIES, false );
  473. break;
  474. case WOL_LEVEL_INLOBBY:
  475. pWO->UpdateChannels( GAME_TYPE, CHANNELFILTER_LOCALLOBBYGAMES, true );
  476. break;
  477. }
  478. pWO->dwTimeNextChannelUpdate = ::timeGetTime() + CHANNELUPDATEWAIT;
  479. }
  480. #ifdef WIN32
  481. /*
  482. ** If we have just received input focus again after running in the background then
  483. ** we need to redraw.
  484. */
  485. if (AllSurfaces.SurfacesRestored) {
  486. AllSurfaces.SurfacesRestored=FALSE;
  487. display = REDRAW_ALL;
  488. }
  489. #endif
  490. if( bFirsttime && !pWO->bChatShownBefore )
  491. {
  492. WWMessageBox().Process( TXT_WOL_FINDINGLOBBY, TXT_NONE );
  493. char szLobbyName[ WOL_CHANNAME_LEN_MAX ];
  494. if( pWO->GetNameOfBeginningLobby( szLobbyName ) )
  495. {
  496. // debugprint( "Found lobby to go into: '%s'\n", szLobbyName );
  497. if( !EnterChannel( pWO, chatlist, NULL, szLobbyName, false ) )
  498. {
  499. // Could not enter channel for some reason. Go to top instead.
  500. pWO->EnterLevel_Top();
  501. }
  502. }
  503. else
  504. {
  505. // Could not find name of a lobby for some reason. Go to top instead.
  506. pWO->EnterLevel_Top();
  507. }
  508. pWO->bChatShownBefore = true;
  509. display = REDRAW_ALL;
  510. // Play login sound.
  511. Sound_Effect( WOLSOUND_LOGIN );
  512. }
  513. bFirsttime = false;
  514. //.....................................................................
  515. // Refresh display if needed
  516. //.....................................................................
  517. if (display)
  518. {
  519. Hide_Mouse();
  520. //..................................................................
  521. // Redraw backgound & dialog box
  522. //..................................................................
  523. if (display >= REDRAW_BACKGROUND)
  524. {
  525. if( pToolTipHitLast && pToolTipHitLast->bShowing )
  526. {
  527. pToolTipHitLast->Unshow();
  528. }
  529. Dialog_Box(d_dialog_x, d_dialog_y, d_dialog_w, d_dialog_h);
  530. //...............................................................
  531. // Dialog & Field labels
  532. //...............................................................
  533. commands->Draw_All();
  534. // Draw title bar above channel list.
  535. Draw_Box( d_chanlist_x, d_chanlist_y - 15, d_chanlist_w, 16, BOXSTYLE_BOX, false );
  536. switch( lesCurrent )
  537. {
  538. case LES_CHANNELS_EXPANDED:
  539. // Draw users title bar at bottom.
  540. Draw_Box( d_userlist_x, d_userlist_y + d_userlist_h - 16, d_userlist_w, 16, BOXSTYLE_BOX, false );
  541. break;
  542. case LES_USERS_EXPANDED:
  543. // Draw users title bar at top.
  544. Draw_Box( d_chanlist_x, d_chanlist_y, d_chanlist_w, 16, BOXSTYLE_BOX, false );
  545. break;
  546. default:
  547. // Draw users title bar in middle.
  548. Draw_Box( d_userlist_x, d_userlist_y - 15, d_userlist_w, 16, BOXSTYLE_BOX, false );
  549. break;
  550. }
  551. }
  552. Show_Mouse();
  553. display = REDRAW_NONE;
  554. }
  555. // Force mouse visible, as some beta testers report unexplicable disappearing cursors.
  556. while( Get_Mouse_State() )
  557. Show_Mouse();
  558. // Be nice to other apps.
  559. Sleep( 50 );
  560. //.....................................................................
  561. // Get user input
  562. //.....................................................................
  563. if( ( ::GetAsyncKeyState( KN_LMOUSE ) & 0x8000 ) || ( ::GetAsyncKeyState( KN_RMOUSE ) & 0x8000 ) )
  564. {
  565. // Mouse button is down.
  566. timeToolTipAppear = ::timeGetTime() + TOOLTIPDELAY;
  567. if( pToolTipHitLast && pToolTipHitLast->bShowing )
  568. {
  569. pToolTipHitLast->Unshow();
  570. }
  571. }
  572. // If anything currently on the controls list is set to redraw, hide tooltip.
  573. if( pToolTipHitLast && pToolTipHitLast->bShowing && commands->Is_List_To_Redraw() )
  574. {
  575. pToolTipHitLast->Unshow();
  576. }
  577. input = commands->Input();
  578. // This hack, used elsewhere in this form, appears to be the standard dodge around GadgetClass::Input's
  579. // tendency to remove any focus the first time it runs for a 'commands' list.
  580. // ajw - Perhaps I could try doing this every cycle regardless - would avoid stupid non-focused editbox key reactions bug.
  581. if( bHackFocus )
  582. {
  583. sendedit.Set_Focus();
  584. sendedit.Flag_To_Redraw();
  585. input = commands->Input();
  586. bHackFocus = false;
  587. }
  588. // Tooltips...
  589. if( pToolTipHead )
  590. {
  591. ToolTipClass* pToolTipHit = pToolTipHead->GetToolTipHit();
  592. if( pToolTipHit == pToolTipHitLast )
  593. {
  594. if( pToolTipHit && bLinkInList( commands, pToolTipHit->pGadget ) ) // (Gadget must be in controls list.)
  595. {
  596. if( !pToolTipHit->bShowing && ::timeGetTime() > timeToolTipAppear &&
  597. !( ( ::GetAsyncKeyState( KN_LMOUSE ) & 0x8000 ) || ( ::GetAsyncKeyState( KN_RMOUSE ) & 0x8000 ) ) )
  598. {
  599. pToolTipHit->Show();
  600. }
  601. else if( pToolTipHit->bIconList && pToolTipHit->bOverDifferentLine() )
  602. {
  603. pToolTipHit->Unshow();
  604. pToolTipHit->Show();
  605. }
  606. }
  607. }
  608. else
  609. {
  610. if( pToolTipHitLast && pToolTipHitLast->bShowing )
  611. pToolTipHitLast->Unshow();
  612. pToolTipHitLast = pToolTipHit;
  613. timeToolTipAppear = ::timeGetTime() + TOOLTIPDELAY;
  614. }
  615. }
  616. //.....................................................................
  617. // Process input
  618. //.....................................................................
  619. switch (input)
  620. {
  621. case ( BUTTON_SENDEDIT | KN_BUTTON ):
  622. // Enter has been pressed - was caught by sendedit control.
  623. if( pWO->CurrentLevel == WOL_LEVEL_INCHATCHANNEL || pWO->CurrentLevel == WOL_LEVEL_INLOBBY )
  624. {
  625. pWO->SendMessage( sendedit.Get_Text(), userlist, false );
  626. // Clear sendedit, reset focus.
  627. szSendBuffer[0] = 0;
  628. sendedit.Set_Focus();
  629. // Mark for redraw.
  630. sendedit.Flag_To_Redraw();
  631. }
  632. else
  633. {
  634. WOL_PrintMessage( chatlist, TXT_WOL_YOURENOTINCHANNEL, WOLCOLORREMAP_LOCALMACHINEMESS );
  635. Sound_Effect( WOLSOUND_ERROR );
  636. sendedit.Set_Focus();
  637. // Mark for redraw.
  638. sendedit.Flag_To_Redraw();
  639. }
  640. break;
  641. case KN_LMOUSE:
  642. break;
  643. case ( BUTTON_EXPANDCHANNELS | KN_BUTTON ):
  644. if( OnExpandChannelList( chanlist, userlist ) )
  645. {
  646. // Hide userlist.
  647. if( ExpandUserBtn.Get_Next() == &userlist )
  648. userlist.Remove();
  649. // Ensure chanlist is visible.
  650. if( ExpandChanBtn.Get_Next() != &chanlist )
  651. chanlist.Add( ExpandChanBtn );
  652. // Move userlist expand button.
  653. ExpandUserBtn.Set_Position( ExpandUserBtn.X, chanlist.Y + chanlist.Height );
  654. TTipUserExpand.Move( ExpandUserBtn.X + 8, ExpandUserBtn.Y - 16 );
  655. userlistTitle.Set_Position( userlistTitle.X, chanlist.Y + chanlist.Height + 2 );
  656. // Set buttons.
  657. ExpandChanBtn.Set_Shape( pShpUnexpand );
  658. ExpandUserBtn.Set_Shape( pShpExpand );
  659. }
  660. else
  661. {
  662. // Show userlist.
  663. if( ExpandUserBtn.Get_Next() != &userlist )
  664. userlist.Add( ExpandUserBtn );
  665. // Move userlist expand button.
  666. ExpandUserBtn.Set_Position( ExpandUserBtn.X, userlist.Y - 14 );
  667. TTipUserExpand.Move( ExpandUserBtn.X + 8, ExpandUserBtn.Y - 16 );
  668. userlistTitle.Set_Position( userlistTitle.X, userlist.Y - 16 + 4 );
  669. // Set buttons.
  670. ExpandChanBtn.Set_Shape( pShpExpand );
  671. ExpandUserBtn.Set_Shape( pShpExpand );
  672. }
  673. // Move rank buttons.
  674. RankRABtn.Set_Position( RankRABtn.X, ExpandUserBtn.Y );
  675. RankAMBtn.Set_Position( RankAMBtn.X, ExpandUserBtn.Y );
  676. TTipRankRA.Move( RankRABtn.X + 8, RankRABtn.Y - 16 );
  677. TTipRankAM.Move( RankAMBtn.X + 8, RankAMBtn.Y - 16 );
  678. display = REDRAW_ALL;
  679. break;
  680. case ( BUTTON_EXPANDUSERS | KN_BUTTON ):
  681. if( OnExpandUserList( chanlist, userlist ) )
  682. {
  683. // Hide chanlist controls.
  684. if( ExpandChanBtn.Get_Next() == &chanlist )
  685. chanlist.Remove();
  686. // Ensure userlist is visible.
  687. if( ExpandUserBtn.Get_Next() != &userlist )
  688. userlist.Add( ExpandUserBtn );
  689. // Set buttons.
  690. ExpandChanBtn.Set_Shape( pShpExpand );
  691. ExpandUserBtn.Set_Shape( pShpUnexpand );
  692. }
  693. else
  694. {
  695. // Show chanlist.
  696. if( ExpandChanBtn.Get_Next() != &chanlist )
  697. chanlist.Add( ExpandChanBtn );
  698. // Set buttons.
  699. ExpandChanBtn.Set_Shape( pShpExpand );
  700. ExpandUserBtn.Set_Shape( pShpExpand );
  701. }
  702. // Move userlist expand button.
  703. ExpandUserBtn.Set_Position( ExpandUserBtn.X, userlist.Y - 14 );
  704. TTipUserExpand.Move( ExpandUserBtn.X + 8, ExpandUserBtn.Y - 16 );
  705. userlistTitle.Set_Position( userlistTitle.X, userlist.Y - 16 + 4 );
  706. // Move rank buttons.
  707. RankRABtn.Set_Position( RankRABtn.X, ExpandUserBtn.Y );
  708. RankAMBtn.Set_Position( RankAMBtn.X, ExpandUserBtn.Y );
  709. TTipRankRA.Move( RankRABtn.X + 8, RankRABtn.Y - 16 );
  710. TTipRankAM.Move( RankAMBtn.X + 8, RankAMBtn.Y - 16 );
  711. display = REDRAW_ALL;
  712. break;
  713. case ( BUTTON_CHANLIST | KN_BUTTON ):
  714. // User clicks on the game list.
  715. //...............................................................
  716. // Handle a double-click
  717. //...............................................................
  718. if( lastclick_timer < 30 && chanlist.Current_Index() == lastclick_idx )
  719. {
  720. // Doubleclick on channel list.
  721. if( ProcessChannelListSelection( pWO, chatlist, chanlist, lastclick_idx ) )
  722. {
  723. // Exit the chat dialog, go to game dialog.
  724. rc = 2;
  725. process = false;
  726. }
  727. display = REDRAW_ALL;
  728. bHackFocus = true;
  729. }
  730. else
  731. {
  732. //...............................................................
  733. // Handle a single-click
  734. //...............................................................
  735. //............................................................
  736. // If no double-click occurred, set the last-clicked index
  737. // & double-click timer.
  738. //............................................................
  739. lastclick_timer = 0;
  740. lastclick_idx = chanlist.Current_Index();
  741. }
  742. break;
  743. case ( BUTTON_JOIN | KN_BUTTON ):
  744. // Pressing the join button is exactly like doubleclicking on the selected index in chanlist, except:
  745. // if the first item is selected, ignore, unless we are at the top level
  746. if( pWO->CurrentLevel == WOL_LEVEL_TOP || chanlist.Current_Index() != 0 )
  747. {
  748. if( ProcessChannelListSelection( pWO, chatlist, chanlist, chanlist.Current_Index() ) )
  749. {
  750. // Exit the chat dialog, go to game dialog.
  751. rc = 2;
  752. process = false;
  753. }
  754. display = REDRAW_ALL;
  755. bHackFocus = true;
  756. }
  757. break;
  758. case ( BUTTON_USERLIST | KN_BUTTON ):
  759. // User clicks on user list.
  760. break;
  761. case ( BUTTON_CREATE | KN_BUTTON ):
  762. switch( pWO->CurrentLevel )
  763. {
  764. case WOL_LEVEL_INCHATCHANNEL:
  765. // debugprint( "%s\n", TXT_WOL_CANTCREATEINCHANNEL );
  766. WOL_PrintMessage( chatlist, TXT_WOL_CANTCREATEINCHANNEL, WOLCOLORREMAP_LOCALMACHINEMESS );
  767. Sound_Effect( WOLSOUND_ERROR );
  768. break;
  769. case WOL_LEVEL_INLOBBY:
  770. {
  771. pWO->bPump_In_Call_Back = true;
  772. CREATEGAMEINFO CreateGameInfo = WOL_CreateGame_Dialog( pWO );
  773. pWO->bPump_In_Call_Back = false;
  774. if( CreateGameInfo.bCreateGame )
  775. {
  776. if( CreateGameChannel( pWO, CreateGameInfo ) )
  777. {
  778. rc = 1;
  779. process = false;
  780. }
  781. }
  782. break;
  783. }
  784. case WOL_LEVEL_GAMES:
  785. case WOL_LEVEL_GAMESOFTYPE:
  786. case WOL_LEVEL_LOBBIES:
  787. WOL_PrintMessage( chatlist, TXT_WOL_CANTCREATEHERE, WOLCOLORREMAP_LOCALMACHINEMESS );
  788. Sound_Effect( WOLSOUND_ERROR );
  789. break;
  790. default:
  791. CreateChatChannel( pWO );
  792. }
  793. display = REDRAW_ALL;
  794. bHackFocus = true;
  795. break;
  796. case ( BUTTON_LEAVE | KN_BUTTON ):
  797. // Because of the way things are set up, this is exactly like selecting the first item in chanlist.
  798. // (Button is disabled when this is not appropriate.)
  799. ProcessChannelListSelection( pWO, chatlist, chanlist, 0 );
  800. display = REDRAW_ALL;
  801. break;
  802. case ( BUTTON_REFRESH | KN_BUTTON ):
  803. pWO->dwTimeNextChannelUpdate = ::timeGetTime();
  804. break;
  805. case ( BUTTON_SQUELCH | KN_BUTTON ):
  806. pWO->DoSquelch( &userlist );
  807. break;
  808. case ( BUTTON_BAN | KN_BUTTON ):
  809. pWO->DoKick( &userlist, true );
  810. // display = REDRAW_ALL;
  811. break;
  812. case ( BUTTON_KICK | KN_BUTTON ):
  813. pWO->DoKick( &userlist, false );
  814. // display = REDRAW_ALL;
  815. break;
  816. case ( BUTTON_FINDPAGE | KN_BUTTON ):
  817. pWO->DoFindPage();
  818. display = REDRAW_ALL;
  819. bHackFocus = true;
  820. break;
  821. case ( BUTTON_OPTIONS | KN_BUTTON ):
  822. pWO->DoOptions();
  823. display = REDRAW_ALL;
  824. bHackFocus = true;
  825. break;
  826. case ( KN_ESC ):
  827. // break; ajw Put back in?
  828. case ( BUTTON_BACK | KN_BUTTON ):
  829. // Pressing the back button is exactly like doubleclicking on the top item in chanlist, except
  830. // when we're at the top level.
  831. if( pWO->CurrentLevel != WOL_LEVEL_TOP )
  832. {
  833. ProcessChannelListSelection( pWO, chatlist, chanlist, 0 );
  834. display = REDRAW_ALL;
  835. break;
  836. }
  837. // Note no break; here. Fall through if at top level.
  838. case ( BUTTON_DISCONNECT | KN_BUTTON ):
  839. if( WWMessageBox().Process( TXT_WOL_CONFIRMLOGOUT, TXT_YES, TXT_NO ) == 0 )
  840. {
  841. if( pWO->CurrentLevel == WOL_LEVEL_INCHATCHANNEL || pWO->CurrentLevel == WOL_LEVEL_INLOBBY )
  842. ExitChatChannel( pWO );
  843. pWO->Logout();
  844. rc = -1;
  845. process = false;
  846. }
  847. display = REDRAW_ALL;
  848. bHackFocus = true;
  849. break;
  850. case ( BUTTON_ACTION | KN_BUTTON ):
  851. if( pWO->CurrentLevel == WOL_LEVEL_INCHATCHANNEL || pWO->CurrentLevel == WOL_LEVEL_INLOBBY )
  852. {
  853. pWO->SendMessage( sendedit.Get_Text(), userlist, true );
  854. // Clear sendedit, reset focus.
  855. szSendBuffer[0] = 0;
  856. sendedit.Set_Focus();
  857. // Mark for redraw.
  858. //chatlist.Flag_To_Redraw();
  859. sendedit.Flag_To_Redraw();
  860. }
  861. else
  862. {
  863. WOL_PrintMessage( chatlist, TXT_WOL_YOURENOTINCHANNEL, WOLCOLORREMAP_LOCALMACHINEMESS );
  864. Sound_Effect( WOLSOUND_ERROR );
  865. sendedit.Set_Focus();
  866. // Mark for redraw.
  867. sendedit.Flag_To_Redraw();
  868. }
  869. break;
  870. case ( BUTTON_LADDER | KN_BUTTON ):
  871. pWO->DoLadder();
  872. display = REDRAW_ALL;
  873. bHackFocus = true;
  874. break;
  875. case ( BUTTON_HELP | KN_BUTTON ):
  876. pWO->DoHelp();
  877. display = REDRAW_ALL;
  878. bHackFocus = true;
  879. break;
  880. case ( BUTTON_RANKRA | KN_BUTTON ):
  881. pWO->bShowRankRA = true;
  882. pWO->bShowRankUpdated = true;
  883. break;
  884. case ( BUTTON_RANKAM | KN_BUTTON ):
  885. pWO->bShowRankRA = false;
  886. pWO->bShowRankUpdated = true;
  887. break;
  888. default:
  889. break;
  890. }
  891. //.....................................................................
  892. // Service the sounds & score; GameActive must be false at this point,
  893. // so Call_Back() doesn't intercept global messages from me!
  894. //.....................................................................
  895. Call_Back();
  896. } // end of while
  897. if( pToolTipHitLast && pToolTipHitLast->bShowing )
  898. pToolTipHitLast->Unshow();
  899. /*
  900. //------------------------------------------------------------------------
  901. // Restore screen
  902. //------------------------------------------------------------------------
  903. Hide_Mouse();
  904. Load_Title_Page(true);
  905. Show_Mouse();
  906. */
  907. pWO->SaveChat();
  908. pWO->ClearListPtrs();
  909. return rc;
  910. }
  911. //***********************************************************************************************
  912. void WOL_PrintMessage( IconListClass& ILTarget, const char* szText, PlayerColorType iColorRemap /* = PCOLOR_NONE */ )
  913. {
  914. RemapControlType* pColorRemap = ( iColorRemap == PCOLOR_NONE ? NULL : &ColorRemaps[ iColorRemap ] );
  915. WOL_PrintMessage( ILTarget, szText, pColorRemap );
  916. }
  917. //***********************************************************************************************
  918. void WOL_PrintMessage( IconListClass& ILTarget, const char* szText, RemapControlType* pColorRemap )
  919. {
  920. ILTarget.Add_Item( szText, NULL, NULL, ICON_SHAPE, NULL, NULL, pColorRemap );
  921. if( !ILTarget.bScrollBeingDragged() )
  922. ILTarget.Show_Last_Item();
  923. }
  924. //***********************************************************************************************
  925. bool OnExpandChannelList( IconListClass& chanlist, IconListClass& userlist )
  926. {
  927. // Expand channel list button was pressed.
  928. // Returns true if userlist controls are to be hidden, false if they are to be shown.
  929. switch( lesCurrent )
  930. {
  931. case LES_NORMAL:
  932. ResizeChannelList( chanlist, true );
  933. lesCurrent = LES_CHANNELS_EXPANDED;
  934. break;
  935. case LES_USERS_EXPANDED:
  936. ResizeUserList( userlist, false );
  937. ResizeChannelList( chanlist, true );
  938. lesCurrent = LES_CHANNELS_EXPANDED;
  939. break;
  940. case LES_CHANNELS_EXPANDED:
  941. ResizeChannelList( chanlist, false );
  942. lesCurrent = LES_NORMAL;
  943. return false;
  944. }
  945. return true;
  946. }
  947. //***********************************************************************************************
  948. bool OnExpandUserList( IconListClass& chanlist, IconListClass& userlist )
  949. {
  950. // Expand user list button was pressed.
  951. // Returns true if chanlist controls are to be hidden, false if they are to be shown.
  952. switch( lesCurrent )
  953. {
  954. case LES_NORMAL:
  955. ResizeUserList( userlist, true );
  956. lesCurrent = LES_USERS_EXPANDED;
  957. break;
  958. case LES_CHANNELS_EXPANDED:
  959. ResizeChannelList( chanlist, false );
  960. ResizeUserList( userlist, true );
  961. lesCurrent = LES_USERS_EXPANDED;
  962. break;
  963. case LES_USERS_EXPANDED:
  964. ResizeUserList( userlist, false );
  965. lesCurrent = LES_NORMAL;
  966. return false;
  967. }
  968. return true;
  969. }
  970. //***********************************************************************************************
  971. void ResizeChannelList( IconListClass& chanlist, bool bExpand )
  972. {
  973. // If bExpand, makes list big, else normal size.
  974. if( bExpand )
  975. chanlist.Resize( d_chanlist_x, d_chanlist_y, d_chanlist_w, d_userlist_y + d_userlist_h - 15 - d_chanlist_y );
  976. else
  977. chanlist.Resize( d_chanlist_x, d_chanlist_y, d_chanlist_w, d_chanlist_h );
  978. }
  979. //***********************************************************************************************
  980. void ResizeUserList( IconListClass& userlist, bool bExpand )
  981. {
  982. // If bExpand, makes list big, else normal size.
  983. if( bExpand )
  984. userlist.Resize( d_userlist_x, d_chanlist_y + 15, d_userlist_w, d_userlist_y + d_userlist_h - ( d_chanlist_y + 15 ) );
  985. else
  986. userlist.Resize( d_userlist_x, d_userlist_y, d_userlist_w, d_userlist_h );
  987. }
  988. //***********************************************************************************************
  989. bool EnterChannel( WolapiObject* pWO, IconListClass& chatlist, IconListClass& chanlist, int iIndex, bool bGame )
  990. {
  991. // Enter the channel specified in chanlist at iIndex.
  992. // Called to enter chat channels, "lobbies", and game channels.
  993. // We've stored the channel pointer in the hidden extra data field.
  994. // ( Be careful about calling RAChatEventSink::DeleteChannelList()! )
  995. Channel* pChannel = (Channel*)chanlist.Get_Item_ExtraDataPtr( iIndex );
  996. return EnterChannel( pWO, chatlist, pChannel, NULL, bGame );
  997. }
  998. //***********************************************************************************************
  999. bool EnterChannel( WolapiObject* pWO, IconListClass& chatlist, Channel* pChannel, char* szChannelName, bool bGame )
  1000. {
  1001. // Called to cause the user to enter a channel (chat, lobby, or game).
  1002. // If pChannel is NULL, szChannelName will be used.
  1003. Channel ChannelWhenNameOnly;
  1004. if( !pChannel )
  1005. {
  1006. if( !szChannelName )
  1007. {
  1008. // debugprint( "pChannel and szChannelName null in EnterChannel" );
  1009. pWO->bSelfDestruct = true;
  1010. return false;
  1011. }
  1012. pChannel = &ChannelWhenNameOnly;
  1013. strcpy( (char*)pChannel->name, szChannelName );
  1014. }
  1015. if( bGame && pChannel->currentUsers >= pChannel->maxUsers ) // Pre-emptive fullness check.
  1016. {
  1017. WOL_PrintMessage( chatlist, TXT_WOL_CHANNELFULL, WOLCOLORREMAP_LOCALMACHINEMESS );
  1018. Sound_Effect( WOLSOUND_ERROR );
  1019. return false;
  1020. }
  1021. if( bGame )
  1022. {
  1023. // It is possible to enter a game channel while currently in a chat channel. (A lobby, presumably.)
  1024. if( pWO->CurrentLevel == WOL_LEVEL_INCHATCHANNEL || pWO->CurrentLevel == WOL_LEVEL_INLOBBY )
  1025. if( !pWO->ExitChatChannelForGameChannel() )
  1026. {
  1027. *pWO->szChannelReturnOnGameEnterFail = 0;
  1028. // debugprint( "ExitChatChannelForGameChannel on join failed" );
  1029. pWO->bSelfDestruct = true;
  1030. return false;
  1031. }
  1032. }
  1033. /* The following doesn't work because the needpw field is not currently being set in wolapi for chat channels.
  1034. Instead, we wait for a fail on join, then present this dialog and try again.
  1035. if( pChannel->needpw )
  1036. {
  1037. SimpleEditDlgClass* pEditDlg = new SimpleEditDlgClass( 300, TXT_WOL_JOINPRIVATETITLE, TXT_WOL_JOINPRIVATEPROMPT,
  1038. WOL_CHANKEY_LEN_MAX );
  1039. if( !pEditDlg->Show() || !*pEditDlg->szEdit )
  1040. return false;
  1041. strcpy( (char*)pChannel->key, pEditDlg->szEdit );
  1042. }
  1043. */
  1044. bool bKeepTrying = true;
  1045. // Set password automatically for our lobbies, if trying to join one.
  1046. int iLobby = iChannelLobbyNumber( pChannel->name );
  1047. if( iLobby != -1 )
  1048. strcpy( (char*)pChannel->key, LOBBYPASSWORD );
  1049. char szSuccessfulPassword[ WOL_PASSWORD_LEN + 5 ];
  1050. *szSuccessfulPassword = 0;
  1051. HRESULT hRes;
  1052. while( bKeepTrying )
  1053. {
  1054. hRes = pWO->ChannelJoin( pChannel );
  1055. switch( hRes )
  1056. {
  1057. case CHAT_E_BADCHANNELPASSWORD:
  1058. {
  1059. Fancy_Text_Print( TXT_NONE, 0, 0, TBLACK, TBLACK, TPF_TEXT ); // Required before String_Pixel_Width() call, for god's sake.
  1060. #ifdef ENGLISH
  1061. SimpleEditDlgClass* pEditDlg = new SimpleEditDlgClass( 300, TXT_WOL_JOINPRIVATETITLE, TXT_WOL_JOINPRIVATEPROMPT,
  1062. WOL_CHANKEY_LEN_MAX );
  1063. #else
  1064. #ifdef GERMAN
  1065. SimpleEditDlgClass* pEditDlg = new SimpleEditDlgClass( 400, TXT_WOL_JOINPRIVATETITLE, TXT_WOL_JOINPRIVATEPROMPT,
  1066. WOL_CHANKEY_LEN_MAX );
  1067. #else
  1068. SimpleEditDlgClass* pEditDlg = new SimpleEditDlgClass( 500, TXT_WOL_JOINPRIVATETITLE, TXT_WOL_JOINPRIVATEPROMPT,
  1069. WOL_CHANKEY_LEN_MAX );
  1070. #endif
  1071. #endif
  1072. pWO->bPump_In_Call_Back = true;
  1073. if( strcmp( pEditDlg->Show(), Text_String( TXT_OK ) ) != 0 || !*pEditDlg->szEdit )
  1074. {
  1075. pWO->bPump_In_Call_Back = false;
  1076. delete pEditDlg;
  1077. bKeepTrying = false;
  1078. break;
  1079. }
  1080. pWO->bPump_In_Call_Back = false;
  1081. strcpy( (char*)pChannel->key, pEditDlg->szEdit );
  1082. strcpy( szSuccessfulPassword, pEditDlg->szEdit );
  1083. delete pEditDlg;
  1084. break;
  1085. }
  1086. case CHAT_E_TIMEOUT:
  1087. pWO->bPump_In_Call_Back = true;
  1088. WWMessageBox().Process( TXT_WOL_TIMEOUT );
  1089. pWO->bPump_In_Call_Back = false;
  1090. bKeepTrying = false;
  1091. break;
  1092. case CHAT_E_CHANNELDOESNOTEXIST:
  1093. pWO->bPump_In_Call_Back = true;
  1094. WWMessageBox().Process( TXT_WOL_CHANNELGONE );
  1095. pWO->bPump_In_Call_Back = false;
  1096. bKeepTrying = false;
  1097. break;
  1098. case CHAT_E_BANNED:
  1099. WOL_PrintMessage( chatlist, TXT_WOL_YOUREBANNED, WOLCOLORREMAP_LOCALMACHINEMESS );
  1100. Sound_Effect( WOLSOUND_ERROR );
  1101. bKeepTrying = false;
  1102. break;
  1103. case CHAT_E_CHANNELFULL:
  1104. WOL_PrintMessage( chatlist, TXT_WOL_CHANNELFULL, WOLCOLORREMAP_LOCALMACHINEMESS );
  1105. Sound_Effect( WOLSOUND_ERROR );
  1106. bKeepTrying = false;
  1107. break;
  1108. case E_FAIL:
  1109. pWO->GenericErrorMessage();
  1110. bKeepTrying = false;
  1111. break;
  1112. case S_OK:
  1113. bKeepTrying = false;
  1114. break;
  1115. }
  1116. }
  1117. if( !bGame )
  1118. {
  1119. if( hRes == S_OK )
  1120. return pWO->OnEnteringChatChannel( (char*)pChannel->name, false, iLobby );
  1121. else
  1122. return false;
  1123. }
  1124. else
  1125. {
  1126. if( hRes == S_OK )
  1127. {
  1128. *pWO->szChannelReturnOnGameEnterFail = 0;
  1129. // Return later to the lobby of the channel creator - which was saved in the channel itself.
  1130. pWO->iLobbyReturnAfterGame = pChannel->reserved & 0x00FFFFFF;
  1131. if( pWO->iLobbyReturnAfterGame == 0x00FFFFFF )
  1132. pWO->iLobbyReturnAfterGame = -1;
  1133. CREATEGAMEINFO CreateGameInfo;
  1134. // Not all of these values are currently used during setup.
  1135. CreateGameInfo.bCreateGame = false;
  1136. CreateGameInfo.iPlayerMax = pChannel->maxUsers;
  1137. CreateGameInfo.bTournament = pChannel->tournament;
  1138. if( *szSuccessfulPassword )
  1139. {
  1140. CreateGameInfo.bPrivate = true;
  1141. strcpy( CreateGameInfo.szPassword, szSuccessfulPassword );
  1142. }
  1143. else
  1144. {
  1145. CreateGameInfo.bPrivate = false;
  1146. *CreateGameInfo.szPassword = 0;
  1147. }
  1148. CreateGameInfo.GameKind = (CREATEGAMEINFO::GAMEKIND)( pChannel->reserved & 0xFF000000 );
  1149. return pWO->OnEnteringGameChannel( (char*)pChannel->name, false, CreateGameInfo );
  1150. }
  1151. else
  1152. {
  1153. pWO->OnFailedToEnterGameChannel();
  1154. *pWO->szChannelReturnOnGameEnterFail = 0;
  1155. return false;
  1156. }
  1157. }
  1158. }
  1159. //***********************************************************************************************
  1160. bool ExitChatChannel( WolapiObject* pWO )
  1161. {
  1162. // Called to cause user to leave current chat or lobby channel.
  1163. // debugprint( "ExitChatChannel\n" );
  1164. if( !pWO->ChannelLeave() )
  1165. {
  1166. pWO->GenericErrorMessage();
  1167. return false;
  1168. }
  1169. pWO->OnExitingChatChannel();
  1170. return true;
  1171. }
  1172. //***********************************************************************************************
  1173. //void CreateChatChannel( WolapiObject* pWO, bool bPrivate )
  1174. void CreateChatChannel( WolapiObject* pWO )
  1175. {
  1176. SimpleEditDlgClass* pEditDlg;
  1177. /* if( !bPrivate )
  1178. {
  1179. pEditDlg = new SimpleEditDlgClass( 300, TXT_WOL_CREATECHANNELTITLE, TXT_WOL_CREATECHANNELPROMPT,
  1180. WOL_CHANNAME_LEN_MAX );
  1181. if( strcmp( pEditDlg->Show(), Text_String( TXT_OK ) ) == 0 && *pEditDlg->szEdit )
  1182. {
  1183. if( pWO->ChannelCreate( pEditDlg->szEdit, NULL ) )
  1184. pWO->OnEnteringChatChannel( pEditDlg->szEdit, true, -1 );
  1185. }
  1186. }
  1187. else
  1188. */ {
  1189. Fancy_Text_Print( TXT_NONE, 0, 0, TBLACK, TBLACK, TPF_TEXT ); // Required before String_Pixel_Width() call, for god's sake.
  1190. pEditDlg = new SimpleEditDlgClass( 350, TXT_WOL_CREATECHANNELTITLE, TXT_WOL_CREATECHANNELPROMPT,
  1191. WOL_CHANNAME_LEN_MAX, TXT_WOL_OPTIONALPASSPROMPT, WOL_CHANKEY_LEN_MAX );
  1192. pWO->bPump_In_Call_Back = true;
  1193. if( strcmp( pEditDlg->Show(), Text_String( TXT_OK ) ) == 0 && *pEditDlg->szEdit )
  1194. {
  1195. pWO->bPump_In_Call_Back = false;
  1196. if( *pEditDlg->szEdit2 )
  1197. {
  1198. if( pWO->ChannelCreate( pEditDlg->szEdit, pEditDlg->szEdit2 ) )
  1199. pWO->OnEnteringChatChannel( pEditDlg->szEdit, true, -1 );
  1200. }
  1201. else
  1202. {
  1203. // Create public channel.
  1204. if( pWO->ChannelCreate( pEditDlg->szEdit, NULL ) )
  1205. pWO->OnEnteringChatChannel( pEditDlg->szEdit, true, -1 );
  1206. }
  1207. }
  1208. pWO->bPump_In_Call_Back = false;
  1209. }
  1210. delete pEditDlg;
  1211. }
  1212. //***********************************************************************************************
  1213. bool CreateGameChannel( WolapiObject* pWO, const CREATEGAMEINFO& cgi )
  1214. {
  1215. char szNewChannelName[ WOL_CHANNAME_LEN_MAX ];
  1216. sprintf( szNewChannelName, "%s's_game", pWO->szMyName );
  1217. if( pWO->CurrentLevel == WOL_LEVEL_INCHATCHANNEL || pWO->CurrentLevel == WOL_LEVEL_INLOBBY )
  1218. if( !pWO->ExitChatChannelForGameChannel() )
  1219. {
  1220. *pWO->szChannelReturnOnGameEnterFail = 0;
  1221. // debugprint( "ExitChatChannelForGameChannel in CreateGameChannel() error" );
  1222. pWO->bSelfDestruct = true;
  1223. return false;
  1224. }
  1225. const char* szKey;
  1226. if( *cgi.szPassword )
  1227. szKey = cgi.szPassword;
  1228. else
  1229. szKey = NULL;
  1230. if( pWO->ChannelCreate( szNewChannelName, szKey, true, cgi.iPlayerMax, cgi.bTournament, pWO->iLobbyLast, cgi.GameKind ) )
  1231. pWO->OnEnteringGameChannel( szNewChannelName, true, cgi );
  1232. else
  1233. {
  1234. pWO->OnFailedToEnterGameChannel();
  1235. // debugprint( "CreateGameChannel fail" );
  1236. return false;
  1237. }
  1238. *pWO->szChannelReturnOnGameEnterFail = 0;
  1239. return true;
  1240. }
  1241. //***********************************************************************************************
  1242. bool ProcessChannelListSelection( WolapiObject* pWO, IconListClass& chatlist, IconListClass& chanlist, int iIndex )
  1243. {
  1244. // Takes whatever action necessary due to user selecting iIndex from chanlist.
  1245. // Returns true if user selected to enter a game channel, else false.
  1246. if( iIndex < 0 )
  1247. return false;
  1248. // debugprint( "iIndex %i\n", iIndex );
  1249. const char* szChannelType = chanlist.Get_Item_ExtraDataString( iIndex );
  1250. if( szChannelType )
  1251. {
  1252. //debugprint( "szChannelType %s\n", szChannelType );
  1253. if( strcmp( szChannelType, CHANNELTYPE_OFFICIALCHAT ) == 0 )
  1254. {
  1255. if( pWO->CurrentLevel == WOL_LEVEL_INCHATCHANNEL )
  1256. {
  1257. if( !ExitChatChannel( pWO ) )
  1258. {
  1259. pWO->bSelfDestruct = true;
  1260. return false;
  1261. }
  1262. }
  1263. pWO->EnterLevel_OfficialChat();
  1264. }
  1265. else if( strcmp( szChannelType, CHANNELTYPE_USERCHAT ) == 0 )
  1266. {
  1267. if( pWO->CurrentLevel == WOL_LEVEL_INCHATCHANNEL )
  1268. {
  1269. if( !ExitChatChannel( pWO ) )
  1270. {
  1271. pWO->bSelfDestruct = true;
  1272. return false;
  1273. }
  1274. }
  1275. pWO->EnterLevel_UserChat();
  1276. }
  1277. else if( strcmp( szChannelType, CHANNELTYPE_TOP ) == 0 )
  1278. {
  1279. if( pWO->CurrentLevel == WOL_LEVEL_INCHATCHANNEL )
  1280. {
  1281. // Now not possible.
  1282. if( !ExitChatChannel( pWO ) )
  1283. {
  1284. pWO->bSelfDestruct = true;
  1285. return false;
  1286. }
  1287. }
  1288. pWO->EnterLevel_Top();
  1289. }
  1290. else if( strcmp( szChannelType, CHANNELTYPE_GAMES ) == 0 )
  1291. {
  1292. if( pWO->CurrentLevel == WOL_LEVEL_INCHATCHANNEL )
  1293. {
  1294. // Now not possible.
  1295. if( !ExitChatChannel( pWO ) )
  1296. {
  1297. pWO->bSelfDestruct = true;
  1298. return false;
  1299. }
  1300. }
  1301. pWO->EnterLevel_Games();
  1302. }
  1303. else if( strcmp( szChannelType, CHANNELTYPE_GAMESOFTYPE ) == 0 )
  1304. {
  1305. if( pWO->CurrentLevel == WOL_LEVEL_INCHATCHANNEL )
  1306. {
  1307. // Now not possible.
  1308. if( !ExitChatChannel( pWO ) )
  1309. {
  1310. pWO->bSelfDestruct = true;
  1311. return false;
  1312. }
  1313. }
  1314. void* pExtraData = chanlist.Get_Item_ExtraDataPtr( iIndex );
  1315. pWO->EnterLevel_GamesOfType( (WOL_GAMETYPEINFO*)pExtraData );
  1316. }
  1317. else if( strcmp( szChannelType, CHANNELTYPE_CHATCHANNEL ) == 0 )
  1318. {
  1319. if( pWO->CurrentLevel == WOL_LEVEL_INCHATCHANNEL )
  1320. {
  1321. // Not currently possible.
  1322. // debugprint( "Trying to jump from channel to channel?!\n" );
  1323. pWO->bSelfDestruct = true;
  1324. return false;
  1325. }
  1326. // Join the chat channel.
  1327. EnterChannel( pWO, chatlist, chanlist, iIndex, false ); // Can fail.
  1328. }
  1329. else if( strcmp( szChannelType, CHANNELTYPE_GAMECHANNEL ) == 0 )
  1330. {
  1331. // User attempting to join game channel.
  1332. if( pWO->CurrentLevel == WOL_LEVEL_INCHATCHANNEL )
  1333. {
  1334. // Not currently possible.
  1335. // debugprint( "Trying to jump from channel to channel?!\n" );
  1336. pWO->bSelfDestruct = true;
  1337. return false;
  1338. }
  1339. // Check if local user is allowed to join GameKind.
  1340. Channel* pChannel = (Channel*)chanlist.Get_Item_ExtraDataPtr( iIndex );
  1341. if( pChannel->type == GAME_TYPE )
  1342. {
  1343. // It is a game of our type, at least.
  1344. CREATEGAMEINFO::GAMEKIND GameKind = (CREATEGAMEINFO::GAMEKIND)( pChannel->reserved & 0xFF000000 );
  1345. switch( GameKind )
  1346. {
  1347. case CREATEGAMEINFO::RAGAME:
  1348. break;
  1349. case CREATEGAMEINFO::CSGAME:
  1350. if( !Is_Counterstrike_Installed() )
  1351. {
  1352. WOL_PrintMessage( chatlist, TXT_WOL_NEEDCOUNTERSTRIKE, WOLCOLORREMAP_LOCALMACHINEMESS );
  1353. Sound_Effect( WOLSOUND_ERROR );
  1354. return false;
  1355. }
  1356. break;
  1357. case CREATEGAMEINFO::AMGAME:
  1358. if( !Is_Aftermath_Installed() )
  1359. {
  1360. WOL_PrintMessage( chatlist, TXT_WOL_NEEDAFTERMATH, WOLCOLORREMAP_LOCALMACHINEMESS );
  1361. Sound_Effect( WOLSOUND_ERROR );
  1362. return false;
  1363. }
  1364. break;
  1365. default:
  1366. // debugprint( "Illegal value for GameKind channel reserved field: %s\n", (char*)pChannel->name );
  1367. Sound_Effect( WOLSOUND_ERROR );
  1368. return false;
  1369. }
  1370. // Join the game channel.
  1371. if( EnterChannel( pWO, chatlist, chanlist, iIndex, true ) )
  1372. {
  1373. // Exit the chat dialog, go to game dialog.
  1374. return true;
  1375. }
  1376. }
  1377. else
  1378. {
  1379. // User doubleclicked on a game that is of a different type.
  1380. // Offer to take them to a web page regarding the game type.
  1381. pWO->DoGameAdvertising( pChannel );
  1382. }
  1383. }
  1384. else if( strcmp( szChannelType, CHANNELTYPE_LOBBIES ) == 0 )
  1385. {
  1386. if( pWO->CurrentLevel == WOL_LEVEL_INCHATCHANNEL )
  1387. {
  1388. // Not currently possible.
  1389. // debugprint( "Chat channel to lobbies level?!\n" );
  1390. pWO->bSelfDestruct = true;
  1391. return false;
  1392. }
  1393. if( pWO->CurrentLevel == WOL_LEVEL_INLOBBY )
  1394. {
  1395. if( !ExitChatChannel( pWO ) )
  1396. {
  1397. pWO->bSelfDestruct = true;
  1398. return false;
  1399. }
  1400. }
  1401. pWO->EnterLevel_Lobbies();
  1402. }
  1403. else if( strcmp( szChannelType, CHANNELTYPE_LOBBYCHANNEL ) == 0 )
  1404. {
  1405. if( pWO->CurrentLevel == WOL_LEVEL_INCHATCHANNEL ||
  1406. pWO->CurrentLevel == WOL_LEVEL_INLOBBY )
  1407. {
  1408. // Not currently possible.
  1409. // debugprint( "Chat or lobby channel to lobby channel?!\n" );
  1410. pWO->bSelfDestruct = true;
  1411. return false;
  1412. }
  1413. // Join the lobby chat channel.
  1414. EnterChannel( pWO, chatlist, chanlist, iIndex, false ); // Can fail.
  1415. }
  1416. else if( strcmp( szChannelType, CHANNELTYPE_LOADING ) == 0 )
  1417. {
  1418. // User clicked on the channel list loading notification - do nothing.
  1419. }
  1420. else
  1421. {
  1422. // debugprint( "Item selected in channel list unidentifiable from extradata field\n" );
  1423. pWO->bSelfDestruct = true;
  1424. return false;
  1425. }
  1426. }
  1427. return false;
  1428. }
  1429. //***********************************************************************************************
  1430. bool bLinkInList( const LinkClass* pListHead, const LinkClass* pLinkToFind )
  1431. {
  1432. const LinkClass* pLink = pListHead;
  1433. while( pLink )
  1434. {
  1435. if( pLink == pLinkToFind )
  1436. return true;
  1437. pLink = pLink->Get_Next();
  1438. }
  1439. return false;
  1440. }
  1441. #endif