/*
** Command & Conquer Generals Zero Hour(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 .
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
// FILE: WOLLobbyMenu.cpp
// Author: Chris Huybregts, November 2001
// Description: WOL Lobby Menu
///////////////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/GameEngine.h"
#include "Common/GameState.h"
#include "Common/MiniLog.h"
#include "Common/MultiplayerSettings.h"
#include "Common/PlayerTemplate.h"
#include "Common/CustomMatchPreferences.h"
#include "Common/Version.h"
#include "GameClient/AnimateWindowManager.h"
#include "GameClient/WindowLayout.h"
#include "GameClient/Gadget.h"
#include "GameClient/GameClient.h"
#include "GameClient/Shell.h"
#include "GameClient/ShellHooks.h"
#include "GameClient/KeyDefs.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/GadgetComboBox.h"
#include "GameClient/GadgetListBox.h"
#include "GameClient/GadgetSlider.h"
#include "GameClient/GadgetTextEntry.h"
#include "GameClient/GameText.h"
#include "GameClient/MessageBox.h"
#include "GameClient/Mouse.h"
#include "GameClient/Display.h"
#include "GameNetwork/GameSpyOverlay.h"
#include "GameClient/GameWindowTransitions.h"
#include "GameLogic/GameLogic.h"
#include "GameClient/LanguageFilter.h"
#include "GameNetwork/GameSpy/BuddyDefs.h"
#include "GameNetwork/GameSpy/GSConfig.h"
#include "GameNetwork/GameSpy/LadderDefs.h"
#include "GameNetwork/GameSpy/PeerDefs.h"
#include "GameNetwork/GameSpy/PeerThread.h"
#include "GameNetwork/GameSpy/PersistentStorageDefs.h"
#include "GameNetwork/GameSpy/PersistentStorageThread.h"
#include "GameNetwork/GameSpy/LobbyUtils.h"
#include "GameNetwork/RankPointValue.h"
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
void refreshGameList( Bool forceRefresh = FALSE );
void refreshPlayerList( Bool forceRefresh = FALSE );
#ifdef DEBUG_LOGGING
#define PERF_TEST
static LogClass s_perfLog("Perf.txt");
#define PERF_LOG(x) s_perfLog.log x
#else // DEBUG_LOGGING
#define PERF_LOG(x) {}
#endif // DEBUG_LOGGING
// PRIVATE DATA ///////////////////////////////////////////////////////////////////////////////////
static Bool isShuttingDown = false;
static Bool buttonPushed = false;
static char *nextScreen = NULL;
static Bool raiseMessageBoxes = false;
static time_t gameListRefreshTime = 0;
static const time_t gameListRefreshInterval = 10000;
static time_t playerListRefreshTime = 0;
static const time_t playerListRefreshInterval = 5000;
void setUnignoreText( WindowLayout *layout, AsciiString nick, GPProfile id);
static void doSliderTrack(GameWindow *control, Int val);
Bool DontShowMainMenu = FALSE;
enum { COLUMN_PLAYERNAME = 1 };
// window ids ------------------------------------------------------------------------------
static NameKeyType parentWOLLobbyID = NAMEKEY_INVALID;
static NameKeyType buttonBackID = NAMEKEY_INVALID;
static NameKeyType buttonHostID = NAMEKEY_INVALID;
static NameKeyType buttonRefreshID = NAMEKEY_INVALID;
static NameKeyType buttonJoinID = NAMEKEY_INVALID;
static NameKeyType buttonBuddyID = NAMEKEY_INVALID;
static NameKeyType buttonEmoteID = NAMEKEY_INVALID;
static NameKeyType textEntryChatID = NAMEKEY_INVALID;
static NameKeyType listboxLobbyPlayersID = NAMEKEY_INVALID;
static NameKeyType listboxLobbyChatID = NAMEKEY_INVALID;
static NameKeyType comboLobbyGroupRoomsID = NAMEKEY_INVALID;
//static NameKeyType // sliderChatAdjustID = NAMEKEY_INVALID;
// Window Pointers ------------------------------------------------------------------------
static GameWindow *parentWOLLobby = NULL;
static GameWindow *buttonBack = NULL;
static GameWindow *buttonHost = NULL;
static GameWindow *buttonRefresh = NULL;
static GameWindow *buttonJoin = NULL;
static GameWindow *buttonBuddy = NULL;
static GameWindow *buttonEmote = NULL;
static GameWindow *textEntryChat = NULL;
static GameWindow *listboxLobbyPlayers = NULL;
static GameWindow *listboxLobbyChat = NULL;
static GameWindow *comboLobbyGroupRooms = NULL;
static GameWindow *parent = NULL;
static Int groupRoomToJoin = 0;
static Int initialGadgetDelay = 2;
static Bool justEntered = FALSE;
#if defined(_INTERNAL) || defined(_DEBUG)
Bool g_fakeCRC = FALSE;
Bool g_debugSlots = FALSE;
#endif
std::list TheLobbyQueuedUTMs;
// Slash commands -------------------------------------------------------------------------
extern "C" {
int getQR2HostingStatus(void);
}
extern int isThreadHosting;
Bool handleLobbySlashCommands(UnicodeString uText)
{
AsciiString message;
message.translate(uText);
if (message.getCharAt(0) != '/')
{
return FALSE; // not a slash command
}
AsciiString remainder = message.str() + 1;
AsciiString token;
remainder.nextToken(&token);
token.toLower();
if (token == "host")
{
UnicodeString s;
s.format(L"Hosting qr2:%d thread:%d", getQR2HostingStatus(), isThreadHosting);
TheGameSpyInfo->addText(s, GameSpyColor[GSCOLOR_DEFAULT], NULL);
return TRUE; // was a slash command
}
else if (token == "me" && uText.getLength()>4)
{
TheGameSpyInfo->sendChat(UnicodeString(uText.str()+4), TRUE, listboxLobbyPlayers);
return TRUE; // was a slash command
}
else if (token == "refresh")
{
// Added 2/19/03 added the game refresh
refreshGameList(TRUE);
refreshPlayerList(TRUE);
return TRUE; // was a slash command
}
/*
if (token == "togglegamelist")
{
NameKeyType buttonID = NAMEKEY("WOLCustomLobby.wnd:ButtonGameListToggle");
GameWindow *button = TheWindowManager->winGetWindowFromId(parent, buttonID);
if (button)
{
button->winHide(!button->winIsHidden());
}
return TRUE; // was a slash command
}
else if (token == "adjustchat")
{
NameKeyType sliderID = NAMEKEY("WOLCustomLobby.wnd:SliderChatAdjust");
GameWindow *slider = TheWindowManager->winGetWindowFromId(parent, sliderID);
if (slider)
{
slider->winHide(!slider->winIsHidden());
}
return TRUE; // was a slash command
}
*/
#if defined(_INTERNAL) || defined(_DEBUG)
else if (token == "fakecrc")
{
g_fakeCRC = !g_fakeCRC;
TheGameSpyInfo->addText(UnicodeString(L"Toggled CRC fakery"), GameSpyColor[GSCOLOR_DEFAULT], NULL);
return TRUE; // was a slash command
}
else if (token == "slots")
{
g_debugSlots = !g_debugSlots;
TheGameSpyInfo->addText(UnicodeString(L"Toggled SlotList debug"), GameSpyColor[GSCOLOR_DEFAULT], NULL);
return TRUE; // was a slash command
}
#endif
return FALSE; // not a slash command
}
static Bool s_tryingToHostOrJoin = FALSE;
void SetLobbyAttemptHostJoin(Bool start)
{
s_tryingToHostOrJoin = start;
}
// Tooltips -------------------------------------------------------------------------------
static void playerTooltip(GameWindow *window,
WinInstanceData *instData,
UnsignedInt mouse)
{
Int x, y, row, col;
x = LOLONGTOSHORT(mouse);
y = HILONGTOSHORT(mouse);
GadgetListBoxGetEntryBasedOnXY(window, x, y, row, col);
if (row == -1 || col == -1)
{
TheMouse->setCursorTooltip( UnicodeString::TheEmptyString);//TheGameText->fetch("TOOLTIP:PlayersInLobby") );
return;
}
UnicodeString uName = GadgetListBoxGetText(window, row, COLUMN_PLAYERNAME);
AsciiString aName;
aName.translate(uName);
PlayerInfoMap::iterator it = TheGameSpyInfo->getPlayerInfoMap()->find(aName);
PlayerInfo *info = &(it->second);
Bool isLocalPlayer = (TheGameSpyInfo->getLocalName().compareNoCase(info->m_name) == 0);
if (col == 0)
{
if (info->m_preorder)
{
TheMouse->setCursorTooltip( TheGameText->fetch("TOOLTIP:LobbyOfficersClub") );
}
else
{
TheMouse->setCursorTooltip( UnicodeString::TheEmptyString);
}
return;
}
AsciiString playerLocale = info->m_locale;
AsciiString localeIdentifier;
localeIdentifier.format("WOL:Locale%2.2d", atoi(playerLocale.str()));
Int playerWins = info->m_wins;
Int playerLosses = info->m_losses;
UnicodeString playerInfo;
playerInfo.format(TheGameText->fetch("TOOLTIP:PlayerInfo"), TheGameText->fetch(localeIdentifier).str(), playerWins, playerLosses);
UnicodeString tooltip = UnicodeString::TheEmptyString;//TheGameText->fetch("TOOLTIP:PlayersInLobby");
if (isLocalPlayer)
{
tooltip.format(TheGameText->fetch("TOOLTIP:LocalPlayer"), uName.str());
}
else
{
// not us
if (TheGameSpyInfo->getBuddyMap()->find(info->m_profileID) != TheGameSpyInfo->getBuddyMap()->end())
{
// buddy
tooltip.format(TheGameText->fetch("TOOLTIP:BuddyPlayer"), uName.str());
}
else
{
if (info->m_profileID)
{
// non-buddy profiled player
tooltip.format(TheGameText->fetch("TOOLTIP:ProfiledPlayer"), uName.str());
}
else
{
// non-profiled player
tooltip.format(TheGameText->fetch("TOOLTIP:GenericPlayer"), uName.str());
}
}
}
if (info->isIgnored())
{
tooltip.concat(TheGameText->fetch("TOOLTIP:IgnoredModifier"));
}
if (info->m_profileID)
{
tooltip.concat(playerInfo);
}
Int rank = 0;
Int i = 0;
while( info->m_rankPoints >= TheRankPointValues->m_ranks[i + 1])
++i;
rank = i;
AsciiString sideName = "GUI:RandomSide";
if (info->m_side > 0)
{
const PlayerTemplate *fac = ThePlayerTemplateStore->getNthPlayerTemplate(info->m_side);
if (fac)
{
sideName.format("SIDE:%s", fac->getSide().str());
}
}
AsciiString rankName;
rankName.format("GUI:GSRank%d", rank);
UnicodeString tmp;
tmp.format(L"\n%ls %ls", TheGameText->fetch(sideName).str(), TheGameText->fetch(rankName).str());
tooltip.concat(tmp);
TheMouse->setCursorTooltip( tooltip, -1, NULL, 1.5f ); // the text and width are the only params used. the others are the default values.
}
static void populateGroupRoomListbox(GameWindow *lb)
{
if (!lb)
return;
GadgetComboBoxReset(lb);
Int indexToSelect = -1;
GroupRoomMap::iterator iter;
// now populate the combo box
for (iter = TheGameSpyInfo->getGroupRoomList()->begin(); iter != TheGameSpyInfo->getGroupRoomList()->end(); ++iter)
{
GameSpyGroupRoom room = iter->second;
if (room.m_groupID != TheGameSpyConfig->getQMChannel())
{
DEBUG_LOG(("populateGroupRoomListbox(): groupID %d\n", room.m_groupID));
if (room.m_groupID == TheGameSpyInfo->getCurrentGroupRoom())
{
Int selected = GadgetComboBoxAddEntry(lb, room.m_translatedName, GameSpyColor[GSCOLOR_CURRENTROOM]);
GadgetComboBoxSetItemData(lb, selected, (void *)(room.m_groupID));
indexToSelect = selected;
}
else
{
Int selected = GadgetComboBoxAddEntry(lb, room.m_translatedName, GameSpyColor[GSCOLOR_ROOM]);
GadgetComboBoxSetItemData(lb, selected, (void *)(room.m_groupID));
}
}
else
{
DEBUG_LOG(("populateGroupRoomListbox(): skipping QM groupID %d\n", room.m_groupID));
}
}
GadgetComboBoxSetSelectedPos(lb, indexToSelect);
}
static const char *rankNames[] = {
"Private",
"Corporal",
"Sergeant",
"Lieutenant",
"Captain",
"Major",
"Colonel",
"General",
"Brigadier",
"Commander",
};
const Image* LookupSmallRankImage(Int side, Int rankPoints)
{
if (rankPoints == 0)
return NULL;
Int rank = 0;
Int i = 0;
while( rankPoints >= TheRankPointValues->m_ranks[i + 1])
++i;
rank = i;
if (rank < 0 || rank >= 10)
return NULL;
AsciiString sideStr = "N";
switch(side)
{
case 2: //USA
case 5: //Super Weapon
case 6: //Laser
case 7: //Air Force
sideStr = "USA";
break;
case 3: //China
case 8: //Tank
case 9: //Infantry
case 10: //Nuke
sideStr = "CHA";
break;
case 4: //GLA
case 11: //Toxin
case 12: //Demolition
case 13: //Stealth
sideStr = "GLA";
break;
}
AsciiString fullImageName;
fullImageName.format("%s-%s", rankNames[rank], sideStr.str());
const Image *img = TheMappedImageCollection->findImageByName(fullImageName);
DEBUG_ASSERTLOG(img, ("*** Could not load small rank image '%s' from TheMappedImageCollection!\n", fullImageName.str()));
return img;
}
static Int insertPlayerInListbox(const PlayerInfo& info, Color color)
{
UnicodeString uStr;
uStr.translate(info.m_name);
Int currentRank = info.m_rankPoints;
Int currentSide = info.m_side;
/* since PersistentStorage updates now update PlayerInfo, we don't need this.
if (info.m_profileID)
{
PSPlayerStats psStats = TheGameSpyPSMessageQueue->findPlayerStatsByID(info.m_profileID);
if (psStats.id)
{
currentRank = CalculateRank(psStats);
PerGeneralMap::iterator it;
Int numGames = 0;
for(it = psStats.games.begin(); it != psStats.games.end(); ++it)
{
if(it->second >= numGames)
{
numGames = it->second;
currentSide = it->first;
}
}
if(numGames == 0 || psStats.gamesAsRandom >= numGames )
{
currentSide = 0;
}
}
}
*/
Bool isPreorder = TheGameSpyInfo->didPlayerPreorder(info.m_profileID);
const Image *preorderImg = TheMappedImageCollection->findImageByName("OfficersClubsmall");
Int w = (preorderImg)?preorderImg->getImageWidth():10;
//Int h = (preorderImg)?preorderImg->getImageHeight():10;
w = min(GadgetListBoxGetColumnWidth(listboxLobbyPlayers, 0), w);
Int h = w;
if (!isPreorder)
preorderImg = NULL;
const Image *rankImg = LookupSmallRankImage(currentSide, currentRank);
#if 0 //Officer's Club (preorder image) no longer used in Zero Hour
Int index = GadgetListBoxAddEntryImage(listboxLobbyPlayers, preorderImg, -1, 0, w, h);
GadgetListBoxAddEntryImage(listboxLobbyPlayers, rankImg, index, 1, w, h);
GadgetListBoxAddEntryText(listboxLobbyPlayers, uStr, color, index, 2);
#else
Int index = GadgetListBoxAddEntryImage(listboxLobbyPlayers, rankImg, -1, 0, w, h);
GadgetListBoxAddEntryText(listboxLobbyPlayers, uStr, color, index, 1);
#endif
return index;
}
void PopulateLobbyPlayerListbox(void)
{
if (!listboxLobbyPlayers)
return;
// Display players
PlayerInfoMap *players = TheGameSpyInfo->getPlayerInfoMap();
PlayerInfoMap::iterator it;
BuddyInfoMap *buddies = TheGameSpyInfo->getBuddyMap();
BuddyInfoMap::iterator bIt;
if (listboxLobbyPlayers)
{
// save off old selection
Int maxSelectedItems = GadgetListBoxGetNumEntries(listboxLobbyPlayers);
Int *selectedIndices;
GadgetListBoxGetSelected(listboxLobbyPlayers, (Int *)(&selectedIndices));
std::set selectedNames;
std::set::const_iterator selIt;
std::set indicesToSelect;
UnicodeString uStr;
Int numSelected = 0;
for (Int i=0; ibegin(); it != players->end(); ++it)
{
PlayerInfo info = it->second;
if (info.m_flags & PEER_FLAG_OP || TheGameSpyConfig->isPlayerVIP(info.m_profileID))
{
Int index = insertPlayerInListbox(info, info.isIgnored()?GameSpyColor[GSCOLOR_PLAYER_IGNORED]:GameSpyColor[GSCOLOR_PLAYER_OWNER]);
selIt = selectedNames.find(info.m_name);
if (selIt != selectedNames.end())
{
DEBUG_LOG(("Marking index %d (%s) to re-select\n", index, info.m_name.str()));
indicesToSelect.insert(index);
}
}
}
// Buddies
for (it = players->begin(); it != players->end(); ++it)
{
PlayerInfo info = it->second;
bIt = buddies->find(info.m_profileID);
if ( !(info.m_flags & PEER_FLAG_OP || TheGameSpyConfig->isPlayerVIP(info.m_profileID)) && bIt != buddies->end() )
{
Int index = insertPlayerInListbox(info, info.isIgnored()?GameSpyColor[GSCOLOR_PLAYER_IGNORED]:GameSpyColor[GSCOLOR_PLAYER_BUDDY]);
selIt = selectedNames.find(info.m_name);
if (selIt != selectedNames.end())
{
DEBUG_LOG(("Marking index %d (%s) to re-select\n", index, info.m_name.str()));
indicesToSelect.insert(index);
}
}
}
// Everyone else
for (it = players->begin(); it != players->end(); ++it)
{
PlayerInfo info = it->second;
bIt = buddies->find(info.m_profileID);
if ( !(info.m_flags & PEER_FLAG_OP || TheGameSpyConfig->isPlayerVIP(info.m_profileID)) && bIt == buddies->end() )
{
Int index = insertPlayerInListbox(info, info.isIgnored()?GameSpyColor[GSCOLOR_PLAYER_IGNORED]:GameSpyColor[GSCOLOR_PLAYER_NORMAL]);
selIt = selectedNames.find(info.m_name);
if (selIt != selectedNames.end())
{
DEBUG_LOG(("Marking index %d (%s) to re-select\n", index, info.m_name.str()));
indicesToSelect.insert(index);
}
}
}
// restore selection
if (indicesToSelect.size())
{
std::set::const_iterator indexIt;
Int *newIndices = NEW Int[indicesToSelect.size()];
for (i=0, indexIt = indicesToSelect.begin(); indexIt != indicesToSelect.end(); ++i, ++indexIt)
{
newIndices[i] = *indexIt;
DEBUG_LOG(("Queueing up index %d to re-select\n", *indexIt));
}
GadgetListBoxSetSelected(listboxLobbyPlayers, newIndices, indicesToSelect.size());
delete[] newIndices;
}
if (indicesToSelect.size() != numSelected)
{
TheWindowManager->winSetLoneWindow(NULL);
}
// restore top visible entry
GadgetListBoxSetTopVisibleEntry(listboxLobbyPlayers, previousTopIndex);
}
}
//-------------------------------------------------------------------------------------------------
/** Initialize the WOL Lobby Menu */
//-------------------------------------------------------------------------------------------------
void WOLLobbyMenuInit( WindowLayout *layout, void *userData )
{
nextScreen = NULL;
buttonPushed = false;
isShuttingDown = false;
SetLobbyAttemptHostJoin(FALSE); // not trying to host or join
gameListRefreshTime = 0;
playerListRefreshTime = 0;
parentWOLLobbyID = TheNameKeyGenerator->nameToKey( AsciiString( "WOLCustomLobby.wnd:WOLLobbyMenuParent" ) );
parent = TheWindowManager->winGetWindowFromId(NULL, parentWOLLobbyID);
buttonBackID = TheNameKeyGenerator->nameToKey(AsciiString("WOLCustomLobby.wnd:ButtonBack"));
buttonBack = TheWindowManager->winGetWindowFromId(parent, buttonBackID);
buttonHostID = TheNameKeyGenerator->nameToKey(AsciiString("WOLCustomLobby.wnd:ButtonHost"));
buttonHost = TheWindowManager->winGetWindowFromId(parent, buttonHostID);
buttonRefreshID = TheNameKeyGenerator->nameToKey(AsciiString("WOLCustomLobby.wnd:ButtonRefresh"));
buttonRefresh = TheWindowManager->winGetWindowFromId(parent, buttonRefreshID);
buttonJoinID = TheNameKeyGenerator->nameToKey(AsciiString("WOLCustomLobby.wnd:ButtonJoin"));
buttonJoin = TheWindowManager->winGetWindowFromId(parent, buttonJoinID);
buttonJoin->winEnable(FALSE);
buttonBuddyID = TheNameKeyGenerator->nameToKey(AsciiString("WOLCustomLobby.wnd:ButtonBuddy"));
buttonBuddy = TheWindowManager->winGetWindowFromId(parent, buttonBuddyID);
buttonEmoteID = TheNameKeyGenerator->nameToKey(AsciiString("WOLCustomLobby.wnd:ButtonEmote"));
buttonEmote = TheWindowManager->winGetWindowFromId(parent, buttonEmoteID);
textEntryChatID = TheNameKeyGenerator->nameToKey(AsciiString("WOLCustomLobby.wnd:TextEntryChat"));
textEntryChat = TheWindowManager->winGetWindowFromId(parent, textEntryChatID);
listboxLobbyPlayersID = TheNameKeyGenerator->nameToKey(AsciiString("WOLCustomLobby.wnd:ListboxPlayers"));
listboxLobbyPlayers = TheWindowManager->winGetWindowFromId(parent, listboxLobbyPlayersID);
listboxLobbyPlayers->winSetTooltipFunc(playerTooltip);
listboxLobbyChatID = TheNameKeyGenerator->nameToKey(AsciiString("WOLCustomLobby.wnd:ListboxChat"));
listboxLobbyChat = TheWindowManager->winGetWindowFromId(parent, listboxLobbyChatID);
TheGameSpyInfo->registerTextWindow(listboxLobbyChat);
comboLobbyGroupRoomsID = TheNameKeyGenerator->nameToKey(AsciiString("WOLCustomLobby.wnd:ComboBoxGroupRooms"));
comboLobbyGroupRooms = TheWindowManager->winGetWindowFromId(parent, comboLobbyGroupRoomsID);
GadgetTextEntrySetText(textEntryChat, UnicodeString.TheEmptyString);
populateGroupRoomListbox(comboLobbyGroupRooms);
// Show Menu
layout->hide( FALSE );
// if we're not in a room, this will join the best available one
if (!TheGameSpyInfo->getCurrentGroupRoom())
{
if (groupRoomToJoin)
{
DEBUG_LOG(("WOLLobbyMenuInit() - rejoining group room %d\n", groupRoomToJoin));
TheGameSpyInfo->joinGroupRoom(groupRoomToJoin);
groupRoomToJoin = 0;
}
else
{
DEBUG_LOG(("WOLLobbyMenuInit() - joining best group room\n"));
TheGameSpyInfo->joinBestGroupRoom();
}
}
else
{
DEBUG_LOG(("WOLLobbyMenuInit() - not joining group room because we're already in one\n"));
}
GrabWindowInfo();
TheGameSpyInfo->clearStagingRoomList();
PeerRequest req;
req.peerRequestType = PeerRequest::PEERREQUEST_STARTGAMELIST;
req.gameList.restrictGameList = TheGameSpyConfig->restrictGamesToLobby();
TheGameSpyPeerMessageQueue->addRequest(req);
// animate controls
// TheShell->registerWithAnimateManager(parent, WIN_ANIMATION_SLIDE_TOP, TRUE);
TheShell->showShellMap(TRUE);
TheGameSpyGame->reset();
CustomMatchPreferences pref;
// GameWindow *slider = TheWindowManager->winGetWindowFromId(parent, sliderChatAdjustID);
// if (slider)
// {
// GadgetSliderSetPosition(slider, pref.getChatSizeSlider());
// doSliderTrack(slider, pref.getChatSizeSlider());
// }
//
if (pref.usesLongGameList())
{
ToggleGameListType();
}
// Set Keyboard to chat window
TheWindowManager->winSetFocus( textEntryChat );
raiseMessageBoxes = true;
TheLobbyQueuedUTMs.clear();
justEntered = TRUE;
initialGadgetDelay = 2;
GameWindow *win = TheWindowManager->winGetWindowFromId(NULL, TheNameKeyGenerator->nameToKey("WOLCustomLobby.wnd:GadgetParent"));
if(win)
win->winHide(TRUE);
DontShowMainMenu = TRUE;
} // WOLLobbyMenuInit
//-------------------------------------------------------------------------------------------------
/** This is called when a shutdown is complete for this menu */
//-------------------------------------------------------------------------------------------------
static void shutdownComplete( WindowLayout *layout )
{
isShuttingDown = false;
// hide the layout
layout->hide( TRUE );
// our shutdown is complete
TheShell->shutdownComplete( layout, (nextScreen != NULL) );
if (nextScreen != NULL)
{
TheShell->push(nextScreen);
}
nextScreen = NULL;
} // end if
//-------------------------------------------------------------------------------------------------
/** WOL Lobby Menu shutdown method */
//-------------------------------------------------------------------------------------------------
void WOLLobbyMenuShutdown( WindowLayout *layout, void *userData )
{
CustomMatchPreferences pref;
// GameWindow *slider = TheWindowManager->winGetWindowFromId(parent, sliderChatAdjustID);
// if (slider)
// {
// pref.setChatSizeSlider(GadgetSliderGetPosition(slider));
// }
if (GetGameInfoListBox())
{
pref.setUsesLongGameList(FALSE);
}
else
{
pref.setUsesLongGameList(TRUE);
}
pref.write();
ReleaseWindowInfo();
TheGameSpyInfo->unregisterTextWindow(listboxLobbyChat);
//TheGameSpyChat->stopListingGames();
PeerRequest req;
req.peerRequestType = PeerRequest::PEERREQUEST_STOPGAMELIST;
TheGameSpyPeerMessageQueue->addRequest(req);
listboxLobbyChat = NULL;
listboxLobbyPlayers = NULL;
isShuttingDown = true;
// if we are shutting down for an immediate pop, skip the animations
Bool popImmediate = *(Bool *)userData;
if( popImmediate )
{
shutdownComplete( layout );
return;
} //end if
TheShell->reverseAnimatewindow();
DontShowMainMenu = FALSE;
RaiseGSMessageBox();
TheTransitionHandler->reverse("WOLCustomLobbyFade");
} // WOLLobbyMenuShutdown
static void fillPlayerInfo(const PeerResponse *resp, PlayerInfo *info)
{
info->m_name = resp->nick.c_str();
info->m_profileID = resp->player.profileID;
info->m_flags = resp->player.flags;
info->m_wins = resp->player.wins;
info->m_losses = resp->player.losses;
info->m_locale = resp->locale.c_str();
info->m_rankPoints= resp->player.rankPoints;
info->m_side = resp->player.side;
info->m_preorder = resp->player.preorder;
}
#ifdef PERF_TEST
static const char* getMessageString(Int t)
{
switch(t)
{
case PeerResponse::PEERRESPONSE_LOGIN:
return "login";
case PeerResponse::PEERRESPONSE_DISCONNECT:
return "disconnect";
case PeerResponse::PEERRESPONSE_MESSAGE:
return "message";
case PeerResponse::PEERRESPONSE_GROUPROOM:
return "group room";
case PeerResponse::PEERRESPONSE_STAGINGROOM:
return "staging room";
case PeerResponse::PEERRESPONSE_STAGINGROOMPLAYERINFO:
return "staging room player info";
case PeerResponse::PEERRESPONSE_JOINGROUPROOM:
return "group room join";
case PeerResponse::PEERRESPONSE_CREATESTAGINGROOM:
return "staging room create";
case PeerResponse::PEERRESPONSE_JOINSTAGINGROOM:
return "staging room join";
case PeerResponse::PEERRESPONSE_PLAYERJOIN:
return "player join";
case PeerResponse::PEERRESPONSE_PLAYERLEFT:
return "player part";
case PeerResponse::PEERRESPONSE_PLAYERCHANGEDNICK:
return "player nick";
case PeerResponse::PEERRESPONSE_PLAYERINFO:
return "player info";
case PeerResponse::PEERRESPONSE_PLAYERCHANGEDFLAGS:
return "player flags";
case PeerResponse::PEERRESPONSE_ROOMUTM:
return "room UTM";
case PeerResponse::PEERRESPONSE_PLAYERUTM:
return "player UTM";
case PeerResponse::PEERRESPONSE_QUICKMATCHSTATUS:
return "QM status";
case PeerResponse::PEERRESPONSE_GAMESTART:
return "game start";
case PeerResponse::PEERRESPONSE_FAILEDTOHOST:
return "host failure";
}
return "unknown";
}
#endif // PERF_TEST
//-------------------------------------------------------------------------------------------------
/** refreshGameList
The Bool is used to force refresh if the refresh button was hit.*/
//-------------------------------------------------------------------------------------------------
static void refreshGameList( Bool forceRefresh )
{
Int refreshInterval = gameListRefreshInterval;
if (forceRefresh || ((gameListRefreshTime == 0) || ((gameListRefreshTime + refreshInterval) <= timeGetTime())))
{
if (TheGameSpyInfo->hasStagingRoomListChanged())
{
//DEBUG_LOG(("################### refreshing game list\n"));
//DEBUG_LOG(("gameRefreshTime=%d, refreshInterval=%d, now=%d\n", gameListRefreshTime, refreshInterval, timeGetTime()));
RefreshGameListBoxes();
gameListRefreshTime = timeGetTime();
} else {
//DEBUG_LOG(("-"));
}
} else {
//DEBUG_LOG(("gameListRefreshTime: %d refreshInterval: %d\n"));
}
}
//-------------------------------------------------------------------------------------------------
/** refreshPlayerList
The Bool is used to force refresh if the refresh button was hit.*/
//-------------------------------------------------------------------------------------------------
static void refreshPlayerList( Bool forceRefresh )
{
Int refreshInterval = playerListRefreshInterval;
if (forceRefresh ||((playerListRefreshTime == 0) || ((playerListRefreshTime + refreshInterval) <= timeGetTime())))
{
PopulateLobbyPlayerListbox();
playerListRefreshTime = timeGetTime();
}
}
//-------------------------------------------------------------------------------------------------
/** WOL Lobby Menu update method */
//-------------------------------------------------------------------------------------------------
void WOLLobbyMenuUpdate( WindowLayout * layout, void *userData)
{
if(justEntered)
{
if(initialGadgetDelay == 1)
{
TheTransitionHandler->remove("MainMenuDefaultMenuLogoFade");
TheTransitionHandler->setGroup("WOLCustomLobbyFade");
initialGadgetDelay = 2;
justEntered = FALSE;
}
else
initialGadgetDelay--;
}
if (TheGameLogic->isInShellGame() && TheGameLogic->getFrame() == 1)
{
SignalUIInteraction(SHELL_SCRIPT_HOOK_GENERALS_ONLINE_ENTERED_FROM_GAME);
}
// We'll only be successful if we've requested to
if(isShuttingDown && TheShell->isAnimFinished() && TheTransitionHandler->isFinished())
shutdownComplete(layout);
if (raiseMessageBoxes)
{
RaiseGSMessageBox();
raiseMessageBoxes = false;
}
if (TheShell->isAnimFinished() && TheTransitionHandler->isFinished() && !buttonPushed && TheGameSpyPeerMessageQueue)
{
HandleBuddyResponses();
HandlePersistentStorageResponses();
#ifdef PERF_TEST
UnsignedInt start = timeGetTime();
UnsignedInt end = timeGetTime();
std::list responses;
Int numMessages = 0;
#endif // PERF_TEST
Int allowedMessages = TheGameSpyInfo->getMaxMessagesPerUpdate();
Bool sawImportantMessage = FALSE;
Bool shouldRepopulatePlayers = FALSE;
PeerResponse resp;
while (allowedMessages-- && !sawImportantMessage && TheGameSpyPeerMessageQueue->getResponse( resp ))
{
#ifdef PERF_TEST
++numMessages;
responses.push_back(resp.peerResponseType);
#endif // PERF_TEST
switch (resp.peerResponseType)
{
case PeerResponse::PEERRESPONSE_JOINGROUPROOM:
sawImportantMessage = TRUE;
if (resp.joinGroupRoom.ok)
{
//buttonPushed = true;
TheGameSpyInfo->setCurrentGroupRoom(resp.joinGroupRoom.id);
TheGameSpyInfo->getPlayerInfoMap()->clear();
GroupRoomMap::iterator iter = TheGameSpyInfo->getGroupRoomList()->find(resp.joinGroupRoom.id);
if (iter != TheGameSpyInfo->getGroupRoomList()->end())
{
GameSpyGroupRoom room = iter->second;
UnicodeString msg;
msg.format(TheGameText->fetch("GUI:LobbyJoined"), room.m_translatedName.str());
TheGameSpyInfo->addText(msg, GameSpyColor[GSCOLOR_DEFAULT], NULL);
}
}
else
{
DEBUG_LOG(("WOLLobbyMenuUpdate() - joining best group room\n"));
TheGameSpyInfo->joinBestGroupRoom();
}
populateGroupRoomListbox(comboLobbyGroupRooms);
shouldRepopulatePlayers = TRUE;
break;
case PeerResponse::PEERRESPONSE_PLAYERCHANGEDFLAGS:
{
PlayerInfo p;
fillPlayerInfo(&resp, &p);
TheGameSpyInfo->updatePlayerInfo(p);
shouldRepopulatePlayers = TRUE;
}
break;
case PeerResponse::PEERRESPONSE_PLAYERCHANGEDNICK:
{
PlayerInfo p;
fillPlayerInfo(&resp, &p);
TheGameSpyInfo->updatePlayerInfo(p);
shouldRepopulatePlayers = TRUE;
}
break;
case PeerResponse::PEERRESPONSE_PLAYERINFO:
{
PlayerInfo p;
fillPlayerInfo(&resp, &p);
TheGameSpyInfo->updatePlayerInfo(p);
shouldRepopulatePlayers = TRUE;
}
break;
case PeerResponse::PEERRESPONSE_PLAYERJOIN:
{
if (resp.player.roomType == GroupRoom)
{
PlayerInfo p;
fillPlayerInfo(&resp, &p);
TheGameSpyInfo->updatePlayerInfo(p);
shouldRepopulatePlayers = TRUE;
}
}
break;
case PeerResponse::PEERRESPONSE_PLAYERUTM:
case PeerResponse::PEERRESPONSE_ROOMUTM:
{
DEBUG_LOG(("Putting off a UTM in the lobby\n"));
TheLobbyQueuedUTMs.push_back(resp);
}
break;
case PeerResponse::PEERRESPONSE_PLAYERLEFT:
{
PlayerInfo p;
fillPlayerInfo(&resp, &p);
TheGameSpyInfo->playerLeftGroupRoom(resp.nick.c_str());
shouldRepopulatePlayers = TRUE;
}
break;
case PeerResponse::PEERRESPONSE_MESSAGE:
{
TheGameSpyInfo->addChat(resp.nick.c_str(), resp.message.profileID,
UnicodeString(resp.text.c_str()), !resp.message.isPrivate, resp.message.isAction, listboxLobbyChat);
}
break;
case PeerResponse::PEERRESPONSE_DISCONNECT:
{
sawImportantMessage = TRUE;
UnicodeString title, body;
AsciiString disconMunkee;
disconMunkee.format("GUI:GSDisconReason%d", resp.discon.reason);
title = TheGameText->fetch( "GUI:GSErrorTitle" );
body = TheGameText->fetch( disconMunkee );
GameSpyCloseAllOverlays();
GSMessageBoxOk( title, body );
TheGameSpyInfo->reset();
TheShell->pop();
}
case PeerResponse::PEERRESPONSE_CREATESTAGINGROOM:
{
sawImportantMessage = TRUE;
SetLobbyAttemptHostJoin(FALSE);
if (resp.createStagingRoom.result == PEERJoinSuccess)
{
// Woohoo! On to our next screen!
buttonPushed = true;
nextScreen = "Menus/GameSpyGameOptionsMenu.wnd";
TheShell->pop();
TheGameSpyInfo->markAsStagingRoomHost();
TheGameSpyInfo->setGameOptions();
}
}
break;
case PeerResponse::PEERRESPONSE_JOINSTAGINGROOM:
{
sawImportantMessage = TRUE;
SetLobbyAttemptHostJoin(FALSE);
Bool isHostPresent = TRUE;
if (resp.joinStagingRoom.ok == PEERTrue)
{
GameSpyStagingRoom *room = TheGameSpyInfo->getCurrentStagingRoom();
if (!room)
{
isHostPresent = FALSE;
}
else
{
isHostPresent = FALSE;
for (Int i=0; igetConstSlot(0)->getName());
const char *firstPlayer = resp.stagingRoomPlayerNames[i].c_str();
if (!strcmp(hostName.str(), firstPlayer))
{
DEBUG_LOG(("Saw host %s == %s in slot %d\n", hostName.str(), firstPlayer, i));
isHostPresent = TRUE;
}
}
}
}
if (resp.joinStagingRoom.ok == PEERTrue && isHostPresent)
{
// Woohoo! On to our next screen!
buttonPushed = true;
nextScreen = "Menus/GameSpyGameOptionsMenu.wnd";
TheShell->pop();
}
else
{
UnicodeString s;
switch(resp.joinStagingRoom.result)
{
case PEERFullRoom: // The room is full.
s = TheGameText->fetch("GUI:JoinFailedRoomFull");
break;
case PEERInviteOnlyRoom: // The room is invite only.
s = TheGameText->fetch("GUI:JoinFailedInviteOnly");
break;
case PEERBannedFromRoom: // The local user is banned from the room.
s = TheGameText->fetch("GUI:JoinFailedBannedFromRoom");
break;
case PEERBadPassword: // An incorrect password (or none) was given for a passworded room.
s = TheGameText->fetch("GUI:JoinFailedBadPassword");
break;
case PEERAlreadyInRoom: // The local user is already in or entering a room of the same type.
s = TheGameText->fetch("GUI:JoinFailedAlreadyInRoom");
break;
case PEERNoConnection: // Can't join a room if there's no chat connection.
s = TheGameText->fetch("GUI:JoinFailedNoConnection");
break;
default:
s = TheGameText->fetch("GUI:JoinFailedDefault");
break;
}
GSMessageBoxOk(TheGameText->fetch("GUI:JoinFailedDefault"), s);
if (groupRoomToJoin)
{
DEBUG_LOG(("WOLLobbyMenuUpdate() - rejoining group room %d\n", groupRoomToJoin));
TheGameSpyInfo->joinGroupRoom(groupRoomToJoin);
groupRoomToJoin = 0;
}
else
{
DEBUG_LOG(("WOLLobbyMenuUpdate() - joining best group room\n"));
TheGameSpyInfo->joinBestGroupRoom();
}
}
}
break;
case PeerResponse::PEERRESPONSE_STAGINGROOMLISTCOMPLETE:
TheGameSpyInfo->sawFullGameList();
break;
case PeerResponse::PEERRESPONSE_STAGINGROOM:
{
GameSpyStagingRoom room;
switch(resp.stagingRoom.action)
{
case PEER_CLEAR:
TheGameSpyInfo->clearStagingRoomList();
//TheGameSpyInfo->addText( UnicodeString(L"gameList: PEER_CLEAR"), GameSpyColor[GSCOLOR_DEFAULT], listboxLobbyChat );
break;
case PEER_ADD:
case PEER_UPDATE:
{
if (resp.stagingRoom.percentComplete == 100)
{
TheGameSpyInfo->sawFullGameList();
}
//if (ParseAsciiStringToGameInfo(&room, resp.stagingRoomMapName.c_str()))
//if (ParseAsciiStringToGameInfo(&room, resp.stagingServerGameOptions.c_str()))
Bool serverOk = TRUE;
if (!resp.stagingRoomMapName.length())
{
serverOk = FALSE;
}
// fix for ghost game problem - need to iterate over all resp.stagingRoomPlayerNames[i]
Bool sawSelf = FALSE;
//for (Int i=0; igetLocalName() == resp.stagingRoomPlayerNames[0].c_str())
{
sawSelf = TRUE; // don't show ghost games for myself
}
//}
if (sawSelf)
serverOk = FALSE;
if (serverOk)
{
room.setGameName(UnicodeString(resp.stagingServerName.c_str()));
room.setID(resp.stagingRoom.id);
room.setHasPassword(resp.stagingRoom.requiresPassword);
room.setVersion(resp.stagingRoom.version);
room.setExeCRC(resp.stagingRoom.exeCRC);
room.setIniCRC(resp.stagingRoom.iniCRC);
room.setAllowObservers(resp.stagingRoom.allowObservers);
room.setUseStats(resp.stagingRoom.useStats);
room.setPingString(resp.stagingServerPingString.c_str());
room.setLadderIP(resp.stagingServerLadderIP.c_str());
room.setLadderPort(resp.stagingRoom.ladderPort);
room.setReportedNumPlayers(resp.stagingRoom.numPlayers);
room.setReportedMaxPlayers(resp.stagingRoom.maxPlayers);
room.setReportedNumObservers(resp.stagingRoom.numObservers);
Int i;
AsciiString gsMapName = resp.stagingRoomMapName.c_str();
AsciiString mapName = "";
for (i=0; iportableMapPathToRealMapPath(mapName));
Int numPlayers = 0;
for (i=0; isetWins( resp.stagingRoom.wins[i] );
slot->setLosses( resp.stagingRoom.losses[i] );
slot->setProfileID( resp.stagingRoom.profileID[i] );
slot->setPlayerTemplate( resp.stagingRoom.faction[i] );
slot->setColor( resp.stagingRoom.color[i] );
if (resp.stagingRoom.profileID[i] == SLOT_EASY_AI)
{
slot->setState(SLOT_EASY_AI);
++numPlayers;
}
else if (resp.stagingRoom.profileID[i] == SLOT_MED_AI)
{
slot->setState(SLOT_MED_AI);
++numPlayers;
}
else if (resp.stagingRoom.profileID[i] == SLOT_BRUTAL_AI)
{
slot->setState(SLOT_BRUTAL_AI);
++numPlayers;
}
else if (resp.stagingRoomPlayerNames[i].length())
{
UnicodeString nameUStr;
nameUStr.translate(resp.stagingRoomPlayerNames[i].c_str());
slot->setState(SLOT_PLAYER, nameUStr);
++numPlayers;
}
else
{
slot->setState(SLOT_OPEN);
}
}
}
DEBUG_ASSERTCRASH(numPlayers, ("Game had no players!\n"));
//DEBUG_LOG(("Saw room: hasPass=%d, allowsObservers=%d\n", room.getHasPassword(), room.getAllowObservers()));
if (resp.stagingRoom.action == PEER_ADD)
{
TheGameSpyInfo->addStagingRoom(room);
//TheGameSpyInfo->addText( UnicodeString(L"gameList: PEER_ADD"), GameSpyColor[GSCOLOR_DEFAULT], listboxLobbyChat );
}
else
{
TheGameSpyInfo->updateStagingRoom(room);
//TheGameSpyInfo->addText( UnicodeString(L"gameList: PEER_UPDATE"), GameSpyColor[GSCOLOR_DEFAULT], listboxLobbyChat );
}
}
else
{
room.setID(resp.stagingRoom.id);
TheGameSpyInfo->removeStagingRoom(room);
//TheGameSpyInfo->addText( UnicodeString(L"gameList: PEER_UPDATE FAILED"), GameSpyColor[GSCOLOR_DEFAULT], listboxLobbyChat );
}
break;
}
case PEER_REMOVE:
room.setID(resp.stagingRoom.id);
TheGameSpyInfo->removeStagingRoom(room);
//TheGameSpyInfo->addText( UnicodeString(L"gameList: PEER_REMOVE"), GameSpyColor[GSCOLOR_DEFAULT], listboxLobbyChat );
break;
default:
//TheGameSpyInfo->addText( UnicodeString(L"gameList: Unknown"), GameSpyColor[GSCOLOR_DEFAULT], listboxLobbyChat );
break;
}
}
break;
}
}
#if 0
if (shouldRepopulatePlayers)
{
PopulateLobbyPlayerListbox();
}
#else
refreshPlayerList();
#endif
#ifdef PERF_TEST
// check performance
end = timeGetTime();
PERF_LOG(("Frame time was %d ms\n", end-start));
std::list::const_iterator it;
for (it = responses.begin(); it != responses.end(); ++it)
{
PERF_LOG((" %s\n", getMessageString(*it)));
}
PERF_LOG(("\n"));
#endif // PERF_TEST
#if 0
// Removed 2-17-03 to pull out into a function so we can do the same checks
Int refreshInterval = gameListRefreshInterval;
if ((gameListRefreshTime == 0) || ((gameListRefreshTime + refreshInterval) <= timeGetTime()))
{
if (TheGameSpyInfo->hasStagingRoomListChanged())
{
//DEBUG_LOG(("################### refreshing game list\n"));
//DEBUG_LOG(("gameRefreshTime=%d, refreshInterval=%d, now=%d\n", gameListRefreshTime, refreshInterval, timeGetTime()));
RefreshGameListBoxes();
gameListRefreshTime = timeGetTime();
} else {
//DEBUG_LOG(("-"));
}
} else {
//DEBUG_LOG(("gameListRefreshTime: %d refreshInterval: %d\n"));
}
#else
refreshGameList();
#endif
}
}// WOLLobbyMenuUpdate
//-------------------------------------------------------------------------------------------------
/** WOL Lobby Menu input callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType WOLLobbyMenuInput( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
switch( msg )
{
// --------------------------------------------------------------------------------------------
case GWM_CHAR:
{
UnsignedByte key = mData1;
UnsignedByte state = mData2;
if (buttonPushed)
break;
switch( key )
{
// ----------------------------------------------------------------------------------------
case KEY_ESC:
{
//
// send a simulated selected event to the parent window of the
// back/exit button
//
if( BitTest( state, KEY_STATE_UP ) )
{
TheWindowManager->winSendSystemMsg( window, GBM_SELECTED,
(WindowMsgData)buttonBack, buttonBackID );
} // end if
// don't let key fall through anywhere else
return MSG_HANDLED;
} // end escape
} // end switch( key )
} // end char
} // end switch( msg )
return MSG_IGNORED;
}// WOLLobbyMenuInput
//static void doSliderTrack(GameWindow *control, Int val)
//{
// Int sliderW, sliderH, sliderX, sliderY;
// control->winGetPosition(&sliderX, &sliderY);
// control->winGetSize(&sliderW, &sliderH);
// Real cursorY = sliderY + (100-val)*0.01f*sliderH;
//
// extern GameWindow *listboxLobbyGamesSmall;
// extern GameWindow *listboxLobbyGamesLarge;
// extern GameWindow *listboxLobbyGameInfo;
//
// static Int gwsX = 0, gwsY = 0, gwsW = 0, gwsH = 0;
// static Int gwlX = 0, gwlY = 0, gwlW = 0, gwlH = 0;
// static Int gwiX = 0, gwiY = 0, gwiW = 0, gwiH = 0;
// static Int pwX = 0, pwY = 0, pwW = 0, pwH = 0;
// static Int chatPosX = 0, chatPosY = 0, chatW = 0, chatH = 0;
// static Int spacing = 0;
// if (chatPosX == 0)
// {
// listboxLobbyChat->winGetPosition(&chatPosX, &chatPosY);
// listboxLobbyChat->winGetSize(&chatW, &chatH);
//
//// listboxLobbyGamesSmall->winGetPosition(&gwsX, &gwsY);
//// listboxLobbyGamesSmall->winGetSize(&gwsW, &gwsH);
//
// listboxLobbyGamesLarge->winGetPosition(&gwlX, &gwlY);
// listboxLobbyGamesLarge->winGetSize(&gwlW, &gwlH);
//
//// listboxLobbyGameInfo->winGetPosition(&gwiX, &gwiY);
//// listboxLobbyGameInfo->winGetSize(&gwiW, &gwiH);
////
// listboxLobbyPlayers->winGetPosition(&pwX, &pwY);
// listboxLobbyPlayers->winGetSize(&pwW, &pwH);
//
// spacing = chatPosY - pwY - pwH;
// }
//
// Int newChatY = cursorY;
// Int newChatH = chatH + chatPosY - newChatY;
// listboxLobbyChat->winSetPosition(chatPosX, newChatY);
// listboxLobbyChat->winSetSize(chatW, newChatH);
//
// Int newH = cursorY - pwY - spacing;
// listboxLobbyPlayers->winSetSize(pwW, newH);
//// listboxLobbyGamesSmall->winSetSize(gwsW, newH);
// listboxLobbyGamesLarge->winSetSize(gwlW, newH);
//// listboxLobbyGameInfo->winSetSize(gwiW, newH);
//-------------------------------------------------------------------------------------------------
/** WOL Lobby Menu window system callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType WOLLobbyMenuSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
UnicodeString txtInput;
static NameKeyType buttonGameListTypeToggleID = NAMEKEY_INVALID;
switch( msg )
{
//---------------------------------------------------------------------------------------------
case GWM_CREATE:
{
buttonGameListTypeToggleID = NAMEKEY("WOLCustomLobby.wnd:ButtonGameListToggle");
// sliderChatAdjustID = NAMEKEY("WOLCustomLobby.wnd:SliderChatAdjust");
break;
} // case GWM_DESTROY:
//---------------------------------------------------------------------------------------------
case GWM_DESTROY:
{
break;
} // case GWM_DESTROY:
//---------------------------------------------------------------------------------------------
case GWM_INPUT_FOCUS:
{
// if we're givin the opportunity to take the keyboard focus we must say we want it
if( mData1 == TRUE )
*(Bool *)mData2 = TRUE;
return MSG_HANDLED;
}//case GWM_INPUT_FOCUS:
//---------------------------------------------------------------------------------------------
case GLM_SELECTED:
{
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if ( controlID == GetGameListBoxID() )
{
int rowSelected = mData2;
if( rowSelected >= 0 )
{
buttonJoin->winEnable(TRUE);
static UnsignedInt lastFrame = 0;
static Int lastID = -1;
UnsignedInt now = TheGameClient->getFrame();
PeerRequest req;
req.peerRequestType = PeerRequest::PEERREQUEST_GETEXTENDEDSTAGINGROOMINFO;
req.stagingRoom.id = (Int)GadgetListBoxGetItemData(control, rowSelected, 0);
if (lastID != req.stagingRoom.id || now > lastFrame + 60)
{
TheGameSpyPeerMessageQueue->addRequest(req);
}
lastID = req.stagingRoom.id;
lastFrame = now;
}
else
{
buttonJoin->winEnable(FALSE);
}
if (GetGameInfoListBox())
{
RefreshGameInfoListBox(GetGameListBox(), GetGameInfoListBox());
}
} //if ( controlID == GetGameListBoxID() )
break;
}
//---------------------------------------------------------------------------------------------
case GBM_SELECTED:
{
if (buttonPushed)
break;
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if (HandleSortButton((NameKeyType)controlID))
break;
// If we back out, just bail - we haven't gotten far enough to need to log out
if ( controlID == buttonBackID )
{
if (s_tryingToHostOrJoin)
break;
// Leave any group room, then pop off the screen
TheGameSpyInfo->leaveGroupRoom();
SetLobbyAttemptHostJoin( TRUE ); // pretend, since we don't want to queue up another action
buttonPushed = true;
nextScreen = "Menus/WOLWelcomeMenu.wnd";
TheShell->pop();
} //if ( controlID == buttonBack )
else if ( controlID == buttonRefreshID )
{
// Added 2/17/03 added the game refresh button
refreshGameList(TRUE);
refreshPlayerList(TRUE);
}
else if ( controlID == buttonHostID )
{
if (s_tryingToHostOrJoin)
break;
SetLobbyAttemptHostJoin( TRUE );
TheLobbyQueuedUTMs.clear();
groupRoomToJoin = TheGameSpyInfo->getCurrentGroupRoom();
GameSpyOpenOverlay(GSOVERLAY_GAMEOPTIONS);
}
else if ( controlID == buttonJoinID )
{
if (s_tryingToHostOrJoin)
break;
TheLobbyQueuedUTMs.clear();
// Look for a game to join
groupRoomToJoin = TheGameSpyInfo->getCurrentGroupRoom();
Int selected;
GadgetListBoxGetSelected(GetGameListBox(), &selected);
if (selected >= 0)
{
Int selectedID = (Int)GadgetListBoxGetItemData(GetGameListBox(), selected);
if (selectedID > 0)
{
StagingRoomMap *srm = TheGameSpyInfo->getStagingRoomList();
StagingRoomMap::iterator srmIt = srm->find(selectedID);
if (srmIt != srm->end())
{
GameSpyStagingRoom *roomToJoin = srmIt->second;
if (!roomToJoin || roomToJoin->getExeCRC() != TheGlobalData->m_exeCRC || roomToJoin->getIniCRC() != TheGlobalData->m_iniCRC)
{
// bad crc. don't go.
DEBUG_LOG(("WOLLobbyMenuSystem - CRC mismatch with the game I'm trying to join. My CRC's - EXE:0x%08X INI:0x%08X Their CRC's - EXE:0x%08x INI:0x%08x\n", TheGlobalData->m_exeCRC, TheGlobalData->m_iniCRC, roomToJoin->getExeCRC(), roomToJoin->getIniCRC()));
#if defined(_DEBUG) || defined(_INTERNAL)
if (TheGlobalData->m_netMinPlayers)
{
GSMessageBoxOk(TheGameText->fetch("GUI:JoinFailedDefault"), TheGameText->fetch("GUI:JoinFailedCRCMismatch"));
break;
}
else if (g_fakeCRC)
{
TheWritableGlobalData->m_exeCRC = roomToJoin->getExeCRC();
TheWritableGlobalData->m_iniCRC = roomToJoin->getIniCRC();
}
#else
GSMessageBoxOk(TheGameText->fetch("GUI:JoinFailedDefault"), TheGameText->fetch("GUI:JoinFailedCRCMismatch"));
break;
#endif
}
Bool unknownLadder = (roomToJoin->getLadderPort() && TheLadderList->findLadder(roomToJoin->getLadderIP(), roomToJoin->getLadderPort()) == NULL);
if (unknownLadder)
{
GSMessageBoxOk(TheGameText->fetch("GUI:JoinFailedDefault"), TheGameText->fetch("GUI:JoinFailedUnknownLadder"));
break;
}
if (roomToJoin->getNumPlayers() == MAX_SLOTS)
{
GSMessageBoxOk(TheGameText->fetch("GUI:JoinFailedDefault"), TheGameText->fetch("GUI:JoinFailedRoomFull"));
break;
}
TheGameSpyInfo->markAsStagingRoomJoiner(selectedID);
TheGameSpyGame->setGameName(roomToJoin->getGameName());
TheGameSpyGame->setLadderIP(roomToJoin->getLadderIP());
TheGameSpyGame->setLadderPort(roomToJoin->getLadderPort());
SetLobbyAttemptHostJoin( TRUE );
if (roomToJoin->getHasPassword())
{
GameSpyOpenOverlay(GSOVERLAY_GAMEPASSWORD);
}
else
{
// no password - just join it
PeerRequest req;
req.peerRequestType = PeerRequest::PEERREQUEST_JOINSTAGINGROOM;
req.text = srmIt->second->getGameName().str();
req.stagingRoom.id = selectedID;
req.password = "";
TheGameSpyPeerMessageQueue->addRequest(req);
}
}
}
else
{
GSMessageBoxOk(TheGameText->fetch("GUI:Error"), TheGameText->fetch("GUI:NoGameInfo"), NULL);
}
}
else
{
GSMessageBoxOk(TheGameText->fetch("GUI:Error"), TheGameText->fetch("GUI:NoGameSelected"), NULL);
}
}
else if ( controlID == buttonBuddyID )
{
GameSpyToggleOverlay( GSOVERLAY_BUDDY );
}
else if ( controlID == buttonGameListTypeToggleID )
{
ToggleGameListType();
}
else if ( controlID == buttonEmoteID )
{
// read the user's input and clear the entry box
UnicodeString txtInput;
txtInput.set(GadgetTextEntryGetText( textEntryChat ));
GadgetTextEntrySetText(textEntryChat, UnicodeString::TheEmptyString);
txtInput.trim();
if (!txtInput.isEmpty())
{
// Send the message
TheGameSpyInfo->sendChat( txtInput, FALSE, listboxLobbyPlayers ); // 'emote' button now just sends text
}
}
break;
}// case GBM_SELECTED:
//---------------------------------------------------------------------------------------------
case GCM_SELECTED:
{
if (s_tryingToHostOrJoin)
break;
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if( controlID == comboLobbyGroupRoomsID )
{
int rowSelected = -1;
GadgetComboBoxGetSelectedPos(control, &rowSelected);
DEBUG_LOG(("Row selected = %d\n", rowSelected));
if (rowSelected >= 0)
{
Int groupID;
groupID = (Int)GadgetComboBoxGetItemData(comboLobbyGroupRooms, rowSelected);
DEBUG_LOG(("ItemData was %d, current Group Room is %d\n", groupID, TheGameSpyInfo->getCurrentGroupRoom()));
if (groupID && groupID != TheGameSpyInfo->getCurrentGroupRoom())
{
TheGameSpyInfo->leaveGroupRoom();
TheGameSpyInfo->joinGroupRoom(groupID);
if (TheGameSpyConfig->restrictGamesToLobby())
{
TheGameSpyInfo->clearStagingRoomList();
RefreshGameListBoxes();
PeerRequest req;
req.peerRequestType = PeerRequest::PEERREQUEST_STARTGAMELIST;
req.gameList.restrictGameList = TRUE;
TheGameSpyPeerMessageQueue->addRequest(req);
}
}
}
}
} // case GCM_SELECTED
break;
//---------------------------------------------------------------------------------------------
case GLM_DOUBLE_CLICKED:
{
if (buttonPushed)
break;
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if (controlID == GetGameListBoxID())
{
int rowSelected = mData2;
if (rowSelected >= 0)
{
GadgetListBoxSetSelected( control, rowSelected );
GameWindow *button = TheWindowManager->winGetWindowFromId( window, buttonJoinID );
TheWindowManager->winSendSystemMsg( window, GBM_SELECTED,
(WindowMsgData)button, buttonJoinID );
}
}
break;
}// case GLM_DOUBLE_CLICKED:
//---------------------------------------------------------------------------------------------
case GLM_RIGHT_CLICKED:
{
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if( controlID == listboxLobbyPlayersID )
{
RightClickStruct *rc = (RightClickStruct *)mData2;
WindowLayout *rcLayout = NULL;
GameWindow *rcMenu;
if(rc->pos < 0)
{
GadgetListBoxSetSelected(control, -1);
break;
}
GPProfile profileID = 0;
AsciiString aName;
aName.translate(GadgetListBoxGetText(control, rc->pos, COLUMN_PLAYERNAME));
PlayerInfoMap::iterator it = TheGameSpyInfo->getPlayerInfoMap()->find(aName);
if (it != TheGameSpyInfo->getPlayerInfoMap()->end())
profileID = it->second.m_profileID;
Bool isBuddy = FALSE;
if (profileID <= 0)
rcLayout = TheWindowManager->winCreateLayout(AsciiString("Menus/RCNoProfileMenu.wnd"));
else
{
if (profileID == TheGameSpyInfo->getLocalProfileID())
{
rcLayout = TheWindowManager->winCreateLayout(AsciiString("Menus/RCLocalPlayerMenu.wnd"));
}
else if(TheGameSpyInfo->isBuddy(profileID))
{
rcLayout = TheWindowManager->winCreateLayout(AsciiString("Menus/RCBuddiesMenu.wnd"));
isBuddy = TRUE;
}
else
rcLayout = TheWindowManager->winCreateLayout(AsciiString("Menus/RCNonBuddiesMenu.wnd"));
}
if(!rcLayout)
break;
GadgetListBoxSetSelected(control, rc->pos);
rcMenu = rcLayout->getFirstWindow();
rcMenu->winGetLayout()->runInit();
rcMenu->winBringToTop();
rcMenu->winHide(FALSE);
setUnignoreText( rcLayout, aName, profileID);
ICoord2D rcSize, rcPos;
rcMenu->winGetSize(&rcSize.x, &rcSize.y);
rcPos.x = rc->mouseX;
rcPos.y = rc->mouseY;
if(rc->mouseX + rcSize.x > TheDisplay->getWidth())
rcPos.x = TheDisplay->getWidth() - rcSize.x;
if(rc->mouseY + rcSize.y > TheDisplay->getHeight())
rcPos.y = TheDisplay->getHeight() - rcSize.y;
rcMenu->winSetPosition(rcPos.x, rcPos.y);
GameSpyRCMenuData *rcData = NEW GameSpyRCMenuData;
rcData->m_id = profileID;
rcData->m_nick = aName;
rcData->m_itemType = (isBuddy)?ITEM_BUDDY:ITEM_NONBUDDY;
rcMenu->winSetUserData((void *)rcData);
TheWindowManager->winSetLoneWindow(rcMenu);
}
else if( controlID == GetGameListBoxID() )
{
RightClickStruct *rc = (RightClickStruct *)mData2;
WindowLayout *rcLayout = NULL;
GameWindow *rcMenu;
if(rc->pos < 0)
{
GadgetListBoxSetSelected(control, -1);
break;
}
Int selectedID = (Int)GadgetListBoxGetItemData(control, rc->pos);
if (selectedID > 0)
{
StagingRoomMap *srm = TheGameSpyInfo->getStagingRoomList();
StagingRoomMap::iterator srmIt = srm->find(selectedID);
if (srmIt != srm->end())
{
GameSpyStagingRoom *theRoom = srmIt->second;
if (!theRoom)
break;
const LadderInfo *linfo = TheLadderList->findLadder(theRoom->getLadderIP(), theRoom->getLadderPort());
if (linfo)
{
rcLayout = TheWindowManager->winCreateLayout(AsciiString("Menus/RCGameDetailsMenu.wnd"));
if (!rcLayout)
break;
GadgetListBoxSetSelected(control, rc->pos);
rcMenu = rcLayout->getFirstWindow();
rcMenu->winGetLayout()->runInit();
rcMenu->winBringToTop();
rcMenu->winHide(FALSE);
rcMenu->winSetPosition(rc->mouseX, rc->mouseY);
rcMenu->winSetUserData((void *)selectedID);
TheWindowManager->winSetLoneWindow(rcMenu);
}
}
}
}
break;
}
// //---------------------------------------------------------------------------------------------
// case GSM_SLIDER_TRACK:
// {
// if (buttonPushed)
// break;
//
// GameWindow *control = (GameWindow *)mData1;
// Int val = (Int)mData2;
// Int controlID = control->winGetWindowId();
// if (controlID == sliderChatAdjustID)
// {
// doSliderTrack(control, val);
// }
// break;
// }
//---------------------------------------------------------------------------------------------
case GEM_EDIT_DONE:
{
if (buttonPushed)
break;
// read the user's input and clear the entry box
UnicodeString txtInput;
txtInput.set(GadgetTextEntryGetText( textEntryChat ));
GadgetTextEntrySetText(textEntryChat, UnicodeString::TheEmptyString);
txtInput.trim();
if (!txtInput.isEmpty())
{
// Send the message
if (!handleLobbySlashCommands(txtInput))
{
TheGameSpyInfo->sendChat( txtInput, false, listboxLobbyPlayers );
}
}
break;
}
//---------------------------------------------------------------------------------------------
default:
return MSG_IGNORED;
}//Switch
return MSG_HANDLED;
}// WOLLobbyMenuSystem