/* ** Command & Conquer Generals(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: Diplomacy.cpp /////////////////////////////////////////////////////////////////////// // Author: Matthew D. Campbell - August 2002 // Desc: GUI callbacks for the diplomacy menu /////////////////////////////////////////////////////////////////////////////////////////////////// // INCLUDES /////////////////////////////////////////////////////////////////////////////////////// #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine #include "Common/GlobalData.h" #include "Common/MultiplayerSettings.h" #include "Common/Player.h" #include "Common/PlayerList.h" #include "Common/PlayerTemplate.h" #include "Common/Recorder.h" #include "GameClient/AnimateWindowManager.h" #include "GameClient/Diplomacy.h" #include "GameClient/DisconnectMenu.h" #include "GameClient/GameWindow.h" #include "GameClient/Gadget.h" #include "GameClient/GadgetCheckBox.h" #include "GameClient/GadgetListBox.h" #include "GameClient/GadgetTextEntry.h" #include "GameClient/GadgetStaticText.h" #include "GameClient/GadgetRadioButton.h" #include "GameClient/GameClient.h" #include "GameClient/GameText.h" #include "GameClient/GUICallbacks.h" #include "GameClient/InGameUI.h" #include "GameLogic/GameLogic.h" #include "GameLogic/VictoryConditions.h" #include "GameNetwork/GameInfo.h" #include "GameNetwork/NetworkInterface.h" #include "GameNetwork/GameSpy/BuddyDefs.h" #include "GameNetwork/GameSpy/peerDefs.h" #ifdef _INTERNAL // for occasional debugging... //#pragma optimize("", off) //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes") #endif //------------------------------------------------------------------------------------------------- static NameKeyType staticTextPlayerID[MAX_SLOTS]; static NameKeyType staticTextSideID[MAX_SLOTS]; static NameKeyType staticTextTeamID[MAX_SLOTS]; static NameKeyType staticTextStatusID[MAX_SLOTS]; static NameKeyType buttonMuteID[MAX_SLOTS]; static NameKeyType buttonUnMuteID[MAX_SLOTS]; static NameKeyType radioButtonInGameID = NAMEKEY_INVALID; static NameKeyType radioButtonBuddiesID = NAMEKEY_INVALID; static GameWindow *radioButtonInGame = NULL; static GameWindow *radioButtonBuddies = NULL; static NameKeyType winInGameID = NAMEKEY_INVALID; static NameKeyType winBuddiesID = NAMEKEY_INVALID; static NameKeyType winSoloID = NAMEKEY_INVALID; static GameWindow *winInGame = NULL; static GameWindow *winBuddies = NULL; static GameWindow *winSolo = NULL; static GameWindow *staticTextPlayer[MAX_SLOTS] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; static GameWindow *staticTextSide[MAX_SLOTS] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; static GameWindow *staticTextTeam[MAX_SLOTS] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; static GameWindow *staticTextStatus[MAX_SLOTS] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; static GameWindow *buttonMute[MAX_SLOTS] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; static GameWindow *buttonUnMute[MAX_SLOTS] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; static Int slotNumInRow[MAX_SLOTS]; //------------------------------------------------------------------------------------------------- static WindowLayout *theLayout = NULL; static GameWindow *theWindow = NULL; static AnimateWindowManager *theAnimateWindowManager = NULL; WindowMsgHandledType BuddyControlSystem( GameWindow *window, UnsignedInt msg, WindowMsgData mData1, WindowMsgData mData2); void InitBuddyControls(Int type); void updateBuddyInfo( void ); static void grabWindowPointers( void ) { for (Int i=0; iwinGetWindowFromId(theWindow, staticTextPlayerID[i]); staticTextSide[i] = TheWindowManager->winGetWindowFromId(theWindow, staticTextSideID[i]); staticTextTeam[i] = TheWindowManager->winGetWindowFromId(theWindow, staticTextTeamID[i]); staticTextStatus[i] = TheWindowManager->winGetWindowFromId(theWindow, staticTextStatusID[i]); buttonMute[i] = TheWindowManager->winGetWindowFromId(theWindow, buttonMuteID[i]); buttonUnMute[i] = TheWindowManager->winGetWindowFromId(theWindow, buttonUnMuteID[i]); slotNumInRow[i] = -1; } } static void releaseWindowPointers( void ) { for (Int i=0; im_animateWindows) { Bool wasFinished = theAnimateWindowManager->isFinished(); theAnimateWindowManager->update(); if (theAnimateWindowManager->isFinished() && !wasFinished && theAnimateWindowManager->isReversed()) theWindow->winHide( TRUE ); } } //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- static BriefingList theBriefingList; //------------------------------------------------------------------------------------------------- BriefingList* GetBriefingTextList(void) { return &theBriefingList; } //------------------------------------------------------------------------------------------------- void UpdateDiplomacyBriefingText(AsciiString newText, Bool clear) { GameWindow *listboxSolo = TheWindowManager->winGetWindowFromId(theWindow, NAMEKEY("Diplomacy.wnd:ListboxSolo")); if (clear) { theBriefingList.clear(); if (listboxSolo) GadgetListBoxReset(listboxSolo); } if (newText.isEmpty()) return; if (std::find(theBriefingList.begin(), theBriefingList.end(), newText) != theBriefingList.end()) return; theBriefingList.push_back(newText); if (!listboxSolo) return; UnicodeString translated = TheGameText->fetch(newText); Int numEntries = GadgetListBoxGetNumEntries(listboxSolo); GadgetListBoxAddEntryText(listboxSolo, translated, TheInGameUI->getMessageColor(numEntries%2), -1); } // ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------ void ShowDiplomacy( Bool immediate ) { if (!TheInGameUI->getInputEnabled() || TheGameLogic->isIntroMoviePlaying() || TheGameLogic->isLoadingGame()) return; if (TheInGameUI->isQuitMenuVisible()) return; if (TheDisconnectMenu && TheDisconnectMenu->isScreenVisible()) return; if (theWindow) { theWindow->winHide(FALSE); theWindow->winEnable(TRUE); } else { theLayout = TheWindowManager->winCreateLayout( "Diplomacy.wnd" ); theWindow = theLayout->getFirstWindow(); theLayout->setUpdate(updateFunc); theAnimateWindowManager = NEW AnimateWindowManager; radioButtonInGameID = TheNameKeyGenerator->nameToKey("Diplomacy.wnd:RadioButtonInGame"); radioButtonBuddiesID = TheNameKeyGenerator->nameToKey("Diplomacy.wnd:RadioButtonBuddies"); radioButtonInGame = TheWindowManager->winGetWindowFromId(NULL, radioButtonInGameID); radioButtonBuddies = TheWindowManager->winGetWindowFromId(NULL, radioButtonBuddiesID); winInGameID = TheNameKeyGenerator->nameToKey("Diplomacy.wnd:InGameParent"); winBuddiesID = TheNameKeyGenerator->nameToKey("Diplomacy.wnd:BuddiesParent"); winSoloID = TheNameKeyGenerator->nameToKey("Diplomacy.wnd:SoloParent"); winInGame = TheWindowManager->winGetWindowFromId(NULL, winInGameID); winBuddies = TheWindowManager->winGetWindowFromId(NULL, winBuddiesID); winSolo = TheWindowManager->winGetWindowFromId(NULL, winSoloID); if (!TheRecorder->isMultiplayer()) { GameWindow *listboxSolo = TheWindowManager->winGetWindowFromId(theWindow, NAMEKEY("Diplomacy.wnd:ListboxSolo")); if (listboxSolo) { for (BriefingList::iterator it = theBriefingList.begin(); it != theBriefingList.end(); ++it) { UnicodeString translated = TheGameText->fetch(*it); Int numEntries = GadgetListBoxGetNumEntries(listboxSolo); GadgetListBoxAddEntryText(listboxSolo, translated, TheInGameUI->getMessageColor(numEntries%2), -1); } } } } theLayout->hide(FALSE); radioButtonInGame->winHide(TRUE); radioButtonBuddies->winHide(TRUE); GadgetRadioSetSelection(radioButtonInGame, FALSE); if (TheRecorder->isMultiplayer()) { winInGame->winHide(FALSE); winBuddies->winHide(TRUE); winSolo->winHide(TRUE); } else { winInGame->winHide(TRUE); winBuddies->winHide(TRUE); winSolo->winHide(FALSE); } theAnimateWindowManager->reset(); if (!immediate && TheGlobalData->m_animateWindows) theAnimateWindowManager->registerGameWindow( theWindow, WIN_ANIMATION_SLIDE_TOP, TRUE, 200 ); TheInGameUI->registerWindowLayout(theLayout); grabWindowPointers(); PopulateInGameDiplomacyPopup(); if(TheGameSpyInfo && TheGameSpyInfo->getLocalProfileID() != 0) { radioButtonInGame->winHide(FALSE); radioButtonBuddies->winHide(FALSE); InitBuddyControls(1); PopulateOldBuddyMessages(); updateBuddyInfo(); } } // ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------ void ResetDiplomacy( void ) { if(theLayout) { TheInGameUI->unregisterWindowLayout(theLayout); theLayout->destroyWindows(); theLayout->deleteInstance(); InitBuddyControls(-1); } theLayout = NULL; theWindow = NULL; if (theAnimateWindowManager) delete theAnimateWindowManager; theAnimateWindowManager = NULL; } // ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------ void HideDiplomacy( Bool immediate ) { releaseWindowPointers(); if (theWindow) { if (immediate || !TheGlobalData->m_animateWindows) { theWindow->winHide(TRUE); theWindow->winEnable(FALSE); } else { if (theAnimateWindowManager->isFinished()) theAnimateWindowManager->reverseAnimateWindow(); } } } // ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------ void ToggleDiplomacy( Bool immediate ) { // If we bring this up, let's hide the quit menu HideQuitMenu(); if (theWindow) { Bool show = theWindow->winIsHidden(); if (show) ShowDiplomacy( immediate ); else HideDiplomacy( immediate ); } else { ShowDiplomacy( immediate ); } } //------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- WindowMsgHandledType DiplomacyInput( GameWindow *window, UnsignedInt msg, WindowMsgData mData1, WindowMsgData mData2 ) { switch( msg ) { // -------------------------------------------------------------------------------------------- case GWM_CHAR: { UnsignedByte key = mData1; // UnsignedByte state = mData2; switch( key ) { // ---------------------------------------------------------------------------------------- case KEY_ESC: { HideDiplomacy(); return MSG_HANDLED; //return MSG_IGNORED; } // end escape } // end switch( key ) return MSG_HANDLED; } // end char } return MSG_IGNORED; } // end DiplomacyInput //------------------------------------------------------------------------------------------------- WindowMsgHandledType DiplomacySystem( GameWindow *window, UnsignedInt msg, WindowMsgData mData1, WindowMsgData mData2 ) { if(BuddyControlSystem(window, msg, mData1, mData2) == MSG_HANDLED) { return MSG_HANDLED; } switch( msg ) { //--------------------------------------------------------------------------------------------- case GGM_FOCUS_CHANGE: { // Bool focus = (Bool) mData1; //if (focus) //TheWindowManager->winSetGrabWindow( chatTextEntry ); break; } // end focus change //--------------------------------------------------------------------------------------------- case GWM_INPUT_FOCUS: { // if we're given the opportunity to take the keyboard focus we must say we don't want it if( mData1 == TRUE ) *(Bool *)mData2 = FALSE; return MSG_HANDLED; }//case GWM_INPUT_FOCUS: //--------------------------------------------------------------------------------------------- case GBM_SELECTED: { GameWindow *control = (GameWindow *)mData1; NameKeyType controlID = (NameKeyType)control->winGetWindowId(); static NameKeyType buttonHideID = NAMEKEY( "Diplomacy.wnd:ButtonHide" ); if (controlID == buttonHideID) { HideDiplomacy( FALSE ); } else if( controlID == radioButtonInGameID) { winInGame->winHide(FALSE); winBuddies->winHide(TRUE); } else if( controlID == radioButtonBuddiesID) { winInGame->winHide(TRUE); winBuddies->winHide(FALSE); } for (Int i=0; i= 0) { TheGameInfo->getSlot(slotNumInRow[i])->mute(TRUE); PopulateInGameDiplomacyPopup(); break; } if (controlID == buttonUnMuteID[i] && slotNumInRow[i] >= 0) { TheGameInfo->getSlot(slotNumInRow[i])->mute(FALSE); PopulateInGameDiplomacyPopup(); break; } } break; } // end button selected //--------------------------------------------------------------------------------------------- default: return MSG_IGNORED; } // end switch( msg ) return MSG_HANDLED; } // end DiplomacySystem void PopulateInGameDiplomacyPopup( void ) { if (!TheGameInfo) return; Int rowNum = 0; for (Int slotNum=0; slotNumgetConstSlot(slotNum); if (slot && slot->isOccupied()) { Bool isInGame = false; // Note - for skirmish, TheNetwork == NULL. jba. if (TheNetwork && TheNetwork->isPlayerConnected(slotNum)) { isInGame = true; } else if ((TheNetwork == NULL) && slot->isHuman()) { // this is a skirmish game and it is the human player. isInGame = true; } if (slot->isAI()) isInGame = true; AsciiString playerName; playerName.format("player%d", slotNum); Player *player = ThePlayerList->findPlayerWithNameKey(NAMEKEY(playerName)); Bool isAlive = !TheVictoryConditions->hasSinglePlayerBeenDefeated(player); Bool isObserver = player->isPlayerObserver(); if (slot->isHuman() && TheGameInfo->getLocalSlotNum() != slotNum && isInGame) { // show mute button if (buttonMute[rowNum]) { buttonMute[rowNum]->winHide(slot->isMuted()); } if (buttonUnMute[rowNum]) { buttonUnMute[rowNum]->winHide(!slot->isMuted()); } } else { // can't mute self, AI players, or MIA humans if (buttonMute[rowNum]) buttonMute[rowNum]->winHide(TRUE); if (buttonUnMute[rowNum]) buttonUnMute[rowNum]->winHide(TRUE); } Color playerColor = TheMultiplayerSettings->getColor(slot->getApparentColor())->getColor(); Color backColor = GameMakeColor(0, 0, 0, 255); Color aliveColor = GameMakeColor(0, 255, 0, 255); Color deadColor = GameMakeColor(255, 0, 0, 255); Color observerInGameColor = GameMakeColor(255, 255, 255, 255); Color goneColor = GameMakeColor(196, 0, 0, 255); Color observerGoneColor = GameMakeColor(196, 196, 196, 255); if (staticTextPlayer[rowNum]) { staticTextPlayer[rowNum]->winSetEnabledTextColors( playerColor, backColor ); GadgetStaticTextSetText(staticTextPlayer[rowNum], slot->getName()); } if (staticTextSide[rowNum]) { staticTextSide[rowNum]->winSetEnabledTextColors( playerColor, backColor ); GadgetStaticTextSetText(staticTextSide[rowNum], slot->getApparentPlayerTemplateDisplayName() ); } if (staticTextTeam[rowNum]) { staticTextTeam[rowNum]->winSetEnabledTextColors( playerColor, backColor ); AsciiString teamStr; teamStr.format("Team:%d", slot->getTeamNumber() + 1); if (slot->isAI() && slot->getTeamNumber() == -1) teamStr = "Team:AI"; GadgetStaticTextSetText(staticTextTeam[rowNum], TheGameText->fetch(teamStr) ); } if (staticTextStatus[rowNum]) { staticTextStatus[rowNum]->winHide(FALSE); if (isInGame) { if (isAlive) { staticTextStatus[rowNum]->winSetEnabledTextColors( aliveColor, backColor ); GadgetStaticTextSetText(staticTextStatus[rowNum], TheGameText->fetch("GUI:PlayerAlive")); } else { if (isObserver) { staticTextStatus[rowNum]->winSetEnabledTextColors( observerInGameColor, backColor ); GadgetStaticTextSetText(staticTextStatus[rowNum], TheGameText->fetch("GUI:PlayerObserver")); } else { staticTextStatus[rowNum]->winSetEnabledTextColors( deadColor, backColor ); GadgetStaticTextSetText(staticTextStatus[rowNum], TheGameText->fetch("GUI:PlayerDead")); } } } else { // not in game if (isObserver) { staticTextStatus[rowNum]->winSetEnabledTextColors( observerGoneColor, backColor ); GadgetStaticTextSetText(staticTextStatus[rowNum], TheGameText->fetch("GUI:PlayerObserverGone")); } else { staticTextStatus[rowNum]->winSetEnabledTextColors( goneColor, backColor ); GadgetStaticTextSetText(staticTextStatus[rowNum], TheGameText->fetch("GUI:PlayerGone")); } } } slotNumInRow[rowNum++] = slotNum; } } while (rowNum < MAX_SLOTS) { slotNumInRow[rowNum] = -1; if (staticTextPlayer[rowNum]) staticTextPlayer[rowNum]->winHide(TRUE); if (staticTextSide[rowNum]) staticTextSide[rowNum]->winHide(TRUE); if (staticTextTeam[rowNum]) staticTextTeam[rowNum]->winHide(TRUE); if (staticTextStatus[rowNum]) staticTextStatus[rowNum]->winHide(TRUE); if (buttonMute[rowNum]) buttonMute[rowNum]->winHide(TRUE); if (buttonUnMute[rowNum]) buttonUnMute[rowNum]->winHide(TRUE); ++rowNum; } }