// // Copyright 2020 Electronic Arts Inc. // // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free // software: you can redistribute it and/or modify it under the terms of // the GNU General Public License as published by the Free Software Foundation, // either version 3 of the License, or (at your option) any later version. // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed // in the hope that it will be useful, but with permitted additional restrictions // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT // distributed with this program. You should have received a copy of the // GNU General Public License along with permitted additional restrictions // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection #ifdef WOLAPI_INTEGRATION // wol_chat.cpp // ajw 7/8/98 #include "function.h" #include "iconlist.h" #include "WolapiOb.h" #include "SEditDlg.h" #include "WolStrng.h" #include "ToolTip.h" //#include "WolDebug.h" void WOL_PrintMessage( IconListClass& ILTarget, const char* szText, PlayerColorType iColorRemap = PCOLOR_NONE ); void WOL_PrintMessage( IconListClass& ILTarget, const char* szText, RemapControlType* pColorRemap ); bool EnterChannel( WolapiObject* pWO, IconListClass& chatlist, Channel* pChannel, char* szChannelName, bool bGame ); bool EnterChannel( WolapiObject* pWO, IconListClass& chatlist, IconListClass& chanlist, int iIndex, bool bGame ); bool ExitChatChannel( WolapiObject* pWO ); void CreateChatChannel( WolapiObject* pWO ); bool CreateGameChannel( WolapiObject* pWO, const CREATEGAMEINFO& cgi ); bool ProcessChannelListSelection( WolapiObject* pWO, IconListClass& chatlist, IconListClass& chanlist, int iIndex ); enum LIST_EXPAND_STATE { LES_NORMAL, LES_CHANNELS_EXPANDED, LES_USERS_EXPANDED, }; static LIST_EXPAND_STATE lesCurrent = LES_NORMAL; bool OnExpandChannelList( IconListClass& chanlist, IconListClass& userlist ); bool OnExpandUserList( IconListClass& chanlist, IconListClass& userlist ); void ResizeChannelList( IconListClass& chanlist, bool bExpand ); void ResizeUserList( IconListClass& userlist, bool bExpand ); bool bLinkInList( const LinkClass* pListHead, const LinkClass* pLinkToFind ); extern CREATEGAMEINFO WOL_CreateGame_Dialog( WolapiObject* pWO ); static int d_chanlist_w; static int d_chanlist_h; static int d_chanlist_x; static int d_chanlist_y; static int d_userlist_w; static int d_userlist_h; static int d_userlist_x; static int d_userlist_y; #define DRAWTOGDOWN Turn_Off() #define DRAWTOGUP Turn_On() //*********************************************************************************************** int WOL_Chat_Dialog( WolapiObject* pWO ) { int rc; bool bFirsttime = true; bool bHackFocus = true; //------------------------------------------------------------------------ // Dialog & button dimensions //------------------------------------------------------------------------ int d_dialog_w = 320 *RESFACTOR; // dialog width int d_dialog_h = 200 *RESFACTOR; // dialog height int d_dialog_x = ((320*RESFACTOR - d_dialog_w) / 2); // dialog x-coord int d_dialog_y = ((200*RESFACTOR - d_dialog_h) / 2); // centered y-coord int d_dialog_cx = d_dialog_x + (d_dialog_w / 2); // center x-coord int d_text_h = 12; int d_margin1 = 34; // large margin int d_margin2 = 14; // small margin int d_chatlist_w = 340; int d_chatlist_x = d_dialog_x + d_margin1; int d_chatlist_y = d_dialog_y + d_margin2 + d_margin1 + 27; int d_chatlist_h = 337 - d_chatlist_y; d_chanlist_w = 227; d_chanlist_h = 50 * RESFACTOR; d_chanlist_x = d_dialog_x + d_dialog_w - (d_margin1 + d_chanlist_w); d_chanlist_y = d_chatlist_y; d_userlist_w = d_chanlist_w; // int d_userlist_h = ((10 * 6) + 3) *RESFACTOR; d_userlist_x = d_chanlist_x; d_userlist_y = d_chanlist_y + d_chanlist_h + 14 + 5; d_userlist_h = d_chatlist_y + d_chatlist_h - d_userlist_y; int d_action_w = 100; int d_action_h = 9 *RESFACTOR; int d_action_x = d_dialog_x + 500; int d_action_y = 365; // int d_chanpriv_w = 60; // int d_chanpriv_h = 9 *RESFACTOR; // int d_chanpriv_x = d_dialog_x + 150; // int d_chanpriv_y = d_action_y; // int d_cgame_w = 60; // int d_cgame_h = 9 *RESFACTOR; // int d_cgame_x = d_dialog_x + 390; //d_dialog_cx - d_cgame_w / 2; // int d_cgame_y = d_action_y; int d_back_w = 100; int d_back_h = 9 *RESFACTOR; int d_back_x = d_dialog_x + 100; int d_back_y = d_action_y; int d_join_w = 100; int d_join_h = 9 *RESFACTOR; int d_join_x = d_dialog_x + 210; int d_join_y = d_action_y; int d_create_w = 100; int d_create_h = 9 *RESFACTOR; int d_create_x = d_dialog_x + 320; //((d_dialog_w * 5) / 6) - (d_create_w / 2); int d_create_y = d_action_y; int d_send_w = d_chanlist_x + d_chanlist_w - d_chatlist_x; int d_send_h = 9 *RESFACTOR; int d_send_x = d_chatlist_x; int d_send_y = d_chatlist_y + d_chatlist_h + 5; //------------------------------------------------------------------------ // Button Enumerations //------------------------------------------------------------------------ enum { BUTTON_DISCONNECT = 100, // Note: standard WOL button IDs must match values in WolapiObject::PrepareButtonsAndIcons(). BUTTON_LEAVE, BUTTON_REFRESH, BUTTON_SQUELCH, BUTTON_BAN, BUTTON_KICK, BUTTON_FINDPAGE, BUTTON_OPTIONS, BUTTON_LADDER, BUTTON_HELP, BUTTON_CHATLIST, BUTTON_CHANLIST, BUTTON_USERLIST, BUTTON_SENDEDIT, BUTTON_ACTION, // BUTTON_CGAME, BUTTON_CREATE, BUTTON_JOIN, BUTTON_BACK, BUTTON_EXPANDCHANNELS, BUTTON_EXPANDUSERS, BUTTON_RANKRA, BUTTON_RANKAM }; //------------------------------------------------------------------------ // Redraw values: in order from "top" to "bottom" layer of the dialog //------------------------------------------------------------------------ typedef enum { REDRAW_NONE = 0, REDRAW_BACKGROUND, REDRAW_ALL = REDRAW_BACKGROUND } RedrawType; //------------------------------------------------------------------------ // Dialog variables //------------------------------------------------------------------------ RedrawType display = REDRAW_ALL; // redraw level bool process = true; // process while true KeyNumType input; TTimerClass lastclick_timer; int lastclick_idx = 0; // index of item last clicked on RemapControlType * scheme = GadgetClass::Get_Color_Scheme(); //------------------------------------------------------------------------ // Buttons //------------------------------------------------------------------------ GadgetClass *commands; // button list char* pShpExpand = (char*)MFCD::Retrieve( "exp.shp" ); char* pShpUnexpand = (char*)MFCD::Retrieve( "unexp.shp" ); 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 ); ShapeButtonClass ExpandChanBtn( BUTTON_EXPANDCHANNELS, pShpExpand, d_chanlist_x + d_chanlist_w - 17, d_chanlist_y - 14 ); 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 ); ShapeButtonClass ExpandUserBtn( BUTTON_EXPANDUSERS, pShpExpand, d_userlist_x + d_userlist_w - 17, d_userlist_y - 14 ); 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 ); TextButtonClass ActionBtn( BUTTON_ACTION, TXT_WOL_ACTION, TPF_BUTTON, d_action_x, d_action_y, d_action_w ); TextButtonClass CreateBtn( BUTTON_CREATE, TXT_WOL_NEWSOMETHING, TPF_BUTTON, d_create_x, d_create_y, d_create_w ); TextButtonClass JoinBtn( BUTTON_JOIN, TXT_WOL_JOIN, TPF_BUTTON, d_join_x, d_join_y, d_join_w ); TextButtonClass BackBtn( BUTTON_BACK, TXT_WOL_BACK, TPF_BUTTON, d_back_x, d_back_y, d_back_w ); char* szRecordToStartWith; if( pWO->bShowRankRA ) szRecordToStartWith = pWO->szMyRecord; else szRecordToStartWith = pWO->szMyRecordAM; StaticButtonClass chatlistTitle( 0, szRecordToStartWith, TPF_TYPE, d_chatlist_x + 2, d_chatlist_y - 13, d_chatlist_w - 4, 12 ); StaticButtonClass chanlistTitle( 0, "", TPF_TYPE, d_chanlist_x + 2, d_chanlist_y - 16 + 4, d_chanlist_w - 4 - 16, 12 ); StaticButtonClass userlistTitle( 0, TXT_WOL_NOUSERLIST, TPF_TYPE, d_userlist_x + 2, d_userlist_y - 16 + 4, d_userlist_w - 4 - 16 * 4, 12 ); char szSendBuffer[MAXCHATSENDLENGTH] = ""; EditClass sendedit( BUTTON_SENDEDIT, szSendBuffer, MAXCHATSENDLENGTH, TPF_TEXT, d_send_x, d_send_y, d_send_w, d_send_h ); char* pShpRankRA = (char*)MFCD::Retrieve( "rank_ra.shp" ); char* pShpRankAM = (char*)MFCD::Retrieve( "rank_am.shp" ); ShapeButtonClass RankRABtn( BUTTON_RANKRA, pShpRankRA, d_userlist_x + d_userlist_w - ( 16 * 4 + 1 ), d_userlist_y - 14 ); ShapeButtonClass RankAMBtn( BUTTON_RANKAM, pShpRankAM, d_userlist_x + d_userlist_w - ( 16 * 3 + 1 ), d_userlist_y - 14 ); // Change draw behavior of toggle buttons. RankRABtn.ReflectButtonState = true; RankAMBtn.ReflectButtonState = true; // Build the button list. commands = pWO->pShpBtnDiscon; pWO->pShpBtnLeave->Add_Tail(*commands); pWO->pShpBtnRefresh->Add_Tail(*commands); pWO->pShpBtnSquelch->Add_Tail(*commands); pWO->pShpBtnBan->Add_Tail(*commands); pWO->pShpBtnKick->Add_Tail(*commands); pWO->pShpBtnFindpage->Add_Tail(*commands); pWO->pShpBtnOptions->Add_Tail(*commands); pWO->pShpBtnLadder->Add_Tail(*commands); pWO->pShpBtnHelp->Add_Tail(*commands); chatlist.Add_Tail(*commands); ExpandChanBtn.Add_Tail(*commands); chanlist.Add_Tail(*commands); ExpandUserBtn.Add_Tail(*commands); userlist.Add_Tail(*commands); ActionBtn.Add_Tail(*commands); CreateBtn.Add_Tail(*commands); // CreatePrivBtn.Add_Tail(*commands); JoinBtn.Add_Tail(*commands); BackBtn.Add_Tail(*commands); // CGameBtn.Add_Tail(*commands); chatlistTitle.Add_Tail(*commands); chanlistTitle.Add_Tail(*commands); userlistTitle.Add_Tail(*commands); sendedit.Add_Tail(*commands); // Tooltips... DWORD timeToolTipAppear; ToolTipClass* pToolTipHead = NULL; // Head of list of ToolTips that parallels gadget list. ToolTipClass* pToolTipHitLast = NULL; // ToolTip the mouse was last over, or null. ToolTipClass* pToolTip = pToolTipHead = pWO->pTTipDiscon; pToolTip->next = pWO->pTTipLeave; pToolTip = pToolTip->next; pToolTip->next = pWO->pTTipRefresh; pToolTip = pToolTip->next; pToolTip->next = pWO->pTTipSquelch; pToolTip = pToolTip->next; pToolTip->next = pWO->pTTipBan; pToolTip = pToolTip->next; pToolTip->next = pWO->pTTipKick; pToolTip = pToolTip->next; pToolTip->next = pWO->pTTipFindpage; pToolTip = pToolTip->next; pToolTip->next = pWO->pTTipOptions; pToolTip = pToolTip->next; pToolTip->next = pWO->pTTipLadder; pToolTip = pToolTip->next; pToolTip->next = pWO->pTTipHelp; pToolTip = pToolTip->next; ToolTipClass TTipChanExpand( &ExpandChanBtn, TXT_WOL_TTIP_EXPANDLIST, ExpandChanBtn.X + 8, ExpandChanBtn.Y - 9, true ); pToolTip->next = &TTipChanExpand; pToolTip = pToolTip->next; ToolTipClass TTipUserExpand( &ExpandUserBtn, TXT_WOL_TTIP_EXPANDLIST, ExpandUserBtn.X + 8, ExpandUserBtn.Y - 9, true ); pToolTip->next = &TTipUserExpand; pToolTip = pToolTip->next; ToolTipClass TTipChanList( &chanlist, 0, chanlist.X + 1, chanlist.Y + 1, true, true ); pToolTip->next = &TTipChanList; pToolTip = pToolTip->next; ToolTipClass TTipJoin( &JoinBtn, TXT_WOL_TTIP_JOIN, d_join_x + d_join_w/2, d_join_y - 6 ); pToolTip->next = &TTipJoin; pToolTip = pToolTip->next; ToolTipClass TTipBack( &BackBtn, TXT_WOL_TTIP_BACK, d_back_x + d_back_w/2, d_back_y - 6 ); pToolTip->next = &TTipBack; pToolTip = pToolTip->next; ToolTipClass TTipCreate( &CreateBtn, TXT_WOL_TTIP_CREATE, d_create_x + d_create_w/2, d_create_y - 6 ); pToolTip->next = &TTipCreate; pToolTip = pToolTip->next; ToolTipClass TTipAction( &ActionBtn, TXT_WOL_TTIP_ACTION, d_action_x + d_action_w/2, d_action_y - 6, true ); pToolTip->next = &TTipAction; pToolTip = pToolTip->next; ToolTipClass TTipRankRA( &RankRABtn, TXT_WOL_TTIP_RANKRA, RankRABtn.X + 8, RankRABtn.Y - 9, true ); pToolTip->next = &TTipRankRA; pToolTip = pToolTip->next; ToolTipClass TTipRankAM( &RankAMBtn, TXT_WOL_TTIP_RANKAM, RankAMBtn.X + 8, RankAMBtn.Y - 9, true ); pToolTip->next = &TTipRankAM; pToolTip = pToolTip->next; pToolTip->next = NULL; //........................................................................ // List boxes //........................................................................ int tabs[] = { 150 }; // tabs for channel list chanlist.Set_Tabs( tabs ); // Fancy_Text_Print("", 0, 0, scheme, TBLACK, TPF_TEXT); lastclick_timer = 0; // Tell WolapiObject about lists to use for output. // (Sure wish I'd gone against the grain and made this dialog a class...) pWO->LinkToChatDlg( &chatlist, &chanlist, &userlist, &userlistTitle ); if( !pWO->bChatShownBefore ) { // Print message of the day. chatlist.Add_Item( pWO->pChatSink->szMotd, NULL, NULL, ICON_SHAPE ); } else { // We have returned to the chat dialog after being in either game setup or an actual game. pWO->RestoreChat(); pWO->DeleteSavedChat(); if( pWO->bReturningAfterGame ) pWO->RejoinLobbyAfterGame(); else { if( pWO->pChatSink->bGotKickedTrigger ) { // We got kicked out of a game setup. WOL_PrintMessage( chatlist, TXT_WOL_YOUWEREKICKEDFROMGAME, WOLCOLORREMAP_KICKORBAN ); pWO->pChatSink->bGotKickedTrigger = false; } } if( pWO->iLobbyReturnAfterGame != -1 ) { char szChannelToJoin[ WOL_CHANNAME_LEN_MAX ]; //sprintf( szChannelToJoin, "Lob_%i_%i", GAME_TYPE, pWO->iLobbyReturnAfterGame ); sprintf( szChannelToJoin, "%s%i", LOB_PREFIX, pWO->iLobbyReturnAfterGame ); pWO->OnEnteringChatChannel( szChannelToJoin, false, iChannelLobbyNumber( (unsigned char*)szChannelToJoin ) ); } else // Will never happen presumably, if games are always entered via a lobby chat channel. pWO->EnterLevel_Top(); pWO->iLobbyReturnAfterGame = -1; if( pWO->bReturningAfterGame ) { Sound_Effect( WOLSOUND_LOGIN ); pWO->bReturningAfterGame = false; } else Sound_Effect( WOLSOUND_EXITGAME ); } // Cause a refresh of szMyRecord, the string showing my win/loss record. pWO->RequestLadders( pWO->szMyName ); //------------------------------------------------------------------------ // Init Mono Output //------------------------------------------------------------------------ #if(SHOW_MONO) Ipx.Configure_Debug(-1, sizeof (GlobalHeaderType), sizeof(NetCommandType), GlobalPacketNames, 0, 13); Ipx.Mono_Debug_Print(-1,1); #endif //------------------------------------------------------------------------ // Processing loop //------------------------------------------------------------------------ while (process) { #if(SHOW_MONO) Ipx.Mono_Debug_Print(-1,0); #endif // Regularly check for incoming messages from wolapi. if( ::timeGetTime() > pWO->dwTimeNextWolapiPump ) { /* if( pToolTipHitLast && pToolTipHitLast->bShowing ) // Lame hack. Problem is draws that occur in callbacks. { pToolTipHitLast->Unshow(); pWO->pChat->PumpMessages(); pWO->pNetUtil->PumpMessages(); pToolTipHitLast->Show(); } else { pWO->pChat->PumpMessages(); pWO->pNetUtil->PumpMessages(); } */ pWO->pChat->PumpMessages(); pWO->pNetUtil->PumpMessages(); // Special post-callback processing... if( pWO->bSelfDestruct ) { if( pWO->pChatSink->bConnected ) pWO->Logout(); rc = -1; // As if the user logged himself out. process = false; break; } if( pWO->pChatSink->bGotKickedTrigger ) { if( pWO->CurrentLevel == WOL_LEVEL_INCHATCHANNEL ) { pWO->OnExitingChatChannel(); pWO->EnterLevel_UserChat(); } else if( pWO->CurrentLevel == WOL_LEVEL_INLOBBY ) { pWO->OnExitingChatChannel(); pWO->EnterLevel_Lobbies(); } else // Must be WOL_LEVEL_INOFFICIALCHATCHANNEL. { pWO->OnExitingChatChannel(); pWO->EnterLevel_OfficialChat(); } pWO->pChatSink->bGotKickedTrigger = false; display = REDRAW_ALL; } if( pWO->bMyRecordUpdated ) { if( pWO->bShowRankRA ) chatlistTitle.Set_Text( pWO->szMyRecord ); else chatlistTitle.Set_Text( pWO->szMyRecordAM ); pWO->bMyRecordUpdated = false; } if( pWO->bChannelListTitleUpdated ) { chanlistTitle.Set_Text( pWO->szChannelListTitle ); pWO->bChannelListTitleUpdated = false; } pWO->dwTimeNextWolapiPump = ::timeGetTime() + WOLAPIPUMPWAIT; } // Synch rank toggle buttons state. if( BackBtn.Get_Prev() == &RankAMBtn ) { if( pWO->CurrentLevel != WOL_LEVEL_INLOBBY ) { // Rank buttons are there and shouldn't be. RankRABtn.Remove(); RankAMBtn.Remove(); display = REDRAW_ALL; } else { if( pWO->bShowRankUpdated ) { if( pWO->bShowRankRA ) { RankRABtn.DRAWTOGDOWN; RankAMBtn.DRAWTOGUP; } else { RankRABtn.DRAWTOGUP; RankAMBtn.DRAWTOGDOWN; } // Buttons have been refreshed. pWO->bShowRankUpdated = false; // Cause my own record to get refreshed. pWO->bMyRecordUpdated = true; // Refresh list to show different rankings type. pWO->ListChannelUsers(); } } } else { if( pWO->CurrentLevel == WOL_LEVEL_INLOBBY ) { // Rank buttons aren't there and should be. RankRABtn.Add( JoinBtn ); RankAMBtn.Add( RankRABtn ); RankRABtn.Flag_To_Redraw(); RankAMBtn.Flag_To_Redraw(); if( pWO->bShowRankRA ) { RankRABtn.DRAWTOGDOWN; RankAMBtn.DRAWTOGUP; } else { RankRABtn.DRAWTOGUP; RankAMBtn.DRAWTOGDOWN; } // Buttons have been refreshed. pWO->bShowRankUpdated = false; } } // Regularly update the channels list in certain cases. if( ( pWO->CurrentLevel == WOL_LEVEL_OFFICIALCHAT || pWO->CurrentLevel == WOL_LEVEL_USERCHAT || pWO->CurrentLevel == WOL_LEVEL_LOBBIES || pWO->CurrentLevel == WOL_LEVEL_INLOBBY ) && ::timeGetTime() > pWO->dwTimeNextChannelUpdate ) { switch( pWO->CurrentLevel ) { case WOL_LEVEL_OFFICIALCHAT: pWO->UpdateChannels( 0, CHANNELFILTER_OFFICIAL, false ); break; case WOL_LEVEL_USERCHAT: pWO->UpdateChannels( 0, CHANNELFILTER_UNOFFICIAL, false ); break; case WOL_LEVEL_LOBBIES: // Overkill in this case to update so often... pWO->UpdateChannels( 0, CHANNELFILTER_LOBBIES, false ); break; case WOL_LEVEL_INLOBBY: pWO->UpdateChannels( GAME_TYPE, CHANNELFILTER_LOCALLOBBYGAMES, true ); break; } pWO->dwTimeNextChannelUpdate = ::timeGetTime() + CHANNELUPDATEWAIT; } #ifdef WIN32 /* ** If we have just received input focus again after running in the background then ** we need to redraw. */ if (AllSurfaces.SurfacesRestored) { AllSurfaces.SurfacesRestored=FALSE; display = REDRAW_ALL; } #endif if( bFirsttime && !pWO->bChatShownBefore ) { WWMessageBox().Process( TXT_WOL_FINDINGLOBBY, TXT_NONE ); char szLobbyName[ WOL_CHANNAME_LEN_MAX ]; if( pWO->GetNameOfBeginningLobby( szLobbyName ) ) { // debugprint( "Found lobby to go into: '%s'\n", szLobbyName ); if( !EnterChannel( pWO, chatlist, NULL, szLobbyName, false ) ) { // Could not enter channel for some reason. Go to top instead. pWO->EnterLevel_Top(); } } else { // Could not find name of a lobby for some reason. Go to top instead. pWO->EnterLevel_Top(); } pWO->bChatShownBefore = true; display = REDRAW_ALL; // Play login sound. Sound_Effect( WOLSOUND_LOGIN ); } bFirsttime = false; //..................................................................... // Refresh display if needed //..................................................................... if (display) { Hide_Mouse(); //.................................................................. // Redraw backgound & dialog box //.................................................................. if (display >= REDRAW_BACKGROUND) { if( pToolTipHitLast && pToolTipHitLast->bShowing ) { pToolTipHitLast->Unshow(); } Dialog_Box(d_dialog_x, d_dialog_y, d_dialog_w, d_dialog_h); //............................................................... // Dialog & Field labels //............................................................... commands->Draw_All(); // Draw title bar above channel list. Draw_Box( d_chanlist_x, d_chanlist_y - 15, d_chanlist_w, 16, BOXSTYLE_BOX, false ); switch( lesCurrent ) { case LES_CHANNELS_EXPANDED: // Draw users title bar at bottom. Draw_Box( d_userlist_x, d_userlist_y + d_userlist_h - 16, d_userlist_w, 16, BOXSTYLE_BOX, false ); break; case LES_USERS_EXPANDED: // Draw users title bar at top. Draw_Box( d_chanlist_x, d_chanlist_y, d_chanlist_w, 16, BOXSTYLE_BOX, false ); break; default: // Draw users title bar in middle. Draw_Box( d_userlist_x, d_userlist_y - 15, d_userlist_w, 16, BOXSTYLE_BOX, false ); break; } } Show_Mouse(); display = REDRAW_NONE; } // Force mouse visible, as some beta testers report unexplicable disappearing cursors. while( Get_Mouse_State() ) Show_Mouse(); // Be nice to other apps. Sleep( 50 ); //..................................................................... // Get user input //..................................................................... if( ( ::GetAsyncKeyState( KN_LMOUSE ) & 0x8000 ) || ( ::GetAsyncKeyState( KN_RMOUSE ) & 0x8000 ) ) { // Mouse button is down. timeToolTipAppear = ::timeGetTime() + TOOLTIPDELAY; if( pToolTipHitLast && pToolTipHitLast->bShowing ) { pToolTipHitLast->Unshow(); } } // If anything currently on the controls list is set to redraw, hide tooltip. if( pToolTipHitLast && pToolTipHitLast->bShowing && commands->Is_List_To_Redraw() ) { pToolTipHitLast->Unshow(); } input = commands->Input(); // This hack, used elsewhere in this form, appears to be the standard dodge around GadgetClass::Input's // tendency to remove any focus the first time it runs for a 'commands' list. // ajw - Perhaps I could try doing this every cycle regardless - would avoid stupid non-focused editbox key reactions bug. if( bHackFocus ) { sendedit.Set_Focus(); sendedit.Flag_To_Redraw(); input = commands->Input(); bHackFocus = false; } // Tooltips... if( pToolTipHead ) { ToolTipClass* pToolTipHit = pToolTipHead->GetToolTipHit(); if( pToolTipHit == pToolTipHitLast ) { if( pToolTipHit && bLinkInList( commands, pToolTipHit->pGadget ) ) // (Gadget must be in controls list.) { if( !pToolTipHit->bShowing && ::timeGetTime() > timeToolTipAppear && !( ( ::GetAsyncKeyState( KN_LMOUSE ) & 0x8000 ) || ( ::GetAsyncKeyState( KN_RMOUSE ) & 0x8000 ) ) ) { pToolTipHit->Show(); } else if( pToolTipHit->bIconList && pToolTipHit->bOverDifferentLine() ) { pToolTipHit->Unshow(); pToolTipHit->Show(); } } } else { if( pToolTipHitLast && pToolTipHitLast->bShowing ) pToolTipHitLast->Unshow(); pToolTipHitLast = pToolTipHit; timeToolTipAppear = ::timeGetTime() + TOOLTIPDELAY; } } //..................................................................... // Process input //..................................................................... switch (input) { case ( BUTTON_SENDEDIT | KN_BUTTON ): // Enter has been pressed - was caught by sendedit control. if( pWO->CurrentLevel == WOL_LEVEL_INCHATCHANNEL || pWO->CurrentLevel == WOL_LEVEL_INLOBBY ) { pWO->SendMessage( sendedit.Get_Text(), userlist, false ); // Clear sendedit, reset focus. szSendBuffer[0] = 0; sendedit.Set_Focus(); // Mark for redraw. sendedit.Flag_To_Redraw(); } else { WOL_PrintMessage( chatlist, TXT_WOL_YOURENOTINCHANNEL, WOLCOLORREMAP_LOCALMACHINEMESS ); Sound_Effect( WOLSOUND_ERROR ); sendedit.Set_Focus(); // Mark for redraw. sendedit.Flag_To_Redraw(); } break; case KN_LMOUSE: break; case ( BUTTON_EXPANDCHANNELS | KN_BUTTON ): if( OnExpandChannelList( chanlist, userlist ) ) { // Hide userlist. if( ExpandUserBtn.Get_Next() == &userlist ) userlist.Remove(); // Ensure chanlist is visible. if( ExpandChanBtn.Get_Next() != &chanlist ) chanlist.Add( ExpandChanBtn ); // Move userlist expand button. ExpandUserBtn.Set_Position( ExpandUserBtn.X, chanlist.Y + chanlist.Height ); TTipUserExpand.Move( ExpandUserBtn.X + 8, ExpandUserBtn.Y - 16 ); userlistTitle.Set_Position( userlistTitle.X, chanlist.Y + chanlist.Height + 2 ); // Set buttons. ExpandChanBtn.Set_Shape( pShpUnexpand ); ExpandUserBtn.Set_Shape( pShpExpand ); } else { // Show userlist. if( ExpandUserBtn.Get_Next() != &userlist ) userlist.Add( ExpandUserBtn ); // Move userlist expand button. ExpandUserBtn.Set_Position( ExpandUserBtn.X, userlist.Y - 14 ); TTipUserExpand.Move( ExpandUserBtn.X + 8, ExpandUserBtn.Y - 16 ); userlistTitle.Set_Position( userlistTitle.X, userlist.Y - 16 + 4 ); // Set buttons. ExpandChanBtn.Set_Shape( pShpExpand ); ExpandUserBtn.Set_Shape( pShpExpand ); } // Move rank buttons. RankRABtn.Set_Position( RankRABtn.X, ExpandUserBtn.Y ); RankAMBtn.Set_Position( RankAMBtn.X, ExpandUserBtn.Y ); TTipRankRA.Move( RankRABtn.X + 8, RankRABtn.Y - 16 ); TTipRankAM.Move( RankAMBtn.X + 8, RankAMBtn.Y - 16 ); display = REDRAW_ALL; break; case ( BUTTON_EXPANDUSERS | KN_BUTTON ): if( OnExpandUserList( chanlist, userlist ) ) { // Hide chanlist controls. if( ExpandChanBtn.Get_Next() == &chanlist ) chanlist.Remove(); // Ensure userlist is visible. if( ExpandUserBtn.Get_Next() != &userlist ) userlist.Add( ExpandUserBtn ); // Set buttons. ExpandChanBtn.Set_Shape( pShpExpand ); ExpandUserBtn.Set_Shape( pShpUnexpand ); } else { // Show chanlist. if( ExpandChanBtn.Get_Next() != &chanlist ) chanlist.Add( ExpandChanBtn ); // Set buttons. ExpandChanBtn.Set_Shape( pShpExpand ); ExpandUserBtn.Set_Shape( pShpExpand ); } // Move userlist expand button. ExpandUserBtn.Set_Position( ExpandUserBtn.X, userlist.Y - 14 ); TTipUserExpand.Move( ExpandUserBtn.X + 8, ExpandUserBtn.Y - 16 ); userlistTitle.Set_Position( userlistTitle.X, userlist.Y - 16 + 4 ); // Move rank buttons. RankRABtn.Set_Position( RankRABtn.X, ExpandUserBtn.Y ); RankAMBtn.Set_Position( RankAMBtn.X, ExpandUserBtn.Y ); TTipRankRA.Move( RankRABtn.X + 8, RankRABtn.Y - 16 ); TTipRankAM.Move( RankAMBtn.X + 8, RankAMBtn.Y - 16 ); display = REDRAW_ALL; break; case ( BUTTON_CHANLIST | KN_BUTTON ): // User clicks on the game list. //............................................................... // Handle a double-click //............................................................... if( lastclick_timer < 30 && chanlist.Current_Index() == lastclick_idx ) { // Doubleclick on channel list. if( ProcessChannelListSelection( pWO, chatlist, chanlist, lastclick_idx ) ) { // Exit the chat dialog, go to game dialog. rc = 2; process = false; } display = REDRAW_ALL; bHackFocus = true; } else { //............................................................... // Handle a single-click //............................................................... //............................................................ // If no double-click occurred, set the last-clicked index // & double-click timer. //............................................................ lastclick_timer = 0; lastclick_idx = chanlist.Current_Index(); } break; case ( BUTTON_JOIN | KN_BUTTON ): // Pressing the join button is exactly like doubleclicking on the selected index in chanlist, except: // if the first item is selected, ignore, unless we are at the top level if( pWO->CurrentLevel == WOL_LEVEL_TOP || chanlist.Current_Index() != 0 ) { if( ProcessChannelListSelection( pWO, chatlist, chanlist, chanlist.Current_Index() ) ) { // Exit the chat dialog, go to game dialog. rc = 2; process = false; } display = REDRAW_ALL; bHackFocus = true; } break; case ( BUTTON_USERLIST | KN_BUTTON ): // User clicks on user list. break; case ( BUTTON_CREATE | KN_BUTTON ): switch( pWO->CurrentLevel ) { case WOL_LEVEL_INCHATCHANNEL: // debugprint( "%s\n", TXT_WOL_CANTCREATEINCHANNEL ); WOL_PrintMessage( chatlist, TXT_WOL_CANTCREATEINCHANNEL, WOLCOLORREMAP_LOCALMACHINEMESS ); Sound_Effect( WOLSOUND_ERROR ); break; case WOL_LEVEL_INLOBBY: { pWO->bPump_In_Call_Back = true; CREATEGAMEINFO CreateGameInfo = WOL_CreateGame_Dialog( pWO ); pWO->bPump_In_Call_Back = false; if( CreateGameInfo.bCreateGame ) { if( CreateGameChannel( pWO, CreateGameInfo ) ) { rc = 1; process = false; } } break; } case WOL_LEVEL_GAMES: case WOL_LEVEL_GAMESOFTYPE: case WOL_LEVEL_LOBBIES: WOL_PrintMessage( chatlist, TXT_WOL_CANTCREATEHERE, WOLCOLORREMAP_LOCALMACHINEMESS ); Sound_Effect( WOLSOUND_ERROR ); break; default: CreateChatChannel( pWO ); } display = REDRAW_ALL; bHackFocus = true; break; case ( BUTTON_LEAVE | KN_BUTTON ): // Because of the way things are set up, this is exactly like selecting the first item in chanlist. // (Button is disabled when this is not appropriate.) ProcessChannelListSelection( pWO, chatlist, chanlist, 0 ); display = REDRAW_ALL; break; case ( BUTTON_REFRESH | KN_BUTTON ): pWO->dwTimeNextChannelUpdate = ::timeGetTime(); break; case ( BUTTON_SQUELCH | KN_BUTTON ): pWO->DoSquelch( &userlist ); break; case ( BUTTON_BAN | KN_BUTTON ): pWO->DoKick( &userlist, true ); // display = REDRAW_ALL; break; case ( BUTTON_KICK | KN_BUTTON ): pWO->DoKick( &userlist, false ); // display = REDRAW_ALL; break; case ( BUTTON_FINDPAGE | KN_BUTTON ): pWO->DoFindPage(); display = REDRAW_ALL; bHackFocus = true; break; case ( BUTTON_OPTIONS | KN_BUTTON ): pWO->DoOptions(); display = REDRAW_ALL; bHackFocus = true; break; case ( KN_ESC ): // break; ajw Put back in? case ( BUTTON_BACK | KN_BUTTON ): // Pressing the back button is exactly like doubleclicking on the top item in chanlist, except // when we're at the top level. if( pWO->CurrentLevel != WOL_LEVEL_TOP ) { ProcessChannelListSelection( pWO, chatlist, chanlist, 0 ); display = REDRAW_ALL; break; } // Note no break; here. Fall through if at top level. case ( BUTTON_DISCONNECT | KN_BUTTON ): if( WWMessageBox().Process( TXT_WOL_CONFIRMLOGOUT, TXT_YES, TXT_NO ) == 0 ) { if( pWO->CurrentLevel == WOL_LEVEL_INCHATCHANNEL || pWO->CurrentLevel == WOL_LEVEL_INLOBBY ) ExitChatChannel( pWO ); pWO->Logout(); rc = -1; process = false; } display = REDRAW_ALL; bHackFocus = true; break; case ( BUTTON_ACTION | KN_BUTTON ): if( pWO->CurrentLevel == WOL_LEVEL_INCHATCHANNEL || pWO->CurrentLevel == WOL_LEVEL_INLOBBY ) { pWO->SendMessage( sendedit.Get_Text(), userlist, true ); // Clear sendedit, reset focus. szSendBuffer[0] = 0; sendedit.Set_Focus(); // Mark for redraw. //chatlist.Flag_To_Redraw(); sendedit.Flag_To_Redraw(); } else { WOL_PrintMessage( chatlist, TXT_WOL_YOURENOTINCHANNEL, WOLCOLORREMAP_LOCALMACHINEMESS ); Sound_Effect( WOLSOUND_ERROR ); sendedit.Set_Focus(); // Mark for redraw. sendedit.Flag_To_Redraw(); } break; case ( BUTTON_LADDER | KN_BUTTON ): pWO->DoLadder(); display = REDRAW_ALL; bHackFocus = true; break; case ( BUTTON_HELP | KN_BUTTON ): pWO->DoHelp(); display = REDRAW_ALL; bHackFocus = true; break; case ( BUTTON_RANKRA | KN_BUTTON ): pWO->bShowRankRA = true; pWO->bShowRankUpdated = true; break; case ( BUTTON_RANKAM | KN_BUTTON ): pWO->bShowRankRA = false; pWO->bShowRankUpdated = true; break; default: break; } //..................................................................... // Service the sounds & score; GameActive must be false at this point, // so Call_Back() doesn't intercept global messages from me! //..................................................................... Call_Back(); } // end of while if( pToolTipHitLast && pToolTipHitLast->bShowing ) pToolTipHitLast->Unshow(); /* //------------------------------------------------------------------------ // Restore screen //------------------------------------------------------------------------ Hide_Mouse(); Load_Title_Page(true); Show_Mouse(); */ pWO->SaveChat(); pWO->ClearListPtrs(); return rc; } //*********************************************************************************************** void WOL_PrintMessage( IconListClass& ILTarget, const char* szText, PlayerColorType iColorRemap /* = PCOLOR_NONE */ ) { RemapControlType* pColorRemap = ( iColorRemap == PCOLOR_NONE ? NULL : &ColorRemaps[ iColorRemap ] ); WOL_PrintMessage( ILTarget, szText, pColorRemap ); } //*********************************************************************************************** void WOL_PrintMessage( IconListClass& ILTarget, const char* szText, RemapControlType* pColorRemap ) { ILTarget.Add_Item( szText, NULL, NULL, ICON_SHAPE, NULL, NULL, pColorRemap ); if( !ILTarget.bScrollBeingDragged() ) ILTarget.Show_Last_Item(); } //*********************************************************************************************** bool OnExpandChannelList( IconListClass& chanlist, IconListClass& userlist ) { // Expand channel list button was pressed. // Returns true if userlist controls are to be hidden, false if they are to be shown. switch( lesCurrent ) { case LES_NORMAL: ResizeChannelList( chanlist, true ); lesCurrent = LES_CHANNELS_EXPANDED; break; case LES_USERS_EXPANDED: ResizeUserList( userlist, false ); ResizeChannelList( chanlist, true ); lesCurrent = LES_CHANNELS_EXPANDED; break; case LES_CHANNELS_EXPANDED: ResizeChannelList( chanlist, false ); lesCurrent = LES_NORMAL; return false; } return true; } //*********************************************************************************************** bool OnExpandUserList( IconListClass& chanlist, IconListClass& userlist ) { // Expand user list button was pressed. // Returns true if chanlist controls are to be hidden, false if they are to be shown. switch( lesCurrent ) { case LES_NORMAL: ResizeUserList( userlist, true ); lesCurrent = LES_USERS_EXPANDED; break; case LES_CHANNELS_EXPANDED: ResizeChannelList( chanlist, false ); ResizeUserList( userlist, true ); lesCurrent = LES_USERS_EXPANDED; break; case LES_USERS_EXPANDED: ResizeUserList( userlist, false ); lesCurrent = LES_NORMAL; return false; } return true; } //*********************************************************************************************** void ResizeChannelList( IconListClass& chanlist, bool bExpand ) { // If bExpand, makes list big, else normal size. if( bExpand ) chanlist.Resize( d_chanlist_x, d_chanlist_y, d_chanlist_w, d_userlist_y + d_userlist_h - 15 - d_chanlist_y ); else chanlist.Resize( d_chanlist_x, d_chanlist_y, d_chanlist_w, d_chanlist_h ); } //*********************************************************************************************** void ResizeUserList( IconListClass& userlist, bool bExpand ) { // If bExpand, makes list big, else normal size. if( bExpand ) userlist.Resize( d_userlist_x, d_chanlist_y + 15, d_userlist_w, d_userlist_y + d_userlist_h - ( d_chanlist_y + 15 ) ); else userlist.Resize( d_userlist_x, d_userlist_y, d_userlist_w, d_userlist_h ); } //*********************************************************************************************** bool EnterChannel( WolapiObject* pWO, IconListClass& chatlist, IconListClass& chanlist, int iIndex, bool bGame ) { // Enter the channel specified in chanlist at iIndex. // Called to enter chat channels, "lobbies", and game channels. // We've stored the channel pointer in the hidden extra data field. // ( Be careful about calling RAChatEventSink::DeleteChannelList()! ) Channel* pChannel = (Channel*)chanlist.Get_Item_ExtraDataPtr( iIndex ); return EnterChannel( pWO, chatlist, pChannel, NULL, bGame ); } //*********************************************************************************************** bool EnterChannel( WolapiObject* pWO, IconListClass& chatlist, Channel* pChannel, char* szChannelName, bool bGame ) { // Called to cause the user to enter a channel (chat, lobby, or game). // If pChannel is NULL, szChannelName will be used. Channel ChannelWhenNameOnly; if( !pChannel ) { if( !szChannelName ) { // debugprint( "pChannel and szChannelName null in EnterChannel" ); pWO->bSelfDestruct = true; return false; } pChannel = &ChannelWhenNameOnly; strcpy( (char*)pChannel->name, szChannelName ); } if( bGame && pChannel->currentUsers >= pChannel->maxUsers ) // Pre-emptive fullness check. { WOL_PrintMessage( chatlist, TXT_WOL_CHANNELFULL, WOLCOLORREMAP_LOCALMACHINEMESS ); Sound_Effect( WOLSOUND_ERROR ); return false; } if( bGame ) { // It is possible to enter a game channel while currently in a chat channel. (A lobby, presumably.) if( pWO->CurrentLevel == WOL_LEVEL_INCHATCHANNEL || pWO->CurrentLevel == WOL_LEVEL_INLOBBY ) if( !pWO->ExitChatChannelForGameChannel() ) { *pWO->szChannelReturnOnGameEnterFail = 0; // debugprint( "ExitChatChannelForGameChannel on join failed" ); pWO->bSelfDestruct = true; return false; } } /* The following doesn't work because the needpw field is not currently being set in wolapi for chat channels. Instead, we wait for a fail on join, then present this dialog and try again. if( pChannel->needpw ) { SimpleEditDlgClass* pEditDlg = new SimpleEditDlgClass( 300, TXT_WOL_JOINPRIVATETITLE, TXT_WOL_JOINPRIVATEPROMPT, WOL_CHANKEY_LEN_MAX ); if( !pEditDlg->Show() || !*pEditDlg->szEdit ) return false; strcpy( (char*)pChannel->key, pEditDlg->szEdit ); } */ bool bKeepTrying = true; // Set password automatically for our lobbies, if trying to join one. int iLobby = iChannelLobbyNumber( pChannel->name ); if( iLobby != -1 ) strcpy( (char*)pChannel->key, LOBBYPASSWORD ); char szSuccessfulPassword[ WOL_PASSWORD_LEN + 5 ]; *szSuccessfulPassword = 0; HRESULT hRes; while( bKeepTrying ) { hRes = pWO->ChannelJoin( pChannel ); switch( hRes ) { case CHAT_E_BADCHANNELPASSWORD: { Fancy_Text_Print( TXT_NONE, 0, 0, TBLACK, TBLACK, TPF_TEXT ); // Required before String_Pixel_Width() call, for god's sake. #ifdef ENGLISH SimpleEditDlgClass* pEditDlg = new SimpleEditDlgClass( 300, TXT_WOL_JOINPRIVATETITLE, TXT_WOL_JOINPRIVATEPROMPT, WOL_CHANKEY_LEN_MAX ); #else #ifdef GERMAN SimpleEditDlgClass* pEditDlg = new SimpleEditDlgClass( 400, TXT_WOL_JOINPRIVATETITLE, TXT_WOL_JOINPRIVATEPROMPT, WOL_CHANKEY_LEN_MAX ); #else SimpleEditDlgClass* pEditDlg = new SimpleEditDlgClass( 500, TXT_WOL_JOINPRIVATETITLE, TXT_WOL_JOINPRIVATEPROMPT, WOL_CHANKEY_LEN_MAX ); #endif #endif pWO->bPump_In_Call_Back = true; if( strcmp( pEditDlg->Show(), Text_String( TXT_OK ) ) != 0 || !*pEditDlg->szEdit ) { pWO->bPump_In_Call_Back = false; delete pEditDlg; bKeepTrying = false; break; } pWO->bPump_In_Call_Back = false; strcpy( (char*)pChannel->key, pEditDlg->szEdit ); strcpy( szSuccessfulPassword, pEditDlg->szEdit ); delete pEditDlg; break; } case CHAT_E_TIMEOUT: pWO->bPump_In_Call_Back = true; WWMessageBox().Process( TXT_WOL_TIMEOUT ); pWO->bPump_In_Call_Back = false; bKeepTrying = false; break; case CHAT_E_CHANNELDOESNOTEXIST: pWO->bPump_In_Call_Back = true; WWMessageBox().Process( TXT_WOL_CHANNELGONE ); pWO->bPump_In_Call_Back = false; bKeepTrying = false; break; case CHAT_E_BANNED: WOL_PrintMessage( chatlist, TXT_WOL_YOUREBANNED, WOLCOLORREMAP_LOCALMACHINEMESS ); Sound_Effect( WOLSOUND_ERROR ); bKeepTrying = false; break; case CHAT_E_CHANNELFULL: WOL_PrintMessage( chatlist, TXT_WOL_CHANNELFULL, WOLCOLORREMAP_LOCALMACHINEMESS ); Sound_Effect( WOLSOUND_ERROR ); bKeepTrying = false; break; case E_FAIL: pWO->GenericErrorMessage(); bKeepTrying = false; break; case S_OK: bKeepTrying = false; break; } } if( !bGame ) { if( hRes == S_OK ) return pWO->OnEnteringChatChannel( (char*)pChannel->name, false, iLobby ); else return false; } else { if( hRes == S_OK ) { *pWO->szChannelReturnOnGameEnterFail = 0; // Return later to the lobby of the channel creator - which was saved in the channel itself. pWO->iLobbyReturnAfterGame = pChannel->reserved & 0x00FFFFFF; if( pWO->iLobbyReturnAfterGame == 0x00FFFFFF ) pWO->iLobbyReturnAfterGame = -1; CREATEGAMEINFO CreateGameInfo; // Not all of these values are currently used during setup. CreateGameInfo.bCreateGame = false; CreateGameInfo.iPlayerMax = pChannel->maxUsers; CreateGameInfo.bTournament = pChannel->tournament; if( *szSuccessfulPassword ) { CreateGameInfo.bPrivate = true; strcpy( CreateGameInfo.szPassword, szSuccessfulPassword ); } else { CreateGameInfo.bPrivate = false; *CreateGameInfo.szPassword = 0; } CreateGameInfo.GameKind = (CREATEGAMEINFO::GAMEKIND)( pChannel->reserved & 0xFF000000 ); return pWO->OnEnteringGameChannel( (char*)pChannel->name, false, CreateGameInfo ); } else { pWO->OnFailedToEnterGameChannel(); *pWO->szChannelReturnOnGameEnterFail = 0; return false; } } } //*********************************************************************************************** bool ExitChatChannel( WolapiObject* pWO ) { // Called to cause user to leave current chat or lobby channel. // debugprint( "ExitChatChannel\n" ); if( !pWO->ChannelLeave() ) { pWO->GenericErrorMessage(); return false; } pWO->OnExitingChatChannel(); return true; } //*********************************************************************************************** //void CreateChatChannel( WolapiObject* pWO, bool bPrivate ) void CreateChatChannel( WolapiObject* pWO ) { SimpleEditDlgClass* pEditDlg; /* if( !bPrivate ) { pEditDlg = new SimpleEditDlgClass( 300, TXT_WOL_CREATECHANNELTITLE, TXT_WOL_CREATECHANNELPROMPT, WOL_CHANNAME_LEN_MAX ); if( strcmp( pEditDlg->Show(), Text_String( TXT_OK ) ) == 0 && *pEditDlg->szEdit ) { if( pWO->ChannelCreate( pEditDlg->szEdit, NULL ) ) pWO->OnEnteringChatChannel( pEditDlg->szEdit, true, -1 ); } } else */ { Fancy_Text_Print( TXT_NONE, 0, 0, TBLACK, TBLACK, TPF_TEXT ); // Required before String_Pixel_Width() call, for god's sake. pEditDlg = new SimpleEditDlgClass( 350, TXT_WOL_CREATECHANNELTITLE, TXT_WOL_CREATECHANNELPROMPT, WOL_CHANNAME_LEN_MAX, TXT_WOL_OPTIONALPASSPROMPT, WOL_CHANKEY_LEN_MAX ); pWO->bPump_In_Call_Back = true; if( strcmp( pEditDlg->Show(), Text_String( TXT_OK ) ) == 0 && *pEditDlg->szEdit ) { pWO->bPump_In_Call_Back = false; if( *pEditDlg->szEdit2 ) { if( pWO->ChannelCreate( pEditDlg->szEdit, pEditDlg->szEdit2 ) ) pWO->OnEnteringChatChannel( pEditDlg->szEdit, true, -1 ); } else { // Create public channel. if( pWO->ChannelCreate( pEditDlg->szEdit, NULL ) ) pWO->OnEnteringChatChannel( pEditDlg->szEdit, true, -1 ); } } pWO->bPump_In_Call_Back = false; } delete pEditDlg; } //*********************************************************************************************** bool CreateGameChannel( WolapiObject* pWO, const CREATEGAMEINFO& cgi ) { char szNewChannelName[ WOL_CHANNAME_LEN_MAX ]; sprintf( szNewChannelName, "%s's_game", pWO->szMyName ); if( pWO->CurrentLevel == WOL_LEVEL_INCHATCHANNEL || pWO->CurrentLevel == WOL_LEVEL_INLOBBY ) if( !pWO->ExitChatChannelForGameChannel() ) { *pWO->szChannelReturnOnGameEnterFail = 0; // debugprint( "ExitChatChannelForGameChannel in CreateGameChannel() error" ); pWO->bSelfDestruct = true; return false; } const char* szKey; if( *cgi.szPassword ) szKey = cgi.szPassword; else szKey = NULL; if( pWO->ChannelCreate( szNewChannelName, szKey, true, cgi.iPlayerMax, cgi.bTournament, pWO->iLobbyLast, cgi.GameKind ) ) pWO->OnEnteringGameChannel( szNewChannelName, true, cgi ); else { pWO->OnFailedToEnterGameChannel(); // debugprint( "CreateGameChannel fail" ); return false; } *pWO->szChannelReturnOnGameEnterFail = 0; return true; } //*********************************************************************************************** bool ProcessChannelListSelection( WolapiObject* pWO, IconListClass& chatlist, IconListClass& chanlist, int iIndex ) { // Takes whatever action necessary due to user selecting iIndex from chanlist. // Returns true if user selected to enter a game channel, else false. if( iIndex < 0 ) return false; // debugprint( "iIndex %i\n", iIndex ); const char* szChannelType = chanlist.Get_Item_ExtraDataString( iIndex ); if( szChannelType ) { //debugprint( "szChannelType %s\n", szChannelType ); if( strcmp( szChannelType, CHANNELTYPE_OFFICIALCHAT ) == 0 ) { if( pWO->CurrentLevel == WOL_LEVEL_INCHATCHANNEL ) { if( !ExitChatChannel( pWO ) ) { pWO->bSelfDestruct = true; return false; } } pWO->EnterLevel_OfficialChat(); } else if( strcmp( szChannelType, CHANNELTYPE_USERCHAT ) == 0 ) { if( pWO->CurrentLevel == WOL_LEVEL_INCHATCHANNEL ) { if( !ExitChatChannel( pWO ) ) { pWO->bSelfDestruct = true; return false; } } pWO->EnterLevel_UserChat(); } else if( strcmp( szChannelType, CHANNELTYPE_TOP ) == 0 ) { if( pWO->CurrentLevel == WOL_LEVEL_INCHATCHANNEL ) { // Now not possible. if( !ExitChatChannel( pWO ) ) { pWO->bSelfDestruct = true; return false; } } pWO->EnterLevel_Top(); } else if( strcmp( szChannelType, CHANNELTYPE_GAMES ) == 0 ) { if( pWO->CurrentLevel == WOL_LEVEL_INCHATCHANNEL ) { // Now not possible. if( !ExitChatChannel( pWO ) ) { pWO->bSelfDestruct = true; return false; } } pWO->EnterLevel_Games(); } else if( strcmp( szChannelType, CHANNELTYPE_GAMESOFTYPE ) == 0 ) { if( pWO->CurrentLevel == WOL_LEVEL_INCHATCHANNEL ) { // Now not possible. if( !ExitChatChannel( pWO ) ) { pWO->bSelfDestruct = true; return false; } } void* pExtraData = chanlist.Get_Item_ExtraDataPtr( iIndex ); pWO->EnterLevel_GamesOfType( (WOL_GAMETYPEINFO*)pExtraData ); } else if( strcmp( szChannelType, CHANNELTYPE_CHATCHANNEL ) == 0 ) { if( pWO->CurrentLevel == WOL_LEVEL_INCHATCHANNEL ) { // Not currently possible. // debugprint( "Trying to jump from channel to channel?!\n" ); pWO->bSelfDestruct = true; return false; } // Join the chat channel. EnterChannel( pWO, chatlist, chanlist, iIndex, false ); // Can fail. } else if( strcmp( szChannelType, CHANNELTYPE_GAMECHANNEL ) == 0 ) { // User attempting to join game channel. if( pWO->CurrentLevel == WOL_LEVEL_INCHATCHANNEL ) { // Not currently possible. // debugprint( "Trying to jump from channel to channel?!\n" ); pWO->bSelfDestruct = true; return false; } // Check if local user is allowed to join GameKind. Channel* pChannel = (Channel*)chanlist.Get_Item_ExtraDataPtr( iIndex ); if( pChannel->type == GAME_TYPE ) { // It is a game of our type, at least. CREATEGAMEINFO::GAMEKIND GameKind = (CREATEGAMEINFO::GAMEKIND)( pChannel->reserved & 0xFF000000 ); switch( GameKind ) { case CREATEGAMEINFO::RAGAME: break; case CREATEGAMEINFO::CSGAME: if( !Is_Counterstrike_Installed() ) { WOL_PrintMessage( chatlist, TXT_WOL_NEEDCOUNTERSTRIKE, WOLCOLORREMAP_LOCALMACHINEMESS ); Sound_Effect( WOLSOUND_ERROR ); return false; } break; case CREATEGAMEINFO::AMGAME: if( !Is_Aftermath_Installed() ) { WOL_PrintMessage( chatlist, TXT_WOL_NEEDAFTERMATH, WOLCOLORREMAP_LOCALMACHINEMESS ); Sound_Effect( WOLSOUND_ERROR ); return false; } break; default: // debugprint( "Illegal value for GameKind channel reserved field: %s\n", (char*)pChannel->name ); Sound_Effect( WOLSOUND_ERROR ); return false; } // Join the game channel. if( EnterChannel( pWO, chatlist, chanlist, iIndex, true ) ) { // Exit the chat dialog, go to game dialog. return true; } } else { // User doubleclicked on a game that is of a different type. // Offer to take them to a web page regarding the game type. pWO->DoGameAdvertising( pChannel ); } } else if( strcmp( szChannelType, CHANNELTYPE_LOBBIES ) == 0 ) { if( pWO->CurrentLevel == WOL_LEVEL_INCHATCHANNEL ) { // Not currently possible. // debugprint( "Chat channel to lobbies level?!\n" ); pWO->bSelfDestruct = true; return false; } if( pWO->CurrentLevel == WOL_LEVEL_INLOBBY ) { if( !ExitChatChannel( pWO ) ) { pWO->bSelfDestruct = true; return false; } } pWO->EnterLevel_Lobbies(); } else if( strcmp( szChannelType, CHANNELTYPE_LOBBYCHANNEL ) == 0 ) { if( pWO->CurrentLevel == WOL_LEVEL_INCHATCHANNEL || pWO->CurrentLevel == WOL_LEVEL_INLOBBY ) { // Not currently possible. // debugprint( "Chat or lobby channel to lobby channel?!\n" ); pWO->bSelfDestruct = true; return false; } // Join the lobby chat channel. EnterChannel( pWO, chatlist, chanlist, iIndex, false ); // Can fail. } else if( strcmp( szChannelType, CHANNELTYPE_LOADING ) == 0 ) { // User clicked on the channel list loading notification - do nothing. } else { // debugprint( "Item selected in channel list unidentifiable from extradata field\n" ); pWO->bSelfDestruct = true; return false; } } return false; } //*********************************************************************************************** bool bLinkInList( const LinkClass* pListHead, const LinkClass* pLinkToFind ) { const LinkClass* pLink = pListHead; while( pLink ) { if( pLink == pLinkToFind ) return true; pLink = pLink->Get_Next(); } return false; } #endif