/* ** 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: WOLMapSelectMenu.cpp //////////////////////////////////////////////////////////////////////// // Author: Matt Campbell, December 2001 // Description: MapSelect menu window callbacks /////////////////////////////////////////////////////////////////////////////////////////////////// // INCLUDES /////////////////////////////////////////////////////////////////////////////////////// #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine #include "Common/CustomMatchPreferences.h" #include "Common/GameEngine.h" #include "Common/MessageStream.h" #include "GameClient/WindowLayout.h" #include "GameClient/Gadget.h" #include "GameClient/GadgetRadioButton.h" #include "GameClient/Shell.h" #include "GameClient/GameWindowManager.h" #include "GameClient/GadgetListBox.h" #include "GameNetwork/GameSpy/PeerDefs.h" #include "GameNetwork/GameSpyOverlay.h" #include "GameClient/MapUtil.h" #include "GameNetwork/GUIUtil.h" #ifdef _INTERNAL // for occasional debugging... //#pragma optimize("", off) //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes") #endif // PRIVATE DATA /////////////////////////////////////////////////////////////////////////////////// static NameKeyType buttonBack = NAMEKEY_INVALID; static NameKeyType buttonOK = NAMEKEY_INVALID; static NameKeyType listboxMap = NAMEKEY_INVALID; static GameWindow *parent = NULL; static Bool raiseMessageBoxes = FALSE; static GameWindow *winMapPreview = NULL; static NameKeyType winMapPreviewID = NAMEKEY_INVALID; static NameKeyType radioButtonSystemMapsID = NAMEKEY_INVALID; static NameKeyType radioButtonUserMapsID = NAMEKEY_INVALID; extern WindowLayout *WOLMapSelectLayout; ///< Map selection overlay static GameWindow *mapList = NULL; static GameWindow *buttonMapStartPosition[MAX_SLOTS] = {NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL }; static NameKeyType buttonMapStartPositionID[MAX_SLOTS] = { NAMEKEY_INVALID,NAMEKEY_INVALID, NAMEKEY_INVALID,NAMEKEY_INVALID, NAMEKEY_INVALID,NAMEKEY_INVALID, NAMEKEY_INVALID,NAMEKEY_INVALID }; static GameWindow *winMapWindow = NULL; static void NullifyControls(void) { parent = NULL; winMapPreview = NULL; mapList = NULL; for (Int i=0; iwinGetWindowFromId( NULL, TheNameKeyGenerator->nameToKey("GameSpyGameOptionsMenu.wnd:ButtonBack") ); if(win) win->winEnable( show ); } // PUBLIC FUNCTIONS /////////////////////////////////////////////////////////////////////////////// //------------------------------------------------------------------------------------------------- /** Initialize the MapSelect menu */ //------------------------------------------------------------------------------------------------- void WOLMapSelectMenuInit( WindowLayout *layout, void *userData ) { // set keyboard focus to main parent AsciiString parentName( "WOLMapSelectMenu.wnd:WOLMapSelectMenuParent" ); NameKeyType parentID = TheNameKeyGenerator->nameToKey( parentName ); parent = TheWindowManager->winGetWindowFromId( NULL, parentID ); TheWindowManager->winSetFocus( parent ); CustomMatchPreferences pref; Bool usesSystemMapDir = pref.usesSystemMapDir(); winMapPreviewID = TheNameKeyGenerator->nameToKey( AsciiString("WOLMapSelectMenu.wnd:WinMapPreview") ); winMapPreview = TheWindowManager->winGetWindowFromId(parent, winMapPreviewID); const MapMetaData *mmd = TheMapCache->findMap(TheGameSpyGame->getMap()); if (mmd) { usesSystemMapDir = mmd->m_isOfficial; } //if stats are enabled, only official maps can be used if( TheGameSpyInfo->getCurrentStagingRoom()->getUseStats() ) usesSystemMapDir = true; buttonBack = TheNameKeyGenerator->nameToKey( AsciiString("WOLMapSelectMenu.wnd:ButtonBack") ); buttonOK = TheNameKeyGenerator->nameToKey( AsciiString("WOLMapSelectMenu.wnd:ButtonOK") ); listboxMap = TheNameKeyGenerator->nameToKey( AsciiString("WOLMapSelectMenu.wnd:ListboxMap") ); radioButtonSystemMapsID = TheNameKeyGenerator->nameToKey( "WOLMapSelectMenu.wnd:RadioButtonSystemMaps" ); radioButtonUserMapsID = TheNameKeyGenerator->nameToKey( "WOLMapSelectMenu.wnd:RadioButtonUserMaps" ); winMapWindow = TheWindowManager->winGetWindowFromId( parent, listboxMap ); GameWindow *radioButtonSystemMaps = TheWindowManager->winGetWindowFromId( parent, radioButtonSystemMapsID ); GameWindow *radioButtonUserMaps = TheWindowManager->winGetWindowFromId( parent, radioButtonUserMapsID ); if( TheGameSpyInfo->getCurrentStagingRoom()->getUseStats() ) { //disable unofficial maps if stats are being recorded GadgetRadioSetSelection( radioButtonSystemMaps, FALSE ); radioButtonUserMaps->winEnable( FALSE ); } else if (usesSystemMapDir) GadgetRadioSetSelection( radioButtonSystemMaps, FALSE ); else GadgetRadioSetSelection( radioButtonUserMaps, FALSE ); AsciiString tmpString; for (Int i = 0; i < MAX_SLOTS; i++) { tmpString.format("WOLMapSelectMenu.wnd:ButtonMapStartPosition%d", i); buttonMapStartPositionID[i] = TheNameKeyGenerator->nameToKey( tmpString ); buttonMapStartPosition[i] = TheWindowManager->winGetWindowFromId( winMapPreview, buttonMapStartPositionID[i] ); DEBUG_ASSERTCRASH(buttonMapStartPosition[i], ("Could not find the ButtonMapStartPosition[%d]",i )); buttonMapStartPosition[i]->winHide(TRUE); buttonMapStartPosition[i]->winEnable(FALSE); } raiseMessageBoxes = TRUE; showGameSpyGameOptionsUnderlyingGUIElements( FALSE ); // get the listbox window AsciiString listString( "WOLMapSelectMenu.wnd:ListboxMap" ); NameKeyType mapListID = TheNameKeyGenerator->nameToKey( listString ); mapList = TheWindowManager->winGetWindowFromId( parent, mapListID ); if( mapList ) { if (TheMapCache) TheMapCache->updateCache(); populateMapListbox( mapList, usesSystemMapDir, TRUE, TheGameSpyGame->getMap() ); } } // end WOLMapSelectMenuInit //------------------------------------------------------------------------------------------------- /** MapSelect menu shutdown method */ //------------------------------------------------------------------------------------------------- void WOLMapSelectMenuShutdown( WindowLayout *layout, void *userData ) { NullifyControls(); // hide menu layout->hide( TRUE ); // our shutdown is complete TheShell->shutdownComplete( layout ); } // end WOLMapSelectMenuShutdown //------------------------------------------------------------------------------------------------- /** MapSelect menu update method */ //------------------------------------------------------------------------------------------------- void WOLMapSelectMenuUpdate( WindowLayout *layout, void *userData ) { if (raiseMessageBoxes) { RaiseGSMessageBox(); raiseMessageBoxes = false; } // No update because the game setup screen is up at the same // time and it does the update for us... } // end WOLMapSelectMenuUpdate //------------------------------------------------------------------------------------------------- /** Map select menu input callback */ //------------------------------------------------------------------------------------------------- WindowMsgHandledType WOLMapSelectMenuInput( GameWindow *window, UnsignedInt msg, WindowMsgData mData1, WindowMsgData mData2 ) { switch( msg ) { // -------------------------------------------------------------------------------------------- case GWM_CHAR: { UnsignedByte key = mData1; UnsignedByte state = mData2; 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 ) ) { AsciiString buttonName( "WOLMapSelectMenu.wnd:ButtonBack" ); NameKeyType buttonID = TheNameKeyGenerator->nameToKey( buttonName ); GameWindow *button = TheWindowManager->winGetWindowFromId( window, buttonID ); TheWindowManager->winSendSystemMsg( window, GBM_SELECTED, (WindowMsgData)button, buttonID ); } // 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; } // end WOLMapSelectMenuInput void WOLPositionStartSpots( void ); //------------------------------------------------------------------------------------------------- /** MapSelect menu window system callback */ //------------------------------------------------------------------------------------------------- WindowMsgHandledType WOLMapSelectMenuSystem( GameWindow *window, UnsignedInt msg, WindowMsgData mData1, WindowMsgData mData2 ) { switch( msg ) { // -------------------------------------------------------------------------------------------- case GWM_CREATE: { break; } // end create //--------------------------------------------------------------------------------------------- case GWM_DESTROY: { NullifyControls(); break; } // end case // -------------------------------------------------------------------------------------------- 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; } // end input //--------------------------------------------------------------------------------------------- case GLM_DOUBLE_CLICKED: { GameWindow *control = (GameWindow *)mData1; Int controlID = control->winGetWindowId(); if( controlID == listboxMap ) { int rowSelected = mData2; if (rowSelected >= 0) { GadgetListBoxSetSelected( control, rowSelected ); GameWindow *button = TheWindowManager->winGetWindowFromId( window, buttonOK ); TheWindowManager->winSendSystemMsg( window, GBM_SELECTED, (WindowMsgData)button, buttonOK ); } } break; } //--------------------------------------------------------------------------------------------- case GLM_SELECTED: { GameWindow *control = (GameWindow *)mData1; Int controlID = control->winGetWindowId(); if( controlID == listboxMap ) { int rowSelected = mData2; if( rowSelected < 0 ) { positionStartSpots( AsciiString::TheEmptyString, buttonMapStartPosition, winMapPreview); // winMapPreview->winClearStatus(WIN_STATUS_IMAGE); break; } winMapPreview->winSetStatus(WIN_STATUS_IMAGE); UnicodeString map; // get text of the map to load map = GadgetListBoxGetText( winMapWindow, rowSelected, 0 ); // set the map name in the global data map name AsciiString asciiMap; const char *mapFname = (const char *)GadgetListBoxGetItemData( winMapWindow, rowSelected ); DEBUG_ASSERTCRASH(mapFname, ("No map item data")); if (mapFname) asciiMap = mapFname; else asciiMap.translate( map ); asciiMap.toLower(); Image *image = getMapPreviewImage(asciiMap); winMapPreview->winSetUserData((void *)TheMapCache->findMap(asciiMap)); if(image) { winMapPreview->winSetEnabledImage(0, image); } else { winMapPreview->winClearStatus(WIN_STATUS_IMAGE); } positionStartSpots( asciiMap, buttonMapStartPosition, winMapPreview); } break; } //--------------------------------------------------------------------------------------------- case GBM_SELECTED: { GameWindow *control = (GameWindow *)mData1; Int controlID = control->winGetWindowId(); if( controlID == buttonBack ) { showGameSpyGameOptionsUnderlyingGUIElements( TRUE ); WOLMapSelectLayout->destroyWindows(); WOLMapSelectLayout->deleteInstance(); WOLMapSelectLayout = NULL; WOLPositionStartSpots(); } // end if else if ( controlID == radioButtonSystemMapsID ) { if (TheMapCache) TheMapCache->updateCache(); populateMapListbox( mapList, TRUE, TRUE, TheGameSpyGame->getMap() ); CustomMatchPreferences pref; pref.setUsesSystemMapDir(TRUE); pref.write(); } else if ( controlID == radioButtonUserMapsID ) { if (TheMapCache) TheMapCache->updateCache(); populateMapListbox( mapList, FALSE, TRUE, TheGameSpyGame->getMap() ); CustomMatchPreferences pref; pref.setUsesSystemMapDir(FALSE); pref.write(); } else if( controlID == buttonOK ) { Int selected; UnicodeString map; // get the selected index GadgetListBoxGetSelected( winMapWindow, &selected ); if( selected != -1 ) { // get text of the map to load map = GadgetListBoxGetText( winMapWindow, selected, 0 ); // set the map name in the global data map name AsciiString asciiMap; const char *mapFname = (const char *)GadgetListBoxGetItemData( winMapWindow, selected ); DEBUG_ASSERTCRASH(mapFname, ("No map item data")); if (mapFname) asciiMap = mapFname; else asciiMap.translate( map ); TheGameSpyGame->setMap(asciiMap); asciiMap.toLower(); std::map::iterator it = TheMapCache->find(asciiMap); if (it != TheMapCache->end()) { TheGameSpyGame->getGameSpySlot(0)->setMapAvailability(TRUE); TheGameSpyGame->setMapCRC( it->second.m_CRC ); TheGameSpyGame->setMapSize( it->second.m_filesize ); } TheGameSpyGame->adjustSlotsForMap(); // BGC- adjust the slots for the new map. TheGameSpyGame->resetAccepted(); TheGameSpyGame->resetStartSpots(); TheGameSpyInfo->setGameOptions(); WOLDisplaySlotList(); WOLDisplayGameOptions(); WOLMapSelectLayout->destroyWindows(); WOLMapSelectLayout->deleteInstance(); WOLMapSelectLayout = NULL; showGameSpyGameOptionsUnderlyingGUIElements( TRUE ); WOLPositionStartSpots(); } // end if } // end else if break; } // end selected default: return MSG_IGNORED; } // end switch return MSG_HANDLED; } // end WOLMapSelectMenuSystem