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