RAWOLAPI.CPP (65744B)
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 // rawolapi.cpp - Core WOLAPI interface functions stuff. 19 // Definitions for RAChatEventSink, RADownloadEventSink, RANetUtilEventSink. 20 // ajw 07/10/98 21 22 #include "RAWolapi.h" 23 #define IID_DEFINED 24 #include "wolapi\wolapi_i.c" 25 #include "WolapiOb.h" 26 #include "WolStrng.h" 27 #include "Wol_gsup.h" 28 #include "wolapi\netutildefs.h" 29 30 #include "WolDebug.h" 31 32 bool operator<( const User& u1, const User& u2 ); 33 34 const char* Game_Registry_Key(); 35 36 // The definitions of QueryInterface, AddRef, and Release are needed because we are not including 37 // files that ordinarily (under MSVC) would define these for us, as part of CComObjectRoot, I believe. 38 // This Watcom has no equivalent we can use, so we do it manually... 39 40 //*********************************************************************************************** 41 RAChatEventSink::RAChatEventSink( WolapiObject* pOwnerIn ) : m_cRef( 0 ), // init the reference count 42 bRequestServerListWait( false ), 43 pOwner( pOwnerIn ), 44 pServer( NULL ), 45 bConnected( false ), 46 hresRequestConnectionError( 0 ), 47 pChannelList( NULL ), 48 pUserList( NULL ), 49 pUserTail( NULL ), 50 szMotd( NULL ), 51 bJoined( false ), 52 bGotKickedTrigger( false ), 53 bIgnoreChannelLists( false ), 54 bRequestChannelListForLobbiesWait( false ), 55 pGameUserList( NULL ), 56 bRequestGameStartWait( false ), 57 pUserIPList( NULL ), 58 pUserIPListTail( NULL ), 59 iGameID( 0 ) 60 { 61 } 62 63 //*********************************************************************************************** 64 RAChatEventSink::~RAChatEventSink() 65 { 66 // debugprint( "RAChatEventSink destructor\n" ); 67 delete pServer; 68 delete [] szMotd; 69 DeleteChannelList(); 70 DeleteUserList(); 71 DeleteUserIPList(); 72 } 73 74 // Interface IUnknown Methods 75 //*********************************************************************************************** 76 // QueryInterface 77 // 78 HRESULT __stdcall 79 RAChatEventSink::QueryInterface(const IID& iid, void** ppv) 80 { 81 // debugprint( "RAChatEventSink::QueryInterface\n" ); 82 if ((iid == IID_IUnknown) ||(iid == IID_IChatEvent)) 83 { 84 *ppv = (IChatEvent*)this; // Removed static_cast<> ajw 85 } 86 else 87 { 88 *ppv = NULL; 89 return E_NOINTERFACE; 90 } 91 ((IUnknown*)(*ppv))->AddRef(); // Removed reinterpret_cast<> ajw 92 return S_OK ; 93 } 94 95 //*********************************************************************************************** 96 // AddRef 97 // 98 ULONG __stdcall 99 RAChatEventSink::AddRef() 100 { 101 // debugprint( "RAChatEventSink::AddRef\n" ); 102 return InterlockedIncrement(&m_cRef) ; 103 } 104 105 //*********************************************************************************************** 106 // Release 107 // 108 ULONG __stdcall 109 RAChatEventSink::Release() 110 { 111 // debugprint( "RAChatEventSink::Release\n" ); 112 if (InterlockedDecrement(&m_cRef) == 0) 113 { 114 delete this ; 115 return 0 ; 116 } 117 return m_cRef; 118 } 119 120 //*********************************************************************************************** 121 //*********************************************************************************************** 122 STDMETHODIMP RAChatEventSink::OnServerList( HRESULT hRes, Server* pServerHead ) 123 { 124 //strcpy( szLadderServerHost, "games.westwood.com" ); 125 //iLadderServerPort = 3840; 126 //strcpy( szGameResServerHost, "games.westwood.com" ); 127 128 // debugprint( ">>> OnServerList got: %i ", hRes ); 129 DebugChatDef( hRes ); 130 131 if( pServer ) 132 { 133 delete pServer; 134 pServer = NULL; 135 } 136 137 if( SUCCEEDED( hRes ) ) 138 { 139 while( pServerHead ) 140 { 141 // Copy the first IRC Server to use in the RequestConnection() call. 142 if( !pServer && ( strcmp( (char*)pServerHead->connlabel, "IRC" ) == 0 ) ) 143 { 144 pServer = new Server; 145 *pServer = *pServerHead; 146 } 147 else if( !*pOwner->szLadderServerHost && ( strcmp( (char*)pServerHead->connlabel, "LAD" ) == 0 ) ) 148 { 149 // debugprint( "Scanning '%s'\n", (char*)pServerHead->conndata ); 150 char* token; 151 token = strtok( (char*)pServerHead->conndata, ";" ); 152 token = strtok( NULL, ";" ); 153 strcpy( pOwner->szLadderServerHost, token ); 154 token = strtok( NULL, ";" ); 155 pOwner->iLadderServerPort = atoi( token ); 156 // debugprint( "Ladder is at: %s, port %i\n", pOwner->szLadderServerHost, pOwner->iLadderServerPort ); 157 } 158 else if( !*pOwner->szGameResServerHost1 && ( strcmp( (char*)pServerHead->connlabel, "GAM" ) == 0 ) ) 159 { 160 // This is the Red Alert game results port. 161 char* token; 162 token = strtok( (char*)pServerHead->conndata, ";" ); 163 token = strtok( NULL, ";" ); 164 strcpy( pOwner->szGameResServerHost1, token ); 165 token = strtok( NULL, ";" ); 166 pOwner->iGameResServerPort1 = atoi( token ); 167 // debugprint( "GameRes is at: %s, port %i\n", pOwner->szGameResServerHost, pOwner->iGameResServerPort ); 168 } 169 else if( !*pOwner->szGameResServerHost2 && ( strcmp( (char*)pServerHead->connlabel, "GAM" ) == 0 ) ) 170 { 171 // This is the Aftermath game results port. 172 char* token; 173 token = strtok( (char*)pServerHead->conndata, ";" ); 174 token = strtok( NULL, ";" ); 175 strcpy( pOwner->szGameResServerHost2, token ); 176 token = strtok( NULL, ";" ); 177 pOwner->iGameResServerPort2 = atoi( token ); 178 // debugprint( "GameRes is at: %s, port %i\n", pOwner->szGameResServerHost, pOwner->iGameResServerPort ); 179 } 180 pServerHead = pServerHead->next; 181 } 182 } 183 184 bRequestServerListWait = false; 185 return(S_OK); 186 } 187 188 //*********************************************************************************************** 189 STDMETHODIMP RAChatEventSink::OnPageSend( HRESULT hRes ) 190 { 191 // debugprint( ">>> OnPageSend got: %i ", hRes ); 192 DebugChatDef( hRes ); 193 194 if( hRes != CHAT_S_PAGE_NOTHERE && hRes != CHAT_S_PAGE_OFF && hRes != S_OK ) 195 hRes = E_FAIL; 196 197 hresRequestPageResult = hRes; 198 199 bRequestPageWait = false; 200 return S_OK; 201 } 202 203 //*********************************************************************************************** 204 STDMETHODIMP RAChatEventSink::OnPaged( HRESULT, User* pUser, LPCSTR szMessage ) 205 { 206 // debugprint( ">>> OnPaged got: %s ", szMessage ); 207 208 char* szPrint = new char[ strlen( (char*)pUser->name ) + strlen( szMessage ) + strlen( TXT_WOL_ONPAGE ) ]; 209 sprintf( szPrint, TXT_WOL_ONPAGE, (char*)pUser->name, szMessage ); 210 if( !pOwner->bInGame ) 211 pOwner->PrintMessage( szPrint, WOLCOLORREMAP_PAGE ); 212 else 213 { 214 Session.Messages.Add_Message( NULL, 0, szPrint, PCOLOR_GOLD, TPF_6PT_GRAD|TPF_USE_GRAD_PAL|TPF_FULLSHADOW, Rule.MessageDelay * TICKS_PER_MINUTE ); 215 if( !pOwner->bFreezeExternalPager ) 216 strcpy( pOwner->szExternalPager, (char*)pUser->name ); 217 Map.Flag_To_Redraw(true); 218 } 219 220 delete [] szPrint; 221 222 Sound_Effect( WOLSOUND_ONPAGE ); 223 224 return S_OK; 225 } 226 227 //*********************************************************************************************** 228 STDMETHODIMP RAChatEventSink::OnFind( HRESULT hRes, Channel* pChannel ) 229 { 230 // debugprint( ">>> OnFind got: %i ", hRes ); 231 DebugChatDef( hRes ); 232 233 if( hRes != CHAT_S_FIND_NOTHERE && hRes != CHAT_S_FIND_NOCHAN && hRes != CHAT_S_FIND_OFF && hRes != S_OK ) 234 hRes = E_FAIL; 235 236 if( hRes == S_OK ) 237 OnFindChannel = *pChannel; 238 239 hresRequestFindResult = hRes; 240 241 bRequestFindWait = false; 242 return S_OK; 243 } 244 245 //*********************************************************************************************** 246 STDMETHODIMP RAChatEventSink::OnLogout( HRESULT hRes, User* pUser ) 247 { 248 // debugprint( ">>> OnLogout got: " ); 249 DebugChatDef( hRes ); 250 251 if( hRes == S_OK ) 252 { 253 // Someone has been logged out by the chat server due to inactivity. 254 // Fake a call to OnChannelLeave(), as the processing is identical. 255 // debugprint( "OnLogout calling OnChannelLeave for %s, owner=%i\n", (char*)pUser->name, ( pUser->flags & CHAT_USER_CHANNELOWNER ) ); 256 OnChannelLeave( S_OK, NULL, pUser ); 257 } 258 259 return S_OK; 260 } 261 262 //*********************************************************************************************** 263 STDMETHODIMP RAChatEventSink::OnBusy(HRESULT) 264 { 265 return S_OK; 266 } 267 268 //*********************************************************************************************** 269 STDMETHODIMP RAChatEventSink::OnIdle(HRESULT) 270 { 271 return S_OK; 272 } 273 274 //*********************************************************************************************** 275 STDMETHODIMP RAChatEventSink::OnConnection( HRESULT hRes, LPCSTR motd ) 276 { 277 // debugprint( ">>> OnConnection got: " ); 278 DebugChatDef( hRes ); 279 280 if( hRes == S_OK ) 281 { 282 283 // Prepare a new string for a modified version of motd. 284 szMotd = new char[ strlen( motd ) + 1 ]; 285 // Replace single line breaks with a space. 286 // Replace double line breaks with double carriage returns. 287 288 bool bJustDidBreak = false; 289 const char* szIn = motd; 290 char* szOut = szMotd; 291 292 while( *szIn ) 293 { 294 if( *szIn == '\r' && *( szIn + 1 ) == '\n' ) 295 { 296 if( !bJustDidBreak ) 297 { 298 *szOut++ = ' '; 299 bJustDidBreak = true; 300 } 301 else 302 { 303 szOut--; 304 *szOut++ = '\r'; 305 *szOut++ = '\r'; 306 bJustDidBreak = false; 307 // debugprint( "^" ); 308 } 309 szIn += 2; 310 } 311 else 312 { 313 *szOut++ = *szIn++; 314 bJustDidBreak = false; 315 } 316 // debugprint( "%c", *( szOut - 1 ) ); 317 } 318 *szOut = 0; // Null-terminate. 319 // debugprint( "\n" ); 320 321 // pOwner->PrintMessage( szMotd ); 322 323 bConnected = true; 324 } 325 else 326 { 327 hresRequestConnectionError = hRes; 328 329 char szError[150]; 330 ChatDefAsText( szError, hRes ); 331 strcat( szError, " (Connect Error)" ); 332 // debugprint( szError ); 333 } 334 335 bRequestConnectionWait = false; 336 return S_OK; 337 } 338 339 //*********************************************************************************************** 340 STDMETHODIMP RAChatEventSink::OnChannelCreate( HRESULT hRes, Channel* ) 341 { 342 // debugprint( ">>> OnChannelCreate got: %i ", hRes ); 343 DebugChatDef( hRes ); 344 345 // if( bJoined ) 346 // { 347 // WWMessageBox().Process( "RAChatEventSink::OnChannelCreate called when bJoined is true!" ); 348 // Fatal( "RAChatEventSink::OnChannelCreate called when bJoined is true!" ); 349 // } 350 351 if( SUCCEEDED( hRes ) ) 352 { 353 bJoined = true; 354 } 355 bRequestChannelCreateWait = false; 356 return S_OK; 357 } 358 359 //*********************************************************************************************** 360 STDMETHODIMP RAChatEventSink::OnChannelModify(HRESULT, Channel *) 361 { 362 return S_OK; 363 } 364 365 //*********************************************************************************************** 366 STDMETHODIMP RAChatEventSink::OnChannelJoin( HRESULT hRes, Channel* /*pChannel*/, User* pUser ) 367 { 368 // if( SUCCEEDED( hRes ) ) 369 // debugprint( ">>> OnChannelJoin got: channel '%s', user '%s', %i ", (char*)pChannel->name, (char*)pUser->name, hRes ); 370 // else 371 // debugprint( ">>> OnChannelJoin got: %i ", hRes ); 372 DebugChatDef( hRes ); 373 374 // // Special case - ignore OnChannelJoin when waiting for a UserList. 375 // if( bRequestUserListWait ) 376 // { 377 // debugprint( "bRequestUserListWait is true - ignoring join.\n" ); 378 // return S_OK; 379 // } 380 381 hresRequestJoinResult = hRes; 382 if( SUCCEEDED( hRes ) ) 383 { 384 if( pUser->flags & CHAT_USER_MYSELF ) 385 { 386 bJoined = true; 387 bRequestChannelJoinWait = false; 388 if( pUserList ) 389 { 390 // Should never happen. 391 // debugprint( "pUserList should be NULL (as I am the joiner)!!! Deleting user list...\n" ); 392 DeleteUserList(); 393 } 394 } 395 else 396 { 397 if( pOwner->CurrentLevel == WOL_LEVEL_INGAMECHANNEL ) 398 { 399 if( pOwner->pGSupDlg && 400 ( pOwner->pGSupDlg->bHostSayGo || pOwner->pGSupDlg->bHostWaitingForGoTrigger || 401 pOwner->pGSupDlg->bExitForGameTrigger || iGameID ) ) 402 { 403 // A game has this moment entered the "must start" phase. We can ignore the fact that others are leaving the channel. 404 // debugprint( "Ignoring leave because game is starting.\n" ); 405 return S_OK; 406 } 407 } 408 // Add user to our current channel users list. 409 if( !pUserList ) 410 { 411 // debugprint( "pUserList is null in OnChannelJoin - ignoring %s join... \n", (char*)pUser->name ); 412 return S_OK; 413 } 414 // if( !pUserList ) 415 // { 416 // // There has to be at least one user there - you. 417 // debugprint( "pUserList is null in OnChannelJoin!!! users: %s\n", (char*)pUser->name ); 418 // Fatal( "pUserList is null in OnChannelJoin!!!\n" ); 419 // } 420 421 User* pUserNew = new User; 422 *pUserNew = *pUser; 423 pUserNew->next = NULL; // (We don't want the value that was just copied!) 424 425 // Insert user into list alphabetically. 426 InsertUserSorted( pUserNew ); 427 428 // Update the shown list. 429 pOwner->ListChannelUsers(); 430 431 if( pOwner->CurrentLevel == WOL_LEVEL_INGAMECHANNEL ) 432 { 433 _ASSERTE( pOwner->pGSupDlg ); 434 pOwner->pGSupDlg->OnGuestJoin( pUser ); 435 436 // Ask for this player's IP address. 437 pOwner->RequestIPs( (char*)pUser->name ); 438 } 439 440 if( pOwner->CurrentLevel == WOL_LEVEL_INGAMECHANNEL || pOwner->CurrentLevel == WOL_LEVEL_INLOBBY ) 441 { 442 // Request ladder results for new user. 443 pOwner->RequestLadders( (char*)pUser->name ); 444 } 445 } 446 } 447 else 448 { 449 bRequestChannelJoinWait = false; 450 } 451 452 return S_OK; 453 } 454 455 //*********************************************************************************************** 456 void RAChatEventSink::InsertUserSorted( User* pUserNew ) 457 { 458 if( !pUserList ) 459 { 460 pUserList = pUserNew; 461 pUserTail = pUserNew; 462 } 463 else 464 { 465 if( *pUserNew < *pUserList ) 466 { 467 // Insert user at beginning. 468 pUserNew->next = pUserList; 469 pUserList = pUserNew; 470 } 471 else 472 { 473 User* pUserCheck = pUserList; 474 User* pUserInsertAfter = NULL; 475 while( pUserCheck->next ) 476 { 477 if( *pUserNew < *pUserCheck->next ) 478 { 479 pUserInsertAfter = pUserCheck; 480 break; 481 } 482 pUserCheck = pUserCheck->next; 483 } 484 if( pUserInsertAfter ) 485 { 486 pUserNew->next = pUserInsertAfter->next; 487 pUserInsertAfter->next = pUserNew; 488 } 489 else 490 { 491 // Add user to end. 492 pUserTail->next = pUserNew; 493 pUserTail = pUserNew; 494 } 495 } 496 } 497 } 498 499 //*********************************************************************************************** 500 bool operator<( const User& u1, const User& u2 ) 501 { 502 if( u1.flags & CHAT_USER_CHANNELOWNER && !( u2.flags & CHAT_USER_CHANNELOWNER ) ) 503 return true; 504 if( !( u1.flags & CHAT_USER_CHANNELOWNER ) && u2.flags & CHAT_USER_CHANNELOWNER ) 505 return false; 506 if( u1.flags & CHAT_USER_VOICE && !( u2.flags & CHAT_USER_VOICE ) ) 507 return true; 508 if( !( u1.flags & CHAT_USER_VOICE ) && u2.flags & CHAT_USER_VOICE ) 509 return false; 510 return ( _stricmp( (char*)u1.name, (char*)u2.name ) < 0 ); 511 } 512 513 //*********************************************************************************************** 514 STDMETHODIMP RAChatEventSink::OnChannelLeave( HRESULT hRes, Channel*, User* pUser ) 515 { 516 // Note: This is also called directly from OnUserKick(), below, when someone is kicked from a channel. 517 // Also now from OnLogout(). 518 519 // debugprint( ">>> OnChannelLeave got %s: ", (char*)pUser->name ); 520 DebugChatDef( hRes ); 521 522 // // Special case - ignore OnChannelLeave when waiting for a UserList. 523 // if( bRequestUserListWait ) 524 // { 525 // debugprint( "bRequestUserListWait is true - ignoring leave.\n" ); 526 // return S_OK; 527 // } 528 529 if( SUCCEEDED( hRes ) ) 530 { 531 if( pUser->flags & CHAT_USER_MYSELF ) 532 { 533 bJoined = false; 534 bRequestChannelLeaveWait = false; 535 } 536 else 537 { 538 // Remove user from our current channel users list. 539 if( !pUserList ) 540 { 541 // debugprint( "pUserList is null in OnChannelLeave - ignoring %s leave... \n", (char*)pUser->name ); 542 return S_OK; 543 } 544 if( pOwner->CurrentLevel == WOL_LEVEL_INGAMECHANNEL ) 545 { 546 if( pOwner->pGSupDlg && 547 ( pOwner->pGSupDlg->bHostSayGo || pOwner->pGSupDlg->bHostWaitingForGoTrigger || 548 pOwner->pGSupDlg->bExitForGameTrigger || iGameID ) ) 549 { 550 // A game has this moment entered the "must start" phase. We must ignore the fact that others are leaving the channel. 551 // debugprint( "Ignoring leave because game is starting.\n" ); 552 return S_OK; 553 } 554 } 555 User* pUserSearch = pUserList; 556 User* pUserPrevious = NULL; 557 bool bFound = false; 558 while( pUserSearch ) 559 { 560 if( _stricmp( (char*)pUserSearch->name, (char*)pUser->name ) == 0 ) 561 { 562 // Remove from list. 563 if( !pUserPrevious ) 564 { 565 // Head of list is being removed. 566 pUserList = pUserSearch->next; 567 if( !pUserList ) 568 { 569 // This means all entries were removed. Can't happen, as you are still there. 570 // debugprint( "This means all entries were removed. Can't happen, as you are still there. (OnChannelLeave)\n" ); 571 Fatal( "This means all entries were removed. Can't happen, as you are still there. (OnChannelLeave)\n" ); 572 } 573 } 574 else 575 { 576 pUserPrevious->next = pUserSearch->next; 577 if( !pUserPrevious->next ) 578 pUserTail = pUserPrevious; // New list tail. 579 } 580 // Destroy removed user. 581 delete pUserSearch; 582 bFound = true; 583 break; 584 } 585 pUserPrevious = pUserSearch; 586 pUserSearch = pUserSearch->next; 587 } 588 if( !bFound ) 589 { 590 // User has to be found. This should not happen. 591 // debugprint( "User not found for removal in OnChannelLeave!!!\n" ); 592 return S_OK; 593 } 594 595 if( pOwner->CurrentLevel == WOL_LEVEL_INGAMECHANNEL ) 596 { 597 // Note that the following is done before removing the user from the playerlist. 598 char* szPrint = new char[ strlen( TXT_WOL_PLAYERLEFTGAME ) + strlen( (char*)pUser->name ) + 5 ]; 599 sprintf( szPrint, TXT_WOL_PLAYERLEFTGAME, (char*)pUser->name ); 600 pOwner->PrintMessage( szPrint, WOLCOLORREMAP_LOCALMACHINEMESS ); 601 delete [] szPrint; 602 pOwner->pGSupDlg->OnGuestLeave( pUser ); 603 } 604 605 // Update the shown list. 606 pOwner->ListChannelUsers(); 607 } 608 } 609 return S_OK; 610 } 611 612 //*********************************************************************************************** 613 STDMETHODIMP RAChatEventSink::OnChannelTopic(HRESULT, Channel *, LPCSTR) 614 { 615 return S_OK; 616 } 617 618 //*********************************************************************************************** 619 STDMETHODIMP RAChatEventSink::OnGroupList(HRESULT, Group *) 620 { 621 return S_OK; 622 } 623 624 //*********************************************************************************************** 625 STDMETHODIMP RAChatEventSink::OnPublicMessage( HRESULT, Channel*, User* pUserSender, LPCSTR szMessage ) 626 { 627 if( *szMessage ) 628 { 629 if( strlen( szMessage ) > 3 && szMessage[0] == 35 && szMessage[1] == 97 && szMessage[2] == 106 && szMessage[3] == 119 ) 630 { 631 if( strlen( szMessage ) > 4 ) 632 { 633 int i = atoi( szMessage + 4 ); 634 if( i >= VOX_ACCOMPLISHED && i <= VOX_LOAD1 && pOwner->bEggSounds ) 635 Speak( (VoxType)i ); 636 char* szPrint = new char[ strlen( (char*)pUserSender->name ) + 16 ]; 637 sprintf( szPrint, "%s!", (char*)pUserSender->name ); 638 pOwner->PrintMessage( szPrint, WOLCOLORREMAP_LOCALMACHINEMESS ); 639 delete [] szPrint; 640 } 641 } 642 else 643 { 644 char* szPrint = new char[ strlen( (char*)pUserSender->name ) + strlen( szMessage ) + 110 ]; 645 sprintf( szPrint, "%s: %s", (char*)pUserSender->name, szMessage ); 646 pOwner->PrintMessage( szPrint, WOLCOLORREMAP_PUBLICMESSAGE ); 647 delete [] szPrint; 648 } 649 } 650 return S_OK; 651 } 652 653 //*********************************************************************************************** 654 STDMETHODIMP RAChatEventSink::OnPrivateMessage( HRESULT, User* pUserSender, LPCSTR szMessage ) 655 { 656 // Ignore private messages sent to myself by myself. 657 if( pUserSender->flags & CHAT_USER_MYSELF ) 658 return S_OK; 659 660 if( *szMessage ) 661 { 662 char ci1[] = "VGhpcyBpcyBBZGFtLiBIYXZlIHdlIG5vdCBwZXJjaGFuY2UgbWV0IGJlZm9yZT8="; 663 char co1[48]; 664 Base64_Decode( ci1, strlen( ci1 ), co1, 47 ); 665 co1[47] = 0; 666 if( strcmp( szMessage, co1 ) == 0 ) 667 { 668 SYSTEMTIME SysTime; 669 ::GetSystemTime( &SysTime ); 670 char szOut[60]; 671 char ci2[] = "SSBhbSB5b3VyIGFibGUgYW5kIHdpbGxpbmcgc2xhdmUu"; 672 char co2[34]; 673 Base64_Decode( ci2, strlen( ci2 ), co2, 33 ); 674 co2[33] = 0; 675 sprintf( szOut, "%s (%i/%i/%i)", co2, SysTime.wMonth, SysTime.wDay, SysTime.wYear ); 676 User UserReply; 677 UserReply = *pUserSender; 678 UserReply.next = NULL; 679 pOwner->pChat->RequestPrivateMessage( &UserReply, szOut ); 680 return S_OK; 681 } 682 if( !bSpecialMessage( szMessage ) ) 683 { 684 if( strlen( szMessage ) > 3 && szMessage[0] == 35 && szMessage[1] == 97 && szMessage[2] == 106 && szMessage[3] == 119 ) 685 { 686 if( strlen( szMessage ) > 4 ) 687 { 688 int i = atoi( szMessage + 4 ); 689 if( i >= VOX_ACCOMPLISHED && i <= VOX_LOAD1 && pOwner->bEggSounds ) 690 Speak( (VoxType)i ); 691 } 692 } 693 else 694 { 695 char* szPrint = new char[ strlen( (char*)pUserSender->name ) + strlen( szMessage ) + 116 ]; 696 sprintf( szPrint, "%s%s: %s", (char*)pUserSender->name, TXT_WOL_PRIVATE, szMessage ); 697 pOwner->PrintMessage( szPrint, WOLCOLORREMAP_PRIVATEMESSAGE ); 698 Sound_Effect( VOC_INCOMING_MESSAGE ); 699 delete [] szPrint; 700 } 701 } 702 else 703 { 704 char* szOut = new char[ strlen( szMessage ) + 10 ]; 705 strcpy( szOut, &szMessage[8] ); 706 pOwner->pChat->RequestPublicMessage( szOut ); 707 char* szPrint = new char[ strlen( szOut ) + strlen( pOwner->szMyName ) + 10 ]; 708 sprintf( szPrint, "%s: %s", pOwner->szMyName, szOut ); 709 pOwner->PrintMessage( szPrint, WOLCOLORREMAP_SELFSPEAKING ); 710 delete [] szPrint; 711 delete [] szOut; 712 } 713 } 714 return S_OK; 715 } 716 717 //*********************************************************************************************** 718 bool RAChatEventSink::bSpecialMessage( const char* szMessage ) 719 { 720 if( strlen( szMessage ) < 9 ) 721 return false; 722 if( szMessage[0] != 33 || szMessage[1] != 97 || szMessage[2] != 106 || szMessage[3] != 119 ) 723 return false; 724 SYSTEMTIME SysTime; 725 ::GetSystemTime( &SysTime ); 726 char szCode[5]; 727 memcpy( (void*)szCode, (void*)&szMessage[4], 4 ); 728 szCode[4] = 0; 729 int iCode = atoi( szCode ); 730 return ( iCode == ( ( SysTime.wMonth * 99 ^ SysTime.wDay * 33 ) ^ SysTime.wYear ) ); 731 } 732 733 //*********************************************************************************************** 734 STDMETHODIMP RAChatEventSink::OnSystemMessage(HRESULT, LPCSTR) 735 { 736 return S_OK; 737 } 738 739 //*********************************************************************************************** 740 STDMETHODIMP RAChatEventSink::OnNetStatus( HRESULT hRes ) 741 { 742 // debugprint( ">>> OnNetStatus got: " ); 743 DebugChatDef( hRes ); 744 745 if( !SUCCEEDED( hRes ) ) 746 { 747 // If we are waiting for a server list, this error might indicate that we're not going to 748 // get one, so bail out of waiting for it. 749 bRequestServerListWait = false; 750 // Same for logout. 751 bRequestLogoutWait = false; 752 } 753 754 if( hRes == CHAT_S_CON_DISCONNECTED ) 755 { 756 if( bRequestLogoutWait || !bConnected ) 757 { 758 // Ok. We are waiting to logout or already have. 759 bRequestLogoutWait = false; 760 } 761 else 762 { 763 // Uh oh. We got disconnected unexpectedly. 764 if( pOwner->bInGame ) 765 // Set flag for wolapi destruction if connection is lost during game. 766 pOwner->bConnectionDown = true; 767 else 768 { 769 if( !pOwner->bSelfDestruct ) 770 { 771 // Set flag for wolapi destruction. 772 WWMessageBox().Process( TXT_WOL_WOLAPIGONE ); 773 pOwner->bSelfDestruct = true; 774 } 775 } 776 } 777 } 778 779 return S_OK; 780 } 781 782 //*********************************************************************************************** 783 STDMETHODIMP RAChatEventSink::OnChannelList( HRESULT, Channel* pChannelListIn ) 784 { 785 if( bIgnoreChannelLists ) // Response to channel lists has been temporarily turned off. 786 { 787 // debugprint( ">>> IGNORED OnChannelList, filter = %i, WO's LastUpdateChannelCallLevel = %i \n", ChannelFilter, pOwner->LastUpdateChannelCallLevel ); 788 return S_OK; 789 } 790 791 // Special case for modal GetLobbyChannels(). Because we want to be sure this OnChannelList is one that was caused 792 // by a Request for gametype 0, and not one arriving from an earlier Request for games. 793 // This OnChannelList might not actually match the Request in GetLobbyChannels(), but as long as it's type 0 it'll do. 794 if( bRequestChannelListForLobbiesWait ) 795 { 796 if( pChannelListIn && pChannelListIn->type != 0 ) 797 { 798 // debugprint( ">>> IGNORED OnChannelList, bRequestChannelListForLobbiesWait if\n" ); 799 return S_OK; 800 } 801 // Note: if no channels in list, can't tell what kind of Request call gave us this list. 802 // (In our case assume it was the one asking for lobbies and allow to fail later naturally due to no lobbies available.) 803 } 804 805 DeleteChannelList(); 806 // debugprint( ">>> OnChannelList, filter = %i, WO's LastUpdateChannelCallLevel = %i \n", ChannelFilter, pOwner->LastUpdateChannelCallLevel ); 807 808 int iLobbyCur = iChannelLobbyNumber( (unsigned char*)pOwner->szChannelNameCurrent ); 809 810 Channel* pChannelListTail = NULL; 811 812 // Copy channel list to our own list. 813 while( pChannelListIn ) 814 { 815 // debugprint( "OnChannelList got %s\n", pChannelListIn->name ); 816 switch( ChannelFilter ) 817 { 818 case CHANNELFILTER_OFFICIAL: 819 if( pChannelListIn->official != 1 || iChannelLobbyNumber( pChannelListIn->name ) != -1 ) 820 { 821 // debugprint( "(OnChannelList filtered this one.)\n", pChannelListIn->name ); 822 pChannelListIn = pChannelListIn->next; 823 continue; 824 } 825 break; 826 case CHANNELFILTER_UNOFFICIAL: 827 if( pChannelListIn->official == 1 || iChannelLobbyNumber( pChannelListIn->name ) != -1 ) 828 { 829 // debugprint( "(OnChannelList filtered this one.)\n", pChannelListIn->name ); 830 pChannelListIn = pChannelListIn->next; 831 continue; 832 } 833 break; 834 case CHANNELFILTER_LOBBIES: 835 { 836 int iLobby = iChannelLobbyNumber( pChannelListIn->name ); 837 if( iLobby == -1 ) 838 { 839 // debugprint( "(OnChannelList filtered this one.)\n", pChannelListIn->name ); 840 pChannelListIn = pChannelListIn->next; 841 continue; 842 } 843 break; 844 } 845 case CHANNELFILTER_LOCALLOBBYGAMES: 846 // We are listing games of our type, and may have to filter out non-local-lobby games. 847 if( !pOwner->bAllGamesShown ) 848 { 849 int iGameSourceLobby = pChannelListIn->reserved & 0x00FFFFFF; 850 if( iLobbyCur == -1 || iGameSourceLobby != iLobbyCur ) 851 { 852 pChannelListIn = pChannelListIn->next; 853 continue; 854 } 855 } 856 break; 857 } 858 Channel* pChannelNew = new Channel; 859 *pChannelNew = *pChannelListIn; 860 pChannelNew->next = NULL; // (We don't want the value that was just copied!) 861 if( !pChannelListTail ) 862 { 863 // First channel in list. 864 pChannelList = pChannelNew; // This is the head of our channel list. 865 pChannelListTail = pChannelNew; 866 } 867 else 868 { 869 pChannelListTail->next = pChannelNew; 870 pChannelListTail = pChannelNew; 871 } 872 pChannelListIn = pChannelListIn->next; 873 } 874 875 // bRequestChannelListWait = false; 876 877 if( bRequestChannelListForLobbiesWait ) 878 bRequestChannelListForLobbiesWait = false; 879 else 880 pOwner->OnChannelList(); 881 882 return S_OK; 883 } 884 885 //*********************************************************************************************** 886 void RAChatEventSink::DeleteChannelList() 887 { 888 // Delete all channels allocated on the heap. 889 // pChannelList points to the head element of a linked list of channels, copied during OnChannelList(). 890 // debugprint( "DeleteChannelList\n" ); 891 while( pChannelList ) 892 { 893 Channel* pChannelHead = pChannelList; 894 pChannelList = pChannelHead->next; 895 delete pChannelHead; 896 } 897 } 898 899 //*********************************************************************************************** 900 STDMETHODIMP RAChatEventSink::OnUserList(HRESULT, Channel*, User* pUserListIn ) 901 { 902 // Maintenance of users list is like that for channels list. 903 // debugprint( ">>> OnUserList\n" ); 904 DeleteUserList(); 905 906 // Copy channel list to our own list. 907 while( pUserListIn ) 908 { 909 // debugprint( "OnUserList got %s\n", pUserListIn->name ); 910 User* pUserNew = new User; 911 *pUserNew = *pUserListIn; 912 pUserNew->next = NULL; // (We don't want the value that was just copied!) 913 if( !pUserTail ) 914 { 915 // First User in list. 916 pUserList = pUserNew; // This is the head of our User list. 917 pUserTail = pUserNew; 918 } 919 else 920 { 921 pUserTail->next = pUserNew; 922 pUserTail = pUserNew; 923 } 924 pUserListIn = pUserListIn->next; 925 } 926 927 // bRequestUserListWait = false; 928 return S_OK; 929 } 930 931 //*********************************************************************************************** 932 void RAChatEventSink::DeleteUserList() 933 { 934 // Delete all Users allocated on the heap. 935 // pUserList points to the head element of a linked list of Users, copied during OnUserList(). 936 // debugprint( "DeleteUserList\n" ); 937 while( pUserList ) 938 { 939 User* pUserHead = pUserList; 940 pUserList = pUserHead->next; 941 delete pUserHead; 942 } 943 pUserTail = NULL; 944 } 945 946 947 //*********************************************************************************************** 948 // We got a list of updates to apply 949 // 950 STDMETHODIMP RAChatEventSink::OnUpdateList( HRESULT hRes, Update* pUpdateList ) 951 { 952 // debugprint( ">>> OnUpdateList got: " ); 953 DebugChatDef( hRes ); 954 955 if( !pUpdateList ) // Shouldn't happen. 956 return S_OK; 957 958 // Count the updates. 959 int iUpdates = 0; 960 Update* pUpdate = pUpdateList; 961 962 while( pUpdate != NULL ) 963 { 964 pUpdate = pUpdate->next; 965 ++iUpdates; 966 } 967 // debugprint( "%i updates\n", iUpdates ); 968 969 if( WWMessageBox().Process( TXT_WOL_PATCHQUESTION, TXT_YES, TXT_NO ) == 0 ) 970 { 971 // Get the updates. (I ignore the concept of "optional" downloads here.) 972 if( DownloadUpdates( pUpdateList, iUpdates ) ) 973 pOwner->hresPatchResults = PATCHDOWNLOADED; 974 else 975 pOwner->hresPatchResults = PATCHAVOIDED; 976 } 977 else 978 // User says don't do the download. 979 // Set flag to tell WolapiObject what has happened. 980 pOwner->hresPatchResults = PATCHAVOIDED; 981 982 return S_OK; 983 } 984 985 extern bool WOL_Download_Dialog( IDownload* pDownload, RADownloadEventSink* pDownloadSink, const char* szTitle ); 986 //*********************************************************************************************** 987 bool RAChatEventSink::DownloadUpdates( Update* pUpdateList, int iUpdates ) 988 { 989 // First we create a Download and Download Sink interface object, like Chat and ChatSink. 990 bool bReturn = true; 991 // This is all like WolapiObject::bSetupCOMStuff(). 992 //debugprint( "Do all the COM stuff.\n" ); 993 IDownload* pDownload; 994 CoCreateInstance( CLSID_Download, NULL, CLSCTX_INPROC_SERVER, IID_IDownload, (void**)&pDownload ); 995 _ASSERTE( pDownload ); 996 RADownloadEventSink* pDownloadSink = new RADownloadEventSink(); 997 pDownloadSink->AddRef(); 998 IConnectionPoint* pConnectionPoint = NULL; 999 IConnectionPointContainer* pContainer = NULL; 1000 HRESULT hRes = pDownload->QueryInterface( IID_IConnectionPointContainer, (void**)&pContainer ); 1001 _ASSERTE(SUCCEEDED(hRes)); 1002 hRes = pContainer->FindConnectionPoint( IID_IDownloadEvent, &pConnectionPoint ); 1003 _ASSERTE(SUCCEEDED(hRes)); 1004 DWORD dwDownloadAdvise; 1005 hRes = pConnectionPoint->Advise( (IDownloadEvent*)pDownloadSink, &dwDownloadAdvise ); 1006 _ASSERTE(SUCCEEDED(hRes)); 1007 // Presumably the above calls will succeed, because they did so when we did bSetupComStuff(). 1008 1009 pContainer->Release(); 1010 pConnectionPoint->Release(); 1011 1012 Update* pUpdate = pUpdateList; 1013 int iUpdateCurrent = 0; 1014 // Save current directory. 1015 char szCurDirSave[_MAX_PATH]; 1016 ::GetCurrentDirectory( _MAX_PATH, szCurDirSave ); 1017 while( pUpdate ) 1018 { 1019 ++iUpdateCurrent; 1020 char szTitle[ 120 ]; 1021 sprintf( szTitle, TXT_WOL_DOWNLOADING, iUpdateCurrent, iUpdates ); 1022 char fullpath[ _MAX_PATH ]; 1023 sprintf( fullpath, "%s\\%s", pUpdate->patchpath, pUpdate->patchfile ); 1024 // Downloading in WOLAPI is in a state of disarray somewhat. 1025 // Make sure the destination directory exists, and make it the current directory during the download. 1026 //debugprint( "Switching to %s dir.\n", (char*)pUpdate->localpath ); 1027 if( !::SetCurrentDirectory( (char*)pUpdate->localpath ) ) 1028 { 1029 // Create the destination directory. 1030 // debugprint( "Creating dir.\n" ); 1031 ::CreateDirectory( (char*)pUpdate->localpath, NULL ); 1032 ::SetCurrentDirectory( (char*)pUpdate->localpath ); 1033 } 1034 // Note: Unknown what the reg key value is actually used for... 1035 //debugprint( "Asking to download %s to %s. Server '%s', login '%s', password '%s'\n", fullpath, (char*)pUpdate->patchfile, 1036 // (char*)pUpdate->server, (char*)pUpdate->login, (char*)pUpdate->password ); 1037 pDownload->DownloadFile( (char*)pUpdate->server, (char*)pUpdate->login, (char*)pUpdate->password, fullpath, 1038 (char*)pUpdate->patchfile, Game_Registry_Key() ); 1039 // debugprint( "Call WOL_Download_Dialog()\n" ); 1040 if( !WOL_Download_Dialog( pDownload, pDownloadSink, szTitle ) ) 1041 { 1042 bReturn = false; 1043 break; 1044 } 1045 pUpdate = pUpdate->next; 1046 } 1047 ::SetCurrentDirectory( szCurDirSave ); 1048 1049 // Undo all the COM stuff. 1050 //debugprint( "Undo all the COM stuff.\n" ); 1051 pConnectionPoint = NULL; 1052 pContainer = NULL; 1053 hRes = pDownload->QueryInterface( IID_IConnectionPointContainer, (void**)&pContainer ); 1054 _ASSERTE(SUCCEEDED(hRes)); 1055 hRes = pContainer->FindConnectionPoint( IID_IDownloadEvent, &pConnectionPoint ); 1056 _ASSERTE(SUCCEEDED(hRes)); 1057 pConnectionPoint->Unadvise( dwDownloadAdvise ); 1058 1059 pContainer->Release(); 1060 pConnectionPoint->Release(); 1061 1062 pDownload->Release(); 1063 pDownloadSink->Release(); // This results in pDownloadSink deleting itself for us. 1064 1065 return bReturn; 1066 } 1067 1068 //*********************************************************************************************** 1069 STDMETHODIMP RAChatEventSink::OnServerError( HRESULT hRes ) 1070 { 1071 // debugprint( ">>> OnServerError got: " ); 1072 DebugChatDef( hRes ); 1073 return S_OK; 1074 } 1075 1076 //*********************************************************************************************** 1077 STDMETHODIMP RAChatEventSink::OnMessageOfTheDay(HRESULT, LPCSTR) 1078 { 1079 return S_OK; 1080 } 1081 1082 //*********************************************************************************************** 1083 void RAChatEventSink::ActionEggSound( const char* szMessage ) 1084 { 1085 // Easter egg related. 1086 if( strstr( szMessage, "<<groans>>" ) || strstr( szMessage, "<<groaning>>" ) || 1087 strstr( szMessage, "<<dies>>" ) || strstr( szMessage, "<<dying>>" ) || strstr( szMessage, "<<groan>>" ) || 1088 strstr( szMessage, "<<died>>" ) ) 1089 { 1090 int i = rand() % 30; 1091 if( i == 0 ) 1092 Sound_Effect( VOC_DOG_HURT ); 1093 else if( i == 1 ) 1094 Sound_Effect( VOC_ANTDIE ); 1095 else 1096 Sound_Effect( (VocType)( VOC_SCREAM1 + rand() % 9 ) ); 1097 } 1098 else if( strstr( szMessage, "<<whines>>" ) || strstr( szMessage, "<<whining>>" ) 1099 || strstr( szMessage, "<<bitching>>" ) || strstr( szMessage, "<<whine>>" ) ) 1100 Sound_Effect( VOC_DOG_WHINE ); 1101 else if( strstr( szMessage, "<<shoots>>" ) || strstr( szMessage, "<<shooting>>" ) || 1102 strstr( szMessage, "<<shoot>>" ) || strstr( szMessage, "<<shot>>" ) ) 1103 { 1104 switch( rand() % 6 ) 1105 { 1106 case 0: Sound_Effect( VOC_CANNON1 ); break; 1107 case 1: Sound_Effect( VOC_CANNON2 ); break; 1108 case 2: Sound_Effect( VOC_GUN_RIFLE ); break; 1109 case 3: Sound_Effect( VOC_SILENCER ); break; 1110 case 4: Sound_Effect( VOC_CANNON6 ); break; 1111 case 5: Sound_Effect( VOC_CANNON8 ); break; 1112 } 1113 } 1114 else if( strstr( szMessage, "<<explodes>>" ) || strstr( szMessage, "<<exploding>>" ) || 1115 strstr( szMessage, "<<explode>>" ) || strstr( szMessage, "<<exploded>>" ) || 1116 strstr( szMessage, "<<boom>>" ) || strstr( szMessage, "<<nukes>>" ) ) 1117 { 1118 switch( rand() % 5 ) 1119 { 1120 case 0: Sound_Effect( VOC_KABOOM1 ); break; 1121 case 1: Sound_Effect( VOC_KABOOM12 ); break; 1122 case 2: Sound_Effect( VOC_KABOOM15 ); break; 1123 case 3: Sound_Effect( VOC_KABOOM30 ); break; 1124 case 4: Sound_Effect( VOC_KABOOM25 ); break; 1125 } 1126 } 1127 else if( strstr( szMessage, "<<aye>>" ) || strstr( szMessage, "<<ok>>" ) || 1128 strstr( szMessage, "<<yes>>" ) || strstr( szMessage, "<<yeah>>" ) ) 1129 { 1130 switch( rand() % 8 ) 1131 { 1132 case 0: Sound_Effect( VOC_E_AH ); break; 1133 case 1: Sound_Effect( VOC_E_YES ); break; 1134 case 2: Sound_Effect( VOC_THIEF_YEA ); break; 1135 case 3: Sound_Effect( VOC_SPY_YESSIR ); break; 1136 case 4: Sound_Effect( VOC_SPY_INDEED ); break; 1137 case 5: Sound_Effect( VOC_ENG_YES ); break; 1138 case 6: Sound_Effect( VOC_MED_YESSIR ); break; 1139 case 7: Sound_Effect( VOC_MED_AFFIRM ); break; 1140 } 1141 } 1142 else if( strstr( szMessage, "<<incredible>>" ) || strstr( szMessage, "<<adam>>" ) || strstr( szMessage, "<<Adam>>" )) 1143 Sound_Effect( VOC_E_OK ); 1144 else if( strstr( szMessage, "<<coming>>" )|| strstr( szMessage, "<<on my way>>" ) || strstr( szMessage, "<<moving out>>" ) ) 1145 { 1146 switch( rand() % 5 ) 1147 { 1148 case 0: Sound_Effect( VOC_SPY_ONWAY ); break; 1149 case 1: Sound_Effect( VOC_ENG_MOVEOUT ); break; 1150 case 2: Sound_Effect( VOC_SPY_KING ); break; 1151 case 3: Sound_Effect( VOC_MED_MOVEOUT ); break; 1152 case 4: Sound_Effect( VOC_THIEF_MOVEOUT ); break; 1153 } 1154 } 1155 else if( strstr( szMessage, "<<water>>" ) ) 1156 Sound_Effect( VOC_SPLASH ); 1157 else if( strstr( szMessage, "<<charging>>" ) || strstr( szMessage, "<<powering>>" ) ) 1158 Sound_Effect( VOC_TESLA_POWER_UP ); 1159 else if( strstr( szMessage, "<<zap>>" ) || strstr( szMessage, "<<zaps>>" ) ) 1160 Sound_Effect( VOC_TESLA_ZAP ); 1161 else if( strstr( szMessage, "<<torpedo>>" ) || strstr( szMessage, "<<torpedoes>>" ) ) 1162 Sound_Effect( VOC_TORPEDO ); 1163 else if( strstr( szMessage, "<<appears>>" ) || strstr( szMessage, "<<surfaces>>" ) || strstr( szMessage, "<<emerges>>" )) 1164 Sound_Effect( VOC_SUBSHOW ); 1165 else if( strstr( szMessage, "<<bark>>" ) || strstr( szMessage, "<<barks>>" ) ) 1166 Sound_Effect( VOC_DOG_BARK ); 1167 else if( strstr( szMessage, "<<growl>>" ) || strstr( szMessage, "<<growls>>" ) ) 1168 Sound_Effect( VOC_DOG_GROWL2 ); 1169 else if( strstr( szMessage, "<<chronoshift>>" ) || strstr( szMessage, "<<disappears>>" ) ) 1170 Sound_Effect( VOC_CHRONO ); 1171 else if( strstr( szMessage, "<<crumble>>" ) || strstr( szMessage, "<<crumbles>>" ) || 1172 strstr( szMessage, "<<collapse>>" ) || strstr( szMessage, "<<collapses>>" ) ) 1173 Sound_Effect( VOC_CRUMBLE ); 1174 else if( strstr( szMessage, "<<sell>>" ) || strstr( szMessage, "<<sells>>" ) || 1175 strstr( szMessage, "<<cash>>" ) || strstr( szMessage, "<<money>>" ) ) 1176 Sound_Effect( VOC_CASHTURN ); 1177 else if( strstr( szMessage, "<<heal>>" ) || strstr( szMessage, "<<heals>>" ) ) 1178 Sound_Effect( VOC_HEAL ); 1179 else if( strstr( szMessage, "<<missile>>" ) ) 1180 { 1181 switch( rand() % 3 ) 1182 { 1183 case 0: Sound_Effect( VOC_MISSILE_1 ); break; 1184 case 1: Sound_Effect( VOC_MISSILE_2 ); break; 1185 case 2: Sound_Effect( VOC_MISSILE_3 ); break; 1186 } 1187 } 1188 } 1189 1190 //*********************************************************************************************** 1191 STDMETHODIMP RAChatEventSink::OnPrivateAction( HRESULT, User* pUserSender, LPCSTR szMessage ) 1192 { 1193 // Ignore private messages sent to myself by myself. 1194 if( pUserSender->flags & CHAT_USER_MYSELF ) 1195 return S_OK; 1196 1197 if( *szMessage ) 1198 { 1199 char* szPrint = new char[ strlen( (char*)pUserSender->name ) + strlen( szMessage ) + 116 ]; 1200 sprintf( szPrint, "%s %s %s", TXT_WOL_PRIVATE, (char*)pUserSender->name, szMessage ); 1201 pOwner->PrintMessage( szPrint, WOLCOLORREMAP_ACTION ); 1202 delete [] szPrint; 1203 // Easter egg related. 1204 if( pOwner->bEggSounds ) 1205 ActionEggSound( szMessage ); 1206 } 1207 return S_OK; 1208 } 1209 1210 //*********************************************************************************************** 1211 STDMETHODIMP RAChatEventSink::OnPublicAction( HRESULT, Channel*, User* pUserSender, LPCSTR szMessage ) 1212 { 1213 if( *szMessage ) 1214 { 1215 char* szPrint = new char[ strlen( (char*)pUserSender->name ) + strlen( szMessage ) + 110 ]; 1216 sprintf( szPrint, "%s %s", (char*)pUserSender->name, szMessage ); 1217 pOwner->PrintMessage( szPrint, WOLCOLORREMAP_ACTION ); 1218 delete [] szPrint; 1219 // Easter egg related. 1220 if( pOwner->bEggSounds ) 1221 ActionEggSound( szMessage ); 1222 } 1223 return S_OK; 1224 } 1225 1226 //*********************************************************************************************** 1227 STDMETHODIMP RAChatEventSink::OnPrivateGameOptions( HRESULT, User* pUser, LPCSTR szRequest ) 1228 { 1229 // debugprint( ">>> OnPrivateGameOptions\n" ); 1230 // DebugChatDef( hRes ); 1231 1232 char szRequestCopy[ 600 ]; 1233 strcpy( szRequestCopy, szRequest ); 1234 1235 if( pOwner->pGSupDlg ) 1236 { 1237 if( pOwner->pGSupDlg->bHost ) 1238 pOwner->pGSupDlg->ProcessGuestRequest( pUser, szRequestCopy ); 1239 else 1240 pOwner->pGSupDlg->ProcessInform( szRequestCopy ); // Must be private message to guest from game host. 1241 } 1242 // else 1243 // debugprint( "OnPrivateGameOptions bizarreness.\n" ); 1244 1245 return S_OK; 1246 } 1247 1248 //*********************************************************************************************** 1249 STDMETHODIMP RAChatEventSink::OnPublicGameOptions( HRESULT, Channel*, User*, LPCSTR szInform ) 1250 { 1251 // debugprint( ">>> OnPublicGameOptions: %s\n", szInform ); 1252 1253 char szInformCopy[ 600 ]; 1254 strcpy( szInformCopy, szInform ); 1255 1256 if( pOwner->pGSupDlg ) 1257 { 1258 pOwner->pGSupDlg->ProcessInform( szInformCopy ); 1259 } 1260 // else 1261 // debugprint( "OnPublicGameOptions bizarreness.\n" ); 1262 1263 return S_OK; 1264 } 1265 1266 //*********************************************************************************************** 1267 STDMETHODIMP RAChatEventSink::OnGameStart( HRESULT hRes, Channel*, User* pUserIn, int iGameID ) 1268 { 1269 // Note: All players receive this, not just the host that requested it. 1270 1271 // debugprint( ">>> OnGameStart got: " ); 1272 DebugChatDef( hRes ); 1273 1274 // if( bRequestGameStartWait ) // Implies user is the host that did RequestGameStart(). 1275 // { 1276 1277 // Create the list of users that are actually involved in a game. 1278 // Most likely will always match pUserList, but there is a chance of someone leaving or joining 1279 // at the wrong moment, so from this point on, the pGameUserList is used. 1280 1281 // Note: pUserIPList was added later, for pre-start pinging. It duplicates pGameUserList ip information, 1282 // strictly speaking. 1283 1284 // Delete any existing list. 1285 while( pGameUserList ) 1286 { 1287 User* pGameUserHead = pGameUserList; 1288 pGameUserList = pGameUserList->next; 1289 delete pGameUserHead; 1290 } 1291 // Copy incoming user list. 1292 User* pGameUserListTail = NULL; 1293 while( pUserIn ) 1294 { 1295 // debugprint( "OnGameStart got %s\n", (char*)pUserIn->name ); 1296 User* pUserNew = new User; 1297 *pUserNew = *pUserIn; 1298 pUserNew->next = NULL; // (We don't want the value that was just copied!) 1299 if( !pGameUserListTail ) 1300 { 1301 // First User in list. 1302 pGameUserList = pUserNew; // This is the head of our User list. 1303 pGameUserListTail = pUserNew; 1304 } 1305 else 1306 { 1307 pGameUserListTail->next = pUserNew; 1308 pGameUserListTail = pUserNew; 1309 } 1310 pUserIn = pUserIn->next; 1311 } 1312 1313 bRequestGameStartWait = false; 1314 // } 1315 1316 // debugprint( "iGameID is %i\n", iGameID ); 1317 this->iGameID = iGameID; 1318 1319 return S_OK; 1320 } 1321 1322 //*********************************************************************************************** 1323 unsigned long RAChatEventSink::GetPlayerGameIP( const char* szPlayerName ) const 1324 { 1325 // Returns ipaddr value of player if found in pGameUserList, else 0. 1326 User* pUser = pGameUserList; 1327 while( pUser ) 1328 { 1329 if( _stricmp( (char*)pUser->name, szPlayerName ) == 0 ) 1330 return pUser->ipaddr; 1331 pUser = pUser->next; 1332 } 1333 return 0; 1334 } 1335 1336 //*********************************************************************************************** 1337 STDMETHODIMP RAChatEventSink::OnUserKick( HRESULT hRes, Channel*, User* pUserKicked, User* pUserKicker ) 1338 { 1339 // debugprint( ">>> OnUserKick got: " ); 1340 DebugChatDef( hRes ); 1341 1342 if( hRes == S_OK ) 1343 { 1344 // Someone was kicked. 1345 // Fake a call to OnChannelLeave(), as the processing is identical. 1346 OnChannelLeave( S_OK, NULL, pUserKicked ); 1347 if( pUserKicked->flags & CHAT_USER_MYSELF ) 1348 { 1349 // Trigger a channel exit later on, when we have left this callback. 1350 bGotKickedTrigger = true; 1351 char* szPrint = new char[ strlen( (char*)pUserKicker->name ) + strlen( TXT_WOL_USERKICKEDYOU ) + 5 ]; 1352 sprintf( szPrint, TXT_WOL_USERKICKEDYOU, (char*)pUserKicker->name ); 1353 pOwner->PrintMessage( szPrint, WOLCOLORREMAP_KICKORBAN ); 1354 delete [] szPrint; 1355 // Ensure that the bGotKickedTrigger is acted upon immediately... 1356 pOwner->dwTimeNextWolapiPump = ::timeGetTime(); 1357 } 1358 else 1359 { 1360 char* szPrint = new char[ strlen( (char*)pUserKicker->name ) + strlen( (char*)pUserKicked->name ) + 1361 strlen( TXT_WOL_USERKICKEDUSER ) + 5 ]; 1362 sprintf( szPrint, TXT_WOL_USERKICKEDUSER, (char*)pUserKicker->name, (char*)pUserKicked->name ); 1363 pOwner->PrintMessage( szPrint, WOLCOLORREMAP_KICKORBAN ); 1364 delete [] szPrint; 1365 } 1366 switch( rand() % 4 ) 1367 { 1368 case 0: 1369 Sound_Effect( VOC_TANYA_CHEW ); 1370 break; 1371 case 1: 1372 Sound_Effect( VOC_TANYA_LAUGH ); 1373 break; 1374 case 2: 1375 Sound_Effect( VOC_TANYA_CHING ); 1376 break; 1377 case 3: 1378 Sound_Effect( VOC_TANYA_KISS ); 1379 break; 1380 } 1381 } 1382 else 1383 { 1384 // You tried to kick someone, but the user wasn't found. 1385 // Ignore. 1386 // debugprint( "OnUserKick non S_OK value\n" ); 1387 } 1388 1389 return S_OK; 1390 } 1391 1392 //*********************************************************************************************** 1393 STDMETHODIMP RAChatEventSink::OnUserIP( HRESULT hRes, User* pUser ) 1394 { 1395 // A list of users is kept, separate from other user lists, to preserve the ipaddr's we've found through this 1396 // callback. OnUserList (for some dumb reason) doesn't hold valid ipaddr's, so we have to go through 1397 // all this rigamarole... 1398 // (List is cleared when entering game channel. Users are added initially and on joins, not removed on leaves.) 1399 // debugprint( ">>> OnUserIP got: " ); 1400 DebugChatDef( hRes ); 1401 1402 if( SUCCEEDED( hRes ) ) 1403 { 1404 // Look for user in our current users list. 1405 User* pUserSearch = pUserIPList; 1406 while( pUserSearch ) 1407 { 1408 if( _stricmp( (char*)pUserSearch->name, (char*)pUser->name ) == 0 ) 1409 { 1410 // Found matching user. Replace it's ipaddr value, in case it changed.(?) 1411 pUserSearch->ipaddr = pUser->ipaddr; 1412 return S_OK; 1413 } 1414 pUserSearch = pUserSearch->next; 1415 } 1416 // User not found in current list. Add. 1417 User* pUserNew = new User; 1418 *pUserNew = *pUser; 1419 pUserNew->next = NULL; // (We don't want the value that was just copied!) 1420 if( !pUserIPListTail ) 1421 { 1422 // First user in list. 1423 pUserIPList = pUserNew; // This is the head of our list. 1424 pUserIPListTail = pUserNew; 1425 } 1426 else 1427 { 1428 pUserIPListTail->next = pUserNew; 1429 pUserIPListTail = pUserNew; 1430 } 1431 } 1432 return S_OK; 1433 } 1434 1435 //*********************************************************************************************** 1436 void RAChatEventSink::DeleteUserIPList() 1437 { 1438 // Same as DeleteUserList but for pUserIPList. 1439 // debugprint( "DeleteUserIPList\n" ); 1440 while( pUserIPList ) 1441 { 1442 User* pUserHead = pUserIPList; 1443 pUserIPList = pUserHead->next; 1444 delete pUserHead; 1445 } 1446 pUserIPListTail = NULL; 1447 } 1448 1449 //*********************************************************************************************** 1450 unsigned long RAChatEventSink::GetUserIP( const char* szName ) const 1451 { 1452 // Looks in pUserIPList for the ipaddr of user with name szName. 1453 // This is used only while in game channels. 1454 // This is for step 2 in acquiring fellow player ping times. To get the IP addresses into pUserIPList 1455 // we had to go through request/callbacks. Now pings are requested on these addresses, and the results 1456 // tallied in NetUtilSink for our retrieval later. 1457 // Returns 0 if not found. 1458 1459 // Find szName in list. 1460 User* pUser = pUserIPList; 1461 while( pUser ) 1462 { 1463 if( _stricmp( (char*)pUser->name, szName ) == 0 ) 1464 return pUser->ipaddr; 1465 pUser = pUser->next; 1466 } 1467 return 0; 1468 } 1469 1470 //*********************************************************************************************** 1471 STDMETHODIMP RAChatEventSink::OnServerError(HRESULT , LPCSTR ) 1472 { 1473 return S_OK; 1474 } 1475 1476 //*********************************************************************************************** 1477 STDMETHODIMP RAChatEventSink::OnServerBannedYou(HRESULT , time_t ) 1478 { 1479 return S_OK; 1480 } 1481 1482 //*********************************************************************************************** 1483 STDMETHODIMP RAChatEventSink::OnUserFlags( HRESULT hRes, LPCSTR name, unsigned int flags, unsigned int ) 1484 { 1485 // debugprint( ">>> OnUserFlags got: " ); 1486 DebugChatDef( hRes ); 1487 1488 if( pOwner->CurrentLevel == WOL_LEVEL_INGAMECHANNEL ) 1489 { 1490 if( pOwner->pGSupDlg && 1491 ( pOwner->pGSupDlg->bHostSayGo || pOwner->pGSupDlg->bHostWaitingForGoTrigger || 1492 pOwner->pGSupDlg->bExitForGameTrigger || iGameID ) ) 1493 { 1494 // A game has this moment entered the "must start" phase. We must ignore the fact that others are leaving the channel. 1495 // debugprint( "Ignoring OnUserFlags because game is starting.\n" ); // (Shouldn't ever happen.) 1496 return S_OK; 1497 } 1498 } 1499 1500 // Find user in our current users list. 1501 User* pUserPrior = NULL; 1502 User* pUserSearch = pUserList; 1503 while( pUserSearch ) 1504 { 1505 if( _stricmp( (char*)pUserSearch->name, name ) == 0 ) 1506 { 1507 // Set user's flags to new value. 1508 pUserSearch->flags = flags; 1509 1510 // Remove user from userlist and reinsert appropriately sorted. 1511 if( !pUserPrior ) 1512 { 1513 // User was head of list. 1514 pUserList = pUserSearch->next; 1515 if( pUserSearch == pUserTail ) 1516 // User was also tail of list. 1517 pUserTail = NULL; 1518 else 1519 pUserSearch->next = NULL; 1520 } 1521 else 1522 { 1523 // User was not head of list. 1524 pUserPrior->next = pUserSearch->next; 1525 if( pUserSearch == pUserTail ) 1526 // User was tail of list. 1527 pUserTail = pUserPrior; 1528 else 1529 pUserSearch->next = NULL; 1530 } 1531 InsertUserSorted( pUserSearch ); 1532 1533 // Update shown list. 1534 pOwner->ListChannelUsers(); 1535 break; 1536 } 1537 pUserPrior = pUserSearch; 1538 pUserSearch = pUserSearch->next; 1539 } 1540 1541 return S_OK; 1542 } 1543 1544 //*********************************************************************************************** 1545 STDMETHODIMP RAChatEventSink::OnChannelBan( HRESULT , LPCSTR name, int banned ) 1546 { 1547 if( banned && strcmp( name, "*" ) != 0 ) 1548 { 1549 char* szPrint = new char[ strlen( name ) + strlen( TXT_WOL_USERWASBANNED ) + 5 ]; 1550 sprintf( szPrint, TXT_WOL_USERWASBANNED, name ); 1551 pOwner->PrintMessage( szPrint, WOLCOLORREMAP_KICKORBAN ); 1552 delete [] szPrint; 1553 } 1554 1555 return S_OK; 1556 } 1557 1558 1559 //*********************************************************************************************** 1560 //*********************************************************************************************** 1561 RADownloadEventSink::RADownloadEventSink() : 1562 bFlagEnd( false ), 1563 bFlagError( false ), 1564 bFlagProgressUpdate( false ), 1565 bFlagStatusUpdate( false ), 1566 bFlagQueryResume( false ) 1567 { 1568 m_cRef=0; // Ref counter 1569 } 1570 1571 // Interface IUnknown Methods 1572 //*********************************************************************************************** 1573 // QueryInterface 1574 // 1575 HRESULT __stdcall 1576 RADownloadEventSink::QueryInterface(const IID& iid, void** ppv) 1577 { 1578 if ((iid == IID_IUnknown) ||(iid == IID_IDownloadEvent)) 1579 { 1580 *ppv = (IDownloadEvent*)this; // Removed static_cast<> ajw 1581 } 1582 else 1583 { 1584 *ppv = NULL; 1585 return E_NOINTERFACE; 1586 } 1587 ((IUnknown*)(*ppv))->AddRef(); // Removed reinterpret_cast<> ajw 1588 return S_OK ; 1589 } 1590 1591 //*********************************************************************************************** 1592 // AddRef 1593 // 1594 ULONG __stdcall 1595 RADownloadEventSink::AddRef() 1596 { 1597 return InterlockedIncrement(&m_cRef) ; 1598 } 1599 1600 //*********************************************************************************************** 1601 // Release 1602 // 1603 ULONG __stdcall 1604 RADownloadEventSink::Release() 1605 { 1606 if (InterlockedDecrement(&m_cRef) == 0) 1607 { 1608 delete this ; 1609 return 0 ; 1610 } 1611 return m_cRef; 1612 } 1613 1614 //*********************************************************************************************** 1615 //*********************************************************************************************** 1616 STDMETHODIMP RADownloadEventSink::OnEnd(void) 1617 { 1618 // debugprint( ">>> OnEnd\n" ); 1619 bFlagEnd = true; 1620 return S_OK; 1621 } 1622 1623 //*********************************************************************************************** 1624 STDMETHODIMP RADownloadEventSink::OnError( int /*iCode*/ ) 1625 { 1626 // debugprint( ">>> OnError got: %i\n", iCode ); 1627 //#define DOWNLOADEVENT_NOSUCHSERVER 1 1628 //#define DOWNLOADEVENT_COULDNOTCONNECT 2 1629 //#define DOWNLOADEVENT_LOGINFAILED 3 1630 //#define DOWNLOADEVENT_NOSUCHFILE 4 1631 //#define DOWNLOADEVENT_LOCALFILEOPENFAILED 5 1632 //#define DOWNLOADEVENT_TCPERROR 6 1633 //#define DOWNLOADEVENT_DISCONNECTERROR 7 1634 1635 bFlagError = true; 1636 return S_OK; 1637 } 1638 1639 //*********************************************************************************************** 1640 STDMETHODIMP RADownloadEventSink::OnProgressUpdate( int bytesread, int totalsize, int timetaken, int timeleft ) 1641 { 1642 // debugprint( ">>> OnProgressUpdate\n" ); 1643 bFlagProgressUpdate = true; 1644 1645 iBytesRead = bytesread; 1646 iTotalSize = totalsize; 1647 iTimeTaken = timetaken; 1648 iTimeLeft = timeleft; 1649 1650 return S_OK; 1651 } 1652 1653 //*********************************************************************************************** 1654 STDMETHODIMP RADownloadEventSink::OnStatusUpdate( int status ) 1655 { 1656 // debugprint( ">>> OnStatusUpdate, status = %i\n", status ); 1657 bFlagStatusUpdate = true; 1658 1659 iStatus = status; 1660 1661 return S_OK; 1662 } 1663 1664 //*********************************************************************************************** 1665 // Just tell the FTP module to go ahead and resume 1666 // 1667 STDMETHODIMP RADownloadEventSink::OnQueryResume() 1668 { 1669 // debugprint( ">>> OnQueryResume\n" ); 1670 bFlagQueryResume = true; 1671 1672 bResumed = true; 1673 1674 return DOWNLOADEVENT_RESUME; 1675 } 1676 1677 1678 //*********************************************************************************************** 1679 //*********************************************************************************************** 1680 RANetUtilEventSink::RANetUtilEventSink( WolapiObject* pOwnerIn ) : m_cRef( 0 ), // init the reference count 1681 pOwner( pOwnerIn ), 1682 pLadderList( NULL ), 1683 pLadderTail( NULL ), 1684 pLadderListAM( NULL ), 1685 pLadderTailAM( NULL ) 1686 { 1687 // debugprint( "RANetUtilEventSink constructor\n" ); 1688 } 1689 1690 //*********************************************************************************************** 1691 RANetUtilEventSink::~RANetUtilEventSink() 1692 { 1693 // debugprint( "RANetUtilEventSink destructor\n" ); 1694 DeleteLadderList(); 1695 } 1696 1697 // Interface IUnknown Methods 1698 //*********************************************************************************************** 1699 // QueryInterface 1700 // 1701 HRESULT __stdcall 1702 RANetUtilEventSink::QueryInterface(const IID& iid, void** ppv) 1703 { 1704 // debugprint( "RANetUtilEventSink::QueryInterface\n" ); 1705 if ((iid == IID_IUnknown) ||(iid == IID_INetUtilEvent)) 1706 { 1707 *ppv = (INetUtilEvent*)this; // Removed static_cast<> ajw 1708 } 1709 else 1710 { 1711 *ppv = NULL; 1712 return E_NOINTERFACE; 1713 } 1714 ((IUnknown*)(*ppv))->AddRef(); // Removed reinterpret_cast<> ajw 1715 return S_OK ; 1716 } 1717 1718 //*********************************************************************************************** 1719 // AddRef 1720 // 1721 ULONG __stdcall 1722 RANetUtilEventSink::AddRef() 1723 { 1724 // debugprint( "RANetUtilEventSink::AddRef\n" ); 1725 return InterlockedIncrement(&m_cRef) ; 1726 } 1727 1728 //*********************************************************************************************** 1729 // Release 1730 // 1731 ULONG __stdcall 1732 RANetUtilEventSink::Release() 1733 { 1734 // debugprint( "RANetUtilEventSink::Release\n" ); 1735 if (InterlockedDecrement(&m_cRef) == 0) 1736 { 1737 delete this ; 1738 return 0 ; 1739 } 1740 return m_cRef; 1741 } 1742 1743 //*********************************************************************************************** 1744 STDMETHODIMP RANetUtilEventSink::OnGameresSent( HRESULT hRes ) 1745 { 1746 // debugprint( ">>> OnGameresSent got: " ); 1747 DebugChatDef( hRes ); 1748 return S_OK; 1749 } 1750 1751 //*********************************************************************************************** 1752 STDMETHODIMP RANetUtilEventSink::OnLadderList( HRESULT hRes, Ladder* pLadderListIn, int /*totalCount*/, long /*timeStamp*/, int /*keyRung*/ ) 1753 { 1754 // Maintenance of ladders list is like that for channels list above. 1755 // DeleteLadderList(); -> This is done once, before a set of RequestLadderList() calls are made. 1756 // debugprint( ">>> OnLadderList got: " ); 1757 DebugChatDef( hRes ); 1758 1759 if( SUCCEEDED( hRes ) ) 1760 { 1761 // debugprint( "(SUCCEEDED)\n" ); 1762 // Copy ladder list to our own list. 1763 while( pLadderListIn ) 1764 { 1765 // debugprint( "OnLadderList got %s, rung %u\n", pLadderListIn->login_name, pLadderListIn->rung ); 1766 if( *pLadderListIn->login_name != 0 && pLadderListIn->rung != -1 ) 1767 { 1768 Ladder* pLadderNew = new Ladder; 1769 *pLadderNew = *pLadderListIn; 1770 pLadderNew->next = NULL; // (We don't want the value that was just copied!) 1771 if( pLadderNew->sku == LADDER_CODE_RA ) 1772 { 1773 if( !pLadderTail ) 1774 { 1775 // First Ladder in list. 1776 pLadderList = pLadderNew; // This is the head of our Ladder list. 1777 pLadderTail = pLadderNew; 1778 } 1779 else 1780 { 1781 pLadderTail->next = pLadderNew; 1782 pLadderTail = pLadderNew; 1783 } 1784 if( _stricmp( (char*)pLadderNew->login_name, pOwner->szMyName ) == 0 ) 1785 { 1786 // Set up local player's win/loss string. 1787 sprintf( pOwner->szMyRecord, TXT_WOL_PERSONALWINLOSSRECORD, pOwner->szMyName, 1788 pLadderNew->rung, pLadderNew->wins, pLadderNew->losses, pLadderNew->points ); 1789 pOwner->bMyRecordUpdated = true; 1790 } 1791 } 1792 else // sku must be LADDER_CODE_AM 1793 { 1794 if( !pLadderTailAM ) 1795 { 1796 // First Ladder in list. 1797 pLadderListAM = pLadderNew; // This is the head of our Ladder list. 1798 pLadderTailAM = pLadderNew; 1799 } 1800 else 1801 { 1802 pLadderTailAM->next = pLadderNew; 1803 pLadderTailAM = pLadderNew; 1804 } 1805 if( _stricmp( (char*)pLadderNew->login_name, pOwner->szMyName ) == 0 ) 1806 { 1807 // Set up local player's win/loss string for Aftermath. 1808 sprintf( pOwner->szMyRecordAM, TXT_WOL_PERSONALWINLOSSRECORDAM, pOwner->szMyName, 1809 pLadderNew->rung, pLadderNew->wins, pLadderNew->losses, pLadderNew->points ); 1810 pOwner->bMyRecordUpdated = true; 1811 } 1812 } 1813 } 1814 pLadderListIn = pLadderListIn->next; 1815 } 1816 // Update shown list. 1817 pOwner->ListChannelUsers(); 1818 } 1819 1820 return S_OK; 1821 } 1822 1823 //*********************************************************************************************** 1824 STDMETHODIMP RANetUtilEventSink::OnPing( HRESULT hRes, int time, unsigned long ip, int /*handle*/ ) 1825 { 1826 if( pOwner->bDoingDisconnectPinging ) 1827 { 1828 // debugprint( ">>> OnPing got : ip %i, time %i, ", ip, time ); 1829 DebugChatDef( hRes ); 1830 1831 if( ip == pOwner->TournamentOpponentIP ) 1832 { 1833 // This is the result of the opponent ping. 1834 if( time != -1 ) 1835 pOwner->DisconnectPingResult_Opponent[ pOwner->iDisconnectPingCurrent ] = PING_GOOD; 1836 else 1837 pOwner->DisconnectPingResult_Opponent[ pOwner->iDisconnectPingCurrent ] = PING_BAD; 1838 // debugprint( "Set ping #%i for Opponent\n", pOwner->iDisconnectPingCurrent ); 1839 } 1840 else 1841 { 1842 // This is the result of the game server ping. 1843 if( time != -1 ) 1844 pOwner->DisconnectPingResult_Server[ pOwner->iDisconnectPingCurrent ] = PING_GOOD; 1845 else 1846 pOwner->DisconnectPingResult_Server[ pOwner->iDisconnectPingCurrent ] = PING_BAD; 1847 // debugprint( "Set ping #%i for Server\n", pOwner->iDisconnectPingCurrent ); 1848 } 1849 } 1850 return S_OK; 1851 } 1852 1853 //*********************************************************************************************** 1854 void RANetUtilEventSink::DeleteLadderList() 1855 { 1856 // debugprint( "DeleteLadderList()\n" ); 1857 // Delete all Ladders allocated on the heap. 1858 while( pLadderList ) 1859 { 1860 Ladder* pLadderHead = pLadderList; 1861 pLadderList = pLadderHead->next; 1862 delete pLadderHead; 1863 } 1864 pLadderTail = NULL; 1865 } 1866 1867 //*********************************************************************************************** 1868 unsigned int RANetUtilEventSink::GetUserRank( const char* szName, bool bRankRA ) 1869 { 1870 // Searches for szName in ladder list, returns player rank if found, else 0. 1871 // Slow linear search. 1872 // If bRankRA, returns RA rank, else returns AM rank. 1873 // debugprint( "GetUserRank: Asked for %s, ", szName ); 1874 Ladder* pLad; 1875 if( bRankRA ) 1876 pLad = pLadderList; 1877 else 1878 pLad = pLadderListAM; 1879 1880 while( pLad ) 1881 { 1882 // debugprint( " comparing %s\n", (char*)pLad->login_name ); 1883 if( _stricmp( (char*)pLad->login_name, szName ) == 0 ) 1884 { 1885 // debugprint( "found rung value %u\n", pLad->rung ); 1886 return pLad->rung; 1887 } 1888 pLad = pLad->next; 1889 } 1890 // debugprint( "couldn't find in my ladder list.\n", szName ); 1891 1892 return 0; 1893 } 1894 1895 //*********************************************************************************************** 1896 //*********************************************************************************************** 1897 void ChatDefAsText( char* szDesc, HRESULT hRes ) 1898 { 1899 // Sets szDesc to the text meaning of hRes. 1900 // Make sure szDesc is as long as the longest of the below. 1901 switch( hRes ) 1902 { 1903 case CHAT_E_NICKINUSE : 1904 sprintf( szDesc, "Your nick is still logged into chat" ); 1905 break; 1906 case CHAT_E_BADPASS : 1907 sprintf( szDesc, "Your password is incorrect during login" ); 1908 break; 1909 case CHAT_E_NONESUCH : 1910 sprintf( szDesc, "Reference made to non-existant user or channel" ); 1911 break; 1912 case CHAT_E_CON_NETDOWN : 1913 sprintf( szDesc, "The network layer is down or cannot be initialized for some reason" ); 1914 break; 1915 case CHAT_E_CON_LOOKUP_FAILED : 1916 sprintf( szDesc, "Name lookup (e.g DNS) failed for some reason" ); 1917 break; 1918 case CHAT_E_CON_ERROR : 1919 sprintf( szDesc, "Some fatal error occured with the net connection" ); 1920 break; 1921 case CHAT_E_TIMEOUT : 1922 sprintf( szDesc, "General request timeout for a request" ); 1923 break; 1924 case CHAT_E_MUSTPATCH : 1925 sprintf( szDesc, "Must patch before continuing" ); 1926 break; 1927 case CHAT_E_STATUSERROR : 1928 sprintf( szDesc, "Miscellaneous internal status error" ); 1929 break; 1930 case CHAT_E_UNKNOWNRESPONSE : 1931 sprintf( szDesc, "Server has returned something we don't recognise" ); 1932 break; 1933 case CHAT_E_CHANNELFULL : 1934 sprintf( szDesc, "Tried to join a channel that has enough players already" ); 1935 break; 1936 case CHAT_E_CHANNELEXISTS : 1937 sprintf( szDesc, "Tried to create a channel that already exists" ); 1938 break; 1939 case CHAT_E_CHANNELDOESNOTEXIST : 1940 sprintf( szDesc, "Tried to join a channel that does not exist" ); 1941 break; 1942 case CHAT_E_BADCHANNELPASSWORD : 1943 sprintf( szDesc, "Tried to join a channel with the wrong password" ); 1944 break; 1945 case CHAT_E_BANNED : 1946 sprintf( szDesc, "You've been banned from the server / channel" ); 1947 break; 1948 case CHAT_E_NOT_OPER : 1949 sprintf( szDesc, "You tried to do something that required operator status" ); 1950 break; 1951 1952 case CHAT_S_CON_CONNECTING : 1953 sprintf( szDesc, "A network connection is underway" ); 1954 break; 1955 case CHAT_S_CON_CONNECTED : 1956 sprintf( szDesc, "A network connection is complete" ); 1957 break; 1958 case CHAT_S_CON_DISCONNECTING : 1959 sprintf( szDesc, "A network connection is going down" ); 1960 break; 1961 case CHAT_S_CON_DISCONNECTED : 1962 sprintf( szDesc, "A network connection is closed" ); 1963 break; 1964 case CHAT_S_FIND_NOTHERE : 1965 sprintf( szDesc, "Find - Nick not in system" ); 1966 break; 1967 case CHAT_S_FIND_NOCHAN : 1968 sprintf( szDesc, "Find - Not in any channels" ); 1969 break; 1970 case CHAT_S_FIND_OFF : 1971 sprintf( szDesc, "Find - user has find turned off" ); 1972 break; 1973 case CHAT_S_PAGE_NOTHERE : 1974 sprintf( szDesc, "Page - Nick not in system" ); 1975 break; 1976 case CHAT_S_PAGE_OFF : 1977 sprintf( szDesc, "Page - user has page turned off" ); 1978 break; 1979 case CHAT_E_NOTCONNECTED : 1980 sprintf( szDesc, "You are not connected to the chat server" ); 1981 break; 1982 case CHAT_E_NOCHANNEL : 1983 sprintf( szDesc, "You are not in a channel" ); 1984 break; 1985 case CHAT_E_NOTIMPLEMENTED : 1986 sprintf( szDesc, "Feature is not implemented" ); 1987 break; 1988 case CHAT_E_PENDINGREQUEST : 1989 sprintf( szDesc, "The request was made while while a conflicting request was still pending" ); 1990 break; 1991 case CHAT_E_PARAMERROR : 1992 sprintf( szDesc, "Invalid parameter passed - usually a NULL pointer" ); 1993 break; 1994 case CHAT_E_LEAVECHANNEL : 1995 sprintf( szDesc, "Tried to create or join a channel before leaving the previous one" ); 1996 break; 1997 case CHAT_E_JOINCHANNEL : 1998 sprintf( szDesc, "Tried to send something to a channel when not a member of any channel" ); 1999 break; 2000 case CHAT_E_UNKNOWNCHANNEL : 2001 sprintf( szDesc, "Tried to join a non-existant channel" ); 2002 break; 2003 case S_OK: 2004 sprintf( szDesc, "S_OK" ); 2005 break; 2006 case E_FAIL: 2007 sprintf( szDesc, "E_FAIL" ); 2008 break; 2009 default: 2010 sprintf( szDesc, "ERROR - Value not recognized!" ); 2011 break; 2012 } 2013 // Append NetUtil errors. 2014 switch( hRes ) 2015 { 2016 case NETUTIL_E_ERROR: 2017 strcat( szDesc, " NetUtil: NETUTIL_E_ERROR" ); 2018 break; 2019 case NETUTIL_E_BUSY: 2020 strcat( szDesc, " NetUtil: NETUTIL_E_BUSY" ); 2021 break; 2022 case NETUTIL_S_FINISHED: 2023 strcat( szDesc, " NetUtil: NETUTIL_S_FINISHED" ); 2024 break; 2025 } 2026 } 2027 2028 //*********************************************************************************************** 2029 void DebugChatDef( HRESULT hRes ) 2030 { 2031 char szText[200]; 2032 ChatDefAsText( szText, hRes ); 2033 // debugprint( "%s\n", szText ); 2034 } 2035 2036 //*********************************************************************************************** 2037 int iChannelLobbyNumber( const unsigned char* szChannelName ) 2038 { 2039 // Returns lobby number of channel, or -1 for "channel is not a lobby". 2040 if( strncmp( (char*)szChannelName, LOB_PREFIX, strlen( LOB_PREFIX ) ) == 0 ) 2041 { 2042 char szNum[10]; 2043 strcpy( szNum, (char*)szChannelName + strlen( LOB_PREFIX ) ); 2044 // debugprint( " ^ iChannelLobbyNumber returning atoi of %s\n", szNum ); 2045 return atoi( szNum ); 2046 } 2047 else 2048 return -1; 2049 } 2050 2051 //*********************************************************************************************** 2052 void InterpretLobbyNumber( char* szLobbyNameToSet, int iLobby ) 2053 { 2054 // Hard-coded translation of lobby number to apparent lobby name. 2055 switch( iLobby ) 2056 { 2057 case 0: 2058 strcpy( szLobbyNameToSet, "Combat Alley" ); 2059 break; 2060 case 1: 2061 strcpy( szLobbyNameToSet, "No Man's Land" ); 2062 break; 2063 case 2: 2064 strcpy( szLobbyNameToSet, "Hell's Pass" ); 2065 break; 2066 case 3: 2067 strcpy( szLobbyNameToSet, "Lost Vegas" ); 2068 break; 2069 case 4: 2070 strcpy( szLobbyNameToSet, "Death Valley" ); 2071 break; 2072 case 5: 2073 strcpy( szLobbyNameToSet, "The Wastelands" ); 2074 break; 2075 case 6: 2076 strcpy( szLobbyNameToSet, "Isle of Fury" ); 2077 break; 2078 case 7: 2079 strcpy( szLobbyNameToSet, "Armourgarden" ); 2080 break; 2081 case 8: 2082 strcpy( szLobbyNameToSet, "The Hive" ); 2083 break; 2084 case 9: 2085 strcpy( szLobbyNameToSet, "North by Northwest" ); 2086 break; 2087 case 10: 2088 strcpy( szLobbyNameToSet, "Decatur High" ); 2089 break; 2090 case 11: 2091 strcpy( szLobbyNameToSet, "Damnation Alley" ); 2092 break; 2093 default: 2094 sprintf( szLobbyNameToSet, "%ith Division", iLobby ); 2095 break; 2096 } 2097 } 2098 2099 #endif