1517 lines
40 KiB
C++
1517 lines
40 KiB
C++
|
/*
|
||
|
** Command & Conquer Renegade(tm)
|
||
|
** Copyright 2025 Electronic Arts Inc.
|
||
|
**
|
||
|
** This program 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.
|
||
|
**
|
||
|
** This program is distributed in the hope that it will be useful,
|
||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
** GNU General Public License for more details.
|
||
|
**
|
||
|
** You should have received a copy of the GNU General Public License
|
||
|
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
/***********************************************************************************************
|
||
|
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
|
||
|
***********************************************************************************************
|
||
|
* *
|
||
|
* Project Name : Combat *
|
||
|
* *
|
||
|
* $Archive:: /Commando/Code/Commando/dlgmpwolgamelist.cpp $*
|
||
|
* *
|
||
|
* Author:: Patrick Smith *
|
||
|
* *
|
||
|
* $Modtime:: 11/24/02 4:52p $*
|
||
|
* *
|
||
|
* $Revision:: 76 $*
|
||
|
* *
|
||
|
*---------------------------------------------------------------------------------------------*
|
||
|
* Functions: *
|
||
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||
|
|
||
|
#include "DlgMPWOLGameList.h"
|
||
|
#include "specialbuilds.h"
|
||
|
#include "cNetwork.h"
|
||
|
#include "BandwidthCheck.h"
|
||
|
#include "UserOptions.h"
|
||
|
#include "GameInitMgr.h"
|
||
|
#include "DlgMPWOLPageBuddy.h"
|
||
|
#include "DlgMessageBox.h"
|
||
|
#include "DlgPasswordPrompt.h"
|
||
|
#include <Combat\PlayerType.h>
|
||
|
#include "WOLJoinGame.h"
|
||
|
#include "WOLLogonMgr.h"
|
||
|
#include <WWOnline\WOLServer.h>
|
||
|
#include <WWOnline\WOLChannel.h>
|
||
|
#include <WWUI\DialogMgr.h>
|
||
|
#include <WWUI\ShortcutBarCtrl.h>
|
||
|
#include <WWUI\ButtonCtrl.h>
|
||
|
#include <WWUI\CheckBoxCtrl.h>
|
||
|
#include <WWUI\ListCtrl.h>
|
||
|
#include "String_IDs.h"
|
||
|
#include <WWTranslateDB\TranslateDB.h>
|
||
|
#include "dlgmplanhostoptions.h"
|
||
|
#include "debug.h"
|
||
|
#include "init.h"
|
||
|
|
||
|
using namespace WWOnline;
|
||
|
|
||
|
// Game List columns
|
||
|
static enum
|
||
|
{
|
||
|
COL_ICON = 0,
|
||
|
COL_HOST_NAME,
|
||
|
COL_GAME_TITLE,
|
||
|
COL_GAME_MAP,
|
||
|
COL_PLAYERS,
|
||
|
COL_PING
|
||
|
};
|
||
|
|
||
|
#define CLAN_ENTRY_MARKER 0x0C1A0C1A
|
||
|
|
||
|
#define PING_GREEN_THRESHOLD 655
|
||
|
#define PING_YELLOW_THRESHOLD 2621
|
||
|
|
||
|
// Sorting flags for game attributes
|
||
|
#define FLAGSORT_DEDICATED 0x01
|
||
|
#define FLAGSORT_LADDERED 0x02
|
||
|
#define FLAGSORT_PASSWORDED 0x04
|
||
|
#define FLAGSORT_CLAN 0x08
|
||
|
|
||
|
static void SetGameTypeFlags(ListCtrlClass* list, int itemIndex, const WOLGameInfo& gameInfo);
|
||
|
static void SetPingTimeIcon(ListCtrlClass* list, int itemIndex, long pingTime);
|
||
|
static int CALLBACK FlagsSortCallback(ListCtrlClass* list, int item1, int item2, uint32 param);
|
||
|
static int CALLBACK NumericSortCallback(ListCtrlClass* list, int item1, int item2, uint32 param);
|
||
|
static int CALLBACK AlphaSortCallback(ListCtrlClass* list, int index1, int index2, uint32 param);
|
||
|
|
||
|
|
||
|
MPWolGameListMenuClass* MPWolGameListMenuClass::_mInstance = NULL;
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* MPWolGameListMenuClass::DoDialog
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Display the Westwood Online advanced game listings dialog.
|
||
|
*
|
||
|
* INPUTS
|
||
|
* NONE
|
||
|
*
|
||
|
* RESULT
|
||
|
* NONE
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void MPWolGameListMenuClass::DoDialog(void)
|
||
|
{
|
||
|
// Create the dialog if necessary, otherwise simply bring it to the front
|
||
|
if (_mInstance == NULL)
|
||
|
{
|
||
|
MPWolGameListMenuClass* dialog = new MPWolGameListMenuClass;
|
||
|
WWASSERT(dialog != NULL && "Failed to create WOL GameList dialog");
|
||
|
|
||
|
if (dialog)
|
||
|
{
|
||
|
dialog->Start_Dialog();
|
||
|
dialog->Release_Ref();
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (_mInstance->Is_Active_Menu() == false)
|
||
|
{
|
||
|
DialogMgrClass::Rollback(_mInstance);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* MPWolGameListMenuClass::MPWolGameListMenuClass
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Constructor
|
||
|
*
|
||
|
* INPUTS
|
||
|
* NONE
|
||
|
*
|
||
|
* RESULT
|
||
|
* NONE
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
MPWolGameListMenuClass::MPWolGameListMenuClass(void) :
|
||
|
MenuDialogClass(IDD_MP_WOL_GAME_LIST),
|
||
|
mChannelListPending(false),
|
||
|
mSortColumn(COL_HOST_NAME),
|
||
|
mIsSortAscending(true),
|
||
|
mSortFlags(0)
|
||
|
{
|
||
|
WWDEBUG_SAY(("MPWolGameListMenuClass Instantiated\n"));
|
||
|
WWASSERT(_mInstance == NULL);
|
||
|
_mInstance = this;
|
||
|
|
||
|
mWOLSession = Session::GetInstance(false);
|
||
|
WWASSERT_PRINT(mWOLSession.IsValid(), "WOLSession not instantiated!");
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* MPWolGameListMenuClass::~MPWolGameListMenuClass
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Destructor
|
||
|
*
|
||
|
* INPUTS
|
||
|
* NONE
|
||
|
*
|
||
|
* RESULT
|
||
|
* NONE
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
MPWolGameListMenuClass::~MPWolGameListMenuClass(void)
|
||
|
{
|
||
|
WWDEBUG_SAY(("MPWolGameListMenuClass Destroyed\n"));
|
||
|
_mInstance = NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* MPWolGameListMenuClass::On_Init_Dialog
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* One time dialog initialization
|
||
|
*
|
||
|
* INPUTS
|
||
|
* NONE
|
||
|
*
|
||
|
* RESULT
|
||
|
* NONE
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void MPWolGameListMenuClass::On_Init_Dialog(void)
|
||
|
{
|
||
|
#ifdef FREEDEDICATEDSERVER
|
||
|
Enable_Dlg_Item(IDC_JOIN_GAME_BUTTON, false);
|
||
|
#endif // FREEDEDICATEDSERVER
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// Configure the shortcut bar
|
||
|
//---------------------------------------------------------------------------
|
||
|
ShortcutBarCtrlClass* bar = (ShortcutBarCtrlClass*)Get_Dlg_Item(IDC_SHORTCUT_BAR);
|
||
|
|
||
|
if (bar)
|
||
|
{
|
||
|
bar->Add_Button(IDC_MP_SHORTCUT_CHAT, TRANSLATE(IDS_MP_SHORTCUT_CHAT));
|
||
|
bar->Add_Button(IDC_MP_SHORTCUT_BUDDIES, TRANSLATE(IDS_MP_SHORTCUT_BUDDIES));
|
||
|
bar->Add_Button(IDC_MP_SHORTCUT_INTERNET_OPTIONS, TRANSLATE(IDS_INTERNET_OPTIONS));
|
||
|
bar->Add_Button(IDC_MP_SHORTCUT_NEWS, TRANSLATE(IDS_MP_SHORTCUT_NEWS));
|
||
|
bar->Add_Button(IDC_MP_SHORTCUT_CLANS, TRANSLATE(IDS_MP_SHORTCUT_CLANS));
|
||
|
bar->Add_Button(IDC_MP_SHORTCUT_RANKINGS, TRANSLATE(IDS_MP_SHORTCUT_RANKINGS));
|
||
|
bar->Add_Button(IDC_MP_SHORTCUT_NET_STATUS, TRANSLATE(IDS_MP_SHORTCUT_NET_STATUS));
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// Show the current login and server
|
||
|
//---------------------------------------------------------------------------
|
||
|
WideStringClass serverName(64, true);
|
||
|
WOLLogonMgr::GetServerName(serverName);
|
||
|
|
||
|
WideStringClass string(128, true);
|
||
|
string.Format(TRANSLATE (IDS_MENU_CONNECTED_TO_FORMAT), serverName);
|
||
|
Set_Dlg_Item_Text(IDC_SERVERNAME, string);
|
||
|
|
||
|
WideStringClass loginName(64, true);
|
||
|
WOLLogonMgr::GetLoginName(loginName);
|
||
|
|
||
|
string.Format(TRANSLATE (IDS_MENU_LOGIN_NAME_FORMAT), loginName);
|
||
|
Set_Dlg_Item_Text(IDC_LOGINNAME, string);
|
||
|
|
||
|
WideStringClass conn(BandwidthCheckerClass::Get_Bandwidth_As_String(), true);
|
||
|
string.Format(TRANSLATE (IDS_MENU_SPEED_FORMAT), conn);
|
||
|
Set_Dlg_Item_Text(IDC_CONNECTIONSPEED, string);
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// Configure sorting buttons
|
||
|
//---------------------------------------------------------------------------
|
||
|
ButtonCtrlClass* button = (ButtonCtrlClass*)Get_Dlg_Item(IDC_SORT_DEDICATED_BUTTON);
|
||
|
|
||
|
if (button)
|
||
|
{
|
||
|
button->Set_Bitmap("mul_spec.tga", "mul_nopts.tga");
|
||
|
button->Set_Tooltip_Text(TRANSLATE (IDS_MENU_TOOLTIP_SORT_01));
|
||
|
}
|
||
|
|
||
|
button = (ButtonCtrlClass*)Get_Dlg_Item(IDC_SORT_PASSWORD_BUTTON);
|
||
|
|
||
|
if (button)
|
||
|
{
|
||
|
button->Set_Bitmap("mul_pswrd.tga", "mul_nopts.tga");
|
||
|
button->Set_Tooltip_Text(TRANSLATE (IDS_MENU_TOOLTIP_SORT_02));
|
||
|
}
|
||
|
|
||
|
button = (ButtonCtrlClass*)Get_Dlg_Item(IDC_SORT_LADDERED_BUTTON);
|
||
|
|
||
|
if (button)
|
||
|
{
|
||
|
button->Set_Bitmap("mul_pts.tga", "mul_nopts.tga");
|
||
|
button->Set_Tooltip_Text(TRANSLATE (IDS_MENU_TOOLTIP_SORT_03));
|
||
|
}
|
||
|
|
||
|
button = (ButtonCtrlClass*)Get_Dlg_Item(IDC_SORT_CLAN_BUTTON);
|
||
|
|
||
|
if (button)
|
||
|
{
|
||
|
button->Set_Bitmap("mul_btlcln.tga", "mul_nopts.tga");
|
||
|
button->Set_Tooltip_Text(TRANSLATE (IDS_MENU_TOOLTIP_SORT_04));
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// Configure game listing control
|
||
|
//---------------------------------------------------------------------------
|
||
|
ListCtrlClass* list_ctrl = (ListCtrlClass*)Get_Dlg_Item(IDC_GAME_LIST_CTRL);
|
||
|
|
||
|
if (list_ctrl)
|
||
|
{
|
||
|
Vector3 color(1,1,1);
|
||
|
list_ctrl->Add_Column(TRANSLATE(IDS_MP_GAME_LIST_HEADER_ICON), 0.1F, color);
|
||
|
list_ctrl->Add_Column(TRANSLATE(IDS_MP_GAME_LIST_HEADER_HOST_NAME), 0.175F, color);
|
||
|
list_ctrl->Add_Column(TRANSLATE(IDS_MP_GAME_LIST_HEADER_GAME_NAME), 0.325F, color);
|
||
|
list_ctrl->Add_Column(TRANSLATE(IDS_MP_GAME_LIST_HEADER_GAME_MAP), 0.2F, color);
|
||
|
list_ctrl->Add_Column(TRANSLATE(IDS_MP_GAME_LIST_HEADER_PLAYERS), 0.1F, color);
|
||
|
list_ctrl->Add_Column(TRANSLATE(IDS_MP_GAME_LIST_HEADER_PING), 0.1F, color);
|
||
|
|
||
|
list_ctrl->Allow_NoSelection(true);
|
||
|
|
||
|
Observer<ChannelListEvent>::NotifyMe(*mWOLSession);
|
||
|
Observer<ServerError>::NotifyMe(*mWOLSession);
|
||
|
Observer<SquadEvent>::NotifyMe(*mWOLSession);
|
||
|
|
||
|
RequestGameList();
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// Configure game details list control
|
||
|
//---------------------------------------------------------------------------
|
||
|
list_ctrl = (ListCtrlClass*)Get_Dlg_Item(IDC_DETAILS_LIST);
|
||
|
|
||
|
if (list_ctrl)
|
||
|
{
|
||
|
list_ctrl->Allow_Selection(false);
|
||
|
list_ctrl->Set_Tabstop(20.0f);
|
||
|
}
|
||
|
|
||
|
MenuDialogClass::On_Init_Dialog();
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* MPWolGameListMenuClass::On_Command
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Respond to command messages from UI controls
|
||
|
*
|
||
|
* INPUTS
|
||
|
* ID - ID of control originating the message
|
||
|
* Msg - Message identifier
|
||
|
* Param - Message specific parameter
|
||
|
*
|
||
|
* RESULT
|
||
|
* NONE
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void MPWolGameListMenuClass::On_Command(int id, int msg, DWORD param)
|
||
|
{
|
||
|
switch (id)
|
||
|
{
|
||
|
case IDC_PAGE_BUDDY_BUTTON:
|
||
|
START_DIALOG(MPWolPageBuddyPopupClass);
|
||
|
break;
|
||
|
|
||
|
case IDC_REFRESH_GAME_LIST:
|
||
|
RequestGameList();
|
||
|
break;
|
||
|
|
||
|
case IDC_SORT_DEDICATED_BUTTON:
|
||
|
SortGameChannels(COL_ICON, true, FLAGSORT_DEDICATED);
|
||
|
break;
|
||
|
|
||
|
case IDC_SORT_PASSWORD_BUTTON:
|
||
|
SortGameChannels(COL_ICON, true, FLAGSORT_PASSWORDED);
|
||
|
break;
|
||
|
|
||
|
case IDC_SORT_LADDERED_BUTTON:
|
||
|
SortGameChannels(COL_ICON, true, FLAGSORT_LADDERED);
|
||
|
break;
|
||
|
|
||
|
case IDC_SORT_CLAN_BUTTON:
|
||
|
SortGameChannels(COL_ICON, true, FLAGSORT_CLAN);
|
||
|
break;
|
||
|
|
||
|
case IDC_JOIN_GAME_BUTTON:
|
||
|
Join_Game();
|
||
|
break;
|
||
|
|
||
|
case IDC_MENU_MP_LAN_HOST_BUTTON:
|
||
|
// Return to the game list on exit
|
||
|
GameInitMgrClass::Set_WOL_Return_Dialog(RenegadeDialogMgrClass::LOC_INTERNET_GAME_LIST);
|
||
|
|
||
|
// Create the new game data
|
||
|
if ( PTheGameData != NULL ) {
|
||
|
delete PTheGameData;
|
||
|
PTheGameData = NULL;
|
||
|
}
|
||
|
PTheGameData = cGameData::Create_Game_Of_Type(cGameData::GAME_TYPE_CNC);
|
||
|
WWASSERT(PTheGameData != NULL);
|
||
|
|
||
|
// WOL games default as quickmatch servers
|
||
|
The_Game()->Set_QuickMatch_Server(true);
|
||
|
|
||
|
// Load server preferences.
|
||
|
The_Game()->Load_From_Server_Config();
|
||
|
|
||
|
// Move to the next menu
|
||
|
DialogBaseClass* dialog = new MPLanHostOptionsMenuClass;
|
||
|
dialog->Start_Dialog();
|
||
|
REF_PTR_RELEASE(dialog);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
MenuDialogClass::On_Command(id, msg, param);
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* MPWolGameListMenuClass::On_Key_Down
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
*
|
||
|
* INPUTS
|
||
|
*
|
||
|
* RESULT
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
bool MPWolGameListMenuClass::On_Key_Down(uint32 key_id, uint32 key_data)
|
||
|
{
|
||
|
if (VK_F5 == key_id)
|
||
|
{
|
||
|
RequestGameList();
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return MenuDialogClass::On_Key_Down(key_id, key_data);
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* MPWolGameListMenuClass::Join_Game
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Join the currently selected game
|
||
|
*
|
||
|
* INPUTS
|
||
|
* NONE
|
||
|
*
|
||
|
* RESULT
|
||
|
* NONE
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void MPWolGameListMenuClass::Join_Game(void)
|
||
|
{
|
||
|
ListCtrlClass* list = (ListCtrlClass*)Get_Dlg_Item(IDC_GAME_LIST_CTRL);
|
||
|
|
||
|
if (list)
|
||
|
{
|
||
|
// Get the currently selected index
|
||
|
int index = list->Get_Curr_Sel();
|
||
|
|
||
|
if (index >= 0)
|
||
|
{
|
||
|
RefPtr<ChannelData> channel = (ChannelData*)list->Get_Entry_Data(index, COL_HOST_NAME);
|
||
|
|
||
|
// If the channel is invalid then do not proceed
|
||
|
if (!channel.IsValid())
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
WOLGameInfo selectedGame(channel);
|
||
|
|
||
|
// If the channel data is invalid then do not proceed
|
||
|
if (!selectedGame.IsDataValid())
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// If the user cannot join this game then do not proceed.
|
||
|
if (!selectedGame.CanUserJoin(mWOLSession->GetCurrentUser()))
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Return to the game list on exit
|
||
|
GameInitMgrClass::Set_WOL_Return_Dialog(RenegadeDialogMgrClass::LOC_INTERNET_GAME_LIST);
|
||
|
|
||
|
// If the game to join is passworded then it is necessary for the user to
|
||
|
// supply the correct password. Therefore prompt the user to enter the
|
||
|
// password. We will attempt to connect to the game when we receive a
|
||
|
// signal from the dialog that the user has entered a password.
|
||
|
if (channel->IsPassworded())
|
||
|
{
|
||
|
mGameToJoin = channel;
|
||
|
DlgPasswordPrompt::DoDialog(this);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// No password require
|
||
|
WOLJoinGame::JoinTheGame(channel->GetName(), L"", true);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* MPWolGameListMenuClass::ReceiveSignal
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Handle receipt of password entered signal from the password prompt dialog.
|
||
|
*
|
||
|
* INPUTS
|
||
|
* Signal - Signal that the user has entered a password.
|
||
|
*
|
||
|
* RESULT
|
||
|
* NONE
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void MPWolGameListMenuClass::ReceiveSignal(DlgPasswordPrompt& passwordDialog)
|
||
|
{
|
||
|
if (mGameToJoin.IsValid())
|
||
|
{
|
||
|
WOLJoinGame::JoinTheGame(mGameToJoin->GetName(), passwordDialog.GetPassword(), true);
|
||
|
mGameToJoin.Release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* MPWolGameListMenuClass::RequestGameList
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Submit a request for an updated game list.
|
||
|
*
|
||
|
* INPUTS
|
||
|
* NONE
|
||
|
*
|
||
|
* RESULT
|
||
|
* NONE
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void MPWolGameListMenuClass::RequestGameList(void)
|
||
|
{
|
||
|
if (mChannelListPending == false)
|
||
|
{
|
||
|
if (mWOLSession->RequestGameChannelList())
|
||
|
{
|
||
|
mChannelListPending = true;
|
||
|
Enable_Dlg_Item(IDC_REFRESH_GAME_LIST, false);
|
||
|
|
||
|
ListCtrlClass* list = (ListCtrlClass*)Get_Dlg_Item(IDC_DETAILS_LIST);
|
||
|
|
||
|
if (list)
|
||
|
{
|
||
|
list->Delete_All_Entries();
|
||
|
list->Add_Column(L"", 1.0F, Vector3(1, 1, 1));
|
||
|
list->Insert_Entry(0, TRANSLATE (IDS_MENU_REQUESTING_NEW_CHANNELS));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* MPWolGameListMenuClass::UpdateChannels
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Update the list of game channels.
|
||
|
*
|
||
|
* INPUTS
|
||
|
* List - List control to view channels.
|
||
|
* Channels - List of channels
|
||
|
*
|
||
|
* RESULT
|
||
|
* True if the list changed.
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void MPWolGameListMenuClass::UpdateChannels(ListCtrlClass* list, const ChannelList& chanList)
|
||
|
{
|
||
|
// Get current selection so we can reselect it.
|
||
|
WideStringClass selectedGameName(64, true);
|
||
|
int selIndex = list->Get_Curr_Sel();
|
||
|
|
||
|
if (selIndex >= 0)
|
||
|
{
|
||
|
selectedGameName = list->Get_Entry_Text(selIndex, COL_HOST_NAME);
|
||
|
}
|
||
|
|
||
|
selIndex = -1;
|
||
|
|
||
|
int listIndex = list->Get_Entry_Count();
|
||
|
ChannelList::const_iterator chanIter = chanList.begin();
|
||
|
|
||
|
while (chanIter != chanList.end())
|
||
|
{
|
||
|
RefPtr<ChannelData> channel = (*chanIter);
|
||
|
|
||
|
if (channel.IsValid())
|
||
|
{
|
||
|
WOLGameInfo gameInfo(channel);
|
||
|
|
||
|
// Only show the channel if it is a valid game channel
|
||
|
if (gameInfo.IsDataValid())
|
||
|
{
|
||
|
bool newlyAdded = false;
|
||
|
|
||
|
// Check if the channel entry is already in the listbox.
|
||
|
int itemIndex = list->Find_Entry(COL_HOST_NAME, channel->GetName());
|
||
|
|
||
|
// If the channel was not found then add it now.
|
||
|
if (itemIndex == -1)
|
||
|
{
|
||
|
itemIndex = list->Insert_Entry(listIndex, L"");
|
||
|
newlyAdded = true;
|
||
|
}
|
||
|
|
||
|
// Update the channel in the listbox
|
||
|
if (itemIndex >= 0)
|
||
|
{
|
||
|
// Associate the channel data inside with the entry
|
||
|
if (newlyAdded)
|
||
|
{
|
||
|
ChannelData* rawChannel = channel.ReferencedObject();
|
||
|
rawChannel->AddReference();
|
||
|
list->Set_Entry_Data(itemIndex, COL_HOST_NAME, (unsigned long)rawChannel);
|
||
|
|
||
|
// Show the game channel name
|
||
|
list->Set_Entry_Text(itemIndex, COL_HOST_NAME, channel->GetName());
|
||
|
}
|
||
|
|
||
|
WideStringClass title(0, true);
|
||
|
title.Convert_From(gameInfo.Title());
|
||
|
list->Set_Entry_Text(itemIndex, COL_GAME_TITLE, title);
|
||
|
|
||
|
// Show the game type icons
|
||
|
SetGameTypeFlags(list, itemIndex, gameInfo);
|
||
|
|
||
|
// Show the map name
|
||
|
WideStringClass mapName(64, true);
|
||
|
|
||
|
//
|
||
|
// If this is a mod'd game, then display the mod_name\map_name...
|
||
|
//
|
||
|
if (gameInfo.ModName() != NULL && gameInfo.ModName()[0] != 0) {
|
||
|
|
||
|
//
|
||
|
// Strip off the extension for both the map and the mod package
|
||
|
//
|
||
|
char map_name[_MAX_FNAME] = { 0 };
|
||
|
char mod_name[_MAX_FNAME] = { 0 };
|
||
|
::_splitpath (gameInfo.MapName(), NULL, NULL, map_name, NULL);
|
||
|
::_splitpath (gameInfo.ModName(), NULL, NULL, mod_name, NULL);
|
||
|
|
||
|
//
|
||
|
// Create the map name from the aggregate of the mod and map
|
||
|
//
|
||
|
StringClass ascii_map_name;
|
||
|
ascii_map_name.Format ("%s\\%s", mod_name, map_name);
|
||
|
mapName.Convert_From (ascii_map_name);
|
||
|
} else {
|
||
|
mapName = gameInfo.MapName();
|
||
|
}
|
||
|
|
||
|
list->Set_Entry_Text(itemIndex, COL_GAME_MAP, mapName);
|
||
|
|
||
|
// Show the number of current / max players
|
||
|
list->Set_Entry_Data(itemIndex, COL_PLAYERS, MAKELONG(gameInfo.NumPlayers(), gameInfo.MaxPlayers()));
|
||
|
|
||
|
WideStringClass playersString(64, true);
|
||
|
playersString.Format(L"%u/%u", gameInfo.NumPlayers(), gameInfo.MaxPlayers());
|
||
|
list->Set_Entry_Text(itemIndex, COL_PLAYERS, playersString);
|
||
|
|
||
|
// Show the ping time ranking
|
||
|
SetPingTimeIcon(list, itemIndex, gameInfo.PingTime());
|
||
|
|
||
|
if ((selIndex == -1) && (selectedGameName.Compare_No_Case(channel->GetName()) == 0))
|
||
|
{
|
||
|
selIndex = itemIndex;
|
||
|
}
|
||
|
|
||
|
if (gameInfo.Version() != (unsigned long)cNetwork::Get_Exe_Key() || !gameInfo.IsMapValid())
|
||
|
{
|
||
|
ChannelData* rawChannel = (ChannelData*)list->Get_Entry_Data(itemIndex, COL_HOST_NAME);
|
||
|
|
||
|
if (rawChannel)
|
||
|
{
|
||
|
rawChannel->ReleaseReference();
|
||
|
}
|
||
|
|
||
|
list->Set_Entry_Data(itemIndex, COL_HOST_NAME, 0);
|
||
|
if (gameInfo.IsMapValid()) {
|
||
|
list->Set_Entry_Text(itemIndex, COL_GAME_TITLE, TRANSLATE(IDS_MENU_VERSION_MISMATCH));
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
WideStringClass diagnostic;
|
||
|
diagnostic.Format(L"Version Mismatch (v. %u.%u)",
|
||
|
HIWORD(gameInfo.Version()), LOWORD(gameInfo.Version()));
|
||
|
list->Set_Entry_Text(itemIndex, COL_GAME_TITLE, diagnostic);
|
||
|
*/
|
||
|
|
||
|
Vector3 grey(0.5F, 0.5F, 0.5F);
|
||
|
list->Set_Entry_Color(itemIndex, COL_ICON, grey);
|
||
|
list->Set_Entry_Color(itemIndex, COL_HOST_NAME, grey);
|
||
|
list->Set_Entry_Color(itemIndex, COL_GAME_TITLE, grey);
|
||
|
list->Set_Entry_Color(itemIndex, COL_GAME_MAP, grey);
|
||
|
list->Set_Entry_Color(itemIndex, COL_PLAYERS, grey);
|
||
|
list->Set_Entry_Color(itemIndex, COL_PING, grey);
|
||
|
list->Set_Entry_Data(itemIndex, 0, 0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
++listIndex;
|
||
|
}
|
||
|
|
||
|
++chanIter;
|
||
|
}
|
||
|
|
||
|
// Select the previously selected entry
|
||
|
if ((selIndex != -1) && (list->Get_Entry_Count() > 0))
|
||
|
{
|
||
|
list->Set_Curr_Sel(selIndex);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* MPWolGameListMenuClass::HandleNotification(ChannelListEvent)
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Process the receipt of a game channel list.
|
||
|
*
|
||
|
* INPUTS
|
||
|
* Channels - List of channels
|
||
|
*
|
||
|
* RESULT
|
||
|
* NONE
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void MPWolGameListMenuClass::HandleNotification(ChannelListEvent& event)
|
||
|
{
|
||
|
// Ignore chat channels
|
||
|
if (event.GetChannelType() == 0)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Update the channel listbox
|
||
|
ListCtrlClass* list = (ListCtrlClass*)Get_Dlg_Item(IDC_GAME_LIST_CTRL);
|
||
|
|
||
|
if (list)
|
||
|
{
|
||
|
bool sort = false;
|
||
|
|
||
|
switch (event.GetEvent())
|
||
|
{
|
||
|
default:
|
||
|
case ChannelListEvent::Error:
|
||
|
case ChannelListEvent::NewList:
|
||
|
{
|
||
|
ChannelList& chanList = event.Subject();
|
||
|
bool listEmpty = chanList.empty();
|
||
|
|
||
|
ListCtrlClass* details = (ListCtrlClass*)Get_Dlg_Item(IDC_DETAILS_LIST);
|
||
|
|
||
|
if (details)
|
||
|
{
|
||
|
details->Delete_All_Entries();
|
||
|
|
||
|
if (listEmpty)
|
||
|
{
|
||
|
details->Insert_Entry(0, TRANSLATE(IDS_MENU_NO_GAME_SERVERS_FOUND));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Enable_Dlg_Item(IDC_JOIN_GAME_BUTTON, !listEmpty);
|
||
|
Enable_Dlg_Item(IDC_REFRESH_GAME_LIST, true);
|
||
|
mChannelListPending = false;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case ChannelListEvent::Update:
|
||
|
UpdateChannels(list, event.Subject());
|
||
|
sort = true;
|
||
|
break;
|
||
|
|
||
|
case ChannelListEvent::Remove:
|
||
|
{
|
||
|
ChannelList& chanList = event.Subject();
|
||
|
ChannelList::iterator chanIter = chanList.begin();
|
||
|
|
||
|
while (chanIter != chanList.end())
|
||
|
{
|
||
|
RefPtr<ChannelData> channel = (*chanIter);
|
||
|
int index = list->Find_Entry(COL_HOST_NAME, channel->GetName());
|
||
|
|
||
|
if (index >= 0)
|
||
|
{
|
||
|
list->Delete_Entry(index);
|
||
|
sort = true;
|
||
|
}
|
||
|
|
||
|
++chanIter;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (sort)
|
||
|
{
|
||
|
SortGameChannels(mSortColumn, mIsSortAscending, mSortFlags);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* MPWolGameListMenuClass::On_ListCtrl_Delete_Entry
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Handle the deletion of a listbox entry
|
||
|
*
|
||
|
* INPUTS
|
||
|
* List - Pointer to list control originating notification.
|
||
|
* ID - Identifier of list control originating notification.
|
||
|
* Index - Index of entry being deleted
|
||
|
*
|
||
|
* RESULT
|
||
|
* NONE
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void MPWolGameListMenuClass::On_ListCtrl_Delete_Entry(ListCtrlClass* list, int id, int index)
|
||
|
{
|
||
|
if (IDC_GAME_LIST_CTRL == id)
|
||
|
{
|
||
|
ChannelData* rawChannel = (ChannelData*)list->Get_Entry_Data(index, COL_HOST_NAME);
|
||
|
|
||
|
if (rawChannel)
|
||
|
{
|
||
|
rawChannel->ReleaseReference();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* MPWolGameListMenuClass::On_ListCtrl_Sel_Change
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Handle user selecting a game entry.
|
||
|
*
|
||
|
* INPUTS
|
||
|
* List - Pointer to list control originating notification.
|
||
|
* ID - Identifier of list control originating notification.
|
||
|
* OldSel - Index of previous selection
|
||
|
* NewSel - Index of new selection
|
||
|
*
|
||
|
* RESULT
|
||
|
* NONE
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void MPWolGameListMenuClass::On_ListCtrl_Sel_Change(ListCtrlClass* list, int id, int oldIndex, int newIndex)
|
||
|
{
|
||
|
if (IDC_GAME_LIST_CTRL == id)
|
||
|
{
|
||
|
Enable_Dlg_Item(IDC_JOIN_GAME_BUTTON, false);
|
||
|
|
||
|
mSelectedGame.Reset();
|
||
|
|
||
|
// Clear any detailed game information.
|
||
|
ListCtrlClass* detailsList = (ListCtrlClass*)Get_Dlg_Item(IDC_DETAILS_LIST);
|
||
|
detailsList->Delete_All_Entries();
|
||
|
|
||
|
if (newIndex >= 0)
|
||
|
{
|
||
|
RefPtr<ChannelData> channel = (ChannelData*)list->Get_Entry_Data(newIndex, COL_HOST_NAME);
|
||
|
|
||
|
if (channel.IsValid())
|
||
|
{
|
||
|
mSelectedGame.ImportFromChannel(channel);
|
||
|
|
||
|
if (mSelectedGame.IsDataValid())
|
||
|
{
|
||
|
WideStringClass text(255, true);
|
||
|
|
||
|
// Show host name and exe version
|
||
|
// Denzil 02/14/02 The version encoded in the channel is NOT the printable version.
|
||
|
// Just show the EXE version until we can work this out.
|
||
|
#if(0)
|
||
|
text.Format(TRANSLATE(IDS_MENU_HOST_INFO_FORMAT), (const WCHAR*)channel->GetName(),
|
||
|
mSelectedGame.Title(), HIWORD(mSelectedGame.Version()), LOWORD(mSelectedGame.Version()));
|
||
|
#else
|
||
|
unsigned long verMajor = 0;
|
||
|
unsigned long verMinor = 0;
|
||
|
Get_Version_Number(&verMajor,&verMinor);
|
||
|
|
||
|
text.Format(TRANSLATE(IDS_MENU_HOST_INFO_FORMAT), (const WCHAR*)channel->GetName(),
|
||
|
mSelectedGame.Title(), HIWORD(verMajor), LOWORD(verMajor));
|
||
|
#endif
|
||
|
detailsList->Insert_Entry(0, text);
|
||
|
|
||
|
// If this is a clan game then show the opposing clans
|
||
|
if (mSelectedGame.IsClanGame()) {
|
||
|
GetClanVSClanString(mSelectedGame, text);
|
||
|
int entryIndex = detailsList->Insert_Entry(detailsList->Get_Entry_Count(), text);
|
||
|
detailsList->Set_Entry_Data(entryIndex, 0, CLAN_ENTRY_MARKER);
|
||
|
}
|
||
|
|
||
|
// Show server settings
|
||
|
text.Format(TRANSLATE(IDS_MENU_HOST_OPTIONS_INFO_FORMAT),
|
||
|
mSelectedGame.IsDedicated() ? TRANSLATE(IDS_MENU_TEXT463) : TRANSLATE(IDS_MENU_TEXT464),
|
||
|
mSelectedGame.IsPassworded() ? TRANSLATE(IDS_MENU_TEXT463) : TRANSLATE(IDS_MENU_TEXT464),
|
||
|
mSelectedGame.IsLaddered() ? TRANSLATE(IDS_MENU_TEXT463) : TRANSLATE(IDS_MENU_TEXT464),
|
||
|
mSelectedGame.IsQuickmatch() ? TRANSLATE(IDS_MENU_TEXT463) : TRANSLATE(IDS_MENU_TEXT464));
|
||
|
|
||
|
detailsList->Insert_Entry(detailsList->Get_Entry_Count(), text);
|
||
|
|
||
|
text.Format(TRANSLATE(IDS_MENU_HOST_OPTIONS_INFO2_FORMAT),
|
||
|
mSelectedGame.IsClanGame() ? TRANSLATE (IDS_MENU_ON) : TRANSLATE(IDS_MENU_OFF),
|
||
|
mSelectedGame.IsTeamChange() ? TRANSLATE (IDS_MENU_ON) : TRANSLATE(IDS_MENU_OFF),
|
||
|
mSelectedGame.IsTeamRemix() ? TRANSLATE (IDS_MENU_ON) : TRANSLATE(IDS_MENU_OFF),
|
||
|
mSelectedGame.IsFriendlyFire() ? TRANSLATE (IDS_MENU_ON) : TRANSLATE(IDS_MENU_OFF));
|
||
|
|
||
|
detailsList->Insert_Entry(detailsList->Get_Entry_Count(), text);
|
||
|
|
||
|
text.Format(TRANSLATE(IDS_MENU_HOST_OPTIONS_INFO3_FORMAT),
|
||
|
mSelectedGame.IsDriverGunner() ? TRANSLATE(IDS_MENU_ON) : TRANSLATE(IDS_MENU_OFF),
|
||
|
mSelectedGame.IsSpawnWeapons() ? TRANSLATE(IDS_MENU_ON) : TRANSLATE(IDS_MENU_OFF),
|
||
|
mSelectedGame.IsRepairBuildings() ? TRANSLATE(IDS_MENU_ON) : TRANSLATE(IDS_MENU_OFF));
|
||
|
|
||
|
detailsList->Insert_Entry(detailsList->Get_Entry_Count(), text);
|
||
|
}
|
||
|
|
||
|
bool canJoin = mSelectedGame.CanUserJoin(mWOLSession->GetCurrentUser());
|
||
|
Enable_Dlg_Item(IDC_JOIN_GAME_BUTTON, canJoin);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* MPWolGameListMenuClass::
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
*
|
||
|
* INPUTS
|
||
|
*
|
||
|
* RESULT
|
||
|
* NONE
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void MPWolGameListMenuClass::GetClanVSClanString(WOLGameInfo& gameInfo, WideStringClass& text)
|
||
|
{
|
||
|
const char* clan1Name = "____";
|
||
|
const char* clan2Name = "____";
|
||
|
|
||
|
RefPtr<SquadData> clan = SquadData::FindByID(gameInfo.ClanID1());
|
||
|
|
||
|
if (clan.IsValid())
|
||
|
{
|
||
|
clan1Name = clan->GetName();
|
||
|
}
|
||
|
else if (gameInfo.ClanID1() != 0)
|
||
|
{
|
||
|
clan1Name = "????";
|
||
|
mWOLSession->RequestSquadInfoByID(gameInfo.ClanID1());
|
||
|
}
|
||
|
|
||
|
clan = SquadData::FindByID(gameInfo.ClanID2());
|
||
|
|
||
|
if (clan.IsValid())
|
||
|
{
|
||
|
clan2Name = clan->GetName();
|
||
|
}
|
||
|
else if (gameInfo.ClanID2() != 0)
|
||
|
{
|
||
|
clan2Name = "????";
|
||
|
mWOLSession->RequestSquadInfoByID(gameInfo.ClanID2());
|
||
|
}
|
||
|
|
||
|
text.Format(L"%S -VS- %S", clan1Name, clan2Name);
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* MPWolGameListMenuClass::On_ListCtrl_Column_Click
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Respond to user clicking on a column header of a list control.
|
||
|
*
|
||
|
* INPUTS
|
||
|
* List - Pointer to list control originating notification.
|
||
|
* ID - Identifier of list control originating notification.
|
||
|
* Column - Number of column clicked.
|
||
|
*
|
||
|
* RESULT
|
||
|
* NONE
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void MPWolGameListMenuClass::On_ListCtrl_Column_Click(ListCtrlClass* list, int id, int column)
|
||
|
{
|
||
|
if (IDC_GAME_LIST_CTRL == id)
|
||
|
{
|
||
|
// If clicking the same column then toggle ascending / descending
|
||
|
if (mSortColumn == column)
|
||
|
{
|
||
|
SortGameChannels(column, !mIsSortAscending, mSortFlags);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SortGameChannels(column, true, mSortFlags);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* MPWolGameListMenuClass::On_ListCtrl_DblClk
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Automatically attempt to join a game if the user double-clicks on the
|
||
|
* game entry.
|
||
|
*
|
||
|
* INPUTS
|
||
|
* List - List control
|
||
|
* ID - Identifier of list control
|
||
|
* Index - Entry index double-clicked
|
||
|
*
|
||
|
* RESULT
|
||
|
* NONE
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void MPWolGameListMenuClass::On_ListCtrl_DblClk(ListCtrlClass* list, int id, int index)
|
||
|
{
|
||
|
if (IDC_GAME_LIST_CTRL == id)
|
||
|
{
|
||
|
Join_Game();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* On_Last_Menu_Ending
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Callback from menu class signifying the close of the last menu
|
||
|
*
|
||
|
* INPUTS
|
||
|
*
|
||
|
* RESULT
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void MPWolGameListMenuClass::On_Last_Menu_Ending (void)
|
||
|
{
|
||
|
RenegadeDialogMgrClass::Goto_Location(RenegadeDialogMgrClass::LOC_INTERNET_MAIN);
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* MPWolGameListMenuClass::HandleNotification(ServerError)
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Handle server error notifications from WWOnline session.
|
||
|
*
|
||
|
* INPUTS
|
||
|
* Error - Server error
|
||
|
*
|
||
|
* RESULT
|
||
|
* NONE
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void MPWolGameListMenuClass::HandleNotification(ServerError& error)
|
||
|
{
|
||
|
if (CHAT_E_BANNED == error.GetErrorCode())
|
||
|
{
|
||
|
// DlgMsgBox::DoDialog(TRANSLATE(IDS_WOL_SERVERMESSAGE), TRANSLATE(IDS_WOL_BANNED));
|
||
|
DlgMsgBox::DoDialog(TRANSLATE (IDS_MENU_SERVER_MESSAGE_TITLE), TRANSLATE (IDS_MENU_WOL_BAN_USER_MESSAGE));
|
||
|
End_Dialog();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* MPWolGameListMenuClass::HandleNotification(SquadEvent)
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
*
|
||
|
* INPUTS
|
||
|
*
|
||
|
* RESULT
|
||
|
* NONE
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void MPWolGameListMenuClass::HandleNotification(WWOnline::SquadEvent& event)
|
||
|
{
|
||
|
if (!mSelectedGame.IsDataValid() && mSelectedGame.IsClanGame())
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
RefPtr<SquadData> squad = event.GetSquadData();
|
||
|
|
||
|
if (squad.IsValid())
|
||
|
{
|
||
|
unsigned long squadID = squad->GetID();
|
||
|
|
||
|
if (mSelectedGame.ClanID1() == squadID || mSelectedGame.ClanID2() == squadID)
|
||
|
{
|
||
|
ListCtrlClass* detailsList = (ListCtrlClass*)Get_Dlg_Item(IDC_DETAILS_LIST);
|
||
|
|
||
|
if (detailsList)
|
||
|
{
|
||
|
// Find entry with marker indicating clan vs clan
|
||
|
const int count = detailsList->Get_Entry_Count();
|
||
|
|
||
|
for (int index = 0; index < count; ++index)
|
||
|
{
|
||
|
int marker = detailsList->Get_Entry_Data(index, 0);
|
||
|
|
||
|
if (CLAN_ENTRY_MARKER == marker)
|
||
|
{
|
||
|
WideStringClass text(0, true);
|
||
|
GetClanVSClanString(mSelectedGame, text);
|
||
|
detailsList->Set_Entry_Text(index, 0, text);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* SetGameTypeFlags
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Setup the game type flags in the icon column of the game listings.
|
||
|
*
|
||
|
* INPUTS
|
||
|
* List - Pointer to list control to work with.
|
||
|
* Index - Entry index to set type flags for.
|
||
|
* GameInfo - Game information
|
||
|
*
|
||
|
* RESULT
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void SetGameTypeFlags(ListCtrlClass* list, int itemIndex, const WOLGameInfo& gameInfo)
|
||
|
{
|
||
|
WWASSERT(list != NULL);
|
||
|
|
||
|
list->Reset_Icons(itemIndex, COL_ICON);
|
||
|
uint32 flags = 0;
|
||
|
|
||
|
if (gameInfo.IsLaddered())
|
||
|
{
|
||
|
list->Add_Icon(itemIndex, COL_ICON, "MUL_pts.tga");
|
||
|
flags |= FLAGSORT_LADDERED;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
list->Add_Icon(itemIndex, COL_ICON, "MUL_NoPts.tga");
|
||
|
}
|
||
|
|
||
|
if (gameInfo.IsDedicated())
|
||
|
{
|
||
|
list->Add_Icon(itemIndex, COL_ICON, "MUL_Spec.tga");
|
||
|
flags |= FLAGSORT_DEDICATED;
|
||
|
}
|
||
|
|
||
|
if (gameInfo.IsPassworded())
|
||
|
{
|
||
|
list->Add_Icon(itemIndex, COL_ICON, "MUL_Pswrd.tga");
|
||
|
flags |= FLAGSORT_PASSWORDED;
|
||
|
}
|
||
|
|
||
|
if (gameInfo.IsClanGame())
|
||
|
{
|
||
|
list->Add_Icon(itemIndex, COL_ICON, "MUL_Btlcln.tga");
|
||
|
flags |= FLAGSORT_CLAN;
|
||
|
}
|
||
|
|
||
|
list->Set_Entry_Data(itemIndex, COL_ICON, flags);
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* SetPingTimeIcon
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Set an icon reflecting the latency for this game.
|
||
|
*
|
||
|
* INPUTS
|
||
|
* List - List control
|
||
|
* Index - Entry index
|
||
|
* Time - Latency
|
||
|
*
|
||
|
* RESULT
|
||
|
* NONE
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void SetPingTimeIcon(ListCtrlClass* list, int itemIndex, long pingTime)
|
||
|
{
|
||
|
const char* pingIcon = NULL;
|
||
|
|
||
|
if (pingTime <= PING_GREEN_THRESHOLD)
|
||
|
{
|
||
|
pingIcon = "mul_statg.tga";
|
||
|
}
|
||
|
else if (pingTime <= PING_YELLOW_THRESHOLD)
|
||
|
{
|
||
|
pingIcon = "mul_staty.tga";
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pingIcon = "mul_statr.tga";
|
||
|
}
|
||
|
|
||
|
list->Reset_Icons(itemIndex, COL_PING);
|
||
|
list->Add_Icon(itemIndex, COL_PING, pingIcon);
|
||
|
|
||
|
unsigned long displayPing = (unsigned long)((1000.0 / 256.0) * (sqrt(double(pingTime))));
|
||
|
list->Set_Entry_Data(itemIndex, COL_PING, displayPing);
|
||
|
|
||
|
WideStringClass text(32, true);
|
||
|
text.Format(L" (%lu)", displayPing);
|
||
|
list->Set_Entry_Text(itemIndex, COL_PING, text);
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* MPWolGameListMenuClass::SortGameChannels
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Sort the game channels
|
||
|
*
|
||
|
* INPUTS
|
||
|
* Column - Number of column to sort by.
|
||
|
* Ascending - True to sort ascending; false to sort descending
|
||
|
* Flags - Game flags to sort by if column is COL_ICON
|
||
|
*
|
||
|
* RESULT
|
||
|
* NONE
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void MPWolGameListMenuClass::SortGameChannels(int column, bool isAscending, unsigned long param)
|
||
|
{
|
||
|
mSortColumn = column;
|
||
|
mIsSortAscending = isAscending;
|
||
|
mSortFlags = param;
|
||
|
|
||
|
ListCtrlClass* list = (ListCtrlClass*)Get_Dlg_Item(IDC_GAME_LIST_CTRL);
|
||
|
|
||
|
if (list)
|
||
|
{
|
||
|
ListCtrlClass::SORT_TYPE sortDirection = ListCtrlClass::SORT_DESCENDING;
|
||
|
|
||
|
if (isAscending)
|
||
|
{
|
||
|
sortDirection = ListCtrlClass::SORT_ASCENDING;
|
||
|
}
|
||
|
|
||
|
if (COL_ICON == column)
|
||
|
{
|
||
|
list->Sort(FlagsSortCallback, mSortFlags);
|
||
|
}
|
||
|
else if (COL_PLAYERS == column || COL_PING == column)
|
||
|
{
|
||
|
list->Sort(NumericSortCallback, MAKELONG(column, sortDirection));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
list->Sort(AlphaSortCallback, MAKELONG(column, sortDirection));
|
||
|
}
|
||
|
|
||
|
list->Set_Sort_Designator(column, sortDirection);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* FlagSortCallback
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Sort list entries by game type flags.
|
||
|
*
|
||
|
* INPUTS
|
||
|
* List - List control performing sort.
|
||
|
* Index1 - First entry to compare
|
||
|
* Index2 - Second entry to compare
|
||
|
*
|
||
|
* RESULT
|
||
|
* 0 - Items are equal
|
||
|
* -1 - Item1 is less than item2
|
||
|
* 1 - Item1 is greater than item2
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
int CALLBACK FlagsSortCallback(ListCtrlClass* list, int index1, int index2, uint32 mask)
|
||
|
{
|
||
|
uint32 flags1 = list->Get_Entry_Data(index1, COL_ICON);
|
||
|
flags1 &= mask;
|
||
|
|
||
|
uint32 flags2 = list->Get_Entry_Data(index2, COL_ICON);
|
||
|
flags2 &= mask;
|
||
|
|
||
|
if (flags1 && !flags2)
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
else if (!flags1 && flags2)
|
||
|
{
|
||
|
return 1;
|
||
|
}
|
||
|
else if (flags1 && flags2)
|
||
|
{
|
||
|
// Secondary sort by ping time
|
||
|
int ping1 = list->Get_Entry_Data(index1, COL_PING);
|
||
|
int ping2 = list->Get_Entry_Data(index2, COL_PING);
|
||
|
|
||
|
int delta = (ping1 - ping2);
|
||
|
|
||
|
if (delta < 0)
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
else if (delta > 0)
|
||
|
{
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
const WCHAR* name1 = list->Get_Entry_Text(index1, COL_HOST_NAME);
|
||
|
const WCHAR* name2 = list->Get_Entry_Text(index2, COL_HOST_NAME);
|
||
|
return wcsicmp(name1, name2);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* NumericSortCallback
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Sort list entries numerically from the numbers contained in the entries
|
||
|
* data field.
|
||
|
*
|
||
|
* INPUTS
|
||
|
* List - List control performing sort.
|
||
|
* Index1 - First entry to compare
|
||
|
* Index2 - Second entry to compare
|
||
|
*
|
||
|
* RESULT
|
||
|
* -1 - Item1 is less than item2
|
||
|
* 0 - Items are equal
|
||
|
* 1 - Item1 is greater than item2
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
int CALLBACK NumericSortCallback(ListCtrlClass* list, int index1, int index2, uint32 param)
|
||
|
{
|
||
|
// Sort by numeric value stored in entry data field
|
||
|
int column = LOWORD(param);
|
||
|
|
||
|
uint32 data1 = list->Get_Entry_Data(index1, column);
|
||
|
uint32 data2 = list->Get_Entry_Data(index2, column);
|
||
|
|
||
|
int retval = (data1 - data2);
|
||
|
|
||
|
if (retval < 0)
|
||
|
{
|
||
|
retval = -1;
|
||
|
}
|
||
|
else if (retval > 0)
|
||
|
{
|
||
|
retval = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (column != COL_PING)
|
||
|
{
|
||
|
// Secondary sort by ping time
|
||
|
data1 = list->Get_Entry_Data(index1, COL_PING);
|
||
|
data2 = list->Get_Entry_Data(index2, COL_PING);
|
||
|
|
||
|
retval = (data1 - data2);
|
||
|
|
||
|
if (retval < 0)
|
||
|
{
|
||
|
retval = -1;
|
||
|
}
|
||
|
else if (retval > 0)
|
||
|
{
|
||
|
retval = 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (retval == 0)
|
||
|
{
|
||
|
const WCHAR* name1 = list->Get_Entry_Text(index1, COL_HOST_NAME);
|
||
|
const WCHAR* name2 = list->Get_Entry_Text(index2, COL_HOST_NAME);
|
||
|
retval = wcsicmp(name1, name2);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Invert the return value if we are sorting descendingly
|
||
|
ListCtrlClass::SORT_TYPE sortType = (ListCtrlClass::SORT_TYPE)HIWORD(param);
|
||
|
|
||
|
if (ListCtrlClass::SORT_DESCENDING == sortType)
|
||
|
{
|
||
|
return -retval;
|
||
|
}
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* NumericSortCallback
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Sort list entries alphbetically then by ping time.
|
||
|
*
|
||
|
* INPUTS
|
||
|
* List - List control performing sort.
|
||
|
* Index1 - First entry to compare
|
||
|
* Index2 - Second entry to compare
|
||
|
*
|
||
|
* RESULT
|
||
|
* -1 - Item1 is less than item2
|
||
|
* 0 - Items are equal
|
||
|
* 1 - Item1 is greater than item2
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
int CALLBACK AlphaSortCallback(ListCtrlClass* list, int index1, int index2, uint32 param)
|
||
|
{
|
||
|
// Sort by numeric value stored in entry data field
|
||
|
int column = LOWORD(param);
|
||
|
|
||
|
const WCHAR* text1 = list->Get_Entry_Text(index1, column);
|
||
|
const WCHAR* text2 = list->Get_Entry_Text(index2, column);
|
||
|
int retval = wcsicmp(text1, text2);
|
||
|
|
||
|
// If the strings match then secondary sort by ping time.
|
||
|
if (retval == 0)
|
||
|
{
|
||
|
uint32 data1 = list->Get_Entry_Data(index1, COL_PING);
|
||
|
uint32 data2 = list->Get_Entry_Data(index2, COL_PING);
|
||
|
|
||
|
retval = (data1 - data2);
|
||
|
|
||
|
if (retval < 0)
|
||
|
{
|
||
|
retval = -1;
|
||
|
}
|
||
|
else if (retval > 0)
|
||
|
{
|
||
|
retval = 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Invert the return value if we are sorting descendingly
|
||
|
ListCtrlClass::SORT_TYPE sortType = (ListCtrlClass::SORT_TYPE)HIWORD(param);
|
||
|
|
||
|
if (ListCtrlClass::SORT_DESCENDING == sortType)
|
||
|
{
|
||
|
return -retval;
|
||
|
}
|
||
|
|
||
|
return retval;
|
||
|
}
|