/*
** 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: GUIUtil.cpp //////////////////////////////////////////////////////
// Author: Matthew D. Campbell, Sept 2002
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "GameNetwork/GUIUtil.h"
#include "GameNetwork/NetworkDefs.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/MapUtil.h"
#include "Common/NameKeyGenerator.h"
#include "Common/MultiplayerSettings.h"
#include "GameClient/GadgetListBox.h"
#include "GameClient/GadgetComboBox.h"
#include "GameClient/GadgetTextEntry.h"
#include "GameClient/GadgetStaticText.h"
#include "GameClient/GadgetPushButton.h"
#include "GameClient/GameText.h"
#include "GameNetwork/GameInfo.h"
#include "Common/PlayerTemplate.h"
#include "GameNetwork/LANAPICallbacks.h" // for acceptTrueColor, etc
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
// -----------------------------------------------------------------------------
static Bool winInitialized = FALSE;
void EnableSlotListUpdates( Bool val )
{
winInitialized = val;
}
Bool AreSlotListUpdatesEnabled( void )
{
return winInitialized;
}
// -----------------------------------------------------------------------------
void EnableAcceptControls(Bool Enabled, GameInfo *myGame, GameWindow *comboPlayer[],
GameWindow *comboColor[], GameWindow *comboPlayerTemplate[],
GameWindow *comboTeam[], GameWindow *buttonAccept[], GameWindow *buttonStart,
GameWindow *buttonMapStartPosition[], Int slotNum)
{
if(slotNum == -1 || slotNum >= MAX_SLOTS )
slotNum = myGame->getLocalSlotNum();
Bool isObserver = myGame->getConstSlot(slotNum)->getPlayerTemplate() == PLAYERTEMPLATE_OBSERVER;
if( !myGame->amIHost() && (buttonStart != NULL) )
buttonStart->winEnable(Enabled);
if(comboColor[slotNum])
{
if (isObserver)
{
GadgetComboBoxHideList(comboColor[slotNum]);
}
comboColor[slotNum]->winEnable(Enabled && !isObserver);
}
if(comboPlayerTemplate[slotNum])
comboPlayerTemplate[slotNum]->winEnable(Enabled);
if(comboTeam[slotNum])
{
if (isObserver)
{
GadgetComboBoxHideList(comboTeam[slotNum]);
}
comboTeam[slotNum]->winEnable(Enabled && !isObserver);
}
Bool canChooseStartSpot = FALSE;
if (!isObserver)
canChooseStartSpot = TRUE;
for (Int i=0; iamIHost(); ++i)
{
if (myGame->getConstSlot(i) && myGame->getConstSlot(i)->isAI())
canChooseStartSpot = TRUE;
}
if (slotNum == myGame->getLocalSlotNum())
{
if (myGame->getConstSlot(myGame->getLocalSlotNum())->hasMap())
{
for (Int i=0; iwinEnable(Enabled && canChooseStartSpot);
}
}
}
else
{
for (Int i=0; iwinEnable(FALSE);
}
}
}
}
// -----------------------------------------------------------------------------
void ShowUnderlyingGUIElements( Bool show, const char *layoutFilename, const char *parentName,
const char **gadgetsToHide, const char **perPlayerGadgetsToHide )
{
AsciiString parentNameStr;
parentNameStr.format("%s:%s", layoutFilename, parentName);
NameKeyType parentID = NAMEKEY(parentNameStr);
GameWindow *parent = TheWindowManager->winGetWindowFromId( NULL, parentID );
if (!parent)
{
DEBUG_CRASH(("Window %s not found\n", parentNameStr.str()));
return;
}
// hide some GUI elements of the screen underneath
GameWindow *win;
Int player;
const char **text;
text = gadgetsToHide;
while (*text)
{
AsciiString gadgetName;
gadgetName.format("%s:%s", layoutFilename, *text);
win = TheWindowManager->winGetWindowFromId( parent, NAMEKEY(gadgetName) );
//DEBUG_ASSERTCRASH(win, ("Cannot find %s to show/hide it", gadgetName.str()));
if (win)
{
win->winHide( !show );
}
++text;
}
text = perPlayerGadgetsToHide;
while (*text)
{
for (player = 0; player < MAX_SLOTS; ++player)
{
AsciiString gadgetName;
gadgetName.format("%s:%s%d", layoutFilename, *text, player);
win = TheWindowManager->winGetWindowFromId( parent, NAMEKEY(gadgetName) );
//DEBUG_ASSERTCRASH(win, ("Cannot find %s to show/hide it", gadgetName.str()));
if (win)
{
win->winHide( !show );
}
}
++text;
}
}
// -----------------------------------------------------------------------------
void PopulateColorComboBox(Int comboBox, GameWindow *comboArray[], GameInfo *myGame, Bool isObserver)
{
Int numColors = TheMultiplayerSettings->getNumColors();
UnicodeString colorName;
std::vector availableColors;
for (Int i = 0; i < numColors; i++)
availableColors.push_back(true);
for (i = 0; i < MAX_SLOTS; i++)
{
GameSlot *slot = myGame->getSlot(i);
if( slot && (i != comboBox) && (slot->getColor() >= 0 )&& (slot->getColor() < numColors))
{
DEBUG_ASSERTCRASH(slot->getColor() >= 0,("We've tried to access array %d and that ain't good",slot->getColor()));
availableColors[slot->getColor()] = false;
}
}
Bool wasObserver = (GadgetComboBoxGetLength(comboArray[comboBox]) == 1);
GadgetComboBoxReset(comboArray[comboBox]);
MultiplayerColorDefinition *def = TheMultiplayerSettings->getColor(PLAYERTEMPLATE_RANDOM);
Int newIndex = GadgetComboBoxAddEntry(comboArray[comboBox],
(isObserver)?TheGameText->fetch("GUI:None"):TheGameText->fetch("GUI:???"), def->getColor());
GadgetComboBoxSetItemData(comboArray[comboBox], newIndex, (void *)-1);
if (isObserver)
{
GadgetComboBoxSetSelectedPos(comboArray[comboBox], 0);
return;
}
for (Int c=0; cgetColor(c);
if (!def || availableColors[c] == false)
continue;
colorName = TheGameText->fetch(def->getTooltipName().str());
newIndex = GadgetComboBoxAddEntry(comboArray[comboBox], colorName, def->getColor());
GadgetComboBoxSetItemData(comboArray[comboBox], newIndex, (void *)c);
}
if (wasObserver)
GadgetComboBoxSetSelectedPos(comboArray[comboBox], 0);
}
// -----------------------------------------------------------------------------
void PopulatePlayerTemplateComboBox(Int comboBox, GameWindow *comboArray[], GameInfo *myGame, Bool allowObservers)
{
Int numPlayerTemplates = ThePlayerTemplateStore->getPlayerTemplateCount();
UnicodeString playerTemplateName;
GadgetComboBoxReset(comboArray[comboBox]);
MultiplayerColorDefinition *def = TheMultiplayerSettings->getColor(PLAYERTEMPLATE_RANDOM);
Int newIndex = GadgetComboBoxAddEntry(comboArray[comboBox], TheGameText->fetch("GUI:Random"), def->getColor());
GadgetComboBoxSetItemData(comboArray[comboBox], newIndex, (void *)PLAYERTEMPLATE_RANDOM);
std::set seenSides;
for (Int c=0; cgetNthPlayerTemplate(c);
if (!fac)
continue;
if (fac->getStartingBuilding().isEmpty())
continue;
AsciiString side;
side.format("SIDE:%s", fac->getSide().str());
if (seenSides.find(side) != seenSides.end())
continue;
seenSides.insert(side);
newIndex = GadgetComboBoxAddEntry(comboArray[comboBox], TheGameText->fetch(side), def->getColor());
GadgetComboBoxSetItemData(comboArray[comboBox], newIndex, (void *)c);
}
seenSides.clear();
// disabling observers for Multiplayer test
#ifndef _PLAYTEST
if (allowObservers)
{
def = TheMultiplayerSettings->getColor(PLAYERTEMPLATE_OBSERVER);
newIndex = GadgetComboBoxAddEntry(comboArray[comboBox], TheGameText->fetch("GUI:Observer"), def->getColor());
GadgetComboBoxSetItemData(comboArray[comboBox], newIndex, (void *)PLAYERTEMPLATE_OBSERVER);
}
#endif
GadgetComboBoxSetSelectedPos(comboArray[comboBox], 0);
}
// -----------------------------------------------------------------------------
void PopulateTeamComboBox(Int comboBox, GameWindow *comboArray[], GameInfo *myGame, Bool isObserver)
{
Int numTeams = MAX_SLOTS/2;
UnicodeString teamName;
GadgetComboBoxReset(comboArray[comboBox]);
MultiplayerColorDefinition *def = TheMultiplayerSettings->getColor(PLAYERTEMPLATE_RANDOM);
Int newIndex = GadgetComboBoxAddEntry(comboArray[comboBox], TheGameText->fetch("Team:0"), def->getColor());
GadgetComboBoxSetItemData(comboArray[comboBox], newIndex, (void *)-1);
if (isObserver)
{
GadgetComboBoxSetSelectedPos(comboArray[comboBox], 0);
return;
}
for (Int c=0; cfetch(teamStr.str());
newIndex = GadgetComboBoxAddEntry(comboArray[comboBox], teamName, def->getColor());
GadgetComboBoxSetItemData(comboArray[comboBox], newIndex, (void *)c);
}
GadgetComboBoxSetSelectedPos(comboArray[comboBox], 0);
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------
// The slot list displaying function
//-------------------------------------------------------------------------------------------------
void UpdateSlotList( GameInfo *myGame, GameWindow *comboPlayer[],
GameWindow *comboColor[], GameWindow *comboPlayerTemplate[],
GameWindow *comboTeam[], GameWindow *buttonAccept[],
GameWindow *buttonStart, GameWindow *buttonMapStartPosition[] )
{
if(!AreSlotListUpdatesEnabled())
return;
//LANGameInfo *myGame = TheLAN->GetMyGame();
const MapMetaData *mapData = TheMapCache->findMap( myGame->getMap() );
Bool willTransfer = TRUE;
if (mapData)
{
willTransfer = !mapData->m_isOfficial;
}
else
{
willTransfer = WouldMapTransfer(myGame->getMap());
}
if (myGame)
{
for( int i =0; i < MAX_SLOTS; i++ )
{
GameSlot * slot = myGame->getSlot(i);
// if i'm host, enable the controls for AI
if(myGame->amIHost() && slot && slot->isAI())
{
EnableAcceptControls(TRUE, myGame, comboPlayer, comboColor, comboPlayerTemplate,
comboTeam, buttonAccept, buttonStart, buttonMapStartPosition, i);
}
else if (slot && myGame->getLocalSlotNum() == i)
{
if(slot->isAccepted() && !myGame->amIHost())
{
EnableAcceptControls(FALSE, myGame, comboPlayer, comboColor, comboPlayerTemplate,
comboTeam, buttonAccept, buttonStart, buttonMapStartPosition);
}
else
{
if (slot->hasMap()) {
EnableAcceptControls(TRUE, myGame, comboPlayer, comboColor, comboPlayerTemplate,
comboTeam, buttonAccept, buttonStart, buttonMapStartPosition);
}
else
{
EnableAcceptControls(willTransfer, myGame, comboPlayer, comboColor, comboPlayerTemplate,
comboTeam, buttonAccept, buttonStart, buttonMapStartPosition);
}
}
}
else if(myGame->amIHost())
{
EnableAcceptControls(FALSE, myGame, comboPlayer, comboColor, comboPlayerTemplate,
comboTeam, buttonAccept, buttonStart, buttonMapStartPosition, i);
}
if(slot && slot->isHuman())
{
UnicodeString newName = slot->getName();
UnicodeString oldName = GadgetComboBoxGetText(comboPlayer[i]);
if (comboPlayer[i] && newName.compare(oldName))
{
GadgetComboBoxSetText(comboPlayer[i], newName);
}
if(i!= 0 && buttonAccept && buttonAccept[i])
{
buttonAccept[i]->winHide(FALSE);
//Color In the little accepted boxes
if(slot->isAccepted())
{
if(BitTest(buttonAccept[i]->winGetStatus(), WIN_STATUS_IMAGE ))
buttonAccept[i]->winEnable(TRUE);
else
GadgetButtonSetEnabledColor(buttonAccept[i], acceptTrueColor );
}
else
{
if(BitTest(buttonAccept[i]->winGetStatus(), WIN_STATUS_IMAGE ))
buttonAccept[i]->winEnable(FALSE);
else
GadgetButtonSetEnabledColor(buttonAccept[i], acceptFalseColor );
}
}
}
else
{
GadgetComboBoxSetSelectedPos(comboPlayer[i], slot->getState(), TRUE);
if( buttonAccept && buttonAccept[i] )
buttonAccept[i]->winHide(TRUE);
}
/*
if (myGame->getLocalSlotNum() == i && i!=0)
{
if (comboPlayer[i])
comboPlayer[i]->winEnable( TRUE );
}
else*/ if (!myGame->amIHost())
{
if (comboPlayer[i])
comboPlayer[i]->winEnable( FALSE );
}
//if( i == myGame->getLocalSlotNum())
if((comboColor[i] != NULL) && BitTest(comboColor[i]->winGetStatus(), WIN_STATUS_ENABLED))
PopulateColorComboBox(i, comboColor, myGame, myGame->getConstSlot(i)->getPlayerTemplate() == PLAYERTEMPLATE_OBSERVER);
Int max, idx;
if (comboColor[i] != NULL) {
max = GadgetComboBoxGetLength(comboColor[i]);
for (idx=0; idxgetColor())
{
GadgetComboBoxSetSelectedPos(comboColor[i], idx, TRUE);
break;
}
}
}
if (comboTeam[i] != NULL) {
max = GadgetComboBoxGetLength(comboTeam[i]);
for (idx=0; idxgetTeamNumber())
{
GadgetComboBoxSetSelectedPos(comboTeam[i], idx, TRUE);
break;
}
}
}
if (comboPlayerTemplate[i] != NULL) {
max = GadgetComboBoxGetLength(comboPlayerTemplate[i]);
for (idx=0; idxgetPlayerTemplate())
{
GadgetComboBoxSetSelectedPos(comboPlayerTemplate[i], idx, TRUE);
break;
}
}
}
}
}
}
// -----------------------------------------------------------------------------