Initial commit of Command & Conquer Generals and Command & Conquer Generals Zero Hour source code.

This commit is contained in:
LFeenanEA
2025-02-27 17:34:39 +00:00
parent 2e338c00cb
commit 3d0ee53a05
6072 changed files with 2283311 additions and 0 deletions

View File

@@ -0,0 +1,117 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: Color.cpp ////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Westwood Studios Pacific.
//
// Confidential Information
// Copyright (C) 2001 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// Project: RTS3
//
// File name: Color.cpp
//
// Created: Colin Day, July 2001
//
// Desc: Management of color representations
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
// USER INCLUDES //////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "GameClient/Color.h"
// DEFINES ////////////////////////////////////////////////////////////////////
// PRIVATE TYPES //////////////////////////////////////////////////////////////
// PRIVATE DATA ///////////////////////////////////////////////////////////////
// PUBLIC DATA ////////////////////////////////////////////////////////////////
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// GameMakeColor ==============================================================
/** Create a color representation given red, green, blue, and
* alpha components
*
* NOTE: pure solid white (255, 255, 255, 255) will translate
* intoa -1 which is GAME_COLOR_UNDEFINED
*/
//=============================================================================
// GameGetColorComponents =====================================================
/** Get the RGB color comonents of a color */
//=============================================================================
void GameGetColorComponents( Color color,
UnsignedByte *red,
UnsignedByte *green,
UnsignedByte *blue,
UnsignedByte *alpha )
{
*alpha = (color & 0xFF000000) >> 24;
*red = (color & 0x00FF0000) >> 16;
*green = (color & 0x0000FF00) >> 8;
*blue = (color & 0x000000FF);
} // end GameGetColorComponents
void GameGetColorComponentsReal( Color color, Real *red, Real *green, Real *blue, Real *alpha )
{
*alpha = ((color & 0xFF000000) >> 24) / 255.0f;
*red = ((color & 0x00FF0000) >> 16) / 255.0f;
*green = ((color & 0x0000FF00) >> 8) / 255.0f;
*blue = (color & 0x000000FF) / 255.0f;
}
Color GameDarkenColor( Color color, Int percent )
{
// if they try to go to dark, just return their old color
if(percent >= 90 || percent <= 0)
return color;
UnsignedByte r, g, b, a;
GameGetColorComponents(color,&r,&g,&b,&a);
r -= (r * percent / 100);
g -= (g * percent / 100);
b -= (b * percent / 100);
return GameMakeColor(r,g,b,a);
}// end GameDarkenColor

View File

@@ -0,0 +1,490 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: Credits.cpp /////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Electronic Arts Pacific.
//
// Confidential Information
// Copyright (C) 2002 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// created: Dec 2002
//
// Filename: Credits.cpp
//
// author: Chris Huybregts
//
// purpose: This is where all the credit texts is going to be held.
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine
//-----------------------------------------------------------------------------
// USER INCLUDES //////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
#include "Common/INI.h"
#include "GameClient/Credits.h"
#include "GameClient/DisplayStringManager.h"
#include "GameClient/Display.h"
#include "GameClient/GameText.h"
#include "GameClient/GlobalLanguage.h"
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
//-----------------------------------------------------------------------------
// DEFINES ////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
CreditsManager *TheCredits = NULL;
const FieldParse CreditsManager::m_creditsFieldParseTable[] =
{
{ "ScrollRate", INI::parseInt, NULL, offsetof( CreditsManager, m_scrollRate ) },
{ "ScrollRateEveryFrames", INI::parseInt, NULL, offsetof( CreditsManager, m_scrollRatePerFrames ) },
{ "ScrollDown", INI::parseBool, NULL, offsetof( CreditsManager, m_scrollDown ) },
{ "TitleColor", INI::parseColorInt, NULL, offsetof( CreditsManager, m_titleColor ) },
{ "MinorTitleColor", INI::parseColorInt, NULL, offsetof( CreditsManager, m_positionColor ) },
{ "NormalColor", INI::parseColorInt, NULL, offsetof( CreditsManager, m_normalColor ) },
{ "Style", INI::parseLookupList, CreditStyleNames, offsetof( CreditsManager, m_currentStyle ) },
{ "Blank", CreditsManager::parseBlank, NULL, NULL },
{ "Text", CreditsManager::parseText, NULL, NULL },
{ NULL, NULL, NULL, 0 } // keep this last
};
//-----------------------------------------------------------------------------
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
void INI::parseCredits( INI *ini )
{
// find existing item if present
DEBUG_ASSERTCRASH( TheCredits, ("parseCredits: TheCredits has not been ininialized yet.\n") );
if( !TheCredits )
return;
// parse the ini definition
ini->initFromINI( TheCredits, TheCredits->getFieldParse() );
} // end parseCommandButtonDefinition
CreditsLine::CreditsLine()
{
m_useSecond = FALSE;
m_done = FALSE;
m_style = CREDIT_STYLE_BLANK;
m_displayString = NULL;
m_secondDisplayString = NULL;
}
CreditsLine::~CreditsLine()
{
if(m_displayString)
TheDisplayStringManager->freeDisplayString(m_displayString);
if(m_secondDisplayString)
TheDisplayStringManager->freeDisplayString(m_secondDisplayString);
m_displayString = NULL;
m_secondDisplayString = NULL;
}
CreditsManager::CreditsManager(void)
{
m_scrollRate = 1; // in pixels
m_scrollRatePerFrames = 1;
m_scrollDown = TRUE; // if TRUE text will come from the top to the bottom if False, it will go from the bottom up
m_framesSinceStarted = 0;
m_titleColor = m_positionColor = m_normalColor = GameMakeColor(255,255,255,255);
m_currentStyle = CREDIT_STYLE_NORMAL;
m_isFinished = FALSE;
m_normalFontHeight = 10;
}
CreditsManager::~CreditsManager(void)
{
m_displayedCreditLineList.clear();
CreditsLineList::iterator it =m_creditLineList.begin();
while (it != m_creditLineList.end())
{
CreditsLine *cLine = *it;
delete cLine;
it = m_creditLineList.erase(it);
}
}
void CreditsManager::init(void )
{
m_isFinished = FALSE;
m_creditLineListIt = m_creditLineList.begin();
m_framesSinceStarted = 0;
}
void CreditsManager::load(void )
{
INI ini;
// Read from INI all the ControlBarSchemes
ini.load( AsciiString( "Data\\INI\\Credits.ini" ), INI_LOAD_OVERWRITE, NULL );
if(m_scrollRatePerFrames <=0)
m_scrollRatePerFrames = 1;
if(m_scrollRate <=0)
m_scrollRate = 1;
GameFont *font = TheFontLibrary->getFont(TheGlobalLanguageData->m_creditsNormalFont.name,
TheGlobalLanguageData->adjustFontSize(TheGlobalLanguageData->m_creditsNormalFont.size),
TheGlobalLanguageData->m_creditsNormalFont.bold);
m_normalFontHeight = font->height;
}
void CreditsManager::reset( void )
{
m_displayedCreditLineList.clear();
m_isFinished = FALSE;
m_creditLineListIt = m_creditLineList.begin();
m_framesSinceStarted = 0;
}
void CreditsManager::update( void )
{
if(m_isFinished)
return;
m_framesSinceStarted++;
if(m_framesSinceStarted%m_scrollRatePerFrames != 0)
return;
Int y = 0;
Int yTest = 0;
Int lastHeight = 0;
Int start = m_scrollDown? 0:TheDisplay->getHeight();
Int end =m_scrollDown? TheDisplay->getHeight():0;
Int offsetStartMultiplyer = m_scrollDown? -1:0; // if we're scrolling from the top, we need to subtract the height
Int offsetEndMultiplyer = m_scrollDown? 0:1;
Int directionMultiplyer = m_scrollDown? 1:-1;
CreditsLineList::iterator drawIt = m_displayedCreditLineList.begin();
while (drawIt != m_displayedCreditLineList.end())
{
CreditsLine *cLine = *drawIt;
y = cLine->m_pos.y = cLine->m_pos.y + (m_scrollRate * directionMultiplyer);
lastHeight = cLine->m_height;
yTest = y + ((lastHeight + CREDIT_SPACE_OFFSET) * offsetEndMultiplyer);
if(((m_scrollDown && (yTest > end)) || (!m_scrollDown && (yTest < end))))
{
TheDisplayStringManager->freeDisplayString(cLine->m_displayString);
TheDisplayStringManager->freeDisplayString(cLine->m_secondDisplayString);
cLine->m_displayString = NULL;
cLine->m_secondDisplayString = NULL;
drawIt = m_displayedCreditLineList.erase(drawIt);
}
else
drawIt++;
}
y= y + ((lastHeight + CREDIT_SPACE_OFFSET) * offsetStartMultiplyer);
// is it time to add a new string?
if(!((m_scrollDown && (yTest >= start)) || (!m_scrollDown && (yTest <= start))))
return;
if(m_displayedCreditLineList.size() == 0 && m_creditLineListIt == m_creditLineList.end())
m_isFinished = TRUE;
if(m_creditLineListIt == m_creditLineList.end())
return;
CreditsLine *cLine = *m_creditLineListIt;
ICoord2D pos;
switch (cLine->m_style)
{
case CREDIT_STYLE_TITLE:
{
cLine->m_color = m_titleColor;
if(TheGlobalLanguageData&& !cLine->m_text.isEmpty())
{
DisplayString *ds = TheDisplayStringManager->newDisplayString();
if(!ds)
return;
ds->setFont(TheFontLibrary->getFont(TheGlobalLanguageData->m_creditsTitleFont.name,
TheGlobalLanguageData->adjustFontSize(TheGlobalLanguageData->m_creditsTitleFont.size),
TheGlobalLanguageData->m_creditsTitleFont.bold));
ds->setText(cLine->m_text);
ds->getSize(&pos.x,&pos.y);
cLine->m_height = pos.y;
cLine->m_pos.x = TheDisplay->getWidth()/2 - pos.x/2 ;
cLine->m_pos.y = start + (cLine->m_height * offsetStartMultiplyer);
cLine->m_displayString = ds;
}
}
break;
case CREDIT_STYLE_POSITION:
{
cLine->m_color = m_positionColor;
if(TheGlobalLanguageData && !cLine->m_text.isEmpty())
{
DisplayString *ds = TheDisplayStringManager->newDisplayString();
if(!ds)
return;
ds->setFont(TheFontLibrary->getFont(TheGlobalLanguageData->m_creditsPositionFont.name,
TheGlobalLanguageData->adjustFontSize(TheGlobalLanguageData->m_creditsPositionFont.size),
TheGlobalLanguageData->m_creditsPositionFont.bold));
ds->setText(cLine->m_text);
ds->getSize(&pos.x,&pos.y);
cLine->m_height = pos.y;
cLine->m_pos.x = TheDisplay->getWidth()/2 - pos.x/2 ;
cLine->m_pos.y = start + (cLine->m_height * offsetStartMultiplyer);
cLine->m_displayString = ds;
}
}
break;
case CREDIT_STYLE_NORMAL:
{
cLine->m_color = m_normalColor;
if(TheGlobalLanguageData && !cLine->m_text.isEmpty())
{
DisplayString *ds = TheDisplayStringManager->newDisplayString();
if(!ds)
return;
ds->setFont(TheFontLibrary->getFont(TheGlobalLanguageData->m_creditsNormalFont.name,
TheGlobalLanguageData->adjustFontSize(TheGlobalLanguageData->m_creditsNormalFont.size),
TheGlobalLanguageData->m_creditsNormalFont.bold));
ds->setText(cLine->m_text);
ds->getSize(&pos.x,&pos.y);
cLine->m_height = pos.y;
cLine->m_pos.x = TheDisplay->getWidth()/2 - pos.x/2 ;
cLine->m_pos.y = start + (cLine->m_height * offsetStartMultiplyer);
cLine->m_displayString = ds;
}
}
break;
case CREDIT_STYLE_COLUMN:
{
cLine->m_color = m_normalColor;
if(TheGlobalLanguageData && !cLine->m_text.isEmpty())
{
DisplayString *ds = TheDisplayStringManager->newDisplayString();
if(!ds)
return;
ds->setFont(TheFontLibrary->getFont(TheGlobalLanguageData->m_creditsNormalFont.name,
TheGlobalLanguageData->adjustFontSize(TheGlobalLanguageData->m_creditsNormalFont.size),
TheGlobalLanguageData->m_creditsNormalFont.bold));
ds->setText(cLine->m_text);
ds->getSize(&pos.x,&pos.y);
cLine->m_height = pos.y;
cLine->m_pos.x = TheDisplay->getWidth()/2 - pos.x/2 ;
cLine->m_pos.y = start + (cLine->m_height * offsetStartMultiplyer);
cLine->m_displayString = ds;
}
if(TheGlobalLanguageData && !cLine->m_secondText.isEmpty())
{
DisplayString *ds = TheDisplayStringManager->newDisplayString();
if(!ds)
return;
ds->setFont(TheFontLibrary->getFont(TheGlobalLanguageData->m_creditsNormalFont.name,
TheGlobalLanguageData->adjustFontSize(TheGlobalLanguageData->m_creditsNormalFont.size),
TheGlobalLanguageData->m_creditsNormalFont.bold));
ds->setText(cLine->m_secondText);
ds->getSize(&pos.x,&pos.y);
cLine->m_height = pos.y;
cLine->m_pos.x = TheDisplay->getWidth()/2 - pos.x/2 ;
cLine->m_pos.y = start + (cLine->m_height * offsetStartMultiplyer);
cLine->m_secondDisplayString = ds;
}
}
break;
case CREDIT_STYLE_BLANK:
{
cLine->m_height = m_normalFontHeight;
cLine->m_pos.y = start + (cLine->m_height * offsetStartMultiplyer);
}
break;
}
m_displayedCreditLineList.push_back(cLine);
if(m_creditLineListIt != m_creditLineList.end())
m_creditLineListIt++;
}
void CreditsManager::draw( void )
{
CreditsLineList::iterator drawIt = m_displayedCreditLineList.begin();
while (drawIt != m_displayedCreditLineList.end())
{
CreditsLine *cLine = *drawIt;
Int heightChunk = TheDisplay->getHeight()/3;
Real perc = 0.0f;
if(cLine->m_pos.y < heightChunk || cLine->m_pos.y > heightChunk * 2)
{
// adjust the color
if( cLine->m_pos.y < 0 || cLine->m_pos.y > TheDisplay->getHeight())
perc = 0.0f;
else if( cLine->m_pos.y < heightChunk)
perc = INT_TO_REAL(cLine->m_pos.y) / heightChunk;
else
perc = 1 - INT_TO_REAL(cLine->m_pos.y - 2*heightChunk) / heightChunk;
}
else
perc = 1.0f;
UnsignedByte r,g,b,a;
GameGetColorComponents(cLine->m_color, &r, &g, &b, &a);
Int color = GameMakeColor( r,g,b, a * perc);
Int bColor= GameMakeColor( 0,0,0, a * perc);
switch (cLine->m_style) {
case CREDIT_STYLE_TITLE:
case CREDIT_STYLE_POSITION:
case CREDIT_STYLE_NORMAL:
{
if(cLine->m_displayString)
cLine->m_displayString->draw(cLine->m_pos.x,cLine->m_pos.y,color, bColor, 1,1 );
}
break;
case CREDIT_STYLE_COLUMN:
{
Int chunk = TheDisplay->getWidth()/3;
ICoord2D pos;
if(cLine->m_displayString)
{
cLine->m_displayString->getSize(&pos.x, &pos.y);
cLine->m_displayString->draw(chunk - (pos.x/2),cLine->m_pos.y,color, bColor, 1,1 );
}
if(cLine->m_secondDisplayString)
{
cLine->m_secondDisplayString->getSize(&pos.x, &pos.y);
cLine->m_secondDisplayString->draw(2*chunk - (pos.x/2),cLine->m_pos.y,color, bColor, 1,1 );
}
}
break;
}
drawIt++;
}
}
void CreditsManager::addBlank( void )
{
CreditsLine *cLine = new CreditsLine;
cLine->m_style = CREDIT_STYLE_BLANK;
m_creditLineList.push_back(cLine);
}
void CreditsManager::parseBlank( INI* ini, void *instance, void *store, const void *userData )
{
CreditsManager *cManager = (CreditsManager *)instance;
cManager->addBlank();
}
void CreditsManager::parseText( INI* ini, void *instance, void *store, const void *userData )
{
AsciiString asciiString = ini->getNextQuotedAsciiString();
CreditsManager *cManager = (CreditsManager *)instance;
cManager->addText(asciiString);
}
void CreditsManager::addText( AsciiString text )
{
CreditsLine *cLine = new CreditsLine;
switch (m_currentStyle)
{
case CREDIT_STYLE_TITLE:
case CREDIT_STYLE_POSITION:
case CREDIT_STYLE_NORMAL:
{
cLine->m_text = getUnicodeString(text);
cLine->m_style = m_currentStyle;
m_creditLineList.push_back(cLine);
}
break;
case CREDIT_STYLE_COLUMN:
{
CreditsLineList::reverse_iterator rIt = m_creditLineList.rbegin();
CreditsLine *rcLine = *rIt;
if(rIt == m_creditLineList.rend() || rcLine->m_style != CREDIT_STYLE_COLUMN
|| (rcLine->m_style == CREDIT_STYLE_COLUMN && rcLine->m_done == TRUE))
{
cLine->m_text = getUnicodeString(text);
cLine->m_style = CREDIT_STYLE_COLUMN;
cLine->m_useSecond = TRUE;
m_creditLineList.push_back(cLine);
}
else
{
rcLine->m_secondText = getUnicodeString(text);
rcLine->m_done = TRUE;
delete cLine;
}
}
break;
default:
DEBUG_ASSERTCRASH( FALSE, ("CreditsManager::addText we tried to add a credit text with the wrong style before it. Style is %d\n", m_currentStyle) );
delete cLine;
}
}
//-----------------------------------------------------------------------------
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
UnicodeString CreditsManager::getUnicodeString(AsciiString str)
{
UnicodeString uStr;
if(str.compare("<BLANK>") == 0)
return UnicodeString::TheEmptyString;
if(str.find(':'))
uStr = TheGameText->fetch(str);
else
uStr.translate(str);
return uStr;
}

View File

@@ -0,0 +1,385 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: Display.cpp //////////////////////////////////////////////////////////
// The implementation of the Display class
// Author: Michael S. Booth, March 2001
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "GameClient/Display.h"
#include "GameClient/Mouse.h"
#include "GameClient/VideoPlayer.h"
#include "GameClient/DisplayStringManager.h"
#include "GameClient/GameText.h"
#include "GameClient/GlobalLanguage.h"
//#include "GameLogic/ScriptEngine.h"
//#include "GameLogic/GameLogic.h"
/// The Display singleton instance.
Display *TheDisplay = NULL;
Display::Display()
{
m_viewList = NULL;
m_width = 0;
m_height = 0;
m_bitDepth = 0;
m_windowed = FALSE;
m_videoBuffer = NULL;
m_videoStream = NULL;
m_debugDisplayCallback = NULL;
m_debugDisplayUserData = NULL;
m_debugDisplay = NULL;
m_letterBoxFadeLevel = 0;
m_letterBoxEnabled = FALSE;
m_cinematicText = AsciiString::TheEmptyString;
m_cinematicFont = NULL;
m_cinematicTextFrames = 0;
m_movieHoldTime = -1;
m_copyrightHoldTime = -1;
m_elapsedMovieTime = 0;
m_elapsedCopywriteTime = 0;
m_copyrightDisplayString = NULL;
// Added by Sadullah Nader
// Initializations missing and needed
m_currentlyPlayingMovie.clear();
m_letterBoxFadeStartTime = 0;
// End Add
}
/**
* Destructor for the Display. Destroy all views attached to it.
*/
Display::~Display()
{
stopMovie();
// delete all our views if present
deleteViews();
}
/**
* Delete all views in the Display
*/
void Display::deleteViews( void )
{
View *v, *next;
for( v = m_viewList; v; v = next )
{
next = v->getNextView();
delete v;
}
m_viewList = NULL;
}
/**
* Attach the given view to the world
* @todo Rethink the "attachView" notion...
*/
void Display::attachView( View *view )
{
// prepend to head of list
m_viewList = view->prependViewToList( m_viewList );
}
/**
* Render all views of the world
*/
void Display::drawViews( void )
{
for( View *v = m_viewList; v; v = v->getNextView() )
v->drawView();
}
/**
* Updates all views of the world. This forces state variables
to refresh without actually drawing anything.
*/
void Display::updateViews( void )
{
for( View *v = m_viewList; v; v = v->getNextView() )
v->updateView();
}
/// Redraw the entire display
void Display::draw( void )
{
// redraw all views
drawViews();
// redraw the in-game user interface
/// @todo Switch between in-game and shell interfaces
}
/** Sets screen resolution/mode*/
Bool Display::setDisplayMode( UnsignedInt xres, UnsignedInt yres, UnsignedInt bitdepth, Bool windowed )
{
//Get old values
UnsignedInt oldDisplayHeight=getHeight();
UnsignedInt oldDisplayWidth=getWidth();
Int oldViewWidth=TheTacticalView->getWidth();
Int oldViewHeight=TheTacticalView->getHeight();
Int oldViewOriginX,oldViewOriginY;
TheTacticalView->getOrigin(&oldViewOriginX,&oldViewOriginY);
setWidth(xres);
setHeight(yres);
//Adjust view to match previous proportions
TheTacticalView->setWidth((Real)oldViewWidth/(Real)oldDisplayWidth*(Real)xres);
TheTacticalView->setHeight((Real)oldViewHeight/(Real)oldDisplayHeight*(Real)yres);
TheTacticalView->setOrigin((Real)oldViewOriginX/(Real)oldDisplayWidth*(Real)xres,
(Real)oldViewOriginY/(Real)oldDisplayHeight*(Real)yres);
return TRUE;
}
// Display::setWidth ==========================================================
/** Set the width of the display */
//=============================================================================
void Display::setWidth( UnsignedInt width )
{
// set the new width
m_width = width;
// set the new mouse limits
if( TheMouse )
TheMouse->setMouseLimits();
} // end setWidth
// Display::setHeight =========================================================
/** Set the height of the display */
//=============================================================================
void Display::setHeight( UnsignedInt height )
{
// se the new height
m_height = height;
// set the new mouse limits
if( TheMouse )
TheMouse->setMouseLimits();
} // end setHeight
//============================================================================
// Display::playLogoMovie
// minMovieLength is in milliseconds
// minCopyrightLength
//============================================================================
void Display::playLogoMovie( AsciiString movieName, Int minMovieLength, Int minCopyrightLength )
{
stopMovie();
m_videoStream = TheVideoPlayer->open( movieName );
if ( m_videoStream == NULL )
{
return;
}
m_currentlyPlayingMovie = movieName;
m_movieHoldTime = minMovieLength;
m_copyrightHoldTime = minCopyrightLength;
m_elapsedMovieTime = timeGetTime(); // we're using time get time becuase legal want's actual "Seconds"
m_videoBuffer = createVideoBuffer();
if ( m_videoBuffer == NULL ||
!m_videoBuffer->allocate( m_videoStream->width(),
m_videoStream->height())
)
{
stopMovie();
return;
}
}
//============================================================================
// Display::playMovie
//============================================================================
void Display::playMovie( AsciiString movieName)
{
stopMovie();
m_videoStream = TheVideoPlayer->open( movieName );
if ( m_videoStream == NULL )
{
return;
}
m_currentlyPlayingMovie = movieName;
m_videoBuffer = createVideoBuffer();
if ( m_videoBuffer == NULL ||
!m_videoBuffer->allocate( m_videoStream->width(),
m_videoStream->height())
)
{
stopMovie();
return;
}
}
//============================================================================
// Display::stopMovie
//============================================================================
void Display::stopMovie( void )
{
delete m_videoBuffer;
m_videoBuffer = NULL;
if ( m_videoStream )
{
m_videoStream->close();
m_videoStream = NULL;
}
if (!m_currentlyPlayingMovie.isEmpty()) {
//TheScriptEngine->notifyOfCompletedVideo(m_currentlyPlayingMovie); // Removing this sync-error cause MDC
m_currentlyPlayingMovie = AsciiString::TheEmptyString;
}
if(m_copyrightDisplayString)
{
TheDisplayStringManager->freeDisplayString(m_copyrightDisplayString);
m_copyrightDisplayString = NULL;
}
m_copyrightHoldTime = -1;
m_movieHoldTime = -1;
}
//============================================================================
// Display::update
//============================================================================
void Display::update( void )
{
if ( m_videoStream && m_videoBuffer )
{
if ( m_videoStream->isFrameReady())
{
m_videoStream->frameDecompress();
m_videoStream->frameRender( m_videoBuffer );
if( m_videoStream->frameIndex() != m_videoStream->frameCount() - 1)
m_videoStream->frameNext();
else if( m_copyrightHoldTime >= 0 ||m_movieHoldTime >= 0 )
{
if( m_elapsedCopywriteTime == 0 && m_elapsedCopywriteTime >= 0)
{
//display the copyrighttext;
if(m_copyrightDisplayString)
m_copyrightDisplayString->deleteInstance();
m_copyrightDisplayString = TheDisplayStringManager->newDisplayString();
m_copyrightDisplayString->setText(TheGameText->fetch("GUI:EACopyright"));
if (TheGlobalLanguageData && TheGlobalLanguageData->m_copyrightFont.name.isNotEmpty())
{ FontDesc *fontdesc=&TheGlobalLanguageData->m_copyrightFont;
m_copyrightDisplayString->setFont(TheFontLibrary->getFont(fontdesc->name,
TheGlobalLanguageData->adjustFontSize(fontdesc->size),
fontdesc->bold));
}
else
m_copyrightDisplayString->setFont(TheFontLibrary->getFont("Courier",
TheGlobalLanguageData->adjustFontSize(12), TRUE));
m_elapsedCopywriteTime = timeGetTime();
}
if(m_movieHoldTime + m_elapsedMovieTime < timeGetTime() &&
m_copyrightHoldTime + m_elapsedCopywriteTime < timeGetTime())
{
m_movieHoldTime = -1;
m_elapsedMovieTime = 0;
m_elapsedCopywriteTime = 0;
m_copyrightHoldTime = -1;
}
}
else
{
stopMovie();
}
}
}
}
//============================================================================
// Display::reset
//============================================================================
void Display::reset()
{
//Remove letterbox border that may have been enabled by a script
m_letterBoxFadeLevel = 0;
m_letterBoxEnabled = FALSE;
stopMovie();
// Reset all views that need resetting
for( View *v = m_viewList; v; v = v->getNextView() )
v->reset();
}
//============================================================================
// Display::isMoviePlaying
//============================================================================
Bool Display::isMoviePlaying(void)
{
return m_videoStream != NULL && m_videoBuffer != NULL;
}
//============================================================================
// Display::setDebugDisplayCallback
//============================================================================
void Display::setDebugDisplayCallback( DebugDisplayCallback *callback, void *userData )
{
m_debugDisplayCallback = callback;
m_debugDisplayUserData = userData;
}
//============================================================================
// Display::getDebugDisplayCallback
//============================================================================
Display::DebugDisplayCallback *Display::getDebugDisplayCallback()
{
return m_debugDisplayCallback;
}

View File

@@ -0,0 +1,147 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: DisplayString.cpp ////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Westwood Studios Pacific.
//
// Confidential Information
// Copyright (C) 2001 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// Project: RTS3
//
// File name: DisplayString.cpp
//
// Created: Colin Day, July 2001
//
// Desc: Contstuct for holding double byte game string data and being
// able to draw that text to the screen.
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
// USER INCLUDES //////////////////////////////////////////////////////////////
#include "Common/Debug.h"
#include "Common/Language.h"
#include "GameClient/DisplayString.h"
// DEFINES ////////////////////////////////////////////////////////////////////
// PRIVATE TYPES //////////////////////////////////////////////////////////////
// PRIVATE DATA ///////////////////////////////////////////////////////////////
// PUBLIC DATA ////////////////////////////////////////////////////////////////
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// DisplayString::DisplayString ===============================================
/** */
//=============================================================================
DisplayString::DisplayString( void )
{
// m_textString = ""; // not necessary, done by default
m_font = NULL;
m_next = NULL;
m_prev = NULL;
} // end DisplayString
// DisplayString::~DisplayString ==============================================
/** */
//=============================================================================
DisplayString::~DisplayString( void )
{
// free any data
reset();
} // end ~DisplayString
// DisplayString::setText =====================================================
/** Copy the text to this instance */
//=============================================================================
void DisplayString::setText( UnicodeString text )
{
if (text == m_textString)
return;
m_textString = text;
// our text has now changed
notifyTextChanged();
} // end setText
// DisplayString::reset =======================================================
/** Free and reset all the data for this string, effectively making this
* instance like brand new */
//=============================================================================
void DisplayString::reset( void )
{
m_textString.clear();
// no font
m_font = NULL;
} // end reset
// DisplayString::removeLastChar ==============================================
/** Remove the last character from the string text */
//=============================================================================
void DisplayString::removeLastChar( void )
{
m_textString.removeLastChar();
// our text has now changed
notifyTextChanged();
} // end removeLastChar
// DisplayString::appendChar ==================================================
/** Append character to the end of the string */
//=============================================================================
void DisplayString::appendChar( WideChar c )
{
m_textString.concat(c);
// text has now changed
notifyTextChanged();
} // end appendchar

View File

@@ -0,0 +1,103 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: DisplayStringManager.cpp /////////////////////////////////////////////////////////////////
// Created: Colin Day, July 2001
// Desc: Access for creating game managed display strings
///////////////////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "GameClient/DisplayStringManager.h"
// PUBLIC DATA ////////////////////////////////////////////////////////////////////////////////////
DisplayStringManager *TheDisplayStringManager = NULL;
///////////////////////////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTIONS
///////////////////////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
DisplayStringManager::DisplayStringManager( void )
{
m_stringList = NULL;
m_currentCheckpoint = NULL;
} // end DisplayStringManager
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
DisplayStringManager::~DisplayStringManager( void )
{
//
// we only keep track of the strings, we do NOT de-allocate them, our
// list better be cleaned out before we destroy ourselves
//
assert( m_stringList == NULL );
} // end ~DisplayStringManager
//-------------------------------------------------------------------------------------------------
/** Link a display string to the master list */
//-------------------------------------------------------------------------------------------------
void DisplayStringManager::link( DisplayString *string )
{
assert( string );
assert( string->m_next == NULL );
assert( string->m_prev == NULL );
string->m_next = m_stringList;
if( m_stringList )
m_stringList->m_prev = string;
m_stringList = string;
} // end link
//-------------------------------------------------------------------------------------------------
/** Unlink a display string from the master list */
//-------------------------------------------------------------------------------------------------
void DisplayStringManager::unLink( DisplayString *string )
{
assert( string );
assert( m_stringList );
if( string->m_next )
string->m_next->m_prev = string->m_prev;
if( string->m_prev )
string->m_prev->m_next = string->m_next;
else
{
assert( string == m_stringList );
m_stringList = string->m_next;
} // end else
} // end unLink

View File

@@ -0,0 +1,55 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// DrawGroupInfo.cpp //////////////////////////////////////////////////////////////////////////////
// Author: John McDonald, October 2002
///////////////////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "GameClient/DrawGroupInfo.h"
// Useful defaults.
DrawGroupInfo::DrawGroupInfo()
{
m_fontName = "Arial";
m_fontSize = 10;
m_fontIsBold = FALSE;
m_usePlayerColor = TRUE;
m_colorForText = GameMakeColor(255, 255, 255, 255);
m_colorForTextDropShadow = GameMakeColor(0, 0, 0, 255);
m_dropShadowOffsetX = -1;
m_dropShadowOffsetY = -1;
m_percentOffsetX = -0.05f;
m_usingPixelOffsetX = FALSE;
m_pixelOffsetY = -10;
m_usingPixelOffsetY = TRUE;
}
DrawGroupInfo *TheDrawGroupInfo = NULL;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,26 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine

View File

@@ -0,0 +1,133 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: AnimatedParticleSysBoneClientUpdate.cpp //////////////////////////////////////////////////////////////////
// Author: Mark Lorenzen, October 2002
// Desc: client update module to translate particle systems with animation
///////////////////////////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "GameClient/Drawable.h"
#include "GameClient/Module/AnimatedParticleSysBoneClientUpdate.h"
#include "Common/Player.h"
#include "Common/PlayerList.h"
#include "Common/ThingFactory.h"
#include "Common/ThingTemplate.h"
#include "Common/RandomValue.h"
#include "Common/DrawModule.h"
#include "Common/PerfTimer.h"
#include "Common/Xfer.h"
#include "GameLogic/Object.h"
#include "GameLogic/ScriptEngine.h"
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
AnimatedParticleSysBoneClientUpdate::AnimatedParticleSysBoneClientUpdate( Thing *thing, const ModuleData* moduleData ) :
ClientUpdateModule( thing, moduleData )
{
m_life = 0;
}
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
AnimatedParticleSysBoneClientUpdate::~AnimatedParticleSysBoneClientUpdate( void )
{
}
//-------------------------------------------------------------------------------------------------
/** The client update callback. */
//-------------------------------------------------------------------------------------------------
void AnimatedParticleSysBoneClientUpdate::clientUpdate( void )
{
//THIS IS HAPPENING CLIENT-SIDE
// I CAN DO WHAT I NEED HERE AND NOT HAVE TO BE LOGIC SYNC-SAFE
++m_life;
Drawable *draw = getDrawable();
if (draw)
{
for (DrawModule** dm = draw->getDrawModules(); *dm; ++dm)
{
ObjectDrawInterface* di = (*dm)->getObjectDrawInterface();
if (di)
{
if (di->updateBonesForClientParticleSystems())
break;
}
}
}
}
// ------------------------------------------------------------------------------------------------
/** CRC */
// ------------------------------------------------------------------------------------------------
void AnimatedParticleSysBoneClientUpdate::crc( Xfer *xfer )
{
// extend base class
ClientUpdateModule::crc( xfer );
} // end crc
// ------------------------------------------------------------------------------------------------
/** Xfer method
* Version Info:
* 1: Initial version */
// ------------------------------------------------------------------------------------------------
void AnimatedParticleSysBoneClientUpdate::xfer( Xfer *xfer )
{
// version
XferVersion currentVersion = 1;
XferVersion version = currentVersion;
xfer->xferVersion( &version, currentVersion );
// extend base class
ClientUpdateModule::xfer( xfer );
} // end xfer
// ------------------------------------------------------------------------------------------------
/** Load post process */
// ------------------------------------------------------------------------------------------------
void AnimatedParticleSysBoneClientUpdate::loadPostProcess( void )
{
// extend base class
ClientUpdateModule::loadPostProcess();
} // end loadPostProcess

View File

@@ -0,0 +1,230 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: BeaconClientUpdate.cpp //////////////////////////////////////////////////////////////////
// Author: Matthew D. Campbell, August 2002
// Desc: Beacon client update module
///////////////////////////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine
#include "GameClient/Drawable.h"
#include "GameClient/ParticleSys.h"
#include "GameClient/Module/BeaconClientUpdate.h"
#include "Common/Player.h"
#include "Common/PlayerList.h"
#include "Common/Radar.h"
#include "Common/Xfer.h"
#include "GameLogic/GameLogic.h"
//-------------------------------------------------------------------------------------------------
BeaconClientUpdateModuleData::BeaconClientUpdateModuleData() :
m_framesBetweenRadarPulses(30),
m_radarPulseDuration(15)
{
}
//-------------------------------------------------------------------------------------------------
BeaconClientUpdateModuleData::~BeaconClientUpdateModuleData()
{
}
//-------------------------------------------------------------------------------------------------
void BeaconClientUpdateModuleData::buildFieldParse(MultiIniFieldParse& p)
{
ClientUpdateModuleData::buildFieldParse(p);
static const FieldParse dataFieldParse[] =
{
{ "RadarPulseFrequency", INI::parseDurationUnsignedInt, NULL, offsetof(BeaconClientUpdateModuleData, m_framesBetweenRadarPulses) },
{ "RadarPulseDuration", INI::parseDurationUnsignedInt, NULL, offsetof(BeaconClientUpdateModuleData, m_radarPulseDuration) },
{ 0, 0, 0, 0 }
};
p.add(dataFieldParse);
}
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
BeaconClientUpdate::BeaconClientUpdate( Thing *thing, const ModuleData* moduleData ) :
ClientUpdateModule( thing, moduleData ),
m_particleSystemID(INVALID_PARTICLE_SYSTEM_ID),
m_lastRadarPulse(TheGameLogic->getFrame())
{
}
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
BeaconClientUpdate::~BeaconClientUpdate( void )
{
}
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
static ParticleSystem* createParticleSystem( Drawable *draw )
{
ParticleSystem *system = NULL;
if (draw)
{
Object *obj = draw->getObject();
if (obj)
{
AsciiString templateName;
templateName.format("BeaconSmoke%6.6X", (0xffffff & obj->getIndicatorColor()));
const ParticleSystemTemplate *particleTemplate = TheParticleSystemManager->findTemplate( templateName );
DEBUG_ASSERTCRASH(particleTemplate, ("Could not find particle system %s\n", templateName.str()));
if (particleTemplate)
{
system = TheParticleSystemManager->createParticleSystem( particleTemplate );
if (system)
system->attachToDrawable( draw );
}
else// This is a failsafe... if someone has monkeyed with the particle system names, or the MP house colors
{// THis this will whip up a new particle system to match the house color provided
templateName.format("BeaconSmokeFFFFFF");
const ParticleSystemTemplate *failsafeTemplate = TheParticleSystemManager->findTemplate( templateName );
DEBUG_ASSERTCRASH(failsafeTemplate, ("Doh, this is bad \n I Could not even find the white particle system to make a failsafe system out of."));
if (failsafeTemplate)
{
system = TheParticleSystemManager->createParticleSystem( failsafeTemplate );
if (system)
{
system->attachToDrawable( draw );
system->tintAllColors( obj->getIndicatorColor() );
}
}
}
}
}
return system;
}
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
void BeaconClientUpdate::hideBeacon( void )
{
Drawable *draw = getDrawable();
if (draw)
{
draw->setDrawableHidden( true );
draw->setShadowsEnabled( false );
}
ParticleSystem *system;
if (draw && m_particleSystemID == INVALID_PARTICLE_SYSTEM_ID)
{
system = createParticleSystem( draw );
if (system)
m_particleSystemID = system->getSystemID();
}
// clean up particle system
if (m_particleSystemID != INVALID_PARTICLE_SYSTEM_ID)
{
ParticleSystem *system = TheParticleSystemManager->findParticleSystem( m_particleSystemID );
if( system )
system->stop();
} // end if
// DEBUG_LOG(("in hideBeacon(): draw=%d, m_particleSystemID=%d\n", draw, m_particleSystemID));
}
//-------------------------------------------------------------------------------------------------
/** The client update callback. */
//-------------------------------------------------------------------------------------------------
void BeaconClientUpdate::clientUpdate( void )
{
Drawable *draw = getDrawable();
if (!draw)
return;
if (m_particleSystemID == INVALID_PARTICLE_SYSTEM_ID)
{
ParticleSystem *system = createParticleSystem( draw );
if( system )
m_particleSystemID = system->getSystemID();
}
if (!draw->isDrawableEffectivelyHidden())
{
BeaconClientUpdateModuleData *moduleData = (BeaconClientUpdateModuleData *)getModuleData();
if (TheGameLogic->getFrame() > m_lastRadarPulse + moduleData->m_framesBetweenRadarPulses)
{
TheRadar->createEvent( draw->getPosition(), RADAR_EVENT_BEACON_PULSE, moduleData->m_radarPulseDuration * SECONDS_PER_LOGICFRAME_REAL );
m_lastRadarPulse = TheGameLogic->getFrame();
}
}
}
// ------------------------------------------------------------------------------------------------
/** CRC */
// ------------------------------------------------------------------------------------------------
void BeaconClientUpdate::crc( Xfer *xfer )
{
// extend base class
ClientUpdateModule::crc( xfer );
} // end crc
// ------------------------------------------------------------------------------------------------
/** Xfer method
* Version Info:
* 1: Initial version */
// ------------------------------------------------------------------------------------------------
void BeaconClientUpdate::xfer( Xfer *xfer )
{
// version
XferVersion currentVersion = 1;
XferVersion version = currentVersion;
xfer->xferVersion( &version, currentVersion );
// extend base class
ClientUpdateModule::xfer( xfer );
// particle system ID
xfer->xferUser( &m_particleSystemID, sizeof( ParticleSystemID ) );
// last radar pulse
xfer->xferUnsignedInt( &m_lastRadarPulse );
} // end xfer
// ------------------------------------------------------------------------------------------------
/** Load post process */
// ------------------------------------------------------------------------------------------------
void BeaconClientUpdate::loadPostProcess( void )
{
// extend base class
ClientUpdateModule::loadPostProcess();
} // end loadPostProcess

View File

@@ -0,0 +1,205 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: SwayClientUpdate.cpp //////////////////////////////////////////////////////////////////
// Author: Matthew D. Campbell, May 2002
// Desc: Tree sway client update module
///////////////////////////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "GameClient/Drawable.h"
#include "GameClient/Module/SwayClientUpdate.h"
#include "Common/Player.h"
#include "Common/PlayerList.h"
#include "Common/ThingFactory.h"
#include "Common/ThingTemplate.h"
#include "Common/RandomValue.h"
#include "Common/PerfTimer.h"
#include "Common/Xfer.h"
#include "GameLogic/Object.h"
#include "GameLogic/ScriptEngine.h"
#include "GameLogic/GameLogic.h"
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
SwayClientUpdate::SwayClientUpdate( Thing *thing, const ModuleData* moduleData ) :
ClientUpdateModule( thing, moduleData ),
m_curDelta(0),
m_curValue(0),
m_curAngle(0),
m_curAngleLimit(0),
m_leanAngle(0),
m_swaying(true),
m_unused(false),
m_curVersion(-1) // so that we never match the first time
{
// don't do updateSway here; wait till the first time we go thru our update loop.
//updateSway();
}
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
SwayClientUpdate::~SwayClientUpdate( void )
{
}
//-------------------------------------------------------------------------------------------------
// Update the sway parameters.
//-------------------------------------------------------------------------------------------------
void SwayClientUpdate::updateSway()
{
const BreezeInfo& info = TheScriptEngine->getBreezeInfo();
if (info.m_randomness == 0.0f)
{
m_curValue = 0;
}
Real delta = info.m_randomness * 0.5f;
m_curAngleLimit = info.m_intensity * GameClientRandomValueReal(1.0f-delta, 1.0f+delta);
m_curDelta = 2*PI/info.m_breezePeriod * GameClientRandomValueReal(1.0f-delta, 1.0f+delta);
m_leanAngle = info.m_lean * GameClientRandomValueReal(1.0f-delta, 1.0f+delta);
m_curVersion = info.m_breezeVersion;
}
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
/** The client update callback. */
//-------------------------------------------------------------------------------------------------
void SwayClientUpdate::clientUpdate( void )
{
if( !m_swaying )
return;
Drawable *draw = getDrawable();
// if breeze changes, always process the full update, even if not visible,
// so that things offscreen won't 'pop' when first viewed
const BreezeInfo& info = TheScriptEngine->getBreezeInfo();
if (info.m_breezeVersion != m_curVersion)
{
updateSway();
}
else
{
// Otherwise, only update visible drawables
if (!draw || !draw->isVisible())
return;
}
m_curValue += m_curDelta;
if (m_curValue > 2*PI)
m_curValue -= 2*PI;
Real cosine = Cos(m_curValue);
Real targetAngle = cosine * m_curAngleLimit + m_leanAngle;
Real deltaAngle = targetAngle - m_curAngle;
Matrix3D xfrm = *draw->getInstanceMatrix();
xfrm.In_Place_Pre_Rotate_X(-deltaAngle * info.m_directionVec.x);
xfrm.In_Place_Pre_Rotate_Y(deltaAngle * info.m_directionVec.y);
draw->setInstanceMatrix(&xfrm);
m_curAngle = targetAngle;
// burned things don't sway.
Object* obj = draw->getObject();
if (obj && (obj->getStatusBits() & OBJECT_STATUS_BURNED) != 0)
stopSway();
}
// ------------------------------------------------------------------------------------------------
/** CRC */
// ------------------------------------------------------------------------------------------------
void SwayClientUpdate::crc( Xfer *xfer )
{
// extend base class
ClientUpdateModule::crc( xfer );
} // end crc
// ------------------------------------------------------------------------------------------------
/** Xfer method
* Version Info:
* 1: Initial version */
// ------------------------------------------------------------------------------------------------
void SwayClientUpdate::xfer( Xfer *xfer )
{
// version
XferVersion currentVersion = 1;
XferVersion version = currentVersion;
xfer->xferVersion( &version, currentVersion );
// extend base class
ClientUpdateModule::xfer( xfer );
// cur value
xfer->xferReal( &m_curValue );
// cur angle
xfer->xferReal( &m_curAngle );
// cur delta
xfer->xferReal( &m_curDelta );
// cur angle limit
xfer->xferReal( &m_curAngleLimit );
// lean angle
xfer->xferReal( &m_leanAngle );
// cur version
xfer->xferShort( &m_curVersion );
// swaying
xfer->xferBool( &m_swaying );
} // end xfer
// ------------------------------------------------------------------------------------------------
/** Load post process */
// ------------------------------------------------------------------------------------------------
void SwayClientUpdate::loadPostProcess( void )
{
// extend base class
ClientUpdateModule::loadPostProcess();
updateSway();
} // end loadPostProcess

View File

@@ -0,0 +1,22 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
// DrawableManager.cpp
// Message stream translator
// Author: Michael S. Booth, March 2001

View File

@@ -0,0 +1,465 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// GameClient/Eva.cpp /////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "GameClient/Eva.h"
#include "Common/Player.h"
#include "Common/PlayerList.h"
#include "GameLogic/GameLogic.h"
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
//-------------------------------------------------------------------------------------------------
const char *TheEvaMessageNames[] =
{
"LOWPOWER",
"INSUFFICIENTFUNDS",
"SUPERWEAPONDETECTED_PARTICLECANNON",
"SUPERWEAPONDETECTED_NUKE",
"SUPERWEAPONDETECTED_SCUDSTORM",
"SUPERWEAPONLAUNCHED_PARTICLECANNON",
"SUPERWEAPONLAUNCHED_NUKE",
"SUPERWEAPONLAUNCHED_SCUDSTORM",
"BUILDINGLOST",
"BASEUNDERATTACK",
"ALLYUNDERATTACK",
"BEACONDETECTED",
"UNITLOST",
"GENERALLEVELUP",
"VEHICLESTOLEN",
"BUILDINGSTOLEN",
"CASHSTOLEN",
"UPGRADECOMPLETE",
"BUILDINGBEINGSTOLEN",
"EVA_INVALID",
};
//------------------------------------------------------------------------------ INI::parseEvaEvent
void INI::parseEvaEvent( INI* ini )
{
AsciiString name;
// read the name
const char* c = ini->getNextToken();
name.set( c );
EvaCheckInfo *check = TheEva->newEvaCheckInfo( name );
if (!check) {
// could be null because it already exists.
return;
}
// parse the ini definition
ini->initFromINI( check, check->getFieldParse() );
}
//----------------------------------------------------------------------------------- EvaSideSounds
static void parseSideSoundsList( INI *ini, void *instance, void *store, const void* userData )
{
std::vector<EvaSideSounds> *sounds = (std::vector<EvaSideSounds>*) store;
EvaSideSounds newSounds;
ini->initFromINI( &newSounds, newSounds.getFieldParse() );
// This could be made more efficient, but to be honest, it shouldn't be that slow.
sounds->push_back(newSounds);
}
//----------------------------------------------------------------------------------- EvaSideSounds
const FieldParse EvaSideSounds::s_evaSideSounds[] =
{
{ "Side", INI::parseAsciiString, NULL, offsetof( EvaSideSounds, m_side) },
{ "Sounds", INI::parseSoundsList, NULL, offsetof( EvaSideSounds, m_soundNames) },
{ 0, 0, 0, 0 },
};
//------------------------------------------------------------------------------------ EvaCheckInfo
EvaCheckInfo::EvaCheckInfo() :
m_message(EVA_COUNT),
m_priority(0), // lowest of all priorities
m_framesBetweenChecks(900), // 30 seconds at 30 fps
m_framesToExpire(150) // 5 seconds at 30 fps
{
}
//-------------------------------------------------------------------------------------------------
const FieldParse EvaCheckInfo::s_evaEventInfo[] =
{
{ "Priority", INI::parseUnsignedInt, NULL, offsetof( EvaCheckInfo, m_priority ) },
{ "TimeBetweenChecksMS", INI::parseDurationUnsignedInt, NULL, offsetof( EvaCheckInfo, m_framesBetweenChecks ) },
{ "ExpirationTimeMS", INI::parseDurationUnsignedInt, NULL, offsetof( EvaCheckInfo, m_framesToExpire) },
{ "SideSounds", parseSideSoundsList, NULL, offsetof( EvaCheckInfo, m_evaSideSounds ) },
{ 0, 0, 0, 0 },
};
//-------------------------------------------------------------------------------------------------
const ShouldPlayFunc Eva::s_shouldPlayFuncs[] =
{
Eva::shouldPlayLowPower,
Eva::shouldPlayGenericHandler,
Eva::shouldPlayGenericHandler,
Eva::shouldPlayGenericHandler,
Eva::shouldPlayGenericHandler,
Eva::shouldPlayGenericHandler,
Eva::shouldPlayGenericHandler,
Eva::shouldPlayGenericHandler,
Eva::shouldPlayGenericHandler,
Eva::shouldPlayGenericHandler,
Eva::shouldPlayGenericHandler,
Eva::shouldPlayGenericHandler,
Eva::shouldPlayGenericHandler,
Eva::shouldPlayGenericHandler,
Eva::shouldPlayGenericHandler,
Eva::shouldPlayGenericHandler,
Eva::shouldPlayGenericHandler,
Eva::shouldPlayGenericHandler,
Eva::shouldPlayGenericHandler,
NULL,
};
//-------------------------------------------------------------------------------------------------
EvaCheck::EvaCheck() :
m_evaInfo(NULL),
m_triggeredOnFrame(TRIGGEREDON_NOT),
m_timeForNextCheck(NEXT_CHECK_NOW),
m_alreadyPlayed(FALSE)
{
}
//-------------------------------------------------------------------------------------------------
Eva::Eva() :
m_localPlayer(NULL),
m_previousBuildingCount(0),
m_previousUnitCount(0),
m_enabled(TRUE)
{
for (Int i = 0; i < EVA_COUNT; ++i) {
m_shouldPlay[i] = FALSE;
}
}
//-------------------------------------------------------------------------------------------------
Eva::~Eva()
{
EvaCheckInfoPtrVecIt it;
for (it = m_allCheckInfos.begin(); it != m_allCheckInfos.end(); ++it) {
if (*it)
(*it)->deleteInstance();
}
}
//-------------------------------------------------------------------------------------------------
void Eva::init()
{
// parse the INI here, etc.
INI ini;
ini.load( AsciiString( "Data\\INI\\Eva.ini" ), INI_LOAD_OVERWRITE, NULL);
}
//-------------------------------------------------------------------------------------------------
void Eva::reset()
{
m_previousUnitCount = 0;
m_previousBuildingCount = 0;
// remove all pending counters, etc, here.
EvaCheckVecIt it;
for (it = m_checks.begin(); it != m_checks.end(); /* empty */) {
it = m_checks.erase(it);
}
// remove all things flagged as "need to play"
for (Int i = 0; i < EVA_COUNT; ++i) {
m_shouldPlay[i] = FALSE;
}
// If we were previously disabled, re-enable ourselves.
m_enabled = TRUE;
}
//-------------------------------------------------------------------------------------------------
void Eva::update()
{
if (!m_enabled) {
return;
}
m_localPlayer = ThePlayerList->getLocalPlayer();
UnsignedInt frame = TheGameLogic->getFrame();
// Don't update for the first few frames. This way, we don't have to deal with our initial power
// being 0, etc.
if (frame < 2) {
return;
}
for (Int mesg = (Int)EVA_FIRST; mesg < (Int)EVA_COUNT; ++mesg) {
if (isTimeForCheck((EvaMessage)mesg, frame)) {
if (messageShouldPlay((EvaMessage)mesg, frame)) {
playMessage((EvaMessage)mesg, frame);
}
}
}
processPlayingMessages(frame);
m_localPlayer = NULL;
// Reset all of the flags that have been set to true that haven't actually been probed, because
// they will need to trigger again to be valid messages.
for (Int i = EVA_FIRST; i < EVA_COUNT; ++i) {
m_shouldPlay[i] = FALSE;
}
}
//-------------------------------------------------------------------------------------------------
EvaMessage Eva::nameToMessage(const AsciiString& name)
{
for (Int i = EVA_FIRST; i < EVA_COUNT; ++i) {
if (name.compareNoCase(TheEvaMessageNames[i]) == 0) {
return (EvaMessage) i;
}
}
DEBUG_CRASH(("Invalid requested Eva message translation :%s: jkmcd", name.str()));
return EVA_COUNT;
}
//-------------------------------------------------------------------------------------------------
AsciiString Eva::messageToName(EvaMessage message)
{
if (message >= EVA_FIRST && message < EVA_COUNT)
return TheEvaMessageNames[message];
DEBUG_CRASH(("Invalid requested Eva message translation. jkmcd"));
return AsciiString::TheEmptyString;
}
//-------------------------------------------------------------------------------------------------
EvaCheckInfo *Eva::newEvaCheckInfo(AsciiString name)
{
EvaMessage mesg = nameToMessage(name);
// Only return a new one if there isn't an existing one.
EvaCheckInfoPtrVecIt it;
for (it = m_allCheckInfos.begin(); it != m_allCheckInfos.end(); ++it) {
if (*it && (*it)->m_message == mesg)
return NULL;
}
EvaCheckInfo *checkInfo = newInstance(EvaCheckInfo);
m_allCheckInfos.push_back(checkInfo);
checkInfo->m_message = mesg;
return checkInfo;
}
//-------------------------------------------------------------------------------------------------
const EvaCheckInfo *Eva::getEvaCheckInfo(AsciiString name)
{
EvaMessage mesg = nameToMessage(name);
// Only return a new one if there isn't an existing one.
EvaCheckInfoPtrVecIt it;
for (it = m_allCheckInfos.begin(); it != m_allCheckInfos.end(); ++it) {
if (*it && (*it)->m_message == mesg)
return *it;
}
return NULL;
}
//-------------------------------------------------------------------------------------------------
void Eva::setShouldPlay(EvaMessage messageToPlay)
{
m_shouldPlay[messageToPlay] = TRUE;
}
//-------------------------------------------------------------------------------------------------
void Eva::setEvaEnabled(Bool enabled)
{
// clear out any waiting messages.
for (Int i = EVA_FIRST; i < EVA_COUNT; ++i) {
m_shouldPlay[i] = FALSE;
}
m_enabled = enabled;
}
//-------------------------------------------------------------------------------------------------
Bool Eva::isTimeForCheck(EvaMessage messageToTest, UnsignedInt currentFrame) const
{
EvaCheckVec::const_iterator it;
for (it = m_checks.begin(); it != m_checks.end(); ++it) {
if (it->m_evaInfo->m_message == messageToTest) {
return FALSE;
}
}
return TRUE;
}
//-------------------------------------------------------------------------------------------------
Bool Eva::messageShouldPlay(EvaMessage messageToTest, UnsignedInt currentFrame) const
{
if (m_localPlayer == NULL) {
return FALSE;
}
m_messageBeingTested = messageToTest;
return s_shouldPlayFuncs[messageToTest](m_localPlayer);
}
//-------------------------------------------------------------------------------------------------
Bool Eva::shouldPlayLowPower( Player *localPlayer )
{
// @todo make eva sensitive to whether player can do anything about it...
// "Low power, Low power, Low power, yadda yadda yadda..."
//const ThingTemplate *chinaReactorTemplate = findTemplate(;
//const ThingTemplate *americanReactorTemplate;
//if ( chinaReactorTemplate && americanReactorTemplate )
//{
// if ( ! (localPlayer->canBuild(chinaReactorTemplate) || localPlayer->canBuild(americanReactorTemplate)) )
// return FALSE
//}
return !localPlayer->getEnergy()->hasSufficientPower();
}
//-------------------------------------------------------------------------------------------------
Bool Eva::shouldPlayGenericHandler( Player * )
{
if (TheEva->m_shouldPlay[TheEva->m_messageBeingTested]) {
TheEva->m_shouldPlay[TheEva->m_messageBeingTested] = FALSE;
return TRUE;
}
return FALSE;
}
//-------------------------------------------------------------------------------------------------
void Eva::playMessage(EvaMessage messageToTest, UnsignedInt currentFrame)
{
EvaCheck check;
check.m_evaInfo = getEvaCheckInfo(Eva::messageToName(messageToTest));
if (!check.m_evaInfo) {
return;
}
check.m_timeForNextCheck = currentFrame + check.m_evaInfo->m_framesBetweenChecks;
check.m_triggeredOnFrame = currentFrame;
check.m_alreadyPlayed = FALSE;
m_checks.push_back(check);
}
//-------------------------------------------------------------------------------------------------
void Eva::processPlayingMessages(UnsignedInt currentFrame)
{
// First pass, remove all the objects that can check after this frame.
EvaCheckVecIt it;
for (it = m_checks.begin(); it != m_checks.end(); /* empty */) {
// These are requests that will be available next frame because they've played.
if (it->m_timeForNextCheck <= currentFrame + 1 && it->m_alreadyPlayed) {
it = m_checks.erase(it);
continue;
}
// These are requests that never got a chance to play and have since expired.
if (it->m_triggeredOnFrame + it->m_evaInfo->m_framesToExpire <= currentFrame && !it->m_alreadyPlayed) {
it = m_checks.erase(it);
continue;
}
++it;
}
// It's possible, although unlikely, that we removed everything in the list.
if (m_checks.begin() == m_checks.end()) {
return;
}
// If we're currently playing some audio, we're done.
if (m_evaSpeech.isCurrentlyPlaying()) {
return;
}
// Okay. No one is currently playing anything, so lets find an event and trigger it.
EvaCheckVecIt storedIt = m_checks.end();
UnsignedInt highestPriority = 0;
for (it = m_checks.begin(); it != m_checks.end(); ++it) {
if (it->m_evaInfo->m_priority > highestPriority && !it->m_alreadyPlayed) {
storedIt = it;
highestPriority = it->m_evaInfo->m_priority;
}
}
// There wasn't anything waiting to play.
if (storedIt == m_checks.end()) {
return;
}
// We've got a winner!
AsciiString side = ThePlayerList->getLocalPlayer()->getSide();
Int numSides = storedIt->m_evaInfo->m_evaSideSounds.size();
for (Int i = 0; i < numSides; ++i) {
if (side.compareNoCase(storedIt->m_evaInfo->m_evaSideSounds[i].m_side) == 0) {
// Its this one.
if (storedIt->m_evaInfo->m_evaSideSounds[i].m_soundNames.size() > 0) {
Int soundToPlay = GameClientRandomValue(0, storedIt->m_evaInfo->m_evaSideSounds[i].m_soundNames.size() - 1);
m_evaSpeech.setEventName(storedIt->m_evaInfo->m_evaSideSounds[i].m_soundNames[soundToPlay]);
} else {
// clear it.
m_evaSpeech.setEventName(AsciiString::TheEmptyString);
}
}
}
// Update the entry
storedIt->m_alreadyPlayed = true;
storedIt->m_timeForNextCheck = currentFrame + storedIt->m_evaInfo->m_framesBetweenChecks;
// Now that we correctly filter messages, we need to set the player index for who should hear the
// sound to the local player.
m_evaSpeech.setPlayerIndex(m_localPlayer->getPlayerIndex());
m_evaSpeech.setPlayingHandle(TheAudio->addAudioEvent(&m_evaSpeech));
}
//-------------------------------------------------------------------------------------------------
Eva *TheEva = NULL;

View File

@@ -0,0 +1,877 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: FXList.cpp ///////////////////////////////////////////////////////////////////////////////
// Author: Steven Johnson, December 2001
// Desc: FXList descriptions
///////////////////////////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "GameClient/FXList.h"
#include "Common/DrawModule.h"
#include "Common/GameAudio.h"
#include "Common/INI.h"
#include "Common/Player.h"
#include "Common/PlayerList.h"
#include "Common/RandomValue.h"
#include "Common/ThingTemplate.h"
#include "Common/ThingFactory.h"
#include "GameLogic/Object.h"
#include "GameLogic/GameLogic.h"
#include "GameLogic/TerrainLogic.h"
#include "GameClient/Display.h"
#include "GameClient/GameClient.h"
#include "GameClient/Drawable.h"
#include "GameClient/ParticleSys.h"
#include "GameLogic/PartitionManager.h"
///////////////////////////////////////////////////////////////////////////////////////////////////
// PUBLIC DATA ////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
FXListStore *TheFXListStore = NULL; ///< the FXList store definition
//-------------------------------------------------------------------------------------------------
static void adjustVector(Coord3D *vec, const Matrix3D* mtx)
{
if (mtx)
{
Vector3 vectmp;
vectmp.X = vec->x;
vectmp.Y = vec->y;
vectmp.Z = vec->z;
vectmp = mtx->Rotate_Vector(vectmp);
vec->x = vectmp.X;
vec->y = vectmp.Y;
vec->z = vectmp.Z;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// PRIVATE CLASSES ///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------------------------
void FXNugget::doFXObj(const Object* primary, const Object* secondary) const
{
const Coord3D* p = primary ? primary->getPosition() : NULL;
const Matrix3D* mtx = primary ? primary->getTransformMatrix() : NULL;
const Real speed = 0.0f; // yes, that's right -- NOT the object's speed.
const Coord3D* s = secondary ? secondary->getPosition() : NULL;
doFXPos(p, mtx, speed, s);
}
//-------------------------------------------------------------------------------------------------
class SoundFXNugget : public FXNugget
{
MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(SoundFXNugget, "SoundFXNugget")
public:
virtual void doFXPos(const Coord3D *primary, const Matrix3D* /*primaryMtx*/, const Real /*primarySpeed*/, const Coord3D * /*secondary*/, const Real /*overrideRadius*/ ) const
{
AudioEventRTS sound(m_soundName);
if (primary)
{
sound.setPosition(primary);
}
TheAudio->addAudioEvent(&sound);
}
virtual void doFXObj(const Object* primary, const Object* secondary = NULL) const
{
AudioEventRTS sound(m_soundName);
if (primary)
{
sound.setPlayerIndex(primary->getControllingPlayer()->getPlayerIndex());
sound.setPosition(primary->getPosition());
}
TheAudio->addAudioEvent(&sound);
}
static void parse(INI *ini, void *instance, void* /*store*/, const void* /*userData*/)
{
static const FieldParse myFieldParse[] =
{
{ "Name", INI::parseAsciiString, NULL, offsetof( SoundFXNugget, m_soundName ) },
{ 0, 0, 0, 0 }
};
SoundFXNugget* nugget = newInstance(SoundFXNugget);
ini->initFromINI(nugget, myFieldParse);
((FXList*)instance)->addFXNugget(nugget);
}
private:
AsciiString m_soundName;
};
EMPTY_DTOR(SoundFXNugget)
//-------------------------------------------------------------------------------------------------
static Real calcDist(const Coord3D& src, const Coord3D& dst)
{
Real dx = dst.x - src.x;
Real dy = dst.y - src.y;
Real dz = dst.z - src.z;
return sqrt(dx*dx + dy*dy + dz*dz);
}
//-------------------------------------------------------------------------------------------------
class TracerFXNugget : public FXNugget
{
MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(TracerFXNugget, "TracerFXNugget")
public:
TracerFXNugget()
{
m_tracerName.set("GenericTracer");
m_boneName.clear();
m_speed = 0.0f; // means "use passed-in speed"
m_decayAt = 1.0f;
m_length = 10.0f;
m_width = 1.0f;
m_color.red = m_color.green = m_color.blue = 1.0f;
m_probability = 1.0f;
}
virtual void doFXPos(const Coord3D *primary, const Matrix3D* primaryMtx, const Real primarySpeed, const Coord3D *secondary, const Real /*overrideRadius*/ ) const
{
if (m_probability <= GameClientRandomValueReal(0, 1))
return;
if (primary && secondary)
{
Drawable *tracer = TheThingFactory->newDrawable(TheThingFactory->findTemplate(m_tracerName));
if(!tracer)
return;
//Kris -- Redid this section Sept 18, 2002
//Calculate tracer orientations to face from primary to secondary position. This
//should be the direction that the projectile is being fired towards. It doesn't make
//sense that the old stuff made use of the muzzle fx bone orientation (because it's a
//subobject). It had other problems because of elevation variations the tracers would
//stay on the ground.
//tracer->setTransformMatrix(primaryMtx);
Matrix3D tracerMtx;
Vector3 pos( primary->x, primary->y, primary->z );
Vector3 dir( secondary->x - primary->x, secondary->y - primary->y, secondary->z - primary->z );
dir.Normalize(); //This is fantastically crucial for calling buildTransformMatrix!!!!!
tracerMtx.buildTransformMatrix( pos, dir );
tracer->setTransformMatrix( &tracerMtx );
tracer->setPosition(primary);
Real speed = m_speed;
if (speed == 0.0f)
{
speed = primarySpeed;
}
TracerDrawInterface* tdi = NULL;
for (DrawModule** d = tracer->getDrawModules(); *d; ++d)
{
if ((tdi = (*d)->getTracerDrawInterface()) != NULL)
{
tdi->setTracerParms(speed, m_length, m_width, m_color, 1.0f);
}
}
// estimate how long it will take us to get to the destination
Real dist = calcDist(*primary, *secondary) - m_length;
Real frames = (dist >= 0.0f && speed >= 0.0f) ? (dist / speed) : 1;
Int framesAdjusted = REAL_TO_INT_CEIL(frames * m_decayAt);
tracer->setExpirationDate(TheGameLogic->getFrame() + framesAdjusted);
}
else
{
DEBUG_CRASH(("You must have a primary and secondary source for this effect"));
}
}
static void parse(INI *ini, void *instance, void* /*store*/, const void* /*userData*/)
{
static const FieldParse myFieldParse[] =
{
{ "TracerName", INI::parseAsciiString, NULL, offsetof( TracerFXNugget, m_tracerName ) },
{ "BoneName", INI::parseAsciiString, NULL, offsetof( TracerFXNugget, m_boneName ) },
{ "Speed", INI::parseVelocityReal, NULL, offsetof( TracerFXNugget, m_speed ) },
{ "DecayAt", INI::parseReal, NULL, offsetof( TracerFXNugget, m_decayAt ) },
{ "Length", INI::parseReal, NULL, offsetof( TracerFXNugget, m_length ) },
{ "Width", INI::parseReal, NULL, offsetof( TracerFXNugget, m_width ) },
{ "Color", INI::parseRGBColor, NULL, offsetof( TracerFXNugget, m_color ) },
{ "Probability", INI::parseReal, NULL, offsetof( TracerFXNugget, m_probability ) },
{ 0, 0, 0, 0 }
};
TracerFXNugget* nugget = newInstance( TracerFXNugget );
ini->initFromINI(nugget, myFieldParse);
((FXList*)instance)->addFXNugget(nugget);
}
private:
AsciiString m_tracerName;
AsciiString m_boneName;
Real m_speed;
Real m_decayAt;
Real m_length;
Real m_width;
RGBColor m_color;
Real m_probability;
};
EMPTY_DTOR(TracerFXNugget)
//-------------------------------------------------------------------------------------------------
class RayEffectFXNugget : public FXNugget
{
MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(RayEffectFXNugget, "RayEffectFXNugget")
public:
RayEffectFXNugget()
{
m_templateName.clear();
m_primaryOffset.x = m_primaryOffset.y = m_primaryOffset.z = 0;
m_secondaryOffset.x = m_secondaryOffset.y = m_secondaryOffset.z = 0;
}
virtual void doFXPos(const Coord3D *primary, const Matrix3D* /*primaryMtx*/, const Real /*primarySpeed*/, const Coord3D * secondary, const Real /*overrideRadius*/ ) const
{
const ThingTemplate* tmpl = TheThingFactory->findTemplate(m_templateName);
DEBUG_ASSERTCRASH(tmpl, ("RayEffect %s not found\n",m_templateName.str()));
if (primary && secondary && tmpl)
{
Coord3D sourcePos = *primary;
sourcePos.x += m_primaryOffset.x;
sourcePos.y += m_primaryOffset.y;
sourcePos.z += m_primaryOffset.z;
Coord3D targetPos = *secondary;
targetPos.x += m_secondaryOffset.x;
targetPos.y += m_secondaryOffset.y;
targetPos.z += m_secondaryOffset.z;
TheGameClient->createRayEffectByTemplate(&sourcePos, &targetPos, tmpl);
}
else
{
DEBUG_CRASH(("You must have a primary AND secondary source for this effect"));
}
}
static void parse(INI *ini, void *instance, void* /*store*/, const void* /*userData*/)
{
static const FieldParse myFieldParse[] =
{
{ "Name", INI::parseAsciiString, NULL, offsetof( RayEffectFXNugget, m_templateName ) },
{ "PrimaryOffset", INI::parseCoord3D, NULL, offsetof( RayEffectFXNugget, m_primaryOffset ) },
{ "SecondaryOffset", INI::parseCoord3D, NULL, offsetof( RayEffectFXNugget, m_secondaryOffset ) },
{ 0, 0, 0, 0 }
};
RayEffectFXNugget* nugget = newInstance( RayEffectFXNugget );
ini->initFromINI(nugget, myFieldParse);
((FXList*)instance)->addFXNugget(nugget);
}
private:
AsciiString m_templateName;
Coord3D m_primaryOffset;
Coord3D m_secondaryOffset;
};
EMPTY_DTOR(RayEffectFXNugget)
//-------------------------------------------------------------------------------------------------
class LightPulseFXNugget : public FXNugget
{
MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(LightPulseFXNugget, "LightPulseFXNugget")
public:
LightPulseFXNugget() : m_radius(0), m_increaseFrames(0), m_decreaseFrames(0), m_boundingCirclePct(0)
{
m_color.red = m_color.green = m_color.blue = 0;
}
virtual void doFXObj(const Object* primary, const Object* /*secondary*/) const
{
if (primary)
{
Real radius = m_radius;
if (m_boundingCirclePct > 0)
radius = (primary->getGeometryInfo().getBoundingCircleRadius() * m_boundingCirclePct);
TheDisplay->createLightPulse(primary->getPosition(), &m_color, 1, radius, m_increaseFrames, m_decreaseFrames);
}
else
{
DEBUG_CRASH(("You must have a primary source for this effect"));
}
}
virtual void doFXPos(const Coord3D *primary, const Matrix3D* /*primaryMtx*/, const Real /*primarySpeed*/, const Coord3D * /*secondary*/, const Real /*overrideRadius*/ ) const
{
if (primary)
{
TheDisplay->createLightPulse(primary, &m_color, 1, m_radius, m_increaseFrames, m_decreaseFrames);
}
else
{
DEBUG_CRASH(("You must have a primary source for this effect"));
}
}
static void parse(INI *ini, void *instance, void* /*store*/, const void* /*userData*/)
{
static const FieldParse myFieldParse[] =
{
{ "Color", INI::parseRGBColor, NULL, offsetof( LightPulseFXNugget, m_color ) },
{ "Radius", INI::parseReal, NULL, offsetof( LightPulseFXNugget, m_radius ) },
{ "RadiusAsPercentOfObjectSize", INI::parsePercentToReal, NULL, offsetof( LightPulseFXNugget, m_boundingCirclePct ) },
{ "IncreaseTime", INI::parseDurationUnsignedInt, NULL, offsetof( LightPulseFXNugget, m_increaseFrames ) },
{ "DecreaseTime", INI::parseDurationUnsignedInt, NULL, offsetof( LightPulseFXNugget, m_decreaseFrames ) },
{ 0, 0, 0, 0 }
};
LightPulseFXNugget* nugget = newInstance( LightPulseFXNugget );
ini->initFromINI(nugget, myFieldParse);
((FXList*)instance)->addFXNugget(nugget);
}
private:
RGBColor m_color;
Real m_radius;
Real m_boundingCirclePct;
UnsignedInt m_increaseFrames;
UnsignedInt m_decreaseFrames;
};
EMPTY_DTOR(LightPulseFXNugget)
//-------------------------------------------------------------------------------------------------
class ViewShakeFXNugget : public FXNugget
{
MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(ViewShakeFXNugget, "ViewShakeFXNugget")
public:
ViewShakeFXNugget() : m_shake(View::SHAKE_NORMAL)
{
}
virtual void doFXPos(const Coord3D *primary, const Matrix3D* /*primaryMtx*/, const Real /*primarySpeed*/, const Coord3D * /*secondary*/, const Real /*overrideRadius*/ ) const
{
if (primary)
{
if (TheTacticalView)
TheTacticalView->shake(primary, m_shake);
}
else
{
DEBUG_CRASH(("You must have a primary source for this effect"));
}
}
static void parse(INI *ini, void *instance, void* /*store*/, const void* /*userData*/)
{
static const FieldParse myFieldParse[] =
{
{ "Type", parseShakeType, NULL, offsetof( ViewShakeFXNugget, m_shake ) },
{ 0, 0, 0, 0 }
};
ViewShakeFXNugget* nugget = newInstance( ViewShakeFXNugget );
ini->initFromINI(nugget, myFieldParse);
((FXList*)instance)->addFXNugget(nugget);
}
protected:
static void parseShakeType( INI* ini, void *instance, void *store, const void* /*userData*/ )
{
static const LookupListRec shakeTypeNames[] =
{
{ "SUBTLE", View::SHAKE_SUBTLE },
{ "NORMAL", View::SHAKE_NORMAL },
{ "STRONG", View::SHAKE_STRONG },
{ "SEVERE", View::SHAKE_SEVERE },
{ "CINE_EXTREME", View::SHAKE_CINE_EXTREME },
{ "CINE_INSANE", View::SHAKE_CINE_INSANE },
{ 0, 0 }
};
*(Int *)store = INI::scanLookupList(ini->getNextToken(), shakeTypeNames);
}
private:
View::CameraShakeType m_shake;
};
EMPTY_DTOR(ViewShakeFXNugget)
//-------------------------------------------------------------------------------------------------
class TerrainScorchFXNugget : public FXNugget
{
MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(TerrainScorchFXNugget, "TerrainScorchFXNugget")
public:
TerrainScorchFXNugget() : m_scorch(-1), m_radius(0)
{
}
virtual void doFXPos(const Coord3D *primary, const Matrix3D* /*primaryMtx*/, const Real /*primarySpeed*/, const Coord3D * /*secondary*/, const Real /*overrideRadius*/ ) const
{
if (primary)
{
Int scorch = m_scorch;
if (scorch < 0)
{
scorch = GameClientRandomValue( SCORCH_1, SCORCH_4 );
}
TheGameClient->addScorch(primary, m_radius, (Scorches)scorch);
}
else
{
DEBUG_CRASH(("You must have a primary source for this effect"));
}
}
static void parse(INI *ini, void *instance, void* /*store*/, const void* /*userData*/)
{
static const FieldParse myFieldParse[] =
{
{ "Type", parseScorchType, NULL, offsetof( TerrainScorchFXNugget, m_scorch ) },
{ "Radius", INI::parseReal, NULL, offsetof( TerrainScorchFXNugget, m_radius ) },
{ 0, 0, 0, 0 }
};
TerrainScorchFXNugget* nugget = newInstance( TerrainScorchFXNugget );
ini->initFromINI(nugget, myFieldParse);
((FXList*)instance)->addFXNugget(nugget);
}
protected:
static void parseScorchType( INI* ini, void *instance, void *store, const void* /*userData*/ )
{
static const LookupListRec scorchTypeNames[] =
{
{ "SCORCH_1", SCORCH_1 },
{ "SCORCH_2", SCORCH_2 },
{ "SCORCH_3", SCORCH_3 },
{ "SCORCH_4", SCORCH_4 },
{ "SHADOW_SCORCH", SHADOW_SCORCH },
{ "RANDOM", -1 },
{ 0, 0 }
};
*(Int *)store = INI::scanLookupList(ini->getNextToken(), scorchTypeNames);
}
private:
Int m_scorch;
Real m_radius;
};
EMPTY_DTOR(TerrainScorchFXNugget)
//-------------------------------------------------------------------------------------------------
class ParticleSystemFXNugget : public FXNugget
{
MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(ParticleSystemFXNugget, "ParticleSystemFXNugget")
public:
ParticleSystemFXNugget()
{
m_name.clear();
m_count = 1;
m_radius.setRange(0, 0, GameClientRandomVariable::CONSTANT);
m_height.setRange(0, 0, GameClientRandomVariable::CONSTANT);
// -1 means "don't mess with it, just accept the particle-system's defaults"
m_delay.setRange(-1, -1, GameClientRandomVariable::CONSTANT);
m_offset.x = m_offset.y = m_offset.z = 0;
m_orientToObject = false;
m_attachToObject = false;
m_createAtGroundHeight = FALSE;
m_useCallersRadius = FALSE;
m_rotateX = m_rotateY = m_rotateZ = 0;
}
virtual void doFXPos(const Coord3D *primary, const Matrix3D* primaryMtx, const Real /*primarySpeed*/, const Coord3D * /*secondary*/, const Real overrideRadius ) const
{
if (primary)
{
reallyDoFX(primary, primaryMtx, NULL, overrideRadius);
}
else
{
DEBUG_CRASH(("You must have a primary source for this effect"));
}
}
virtual void doFXObj(const Object* primary, const Object* secondary) const
{
if (primary)
{
if (m_ricochet && secondary)
{
// HERE WE MUST BUILD A MATRIX WHICH WILL ORIENT THE NEW PARTICLE SYSTEM TO FACE AWAY FROM THE SECONDARY OBJECT
// THE RESULT SHOULD LOOK LIKE THE DIRECTION OF THE "ATTACK" IS CARRIED THROUGH LIKE A RICOCHET
Real deltaX = primary->getPosition()->x - secondary->getPosition()->x;
Real deltaY = primary->getPosition()->y - secondary->getPosition()->y;
Real aimingAngle = atan2(deltaY, deltaX);
Matrix3D aimingMatrix(1);
aimingMatrix.Rotate_Z( aimingAngle );
reallyDoFX(primary->getPosition(), &aimingMatrix, primary, 0.0f);
}
else
// if we have an object, then adjust the offset and direction by the object's transformation
// matrix, so that (say) an offset of +10 in the z axis "follows" the orientation of the object.
reallyDoFX(primary->getPosition(), primary->getTransformMatrix(), primary, 0.0f);
}
else
{
DEBUG_CRASH(("You must have a primary source for this effect"));
}
}
static void parse(INI *ini, void *instance, void* /*store*/, const void* /*userData*/)
{
static const FieldParse myFieldParse[] =
{
{ "Name", INI::parseAsciiString, NULL, offsetof( ParticleSystemFXNugget, m_name ) },
{ "Count", INI::parseInt, NULL, offsetof( ParticleSystemFXNugget, m_count ) },
{ "Offset", INI::parseCoord3D, NULL, offsetof( ParticleSystemFXNugget, m_offset ) },
{ "Radius", INI::parseGameClientRandomVariable, NULL, offsetof( ParticleSystemFXNugget, m_radius ) },
{ "Height", INI::parseGameClientRandomVariable, NULL, offsetof( ParticleSystemFXNugget, m_height ) },
{ "InitialDelay", INI::parseGameClientRandomVariable, NULL, offsetof( ParticleSystemFXNugget, m_delay ) },
{ "RotateX", INI::parseAngleReal, NULL, offsetof( ParticleSystemFXNugget, m_rotateX ) },
{ "RotateY", INI::parseAngleReal, NULL, offsetof( ParticleSystemFXNugget, m_rotateY ) },
{ "RotateZ", INI::parseAngleReal, NULL, offsetof( ParticleSystemFXNugget, m_rotateZ ) },
{ "OrientToObject", INI::parseBool, NULL, offsetof( ParticleSystemFXNugget, m_orientToObject ) },
{ "Ricochet", INI::parseBool, NULL, offsetof( ParticleSystemFXNugget, m_ricochet ) },
{ "AttachToObject", INI::parseBool, NULL, offsetof( ParticleSystemFXNugget, m_attachToObject ) },
{ "CreateAtGroundHeight", INI::parseBool, NULL, offsetof( ParticleSystemFXNugget, m_createAtGroundHeight ) },
{ "UseCallersRadius", INI::parseBool, NULL, offsetof( ParticleSystemFXNugget, m_useCallersRadius ) },
{ 0, 0, 0, 0 }
};
ParticleSystemFXNugget* nugget = newInstance( ParticleSystemFXNugget );
ini->initFromINI(nugget, myFieldParse);
((FXList*)instance)->addFXNugget(nugget);
}
protected:
void reallyDoFX(const Coord3D *primary, const Matrix3D* mtx, const Object* thingToAttachTo, Real overrideRadius ) const
{
Coord3D offset = m_offset;
if (mtx)
{
adjustVector(&offset, mtx);
}
const ParticleSystemTemplate *tmp = TheParticleSystemManager->findTemplate(m_name);
DEBUG_ASSERTCRASH(tmp, ("ParticleSystem %s not found\n",m_name.str()));
if (tmp)
{
for (Int i = 0; i < m_count; i++ )
{
ParticleSystem *sys = TheParticleSystemManager->createParticleSystem(tmp);
if (sys)
{
Coord3D newPos;
Real radius = m_radius.getValue();
Real angle = GameClientRandomValueReal( 0.0f, 2.0f * PI );
newPos.x = primary->x + offset.x + radius * cos(angle);
newPos.y = primary->y + offset.y + radius * sin(angle);
if( m_createAtGroundHeight && TheTerrainLogic )
{
//old way:
//newPos.z = TheTerrainLogic->getGrsoundHeight( newPos.x, newPos.y ) + 1;// The plus one prevents scissoring with terrain
//new way: now we allow bridges in the GroundHeight.
PathfindLayerEnum layer = TheTerrainLogic->getLayerForDestination(&newPos);
newPos.z = TheTerrainLogic->getLayerHeight( newPos.x, newPos.y, layer );
}
else
newPos.z = primary->z + offset.z + m_height.getValue();
if (m_orientToObject && mtx)
{
sys->setLocalTransform(mtx);
}
if (m_rotateX != 0.0f)
sys->rotateLocalTransformX(m_rotateX);
if (m_rotateY != 0.0f)
sys->rotateLocalTransformY(m_rotateY);
if (m_rotateZ != 0.0f)
sys->rotateLocalTransformZ(m_rotateZ);
if (m_attachToObject && thingToAttachTo)
sys->attachToObject(thingToAttachTo);
else
sys->setPosition( &newPos );
Real delayInMsec = m_delay.getValue();
if (delayInMsec >= 0.0f)
{
UnsignedInt delayInFrames = REAL_TO_INT_CEIL(ConvertDurationFromMsecsToFrames(delayInMsec));
sys->setInitialDelay(delayInFrames);
}
if( m_useCallersRadius && overrideRadius )
{
ParticleSystemInfo::EmissionVolumeType type = sys->getEmisionVolumeType();
if( type == ParticleSystemInfo::EmissionVolumeType::SPHERE )
sys->setEmissionVolumeSphereRadius( overrideRadius );
else if( type == ParticleSystemInfo::EmissionVolumeType::CYLINDER )
sys->setEmissionVolumeCylinderRadius( overrideRadius );
}
}
}
}
}
private:
AsciiString m_name;
Int m_count;
Coord3D m_offset;
GameClientRandomVariable m_radius;
GameClientRandomVariable m_height;
GameClientRandomVariable m_delay;
Real m_rotateX, m_rotateY, m_rotateZ;
Bool m_orientToObject;
Bool m_attachToObject;
Bool m_createAtGroundHeight;
Bool m_useCallersRadius;
Bool m_ricochet;
};
EMPTY_DTOR(ParticleSystemFXNugget)
//-------------------------------------------------------------------------------------------------
class FXListAtBonePosFXNugget : public FXNugget
{
MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(FXListAtBonePosFXNugget, "FXListAtBonePosFXNugget")
public:
FXListAtBonePosFXNugget()
{
m_fx = NULL;
m_boneName.clear();
m_orientToBone = true;
}
virtual void doFXPos(const Coord3D *primary, const Matrix3D* primaryMtx, const Real /*primarySpeed*/, const Coord3D * /*secondary*/, const Real /*overrideRadius*/ ) const
{
DEBUG_CRASH(("You must use the object form for this effect"));
}
virtual void doFXObj(const Object* primary, const Object* /*secondary*/) const
{
if (primary)
{
// first, try the unadorned name.
doFxAtBones(primary, 0);
// then, try the 01,02,03...etc names.
doFxAtBones(primary, 1);
}
else
{
DEBUG_CRASH(("You must have a primary source for this effect"));
}
}
static void parse(INI *ini, void *instance, void* /*store*/, const void* /*userData*/)
{
static const FieldParse myFieldParse[] =
{
{ "FX", INI::parseFXList, NULL, offsetof( FXListAtBonePosFXNugget, m_fx ) },
{ "BoneName", INI::parseAsciiString, NULL, offsetof( FXListAtBonePosFXNugget, m_boneName ) },
{ "OrientToBone", INI::parseBool, NULL, offsetof( FXListAtBonePosFXNugget, m_orientToBone ) },
{ 0, 0, 0, 0 }
};
FXListAtBonePosFXNugget* nugget = newInstance( FXListAtBonePosFXNugget );
ini->initFromINI(nugget, myFieldParse);
((FXList*)instance)->addFXNugget(nugget);
}
protected:
void doFxAtBones(const Object* obj, Int start) const
{
Coord3D bonePos[MAX_BONE_POINTS];
Matrix3D boneMtx[MAX_BONE_POINTS];
Drawable* draw = obj->getDrawable();
if (draw)
{
// yes, BONEPOS_CURRENT_CLIENT_ONLY -- this is client-only, so should be safe to do.
Int count = draw->getCurrentClientBonePositions(m_boneName.str(), start, bonePos, boneMtx, MAX_BONE_POINTS);
for (Int i = 0; i < count; ++i)
{
Coord3D p;
Matrix3D m;
obj->convertBonePosToWorldPos(&bonePos[i], &boneMtx[i], &p, &m);
FXList::doFXPos(m_fx, &p, &m, 0.0f, NULL, 0.0f);
}
}
}
private:
enum { MAX_BONE_POINTS = 40 };
const FXList* m_fx;
AsciiString m_boneName;
Bool m_orientToBone;
};
EMPTY_DTOR(FXListAtBonePosFXNugget)
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
static const FieldParse TheFXListFieldParse[] =
{
{ "Sound", SoundFXNugget::parse, 0, 0},
{ "RayEffect", RayEffectFXNugget::parse, 0, 0},
{ "Tracer", TracerFXNugget::parse, 0, 0},
{ "LightPulse", LightPulseFXNugget::parse, 0, 0},
{ "ViewShake", ViewShakeFXNugget::parse, 0, 0},
{ "TerrainScorch", TerrainScorchFXNugget::parse, 0, 0},
{ "ParticleSystem", ParticleSystemFXNugget::parse, 0, 0},
{ "FXListAtBonePos", FXListAtBonePosFXNugget::parse, 0, 0},
{ NULL, NULL, 0, 0 } // keep this last
};
//-------------------------------------------------------------------------------------------------
FXList::FXList()
{
}
//-------------------------------------------------------------------------------------------------
FXList::~FXList()
{
clear();
}
//-------------------------------------------------------------------------------------------------
void FXList::clear()
{
for (FXNuggetList::iterator it = m_nuggets.begin(); it != m_nuggets.end(); ++it)
{
if (*it)
(*it)->deleteInstance();
}
m_nuggets.clear();
}
//-------------------------------------------------------------------------------------------------
void FXList::doFXPos(const Coord3D *primary, const Matrix3D* primaryMtx, const Real primarySpeed, const Coord3D *secondary, const Real overrideRadius ) const
{
if (ThePartitionManager->getShroudStatusForPlayer(ThePlayerList->getLocalPlayer()->getPlayerIndex(), primary) != CELLSHROUD_CLEAR)
return;
for (FXNuggetList::const_iterator it = m_nuggets.begin(); it != m_nuggets.end(); ++it)
{
(*it)->doFXPos(primary, primaryMtx, primarySpeed, secondary, overrideRadius);
}
}
//-------------------------------------------------------------------------------------------------
void FXList::doFXObj(const Object* primary, const Object* secondary) const
{
if (primary && primary->getShroudedStatus(ThePlayerList->getLocalPlayer()->getPlayerIndex()) > OBJECTSHROUD_PARTIAL_CLEAR)
return; //the primary object is fogged or shrouded so don't bother with the effect.
for (FXNuggetList::const_iterator it = m_nuggets.begin(); it != m_nuggets.end(); ++it)
{
// HERE THE PRIMARY IS THE GUY RECEIVING THE FX, AND SECONDARY MIGHT BE THE GUY DEALING IT
(*it)->doFXObj(primary, secondary);
}
}
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
FXListStore::FXListStore()
{
}
//-------------------------------------------------------------------------------------------------
FXListStore::~FXListStore()
{
m_fxmap.clear();
}
//-------------------------------------------------------------------------------------------------
const FXList *FXListStore::findFXList(const char* name) const
{
if (stricmp(name, "None") == 0)
return NULL;
FXListMap::const_iterator it = m_fxmap.find(NAMEKEY(name));
if (it != m_fxmap.end())
{
return &(*it).second;
}
return NULL;
}
//-------------------------------------------------------------------------------------------------
/*static */ void FXListStore::parseFXListDefinition(INI *ini)
{
// read the FXList name
const char *c = ini->getNextToken();
NameKeyType key = TheNameKeyGenerator->nameToKey(c);
FXList& fxl = TheFXListStore->m_fxmap[key];
fxl.clear();
ini->initFromINI(&fxl, TheFXListFieldParse);
}
//-------------------------------------------------------------------------------------------------
/*static*/ void INI::parseFXListDefinition(INI *ini)
{
FXListStore::parseFXListDefinition(ini);
}

View File

@@ -0,0 +1,429 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: AnimateWindowManager.cpp /////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Electronic Arts Pacific.
//
// Confidential Information
// Copyright (C) 2002 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// created: Mar 2002
//
// Filename: AnimateWindowManager.cpp
//
// author: Chris Huybregts
//
// purpose: This will contain the logic behind the different animations that
// can happen to a window.
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// USER INCLUDES //////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "GameClient/AnimateWindowManager.h"
#include "GameClient/GameWindow.h"
#include "GameClient/Display.h"
#include "GameClient/ProcessAnimateWindow.h"
//-----------------------------------------------------------------------------
// DEFINES ////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// AnimateWindow PUBLIC FUNCTIONS /////////////////////////////////////////////
//-----------------------------------------------------------------------------
AnimateWindow::AnimateWindow( void )
{
m_delay = 0;
m_startPos.x = m_startPos.y = 0;
m_endPos.x = m_endPos.y = 0;
m_curPos.x = m_curPos.y = 0;
m_win = NULL;
m_animType = WIN_ANIMATION_NONE;
m_restPos.x = m_restPos.y = 0;
m_vel.x = m_vel.y = 0.0f;
m_needsToFinish = FALSE;
m_isFinished = FALSE;
m_endTime = 0;
m_startTime = 0;
}
AnimateWindow::~AnimateWindow( void )
{
m_win = NULL;
}
void AnimateWindow::setAnimData( ICoord2D startPos, ICoord2D endPos,
ICoord2D curPos, ICoord2D restPos,
Coord2D vel, UnsignedInt startTime,
UnsignedInt endTime )
{
m_startPos = startPos;
m_endPos = endPos;
m_curPos = curPos;
m_restPos = restPos;
m_vel = vel;
m_startTime = startTime;
m_endTime = endTime;
}
//-----------------------------------------------------------------------------
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
static void clearWinList(AnimateWindowList &winList)
{
AnimateWindow *win = NULL;
while (!winList.empty())
{
win = *(winList.begin());
winList.pop_front();
if (win)
win->deleteInstance();
win = NULL;
}
}
AnimateWindowManager::AnimateWindowManager( void )
{
// we don't allocate many of these, so no MemoryPools used
m_slideFromRight = NEW ProcessAnimateWindowSlideFromRight;
m_slideFromRightFast = NEW ProcessAnimateWindowSlideFromRightFast;
m_slideFromLeft = NEW ProcessAnimateWindowSlideFromLeft;
m_slideFromTop = NEW ProcessAnimateWindowSlideFromTop;
m_slideFromTopFast = NEW ProcessAnimateWindowSlideFromTopFast;
m_slideFromBottom = NEW ProcessAnimateWindowSlideFromBottom;
m_spiral = NEW ProcessAnimateWindowSpiral;
m_slideFromBottomTimed = NEW ProcessAnimateWindowSlideFromBottomTimed;
m_winList.clear();
m_needsUpdate = FALSE;
m_reverse = FALSE;
m_winMustFinishList.clear();
}
AnimateWindowManager::~AnimateWindowManager( void )
{
if(m_slideFromRight)
delete m_slideFromRight;
if(m_slideFromRightFast)
delete m_slideFromRightFast;
if(m_slideFromLeft)
delete m_slideFromLeft;
if(m_slideFromTop)
delete m_slideFromTop;
if(m_slideFromTopFast)
delete m_slideFromTopFast;
if(m_slideFromBottom)
delete m_slideFromBottom;
if(m_spiral)
delete m_spiral;
if (m_slideFromBottomTimed)
delete m_slideFromBottomTimed;
m_slideFromRight = NULL;
resetToRestPosition( );
clearWinList(m_winList);
clearWinList(m_winMustFinishList);
}
void AnimateWindowManager::init( void )
{
clearWinList(m_winList);
clearWinList(m_winMustFinishList);
m_needsUpdate = FALSE;
m_reverse = FALSE;
}
void AnimateWindowManager::reset( void )
{
resetToRestPosition();
clearWinList(m_winList);
clearWinList(m_winMustFinishList);
m_needsUpdate = FALSE;
m_reverse = FALSE;
}
void AnimateWindowManager::update( void )
{
ProcessAnimateWindow *processAnim = NULL;
// if we need to update the windows that need to finish, update that list
if(m_needsUpdate)
{
AnimateWindowList::iterator it = m_winMustFinishList.begin();
m_needsUpdate = FALSE;
while (it != m_winMustFinishList.end())
{
AnimateWindow *animWin = *it;
if (!animWin)
{
DEBUG_CRASH(("There's No AnimateWindow in the AnimateWindow List"));
return;
}
processAnim = getProcessAnimate( animWin->getAnimType() );
if(processAnim)
{
if(m_reverse)
{
if(!processAnim->reverseAnimateWindow(animWin))
m_needsUpdate = TRUE;
}
else
{
if(!processAnim->updateAnimateWindow(animWin))
m_needsUpdate = TRUE;
}
}
it ++;
}
}
AnimateWindowList::iterator it = m_winList.begin();
while (it != m_winList.end())
{
AnimateWindow *animWin = *it;
if (!animWin)
{
DEBUG_CRASH(("There's No AnimateWindow in the AnimateWindow List"));
return;
}
processAnim = getProcessAnimate( animWin->getAnimType() );
if(m_reverse)
{
if(processAnim)
processAnim->reverseAnimateWindow(animWin);
}
else
{
if(processAnim)
processAnim->updateAnimateWindow(animWin);
}
it ++;
}
}
void AnimateWindowManager::registerGameWindow(GameWindow *win, AnimTypes animType, Bool needsToFinish, UnsignedInt ms, UnsignedInt delayMs)
{
if(!win)
{
DEBUG_CRASH(("Win was NULL as it was passed into registerGameWindow... not good indeed"));
return;
}
if(animType <= WIN_ANIMATION_NONE || animType >= WIN_ANIMATION_COUNT )
{
DEBUG_CRASH(("an Invalid WIN_ANIMATION type was passed into registerGameWindow... please fix me "));
return;
}
// Create a new AnimateWindow class and fill in it's data.
AnimateWindow *animWin = newInstance(AnimateWindow);
animWin->setGameWindow(win);
animWin->setAnimType(animType);
animWin->setNeedsToFinish(needsToFinish);
animWin->setDelay(delayMs);
// Run the window through the processAnim's init function.
ProcessAnimateWindow *processAnim = getProcessAnimate( animType );
if(processAnim)
{
processAnim->setMaxDuration(ms);
processAnim->initAnimateWindow( animWin );
}
// Add the Window to the proper list
if(needsToFinish)
{
m_winMustFinishList.push_back(animWin);
m_needsUpdate = TRUE;
}
else
m_winList.push_back(animWin);
}
ProcessAnimateWindow *AnimateWindowManager::getProcessAnimate( AnimTypes animType )
{
switch (animType) {
case WIN_ANIMATION_SLIDE_RIGHT:
{
return m_slideFromRight;
}
case WIN_ANIMATION_SLIDE_RIGHT_FAST:
{
return m_slideFromRightFast;
}
case WIN_ANIMATION_SLIDE_LEFT:
{
return m_slideFromLeft;
}
case WIN_ANIMATION_SLIDE_TOP:
{
return m_slideFromTop;
}
case WIN_ANIMATION_SLIDE_BOTTOM:
{
return m_slideFromBottom;
}
case WIN_ANIMATION_SPIRAL:
{
return m_spiral;
}
case WIN_ANIMATION_SLIDE_BOTTOM_TIMED:
{
return m_slideFromBottomTimed;
}
case WIN_ANIMATION_SLIDE_TOP_FAST:
{
return m_slideFromTopFast;
}
default:
return NULL;
}
}
void AnimateWindowManager::reverseAnimateWindow( void )
{
m_reverse = TRUE;
m_needsUpdate = TRUE;
ProcessAnimateWindow *processAnim = NULL;
UnsignedInt maxDelay = 0;
AnimateWindowList::iterator it = m_winMustFinishList.begin();
while (it != m_winMustFinishList.end())
{
AnimateWindow *animWin = *it;
if (!animWin)
{
DEBUG_CRASH(("There's No AnimateWindow in the AnimateWindow List"));
return;
}
if(animWin->getDelay() > maxDelay)
maxDelay = animWin->getDelay();
it ++;
}
it = m_winMustFinishList.begin();
while (it != m_winMustFinishList.end())
{
AnimateWindow *animWin = *it;
if (!animWin)
{
DEBUG_CRASH(("There's No AnimateWindow in the AnimateWindow List"));
return;
}
// Run the window through the processAnim's init function.
processAnim = getProcessAnimate( animWin->getAnimType() );
if(processAnim)
{
processAnim->initReverseAnimateWindow( animWin, maxDelay );
}
animWin->setFinished(FALSE);
it ++;
}
it = m_winList.begin();
while (it != m_winList.end())
{
AnimateWindow *animWin = *it;
if (!animWin)
{
DEBUG_CRASH(("There's No AnimateWindow in the AnimateWindow List"));
return;
}
processAnim = getProcessAnimate( animWin->getAnimType() );
if(processAnim)
processAnim->initReverseAnimateWindow(animWin);
animWin->setFinished(FALSE);
it ++;
}
}
void AnimateWindowManager::resetToRestPosition( void )
{
m_reverse = TRUE;
m_needsUpdate = TRUE;
AnimateWindowList::iterator it = m_winMustFinishList.begin();
while (it != m_winMustFinishList.end())
{
AnimateWindow *animWin = *it;
if (!animWin)
{
DEBUG_CRASH(("There's No AnimateWindow in the AnimateWindow List"));
return;
}
ICoord2D restPos = animWin->getRestPos();
GameWindow *win = animWin->getGameWindow();
if(win)
win->winSetPosition(restPos.x, restPos.y);
it ++;
}
it = m_winList.begin();
while (it != m_winList.end())
{
AnimateWindow *animWin = *it;
if (!animWin)
{
DEBUG_CRASH(("There's No AnimateWindow in the AnimateWindow List"));
return;
}
ICoord2D restPos = animWin->getRestPos();
GameWindow *win = animWin->getGameWindow();
if(win)
win->winSetPosition(restPos.x, restPos.y);
it ++;
}
}
//-----------------------------------------------------------------------------
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,106 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: ControlBarBeacon.cpp /////////////////////////////////////////////////////////////////////
// Author: Colin Day, March 2002
// Desc: Methods specific to the control bar beacon display
///////////////////////////////////////////////////////////////////////////////////////////////////
// USER INCLUDES //////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/NameKeyGenerator.h"
#include "Common/ThingTemplate.h"
#include "GameClient/ControlBar.h"
#include "GameClient/Drawable.h"
#include "GameClient/GameWindow.h"
#include "GameClient/GadgetTextEntry.h"
#include "GameClient/InGameUI.h"
#include "GameLogic/Object.h"
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
void ControlBar::populateBeacon( Object *beacon )
{
// set the portrait for the thing being constructed
setPortraitByObject( beacon );
static NameKeyType textID = NAMEKEY("ControlBar.wnd:EditBeaconText");
static NameKeyType staticTextID = NAMEKEY("ControlBar.wnd:StaticTextBeaconLabel");
static NameKeyType clearButtonID = NAMEKEY("ControlBar.wnd:ButtonClearBeaconText");
GameWindow *textEntryWin = TheWindowManager->winGetWindowFromId(NULL, textID);
GameWindow *staticTextWin = TheWindowManager->winGetWindowFromId(NULL, staticTextID);
GameWindow *buttonWin = TheWindowManager->winGetWindowFromId(NULL, clearButtonID);
if (beacon->isLocallyControlled())
{
if (textEntryWin)
{
textEntryWin->winHide(FALSE);
GadgetTextEntrySetText( textEntryWin, beacon->getDrawable()->getCaptionText() );
TheWindowManager->winSetFocus( textEntryWin );
}
if (staticTextWin)
staticTextWin->winHide(FALSE);
if (buttonWin)
buttonWin->winHide(FALSE);
}
else
{
if (textEntryWin)
textEntryWin->winHide(TRUE);
if (staticTextWin)
staticTextWin->winHide(TRUE);
if (buttonWin)
buttonWin->winHide(TRUE);
}
} // end populateBeacon
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
void ControlBar::updateContextBeacon( void )
{
} // end updateContextBeacon
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType BeaconWindowInput( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
if (msg == GWM_CHAR && mData1 == KEY_ESC)
{
TheInGameUI->deselectAllDrawables(TRUE); // there should only be one beacon and nothing else selected
return MSG_HANDLED;
}
return MSG_IGNORED;
} // end InGameChatInput

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,733 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: ControlBarCommandProcessing.cpp //////////////////////////////////////////////////////////
// Author: Colin Day, March 2002
// Desc: This file contain just the method responsible for processing the actual command
// clicks from the window controls in the UI
///////////////////////////////////////////////////////////////////////////////////////////////////
// USER INCLUDES //////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/BuildAssistant.h"
#include "Common/Money.h"
#include "Common/Player.h"
#include "Common/PlayerList.h"
#include "Common/Science.h"
#include "Common/SpecialPower.h"
#include "Common/ThingTemplate.h"
#include "Common/Upgrade.h"
#include "Common/PlayerTemplate.h"
#include "GameClient/CommandXlat.h"
#include "GameClient/ControlBar.h"
#include "GameClient/Drawable.h"
#include "GameClient/Eva.h"
#include "GameClient/GameClient.h"
#include "GameClient/GadgetPushButton.h"
#include "GameClient/GameWindow.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/InGameUI.h"
#include "GameClient/AnimateWindowManager.h"
#include "GameLogic/GameLogic.h"
#include "GameLogic/Object.h"
#include "GameLogic/Module/ProductionUpdate.h"
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
//-------------------------------------------------------------------------------------------------
/** Process a button transition message from the window system that should be for one of
* our GUI commands */
//-------------------------------------------------------------------------------------------------
CBCommandStatus ControlBar::processCommandTransitionUI( GameWindow *control, GadgetGameMessage gadgetMessage )
{
// sanity, we won't process messages if we have no source object
if( m_currContext != CB_CONTEXT_MULTI_SELECT &&
(m_currentSelectedDrawable == NULL ||
m_currentSelectedDrawable->getObject() == NULL) )
{
if( m_currContext != CB_CONTEXT_NONE &&
m_currContext != CB_CONTEXT_OBSERVER_INFO &&
m_currContext != CB_CONTEXT_OBSERVER_LIST)
switchToContext( CB_CONTEXT_NONE, NULL );
return CBC_COMMAND_NOT_USED;
} // end if
return CBC_COMMAND_USED;
}
//-------------------------------------------------------------------------------------------------
/** Process a button selected message from the window system that should be for one of
* our GUI commands */
//-------------------------------------------------------------------------------------------------
CBCommandStatus ControlBar::processCommandUI( GameWindow *control,
GadgetGameMessage gadgetMessage )
{
// get the command pointer from the control user data we put in the button
const CommandButton *commandButton = (const CommandButton *)GadgetButtonGetData(control);
// sanity, we won't process messages if we have no source object,
// unless we're CB_CONTEXT_PURCHASE_SCIENCE or GUI_COMMAND_SPECIAL_POWER_FROM_COMMAND_CENTER
if( m_currContext != CB_CONTEXT_MULTI_SELECT &&
commandButton->getCommandType() != GUI_COMMAND_PURCHASE_SCIENCE &&
commandButton->getCommandType() != GUI_COMMAND_SPECIAL_POWER_FROM_COMMAND_CENTER &&
(m_currentSelectedDrawable == NULL ||
m_currentSelectedDrawable->getObject() == NULL) )
{
if( m_currContext != CB_CONTEXT_NONE )
switchToContext( CB_CONTEXT_NONE, NULL );
return CBC_COMMAND_NOT_USED;
} // end if
// sanity
if( control == NULL )
return CBC_COMMAND_NOT_USED;
// the context sensitive gui only is only made of buttons ... sanity
if( control->winGetInputFunc() != GadgetPushButtonInput )
return CBC_COMMAND_NOT_USED;
if( commandButton == NULL )
return CBC_COMMAND_NOT_USED;
// if the button is flashing, tell it to stop flashing
commandButton->setFlashCount(0);
TheControlBar->setFlash( FALSE );
if( commandButton->getCommandType() != GUI_COMMAND_EXIT_CONTAINER )
{
GadgetButtonSetEnabledImage( control, commandButton->getButtonImage() );
}
//
// get the object that is driving the context sensitive UI if we're not in a multi
// select context
//
Object *obj = NULL;
if( m_currContext != CB_CONTEXT_MULTI_SELECT &&
commandButton->getCommandType() != GUI_COMMAND_PURCHASE_SCIENCE &&
commandButton->getCommandType() != GUI_COMMAND_SPECIAL_POWER_FROM_COMMAND_CENTER)
obj = m_currentSelectedDrawable->getObject();
//@todo Kris -- Special case code so convoy trucks can detonate nuke trucks -- if other things need this,
//rethink it.
if( obj && BitTest( commandButton->getOptions(), SINGLE_USE_COMMAND ) )
{
/** @todo Added obj check because Single Use and Multi Select crash when used together, but with this check
* they just won't work. When the "rethinking" occurs, this can get fixed. Right now it is unused.
* Convoy Truck needs Multi Select so Single Use is turned off, and noone else has it.
*/
//Make sure the command button is marked as used if it's a single use command. That way
//we can never press the button again. This was added specifically for nuke convoy trucks.
//When you click to detonate the nuke, it takes a few seconds to detonate in order to play
//a sound. But we want to disable the button after the first click.
obj->markSingleUseCommandUsed(); //Yeah, an object can only use one single use command...
}
TheInGameUI->placeBuildAvailable( NULL, NULL );
//Play any available unit specific sound for button
Player *player = ThePlayerList->getLocalPlayer();
if( player )
{
AudioEventRTS sound = *commandButton->getUnitSpecificSound();
sound.setPlayerIndex( player->getPlayerIndex() );
TheAudio->addAudioEvent( &sound );
}
if( BitTest( commandButton->getOptions(), COMMAND_OPTION_NEED_TARGET ) )
{
if (commandButton->getOptions() & USES_MINE_CLEARING_WEAPONSET)
{
TheMessageStream->appendMessage( GameMessage::MSG_SET_MINE_CLEARING_DETAIL );
}
//June 06, 2002 -- Major change
//I've added support for specific context sensitive commands which need targets just like
//other options may need. When we need a target, the user must move the cursor to a position
//where he wants the GUI command to take place. Older commands such as napalm strikes or daisy
//cutter drops simply needed the user to click anywhere he desired.
//
//Now, we have new commands that will only work when the user clicks on valid targets to interact
//with. For example, the terrorist can jack a car and convert it into a carbomb, but he has to
//click on a valid car. In this case the doCommandOrHint code will determine if the mode is valid
//or not and the cursor modes will be set appropriately.
TheInGameUI->setGUICommand( commandButton );
}
else switch( commandButton->getCommandType() )
{
//---------------------------------------------------------------------------------------------
case GUI_COMMAND_DOZER_CONSTRUCT:
{
// sanity
if( m_currentSelectedDrawable == NULL )
break;
//Kris: September 27, 2002
//Make sure we have enough CASH to build it WHEN we click the button to build it,
//before actually previewing the purchase, otherwise, cancel altogether.
const ThingTemplate *whatToBuild = commandButton->getThingTemplate();
CanMakeType cmt = TheBuildAssistant->canMakeUnit( obj, whatToBuild );
if (cmt == CANMAKE_NO_MONEY)
{
TheEva->setShouldPlay(EVA_InsufficientFunds);
TheInGameUI->message( "GUI:NotEnoughMoneyToBuild" );
break;
}
else if (cmt == CANMAKE_QUEUE_FULL)
{
TheInGameUI->message( "GUI:ProductionQueueFull" );
break;
}
else if (cmt == CANMAKE_PARKING_PLACES_FULL)
{
TheInGameUI->message( "GUI:ParkingPlacesFull" );
break;
}
else if( cmt == CANMAKE_MAXED_OUT_FOR_PLAYER )
{
TheInGameUI->message( "GUI:UnitMaxedOut" );
break;
}
// tell the UI that we want to build something so we get a building at the cursor
TheInGameUI->placeBuildAvailable( commandButton->getThingTemplate(), m_currentSelectedDrawable );
break;
} // end dozer construct
//---------------------------------------------------------------------------------------------
case GUI_COMMAND_DOZER_CONSTRUCT_CANCEL:
{
// get the object we have selected
Object *building = obj;
if( building == NULL )
break;
// sanity check, the building must be under our control to cancel construction
if( building->getControllingPlayer() != ThePlayerList->getLocalPlayer() )
break;
// do the message
TheMessageStream->appendMessage( GameMessage::MSG_DOZER_CANCEL_CONSTRUCT );
break;
} // end cancel dozer construction
//---------------------------------------------------------------------------------------------
case GUI_COMMAND_UNIT_BUILD:
{
const ThingTemplate *whatToBuild = commandButton->getThingTemplate();
// get the "factory" object that is going to make the thing
Object *factory = obj;
if( factory == NULL )
break;
// sanity, we must have something to build
DEBUG_ASSERTCRASH( whatToBuild, ("Undefined BUILD command for object '%s'\n",
commandButton->getThingTemplate()->getName().str()) );
CanMakeType cmt = TheBuildAssistant->canMakeUnit(factory, whatToBuild);
if (cmt == CANMAKE_NO_MONEY)
{
TheEva->setShouldPlay(EVA_InsufficientFunds);
TheInGameUI->message( "GUI:NotEnoughMoneyToBuild" );
break;
}
else if (cmt == CANMAKE_QUEUE_FULL)
{
TheInGameUI->message( "GUI:ProductionQueueFull" );
break;
}
else if (cmt == CANMAKE_PARKING_PLACES_FULL)
{
TheInGameUI->message( "GUI:ParkingPlacesFull" );
break;
}
else if( cmt == CANMAKE_MAXED_OUT_FOR_PLAYER )
{
TheInGameUI->message( "GUI:UnitMaxedOut" );
break;
}
else if (cmt != CANMAKE_OK)
{
DEBUG_ASSERTCRASH( 0, ("Cannot create '%s' because the factory object '%s' returns false for canMakeUnit\n",
whatToBuild->getName().str(),
factory->getTemplate()->getName().str()) );
break;
}
// get the production interface from the factory object
ProductionUpdateInterface *pu = factory->getProductionUpdateInterface();
// sanity, we can't build things if we can't produce units
if( pu == NULL )
{
DEBUG_ASSERTCRASH( 0, ("Cannot create '%s' because the factory object '%s' is not capable of producting units\n",
whatToBuild->getName().str(),
factory->getTemplate()->getName().str()) );
break;
} // end if
// get a new production id to assign to this
ProductionID productionID = pu->requestUniqueUnitID();
// create a message to build this thing
GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_QUEUE_UNIT_CREATE );
msg->appendIntegerArgument( whatToBuild->getTemplateID() );
msg->appendIntegerArgument( productionID );
break;
} // end build unit
//---------------------------------------------------------------------------------------------
case GUI_COMMAND_CANCEL_UNIT_BUILD:
{
Int i;
// find out which index (i) in the queue represents the button clicked
for( i = 0; i < MAX_BUILD_QUEUE_BUTTONS; i++ )
if( m_queueData[ i ].control == control )
break;
// sanity, control not found
if( i == MAX_BUILD_QUEUE_BUTTONS )
{
DEBUG_ASSERTCRASH( 0, ("Control not found in build queue data\n") );
break;
} // end if
// sanity
if( m_queueData[ i ].type != PRODUCTION_UNIT )
break;
// the the production ID to cancel
ProductionID productionIDToCancel = m_queueData[ i ].productionID;
// get the object that is the producer
Object *producer = obj;
if( producer == NULL )
break;
// sanity, we must control the producer ... if this isn't true they might be hacking the game
if( producer->getControllingPlayer() != ThePlayerList->getLocalPlayer() )
break;
// send a message to cancel that particular production entry
GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_CANCEL_UNIT_CREATE );
msg->appendIntegerArgument( productionIDToCancel );
break;
} // end cancel unit build
//---------------------------------------------------------------------------------------------
case GUI_COMMAND_PLAYER_UPGRADE:
{
const UpgradeTemplate *upgradeT = commandButton->getUpgradeTemplate();
DEBUG_ASSERTCRASH( upgradeT, ("Undefined upgrade '%s' in player upgrade command\n", "UNKNOWN") );
// sanity
if( obj == NULL || upgradeT == NULL )
break;
// make sure the player can really make this
if( TheUpgradeCenter->canAffordUpgrade( ThePlayerList->getLocalPlayer(), upgradeT, TRUE ) == FALSE )
{
break;
}
ProductionUpdateInterface* pu = obj ? obj->getProductionUpdateInterface() : NULL;
if (pu != NULL)
{
CanMakeType cmt = pu->canQueueUpgrade(upgradeT);
if (cmt == CANMAKE_QUEUE_FULL)
{
TheInGameUI->message( "GUI:ProductionQueueFull" );
break;
}
}
// send the message
GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_QUEUE_UPGRADE );
msg->appendObjectIDArgument( obj->getID() );
msg->appendIntegerArgument( upgradeT->getUpgradeNameKey() );
break;
} // command player upgrade
//---------------------------------------------------------------------------------------------
case GUI_COMMAND_OBJECT_UPGRADE:
{
const UpgradeTemplate *upgradeT = commandButton->getUpgradeTemplate();
DEBUG_ASSERTCRASH( upgradeT, ("Undefined upgrade '%s' in object upgrade command\n", "UNKNOWN") );
// sanity
if( upgradeT == NULL )
break;
//Make sure the player can really make this
if( TheUpgradeCenter->canAffordUpgrade( ThePlayerList->getLocalPlayer(), upgradeT, TRUE ) == FALSE )
{
//Kris: Disabled because we can get a valid reason for not being able to afford the upgrade!
//TheInGameUI->message( "upgrade unsupported in commandprocessing." );
break;
}
ProductionUpdateInterface* pu = obj ? obj->getProductionUpdateInterface() : NULL;
if (pu != NULL)
{
CanMakeType cmt = pu->canQueueUpgrade(upgradeT);
if (cmt == CANMAKE_QUEUE_FULL)
{
TheInGameUI->message( "GUI:ProductionQueueFull" );
break;
}
}
ObjectID objID = INVALID_ID;
if (obj)
objID = obj->getID();
// make sure that the this object can actually build the upgrade
if( obj && (obj->hasUpgrade( upgradeT ) == TRUE || obj->affectedByUpgrade( upgradeT ) == FALSE) )
break;
// send the message
GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_QUEUE_UPGRADE );
msg->appendObjectIDArgument( objID );
msg->appendIntegerArgument( upgradeT->getUpgradeNameKey() );
break;
} // end object upgrade
//---------------------------------------------------------------------------------------------
case GUI_COMMAND_CANCEL_UPGRADE:
{
Int i;
// find out which index (i) in the queue represents the button clicked
for( i = 0; i < MAX_BUILD_QUEUE_BUTTONS; i++ )
if( m_queueData[ i ].control == control )
break;
// sanity, control not found
if( i == MAX_BUILD_QUEUE_BUTTONS )
{
DEBUG_ASSERTCRASH( 0, ("Control not found in build queue data\n") );
break;
} // end if
// sanity
if( m_queueData[ i ].type != PRODUCTION_UPGRADE )
break;
// get the upgrade to cancel
const UpgradeTemplate *upgradeT = m_queueData[ i ].upgradeToResearch;
// get producer object (the thing driving our UI)
Object *producer = obj;
// sanity
if( upgradeT == NULL || producer == NULL )
break;
// send the message
GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_CANCEL_UPGRADE );
msg->appendIntegerArgument( upgradeT->getUpgradeNameKey() );
break;
} // end cancel upgrade
//---------------------------------------------------------------------------------------------
case GUI_COMMAND_ATTACK_MOVE:
TheMessageStream->appendMessage(GameMessage::MSG_META_TOGGLE_ATTACKMOVE);
break;
//---------------------------------------------------------------------------------------------
case GUI_COMMAND_STOP:
{
// This message always works on the currently selected team
TheMessageStream->appendMessage(GameMessage::MSG_DO_STOP);
break;
}
//---------------------------------------------------------------------------------------------
case GUI_COMMAND_WAYPOINTS:
break;
//-------------------------------------------------------------------------------------------------
case GUI_COMMAND_EXIT_CONTAINER:
{
Int i;
ObjectID objID;
//
// find the object ID that wants to exit by scanning through the transport data and looking
// for the matching control button
//
for( i = 0; i < MAX_COMMANDS_PER_SET; i++ )
if( m_containData[ i ].control == control )
objID = m_containData[ i ].objectID;
// get the actual object
Object *objWantingExit = TheGameLogic->findObjectByID( objID );
// if object is not found remove inventory entry and exit
if( objWantingExit == NULL )
{
//
// remove from inventory data to avoid future matches ... the inventory update
// cycle of the UI will repopulate any buttons as the contents of objects
// change so this is only an edge case that will be visually corrected next frame
//
m_containData[ i ].control = NULL;
m_containData[ i ].objectID = INVALID_ID;
break; // exit case
} // end if
// send message to exit
GameMessage *exitMsg = TheMessageStream->appendMessage( GameMessage::MSG_EXIT );
exitMsg->appendObjectIDArgument( objWantingExit->getID() ); // 0 is the thing inside coming out
break;
} // end transport exit
//---------------------------------------------------------------------------------------------
case GUI_COMMAND_EVACUATE:
{
// Cancel GUI command mode.
TheInGameUI->setGUICommand( NULL );
if (BitTest(commandButton->getOptions(), NEED_TARGET_POS) == FALSE) {
pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_EVACUATE );
TheMessageStream->appendMessage( GameMessage::MSG_EVACUATE );
}
break;
} // end evacuate
// --------------------------------------------------------------------------------------------
case GUI_COMMAND_EXECUTE_RAILED_TRANSPORT:
{
TheMessageStream->appendMessage( GameMessage::MSG_EXECUTE_RAILED_TRANSPORT );
break;
} // end execute railed transport
// --------------------------------------------------------------------------------------------
case GUI_COMMAND_HACK_INTERNET:
{
pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_INTERNET_HACK );
TheMessageStream->appendMessage( GameMessage::MSG_INTERNET_HACK );
break;
}
//---------------------------------------------------------------------------------------------
case GUI_COMMAND_SET_RALLY_POINT:
{
break;
} // end set rally point
//---------------------------------------------------------------------------------------------
case GUI_COMMAND_SELL:
{
// command needs no additional data, send the message
TheMessageStream->appendMessage( GameMessage::MSG_SELL );
break;
} // end sell
// --------------------------------------------------------------------------------------------
case GUI_COMMAND_TOGGLE_OVERCHARGE:
{
TheMessageStream->appendMessage( GameMessage::MSG_TOGGLE_OVERCHARGE );
break;
} // end overcharge
#ifdef ALLOW_SURRENDER
// ------------------------------------------------------------------------------------------------
case GUI_COMMAND_POW_RETURN_TO_PRISON:
{
TheMessageStream->appendMessage( GameMessage::MSG_RETURN_TO_PRISON );
break;
} // end return to prison
#endif
//---------------------------------------------------------------------------------------------
case GUI_COMMAND_BEACON_DELETE:
{
break;
} // end delete beacon
//---------------------------------------------------------------------------------------------
case GUI_COMMAND_GUARD:
case GUI_COMMAND_GUARD_WITHOUT_PURSUIT:
case GUI_COMMAND_GUARD_FLYING_UNITS_ONLY:
case GUI_COMMAND_COMBATDROP:
{
DEBUG_CRASH(("hmm, should never occur"));
}
break;
//---------------------------------------------------------------------------------------------
case GUI_COMMAND_SWITCH_WEAPON:
{
// command needs no additional data, send the message
GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_SWITCH_WEAPONS );
//Play mode change acknowledgement
PickAndPlayInfo info;
WeaponSlotType slot = commandButton->getWeaponSlot();
info.m_weaponSlot = &slot;
pickAndPlayUnitVoiceResponse( TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_SWITCH_WEAPONS, &info );
msg->appendIntegerArgument( commandButton->getWeaponSlot() );
break;
}
//---------------------------------------------------------------------------------------------
case GUI_COMMAND_FIRE_WEAPON:
{
// command needs no additional data, send the message
GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_DO_WEAPON );
msg->appendIntegerArgument( commandButton->getWeaponSlot() );
msg->appendIntegerArgument( commandButton->getMaxShotsToFire() );
break;
} // end fire weapon
//---------------------------------------------------------------------------------------------
case GUI_COMMAND_SPECIAL_POWER_FROM_COMMAND_CENTER:
{
Object* cmdCenter = ThePlayerList->getLocalPlayer()->findNaturalCommandCenter();
if (cmdCenter == NULL)
break;
// command needs no additional data, send the message
GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_DO_SPECIAL_POWER );
msg->appendIntegerArgument( commandButton->getSpecialPowerTemplate()->getID() );
msg->appendIntegerArgument( commandButton->getOptions() );
msg->appendObjectIDArgument( cmdCenter->getID() );
break;
} // end special weapon
case GUI_COMMAND_SPECIAL_POWER:
{
// command needs no additional data, send the message
GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_DO_SPECIAL_POWER );
msg->appendIntegerArgument( commandButton->getSpecialPowerTemplate()->getID() );
msg->appendIntegerArgument( commandButton->getOptions() );
msg->appendObjectIDArgument( INVALID_ID ); // no specific source
break;
} // end special weapon
//---------------------------------------------------------------------------------------------
case GUI_COMMAND_PURCHASE_SCIENCE:
{
// loop through all the sciences on the button and select the one we don't have
ScienceType st = SCIENCE_INVALID;
Player *player = ThePlayerList->getLocalPlayer();
for(Int i = 0; i < commandButton->getScienceVec().size(); ++i)
{
st = commandButton->getScienceVec()[ i ];
if(!player->hasScience(st) && TheScienceStore->playerHasPrereqsForScience(player, st) && TheScienceStore->getSciencePurchaseCost(st) <= player->getSciencePurchasePoints())
{
break;
}
}
if( st == SCIENCE_INVALID)
{
switchToContext( CB_CONTEXT_NONE, NULL );
break;
}
GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_PURCHASE_SCIENCE );
msg->appendIntegerArgument( st );
markUIDirty();
break;
} // end pick specialized science
//---------------------------------------------------------------------------------------------
default:
DEBUG_ASSERTCRASH( 0, ("Unknown command '%d'\n", commandButton->getCommandType()) );
return CBC_COMMAND_NOT_USED;
} // end switch
return CBC_COMMAND_USED;
} // end processCommandUI

View File

@@ -0,0 +1,414 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: ControlBarMultiSelect.cpp ////////////////////////////////////////////////////////////////
// Author: Colin Day, March 2002
// Desc: Context sensitive GUI for when you select mutiple objects. What we do is show
// the commands that you can use between them all
///////////////////////////////////////////////////////////////////////////////////////////////////
// USER INCLUDES //////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/ThingTemplate.h"
#include "GameClient/ControlBar.h"
#include "GameClient/Drawable.h"
#include "GameClient/GameClient.h"
#include "GameClient/GadgetPushButton.h"
#include "GameClient/GameWindow.h"
#include "GameClient/InGameUI.h"
#include "GameLogic/Object.h"
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
//-------------------------------------------------------------------------------------------------
/** Reset the common command data */
//-------------------------------------------------------------------------------------------------
void ControlBar::resetCommonCommandData( void )
{
Int i;
for( i = 0; i < MAX_COMMANDS_PER_SET; i++ )
{
m_commonCommands[ i ] = NULL;
//Clear out any remnant overlays.
GadgetButtonDrawOverlayImage( m_commandWindows[ i ], NULL );
}
} // end resetCommonCommandData
//-------------------------------------------------------------------------------------------------
/** add the common commands of this drawable to the common command set */
//-------------------------------------------------------------------------------------------------
void ControlBar::addCommonCommands( Drawable *draw, Bool firstDrawable )
{
Int i;
const CommandButton *command;
// sanity
if( draw == NULL )
return;
Object* obj = draw->getObject();
if (!obj)
return;
if (obj->isKindOf(KINDOF_IGNORED_IN_GUI)) // ignore these guys
return;
// get the command set of this drawable
const CommandSet *commandSet = findCommandSet( obj->getCommandSetString() );
if( commandSet == NULL )
{
//
// if there is no command set for this drawable, none of the selected drawables
// can possibly have matching commands so we'll get rid of them all
//
for( i = 0; i < MAX_COMMANDS_PER_SET; i++ )
{
m_commonCommands[ i ] = NULL;
m_commandWindows[ i ]->winHide( TRUE );
// After Every change to the m_commandWIndows, we need to show fill in the missing blanks with the images
// removed from multiplayer branch
//showCommandMarkers();
} // end for i
return;
} // end if
//
// easy case, if we're adding the first drawable we simply just add any of the commands
// in its set that can be multi-select commands to the common command set
//
if( firstDrawable == TRUE )
{
// just add each command that is classified as a common command
for( i = 0; i < MAX_COMMANDS_PER_SET; i++ )
{
// get command
command = commandSet->getCommandButton(i);
// add if present and can be used in a multi select
if( command && BitTest( command->getOptions(), OK_FOR_MULTI_SELECT ) == TRUE )
{
// put it in the common command set
m_commonCommands[ i ] = command;
// show and enable this control
m_commandWindows[ i ]->winHide( FALSE );
m_commandWindows[ i ]->winEnable( TRUE );
// set the command into the control
setControlCommand( m_commandWindows[ i ], command );
} // end if
} // end for i
} // end if
else
{
// go through each command one by one
for( i = 0; i < MAX_COMMANDS_PER_SET; i++ )
{
// get the command
command = commandSet->getCommandButton(i);
Bool attackMove = (command && command->getCommandType() == GUI_COMMAND_ATTACK_MOVE) ||
(m_commonCommands[ i ] && m_commonCommands[ i ]->getCommandType() == GUI_COMMAND_ATTACK_MOVE);
// Kris: When any units have attack move, they all get it. This is to allow
// combat units to be selected with the odd dozer or pilot and still retain that ability.
if( attackMove && !m_commonCommands[ i ] )
{
// put it in the common command set
m_commonCommands[ i ] = command;
// show and enable this control
m_commandWindows[ i ]->winHide( FALSE );
m_commandWindows[ i ]->winEnable( TRUE );
// set the command into the control
setControlCommand( m_commandWindows[ i ], command );
}
else if( command != m_commonCommands[ i ] && !attackMove )
{
//
// if this command does not match the command that is in the common command set then
// *neither* this command OR the command in the common command set are really common
// commands, so we will remove the one that has been stored in the common set
//
// remove the common command
m_commonCommands[ i ] = NULL;
//
// hide the window control cause it should have been made visible from a command
// that was placed in this common 'slot' earlier
//
m_commandWindows[ i ]->winHide( TRUE );
}
} // end if
} // end else
// After Every change to the m_commandWIndows, we need to show fill in the missing blanks with the images
// removed from multiplayer branch
//showCommandMarkers();
} // end addCommonCommands
//-------------------------------------------------------------------------------------------------
/** Populate the visible command bar with commands that are common to all the objects
* that are selected in the UI */
//-------------------------------------------------------------------------------------------------
void ControlBar::populateMultiSelect( void )
{
Drawable *draw;
Bool firstDrawable = TRUE;
Bool portraitSet = FALSE;
const Image *portrait = NULL;
Object *portraitObj = NULL;
// first reset the common command data
resetCommonCommandData();
// by default, hide all the controls in the command section
for( Int i = 0; i < MAX_COMMANDS_PER_SET; i++ )
m_commandWindows[ i ]->winHide( TRUE );
// sanity
DEBUG_ASSERTCRASH( TheInGameUI->getSelectCount() > 1,
("populateMultiSelect: Can't populate multiselect context cause there are only '%d' things selected\n",
TheInGameUI->getSelectCount()) );
// get the list of drawable IDs from the in game UI
const DrawableList *selectedDrawables = TheInGameUI->getAllSelectedDrawables();
// sanity
DEBUG_ASSERTCRASH( selectedDrawables->empty() == FALSE, ("populateMultiSelect: Drawable list is empty\n") );
// loop through all the selected drawables
for( DrawableListCIt it = selectedDrawables->begin();
it != selectedDrawables->end(); ++it )
{
// get the drawable
draw = *it;
if (draw->getObject()->isKindOf(KINDOF_IGNORED_IN_GUI)) // ignore these guys
continue;
//
// add command for this drawable, note that we also sanity check to make sure the
// drawable has an object as all interesting drawables that we can select should
// actually have an object underneath it so that we can do interesting things with
// it ... otherwise we should have never selected it.
// NOTE that we're not considering objects that are currently in the process of
// being sold as those objects can't be issued anymore commands
//
if( draw && draw->getObject() &&
BitTest( draw->getObject()->getStatusBits(), OBJECT_STATUS_SOLD ) == FALSE )
{
// add the common commands of this drawable to the common command set
addCommonCommands( draw, firstDrawable );
// not adding the first drawble anymore
firstDrawable = FALSE;
//
// keep track of the portrait images, if all units selected have the same portrait
// we will display it in the right HUD, otherwise we won't
//
if( portraitSet == FALSE )
{
portrait = draw->getTemplate()->getSelectedPortraitImage();
portraitObj = draw->getObject();
portraitSet = TRUE;
} // end if
else if( draw->getTemplate()->getSelectedPortraitImage() != portrait )
portrait = NULL;
} // end if
} // end for, drawble id iterator
// set the portrait image
setPortraitByObject( portraitObj );
} // end populateMultiSelect
//-------------------------------------------------------------------------------------------------
/** Update logic for the multi select context sensitive GUI */
//-------------------------------------------------------------------------------------------------
void ControlBar::updateContextMultiSelect( void )
{
Drawable *draw;
Object *obj;
const CommandButton *command;
GameWindow *win;
Int objectsThatCanDoCommand[ MAX_COMMANDS_PER_SET ];
Int i;
// zero the array that counts how many objects can do each command
memset( objectsThatCanDoCommand, 0, sizeof( objectsThatCanDoCommand ) );
// santiy
DEBUG_ASSERTCRASH( TheInGameUI->getSelectCount() > 1,
("updateContextMultiSelect: TheInGameUI only has '%d' things selected\n",
TheInGameUI->getSelectCount()) );
// get the list of drawable IDs from the in game UI
const DrawableList *selectedDrawables = TheInGameUI->getAllSelectedDrawables();
// sanity
DEBUG_ASSERTCRASH( selectedDrawables->empty() == FALSE, ("populateMultiSelect: Drawable list is empty\n") );
// loop through all the selected drawable IDs
for( DrawableListCIt it = selectedDrawables->begin();
it != selectedDrawables->end(); ++it )
{
// get the drawable from the ID
draw = *it;
if (draw->getObject()->isKindOf(KINDOF_IGNORED_IN_GUI)) // ignore these guys
continue;
// get the object
obj = draw->getObject();
// sanity
if( obj == NULL )
continue;
// for each of the visible command windows make sure the object can execute the command
for( i = 0; i < MAX_COMMANDS_PER_SET; i++ )
{
// get the control window
win = m_commandWindows[ i ];
// don't consider hidden windows
if( win->winIsHidden() == TRUE )
continue;
// get the command
command = (const CommandButton *)GadgetButtonGetData(win);
if( command == NULL )
continue;
// can we do the command
CommandAvailability availability = getCommandAvailability( command, obj, win );
win->winClearStatus( WIN_STATUS_NOT_READY );
win->winClearStatus( WIN_STATUS_ALWAYS_COLOR );
// enable/disable the window control
switch( availability )
{
case COMMAND_HIDDEN:
win->winHide( TRUE );
break;
case COMMAND_RESTRICTED:
win->winEnable( FALSE );
break;
case COMMAND_NOT_READY:
win->winEnable( FALSE );
win->winSetStatus( WIN_STATUS_NOT_READY );
break;
case COMMAND_CANT_AFFORD:
win->winEnable( FALSE );
win->winSetStatus( WIN_STATUS_ALWAYS_COLOR );
break;
default:
win->winEnable( TRUE );
break;
}
//If button is a CHECK_LIKE, then update it's status now.
if( BitTest( command->getOptions(), CHECK_LIKE ) )
{
GadgetCheckLikeButtonSetVisualCheck( win, availability == COMMAND_ACTIVE );
}
if( availability == COMMAND_AVAILABLE || availability == COMMAND_ACTIVE )
objectsThatCanDoCommand[ i ]++;
} // end for i
} // end for, selected drawables
//
// for each command, if any objects can do the command we enable the window, otherwise
// we disable it
//
for( i = 0; i < MAX_COMMANDS_PER_SET; i++ )
{
// don't consider hidden commands
if( m_commandWindows[ i ]->winIsHidden() == TRUE )
continue;
// don't consider slots that don't have commands
if( m_commonCommands[ i ] == NULL )
continue;
// check the count of objects that can do the command and enable/disable the control,
if( objectsThatCanDoCommand[ i ] > 0 )
m_commandWindows[ i ]->winEnable( TRUE );
else
m_commandWindows[ i ]->winEnable( FALSE );
} // end for i
// After Every change to the m_commandWIndows, we need to show fill in the missing blanks with the images
// removed from multiplayer branch
//showCommandMarkers();
} // end updateContextMultiSelect

View File

@@ -0,0 +1,125 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: ControlBarOCLTimer.cpp //////////////////////////////////////////////////////////
// Author: Colin Day, March 2002
// Desc: Methods specific to the control bar OCL Timer context
///////////////////////////////////////////////////////////////////////////////////////////////////
// USER INCLUDES //////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/NameKeyGenerator.h"
#include "Common/ThingTemplate.h"
#include "GameLogic/Object.h"
#include "GameLogic/Module/OCLUpdate.h"
#include "GameClient/Drawable.h"
#include "GameClient/GameText.h"
#include "GameClient/ControlBar.h"
#include "GameClient/GameWindow.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/GadgetStaticText.h"
#include "GameClient/GadgetProgressBar.h"
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
void ControlBar::updateOCLTimerTextDisplay( UnsignedInt totalSeconds, Real percent )
{
UnicodeString text;
static UnsignedInt descID = TheNameKeyGenerator->nameToKey( "ControlBar.wnd:OCLTimerStaticText" );
GameWindow *descWindow = TheWindowManager->winGetWindowFromId( NULL, descID );
static UnsignedInt barID = TheNameKeyGenerator->nameToKey( "ControlBar.wnd:OCLTimerProgressBar" );
GameWindow *barWindow = TheWindowManager->winGetWindowFromId( NULL, barID );
// santiy
DEBUG_ASSERTCRASH( descWindow, ("Under construction window not found\n") );
Int minutes = totalSeconds / 60;
Int seconds = totalSeconds - (minutes * 60);
// format the message
if( seconds < 10 )
text.format( TheGameText->fetch( "CONTROLBAR:OCLTimerDescWithPadding" ), minutes, seconds );
else
text.format( TheGameText->fetch( "CONTROLBAR:OCLTimerDesc" ), minutes, seconds );
GadgetStaticTextSetText( descWindow, text );
GadgetProgressBarSetProgress(barWindow, (percent * 100));
// record this as the last time displayed
m_displayedOCLTimerSeconds = totalSeconds;
} // end updateOCLTimerTextDisplay
//-------------------------------------------------------------------------------------------------
/** Populate the interface for an OCL Timer context. */
//-------------------------------------------------------------------------------------------------
void ControlBar::populateOCLTimer( Object *creatorObject )
{
// sanity
if( creatorObject == NULL )
return;
// get our parent window
GameWindow *parent = m_contextParent[ CP_OCL_TIMER ];
// set the sell button
/// @todo srj -- remove hard-coding here, please
const CommandButton *commandButton = findCommandButton( "Command_Sell" );
NameKeyType id;
id = TheNameKeyGenerator->nameToKey( "ControlBar.wnd:OCLTimerSellButton" );
GameWindow *win = TheWindowManager->winGetWindowFromId( parent, id );
setControlCommand( win, commandButton );
win->winSetStatus( WIN_STATUS_USE_OVERLAY_STATES );
// set the text percent and bar of our timer we are displaying
updateContextOCLTimer( );
// set the portrait for the thing being constructed
setPortraitByObject( creatorObject );
} // end populateUnderConstruction
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
void ControlBar::updateContextOCLTimer( void )
{
Object *obj = m_currentSelectedDrawable->getObject();
static const NameKeyType key_OCLUpdate = NAMEKEY( "OCLUpdate" );
OCLUpdate *update = (OCLUpdate*)obj->findUpdateModule( key_OCLUpdate );
UnsignedInt frames = update->getRemainingFrames();
UnsignedInt seconds = frames / LOGICFRAMES_PER_SECOND;
Real percent = update->getCountdownPercent();
// if the time has changed since what was last shown to the user update the text
if( m_displayedOCLTimerSeconds != seconds )
updateOCLTimerTextDisplay( seconds, percent );
} // end updatecontextUnderConstruction

View File

@@ -0,0 +1,341 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: ControlBarObserver.cpp /////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Electronic Arts Pacific.
//
// Confidential Information
// Copyright (C) 2002 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// created: Aug 2002
//
// Filename: ControlBarObserver.cpp
//
// author: Chris Huybregts
//
// purpose: All things related to the Observer Control bar, are in here.
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// USER INCLUDES //////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/NameKeyGenerator.h"
#include "Common/PlayerList.h"
#include "Common/Player.h"
#include "Common/PlayerTemplate.h"
#include "Common/KindOf.h"
#include "Common/Recorder.h"
#include "GameClient/ControlBar.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/GadgetPushButton.h"
#include "GameClient/GadgetStaticText.h"
#include "GameClient/GameText.h"
#include "GameNetwork/NetworkDefs.h"
//-----------------------------------------------------------------------------
// DEFINES ////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
enum { MAX_BUTTONS = 8};
static NameKeyType buttonPlayerID[MAX_BUTTONS] = { NAMEKEY_INVALID,NAMEKEY_INVALID,
NAMEKEY_INVALID,NAMEKEY_INVALID,
NAMEKEY_INVALID,NAMEKEY_INVALID,
NAMEKEY_INVALID,NAMEKEY_INVALID };
static NameKeyType staticTextPlayerID[MAX_BUTTONS] = { NAMEKEY_INVALID,NAMEKEY_INVALID,
NAMEKEY_INVALID,NAMEKEY_INVALID,
NAMEKEY_INVALID,NAMEKEY_INVALID,
NAMEKEY_INVALID,NAMEKEY_INVALID };
static GameWindow *ObserverPlayerInfoWindow = NULL;
static GameWindow *ObserverPlayerListWindow = NULL;
static GameWindow *buttonPlayer[MAX_BUTTONS] = {NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL };
static GameWindow *staticTextPlayer[MAX_BUTTONS] = {NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL };
static NameKeyType buttonCancelID = NAMEKEY_INVALID;
static GameWindow *winFlag = NULL;
static GameWindow *winGeneralPortrait = NULL;
static GameWindow *staticTextNumberOfUnits = NULL;
static GameWindow *staticTextNumberOfBuildings = NULL;
static GameWindow *staticTextNumberOfUnitsKilled = NULL;
static GameWindow *staticTextNumberOfUnitsLost = NULL;
static GameWindow *staticTextPlayerName = NULL;
//-----------------------------------------------------------------------------
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
void ControlBar::initObserverControls( void )
{
ObserverPlayerInfoWindow = TheWindowManager->winGetWindowFromId(NULL, TheNameKeyGenerator->nameToKey("ControlBar.wnd:ObserverPlayerInfoWindow"));
ObserverPlayerListWindow = TheWindowManager->winGetWindowFromId(NULL, TheNameKeyGenerator->nameToKey("ControlBar.wnd:ObserverPlayerListWindow"));
for (Int i = 0; i < MAX_BUTTONS; i++)
{
AsciiString tmpString;
tmpString.format("ControlBar.wnd:ButtonPlayer%d", i);
buttonPlayerID[i] = TheNameKeyGenerator->nameToKey( tmpString );
buttonPlayer[i] = TheWindowManager->winGetWindowFromId( ObserverPlayerListWindow, buttonPlayerID[i] );
tmpString.format("ControlBar.wnd:StaticTextPlayer%d", i);
staticTextPlayerID[i] = TheNameKeyGenerator->nameToKey( tmpString );
staticTextPlayer[i] = TheWindowManager->winGetWindowFromId( ObserverPlayerListWindow, staticTextPlayerID[i] );
}
staticTextNumberOfUnits = TheWindowManager->winGetWindowFromId(NULL, TheNameKeyGenerator->nameToKey("ControlBar.wnd:StaticTextNumberOfUnits"));
staticTextNumberOfBuildings = TheWindowManager->winGetWindowFromId(NULL, TheNameKeyGenerator->nameToKey("ControlBar.wnd:StaticTextNumberOfBuildings"));
staticTextNumberOfUnitsKilled = TheWindowManager->winGetWindowFromId(NULL, TheNameKeyGenerator->nameToKey("ControlBar.wnd:StaticTextNumberOfUnitsKilled"));
staticTextNumberOfUnitsLost = TheWindowManager->winGetWindowFromId(NULL, TheNameKeyGenerator->nameToKey("ControlBar.wnd:StaticTextNumberOfUnitsLost"));
staticTextPlayerName = TheWindowManager->winGetWindowFromId(NULL, TheNameKeyGenerator->nameToKey("ControlBar.wnd:StaticTextPlayerName"));
winFlag = TheWindowManager->winGetWindowFromId(NULL, TheNameKeyGenerator->nameToKey("ControlBar.wnd:WinFlag"));
winGeneralPortrait = TheWindowManager->winGetWindowFromId(NULL, TheNameKeyGenerator->nameToKey("ControlBar.wnd:WinGeneralPortrait"));
buttonCancelID = TheNameKeyGenerator->nameToKey("ControlBar.wnd:ButtonCancel");
}
//-------------------------------------------------------------------------------------------------
/** System callback for the ControlBarObserverSystem */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType ControlBarObserverSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
static NameKeyType buttonCommunicator = NAMEKEY_INVALID;
switch( msg )
{
// --------------------------------------------------------------------------------------------
case GWM_CREATE:
{
break;
} // end create
//---------------------------------------------------------------------------------------------
case GBM_MOUSE_ENTERING:
case GBM_MOUSE_LEAVING:
{
break;
}
//---------------------------------------------------------------------------------------------
case GBM_SELECTED:
case GBM_SELECTED_RIGHT:
{
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if( controlID == buttonCancelID)
{
TheControlBar->setObserverLookAtPlayer(NULL);
ObserverPlayerInfoWindow->winHide(TRUE);
ObserverPlayerListWindow->winHide(FALSE);
TheControlBar->populateObserverList();
}
for(Int i = 0; i <MAX_BUTTONS; ++i)
{
if( controlID == buttonPlayerID[i])
{
ObserverPlayerInfoWindow->winHide(FALSE);
ObserverPlayerListWindow->winHide(TRUE);
TheControlBar->setObserverLookAtPlayer((Player *) GadgetButtonGetData( buttonPlayer[i]));
if(TheControlBar->getObserverLookAtPlayer())
TheControlBar->populateObserverInfoWindow();
return MSG_HANDLED;
}
}
// if( controlID == buttonCommunicator && TheGameLogic->getGameMode() == GAME_INTERNET )
/*
{
popupCommunicatorLayout = TheWindowManager->winCreateLayout( AsciiString( "Menus/PopupCommunicator.wnd" ) );
popupCommunicatorLayout->runInit();
popupCommunicatorLayout->hide( FALSE );
popupCommunicatorLayout->bringForward();
}
*/
break;
} // end button selected
//---------------------------------------------------------------------------------------------
default:
return MSG_IGNORED;
} // end switch( msg )
return MSG_HANDLED;
} // end ControlBarSystem
//-----------------------------------------------------------------------------
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
void ControlBar::populateObserverList( void )
{
Int currentButton = 0, i;
if(TheRecorder->isMultiplayer())
{
for (i = 0; i < MAX_SLOTS; ++i)
{
AsciiString name;
name.format("player%d", i);
Player *p = ThePlayerList->findPlayerWithNameKey(TheNameKeyGenerator->nameToKey(name));
if(p)
{
if(p->isPlayerObserver())
continue;
DEBUG_ASSERTCRASH(currentButton < MAX_BUTTONS, ("ControlBar::populateObserverList trying to populate more buttons then we have"));
GadgetButtonSetData(buttonPlayer[currentButton], (void *)p);
GadgetButtonSetEnabledImage( buttonPlayer[currentButton], p->getPlayerTemplate()->getEnabledImage() );
//GadgetButtonSetHiliteImage( buttonPlayer[currentButton], p->getPlayerTemplate()->getHiliteImage() );
//GadgetButtonSetHiliteSelectedImage( buttonPlayer[currentButton], p->getPlayerTemplate()->getPushedImage() );
//GadgetButtonSetDisabledImage( buttonPlayer[currentButton], p->getPlayerTemplate()->getDisabledImage() );
buttonPlayer[currentButton]->winSetTooltip(p->getPlayerDisplayName());
buttonPlayer[currentButton]->winHide(FALSE);
buttonPlayer[currentButton]->winSetStatus( WIN_STATUS_USE_OVERLAY_STATES );
const GameSlot *slot = TheGameInfo->getConstSlot(currentButton);
Color playerColor = p->getPlayerColor();
Color backColor = GameMakeColor(0, 0, 0, 255);
staticTextPlayer[currentButton]->winSetEnabledTextColors( playerColor, backColor );
staticTextPlayer[currentButton]->winHide(FALSE);
AsciiString teamStr;
teamStr.format("Team:%d", slot->getTeamNumber() + 1);
if (slot->isAI() && slot->getTeamNumber() == -1)
teamStr = "Team:AI";
UnicodeString text;
text.format(TheGameText->fetch("CONTROLBAR:ObsPlayerLabel"), p->getPlayerDisplayName().str(),
TheGameText->fetch(teamStr).str());
GadgetStaticTextSetText(staticTextPlayer[currentButton], text );
++currentButton;
}
}
for(currentButton; currentButton<MAX_BUTTONS; ++currentButton)
{
buttonPlayer[currentButton]->winHide(TRUE);
staticTextPlayer[currentButton]->winHide(TRUE);
}
}
else
{
for(i =0; i < MAX_PLAYER_COUNT; ++i)
{
Player *p = ThePlayerList->getNthPlayer(i);
if(p && !p->isPlayerObserver() && p->getPlayerType() == PLAYER_HUMAN)
{
DEBUG_ASSERTCRASH(currentButton < MAX_BUTTONS, ("ControlBar::populateObserverList trying to populate more buttons then we have"));
GadgetButtonSetData(buttonPlayer[currentButton], (void *)p);
GadgetButtonSetEnabledImage( buttonPlayer[currentButton], p->getPlayerTemplate()->getEnabledImage() );
//GadgetButtonSetHiliteImage( buttonPlayer[currentButton], p->getPlayerTemplate()->getHiliteImage() );
//GadgetButtonSetHiliteSelectedImage( buttonPlayer[currentButton], p->getPlayerTemplate()->getPushedImage() );
//GadgetButtonSetDisabledImage( buttonPlayer[currentButton], p->getPlayerTemplate()->getDisabledImage() );
buttonPlayer[currentButton]->winSetTooltip(p->getPlayerDisplayName());
buttonPlayer[currentButton]->winHide(FALSE);
buttonPlayer[currentButton]->winSetStatus( WIN_STATUS_USE_OVERLAY_STATES );
Color playerColor = p->getPlayerColor();
Color backColor = GameMakeColor(0, 0, 0, 255);
staticTextPlayer[currentButton]->winSetEnabledTextColors( playerColor, backColor );
staticTextPlayer[currentButton]->winHide(FALSE);
GadgetStaticTextSetText(staticTextPlayer[currentButton], p->getPlayerDisplayName());
++currentButton;
break;
}
}
for(currentButton; currentButton<MAX_BUTTONS; ++currentButton)
{
buttonPlayer[currentButton]->winHide(TRUE);
staticTextPlayer[currentButton]->winHide(TRUE);
}
}
}
void ControlBar::populateObserverInfoWindow ( void )
{
if(ObserverPlayerInfoWindow->winIsHidden())
return;
if( !m_observerLookAtPlayer )
{
ObserverPlayerInfoWindow->winHide(TRUE);
ObserverPlayerListWindow->winHide(FALSE);
populateObserverList();
return;
}
UnicodeString uString;
KindOfMaskType mask,clearmask;
mask.set(KINDOF_SCORE);
clearmask.set(KINDOF_STRUCTURE);
uString.format(L"%d",m_observerLookAtPlayer->countObjects(mask,clearmask));
GadgetStaticTextSetText(staticTextNumberOfUnits, uString);
Int numBuildings = 0;
mask.clear();
mask.set(KINDOF_SCORE);
mask.set(KINDOF_STRUCTURE);
clearmask.clear();
numBuildings = m_observerLookAtPlayer->countObjects(mask,clearmask);
mask.clear();
mask.set(KINDOF_SCORE_CREATE);
mask.set(KINDOF_STRUCTURE);
numBuildings += m_observerLookAtPlayer->countObjects(mask,clearmask);
mask.clear();
mask.set(KINDOF_SCORE_DESTROY);
mask.set(KINDOF_STRUCTURE);
numBuildings += m_observerLookAtPlayer->countObjects(mask,clearmask);
uString.format(L"%d",numBuildings);
GadgetStaticTextSetText(staticTextNumberOfBuildings, uString);
uString.format(L"%d",m_observerLookAtPlayer->getScoreKeeper()->getTotalUnitsDestroyed());
GadgetStaticTextSetText(staticTextNumberOfUnitsKilled, uString);
uString.format(L"%d",m_observerLookAtPlayer->getScoreKeeper()->getTotalUnitsLost());
GadgetStaticTextSetText(staticTextNumberOfUnitsLost, uString);
GadgetStaticTextSetText(staticTextPlayerName, m_observerLookAtPlayer->getPlayerDisplayName());
Color color = m_observerLookAtPlayer->getPlayerColor();
staticTextPlayerName->winSetEnabledTextColors(color, GameMakeColor(0,0,0,255));
winFlag->winSetEnabledImage(0, m_observerLookAtPlayer->getPlayerTemplate()->getFlagWaterMarkImage());
winGeneralPortrait->winHide(FALSE);
}

View File

@@ -0,0 +1,105 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: ControlBarPrintPositions.cpp /////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Electronic Arts Pacific.
//
// Confidential Information
// Copyright (C) 2002 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// created: Sep 2002
//
// Filename: ControlBarPrintPositions.cpp
//
// author: Chris Huybregts
//
// purpose: Convience function for degayifying the whole squished control bar
// process
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include <stdio.h>
//-----------------------------------------------------------------------------
// USER INCLUDES //////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
#include "GameClient/GameWindowManager.h"
#include "GameClient/WindowLayout.h"
//-----------------------------------------------------------------------------
// DEFINES ////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
void PrintInfoRecursive( GameWindow *win, FILE *fp)
{
if(!win)
return;
ICoord2D pos, size;
win->winGetSize(&size.x, &size.y);
win->winGetPosition(&pos.x, &pos.y);
fprintf(fp, "ControlBarResizer %s\n",win->winGetInstanceData()->m_decoratedNameString.str());
fprintf(fp, " AltPosition = X:%d Y:%d\n",pos.x, pos.y);
fprintf(fp, " AltSize = X:%d Y:%d\n",size.x, size.y);
fprintf(fp, "END\n\n");
PrintInfoRecursive(win->winGetChild(),fp);
PrintInfoRecursive(win->winGetNext(),fp);
}
void PrintOffsetsFromControlBarParent( void )
{
GameWindow *controlBarParent = TheWindowManager->winGetWindowFromId( NULL, TheNameKeyGenerator->nameToKey( "ControlBar.wnd:ControlBarParent" ));
if(!controlBarParent)
return;
WindowLayout *layout = TheWindowManager->winCreateLayout("controlBarHidden.wnd");
if(!layout)
return;
FILE *fp = fopen("ControlBarEasier.txt", "w");
if(!fp)
return;
PrintInfoRecursive(layout->getFirstWindow(), fp);
fclose(fp);
layout->destroyWindows();
layout->deleteInstance();
}
//-----------------------------------------------------------------------------
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------

View File

@@ -0,0 +1,245 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: ControlBarResizer.cpp /////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Electronic Arts Pacific.
//
// Confidential Information
// Copyright (C) 2002 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// created: Sep 2002
//
// Filename: ControlBarResizer.cpp
//
// author: Chris Huybregts
//
// purpose: We want a "squished" control bar, this is the methods that will do it
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
//-----------------------------------------------------------------------------
// USER INCLUDES //////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
#include "GameClient/ControlBar.h"
#include "GameClient/ControlBarResizer.h"
#include "GameClient/GameWindow.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/Display.h"
//-----------------------------------------------------------------------------
// DEFINES ////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
const FieldParse ControlBarResizer::m_controlBarResizerParseTable[] =
{
{ "AltPosition", INI::parseICoord2D, NULL, offsetof( ResizerWindow, m_altPos ) },
{ "AltSize", INI::parseICoord2D, NULL, offsetof( ResizerWindow, m_altSize ) },
{ NULL, NULL, NULL, 0 } // keep this last
};
//-----------------------------------------------------------------------------
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
ResizerWindow::ResizerWindow(void)
{
m_defaultPos.x = m_defaultPos.y = 0;
m_defaultSize.x = m_defaultSize.y = 0;
m_altSize.x = m_altSize.y = 0;
m_altPos.x = m_altPos.y = 0;
}
ControlBarResizer::ControlBarResizer( void )
{
}
ControlBarResizer::~ControlBarResizer( void )
{
ResizerWindowList::iterator it = m_resizerWindowsList.begin();
while (it != m_resizerWindowsList.end())
{
ResizerWindow *rWin = *it;
if( !rWin )
{
it = m_resizerWindowsList.erase(it);
continue;
}
delete rWin;
it = m_resizerWindowsList.erase(it);
}
m_resizerWindowsList.clear();
}
void ControlBarResizer::init( void )
{
INI ini;
// Read from INI all the ControlBarSchemes
ini.load( AsciiString( "Data\\INI\\ControlBarResizer.ini" ), INI_LOAD_OVERWRITE, NULL );
}
ResizerWindow *ControlBarResizer::findResizerWindow( AsciiString name )
{
ResizerWindowList::iterator it = m_resizerWindowsList.begin();
while (it != m_resizerWindowsList.end())
{
ResizerWindow *rWin = *it;
if( !rWin )
{
DEBUG_ASSERTCRASH(FALSE,("There's no resizerWindow in ControlBarResizer::findResizerWindow"));
it++;
continue;
}
// find the scheme that best matches our resolution
if(rWin->m_name.compare(name) == 0)
{
return rWin;
}
it ++;
}
return NULL;
}
ResizerWindow *ControlBarResizer::newResizerWindow( AsciiString name )
{
ResizerWindow *newRwin = NEW ResizerWindow;
if(!newRwin)
return NULL;
newRwin->m_name = name;
GameWindow *win = NULL;
win = TheWindowManager->winGetWindowFromId(NULL, TheNameKeyGenerator->nameToKey(name));
if( !win )
{
DEBUG_ASSERTCRASH(win,("ControlBarResizer::newResizerWindow could not find window %s Are you sure that window is loaded yet?", name.str()) );
delete newRwin;
return NULL;
}
win->winGetPosition(&newRwin->m_defaultPos.x,&newRwin->m_defaultPos.y);
win->winGetSize(&newRwin->m_defaultSize.x,&newRwin->m_defaultSize.y);
m_resizerWindowsList.push_back(newRwin);
return newRwin;
}
void ControlBarResizer::sizeWindowsDefault( void )
{
ResizerWindowList::iterator it = m_resizerWindowsList.begin();
GameWindow *win = NULL;
while (it != m_resizerWindowsList.end())
{
ResizerWindow *rWin = *it;
if( !rWin )
{
DEBUG_ASSERTCRASH(FALSE,("There's no resizerWindow in ControlBarResizer::sizeWindowsDefault"));
it++;
continue;
}
win = TheWindowManager->winGetWindowFromId(NULL, TheNameKeyGenerator->nameToKey(rWin->m_name));
if(!win)
{
it++;
continue;
}
win->winSetPosition(rWin->m_defaultPos.x, rWin->m_defaultPos.y);
win->winSetSize(rWin->m_defaultSize.x, rWin->m_defaultSize.y);
DEBUG_LOG(("sizeWindowsDefault:%s pos X:%d pos Y: %d size X:%d sizeY: %d",rWin->m_name.str(),rWin->m_defaultPos.x, rWin->m_defaultPos.y,rWin->m_defaultSize.x, rWin->m_defaultSize.y ));
it ++;
}
}
void ControlBarResizer::sizeWindowsAlt( void )
{
ResizerWindowList::iterator it = m_resizerWindowsList.begin();
GameWindow *win = NULL;
Real x = (Real)TheDisplay->getWidth() / 800;
Real y = (Real)TheDisplay->getHeight() / 600;
while (it != m_resizerWindowsList.end())
{
ResizerWindow *rWin = *it;
if( !rWin )
{
DEBUG_ASSERTCRASH(FALSE,("There's no resizerWindow in ControlBarResizer::sizeWindowsDefault"));
it++;
continue;
}
win = TheWindowManager->winGetWindowFromId(NULL, TheNameKeyGenerator->nameToKey(rWin->m_name));
if(!win)
{
it++;
continue;
}
win->winSetPosition(rWin->m_altPos.x * x, rWin->m_altPos.y * y);
if(rWin->m_altSize.x >0 || rWin->m_altSize.y > 0)
win->winSetSize(rWin->m_altSize.x *x, rWin->m_altSize.y *y);
DEBUG_LOG(("sizeWindowsAlt:%s pos X:%d pos Y: %d size X:%d sizeY: %d",rWin->m_name.str(), rWin->m_altPos.x*x, rWin->m_altPos.y*y,rWin->m_altSize.x*x, rWin->m_altSize.y *y));
it ++;
}
}
void INI::parseControlBarResizerDefinition( INI* ini )
{
// AsciiString name;
// ResizerWindow *rWin = NULL;
//
// // read the name
// const char* c = ini->getNextToken();
// name.set( c );
//
//// ControlBarResizer *resizer = TheControlBar->getControlBarResizer();
// if( !resizer )
// {
// //We don't need it if we're in the builder... which doesn't have this.
// return;
// }
// rWin = resizer->findResizerWindow( name );
// if( rWin == NULL )
// {
//
// // image not found, create a new one
// rWin = resizer->newResizerWindow(name);
// DEBUG_ASSERTCRASH( rWin, ("parseControlBarResizerDefinition: unable to allocate ResizerWindow for '%s'\n",
// name.str()) );
//
// } // end if
//
// // parse the ini definition
// ini->initFromINI( rWin, resizer->getFieldParse());
//
} // end parseMappedImage
//-----------------------------------------------------------------------------
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,229 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: ControlBarStructureInventory.cpp /////////////////////////////////////////////////////////
// Author: Colin Day, March 2002
// Desc: Methods specific to the control bar garrison display
///////////////////////////////////////////////////////////////////////////////////////////////////
// USER INCLUDES //////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/NameKeyGenerator.h"
#include "Common/ThingTemplate.h"
#include "Common/Player.h"
#include "Common/PlayerList.h"
#include "GameLogic/Object.h"
#include "GameLogic/Module/OpenContain.h"
#include "GameClient/InGameUI.h"
#include "GameClient/Drawable.h"
#include "GameClient/ControlBar.h"
#include "GameClient/GameWindow.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/GadgetPushButton.h"
#include "GameClient/Hotkey.h"
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
#define STOP_ID 10
#define EVACUATE_ID 11
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
struct PopulateButtonInfo
{
Object *source;
Int buttonIndex;
ControlBar* self;
GameWindow** inventoryButtons;
};
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
void ControlBar::populateButtonProc( Object *obj, void *userData )
{
PopulateButtonInfo* info = (PopulateButtonInfo*)userData;
// sanity
DEBUG_ASSERTCRASH( info->buttonIndex < MAX_STRUCTURE_INVENTORY_BUTTONS,
("Too many objects inside '%s' for the inventory buttons to hold",
info->source->getTemplate()->getName().str()) );
// put object in inventory data
info->self->m_containData[ info->buttonIndex ].control = info->inventoryButtons[ info->buttonIndex ];
info->self->m_containData[ info->buttonIndex ].objectID = obj->getID();
// set the UI button that will allow us to press it and cause the object to exit the container
const Image *image;
image = obj->getTemplate()->getButtonImage();
GadgetButtonSetEnabledImage( info->inventoryButtons[ info->buttonIndex ], image );
//Show the auto-contained object's veterancy symbol!
image = calculateVeterancyOverlayForObject( obj );
GadgetButtonDrawOverlayImage( info->inventoryButtons[ info->buttonIndex ], image );
// Enable the button
info->inventoryButtons[ info->buttonIndex ]->winEnable( TRUE );
// move to the next button index
info->buttonIndex++;
}
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
void ControlBar::populateStructureInventory( Object *building )
{
Int i;
// reset the inventory data
resetContainData();
// reset hotkeys -- seeing it only is reset in switching contexts. This is a special case
// because we are building the hotkeys on the fly sort of... and it changes as guys enter
// and leave. Taking this call out will cause multiple hotkeys to be added.
if(TheHotKeyManager)
TheHotKeyManager->reset();
// get the contain module of the object
ContainModuleInterface *contain = building->getContain();
DEBUG_ASSERTCRASH( contain, ("Object in structure inventory does not contain a Contain Module\n") );
if (!contain)
return;
/// @todo srj -- remove hard-coding here, please
const CommandButton *evacuateCommand = findCommandButton( "Command_Evacuate" );
setControlCommand( m_commandWindows[ EVACUATE_ID ], evacuateCommand );
m_commandWindows[ EVACUATE_ID ]->winEnable( FALSE );
/// @todo srj -- remove hard-coding here, please
const CommandButton *stopCommand = findCommandButton( "Command_Stop" );
setControlCommand( m_commandWindows[ STOP_ID ], stopCommand );
m_commandWindows[ STOP_ID ]->winEnable( FALSE );
// get the inventory exit command to assign into the button
/// @todo srj -- remove hard-coding here, please
const CommandButton *exitCommand = findCommandButton( "Command_StructureExit" );
// get window handles for each of the inventory buttons
AsciiString windowName;
for( i = 0; i < MAX_STRUCTURE_INVENTORY_BUTTONS; i++ )
{
// show the window
m_commandWindows[ i ]->winHide( FALSE );
//
// disable the button for now, it will be enabled if there is something there
// for its contents
//
m_commandWindows[ i ]->winEnable( FALSE );
m_commandWindows[ i ]->winSetStatus( WIN_STATUS_ALWAYS_COLOR );
m_commandWindows[ i ]->winClearStatus( WIN_STATUS_NOT_READY );
// set an inventory command into the game window UI element
setControlCommand( m_commandWindows[ i ], exitCommand );
// Clear any veterancy icon incase the unit leaves!
GadgetButtonDrawOverlayImage( m_commandWindows[ i ], NULL );
//
// if the structure can hold a lesser amount inside it than what the GUI displays
// we will completely hide the buttons that can't contain anything
//
if( i + 1 > contain->getContainMax() )
m_commandWindows[ i ]->winHide( TRUE );
} // end for i
// show the window
m_commandWindows[ EVACUATE_ID ]->winHide( FALSE );
m_commandWindows[ STOP_ID ]->winHide( FALSE );
// if there is at least one item in there enable the evacuate and stop buttons
if( contain->getContainCount() != 0 )
{
m_commandWindows[ EVACUATE_ID ]->winEnable( TRUE );
m_commandWindows[ STOP_ID ]->winEnable( TRUE );
}
//
// iterate each of the objects inside the container and put them in a button, note
// we're iterating in reverse order here
//
PopulateButtonInfo info;
info.source = building;
info.buttonIndex = 0;
info.self = this;
info.inventoryButtons = m_commandWindows;
contain->iterateContained(populateButtonProc, &info, FALSE );
//
// save how many items were contained by the object at this time so that we can update
// it if they change in the future while selected
//
m_lastRecordedInventoryCount = contain->getContainCount();
} // end populateStructureInventory
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
void ControlBar::updateContextStructureInventory( void )
{
Object *source = m_currentSelectedDrawable->getObject();
//
// we're visible, so there is something selected. It is possible that we had a building
// selected that can be garrisoned, and while it was selected the enemy occupied it.
// in that case we want to unselect the building so that we can't see the contents
//
Player *localPlayer = ThePlayerList->getLocalPlayer();
if( source->isLocallyControlled() == FALSE &&
localPlayer->getRelationship( source->getTeam() ) != NEUTRAL )
{
Drawable *draw = source->getDrawable();
if( draw )
TheInGameUI->deselectDrawable( draw );
return;
} // end if
//
// if the object being displayed in the interface has a different count than we last knew
// about we need to repopulate the buttons of the interface
//
ContainModuleInterface *contain = source->getContain();
DEBUG_ASSERTCRASH( contain, ("No contain module defined for object in the iventory bar\n") );
if (!contain)
return;
if( m_lastRecordedInventoryCount != contain->getContainCount() )
populateStructureInventory( source );
} // end updateContextStructureInventory

View File

@@ -0,0 +1,123 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: ControlBarUnderConstruction.cpp //////////////////////////////////////////////////////////
// Author: Colin Day, March 2002
// Desc: Methods specific to the control bar under construction context
///////////////////////////////////////////////////////////////////////////////////////////////////
// USER INCLUDES //////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/NameKeyGenerator.h"
#include "Common/ThingTemplate.h"
#include "GameLogic/Object.h"
#include "GameLogic/Module/UpdateModule.h"
#include "GameClient/Drawable.h"
#include "GameClient/GameText.h"
#include "GameClient/ControlBar.h"
#include "GameClient/GameWindow.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/GadgetStaticText.h"
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
void ControlBar::updateConstructionTextDisplay( Object *obj )
{
UnicodeString text;
static UnsignedInt descID = TheNameKeyGenerator->nameToKey( "ControlBar.wnd:UnderConstructionDesc" );
GameWindow *descWindow = TheWindowManager->winGetWindowFromId( NULL, descID );
// santiy
DEBUG_ASSERTCRASH( descWindow, ("Under construction window not found\n") );
// format the message
text.format( TheGameText->fetch( "CONTROLBAR:UnderConstructionDesc" ),
obj->getConstructionPercent() );
GadgetStaticTextSetText( descWindow, text );
// record this as the last percentage displayed
m_displayedConstructPercent = obj->getConstructionPercent();
} // end updateConstructionTextDisplay
//-------------------------------------------------------------------------------------------------
/** Populate the interface for an under construction context. */
//-------------------------------------------------------------------------------------------------
void ControlBar::populateUnderConstruction( Object *objectUnderConstruction )
{
// sanity
if( objectUnderConstruction == NULL )
return;
// get our parent window
GameWindow *parent = m_contextParent[ CP_UNDER_CONSTRUCTION ];
// set the cancel construction button
/// @todo srj -- remove hard-coding here, please
const CommandButton *commandButton = findCommandButton( "Command_CancelConstruction" );
NameKeyType id;
id = TheNameKeyGenerator->nameToKey( "ControlBar.wnd:ButtonCancelConstruction" );
GameWindow *win = TheWindowManager->winGetWindowFromId( parent, id );
setControlCommand( win, commandButton );
win->winSetStatus( WIN_STATUS_USE_OVERLAY_STATES );
// set the text description of what is building
updateConstructionTextDisplay( objectUnderConstruction );
// set the portrait for the thing being constructed
setPortraitByObject( objectUnderConstruction );
// and show the rally point, if it should have one,
ExitInterface *exit = objectUnderConstruction->getObjectExitInterface();
if( exit )
showRallyPoint( exit->getRallyPoint() );
} // end populateUnderConstruction
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
void ControlBar::updateContextUnderConstruction( void )
{
Object *obj = m_currentSelectedDrawable->getObject();
// if the object is no longer under construction switch to a new appropriate context
if( BitTest( obj->getStatusBits(), OBJECT_STATUS_UNDER_CONSTRUCTION ) == FALSE )
{
evaluateContextUI();
return;
} // end if
// if the construction percent has changed since what was last shown to the user update the text
if( m_displayedConstructPercent != obj->getConstructionPercent() )
updateConstructionTextDisplay( obj );
} // end updatecontextUnderConstruction

View File

@@ -0,0 +1,332 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "GameClient/DisconnectMenu.h"
#include "GameClient/GUICallbacks.h"
#include "Common/NameKeyGenerator.h"
#include "GameClient/GameWindow.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/GadgetStaticText.h"
#include "GameClient/GadgetListBox.h"
#include "GameClient/GameText.h"
#include "GameNetwork/GameInfo.h"
#include "GameNetwork/NetworkInterface.h"
char *DisconnectMenu::m_playerNameTextControlNames[] = {
"DisconnectScreen.wnd:StaticPlayer1Name",
"DisconnectScreen.wnd:StaticPlayer2Name",
"DisconnectScreen.wnd:StaticPlayer3Name",
"DisconnectScreen.wnd:StaticPlayer4Name",
"DisconnectScreen.wnd:StaticPlayer5Name",
"DisconnectScreen.wnd:StaticPlayer6Name",
"DisconnectScreen.wnd:StaticPlayer7Name",
NULL
};
char *DisconnectMenu::m_playerTimeoutTextControlNames[] = {
"DisconnectScreen.wnd:StaticPlayer1Timeout",
"DisconnectScreen.wnd:StaticPlayer2Timeout",
"DisconnectScreen.wnd:StaticPlayer3Timeout",
"DisconnectScreen.wnd:StaticPlayer4Timeout",
"DisconnectScreen.wnd:StaticPlayer5Timeout",
"DisconnectScreen.wnd:StaticPlayer6Timeout",
"DisconnectScreen.wnd:StaticPlayer7Timeout",
NULL
};
char *DisconnectMenu::m_playerVoteButtonControlNames[] = {
"DisconnectScreen.wnd:ButtonKickPlayer1",
"DisconnectScreen.wnd:ButtonKickPlayer2",
"DisconnectScreen.wnd:ButtonKickPlayer3",
"DisconnectScreen.wnd:ButtonKickPlayer4",
"DisconnectScreen.wnd:ButtonKickPlayer5",
"DisconnectScreen.wnd:ButtonKickPlayer6",
"DisconnectScreen.wnd:ButtonKickPlayer7",
NULL
};
char *DisconnectMenu::m_playerVoteCountControlNames[] = {
"DisconnectScreen.wnd:StaticPlayer1Votes",
"DisconnectScreen.wnd:StaticPlayer2Votes",
"DisconnectScreen.wnd:StaticPlayer3Votes",
"DisconnectScreen.wnd:StaticPlayer4Votes",
"DisconnectScreen.wnd:StaticPlayer5Votes",
"DisconnectScreen.wnd:StaticPlayer6Votes",
"DisconnectScreen.wnd:StaticPlayer7Votes",
NULL
};
char *DisconnectMenu::m_packetRouterTimeoutControlName = "DisconnectScreen.wnd:StaticPacketRouterTimeout";
char *DisconnectMenu::m_packetRouterTimeoutLabelControlName = "DisconnectScreen.wnd:StaticPacketRouterTimeoutLabel";
char *DisconnectMenu::m_textDisplayControlName = "DisconnectScreen.wnd:ListboxTextDisplay";
static const Color chatNormalColor = GameMakeColor(255,0,0,255);
DisconnectMenu *TheDisconnectMenu = NULL;
DisconnectMenu::DisconnectMenu() {
m_disconnectManager = NULL;
}
DisconnectMenu::~DisconnectMenu() {
}
void DisconnectMenu::init() {
m_disconnectManager = NULL;
HideDisconnectWindow();
m_menuState = DISCONNECTMENUSTATETYPE_SCREENOFF;
}
void DisconnectMenu::attachDisconnectManager(DisconnectManager *disconnectManager) {
m_disconnectManager = disconnectManager;
}
void DisconnectMenu::showScreen() {
HideDiplomacy();
HideInGameChat();
HideQuitMenu();
ShowDisconnectWindow();
m_menuState = DISCONNECTMENUSTATETYPE_SCREENON;
}
void DisconnectMenu::hideScreen() {
HideDisconnectWindow();
m_menuState = DISCONNECTMENUSTATETYPE_SCREENOFF;
}
void DisconnectMenu::setPlayerName(Int playerNum, UnicodeString name) {
NameKeyType id = TheNameKeyGenerator->nameToKey(m_playerNameTextControlNames[playerNum]);
GameWindow *control = TheWindowManager->winGetWindowFromId(NULL, id);
if (control != NULL) {
if (name.getLength() > 0) {
GadgetStaticTextSetText(control, name);
// showPlayerControls(playerNum);
}
}
id = TheNameKeyGenerator->nameToKey(m_playerTimeoutTextControlNames[playerNum]);
control = TheWindowManager->winGetWindowFromId(NULL, id);
if (control != NULL) {
if (name.getLength() > 0) {
GadgetStaticTextSetText(control, UnicodeString(L""));
}
}
if (name.getLength() > 0) {
showPlayerControls(playerNum);
} else {
hidePlayerControls(playerNum);
}
}
void DisconnectMenu::setPlayerTimeoutTime(Int playerNum, time_t newTime) {
NameKeyType id = TheNameKeyGenerator->nameToKey(m_playerTimeoutTextControlNames[playerNum]);
GameWindow *control = TheWindowManager->winGetWindowFromId(NULL, id);
char str[33]; // itoa uses a max of 33 bytes.
itoa(newTime, str, 10);
AsciiString asciiNum;
asciiNum.set(str);
UnicodeString uninum;
uninum.translate(asciiNum);
if (control != NULL) {
GadgetStaticTextSetText(control, uninum);
}
}
void DisconnectMenu::showPlayerControls(Int slot) {
NameKeyType id = TheNameKeyGenerator->nameToKey(m_playerNameTextControlNames[slot]);
GameWindow *control = TheWindowManager->winGetWindowFromId(NULL, id);
if (control != NULL) {
control->winHide(FALSE);
}
id = TheNameKeyGenerator->nameToKey(m_playerTimeoutTextControlNames[slot]);
control = TheWindowManager->winGetWindowFromId(NULL, id);
if (control != NULL) {
control->winHide(FALSE);
}
id = TheNameKeyGenerator->nameToKey(m_playerVoteButtonControlNames[slot]);
control = TheWindowManager->winGetWindowFromId(NULL, id);
if (control != NULL) {
control->winHide(FALSE);
// Disallow voting for 2-player games. Cheating punk.
if ( TheGameInfo && TheGameInfo->getNumPlayers() < 3 )
{
control->winEnable(FALSE);
}
else
{
control->winEnable(TRUE);
}
}
id = TheNameKeyGenerator->nameToKey(m_playerVoteCountControlNames[slot]);
control = TheWindowManager->winGetWindowFromId(NULL, id);
if (control != NULL) {
control->winHide(FALSE);
}
}
void DisconnectMenu::hidePlayerControls(Int slot) {
NameKeyType id = TheNameKeyGenerator->nameToKey(m_playerNameTextControlNames[slot]);
GameWindow *control = TheWindowManager->winGetWindowFromId(NULL, id);
if (control != NULL) {
control->winHide(TRUE);
}
id = TheNameKeyGenerator->nameToKey(m_playerTimeoutTextControlNames[slot]);
control = TheWindowManager->winGetWindowFromId(NULL, id);
if (control != NULL) {
control->winHide(TRUE);
}
id = TheNameKeyGenerator->nameToKey(m_playerVoteButtonControlNames[slot]);
control = TheWindowManager->winGetWindowFromId(NULL, id);
if (control != NULL) {
control->winHide(TRUE);
// Disallow voting for 2-player games. Cheating punk.
if ( TheGameInfo && TheGameInfo->getNumPlayers() < 3 )
{
control->winEnable(FALSE);
}
else
{
control->winEnable(TRUE);
}
}
id = TheNameKeyGenerator->nameToKey(m_playerVoteCountControlNames[slot]);
control = TheWindowManager->winGetWindowFromId(NULL, id);
if (control != NULL) {
control->winHide(TRUE);
}
}
void DisconnectMenu::showPacketRouterTimeout() {
NameKeyType id = TheNameKeyGenerator->nameToKey(m_packetRouterTimeoutLabelControlName);
GameWindow *control = TheWindowManager->winGetWindowFromId(NULL, id);
if (control != NULL) {
control->winHide(FALSE);
}
id = TheNameKeyGenerator->nameToKey(m_packetRouterTimeoutControlName);
control = TheWindowManager->winGetWindowFromId(NULL, id);
if (control != NULL) {
GadgetStaticTextSetText(control, UnicodeString(L"")); // start it off with a blank string.
control->winHide(FALSE);
}
}
void DisconnectMenu::hidePacketRouterTimeout() {
NameKeyType id = TheNameKeyGenerator->nameToKey(m_packetRouterTimeoutLabelControlName);
GameWindow *control = TheWindowManager->winGetWindowFromId(NULL, id);
if (control != NULL) {
control->winHide(TRUE);
}
id = TheNameKeyGenerator->nameToKey(m_packetRouterTimeoutControlName);
control = TheWindowManager->winGetWindowFromId(NULL, id);
if (control != NULL) {
control->winHide(TRUE);
}
}
void DisconnectMenu::setPacketRouterTimeoutTime(time_t newTime) {
NameKeyType id = TheNameKeyGenerator->nameToKey(m_packetRouterTimeoutControlName);
GameWindow *control = TheWindowManager->winGetWindowFromId(NULL, id);
char str[33]; // itoa uses a max of 33 bytes.
itoa(newTime, str, 10);
AsciiString asciiNum;
asciiNum.set(str);
UnicodeString uninum;
uninum.translate(asciiNum);
if (control != NULL) {
GadgetStaticTextSetText(control, uninum);
}
}
void DisconnectMenu::sendChat(UnicodeString text) {
TheNetwork->sendDisconnectChat(text);
}
void DisconnectMenu::showChat(UnicodeString text) {
NameKeyType displayID = TheNameKeyGenerator->nameToKey(m_textDisplayControlName);
GameWindow *displayControl = TheWindowManager->winGetWindowFromId(NULL, displayID);
if (displayControl != NULL) {
GadgetListBoxAddEntryText(displayControl, text, chatNormalColor, -1, -1);
}
}
void DisconnectMenu::quitGame() {
TheNetwork->quitGame();
}
void DisconnectMenu::removePlayer(Int slot, UnicodeString playerName) {
hidePlayerControls(slot);
NameKeyType displayID = TheNameKeyGenerator->nameToKey(m_textDisplayControlName);
GameWindow *displayControl = TheWindowManager->winGetWindowFromId(NULL, displayID);
UnicodeString text;
// UnicodeString name;
// name.translate(playerName);
text.format(TheGameText->fetch("Network:PlayerLeftGame"), playerName.str());
if (displayControl != NULL) {
GadgetListBoxAddEntryText(displayControl, text, chatNormalColor, -1, -1);
}
}
void DisconnectMenu::voteForPlayer(Int slot) {
DEBUG_LOG(("Casting vote for disconnect slot %d\n", slot));
TheNetwork->voteForPlayerDisconnect(slot); // Do this next.
}
void DisconnectMenu::updateVotes(Int slot, Int votes) {
NameKeyType id = TheNameKeyGenerator->nameToKey(m_playerVoteCountControlNames[slot]);
GameWindow *control = TheWindowManager->winGetWindowFromId(NULL, id);
if (control != NULL) {
char votestr[16];
itoa(votes, votestr, 10);
AsciiString asciivotes;
asciivotes.set(votestr);
UnicodeString unistr;
unistr.translate(asciivotes);
GadgetStaticTextSetText(control, unistr);
}
}

View File

@@ -0,0 +1,144 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
//// EstablishConnectionsMenu.cpp /////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "GameClient/GUICallbacks.h"
#include "GameClient/EstablishConnectionsMenu.h"
#include "Common/NameKeyGenerator.h"
#include "GameClient/GameWindow.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/GadgetStaticText.h"
#include "GameClient/GameText.h"
EstablishConnectionsMenu *TheEstablishConnectionsMenu = NULL;
char *EstablishConnectionsMenu::m_playerReadyControlNames[] = {
"EstablishConnectionsScreen.wnd:ButtonAccept1",
"EstablishConnectionsScreen.wnd:ButtonAccept2",
"EstablishConnectionsScreen.wnd:ButtonAccept3",
"EstablishConnectionsScreen.wnd:ButtonAccept4",
"EstablishConnectionsScreen.wnd:ButtonAccept5",
"EstablishConnectionsScreen.wnd:ButtonAccept6",
"EstablishConnectionsScreen.wnd:ButtonAccept7",
NULL};
char *EstablishConnectionsMenu::m_playerNameControlNames[] = {
"EstablishConnectionsScreen.wnd:StaticPlayer1Name",
"EstablishConnectionsScreen.wnd:StaticPlayer2Name",
"EstablishConnectionsScreen.wnd:StaticPlayer3Name",
"EstablishConnectionsScreen.wnd:StaticPlayer4Name",
"EstablishConnectionsScreen.wnd:StaticPlayer5Name",
"EstablishConnectionsScreen.wnd:StaticPlayer6Name",
"EstablishConnectionsScreen.wnd:StaticPlayer7Name",
NULL
};
char *EstablishConnectionsMenu::m_playerStatusControlNames[] = {
"EstablishConnectionsScreen.wnd:StaticPlayer1Status",
"EstablishConnectionsScreen.wnd:StaticPlayer2Status",
"EstablishConnectionsScreen.wnd:StaticPlayer3Status",
"EstablishConnectionsScreen.wnd:StaticPlayer4Status",
"EstablishConnectionsScreen.wnd:StaticPlayer5Status",
"EstablishConnectionsScreen.wnd:StaticPlayer6Status",
"EstablishConnectionsScreen.wnd:StaticPlayer7Status",
NULL
};
/**
Constructor
*/
EstablishConnectionsMenu::EstablishConnectionsMenu() {
}
/**
Destructor
*/
EstablishConnectionsMenu::~EstablishConnectionsMenu() {
}
/**
Initialize the menu
*/
void EstablishConnectionsMenu::initMenu() {
ShowEstablishConnectionsWindow();
}
/**
Close down the menu
*/
void EstablishConnectionsMenu::endMenu() {
HideEstablishConnectionsWindow();
}
/**
Abort the game gracefully...ok, as gracefully as possible considering
the game was supposed to be started and now for some reason we have to
stop it. Its really sad that this game isn't going to be played
considering how difficult it is to even get a game going in the first
place, especially one with more than two players.
*/
void EstablishConnectionsMenu::abortGame() {
}
// the slot number passed in is the index we are to use for the menu.
void EstablishConnectionsMenu::setPlayerName(Int slot, UnicodeString name) {
NameKeyType controlID = TheNameKeyGenerator->nameToKey(m_playerNameControlNames[slot]);
GameWindow *control = TheWindowManager->winGetWindowFromId(NULL, controlID);
if (control == NULL) {
DEBUG_ASSERTCRASH(control != NULL, ("player name control for slot %d is NULL", slot));
return;
}
GadgetStaticTextSetText(control, name);
}
void EstablishConnectionsMenu::setPlayerStatus(Int slot, NATConnectionState state) {
NameKeyType controlID = TheNameKeyGenerator->nameToKey(m_playerStatusControlNames[slot]);
GameWindow *control = TheWindowManager->winGetWindowFromId(NULL, controlID);
if (control == NULL) {
DEBUG_ASSERTCRASH(control != NULL, ("player status control for slot %d is NULL", slot));
return;
}
// if (state == NATCONNECTIONSTATE_NETGEARDELAY) {
// GadgetStaticTextSetText(control, TheGameText->fetch("GUI:NetgearDelay"));
if (state == NATCONNECTIONSTATE_WAITINGFORMANGLERRESPONSE) {
GadgetStaticTextSetText(control, TheGameText->fetch("GUI:WaitingForManglerResponse"));
} else if (state == NATCONNECTIONSTATE_WAITINGFORMANGLEDPORT) {
GadgetStaticTextSetText(control, TheGameText->fetch("GUI:WaitingForMangledPort"));
} else if (state == NATCONNECTIONSTATE_WAITINGFORRESPONSE) {
GadgetStaticTextSetText(control, TheGameText->fetch("GUI:WaitingForResponse"));
} else if (state == NATCONNECTIONSTATE_DONE) {
GadgetStaticTextSetText(control, TheGameText->fetch("GUI:ConnectionDone"));
} else if (state == NATCONNECTIONSTATE_FAILED) {
GadgetStaticTextSetText(control, TheGameText->fetch("GUI:ConnectionFailed"));
} else if (state == NATCONNECTIONSTATE_WAITINGTOBEGIN) {
GadgetStaticTextSetText(control, TheGameText->fetch("GUI:WaitingToBeginConnection"));
} else {
GadgetStaticTextSetText(control, TheGameText->fetch("GUI:UnknownConnectionState"));
}
}

View File

@@ -0,0 +1,622 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: ControlBarCallback.cpp ///////////////////////////////////////////////////////////////////
// Author: Colin Day - October 2001
// Desc: GUI Control bar at the bottom of the screen that houses the
// the build buttons, radar etc.
///////////////////////////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/NameKeyGenerator.h"
#include "Common/Player.h"
#include "Common/PlayerList.h"
#include "Common/MessageStream.h"
#include "Common/ThingFactory.h"
#include "Common/ThingTemplate.h"
#include "Common/Radar.h"
#include "GameClient/AnimateWindowManager.h"
#include "GameClient/Drawable.h"
#include "GameClient/GameWindow.h"
#include "GameClient/Gadget.h"
#include "GameClient/GadgetTextEntry.h"
#include "GameClient/GameClient.h"
#include "GameClient/GUICallbacks.h"
#include "GameClient/InGameUI.h"
#include "GameClient/ControlBar.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/LanguageFilter.h"
#include "GameClient/CommandXlat.h"
#include "GameLogic/GameLogic.h"
#include "GameLogic/ScriptEngine.h"
//external declarations of the Gadgets the callbacks can use
WindowLayout *popupCommunicatorLayout = NULL;
//-------------------------------------------------------------------------------------------------
/** Input procedure for the left HUD */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType LeftHUDInput( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
// get player
Player *player = ThePlayerList->getLocalPlayer();
//
// if the player doesn't have a radar, or the radar is hidden, and the radar is not being
// forced to on, we just eat input over the radar window
//
if( !TheRadar->isRadarForced() && (TheRadar->isRadarHidden() || !player->hasRadar()) )
return MSG_HANDLED;
// If the middle mouse button is depressed, then just let the message fall all the
// way back to the usual middle mouse button processing.
// jkmcd
if( TheMouse->getMouseStatus()->middleState == MBS_Down )
return MSG_IGNORED;
switch( msg )
{
/** @todo
This is wrong. The radar should be in the message stream, and eat all messages and propagate them
as a new message with the coords converted to world coords and the message flagged as being from
the radar. This would let all of the normal processing occur, and allow individual commands to easily
reject being used on the radar.
*/
// ------------------------------------------------------------------------
case GWM_NONE:
case GWM_MOUSE_ENTERING:
case GWM_MOUSE_LEAVING:
{
//
// consider changing the mouse cursor if we are not in the process of firing
// targeted "superweapons" which we can use the radar itself to fire
//
Bool targeting = FALSE;
const CommandButton *command = TheInGameUI->getGUICommand();
if( command
&& (command->getCommandType() == GUI_COMMAND_SPECIAL_POWER || command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_FROM_COMMAND_CENTER)
&& BitTest( command->getOptions(), NEED_TARGET_POS ) )
targeting = TRUE;
if( targeting == FALSE )
{
const DrawableList *drawableList = TheInGameUI->getAllSelectedLocalDrawables();
Mouse::MouseCursor cur = Mouse::ARROW;
if (!(drawableList->empty() || msg == GWM_MOUSE_LEAVING))
{
if (command && command->getCommandType() == GUI_COMMAND_ATTACK_MOVE)
{
cur = Mouse::ATTACKMOVETO;
}
else
{
cur = Mouse::MOVETO;
}
}
// Groovy
TheMouse->setCursor(cur);
} // end if
return MSG_HANDLED;
}
// --------------------------------------------------------------------------------------------
case GWM_MOUSE_POS:
{
// get mouse position
ICoord2D mouse;
mouse.x = mData1 & 0xFFFF;
mouse.y = mData1 >> 16;
// get window screen position
ICoord2D screenPos;
window->winGetScreenPosition( &screenPos.x, &screenPos.y );
// set mouse position to be relative to this window
mouse.x -= screenPos.x;
mouse.y -= screenPos.y;
// is the mouse in the radar window
ICoord2D radar;
if( (TheRadar->isRadarHidden() == FALSE || TheRadar->isRadarForced()) &&
TheRadar->localPixelToRadar( &mouse, &radar ) )
{
/*
//
// this is an example piece of code to find the object under the pixel position
// of the radar ... should we in the future wish to allow commands to be executed
// on objects throught he radar. note tho that this is extremely hard to do because
// the pixels on the radar are very small and it's hard to do accurate targeting
//
Object *obj = TheRadar->objectUnderRadarPixel( &mouse );
UnicodeString msg;
if( obj )
msg.format( L"Object under mouse on radar '%S'(%d)",
obj->getTemplate()->getName().str(), obj->getID() );
else
msg.format( L"Mouse (%d,%d) in Radar window L(%d,%d)", mouse.x, mouse.y, radar.x, radar.y );
TheInGameUI->message( msg );
*/
// keep the cursor for any context commands
const CommandButton *command = TheInGameUI->getGUICommand();
if( command
&& (command->getCommandType() == GUI_COMMAND_SPECIAL_POWER || command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_FROM_COMMAND_CENTER)
&& BitTest( command->getOptions(), NEED_TARGET_POS ) )
{
Int index = TheMouse->getCursorIndex( command->getCursorName() );
if( index != Mouse::INVALID_MOUSE_CURSOR )
TheMouse->setCursor( (Mouse::MouseCursor)index );
else
TheMouse->setCursor( Mouse::CROSS );
} // end if
else
{
// Else we are not super targeting, so we have to try to refresh the move cursor.
// We can't just do this on Enter and Exit, because hotkeys allow state to change
// while we are in the radar.
const DrawableList *drawableList = TheInGameUI->getAllSelectedLocalDrawables();
Mouse::MouseCursor cur = Mouse::ARROW;
if (!(drawableList->empty() || msg == GWM_MOUSE_LEAVING))
{
if (command && command->getCommandType() == GUI_COMMAND_ATTACK_MOVE)
{
cur = Mouse::ATTACKMOVETO;
}
else
{
cur = Mouse::MOVETO;
}
}
// Groovy
TheMouse->setCursor(cur);
}
} // end if
break;
} // end case mouse position
// ------------------------------------------------------------------------
case GWM_RIGHT_UP:// Here to eat
case GWM_LEFT_UP:// Here to eat
break;
case GWM_RIGHT_DOWN:
case GWM_LEFT_DOWN:
{
ICoord2D mouse;
ICoord2D radar;
ICoord2D size;
ICoord2D screenPos;
Coord3D world;
// get window size
window->winGetSize( &size.x, &size.y );
// get mouse position
mouse.x = mData1 & 0xFFFF;
mouse.y = mData1 >> 16;
// get window screen position
window->winGetScreenPosition( &screenPos.x, &screenPos.y );
// set mouse position to be relative to this window
mouse.x -= screenPos.x;
mouse.y -= screenPos.y;
//
// translate mouse position to radar position ... we know that the mouse
// location given to us here is relative to the HUD window, which is
// completely drawn with the radar ... so it's just a translation from
// our window size we're drawing into to the radar cell size
//
if( (TheRadar->isRadarHidden() == FALSE || TheRadar->isRadarForced()) &&
TheRadar->localPixelToRadar( &mouse, &radar ) &&
TheRadar->radarToWorld( &radar, &world ) )
{
// No drawables, or a right click automatically means its a look at.
// Having drawables and being in attack move mode means that we should attack move.
// Having drawables and not being in attack move mode means that we should move.
const DrawableList *drawableList = TheInGameUI->getAllSelectedLocalDrawables(); // locally-owned only
// see if the user wants to move the tactical view
if ( drawableList->empty()
|| (! TheGlobalData->m_useAlternateMouse && msg == GWM_RIGHT_DOWN)
|| (TheGlobalData->m_useAlternateMouse && msg == GWM_LEFT_DOWN) )
{
TheTacticalView->lookAt( &world );
break;
}
// evaluate any special powers that can be executed from the radar
const CommandButton *command = TheInGameUI->getGUICommand();
if( command
&& (command->getCommandType() == GUI_COMMAND_SPECIAL_POWER || command->getCommandType() == GUI_COMMAND_SPECIAL_POWER_FROM_COMMAND_CENTER)
&& BitTest( command->getOptions(), NEED_TARGET_POS )
)
{
// do the command
TheGameClient->evaluateContextCommand( NULL, &world, CommandTranslator::DO_COMMAND );
} // end if
else if( command && command->getCommandType() == GUI_COMMAND_ATTACK_MOVE)
{
// Attack move has changed from a modifier to a command, so it moves up here.
GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_DO_ATTACKMOVETO );
msg->appendLocationArgument( world );
// Play the unit voice response
pickAndPlayUnitVoiceResponse(TheInGameUI->getAllSelectedDrawables(), GameMessage::MSG_DO_ATTACKMOVETO);
}
else
{
GameMessage *newMsg = NULL;
// Do the superweapon stuff here, before issuing these other messages
// GS Leaving commented out to show that isInAttackMoveToMode is NEVER SET. It's a command now, not a modifier.
// if (TheInGameUI->isInAttackMoveToMode())
// {
// newMsg = TheMessageStream->appendMessage(GameMessage::MSG_DO_ATTACKMOVETO);
// newMsg->appendLocationArgument(world);
// // Play the unit voice response
// pickAndPlayUnitVoiceResponse(drawableList, GameMessage::MSG_DO_ATTACKMOVETO);
// break;
// }
newMsg = TheMessageStream->appendMessage(GameMessage::MSG_DO_MOVETO);
newMsg->appendLocationArgument(world);
// Play the unit voice response
pickAndPlayUnitVoiceResponse(drawableList, GameMessage::MSG_DO_MOVETO);
} // end else
}
break;
} // end left down
// ------------------------------------------------------------------------
default:
return MSG_IGNORED;
} // end switch( msg )
TheInGameUI->clearAttackMoveToMode();
return MSG_HANDLED;
} // end LeftHUDInput
//-------------------------------------------------------------------------------------------------
/** Input procedure for the control bar */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType ControlBarInput( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
return MSG_IGNORED;
} // end ControlBarInput
void ToggleQuitMenu(void);
//-------------------------------------------------------------------------------------------------
/** System callback for the control bar parent */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType ControlBarSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
static NameKeyType buttonCommunicator = NAMEKEY_INVALID;
if(TheScriptEngine && TheScriptEngine->isGameEnding())
return MSG_IGNORED;
switch( msg )
{
// --------------------------------------------------------------------------------------------
case GWM_CREATE:
{
// get ids for our children controls
buttonCommunicator = TheNameKeyGenerator->nameToKey( AsciiString("ControlBar.wnd:PopupCommunicator") );
break;
} // end create
//---------------------------------------------------------------------------------------------
case GBM_MOUSE_ENTERING:
case GBM_MOUSE_LEAVING:
{
GameWindow *control = (GameWindow *)mData1;
TheControlBar->processContextSensitiveButtonTransition( control, (GadgetGameMessage)msg);
break;
}
//---------------------------------------------------------------------------------------------
case GBM_SELECTED:
case GBM_SELECTED_RIGHT:
{
GameWindow *control = (GameWindow *)mData1;
static NameKeyType beaconPlacementButtonID = NAMEKEY("ControlBar.wnd:ButtonPlaceBeacon");
static NameKeyType beaconDeleteButtonID = NAMEKEY("ControlBar.wnd:ButtonDeleteBeacon");
static NameKeyType beaconClearTextButtonID = NAMEKEY("ControlBar.wnd:ButtonClearBeaconText");
static NameKeyType beaconGeneralButtonID = NAMEKEY("ControlBar.wnd:ButtonGeneral");
// static NameKeyType buttonSmallID = NAMEKEY("ControlBar.wnd:ButtonSmall");
// static NameKeyType buttonMediumID = NAMEKEY("ControlBar.wnd:ButtonMedium");
static NameKeyType buttonLargeID = NAMEKEY("ControlBar.wnd:ButtonLarge");
static NameKeyType buttonOptions = NAMEKEY("ControlBar.wnd:ButtonOptions");
static NameKeyType buttonIdleWorker = NAMEKEY("ControlBar.wnd:ButtonIdleWorker");
Int controlID = control->winGetWindowId();
if( controlID == buttonCommunicator )
{
ToggleDiplomacy(FALSE);
}
else if( controlID == beaconPlacementButtonID && TheGameLogic->isInMultiplayerGame() &&
ThePlayerList->getLocalPlayer()->isPlayerActive())
{
const CommandButton *commandButton = TheControlBar->findCommandButton( "Command_PlaceBeacon" );
TheInGameUI->setGUICommand( commandButton );
}
else if( controlID == beaconDeleteButtonID && TheGameLogic->isInMultiplayerGame() )
{
TheMessageStream->appendMessage( GameMessage::MSG_REMOVE_BEACON );
}
else if( controlID == beaconClearTextButtonID && TheGameLogic->isInMultiplayerGame() )
{
static NameKeyType textID = NAMEKEY("ControlBar.wnd:EditBeaconText");
GameWindow *win = TheWindowManager->winGetWindowFromId(NULL, textID);
if (win)
{
GadgetTextEntrySetText( win, UnicodeString::TheEmptyString );
}
}
else if( controlID == beaconGeneralButtonID)
{
HideQuitMenu( );
TheControlBar->togglePurchaseScience();
}
//else if( controlID == buttonSmallID)
// {
// TheControlBar->switchControlBarStage( CONTROL_BAR_STAGE_LOW );
// }
// else if( controlID == buttonMediumID)
// {
// TheControlBar->switchControlBarStage( CONTROL_BAR_STAGE_SQUISHED );
// }
else if( controlID == buttonLargeID)
{
TheControlBar->toggleControlBarStage();
}
else if( controlID == buttonOptions)
{
ToggleQuitMenu();
}
else if( controlID == buttonIdleWorker)
{
HideQuitMenu( );
TheInGameUI->selectNextIdleWorker();
}
else
{
//
// all buttons from all the context sensitive user interface windows are part of the
// control bar, send the button processing that way
//
TheControlBar->processContextSensitiveButtonClick( control, (GadgetGameMessage)msg );
}
break;
} // end button selected
//---------------------------------------------------------------------------------------------
case GEM_EDIT_DONE:
{
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
static NameKeyType textID = NAMEKEY("ControlBar.wnd:EditBeaconText");
if (controlID == textID)
{
// set beacon text
if (TheInGameUI->getSelectCount() == 1)
{
GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_SET_BEACON_TEXT );
UnicodeString newText = GadgetTextEntryGetText( control );
TheLanguageFilter->filterLine(newText);
const WideChar * c = newText.str();
while ( c && *c )
{
msg->appendWideCharArgument( *c++ );
}
msg->appendWideCharArgument( L'\0' ); // trailing NULL
}
}
break;
} // end edit done
//---------------------------------------------------------------------------------------------
default:
return MSG_IGNORED;
} // end switch( msg )
return MSG_HANDLED;
} // end ControlBarSystem
extern void showReplayControls( void );
extern void hideReplayControls( void );
extern void toggleReplayControls( void );
//-------------------------------------------------------------------------------------------------
/** Force the control bar to be shown */
//-------------------------------------------------------------------------------------------------
void ShowControlBar( Bool immediate )
{
showReplayControls();
if(TheControlBar)
TheControlBar->showSpecialPowerShortcut();
if (TheWindowManager)
{
Int id = (Int)TheNameKeyGenerator->nameToKey(AsciiString("ControlBar.wnd:ControlBarParent"));
GameWindow *window = TheWindowManager->winGetWindowFromId(NULL, id);
if (window)
{
TheControlBar->switchControlBarStage(CONTROL_BAR_STAGE_DEFAULT);
TheTacticalView->setHeight((Int)(TheDisplay->getHeight() * 0.80f));
if (TheControlBar->m_animateWindowManager && !immediate)
{
TheControlBar->m_animateWindowManager->reset();
//TheControlBar->m_animateWindowManager->registerGameWindow(window, WIN_ANIMATION_SLIDE_BOTTOM_TIMED, TRUE, 1000, 0);
TheControlBar->m_animateWindowManager->registerGameWindow(window, WIN_ANIMATION_SLIDE_BOTTOM, TRUE, 500, 0);
TheControlBar->animateSpecialPowerShortcut(TRUE);
}
window->winHide(FALSE);
}
}
// We want to get everything recalced since this is a major state change.
if(TheControlBar)
TheControlBar->markUIDirty();
}// void ShowControlBar(void)
//-------------------------------------------------------------------------------------------------
/** Force the control bar to be hidden */
//-------------------------------------------------------------------------------------------------
void HideControlBar( Bool immediate )
{
hideReplayControls();
if(TheControlBar)
TheControlBar->hideSpecialPowerShortcut();
if (TheWindowManager)
{
Int id = (Int)TheNameKeyGenerator->nameToKey(AsciiString("ControlBar.wnd:ControlBarParent"));
GameWindow *window = TheWindowManager->winGetWindowFromId(NULL, id);
if (window)
{
#ifdef SLIDE_LETTERBOX
TheTacticalView->setHeight((Int)(TheDisplay->getHeight() * 0.80f));
#else
TheTacticalView->setHeight(TheDisplay->getHeight());
#endif
}
if (immediate)
{
window->winHide(TRUE);
if(TheControlBar)
TheControlBar->hideSpecialPowerShortcut();
}
else
{
TheControlBar->m_animateWindowManager->reverseAnimateWindow();
TheControlBar->animateSpecialPowerShortcut(FALSE);
}
//Always get rid of the purchase science screen!
if( TheControlBar )
{
TheControlBar->hidePurchaseScience();
}
}
}//void HideControlBar( void )
//-------------------------------------------------------------------------------------------------
/** Toggle the control bar on or off */
//-------------------------------------------------------------------------------------------------
void ToggleControlBar( Bool immediate )
{
toggleReplayControls();
if (TheWindowManager)
{
Int id = (Int)TheNameKeyGenerator->nameToKey(AsciiString("ControlBar.wnd:ControlBarParent"));
GameWindow *window = TheWindowManager->winGetWindowFromId(NULL, id);
if (window)
{
if (window->winIsHidden())
{
if(TheControlBar)
TheControlBar->showSpecialPowerShortcut();
//now hidden, we're making it visible again so shrink viewport under the window
TheTacticalView->setHeight((Int)(TheDisplay->getHeight() * 0.80f));
window->winHide(!window->winIsHidden());
TheControlBar->switchControlBarStage(CONTROL_BAR_STAGE_DEFAULT);
if (TheControlBar->m_animateWindowManager && !immediate)
{
TheControlBar->m_animateWindowManager->reset();
//TheControlBar->m_animateWindowManager->registerGameWindow(window, WIN_ANIMATION_SLIDE_BOTTOM_TIMED, FALSE, 500, 0);
TheControlBar->m_animateWindowManager->registerGameWindow(window, WIN_ANIMATION_SLIDE_BOTTOM, TRUE, 500, 0);
TheControlBar->animateSpecialPowerShortcut(TRUE);
}
}
else
{
if(TheControlBar)
TheControlBar->hideSpecialPowerShortcut();
TheTacticalView->setHeight(TheDisplay->getHeight());
window->winHide(!window->winIsHidden());
}
}
}
}// end void ToggleControlBar( void )
//-------------------------------------------------------------------------------------------------
/** Resize the control bar */
//-------------------------------------------------------------------------------------------------

View File

@@ -0,0 +1,659 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: ControlBarPopupDescription.cpp /////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Electronic Arts Pacific.
//
// Confidential Information
// Copyright (C) 2002 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// created: Sep 2002
//
// Filename: ControlBarPopupDescription.cpp
//
// author: Chris Huybregts
//
// purpose:
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// USER INCLUDES //////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// DEFINES ////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/GlobalData.h"
#include "Common/BuildAssistant.h"
#include "Common/Player.h"
#include "Common/PlayerList.h"
#include "Common/ProductionPrerequisite.h"
#include "Common/ThingTemplate.h"
#include "Common/Upgrade.h"
#include "GameClient/AnimateWindowManager.h"
#include "GameClient/DisconnectMenu.h"
#include "GameClient/GameWindow.h"
#include "GameClient/Gadget.h"
#include "GameClient/GadgetTextEntry.h"
#include "GameClient/GadgetPushButton.h"
#include "GameClient/GadgetStaticText.h"
#include "GameClient/GameClient.h"
#include "GameClient/GameText.h"
#include "GameClient/GUICallbacks.h"
#include "GameClient/InGameUI.h"
#include "GameClient/Controlbar.h"
#include "GameClient/DisplayStringManager.h"
#include "GameLogic/GameLogic.h"
#include "GameLogic/Module/OverchargeBehavior.h"
#include "GameLogic/Module/ProductionUpdate.h"
#include "GameLogic/ScriptEngine.h"
#include "GameNetwork/NetworkInterface.h"
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
static WindowLayout *theLayout = NULL;
static GameWindow *theWindow = NULL;
static AnimateWindowManager *theAnimateWindowManager = NULL;
static GameWindow *prevWindow = NULL;
static Bool useAnimation = FALSE;
void ControlBarPopupDescriptionUpdateFunc( WindowLayout *layout, void *param )
{
if(TheScriptEngine->isGameEnding())
TheControlBar->hideBuildTooltipLayout();
if(theAnimateWindowManager && !TheControlBar->getShowBuildTooltipLayout() && !theAnimateWindowManager->isReversed())
theAnimateWindowManager->reverseAnimateWindow();
else if(!TheControlBar->getShowBuildTooltipLayout() && (!TheGlobalData->m_animateWindows || !useAnimation))
TheControlBar->deleteBuildTooltipLayout();
if ( useAnimation && theAnimateWindowManager && TheGlobalData->m_animateWindows)
{
Bool wasFinished = theAnimateWindowManager->isFinished();
theAnimateWindowManager->update();
if (theAnimateWindowManager && theAnimateWindowManager->isFinished() && !wasFinished && theAnimateWindowManager->isReversed())
{
delete theAnimateWindowManager;
theAnimateWindowManager = NULL;
TheControlBar->deleteBuildTooltipLayout();
}
}
}
// ---------------------------------------------------------------------------------------
void ControlBar::showBuildTooltipLayout( GameWindow *cmdButton )
{
if (TheInGameUI->areTooltipsDisabled() || TheScriptEngine->isGameEnding())
{
return;
}
Bool passedWaitTime = FALSE;
static Bool isInitialized = FALSE;
static UnsignedInt beginWaitTime;
if(prevWindow == cmdButton)
{
m_showBuildToolTipLayout = TRUE;
if(!isInitialized && beginWaitTime + cmdButton->getTooltipDelay() < timeGetTime())
{
//DEBUG_LOG(("%d beginwaittime, %d tooltipdelay, %dtimegettime\n", beginWaitTime, cmdButton->getTooltipDelay(), timeGetTime()));
passedWaitTime = TRUE;
}
if(!passedWaitTime)
return;
}
else if( !m_buildToolTipLayout->isHidden() )
{
if(useAnimation && TheGlobalData->m_animateWindows && !theAnimateWindowManager->isReversed())
theAnimateWindowManager->reverseAnimateWindow();
else if( useAnimation && TheGlobalData->m_animateWindows && theAnimateWindowManager->isReversed())
{
return;
}
else
{
// m_buildToolTipLayout->destroyWindows();
// m_buildToolTipLayout->deleteInstance();
// m_buildToolTipLayout = NULL;
m_buildToolTipLayout->hide(TRUE);
prevWindow = NULL;
}
return;
}
// will only get here the firsttime through the function through this window
if(!passedWaitTime)
{
prevWindow = cmdButton;
beginWaitTime = timeGetTime();
isInitialized = FALSE;
return;
}
isInitialized = TRUE;
if(!cmdButton)
return;
if(BitTest(cmdButton->winGetStyle(), GWS_PUSH_BUTTON))
{
const CommandButton *commandButton = (const CommandButton *)GadgetButtonGetData(cmdButton);
if(!commandButton)
return;
// note that, in this branch, ENABLE_SOLO_PLAY is ***NEVER*** defined...
// this is so that we have a multiplayer build that cannot possibly be hacked
// to work as a solo game!
#if !defined(_PLAYTEST)
if (TheGameLogic->isInReplayGame())
return;
#endif
if (TheInGameUI->isQuitMenuVisible())
return;
if (TheDisconnectMenu && TheDisconnectMenu->isScreenVisible())
return;
// if (m_buildToolTipLayout)
// {
// m_buildToolTipLayout->destroyWindows();
// m_buildToolTipLayout->deleteInstance();
//
// }
m_showBuildToolTipLayout = TRUE;
// m_buildToolTipLayout = TheWindowManager->winCreateLayout( "ControlBarPopupDescription.wnd" );
// m_buildToolTipLayout->setUpdate(ControlBarPopupDescriptionUpdateFunc);
populateBuildTooltipLayout(commandButton);
}
else
{
// we're a generic window
if(!BitTest(cmdButton->winGetStyle(), GWS_USER_WINDOW) && !BitTest(cmdButton->winGetStyle(), GWS_STATIC_TEXT))
return;
populateBuildTooltipLayout(NULL, cmdButton);
}
m_buildToolTipLayout->hide(FALSE);
if (useAnimation && TheGlobalData->m_animateWindows)
{
theAnimateWindowManager = NEW AnimateWindowManager;
theAnimateWindowManager->reset();
theAnimateWindowManager->registerGameWindow( m_buildToolTipLayout->getFirstWindow(), WIN_ANIMATION_SLIDE_RIGHT_FAST, TRUE, 200 );
}
}
void ControlBar::repopulateBuildTooltipLayout( void )
{
if(!prevWindow || !m_buildToolTipLayout)
return;
if(!BitTest(prevWindow->winGetStyle(), GWS_PUSH_BUTTON))
return;
const CommandButton *commandButton = (const CommandButton *)GadgetButtonGetData(prevWindow);
populateBuildTooltipLayout(commandButton);
}
void ControlBar::populateBuildTooltipLayout( const CommandButton *commandButton, GameWindow *tooltipWin)
{
if(!m_buildToolTipLayout)
return;
Player *player = ThePlayerList->getLocalPlayer();
UnicodeString name, cost, descrip;
UnicodeString requires = UnicodeString::TheEmptyString, requiresList;
Bool firstRequirement = true;
const ProductionPrerequisite *prereq;
Bool fireScienceButton = false;
if(commandButton)
{
const ThingTemplate *thingTemplate = commandButton->getThingTemplate();
const UpgradeTemplate *upgradeTemplate = commandButton->getUpgradeTemplate();
ScienceType st = SCIENCE_INVALID;
if(commandButton->getScienceVec().size() > 1)
{
for(Int j = 0; j < commandButton->getScienceVec().size(); ++j)
{
st = commandButton->getScienceVec()[ j ];
if( commandButton->getCommandType() != GUI_COMMAND_PURCHASE_SCIENCE )
{
if( !player->hasScience( st ) && j > 0 )
{
//If we're not looking at a command button that purchases a science, then
//it means we are looking at a command button that can USE the science. This
//means we want to get the description for the previous science -- the one
//we can use, not purchase!
st = commandButton->getScienceVec()[ j - 1 ];
}
//Now that we got the science for the button that executes the science, we need
//to generate a simpler help text!
fireScienceButton = true;
break;
}
else if( !player->hasScience( st ) )
{
//Purchase science case. The first science we run into that we don't have, that's the
//one we'll want to show!
break;
}
}
}
else if(commandButton->getScienceVec().size() == 1 )
{
st = commandButton->getScienceVec()[ 0 ];
}
if( commandButton->getDescriptionLabel().isNotEmpty() )
{
descrip = TheGameText->fetch(commandButton->getDescriptionLabel());
Drawable *draw = TheInGameUI->getFirstSelectedDrawable();
Object *selectedObject = draw ? draw->getObject() : NULL;
if( selectedObject )
{
//Special case: Append status of overcharge on China power plant.
if( commandButton->getCommandType() == GUI_COMMAND_TOGGLE_OVERCHARGE )
{
{
OverchargeBehaviorInterface *obi;
for( BehaviorModule **bmi = selectedObject->getBehaviorModules(); *bmi; ++bmi )
{
obi = (*bmi)->getOverchargeBehaviorInterface();
if( obi )
{
descrip.concat( L"\n" );
if( obi->isOverchargeActive() )
descrip.concat( TheGameText->fetch( "TOOLTIP:TooltipNukeReactorOverChargeIsOn" ) );
else
descrip.concat( TheGameText->fetch( "TOOLTIP:TooltipNukeReactorOverChargeIsOff" ) );
}
}
}
} //End overcharge special case
//Special case: When building units, the CanMakeType determines reasons for not being able to buy stuff.
else if( thingTemplate )
{
CanMakeType makeType = TheBuildAssistant->canMakeUnit( selectedObject, commandButton->getThingTemplate() );
switch( makeType )
{
case CANMAKE_NO_MONEY:
descrip.concat( L"\n\n" );
descrip.concat( TheGameText->fetch( "TOOLTIP:TooltipNotEnoughMoneyToBuild" ) );
break;
case CANMAKE_QUEUE_FULL:
descrip.concat( L"\n\n" );
descrip.concat( TheGameText->fetch( "TOOLTIP:TooltipCannotPurchaseBecauseQueueFull" ) );
break;
case CANMAKE_PARKING_PLACES_FULL:
descrip.concat( L"\n\n" );
descrip.concat( TheGameText->fetch( "TOOLTIP:TooltipCannotBuildUnitBecauseParkingFull" ) );
break;
case CANMAKE_MAXED_OUT_FOR_PLAYER:
descrip.concat( L"\n\n" );
descrip.concat( TheGameText->fetch( "TOOLTIP:TooltipCannotBuildUnitBecauseMaximumNumber" ) );
break;
//case CANMAKE_NO_PREREQ:
// descrip.concat( L"\n\n" );
// descrip.concat( TheGameText->fetch( "TOOLTIP:TooltipCannotBuildDueToPrerequisites" ) );
// break;
}
}
//Special case: When building upgrades
else if( upgradeTemplate && !player->hasUpgradeInProduction( upgradeTemplate ) )
{
if( commandButton->getCommandType() == GUI_COMMAND_PLAYER_UPGRADE ||
commandButton->getCommandType() == GUI_COMMAND_OBJECT_UPGRADE )
{
ProductionUpdateInterface *pui = selectedObject->getProductionUpdateInterface();
if( pui && pui->getProductionCount() == MAX_BUILD_QUEUE_BUTTONS )
{
descrip.concat( L"\n\n" );
descrip.concat( TheGameText->fetch( "TOOLTIP:TooltipCannotPurchaseBecauseQueueFull" ) );
}
else if( !TheUpgradeCenter->canAffordUpgrade( ThePlayerList->getLocalPlayer(), upgradeTemplate, FALSE ) )
{
descrip.concat( L"\n\n" );
descrip.concat( TheGameText->fetch( "TOOLTIP:TooltipNotEnoughMoneyToBuild" ) );
}
}
}
}
}
name = TheGameText->fetch(commandButton->getTextLabel().str());
if( thingTemplate && commandButton->getCommandType() != GUI_COMMAND_PURCHASE_SCIENCE )
{
//We are either looking at building a unit or a structure that may or may not have any
//prerequisites.
//Format the cost only when we have to pay for it.
cost.format(TheGameText->fetch("TOOLTIP:Cost"), thingTemplate->calcCostToBuild(player));
// ask each prerequisite to give us a list of the non satisfied prerequisites
for( Int i=0; i<thingTemplate->getPrereqCount(); i++ )
{
prereq = thingTemplate->getNthPrereq(i);
requiresList = prereq->getRequiresList(player);
if( requiresList != UnicodeString::TheEmptyString )
{
// make sure to put in 'returns' to space things correctly
if (firstRequirement)
firstRequirement = false;
else
requires.concat(L", ");
}
requires.concat(requiresList);
}
if( !requires.isEmpty() )
{
UnicodeString requireFormat = TheGameText->fetch("CONTROLBAR:Requirements");
requires.format(requireFormat.str(), requires.str());
if(!descrip.isEmpty())
descrip.concat(L"\n");
descrip.concat(requires);
}
}
else if( upgradeTemplate )
{
//We are looking at an upgrade purchase icon. Maybe we already purchased it?
Bool hasUpgradeAlready = false;
Bool hasConflictingUpgrade = false;
Bool playerUpgradeButton = commandButton->getCommandType() == GUI_COMMAND_PLAYER_UPGRADE;
Bool objectUpgradeButton = commandButton->getCommandType() == GUI_COMMAND_OBJECT_UPGRADE;
//Check if the local player has the specified upgrade
hasUpgradeAlready = player->hasUpgradeComplete( upgradeTemplate );
if( !hasUpgradeAlready )
{
//Check if the first selected object has the specified upgrade.
Drawable *draw = TheInGameUI->getFirstSelectedDrawable();
if( draw )
{
Object *object = draw->getObject();
if( object )
{
hasUpgradeAlready = object->hasUpgrade( upgradeTemplate );
if( objectUpgradeButton )
{
hasConflictingUpgrade = !object->affectedByUpgrade( upgradeTemplate );
}
}
}
}
if( hasConflictingUpgrade && !hasUpgradeAlready )
{
if( commandButton->getConflictingLabel().isNotEmpty() )
{
descrip = TheGameText->fetch( commandButton->getConflictingLabel() );
}
else
{
descrip = TheGameText->fetch( "TOOLTIP:HasConflictingUpgradeDefault" );
}
}
else if( hasUpgradeAlready && ( playerUpgradeButton || objectUpgradeButton ) )
{
//See if we can fetch the "already upgraded" text for this upgrade. If not.... use the default "fill me in".
if( commandButton->getPurchasedLabel().isNotEmpty() )
{
descrip = TheGameText->fetch( commandButton->getPurchasedLabel() );
}
else
{
descrip = TheGameText->fetch( "TOOLTIP:AlreadyUpgradedDefault" );
}
}
else if( !hasUpgradeAlready )
{
//Determine the cost of the upgrade.
cost.format(TheGameText->fetch("TOOLTIP:Cost"),upgradeTemplate->calcCostToBuild(player));
}
}
else if( st != SCIENCE_INVALID && !fireScienceButton )
{
TheScienceStore->getNameAndDescription(st, name, descrip);
cost.format(TheGameText->fetch("TOOLTIP:ScienceCost"),TheScienceStore->getSciencePurchaseCost(st));
// ask each prerequisite to give us a list of the non satisfied prerequisites
if( thingTemplate )
{
for( Int i=0; i<thingTemplate->getPrereqCount(); i++ )
{
prereq = thingTemplate->getNthPrereq(i);
requiresList = prereq->getRequiresList(player);
if( requiresList != UnicodeString::TheEmptyString )
{
// make sure to put in 'returns' to space things correctly
if (firstRequirement)
firstRequirement = false;
else
requires.concat(L", ");
}
requires.concat(requiresList);
}
if( !requires.isEmpty() )
{
UnicodeString requireFormat = TheGameText->fetch("CONTROLBAR:Requirements");
requires.format(requireFormat.str(), requires.str());
if(!descrip.isEmpty())
descrip.concat(L"\n");
descrip.concat(requires);
}
}
}
}
else if(tooltipWin)
{
if( tooltipWin == TheWindowManager->winGetWindowFromId(m_buildToolTipLayout->getFirstWindow(), TheNameKeyGenerator->nameToKey("ControlBar.wnd:MoneyDisplay")))
{
name = TheGameText->fetch("CONTROLBAR:Money");
descrip = TheGameText->fetch("CONTROLBAR:MoneyDescription");
}
else if(tooltipWin == TheWindowManager->winGetWindowFromId(m_buildToolTipLayout->getFirstWindow(), TheNameKeyGenerator->nameToKey("ControlBar.wnd:PowerWindow")) )
{
name = TheGameText->fetch("CONTROLBAR:Power");
descrip = TheGameText->fetch("CONTROLBAR:PowerDescription");
Player *playerToDisplay = NULL;
if(TheControlBar->isObserverControlBarOn())
playerToDisplay = TheControlBar->getObserverLookAtPlayer();
else
playerToDisplay = ThePlayerList->getLocalPlayer();
if( playerToDisplay && playerToDisplay->getEnergy() )
{
Energy *energy = playerToDisplay->getEnergy();
descrip.format(descrip, energy->getProduction(), energy->getConsumption());
}
else
{
descrip.format(descrip, 0, 0);
}
}
else if(tooltipWin == TheWindowManager->winGetWindowFromId(m_buildToolTipLayout->getFirstWindow(), TheNameKeyGenerator->nameToKey("ControlBar.wnd:GeneralsExp")) )
{
name = TheGameText->fetch("CONTROLBAR:GeneralsExp");
descrip = TheGameText->fetch("CONTROLBAR:GeneralsExpDescription");
}
else
{
DEBUG_ASSERTCRASH(FALSE, ("ControlBar::populateBuildTooltipLayout We attempted to call the popup tooltip on a game window that has yet to be hand coded in as this fuction was/is designed for only buttons but has been hacked to work with GameWindows."));
return;
}
}
GameWindow *win = TheWindowManager->winGetWindowFromId(m_buildToolTipLayout->getFirstWindow(), TheNameKeyGenerator->nameToKey("ControlBarPopupDescription.wnd:StaticTextName"));
if(win)
{
GadgetStaticTextSetText(win, name);
}
win = TheWindowManager->winGetWindowFromId(m_buildToolTipLayout->getFirstWindow(), TheNameKeyGenerator->nameToKey("ControlBarPopupDescription.wnd:StaticTextCost"));
if(win)
{
GadgetStaticTextSetText(win, cost);
}
win = TheWindowManager->winGetWindowFromId(m_buildToolTipLayout->getFirstWindow(), TheNameKeyGenerator->nameToKey("ControlBarPopupDescription.wnd:StaticTextDescription"));
if(win)
{
static NameKeyType winNamekey = TheNameKeyGenerator->nameToKey( AsciiString( "ControlBar.wnd:BackgroundMarker" ) );
static ICoord2D lastOffset = { 0, 0 };
ICoord2D size, newSize, pos;
Int diffSize;
DisplayString *tempDString = TheDisplayStringManager->newDisplayString();
win->winGetSize(&size.x, &size.y);
tempDString->setFont(win->winGetFont());
tempDString->setWordWrap(size.x - 10);
tempDString->setText(descrip);
tempDString->getSize(&newSize.x, &newSize.y);
TheDisplayStringManager->freeDisplayString(tempDString);
tempDString = NULL;
diffSize = newSize.y - size.y;
GameWindow *parent = m_buildToolTipLayout->getFirstWindow();
if(!parent)
return;
parent->winGetSize(&size.x, &size.y);
if(size.y + diffSize < 102) {
diffSize = 102 - size.y;
}
parent->winSetSize(size.x, size.y + diffSize);
parent->winGetPosition(&pos.x, &pos.y);
// if(size.y + diffSize < 102)
// {
//
// parent->winSetPosition(pos.x, pos.y - (102 - (newSize.y + size.y + diffSize) ));
// }
// else
// heightChange = controlBarPos.y - m_defaultControlBarPosition.y;
GameWindow *marker = TheWindowManager->winGetWindowFromId(NULL,winNamekey);
static ICoord2D basePos;
if(!marker)
{
return;
}
TheControlBar->getBackgroundMarkerPos(&basePos.x, &basePos.y);
ICoord2D curPos, offset;
marker->winGetScreenPosition(&curPos.x,&curPos.y);
offset.x = curPos.x - basePos.x;
offset.y = curPos.y - basePos.y;
parent->winSetPosition(pos.x, (pos.y - diffSize) + (offset.y - lastOffset.y));
lastOffset.x = offset.x;
lastOffset.y = offset.y;
win->winGetSize(&size.x, &size.y);
win->winSetSize(size.x, size.y + diffSize);
GadgetStaticTextSetText(win, descrip);
}
m_buildToolTipLayout->hide(FALSE);
}
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
void ControlBar::hideBuildTooltipLayout()
{
if(theAnimateWindowManager && theAnimateWindowManager->isReversed())
return;
if(useAnimation && theAnimateWindowManager && TheGlobalData->m_animateWindows)
theAnimateWindowManager->reverseAnimateWindow();
else
deleteBuildTooltipLayout();
}
void ControlBar::deleteBuildTooltipLayout( void )
{
m_showBuildToolTipLayout = FALSE;
prevWindow= NULL;
m_buildToolTipLayout->hide(TRUE);
// if(!m_buildToolTipLayout)
// return;
//
// m_buildToolTipLayout->destroyWindows();
// m_buildToolTipLayout->deleteInstance();
// m_buildToolTipLayout = NULL;
if(theAnimateWindowManager)
delete theAnimateWindowManager;
theAnimateWindowManager = NULL;
}

View File

@@ -0,0 +1,602 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (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; i<MAX_SLOTS; ++i)
{
AsciiString temp;
temp.format("Diplomacy.wnd:StaticTextPlayer%d", i);
staticTextPlayerID[i] = NAMEKEY(temp);
temp.format("Diplomacy.wnd:StaticTextSide%d", i);
staticTextSideID[i] = NAMEKEY(temp);
temp.format("Diplomacy.wnd:StaticTextTeam%d", i);
staticTextTeamID[i] = NAMEKEY(temp);
temp.format("Diplomacy.wnd:StaticTextStatus%d", i);
staticTextStatusID[i] = NAMEKEY(temp);
temp.format("Diplomacy.wnd:ButtonMute%d", i);
buttonMuteID[i] = NAMEKEY(temp);
temp.format("Diplomacy.wnd:ButtonUnMute%d", i);
buttonUnMuteID[i] = NAMEKEY(temp);
staticTextPlayer[i] = TheWindowManager->winGetWindowFromId(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; i<MAX_SLOTS; ++i)
{
staticTextPlayer[i] = NULL;
staticTextSide[i] = NULL;
staticTextTeam[i] = NULL;
staticTextStatus[i] = NULL;
buttonMute[i] = NULL;
buttonUnMute[i] = NULL;
slotNumInRow[i] = -1;
}
}
//-------------------------------------------------------------------------------------------------
static void updateFunc( WindowLayout *layout, void *param )
{
if (theAnimateWindowManager && TheGlobalData->m_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<MAX_SLOTS; ++i)
{
if (controlID == buttonMuteID[i] && slotNumInRow[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; slotNum<MAX_SLOTS; ++slotNum)
{
const GameSlot *slot = TheGameInfo->getConstSlot(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;
}
}

View File

@@ -0,0 +1,308 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: ExtendedMessageBox.cpp ///////////////////////////////////////////////////////////////////
// Author: Matt Campbell, January 2003
// Description: We go quiet in 1 day, gold in 15. Poor time to rewrite message boxes, so
// we get this file instead. Phooey.
///////////////////////////////////////////////////////////////////////////////////////////////////
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
// USER INCLUDES //////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/GameEngine.h"
#include "Common/NameKeyGenerator.h"
#include "GameClient/WindowLayout.h"
#include "GameClient/Gadget.h"
#include "GameClient/Shell.h"
#include "GameClient/KeyDefs.h"
#include "GameClient/GadgetStaticText.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/ExtendedMessageBox.h"
WindowMsgHandledType ExtendedMessageBoxSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 );
//-------------------------------------------------------------------------------------------------
/** Create an extended Modal Message Box */
//-------------------------------------------------------------------------------------------------
static GameWindow *gogoExMessageBox(Int x, Int y, Int width, Int height, UnsignedShort buttonFlags,
UnicodeString titleString, UnicodeString bodyString, void *userData,
MessageBoxFunc yesCallback,
MessageBoxFunc noCallback,
MessageBoxFunc okCallback,
MessageBoxFunc cancelCallback )
{
// first check to make sure we have some buttons to display
if(buttonFlags == 0 )
{
return NULL;
}
GameWindow *parent = TheWindowManager->winCreateFromScript( AsciiString("Menus/MessageBox.wnd") );
TheWindowManager->winSetModal( parent );
TheWindowManager->winSetFocus( NULL ); // make sure we lose focus from other windows even if we refuse focus ourselves
TheWindowManager->winSetFocus( parent );
// If the user wants the size to be different then the default
float ratioX, ratioY = 1;
if( width > 0 && height > 0 )
{
ICoord2D temp;
//First grab the percent increase/decrease compaired to the default size
parent->winGetSize( &temp.x, &temp.y);
ratioX = (float)width / (float)temp.x;
ratioY = (float)height / (float)temp.y;
//Set the window's new size
parent->winSetSize( width, height);
//Resize/reposition all the children windows based off the ratio
GameWindow *child;
for( child = parent->winGetChild(); child; child = child->winGetNext() )
{
child->winGetSize(&temp.x, &temp.y);
temp.x =Int(temp.x * ratioX);
temp.y =Int(temp.y * ratioY);
child->winSetSize(temp.x, temp.y);
child->winGetPosition(&temp.x, &temp.y);
temp.x =Int(temp.x * ratioX);
temp.y =Int(temp.y * ratioY);
child->winSetPosition(temp.x, temp.y);
}
}
// If the user wants to position the message box somewhere other then default
if( x >= 0 && y >= 0)
parent->winSetPosition(x, y);
// Reposition the buttons
Int buttonX[3], buttonY[3];
//In the layout, buttonOk will be in the first button position
NameKeyType buttonOkID = TheNameKeyGenerator->nameToKey( AsciiString( "MessageBox.wnd:ButtonOk" ) );
GameWindow *buttonOk = TheWindowManager->winGetWindowFromId(parent, buttonOkID);
buttonOk->winGetPosition(&buttonX[0], &buttonY[0]);
NameKeyType buttonYesID = TheNameKeyGenerator->nameToKey( AsciiString( "MessageBox.wnd:ButtonYes" ) );
GameWindow *buttonYes = TheWindowManager->winGetWindowFromId(parent, buttonYesID);
//buttonNo in the second position
NameKeyType buttonNoID = TheNameKeyGenerator->nameToKey( AsciiString( "MessageBox.wnd:ButtonNo" ) );
GameWindow *buttonNo = TheWindowManager->winGetWindowFromId(parent, buttonNoID);
buttonNo->winGetPosition(&buttonX[1], &buttonY[1]);
//and buttonCancel in the third
NameKeyType buttonCancelID = TheNameKeyGenerator->nameToKey( AsciiString( "MessageBox.wnd:ButtonCancel" ) );
GameWindow *buttonCancel = TheWindowManager->winGetWindowFromId(parent, buttonCancelID);
buttonCancel->winGetPosition(&buttonX[2], &buttonY[2]);
//we shouldn't have button OK and Yes on the same dialog
if((buttonFlags & (MSG_BOX_OK | MSG_BOX_YES)) == (MSG_BOX_OK | MSG_BOX_YES) )
{
DEBUG_ASSERTCRASH(false, ("Passed in MSG_BOX_OK and MSG_BOX_YES. Big No No."));
}
//Position the OK button if we have one
if( (buttonFlags & MSG_BOX_OK) == MSG_BOX_OK)
{
buttonOk->winSetPosition(buttonX[0], buttonY[0]);
buttonOk->winHide(FALSE);
}
else if( (buttonFlags & MSG_BOX_YES) == MSG_BOX_YES)
{
//Position the Yes if we have one
buttonYes->winSetPosition(buttonX[0], buttonY[0]);
buttonYes->winHide(FALSE);
}
if((buttonFlags & (MSG_BOX_NO | MSG_BOX_CANCEL)) == (MSG_BOX_NO | MSG_BOX_CANCEL) )
{
//If we have both the No and Cancel button, then the no should go in the middle position
buttonNo->winSetPosition(buttonX[1], buttonY[1]);
buttonCancel->winSetPosition(buttonX[2], buttonY[2]);
buttonNo->winHide(FALSE);
buttonCancel->winHide(FALSE);
}
else if( (buttonFlags & MSG_BOX_NO) == MSG_BOX_NO)
{
//if we just have the no button, then position it in the right most spot
buttonNo->winSetPosition(buttonX[2], buttonY[2]);
buttonNo->winHide(FALSE);
}
else if( (buttonFlags & MSG_BOX_CANCEL) == MSG_BOX_CANCEL)
{
//else if we just have the Cancel button, well, it should always go in the right spot
buttonCancel->winSetPosition(buttonX[2], buttonY[2]);
buttonCancel->winHide(FALSE);
}
// Fill the text into the text boxes
NameKeyType staticTextTitleID = TheNameKeyGenerator->nameToKey( AsciiString( "MessageBox.wnd:StaticTextTitle" ) );
GameWindow *staticTextTitle = TheWindowManager->winGetWindowFromId(parent, staticTextTitleID);
GadgetStaticTextSetText(staticTextTitle,titleString);
NameKeyType staticTextMessageID = TheNameKeyGenerator->nameToKey( AsciiString( "MessageBox.wnd:StaticTextMessage" ) );
GameWindow *staticTextMessage = TheWindowManager->winGetWindowFromId(parent, staticTextMessageID);
GadgetStaticTextSetText(staticTextMessage,bodyString);
// create a structure that will pass the functions to
WindowExMessageBoxData *MsgBoxCallbacks = NEW WindowExMessageBoxData;
MsgBoxCallbacks->cancelCallback = cancelCallback;
MsgBoxCallbacks->noCallback = noCallback;
MsgBoxCallbacks->okCallback = okCallback;
MsgBoxCallbacks->yesCallback = yesCallback;
MsgBoxCallbacks->userData = userData;
//pass the structure to the dialog
parent->winSetUserData( MsgBoxCallbacks );
parent->winSetSystemFunc(ExtendedMessageBoxSystem);
//make sure the dialog is showing and bring it to the top
parent->winHide(FALSE);
parent->winBringToTop();
return parent;
}// gogoExMessageBox
GameWindow *ExMessageBoxYesNo (UnicodeString titleString,UnicodeString bodyString, void *userData,
MessageBoxFunc yesCallback, MessageBoxFunc noCallback)
{
return gogoExMessageBox(-1,-1,-1,-1,MSG_BOX_NO | MSG_BOX_YES , titleString, bodyString, userData, yesCallback, noCallback, NULL, NULL);
}
GameWindow *ExMessageBoxYesNoCancel (UnicodeString titleString,UnicodeString bodyString, void *userData,
MessageBoxFunc yesCallback, MessageBoxFunc noCallback, MessageBoxFunc cancelCallback)
{
return gogoExMessageBox(-1,-1,-1,-1,MSG_BOX_NO | MSG_BOX_YES | MSG_BOX_CANCEL , titleString, bodyString, userData, yesCallback, noCallback, NULL, cancelCallback);
}
GameWindow *ExMessageBoxOkCancel (UnicodeString titleString,UnicodeString bodyString, void *userData,
MessageBoxFunc okCallback, MessageBoxFunc cancelCallback)
{
return gogoExMessageBox(-1,-1,-1,-1,MSG_BOX_OK | MSG_BOX_CANCEL , titleString, bodyString, userData, NULL, NULL, okCallback, cancelCallback);
}
GameWindow *ExMessageBoxOk (UnicodeString titleString,UnicodeString bodyString, void *userData,
MessageBoxFunc okCallback)
{
return gogoExMessageBox(-1,-1,-1,-1,MSG_BOX_OK, titleString, bodyString, userData, NULL, NULL, okCallback, NULL);
}
GameWindow *ExMessageBoxCancel (UnicodeString titleString,UnicodeString bodyString, void *userData,
MessageBoxFunc cancelCallback)
{
return gogoExMessageBox(-1,-1,-1,-1, MSG_BOX_CANCEL, titleString, bodyString, userData, NULL, NULL, NULL, cancelCallback);
}
// PRIVATE DATA ///////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------------------------
/** Message Box window system callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType ExtendedMessageBoxSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
switch( msg )
{
//---------------------------------------------------------------------------------------------
case GWM_DESTROY:
{
delete (WindowExMessageBoxData *)window->winGetUserData();
window->winSetUserData( NULL );
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;
break;
} // end input
//---------------------------------------------------------------------------------------------
case GBM_SELECTED:
{
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
static NameKeyType buttonOkID = TheNameKeyGenerator->nameToKey( AsciiString( "MessageBox.wnd:ButtonOk" ) );
static NameKeyType buttonYesID = TheNameKeyGenerator->nameToKey( AsciiString( "MessageBox.wnd:ButtonYes" ) );
static NameKeyType buttonNoID = TheNameKeyGenerator->nameToKey( AsciiString( "MessageBox.wnd:ButtonNo" ) );
static NameKeyType buttonCancelID = TheNameKeyGenerator->nameToKey( AsciiString( "MessageBox.wnd:ButtonCancel" ) );
WindowExMessageBoxData *MsgBoxCallbacks = (WindowExMessageBoxData *)window->winGetUserData();
MessageBoxReturnType ret = MB_RETURN_CLOSE;
if( controlID == buttonOkID )
{
if (MsgBoxCallbacks->okCallback)
ret = MsgBoxCallbacks->okCallback(MsgBoxCallbacks->userData);
} // end if
else if( controlID == buttonYesID )
{
if (MsgBoxCallbacks->yesCallback)
ret = MsgBoxCallbacks->yesCallback(MsgBoxCallbacks->userData);
} // end else if
else if( controlID == buttonNoID )
{
if (MsgBoxCallbacks->noCallback)
ret = MsgBoxCallbacks->noCallback(MsgBoxCallbacks->userData);
} // end else if
else if( controlID == buttonCancelID )
{
if (MsgBoxCallbacks->cancelCallback)
ret = MsgBoxCallbacks->cancelCallback(MsgBoxCallbacks->userData);
} // end else if
if (ret == MB_RETURN_CLOSE)
TheWindowManager->winDestroy(window);
break;
} // end selected
//---------------------------------------------------------------------------------------------
default:
return MSG_IGNORED;
} // end switch
return MSG_HANDLED;
} // end ExtendedMessageBoxSystem

View File

@@ -0,0 +1,169 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: GeneralsExpPoints.cpp /////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Electronic Arts Pacific.
//
// Confidential Information
// Copyright (C) 2002 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// created: Oct 2002
//
// Filename: GeneralsExpPoints.cpp
//
// author: Chris Huybregts
//
// purpose: File used to populate/update/show/hide the generals exp screen
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
//-----------------------------------------------------------------------------
// USER INCLUDES //////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
#include "GameClient/ControlBar.h"
#include "GameClient/GUICallbacks.h"
#include "GameClient/GameWindow.h"
#include "GameClient/Gadget.h"
#include "GameClient/KeyDefs.h"
#include "GameClient/ControlBar.h"
#include "GameClient/InGameUI.h"
//-----------------------------------------------------------------------------
// DEFINES ////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType GeneralsExpPointsInput( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
switch( msg )
{
// --------------------------------------------------------------------------------------------
case GWM_MOUSE_ENTERING:
//Get rid of any building placement mode!
if( TheInGameUI )
{
TheInGameUI->placeBuildAvailable( NULL, NULL );
}
break;
case GWM_CHAR:
{
UnsignedByte key = mData1;
// UnsignedByte state = mData2;
switch( key )
{
// ----------------------------------------------------------------------------------------
case KEY_ESC:
{
TheControlBar->hidePurchaseScience();
return MSG_HANDLED;
//return MSG_IGNORED;
} // end escape
} // end switch( key )
return MSG_HANDLED;
} // end char
}
return MSG_HANDLED;
} // end DiplomacyInput
//-----------------------------------------------------------------------------
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
WindowMsgHandledType GeneralsExpPointsSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
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 buttonExitID = NAMEKEY( "GeneralsExpPoints.wnd:ButtonExit" );
if (controlID == buttonExitID)
{
TheControlBar->hidePurchaseScience();
}
else
TheControlBar->processContextSensitiveButtonClick( control, (GadgetGameMessage)msg );
break;
} // end button selected
//---------------------------------------------------------------------------------------------
default:
return MSG_IGNORED;
} // end switch( msg )
return MSG_HANDLED;
} // end GeneralsExpPointsSystem
//-----------------------------------------------------------------------------
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------

View File

@@ -0,0 +1,293 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: IMECandidate.cpp /////////////////////////////////////////////////////////////////////////
// Author: TR November 2001
// Desc: IME Candidate window callbacks
///////////////////////////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "GameClient/GameWindow.h"
#include "GameClient/Gadget.h"
#include "GameClient/IMEManager.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/DisplayString.h"
#include "GameClient/DisplayStringManager.h"
Int IMECandidateWindowLineSpacing = 2;
static DisplayString *Dstring = NULL;
//-------------------------------------------------------------------------------------------------
/** Input procedure for the candidate window */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType IMECandidateWindowInput( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
return MSG_HANDLED;
} // end IMECandidateInput
//-------------------------------------------------------------------------------------------------
/** System callback for the IME Candidate widnow */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType IMECandidateWindowSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
switch( msg )
{
case GWM_CREATE:
if ( Dstring == NULL )
{
Dstring = TheDisplayStringManager->newDisplayString();
}
break;
case GWM_DESTROY:
if ( Dstring != NULL )
{
TheDisplayStringManager->freeDisplayString( Dstring );
Dstring = NULL;
}
break;
//---------------------------------------------------------------------------------------------
default:
return MSG_IGNORED;
} // end switch( msg )
return MSG_HANDLED;
} // end IMECandidateWidnowSystem
// IMECandidateDraw ================================================================
/** Draw function for the IME candidate window */
//=============================================================================
void IMECandidateTextAreaDraw( GameWindow *window, WinInstanceData *instData )
{
// set up for rendering
ICoord2D origin, size, start, end;
Color textColor,
textBorder,
textSelectColor,
textSelectBorder;
IRegion2D textRegion;
Color black = GameMakeColor( 0, 0, 0, 255);
// get window position and size
window->winGetScreenPosition( &origin.x, &origin.y );
window->winGetSize( &size.x, &size.y );
// get a nice region from the positions
textRegion.lo.x = origin.x;
textRegion.lo.y = origin.y;
textRegion.hi.x = origin.x + size.x;
textRegion.hi.y = origin.y + size.y;
// get the right colors for drawing
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
{
textSelectColor = window->winGetDisabledTextColor();
textSelectBorder = window->winGetDisabledTextBorderColor();
textColor = window->winGetDisabledTextColor();
textBorder = window->winGetDisabledTextBorderColor();
} // end if, disabled
else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
{
textColor = window->winGetEnabledTextColor();
textBorder = window->winGetEnabledTextBorderColor();
textSelectColor = window->winGetHiliteTextColor();
textSelectBorder = window->winGetHiliteTextBorderColor();
} // end else if, hilited
else
{
textSelectColor = window->winGetHiliteTextColor();
textSelectBorder = window->winGetHiliteTextBorderColor();
textColor = window->winGetEnabledTextColor();
textBorder = window->winGetEnabledTextBorderColor();
} // end else, just enabled
{
Real borderWidth = 1.0f;
start.x = origin.x;
start.y = origin.y;
end.x = start.x + size.x;
end.y = start.y + size.y;
TheWindowManager->winOpenRect( black, borderWidth,
start.x, start.y, end.x, end.y );
}
if ( Dstring == NULL )
{
return;
}
IMEManagerInterface *ime = (IMEManagerInterface*)window->winGetUserData();
if ( ime == NULL )
{
return;
}
GameFont *font = window->winGetFont() ;
Int height;
// set the font
Dstring->setFont( font );
// cacl line height
height = font->height + IMECandidateWindowLineSpacing;
// set the clip region
Dstring->setClipRegion( &textRegion );
Int first = ime->getCandidatePageStart();
Int total = ime->getCandidateCount();
Int pageSize = ime->getCandidatePageSize();
Int selected = ime->getSelectedCandidateIndex();
Int count = pageSize;
if ( count + first > total )
{
count = total - first;
}
selected = selected - first;
UnicodeString number;
// calulate the widest number text
Int width;
Dstring->setText(UnicodeString(L"00:"));
width = Dstring->getWidth();
// calc y start pos
Int y = origin.y;
Int leftEdge = origin.x + 10 + width;
for ( Int i = 0; i < count; i++, y+= height )
{
UnicodeString *candidate = ime->getCandidate( first + i );
Int tcolor, bcolor;
if ( i == selected )
{
tcolor = textSelectColor;
bcolor = textSelectBorder;
}
else
{
tcolor = textColor;
bcolor = textBorder;
}
// draw number tab first
number.format( L"%d:", i + ime->getIndexBase());
Dstring->setText( number );
width = Dstring->getWidth();
Dstring->draw( leftEdge - width, y, tcolor, black);
// draw candidate
Dstring->setText( *candidate );
Dstring->draw( leftEdge, y, tcolor, black );
}
}
// IMECandidateDraw ================================================================
/** Draw function for the IME candidate window */
//=============================================================================
void IMECandidateMainDraw( GameWindow *window, WinInstanceData *instData )
{
// set up for rendering
ICoord2D origin, size, start, end;
Color backColor,
backBorder;
Real borderWidth = 1.0f;
// get window position and size
window->winGetScreenPosition( &origin.x, &origin.y );
window->winGetSize( &size.x, &size.y );
// get the right colors for drawing
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
{
backColor = window->winGetDisabledColor( 0 );
backBorder = window->winGetDisabledBorderColor( 0 );
} // end if, disabled
else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
{
backColor = window->winGetHiliteColor( 0 );
backBorder = window->winGetHiliteBorderColor( 0 );
} // end else if, hilited
else
{
backColor = window->winGetEnabledColor( 0 );
backBorder = window->winGetEnabledBorderColor( 0 );
} // end else, just enabled
// draw the back border
if( backBorder != WIN_COLOR_UNDEFINED )
{
start.x = origin.x;
start.y = origin.y;
end.x = start.x + size.x;
end.y = start.y + size.y;
TheWindowManager->winOpenRect( backBorder, borderWidth,
start.x, start.y, end.x, end.y );
} // end if
// draw the filled back
if( backColor != WIN_COLOR_UNDEFINED )
{
start.x = origin.x + 1;
start.y = origin.y + 1;
end.x = start.x + size.x - 2;
end.y = start.y + size.y - 2;
TheWindowManager->winFillRect( backColor, 0, start.x, start.y, end.x, end.y );
} // end if
}

View File

@@ -0,0 +1,365 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: InGameChat.cpp ///////////////////////////////////////////////////////////////////////
// Author: Matthew D. Campbell - June 2002
// Desc: GUI callbacks for the in-game chat entry
///////////////////////////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/Player.h"
#include "Common/PlayerList.h"
#include "GameClient/DisconnectMenu.h"
#include "GameClient/GameWindow.h"
#include "GameClient/Gadget.h"
#include "GameClient/GadgetTextEntry.h"
#include "GameClient/GadgetStaticText.h"
#include "GameClient/GameClient.h"
#include "GameClient/GameText.h"
#include "GameClient/GUICallbacks.h"
#include "GameClient/InGameUI.h"
#include "GameClient/LanguageFilter.h"
#include "GameLogic/GameLogic.h"
#include "GameNetwork/GameInfo.h"
#include "GameNetwork/NetworkInterface.h"
static GameWindow *chatWindow = NULL;
static GameWindow *chatTextEntry = NULL;
static GameWindow *chatTypeStaticText = NULL;
static UnicodeString s_savedChat;
static InGameChatType inGameChatType;
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
void ShowInGameChat( Bool immediate )
{
#if !defined(_PLAYTEST)
if (TheGameLogic->isInReplayGame())
return;
#endif
if (TheInGameUI->isQuitMenuVisible())
return;
if (TheDisconnectMenu && TheDisconnectMenu->isScreenVisible())
return;
if (chatWindow)
{
chatWindow->winHide(FALSE);
chatWindow->winEnable(TRUE);
chatTextEntry->winHide(FALSE);
chatTextEntry->winEnable(TRUE);
GadgetTextEntrySetText( chatTextEntry, s_savedChat );
s_savedChat.clear();
}
else
{
chatWindow = TheWindowManager->winCreateFromScript( AsciiString("InGameChat.wnd") );
static NameKeyType textEntryChatID = TheNameKeyGenerator->nameToKey( "InGameChat.wnd:TextEntryChat" );
chatTextEntry = TheWindowManager->winGetWindowFromId( NULL, textEntryChatID );
GadgetTextEntrySetText( chatTextEntry, UnicodeString::TheEmptyString );
static NameKeyType chatTypeStaticTextID = TheNameKeyGenerator->nameToKey( "InGameChat.wnd:StaticTextChatType" );
chatTypeStaticText = TheWindowManager->winGetWindowFromId( NULL, chatTypeStaticTextID );
}
TheWindowManager->winSetFocus( chatTextEntry );
SetInGameChatType( INGAME_CHAT_EVERYONE );
}
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
void ResetInGameChat( void )
{
if(chatWindow)
TheWindowManager->winDestroy( chatWindow );
chatWindow = NULL;
chatTextEntry = NULL;
chatTypeStaticText = NULL;
s_savedChat.clear();
}
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
void HideInGameChat( Bool immediate )
{
if (chatWindow)
{
s_savedChat = GadgetTextEntryGetText( chatTextEntry );
chatWindow->winHide(TRUE);
chatWindow->winEnable(FALSE);
chatTextEntry->winHide(TRUE);
chatTextEntry->winEnable(FALSE);
TheWindowManager->winSetFocus( NULL );
}
TheWindowManager->winSetFocus( NULL );
}
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
void SetInGameChatType( InGameChatType chatType )
{
inGameChatType = chatType;
if (chatTypeStaticText)
{
switch (inGameChatType)
{
case INGAME_CHAT_EVERYONE:
if (ThePlayerList->getLocalPlayer()->isPlayerActive())
GadgetStaticTextSetText( chatTypeStaticText, TheGameText->fetch("Chat:Everyone") );
else
GadgetStaticTextSetText( chatTypeStaticText, TheGameText->fetch("Chat:Observers") );
break;
case INGAME_CHAT_ALLIES:
GadgetStaticTextSetText( chatTypeStaticText, TheGameText->fetch("Chat:Allies") );
break;
case INGAME_CHAT_PLAYERS:
GadgetStaticTextSetText( chatTypeStaticText, TheGameText->fetch("Chat:Players") );
break;
}
}
}
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
Bool IsInGameChatActive() {
if (chatWindow != NULL) {
if (chatWindow->winIsHidden() == FALSE) {
return TRUE;
}
}
return FALSE;
}
// Slash commands -------------------------------------------------------------------------
extern "C" {
int getQR2HostingStatus(void);
}
extern int isThreadHosting;
Bool handleInGameSlashCommands(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);
TheInGameUI->message(s);
return TRUE; // was a slash command
}
return FALSE; // not a slash command
}
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
void ToggleInGameChat( Bool immediate )
{
static Bool justHid = false;
if (justHid)
{
justHid = false;
return;
}
#if !defined(_PLAYTEST)
if (TheGameLogic->isInReplayGame())
return;
#endif
if (!TheGameInfo->isMultiPlayer() && TheGlobalData->m_netMinPlayers)
return;
if (chatWindow)
{
Bool show = chatWindow->winIsHidden();
if (show)
ShowInGameChat( immediate );
else
{
if (chatTextEntry)
{
// Send what is there, clear it out, and hide the window
UnicodeString msg = GadgetTextEntryGetText( chatTextEntry );
msg.trim();
if (!msg.isEmpty() && !handleInGameSlashCommands(msg))
{
const Player *localPlayer = ThePlayerList->getLocalPlayer();
AsciiString playerName;
Int playerMask = 0;
for (Int i=0; i<MAX_SLOTS; ++i)
{
playerName.format("player%d", i);
const Player *player = ThePlayerList->findPlayerWithNameKey( TheNameKeyGenerator->nameToKey( playerName ) );
if (player && localPlayer)
{
switch (inGameChatType)
{
case INGAME_CHAT_EVERYONE:
if (!TheGameInfo->getConstSlot(i)->isMuted())
playerMask |= (1<<i);
break;
case INGAME_CHAT_ALLIES:
if ( (player->getRelationship(localPlayer->getDefaultTeam()) == ALLIES &&
localPlayer->getRelationship(player->getDefaultTeam()) == ALLIES) || player==localPlayer )
playerMask |= (1<<i);
break;
case INGAME_CHAT_PLAYERS:
if ( player == localPlayer )
playerMask |= (1<<i);
break;
}
}
}
TheLanguageFilter->filterLine(msg);
TheNetwork->sendChat(msg, playerMask);
}
GadgetTextEntrySetText( chatTextEntry, UnicodeString::TheEmptyString );
HideInGameChat( immediate );
justHid = true;
}
}
}
else
{
ShowInGameChat( immediate );
}
}
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType InGameChatInput( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
switch( msg )
{
// --------------------------------------------------------------------------------------------
case GWM_CHAR:
{
UnsignedByte key = mData1;
// UnsignedByte state = mData2;
switch( key )
{
// ----------------------------------------------------------------------------------------
case KEY_ESC:
{
HideInGameChat();
return MSG_HANDLED;
//return MSG_IGNORED;
} // end escape
} // end switch( key )
return MSG_HANDLED;
} // end char
}
return MSG_IGNORED;
} // end InGameChatInput
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType InGameChatSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
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 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 GEM_EDIT_DONE:
{
ToggleInGameChat();
//HideInGameChat();
break;
} // end button selected
//---------------------------------------------------------------------------------------------
case GBM_SELECTED:
{
GameWindow *control = (GameWindow *)mData1;
static NameKeyType buttonClearID = TheNameKeyGenerator->nameToKey( AsciiString( "InGameChat.wnd:ButtonClear" ) );
if (control && control->winGetWindowId() == buttonClearID)
{
if (chatTextEntry)
GadgetTextEntrySetText( chatTextEntry, UnicodeString::TheEmptyString );
s_savedChat.clear();
}
break;
} // end button selected
//---------------------------------------------------------------------------------------------
default:
return MSG_IGNORED;
} // end switch( msg )
return MSG_HANDLED;
} // end InGameChatSystem

View File

@@ -0,0 +1,250 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: InGamePopupMessage.cpp /////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Electronic Arts Pacific.
//
// Confidential Information
// Copyright (C) 2002 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// created: Jul 2002
//
// Filename: InGamePopupMessage.cpp
//
// author: Chris Huybregts
//
// purpose: Init, input, and system for the in game message popup
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// USER INCLUDES //////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/GlobalData.h"
#include "Common/NameKeyGenerator.h"
#include "Common/Version.h"
#include "Common/MessageStream.h"
#include "GameClient/WindowLayout.h"
#include "GameClient/Gadget.h"
#include "GameClient/GadgetStaticText.h"
#include "GameClient/KeyDefs.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/InGameUI.h"
#include "GameClient/DisplayStringManager.h"
//-----------------------------------------------------------------------------
// DEFINES ////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
static NameKeyType parentID = NAMEKEY_INVALID;
static NameKeyType staticTextMessageID = NAMEKEY_INVALID;
static NameKeyType buttonOkID = NAMEKEY_INVALID;
static GameWindow *parent = NULL;
static GameWindow *staticTextMessage = NULL;
static GameWindow *buttonOk = NULL;
static Bool pause = FALSE;
//-----------------------------------------------------------------------------
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
/** Initialize the InGamePopupMessageInit menu */
//-------------------------------------------------------------------------------------------------
void InGamePopupMessageInit( WindowLayout *layout, void *userData )
{
parentID = TheNameKeyGenerator->nameToKey(AsciiString("InGamePopupMessage.wnd:InGamePopupMessageParent"));
parent = TheWindowManager->winGetWindowFromId(NULL, parentID);
staticTextMessageID = TheNameKeyGenerator->nameToKey(AsciiString("InGamePopupMessage.wnd:StaticTextMessage"));
staticTextMessage = TheWindowManager->winGetWindowFromId(parent, staticTextMessageID);
buttonOkID = TheNameKeyGenerator->nameToKey(AsciiString("InGamePopupMessage.wnd:ButtonOk"));
buttonOk = TheWindowManager->winGetWindowFromId(parent, buttonOkID);
PopupMessageData *pMData = TheInGameUI->getPopupMessageData();
if(!pMData)
{
DEBUG_ASSERTCRASH(pMData, ("We're in InGamePopupMessage without a pointer to pMData\n") );
///< @todo: add a call to the close this bitch method when I implement it CLH
return;
}
DisplayString *tempString = TheDisplayStringManager->newDisplayString();
tempString->setText(pMData->message);
tempString->setFont(staticTextMessage->winGetFont());
tempString->setWordWrap(pMData->width - 14);
Int width, height;
tempString->getSize(&width, &height);
TheDisplayStringManager->freeDisplayString(tempString);
GadgetStaticTextSetText(staticTextMessage, pMData->message);
// set the positions/sizes
Int widthOk, heightOk;
buttonOk->winGetSize(&widthOk, &heightOk);
parent->winSetPosition( pMData->x, pMData->y);
parent->winSetSize( pMData->width, height + 7 + 2 + 2 + heightOk + 2 );
staticTextMessage->winSetPosition( 2, 2);
staticTextMessage->winSetSize( pMData->width - 4, height + 7);
buttonOk->winSetPosition(pMData->width - widthOk - 2, height + 7 + 2 + 2);
staticTextMessage->winSetEnabledTextColors(pMData->textColor, 0);
pause = pMData->pause;
if(pMData->pause)
TheWindowManager->winSetModal( parent );
TheWindowManager->winSetFocus( parent );
parent->winHide(FALSE);
parent->winBringToTop();
}
//-------------------------------------------------------------------------------------------------
/** InGamePopupMessageInput callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType InGamePopupMessageInput( 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_ENTER:
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)buttonOk, buttonOkID );
} // 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;
}
//-------------------------------------------------------------------------------------------------
/** InGamePopupMessageSystem callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType InGamePopupMessageSystem( GameWindow *window, UnsignedInt msg, WindowMsgData mData1, WindowMsgData mData2 )
{
switch( msg )
{
// --------------------------------------------------------------------------------------------
case GWM_CREATE:
{
break;
} // end create
//---------------------------------------------------------------------------------------------
case GWM_DESTROY:
{
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;
break;
} // end input
//---------------------------------------------------------------------------------------------
case GBM_SELECTED:
{
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if( controlID == buttonOkID )
{
if(!pause)
TheMessageStream->appendMessage( GameMessage::MSG_CLEAR_INGAME_POPUP_MESSAGE );
else
TheInGameUI->clearPopupMessageData();
}
break;
}
default:
return MSG_IGNORED;
} // end switch
return MSG_HANDLED;
}
//-----------------------------------------------------------------------------
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------

View File

@@ -0,0 +1,256 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: CreditsMenu.cpp /////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Electronic Arts Pacific.
//
// Confidential Information
// Copyright (C) 2002 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// created: Dec 2002
//
// Filename: CreditsMenu.cpp
//
// author: Chris Huybregts
//
// purpose: The credits screen...yay
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma message("************************************** WARNING, optimization disabled for debugging purposes")
#endif
//-----------------------------------------------------------------------------
// USER INCLUDES //////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
#include "Common/GameAudio.h"
#include "Common/AudioEventRTS.h"
#include "Common/AudioHandleSpecialValues.h"
#include "GameClient/Credits.h"
#include "GameClient/WindowLayout.h"
#include "GameClient/Gadget.h"
#include "GameClient/Shell.h"
#include "GameClient/KeyDefs.h"
#include "GameClient/GameWindowManager.h"
//-----------------------------------------------------------------------------
// DEFINES ////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
static NameKeyType parentMainMenuID = NAMEKEY_INVALID;
// window pointers --------------------------------------------------------------------------------
static GameWindow *parentMainMenu = NULL;
//-----------------------------------------------------------------------------
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
/** Initialize the single player menu */
//-------------------------------------------------------------------------------------------------
void CreditsMenuInit( WindowLayout *layout, void *userData )
{
TheShell->showShellMap(FALSE);
if(TheCredits)
delete TheCredits;
TheCredits = new CreditsManager;
TheCredits->load();
TheCredits->init();
parentMainMenuID = TheNameKeyGenerator->nameToKey( AsciiString("CreditsMenu.wnd:ParentCreditsWindow") );
parentMainMenu = TheWindowManager->winGetWindowFromId( NULL, parentMainMenuID );
// show menu
layout->hide( FALSE );
// set keyboard focus to main parent
TheWindowManager->winSetFocus( parentMainMenu );
TheAudio->removeAudioEvent( AHSV_StopTheMusicFade );
AudioEventRTS event( AsciiString( "Credits" ) );
event.setShouldFade( TRUE );
TheAudio->addAudioEvent( &event );
} // end CreditsMenuInit
//-------------------------------------------------------------------------------------------------
/** single player menu shutdown method */
//-------------------------------------------------------------------------------------------------
void CreditsMenuShutdown( WindowLayout *layout, void *userData )
{
TheCredits->reset();
delete TheCredits;
TheCredits = NULL;
TheShell->showShellMap(TRUE);
// hide menu
layout->hide( TRUE );
// our shutdown is complete
TheShell->shutdownComplete( layout );
TheAudio->removeAudioEvent( AHSV_StopTheMusicFade );
} // end CreditsMenuShutdown
//-------------------------------------------------------------------------------------------------
/** single player menu update method */
//-------------------------------------------------------------------------------------------------
void CreditsMenuUpdate( WindowLayout *layout, void *userData )
{
if(TheCredits)
{
TheWindowManager->winSetFocus( parentMainMenu );
TheCredits->update();
if(TheCredits->isFinished())
TheShell->pop();
}
else
TheShell->pop();
} // end CreditsMenuUpdate
//-------------------------------------------------------------------------------------------------
/** Replay menu input callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType CreditsMenuInput( 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 ) )
{
TheShell->pop();
} // 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 CreditsMenuInput
//-------------------------------------------------------------------------------------------------
/** single player menu window system callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType CreditsMenuSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
switch( msg )
{
// --------------------------------------------------------------------------------------------
case GWM_CREATE:
{
break;
} // end create
//---------------------------------------------------------------------------------------------
case GWM_DESTROY:
{
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 GBM_SELECTED:
{
break;
} // end selected
default:
return MSG_IGNORED;
} // end switch
return MSG_HANDLED;
} // end CreditsMenuSystem
//-----------------------------------------------------------------------------
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------

View File

@@ -0,0 +1,303 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: DifficultySelect.cpp /////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Electronic Arts Pacific.
//
// Confidential Information
// Copyright (C) 2002 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// created: Nov 2002
//
// Filename: DifficultySelect.cpp
//
// author: Chris Huybregts
//
// purpose: The popup campaign difficulty select
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
//-----------------------------------------------------------------------------
// USER INCLUDES //////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
#include "Common/UserPreferences.h"
#include "GameClient/WindowLayout.h"
#include "GameClient/Gadget.h"
#include "GameClient/Shell.h"
#include "GameClient/KeyDefs.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/GadgetPushButton.h"
#include "GameClient/GadgetRadioButton.h"
#include "GameClient/CampaignManager.h"
#include "GameLogic/ScriptEngine.h"
//-----------------------------------------------------------------------------
// DEFINES ////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
static GameDifficulty s_AIDiff = DIFFICULTY_NORMAL;
static NameKeyType buttonOkID = NAMEKEY_INVALID;
static GameWindow * buttonOk = NULL;
static NameKeyType buttonCancelID = NAMEKEY_INVALID;
static GameWindow * buttonCancel = NULL;
static NameKeyType radioButtonEasyAIID = NAMEKEY_INVALID;
static NameKeyType radioButtonMediumAIID = NAMEKEY_INVALID;
static NameKeyType radioButtonHardAIID = NAMEKEY_INVALID;
static GameWindow * radioButtonEasyAI = NULL;
static GameWindow * radioButtonMediumAI = NULL;
static GameWindow * radioButtonHardAI = NULL;
void setupGameStart(AsciiString mapName, GameDifficulty diff);
//-----------------------------------------------------------------------------
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
static void SetDifficultyRadioButton( void )
{
OptionPreferences pref;
if (!TheScriptEngine)
{
s_AIDiff = DIFFICULTY_NORMAL;
}
else
{
switch (pref.getCampaignDifficulty())
{
case DIFFICULTY_EASY:
{
GadgetRadioSetSelection(radioButtonEasyAI, FALSE);
s_AIDiff = DIFFICULTY_EASY;
break;
}
case DIFFICULTY_NORMAL:
{
GadgetRadioSetSelection(radioButtonMediumAI, FALSE);
s_AIDiff = DIFFICULTY_NORMAL;
break;
}
case DIFFICULTY_HARD:
{
GadgetRadioSetSelection(radioButtonHardAI, FALSE);
s_AIDiff = DIFFICULTY_HARD;
break;
}
default:
{
DEBUG_CRASH(("unrecognized difficulty level in the script engine"));
}
}
} // if (TheScriptEngine)
}
void DifficultySelectInit( WindowLayout *layout, void *userData )
{
AsciiString parentName( "DifficultySelect.wnd:DifficultySelectParent" );
NameKeyType parentID = TheNameKeyGenerator->nameToKey( parentName );
GameWindow *parent = TheWindowManager->winGetWindowFromId( NULL, parentID );
buttonOkID = TheNameKeyGenerator->nameToKey( "DifficultySelect.wnd:ButtonOk" );
buttonOk = TheWindowManager->winGetWindowFromId( parent, buttonOkID );
buttonCancelID = TheNameKeyGenerator->nameToKey( "DifficultySelect.wnd:ButtonCancel" );
buttonCancel = TheWindowManager->winGetWindowFromId( parent, buttonCancelID );
radioButtonEasyAIID = TheNameKeyGenerator->nameToKey( AsciiString("DifficultySelect.wnd:RadioButtonEasy") );
radioButtonEasyAI = TheWindowManager->winGetWindowFromId( parent, radioButtonEasyAIID );
radioButtonMediumAIID = TheNameKeyGenerator->nameToKey( AsciiString("DifficultySelect.wnd:RadioButtonMedium") );
radioButtonMediumAI = TheWindowManager->winGetWindowFromId( parent, radioButtonMediumAIID );
radioButtonHardAIID = TheNameKeyGenerator->nameToKey( AsciiString("DifficultySelect.wnd:RadioButtonHard") );
radioButtonHardAI = TheWindowManager->winGetWindowFromId( parent, radioButtonHardAIID );
s_AIDiff = DIFFICULTY_NORMAL;
SetDifficultyRadioButton();
// set keyboard focus to main parent
// AsciiString parentName( "SkirmishMapSelectMenu.wnd:SkrimishMapSelectMenuParent" );
// NameKeyType parentID = TheNameKeyGenerator->nameToKey( parentName );
// parent = TheWindowManager->winGetWindowFromId( NULL, parentID );
//
// TheWindowManager->winSetFocus( parent );
//
parent->winBringToTop();
TheWindowManager->winSetModal(parent);
} // end SkirmishMapSelectMenuInit
//-------------------------------------------------------------------------------------------------
/** Map select menu input callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType DifficultySelectInput( 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( "SkirmishMapSelectMenu.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 SkirmishMapSelectMenuInput
//-------------------------------------------------------------------------------------------------
/** MapSelect menu window system callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType DifficultySelectSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
switch( msg )
{
// --------------------------------------------------------------------------------------------
case GWM_CREATE:
{
break;
} // end create
//---------------------------------------------------------------------------------------------
case GWM_DESTROY:
{
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 GBM_SELECTED:
{
// this isn't fixed yet
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if ( controlID == buttonOkID )
{
OptionPreferences pref;
pref.setCampaignDifficulty(s_AIDiff);
pref.write();
//TheScriptEngine->setGlobalDifficulty(s_AIDiff); // CANNOT DO THIS! REPLAYS WILL BREAK!
WindowLayout *layout = window->winGetLayout();
layout->destroyWindows();
layout->deleteInstance();
setupGameStart(TheCampaignManager->getCurrentMap(), s_AIDiff);
// start the game
}
else if ( controlID == buttonCancelID )
{
TheCampaignManager->setCampaign( AsciiString::TheEmptyString );
TheWindowManager->winUnsetModal(window);
WindowLayout *layout = window->winGetLayout();
layout->destroyWindows();
layout->deleteInstance();
}
else if ( controlID == radioButtonEasyAIID )
{
s_AIDiff = DIFFICULTY_EASY;
}
else if ( controlID == radioButtonMediumAIID )
{
s_AIDiff = DIFFICULTY_NORMAL;
}
else if ( controlID == radioButtonHardAIID )
{
s_AIDiff = DIFFICULTY_HARD;
}
break;
} // end selected
default:
return MSG_IGNORED;
} // end switch
return MSG_HANDLED;
}
//-----------------------------------------------------------------------------
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------

View File

@@ -0,0 +1,286 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: DisconnectControls.cpp ///////////////////////////////////////////////////////////////////////
// Author: Bryan Cleveland - March 2001
// Desc: GUI menu for network disconnects
///////////////////////////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "GameClient/GameWindow.h"
#include "GameClient/GameText.h"
#include "GameClient/Gadget.h"
#include "GameClient/GadgetTextEntry.h"
#include "GameClient/GadgetListBox.h"
#include "GameClient/GameClient.h"
#include "GameClient/DisconnectMenu.h"
#include "GameClient/GameWindowManager.h"
#include "Common/NameKeyGenerator.h"
#include "GameNetwork/GameInfo.h"
// Private Data -----------------------------
static WindowLayout *disconnectMenuLayout;
static NameKeyType textEntryID = NAMEKEY_INVALID;
static NameKeyType textDisplayID = NAMEKEY_INVALID;
static GameWindow *textEntryWindow = NULL;
static GameWindow *textDisplayWindow = NULL;
static NameKeyType buttonQuitID = NAMEKEY_INVALID;
static GameWindow *buttonQuitWindow = NULL;
static NameKeyType buttonVotePlayer1ID = NAMEKEY_INVALID;
static NameKeyType buttonVotePlayer2ID = NAMEKEY_INVALID;
static NameKeyType buttonVotePlayer3ID = NAMEKEY_INVALID;
static NameKeyType buttonVotePlayer4ID = NAMEKEY_INVALID;
static NameKeyType buttonVotePlayer5ID = NAMEKEY_INVALID;
static NameKeyType buttonVotePlayer6ID = NAMEKEY_INVALID;
static NameKeyType buttonVotePlayer7ID = NAMEKEY_INVALID;
static GameWindow *buttonVotePlayer1Window = NULL;
static GameWindow *buttonVotePlayer2Window = NULL;
static GameWindow *buttonVotePlayer3Window = NULL;
static GameWindow *buttonVotePlayer4Window = NULL;
static GameWindow *buttonVotePlayer5Window = NULL;
static GameWindow *buttonVotePlayer6Window = NULL;
static GameWindow *buttonVotePlayer7Window = NULL;
static void InitDisconnectWindow( void ) {
textEntryID = TheNameKeyGenerator->nameToKey( AsciiString("DisconnectScreen.wnd:TextEntry"));
textDisplayID = TheNameKeyGenerator->nameToKey( AsciiString("DisconnectScreen.wnd:ListboxTextDisplay"));
textEntryWindow = TheWindowManager->winGetWindowFromId(NULL, textEntryID);
textDisplayWindow = TheWindowManager->winGetWindowFromId(NULL, textDisplayID);
if (textEntryWindow != NULL) {
GadgetTextEntrySetText(textEntryWindow, UnicodeString::TheEmptyString);
TheWindowManager->winSetFocus(textEntryWindow);
}
buttonQuitID = TheNameKeyGenerator->nameToKey( AsciiString("DisconnectScreen.wnd:ButtonQuitGame"));
buttonQuitWindow = TheWindowManager->winGetWindowFromId(NULL, buttonQuitID);
buttonVotePlayer1ID = TheNameKeyGenerator->nameToKey( AsciiString("DisconnectScreen.wnd:ButtonKickPlayer1"));
buttonVotePlayer2ID = TheNameKeyGenerator->nameToKey( AsciiString("DisconnectScreen.wnd:ButtonKickPlayer2"));
buttonVotePlayer3ID = TheNameKeyGenerator->nameToKey( AsciiString("DisconnectScreen.wnd:ButtonKickPlayer3"));
buttonVotePlayer4ID = TheNameKeyGenerator->nameToKey( AsciiString("DisconnectScreen.wnd:ButtonKickPlayer4"));
buttonVotePlayer5ID = TheNameKeyGenerator->nameToKey( AsciiString("DisconnectScreen.wnd:ButtonKickPlayer5"));
buttonVotePlayer6ID = TheNameKeyGenerator->nameToKey( AsciiString("DisconnectScreen.wnd:ButtonKickPlayer6"));
buttonVotePlayer7ID = TheNameKeyGenerator->nameToKey( AsciiString("DisconnectScreen.wnd:ButtonKickPlayer7"));
buttonVotePlayer1Window = TheWindowManager->winGetWindowFromId(NULL, buttonVotePlayer1ID);
buttonVotePlayer2Window = TheWindowManager->winGetWindowFromId(NULL, buttonVotePlayer2ID);
buttonVotePlayer3Window = TheWindowManager->winGetWindowFromId(NULL, buttonVotePlayer3ID);
buttonVotePlayer4Window = TheWindowManager->winGetWindowFromId(NULL, buttonVotePlayer4ID);
buttonVotePlayer5Window = TheWindowManager->winGetWindowFromId(NULL, buttonVotePlayer5ID);
buttonVotePlayer6Window = TheWindowManager->winGetWindowFromId(NULL, buttonVotePlayer6ID);
buttonVotePlayer7Window = TheWindowManager->winGetWindowFromId(NULL, buttonVotePlayer7ID);
}
//------------------------------------------------------
/** Show the Disconnect Screen */
//------------------------------------------------------
void ShowDisconnectWindow( void )
{
// load the quit menu from the layout file if needed
if( disconnectMenuLayout == NULL )
{
// load layout from disk
disconnectMenuLayout = TheWindowManager->winCreateLayout( "Menus/DisconnectScreen.wnd" );
// init it
InitDisconnectWindow();
// show it
disconnectMenuLayout->hide( FALSE );
} // end if
else
{
disconnectMenuLayout->hide( FALSE );
} // end else
// Disallow voting for 2-player games. Cheating punk.
if ( TheGameInfo && TheGameInfo->getNumPlayers() < 3 )
{
buttonVotePlayer1Window->winEnable(FALSE);
buttonVotePlayer2Window->winEnable(FALSE);
buttonVotePlayer3Window->winEnable(FALSE);
buttonVotePlayer4Window->winEnable(FALSE);
buttonVotePlayer5Window->winEnable(FALSE);
buttonVotePlayer6Window->winEnable(FALSE);
buttonVotePlayer7Window->winEnable(FALSE);
}
else
{
buttonVotePlayer1Window->winEnable(TRUE);
buttonVotePlayer2Window->winEnable(TRUE);
buttonVotePlayer3Window->winEnable(TRUE);
buttonVotePlayer4Window->winEnable(TRUE);
buttonVotePlayer5Window->winEnable(TRUE);
buttonVotePlayer6Window->winEnable(TRUE);
buttonVotePlayer7Window->winEnable(TRUE);
}
buttonQuitWindow->winEnable(TRUE);
disconnectMenuLayout->bringForward();
GadgetListBoxReset(textDisplayWindow);
GadgetListBoxAddEntryText(textDisplayWindow, TheGameText->fetch("GUI:InternetDisconnectionMenuBody1"),
GameMakeColor(255,255,255,255), -1);
} // end ToggleQuitMenu
//------------------------------------------------------
/** Hide the Disconnect Screen */
//------------------------------------------------------
void HideDisconnectWindow( void )
{
// load the quit menu from the layout file if needed
if( disconnectMenuLayout == NULL )
{
// load layout from disk
disconnectMenuLayout = TheWindowManager->winCreateLayout( "Menus/DisconnectScreen.wnd" );
// init it
InitDisconnectWindow();
// show it
disconnectMenuLayout->hide( TRUE );
} // end if
else
{
disconnectMenuLayout->hide( TRUE );
} // end else
} // end ToggleQuitMenu
//-------------------------------------------------------------------------------------------------
/** Input callback for the control bar parent */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType DisconnectControlInput( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
return MSG_IGNORED;
} // end DisconnectControlInput
//-------------------------------------------------------------------------------------------------
/** System callback for the control bar parent */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType DisconnectControlSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
switch( msg )
{
//---------------------------------------------------------------------------------------------
case GBM_SELECTED:
{
GameWindow *control = (GameWindow *) mData1;
Int controlID = control->winGetWindowId();
if (controlID == buttonQuitID) {
TheDisconnectMenu->quitGame();
buttonQuitWindow->winEnable(FALSE);
} else if (controlID == buttonVotePlayer1ID) {
TheDisconnectMenu->voteForPlayer(0);
buttonVotePlayer1Window->winEnable(FALSE);
} else if (controlID == buttonVotePlayer2ID) {
TheDisconnectMenu->voteForPlayer(1);
buttonVotePlayer2Window->winEnable(FALSE);
} else if (controlID == buttonVotePlayer3ID) {
TheDisconnectMenu->voteForPlayer(2);
buttonVotePlayer3Window->winEnable(FALSE);
} else if (controlID == buttonVotePlayer4ID) {
TheDisconnectMenu->voteForPlayer(3);
buttonVotePlayer4Window->winEnable(FALSE);
} else if (controlID == buttonVotePlayer5ID) {
TheDisconnectMenu->voteForPlayer(4);
buttonVotePlayer5Window->winEnable(FALSE);
} else if (controlID == buttonVotePlayer6ID) {
TheDisconnectMenu->voteForPlayer(5);
buttonVotePlayer6Window->winEnable(FALSE);
} else if (controlID == buttonVotePlayer7ID) {
TheDisconnectMenu->voteForPlayer(6);
buttonVotePlayer7Window->winEnable(FALSE);
}
break;
} // end button selected
case GEM_EDIT_DONE:
{
// DEBUG_LOG(("DisconnectControlSystem - got GEM_EDIT_DONE.\n"));
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
// Take the user's input and echo it into the chat window as well as
// send it to the other clients on the lan
if ( controlID == textEntryID )
{
UnicodeString txtInput;
// DEBUG_LOG(("DisconnectControlSystem - GEM_EDIT_DONE was from the text entry control.\n"));
// read the user's input
txtInput.set(GadgetTextEntryGetText( textEntryWindow ));
// Clear the text entry line
GadgetTextEntrySetText(textEntryWindow, UnicodeString::TheEmptyString);
// Clean up the text (remove leading/trailing chars, etc)
txtInput.trim();
// Echo the user's input to the chat window
if (!txtInput.isEmpty()) {
// DEBUG_LOG(("DisconnectControlSystem - sending string %ls\n", txtInput.str()));
TheDisconnectMenu->sendChat(txtInput);
}
}// if ( controlID == textEntryChatID )
break;
}
//---------------------------------------------------------------------------------------------
default:
return MSG_IGNORED;
} // end switch( msg )
return MSG_HANDLED;
} // end ControlBarSystem

View File

@@ -0,0 +1,436 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: DownloadMenu.cpp /////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Electronic Arts Pacific.
//
// Confidential Information
// Copyright (C) 2002 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// Project: RTS3
//
// File name: DownloadMenu.cpp
//
// Created: Matthew D. Campbell, July 2002
//
// Desc: the Patch Download window control
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/GameEngine.h"
#include "Common/NameKeyGenerator.h"
#include "GameClient/GUICallbacks.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/GadgetStaticText.h"
#include "GameClient/GadgetProgressBar.h"
#include "GameClient/GameText.h"
#include "GameClient/MessageBox.h"
#include "GameLogic/GameLogic.h"
#include "GameNetwork/DownloadManager.h"
#include "GameNetwork/GameSpy/MainMenuUtils.h"
// PRIVATE DATA ///////////////////////////////////////////////////////////////////////////////////
static NameKeyType buttonCancelID = NAMEKEY_INVALID;
static NameKeyType staticTextSizeID = NAMEKEY_INVALID;
static NameKeyType staticTextTimeID = NAMEKEY_INVALID;
static NameKeyType staticTextFileID = NAMEKEY_INVALID;
static NameKeyType staticTextStatusID = NAMEKEY_INVALID;
static NameKeyType progressBarMunkeeID = NAMEKEY_INVALID;
static GameWindow * staticTextSize = NULL;
static GameWindow * staticTextTime = NULL;
static GameWindow * staticTextFile = NULL;
static GameWindow * staticTextStatus = NULL;
static GameWindow * progressBarMunkee = NULL;
static GameWindow *parent = NULL;
static void closeDownloadWindow( void )
{
DEBUG_ASSERTCRASH(parent, ("No Parent"));
if (!parent)
return;
WindowLayout *menuLayout = parent->winGetLayout();
menuLayout->runShutdown();
menuLayout->destroyWindows();
menuLayout->deleteInstance();
menuLayout = NULL;
GameWindow *mainWin = TheWindowManager->winGetWindowFromId( NULL, NAMEKEY("MainMenu.wnd:MainMenuParent") );
if (mainWin)
TheWindowManager->winSetFocus( mainWin );
}
static void errorCallback( void )
{
HandleCanceledDownload();
closeDownloadWindow();
}
static void successQuitCallback( void )
{
TheGameEngine->setQuitting( TRUE );
closeDownloadWindow();
// Clean up game data. No crashy-crash for you!
if (TheGameLogic->isInGame())
TheMessageStream->appendMessage( GameMessage::MSG_CLEAR_GAME_DATA );
}
static void successNoQuitCallback( void )
{
HandleCanceledDownload();
closeDownloadWindow();
}
class DownloadManagerMunkee : public DownloadManager
{
public:
DownloadManagerMunkee() {m_shouldQuitOnSuccess = true; m_shouldQuitOnSuccess = false;}
virtual HRESULT OnError( Int error );
virtual HRESULT OnEnd();
virtual HRESULT OnProgressUpdate( Int bytesread, Int totalsize, Int timetaken, Int timeleft );
virtual HRESULT OnStatusUpdate( Int status );
virtual HRESULT downloadFile( AsciiString server, AsciiString username, AsciiString password, AsciiString file, AsciiString localfile, AsciiString regkey, Bool tryResume );
private:
Bool m_shouldQuitOnSuccess;
};
HRESULT DownloadManagerMunkee::downloadFile( AsciiString server, AsciiString username, AsciiString password, AsciiString file, AsciiString localfile, AsciiString regkey, Bool tryResume )
{
// see if we'll need to restart
if (strstr(localfile.str(), "patches\\") != NULL)
{
m_shouldQuitOnSuccess = true;
}
if (staticTextFile)
{
AsciiString bob = file;
// just get the filename, not the pathname
const char *tmp = bob.reverseFind('/');
if (tmp)
bob = tmp+1;
tmp = bob.reverseFind('\\');
if (tmp)
bob = tmp+1;
UnicodeString fileString;
fileString.translate(bob);
GadgetStaticTextSetText(staticTextFile, fileString);
}
password.format("-%s", password.str());
return DownloadManager::downloadFile( server, username, password, file, localfile, regkey, tryResume );
}
HRESULT DownloadManagerMunkee::OnError( Int error )
{
HRESULT ret = DownloadManager::OnError( error );
MessageBoxOk(TheGameText->fetch("GUI:DownloadErrorTitle"), getErrorString(), errorCallback);
return ret;
}
HRESULT DownloadManagerMunkee::OnEnd()
{
HRESULT ret = DownloadManager::OnEnd();
if (isFileQueuedForDownload())
{
return downloadNextQueuedFile();
}
if (m_shouldQuitOnSuccess)
MessageBoxOk(TheGameText->fetch("GUI:DownloadSuccessTitle"), TheGameText->fetch("GUI:DownloadSuccessMustQuit"), successQuitCallback);
else
MessageBoxOk(TheGameText->fetch("GUI:DownloadSuccessTitle"), TheGameText->fetch("GUI:DownloadSuccess"), successNoQuitCallback);
return ret;
}
static time_t lastUpdate = 0;
static Int timeLeft = 0;
HRESULT DownloadManagerMunkee::OnProgressUpdate( Int bytesread, Int totalsize, Int timetaken, Int timeleft )
{
HRESULT ret = DownloadManager::OnProgressUpdate( bytesread, totalsize, timetaken, timeleft );
if (progressBarMunkee)
{
Int percent = bytesread * 100 / totalsize;
GadgetProgressBarSetProgress( progressBarMunkee, percent );
}
if (staticTextSize)
{
UnicodeString sizeString;
sizeString.format(TheGameText->fetch("GUI:DownloadBytesRatio"), bytesread, totalsize);
GadgetStaticTextSetText(staticTextSize, sizeString);
}
timeLeft = timeleft;
if (staticTextTime && GadgetStaticTextGetText(staticTextTime).isEmpty()) // only update immediately the first time
{
lastUpdate = time(NULL);
UnicodeString timeString;
if (timeleft)
{
DEBUG_ASSERTCRASH(timeleft > 0, ("Time left is negative!"));
timeleft = max(1, timeleft);
Int takenHour, takenMin, takenSec;
takenHour = timeleft / 60 / 60;
takenMin = timeleft / 60;
takenSec = timeleft % 60;
timeString.format(TheGameText->fetch("GUI:DownloadTimeLeft"), takenHour, takenMin, takenSec);
}
else
{
timeString = TheGameText->fetch("GUI:DownloadUnknownTime");
}
GadgetStaticTextSetText(staticTextTime, timeString);
}
return ret;
}
HRESULT DownloadManagerMunkee::OnStatusUpdate( Int status )
{
HRESULT ret = DownloadManager::OnStatusUpdate( status );
if (staticTextStatus)
{
GadgetStaticTextSetText(staticTextStatus, getStatusString());
}
return ret;
}
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------------------------
/** Initialize the menu */
//-------------------------------------------------------------------------------------------------
void DownloadMenuInit( WindowLayout *layout, void *userData )
{
//set keyboard focus to main parent and set modal
NameKeyType parentID = TheNameKeyGenerator->nameToKey("DownloadMenu.wnd:ParentDownload");
parent = TheWindowManager->winGetWindowFromId( NULL, parentID );
// get ids for our children controls
buttonCancelID = TheNameKeyGenerator->nameToKey( "DownloadMenu.wnd:ButtonCancel" );
staticTextSizeID = TheNameKeyGenerator->nameToKey( "DownloadMenu.wnd:StaticTextSize" );
staticTextTimeID = TheNameKeyGenerator->nameToKey( "DownloadMenu.wnd:StaticTextTime" );
staticTextFileID = TheNameKeyGenerator->nameToKey( "DownloadMenu.wnd:StaticTextFile" );
staticTextStatusID = TheNameKeyGenerator->nameToKey( "DownloadMenu.wnd:StaticTextStatus" );
progressBarMunkeeID = TheNameKeyGenerator->nameToKey( "DownloadMenu.wnd:ProgressBarMunkee" );
staticTextSize = TheWindowManager->winGetWindowFromId( parent, staticTextSizeID );
staticTextTime = TheWindowManager->winGetWindowFromId( parent, staticTextTimeID );
staticTextFile = TheWindowManager->winGetWindowFromId( parent, staticTextFileID );
staticTextStatus = TheWindowManager->winGetWindowFromId( parent, staticTextStatusID );
progressBarMunkee = TheWindowManager->winGetWindowFromId( parent, progressBarMunkeeID );
DEBUG_ASSERTCRASH(!TheDownloadManager, ("Download manager already exists"));
if (TheDownloadManager)
{
delete TheDownloadManager;
}
TheDownloadManager = NEW DownloadManagerMunkee;
} // end DownloadMenuInit
//-------------------------------------------------------------------------------------------------
/** menu shutdown method */
//-------------------------------------------------------------------------------------------------
void DownloadMenuShutdown( WindowLayout *layout, void *userData )
{
DEBUG_ASSERTCRASH(TheDownloadManager, ("No download manager"));
if (TheDownloadManager)
{
delete TheDownloadManager;
TheDownloadManager = NULL;
}
staticTextSize = NULL;
staticTextTime = NULL;
staticTextFile = NULL;
staticTextStatus = NULL;
progressBarMunkee = NULL;
parent = NULL;
} // end DownloadMenuShutdown
//-------------------------------------------------------------------------------------------------
/** menu update method */
//-------------------------------------------------------------------------------------------------
void DownloadMenuUpdate( WindowLayout *layout, void *userData )
{
if (staticTextTime && !GadgetStaticTextGetText(staticTextTime).isEmpty())
{
time_t now = time(NULL);
if (now <= lastUpdate)
return;
lastUpdate = now;
UnicodeString timeString;
if (timeLeft)
{
DEBUG_ASSERTCRASH(timeLeft > 0, ("Time left is negative!"));
timeLeft = max(1, timeLeft);
Int takenHour, takenMin, takenSec;
takenHour = timeLeft / 60 / 60;
takenMin = timeLeft / 60;
takenSec = timeLeft % 60;
timeString.format(TheGameText->fetch("GUI:DownloadTimeLeft"), takenHour, takenMin, takenSec);
}
else
{
timeString = TheGameText->fetch("GUI:DownloadUnknownTime");
}
GadgetStaticTextSetText(staticTextTime, timeString);
}
} // end DownloadMenuUpdate
//-------------------------------------------------------------------------------------------------
/** menu input callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType DownloadMenuInput( 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( "DownloadMenu.wnd:ButtonCancel" );
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 DownloadMenuInput
//-------------------------------------------------------------------------------------------------
/** menu window system callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType DownloadMenuSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
switch( msg )
{
// --------------------------------------------------------------------------------------------
case GWM_CREATE:
{
break;
} // end create
//---------------------------------------------------------------------------------------------
case GWM_DESTROY:
{
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;
break;
} // end input
//---------------------------------------------------------------------------------------------
case GBM_SELECTED:
{
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if( controlID == buttonCancelID )
{
HandleCanceledDownload();
closeDownloadWindow();
} // end if
break;
} // end selected
default:
return MSG_IGNORED;
} // end switch
return MSG_HANDLED;
} // end DownloadMenuSystem

View File

@@ -0,0 +1,194 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
///// EstablishConnectionsWindow.cpp /////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "GameClient/GameWindowManager.h"
#include "Common/NameKeyGenerator.h"
#include "GameClient/EstablishConnectionsMenu.h"
#include "GameNetwork/GUIUtil.h"
#include "GameNetwork/GameSpy/StagingRoomGameInfo.h"
static WindowLayout *establishConnectionsLayout;
static NameKeyType buttonQuitID = NAMEKEY_INVALID;
static NameKeyType staticPlayer1NameID = NAMEKEY_INVALID;
static NameKeyType staticPlayer2NameID = NAMEKEY_INVALID;
static NameKeyType staticPlayer3NameID = NAMEKEY_INVALID;
static NameKeyType staticPlayer4NameID = NAMEKEY_INVALID;
static NameKeyType staticPlayer5NameID = NAMEKEY_INVALID;
static NameKeyType staticPlayer6NameID = NAMEKEY_INVALID;
static NameKeyType staticPlayer7NameID = NAMEKEY_INVALID;
static NameKeyType staticPlayer1StatusID = NAMEKEY_INVALID;
static NameKeyType staticPlayer2StatusID = NAMEKEY_INVALID;
static NameKeyType staticPlayer3StatusID = NAMEKEY_INVALID;
static NameKeyType staticPlayer4StatusID = NAMEKEY_INVALID;
static NameKeyType staticPlayer5StatusID = NAMEKEY_INVALID;
static NameKeyType staticPlayer6StatusID = NAMEKEY_INVALID;
static NameKeyType staticPlayer7StatusID = NAMEKEY_INVALID;
static GameWindow *buttonQuitWindow = NULL;
static GameWindow *staticPlayer1Name = NULL;
static GameWindow *staticPlayer2Name = NULL;
static GameWindow *staticPlayer3Name = NULL;
static GameWindow *staticPlayer4Name = NULL;
static GameWindow *staticPlayer5Name = NULL;
static GameWindow *staticPlayer6Name = NULL;
static GameWindow *staticPlayer7Name = NULL;
static GameWindow *staticPlayer1Status = NULL;
static GameWindow *staticPlayer2Status = NULL;
static GameWindow *staticPlayer3Status = NULL;
static GameWindow *staticPlayer4Status = NULL;
static GameWindow *staticPlayer5Status = NULL;
static GameWindow *staticPlayer6Status = NULL;
static GameWindow *staticPlayer7Status = NULL;
static const char *layoutFilename = "GameSpyGameOptionsMenu.wnd";
static const char *parentName = "GameSpyGameOptionsMenuParent";
static const char *gadgetsToHide[] =
{
"MapWindow",
"StaticTextGameName",
"StaticTextTeam",
"StaticTextFaction",
"StaticTextColor",
"StaticTextPlayers",
"TextEntryMapDisplay",
"ButtonSelectMap",
"ButtonStart",
"StaticTextMapPreview",
NULL // keep this last
};
static const char *perPlayerGadgetsToHide[] =
{
"ComboBoxTeam",
"ComboBoxColor",
"ComboBoxPlayerTemplate",
"ComboBoxPlayer",
"ButtonAccept",
"GenericPing",
//"ButtonStartPosition",
NULL // keep this last
};
static const char *qmlayoutFilename = "WOLQuickMatchMenu.wnd";
static const char *qmparentName = "WOLQuickMatchMenuParent";
static const char *qmgadgetsToHide[] =
{
"StaticTextTitle",
"ButtonBack",
"ButtonOptions",
"ButtonBuddies",
"ButtonWiden",
"ButtonStop",
"ButtonStart",
NULL // keep this last
};
static const char *qmperPlayerGadgetsToHide[] =
{
//"ButtonStartPosition",
NULL // keep this last
};
static void showGameSpyGameOptionsUnderlyingGUIElements( Bool show )
{
ShowUnderlyingGUIElements( show, layoutFilename, parentName, gadgetsToHide, perPlayerGadgetsToHide );
}
static void showGameSpyQMUnderlyingGUIElements( Bool show )
{
ShowUnderlyingGUIElements( show, qmlayoutFilename, qmparentName, qmgadgetsToHide, qmperPlayerGadgetsToHide );
}
static void InitEstablishConnectionsDialog( void ) {
buttonQuitID = TheNameKeyGenerator->nameToKey( AsciiString("EstablishConnectionsScreen.wnd:ButtonQuit") );
buttonQuitWindow = TheWindowManager->winGetWindowFromId(NULL, buttonQuitID);
}
void ShowEstablishConnectionsWindow( void ) {
if (establishConnectionsLayout == NULL) {
establishConnectionsLayout = TheWindowManager->winCreateLayout( "Menus/EstablishConnectionsScreen.wnd" );
InitEstablishConnectionsDialog();
}
establishConnectionsLayout->hide(FALSE);
TheWindowManager->winSetFocus(establishConnectionsLayout->getFirstWindow());
if (!TheGameSpyGame->isQMGame())
{
showGameSpyGameOptionsUnderlyingGUIElements(FALSE);
}
else
{
showGameSpyQMUnderlyingGUIElements(FALSE);
}
}
void HideEstablishConnectionsWindow( void ) {
if (establishConnectionsLayout == NULL) {
// establishConnectionsLayout = TheWindowManager->winCreateLayout( "Menus/EstablishConnectionsScreen.wnd" );
// InitEstablishConnectionsDialog();
return;
}
// establishConnectionsLayout->hide(TRUE);
// establishConnectionsLayout->hide(TRUE);
// TheWindowManager->winDestroy(establishConnectionsLayout);
establishConnectionsLayout->destroyWindows();
establishConnectionsLayout->deleteInstance();
establishConnectionsLayout = NULL;
if (!TheGameSpyGame->isQMGame())
{
showGameSpyGameOptionsUnderlyingGUIElements(TRUE);
}
else
{
showGameSpyQMUnderlyingGUIElements(TRUE);
}
}
WindowMsgHandledType EstablishConnectionsControlInput(GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2) {
return MSG_IGNORED;
}
WindowMsgHandledType EstablishConnectionsControlSystem(GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2) {
switch (msg) {
case GBM_SELECTED:
{
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if (controlID == buttonQuitID) {
TheEstablishConnectionsMenu->abortGame();
}
break;
}
} // end switch
return MSG_HANDLED;
}

View File

@@ -0,0 +1,295 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: GameInfoWindow.cpp ////////////////////////////////////////////////////////////////////////
// Author: Chris Huybregts, Feb 2002
// Description: Game Info window callbacks
///////////////////////////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "GameClient/WindowLayout.h"
#include "GameClient/MapUtil.h"
#include "GameClient/Shell.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/GadgetListBox.h"
#include "GameClient/GadgetStaticText.h"
#include "GameClient/GameText.h"
#include "GameClient/GameInfoWindow.h"
#include "Common/MultiplayerSettings.h"
#include "Common/PlayerTemplate.h"
#include "GameNetwork/GameInfo.h"
#include "GameNetwork/LANAPI.h"
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
static GameWindow *parent = NULL;
static GameWindow *staticTextGameName = NULL;
static GameWindow *staticTextMapName = NULL;
static GameWindow *listBoxPlayers = NULL;
static GameWindow *winCrates = NULL;
static GameWindow *winSuperWeapons = NULL;
static GameWindow *winFreeForAll = NULL;
static NameKeyType parentID = NAMEKEY_INVALID;
static NameKeyType staticTextGameNameID = NAMEKEY_INVALID;
static NameKeyType staticTextMapNameID = NAMEKEY_INVALID;
static NameKeyType listBoxPlayersID = NAMEKEY_INVALID;
static NameKeyType winCratesID = NAMEKEY_INVALID;
static NameKeyType winSuperWeaponsID = NAMEKEY_INVALID;
static NameKeyType winFreeForAllID = NAMEKEY_INVALID;
static WindowLayout *gameInfoWindowLayout = NULL;
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
void CreateLANGameInfoWindow( GameWindow *sizeAndPosWin )
{
if( !gameInfoWindowLayout )
gameInfoWindowLayout = TheWindowManager->winCreateLayout( AsciiString( "Menus/GameInfoWindow.wnd" ) );
gameInfoWindowLayout->runInit();
gameInfoWindowLayout->bringForward();
gameInfoWindowLayout->hide( TRUE );
if( !parent || !sizeAndPosWin )
return;
Int x, y, width, height;
sizeAndPosWin->winGetScreenPosition(&x,&y);
parent->winSetPosition(x,y);
sizeAndPosWin->winGetSize( &width, &height );
parent->winSetSize(width, height);
}
void DestroyGameInfoWindow(void)
{
if (gameInfoWindowLayout)
{
gameInfoWindowLayout->destroyWindows();
gameInfoWindowLayout->deleteInstance();
gameInfoWindowLayout = NULL;
}
}
void RefreshGameInfoWindow(GameInfo *gameInfo, UnicodeString gameName)
{
static const Image *randomIcon = TheMappedImageCollection->findImageByName("GameinfoRANDOM");
static const Image *observerIcon = TheMappedImageCollection->findImageByName("GameinfoOBSRVR");
if(!gameInfoWindowLayout || !gameInfo )
return;
parent->winHide( FALSE );
parent->winBringToTop();
// Set the game name
GadgetStaticTextSetText(staticTextGameName, ((LANGameInfo *)gameInfo)->getPlayerName(0));
// set the map name
UnicodeString map;
AsciiString asciiMap = gameInfo->getMap();
asciiMap.toLower();
std::map<AsciiString, MapMetaData>::iterator it = TheMapCache->find(asciiMap);
if (it != TheMapCache->end())
{
map = it->second.m_displayName;
}
else
{
// can happen if the map will have to be transferred... so use the leaf name (srj)
const char *noPath = gameInfo->getMap().reverseFind('\\');
if (noPath)
{
++noPath;
}
else
{
noPath = gameInfo->getMap().str();
}
map.translate(noPath);
}
GadgetStaticTextSetText(staticTextMapName,map);
// fill in the player list
GadgetListBoxReset(listBoxPlayers);
Int numColors = TheMultiplayerSettings->getNumColors();
Color white = GameMakeColor(255,255,255,255);
// Color grey = GameMakeColor(188,188,188,255);
for (Int i = 0; i < MAX_SLOTS; i ++)
{
Color playerColor = white;
Int color = -1;
Int addedRow;
GameSlot *slot = gameInfo->getSlot(i);
if(!slot || (slot->isOccupied() == FALSE))
continue;
color = slot->getColor();
if(color > -1 && color < numColors)
{
MultiplayerColorDefinition *def = TheMultiplayerSettings->getColor(color);
playerColor = def->getColor();
}
if(slot->isAI())
{
switch(slot->getState())
{
case SLOT_EASY_AI:
{
addedRow = GadgetListBoxAddEntryText(listBoxPlayers,TheGameText->fetch("GUI:EasyAI"),playerColor,-1, 1);
break;
}
case SLOT_MED_AI:
{
addedRow = GadgetListBoxAddEntryText(listBoxPlayers,TheGameText->fetch("GUI:MediumAI"),playerColor,-1, 1);
break;
}
case SLOT_BRUTAL_AI:
{
addedRow = GadgetListBoxAddEntryText(listBoxPlayers,TheGameText->fetch("GUI:HardAI"),playerColor,-1, 1);
break;
}
default:
break;
}
}
else if(slot->isHuman())
{
addedRow = GadgetListBoxAddEntryText(listBoxPlayers, slot->getName(),playerColor,-1,1);
}
Int playerTemplate = slot->getPlayerTemplate();
if(playerTemplate == PLAYERTEMPLATE_OBSERVER)
{
GadgetListBoxAddEntryImage(listBoxPlayers, observerIcon,addedRow, 0, 22,25);
}
else if(playerTemplate < 0 || playerTemplate >= ThePlayerTemplateStore->getPlayerTemplateCount())
{
///< @todo: When we get art that shows player's side, then we'll actually draw the art instead of putting in text
GadgetListBoxAddEntryImage(listBoxPlayers, randomIcon,addedRow, 0, 22,25);
//GadgetListBoxAddEntryText(listBoxPlayers,TheGameText->fetch("GUI:???"),playerColor,addedRow, 0);
}
else
{
const PlayerTemplate *fact = ThePlayerTemplateStore->getNthPlayerTemplate(playerTemplate);
GadgetListBoxAddEntryImage(listBoxPlayers, fact->getSideIconImage(),addedRow, 0, 22,25);
//GadgetListBoxAddEntryText(listBoxPlayers,fact->getDisplayName(),playerColor,addedRow, 0);
}
}
}
void HideGameInfoWindow(Bool hide)
{
if(!parent)
return;
parent->winHide(hide);
}
//-------------------------------------------------------------------------------------------------
/** Initialize the GameInfoWindow */
//-------------------------------------------------------------------------------------------------
void GameInfoWindowInit( WindowLayout *layout, void *userData )
{
parentID = TheNameKeyGenerator->nameToKey( "GameInfoWindow.wnd:ParentGameInfo" );
staticTextGameNameID = TheNameKeyGenerator->nameToKey( "GameInfoWindow.wnd:StaticTextGameName" );
staticTextMapNameID = TheNameKeyGenerator->nameToKey( "GameInfoWindow.wnd:StaticTextMapName" );
listBoxPlayersID = TheNameKeyGenerator->nameToKey( "GameInfoWindow.wnd:ListBoxPlayers" );
winCratesID = TheNameKeyGenerator->nameToKey( "GameInfoWindow.wnd:WinCrates" );
winSuperWeaponsID = TheNameKeyGenerator->nameToKey( "GameInfoWindow.wnd:WinSuperWeapons" );
winFreeForAllID = TheNameKeyGenerator->nameToKey( "GameInfoWindow.wnd:WinFreeForAll" );
parent = TheWindowManager->winGetWindowFromId( NULL, parentID );
staticTextGameName = TheWindowManager->winGetWindowFromId( parent, staticTextGameNameID );
staticTextMapName = TheWindowManager->winGetWindowFromId( parent, staticTextMapNameID );
listBoxPlayers = TheWindowManager->winGetWindowFromId( parent, listBoxPlayersID );
winCrates = TheWindowManager->winGetWindowFromId( parent, winCratesID );
winSuperWeapons = TheWindowManager->winGetWindowFromId( parent, winSuperWeaponsID );
winFreeForAll = TheWindowManager->winGetWindowFromId( parent, winFreeForAllID );
GadgetStaticTextSetText(staticTextGameName,UnicodeString.TheEmptyString);
GadgetStaticTextSetText(staticTextMapName,UnicodeString.TheEmptyString);
GadgetListBoxReset(listBoxPlayers);
} // end MapSelectMenuInit
//-------------------------------------------------------------------------------------------------
/** GameInfo window system callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType GameInfoWindowSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
switch( msg )
{
// might use these later
// GameWindow *control = (GameWindow *)mData1;
// Int controlID = control->winGetWindowId();
// --------------------------------------------------------------------------------------------
case GWM_CREATE:
{
break;
} // end create
//---------------------------------------------------------------------------------------------
case GWM_DESTROY:
{
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
//---------------------------------------------------------------------------------------------
default:
return MSG_IGNORED;
} // end switch
return MSG_HANDLED;
} // end MapSelectMenuSystem

View File

@@ -0,0 +1,876 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
// FILE: LanLobbyMenu.cpp
// Author: Chris Huybregts, October 2001
// Description: Lan Lobby Menu
///////////////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Lib/BaseType.h"
#include "Common/CRC.h"
#include "Common/GameEngine.h"
#include "Common/GlobalData.h"
#include "Common/MultiplayerSettings.h"
#include "Common/NameKeyGenerator.h"
#include "Common/Player.h"
#include "Common/PlayerTemplate.h"
#include "Common/QuotedPrintable.h"
#include "Common/UserPreferences.h"
#include "GameClient/AnimateWindowManager.h"
#include "GameClient/GameText.h"
#include "GameClient/MapUtil.h"
#include "GameClient/Mouse.h"
#include "GameClient/WindowLayout.h"
#include "GameClient/Gadget.h"
#include "GameClient/Shell.h"
#include "GameClient/ShellHooks.h"
#include "GameClient/KeyDefs.h"
#include "GameClient/GameInfoWindow.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/GadgetListBox.h"
#include "GameClient/GadgetTextEntry.h"
#include "GameClient/MessageBox.h"
#include "GameClient/GameWindowTransitions.h"
#include "GameLogic/GameLogic.h"
#include "GameNetwork/IPEnumeration.h"
#include "GameNetwork/LANAPICallbacks.h"
#include "GameNetwork/LANGameInfo.h"
Bool LANisShuttingDown = false;
Bool LANbuttonPushed = false;
Bool LANSocketErrorDetected = FALSE;
char *LANnextScreen = NULL;
static Int initialGadgetDelay = 2;
static Bool justEntered = FALSE;
LANPreferences::LANPreferences( void )
{
// note, the superclass will put this in the right dir automatically, this is just a leaf name
load("Network.ini");
}
LANPreferences::~LANPreferences()
{
}
UnicodeString LANPreferences::getUserName(void)
{
UnicodeString ret;
LANPreferences::const_iterator it = find("UserName");
if (it == end())
{
IPEnumeration IPs;
ret.translate(IPs.getMachineName());
return ret;
}
ret = QuotedPrintableToUnicodeString(it->second);
ret.trim();
if (ret.isEmpty())
{
IPEnumeration IPs;
ret.translate(IPs.getMachineName());
return ret;
}
return ret;
}
Int LANPreferences::getPreferredColor(void)
{
Int ret;
LANPreferences::const_iterator it = find("Color");
if (it == end())
{
return -1;
}
ret = atoi(it->second.str());
if (ret < -1 || ret >= TheMultiplayerSettings->getNumColors())
ret = -1;
return ret;
}
Int LANPreferences::getPreferredFaction(void)
{
Int ret;
LANPreferences::const_iterator it = find("PlayerTemplate");
if (it == end())
{
return PLAYERTEMPLATE_RANDOM;
}
ret = atoi(it->second.str());
if (ret == PLAYERTEMPLATE_OBSERVER || ret < PLAYERTEMPLATE_MIN || ret >= ThePlayerTemplateStore->getPlayerTemplateCount())
ret = PLAYERTEMPLATE_RANDOM;
if (ret >= 0)
{
const PlayerTemplate *fac = ThePlayerTemplateStore->getNthPlayerTemplate(ret);
if (!fac)
ret = PLAYERTEMPLATE_RANDOM;
else if (fac->getStartingBuilding().isEmpty())
ret = PLAYERTEMPLATE_RANDOM;
}
return ret;
}
Bool LANPreferences::usesSystemMapDir(void)
{
OptionPreferences::const_iterator it = find("UseSystemMapDir");
if (it == end())
return TRUE;
if (stricmp(it->second.str(), "yes") == 0) {
return TRUE;
}
return FALSE;
}
AsciiString LANPreferences::getPreferredMap(void)
{
AsciiString ret;
LANPreferences::const_iterator it = find("Map");
if (it == end())
{
ret = getDefaultMap(TRUE);
return ret;
}
ret = QuotedPrintableToAsciiString(it->second);
ret.trim();
if (ret.isEmpty() || !isValidMap(ret, TRUE))
{
ret = getDefaultMap(TRUE);
return ret;
}
return ret;
}
Int LANPreferences::getNumRemoteIPs(void)
{
Int ret;
LANPreferences::const_iterator it = find("NumRemoteIPs");
if (it == end())
{
ret = 0;
return ret;
}
ret = atoi(it->second.str());
return ret;
}
UnicodeString LANPreferences::getRemoteIPEntry(Int i)
{
UnicodeString ret;
AsciiString key;
key.format("RemoteIP%d", i);
AsciiString ipstr;
AsciiString asciientry;
LANPreferences::const_iterator it = find(key.str());
if (it == end())
{
asciientry = "";
return ret;
}
asciientry = it->second;
asciientry.nextToken(&ipstr, ":");
asciientry.set(asciientry.str() + 1); // skip the ':'
ret.translate(ipstr);
if (asciientry.getLength() > 0)
{
ret.concat(L"(");
ret.concat(QuotedPrintableToUnicodeString(asciientry));
ret.concat(L")");
}
return ret;
}
// PRIVATE DATA ///////////////////////////////////////////////////////////////////////////////////
// window ids ------------------------------------------------------------------------------
static NameKeyType parentLanLobbyID = NAMEKEY_INVALID;
static NameKeyType buttonBackID = NAMEKEY_INVALID;
static NameKeyType buttonClearID = NAMEKEY_INVALID;
static NameKeyType buttonHostID = NAMEKEY_INVALID;
static NameKeyType buttonJoinID = NAMEKEY_INVALID;
static NameKeyType buttonDirectConnectID = NAMEKEY_INVALID;
static NameKeyType buttonEmoteID = NAMEKEY_INVALID;
static NameKeyType staticToolTipID = NAMEKEY_INVALID;
static NameKeyType textEntryPlayerNameID = NAMEKEY_INVALID;
static NameKeyType textEntryChatID = NAMEKEY_INVALID;
static NameKeyType listboxPlayersID = NAMEKEY_INVALID;
static NameKeyType staticTextGameInfoID = NAMEKEY_INVALID;
// Window Pointers ------------------------------------------------------------------------
static GameWindow *parentLanLobby = NULL;
static GameWindow *buttonBack = NULL;
static GameWindow *buttonClear = NULL;
static GameWindow *buttonHost = NULL;
static GameWindow *buttonJoin = NULL;
static GameWindow *buttonDirectConnect = NULL;
static GameWindow *buttonEmote = NULL;
static GameWindow *staticToolTip = NULL;
static GameWindow *textEntryPlayerName = NULL;
static GameWindow *textEntryChat = NULL;
static GameWindow *staticTextGameInfo = NULL;
//external declarations of the Gadgets the callbacks can use
NameKeyType listboxChatWindowID = NAMEKEY_INVALID;
GameWindow *listboxChatWindow = NULL;
GameWindow *listboxPlayers = NULL;
NameKeyType listboxGamesID = NAMEKEY_INVALID;
GameWindow *listboxGames = NULL;
// hack to disable framerate limiter in LAN games
//static Bool shellmapOn;
static Bool useFpsLimit;
static UnicodeString defaultName;
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( TheGameText->fetch("TOOLTIP:LobbyPlayers") );
return;
}
UnsignedInt playerIP = (UnsignedInt)GadgetListBoxGetItemData( window, row, col );
LANPlayer *player = TheLAN->LookupPlayer(playerIP);
if (!player)
{
DEBUG_CRASH(("No player info in listbox!"));
//TheMouse->setCursorTooltip( TheGameText->fetch("TOOLTIP:LobbyPlayers") );
return;
}
UnicodeString tooltip;
tooltip.format(TheGameText->fetch("TOOLTIP:LANPlayer"), player->getName().str(), player->getLogin().str(), player->getHost().str());
TheMouse->setCursorTooltip( tooltip );
}
//-------------------------------------------------------------------------------------------------
/** Initialize the Lan Lobby Menu */
//-------------------------------------------------------------------------------------------------
void LanLobbyMenuInit( WindowLayout *layout, void *userData )
{
LANnextScreen = NULL;
LANbuttonPushed = false;
LANisShuttingDown = false;
// get the ids for our controls
parentLanLobbyID = TheNameKeyGenerator->nameToKey( AsciiString( "LanLobbyMenu.wnd:LanLobbyMenuParent" ) );
buttonBackID = TheNameKeyGenerator->nameToKey( AsciiString( "LanLobbyMenu.wnd:ButtonBack" ) );
buttonClearID = TheNameKeyGenerator->nameToKey( AsciiString( "LanLobbyMenu.wnd:ButtonClear" ) );
buttonHostID = TheNameKeyGenerator->nameToKey( AsciiString( "LanLobbyMenu.wnd:ButtonHost" ) );
buttonJoinID = TheNameKeyGenerator->nameToKey( AsciiString( "LanLobbyMenu.wnd:ButtonJoin" ) );
buttonDirectConnectID = TheNameKeyGenerator->nameToKey( AsciiString( "LanLobbyMenu.wnd:ButtonDirectConnect" ) );
buttonEmoteID = TheNameKeyGenerator->nameToKey( AsciiString( "LanLobbyMenu.wnd:ButtonEmote" ) );
staticToolTipID = TheNameKeyGenerator->nameToKey( AsciiString( "LanLobbyMenu.wnd:StaticToolTip" ) );
textEntryPlayerNameID = TheNameKeyGenerator->nameToKey( AsciiString( "LanLobbyMenu.wnd:TextEntryPlayerName" ) );
textEntryChatID = TheNameKeyGenerator->nameToKey( AsciiString( "LanLobbyMenu.wnd:TextEntryChat" ) );
listboxPlayersID = TheNameKeyGenerator->nameToKey( AsciiString( "LanLobbyMenu.wnd:ListboxPlayers" ) );
listboxChatWindowID = TheNameKeyGenerator->nameToKey( AsciiString( "LanLobbyMenu.wnd:ListboxChatWindowLanLobby" ) );
listboxGamesID = TheNameKeyGenerator->nameToKey( AsciiString( "LanLobbyMenu.wnd:ListboxGames" ) );
staticTextGameInfoID = TheNameKeyGenerator->nameToKey( AsciiString( "LanLobbyMenu.wnd:StaticTextGameInfo" ) );
// Get pointers to the window buttons
parentLanLobby = TheWindowManager->winGetWindowFromId( NULL, parentLanLobbyID );
buttonBack = TheWindowManager->winGetWindowFromId( NULL, buttonBackID);
buttonClear = TheWindowManager->winGetWindowFromId( NULL, buttonClearID);
buttonHost = TheWindowManager->winGetWindowFromId( NULL, buttonHostID );
buttonJoin = TheWindowManager->winGetWindowFromId( NULL, buttonJoinID );
buttonDirectConnect = TheWindowManager->winGetWindowFromId( NULL, buttonDirectConnectID );
buttonEmote = TheWindowManager->winGetWindowFromId( NULL,buttonEmoteID );
staticToolTip = TheWindowManager->winGetWindowFromId( NULL, staticToolTipID );
textEntryPlayerName = TheWindowManager->winGetWindowFromId( NULL, textEntryPlayerNameID );
textEntryChat = TheWindowManager->winGetWindowFromId( NULL, textEntryChatID );
listboxPlayers = TheWindowManager->winGetWindowFromId( NULL, listboxPlayersID );
listboxChatWindow = TheWindowManager->winGetWindowFromId( NULL, listboxChatWindowID );
listboxGames = TheWindowManager->winGetWindowFromId( NULL, listboxGamesID );
staticTextGameInfo = TheWindowManager->winGetWindowFromId( NULL, staticTextGameInfoID );
listboxPlayers->winSetTooltipFunc(playerTooltip);
// Show Menu
layout->hide( FALSE );
// Init LAN API Singleton
if (!TheLAN)
{
TheLAN = NEW LANAPI(); /// @todo clh delete TheLAN and
useFpsLimit = TheGlobalData->m_useFpsLimit;
}
else
{
TheWritableGlobalData->m_useFpsLimit = useFpsLimit;
TheLAN->reset();
}
// Choose an IP address, then initialize the LAN singleton
UnsignedInt IP = TheGlobalData->m_defaultIP;
IPEnumeration IPs;
if (!IP)
{
EnumeratedIP *IPlist = IPs.getAddresses();
/*
while (IPlist && IPlist->getNext())
{
IPlist = IPlist->getNext();
}
*/
DEBUG_ASSERTCRASH(IPlist, ("No IP addresses found!"));
if (!IPlist)
{
/// @todo: display error and exit lan lobby if no IPs are found
}
//UnicodeString str;
//str.format(L"Local IP chosen: %hs", IPlist->getIPstring().str());
//GadgetListBoxAddEntryText(listboxChatWindow, str, chatSystemColor, -1, 0);
IP = IPlist->getIP();
}
else
{
/*
UnicodeString str;
str.format(L"Default local IP: %d.%d.%d.%d",
(IP >> 24),
(IP >> 16) & 0xFF,
(IP >> 8) & 0xFF,
IP & 0xFF);
GadgetListBoxAddEntryText(listboxChatWindow, str, chatSystemColor, -1, 0);
*/
}
// TheLAN->init() sets us to be in a LAN menu screen automatically.
TheLAN->init();
if (TheLAN->SetLocalIP(IP) == FALSE) {
LANSocketErrorDetected = TRUE;
}
//Initialize the gadgets on the window
//UnicodeString txtInput;
//txtInput.translate(IPs.getMachineName());
LANPreferences prefs;
defaultName = prefs.getUserName();
while (defaultName.getLength() > g_lanPlayerNameLength)
defaultName.removeLastChar();
GadgetTextEntrySetText( textEntryPlayerName, defaultName);
// Clear the text entry line
GadgetTextEntrySetText(textEntryChat, UnicodeString::TheEmptyString);
GadgetListBoxReset(listboxPlayers);
GadgetListBoxReset(listboxGames);
while (defaultName.getLength() > g_lanPlayerNameLength)
defaultName.removeLastChar();
TheLAN->RequestSetName(defaultName);
TheLAN->RequestLocations();
/*
UnicodeString unicodeChat;
unicodeChat = L"Local IP list:";
GadgetListBoxAddEntryText(listboxChatWindow, unicodeChat, chatSystemColor, -1, 0);
IPlist = IPs.getAddresses();
while (IPlist)
{
unicodeChat.translate(IPlist->getIPstring());
GadgetListBoxAddEntryText(listboxChatWindow, unicodeChat, chatSystemColor, -1, 0);
IPlist = IPlist->getNext();
}
*/
// Set Keyboard to Main Parent
//TheWindowManager->winSetFocus( parentLanLobby );
TheWindowManager->winSetFocus( textEntryChat );
CreateLANGameInfoWindow(staticTextGameInfo);
//TheShell->showShellMap(FALSE);
//shellmapOn = FALSE;
// coming out of a game, re-load the shell map
TheShell->showShellMap(TRUE);
// check for MOTD
TheLAN->checkMOTD();
layout->hide(FALSE);
layout->bringForward();
justEntered = TRUE;
initialGadgetDelay = 2;
GameWindow *win = TheWindowManager->winGetWindowFromId(NULL, TheNameKeyGenerator->nameToKey("LanLobbyMenu.wnd:GadgetParent"));
if(win)
win->winHide(TRUE);
// animate controls
//TheShell->registerWithAnimateManager(parentLanLobby, WIN_ANIMATION_SLIDE_TOP, TRUE);
// TheShell->registerWithAnimateManager(buttonHost, WIN_ANIMATION_SLIDE_LEFT, TRUE, 600);
// TheShell->registerWithAnimateManager(buttonJoin, WIN_ANIMATION_SLIDE_LEFT, TRUE, 400);
// TheShell->registerWithAnimateManager(buttonDirectConnect, WIN_ANIMATION_SLIDE_LEFT, TRUE, 200);
// //TheShell->registerWithAnimateManager(buttonOptions, WIN_ANIMATION_SLIDE_LEFT, TRUE, 1);
// TheShell->registerWithAnimateManager(buttonBack, WIN_ANIMATION_SLIDE_RIGHT, TRUE, 1);
} // GameLobbyMenuInit
//-------------------------------------------------------------------------------------------------
/** This is called when a shutdown is complete for this menu */
//-------------------------------------------------------------------------------------------------
static void shutdownComplete( WindowLayout *layout )
{
LANisShuttingDown = false;
// hide the layout
layout->hide( TRUE );
// our shutdown is complete
TheShell->shutdownComplete( layout, (LANnextScreen != NULL) );
if (LANnextScreen != NULL)
{
TheShell->push(LANnextScreen);
}
LANnextScreen = NULL;
} // end if
//-------------------------------------------------------------------------------------------------
/** Lan Lobby menu shutdown method */
//-------------------------------------------------------------------------------------------------
void LanLobbyMenuShutdown( WindowLayout *layout, void *userData )
{
LANPreferences prefs;
prefs["UserName"] = UnicodeStringToQuotedPrintable(GadgetTextEntryGetText( textEntryPlayerName ));
prefs.write();
DestroyGameInfoWindow();
// hide menu
//layout->hide( TRUE );
TheLAN->RequestLobbyLeave( true );
// Reset the LAN singleton
//TheLAN->reset();
// our shutdown is complete
//TheShell->shutdownComplete( layout );
TheWritableGlobalData->m_useFpsLimit = useFpsLimit;
LANisShuttingDown = true;
// if we are shutting down for an immediate pop, skip the animations
Bool popImmediate = *(Bool *)userData;
LANSocketErrorDetected = FALSE;
if( popImmediate )
{
shutdownComplete( layout );
return;
} //end if
TheShell->reverseAnimatewindow();
TheTransitionHandler->reverse("LanLobbyFade");
//if( shellmapOn)
// TheShell->showShellMap(TRUE);
} // LanLobbyMenuShutdown
//-------------------------------------------------------------------------------------------------
/** Lan Lobby menu update method */
//-------------------------------------------------------------------------------------------------
void LanLobbyMenuUpdate( WindowLayout * layout, void *userData)
{
if (TheGameLogic->isInShellGame() && TheGameLogic->getFrame() == 1)
{
SignalUIInteraction(SHELL_SCRIPT_HOOK_LAN_ENTERED_FROM_GAME);
}
if(justEntered)
{
if(initialGadgetDelay == 1)
{
TheTransitionHandler->setGroup("LanLobbyFade");
initialGadgetDelay = 2;
justEntered = FALSE;
}
else
initialGadgetDelay--;
}
if(LANisShuttingDown && TheShell->isAnimFinished() && TheTransitionHandler->isFinished())
shutdownComplete(layout);
if (TheShell->isAnimFinished() && !LANbuttonPushed && TheLAN)
TheLAN->update();
if (LANSocketErrorDetected == TRUE) {
LANSocketErrorDetected = FALSE;
DEBUG_LOG(("SOCKET ERROR! BAILING!\n"));
MessageBoxOk(TheGameText->fetch("GUI:NetworkError"), TheGameText->fetch("GUI:SocketError"), NULL);
// we have a socket problem, back out to the main menu.
TheWindowManager->winSendSystemMsg(buttonBack->winGetParent(), GBM_SELECTED,
(WindowMsgData)buttonBack, buttonBackID);
}
}// LanLobbyMenuUpdate
//-------------------------------------------------------------------------------------------------
/** Lan Lobby menu input callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType LanLobbyMenuInput( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
switch( msg )
{
// --------------------------------------------------------------------------------------------
case GWM_CHAR:
{
UnsignedByte key = mData1;
UnsignedByte state = mData2;
if (LANbuttonPushed)
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;
}// LanLobbyMenuInput
//-------------------------------------------------------------------------------------------------
/** Lan Lobby menu window system callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType LanLobbyMenuSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
UnicodeString txtInput;
switch( msg )
{
case GWM_CREATE:
{
SignalUIInteraction(SHELL_SCRIPT_HOOK_LAN_OPENED);
break;
} // case GWM_DESTROY:
case GWM_DESTROY:
{
SignalUIInteraction(SHELL_SCRIPT_HOOK_LAN_CLOSED);
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_DOUBLE_CLICKED:
{
if (LANbuttonPushed)
break;
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if( controlID == listboxGamesID )
{
int rowSelected = mData2;
if (rowSelected >= 0)
{
LANGameInfo * theGame = TheLAN->LookupGameByListOffset(rowSelected);
if (theGame)
{
TheLAN->RequestGameJoin(theGame);
}
}
}
break;
}
case GLM_SELECTED:
{
if (LANbuttonPushed)
break;
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if( controlID == listboxGamesID )
{
int rowSelected = mData2;
if( rowSelected < 0 )
{
HideGameInfoWindow(TRUE);
break;
}
LANGameInfo * theGame = TheLAN->LookupGameByListOffset(rowSelected);
if (theGame)
RefreshGameInfoWindow(theGame, theGame->getName());
else
HideGameInfoWindow(TRUE);
}
break;
}
case GBM_SELECTED:
{
if (LANbuttonPushed)
break;
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if ( controlID == buttonBackID )
{
//shellmapOn = TRUE;
LANbuttonPushed = true;
DEBUG_LOG(("Back was hit - popping to main menu\n"));
TheShell->pop();
delete TheLAN;
TheLAN = NULL;
//TheTransitionHandler->reverse("LanLobbyFade");
} //if ( controlID == buttonBack )
else if ( controlID == buttonHostID )
{
TheLAN->RequestGameCreate( UnicodeString(L""), FALSE);
}//else if ( controlID == buttonHostID )
else if ( controlID == buttonClearID )
{
GadgetTextEntrySetText(textEntryPlayerName, UnicodeString::TheEmptyString);
TheWindowManager->winSendSystemMsg( window,
GEM_UPDATE_TEXT,
(WindowMsgData)textEntryPlayerName,
0 );
}
else if ( controlID == buttonJoinID )
{
//TheShell->push( AsciiString("Menus/LanGameOptionsMenu.wnd") );
int rowSelected = -1;
GadgetListBoxGetSelected( listboxGames, &rowSelected );
if (rowSelected >= 0)
{
LANGameInfo * theGame = TheLAN->LookupGameByListOffset(rowSelected);
if (theGame)
{
TheLAN->RequestGameJoin(theGame);
}
}
else
{
GadgetListBoxAddEntryText(listboxChatWindow, TheGameText->fetch("LAN:ErrorNoGameSelected") , chatSystemColor, -1, 0);
}
} //else if ( controlID == buttonJoinID )
else if ( controlID == buttonEmoteID )
{
// read the user's input
txtInput.set(GadgetTextEntryGetText( textEntryChat ));
// Clear the text entry line
GadgetTextEntrySetText(textEntryChat, UnicodeString::TheEmptyString);
// Clean up the text (remove leading/trailing chars, etc)
txtInput.trim();
// Echo the user's input to the chat window
if (!txtInput.isEmpty()) {
// TheLAN->RequestChat(txtInput, LANAPIInterface::LANCHAT_EMOTE);
TheLAN->RequestChat(txtInput, LANAPIInterface::LANCHAT_NORMAL);
}
} //if ( controlID == buttonEmote )
else if (controlID == buttonDirectConnectID)
{
TheLAN->RequestLobbyLeave( false );
TheShell->push(AsciiString("Menus/NetworkDirectConnect.wnd"));
}
break;
}// case GBM_SELECTED:
case GEM_UPDATE_TEXT:
{
if (LANbuttonPushed)
break;
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if ( controlID == textEntryPlayerNameID )
{
// grab the user's name
txtInput.set(GadgetTextEntryGetText( textEntryPlayerName ));
// Clean up the text (remove leading/trailing chars, etc)
const WideChar *c = txtInput.str();
while (c && (iswspace(*c)))
c++;
if (c)
txtInput = UnicodeString(c);
else
txtInput = UnicodeString::TheEmptyString;
while (txtInput.getLength() > g_lanPlayerNameLength)
txtInput.removeLastChar();
if (!txtInput.isEmpty() && txtInput.getCharAt(txtInput.getLength()-1) == L',')
txtInput.removeLastChar(); // we use , for strtok's so we can't allow them in names. :(
if (!txtInput.isEmpty() && txtInput.getCharAt(txtInput.getLength()-1) == L':')
txtInput.removeLastChar(); // we use : for strtok's so we can't allow them in names. :(
if (!txtInput.isEmpty() && txtInput.getCharAt(txtInput.getLength()-1) == L';')
txtInput.removeLastChar(); // we use ; for strtok's so we can't allow them in names. :(
// send it over the network
if (!txtInput.isEmpty())
TheLAN->RequestSetName(txtInput);
else
{
TheLAN->RequestSetName(defaultName);
}
// Put the whitespace-free version in the box
GadgetTextEntrySetText( textEntryPlayerName, txtInput );
}// if ( controlID == textEntryPlayerNameID )
break;
}//case GEM_UPDATE_TEXT:
case GEM_EDIT_DONE:
{
if (LANbuttonPushed)
break;
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
// Take the user's input and echo it into the chat window as well as
// send it to the other clients on the lan
if ( controlID == textEntryChatID )
{
// read the user's input
txtInput.set(GadgetTextEntryGetText( textEntryChat ));
// Clear the text entry line
GadgetTextEntrySetText(textEntryChat, UnicodeString::TheEmptyString);
// Clean up the text (remove leading/trailing chars, etc)
while (!txtInput.isEmpty() && iswspace(txtInput.getCharAt(0)))
txtInput = UnicodeString(txtInput.str()+1);
// Echo the user's input to the chat window
if (!txtInput.isEmpty())
TheLAN->RequestChat(txtInput, LANAPIInterface::LANCHAT_NORMAL);
}// if ( controlID == textEntryChatID )
/*
else if ( controlID == textEntryPlayerNameID )
{
// grab the user's name
txtInput.set(GadgetTextEntryGetText( textEntryPlayerName ));
// Clean up the text (remove leading/trailing chars, etc)
txtInput.trim();
// send it over the network
if (!txtInput.isEmpty())
TheLAN->RequestSetName(txtInput);
// Put the whitespace-free version in the box
GadgetTextEntrySetText( textEntryPlayerName, txtInput );
}// if ( controlID == textEntryPlayerNameID )
*/
break;
}
default:
return MSG_IGNORED;
}//Switch
return MSG_HANDLED;
}// LanLobbyMenuSystem

View File

@@ -0,0 +1,460 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: LanMapSelectMenu.cpp ////////////////////////////////////////////////////////////////////////
// Author: Colin Day, October 2001
// Description: MapSelect menu window callbacks
///////////////////////////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/GameEngine.h"
#include "Common/NameKeyGenerator.h"
#include "Common/MessageStream.h"
#include "Common/UserPreferences.h"
#include "GameClient/WindowLayout.h"
#include "GameClient/Gadget.h"
#include "GameClient/Shell.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/GadgetListBox.h"
#include "GameClient/GadgetRadioButton.h"
#include "GameNetwork/LANAPICallbacks.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 NameKeyType winMapPreviewID = NAMEKEY_INVALID;
static GameWindow *parent = NULL;
static GameWindow *mapList = NULL;
static GameWindow *winMapPreview = NULL;
static NameKeyType radioButtonSystemMapsID = NAMEKEY_INVALID;
static NameKeyType radioButtonUserMapsID = NAMEKEY_INVALID;
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 };
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
void positionStartSpots( AsciiString mapName, GameWindow *buttonMapStartPositions[], GameWindow *mapWindow);
static const char *layoutFilename = "LanGameOptionsMenu.wnd";
static const char *parentName = "LanGameOptionsMenuParent";
static const char *gadgetsToHide[] =
{
"MapWindow",
//"StaticTextTitle",
"StaticTextTeam",
"StaticTextFaction",
"StaticTextColor",
"TextEntryMapDisplay",
"ButtonSelectMap",
"ButtonStart",
"StaticTextMapPreview",
NULL // keep this last
};
static const char *perPlayerGadgetsToHide[] =
{
"ComboBoxTeam",
"ComboBoxColor",
"ComboBoxPlayerTemplate",
NULL // keep this last
};
static void showLANGameOptionsUnderlyingGUIElements( Bool show )
{
ShowUnderlyingGUIElements( show, layoutFilename, parentName, gadgetsToHide, perPlayerGadgetsToHide );
GameWindow *win = TheWindowManager->winGetWindowFromId( NULL, TheNameKeyGenerator->nameToKey("LanGameOptionsMenu.wnd:ButtonBack") );
if(win)
win->winEnable( show );
}
static void NullifyControls()
{
mapList = NULL;
winMapPreview = NULL;
parent = NULL;
for (Int i=0; i<MAX_SLOTS; ++i)
{
buttonMapStartPosition[i] = NULL;
}
}
//-------------------------------------------------------------------------------------------------
/** Initialize the MapSelect menu */
//-------------------------------------------------------------------------------------------------
void LanMapSelectMenuInit( WindowLayout *layout, void *userData )
{
showLANGameOptionsUnderlyingGUIElements(FALSE);
// set keyboard focus to main parent
AsciiString parentName( "LanMapSelectMenu.wnd:LanMapSelectMenuParent" );
NameKeyType parentID = TheNameKeyGenerator->nameToKey( parentName );
parent = TheWindowManager->winGetWindowFromId( NULL, parentID );
TheWindowManager->winSetFocus( parent );
LANPreferences pref;
Bool usesSystemMapDir = pref.usesSystemMapDir();
const MapMetaData *mmd = TheMapCache->findMap(TheLAN->GetMyGame()->getMap());
if (mmd)
{
usesSystemMapDir = mmd->m_isOfficial;
}
buttonBack = TheNameKeyGenerator->nameToKey( AsciiString("LanMapSelectMenu.wnd:ButtonBack") );
buttonOK = TheNameKeyGenerator->nameToKey( AsciiString("LanMapSelectMenu.wnd:ButtonOK") );
listboxMap = TheNameKeyGenerator->nameToKey( AsciiString("LanMapSelectMenu.wnd:ListboxMap") );
winMapPreviewID = TheNameKeyGenerator->nameToKey( AsciiString("LanMapSelectMenu.wnd:WinMapPreview") );
radioButtonSystemMapsID = TheNameKeyGenerator->nameToKey( "LanMapSelectMenu.wnd:RadioButtonSystemMaps" );
radioButtonUserMapsID = TheNameKeyGenerator->nameToKey( "LanMapSelectMenu.wnd:RadioButtonUserMaps" );
GameWindow *radioButtonSystemMaps = TheWindowManager->winGetWindowFromId( parent, radioButtonSystemMapsID );
GameWindow *radioButtonUserMaps = TheWindowManager->winGetWindowFromId( parent, radioButtonUserMapsID );
winMapPreview = TheWindowManager->winGetWindowFromId(parent, winMapPreviewID);
if (usesSystemMapDir)
GadgetRadioSetSelection( radioButtonSystemMaps, FALSE );
else
GadgetRadioSetSelection( radioButtonUserMaps, FALSE );
AsciiString tmpString;
for (Int i = 0; i < MAX_SLOTS; i++)
{
tmpString.format("LanMapSelectMenu.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);
}
// get the listbox window
AsciiString listString( "LanMapSelectMenu.wnd:ListboxMap" );
NameKeyType mapListID = TheNameKeyGenerator->nameToKey( listString );
mapList = TheWindowManager->winGetWindowFromId( parent, mapListID );
if( mapList )
{
if (TheMapCache)
TheMapCache->updateCache();
populateMapListbox( mapList, usesSystemMapDir, TRUE, TheLAN->GetMyGame()->getMap() );
}
} // end LanMapSelectMenuInit
//-------------------------------------------------------------------------------------------------
/** MapSelect menu shutdown method */
//-------------------------------------------------------------------------------------------------
void LanMapSelectMenuShutdown( WindowLayout *layout, void *userData )
{
// hide menu
layout->hide( TRUE );
NullifyControls();
// our shutdown is complete
TheShell->shutdownComplete( layout );
} // end LanMapSelectMenuShutdown
//-------------------------------------------------------------------------------------------------
/** MapSelect menu update method */
//-------------------------------------------------------------------------------------------------
void LanMapSelectMenuUpdate( WindowLayout *layout, void *userData )
{
} // end LanMapSelectMenuUpdate
//-------------------------------------------------------------------------------------------------
/** Map select menu input callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType LanMapSelectMenuInput( 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( "LanMapSelectMenu.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 LanMapSelectMenuInput
//-------------------------------------------------------------------------------------------------
/** MapSelect menu window system callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType LanMapSelectMenuSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
GameWindow *mapWindow = NULL;
if (listboxMap != NULL)
{
mapWindow = TheWindowManager->winGetWindowFromId( parent, listboxMap );
}
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 GBM_SELECTED:
{
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if ( controlID == radioButtonSystemMapsID )
{
if (TheMapCache)
TheMapCache->updateCache();
populateMapListbox( mapList, TRUE, TRUE, TheLAN->GetMyGame()->getMap() );
LANPreferences pref;
pref["UseSystemMapDir"] = "yes";
pref.write();
}
else if ( controlID == radioButtonUserMapsID )
{
if (TheMapCache)
TheMapCache->updateCache();
populateMapListbox( mapList, FALSE, TRUE, TheLAN->GetMyGame()->getMap() );
LANPreferences pref;
pref["UseSystemMapDir"] = "no";
pref.write();
}
else if ( controlID == buttonBack )
{
mapSelectLayout->destroyWindows();
mapSelectLayout->deleteInstance();
mapSelectLayout = NULL;
// set the controls to NULL since they've been destroyed.
NullifyControls();
showLANGameOptionsUnderlyingGUIElements(TRUE);
PostToLanGameOptions( MAP_BACK );
} // end if
else if ( controlID == buttonOK )
{
Int selected = -1;
UnicodeString map;
// get the selected index
if (mapWindow != NULL)
{
GadgetListBoxGetSelected( mapWindow, &selected );
}
if( selected != -1 )
{
// get text of the map to load
map = GadgetListBoxGetText( mapWindow, selected, 0 );
// set the map name in the global data map name
AsciiString asciiMap;
const char *mapFname = (const char *)GadgetListBoxGetItemData( mapWindow, selected );
DEBUG_ASSERTCRASH(mapFname, ("No map item data"));
if (mapFname)
asciiMap = mapFname;
else
asciiMap.translate( map );
TheLAN->GetMyGame()->setMap( asciiMap );
asciiMap.toLower();
std::map<AsciiString, MapMetaData>::iterator it = TheMapCache->find(asciiMap);
if (it != TheMapCache->end())
{
TheLAN->GetMyGame()->getSlot(0)->setMapAvailability(true);
TheLAN->GetMyGame()->setMapCRC( it->second.m_CRC );
TheLAN->GetMyGame()->setMapSize( it->second.m_filesize );
TheLAN->GetMyGame()->resetStartSpots();
TheLAN->GetMyGame()->adjustSlotsForMap(); // BGC- adjust the slots for the new map.
}
mapSelectLayout->destroyWindows();
mapSelectLayout->deleteInstance();
mapSelectLayout = NULL;
// set the controls to NULL since they've been destroyed.
NullifyControls();
showLANGameOptionsUnderlyingGUIElements(TRUE);
PostToLanGameOptions(SEND_GAME_OPTS);
} // end if
} // end else if
break;
} // end selected
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( mapWindow, rowSelected, 0 );
// set the map name in the global data map name
AsciiString asciiMap;
const char *mapFname = (const char *)GadgetListBoxGetItemData( mapWindow, 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;
}
default:
return MSG_IGNORED;
} // end switch
return MSG_HANDLED;
} // end LanMapSelectMenuSystem

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,478 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: MapSelectMenu.cpp ////////////////////////////////////////////////////////////////////////
// Author: Colin Day, October 2001
// Description: MapSelect menu window callbacks
///////////////////////////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/GameEngine.h"
#include "Common/MessageStream.h"
#include "Common/RandomValue.h"
#include "Common/UserPreferences.h"
#include "GameLogic/GameLogic.h"
#include "GameLogic/ScriptEngine.h"
#include "GameClient/AnimateWindowManager.h"
#include "GameClient/CampaignManager.h"
#include "GameClient/WindowLayout.h"
#include "GameClient/Gadget.h"
#include "GameClient/Shell.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/GadgetListBox.h"
#include "GameClient/GadgetRadioButton.h"
#include "GameClient/MapUtil.h"
#include "GameClient/Mouse.h"
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
static NameKeyType radioButtonSystemMapsID = NAMEKEY_INVALID;
static NameKeyType radioButtonUserMapsID = NAMEKEY_INVALID;
static GameWindow *mapList = NULL;
static Bool showSoloMaps = true;
static Bool isShuttingDown = false;
static Bool startGame = false;
static Bool buttonPushed = false;
static GameDifficulty s_AIDiff = DIFFICULTY_NORMAL;
static void setupGameStart(AsciiString mapName)
{
startGame = true;
TheWritableGlobalData->m_pendingFile = mapName;
TheShell->reverseAnimatewindow();
}
static void doGameStart( void )
{
#if !defined(_PLAYTEST)
startGame = false;
if (TheGameLogic->isInGame())
TheGameLogic->clearGameData();
//TheScriptEngine->setGlobalDifficulty(s_AIDiff); // CANNOT DO THIS! REPLAYS WILL BREAK!!!
// send a message to the logic for a new game
GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_NEW_GAME );
msg->appendIntegerArgument(GAME_SINGLE_PLAYER);
msg->appendIntegerArgument(s_AIDiff);
msg->appendIntegerArgument(0);
/// @todo: when Campaign & skirmish are separated, make campaign have fixed seed and skirmish random.
InitRandom(0);
/*
if (TheGlobalData->m_fixedSeed >= 0)
InitGameLogicRandom(TheGlobalData->m_fixedSeed);
else
InitGameLogicRandom(GameClientRandomValue(0, INT_MAX - 1));
*/
isShuttingDown = true;
#endif
}
//-------------------------------------------------------------------------------------------------
/** 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 );
} // end if
void SetDifficultyRadioButton( void )
{
AsciiString parentName( "MapSelectMenu.wnd:MapSelectMenuParent" );
NameKeyType parentID = TheNameKeyGenerator->nameToKey( parentName );
GameWindow *parent = TheWindowManager->winGetWindowFromId( NULL, parentID );
if (!TheScriptEngine)
{
s_AIDiff = DIFFICULTY_EASY;
}
else
{
switch (TheScriptEngine->getGlobalDifficulty())
{
case DIFFICULTY_EASY:
{
NameKeyType radioButtonEasyAIID = TheNameKeyGenerator->nameToKey( AsciiString("MapSelectMenu.wnd:RadioButtonEasyAI") );
GameWindow *radioButtonEasyAI = TheWindowManager->winGetWindowFromId( parent, radioButtonEasyAIID );
GadgetRadioSetSelection(radioButtonEasyAI, FALSE);
s_AIDiff = DIFFICULTY_EASY;
break;
}
case DIFFICULTY_NORMAL:
{
NameKeyType radioButtonMediumAIID = TheNameKeyGenerator->nameToKey( AsciiString("MapSelectMenu.wnd:RadioButtonMediumAI") );
GameWindow *radioButtonMediumAI = TheWindowManager->winGetWindowFromId( parent, radioButtonMediumAIID );
GadgetRadioSetSelection(radioButtonMediumAI, FALSE);
s_AIDiff = DIFFICULTY_NORMAL;
break;
}
case DIFFICULTY_HARD:
{
NameKeyType radioButtonHardAIID = TheNameKeyGenerator->nameToKey( AsciiString("MapSelectMenu.wnd:RadioButtonHardAI") );
GameWindow *radioButtonHardAI = TheWindowManager->winGetWindowFromId( parent, radioButtonHardAIID );
GadgetRadioSetSelection(radioButtonHardAI, FALSE);
s_AIDiff = DIFFICULTY_HARD;
break;
}
default:
{
DEBUG_CRASH(("unrecognized difficulty level in the script engine"));
}
}
} // if (TheScriptEngine)
}
//-------------------------------------------------------------------------------------------------
/** Initialize the MapSelect menu */
//-------------------------------------------------------------------------------------------------
void MapSelectMenuInit( WindowLayout *layout, void *userData )
{
showSoloMaps = true;
buttonPushed = false;
isShuttingDown = false;
startGame = false;
TheShell->showShellMap(TRUE);
// show menu
layout->hide( FALSE );
OptionPreferences pref;
Bool usesSystemMapDir = pref.usesSystemMapDir();
// get the listbox window
AsciiString listString( "MapSelectMenu.wnd:ListboxMap" );
NameKeyType mapListID = TheNameKeyGenerator->nameToKey( listString );
mapList = TheWindowManager->winGetWindowFromId( NULL, mapListID );
if( mapList )
{
if (TheMapCache)
TheMapCache->updateCache();
populateMapListbox( mapList, usesSystemMapDir, !showSoloMaps );
}
// set keyboard focus to main parent
AsciiString parentName( "MapSelectMenu.wnd:MapSelectMenuParent" );
NameKeyType parentID = TheNameKeyGenerator->nameToKey( parentName );
GameWindow *parent = TheWindowManager->winGetWindowFromId( NULL, parentID );
TheWindowManager->winSetFocus( parent );
NameKeyType buttonBackID = TheNameKeyGenerator->nameToKey( AsciiString("MapSelectMenu.wnd:ButtonBack") );
GameWindow *buttonBack = TheWindowManager->winGetWindowFromId( NULL, buttonBackID );
NameKeyType buttonOKID = TheNameKeyGenerator->nameToKey( AsciiString("MapSelectMenu.wnd:ButtonOK") );
GameWindow *buttonOK = TheWindowManager->winGetWindowFromId( NULL, buttonOKID );
TheShell->registerWithAnimateManager(buttonBack, WIN_ANIMATION_SLIDE_RIGHT, TRUE,0);
TheShell->registerWithAnimateManager(buttonOK, WIN_ANIMATION_SLIDE_LEFT, TRUE, 0);
SetDifficultyRadioButton();
radioButtonSystemMapsID = TheNameKeyGenerator->nameToKey( "MapSelectMenu.wnd:RadioButtonSystemMaps" );
radioButtonUserMapsID = TheNameKeyGenerator->nameToKey( "MapSelectMenu.wnd:RadioButtonUserMaps" );
GameWindow *radioButtonSystemMaps = TheWindowManager->winGetWindowFromId( parent, radioButtonSystemMapsID );
GameWindow *radioButtonUserMaps = TheWindowManager->winGetWindowFromId( parent, radioButtonUserMapsID );
if (usesSystemMapDir)
GadgetRadioSetSelection( radioButtonSystemMaps, FALSE );
else
GadgetRadioSetSelection( radioButtonUserMaps, FALSE );
} // end MapSelectMenuInit
//-------------------------------------------------------------------------------------------------
/** MapSelect menu shutdown method */
//-------------------------------------------------------------------------------------------------
void MapSelectMenuShutdown( WindowLayout *layout, void *userData )
{
if (!startGame)
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
if (!startGame)
TheShell->reverseAnimatewindow();
} // end MapSelectMenuShutdown
//-------------------------------------------------------------------------------------------------
/** MapSelect menu update method */
//-------------------------------------------------------------------------------------------------
void MapSelectMenuUpdate( WindowLayout *layout, void *userData )
{
if (startGame && TheShell->isAnimFinished())
doGameStart();
// We'll only be successful if we've requested to
if(isShuttingDown && TheShell->isAnimFinished())
shutdownComplete(layout);
} // end MapSelectMenuUpdate
//-------------------------------------------------------------------------------------------------
/** Map select menu input callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType MapSelectMenuInput( 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 ) )
{
AsciiString buttonName( "MapSelectMenu.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 MapSelectMenuInput
//-------------------------------------------------------------------------------------------------
/** MapSelect menu window system callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType MapSelectMenuSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
static NameKeyType buttonBack = NAMEKEY_INVALID;
static NameKeyType buttonOK = NAMEKEY_INVALID;
static NameKeyType listboxMap = NAMEKEY_INVALID;
static NameKeyType radioButtonEasyAI = NAMEKEY_INVALID;
static NameKeyType radioButtonMediumAI = NAMEKEY_INVALID;
static NameKeyType radioButtonHardAI = NAMEKEY_INVALID;
switch( msg )
{
// --------------------------------------------------------------------------------------------
case GWM_CREATE:
{
// get ids for our children controls
buttonBack = TheNameKeyGenerator->nameToKey( AsciiString("MapSelectMenu.wnd:ButtonBack") );
buttonOK = TheNameKeyGenerator->nameToKey( AsciiString("MapSelectMenu.wnd:ButtonOK") );
listboxMap = TheNameKeyGenerator->nameToKey( AsciiString("MapSelectMenu.wnd:ListboxMap") );
radioButtonEasyAI = TheNameKeyGenerator->nameToKey( AsciiString("MapSelectMenu.wnd:RadioButtonEasyAI") );
radioButtonMediumAI = TheNameKeyGenerator->nameToKey( AsciiString("MapSelectMenu.wnd:RadioButtonMediumAI") );
radioButtonHardAI = TheNameKeyGenerator->nameToKey( AsciiString("MapSelectMenu.wnd:RadioButtonHardAI") );
break;
} // end create
//---------------------------------------------------------------------------------------------
case GWM_DESTROY:
{
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 GBM_SELECTED:
{
if (buttonPushed)
break;
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
static NameKeyType singlePlayerID = NAMEKEY("MapSelectMenu.wnd:ButtonSinglePlayer");
static NameKeyType multiplayerID = NAMEKEY("MapSelectMenu.wnd:ButtonMultiplayer");
if ( controlID == singlePlayerID )
{
showSoloMaps = true;
OptionPreferences pref;
populateMapListbox( mapList, pref.usesSystemMapDir(), !showSoloMaps );
}
else if ( controlID == multiplayerID )
{
showSoloMaps = false;
OptionPreferences pref;
populateMapListbox( mapList, pref.usesSystemMapDir(), !showSoloMaps );
}
else if ( controlID == radioButtonSystemMapsID )
{
if (TheMapCache)
TheMapCache->updateCache();
populateMapListbox( mapList, TRUE, !showSoloMaps );
OptionPreferences pref;
pref["UseSystemMapDir"] = "yes";
pref.write();
}
else if ( controlID == radioButtonUserMapsID )
{
if (TheMapCache)
TheMapCache->updateCache();
populateMapListbox( mapList, FALSE, !showSoloMaps );
OptionPreferences pref;
pref["UseSystemMapDir"] = "no";
pref.write();
}
else if( controlID == buttonBack )
{
// go back one screen
TheShell->pop();
buttonPushed = true;
} // end if
else if( controlID == buttonOK )
{
Int selected;
UnicodeString map;
GameWindow *mapWindow = TheWindowManager->winGetWindowFromId( NULL, listboxMap );
// get the selected index
GadgetListBoxGetSelected( mapWindow, &selected );
if( selected != -1 )
{
buttonPushed = true;
// reset the campaign manager to empty
if( TheCampaignManager )
TheCampaignManager->setCampaign( AsciiString( "" ) );
// get text of the map to load
const char *mapFname = (const char *)GadgetListBoxGetItemData( mapWindow, selected );
DEBUG_ASSERTCRASH(mapFname, ("No map item data"));
if (mapFname)
setupGameStart(mapFname);
} // end if
} // end else if
else if( controlID == radioButtonEasyAI)
{
s_AIDiff = DIFFICULTY_EASY;
}
else if( controlID == radioButtonMediumAI)
{
s_AIDiff = DIFFICULTY_NORMAL;
}
else if( controlID == radioButtonHardAI)
{
s_AIDiff = DIFFICULTY_HARD;
}
break;
} // end selected
case GLM_DOUBLE_CLICKED:
{
if (buttonPushed)
break;
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if( controlID == listboxMap )
{
int rowSelected = mData2;
if (rowSelected >= 0)
{
//buttonPushed = true;
GadgetListBoxSetSelected( control, rowSelected );
NameKeyType buttonOKID = TheNameKeyGenerator->nameToKey( AsciiString("MapSelectMenu.wnd:ButtonOK") );
GameWindow *buttonOK = TheWindowManager->winGetWindowFromId( NULL, buttonOKID );
TheWindowManager->winSendSystemMsg( window, GBM_SELECTED,
(WindowMsgData)buttonOK, buttonOKID );
}
}
break;
}
default:
return MSG_IGNORED;
} // end switch
return MSG_HANDLED;
} // end MapSelectMenuSystem

View File

@@ -0,0 +1,537 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
// FILE: NetworkDirectConnect.cpp
// Author: Bryan Cleveland, November 2001
// Description: Lan Lobby Menu
///////////////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "GameSpy/peer/peer.h"
#include "Common/QuotedPrintable.h"
#include "Common/UserPreferences.h"
#include "GameClient/AnimateWindowManager.h"
#include "GameClient/WindowLayout.h"
#include "GameClient/Gadget.h"
#include "GameClient/GameText.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/GadgetComboBox.h"
#include "GameClient/GadgetTextEntry.h"
#include "GameClient/GadgetStaticText.h"
#include "GameClient/Shell.h"
#include "GameClient/GameWindowTransitions.h"
#include "GameNetwork/IPEnumeration.h"
#include "GameNetwork/LANAPI.h"
#include "GameNetwork/LANAPICallbacks.h"
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
// window ids ------------------------------------------------------------------------------
// Window Pointers ------------------------------------------------------------------------
// PRIVATE DATA ///////////////////////////////////////////////////////////////////////////////////
extern Bool LANbuttonPushed;
extern Bool LANisShuttingDown;
static Bool isShuttingDown = false;
static Bool buttonPushed = false;
static NameKeyType buttonBackID = NAMEKEY_INVALID;
static NameKeyType buttonHostID = NAMEKEY_INVALID;
static NameKeyType buttonJoinID = NAMEKEY_INVALID;
static NameKeyType editPlayerNameID = NAMEKEY_INVALID;
static NameKeyType comboboxRemoteIPID = NAMEKEY_INVALID;
static NameKeyType staticLocalIPID = NAMEKEY_INVALID;
static GameWindow *buttonBack = NULL;
static GameWindow *buttonHost = NULL;
static GameWindow *buttonJoin = NULL;
static GameWindow *editPlayerName = NULL;
static GameWindow *comboboxRemoteIP = NULL;
static GameWindow *staticLocalIP = NULL;
void PopulateRemoteIPComboBox()
{
LANPreferences userprefs;
GadgetComboBoxReset(comboboxRemoteIP);
Int numRemoteIPs = userprefs.getNumRemoteIPs();
Color white = GameMakeColor(255,255,255,255);
for (Int i = 0; i < numRemoteIPs; ++i)
{
UnicodeString entry;
entry = userprefs.getRemoteIPEntry(i);
GadgetComboBoxAddEntry(comboboxRemoteIP, entry, white);
}
if (numRemoteIPs > 0)
{
GadgetComboBoxSetSelectedPos(comboboxRemoteIP, 0, TRUE);
}
userprefs.write();
}
void UpdateRemoteIPList()
{
Int n1[4], n2[4];
LANPreferences prefs;
Int numEntries = GadgetComboBoxGetLength(comboboxRemoteIP);
Int currentSelection = -1;
GadgetComboBoxGetSelectedPos(comboboxRemoteIP, &currentSelection);
UnicodeString unisel = GadgetComboBoxGetText(comboboxRemoteIP);
AsciiString sel;
sel.translate(unisel);
// UnicodeString newEntry = prefs.getRemoteIPEntry(0);
UnicodeString newEntry = unisel;
UnicodeString newIP;
newEntry.nextToken(&newIP, UnicodeString(L":"));
Int numFields = swscanf(newIP.str(), L"%d.%d.%d.%d", &(n1[0]), &(n1[1]), &(n1[2]), &(n1[3]));
if (numFields != 4) {
// this is not a properly formatted IP, don't change a thing.
return;
}
prefs["RemoteIP0"] = sel;
Int currentINIEntry = 1;
for (Int i = 0; i < numEntries; ++i)
{
if (i != currentSelection)
{
GadgetComboBoxSetSelectedPos(comboboxRemoteIP, i, FALSE);
UnicodeString uni;
uni = GadgetComboBoxGetText(comboboxRemoteIP);
AsciiString ascii;
ascii.translate(uni);
// prevent more than one copy of an IP address from being put in the list.
if (currentSelection == -1)
{
UnicodeString oldEntry = uni;
UnicodeString oldIP;
oldEntry.nextToken(&oldIP, UnicodeString(L":"));
swscanf(oldIP.str(), L"%d.%d.%d.%d", &(n2[0]), &(n2[1]), &(n2[2]), &(n2[3]));
Bool isEqual = TRUE;
for (Int i = 0; (i < 4) && (isEqual == TRUE); ++i) {
if (n1[i] != n2[i]) {
isEqual = FALSE;
}
}
// check to see if this is a duplicate or if this is not a properly formatted IP address.
if (isEqual == TRUE)
{
--numEntries;
continue;
}
}
AsciiString temp;
temp.format("RemoteIP%d", currentINIEntry);
++currentINIEntry;
prefs[temp.str()] = ascii;
}
}
if (currentSelection == -1)
{
++numEntries;
}
AsciiString numRemoteIPs;
numRemoteIPs.format("%d", numEntries);
prefs["NumRemoteIPs"] = numRemoteIPs;
prefs.write();
}
void HostDirectConnectGame()
{
// Init LAN API Singleton
DEBUG_ASSERTCRASH(TheLAN != NULL, ("TheLAN is NULL!"));
if (!TheLAN)
{
TheLAN = NEW LANAPI();
}
UnsignedInt localIP = TheLAN->GetLocalIP();
UnicodeString localIPString;
localIPString.format(L"%d.%d.%d.%d", localIP >> 24, (localIP & 0xff0000) >> 16, (localIP & 0xff00) >> 8, localIP & 0xff);
UnicodeString name;
name = GadgetTextEntryGetText(editPlayerName);
LANPreferences prefs;
prefs["UserName"] = UnicodeStringToQuotedPrintable(name);
prefs.write();
while (name.getLength() > g_lanPlayerNameLength)
name.removeLastChar();
TheLAN->RequestSetName(name);
TheLAN->RequestGameCreate(localIPString, TRUE);
}
void JoinDirectConnectGame()
{
// Init LAN API Singleton
if (!TheLAN)
{
TheLAN = NEW LANAPI();
}
UnsignedInt ipaddress = 0;
UnicodeString ipunistring = GadgetComboBoxGetText(comboboxRemoteIP);
AsciiString asciientry;
asciientry.translate(ipunistring);
AsciiString ipstring;
asciientry.nextToken(&ipstring, "(");
char ipstr[16];
strcpy(ipstr, ipstring.str());
Int ip1, ip2, ip3, ip4;
sscanf(ipstr, "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4);
DEBUG_LOG(("JoinDirectConnectGame - joining at %d.%d.%d.%d\n", ip1, ip2, ip3, ip4));
ipaddress = (ip1 << 24) + (ip2 << 16) + (ip3 << 8) + ip4;
// ipaddress = htonl(ipaddress);
UnicodeString name;
name = GadgetTextEntryGetText(editPlayerName);
LANPreferences prefs;
prefs["UserName"] = UnicodeStringToQuotedPrintable(name);
prefs.write();
UpdateRemoteIPList();
PopulateRemoteIPComboBox();
while (name.getLength() > g_lanPlayerNameLength)
name.removeLastChar();
TheLAN->RequestSetName(name);
TheLAN->RequestGameJoinDirectConnect(ipaddress);
}
//-------------------------------------------------------------------------------------------------
/** Initialize the WOL Welcome Menu */
//-------------------------------------------------------------------------------------------------
void NetworkDirectConnectInit( WindowLayout *layout, void *userData )
{
LANbuttonPushed = false;
LANisShuttingDown = false;
if (TheLAN == NULL)
{
TheLAN = NEW LANAPI();
TheLAN->init();
}
TheLAN->reset();
buttonPushed = false;
isShuttingDown = false;
TheShell->showShellMap(TRUE);
buttonBackID = TheNameKeyGenerator->nameToKey( AsciiString( "NetworkDirectConnect.wnd:ButtonBack" ) );
buttonHostID = TheNameKeyGenerator->nameToKey( AsciiString( "NetworkDirectConnect.wnd:ButtonHost" ) );
buttonJoinID = TheNameKeyGenerator->nameToKey( AsciiString( "NetworkDirectConnect.wnd:ButtonJoin" ) );
editPlayerNameID = TheNameKeyGenerator->nameToKey( AsciiString( "NetworkDirectConnect.wnd:EditPlayerName" ) );
comboboxRemoteIPID = TheNameKeyGenerator->nameToKey( AsciiString( "NetworkDirectConnect.wnd:ComboboxRemoteIP" ) );
staticLocalIPID = TheNameKeyGenerator->nameToKey( AsciiString( "NetworkDirectConnect.wnd:StaticLocalIP" ) );
buttonBack = TheWindowManager->winGetWindowFromId( NULL, buttonBackID);
buttonHost = TheWindowManager->winGetWindowFromId( NULL, buttonHostID);
buttonJoin = TheWindowManager->winGetWindowFromId( NULL, buttonJoinID);
editPlayerName = TheWindowManager->winGetWindowFromId( NULL, editPlayerNameID);
comboboxRemoteIP = TheWindowManager->winGetWindowFromId( NULL, comboboxRemoteIPID);
staticLocalIP = TheWindowManager->winGetWindowFromId( NULL, staticLocalIPID);
// // animate controls
// TheShell->registerWithAnimateManager(buttonBack, WIN_ANIMATION_SLIDE_LEFT, TRUE, 800);
// TheShell->registerWithAnimateManager(buttonHost, WIN_ANIMATION_SLIDE_LEFT, TRUE, 600);
// TheShell->registerWithAnimateManager(buttonJoin, WIN_ANIMATION_SLIDE_LEFT, TRUE, 200);
//
LANPreferences userprefs;
UnicodeString name;
name = userprefs.getUserName();
if (name.getLength() == 0)
{
name = TheGameText->fetch("GUI:Player");
}
GadgetTextEntrySetText(editPlayerName, name);
PopulateRemoteIPComboBox();
UnicodeString ipstr;
delete TheLAN;
TheLAN = NULL;
if (TheLAN == NULL) {
// DEBUG_ASSERTCRASH(TheLAN != NULL, ("TheLAN is null initializing the direct connect screen."));
TheLAN = NEW LANAPI();
OptionPreferences prefs;
UnsignedInt IP = prefs.getOnlineIPAddress();
IPEnumeration IPs;
// if (!IP)
// {
EnumeratedIP *IPlist = IPs.getAddresses();
DEBUG_ASSERTCRASH(IPlist, ("No IP addresses found!"));
if (!IPlist)
{
/// @todo: display error and exit lan lobby if no IPs are found
}
Bool foundIP = FALSE;
EnumeratedIP *tempIP = IPlist;
while ((tempIP != NULL) && (foundIP == FALSE)) {
if (IP == tempIP->getIP()) {
foundIP = TRUE;
}
tempIP = tempIP->getNext();
}
if (foundIP == FALSE) {
// The IP that we had no longer exists, we need to pick a new one.
IP = IPlist->getIP();
}
// IP = IPlist->getIP();
// }
TheLAN->init();
TheLAN->SetLocalIP(IP);
}
UnsignedInt ip = TheLAN->GetLocalIP();
ipstr.format(L"%d.%d.%d.%d", ip >> 24, (ip & 0xff0000) >> 16, (ip & 0xff00) >> 8, ip & 0xff);
GadgetStaticTextSetText(staticLocalIP, ipstr);
TheLAN->RequestLobbyLeave(true);
layout->hide(FALSE);
layout->bringForward();
TheTransitionHandler->setGroup("NetworkDirectConnectFade");
} // NetworkDirectConnectInit
//-------------------------------------------------------------------------------------------------
/** 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 );
} // end if
//-------------------------------------------------------------------------------------------------
/** WOL Welcome Menu shutdown method */
//-------------------------------------------------------------------------------------------------
void NetworkDirectConnectShutdown( WindowLayout *layout, void *userData )
{
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();
TheTransitionHandler->reverse("NetworkDirectConnectFade");
} // NetworkDirectConnectShutdown
//-------------------------------------------------------------------------------------------------
/** WOL Welcome Menu update method */
//-------------------------------------------------------------------------------------------------
void NetworkDirectConnectUpdate( WindowLayout * layout, void *userData)
{
// We'll only be successful if we've requested to
if(isShuttingDown && TheShell->isAnimFinished() && TheTransitionHandler->isFinished())
shutdownComplete(layout);
}// NetworkDirectConnectUpdate
//-------------------------------------------------------------------------------------------------
/** WOL Welcome Menu input callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType NetworkDirectConnectInput( 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;
}// NetworkDirectConnectInput
//-------------------------------------------------------------------------------------------------
/** WOL Welcome Menu window system callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType NetworkDirectConnectSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
UnicodeString txtInput;
switch( msg )
{
case GWM_CREATE:
{
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 GBM_SELECTED:
{
if (buttonPushed)
break;
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if ( controlID == buttonBackID )
{
UnicodeString name;
name = GadgetTextEntryGetText(editPlayerName);
LANPreferences prefs;
prefs["UserName"] = UnicodeStringToQuotedPrintable(name);
prefs.write();
while (name.getLength() > g_lanPlayerNameLength)
name.removeLastChar();
TheLAN->RequestSetName(name);
buttonPushed = true;
LANbuttonPushed = true;
TheShell->pop();
} //if ( controlID == buttonBack )
else if (controlID == buttonHostID)
{
HostDirectConnectGame();
}
else if (controlID == buttonJoinID)
{
JoinDirectConnectGame();
}
break;
}// case GBM_SELECTED:
case GEM_EDIT_DONE:
{
break;
}
default:
return MSG_IGNORED;
}//Switch
return MSG_HANDLED;
}// NetworkDirectConnectSystem

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,204 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: PopupCommunicator.cpp /////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Electronic Arts Pacific.
//
// Confidential Information
// Copyright (C) 2002 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// Project: RTS3
//
// File name: PopupCommunicator.cpp
//
// Created: Chris Brue, July 2002
//
// Desc: Electronic Arts instant messaging system
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "GameClient/GUICallbacks.h"
#include "GameClient/GameWindowManager.h"
// PRIVATE DATA ///////////////////////////////////////////////////////////////////////////////////
static NameKeyType buttonOkID = NAMEKEY_INVALID;
static GameWindow *buttonOk = NULL;
static GameWindow *parent = NULL;
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------------------------
/** Initialize the Popup Communicator */
//-------------------------------------------------------------------------------------------------
void PopupCommunicatorInit( WindowLayout *layout, void *userData )
{
//set keyboard focus to main parent and set modal
NameKeyType parentID = TheNameKeyGenerator->nameToKey("PopupCommunicator.wnd:PopupCommunicator");
parent = TheWindowManager->winGetWindowFromId( NULL, parentID );
TheWindowManager->winSetFocus( parent );
TheWindowManager->winSetModal( parent );
// get ids for our children controls
buttonOkID = TheNameKeyGenerator->nameToKey( AsciiString("PopupCommunicator.wnd:ButtonOk") );
buttonOk = TheWindowManager->winGetWindowFromId( parent, buttonOkID );
} // end PopupCommunicatorInit
//-------------------------------------------------------------------------------------------------
/** Popup Communicator shutdown method */
//-------------------------------------------------------------------------------------------------
void PopupCommunicatorShutdown( WindowLayout *layout, void *userData )
{
} // end PopupCommunicatorShutdown
//-------------------------------------------------------------------------------------------------
/** Popup Communicator update method */
//-------------------------------------------------------------------------------------------------
void PopupcommunicatorUpdate( WindowLayout *layout, void *userData )
{
} // end PopupCommunicatorUpdate
//-------------------------------------------------------------------------------------------------
/** Popup Communicator input callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType PopupCommunicatorInput( 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 ) )
{
TheWindowManager->winSendSystemMsg( window, GBM_SELECTED,
(WindowMsgData)buttonOk, buttonOkID );
} // 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 PopupCommunicatorInput
//-------------------------------------------------------------------------------------------------
/** Popup Communicator window system callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType PopupCommunicatorSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
switch( msg )
{
// --------------------------------------------------------------------------------------------
case GWM_CREATE:
{
break;
} // end create
//---------------------------------------------------------------------------------------------
case GWM_DESTROY:
{
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;
break;
} // end input
//---------------------------------------------------------------------------------------------
case GBM_SELECTED:
{
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if( controlID == buttonOkID )
{
WindowLayout *popupCommunicatorLayout = window->winGetLayout();
popupCommunicatorLayout->destroyWindows();
popupCommunicatorLayout->deleteInstance();
popupCommunicatorLayout = NULL;
} // end if
break;
} // end selected
default:
return MSG_IGNORED;
} // end switch
return MSG_HANDLED;
}

View File

@@ -0,0 +1,591 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: PopupHostGame.cpp /////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Electronic Arts Pacific.
//
// Confidential Information
// Copyright (C) 2002 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// created: Jul 2002
//
// Filename: PopupHostGame.cpp
//
// author: Chris Huybregts
//
// purpose: Contains the Callbacks for the Host Game Popus
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// USER INCLUDES //////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/GlobalData.h"
#include "Common/NameKeyGenerator.h"
#include "Common/Version.h"
#include "GameClient/WindowLayout.h"
#include "GameClient/Gadget.h"
#include "GameClient/GameText.h"
#include "GameClient/KeyDefs.h"
#include "GameClient/GadgetTextEntry.h"
#include "GameClient/GadgetCheckBox.h"
#include "GameClient/GadgetComboBox.h"
#include "GameClient/GadgetListBox.h"
#include "GameNetwork/GameSpy/GSConfig.h"
#include "GameNetwork/GameSpy/Peerdefs.h"
#include "GameNetwork/GameSpy/PeerThread.h"
#include "GameNetwork/GameSpyOverlay.h"
#include "GameNetwork/GameSpy/LadderDefs.h"
#include "Common/CustomMatchPreferences.h"
#include "Common/LadderPreferences.h"
//-----------------------------------------------------------------------------
// DEFINES ////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
static NameKeyType parentPopupID = NAMEKEY_INVALID;
static NameKeyType textEntryGameNameID = NAMEKEY_INVALID;
static NameKeyType buttonCreateGameID = NAMEKEY_INVALID;
static NameKeyType checkBoxAllowObserversID = NAMEKEY_INVALID;
static NameKeyType textEntryGameDescriptionID = NAMEKEY_INVALID;
static NameKeyType buttonCancelID = NAMEKEY_INVALID;
static NameKeyType textEntryLadderPasswordID = NAMEKEY_INVALID;
static NameKeyType comboBoxLadderNameID = NAMEKEY_INVALID;
static NameKeyType textEntryGamePasswordID = NAMEKEY_INVALID;
static GameWindow *parentPopup = NULL;
static GameWindow *textEntryGameName = NULL;
static GameWindow *buttonCreateGame = NULL;
static GameWindow *checkBoxAllowObservers = NULL;
static GameWindow *textEntryGameDescription = NULL;
static GameWindow *buttonCancel = NULL;
static GameWindow *comboBoxLadderName = NULL;
static GameWindow *textEntryLadderPassword = NULL;
static GameWindow *textEntryGamePassword = NULL;
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
void createGame( void );
//-----------------------------------------------------------------------------
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
// Ladders --------------------------------------------------------------------------------
static bool isPopulatingLadderBox = false;
void CustomMatchHideHostPopup(Bool hide)
{
if (!parentPopup)
return;
parentPopup->winHide( hide );
}
void HandleCustomLadderSelection(Int ladderID)
{
if (!parentPopup)
return;
CustomMatchPreferences pref;
if (ladderID == 0)
{
pref.setLastLadder(AsciiString::TheEmptyString, 0);
pref.write();
return;
}
const LadderInfo *info = TheLadderList->findLadderByIndex(ladderID);
if (!info)
{
pref.setLastLadder(AsciiString::TheEmptyString, 0);
}
else
{
pref.setLastLadder(info->address, info->port);
}
pref.write();
}
void PopulateCustomLadderListBox( GameWindow *win )
{
if (!parentPopup || !win)
return;
isPopulatingLadderBox = true;
CustomMatchPreferences pref;
Color specialColor = GameSpyColor[GSCOLOR_MAP_SELECTED];
Color normalColor = GameSpyColor[GSCOLOR_MAP_UNSELECTED];
Color favoriteColor = GameSpyColor[GSCOLOR_MAP_UNSELECTED];
Color localColor = GameSpyColor[GSCOLOR_MAP_UNSELECTED];
Int index;
GadgetListBoxReset( win );
std::set<const LadderInfo *> usedLadders;
// start with "No Ladder"
index = GadgetListBoxAddEntryText( win, TheGameText->fetch("GUI:NoLadder"), normalColor, -1 );
GadgetListBoxSetItemData( win, 0, index );
// add the last ladder
Int selectedPos = 0;
AsciiString lastLadderAddr = pref.getLastLadderAddr();
UnsignedShort lastLadderPort = pref.getLastLadderPort();
const LadderInfo *info = TheLadderList->findLadder( lastLadderAddr, lastLadderPort );
if (info && info->index > 0 && info->validCustom)
{
usedLadders.insert(info);
index = GadgetListBoxAddEntryText( win, info->name, favoriteColor, -1 );
GadgetListBoxSetItemData( win, (void *)(info->index), index );
selectedPos = index;
}
// our recent ladders
LadderPreferences ladPref;
ladPref.loadProfile( TheGameSpyInfo->getLocalProfileID() );
const LadderPrefMap recentLadders = ladPref.getRecentLadders();
for (LadderPrefMap::const_iterator cit = recentLadders.begin(); cit != recentLadders.end(); ++cit)
{
AsciiString addr = cit->second.address;
UnsignedShort port = cit->second.port;
if (addr == lastLadderAddr && port == lastLadderPort)
continue;
const LadderInfo *info = TheLadderList->findLadder( addr, port );
if (info && info->index > 0 && info->validCustom && usedLadders.find(info) == usedLadders.end())
{
usedLadders.insert(info);
index = GadgetListBoxAddEntryText( win, info->name, favoriteColor, -1 );
GadgetListBoxSetItemData( win, (void *)(info->index), index );
}
}
// local ladders
const LadderInfoList *lil = TheLadderList->getLocalLadders();
LadderInfoList::const_iterator lit;
for (lit = lil->begin(); lit != lil->end(); ++lit)
{
const LadderInfo *info = *lit;
if (info && info->index < 0 && info->validCustom && usedLadders.find(info) == usedLadders.end())
{
usedLadders.insert(info);
index = GadgetListBoxAddEntryText( win, info->name, localColor, -1 );
GadgetListBoxSetItemData( win, (void *)(info->index), index );
}
}
// special ladders
lil = TheLadderList->getSpecialLadders();
for (lit = lil->begin(); lit != lil->end(); ++lit)
{
const LadderInfo *info = *lit;
if (info && info->index > 0 && info->validCustom && usedLadders.find(info) == usedLadders.end())
{
usedLadders.insert(info);
index = GadgetListBoxAddEntryText( win, info->name, specialColor, -1 );
GadgetListBoxSetItemData( win, (void *)(info->index), index );
}
}
// standard ladders
lil = TheLadderList->getStandardLadders();
for (lit = lil->begin(); lit != lil->end(); ++lit)
{
const LadderInfo *info = *lit;
if (info && info->index > 0 && info->validCustom && usedLadders.find(info) == usedLadders.end())
{
usedLadders.insert(info);
index = GadgetListBoxAddEntryText( win, info->name, normalColor, -1 );
GadgetListBoxSetItemData( win, (void *)(info->index), index );
}
}
GadgetListBoxSetSelected( win, selectedPos );
isPopulatingLadderBox = false;
}
void PopulateCustomLadderComboBox( void )
{
if (!parentPopup || !comboBoxLadderName)
return;
isPopulatingLadderBox = true;
CustomMatchPreferences pref;
AsciiString userPrefFilename;
Int localProfile = TheGameSpyInfo->getLocalProfileID();
userPrefFilename.format("GeneralsOnline\\CustomPref%d.ini", localProfile);
pref.load(userPrefFilename);
std::set<const LadderInfo *> usedLadders;
Color specialColor = GameSpyColor[GSCOLOR_MAP_SELECTED];
Color normalColor = GameSpyColor[GSCOLOR_MAP_UNSELECTED];
Int index;
GadgetComboBoxReset( comboBoxLadderName );
index = GadgetComboBoxAddEntry( comboBoxLadderName, TheGameText->fetch("GUI:NoLadder"), normalColor );
GadgetComboBoxSetItemData( comboBoxLadderName, index, 0 );
Int selectedPos = 0;
AsciiString lastLadderAddr = pref.getLastLadderAddr();
UnsignedShort lastLadderPort = pref.getLastLadderPort();
const LadderInfo *info = TheLadderList->findLadder( lastLadderAddr, lastLadderPort );
if (info && info->validCustom)
{
usedLadders.insert(info);
index = GadgetComboBoxAddEntry( comboBoxLadderName, info->name, specialColor );
GadgetComboBoxSetItemData( comboBoxLadderName, index, (void *)(info->index) );
selectedPos = index;
}
LadderPreferences ladPref;
ladPref.loadProfile( localProfile );
const LadderPrefMap recentLadders = ladPref.getRecentLadders();
for (LadderPrefMap::const_iterator cit = recentLadders.begin(); cit != recentLadders.end(); ++cit)
{
AsciiString addr = cit->second.address;
UnsignedShort port = cit->second.port;
if (addr == lastLadderAddr && port == lastLadderPort)
continue;
const LadderInfo *info = TheLadderList->findLadder( addr, port );
if (info && info->validCustom && usedLadders.find(info) == usedLadders.end())
{
usedLadders.insert(info);
index = GadgetComboBoxAddEntry( comboBoxLadderName, info->name, normalColor );
GadgetComboBoxSetItemData( comboBoxLadderName, index, (void *)(info->index) );
}
}
index = GadgetComboBoxAddEntry( comboBoxLadderName, TheGameText->fetch("GUI:ChooseLadder"), normalColor );
GadgetComboBoxSetItemData( comboBoxLadderName, index, (void *)-1 );
GadgetComboBoxSetSelectedPos( comboBoxLadderName, selectedPos );
isPopulatingLadderBox = false;
}
// Window Functions -----------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
/** Initialize the PopupHostGameInit menu */
//-------------------------------------------------------------------------------------------------
void PopupHostGameInit( WindowLayout *layout, void *userData )
{
parentPopupID = TheNameKeyGenerator->nameToKey(AsciiString("PopupHostGame.wnd:ParentHostPopUp"));
parentPopup = TheWindowManager->winGetWindowFromId(NULL, parentPopupID);
textEntryGameNameID = TheNameKeyGenerator->nameToKey(AsciiString("PopupHostGame.wnd:TextEntryGameName"));
textEntryGameName = TheWindowManager->winGetWindowFromId(parentPopup, textEntryGameNameID);
UnicodeString name;
name.translate(TheGameSpyInfo->getLocalName());
GadgetTextEntrySetText(textEntryGameName, name);
textEntryGameDescriptionID = TheNameKeyGenerator->nameToKey(AsciiString("PopupHostGame.wnd:TextEntryGameDescription"));
textEntryGameDescription = TheWindowManager->winGetWindowFromId(parentPopup, textEntryGameDescriptionID);
GadgetTextEntrySetText(textEntryGameDescription, UnicodeString::TheEmptyString);
textEntryLadderPasswordID = TheNameKeyGenerator->nameToKey(AsciiString("PopupHostGame.wnd:TextEntryLadderPassword"));
textEntryLadderPassword = TheWindowManager->winGetWindowFromId(parentPopup, textEntryLadderPasswordID);
GadgetTextEntrySetText(textEntryLadderPassword, UnicodeString::TheEmptyString);
textEntryGamePasswordID = TheNameKeyGenerator->nameToKey(AsciiString("PopupHostGame.wnd:TextEntryGamePassword"));
textEntryGamePassword = TheWindowManager->winGetWindowFromId(parentPopup, textEntryGamePasswordID);
GadgetTextEntrySetText(textEntryGamePassword, UnicodeString::TheEmptyString);
buttonCreateGameID = TheNameKeyGenerator->nameToKey(AsciiString("PopupHostGame.wnd:ButtonCreateGame"));
buttonCreateGame = TheWindowManager->winGetWindowFromId(parentPopup, buttonCreateGameID);
buttonCancelID = TheNameKeyGenerator->nameToKey(AsciiString("PopupHostGame.wnd:ButtonCancel"));
buttonCancel = TheWindowManager->winGetWindowFromId(parentPopup, buttonCancelID);
checkBoxAllowObserversID = TheNameKeyGenerator->nameToKey(AsciiString("PopupHostGame.wnd:CheckBoxAllowObservers"));
checkBoxAllowObservers = TheWindowManager->winGetWindowFromId(parentPopup, checkBoxAllowObserversID);
CustomMatchPreferences customPref;
// disabling observers for Multiplayer test
#ifndef _PLAYTEST
GadgetCheckBoxSetChecked(checkBoxAllowObservers, customPref.allowsObservers());
#else
if (checkBoxAllowObservers)
{
GadgetCheckBoxSetChecked(checkBoxAllowObservers, FALSE);
checkBoxAllowObservers->winEnable(FALSE);
}
#endif
comboBoxLadderNameID = TheNameKeyGenerator->nameToKey(AsciiString("PopupHostGame.wnd:ComboBoxLadderName"));
comboBoxLadderName = TheWindowManager->winGetWindowFromId(parentPopup, comboBoxLadderNameID);
if (comboBoxLadderName)
GadgetComboBoxReset(comboBoxLadderName);
PopulateCustomLadderComboBox();
TheWindowManager->winSetFocus( parentPopup );
TheWindowManager->winSetModal( parentPopup );
}
//-------------------------------------------------------------------------------------------------
/** PopupHostGameInput callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType PopupHostGameInput( 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)buttonCancel, buttonCancelID );
} // 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;
}
//-------------------------------------------------------------------------------------------------
/** PopupHostGameSystem callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType PopupHostGameSystem( GameWindow *window, UnsignedInt msg, WindowMsgData mData1, WindowMsgData mData2 )
{
switch( msg )
{
// --------------------------------------------------------------------------------------------
case GWM_CREATE:
{
break;
} // end create
//---------------------------------------------------------------------------------------------
case GWM_DESTROY:
{
parentPopup = NULL;
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;
break;
} // end input
//----------------------------------------------------------------------------------------------
case GEM_UPDATE_TEXT:
{
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if ( controlID == textEntryGameNameID )
{
UnicodeString txtInput;
// grab the game's name
txtInput.set(GadgetTextEntryGetText( textEntryGameName ));
// Clean up the text (remove leading/trailing chars, etc)
const WideChar *c = txtInput.str();
while (c && (iswspace(*c)))
c++;
if (c)
txtInput = UnicodeString(c);
else
txtInput = UnicodeString::TheEmptyString;
// Put the whitespace-free version in the box
GadgetTextEntrySetText( textEntryGameName, txtInput );
}// if ( controlID == textEntryPlayerNameID )
break;
}//case GEM_UPDATE_TEXT:
//---------------------------------------------------------------------------------------------
case GCM_SELECTED:
{
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
Int pos = -1;
GadgetComboBoxGetSelectedPos(control, &pos);
if (controlID == comboBoxLadderNameID && !isPopulatingLadderBox)
{
if (pos >= 0)
{
Int ladderID = (Int)GadgetComboBoxGetItemData(control, pos);
if (ladderID < 0)
{
// "Choose a ladder" selected - open overlay
PopulateCustomLadderComboBox(); // this restores the non-"Choose a ladder" selection
GameSpyOpenOverlay( GSOVERLAY_LADDERSELECT );
}
}
}
break;
} // case GCM_SELECTED
//---------------------------------------------------------------------------------------------
case GBM_SELECTED:
{
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if( controlID == buttonCancelID )
{
parentPopup = NULL;
GameSpyCloseOverlay(GSOVERLAY_GAMEOPTIONS);
SetLobbyAttemptHostJoin( FALSE );
}
else if( controlID == buttonCreateGameID)
{
UnicodeString name;
name = GadgetTextEntryGetText(textEntryGameName);
name.trim();
if(name.getLength() <= 0)
{
name.translate(TheGameSpyInfo->getLocalName());
GadgetTextEntrySetText(textEntryGameName, name);
}
createGame();
parentPopup = NULL;
GameSpyCloseOverlay(GSOVERLAY_GAMEOPTIONS);
}
break;
}
default:
return MSG_IGNORED;
} // end switch
return MSG_HANDLED;
}
//-----------------------------------------------------------------------------
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
void createGame( void )
{
TheGameSpyInfo->setCurrentGroupRoom(0);
PeerRequest req;
UnicodeString gameName = GadgetTextEntryGetText(textEntryGameName);
req.peerRequestType = PeerRequest::PEERREQUEST_CREATESTAGINGROOM;
req.text = gameName.str();
TheGameSpyGame->setGameName(gameName);
AsciiString passwd;
passwd.translate(GadgetTextEntryGetText(textEntryGamePassword));
req.password = passwd.str();
CustomMatchPreferences customPref;
Bool aO = GadgetCheckBoxIsChecked(checkBoxAllowObservers);
customPref.setAllowsObserver(aO);
customPref.write();
req.stagingRoomCreation.allowObservers = aO;
TheGameSpyGame->setAllowObservers(aO);
req.stagingRoomCreation.exeCRC = TheGlobalData->m_exeCRC;
req.stagingRoomCreation.iniCRC = TheGlobalData->m_iniCRC;
req.stagingRoomCreation.gameVersion = TheGameSpyInfo->getInternalIP();
req.stagingRoomCreation.restrictGameList = TheGameSpyConfig->restrictGamesToLobby();
Int ladderSelectPos = -1, ladderID = -1;
GadgetComboBoxGetSelectedPos(comboBoxLadderName, &ladderSelectPos);
req.ladderIP = "localhost";
req.stagingRoomCreation.ladPort = 0;
if (ladderSelectPos >= 0)
{
ladderID = (Int)GadgetComboBoxGetItemData(comboBoxLadderName, ladderSelectPos);
if (ladderID != 0)
{
// actual ladder
const LadderInfo *info = TheLadderList->findLadderByIndex(ladderID);
if (info)
{
req.ladderIP = info->address.str();
req.stagingRoomCreation.ladPort = info->port;
}
}
}
TheGameSpyGame->setLadderIP(req.ladderIP.c_str());
TheGameSpyGame->setLadderPort(req.stagingRoomCreation.ladPort);
req.hostPingStr = TheGameSpyInfo->getPingString().str();
TheGameSpyPeerMessageQueue->addRequest(req);
}

View File

@@ -0,0 +1,263 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: PopupJoinGame.cpp /////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Electronic Arts Pacific.
//
// Confidential Information
// Copyright (C) 2002 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// created: Jul 2002
//
// Filename: PopupJoinGame.cpp
//
// author: Matthew D. Campbell
//
// purpose: Contains the Callbacks for the Join Game Popup
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// USER INCLUDES //////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/GlobalData.h"
#include "Common/NameKeyGenerator.h"
#include "GameClient/WindowLayout.h"
#include "GameClient/Gadget.h"
#include "GameClient/KeyDefs.h"
#include "GameClient/GadgetTextEntry.h"
#include "GameClient/GadgetStaticText.h"
#include "GameNetwork/GameSpy/Peerdefs.h"
#include "GameNetwork/GameSpy/PeerThread.h"
#include "GameNetwork/GameSpyOverlay.h"
//-----------------------------------------------------------------------------
// DEFINES ////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
static NameKeyType parentPopupID = NAMEKEY_INVALID;
static NameKeyType textEntryGamePasswordID = NAMEKEY_INVALID;
static NameKeyType buttonCancelID = NAMEKEY_INVALID;
static GameWindow *parentPopup = NULL;
static GameWindow *textEntryGamePassword = NULL;
static void joinGame( AsciiString password );
//-----------------------------------------------------------------------------
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
/** Initialize the PopupHostGameInit menu */
//-------------------------------------------------------------------------------------------------
void PopupJoinGameInit( WindowLayout *layout, void *userData )
{
parentPopupID = TheNameKeyGenerator->nameToKey(AsciiString("PopupJoinGame.wnd:ParentJoinPopUp"));
parentPopup = TheWindowManager->winGetWindowFromId(NULL, parentPopupID);
textEntryGamePasswordID = TheNameKeyGenerator->nameToKey(AsciiString("PopupJoinGame.wnd:TextEntryGamePassword"));
textEntryGamePassword = TheWindowManager->winGetWindowFromId(parentPopup, textEntryGamePasswordID);
GadgetTextEntrySetText(textEntryGamePassword, UnicodeString::TheEmptyString);
NameKeyType staticTextGameNameID = TheNameKeyGenerator->nameToKey(AsciiString("PopupJoinGame.wnd:StaticTextGameName"));
GameWindow *staticTextGameName = TheWindowManager->winGetWindowFromId(parentPopup, staticTextGameNameID);
GadgetStaticTextSetText(staticTextGameName, UnicodeString::TheEmptyString);
buttonCancelID = NAMEKEY("PopupJoinGame.wnd:ButtonCancel");
GameSpyStagingRoom *ourRoom = TheGameSpyInfo->findStagingRoomByID(TheGameSpyInfo->getCurrentStagingRoomID());
if (ourRoom)
GadgetStaticTextSetText(staticTextGameName, ourRoom->getGameName());
TheWindowManager->winSetFocus( parentPopup );
TheWindowManager->winSetModal( parentPopup );
}
//-------------------------------------------------------------------------------------------------
/** PopupHostGameInput callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType PopupJoinGameInput( 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 ) )
{
GameSpyCloseOverlay(GSOVERLAY_GAMEPASSWORD);
SetLobbyAttemptHostJoin( FALSE );
parentPopup = NULL;
} // 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;
}
//-------------------------------------------------------------------------------------------------
/** PopupHostGameSystem callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType PopupJoinGameSystem( GameWindow *window, UnsignedInt msg, WindowMsgData mData1, WindowMsgData mData2 )
{
switch( msg )
{
// --------------------------------------------------------------------------------------------
case GWM_CREATE:
{
break;
} // end create
//---------------------------------------------------------------------------------------------
case GWM_DESTROY:
{
break;
} // end case
//---------------------------------------------------------------------------------------------
case GBM_SELECTED:
{
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if (controlID == buttonCancelID)
{
GameSpyCloseOverlay(GSOVERLAY_GAMEPASSWORD);
SetLobbyAttemptHostJoin( FALSE );
parentPopup = NULL;
}
break;
}
//----------------------------------------------------------------------------------------------
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;
break;
} // end input
//---------------------------------------------------------------------------------------------
case GEM_EDIT_DONE:
{
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if( controlID == textEntryGamePasswordID )
{
// read the user's input and clear the entry box
UnicodeString txtInput;
txtInput.set(GadgetTextEntryGetText( textEntryGamePassword ));
GadgetTextEntrySetText(textEntryGamePassword, UnicodeString::TheEmptyString);
txtInput.trim();
if (!txtInput.isEmpty())
{
AsciiString munkee;
munkee.translate(txtInput);
joinGame(munkee);
}
}
break;
}
default:
return MSG_IGNORED;
} // end switch
return MSG_HANDLED;
}
//-----------------------------------------------------------------------------
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
static void joinGame( AsciiString password )
{
GameSpyStagingRoom *ourRoom = TheGameSpyInfo->findStagingRoomByID(TheGameSpyInfo->getCurrentStagingRoomID());
if (!ourRoom)
{
GameSpyCloseOverlay(GSOVERLAY_GAMEPASSWORD);
SetLobbyAttemptHostJoin( FALSE );
parentPopup = NULL;
return;
}
PeerRequest req;
req.peerRequestType = PeerRequest::PEERREQUEST_JOINSTAGINGROOM;
req.text = ourRoom->getGameName().str();
req.stagingRoom.id = ourRoom->getID();
req.password = password.str();
TheGameSpyPeerMessageQueue->addRequest(req);
DEBUG_LOG(("Attempting to join game %d(%ls) with password [%s]\n", ourRoom->getID(), ourRoom->getGameName().str(), password.str()));
GameSpyCloseOverlay(GSOVERLAY_GAMEPASSWORD);
parentPopup = NULL;
}

View File

@@ -0,0 +1,682 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: PopupLadderSelect.cpp ////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Electronic Arts Pacific.
//
// Confidential Information
// Copyright (C) 2002 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// created: August 2002
//
// Filename: PopupLadderSelect.cpp
//
// author: Matthew D. Campbell
//
// purpose: Contains the Callbacks for the Ladder Select Popup
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// USER INCLUDES //////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/GlobalData.h"
#include "Common/Encrypt.h"
#include "Common/NameKeyGenerator.h"
#include "GameClient/WindowLayout.h"
#include "GameClient/Gadget.h"
#include "GameClient/GameText.h"
#include "GameClient/KeyDefs.h"
#include "GameClient/MapUtil.h"
#include "GameClient/GadgetListBox.h"
#include "GameClient/GadgetStaticText.h"
#include "GameClient/GadgetTextEntry.h"
#include "GameNetwork/GameSpy/LadderDefs.h"
#include "GameNetwork/GameSpy/PeerDefs.h"
//#include "GameNetwork/GameSpy/PeerThread.h"
#include "GameNetwork/GameSpyOverlay.h"
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
//-----------------------------------------------------------------------------
// DEFINES ////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
static NameKeyType parentID = NAMEKEY_INVALID;
static NameKeyType listboxLadderSelectID = NAMEKEY_INVALID;
static NameKeyType listboxLadderDetailsID = NAMEKEY_INVALID;
static NameKeyType staticTextLadderNameID = NAMEKEY_INVALID;
static NameKeyType buttonOkID = NAMEKEY_INVALID;
static NameKeyType buttonCancelID = NAMEKEY_INVALID;
static GameWindow *parent = NULL;
static GameWindow *listboxLadderSelect = NULL;
static GameWindow *listboxLadderDetails = NULL;
static GameWindow *staticTextLadderName = NULL;
static GameWindow *buttonOk = NULL;
static GameWindow *buttonCancel = NULL;
// password entry popup
static NameKeyType passwordParentID = NAMEKEY_INVALID;
static NameKeyType buttonPasswordOkID = NAMEKEY_INVALID;
static NameKeyType buttonPasswordCancelID = NAMEKEY_INVALID;
static NameKeyType textEntryPasswordID = NAMEKEY_INVALID;
static GameWindow *passwordParent = NULL;
static GameWindow *textEntryPassword = NULL;
// incorrect password popup
static NameKeyType badPasswordParentID = NAMEKEY_INVALID;
static NameKeyType buttonBadPasswordOkID = NAMEKEY_INVALID;
static GameWindow *badPasswordParent = NULL;
static void updateLadderDetails( Int ladderID, GameWindow *staticTextLadderName, GameWindow *listboxLadderDetails );
void PopulateQMLadderComboBox( void );
void PopulateCustomLadderComboBox( void );
void PopulateQMLadderListBox( GameWindow *win );
void PopulateCustomLadderListBox( GameWindow *win );
void HandleQMLadderSelection(Int ladderID);
void HandleCustomLadderSelection(Int ladderID);
void CustomMatchHideHostPopup(Bool hide);
static void populateLadderComboBox( void )
{
// only one of these will do any work...
PopulateQMLadderComboBox();
PopulateCustomLadderComboBox();
}
static void populateLadderListBox( void )
{
// only one of these will do any work...
PopulateQMLadderListBox(listboxLadderSelect);
PopulateCustomLadderListBox(listboxLadderSelect);
Int selIndex, selID;
GadgetListBoxGetSelected(listboxLadderSelect, &selIndex);
if (selIndex < 0)
return;
selID = (Int)GadgetListBoxGetItemData(listboxLadderSelect, selIndex);
if (!selID)
return;
updateLadderDetails(selID, staticTextLadderName, listboxLadderDetails);
}
static void handleLadderSelection( Int ladderID )
{
// only one of these will do any work...
HandleQMLadderSelection(ladderID);
HandleCustomLadderSelection(ladderID);
}
enum PasswordMode
{
PASS_NONE,
PASS_ENTRY,
PASS_ERROR
};
static PasswordMode s_currentMode = PASS_NONE;
static void setPasswordMode(PasswordMode mode)
{
s_currentMode = mode;
switch(mode)
{
case PASS_NONE:
if (passwordParent)
passwordParent->winHide(TRUE);
if (badPasswordParent)
badPasswordParent->winHide(TRUE);
if (buttonOk)
buttonOk->winEnable(TRUE);
if (buttonCancel)
buttonCancel->winEnable(TRUE);
if (textEntryPassword)
textEntryPassword->winEnable(FALSE);
if (listboxLadderSelect)
listboxLadderSelect->winEnable(TRUE);
TheWindowManager->winSetFocus(listboxLadderSelect);
break;
case PASS_ENTRY:
if (passwordParent)
passwordParent->winHide(FALSE);
if (badPasswordParent)
badPasswordParent->winHide(TRUE);
if (buttonOk)
buttonOk->winEnable(FALSE);
if (buttonCancel)
buttonCancel->winEnable(FALSE);
if (textEntryPassword)
{
textEntryPassword->winEnable(TRUE);
GadgetTextEntrySetText(textEntryPassword, UnicodeString::TheEmptyString);
}
if (listboxLadderSelect)
listboxLadderSelect->winEnable(FALSE);
TheWindowManager->winSetFocus(textEntryPassword);
break;
case PASS_ERROR:
if (passwordParent)
passwordParent->winHide(TRUE);
if (badPasswordParent)
badPasswordParent->winHide(FALSE);
if (buttonOk)
buttonOk->winEnable(FALSE);
if (buttonCancel)
buttonCancel->winEnable(FALSE);
if (textEntryPassword)
textEntryPassword->winEnable(FALSE);
if (listboxLadderSelect)
listboxLadderSelect->winEnable(FALSE);
TheWindowManager->winSetFocus(parent);
break;
}
}
//-----------------------------------------------------------------------------
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
/** Initialize the menu */
//-------------------------------------------------------------------------------------------------
void PopupLadderSelectInit( WindowLayout *layout, void *userData )
{
parentID = NAMEKEY("PopupLadderSelect.wnd:Parent");
parent = TheWindowManager->winGetWindowFromId(NULL, parentID);
listboxLadderSelectID = NAMEKEY("PopupLadderSelect.wnd:ListBoxLadderSelect");
listboxLadderSelect = TheWindowManager->winGetWindowFromId(parent, listboxLadderSelectID);
listboxLadderDetailsID = NAMEKEY("PopupLadderSelect.wnd:ListBoxLadderDetails");
listboxLadderDetails = TheWindowManager->winGetWindowFromId(parent, listboxLadderDetailsID);
staticTextLadderNameID = NAMEKEY("PopupLadderSelect.wnd:StaticTextLadderName");
staticTextLadderName = TheWindowManager->winGetWindowFromId(parent, staticTextLadderNameID);
buttonOkID = NAMEKEY("PopupLadderSelect.wnd:ButtonOk");
buttonCancelID = NAMEKEY("PopupLadderSelect.wnd:ButtonCancel");
buttonOk = TheWindowManager->winGetWindowFromId(parent, buttonOkID);
buttonCancel = TheWindowManager->winGetWindowFromId(parent, buttonCancelID);
TheWindowManager->winSetFocus( parent );
TheWindowManager->winSetModal( parent );
// password entry popup
passwordParentID = NAMEKEY("PopupLadderSelect.wnd:PasswordParent");
passwordParent = TheWindowManager->winGetWindowFromId(parent, passwordParentID);
buttonPasswordOkID = NAMEKEY("PopupLadderSelect.wnd:ButtonPasswordOk");
buttonPasswordCancelID = NAMEKEY("PopupLadderSelect.wnd:ButtonPasswordCancel");
textEntryPasswordID = NAMEKEY("PopupLadderSelect.wnd:PasswordEntry");
textEntryPassword = TheWindowManager->winGetWindowFromId(parent, textEntryPasswordID);
// bad password popup
badPasswordParentID = NAMEKEY("PopupLadderSelect.wnd:BadPasswordParent");
badPasswordParent = TheWindowManager->winGetWindowFromId(parent, badPasswordParentID);
buttonBadPasswordOkID = NAMEKEY("PopupLadderSelect.wnd:ButtonBadPasswordOk");
setPasswordMode(PASS_NONE);
CustomMatchHideHostPopup(TRUE);
// populate list box (based on whether we're in custom or quickmatch)
populateLadderListBox();
}
//-------------------------------------------------------------------------------------------------
/** Input callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType PopupLadderSelectInput( 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 ) )
{
switch (s_currentMode)
{
case PASS_NONE:
// re-select whatever was chosen before
populateLadderComboBox();
GameSpyCloseOverlay(GSOVERLAY_LADDERSELECT);
break;
case PASS_ENTRY:
case PASS_ERROR:
setPasswordMode(PASS_NONE);
break;
}
} // 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;
}
static Int ladderIndex = 0;
void ladderSelectedCallback(void)
{
handleLadderSelection( ladderIndex );
// update combo box
populateLadderComboBox();
// tear down overlay
GameSpyCloseOverlay( GSOVERLAY_LADDERSELECT );
}
//-------------------------------------------------------------------------------------------------
/** System callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType PopupLadderSelectSystem( GameWindow *window, UnsignedInt msg, WindowMsgData mData1, WindowMsgData mData2 )
{
switch( msg )
{
// --------------------------------------------------------------------------------------------
case GWM_CREATE:
{
break;
} // end create
//---------------------------------------------------------------------------------------------
case GWM_DESTROY:
{
parent = NULL;
listboxLadderSelect = NULL;
listboxLadderDetails = NULL;
CustomMatchHideHostPopup(FALSE);
break;
} // end case
//----------------------------------------------------------------------------------------------
case GWM_INPUT_FOCUS:
{
// if we're given the opportunity to take the keyboard focus we must say we want it
if( mData1 == TRUE )
*(Bool *)mData2 = TRUE;
break;
} // end input
//----------------------------------------------------------------------------------------------
case GBM_SELECTED:
{
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if (controlID == buttonOkID)
{
// save selection
Int selectPos = -1;
GadgetListBoxGetSelected( listboxLadderSelect, &selectPos );
if (selectPos < 0)
break;
ladderIndex = (Int)GadgetListBoxGetItemData( listboxLadderSelect, selectPos, 0 );
const LadderInfo *li = TheLadderList->findLadderByIndex( ladderIndex );
if (li && li->cryptedPassword.isNotEmpty())
{
// need password asking
setPasswordMode(PASS_ENTRY);
}
else
{
ladderSelectedCallback();
}
}
else if (controlID == buttonCancelID)
{
// reset what had been
populateLadderComboBox();
// tear down overlay
GameSpyCloseOverlay( GSOVERLAY_LADDERSELECT );
}
else if (controlID == buttonPasswordOkID)
{
const LadderInfo *li = TheLadderList->findLadderByIndex( ladderIndex );
if (!li || li->cryptedPassword.isEmpty())
{
// eh? something's not right. just pretend they typed something wrong...
setPasswordMode(PASS_ERROR);
break;
}
AsciiString pass;
pass.translate(GadgetTextEntryGetText(textEntryPassword));
if ( pass.isNotEmpty() ) // password ok
{
AsciiString cryptPass = EncryptString(pass.str());
DEBUG_LOG(("pass is %s, crypted pass is %s, comparing to %s\n",
pass.str(), cryptPass.str(), li->cryptedPassword.str()));
if (cryptPass == li->cryptedPassword)
ladderSelectedCallback();
else
setPasswordMode(PASS_ERROR);
}
else
{
setPasswordMode(PASS_ERROR);
}
}
else if (controlID == buttonPasswordCancelID)
{
setPasswordMode(PASS_NONE);
}
else if (controlID == buttonBadPasswordOkID)
{
setPasswordMode(PASS_NONE);
}
break;
} // end input
//---------------------------------------------------------------------------------------------
case GLM_SELECTED:
{
Int selIndex, selID;
GadgetListBoxGetSelected(listboxLadderSelect, &selIndex);
if (selIndex < 0)
break;
selID = (Int)GadgetListBoxGetItemData(listboxLadderSelect, selIndex);
if (!selID)
break;
updateLadderDetails(selID, staticTextLadderName, listboxLadderDetails);
break;
} // end GLM_DOUBLE_CLICKED
//---------------------------------------------------------------------------------------------
case GLM_DOUBLE_CLICKED:
{
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
Int selectPos = (Int)mData2;
GadgetListBoxSetSelected(control, &selectPos);
if( controlID == listboxLadderSelectID )
{
TheWindowManager->winSendSystemMsg( parent, GBM_SELECTED,
(WindowMsgData)buttonOk, buttonOk->winGetWindowId() );
}
break;
}
//---------------------------------------------------------------------------------------------
case GEM_EDIT_DONE:
{
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if (controlID == textEntryPasswordID)
{
TheWindowManager->winSendSystemMsg( parent, GBM_SELECTED,
(WindowMsgData)(TheWindowManager->winGetWindowFromId(passwordParent, buttonPasswordOkID)), buttonPasswordOkID );
}
break;
}
default:
return MSG_IGNORED;
} // end switch
return MSG_HANDLED;
}
//-----------------------------------------------------------------------------
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
static void updateLadderDetails( Int selID, GameWindow *staticTextLadderName, GameWindow *listboxLadderDetails )
{
if (!staticTextLadderName || !listboxLadderDetails)
return;
GadgetStaticTextSetText(staticTextLadderName, UnicodeString::TheEmptyString);
GadgetListBoxReset(listboxLadderDetails);
const LadderInfo *info = TheLadderList->findLadderByIndex(selID);
if (!info)
return;
UnicodeString line;
Color color = GameMakeColor( 255, 255, 255, 255 );
Color captionColor = GameMakeColor( 0, 255, 255, 255 );
// name
line.format(TheGameText->fetch("GUI:LadderNameAndSize"), info->name.str(), info->playersPerTeam, info->playersPerTeam);
GadgetStaticTextSetText(staticTextLadderName, line);
// location
if (!info->location.isEmpty())
GadgetListBoxAddEntryText(listboxLadderDetails, info->location, captionColor, -1);
// homepage
line.format(TheGameText->fetch("GUI:LadderURL"), info->homepageURL.str());
GadgetListBoxAddEntryText(listboxLadderDetails, line, captionColor, -1);
// description
if (!info->description.isEmpty())
GadgetListBoxAddEntryText(listboxLadderDetails, info->description, color, -1);
// requires password?
if (info->cryptedPassword.isNotEmpty())
{
GadgetListBoxAddEntryText(listboxLadderDetails, TheGameText->fetch("GUI:LadderHasPassword"), captionColor, -1);
}
// wins limits
if (info->minWins)
{
line.format(TheGameText->fetch("GUI:LadderMinWins"), info->minWins);
GadgetListBoxAddEntryText(listboxLadderDetails, line, captionColor, -1);
}
if (info->maxWins)
{
line.format(TheGameText->fetch("GUI:LadderMaxWins"), info->maxWins);
GadgetListBoxAddEntryText(listboxLadderDetails, line, captionColor, -1);
}
// random factions?
if (info->randomFactions)
{
GadgetListBoxAddEntryText(listboxLadderDetails, TheGameText->fetch("GUI:LadderRandomFactions"), captionColor, -1);
}
else
{
GadgetListBoxAddEntryText(listboxLadderDetails, TheGameText->fetch("GUI:LadderFactions"), captionColor, -1);
}
// factions
AsciiStringList validFactions = info->validFactions;
for (AsciiStringListIterator it = validFactions.begin(); it != validFactions.end(); ++it)
{
AsciiString marker;
marker.format("INI:Faction%s", it->str());
GadgetListBoxAddEntryText(listboxLadderDetails, TheGameText->fetch(marker), color, -1);
}
// random maps?
if (info->randomMaps)
{
GadgetListBoxAddEntryText(listboxLadderDetails, TheGameText->fetch("GUI:LadderRandomMaps"), captionColor, -1);
}
else
{
GadgetListBoxAddEntryText(listboxLadderDetails, TheGameText->fetch("GUI:LadderMaps"), captionColor, -1);
}
// maps
AsciiStringList validMaps = info->validMaps;
for (it = validMaps.begin(); it != validMaps.end(); ++it)
{
const MapMetaData *md = TheMapCache->findMap(*it);
if (md)
{
GadgetListBoxAddEntryText(listboxLadderDetails, md->m_displayName, color, -1);
}
}
}
static void closeRightClickMenu(GameWindow *win)
{
if(win)
{
WindowLayout *winLay = win->winGetLayout();
if(!winLay)
return;
winLay->destroyWindows();
winLay->deleteInstance();
winLay = NULL;
}
}
void RCGameDetailsMenuInit( WindowLayout *layout, void *userData )
{
}
WindowMsgHandledType RCGameDetailsMenuSystem( GameWindow *window, UnsignedInt msg, WindowMsgData mData1, WindowMsgData mData2 )
{
static NameKeyType ladderInfoID = NAMEKEY_INVALID;
static NameKeyType buttonOkID = NAMEKEY_INVALID;
switch( msg )
{
case GWM_CREATE:
{
ladderInfoID = NAMEKEY("RCGameDetailsMenu.wnd:ButtonLadderDetails");
buttonOkID = NAMEKEY("PopupLadderDetails.wnd:ButtonOk");
break;
} // case GWM_DESTROY:
case GGM_CLOSE:
{
closeRightClickMenu(window);
//rcMenu = NULL;
break;
}
case GWM_DESTROY:
{
break;
} // case GWM_DESTROY:
case GBM_SELECTED:
{
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
Int selectedID = (Int)window->winGetUserData();
if(!selectedID)
break;
closeRightClickMenu(window);
if (controlID == ladderInfoID)
{
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)
{
WindowLayout *rcLayout = TheWindowManager->winCreateLayout(AsciiString("Menus/PopupLadderDetails.wnd"));
if (!rcLayout)
break;
GameWindow *rcMenu = rcLayout->getFirstWindow();
rcMenu->winGetLayout()->runInit();
rcMenu->winBringToTop();
rcMenu->winHide(FALSE);
rcMenu->winSetUserData((void *)selectedID);
TheWindowManager->winSetLoneWindow(rcMenu);
GameWindow *st = TheWindowManager->winGetWindowFromId(NULL,
NAMEKEY("PopupLadderDetails.wnd:StaticTextLadderName"));
GameWindow *lb = TheWindowManager->winGetWindowFromId(NULL,
NAMEKEY("PopupLadderDetails.wnd:ListBoxLadderDetails"));
updateLadderDetails(selectedID, st, lb);
}
}
}
break;
}
default:
return MSG_IGNORED;
}//Switch
return MSG_HANDLED;
}

View File

@@ -0,0 +1,488 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: PopupReplay.cpp /////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Electronic Arts Pacific.
//
// Confidential Information
// Copyright (C) 2002 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// Project: Generals
//
// File name: PopupReplay.cpp
//
// Created: Matthew D. Campbell, November 2002
//
// Desc: the Replay Save window control
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/LocalFileSystem.h"
#include "Common/MessageStream.h"
#include "Common/Recorder.h"
#include "GameClient/GadgetListBox.h"
#include "GameClient/GadgetTextEntry.h"
#include "GameClient/GameText.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/GUICallbacks.h"
#include "GameClient/MessageBox.h"
#include "GameClient/Shell.h"
#include "GameLogic/GameLogic.h"
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
// PRIVATE DATA ///////////////////////////////////////////////////////////////////////////////////
static NameKeyType buttonBackKey = NAMEKEY_INVALID;
static NameKeyType buttonSaveKey = NAMEKEY_INVALID;
static NameKeyType listboxGamesKey = NAMEKEY_INVALID;
static NameKeyType textEntryReplayNameKey = NAMEKEY_INVALID;
static GameWindow *parent = NULL;
static GameWindow *replaySavedParent = NULL;
static time_t s_fileSavePopupStartTime = 0;
static const time_t s_fileSavePopupDuration = 1000;
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
extern void PopulateReplayFileListbox(GameWindow *listbox);
extern void ScoreScreenEnableControls(Bool enable);
extern UnicodeString GetReplayFilenameFromListbox(GameWindow *listbox, Int index);
extern std::string LastReplayFileName;
//-------------------------------------------------------------------------------------------------
/** Show or hide the "Replay Saved" popup */
//-------------------------------------------------------------------------------------------------
void ShowReplaySavedPopup(Bool show)
{
if (replaySavedParent != NULL) {
if (show) {
replaySavedParent->winHide(FALSE);
} else {
replaySavedParent->winHide(TRUE);
}
}
}
// ------------------------------------------------------------------------------------------------
/** Close the save/load menu */
// ------------------------------------------------------------------------------------------------
static void closeSaveMenu( GameWindow *window )
{
WindowLayout *layout = window->winGetLayout();
if( layout )
layout->hide( TRUE );
} // end closeSaveMenu
//-------------------------------------------------------------------------------------------------
/** Initialize the SaveLoad menu */
//-------------------------------------------------------------------------------------------------
void PopupReplayInit( WindowLayout *layout, void *userData )
{
// get ids for our children controls
buttonBackKey = NAMEKEY( "PopupReplay.wnd:ButtonBack" );
buttonSaveKey = NAMEKEY( "PopupReplay.wnd:ButtonSave" );
listboxGamesKey = NAMEKEY( "PopupReplay.wnd:ListboxGames" );
textEntryReplayNameKey = NAMEKEY( "PopupReplay.wnd:TextEntryReplayName" );
//set keyboard focus to main parent and set modal
NameKeyType parentID = TheNameKeyGenerator->nameToKey("PopupReplay.wnd:PopupReplayMenu");
parent = TheWindowManager->winGetWindowFromId( NULL, parentID );
TheWindowManager->winSetFocus( parent );
NameKeyType replaySavedParentID = TheNameKeyGenerator->nameToKey("PopupReplay.wnd:PopupReplaySaved");
replaySavedParent = TheWindowManager->winGetWindowFromId( NULL, replaySavedParentID);
if (replaySavedParent == NULL) {
DEBUG_CRASH(("replaySavedParent == NULL"));
}
ShowReplaySavedPopup(FALSE);
// enable the menu action buttons
GameWindow *buttonFrame = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupReplay.wnd:MenuButtonFrame" ) );
buttonFrame->winEnable( TRUE );
// get the listbox that will have the save games in it
GameWindow *listboxGames = TheWindowManager->winGetWindowFromId( NULL, listboxGamesKey );
DEBUG_ASSERTCRASH( listboxGames != NULL, ("PopupReplayInit - Unable to find games listbox\n") );
// populate the listbox with the save games on disk
PopulateReplayFileListbox(listboxGames);
GameWindow *textEntryReplayName = TheWindowManager->winGetWindowFromId( parent, textEntryReplayNameKey );
GadgetTextEntrySetText(textEntryReplayName, UnicodeString::TheEmptyString);
TheWindowManager->winSetFocus( textEntryReplayName );
//Disable the button immediately as the code above us starts off with an empty string.
GameWindow *control = TheWindowManager->winGetWindowFromId( parent, buttonSaveKey );
if( control )
{
control->winEnable( FALSE );
}
} // end SaveLoadMenuInit
//-------------------------------------------------------------------------------------------------
/** SaveLoad menu shutdown method */
//-------------------------------------------------------------------------------------------------
void PopupReplayShutdown( WindowLayout *layout, void *userData )
{
parent = NULL;
} // end SaveLoadMenuShutdown
//-------------------------------------------------------------------------------------------------
/** SaveLoad menu update method */
//-------------------------------------------------------------------------------------------------
void PopupReplayUpdate( WindowLayout *layout, void *userData )
{
if (s_fileSavePopupStartTime != 0)
{
// the replay save confirmation popup is up
// check to see if its time to take it down.
if ((timeGetTime() - s_fileSavePopupStartTime) >= s_fileSavePopupDuration)
{
ShowReplaySavedPopup(FALSE);
// close the save/load menu
closeSaveMenu( parent );
ScoreScreenEnableControls(TRUE);
// reset the timer to 0 cause we have to.
s_fileSavePopupStartTime = 0;
}
}
} // end SaveLoadMenuUpdate
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
WindowMsgHandledType PopupReplayInput( 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 ) )
{
GameWindow *button = TheWindowManager->winGetWindowFromId( parent, buttonBackKey );
TheWindowManager->winSendSystemMsg( window, GBM_SELECTED,
(WindowMsgData)button, buttonBackKey );
} // 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;
}
static void reallySaveReplay(void);
static std::string replayPath;
// ------------------------------------------------------------------------------------------------
/** Save the replay */
// ------------------------------------------------------------------------------------------------
static GameWindow *messageBoxWin = NULL;
static void saveReplay( UnicodeString filename )
{
AsciiString translated;
if (filename == TheGameText->fetch("GUI:LastReplay"))
{
translated = TheRecorder->getLastReplayFileName();
}
else
{
translated.translate(filename);
}
AsciiString fullPath = TheRecorder->getReplayDir();
fullPath.concat(translated);
fullPath.concat(TheRecorder->getReplayExtention());
replayPath = fullPath.str();
messageBoxWin = NULL;
if (TheLocalFileSystem->doesFileExist(fullPath.str()))
{
messageBoxWin = MessageBoxOkCancel(TheGameText->fetch("GUI:OverwriteReplayTitle"), TheGameText->fetch("GUI:OverwriteReplay"), reallySaveReplay, NULL);
}
else
{
reallySaveReplay();
}
}
void reallySaveReplay(void)
{
AsciiString filename = replayPath.c_str();
AsciiString oldFilename;
oldFilename = TheRecorder->getReplayDir();
oldFilename.concat(LastReplayFileName.c_str());
oldFilename.concat(TheRecorder->getReplayExtention());
if (oldFilename == filename)
return;
if (TheLocalFileSystem->doesFileExist(filename.str()))
{
if(DeleteFile(filename.str()) == 0)
{
wchar_t buffer[1024];
FormatMessageW ( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, buffer, sizeof(buffer), NULL);
UnicodeString errorStr;
errorStr.set(buffer);
errorStr.trim();
if(messageBoxWin)
{
TheWindowManager->winUnsetModal(messageBoxWin);
messageBoxWin = NULL;
}
MessageBoxOk(TheGameText->fetch("GUI:Error"),errorStr, NULL);
// get the listbox that will have the save games in it
GameWindow *listboxGames = TheWindowManager->winGetWindowFromId( parent, listboxGamesKey );
DEBUG_ASSERTCRASH( listboxGames != NULL, ("reallySaveReplay - Unable to find games listbox\n") );
// populate the listbox with the save games on disk
PopulateReplayFileListbox(listboxGames);
return;
}
}
// copy the replay to the right place
if(CopyFile(oldFilename.str(),filename.str(), FALSE) == 0)
{
wchar_t buffer[1024];
FormatMessageW( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, buffer, sizeof(buffer), NULL);
UnicodeString errorStr;
errorStr.set(buffer);
errorStr.trim();
if(messageBoxWin)
{
TheWindowManager->winUnsetModal(messageBoxWin);
messageBoxWin = NULL;
}
MessageBoxOk(TheGameText->fetch("GUI:Error"),errorStr, NULL);
return;
}
// get the listbox that will have the save games in it
GameWindow *listboxGames = TheWindowManager->winGetWindowFromId( parent, listboxGamesKey );
DEBUG_ASSERTCRASH( listboxGames != NULL, ("reallySaveReplay - Unable to find games listbox\n") );
// populate the listbox with the save games on disk
PopulateReplayFileListbox(listboxGames);
ShowReplaySavedPopup(TRUE);
s_fileSavePopupStartTime = timeGetTime();
}
//-------------------------------------------------------------------------------------------------
/** SaveLoad menu system callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType PopupReplaySystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
switch( msg )
{
// --------------------------------------------------------------------------------------------
case GWM_CREATE:
{
break;
} // end create
//---------------------------------------------------------------------------------------------
case GWM_DESTROY:
{
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;
break;
} // end input
// --------------------------------------------------------------------------------------------
case GLM_SELECTED:
{
GameWindow *control = (GameWindow *)mData1;
GameWindow *listboxGames = TheWindowManager->winGetWindowFromId( window, listboxGamesKey );
DEBUG_ASSERTCRASH( listboxGames != NULL, ("PopupReplaySystem - Unable to find games listbox\n") );
//
// handle games listbox, when certain items are selected in the listbox only some
// commands are available
//
if( control == listboxGames )
{
int rowSelected = mData2;
if (rowSelected >= 0)
{
UnicodeString filename;
filename = GadgetListBoxGetText(listboxGames, rowSelected);
GameWindow *textEntryReplayName = TheWindowManager->winGetWindowFromId( window, textEntryReplayNameKey );
DEBUG_ASSERTCRASH( textEntryReplayName != NULL, ("PopupReplaySystem - Unable to find text entry\n") );
GadgetTextEntrySetText(textEntryReplayName, filename);
}
}
break;
} // end selected
//---------------------------------------------------------------------------------------------
case GEM_EDIT_DONE:
{
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if( controlID == textEntryReplayNameKey )
{
UnicodeString filename = GadgetTextEntryGetText( control );
if (filename.isEmpty())
break;
saveReplay(filename);
}
break;
} // end selected
//---------------------------------------------------------------------------------------------
case GBM_SELECTED:
{
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if( controlID == buttonSaveKey )
{
// get the filename, and see if we are overwriting
GameWindow *textEntryReplayName = TheWindowManager->winGetWindowFromId( window, textEntryReplayNameKey );
DEBUG_ASSERTCRASH( textEntryReplayName != NULL, ("PopupReplaySystem - Unable to find text entry\n") );
UnicodeString filename = GadgetTextEntryGetText( textEntryReplayName );
if (filename.isEmpty())
break;
saveReplay(filename);
}
else if( controlID == buttonBackKey )
{
// close the save/load menu
closeSaveMenu( window );
ScoreScreenEnableControls(TRUE);
} // end if
break;
} // end selected
case GEM_UPDATE_TEXT:
{
//Kris:
//Enable or disable the save button -- disabled when empty.
GameWindow *control = TheWindowManager->winGetWindowFromId( parent, textEntryReplayNameKey );
if( control )
{
UnicodeString filename;
filename.set( GadgetTextEntryGetText( control ) );
control = TheWindowManager->winGetWindowFromId( parent, buttonSaveKey );
if( control )
{
if( filename.isEmpty() )
{
control->winEnable( FALSE );
}
else
{
control->winEnable( TRUE );
}
}
}
}
default:
return MSG_IGNORED;
} // end switch
return MSG_HANDLED;
}

View File

@@ -0,0 +1,903 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: PopupSaveLoad.cpp /////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Electronic Arts Pacific.
//
// Confidential Information
// Copyright (C) 2002 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// Project: RTS3
//
// File name: PopupSaveLoad.cpp
//
// Created: Chris Brue, June 2002
//
// Desc: the Save/Load window control
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
// 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/MessageStream.h"
#include "GameClient/CampaignManager.h"
#include "GameClient/GadgetListBox.h"
#include "GameClient/GadgetTextEntry.h"
#include "GameClient/GameText.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/GUICallbacks.h"
#include "GameClient/Shell.h"
#include "GameLogic/GameLogic.h"
#include "GameClient/GameWindowTransitions.h"
// PRIVATE DATA ///////////////////////////////////////////////////////////////////////////////////
static NameKeyType buttonBackKey = NAMEKEY_INVALID;
static NameKeyType buttonSaveKey = NAMEKEY_INVALID;
static NameKeyType buttonLoadKey = NAMEKEY_INVALID;
static NameKeyType buttonDeleteKey = NAMEKEY_INVALID;
static NameKeyType listboxGamesKey = NAMEKEY_INVALID;
static NameKeyType buttonOverwriteCancel = NAMEKEY_INVALID;
static NameKeyType buttonOverwriteConfirm = NAMEKEY_INVALID;
static NameKeyType buttonLoadCancel = NAMEKEY_INVALID;
static NameKeyType buttonLoadConfirm = NAMEKEY_INVALID;
static NameKeyType buttonSaveDescCancel = NAMEKEY_INVALID;
static NameKeyType buttonSaveDescConfirm = NAMEKEY_INVALID;
static NameKeyType buttonDeleteConfirm = NAMEKEY_INVALID;
static NameKeyType buttonDeleteCancel = NAMEKEY_INVALID;
static GameWindow *buttonFrame = NULL;
static GameWindow *overwriteConfirm = NULL;
static GameWindow *loadConfirm = NULL;
static GameWindow *saveDesc = NULL;
static GameWindow *listboxGames = NULL;
static GameWindow *editDesc = NULL;
static GameWindow *deleteConfirm = NULL;
static GameWindow *parent = NULL;
static SaveLoadLayoutType currentLayoutType = SLLT_INVALID;
static Bool isPopup = FALSE;
static Int initialGadgetDelay = 2;
static Bool justEntered = FALSE;
static Bool isShuttingDown = false;
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
extern Bool DontShowMainMenu; //KRIS
extern Bool ReplayWasPressed;
// ------------------------------------------------------------------------------------------------
/** Given the current layout and selection in the game listbox, update the main save/load
* menu buttons to be enabled or disabled */
// ------------------------------------------------------------------------------------------------
static void updateMenuActions( void )
{
// for loading only, disable the save button, otherwise enable it
GameWindow *saveButton = TheWindowManager->winGetWindowFromId( NULL, buttonSaveKey );
DEBUG_ASSERTCRASH( saveButton, ("SaveLoadMenuInit: Unable to find save button\n") );
if( currentLayoutType == SLLT_LOAD_ONLY )
saveButton->winEnable( FALSE );
else
saveButton->winEnable( TRUE );
// get the games listbox
//GameWindow *listboxGames = TheWindowManager->winGetWindowFromId( NULL, NAMEKEY( "PopupSaveLoad.wnd:ListboxGames" ) );
// if something with a game file is selected we can use load and delete
Int selected;
GadgetListBoxGetSelected( listboxGames, &selected );
AvailableGameInfo *selectedGameInfo;
selectedGameInfo = (AvailableGameInfo *)GadgetListBoxGetItemData( listboxGames, selected );
GameWindow *buttonLoad = TheWindowManager->winGetWindowFromId( NULL, buttonLoadKey );
buttonLoad->winEnable( selectedGameInfo != NULL );
GameWindow *buttonDelete = TheWindowManager->winGetWindowFromId( NULL, buttonDeleteKey );
buttonDelete->winEnable( selectedGameInfo != NULL );
} // end updateMenuActions
//-------------------------------------------------------------------------------------------------
/** Initialize the SaveLoad menu */
//-------------------------------------------------------------------------------------------------
void SaveLoadMenuInit( WindowLayout *layout, void *userData )
{
// set default behavior for this menu
currentLayoutType = SLLT_SAVE_AND_LOAD;
isPopup = TRUE;
// get layout type if present
if( userData )
currentLayoutType = *((SaveLoadLayoutType *)userData);
// get ids for our children controls
buttonBackKey = NAMEKEY( "PopupSaveLoad.wnd:ButtonBack" );
buttonSaveKey = NAMEKEY( "PopupSaveLoad.wnd:ButtonSave" );
buttonLoadKey = NAMEKEY( "PopupSaveLoad.wnd:ButtonLoad" );
buttonDeleteKey = NAMEKEY( "PopupSaveLoad.wnd:ButtonDelete" );
listboxGamesKey = NAMEKEY( "PopupSaveLoad.wnd:ListboxGames" );
buttonOverwriteCancel = NAMEKEY( "PopupSaveLoad.wnd:ButtonOverwriteCancel" );
buttonOverwriteConfirm = NAMEKEY( "PopupSaveLoad.wnd:ButtonOverwriteConfirm" );
buttonLoadCancel = NAMEKEY( "PopupSaveLoad.wnd:ButtonLoadCancel" );
buttonLoadConfirm = NAMEKEY( "PopupSaveLoad.wnd:ButtonLoadConfirm" );
buttonSaveDescCancel = NAMEKEY( "PopupSaveLoad.wnd:ButtonSaveDescCancel" );
buttonSaveDescConfirm = NAMEKEY( "PopupSaveLoad.wnd:ButtonSaveDescConfirm" );
buttonDeleteConfirm = NAMEKEY( "PopupSaveLoad.wnd:ButtonDeleteConfirm" );
buttonDeleteCancel = NAMEKEY( "PopupSaveLoad.wnd:ButtonDeleteCancel" );
//set keyboard focus to main parent and set modal
NameKeyType parentID = TheNameKeyGenerator->nameToKey("PopupSaveLoad.wnd:SaveLoadMenu");
parent = TheWindowManager->winGetWindowFromId( NULL, parentID );
TheWindowManager->winSetFocus( parent );
TheWindowManager->winSetModal( parent );
// enable the menu action buttons
buttonFrame = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:MenuButtonFrame" ) );
buttonFrame->winEnable( TRUE );
// get confirmation windows and hide
overwriteConfirm = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:OverwriteConfirmParent" ) );
overwriteConfirm->winHide( TRUE );
loadConfirm = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:LoadConfirmParent" ) );
loadConfirm->winHide( TRUE );
saveDesc = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:SaveDescParent" ) );
saveDesc->winHide( TRUE );
deleteConfirm = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:DeleteConfirmParent" ) );
editDesc = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:EntryDesc" ) );
// get the listbox that will have the save games in it
listboxGames = TheWindowManager->winGetWindowFromId( NULL, listboxGamesKey );
DEBUG_ASSERTCRASH( listboxGames != NULL, ("SaveLoadMenuInit - Unable to find games listbox\n") );
// populate the listbox with the save games on disk
TheGameState->populateSaveGameListbox( listboxGames, currentLayoutType );
// update the availability of the menu buttons
updateMenuActions();
} // end SaveLoadMenuInit
//-------------------------------------------------------------------------------------------------
/** Initialize the SaveLoad menu */
//-------------------------------------------------------------------------------------------------
void SaveLoadMenuFullScreenInit( WindowLayout *layout, void *userData )
{
TheShell->showShellMap(TRUE);
isPopup = FALSE;
// set default behavior for this menu
currentLayoutType = SLLT_LOAD_ONLY;
// get layout type if present
if( userData )
currentLayoutType = *((SaveLoadLayoutType *)userData);
// get ids for our children controls
buttonBackKey = NAMEKEY( "SaveLoad.wnd:ButtonBack" );
buttonSaveKey = NAMEKEY( "SaveLoad.wnd:ButtonSave" );
buttonLoadKey = NAMEKEY( "SaveLoad.wnd:ButtonLoad" );
buttonDeleteKey = NAMEKEY( "SaveLoad.wnd:ButtonDelete" );
listboxGamesKey = NAMEKEY( "SaveLoad.wnd:ListboxGames" );
buttonOverwriteCancel = NAMEKEY( "SaveLoad.wnd:ButtonOverwriteCancel" );
buttonOverwriteConfirm = NAMEKEY( "SaveLoad.wnd:ButtonOverwriteConfirm" );
buttonLoadCancel = NAMEKEY( "SaveLoad.wnd:ButtonLoadCancel" );
buttonLoadConfirm = NAMEKEY( "SaveLoad.wnd:ButtonLoadConfirm" );
buttonSaveDescCancel = NAMEKEY( "SaveLoad.wnd:ButtonSaveDescCancel" );
buttonSaveDescConfirm = NAMEKEY( "SaveLoad.wnd:ButtonSaveDescConfirm" );
buttonDeleteConfirm = NAMEKEY( "SaveLoad.wnd:ButtonDeleteConfirm" );
buttonDeleteCancel = NAMEKEY( "SaveLoad.wnd:ButtonDeleteCancel" );
//set keyboard focus to main parent and set modal
NameKeyType parentID = TheNameKeyGenerator->nameToKey("SaveLoad.wnd:SaveLoadMenu");
parent = TheWindowManager->winGetWindowFromId( NULL, parentID );
TheWindowManager->winSetFocus( parent );
// TheWindowManager->winSetModal( parent );
// enable the menu action buttons
buttonFrame = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "SaveLoad.wnd:MenuButtonFrame" ) );
buttonFrame->winEnable( TRUE );
// get confirmation windows and hide
overwriteConfirm = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "SaveLoad.wnd:OverwriteConfirmParent" ) );
overwriteConfirm->winHide( TRUE );
loadConfirm = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "SaveLoad.wnd:LoadConfirmParent" ) );
loadConfirm->winHide( TRUE );
saveDesc = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "SaveLoad.wnd:SaveDescParent" ) );
saveDesc->winHide( TRUE );
editDesc = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "SaveLoad.wnd:EntryDesc" ) );
deleteConfirm = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "SaveLoad.wnd:DeleteConfirmParent" ) );
// get the listbox that will have the save games in it
listboxGames = TheWindowManager->winGetWindowFromId( NULL, listboxGamesKey );
DEBUG_ASSERTCRASH( listboxGames != NULL, ("SaveLoadMenuInit - Unable to find games listbox\n") );
// populate the listbox with the save games on disk
TheGameState->populateSaveGameListbox( listboxGames, currentLayoutType );
// update the availability of the menu buttons
updateMenuActions();
layout->hide(FALSE);
justEntered = TRUE;
initialGadgetDelay = 2;
if(parent)
parent->winHide(TRUE);
isShuttingDown = false;
} // end SaveLoadMenuInit
//-------------------------------------------------------------------------------------------------
/** SaveLoad menu shutdown method */
//-------------------------------------------------------------------------------------------------
void SaveLoadMenuShutdown( WindowLayout *layout, void *userData )
{
Bool popImmediate = *(Bool *)userData;
if( popImmediate )
{
layout->hide( TRUE );
TheShell->shutdownComplete( layout );
return;
} //end if
// our shutdown is complete
TheTransitionHandler->reverse("SaveLoadMenuFade");
isShuttingDown = TRUE;
} // end SaveLoadMenuShutdown
//-------------------------------------------------------------------------------------------------
/** SaveLoad menu update method */
//-------------------------------------------------------------------------------------------------
void SaveLoadMenuUpdate( WindowLayout *layout, void *userData )
{
if(DontShowMainMenu && justEntered)
justEntered = FALSE;
if(ReplayWasPressed && justEntered)
{
justEntered = FALSE;
ReplayWasPressed = FALSE;
}
if(justEntered)
{
if(initialGadgetDelay == 1)
{
TheTransitionHandler->remove("MainMenuDefaultMenuLogoFade");
TheTransitionHandler->setGroup("SaveLoadMenuFade");
initialGadgetDelay = 2;
justEntered = FALSE;
}
else
initialGadgetDelay--;
}
if(isShuttingDown && TheShell->isAnimFinished()&& TheTransitionHandler->isFinished())
TheShell->shutdownComplete( layout );
} // end SaveLoadMenuUpdate
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
WindowMsgHandledType SaveLoadMenuInput( 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 ) )
{
GameWindow *button = TheWindowManager->winGetWindowFromId( parent, buttonBackKey );
TheWindowManager->winSendSystemMsg( window, GBM_SELECTED,
(WindowMsgData)button, buttonBackKey );
} // 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;
}
// ------------------------------------------------------------------------------------------------
/** Get the file info of the selected savegame file in the listbox */
// ------------------------------------------------------------------------------------------------
static AvailableGameInfo *getSelectedSaveFileInfo( GameWindow *window )
{
// get the listbox
//GameWindow *listboxGames = TheWindowManager->winGetWindowFromId( window, listboxGamesKey );
DEBUG_ASSERTCRASH( listboxGames != NULL, ("SaveLoadMenuInit - Unable to find games listbox\n") );
// which item is selected
Int selected;
GadgetListBoxGetSelected( listboxGames, &selected );
// get the item data of the selection
AvailableGameInfo *selectedGameInfo;
selectedGameInfo = (AvailableGameInfo *)GadgetListBoxGetItemData( listboxGames, selected );
return selectedGameInfo;
} // end getSelectedSaveFileInfo
// ---------------------------------------------------con------------------------------------------
// ------------------------------------------------------------------------------------------------ // close the save/load menu
static void doLoadGame( void )
{
// get listbox of games
//GameWindow *listboxGames = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:ListboxGames" ) );
DEBUG_ASSERTCRASH( listboxGames, ("doLoadGame: Unable to find game listbox\n") );
// get selected game info
AvailableGameInfo *selectedGameInfo = getSelectedSaveFileInfo( listboxGames );
DEBUG_ASSERTCRASH( selectedGameInfo, ("doLoadGame: No selected game info found\n") );
// when loading a game we also close the quit/esc menu for the user when in-game
if( TheShell->isShellActive() == FALSE )
{
destroyQuitMenu();
// ToggleQuitMenu();
// TheTransitionHandler->remove("QuitNoSave");
// TheTransitionHandler->remove("QuitFull");
}
else
{
TheTransitionHandler->remove("MainMenuLoadReplayMenu");
TheTransitionHandler->remove("MainMenuLoadReplayMenuBack");
TheGameLogic->prepareNewGame( GAME_SINGLE_PLAYER, DIFFICULTY_NORMAL, 0 );
}
//
// load game, note the *copy* of the selected game info is passed here because we will
// loose these allocated user data pointers attached as listbox item data when the
// engine resets
//
if (TheGameState->loadGame( *selectedGameInfo ) != SC_OK)
{
if (TheGameLogic->isInGame())
TheGameLogic->clearGameData( FALSE );
TheGameEngine->reset();
TheShell->showShell(TRUE);
}
} // end doLoadGame
// ------------------------------------------------------------------------------------------------
/** Close the save/load menu */
// ------------------------------------------------------------------------------------------------
static void closeSaveMenu( GameWindow *window )
{
if(isPopup)
{
WindowLayout *saveLoadMenuLayout = window->winGetLayout();
if( saveLoadMenuLayout )
saveLoadMenuLayout->hide( TRUE );
}
else
TheShell->hideShell();
} // end closeSaveMenu
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
static void setEditDescription( GameWindow *editControl )
{
UnicodeString defaultDesc;
Campaign *campaign = TheCampaignManager->getCurrentCampaign();
//
// if we have a campaign we will use a default description that describes the
// location and map in the campaign nicely, otherwise we will default to just
// the map name (which is really only used in debug)
//
if( campaign )
defaultDesc.format( L"%s %d",
TheGameText->fetch( campaign->m_campaignNameLabel ).str(),
TheCampaignManager->getCurrentMissionNumber() + 1 );
else
{
const char *mapName = TheGlobalData->m_mapName.reverseFind( '\\' );
if( mapName )
defaultDesc.format( L"%S", mapName + 1 );
else
defaultDesc.format( L"%S", TheGlobalData->m_mapName.str() );
} // end else
// set into edit control
GadgetTextEntrySetText( editControl, defaultDesc );
} // end setEditDescription
//----------------------------------------------------------------------------------------------
static void processLoadButtonPress(GameWindow *window)
{
// get the filename of the selected savegame in the listbox
AvailableGameInfo *selectedGameInfo = getSelectedSaveFileInfo( window );
if( selectedGameInfo )
{
//
// if we're in the shell we do not need a confirmation dialog that states we will
// lose the current loaded game data cause we're not in a game
//
if( TheShell->isShellActive() == TRUE )
{
// just close the menu and do the load game logic
closeSaveMenu( window );
doLoadGame();
} // end if
else
{
//GameWindow *buttonFrame = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:MenuButtonFrame" ) );
//GameWindow *listboxGames = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:ListboxGames" ) );
//GameWindow *loadConfirm = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:LoadConfirmParent" ) );
// disable listbox and buttons
listboxGames->winEnable( FALSE );
buttonFrame->winEnable( FALSE );
// show the load confirm dialog
loadConfirm->winHide( FALSE );
} // end else
} // end if
}
//-------------------------------------------------------------------------------------------------
/** SaveLoad menu system callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType SaveLoadMenuSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
switch( msg )
{
// --------------------------------------------------------------------------------------------
case GWM_CREATE:
{
break;
} // end create
//---------------------------------------------------------------------------------------------
case GWM_DESTROY:
{
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;
break;
} // end input
//----------------------------------------------------------------------------------------------
case GLM_DOUBLE_CLICKED:
{
GameWindow *control = (GameWindow *)mData1;
GameWindow *listboxGames = TheWindowManager->winGetWindowFromId( window, listboxGamesKey );
DEBUG_ASSERTCRASH( listboxGames != NULL, ("SaveLoadMenuInit - Unable to find games listbox\n") );
if (listboxGames != NULL) {
int rowSelected = mData2;
GadgetListBoxSetSelected(listboxGames, rowSelected);
if (control == listboxGames)
{
processLoadButtonPress(window);
}
}
break;
}
// --------------------------------------------------------------------------------------------
case GLM_SELECTED:
{
GameWindow *control = (GameWindow *)mData1;
GameWindow *listboxGames = TheWindowManager->winGetWindowFromId( window, listboxGamesKey );
DEBUG_ASSERTCRASH( listboxGames != NULL, ("SaveLoadMenuInit - Unable to find games listbox\n") );
//
// handle games listbox, when certain items are selected in the listbox only some
// commands are available
//
if( control == listboxGames )
updateMenuActions();
break;
} // end selected
//---------------------------------------------------------------------------------------------
case GBM_SELECTED:
{
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if( controlID == buttonLoadKey )
{
processLoadButtonPress(window);
} // end if
else if( controlID == buttonSaveKey )
{
// sanity
DEBUG_ASSERTCRASH( currentLayoutType == SLLT_SAVE_AND_LOAD ||
currentLayoutType == SLLT_SAVE_ONLY,
("SaveLoadMenuSystem - layout type '%d' does not allow saving\n",
currentLayoutType) );
// get save file info
AvailableGameInfo *selectedGameInfo = getSelectedSaveFileInfo( window );
// if there is no file info, this is a new game
if( selectedGameInfo == NULL )
{
// show the save description window
//GameWindow *saveDesc = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:SaveDescParent" ) );
saveDesc->winHide( FALSE );
// set the description text entry field to default value
//GameWindow *editDesc = TheWindowManager->winGetWindowFromId( saveDesc, NAMEKEY( "PopupSaveLoad.wnd:EntryDesc" ) );
setEditDescription( editDesc );
// disable the listbox of games
//GameWindow *listboxGames = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:ListboxGames" ) );
listboxGames->winEnable( FALSE );
// disable the frame window of buttons for the main save/load menu
//GameWindow *buttonFrame = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:MenuButtonFrame" ) );
//buttonFrame->winEnable( FALSE );
TheWindowManager->winSetFocus(editDesc);
} // end if
else
{
// disable listbox of games
//GameWindow *listboxGames = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:ListboxGames" ) );
listboxGames->winEnable( FALSE );
// disable and therefore lock out main save/load menu buttons
//GameWindow *buttonFrame = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:MenuButtonFrame" ) );
buttonFrame->winEnable( FALSE );
// show the save save confirm
//GameWindow *overwriteConfirm = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:OverwriteConfirmParent" ) );
overwriteConfirm->winHide( FALSE );
} // end else
}
else if( controlID == buttonDeleteKey )
{
// which item is selected in the game listbox
//GameWindow *listboxGames = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:ListboxGames" ) );
Int selected;
GadgetListBoxGetSelected( listboxGames, &selected );
AvailableGameInfo *selectedGameInfo;
selectedGameInfo = (AvailableGameInfo *)GadgetListBoxGetItemData( listboxGames, selected );
// delete file
if( selectedGameInfo )
{
// disable games listbox
listboxGames->winEnable( FALSE );
// disable menu buttons
//GameWindow *buttonFrame = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:MenuButtonFrame" ) );
buttonFrame->winEnable( FALSE );
// unhide confirmation dialog
//GameWindow *deleteConfirm = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:DeleteConfirmParent" ) );
deleteConfirm->winHide( FALSE );
} // end if
} // end else if
else if( controlID == buttonBackKey )
{
if(isPopup)
{
// close the save/load menu
closeSaveMenu( window );
}
else
{
TheShell->pop();
}
} // end if
else if( controlID == buttonDeleteConfirm || controlID == buttonDeleteCancel )
{
//GameWindow *listboxGames = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:ListboxGames" ) );
// delete if confirm
if( controlID == buttonDeleteConfirm )
{
// which item is selected in the game listbox
Int selected;
GadgetListBoxGetSelected( listboxGames, &selected );
AvailableGameInfo *selectedGameInfo;
selectedGameInfo = (AvailableGameInfo *)GadgetListBoxGetItemData( listboxGames, selected );
// construct path to filename
AsciiString filepath = TheGameState->getFilePathInSaveDirectory(selectedGameInfo->filename);
// delete the file
DeleteFile( filepath.str() );
// repopulate the listbox
TheGameState->populateSaveGameListbox( listboxGames, currentLayoutType );
} // end if
// hide the confirm dialog
//GameWindow *deleteConfirm = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:DeleteConfirmParent" ) );
deleteConfirm->winHide( TRUE );
// enable listbox of games
listboxGames->winEnable( TRUE );
// enable menu actions pane
//GameWindow *buttonFrame = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:MenuButtonFrame" ) );
buttonFrame->winEnable( TRUE );
updateMenuActions();
} // end if
else if( controlID == buttonOverwriteCancel || controlID == buttonOverwriteConfirm )
{
//GameWindow *listboxGames = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:ListboxGames" ) );
// hide save confirm dialog
//GameWindow *overwriteConfirm = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:OverwriteConfirmParent" ) );
overwriteConfirm->winHide( TRUE );
// if saving, do the save for the selected listbox item
if( controlID == buttonOverwriteConfirm )
{
// show the save description window
// GameWindow *saveDesc = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:SaveDescParent" ) );
// saveDesc->winHide( FALSE );
// get save game info for the currently selected game in the listbox
Int selected;
GadgetListBoxGetSelected( listboxGames, &selected );
// get the item data of the selection
AvailableGameInfo *selectedGameInfo;
selectedGameInfo = (AvailableGameInfo *)GadgetListBoxGetItemData( listboxGames, selected );
DEBUG_ASSERTCRASH( selectedGameInfo, ("SaveLoadMenuSystem: Internal error, listbox entry to overwrite game has no item data set into listbox element\n") );
// enable the listbox of games
//GameWindow *listboxGames = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:ListboxGames" ) );
listboxGames->winEnable( TRUE );
// enable the frame window of buttons for the main save/load menu
//GameWindow *buttonFrame = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:MenuButtonFrame" ) );
buttonFrame->winEnable( TRUE );
updateMenuActions();
//Added By Sadullah Nader
//Fix for bug
// close save menuu
closeSaveMenu( window );
//
// given the context of this menu figure out which type of save game we're acutally
// saving right now. As it turns out, when this menu is used in the save only
// mode it means that the save is a mission save between maps because you can only
// save the game between maps and can of course not load one
//
SaveFileType fileType;
if( currentLayoutType == SLLT_SAVE_AND_LOAD )
fileType = SAVE_FILE_TYPE_NORMAL;
else
fileType = SAVE_FILE_TYPE_MISSION;
// save the game
AsciiString filename;
if( selectedGameInfo )
filename = selectedGameInfo->filename;
TheGameState->saveGame( filename, selectedGameInfo->saveGameInfo.description, fileType );
/*
// set the description text entry field to default value
GameWindow *editDesc = TheWindowManager->winGetWindowFromId( saveDesc, NAMEKEY( "PopupSaveLoad.wnd:EntryDesc" ) );
setEditDescription( editDesc );
*/
} // end if
else if( controlID == buttonOverwriteCancel )
{
//GameWindow *buttonFrame = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:MenuButtonFrame" ) );
// enable buttons and list box on main parent
buttonFrame->winEnable( TRUE );
updateMenuActions();
listboxGames->winEnable( TRUE );
} // end else if
} // end else if
else if( controlID == buttonSaveDescConfirm )
{
// get description window
//GameWindow *saveDesc = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:SaveDescParent" ) );
// get description text
//GameWindow *entryDesc = TheWindowManager->winGetWindowFromId( saveDesc, NAMEKEY( "PopupSaveLoad.wnd:EntryDesc" ) );
UnicodeString desc = GadgetTextEntryGetText( editDesc );
// hide desc window
saveDesc->winHide( TRUE );
// enable the listbox of games
//GameWindow *listboxGames = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:ListboxGames" ) );
listboxGames->winEnable( TRUE );
// enable the frame window of buttons for the main save/load menu
//GameWindow *buttonFrame = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:MenuButtonFrame" ) );
buttonFrame->winEnable( TRUE );
updateMenuActions();
// close save menuu
closeSaveMenu( window );
// get save filename
AvailableGameInfo *selectedGameInfo = getSelectedSaveFileInfo( listboxGames );
//
// given the context of this menu figure out which type of save game we're acutally
// saving right now. As it turns out, when this menu is used in the save only
// mode it means that the save is a mission save between maps because you can only
// save the game between maps and can of course not load one
//
SaveFileType fileType;
if( currentLayoutType == SLLT_SAVE_AND_LOAD )
fileType = SAVE_FILE_TYPE_NORMAL;
else
fileType = SAVE_FILE_TYPE_MISSION;
// save the game
AsciiString filename;
if( selectedGameInfo )
filename = selectedGameInfo->filename;
TheGameState->saveGame( filename, desc, fileType );
} // end else if
else if( controlID == buttonSaveDescCancel )
{
// hide the desc window
//GameWindow *saveDesc = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:SaveDescParent" ) );
saveDesc->winHide( TRUE );
// enable the listbox of games
//GameWindow *listboxGames = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:ListboxGames" ) );
listboxGames->winEnable( TRUE );
// enable the frame window of buttons for the main save/load menu
//GameWindow *buttonFrame = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:MenuButtonFrame" ) );
buttonFrame->winEnable( TRUE );
updateMenuActions();
} // end else if
else if( controlID == buttonLoadConfirm || controlID == buttonLoadCancel )
{
// hide confirm dialog
//GameWindow *loadConfirm = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:LoadConfirmParent" ) );
loadConfirm->winHide( TRUE );
// enable the listbox of games again
//GameWindow *listboxGames = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:ListboxGames" ) );
listboxGames->winEnable( TRUE );
// enable the main save/load menu button controls
//GameWindow *buttonFrame = TheWindowManager->winGetWindowFromId( parent, NAMEKEY( "PopupSaveLoad.wnd:MenuButtonFrame" ) );
buttonFrame->winEnable( TRUE );
updateMenuActions();
// do the load game
if( controlID == buttonLoadConfirm )
{
//Moved by Sadullah Nader
//moved to fix the
// close save/load layout menu
closeSaveMenu( window );
doLoadGame();
}
} // end else if
break;
} // end selected
default:
return MSG_IGNORED;
} // end switch
return MSG_HANDLED;
}

View File

@@ -0,0 +1,567 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: QuitMenu.cpp /////////////////////////////////////////////////////////////////////////////
// Author: Colin Day, October 2001
// Description: Quit menu window callbacks
///////////////////////////////////////////////////////////////////////////////////////////////////
// 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/MessageStream.h"
#include "Common/Player.h"
#include "Common/PlayerList.h"
#include "Common/RandomValue.h"
#include "Common/Recorder.h"
#include "GameClient/GUICallbacks.h"
#include "GameClient/WindowLayout.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/Gadget.h"
#include "GameClient/GadgetPushButton.h"
#include "GameClient/GameText.h"
#include "GameClient/MessageBox.h"
#include "GameClient/Shell.h"
#include "GameClient/InGameUI.h"
#include "GameLogic/GameLogic.h"
#include "GameLogic/VictoryConditions.h"
#include "GameClient/ControlBar.h"
#include "GameClient/GameWindowTransitions.h"
#include "GameClient/DisconnectMenu.h"
#include "GameLogic/ScriptEngine.h"
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
// PRIVATE DATA ///////////////////////////////////////////////////////////////////////////////////
static WindowLayout *quitMenuLayout = NULL;
static WindowLayout *fullQuitMenuLayout = NULL;
static WindowLayout *noSaveLoadQuitMenuLayout = NULL;
static Bool isVisible = FALSE;
static GameWindow *quitConfirmationWindow = NULL;
//external declarations of the Gadgets the callbacks can use
static WindowLayout *saveLoadMenuLayout = NULL;
static GameWindow *buttonRestartWin = NULL;
static GameWindow *buttonSaveLoadWin = NULL;
static GameWindow *buttonOptionsWin = NULL;
static GameWindow *buttonExitWin = NULL;
static NameKeyType buttonExit = NAMEKEY_INVALID;
static NameKeyType buttonRestart = NAMEKEY_INVALID;
static NameKeyType buttonReturn = NAMEKEY_INVALID;
static NameKeyType buttonOptions = NAMEKEY_INVALID;
static NameKeyType buttonSaveLoad = NAMEKEY_INVALID;
static void initGadgetsFullQuit( void )
{
buttonExit = TheNameKeyGenerator->nameToKey( AsciiString( "QuitMenu.wnd:ButtonExit" ) );
buttonRestart = TheNameKeyGenerator->nameToKey( AsciiString( "QuitMenu.wnd:ButtonRestart" ) );
buttonReturn = TheNameKeyGenerator->nameToKey( AsciiString( "QuitMenu.wnd:ButtonReturn" ) );
buttonOptions = TheNameKeyGenerator->nameToKey( AsciiString( "QuitMenu.wnd:ButtonOptions" ) );
buttonSaveLoad = TheNameKeyGenerator->nameToKey( AsciiString( "QuitMenu.wnd:ButtonSaveLoad" ) );
buttonRestartWin = TheWindowManager->winGetWindowFromId( NULL, buttonRestart );
buttonSaveLoadWin = TheWindowManager->winGetWindowFromId( NULL, buttonSaveLoad );
buttonOptionsWin = TheWindowManager->winGetWindowFromId( NULL, buttonOptions );
buttonExitWin = TheWindowManager->winGetWindowFromId( NULL, buttonExit );
}
static void initGadgetsNoSaveQuit( void )
{
buttonExit = TheNameKeyGenerator->nameToKey( AsciiString( "QuitNoSave.wnd:ButtonExit" ) );
buttonRestart = TheNameKeyGenerator->nameToKey( AsciiString( "QuitNoSave.wnd:ButtonRestart" ) );
buttonReturn = TheNameKeyGenerator->nameToKey( AsciiString( "QuitNoSave.wnd:ButtonReturn" ) );
buttonOptions = TheNameKeyGenerator->nameToKey( AsciiString( "QuitNoSave.wnd:ButtonOptions" ) );
buttonSaveLoad = NAMEKEY_INVALID;
buttonRestartWin = TheWindowManager->winGetWindowFromId( NULL, buttonRestart );
buttonOptionsWin = TheWindowManager->winGetWindowFromId( NULL, buttonOptions );
buttonSaveLoadWin = NULL;
buttonExitWin = TheWindowManager->winGetWindowFromId( NULL, buttonExit );
}
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
void destroyQuitMenu()
{
// destroy the quit menu
quitConfirmationWindow = NULL;
if(fullQuitMenuLayout)
{
fullQuitMenuLayout->destroyWindows();
fullQuitMenuLayout->deleteInstance();
}
fullQuitMenuLayout = NULL;
if(noSaveLoadQuitMenuLayout)
{
noSaveLoadQuitMenuLayout->destroyWindows();
noSaveLoadQuitMenuLayout->deleteInstance();
}
noSaveLoadQuitMenuLayout = NULL;
quitMenuLayout = NULL;
isVisible = FALSE;
}
/**
* quits the program
*/
static void exitQuitMenu()
{
// destroy the quit menu
destroyQuitMenu();
// clear out all the game data
if ( TheGameLogic->isInMultiplayerGame() && !TheGameLogic->isInSkirmishGame() && !TheGameInfo->isSandbox() )
{
GameMessage *msg = TheMessageStream->appendMessage(GameMessage::MSG_SELF_DESTRUCT);
msg->appendBooleanArgument(TRUE);
}
/*GameMessage *msg =*/ TheMessageStream->appendMessage( GameMessage::MSG_CLEAR_GAME_DATA );
if ( !TheGameLogic->isInMultiplayerGame() )
TheGameLogic->setGamePaused(FALSE);
// TheGameLogic->clearGameData();
// display the menu on top of the shell stack
// TheShell->showShell();
// this will trigger an exit
// TheGameEngine->setQuitting( TRUE );
TheInGameUI->setClientQuiet( TRUE );
}
static void noExitQuitMenu()
{
quitConfirmationWindow = NULL;
}
static void quitToDesktopQuitMenu()
{
// destroy the quit menu
destroyQuitMenu();
if (TheGameLogic->isInGame())
{
if (TheRecorder->getMode() == RECORDERMODETYPE_RECORD)
{
TheRecorder->stopRecording();
}
TheGameLogic->clearGameData();
}
TheGameEngine->setQuitting(TRUE);
TheInGameUI->setClientQuiet( TRUE );
}
static void surrenderQuitMenu()
{
// destroy the quit menu
destroyQuitMenu();
if (TheVictoryConditions->isLocalAlliedVictory())
return;
GameMessage *msg = TheMessageStream->appendMessage(GameMessage::MSG_SELF_DESTRUCT);
msg->appendBooleanArgument(TRUE);
TheInGameUI->setClientQuiet( TRUE );
}
static void restartMissionMenu()
{
// destroy the quit menu
destroyQuitMenu();
Int gameMode = TheGameLogic->getGameMode();
AsciiString mapName = TheGlobalData->m_mapName;
//
// if the map name was from a save game it will have "Save/" at the front of it,
// we want to go back to the original pristine map string for the map name when restarting
//
if (TheGameState->isInSaveDirectory(mapName))
mapName = TheGameState->getPristineMapName();
// End the current game
AsciiString replayFile = TheRecorder->getCurrentReplayFilename();
if (TheRecorder->getMode() == RECORDERMODETYPE_RECORD)
{
TheRecorder->stopRecording();
}
Int rankPointsStartedWith = TheGameLogic->getRankPointsToAddAtGameStart();// must write down before reset
GameDifficulty diff = TheScriptEngine->getGlobalDifficulty();
Int fps = TheGameEngine->getFramesPerSecondLimit();
TheGameLogic->clearGameData(FALSE);
TheGameEngine->setQuitting(FALSE);
if (replayFile.isNotEmpty())
{
TheRecorder->playbackFile(replayFile);
}
else
{
// send a message to the logic for a new game
TheWritableGlobalData->m_pendingFile = mapName;
GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_NEW_GAME );
msg->appendIntegerArgument(gameMode);
msg->appendIntegerArgument(diff);
msg->appendIntegerArgument(rankPointsStartedWith);
msg->appendIntegerArgument(fps);
DEBUG_LOG(("Restarting game mode %d, Diff=%d, RankPoints=%d\n", gameMode,
TheScriptEngine->getGlobalDifficulty(),
rankPointsStartedWith)
);
//if (TheGlobalData->m_fixedSeed >= 0)
//InitRandom(TheGlobalData->m_fixedSeed);
InitRandom(0);
//else
// InitGameLogicRandom(GameClientRandomValue(0, INT_MAX - 1));
}
//TheTransitionHandler->remove("QuitFull"); //KRISMORNESS ADD
//quitMenuLayout = NULL; //KRISMORNESS ADD
//isVisible = TRUE; //KRISMORNESS ADD
//HideQuitMenu(); //KRISMORNESS ADD
TheInGameUI->setClientQuiet( TRUE );
}
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
void HideQuitMenu( void )
{
// Note: This is called as a safety a lot, without checking for the prescence of the quit menu.
// So don't do anything that counts on that menu actually being here.
if(!isVisible)
return;
if(quitMenuLayout && quitMenuLayout == noSaveLoadQuitMenuLayout)
TheTransitionHandler->reverse("QuitNoSaveBack");
else if( quitMenuLayout && quitMenuLayout == fullQuitMenuLayout)
TheTransitionHandler->reverse("QuitFullBack");
TheInGameUI->setQuitMenuVisible( FALSE );
isVisible = FALSE;
if (quitConfirmationWindow)
TheWindowManager->winDestroy(quitConfirmationWindow);
quitConfirmationWindow = NULL;
if ( !TheGameLogic->isInMultiplayerGame() )
TheGameLogic->setGamePaused(FALSE);
}
//-------------------------------------------------------------------------------------------------
/** Toggle visibility of the quit menu */
//-------------------------------------------------------------------------------------------------
void ToggleQuitMenu()
{
//Added By Sadullah Nader
//Added a check to see if we're not in game yet
if (TheGameLogic->isIntroMoviePlaying() || TheGameLogic->isLoadingGame() ||TheScriptEngine->isGameEnding())
return;
//End Add
// BGC- If we are currently in the disconnect screen, don't let the quit menu come up.
if (TheDisconnectMenu != NULL) {
if (TheDisconnectMenu->isScreenVisible() == TRUE) {
return;
}
}
// BGC- this is kind of hackish, but its the safest way to do it I think.
// Basically we're seeing if either the save/load window or the options window is up
// and if one of them is, we quit out of them rather than toggle the quit menu.
if (TheShell->getOptionsLayout(FALSE) != FALSE) {
WindowLayout *optLayout = TheShell->getOptionsLayout(FALSE);
GameWindow *optionsParent = optLayout->getFirstWindow();
DEBUG_ASSERTCRASH(optionsParent != NULL, ("Not able to get the options layout parent window"));
GameWindow *optionsBack = TheWindowManager->winGetWindowFromId(optionsParent, TheNameKeyGenerator->nameToKey( AsciiString( "OptionsMenu.wnd:ButtonBack" ) ));
DEBUG_ASSERTCRASH(optionsBack != NULL, ("Not able to get the back button window from the options menu"));
TheWindowManager->winSendSystemMsg(optLayout->getFirstWindow(), GBM_SELECTED, (WindowMsgData)optionsBack, NULL);
return;
}
if ((saveLoadMenuLayout != NULL) && (saveLoadMenuLayout->isHidden() == FALSE))
{
GameWindow *saveLoadParent = saveLoadMenuLayout->getFirstWindow();
DEBUG_ASSERTCRASH(saveLoadParent != NULL, ("Not able to get the save/load layout parent window"));
GameWindow *saveLoadBack = TheWindowManager->winGetWindowFromId(saveLoadParent, TheNameKeyGenerator->nameToKey( AsciiString( "PopupSaveLoad.wnd:ButtonBack" ) ));
DEBUG_ASSERTCRASH(saveLoadBack != NULL, ("Not able to get the back button window from the save/load menu"));
TheWindowManager->winSendSystemMsg(saveLoadMenuLayout->getFirstWindow(), GBM_SELECTED, (WindowMsgData)saveLoadBack, NULL);
saveLoadMenuLayout = NULL;
return;
}
// if we're visable hide our quit menu
if(isVisible && quitMenuLayout)
{
isVisible = FALSE;
//Added By Sadullah Nader
//Bug: When Toggling the quit menu off, the quit confirmation should also go away
if (quitConfirmationWindow)
TheWindowManager->winDestroy(quitConfirmationWindow);
quitConfirmationWindow = NULL;
//
if ( !TheGameLogic->isInMultiplayerGame() )
TheGameLogic->setGamePaused(FALSE);
if(quitMenuLayout && quitMenuLayout == noSaveLoadQuitMenuLayout)
TheTransitionHandler->reverse("QuitNoSaveBack");
else if( quitMenuLayout && quitMenuLayout == fullQuitMenuLayout )
{
TheTransitionHandler->reverse("QuitFullBack");
//begin KRISMORNESS
//TheTransitionHandler->reverse("QuitFull");
//if( TheTransitionHandler->areTransitionsEnabled() )
//else
//{
// TheTransitionHandler->remove("QuitFull");
// quitMenuLayout = NULL;
// isVisible = TRUE;
// HideQuitMenu();
//}
//end KRISMORNESS
}
}
else
{
//Added By Sadullah Nader
//Added to compensate for the quit confirmation window pop-up
TheMouse->setCursor( Mouse::ARROW );
TheControlBar->hidePurchaseScience();
if ( TheGameLogic->isInMultiplayerGame() || TheGameLogic->isInReplayGame() )
{
// we don't want to show the save load button.
if(!noSaveLoadQuitMenuLayout)
noSaveLoadQuitMenuLayout = TheWindowManager->winCreateLayout( AsciiString( "Menus/QuitNoSave.wnd" ) );
quitMenuLayout = noSaveLoadQuitMenuLayout;
initGadgetsNoSaveQuit();
TheTransitionHandler->remove("QuitNoSave");
TheTransitionHandler->setGroup("QuitNoSave");
}
else
{
if(!fullQuitMenuLayout)
fullQuitMenuLayout= TheWindowManager->winCreateLayout( AsciiString( "Menus/QuitMenu.wnd" ) );
quitMenuLayout = fullQuitMenuLayout;
initGadgetsFullQuit();
TheTransitionHandler->remove("QuitFull");
TheTransitionHandler->setGroup("QuitFull");
}
// load the quit menu from the layout file if needed
if( quitMenuLayout == NULL )
{
DEBUG_ASSERTCRASH(FALSE, ("Could not load a quit menu layout"));
isVisible = FALSE;
TheInGameUI->setQuitMenuVisible(FALSE);
return;
}
//quitMenuLayout->hide(FALSE);
// if we are watching a cinematic, we need to disable the save/load button
// because the save load window doesn't fit in the screen in letterbox mode.
if (TheInGameUI->getInputEnabled() == FALSE) {
if(buttonSaveLoadWin)
buttonSaveLoadWin->winEnable(FALSE);
buttonOptionsWin->winEnable(FALSE);
} else if (buttonSaveLoadWin)
{
if(buttonSaveLoadWin)
buttonSaveLoadWin->winEnable(TRUE);
buttonOptionsWin->winEnable(TRUE);
}
// Disable the restart, load, save, etc buttons in network games
if ( TheGameLogic->isInMultiplayerGame() || TheGameLogic->isInSkirmishGame() )
{
buttonRestartWin->winEnable(TRUE);
if (TheGameLogic->isInSkirmishGame() == FALSE) {
GadgetButtonSetText(buttonRestartWin, TheGameText->fetch("GUI:Surrender"));
}
if (TheGameLogic->isInSkirmishGame() == TRUE) {
TheGameLogic->setGamePaused(TRUE);
}
if ((!ThePlayerList->getLocalPlayer()->isPlayerActive() || TheVictoryConditions->isLocalAlliedVictory()) &&
(TheGameLogic->isInSkirmishGame() == FALSE))
{
buttonRestartWin->winEnable(FALSE); // can't surrender when you're dead
}
}
else
{
buttonRestartWin->winEnable(TRUE);
if(!TheGameLogic->isInReplayGame())
{
GadgetButtonSetText(buttonRestartWin, TheGameText->fetch("GUI:RestartMission"));
GadgetButtonSetText(buttonExitWin, TheGameText->fetch("GUI:ExitMission"));
}
//if we're not in a multiplayer game, pause the game
TheGameLogic->setGamePaused(TRUE);
}
if (quitConfirmationWindow)
TheWindowManager->winDestroy(quitConfirmationWindow);
quitConfirmationWindow = NULL;
HideDiplomacy();
HideInGameChat();
TheControlBar->hidePurchaseScience();
isVisible = TRUE;
}
TheInGameUI->setQuitMenuVisible(isVisible);
} // end ToggleQuitMenu
//-------------------------------------------------------------------------------------------------
/** Quit menu window system callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType QuitMenuSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
switch( msg )
{
// --------------------------------------------------------------------------------------------
case GWM_CREATE:
{
break;
} // end create
//---------------------------------------------------------------------------------------------
case GWM_DESTROY:
{
break;
} // end case
//---------------------------------------------------------------------------------------------
case GBM_SELECTED:
{
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if( controlID == buttonSaveLoad )
{
//
// these commented lines (12-11-2002) will allow access to load only when were
// viewing an in-game cinema ... but it's brittle, so I'm disableing it for
// now and just using the grey button for the whole save/load button for now
// during a cinema
//
// SaveLoadLayoutType layoutType = SLLT_SAVE_AND_LOAD;
//
// if input is disabled we are in an in-game cinematic and can load only, since we
// are in the quit menu we are paused and therefore input is disabled all
// the time ... in order to figure out if the *game* has input disabled we need
// to query for the input enabled memory in the game logic which represents the
// input enabled status of the game if we were not currently paused
//
// if( TheGameLogic->getInputEnabledMemory() == FALSE )
// layoutType = SLLT_LOAD_ONLY;
saveLoadMenuLayout = TheShell->getSaveLoadMenuLayout();
// saveLoadMenuLayout->runInit( &layoutType );
saveLoadMenuLayout->runInit();
saveLoadMenuLayout->hide( FALSE );
saveLoadMenuLayout->bringForward();
}
else if( controlID == buttonExit )
{
quitConfirmationWindow = QuitMessageBoxYesNo(TheGameText->fetch("GUI:QuitPopupTitle"), TheGameText->fetch("GUI:QuitPopupMessage"),/*quitCallback*/exitQuitMenu,noExitQuitMenu);
} // end if
else if( controlID == buttonReturn )
{
// hide this menu
ToggleQuitMenu();
} // end else if
else if( buttonOptions == controlID )
{
WindowLayout *optLayout = TheShell->getOptionsLayout(TRUE);
DEBUG_ASSERTCRASH(optLayout != NULL, ("options menu layout is NULL"));
optLayout->runInit();
optLayout->hide(FALSE);
optLayout->bringForward();
}
// else if( controlID == buttonQuitToDesktop )
// {
// quitConfirmationWindow = MessageBoxYesNo(TheGameText->fetch("GUI:QuitPopupTitle"), TheGameText->fetch("GUI:QuitToDesktopConf"),/*quitCallback*/quitToDesktopQuitMenu,noExitQuitMenu);
//
// } // end else if
else if( controlID == buttonRestart )
{
if ( TheGameLogic->isInMultiplayerGame() )
{
// we really want to surrender
quitConfirmationWindow = MessageBoxYesNo(TheGameText->fetch("GUI:SurrenderConfirmationTitle"),
TheGameText->fetch("GUI:SurrenderConfirmation"),
/*quitCallback*/surrenderQuitMenu,noExitQuitMenu);
}
else
{
//we really want to restart
quitConfirmationWindow = MessageBoxYesNo(TheGameText->fetch("GUI:RestartConfirmationTitle"),
TheGameText->fetch("GUI:RestartConfirmation"),
/*quitCallback*/restartMissionMenu,noExitQuitMenu);
}
} // end else if
break;
} // end selected
default:
return MSG_IGNORED;
} // end switch
return MSG_HANDLED;
} // end QuitMenuSystem

View File

@@ -0,0 +1,680 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: ReplayMenu.cpp /////////////////////////////////////////////////////////////////////
// Author: Chris The masta Huybregts, December 2001
// Description: Replay Menus
///////////////////////////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Lib/BaseType.h"
#include "Common/FileSystem.h"
#include "Common/GameEngine.h"
#include "Common/GameState.h"
#include "Common/Recorder.h"
#include "Common/Version.h"
#include "GameClient/WindowLayout.h"
#include "GameClient/Gadget.h"
#include "GameClient/GadgetListbox.h"
#include "GameClient/Shell.h"
#include "GameClient/KeyDefs.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/MessageBox.h"
#include "GameClient/MapUtil.h"
#include "GameClient/GameText.h"
#include "GameClient/GameWindowTransitions.h"
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
// window ids -------------------------------------------------------------------------------------
static NameKeyType parentReplayMenuID = NAMEKEY_INVALID;
static NameKeyType buttonLoadID = NAMEKEY_INVALID;
static NameKeyType buttonBackID = NAMEKEY_INVALID;
static NameKeyType listboxReplayFilesID = NAMEKEY_INVALID;
static NameKeyType buttonDeleteID = NAMEKEY_INVALID;
static NameKeyType buttonCopyID = NAMEKEY_INVALID;
static Bool isShuttingDown = false;
// window pointers --------------------------------------------------------------------------------
static GameWindow *parentReplayMenu = NULL;
static GameWindow *buttonLoad = NULL;
static GameWindow *buttonBack = NULL;
static GameWindow *listboxReplayFiles = NULL;
static GameWindow *buttonDelete = NULL;
static GameWindow *buttonCopy = NULL;
static Int initialGadgetDelay = 2;
static Bool justEntered = FALSE;
#if defined _DEBUG || defined _INTERNAL
static GameWindow *buttonAnalyzeReplay = NULL;
#endif
void deleteReplay( void );
void copyReplay( void );
static Bool callCopy = FALSE;
static Bool callDelete = FALSE;
void deleteReplayFlag( void ) { callDelete = TRUE;}
void copyReplayFlag( void ) { callCopy = TRUE;}
UnicodeString GetReplayFilenameFromListbox(GameWindow *listbox, Int index)
{
UnicodeString fname = GadgetListBoxGetText(listbox, index);
if (fname == TheGameText->fetch("GUI:LastReplay"))
{
fname.translate(TheRecorder->getLastReplayFileName());
}
UnicodeString ext;
ext.translate(TheRecorder->getReplayExtention());
fname.concat(ext);
return fname;
}
//-------------------------------------------------------------------------------------------------
/** Populate the listbox with the names of the available replay files */
//-------------------------------------------------------------------------------------------------
void PopulateReplayFileListbox(GameWindow *listbox)
{
if (!TheMapCache)
return;
GadgetListBoxReset(listbox);
enum {
COLOR_SP = 0,
COLOR_SP_CRC_MISMATCH,
COLOR_MP,
COLOR_MP_CRC_MISMATCH,
COLOR_MAX
};
Color colors[COLOR_MAX] = {
GameMakeColor( 255, 255, 255, 255 ),
GameMakeColor( 128, 128, 128, 255 ),
GameMakeColor( 255, 255, 255, 255 ),
GameMakeColor( 128, 128, 128, 255 )
};
AsciiString asciistr;
AsciiString asciisearch;
asciisearch = "*";
asciisearch.concat(TheRecorder->getReplayExtention());
FilenameList replayFilenames;
FilenameListIter it;
TheFileSystem->getFileListInDirectory(TheRecorder->getReplayDir(), asciisearch, replayFilenames, TRUE);
TheMapCache->updateCache();
for (it = replayFilenames.begin(); it != replayFilenames.end(); ++it)
{
// just want the filename
asciistr.set((*it).reverseFind('\\') + 1);
// lets get some info about the replay
RecorderClass::ReplayHeader header;
header.forPlayback = FALSE;
header.filename = asciistr;
Bool success = TheRecorder && TheMapCache && TheRecorder->readReplayHeader( header );
if (success)
{
ReplayGameInfo info;
if (ParseAsciiStringToGameInfo( &info, header.gameOptions ))
{
// columns are: name, date, version, map, extra
// name
header.replayName.translate(asciistr);
for (Int tmp=0; tmp < TheRecorder->getReplayExtention().getLength(); ++tmp)
header.replayName.removeLastChar();
UnicodeString replayNameToShow = header.replayName;
AsciiString lastReplayFName = TheRecorder->getLastReplayFileName();
lastReplayFName.concat(TheRecorder->getReplayExtention());
if (lastReplayFName.compareNoCase(asciistr) == 0)
replayNameToShow = TheGameText->fetch("GUI:LastReplay");
UnicodeString displayTimeBuffer = getUnicodeTimeBuffer(header.timeVal);
//displayTimeBuffer.format( L"%ls", timeBuffer);
// version (no-op)
// map
UnicodeString mapStr;
const MapMetaData *md = TheMapCache->findMap(info.getMap());
if (!md)
{
mapStr.translate(info.getMap());
}
else
{
mapStr = md->m_displayName;
}
// // extra
// UnicodeString extraStr;
// if (header.localPlayerIndex >= 0)
// {
// // MP game
// time_t totalSeconds = header.endTime - header.startTime;
// Int mins = totalSeconds/60;
// Int secs = totalSeconds%60;
// Real fps = header.frameDuration/totalSeconds;
// extraStr.format(L"%d:%d (%g fps) %hs", mins, secs, fps, header.desyncGame?"OOS ":"");
//
// for (Int i=0; i<MAX_SLOTS; ++i)
// {
// const GameSlot *slot = info.getConstSlot(i);
// if (slot && slot->isHuman())
// {
// if (i)
// extraStr.concat(L", ");
// if (header.playerDiscons[i])
// extraStr.concat(L'*');
// extraStr.concat(info.getConstSlot(i)->getName());
// }
// }
// }
// else
// {
// // solo game
// time_t totalSeconds = header.endTime - header.startTime;
// Int mins = totalSeconds/60;
// Int secs = totalSeconds%60;
// Real fps = header.frameDuration/totalSeconds;
// extraStr.format(L"%d:%d (%g fps)", mins, secs, fps);
// }
// pick a color
Color color;
if (header.versionString == TheVersion->getUnicodeVersion() && header.versionNumber == TheVersion->getVersionNumber() &&
header.exeCRC == TheGlobalData->m_exeCRC && header.iniCRC == TheGlobalData->m_iniCRC)
{
// good version
if (header.localPlayerIndex >= 0)
{
// MP
color = colors[COLOR_MP];
}
else
{
// SP
color = colors[COLOR_SP];
}
}
else
{
// bad version
if (header.localPlayerIndex >= 0)
{
// MP
color = colors[COLOR_MP_CRC_MISMATCH];
}
else
{
// SP
color = colors[COLOR_SP_CRC_MISMATCH];
}
}
Int insertionIndex = GadgetListBoxAddEntryText(listbox, replayNameToShow, color, -1, 0);
GadgetListBoxAddEntryText(listbox, displayTimeBuffer, color, insertionIndex, 1);
GadgetListBoxAddEntryText(listbox, header.versionString, color, insertionIndex, 2);
GadgetListBoxAddEntryText(listbox, mapStr, color, insertionIndex, 3);
//GadgetListBoxAddEntryText(listbox, extraStr, color, insertionIndex, 4);
}
}
}
GadgetListBoxSetSelected(listbox, 0);
}
//-------------------------------------------------------------------------------------------------
/** Initialize the single player menu */
//-------------------------------------------------------------------------------------------------
void ReplayMenuInit( WindowLayout *layout, void *userData )
{
TheShell->showShellMap(TRUE);
// get ids for our children controls
parentReplayMenuID = TheNameKeyGenerator->nameToKey( AsciiString("ReplayMenu.wnd:ParentReplayMenu") );
buttonLoadID = TheNameKeyGenerator->nameToKey( AsciiString("ReplayMenu.wnd:ButtonLoadReplay") );
buttonBackID = TheNameKeyGenerator->nameToKey( AsciiString("ReplayMenu.wnd:ButtonBack") );
listboxReplayFilesID = TheNameKeyGenerator->nameToKey( AsciiString("ReplayMenu.wnd:ListboxReplayFiles") );
buttonDeleteID = TheNameKeyGenerator->nameToKey( AsciiString("ReplayMenu.wnd:ButtonDeleteReplay") );
buttonCopyID = TheNameKeyGenerator->nameToKey( AsciiString("ReplayMenu.wnd:ButtonCopyReplay") );
parentReplayMenu = TheWindowManager->winGetWindowFromId( NULL, parentReplayMenuID );
buttonLoad = TheWindowManager->winGetWindowFromId( parentReplayMenu, buttonLoadID );
buttonBack = TheWindowManager->winGetWindowFromId( parentReplayMenu, buttonBackID );
listboxReplayFiles = TheWindowManager->winGetWindowFromId( parentReplayMenu, listboxReplayFilesID );
buttonDelete = TheWindowManager->winGetWindowFromId( parentReplayMenu, buttonDeleteID );
buttonCopy = TheWindowManager->winGetWindowFromId( parentReplayMenu, buttonCopyID );
//Load the listbox shiznit
GadgetListBoxReset(listboxReplayFiles);
PopulateReplayFileListbox(listboxReplayFiles);
#if defined _DEBUG || defined _INTERNAL
WinInstanceData instData;
instData.init();
BitSet( instData.m_style, GWS_PUSH_BUTTON | GWS_MOUSE_TRACK );
instData.m_textLabelString = "Debug: Analyze Replay";
instData.setTooltipText(UnicodeString(L"Only Used in Debug and Internal!"));
buttonAnalyzeReplay = TheWindowManager->gogoGadgetPushButton( parentReplayMenu,
WIN_STATUS_ENABLED | WIN_STATUS_IMAGE,
4, 4,
180, 26,
&instData, NULL, TRUE );
#endif
// show menu
layout->hide( FALSE );
// set keyboard focus to main parent
TheWindowManager->winSetFocus( parentReplayMenu );
justEntered = TRUE;
initialGadgetDelay = 2;
GameWindow *win = TheWindowManager->winGetWindowFromId(NULL, TheNameKeyGenerator->nameToKey("ReplayMenu.wnd:GadgetParent"));
if(win)
win->winHide(TRUE);
isShuttingDown = FALSE;
} // end ReplayMenuInit
//-------------------------------------------------------------------------------------------------
/** single player menu shutdown method */
//-------------------------------------------------------------------------------------------------
void ReplayMenuShutdown( WindowLayout *layout, void *userData )
{
Bool popImmediate = *(Bool *)userData;
if( popImmediate )
{
layout->hide( TRUE );
TheShell->shutdownComplete( layout );
return;
} //end if
// our shutdown is complete
TheTransitionHandler->reverse("ReplayMenuFade");
isShuttingDown = TRUE;
} // end ReplayMenuShutdown
//-------------------------------------------------------------------------------------------------
/** single player menu update method */
//-------------------------------------------------------------------------------------------------
void ReplayMenuUpdate( WindowLayout *layout, void *userData )
{
if(justEntered)
{
if(initialGadgetDelay == 1)
{
TheTransitionHandler->remove("MainMenuDefaultMenuLogoFade");
TheTransitionHandler->setGroup("ReplayMenuFade");
initialGadgetDelay = 2;
justEntered = FALSE;
}
else
initialGadgetDelay--;
}
if(callCopy)
copyReplay();
if(callDelete)
deleteReplay();
// We'll only be successful if we've requested to
if(isShuttingDown && TheShell->isAnimFinished()&& TheTransitionHandler->isFinished())
TheShell->shutdownComplete( layout );
} // end ReplayMenuUpdate
//-------------------------------------------------------------------------------------------------
/** Replay menu input callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType ReplayMenuInput( 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 ) )
{
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;
} // end ReplayMenuInput
void reallyLoadReplay(void)
{
UnicodeString filename;
Int selected;
GadgetListBoxGetSelected( listboxReplayFiles, &selected );
if(selected < 0)
{
MessageBoxOk(TheGameText->fetch("GUI:NoFileSelected"),TheGameText->fetch("GUI:PleaseSelectAFile"), NULL);
return;
}
filename = GetReplayFilenameFromListbox(listboxReplayFiles, selected);
AsciiString asciiFilename;
asciiFilename.translate(filename);
TheRecorder->playbackFile(asciiFilename);
if(parentReplayMenu != NULL)
{
parentReplayMenu->winHide(TRUE);
}
}
//-------------------------------------------------------------------------------------------------
/** single player menu window system callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType ReplayMenuSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
switch( msg )
{
// --------------------------------------------------------------------------------------------
case GWM_CREATE:
{
break;
} // end create
//---------------------------------------------------------------------------------------------
case GWM_DESTROY:
{
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 == listboxReplayFilesID )
{
int rowSelected = mData2;
if (rowSelected >= 0)
{
UnicodeString filename;
filename = GetReplayFilenameFromListbox(listboxReplayFiles, rowSelected);
AsciiString asciiFilename;
asciiFilename.translate(filename);
TheRecorder->playbackFile(asciiFilename);
if(parentReplayMenu != NULL)
{
parentReplayMenu->winHide(TRUE);
}
}
}
break;
}
//---------------------------------------------------------------------------------------------
case GBM_SELECTED:
{
UnicodeString filename;
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
#if defined _DEBUG || defined _INTERNAL
if( controlID == buttonAnalyzeReplay->winGetWindowId() )
{
if(listboxReplayFiles)
{
Int selected;
GadgetListBoxGetSelected( listboxReplayFiles, &selected );
if(selected < 0)
{
MessageBoxOk(UnicodeString(L"Blah Blah"),UnicodeString(L"Please select something munkee boy"), NULL);
break;
}
filename = GetReplayFilenameFromListbox(listboxReplayFiles, selected);
AsciiString asciiFilename;
asciiFilename.translate(filename);
if (TheRecorder->analyzeReplay(asciiFilename))
{
do
{
TheRecorder->update();
} while (TheRecorder->isAnalysisInProgress());
}
}
}
else
#endif
if( controlID == buttonLoadID )
{
if(listboxReplayFiles)
{
Int selected;
GadgetListBoxGetSelected( listboxReplayFiles, &selected );
if(selected < 0)
{
MessageBoxOk(TheGameText->fetch("GUI:NoFileSelected"),TheGameText->fetch("GUI:PleaseSelectAFile"), NULL);
break;
}
filename = GetReplayFilenameFromListbox(listboxReplayFiles, selected);
AsciiString asciiFilename;
asciiFilename.translate(filename);
if(TheRecorder->testVersionPlayback(asciiFilename))
{
MessageBoxOkCancel(TheGameText->fetch("GUI:OlderReplayVersionTitle"), TheGameText->fetch("GUI:OlderReplayVersion"),reallyLoadReplay ,NULL);
}
else
{
TheRecorder->playbackFile(asciiFilename);
if(parentReplayMenu != NULL)
{
parentReplayMenu->winHide(TRUE);
}
}
}
} // end else if
else if( controlID == buttonBackID )
{
// thou art directed to return to thy known solar system immediately!
TheShell->pop();
} // end else if
else if( controlID == buttonDeleteID )
{
Int selected;
GadgetListBoxGetSelected( listboxReplayFiles, &selected );
if(selected < 0)
{
MessageBoxOk(TheGameText->fetch("GUI:NoFileSelected"),TheGameText->fetch("GUI:PleaseSelectAFile"), NULL);
break;
}
filename = GetReplayFilenameFromListbox(listboxReplayFiles, selected);
MessageBoxYesNo(TheGameText->fetch("GUI:DeleteFile"), TheGameText->fetch("GUI:AreYouSureDelete"), deleteReplayFlag, NULL);
}
else if( controlID == buttonCopyID )
{
Int selected;
GadgetListBoxGetSelected( listboxReplayFiles, &selected );
if(selected < 0)
{
MessageBoxOk(TheGameText->fetch("GUI:NoFileSelected"),TheGameText->fetch("GUI:PleaseSelectAFile"), NULL);
break;
}
filename = GetReplayFilenameFromListbox(listboxReplayFiles, selected);
MessageBoxYesNo(TheGameText->fetch("GUI:CopyReplay"), TheGameText->fetch("GUI:AreYouSureCopy"), copyReplayFlag, NULL);
}
break;
} // end selected
default:
return MSG_IGNORED;
} // end switch
return MSG_HANDLED;
} // end ReplayMenuSystem
void deleteReplay( void )
{
callDelete = FALSE;
Int selected;
GadgetListBoxGetSelected( listboxReplayFiles, &selected );
if(selected < 0)
{
MessageBoxOk(TheGameText->fetch("GUI:NoFileSelected"),TheGameText->fetch("GUI:PleaseSelectAFile"), NULL);
return;
}
AsciiString filename, translate;
filename = TheRecorder->getReplayDir();
translate.translate(GetReplayFilenameFromListbox(listboxReplayFiles, selected));
filename.concat(translate);
if(DeleteFile(filename.str()) == 0)
{
char buffer[1024];
FormatMessage ( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, buffer, sizeof(buffer), NULL);
UnicodeString errorStr;
translate.set(buffer);
errorStr.translate(translate);
MessageBoxOk(TheGameText->fetch("GUI:Error"),errorStr, NULL);
}
//Load the listbox shiznit
GadgetListBoxReset(listboxReplayFiles);
PopulateReplayFileListbox(listboxReplayFiles);
}
void copyReplay( void )
{
callCopy = FALSE;
Int selected;
GadgetListBoxGetSelected( listboxReplayFiles, &selected );
if(selected < 0)
{
MessageBoxOk(TheGameText->fetch("GUI:NoFileSelected"),TheGameText->fetch("GUI:PleaseSelectAFile"), NULL);
return;
}
AsciiString filename, translate;
filename = TheRecorder->getReplayDir();
translate.translate(GetReplayFilenameFromListbox(listboxReplayFiles, selected));
filename.concat(translate);
char path[1024];
LPITEMIDLIST pidl;
SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOPDIRECTORY, &pidl);
SHGetPathFromIDList(pidl,path);
AsciiString newFilename;
newFilename.set(path);
newFilename.concat("\\");
newFilename.concat(translate);
if(CopyFile(filename.str(),newFilename.str(), FALSE) == 0)
{
wchar_t buffer[1024];
FormatMessageW( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, buffer, sizeof(buffer), NULL);
UnicodeString errorStr;
errorStr.set(buffer);
errorStr.trim();
MessageBoxOk(TheGameText->fetch("GUI:Error"),errorStr, NULL);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,267 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: SinglePlayerMenu.cpp /////////////////////////////////////////////////////////////////////
// Author: Colin Day, October 2001
// Description: Single Player Menus
///////////////////////////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/GameEngine.h"
#include "GameClient/AnimateWindowManager.h"
#include "GameClient/WindowLayout.h"
#include "GameClient/Gadget.h"
#include "GameClient/Shell.h"
#include "GameClient/KeyDefs.h"
#include "GameClient/GameWindowManager.h"
static Bool isShuttingDown = false;
static Bool buttonPushed = false;
//-------------------------------------------------------------------------------------------------
/** 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 );
} // end if
//-------------------------------------------------------------------------------------------------
/** Initialize the single player menu */
//-------------------------------------------------------------------------------------------------
void SinglePlayerMenuInit( WindowLayout *layout, void *userData )
{
TheShell->showShellMap(TRUE);
buttonPushed = false;
isShuttingDown = false;
// show menu
layout->hide( FALSE );
// set keyboard focus to main parent
AsciiString parentName( "SinglePlayerMenu.wnd:SinglePlayerMenuParent" );
NameKeyType parentID = TheNameKeyGenerator->nameToKey( parentName );
GameWindow *parent = TheWindowManager->winGetWindowFromId( NULL, parentID );
TheWindowManager->winSetFocus( parent );
NameKeyType buttonNewID = TheNameKeyGenerator->nameToKey( AsciiString("SinglePlayerMenu.wnd:ButtonNew") );
GameWindow *buttonNew = TheWindowManager->winGetWindowFromId( NULL, buttonNewID );
TheShell->registerWithAnimateManager(buttonNew, WIN_ANIMATION_SLIDE_LEFT, TRUE,1);
NameKeyType buttonLoadID = TheNameKeyGenerator->nameToKey( AsciiString("SinglePlayerMenu.wnd:ButtonLoad") );
GameWindow *buttonLoad = TheWindowManager->winGetWindowFromId( NULL, buttonLoadID );
TheShell->registerWithAnimateManager(buttonLoad, WIN_ANIMATION_SLIDE_LEFT, TRUE,200);
NameKeyType buttonBackID = TheNameKeyGenerator->nameToKey( AsciiString("SinglePlayerMenu.wnd:ButtonBack") );
GameWindow *buttonBack = TheWindowManager->winGetWindowFromId( NULL, buttonBackID );
TheShell->registerWithAnimateManager(buttonBack, WIN_ANIMATION_SLIDE_RIGHT, TRUE,1);
//TheShell->registerWithAnimateManager(parent, WIN_ANIMATION_SLIDE_TOP, TRUE);
} // end SinglePlayerMenuInit
//-------------------------------------------------------------------------------------------------
/** single player menu shutdown method */
//-------------------------------------------------------------------------------------------------
void SinglePlayerMenuShutdown( WindowLayout *layout, void *userData )
{
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();
} // end SinglePlayerMenuShutdown
//-------------------------------------------------------------------------------------------------
/** single player menu update method */
//-------------------------------------------------------------------------------------------------
void SinglePlayerMenuUpdate( WindowLayout *layout, void *userData )
{
// We'll only be successful if we've requested to
if(isShuttingDown && TheShell->isAnimFinished())
shutdownComplete(layout);
} // end SinglePlayerMenuUpdate
//-------------------------------------------------------------------------------------------------
/** SinglePlayer menu input callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType SinglePlayerMenuInput( 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 ) )
{
AsciiString buttonName( "SinglePlayerMenu.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 SinglePlayerMenuInput
//-------------------------------------------------------------------------------------------------
/** single player menu window system callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType SinglePlayerMenuSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
static NameKeyType buttonNew = NAMEKEY_INVALID;
static NameKeyType buttonLoad = NAMEKEY_INVALID;
static NameKeyType buttonBack = NAMEKEY_INVALID;
switch( msg )
{
// --------------------------------------------------------------------------------------------
case GWM_CREATE:
{
// get ids for our children controls
buttonNew = TheNameKeyGenerator->nameToKey( AsciiString("SinglePlayerMenu.wnd:ButtonNew") );
buttonLoad = TheNameKeyGenerator->nameToKey( AsciiString("SinglePlayerMenu.wnd:ButtonLoad") );
buttonBack = TheNameKeyGenerator->nameToKey( AsciiString("SinglePlayerMenu.wnd:ButtonBack") );
break;
} // end create
//---------------------------------------------------------------------------------------------
case GWM_DESTROY:
{
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 GBM_SELECTED:
{
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if (buttonPushed)
break;
if( controlID == buttonNew )
{
// open up the map select menu
TheShell->push( AsciiString( "Menus/MapSelectMenu.wnd" ) );
buttonPushed = true;
} // end if
else if( controlID == buttonLoad )
{
} // end else if
else if( controlID == buttonBack )
{
// thou art directed to return to thy known solar system immediately!
TheShell->pop();
buttonPushed = true;
} // end else if
break;
} // end selected
default:
return MSG_IGNORED;
} // end switch
return MSG_HANDLED;
} // end SinglePlayerMenuSystem

View File

@@ -0,0 +1,605 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: SkirmishMapSelectMenu.cpp ////////////////////////////////////////////////////////////////////////
// Author: Chris Brue, August 2002
// Description: MapSelect menu window callbacks
///////////////////////////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/GameEngine.h"
#include "Common/MessageStream.h"
#include "Common/UserPreferences.h"
#include "GameClient/WindowLayout.h"
#include "GameClient/Gadget.h"
#include "GameClient/GameText.h"
#include "GameClient/Mouse.h"
#include "GameClient/Shell.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/GadgetListBox.h"
#include "GameClient/GadgetRadioButton.h"
#include "GameClient/GadgetStaticText.h"
#include "GameNetwork/LANAPICallbacks.h"
#include "GameClient/MapUtil.h"
// PRIVATE DATA ///////////////////////////////////////////////////////////////////////////////////
static NameKeyType buttonBack = NAMEKEY_INVALID;
static NameKeyType buttonOK = NAMEKEY_INVALID;
static NameKeyType listboxMap = NAMEKEY_INVALID;
static GameWindow *parent = NULL;
static GameWindow *mapList = NULL;
static NameKeyType radioButtonSystemMapsID = NAMEKEY_INVALID;
static NameKeyType radioButtonUserMapsID = NAMEKEY_INVALID;
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 *winMapPreview = NULL;
static NameKeyType winMapPreviewID = NAMEKEY_INVALID;
static void NullifyControls()
{
mapList = NULL;
winMapPreview = NULL;
parent = NULL;
for (Int i=0; i<MAX_SLOTS; ++i)
{
buttonMapStartPosition[i] = NULL;
}
}
extern WindowLayout *skirmishMapSelectLayout;
// Tooltips -------------------------------------------------------------------------------
static void mapListTooltipFunc(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);
return;
}
Int imageItemData = (Int)GadgetListBoxGetItemData(window, row, 1);
UnicodeString tooltip;
switch (imageItemData)
{
case 0:
tooltip = TheGameText->fetch("TOOLTIP:MapNoSuccess");
break;
case 1:
tooltip = TheGameText->fetch("TOOLTIP:MapEasySuccess");
break;
case 2:
tooltip = TheGameText->fetch("TOOLTIP:MapMediumSuccess");
break;
case 3:
tooltip = TheGameText->fetch("TOOLTIP:MapHardSuccess");
break;
}
TheMouse->setCursorTooltip( tooltip );
}
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
void positionStartSpots( AsciiString mapName, GameWindow *buttonMapStartPositions[], GameWindow *mapWindow);
void skirmishPositionStartSpots( void );
void skirmishUpdateSlotList( void );
void showSkirmishGameOptionsUnderlyingGUIElements( Bool show )
{
AsciiString parentName( "SkirmishGameOptionsMenu.wnd:SkirmishGameOptionsMenuParent" );
NameKeyType parentID = TheNameKeyGenerator->nameToKey( parentName );
GameWindow *parent = TheWindowManager->winGetWindowFromId( NULL, parentID );
if (!parent)
return;
// hide some GUI elements of the screen underneath
GameWindow *win;
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:MapWindow") );
win->winHide( !show );
//win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:StaticTextTitle") );
//win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:StaticTextTeam") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:StaticTextFaction") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:StaticTextColor") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:ComboBoxTeam0") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:ComboBoxTeam1") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:ComboBoxTeam2") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:ComboBoxTeam3") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:ComboBoxTeam4") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:ComboBoxTeam5") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:ComboBoxTeam6") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:ComboBoxTeam7") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:ComboBoxColor0") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:ComboBoxColor1") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:ComboBoxColor2") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:ComboBoxColor3") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:ComboBoxColor4") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:ComboBoxColor5") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:ComboBoxColor6") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:ComboBoxColor7") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:ComboBoxPlayerTemplate0") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:ComboBoxPlayerTemplate1") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:ComboBoxPlayerTemplate2") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:ComboBoxPlayerTemplate3") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:ComboBoxPlayerTemplate4") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:ComboBoxPlayerTemplate5") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:ComboBoxPlayerTemplate6") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:ComboBoxPlayerTemplate7") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:TextEntryMapDisplay") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:ButtonSelectMap") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:ButtonStart") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:StaticTextMapPreview") );
win->winHide( !show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:ButtonReset") );
win->winEnable( show );
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:ButtonBack") );
win->winEnable( show );
}
//-------------------------------------------------------------------------------------------------
/** Initialize the MapSelect menu */
//-------------------------------------------------------------------------------------------------
void SkirmishMapSelectMenuInit( WindowLayout *layout, void *userData )
{
// set keyboard focus to main parent
AsciiString parentName( "SkirmishMapSelectMenu.wnd:SkrimishMapSelectMenuParent" );
NameKeyType parentID = TheNameKeyGenerator->nameToKey( parentName );
parent = TheWindowManager->winGetWindowFromId( NULL, parentID );
TheWindowManager->winSetFocus( parent );
LANPreferences pref;
Bool usesSystemMapDir = pref.usesSystemMapDir();
const MapMetaData *mmd = TheMapCache->findMap(TheSkirmishGameInfo->getMap());
if (mmd)
{
usesSystemMapDir = mmd->m_isOfficial;
}
winMapPreviewID = TheNameKeyGenerator->nameToKey( AsciiString("SkirmishMapSelectMenu.wnd:WinMapPreview") );
winMapPreview = TheWindowManager->winGetWindowFromId(parent, winMapPreviewID);
buttonBack = TheNameKeyGenerator->nameToKey( AsciiString("SkirmishMapSelectMenu.wnd:ButtonBack") );
buttonOK = TheNameKeyGenerator->nameToKey( AsciiString("SkirmishMapSelectMenu.wnd:ButtonOK") );
listboxMap = TheNameKeyGenerator->nameToKey( AsciiString("SkirmishMapSelectMenu.wnd:ListboxMap") );
radioButtonSystemMapsID = TheNameKeyGenerator->nameToKey( "SkirmishMapSelectMenu.wnd:RadioButtonSystemMaps" );
radioButtonUserMapsID = TheNameKeyGenerator->nameToKey( "SkirmishMapSelectMenu.wnd:RadioButtonUserMaps" );
GameWindow *radioButtonSystemMaps = TheWindowManager->winGetWindowFromId( parent, radioButtonSystemMapsID );
GameWindow *radioButtonUserMaps = TheWindowManager->winGetWindowFromId( parent, radioButtonUserMapsID );
if (usesSystemMapDir)
GadgetRadioSetSelection( radioButtonSystemMaps, FALSE );
else
GadgetRadioSetSelection( radioButtonUserMaps, FALSE );
AsciiString tmpString;
for (Int i = 0; i < MAX_SLOTS; i++)
{
tmpString.format("SkirmishMapSelectMenu.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);
}
showSkirmishGameOptionsUnderlyingGUIElements(FALSE);
// get the listbox window
AsciiString listString( "SkirmishMapSelectMenu.wnd:ListboxMap" );
NameKeyType mapListID = TheNameKeyGenerator->nameToKey( listString );
mapList = TheWindowManager->winGetWindowFromId( parent, mapListID );
if( mapList )
{
if (TheMapCache)
TheMapCache->updateCache();
if (usesSystemMapDir)
{
populateMapListbox( mapList, TRUE, TRUE, TheSkirmishGameInfo->getMap() );
}
else
{
populateMapListbox( mapList, FALSE, FALSE, TheSkirmishGameInfo->getMap() );
populateMapListboxNoReset( mapList, FALSE, TRUE, TheSkirmishGameInfo->getMap() );
}
mapList->winSetTooltipFunc(mapListTooltipFunc);
}
} // end SkirmishMapSelectMenuInit
//-------------------------------------------------------------------------------------------------
/** MapSelect menu shutdown method */
//-------------------------------------------------------------------------------------------------
void SkirmishMapSelectMenuShutdown( WindowLayout *layout, void *userData )
{
// hide menu
layout->hide( TRUE );
NullifyControls();
// our shutdown is complete
TheShell->shutdownComplete( layout );
} // end LanMapSelectMenuShutdown
//-------------------------------------------------------------------------------------------------
/** MapSelect menu update method */
//-------------------------------------------------------------------------------------------------
void SkirmishMapSelectMenuUpdate( WindowLayout *layout, void *userData )
{
} // end SkirmishMapSelectMenuUpdate
//-------------------------------------------------------------------------------------------------
/** Map select menu input callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType SkirmishMapSelectMenuInput( 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( "SkirmishMapSelectMenu.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 SkirmishMapSelectMenuInput
//-------------------------------------------------------------------------------------------------
/** MapSelect menu window system callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType SkirmishMapSelectMenuSystem( 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 *mapWindow = TheWindowManager->winGetWindowFromId( parent, listboxMap );
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( mapWindow, rowSelected, 0 );
// set the map name in the global data map name
AsciiString asciiMap;
const char *mapFname = (const char *)GadgetListBoxGetItemData( mapWindow, 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:
{
// this isn't fixed yet
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if ( controlID == radioButtonSystemMapsID )
{
if (TheMapCache)
TheMapCache->updateCache();
populateMapListbox( mapList, TRUE, TRUE, TheSkirmishGameInfo->getMap() );
//LANPreferences pref;
//pref["UseSystemMapDir"] = "yes";
//pref.write();
}
else if ( controlID == radioButtonUserMapsID )
{
if (TheMapCache)
TheMapCache->updateCache();
populateMapListbox( mapList, FALSE, FALSE, TheSkirmishGameInfo->getMap() );
populateMapListboxNoReset( mapList, FALSE, TRUE, TheSkirmishGameInfo->getMap() );
//LANPreferences pref;
//pref["UseSystemMapDir"] = "no";
//pref.write();
}
else if ( controlID == buttonBack )
{
showSkirmishGameOptionsUnderlyingGUIElements(TRUE);
skirmishMapSelectLayout->destroyWindows();
skirmishMapSelectLayout->deleteInstance();
skirmishMapSelectLayout = NULL;
skirmishPositionStartSpots();
//TheShell->pop();
//do you need this ??
//PostToLanGameOptions( MAP_BACK );
} // end if
else if ( controlID == buttonOK )
{
Int selected;
UnicodeString map;
GameWindow *mapWindow = TheWindowManager->winGetWindowFromId( parent, listboxMap );
// get the selected index
GadgetListBoxGetSelected( mapWindow, &selected );
if( selected != -1 )
{
//buttonPushed = true;
// set the map name in the global data map name
AsciiString asciiMap;
const char *mapFname = (const char *)GadgetListBoxGetItemData( mapWindow, selected );
DEBUG_ASSERTCRASH(mapFname, ("No map item data"));
if (mapFname)
asciiMap = mapFname;
else
asciiMap.translate( map );
TheSkirmishGameInfo->setMap( asciiMap );
const MapMetaData *md = TheMapCache->findMap(asciiMap);
if (!md)
{
TheSkirmishGameInfo->setMapCRC(0);
TheSkirmishGameInfo->setMapSize(0);
}
else
{
TheSkirmishGameInfo->setMapCRC(md->m_CRC);
TheSkirmishGameInfo->setMapSize(md->m_filesize);
}
// reset the start positions
for(Int i = 0; i < MAX_SLOTS; ++i)
TheSkirmishGameInfo->getSlot(i)->setStartPos(-1);
GameWindow *win;
win = TheWindowManager->winGetWindowFromId( parent, TheNameKeyGenerator->nameToKey("SkirmishGameOptionsMenu.wnd:TextEntryMapDisplay") );
if(win)
{
if (md)
{
GadgetStaticTextSetText(win, md->m_displayName);
}
}
//if (mapFname)
//setupGameStart(mapFname);
showSkirmishGameOptionsUnderlyingGUIElements(TRUE);
skirmishPositionStartSpots();
skirmishUpdateSlotList();
skirmishMapSelectLayout->destroyWindows();
skirmishMapSelectLayout->deleteInstance();
skirmishMapSelectLayout = NULL;
//TheShell->pop();
} // end if
} // end else if
break;
} // end selected
default:
return MSG_IGNORED;
} // end switch
return MSG_HANDLED;
} // end SkirmishMapSelectMenuSystem*/

View File

@@ -0,0 +1,232 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
// FILE: WOLCustomScoreScreen.cpp
// Author: Matt Campbell, December 2001
// Description: Custom match score screen
///////////////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Lib/BaseType.h"
#include "Common/GameEngine.h"
#include "Common/NameKeyGenerator.h"
#include "GameClient/WindowLayout.h"
#include "GameClient/Gadget.h"
#include "GameClient/Shell.h"
#include "GameClient/KeyDefs.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/GadgetListBox.h"
#include "GameClient/GadgetTextEntry.h"
#include "Common/GlobalData.h"
//#include "GameNetwork/WOL.h"
//#include "GameNetwork/WOLmenus.h"
// PRIVATE DATA ///////////////////////////////////////////////////////////////////////////////////
// window ids ------------------------------------------------------------------------------
static NameKeyType parentWOLCustomScoreID = NAMEKEY_INVALID;
static NameKeyType buttonDisconnectID = NAMEKEY_INVALID;
static NameKeyType buttonLobbyID = NAMEKEY_INVALID;
// Window Pointers ------------------------------------------------------------------------
static GameWindow *parentWOLCustomScore = NULL;
static GameWindow *buttonDisconnect = NULL;
static GameWindow *buttonLobby = NULL;
//-------------------------------------------------------------------------------------------------
/** Initialize the WOL Status Menu */
//-------------------------------------------------------------------------------------------------
void WOLCustomScoreScreenInit( WindowLayout *layout, void *userData )
{
parentWOLCustomScoreID = TheNameKeyGenerator->nameToKey( AsciiString( "WOLCustomScoreScreen.wnd:WOLCustomScoreScreenParent" ) );
buttonDisconnectID = TheNameKeyGenerator->nameToKey( AsciiString( "WOLCustomScoreScreen.wnd:ButtonDisconnect" ) );
buttonLobbyID = TheNameKeyGenerator->nameToKey( AsciiString( "WOLCustomScoreScreen.wnd:ButtonLobby" ) );
parentWOLCustomScore = TheWindowManager->winGetWindowFromId( NULL, parentWOLCustomScoreID );
buttonDisconnect = TheWindowManager->winGetWindowFromId( NULL, buttonDisconnectID);
buttonLobby = TheWindowManager->winGetWindowFromId( NULL, buttonLobbyID);
/*
if (WOL::TheWOL->getState() == WOL::WOLAPI_FATAL_ERROR)
{
// We can get to the score screen even though we've been disconnected. Just hide
// any buttons that lead back into WOL.
buttonLobby->winHide( TRUE );
}
*/
// Show Menu
layout->hide( FALSE );
// Set Keyboard to Main Parent
TheWindowManager->winSetFocus( parentWOLCustomScore );
} // WOLCustomScoreScreenInit
//-------------------------------------------------------------------------------------------------
/** WOL Status Menu shutdown method */
//-------------------------------------------------------------------------------------------------
void WOLCustomScoreScreenShutdown( WindowLayout *layout, void *userData )
{
// hide menu
layout->hide( TRUE );
// our shutdown is complete
TheShell->shutdownComplete( layout );
} // WOLCustomScoreScreenShutdown
//-------------------------------------------------------------------------------------------------
/** WOL Status Menu update method */
//-------------------------------------------------------------------------------------------------
void WOLCustomScoreScreenUpdate( WindowLayout * layout, void *userData)
{
/*
if (WOL::TheWOL)
WOL::TheWOL->update();
*/
}// WOLCustomScoreScreenUpdate
//-------------------------------------------------------------------------------------------------
/** WOL Status Menu input callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType WOLCustomScoreScreenInput( 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 ) )
{
TheWindowManager->winSendSystemMsg( window, GBM_SELECTED,
(WindowMsgData)buttonDisconnect, buttonDisconnectID );
} // 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;
}// WOLCustomScoreScreenInput
//-------------------------------------------------------------------------------------------------
/** WOL Status Menu window system callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType WOLCustomScoreScreenSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
UnicodeString txtInput;
switch( msg )
{
case GWM_CREATE:
{
break;
} // case GWM_DESTROY:
case GWM_DESTROY:
{
break;
} // case GWM_DESTROY:
case GWM_INPUT_FOCUS:
{
// if we're given 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 GBM_SELECTED:
{
/*
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if ( controlID == buttonDisconnectID )
{
if (WOL::TheWOL->setState( WOL::WOLAPI_FATAL_ERROR ))
{
WOL::TheWOL->addCommand( WOL::WOLCOMMAND_RESET ); // don't display an error, log out, or anything
}
} //if ( controlID == buttonDisconnect )
else if ( controlID == buttonLobbyID )
{
if (WOL::TheWOL->getState() != WOL::WOLAPI_FATAL_ERROR)
{
WOL::TheWOL->setScreen(WOL::WOLAPI_MENU_CUSTOMLOBBY);
WOL::TheWOL->setGameMode(WOL::WOLTYPE_CUSTOM);
WOL::TheWOL->setState( WOL::WOLAPI_LOBBY );
WOL::TheWOL->addCommand( WOL::WOLCOMMAND_REFRESH_CHANNELS );
}
else
{
}
} //if ( controlID == buttonDisconnect )
*/
break;
}// case GBM_SELECTED:
case GEM_EDIT_DONE:
{
break;
}
default:
return MSG_IGNORED;
}//Switch
return MSG_HANDLED;
}// WOLCustomScoreScreenSystem

View File

@@ -0,0 +1,225 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: ReplayMenu.cpp /////////////////////////////////////////////////////////////////////
// Author: Chris The masta Huybregts, December 2001
// Description: Replay Menus
///////////////////////////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/GameEngine.h"
#include "GameClient/WindowLayout.h"
#include "GameClient/Shell.h"
#include "GameClient/KeyDefs.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/MessageBox.h"
#include "GameNetwork/WOLBrowser/WebBrowser.h"
// window ids -------------------------------------------------------------------------------------
static NameKeyType parentWindowID = NAMEKEY_INVALID;
static NameKeyType buttonBackID = NAMEKEY_INVALID;
static NameKeyType windowLadderID = NAMEKEY_INVALID;
// window pointers --------------------------------------------------------------------------------
static GameWindow *parentWindow = NULL;
static GameWindow *buttonBack = NULL;
static GameWindow *windowLadder = NULL;
//-------------------------------------------------------------------------------------------------
/** Initialize the single player menu */
//-------------------------------------------------------------------------------------------------
void WOLLadderScreenInit( WindowLayout *layout, void *userData )
{
TheShell->showShellMap(TRUE);
// get ids for our children controls
parentWindowID = TheNameKeyGenerator->nameToKey( AsciiString("WOLLadderScreen.wnd:LadderParent") );
buttonBackID = TheNameKeyGenerator->nameToKey( AsciiString("WOLLadderScreen.wnd:ButtonBack") );
windowLadderID = TheNameKeyGenerator->nameToKey( AsciiString("WOLLadderScreen.wnd:WindowLadder") );
parentWindow = TheWindowManager->winGetWindowFromId( NULL, parentWindowID );
buttonBack = TheWindowManager->winGetWindowFromId( parentWindow, buttonBackID );
windowLadder = TheWindowManager->winGetWindowFromId( parentWindow, windowLadderID );
//Load the listbox shiznit
// PopulateReplayFileListbox(listboxReplayFiles);
//TheWebBrowser->createBrowserWindow("Westwood", windowLadder);
if (TheWebBrowser != NULL)
{
TheWebBrowser->createBrowserWindow("MessageBoard", windowLadder);
}
// show menu
layout->hide( FALSE );
// set keyboard focus to main parent
TheWindowManager->winSetFocus( parentWindow );
} // end ReplayMenuInit
//-------------------------------------------------------------------------------------------------
/** single player menu shutdown method */
//-------------------------------------------------------------------------------------------------
void WOLLadderScreenShutdown( WindowLayout *layout, void *userData )
{
if (TheWebBrowser != NULL)
{
TheWebBrowser->closeBrowserWindow(windowLadder);
}
// hide menu
layout->hide( TRUE );
// our shutdown is complete
TheShell->shutdownComplete( layout );
} // end ReplayMenuShutdown
//-------------------------------------------------------------------------------------------------
/** single player menu update method */
//-------------------------------------------------------------------------------------------------
void WOLLadderScreenUpdate( WindowLayout *layout, void *userData )
{
} // end ReplayMenuUpdate
//-------------------------------------------------------------------------------------------------
/** Replay menu input callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType WOLLadderScreenInput( 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 ) )
{
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;
} // end ReplayMenuInput
//-------------------------------------------------------------------------------------------------
/** single player menu window system callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType WOLLadderScreenSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
switch( msg )
{
// --------------------------------------------------------------------------------------------
case GWM_CREATE:
{
break;
} // end create
//---------------------------------------------------------------------------------------------
case GWM_DESTROY:
{
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 GBM_SELECTED:
{
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if( controlID == buttonBackID )
{
// thou art directed to return to thy known solar system immediately!
TheShell->pop();
} // end else if
break;
} // end selected
default:
return MSG_IGNORED;
} // end switch
return MSG_HANDLED;
} // end ReplayMenuSystem

View File

@@ -0,0 +1,235 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
// FILE: WOLLocaleSelectPopup.cpp
// Author: Matt Campbell, December 2001
// Description: WOL locale select popup
///////////////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "GameClient/GameText.h"
#include "Common/CustomMatchPreferences.h"
#include "Common/GameEngine.h"
#include "Common/GameSpyMiscPreferences.h"
#include "GameClient/WindowLayout.h"
#include "GameClient/Gadget.h"
#include "GameClient/Shell.h"
#include "GameClient/KeyDefs.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/GadgetListBox.h"
#include "Common/GlobalData.h"
#include "GameNetwork/GameSpyOverlay.h"
#include "GameNetwork/GameSpy/PeerDefs.h"
#include "GameNetwork/GameSpy/PeerThread.h"
#include "GameNetwork/GameSpy/PersistentStorageDefs.h"
#include "GameNetwork/GameSpy/PersistentStorageThread.h"
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
// PRIVATE DATA ///////////////////////////////////////////////////////////////////////////////////
// window ids ------------------------------------------------------------------------------
static NameKeyType parentLocaleSelectID = NAMEKEY_INVALID;
static NameKeyType buttonOkID = NAMEKEY_INVALID;
static NameKeyType listboxLocaleID = NAMEKEY_INVALID;
// Window Pointers ------------------------------------------------------------------------
static GameWindow *parentLocaleSelect = NULL;
static GameWindow *buttonOk = NULL;
static GameWindow *listboxLocale = NULL;
//-------------------------------------------------------------------------------------------------
/** Initialize the WOL Status Menu */
//-------------------------------------------------------------------------------------------------
void WOLLocaleSelectInit( WindowLayout *layout, void *userData )
{
parentLocaleSelectID = TheNameKeyGenerator->nameToKey( AsciiString( "PopupLocaleSelect.wnd:ParentLocaleSelect" ) );
buttonOkID = TheNameKeyGenerator->nameToKey( AsciiString( "PopupLocaleSelect.wnd:ButtonOk" ) );
listboxLocaleID = TheNameKeyGenerator->nameToKey( AsciiString( "PopupLocaleSelect.wnd:ListBoxLocaleSelect" ) );
parentLocaleSelect = TheWindowManager->winGetWindowFromId( NULL, parentLocaleSelectID );
buttonOk = TheWindowManager->winGetWindowFromId( NULL, buttonOkID);
listboxLocale = TheWindowManager->winGetWindowFromId( NULL, listboxLocaleID);
for (int i=LOC_MIN; i<=LOC_MAX; ++i)
{
AsciiString id;
id.format("WOL:Locale%2.2d", i);
GadgetListBoxAddEntryText(listboxLocale, TheGameText->fetch(id.str()), GameSpyColor[GSCOLOR_DEFAULT], -1, -1);
}
GadgetListBoxSetSelected(listboxLocale, 0);
// Show Menu
layout->hide( FALSE );
// Set Keyboard to Main Parent
TheWindowManager->winSetFocus( parentLocaleSelect );
TheWindowManager->winSetModal( parentLocaleSelect );
} // WOLLocaleSelectInit
//-------------------------------------------------------------------------------------------------
/** WOL Status Menu shutdown method */
//-------------------------------------------------------------------------------------------------
void WOLLocaleSelectShutdown( WindowLayout *layout, void *userData )
{
// hide menu
layout->hide( TRUE );
// our shutdown is complete
TheShell->shutdownComplete( layout );
} // WOLLocaleSelectShutdown
//-------------------------------------------------------------------------------------------------
/** WOL Status Menu update method */
//-------------------------------------------------------------------------------------------------
void WOLLocaleSelectUpdate( WindowLayout * layout, void *userData)
{
}// WOLLocaleSelectUpdate
//-------------------------------------------------------------------------------------------------
/** WOL Status Menu input callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType WOLLocaleSelectInput( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
switch( msg )
{
// --------------------------------------------------------------------------------------------
case GWM_CHAR:
{
// UnsignedByte key = mData1;
// UnsignedByte state = mData2;
// ----------------------------------------------------------------------------------------
// don't let key fall through anywhere else
return MSG_HANDLED;
} // end char
} // end switch( msg )
return MSG_IGNORED;
}// WOLLocaleSelectInput
//Int getRegistryNicknameOffset(AsciiString nick); /// @todo: mdc remove this once we can save ini pref files
//-------------------------------------------------------------------------------------------------
/** WOL Status Menu window system callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType WOLLocaleSelectSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
UnicodeString txtInput;
switch( msg )
{
case GWM_CREATE:
{
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 GBM_SELECTED:
{
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if ( controlID == buttonOkID )
{
int selected;
GadgetListBoxGetSelected(listboxLocale, &selected);
if (selected < 0)
return MSG_HANDLED; // can't select nothing!
PSRequest psReq;
psReq.requestType = PSRequest::PSREQUEST_UPDATEPLAYERLOCALE;
psReq.player.locale = selected + LOC_MIN;
psReq.email = TheGameSpyInfo->getLocalEmail().str();
psReq.nick = TheGameSpyInfo->getLocalBaseName().str();
psReq.password = TheGameSpyInfo->getLocalPassword().str();
psReq.player.id = TheGameSpyInfo->getLocalProfileID();
TheGameSpyPSMessageQueue->addRequest(psReq);
GameSpyCloseOverlay(GSOVERLAY_LOCALESELECT);
GameSpyMiscPreferences cPref;
cPref.setLocale(psReq.player.locale);
cPref.write();
PSPlayerStats stats = TheGameSpyPSMessageQueue->findPlayerStatsByID(TheGameSpyInfo->getLocalProfileID());
stats.locale = psReq.player.locale;
if (stats.id == TheGameSpyInfo->getLocalProfileID())
TheGameSpyPSMessageQueue->trackPlayerStats(stats);
if(stats.id == 0)
{
stats = TheGameSpyInfo->getCachedLocalPlayerStats();
stats.locale = psReq.player.locale;
TheGameSpyInfo->setCachedLocalPlayerStats(stats);
}
else
{
// force an update of our shtuff
PSResponse newResp;
newResp.responseType = PSResponse::PSRESPONSE_PLAYERSTATS;
newResp.player = TheGameSpyPSMessageQueue->findPlayerStatsByID(TheGameSpyInfo->getLocalProfileID());
TheGameSpyPSMessageQueue->addResponse(newResp);
}
CheckReOpenPlayerInfo();
} //if ( controlID == buttonDisconnect )
break;
}// case GBM_SELECTED:
case GEM_EDIT_DONE:
{
break;
}
default:
return MSG_IGNORED;
}//Switch
return MSG_HANDLED;
}// WOLLocaleSelectSystem

View File

@@ -0,0 +1,471 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (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; i<MAX_SLOTS; ++i)
{
buttonMapStartPosition[i] = NULL;
}
}
static const char *layoutFilename = "GameSpyGameOptionsMenu.wnd";
static const char *parentName = "GameSpyGameOptionsMenuParent";
static const char *gadgetsToHide[] =
{
"MapWindow",
//"StaticTextGameName",
"StaticTextTeam",
"StaticTextFaction",
"StaticTextColor",
"TextEntryMapDisplay",
"ButtonSelectMap",
"ButtonStart",
"StaticTextMapPreview",
NULL // keep this last
};
static const char *perPlayerGadgetsToHide[] =
{
"ComboBoxTeam",
"ComboBoxColor",
"ComboBoxPlayerTemplate",
//"ButtonStartPosition",
NULL // keep this last
};
void positionStartSpots( AsciiString mapName, GameWindow *buttonMapStartPositions[], GameWindow *mapWindow);
static void showGameSpyGameOptionsUnderlyingGUIElements( Bool show )
{
ShowUnderlyingGUIElements( show, layoutFilename, parentName, gadgetsToHide, perPlayerGadgetsToHide );
GameWindow *win = TheWindowManager->winGetWindowFromId( 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;
}
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 (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<AsciiString, MapMetaData>::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

View File

@@ -0,0 +1,196 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
// FILE: WOLMessageWindow.cpp
// Author: Chris Huybregts, November 2001
// Description: Lan Lobby Menu
///////////////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/GameEngine.h"
#include "GameClient/WindowLayout.h"
#include "GameClient/Gadget.h"
#include "GameClient/Shell.h"
#include "GameClient/KeyDefs.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/GadgetListBox.h"
#include "GameClient/GadgetTextEntry.h"
#include "GameNetwork/IPEnumeration.h"
//#include "GameNetwork/WOL.h"
// PRIVATE DATA ///////////////////////////////////////////////////////////////////////////////////
// window ids ------------------------------------------------------------------------------
static NameKeyType parentWOLMessageWindowID = NAMEKEY_INVALID;
static NameKeyType buttonCancelID = NAMEKEY_INVALID;
// Window Pointers ------------------------------------------------------------------------
static GameWindow *parentWOLMessageWindow = NULL;
static GameWindow *buttonCancel = NULL;
//-------------------------------------------------------------------------------------------------
/** Initialize the WOLMessage Window */
//-------------------------------------------------------------------------------------------------
void WOLMessageWindowInit( WindowLayout *layout, void *userData )
{
parentWOLMessageWindowID = TheNameKeyGenerator->nameToKey( AsciiString( "WOLMessageWindow.wnd:WOLMessageWindowParent" ) );
buttonCancelID = TheNameKeyGenerator->nameToKey( AsciiString( "WOLMessageWindow.wnd:ButtonCancel" ) );
parentWOLMessageWindow = TheWindowManager->winGetWindowFromId( NULL, parentWOLMessageWindowID );
buttonCancel = TheWindowManager->winGetWindowFromId( NULL, buttonCancelID);
// Show Menu
layout->hide( FALSE );
// Set Keyboard to Main Parent
TheWindowManager->winSetFocus( parentWOLMessageWindow );
} // WOLMessageWindowInit
//-------------------------------------------------------------------------------------------------
/** WOLMessage Window shutdown method */
//-------------------------------------------------------------------------------------------------
void WOLMessageWindowShutdown( WindowLayout *layout, void *userData )
{
// hide menu
layout->hide( TRUE );
// our shutdown is complete
TheShell->shutdownComplete( layout );
} // WOLMessageWindowShutdown
//-------------------------------------------------------------------------------------------------
/** WOLMessage Window update method */
//-------------------------------------------------------------------------------------------------
void WOLMessageWindowUpdate( WindowLayout * layout, void *userData)
{
/*
if (WOL::TheWOL)
WOL::TheWOL->update();
*/
}// WOLMessageWindowUpdate
//-------------------------------------------------------------------------------------------------
/** WOLMessage Window input callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType WOLMessageWindowInput( 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 ) )
{
TheWindowManager->winSendSystemMsg( window, GBM_SELECTED,
(WindowMsgData)buttonCancel, buttonCancelID );
} // 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;
}// WOLMessageWindowInput
//-------------------------------------------------------------------------------------------------
/** WOLMessage Window window system callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType WOLMessageWindowSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
UnicodeString txtInput;
switch( msg )
{
case GWM_CREATE:
{
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 GBM_SELECTED:
{
break;
}// case GBM_SELECTED:
case GEM_EDIT_DONE:
{
break;
}
default:
return MSG_IGNORED;
}//Switch
return MSG_HANDLED;
}// WOLMessageWindowSystem

View File

@@ -0,0 +1,239 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
// FILE: WOLQMScoreScreen.cpp
// Author: Matt Campbell, November 2001
// Description: QuickMatch score screen (different from normal screen in that it has 'QM' and 'Discon' buttons)
///////////////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/GameEngine.h"
#include "GameClient/WindowLayout.h"
#include "GameClient/Gadget.h"
#include "GameClient/Shell.h"
#include "GameClient/KeyDefs.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/GadgetListBox.h"
#include "GameClient/GadgetTextEntry.h"
//#include "GameNetwork/WOL.h"
//#include "GameNetwork/WOLmenus.h"
// PRIVATE DATA ///////////////////////////////////////////////////////////////////////////////////
// window ids ------------------------------------------------------------------------------
static NameKeyType parentWOLQMScoreID = NAMEKEY_INVALID;
static NameKeyType buttonDisconnectID = NAMEKEY_INVALID;
static NameKeyType buttonQuickmatchID = NAMEKEY_INVALID;
// Window Pointers ------------------------------------------------------------------------
static GameWindow *parentWOLQMScore = NULL;
static GameWindow *buttonDisconnect = NULL;
static GameWindow *buttonQuickmatch = NULL;
//-------------------------------------------------------------------------------------------------
/** Initialize the WOL Status Menu */
//-------------------------------------------------------------------------------------------------
void WOLQMScoreScreenInit( WindowLayout *layout, void *userData )
{
parentWOLQMScoreID = TheNameKeyGenerator->nameToKey( AsciiString( "WOLQMScoreScreen.wnd:WOLQMScoreScreenParent" ) );
buttonDisconnectID = TheNameKeyGenerator->nameToKey( AsciiString( "WOLQMScoreScreen.wnd:ButtonDisconnect" ) );
buttonQuickmatchID = TheNameKeyGenerator->nameToKey( AsciiString( "WOLQMScoreScreen.wnd:ButtonQuickMatch" ) );
parentWOLQMScore = TheWindowManager->winGetWindowFromId( NULL, parentWOLQMScoreID );
buttonDisconnect = TheWindowManager->winGetWindowFromId( NULL, buttonDisconnectID);
buttonQuickmatch = TheWindowManager->winGetWindowFromId( NULL, buttonQuickmatchID);
/*
if (WOL::TheWOL->getState() == WOL::WOLAPI_FATAL_ERROR)
{
// We can get to the score screen even though we've been disconnected. Just hide
// any buttons that lead back into WOL.
buttonQuickmatch->winHide( TRUE );
}
*/
// Show Menu
layout->hide( FALSE );
// Set Keyboard to Main Parent
TheWindowManager->winSetFocus( parentWOLQMScore );
//progressLayout = TheShell->top();
} // WOLQMScoreScreenInit
//-------------------------------------------------------------------------------------------------
/** WOL Status Menu shutdown method */
//-------------------------------------------------------------------------------------------------
void WOLQMScoreScreenShutdown( WindowLayout *layout, void *userData )
{
// hide menu
layout->hide( TRUE );
// our shutdown is complete
TheShell->shutdownComplete( layout );
//progressLayout = NULL;
} // WOLQMScoreScreenShutdown
//-------------------------------------------------------------------------------------------------
/** WOL Status Menu update method */
//-------------------------------------------------------------------------------------------------
void WOLQMScoreScreenUpdate( WindowLayout * layout, void *userData)
{
/*
if (WOL::TheWOL)
WOL::TheWOL->update();
*/
}// WOLQMScoreScreenUpdate
//-------------------------------------------------------------------------------------------------
/** WOL Status Menu input callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType WOLQMScoreScreenInput( 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 ) )
{
TheWindowManager->winSendSystemMsg( window, GBM_SELECTED,
(WindowMsgData)buttonDisconnect, buttonDisconnectID );
} // 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;
}// WOLQMScoreScreenInput
//-------------------------------------------------------------------------------------------------
/** WOL Status Menu window system callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType WOLQMScoreScreenSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
UnicodeString txtInput;
switch( msg )
{
case GWM_CREATE:
{
break;
} // case GWM_DESTROY:
case GWM_DESTROY:
{
break;
} // case GWM_DESTROY:
case GWM_INPUT_FOCUS:
{
// if we're given 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 GBM_SELECTED:
{
/*
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if ( controlID == buttonDisconnectID )
{
//TheShell->pop();
if (WOL::TheWOL->setState( WOL::WOLAPI_FATAL_ERROR ))
{
WOL::TheWOL->addCommand( WOL::WOLCOMMAND_RESET ); // don't display an error, log out, or anything
}
} //if ( controlID == buttonDisconnect )
else if ( controlID == buttonQuickmatchID )
{
//TheShell->pop();
if (WOL::TheWOL->getState() != WOL::WOLAPI_FATAL_ERROR)
{
if (WOL::TheWOL->setState( WOL::WOLAPI_TOURNAMENT ))
{
WOL::TheWOL->setScreen( WOL::WOLAPI_MENU_QUICKMATCH );
WOL::TheWOL->addCommand( WOL::WOLCOMMAND_FIND_MATCH_CHANNEL );
}
}
} //if ( controlID == buttonDisconnect )
*/
break;
}// case GBM_SELECTED:
case GEM_EDIT_DONE:
{
break;
}
default:
return MSG_IGNORED;
}//Switch
return MSG_HANDLED;
}// WOLQMScoreScreenSystem

View File

@@ -0,0 +1,216 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
// FILE: WOLLoginMenu.cpp
// Author: Chris Huybregts, November 2001
// Description: Lan Lobby Menu
///////////////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/GameEngine.h"
#include "GameClient/WindowLayout.h"
#include "GameClient/Gadget.h"
#include "GameClient/Shell.h"
#include "GameClient/KeyDefs.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/GadgetListBox.h"
#include "GameClient/GadgetTextEntry.h"
//#include "GameNetwork/WOL.h"
//#include "GameNetwork/WOLmenus.h"
// PRIVATE DATA ///////////////////////////////////////////////////////////////////////////////////
// window ids ------------------------------------------------------------------------------
static NameKeyType parentWOLStatusID = NAMEKEY_INVALID;
static NameKeyType buttonDisconnectID = NAMEKEY_INVALID;
// Window Pointers ------------------------------------------------------------------------
static GameWindow *parentWOLStatus = NULL;
static GameWindow *buttonDisconnect = NULL;
GameWindow *progressTextWindow = NULL;
//-------------------------------------------------------------------------------------------------
/** Initialize the WOL Status Menu */
//-------------------------------------------------------------------------------------------------
void WOLStatusMenuInit( WindowLayout *layout, void *userData )
{
parentWOLStatusID = TheNameKeyGenerator->nameToKey( AsciiString( "WOLStatusMenu.wnd:WOLStatusMenuParent" ) );
buttonDisconnectID = TheNameKeyGenerator->nameToKey( AsciiString( "WOLStatusMenu.wnd:ButtonDisconnect" ) );
parentWOLStatus = TheWindowManager->winGetWindowFromId( NULL, parentWOLStatusID );
buttonDisconnect = TheWindowManager->winGetWindowFromId( NULL, buttonDisconnectID);
progressTextWindow = TheWindowManager->winGetWindowFromId( NULL,
TheNameKeyGenerator->nameToKey( AsciiString( "WOLStatusMenu.wnd:ListboxStatus" ) ) );
// Show Menu
layout->hide( FALSE );
// Set Keyboard to Main Parent
TheWindowManager->winSetFocus( parentWOLStatus );
//progressLayout = TheShell->top();
//WOL::raiseWOLMessageBox();
} // WOLStatusMenuInit
//-------------------------------------------------------------------------------------------------
/** WOL Status Menu shutdown method */
//-------------------------------------------------------------------------------------------------
void WOLStatusMenuShutdown( WindowLayout *layout, void *userData )
{
// hide menu
layout->hide( TRUE );
// our shutdown is complete
TheShell->shutdownComplete( layout );
//progressLayout = NULL;
//WOL::raiseWOLMessageBox();
} // WOLStatusMenuShutdown
//-------------------------------------------------------------------------------------------------
/** WOL Status Menu update method */
//-------------------------------------------------------------------------------------------------
void WOLStatusMenuUpdate( WindowLayout * layout, void *userData)
{
//if (WOL::TheWOL)
//WOL::TheWOL->update();
}// WOLStatusMenuUpdate
//-------------------------------------------------------------------------------------------------
/** WOL Status Menu input callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType WOLStatusMenuInput( 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 ) )
{
TheWindowManager->winSendSystemMsg( window, GBM_SELECTED,
(WindowMsgData)buttonDisconnect, buttonDisconnectID );
} // 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;
}// WOLStatusMenuInput
//-------------------------------------------------------------------------------------------------
/** WOL Status Menu window system callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType WOLStatusMenuSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
UnicodeString txtInput;
switch( msg )
{
case GWM_CREATE:
{
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 GBM_SELECTED:
{
/*
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if ( controlID == buttonDisconnectID )
{
//TheShell->pop();
if (WOL::TheWOL->setState( WOL::WOLAPI_FATAL_ERROR ))
{
WOL::TheWOL->addCommand( WOL::WOLCOMMAND_RESET ); // don't display an error, log out, or anything
}
} //if ( controlID == buttonDisconnect )
*/
break;
}// case GBM_SELECTED:
case GEM_EDIT_DONE:
{
break;
}
default:
return MSG_IGNORED;
}//Switch
return MSG_HANDLED;
}// WOLStatusMenuSystem

View File

@@ -0,0 +1,894 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
// FILE: WOLWelcomeMenu.cpp
// Author: Chris Huybregts, November 2001
// Description: Lan Lobby Menu
///////////////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "GameSpy/peer/peer.h"
#include "Common/GameEngine.h"
#include "Common/GameSpyMiscPreferences.h"
#include "Common/CustomMatchPreferences.h"
#include "Common/GlobalData.h"
#include "Common/UserPreferences.h"
#include "GameClient/AnimateWindowManager.h"
#include "GameClient/Display.h"
#include "GameClient/WindowLayout.h"
#include "GameClient/Gadget.h"
#include "GameClient/GameText.h"
#include "GameClient/Shell.h"
#include "GameClient/KeyDefs.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/GadgetListBox.h"
#include "GameClient/GadgetTextEntry.h"
#include "GameClient/GadgetStaticText.h"
#include "GameClient/MessageBox.h"
#include "GameClient/GameWindowTransitions.h"
#include "GameNetwork/FirewallHelper.h"
#include "GameNetwork/GameSpyOverlay.h"
#include "GameNetwork/GameSpy/BuddyDefs.h"
#include "GameNetwork/GameSpy/BuddyThread.h"
#include "GameNetwork/GameSpy/PeerDefs.h"
#include "GameNetwork/GameSpy/PeerThread.h"
#include "GameNetwork/GameSpy/PersistentStorageDefs.h"
#include "GameNetwork/GameSpy/PersistentStorageThread.h"
#include "GameNetwork/GameSpy/BuddyThread.h"
#include "GameNetwork/GameSpy/ThreadUtils.h"
#include "GameNetwork/GameSpy/MainMenuUtils.h"
#include "GameNetwork/WOLBrowser/WebBrowser.h"
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
// PRIVATE DATA ///////////////////////////////////////////////////////////////////////////////////
static Bool isShuttingDown = FALSE;
static Bool buttonPushed = FALSE;
static char *nextScreen = NULL;
// window ids ------------------------------------------------------------------------------
static NameKeyType parentWOLWelcomeID = NAMEKEY_INVALID;
static NameKeyType buttonBackID = NAMEKEY_INVALID;
static NameKeyType buttonQuickMatchID = NAMEKEY_INVALID;
static NameKeyType buttonLobbyID = NAMEKEY_INVALID;
static NameKeyType buttonBuddiesID = NAMEKEY_INVALID;
static NameKeyType buttonLadderID = NAMEKEY_INVALID;
static NameKeyType buttonMyInfoID = NAMEKEY_INVALID;
static NameKeyType listboxInfoID = NAMEKEY_INVALID;
static NameKeyType buttonOptionsID = NAMEKEY_INVALID;
// Window Pointers ------------------------------------------------------------------------
static GameWindow *parentWOLWelcome = NULL;
static GameWindow *buttonBack = NULL;
static GameWindow *buttonQuickMatch = NULL;
static GameWindow *buttonLobby = NULL;
static GameWindow *buttonBuddies = NULL;
static GameWindow *buttonLadder = NULL;
static GameWindow *buttonMyInfo = NULL;
static GameWindow *buttonbuttonOptions = NULL;
static WindowLayout *welcomeLayout = NULL;
static GameWindow *listboxInfo = NULL;
static GameWindow *staticTextServerName = NULL;
static GameWindow *staticTextLastUpdated = NULL;
static GameWindow *staticTextLadderWins = NULL;
static GameWindow *staticTextLadderLosses = NULL;
static GameWindow *staticTextLadderRank = NULL;
static GameWindow *staticTextLadderPoints = NULL;
static GameWindow *staticTextLadderDisconnects = NULL;
static GameWindow *staticTextHighscoreWins = NULL;
static GameWindow *staticTextHighscoreLosses = NULL;
static GameWindow *staticTextHighscoreRank = NULL;
static GameWindow *staticTextHighscorePoints = NULL;
static UnicodeString gServerName;
void updateServerDisplay(UnicodeString serverName)
{
if (staticTextServerName)
{
GadgetStaticTextSetText(staticTextServerName, serverName);
}
gServerName = serverName;
}
/*
void updateLocalPlayerScores(AsciiString name, const WOL::Ladder *ladder, const WOL::Highscore *highscore)
{
if (ladder)
{
AsciiString a;
UnicodeString u;
a.format("%d", ladder->wins);
u.translate(a);
GadgetStaticTextSetText(staticTextLadderWins, u);
a.format("%d", ladder->losses);
u.translate(a);
GadgetStaticTextSetText(staticTextLadderLosses, u);
a.format("%d", ladder->rank);
u.translate(a);
GadgetStaticTextSetText(staticTextLadderRank, u);
a.format("%d", ladder->points);
u.translate(a);
GadgetStaticTextSetText(staticTextLadderPoints, u);
a.format("%d", ladder->disconnects);
u.translate(a);
GadgetStaticTextSetText(staticTextLadderDisconnects, u);
}
if (highscore)
{
AsciiString a;
UnicodeString u;
a.format("%d", highscore->wins);
u.translate(a);
GadgetStaticTextSetText(staticTextHighscoreWins, u);
a.format("%d", highscore->losses);
u.translate(a);
GadgetStaticTextSetText(staticTextHighscoreLosses, u);
a.format("%d", highscore->rank);
u.translate(a);
GadgetStaticTextSetText(staticTextHighscoreRank, u);
a.format("%d", highscore->points);
u.translate(a);
GadgetStaticTextSetText(staticTextHighscorePoints, u);
}
}
*/
static void enableControls( Bool state )
{
#ifndef _PLAYTEST
if (buttonQuickMatch)
buttonQuickMatch->winEnable(state);
#else
if (buttonQuickMatch)
buttonQuickMatch->winEnable(FALSE);
#endif
if (buttonLobby)
buttonLobby->winEnable(state);
}
//-------------------------------------------------------------------------------------------------
/** 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
//-------------------------------------------------------------------------------------------------
/** Handle Num Players Online data */
//-------------------------------------------------------------------------------------------------
static Int lastNumPlayersOnline = 0;
static UnsignedByte grabUByte(const char *s)
{
char tmp[5] = "0xff";
tmp[2] = s[0];
tmp[3] = s[1];
UnsignedByte b = strtol(tmp, NULL, 16);
return b;
}
static void updateNumPlayersOnline(void)
{
GameWindow *playersOnlineWindow = TheWindowManager->winGetWindowFromId(
NULL, NAMEKEY("WOLWelcomeMenu.wnd:StaticTextNumPlayersOnline") );
if (playersOnlineWindow)
{
UnicodeString valStr;
valStr.format(TheGameText->fetch("GUI:NumPlayersOnline"), lastNumPlayersOnline);
GadgetStaticTextSetText(playersOnlineWindow, valStr);
}
if (listboxInfo && TheGameSpyInfo)
{
GadgetListBoxReset(listboxInfo);
AsciiString aLine;
UnicodeString line;
AsciiString aMotd = TheGameSpyInfo->getMOTD();
UnicodeString headingStr;
headingStr.format(TheGameText->fetch("MOTD:NumPlayersHeading"), lastNumPlayersOnline);
while (headingStr.nextToken(&line, UnicodeString(L"\n")))
{
if (line.getCharAt(line.getLength()-1) == '\r')
line.removeLastChar(); // there is a trailing '\r'
line.trim();
if (line.isEmpty())
{
line = UnicodeString(L" ");
}
GadgetListBoxAddEntryText(listboxInfo, line, GameSpyColor[GSCOLOR_MOTD_HEADING], -1, -1);
}
GadgetListBoxAddEntryText(listboxInfo, UnicodeString(L" "), GameSpyColor[GSCOLOR_MOTD_HEADING], -1, -1);
while (aMotd.nextToken(&aLine, "\n"))
{
if (aLine.getCharAt(aLine.getLength()-1) == '\r')
aLine.removeLastChar(); // there is a trailing '\r'
aLine.trim();
if (aLine.isEmpty())
{
aLine = " ";
}
Color c = GameSpyColor[GSCOLOR_MOTD];
if (aLine.startsWith("\\\\"))
{
aLine = aLine.str()+1;
}
else if (aLine.startsWith("\\") && aLine.getLength() > 9)
{
// take out the hex value from strings starting as "\ffffffffText"
UnsignedByte a, r, g, b;
a = grabUByte(aLine.str()+1);
r = grabUByte(aLine.str()+3);
g = grabUByte(aLine.str()+5);
b = grabUByte(aLine.str()+7);
c = GameMakeColor(r, g, b, a);
DEBUG_LOG(("MOTD line '%s' has color %X\n", aLine.str(), c));
aLine = aLine.str() + 9;
}
line = UnicodeString(MultiByteToWideCharSingleLine(aLine.str()).c_str());
GadgetListBoxAddEntryText(listboxInfo, line, c, -1, -1);
}
}
}
void HandleNumPlayersOnline( Int numPlayersOnline )
{
lastNumPlayersOnline = numPlayersOnline;
if (lastNumPlayersOnline < 1)
lastNumPlayersOnline = 1;
updateNumPlayersOnline();
}
//-------------------------------------------------------------------------------------------------
/** Handle Overall Stats data */
//-------------------------------------------------------------------------------------------------
static OverallStats s_statsUSA, s_statsChina, s_statsGLA;
OverallStats::OverallStats()
{
for (Int i=0; i<STATS_MAX; ++i)
{
wins[i] = losses[i] = 0;
}
}
static UnicodeString calcPercent(const OverallStats& stats, Int n, UnicodeString sideStr)
{
// per side percentage of total wins
Real winPercentUSA = s_statsUSA.wins[n]*100/INT_TO_REAL(max(1, s_statsUSA.wins[n]+s_statsUSA.losses[n])); // 0.0f - 100.0f
Real winPercentChina = s_statsChina.wins[n]*100/INT_TO_REAL(max(1, s_statsChina.wins[n]+s_statsChina.losses[n])); // 0.0f - 100.0f
Real winPercentGLA = s_statsGLA.wins[n]*100/INT_TO_REAL(max(1, s_statsGLA.wins[n]+s_statsGLA.losses[n])); // 0.0f - 100.0f
Real thisWinPercent = stats.wins[n]*100/INT_TO_REAL(max(1, stats.wins[n]+stats.losses[n])); // 0.0f - 100.0f
Real totalWinPercent = winPercentUSA + winPercentChina + winPercentGLA;
Real val = thisWinPercent*100/max(1.0f,totalWinPercent);
UnicodeString s;
s.format(TheGameText->fetch("GUI:PerSideWinPercentage"), REAL_TO_INT(val), sideStr.str());
/*
Int totalDenominator = s_statsUSA.wins[n] + s_statsChina.wins[n] + s_statsGLA.wins[n];
if (!totalDenominator)
totalDenominator = 1;
UnicodeString s;
s.format(TheGameText->fetch("GUI:PerSideWinPercentage"), REAL_TO_INT(stats.wins[n]*100/totalDenominator), sideStr.str());
*/
return s;
}
static void updateOverallStats(void)
{
UnicodeString usa, china, gla;
GameWindow *win;
usa = calcPercent(s_statsUSA, STATS_LASTWEEK, TheGameText->fetch("SIDE:America"));
china = calcPercent(s_statsChina, STATS_LASTWEEK, TheGameText->fetch("SIDE:China"));
gla = calcPercent(s_statsGLA, STATS_LASTWEEK, TheGameText->fetch("SIDE:GLA"));
DEBUG_LOG(("Last Week: %ls %ls %ls\n", usa.str(), china.str(), gla.str()));
win = TheWindowManager->winGetWindowFromId( NULL, NAMEKEY("WOLWelcomeMenu.wnd:StaticTextUSALastWeek") );
GadgetStaticTextSetText(win, usa);
win = TheWindowManager->winGetWindowFromId( NULL, NAMEKEY("WOLWelcomeMenu.wnd:StaticTextChinaLastWeek") );
GadgetStaticTextSetText(win, china);
win = TheWindowManager->winGetWindowFromId( NULL, NAMEKEY("WOLWelcomeMenu.wnd:StaticTextGLALastWeek") );
GadgetStaticTextSetText(win, gla);
usa = calcPercent(s_statsUSA, STATS_TODAY, TheGameText->fetch("SIDE:America"));
china = calcPercent(s_statsChina, STATS_TODAY, TheGameText->fetch("SIDE:China"));
gla = calcPercent(s_statsGLA, STATS_TODAY, TheGameText->fetch("SIDE:GLA"));
DEBUG_LOG(("Today: %ls %ls %ls\n", usa.str(), china.str(), gla.str()));
win = TheWindowManager->winGetWindowFromId( NULL, NAMEKEY("WOLWelcomeMenu.wnd:StaticTextUSAToday") );
GadgetStaticTextSetText(win, usa);
win = TheWindowManager->winGetWindowFromId( NULL, NAMEKEY("WOLWelcomeMenu.wnd:StaticTextChinaToday") );
GadgetStaticTextSetText(win, china);
win = TheWindowManager->winGetWindowFromId( NULL, NAMEKEY("WOLWelcomeMenu.wnd:StaticTextGLAToday") );
GadgetStaticTextSetText(win, gla);
}
void HandleOverallStats( const OverallStats& USA, const OverallStats& China, const OverallStats& GLA )
{
s_statsUSA = USA;
s_statsChina = China;
s_statsGLA = GLA;
updateOverallStats();
}
//-------------------------------------------------------------------------------------------------
/** Handle player stats */
//-------------------------------------------------------------------------------------------------
void UpdateLocalPlayerStats(void)
{
GameWindow *welcomeParent = TheWindowManager->winGetWindowFromId( NULL, NAMEKEY("WOLWelcomeMenu.wnd:WOLWelcomeMenuParent") );
if (welcomeParent)
{
PopulatePlayerInfoWindows( "WOLWelcomeMenu.wnd" );
}
else
{
PopulatePlayerInfoWindows( "WOLQuickMatchMenu.wnd" );
}
return;
}
static Bool raiseMessageBoxes = FALSE;
//-------------------------------------------------------------------------------------------------
/** Initialize the WOL Welcome Menu */
//-------------------------------------------------------------------------------------------------
void WOLWelcomeMenuInit( WindowLayout *layout, void *userData )
{
nextScreen = NULL;
buttonPushed = FALSE;
isShuttingDown = FALSE;
welcomeLayout = layout;
//TheWOL->reset();
parentWOLWelcomeID = TheNameKeyGenerator->nameToKey( AsciiString( "WOLWelcomeMenu.wnd:WOLWelcomeMenuParent" ) );
buttonBackID = TheNameKeyGenerator->nameToKey( AsciiString( "WOLWelcomeMenu.wnd:ButtonBack" ) );
parentWOLWelcome = TheWindowManager->winGetWindowFromId( NULL, parentWOLWelcomeID );
buttonBack = TheWindowManager->winGetWindowFromId( NULL, buttonBackID);
buttonOptionsID = TheNameKeyGenerator->nameToKey( "WOLWelcomeMenu.wnd:ButtonOptions" );
buttonbuttonOptions = TheWindowManager->winGetWindowFromId( NULL, buttonOptionsID);
listboxInfoID = TheNameKeyGenerator->nameToKey( AsciiString( "WOLWelcomeMenu.wnd:InfoListbox" ) );
listboxInfo = TheWindowManager->winGetWindowFromId( NULL, listboxInfoID);
staticTextServerName = TheWindowManager->winGetWindowFromId( parentWOLWelcome,
TheNameKeyGenerator->nameToKey( "WOLWelcomeMenu.wnd:StaticTextServerName" ));
staticTextLastUpdated = TheWindowManager->winGetWindowFromId( parentWOLWelcome,
TheNameKeyGenerator->nameToKey( "WOLWelcomeMenu.wnd:StaticTextLastUpdated" ));
staticTextLadderWins = TheWindowManager->winGetWindowFromId( parentWOLWelcome,
TheNameKeyGenerator->nameToKey( "WOLWelcomeMenu.wnd:StaticTextLadderWins" ));
staticTextLadderLosses = TheWindowManager->winGetWindowFromId( parentWOLWelcome,
TheNameKeyGenerator->nameToKey( "WOLWelcomeMenu.wnd:StaticTextLadderLosses" ));
staticTextLadderPoints = TheWindowManager->winGetWindowFromId( parentWOLWelcome,
TheNameKeyGenerator->nameToKey( "WOLWelcomeMenu.wnd:StaticTextLadderPoints" ));
staticTextLadderRank = TheWindowManager->winGetWindowFromId( parentWOLWelcome,
TheNameKeyGenerator->nameToKey( "WOLWelcomeMenu.wnd:StaticTextLadderRank" ));
staticTextLadderDisconnects = TheWindowManager->winGetWindowFromId( parentWOLWelcome,
TheNameKeyGenerator->nameToKey( "WOLWelcomeMenu.wnd:StaticTextDisconnects" ));
staticTextHighscoreWins = TheWindowManager->winGetWindowFromId( parentWOLWelcome,
TheNameKeyGenerator->nameToKey( "WOLWelcomeMenu.wnd:StaticTextHighscoreWins" ));
staticTextHighscoreLosses = TheWindowManager->winGetWindowFromId( parentWOLWelcome,
TheNameKeyGenerator->nameToKey( "WOLWelcomeMenu.wnd:StaticTextHighscoreLosses" ));
staticTextHighscorePoints = TheWindowManager->winGetWindowFromId( parentWOLWelcome,
TheNameKeyGenerator->nameToKey( "WOLWelcomeMenu.wnd:StaticTextHighscorePoints" ));
staticTextHighscoreRank = TheWindowManager->winGetWindowFromId( parentWOLWelcome,
TheNameKeyGenerator->nameToKey( "WOLWelcomeMenu.wnd:StaticTextHighscoreRank" ));
if (staticTextServerName)
{
GadgetStaticTextSetText(staticTextServerName, gServerName);
}
GameWindow *staticTextTitle = TheWindowManager->winGetWindowFromId(parentWOLWelcome, NAMEKEY("WOLWelcomeMenu.wnd:StaticTextTitle"));
if (staticTextTitle && TheGameSpyInfo)
{
UnicodeString title;
title.format(TheGameText->fetch("GUI:WOLWelcome"), TheGameSpyInfo->getLocalBaseName().str());
GadgetStaticTextSetText(staticTextTitle, title);
}
// Clear some defaults
/*
UnicodeString questionMark = UnicodeString(L"?");
GadgetStaticTextSetText(staticTextLastUpdated, questionMark);
GadgetStaticTextSetText(staticTextLadderWins, questionMark);
GadgetStaticTextSetText(staticTextLadderLosses, questionMark);
GadgetStaticTextSetText(staticTextLadderPoints, questionMark);
GadgetStaticTextSetText(staticTextLadderRank, questionMark);
GadgetStaticTextSetText(staticTextLadderDisconnects, questionMark);
GadgetStaticTextSetText(staticTextHighscoreWins, questionMark);
GadgetStaticTextSetText(staticTextHighscoreLosses, questionMark);
GadgetStaticTextSetText(staticTextHighscorePoints, questionMark);
GadgetStaticTextSetText(staticTextHighscoreRank, questionMark);
*/
//DEBUG_ASSERTCRASH(listboxInfo, ("No control found!"));
buttonQuickMatchID = TheNameKeyGenerator->nameToKey( AsciiString( "WOLWelcomeMenu.wnd:ButtonQuickMatch" ) );
buttonQuickMatch = TheWindowManager->winGetWindowFromId( parentWOLWelcome, buttonQuickMatchID );
buttonLobbyID = TheNameKeyGenerator->nameToKey( AsciiString( "WOLWelcomeMenu.wnd:ButtonCustomMatch" ) );
buttonLobby = TheWindowManager->winGetWindowFromId( parentWOLWelcome, buttonLobbyID );
buttonBuddiesID = TheNameKeyGenerator->nameToKey( AsciiString( "WOLWelcomeMenu.wnd:ButtonBuddies" ) );
buttonBuddies = TheWindowManager->winGetWindowFromId( parentWOLWelcome, buttonBuddiesID );
buttonMyInfoID = TheNameKeyGenerator->nameToKey( AsciiString( "WOLWelcomeMenu.wnd:ButtonMyInfo" ) );
buttonMyInfo = TheWindowManager->winGetWindowFromId( parentWOLWelcome, buttonMyInfoID );
buttonLadderID = TheNameKeyGenerator->nameToKey( AsciiString( "WOLWelcomeMenu.wnd:ButtonLadder" ) );
buttonLadder = TheWindowManager->winGetWindowFromId( parentWOLWelcome, buttonLadderID );
if (TheFirewallHelper == NULL) {
TheFirewallHelper = createFirewallHelper();
}
if (TheFirewallHelper->detectFirewall() == TRUE) {
// don't need to detect firewall, already been done.
delete TheFirewallHelper;
TheFirewallHelper = NULL;
}
/*
if (TheGameSpyChat && TheGameSpyChat->isConnected())
{
const char *keys[3] = { "locale", "wins", "losses" };
char valueStrings[3][20];
char *values[3] = { valueStrings[0], valueStrings[1], valueStrings[2] };
_snprintf(values[0], 20, "%s", TheGameSpyPlayerInfo->getLocale().str());
_snprintf(values[1], 20, "%d", TheGameSpyPlayerInfo->getWins());
_snprintf(values[2], 20, "%d", TheGameSpyPlayerInfo->getLosses());
peerSetGlobalKeys(TheGameSpyChat->getPeer(), 3, (const char **)keys, (const char **)values);
peerSetGlobalWatchKeys(TheGameSpyChat->getPeer(), GroupRoom, 3, keys, PEERFalse);
peerSetGlobalWatchKeys(TheGameSpyChat->getPeer(), StagingRoom, 3, keys, PEERFalse);
}
*/
// // animate controls
// TheShell->registerWithAnimateManager(buttonQuickMatch, WIN_ANIMATION_SLIDE_LEFT, TRUE, 800);
// TheShell->registerWithAnimateManager(buttonLobby, WIN_ANIMATION_SLIDE_LEFT, TRUE, 600);
// //TheShell->registerWithAnimateManager(NULL, WIN_ANIMATION_SLIDE_LEFT, TRUE, 400);
// TheShell->registerWithAnimateManager(buttonBuddies, WIN_ANIMATION_SLIDE_LEFT, TRUE, 200);
// //TheShell->registerWithAnimateManager(NULL, WIN_ANIMATION_SLIDE_LEFT, TRUE, 1);
// TheShell->registerWithAnimateManager(buttonBack, WIN_ANIMATION_SLIDE_BOTTOM, TRUE, 1);
// Show Menu
layout->hide( FALSE );
// Set Keyboard to Main Parent
TheWindowManager->winSetFocus( parentWOLWelcome );
enableControls( TheGameSpyInfo->gotGroupRoomList() );
TheShell->showShellMap(TRUE);
updateNumPlayersOnline();
updateOverallStats();
UpdateLocalPlayerStats();
GameSpyMiscPreferences cPref;
if (cPref.getLocale() < LOC_MIN || cPref.getLocale() > LOC_MAX)
{
GameSpyOpenOverlay(GSOVERLAY_LOCALESELECT);
}
raiseMessageBoxes = TRUE;
TheTransitionHandler->setGroup("WOLWelcomeMenuFade");
} // WOLWelcomeMenuInit
//-------------------------------------------------------------------------------------------------
/** WOL Welcome Menu shutdown method */
//-------------------------------------------------------------------------------------------------
void WOLWelcomeMenuShutdown( WindowLayout *layout, void *userData )
{
listboxInfo = NULL;
if (TheFirewallHelper != NULL) {
delete TheFirewallHelper;
TheFirewallHelper = 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();
TheTransitionHandler->reverse("WOLWelcomeMenuFade");
RaiseGSMessageBox();
} // WOLWelcomeMenuShutdown
//-------------------------------------------------------------------------------------------------
/** WOL Welcome Menu update method */
//-------------------------------------------------------------------------------------------------
void WOLWelcomeMenuUpdate( WindowLayout * layout, void *userData)
{
// We'll only be successful if we've requested to
if(isShuttingDown && TheShell->isAnimFinished() && TheTransitionHandler->isFinished())
shutdownComplete(layout);
if (raiseMessageBoxes)
{
RaiseGSMessageBox();
raiseMessageBoxes = FALSE;
}
if (TheFirewallHelper != NULL)
{
if (TheFirewallHelper->behaviorDetectionUpdate())
{
TheWritableGlobalData->m_firewallBehavior = TheFirewallHelper->getFirewallBehavior();
TheFirewallHelper->writeFirewallBehavior();
TheFirewallHelper->flagNeedToRefresh(FALSE); // 2/19/03 BGC, we're done, so we don't need to refresh the NAT anymore.
// we are now done with the firewall helper
delete TheFirewallHelper;
TheFirewallHelper = NULL;
}
}
if (TheShell->isAnimFinished() && !buttonPushed && TheGameSpyPeerMessageQueue)
{
HandleBuddyResponses();
HandlePersistentStorageResponses();
Int allowedMessages = TheGameSpyInfo->getMaxMessagesPerUpdate();
Bool sawImportantMessage = FALSE;
PeerResponse resp;
while (allowedMessages-- && !sawImportantMessage && TheGameSpyPeerMessageQueue->getResponse( resp ))
{
switch (resp.peerResponseType)
{
case PeerResponse::PEERRESPONSE_GROUPROOM:
{
GameSpyGroupRoom room;
room.m_groupID = resp.groupRoom.id;
room.m_maxWaiting = resp.groupRoom.maxWaiting;
room.m_name = resp.groupRoomName.c_str();
room.m_translatedName = UnicodeString(L"TEST");
room.m_numGames = resp.groupRoom.numGames;
room.m_numPlaying = resp.groupRoom.numPlaying;
room.m_numWaiting = resp.groupRoom.numWaiting;
TheGameSpyInfo->addGroupRoom( room );
if (room.m_groupID == 0)
{
enableControls( TRUE );
}
}
break;
case PeerResponse::PEERRESPONSE_JOINGROUPROOM:
{
sawImportantMessage = TRUE;
enableControls( TRUE );
if (resp.joinGroupRoom.ok)
{
//buttonPushed = TRUE;
TheGameSpyInfo->setCurrentGroupRoom(resp.joinGroupRoom.id);
//GSMessageBoxOk( TheGameText->fetch("GUI:GSErrorTitle"), TheGameText->fetch("GUI:GSGroupRoomJoinOK") );
buttonPushed = TRUE;
nextScreen = "Menus/WOLCustomLobby.wnd";
TheShell->pop();
//TheShell->push( "Menus/WOLCustomLobby.wnd" );
}
else
{
GSMessageBoxOk( TheGameText->fetch("GUI:GSErrorTitle"), TheGameText->fetch("GUI:GSGroupRoomJoinFail") );
}
}
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 );
TheShell->pop();
}
break;
}
}
}
}// WOLWelcomeMenuUpdate
//-------------------------------------------------------------------------------------------------
/** WOL Welcome Menu input callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType WOLWelcomeMenuInput( 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;
}// WOLWelcomeMenuInput
//-------------------------------------------------------------------------------------------------
/** WOL Welcome Menu window system callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType WOLWelcomeMenuSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
UnicodeString txtInput;
switch( msg )
{
case GWM_CREATE:
{
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 GBM_SELECTED:
{
if (buttonPushed)
break;
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
if ( controlID == buttonBackID )
{
//DEBUG_ASSERTCRASH(TheGameSpyChat->getPeer(), ("No GameSpy Peer object!"));
//TheGameSpyChat->disconnectFromChat();
PeerRequest req;
req.peerRequestType = PeerRequest::PEERREQUEST_LOGOUT;
TheGameSpyPeerMessageQueue->addRequest( req );
BuddyRequest breq;
breq.buddyRequestType = BuddyRequest::BUDDYREQUEST_LOGOUT;
TheGameSpyBuddyMessageQueue->addRequest( breq );
DEBUG_LOG(("Tearing down GameSpy from WOLWelcomeMenuSystem(GBM_SELECTED)\n"));
TearDownGameSpy();
/*
if (TheGameSpyChat->getPeer())
{
peerDisconnect(TheGameSpyChat->getPeer());
}
*/
buttonPushed = TRUE;
TheShell->pop();
/// @todo: log out instead of disconnecting
//TheWOL->addCommand( WOL::WOLCOMMAND_LOGOUT );
/**
closeAllOverlays();
TheShell->pop();
delete TheWOL;
TheWOL = NULL;
delete TheWOLGame;
TheWOLGame = NULL;
**/
} //if ( controlID == buttonBack )
else if (controlID == buttonOptionsID)
{
GameSpyOpenOverlay( GSOVERLAY_OPTIONS );
}
else if (controlID == buttonQuickMatchID)
{
GameSpyMiscPreferences mPref;
if ((TheDisplay->getWidth() != 800 || TheDisplay->getHeight() != 600) && mPref.getQuickMatchResLocked())
{
GSMessageBoxOk(TheGameText->fetch("GUI:GSErrorTitle"), TheGameText->fetch("GUI:QuickMatch800x600"));
}
else
{
buttonPushed = TRUE;
nextScreen = "Menus/WOLQuickMatchMenu.wnd";
TheShell->pop();
}
}// else if
else if (controlID == buttonMyInfoID )
{
SetLookAtPlayer(TheGameSpyInfo->getLocalProfileID(), TheGameSpyInfo->getLocalName());
GameSpyToggleOverlay(GSOVERLAY_PLAYERINFO);
}
else if (controlID == buttonLobbyID)
{
//TheGameSpyChat->clearGroupRoomList();
//peerListGroupRooms(TheGameSpyChat->getPeer(), ListGroupRoomsCallback, NULL, PEERTrue);
TheGameSpyInfo->joinBestGroupRoom();
enableControls( FALSE );
/*
TheWOL->setScreen(WOL::WOLAPI_MENU_CUSTOMLOBBY);
TheWOL->setGameMode(WOL::WOLTYPE_CUSTOM);
TheWOL->setState( WOL::WOLAPI_LOBBY );
TheWOL->addCommand( WOL::WOLCOMMAND_REFRESH_CHANNELS );
*/
}// else if
else if (controlID == buttonBuddiesID)
{
GameSpyToggleOverlay( GSOVERLAY_BUDDY );
/*
Bool joinedRoom = FALSE;
ClearGroupRoomList();
peerJoinTitleRoom(TheGameSpyChat->getPeer(), JoinRoomCallback, &joinedRoom, PEERTrue);
if (joinedRoom)
{
GameSpyUsingGroupRooms = FALSE;
GameSpyCurrentGroupRoomID = 0;
TheShell->pop();
TheShell->push("Menus/WOLCustomLobby.wnd");
}
else
{
GameSpyCurrentGroupRoomID = 0;
GSMessageBoxOk(UnicodeString(L"Oops"), UnicodeString(L"Unable to join title room"), NULL);
}
*/
}
else if (controlID == buttonLadderID)
{
TheShell->push(AsciiString("Menus/WOLLadderScreen.wnd"));
}
break;
}// case GBM_SELECTED:
case GEM_EDIT_DONE:
{
break;
}
default:
return MSG_IGNORED;
}//Switch
return MSG_HANDLED;
}// WOLWelcomeMenuSystem

View File

@@ -0,0 +1,265 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: MessageBox.cpp /////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Westwood Studios Pacific.
//
// Confidential Information
// Copyright (C) 2001 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// Project: RTS3
//
// File name: MessageBox.cpp
//
// Created: Chris Huybregts, June 2001
//
// Desc: the Message Box control
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
// USER INCLUDES //////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/GameEngine.h"
#include "Common/NameKeyGenerator.h"
#include "GameClient/WindowLayout.h"
#include "GameClient/Gadget.h"
#include "GameClient/Shell.h"
#include "GameClient/KeyDefs.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/MessageBox.h"
GameWindow *MessageBoxYesNo(UnicodeString titleString,UnicodeString bodyString,GameWinMsgBoxFunc yesCallback,GameWinMsgBoxFunc noCallback) ///< convenience function for displaying a Message box with Yes and No buttons
{
return TheWindowManager->gogoMessageBox(-1,-1,-1,-1,MSG_BOX_NO | MSG_BOX_YES , titleString, bodyString, yesCallback, noCallback, NULL, NULL);
}
GameWindow *QuitMessageBoxYesNo(UnicodeString titleString,UnicodeString bodyString,GameWinMsgBoxFunc yesCallback,GameWinMsgBoxFunc noCallback) ///< convenience function for displaying a Message box with Yes and No buttons
{
return TheWindowManager->gogoMessageBox(-1,-1,-1,-1,MSG_BOX_NO | MSG_BOX_YES , titleString, bodyString, yesCallback, noCallback, NULL, NULL, TRUE);
}
GameWindow *MessageBoxYesNoCancel(UnicodeString titleString,UnicodeString bodyString, GameWinMsgBoxFunc yesCallback, GameWinMsgBoxFunc noCallback, GameWinMsgBoxFunc cancelCallback)///< convenience function for displaying a Message box with Yes,No and Cancel buttons
{
return TheWindowManager->gogoMessageBox(-1,-1,-1,-1,MSG_BOX_NO | MSG_BOX_YES | MSG_BOX_CANCEL , titleString, bodyString, yesCallback, noCallback, NULL, cancelCallback);
}
GameWindow *MessageBoxOkCancel(UnicodeString titleString,UnicodeString bodyString,GameWinMsgBoxFunc okCallback,GameWinMsgBoxFunc cancelCallback)///< convenience function for displaying a Message box with Ok and Cancel buttons
{
return TheWindowManager->gogoMessageBox(-1,-1,-1,-1,MSG_BOX_OK | MSG_BOX_CANCEL , titleString, bodyString, NULL, NULL, okCallback, cancelCallback);
}
GameWindow *MessageBoxOk(UnicodeString titleString,UnicodeString bodyString,GameWinMsgBoxFunc okCallback)///< convenience function for displaying a Message box with Ok button
{
return TheWindowManager->gogoMessageBox(-1,-1,-1,-1,MSG_BOX_OK, titleString, bodyString, NULL, NULL, okCallback, NULL);
}
GameWindow *MessageBoxCancel(UnicodeString titleString,UnicodeString bodyString,GameWinMsgBoxFunc cancelCallback)///< convenience function for displaying a Message box with Cancel button
{
return TheWindowManager->gogoMessageBox(-1,-1,-1,-1, MSG_BOX_CANCEL, titleString, bodyString, NULL, NULL, NULL, cancelCallback);
}
// PRIVATE DATA ///////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------------------------
/** Message Box window system callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType MessageBoxSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
switch( msg )
{
//---------------------------------------------------------------------------------------------
case GWM_DESTROY:
{
delete (WindowMessageBoxData *)window->winGetUserData();
window->winSetUserData( NULL );
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;
break;
} // end input
//---------------------------------------------------------------------------------------------
case GBM_SELECTED:
{
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
static NameKeyType buttonOkID = TheNameKeyGenerator->nameToKey( AsciiString( "MessageBox.wnd:ButtonOk" ) );
static NameKeyType buttonYesID = TheNameKeyGenerator->nameToKey( AsciiString( "MessageBox.wnd:ButtonYes" ) );
static NameKeyType buttonNoID = TheNameKeyGenerator->nameToKey( AsciiString( "MessageBox.wnd:ButtonNo" ) );
static NameKeyType buttonCancelID = TheNameKeyGenerator->nameToKey( AsciiString( "MessageBox.wnd:ButtonCancel" ) );
WindowMessageBoxData *MsgBoxCallbacks = (WindowMessageBoxData *)window->winGetUserData();
if( controlID == buttonOkID )
{
//simple enough,if we have a callback, call it, if not, then just destroy the window
if (MsgBoxCallbacks->okCallback)
MsgBoxCallbacks->okCallback();
TheWindowManager->winDestroy(window);
} // end if
else if( controlID == buttonYesID )
{
if (MsgBoxCallbacks->yesCallback)
MsgBoxCallbacks->yesCallback();
TheWindowManager->winDestroy(window);
} // end else if
else if( controlID == buttonNoID )
{
if (MsgBoxCallbacks->noCallback)
MsgBoxCallbacks->noCallback();
TheWindowManager->winDestroy(window);
} // end else if
else if( controlID == buttonCancelID )
{
if (MsgBoxCallbacks->cancelCallback)
MsgBoxCallbacks->cancelCallback();
TheWindowManager->winDestroy(window);
} // end else if
break;
} // end selected
//---------------------------------------------------------------------------------------------
default:
return MSG_IGNORED;
} // end switch
return MSG_HANDLED;
} // end MessageBoxSystem
//-------------------------------------------------------------------------------------------------
/** Message Box window system callback */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType QuitMessageBoxSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
switch( msg )
{
//---------------------------------------------------------------------------------------------
case GWM_DESTROY:
{
delete (WindowMessageBoxData *)window->winGetUserData();
window->winSetUserData( NULL );
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;
break;
} // end input
//---------------------------------------------------------------------------------------------
case GBM_SELECTED:
{
GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();
static NameKeyType buttonOkID = TheNameKeyGenerator->nameToKey( AsciiString( "QuitMessageBox.wnd:ButtonOk" ) );
static NameKeyType buttonYesID = TheNameKeyGenerator->nameToKey( AsciiString( "QuitMessageBox.wnd:ButtonYes" ) );
static NameKeyType buttonNoID = TheNameKeyGenerator->nameToKey( AsciiString( "QuitMessageBox.wnd:ButtonNo" ) );
static NameKeyType buttonCancelID = TheNameKeyGenerator->nameToKey( AsciiString( "QuitMessageBox.wnd:ButtonCancel" ) );
WindowMessageBoxData *MsgBoxCallbacks = (WindowMessageBoxData *)window->winGetUserData();
if( controlID == buttonOkID )
{
//simple enough,if we have a callback, call it, if not, then just destroy the window
if (MsgBoxCallbacks->okCallback)
MsgBoxCallbacks->okCallback();
TheWindowManager->winDestroy(window);
} // end if
else if( controlID == buttonYesID )
{
if (MsgBoxCallbacks->yesCallback)
MsgBoxCallbacks->yesCallback();
TheWindowManager->winDestroy(window);
} // end else if
else if( controlID == buttonNoID )
{
if (MsgBoxCallbacks->noCallback)
MsgBoxCallbacks->noCallback();
TheWindowManager->winDestroy(window);
} // end else if
else if( controlID == buttonCancelID )
{
if (MsgBoxCallbacks->cancelCallback)
MsgBoxCallbacks->cancelCallback();
TheWindowManager->winDestroy(window);
} // end else if
break;
} // end selected
//---------------------------------------------------------------------------------------------
default:
return MSG_IGNORED;
} // end switch
return MSG_HANDLED;
} // end MessageBoxSystem

View File

@@ -0,0 +1,74 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: ReplayControls.cpp ///////////////////////////////////////////////////////////////////////
// Author: Bryan Cleveland - December 2001
// Desc: GUI Control box for the playback controls
///////////////////////////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "GameClient/GameWindow.h"
#include "GameClient/Gadget.h"
#include "GameClient/GameClient.h"
//-------------------------------------------------------------------------------------------------
/** Input procedure for the control bar */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType ReplayControlInput( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
return MSG_IGNORED;
} // end MapSelectMenuInput
//-------------------------------------------------------------------------------------------------
/** System callback for the control bar parent */
//-------------------------------------------------------------------------------------------------
WindowMsgHandledType ReplayControlSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
switch( msg )
{
//---------------------------------------------------------------------------------------------
case GBM_SELECTED:
{
break;
} // end button selected
//---------------------------------------------------------------------------------------------
default:
return MSG_IGNORED;
} // end switch( msg )
return MSG_HANDLED;
} // end ControlBarSystem

View File

@@ -0,0 +1,353 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: CheckBox.cpp /////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Westwood Studios Pacific.
//
// Confidential Information
// Copyright (C) 2001 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// Project: RTS3
//
// File name: CheckBox.cpp
//
// Created: Colin Day, June 2001
//
// Desc: Checkbox GUI control
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
// USER INCLUDES //////////////////////////////////////////////////////////////
#include "Common/Language.h"
#include "GameClient/Gadget.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/Keyboard.h"
// DEFINES ////////////////////////////////////////////////////////////////////
// PRIVATE TYPES //////////////////////////////////////////////////////////////
// PRIVATE DATA ///////////////////////////////////////////////////////////////
// PUBLIC DATA ////////////////////////////////////////////////////////////////
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// GadgetCheckBoxInput ========================================================
/** Handle input for check box */
//=============================================================================
WindowMsgHandledType GadgetCheckBoxInput( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
WinInstanceData *instData = window->winGetInstanceData();
switch( msg )
{
// ------------------------------------------------------------------------
case GWM_MOUSE_ENTERING:
{
if( BitTest( instData->getStyle(), GWS_MOUSE_TRACK ) )
{
BitSet( instData->m_state, WIN_STATE_HILITED );
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GBM_MOUSE_ENTERING,
(WindowMsgData)window,
mData1 );
//TheWindowManager->winSetFocus( window );
} // end if
break;
} // end mouse entering
// ------------------------------------------------------------------------
case GWM_MOUSE_LEAVING:
{
if( BitTest( instData->getStyle(), GWS_MOUSE_TRACK ) )
{
BitClear( instData->m_state, WIN_STATE_HILITED );
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GBM_MOUSE_LEAVING,
(WindowMsgData)window,
mData1 );
} // end if
break;
} // end mouse leaving
// ------------------------------------------------------------------------
case GWM_LEFT_DRAG:
{
TheWindowManager->winSendSystemMsg( window->winGetOwner(), GGM_LEFT_DRAG,
(WindowMsgData)window, mData1 );
break;
} // end left drag
// ------------------------------------------------------------------------
case GWM_LEFT_DOWN:
{
break;
} // end left down
// ------------------------------------------------------------------------
case GWM_LEFT_UP:
{
if( BitTest( instData->getState(), WIN_STATE_HILITED ) == FALSE )
{
// this up click was not meant for this button
return MSG_IGNORED;
}
// Toggle the check state
instData->m_state ^= WIN_STATE_SELECTED;
TheWindowManager->winSendSystemMsg( window->winGetOwner(), GBM_SELECTED,
(WindowMsgData)window, mData1 );
break;
} // end left up and left click
// ------------------------------------------------------------------------
case GWM_RIGHT_DOWN:
{
break;
} // end right down
//-------------------------------------------------------------------------
case GWM_RIGHT_UP:
{
// Need to be specially marked to care about right mouse events
if( BitTest( instData->getState(), WIN_STATE_SELECTED ) )
{
TheWindowManager->winSendSystemMsg( instData->getOwner(), GBM_SELECTED_RIGHT,
(WindowMsgData)window, mData1 );
BitClear( instData->m_state, WIN_STATE_SELECTED );
}
else
{
// this up click was not meant for this button
return MSG_IGNORED;
}
break;
} // end right up or right click
// ------------------------------------------------------------------------
case GWM_CHAR:
{
switch( mData1 )
{
// --------------------------------------------------------------------
case KEY_ENTER:
case KEY_SPACE:
{
if( BitTest( mData2, KEY_STATE_DOWN ) )
{
// Toggle the check state
instData->m_state ^= WIN_STATE_SELECTED;
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GBM_SELECTED,
(WindowMsgData)window,
0 );
} //end if
break;
} // end enter/space
// --------------------------------------------------------------------
case KEY_DOWN:
case KEY_RIGHT:
case KEY_TAB:
{
if( BitTest( mData2, KEY_STATE_DOWN ) )
TheWindowManager->winNextTab(window);
break;
} // end down, right, tab
// --------------------------------------------------------------------
case KEY_UP:
case KEY_LEFT:
{
if( BitTest( mData2, KEY_STATE_DOWN ) )
TheWindowManager->winPrevTab(window);
break;
} // end up, left
// --------------------------------------------------------------------
default:
{
return MSG_IGNORED;
} // end default
} // end switch
break;
} // end char msg
// ------------------------------------------------------------------------
default:
{
return MSG_IGNORED;
} // end default
} // end switch( msg )
return MSG_HANDLED;
} // end GadgetCheckBoxInput
// GadgetCheckBoxSystem =======================================================
/** Handle system messages for check box */
//=============================================================================
WindowMsgHandledType GadgetCheckBoxSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
WinInstanceData *instData = window->winGetInstanceData();
switch( msg )
{
// ------------------------------------------------------------------------
case GGM_SET_LABEL:
{
window->winSetText( *(UnicodeString*)mData1 );
break;
}
// ------------------------------------------------------------------------
case GWM_CREATE:
break;
// ------------------------------------------------------------------------
case GWM_DESTROY:
break;
// ------------------------------------------------------------------------
case GWM_INPUT_FOCUS:
if( mData1 == FALSE )
BitClear( instData->m_state, WIN_STATE_HILITED );
else
BitSet( instData->m_state, WIN_STATE_HILITED );
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GGM_FOCUS_CHANGE,
mData1,
window->winGetWindowId() );
if( mData1 == FALSE )
*(Bool*)mData2 = FALSE;
else
*(Bool*)mData2 = TRUE;
break;
default:
return MSG_IGNORED;
} // end switch msg
return MSG_HANDLED;
} // end GadgetCheckBoxSystem
// GadgetCheckBoxSetText ======================================================
/** Set the text for the control */
//=============================================================================
void GadgetCheckBoxSetText( GameWindow *g, UnicodeString text )
{
// sanity
if( g == NULL )
return;
TheWindowManager->winSendSystemMsg( g, GGM_SET_LABEL, (WindowMsgData)&text, 0 );
} // end GadgetCheckBoxSetText
// GadgetCheckBoxSetChecked ============================================
//=============================================================================
/** Set the check state for the check box */
//=============================================================================
void GadgetCheckBoxSetChecked( GameWindow *g, Bool isChecked)
{
WinInstanceData *instData = g->winGetInstanceData();
if (isChecked)
{
BitSet(instData->m_state, WIN_STATE_SELECTED);
}
else
{
BitClear(instData->m_state, WIN_STATE_SELECTED);
}
TheWindowManager->winSendSystemMsg( g->winGetOwner(), GBM_SELECTED,
(WindowMsgData)g, 0 );
}
// GadgetCheckBoxIsChecked ======================================================
/** Check the check state */
//=============================================================================
Bool GadgetCheckBoxIsChecked( GameWindow *g )
{
WinInstanceData *instData = g->winGetInstanceData();
return (BitTest(instData->m_state, WIN_STATE_SELECTED));
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,483 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: HorizontalSlider.cpp /////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Westwood Studios Pacific.
//
// Confidential Information
// Copyright (C) 2001 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// Project: RTS3
//
// File name: HorizontalSlider.cpp
//
// Created: Colin Day, June 2001
//
// Desc: Horizontal GUI slider
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
// USER INCLUDES //////////////////////////////////////////////////////////////
#include "Common/Language.h"
#include "Gameclient/GameWindowManager.h"
#include "GameClient/Gadget.h"
#include "GameClient/GadgetSlider.h"
// DEFINES ////////////////////////////////////////////////////////////////////
// PRIVATE TYPES //////////////////////////////////////////////////////////////
// PRIVATE DATA ///////////////////////////////////////////////////////////////
// PUBLIC DATA ////////////////////////////////////////////////////////////////
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
// GadgetHorizontalSliderInput ================================================
/** Handle input for horizontal slider */
//=============================================================================
WindowMsgHandledType GadgetHorizontalSliderInput( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
SliderData *s = (SliderData *)window->winGetUserData();
WinInstanceData *instData = window->winGetInstanceData();
ICoord2D size, childSize, childCenter;
window->winGetSize( &size.x, &size.y );
switch( msg )
{
// ------------------------------------------------------------------------
case GWM_MOUSE_ENTERING:
{
if( BitTest( instData->getStyle(), GWS_MOUSE_TRACK ) )
{
BitSet( instData->m_state, WIN_STATE_HILITED );
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GBM_MOUSE_ENTERING,
(WindowMsgData)window,
0 );
//TheWindowManager->winSetFocus( window );
} // end if
if(window->winGetChild() && BitTest(window->winGetChild()->winGetStyle(),GWS_PUSH_BUTTON) )
{
WinInstanceData *instDataChild = window->winGetChild()->winGetInstanceData();
BitSet(instDataChild->m_state, WIN_STATE_HILITED);
}
break;
} // end mouse entering
// ------------------------------------------------------------------------
case GWM_MOUSE_LEAVING:
{
if( BitTest( instData->getStyle(), GWS_MOUSE_TRACK ))
{
BitClear( instData->m_state, WIN_STATE_HILITED );
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GBM_MOUSE_LEAVING,
(WindowMsgData)window,
0 );
} // end if
if(window->winGetChild() && BitTest(window->winGetChild()->winGetStyle(),GWS_PUSH_BUTTON) )
{
WinInstanceData *instDataChild = window->winGetChild()->winGetInstanceData();
BitClear(instDataChild->m_state, WIN_STATE_HILITED);
}
break;
} // end mouse leaving
// ------------------------------------------------------------------------
case GWM_LEFT_DRAG:
if( BitTest( instData->getStyle(), GWS_MOUSE_TRACK ) )
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GGM_LEFT_DRAG,
(WindowMsgData)window,
mData1 );
break;
// ------------------------------------------------------------------------
case GWM_LEFT_DOWN:
break;
// ------------------------------------------------------------------------
case GWM_LEFT_UP:
{
Int x, y;
Int mousex = mData1 & 0xFFFF;
// Int mousey = mData1 >> 16;
GameWindow *child = window->winGetChild();
Int pageClickSize, clickPos;
window->winGetScreenPosition( &x, &y );
child->winGetSize( &childSize.x, &childSize.y );
child->winGetPosition( &childCenter.x, &childCenter.y );
childCenter.x += childSize.x / 2;
childCenter.y += childSize.y / 2;
//
// when you click on the slider, but not the button, we will jump
// the slider position up/down by this much
//
pageClickSize = size.x / 5;
clickPos = mousex - x;
if( clickPos >= childCenter.x )
{
clickPos = childCenter.x + pageClickSize;
if( clickPos > mousex - x )
clickPos = mousex - x;
} // end if
else
{
clickPos = childCenter.x - pageClickSize;
if( clickPos < mousex - x )
clickPos = mousex - x;
} // end else
// keep it all valid to the window
if( clickPos > x + size.x - childSize.x / 2 )
clickPos = x + size.y - childSize.x / 2;
if( clickPos < childSize.x / 2 )
clickPos = childSize.x / 2;
child->winSetPosition( clickPos - childSize.x / 2, HORIZONTAL_SLIDER_THUMB_POSITION);
TheWindowManager->winSendSystemMsg( window, GGM_LEFT_DRAG, 0, mData1 );
break;
} // end left up, left click
// ------------------------------------------------------------------------
case GWM_CHAR:
{
switch( mData1 )
{
// --------------------------------------------------------------------
case KEY_RIGHT:
if( BitTest( mData2, KEY_STATE_DOWN ) )
{
if( s->position > s->minVal + 1 )
{
GameWindow *child = window->winGetChild();
s->position -= 2;
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GSM_SLIDER_TRACK,
(WindowMsgData)window,
s->position );
// Translate to window coords
child->winSetPosition( (Int)((s->position - s->minVal) * s->numTicks), HORIZONTAL_SLIDER_THUMB_POSITION );
} // end if
} // if key down
break;
// --------------------------------------------------------------------
case KEY_LEFT:
if( BitTest( mData2, KEY_STATE_DOWN ) )
{
if( s->position < s->maxVal - 1 )
{
GameWindow *child = window->winGetChild();
s->position += 2;
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GSM_SLIDER_TRACK,
(WindowMsgData)window,
s->position );
// Translate to window coords
child->winSetPosition( (Int)((s->position - s->minVal) * s->numTicks),HORIZONTAL_SLIDER_THUMB_POSITION );
}
} // end if key down
break;
// --------------------------------------------------------------------
case KEY_DOWN:
case KEY_TAB:
if( BitTest( mData2, KEY_STATE_DOWN ) )
window->winNextTab();
break;
// --------------------------------------------------------------------
case KEY_UP:
if( BitTest( mData2, KEY_STATE_DOWN ) )
window->winPrevTab();
break;
// --------------------------------------------------------------------
default:
return MSG_IGNORED;
} // end switch( mData1 )
break;
} // end char
// ------------------------------------------------------------------------
default:
return MSG_IGNORED;
}
return MSG_HANDLED;
} // end GadgetHorizontalSliderInput
// GadgetHorizontalSliderSystem ===============================================
/** Handle system messages for horizontal slider */
//=============================================================================
WindowMsgHandledType GadgetHorizontalSliderSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
SliderData *s = (SliderData *)window->winGetUserData();
WinInstanceData *instData = window->winGetInstanceData();
ICoord2D size, childSize, childCenter,childRelativePos;
window->winGetSize( &size.x, &size.y );
switch( msg )
{
// ------------------------------------------------------------------------
case GGM_LEFT_DRAG:
{
Int mousex = mData2 & 0xFFFF;
// Int mousey = mData2 >> 16;
Int x, y, delta;
GameWindow *child = window->winGetChild();
window->winGetScreenPosition( &x, &y );
child->winGetSize( &childSize.x, &childSize.y );
child->winGetScreenPosition( &childCenter.x, &childCenter.y );
child->winGetPosition(&childRelativePos.x, &childRelativePos.y);
childCenter.x += childSize.x / 2;
childCenter.y += childSize.y / 2;
//
// ignore drag attempts when the mouse is right or left of slider totally
// and put the dragging thumb back at the slider pos
//
if( mousex > x + size.x -HORIZONTAL_SLIDER_THUMB_WIDTH/2 )
{
TheWindowManager->winSendSystemMsg( window, GSM_SET_SLIDER,
s->maxVal, 0 );
// tell owner i moved
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GSM_SLIDER_TRACK,
(WindowMsgData)window,
s->position );
break;
} // end if
else if( mousex < x + HORIZONTAL_SLIDER_THUMB_WIDTH/2)
{
TheWindowManager->winSendSystemMsg( window, GSM_SET_SLIDER,
s->minVal, 0 );
// tell owner i moved
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GSM_SLIDER_TRACK,
(WindowMsgData)window,
s->position );
break;
} // end else if
if( childCenter.x < x + childSize.x / 2 )
{
child->winSetPosition( 0,HORIZONTAL_SLIDER_THUMB_POSITION );
s->position = s->minVal;
}
else if( childCenter.x >= x + size.x - childSize.x / 2 )
{
child->winSetPosition( (Int)((s->maxVal - s->minVal) * s->numTicks) -HORIZONTAL_SLIDER_THUMB_WIDTH/2 , HORIZONTAL_SLIDER_THUMB_POSITION );
s->position = s->maxVal;
}
else
{
delta = childCenter.x - x -HORIZONTAL_SLIDER_THUMB_WIDTH/2;
// Calc slider position
s->position = (Int)((delta) / s->numTicks)+ s->minVal ;
/*
s->position += s->minVal;
*/
if( s->position > s->maxVal )
s->position = s->maxVal;
if( s->position < s->minVal)
s->position = s->minVal;
child->winSetPosition( childRelativePos.x, HORIZONTAL_SLIDER_THUMB_POSITION );
}
// tell owner i moved
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GSM_SLIDER_TRACK,
(WindowMsgData)window,
s->position );
break;
} // end left drag
// ------------------------------------------------------------------------
case GSM_SET_SLIDER:
{
Int newPos = (Int)mData1;
GameWindow *child = window->winGetChild();
if( newPos < s->minVal || newPos > s->maxVal )
break;
s->position = newPos;
// Translate to window coords
newPos = (Int)((newPos - s->minVal) * s->numTicks);
child->winSetPosition( newPos , HORIZONTAL_SLIDER_THUMB_POSITION );
break;
} // end set slider
// ------------------------------------------------------------------------
case GSM_SET_MIN_MAX:
{
ICoord2D size;
GameWindow *child = window->winGetChild();
window->winGetSize( &size.x, &size.y );
s->minVal = (Int)mData1;
s->maxVal = (Int)mData2;
s->numTicks = (Real)(size.x - HORIZONTAL_SLIDER_THUMB_WIDTH)/(Real)(s->maxVal - s->minVal);
s->position = s->minVal;
child->winSetPosition( 0, HORIZONTAL_SLIDER_THUMB_POSITION );
break;
} // end set min max
// ------------------------------------------------------------------------
case GWM_CREATE:
break;
// ------------------------------------------------------------------------
case GWM_DESTROY:
delete ( (SliderData *)window->winGetUserData() );
break;
// ------------------------------------------------------------------------
case GWM_INPUT_FOCUS:
{
// If we're losing focus
if( mData1 == FALSE )
BitClear( instData->m_state, WIN_STATE_HILITED );
else
BitSet( instData->m_state, WIN_STATE_HILITED );
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GGM_FOCUS_CHANGE,
mData1,
window->winGetWindowId() );
*(Bool*)mData2 = TRUE;
break;
} // end focus msg
// ------------------------------------------------------------------------
case GGM_RESIZED:
{
// Int width = (Int)mData1;
Int height = (Int)mData2;
GameWindow *thumb = window->winGetChild();
if( thumb )
thumb->winSetSize( GADGET_SIZE, height );
break;
} // end resized
default:
return MSG_IGNORED;
} // end switch( msg )
return MSG_HANDLED;
} // end GadgetHorizontalSliderSystem

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,112 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: ProgressBar.cpp //////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Westwood Studios Pacific.
//
// Confidential Information
// Copyright (C) 2001 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// Project: RTS3
//
// File name: ProgressBar.cpp
//
// Created: Colin Day, June 2001
//
// Desc: Progress bar GUI control
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
// USER INCLUDES //////////////////////////////////////////////////////////////
#include "Common/Language.h"
#include "GameClient/GameWindow.h"
#include "GameClient/Gadget.h"
#include "GameClient/GameWindowManager.h"
// DEFINES ////////////////////////////////////////////////////////////////////
// PRIVATE TYPES //////////////////////////////////////////////////////////////
// PRIVATE DATA ///////////////////////////////////////////////////////////////
// PUBLIC DATA ////////////////////////////////////////////////////////////////
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
// GadgetProgressBarSystem ====================================================
/** Handle system messages for Progress Bar */
//=============================================================================
WindowMsgHandledType GadgetProgressBarSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
switch( msg )
{
// ------------------------------------------------------------------------
case GPM_SET_PROGRESS:
{
Int newPos = (Int)mData1;
if (newPos < 0 || newPos > 100)
break;
window->winSetUserData( (void *)newPos );
break;
} // end set progress
// ------------------------------------------------------------------------
default:
return MSG_IGNORED;
} // end switch
return MSG_HANDLED;
} // end GadgetProgressBarSystem
// GadgetProgressBarSetProgress ===============================================
/** send progress system message to Progress Bar */
//=============================================================================
void GadgetProgressBarSetProgress( GameWindow *g, Int progress )
{
if(!g)
return;
TheWindowManager->winSendSystemMsg( g, GPM_SET_PROGRESS, progress, 0);
} // end GadgetProgressBarSetProgress

View File

@@ -0,0 +1,711 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: GadgetPushButton.cpp /////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Westwood Studios Pacific.
//
// Confidential Information
// Copyright (C) 2001 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// Project: RTS3
//
// File name: PushButton.cpp
//
// Created: Colin Day, June 2001
//
// Desc: Pushbutton GUI gadget control callbacks
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
// USER INCLUDES //////////////////////////////////////////////////////////////
#include "Common/AudioEventRTS.h"
#include "Common/Language.h"
#include "Common/GameAudio.h"
#include "GameClient/Gadget.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/InGameUI.h"
// DEFINES ////////////////////////////////////////////////////////////////////
// PRIVATE TYPES //////////////////////////////////////////////////////////////
// PRIVATE DATA ///////////////////////////////////////////////////////////////
// PUBLIC DATA ////////////////////////////////////////////////////////////////
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
// GadgetPushButtonInput ======================================================
/** Handle input for push button */
//=============================================================================
WindowMsgHandledType GadgetPushButtonInput( GameWindow *window,
UnsignedInt msg,
WindowMsgData mData1,
WindowMsgData mData2 )
{
WinInstanceData *instData = window->winGetInstanceData();
switch( msg )
{
// ------------------------------------------------------------------------
case GWM_MOUSE_ENTERING:
{
if( BitTest( instData->getStyle(), GWS_MOUSE_TRACK ) )
{
BitSet( instData->m_state, WIN_STATE_HILITED );
TheWindowManager->winSendSystemMsg( instData->getOwner(),
GBM_MOUSE_ENTERING,
(WindowMsgData)window,
mData1 );
//TheWindowManager->winSetFocus( window );
}
if(window->winGetParent() && BitTest(window->winGetParent()->winGetStyle(),GWS_HORZ_SLIDER) )
{
WinInstanceData *instDataParent = window->winGetParent()->winGetInstanceData();
BitSet(instDataParent->m_state, WIN_STATE_HILITED);
}
break;
} // end mouse entering
// ------------------------------------------------------------------------
case GWM_MOUSE_LEAVING:
{
if(BitTest( instData->getStyle(), GWS_MOUSE_TRACK ) )
{
BitClear( instData->m_state, WIN_STATE_HILITED );
TheWindowManager->winSendSystemMsg( instData->getOwner(),
GBM_MOUSE_LEAVING,
(WindowMsgData)window,
mData1 );
}
//
// if this is not a check-like button, clear any selected state when the
// move leaves the window area
//
if( BitTest( window->winGetStatus(), WIN_STATUS_CHECK_LIKE ) == FALSE )
if( BitTest( instData->getState(), WIN_STATE_SELECTED ) )
BitClear( instData->m_state, WIN_STATE_SELECTED );
//TheWindowManager->winSetFocus( NULL );
if(window->winGetParent() && BitTest(window->winGetParent()->winGetStyle(),GWS_HORZ_SLIDER) )
{
WinInstanceData *instDataParent = window->winGetParent()->winGetInstanceData();
BitClear(instDataParent->m_state, WIN_STATE_HILITED);
}
break;
} // end mouse leaving
// ------------------------------------------------------------------------
case GWM_LEFT_DRAG:
{
TheWindowManager->winSendSystemMsg( instData->getOwner(), GGM_LEFT_DRAG,
(WindowMsgData)window, mData1 );
break;
} // end left drag
// ------------------------------------------------------------------------
case GWM_LEFT_DOWN:
{
PushButtonData *pData = (PushButtonData *)window->winGetUserData();
AudioEventRTS buttonClick;
if(pData && pData->altSound.isNotEmpty())
buttonClick.setEventName(pData->altSound);
else
buttonClick.setEventName("GUIClick");
if( TheAudio )
{
TheAudio->addAudioEvent( &buttonClick );
} // end if
//
// for 'check-like' buttons we have "dual state", we flip the selected status
// in that case instead of just turning it on like normal ... also note
// that selected messages are sent immediately
//
if( BitTest( window->winGetStatus(), WIN_STATUS_CHECK_LIKE ) )
{
if( BitTest( instData->m_state, WIN_STATE_SELECTED ) )
BitClear( instData->m_state, WIN_STATE_SELECTED );
else
BitSet( instData->m_state, WIN_STATE_SELECTED );
TheWindowManager->winSendSystemMsg( instData->getOwner(), GBM_SELECTED,
(WindowMsgData)window, mData1 );
} // end if
else
{
// just select as normal
BitSet( instData->m_state, WIN_STATE_SELECTED );
} // end else
break;
} // end left down
//-------------------------------------------------------------------------
case GWM_LEFT_UP:
{
//
// note check like selected messages aren't sent here ... they are sent
// on the down press
//
if( BitTest( instData->getState(), WIN_STATE_SELECTED ) &&
BitTest( window->winGetStatus(), WIN_STATUS_CHECK_LIKE ) == FALSE )
{
TheWindowManager->winSendSystemMsg( instData->getOwner(), GBM_SELECTED,
(WindowMsgData)window, mData1 );
BitClear( instData->m_state, WIN_STATE_SELECTED );
}
else
{
// this up click was not meant for this button
return MSG_IGNORED;
}
break;
} // end left up or left click
// ------------------------------------------------------------------------
case GWM_RIGHT_DOWN:
{
PushButtonData *pData = (PushButtonData *)window->winGetUserData();
AudioEventRTS buttonClick;
if(pData && pData->altSound.isNotEmpty())
buttonClick.setEventName(pData->altSound);
else
buttonClick.setEventName("GUIClick");
if( BitTest( instData->getStatus(), WIN_STATUS_RIGHT_CLICK ) )
{
// Need to be specially marked to care about right mouse events
if( TheAudio )
{
TheAudio->addAudioEvent( &buttonClick );
} // end if
//
// for 'check-like' buttons we have "dual state", we flip the selected status
// in that case instead of just turning it on like normal ... also note
// that selected messages are sent immediately
//
if( BitTest( window->winGetStatus(), WIN_STATUS_CHECK_LIKE ) )
{
if( BitTest( instData->m_state, WIN_STATE_SELECTED ) )
BitClear( instData->m_state, WIN_STATE_SELECTED );
else
BitSet( instData->m_state, WIN_STATE_SELECTED );
TheWindowManager->winSendSystemMsg( instData->getOwner(), GBM_SELECTED_RIGHT,
(WindowMsgData)window, mData1 );
} // end if
else
{
// just select as normal
BitSet( instData->m_state, WIN_STATE_SELECTED );
} // end else
}
else
{
// Else I don't care about right events
return MSG_IGNORED;
}
break;
} // end right down
//-------------------------------------------------------------------------
case GWM_RIGHT_UP:
{
if( BitTest( instData->getStatus(), WIN_STATUS_RIGHT_CLICK ) )
{
//
// note check like selected messages aren't sent here ... they are sent
// on the down press
//
if( BitTest( instData->getState(), WIN_STATE_SELECTED ) &&
BitTest( window->winGetStatus(), WIN_STATUS_CHECK_LIKE ) == FALSE )
{
TheWindowManager->winSendSystemMsg( instData->getOwner(), GBM_SELECTED_RIGHT,
(WindowMsgData)window, mData1 );
BitClear( instData->m_state, WIN_STATE_SELECTED );
}
else
{
// this up click was not meant for this button
return MSG_IGNORED;
}
}
else
{
// Else I don't care about right events
return MSG_IGNORED;
}
break;
} // end right up or right click
// ------------------------------------------------------------------------
case GWM_CHAR:
{
switch( mData1 )
{
// --------------------------------------------------------------------
case KEY_ENTER:
case KEY_SPACE:
{
if( BitTest( mData2, KEY_STATE_UP ) )
{
//
// note check like selected messages aren't sent here ... they are sent
// on the down press
//
if( BitTest( instData->getState(), WIN_STATE_SELECTED ) &&
BitTest( window->winGetStatus(), WIN_STATUS_CHECK_LIKE ) == FALSE )
{
TheWindowManager->winSendSystemMsg( instData->getOwner(), GBM_SELECTED,
(WindowMsgData)window, 0 );
BitClear( instData->m_state, WIN_STATE_SELECTED );
}
}
else
{
//
// for 'check-like' buttons we have "dual state", we flip the selected status
// in that case instead of just turning it on like normal ... also note
// that selected messages are sent immediately
//
if( BitTest( window->winGetStatus(), WIN_STATUS_CHECK_LIKE ) )
{
if( BitTest( instData->m_state, WIN_STATE_SELECTED ) )
BitClear( instData->m_state, WIN_STATE_SELECTED );
else
BitSet( instData->m_state, WIN_STATE_SELECTED );
TheWindowManager->winSendSystemMsg( instData->getOwner(), GBM_SELECTED,
(WindowMsgData)window, mData1 );
} // end if
else
{
// just select as normal
BitSet( instData->m_state, WIN_STATE_SELECTED );
} // end else
} // end else
break;
} // end handle enter and space button
// --------------------------------------------------------------------
case KEY_DOWN:
case KEY_RIGHT:
case KEY_TAB:
{
if( BitTest( mData2, KEY_STATE_DOWN ) )
TheWindowManager->winNextTab(window);
break;
} // end key down, right or tab
// --------------------------------------------------------------------
case KEY_UP:
case KEY_LEFT:
{
if( BitTest( mData2, KEY_STATE_DOWN ) )
TheWindowManager->winPrevTab(window);
break;
} // end key up or left
// --------------------------------------------------------------------
default:
return MSG_IGNORED;
} // end switch on char
break;
} // end character message
// ------------------------------------------------------------------------
default:
return MSG_IGNORED;
} // end switch( msg )
return MSG_HANDLED;
} // end GadgetPushButtonInput
// GadgetPushButtonSystem =====================================================
/** Handle system messages for push button */
//=============================================================================
WindowMsgHandledType GadgetPushButtonSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
WinInstanceData *instData = window->winGetInstanceData();
switch( msg )
{
// ------------------------------------------------------------------------
case GGM_SET_LABEL:
{
// set text into the win instance text data field
window->winSetText( *(UnicodeString*)mData1 );
break;
}
// ------------------------------------------------------------------------
case GWM_CREATE:
break;
// ------------------------------------------------------------------------
case GWM_DESTROY:
{
PushButtonData *pData = (PushButtonData *)window->winGetUserData();
if(pData)
delete pData;
window->winSetUserData(NULL);
}
break;
// ------------------------------------------------------------------------
case GWM_INPUT_FOCUS:
if( mData1 == FALSE )
BitClear( instData->m_state, WIN_STATE_HILITED );
else
BitSet( instData->m_state, WIN_STATE_HILITED );
TheWindowManager->winSendSystemMsg( instData->getOwner(),
GGM_FOCUS_CHANGE,
(WindowMsgData)mData1,
window->winGetWindowId() );
if( mData1 == FALSE )
*(Bool*)mData2 = FALSE;
else
*(Bool*)mData2 = TRUE;
break;
default:
return MSG_IGNORED;
} // end switch( msg )
return MSG_HANDLED;
} // end GadgetPushButtonSystem
// ------------------------------------------------------------------------------------------------
/** Set the visual status of a button to make it looked checked/unchecked ... DO NOT send
* any actual button selected messages, this is ONLY VISUAL */
// ------------------------------------------------------------------------------------------------
void GadgetCheckLikeButtonSetVisualCheck( GameWindow *g, Bool checked )
{
// sanity
if( g == NULL )
return;
// get instance data
WinInstanceData *instData = g->winGetInstanceData();
if( instData == NULL )
return;
// sanity, must be a check like button
if( BitTest( g->winGetStatus(), WIN_STATUS_CHECK_LIKE ) == FALSE )
{
DEBUG_CRASH(( "GadgetCheckLikeButtonSetVisualCheck: Window is not 'CHECK-LIKE'\n" ));
return;
} // end if
// set or clear the 'pushed' state
if( instData )
{
if( checked == TRUE )
BitSet( instData->m_state, WIN_STATE_SELECTED );
else
BitClear( instData->m_state, WIN_STATE_SELECTED );
} // end if
} // end GadgetCheckLikeButtonSetVisualCheck
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
Bool GadgetCheckLikeButtonIsChecked( GameWindow *g )
{
// sanity
if( g == NULL )
return FALSE;
// get instance data
WinInstanceData *instData = g->winGetInstanceData();
if( instData == NULL )
return FALSE;
// we just hold this "check like dual state thingie" using the selected state
return BitTest( instData->m_state, WIN_STATE_SELECTED );
} // end GadgetCheckLikeButtonIsChecked
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
void GadgetButtonEnableCheckLike( GameWindow *g, Bool makeCheckLike, Bool initiallyChecked )
{
// sanity
if( g == NULL )
return;
// get inst data
WinInstanceData *instData = g->winGetInstanceData();
if( instData == NULL )
return;
// make it check like
if( makeCheckLike )
g->winSetStatus( WIN_STATUS_CHECK_LIKE );
else
g->winClearStatus( WIN_STATUS_CHECK_LIKE );
// set the initially checked "state"
if( initiallyChecked )
BitSet( instData->m_state, WIN_STATE_SELECTED );
else
BitClear( instData->m_state, WIN_STATE_SELECTED );
} // end GadgetButtonEnableCheckLike
// GadgetButtonSetText ========================================================
/** Set the text for a push button */
//=============================================================================
void GadgetButtonSetText( GameWindow *g, UnicodeString text )
{
// sanity
if( g == NULL )
return;
TheWindowManager->winSendSystemMsg( g, GGM_SET_LABEL, (WindowMsgData)&text, 0 );
} // end GadgetButtonSetText
PushButtonData * getNewPushButtonData( void )
{
PushButtonData *p = NEW PushButtonData;
if(!p)
return NULL;
p->userData = NULL;
p->drawBorder = FALSE;
p->drawClock = NO_CLOCK;
p->overlayImage = NULL;
return p;
}
// GadgetButtonSetBorder ======================================================
/** Set to draw the special borders in the game */
//=============================================================================
void GadgetButtonSetBorder( GameWindow *g, Color color, Bool drawBorder = TRUE )
{
if( g == NULL )
return;
PushButtonData *pData = (PushButtonData *)g->winGetUserData();
if(!pData)
{
pData = getNewPushButtonData();
}
pData->drawBorder = drawBorder;
pData->colorBorder = color;
g->winSetUserData(pData);
}
// GadgetButtonDrawClock ======================================================
/** Set to draw a rectClock on the button */
//=============================================================================
void GadgetButtonDrawClock( GameWindow *g, Int percent, Color color )
{
if( g == NULL )
return;
PushButtonData *pData = (PushButtonData *)g->winGetUserData();
if(!pData)
{
pData = getNewPushButtonData();
}
pData->drawClock = NORMAL_CLOCK;
pData->percentClock = percent;
pData->colorClock = color;
g->winSetUserData(pData);
}
// GadgetButtonDrawInverseClock ======================================================
/** Set to draw an inversed rectClock on the button */
//=============================================================================
void GadgetButtonDrawInverseClock( GameWindow *g, Int percent, Color color )
{
if( g == NULL )
return;
PushButtonData *pData = (PushButtonData *)g->winGetUserData();
if(!pData)
{
pData = getNewPushButtonData();
}
pData->drawClock = INVERSE_CLOCK;
pData->percentClock = percent;
pData->colorClock = color;
g->winSetUserData(pData);
}
void GadgetButtonDrawOverlayImage( GameWindow *g, const Image *image )
{
if( g == NULL )
return;
PushButtonData *pData = (PushButtonData *)g->winGetUserData();
if(!pData)
{
pData = getNewPushButtonData();
}
pData->overlayImage = image;
g->winSetUserData(pData);
}
// GadgetButtonSetData ======================================================
/** Sets random data that the user can contain on the button */
//=============================================================================
void GadgetButtonSetData(GameWindow *g, void *data)
{
if( g == NULL )
return;
PushButtonData *pData = (PushButtonData *)g->winGetUserData();
if(!pData)
{
pData = getNewPushButtonData();
}
pData->userData = data;
g->winSetUserData(pData);
}
// GadgetButtonGetData ======================================================
/** Gets the random data the user had already set on the button */
//=============================================================================
void *GadgetButtonGetData(GameWindow *g)
{
if( g == NULL )
return NULL;
PushButtonData *pData = (PushButtonData *)g->winGetUserData();
if(!pData)
{
return NULL;
}
return pData->userData;
}
void GadgetButtonSetAltSound(GameWindow *g, AsciiString altSound )
{
if(!g)
return;
PushButtonData *pData = (PushButtonData *)g->winGetUserData();
if(!pData)
{
return;
}
pData->altSound = altSound;
}

View File

@@ -0,0 +1,449 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: RadioButton.cpp //////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Westwood Studios Pacific.
//
// Confidential Information
// Copyright (C) 2001 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// Project: RTS3
//
// File name: RadioButton.cpp
//
// Created: Colin Day, June 2001
//
// Desc: Radio button GUI control
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
// USER INCLUDES //////////////////////////////////////////////////////////////
#include "Common/Language.h"
#include "Gameclient/GameWindowManager.h"
#include "GameClient/Gadget.h"
// DEFINES ////////////////////////////////////////////////////////////////////
// PRIVATE TYPES //////////////////////////////////////////////////////////////
// PRIVATE DATA ///////////////////////////////////////////////////////////////
// PUBLIC DATA ////////////////////////////////////////////////////////////////
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// doRadioUnselect ============================================================
/** Do the unselect of matching group not including exception window */
//=============================================================================
static void doRadioUnselect( GameWindow *window, Int group, Int screen,
GameWindow *except )
{
//
// if this is a radio button we have something to consider, but we
// will ignore the except window
//
if( window != except && BitTest( window->winGetStyle(), GWS_RADIO_BUTTON ) )
{
RadioButtonData *radioData = (RadioButtonData *)window->winGetUserData();
if( radioData->group == group && radioData->screen == screen )
{
WinInstanceData *instData = window->winGetInstanceData();
BitClear( instData->m_state, WIN_STATE_SELECTED );
} // end if
} // end if
// recursively call on all my children
GameWindow *child;
for( child = window->winGetChild(); child; child = child->winGetNext() )
doRadioUnselect( child, group, screen, except );
} // end doRadioUnselect
// unselectOtherRadioOfGroup ==================================================
/** Go through the entire window system, including child windows and
* unselect any radio buttons of the specified group, but not the
* window specified */
//=============================================================================
static void unselectOtherRadioOfGroup( Int group, Int screen,
GameWindow *except )
{
GameWindow *window = TheWindowManager->winGetWindowList();
for( window = TheWindowManager->winGetWindowList();
window;
window = window->winGetNext() )
doRadioUnselect( window, group, screen, except );
} // end unselectOtherRadioOfGroup
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
// GadgetRadioButtonInput =====================================================
/** Handle input for radio button */
//=============================================================================
WindowMsgHandledType GadgetRadioButtonInput( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
WinInstanceData *instData = window->winGetInstanceData();
switch( msg )
{
// ------------------------------------------------------------------------
case GWM_MOUSE_ENTERING:
{
if( BitTest( instData->getStyle(), GWS_MOUSE_TRACK ) )
{
BitSet( instData->m_state, WIN_STATE_HILITED );
TheWindowManager->winSendSystemMsg( instData->getOwner(),
GBM_MOUSE_ENTERING,
(WindowMsgData)window,
mData1 );
//TheWindowManager->winSetFocus( window );
} // end if
break;
} // end mouse enter
// ------------------------------------------------------------------------
case GWM_MOUSE_LEAVING:
{
if( BitTest( instData->getStyle(), GWS_MOUSE_TRACK ) )
{
BitClear( instData->m_state, WIN_STATE_HILITED );
TheWindowManager->winSendSystemMsg( instData->getOwner(),
GBM_MOUSE_LEAVING,
(WindowMsgData)window,
mData1 );
} // end if
break;
} // end mouse leaving
// ------------------------------------------------------------------------
case GWM_LEFT_DRAG:
{
TheWindowManager->winSendSystemMsg( instData->getOwner(), GGM_LEFT_DRAG,
(WindowMsgData)window, mData1 );
break;
} // end left drag
// ------------------------------------------------------------------------
case GWM_LEFT_DOWN:
{
break;
} // end down
// ------------------------------------------------------------------------
case GWM_LEFT_UP:
{
if( BitTest( instData->getState(), WIN_STATE_SELECTED ) == FALSE )
{
RadioButtonData *radioData = (RadioButtonData *)window->winGetUserData();
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GBM_SELECTED,
(WindowMsgData)window,
mData1 );
//
// unselect any windows in the system (including children) that
// are radio buttons with this same group and screen ID
//
if( radioData->group != 0 )
unselectOtherRadioOfGroup(radioData->group, radioData->screen, window );
// this button is now selected
BitSet( instData->m_state, WIN_STATE_SELECTED );
} // end if, not selected
else if( BitTest( instData->getState(), WIN_STATE_HILITED ) == FALSE )
{
// this up click was not meant for this button
return MSG_IGNORED;
} // end else if
break;
} // end left up or click
// ------------------------------------------------------------------------
case GWM_CHAR:
{
switch( mData1 )
{
// --------------------------------------------------------------------
case KEY_ENTER:
case KEY_SPACE:
if( BitTest( mData2, KEY_STATE_DOWN ) )
{
if( BitTest( instData->getState(), WIN_STATE_SELECTED ) == FALSE )
{
RadioButtonData *radioData = (RadioButtonData *)window->winGetUserData();
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GBM_SELECTED,
(WindowMsgData)window,
mData1 );
//
// unselect any windows in the system (including children) that
// are radio buttons with this same group and screen ID
//
if( radioData->group != 0 )
unselectOtherRadioOfGroup(radioData->group, radioData->screen, window );
// this button is now selected
BitSet( instData->m_state, WIN_STATE_SELECTED );
} // end if, not selected
} // end key down
break;
// --------------------------------------------------------------------
case KEY_DOWN:
case KEY_RIGHT:
case KEY_TAB:
{
if( BitTest( mData2, KEY_STATE_DOWN ) )
window->winNextTab();
break;
} // end down, right, or tab
// --------------------------------------------------------------------
case KEY_UP:
case KEY_LEFT:
{
if( BitTest( mData2, KEY_STATE_DOWN ) )
window->winPrevTab();
break;
} // end up, left
// --------------------------------------------------------------------
default:
{
return MSG_IGNORED;
} // end default
} // end switch( mData1 )
break;
} // end char messsage
// ------------------------------------------------------------------------
default:
{
return MSG_IGNORED;
} // end default
} // end switch( msg )
return MSG_HANDLED;
} // end GadgetRadioButtonInput
// GadgetRadioButtonSystem ====================================================
/** Handle system messages for radio button */
//=============================================================================
WindowMsgHandledType GadgetRadioButtonSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
WinInstanceData *instData = window->winGetInstanceData();
switch( msg )
{
// ------------------------------------------------------------------------
case GBM_SET_SELECTION:
{
if( BitTest( instData->getState(), WIN_STATE_SELECTED ) == FALSE )
{
// do we want to send a selected message?
if( (Bool)mData1 == TRUE )
{
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GBM_SELECTED,
(WindowMsgData)window,
0 );
} // end if
//
// unselect any windows in the system (including children) that
// are radio buttons with this same group and screen ID
//
RadioButtonData *radioData = (RadioButtonData *)window->winGetUserData();
if( radioData->group != 0 )
unselectOtherRadioOfGroup(radioData->group, radioData->screen, window );
// this button is now selected
BitSet( instData->m_state, WIN_STATE_SELECTED );
} // end if
break;
} // end set selection
// ------------------------------------------------------------------------
case GGM_SET_LABEL:
{
window->winSetText( *(UnicodeString*)mData1 );
break;
} // end set label
// ------------------------------------------------------------------------
case GWM_CREATE:
break;
// ------------------------------------------------------------------------
case GWM_DESTROY:
{
RadioButtonData *radioData = (RadioButtonData *)window->winGetUserData();
// free radio button user data
delete radioData;
break;
} // end destroy
// ------------------------------------------------------------------------
case GWM_INPUT_FOCUS:
{
if( mData1 == FALSE )
BitClear( instData->m_state, WIN_STATE_HILITED );
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GGM_FOCUS_CHANGE,
mData1,
window->winGetWindowId() );
*(Bool*)mData2 = TRUE;
break;
} // end focus
default:
return MSG_IGNORED;
} // end switch( msg )
return MSG_HANDLED;
} // end GadgetRadioButtonSystem
// GadgetRadioSetText =========================================================
/** Set the text for the control */
//=============================================================================
void GadgetRadioSetText( GameWindow *g, UnicodeString text )
{
// sanity
if( g == NULL )
return;
TheWindowManager->winSendSystemMsg( g, GGM_SET_LABEL, (WindowMsgData)&text, 0 );
} // end GadgetRadioSetText
// GadgetRadioSetGroup ========================================================
/** Set the group number for a radio button, only one radio button of
* a group can be selected at any given time */
//=============================================================================
void GadgetRadioSetGroup( GameWindow *g, Int group, Int screen )
{
RadioButtonData *radioData = (RadioButtonData *)g->winGetUserData();
radioData->group = group;
radioData->screen = screen;
} // end GadgetRadioSetGroup
// GadgetRadioSetText =========================================================
/** Set the text for the control */
//=============================================================================
void GadgetRadioSetSelection( GameWindow *g, Bool sendMsg )
{
// sanity
if( g == NULL )
return;
TheWindowManager->winSendSystemMsg( g, GBM_SET_SELECTION, (WindowMsgData)&sendMsg, 0 );
} // end GadgetRadioSetText

View File

@@ -0,0 +1,225 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: StaticText.cpp ///////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Westwood Studios Pacific.
//
// Confidential Information
// Copyright (C) 2001 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// Project: RTS3
//
// File name: StaticText.cpp
//
// Created: Colin Day, June 2001
//
// Desc: Static text control
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
// USER INCLUDES //////////////////////////////////////////////////////////////
#include "Common/Language.h"
#include "GameClient/DisplayStringManager.h"
#include "GameClient/GameWindow.h"
#include "GameClient/Gadget.h"
#include "GameClient/GameWindowManager.h"
// DEFINES ////////////////////////////////////////////////////////////////////
// PRIVATE TYPES //////////////////////////////////////////////////////////////
// PRIVATE DATA ///////////////////////////////////////////////////////////////
// PUBLIC DATA ////////////////////////////////////////////////////////////////
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// GadgetStaticTextInput ======================================================
/** Handle input for text field */
//=============================================================================
WindowMsgHandledType GadgetStaticTextInput( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
switch( msg )
{
// ------------------------------------------------------------------------
case GWM_CHAR:
switch (mData1)
{
case KEY_DOWN:
case KEY_RIGHT:
case KEY_TAB:
// Just in case some fool sets static text as a tab stop
if( BitTest( mData2, KEY_STATE_DOWN ) )
window->winNextTab();
break;
case KEY_UP:
case KEY_LEFT:
if( BitTest( mData2, KEY_STATE_DOWN ) )
window->winPrevTab();
break;
default:
return MSG_IGNORED;
}
break;
default:
return MSG_IGNORED;
}
return MSG_HANDLED;
} // end GadgetStaticTextInput
// GadgetStaticTextSystem =====================================================
/** Handle system messages for text field */
//=============================================================================
WindowMsgHandledType GadgetStaticTextSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
// WinInstanceData *instData = window->winGetInstanceData();
switch( msg )
{
// ------------------------------------------------------------------------
case GGM_GET_LABEL:
{
TextData *tData = (TextData *)window->winGetUserData();
if (tData && tData->text)
*(UnicodeString*)mData2 = tData->text->getText();
break;
} // end get label
// ------------------------------------------------------------------------
case GGM_SET_LABEL:
{
if( mData1 )
{
TextData *tData = (TextData *)window->winGetUserData();
if (tData && tData->text)
tData->text->setText( *(UnicodeString*)mData1 );
}
break;
} // end set label
// ------------------------------------------------------------------------
case GWM_CREATE:
break;
// ------------------------------------------------------------------------
case GWM_DESTROY:
{
TextData *data = (TextData *)window->winGetUserData();
// free the display string
TheDisplayStringManager->freeDisplayString( data->text );
// free text data
delete( data );
break;
} // end destroy
default:
return MSG_IGNORED;
} // end switch( msg )
return MSG_HANDLED;
} // end GadgetStaticTextSystem
// GadgetStaticTextSetText ====================================================
/** Set the text for a static text control */
//=============================================================================
void GadgetStaticTextSetText( GameWindow *window, UnicodeString text )
{
if(!window)
return;
TheWindowManager->winSendSystemMsg( window, GGM_SET_LABEL, (WindowMsgData)&text, 0 );
} // end GadgetStaticTextSetText
UnicodeString GadgetStaticTextGetText( GameWindow *window )
{
if(!window)
return UnicodeString::TheEmptyString;
TextData *tData = (TextData *)window->winGetUserData();
if(!tData)
return UnicodeString::TheEmptyString;
return tData->text->getText();
}
// GadgetStaticTextSetFont ====================================================
/** Set the font for a text control, we need to set the window
* text font, the tooltip font, and the static text display strings for
* the text data itself */
//=============================================================================
void GadgetStaticTextSetFont( GameWindow *g, GameFont *font )
{
TextData *textData = (TextData *)g->winGetUserData();
DisplayString *dString;
// set the font for the display strings all windows have
dString = g->winGetInstanceData()->getTextDisplayString();
if( dString )
dString->setFont( font );
dString = g->winGetInstanceData()->getTooltipDisplayString();
if( dString )
dString->setFont( font );
// static text specific
if( textData )
{
dString = textData->text;
if( dString )
dString->setFont( font );
} // end if
} // end GadgetStaticTextSetFont

View File

@@ -0,0 +1,365 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: RadioButton.cpp //////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Westwood Studios Pacific.
//
// Confidential Information
// Copyright (C) 2001 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// Project: RTS3
//
// File name: \projects\RTS\code\gameengine\Source\GameClient\GUI\Gadget\GadgetTabControl.cpp
//
// Created: Graham Smallwood, November 2001
//
// Desc: Tab Set GUI control
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
// USER INCLUDES //////////////////////////////////////////////////////////////
#include "Common/Language.h"
#include "Gameclient/GameWindowManager.h"
#include "GameClient/Gadget.h"
#include "GameClient/GadgetTabControl.h"
// DEFINES ////////////////////////////////////////////////////////////////////
// PRIVATE TYPES //////////////////////////////////////////////////////////////
// PRIVATE DATA ///////////////////////////////////////////////////////////////
// PUBLIC DATA ////////////////////////////////////////////////////////////////
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
// GadgetTabControlInput =====================================================
/** Handle input for TabControl */
//=============================================================================
WindowMsgHandledType GadgetTabControlInput( GameWindow *tabControl, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
// WinInstanceData *instData = tabControl->winGetInstanceData();
TabControlData *tabData = (TabControlData *)tabControl->winGetUserData();
Int tabX, tabY;
tabControl->winGetScreenPosition( &tabX, &tabY );
Int mouseX = LOLONGTOSHORT(mData1) - tabX;//mData1 is packedMouseCoords in screen space
Int mouseY = HILONGTOSHORT(mData1) - tabY;
Int tabsLeft = tabData->tabsLeftLimit;
Int tabsRight = tabData->tabsRightLimit;
Int tabsBottom = tabData->tabsBottomLimit;
Int tabsTop = tabData->tabsTopLimit;
switch( msg )
{
case GWM_LEFT_DOWN:
{
if( (mouseX < tabsLeft)
|| (mouseX > tabsRight)
|| (mouseY < tabsTop)
|| (mouseY > tabsBottom)
)
{//I eat input on myself that isn't a tab (a button click would mean I don't see the input ever.)
return MSG_HANDLED;
}
Int distanceIn;
Int tabSize;
if( (tabData->tabEdge == TP_RIGHT_SIDE) || (tabData->tabEdge == TP_LEFT_SIDE) )
{//scan down to find which button
distanceIn = mouseY - tabsTop;
tabSize = tabData->tabHeight;
}
else
{//scan right to find which button
distanceIn = mouseX - tabsLeft;
tabSize = tabData->tabWidth;
}
Int tabPressed = distanceIn / tabSize;
if( ! tabData->subPaneDisabled[tabPressed] && (tabPressed != tabData->activeTab) )
GadgetTabControlShowSubPane( tabControl, tabPressed );
}
default:
{
return MSG_IGNORED;
}
}
return MSG_HANDLED;
} // end GadgetTabControlInput
// GadgetTabControlSystem ====================================================
/** Handle system messages for TabControl */
//=============================================================================
WindowMsgHandledType GadgetTabControlSystem( GameWindow *tabControl, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
switch( msg )
{
// ------------------------------------------------------------------------
case GWM_CREATE:
break;
// ------------------------------------------------------------------------
case GWM_DESTROY:
{
TabControlData *tabData = (TabControlData *)tabControl->winGetUserData();
// free tab control user data
delete tabData;
break;
} // end destroy
case GGM_RESIZED:
{//On resize, we need to upkeep the pane sizes and tabs since they are bound to us
GadgetTabControlResizeSubPanes( tabControl );
GadgetTabControlComputeTabRegion( tabControl );
break;
}
case GBM_SELECTED:
{//Pass buttons messages up
GameWindow *parent = tabControl->winGetParent();
if( parent )
return TheWindowManager->winSendSystemMsg( parent, msg, mData1, mData2 );
}
default:
return MSG_IGNORED;
} // end switch( msg )
return MSG_HANDLED;
} // end GadgetTabControlSystem
void GadgetTabControlComputeTabRegion( GameWindow *tabControl )///< Recalc the tab positions based on userData
{
Int winWidth, winHeight;
tabControl->winGetSize( &winWidth, &winHeight );
TabControlData *tabData = (TabControlData *)tabControl->winGetUserData();
Int horzOffset = 0, vertOffset = 0;
if( (tabData->tabEdge == TP_TOP_SIDE) || (tabData->tabEdge == TP_BOTTOM_SIDE) )
{
if( tabData->tabOrientation == TP_CENTER )
{
horzOffset = winWidth - ( 2 * tabData->paneBorder ) - ( tabData->tabCount * tabData->tabWidth );
horzOffset /= 2;
}
else if( tabData->tabOrientation == TP_BOTTOMRIGHT )
{
horzOffset = winWidth - ( 2 * tabData->paneBorder ) - ( tabData->tabCount * tabData->tabWidth );
}
else if( tabData->tabOrientation == TP_TOPLEFT )
{
horzOffset = 0;
}
}
else
{
if( tabData->tabOrientation == TP_CENTER )
{
vertOffset = winHeight - ( 2 * tabData->paneBorder ) - ( tabData->tabCount * tabData->tabHeight );
vertOffset /= 2;
}
else if( tabData->tabOrientation == TP_BOTTOMRIGHT )
{
vertOffset = winHeight - ( 2 * tabData->paneBorder ) - ( tabData->tabCount * tabData->tabHeight );
}
else if( tabData->tabOrientation == TP_TOPLEFT )
{
vertOffset = 0;
}
}
if( tabData->tabEdge == TP_TOP_SIDE )
{
tabData->tabsTopLimit = tabData->paneBorder;
tabData->tabsBottomLimit = tabData->paneBorder + tabData->tabHeight;
tabData->tabsLeftLimit = tabData->paneBorder + horzOffset;
tabData->tabsRightLimit = tabData->paneBorder + horzOffset + ( tabData->tabWidth * tabData->tabCount );
}
else if( tabData->tabEdge == TP_BOTTOM_SIDE )
{
tabData->tabsTopLimit = winHeight - tabData->paneBorder - tabData->tabHeight;
tabData->tabsBottomLimit = winHeight - tabData->paneBorder;
tabData->tabsLeftLimit = tabData->paneBorder + horzOffset;
tabData->tabsRightLimit = tabData->paneBorder + horzOffset + ( tabData->tabWidth * tabData->tabCount );
}
else if( tabData->tabEdge == TP_RIGHT_SIDE )
{
tabData->tabsLeftLimit = winWidth - tabData->paneBorder - tabData->tabWidth;
tabData->tabsRightLimit = winWidth - tabData->paneBorder;
tabData->tabsTopLimit = tabData->paneBorder + vertOffset;
tabData->tabsBottomLimit = tabData->paneBorder + vertOffset + ( tabData->tabHeight * tabData->tabCount );
}
else if( tabData->tabEdge == TP_LEFT_SIDE )
{
tabData->tabsLeftLimit = tabData->paneBorder;
tabData->tabsRightLimit = tabData->paneBorder + tabData->tabWidth;
tabData->tabsTopLimit = tabData->paneBorder + vertOffset;
tabData->tabsBottomLimit = tabData->paneBorder + vertOffset + ( tabData->tabHeight * tabData->tabCount );
}
}
void GadgetTabControlComputeSubPaneSize( GameWindow *tabControl, Int *width, Int *height, Int *x, Int *y )
{
Int winWidth, winHeight;
tabControl->winGetSize( &winWidth, &winHeight );
TabControlData *tabData = (TabControlData *)tabControl->winGetUserData();
if( (tabData->tabEdge == TP_TOP_SIDE) || (tabData->tabEdge == TP_BOTTOM_SIDE) )
*height = winHeight - (2 * tabData->paneBorder) - tabData->tabHeight;
else
*height = winHeight - (2 * tabData->paneBorder);
if( (tabData->tabEdge == TP_LEFT_SIDE) || (tabData->tabEdge == TP_RIGHT_SIDE) )
*width = winWidth - (2 * tabData->paneBorder) - tabData->tabWidth;
else
*width = winWidth - (2 * tabData->paneBorder);
if( tabData->tabEdge == TP_LEFT_SIDE )
*x = tabData->paneBorder + tabData->tabWidth;
else
*x = tabData->paneBorder;
if( tabData->tabEdge == TP_TOP_SIDE )
*y = tabData->paneBorder + tabData->tabHeight;
else
*y = tabData->paneBorder;
}
void GadgetTabControlShowSubPane( GameWindow *tabControl, Int whichPane)
{
TabControlData *tabData = (TabControlData *)tabControl->winGetUserData();
for( Int paneIndex = 0; paneIndex < NUM_TAB_PANES; paneIndex++ )
{
if( tabData->subPanes[paneIndex] != NULL )
tabData->subPanes[paneIndex]->winHide( true );
}
if( tabData->subPanes[whichPane] )
tabData->activeTab = whichPane;
else
tabData->activeTab = 0;
tabData->activeTab = min( tabData->activeTab, tabData->tabCount - 1 );
tabData->subPanes[tabData->activeTab]->winHide( false );
}
void GadgetTabControlCreateSubPanes( GameWindow *tabControl )///< Create User Windows attached to userData as Panes
{//These two funcs are called after all the Editor set data is updated
TabControlData *tabData = (TabControlData *)tabControl->winGetUserData();
Int width, height, x, y;
GadgetTabControlComputeSubPaneSize(tabControl, &width, &height, &x, &y);
for( Int paneIndex = 0; paneIndex < NUM_TAB_PANES; paneIndex++ )
{
if( (tabData->subPanes[paneIndex] == NULL) )//This one is blank
{
tabData->subPanes[paneIndex] = TheWindowManager->winCreate( tabControl,
WIN_STATUS_NONE, x, y,
width, height,
PassSelectedButtonsToParentSystem,
NULL);
WinInstanceData *instData = tabData->subPanes[paneIndex]->winGetInstanceData();
BitSet( instData->m_style, GWS_TAB_PANE );
char buffer[20];
sprintf( buffer, "Pane %d", paneIndex );
instData->m_decoratedNameString = buffer;
//set enabled status to that of Parent
tabData->subPanes[paneIndex]->winEnable( BitTest(tabControl->winGetStatus(), WIN_STATUS_ENABLED) );
}
else//this one exists, tabCount will control keeping extra panes perma-hidden
{
tabData->subPanes[paneIndex]->winSetSize( width, height );
tabData->subPanes[paneIndex]->winSetPosition( x, y );
}
}
GadgetTabControlShowSubPane( tabControl, tabData->activeTab );
}
void GadgetTabControlResizeSubPanes( GameWindow *tabControl )
{
TabControlData *tabData = (TabControlData *)tabControl->winGetUserData();
Int width, height, x, y;
GadgetTabControlComputeSubPaneSize(tabControl, &width, &height, &x, &y);
for( Int paneIndex = 0; paneIndex < NUM_TAB_PANES; paneIndex++ )
{
if( tabData->subPanes[paneIndex] )
{
tabData->subPanes[paneIndex]->winSetSize( width, height );
tabData->subPanes[paneIndex]->winSetPosition( x, y );
}
}
}
///<In game creation finished, hook up Children to SubPane array
void GadgetTabControlFixupSubPaneList( GameWindow *tabControl )
{
Int childIndex =0;
TabControlData *tabData = (TabControlData *)tabControl->winGetUserData();
GameWindow *child = tabControl->winGetChild();
if( child )
{//need to write down children, and they are reversed from our array
while( child->winGetNext() != NULL )
{
child = child->winGetNext();
}
while( child )
{
tabData->subPanes[childIndex] = child;
childIndex++;
child = child->winGetPrev();
}
}
}

View File

@@ -0,0 +1,587 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: TextEntry.cpp ////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Westwood Studios Pacific.
//
// Confidential Information
// Copyright (C) 2001 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// Project: RTS3
//
// File name: TextEntry.cpp
//
// Created: Colin Day, June 2001
//
// Desc: Text entry GUI gadget
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
// USER INCLUDES //////////////////////////////////////////////////////////////
#include "Common/Language.h"
#include "GameClient/DisplayStringManager.h"
#include "GameClient/GameWindow.h"
#include "GameClient/Gadget.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/IMEManager.h"
// DEFINES ////////////////////////////////////////////////////////////////////
// PRIVATE TYPES //////////////////////////////////////////////////////////////
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
///////////////////////////////////////////////////////////////////////////////
// PRIVATE DATA ///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static Byte drawCnt = 0;
// static TbIME *ourIME = NULL; ///< @todo need this for IME kanji support
static GameWindow *curWindow = NULL; /**< so we can keep track of the input
window when using IME */
// PUBLIC DATA ////////////////////////////////////////////////////////////////
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// GadgetTextEntryInput =======================================================
/** Handle input for text entry field */
//=============================================================================
WindowMsgHandledType GadgetTextEntryInput( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
EntryData *e = (EntryData *)window->winGetUserData();
WinInstanceData *instData = window->winGetInstanceData();
if ( TheIMEManager && TheIMEManager->isAttachedTo( window) && TheIMEManager->isComposing())
{
// ignore input while IME has focus
return MSG_HANDLED;
}
switch( msg )
{
// ------------------------------------------------------------------------
case GWM_IME_CHAR:
{
WideChar ch = (WideChar) mData1;
// --------------------------------------------------------------------
if ( ch == VK_RETURN )
{
// Done with this edit
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GEM_EDIT_DONE,
(WindowMsgData)window,
0 );
return MSG_HANDLED;
};
if( ch )
{
// Constrain keys based on rules for entry box.
if( e->numericalOnly )
{
if( TheWindowManager->winIsDigit( ch ) == 0 )
return MSG_HANDLED;
}
if( e->alphaNumericalOnly )
{
if( TheWindowManager->winIsAlNum( ch ) == 0 )
return MSG_HANDLED;
}
if ( e->aSCIIOnly )
{
if ( TheWindowManager->winIsAscii( ch ) == 0 )
{
return MSG_HANDLED;
}
}
if( e->charPos < e->maxTextLen-1 )
{
e->text->appendChar( ch );
e->sText->appendChar( L'*' );
e->charPos++;
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GEM_UPDATE_TEXT,
(WindowMsgData)window,
0 );
}
}
break;
}
// ------------------------------------------------------------------------
case GWM_CHAR:
if ( BitTest( mData2, KEY_STATE_DOWN ) && BitTest( mData2, KEY_STATE_ALT | KEY_STATE_CONTROL ) )
{
return MSG_IGNORED; // text extries shouldn't care about CTRL+* or ALT+*
}
switch( mData1 )
{
/*
// --------------------------------------------------------------------
case KEY_KPENTER:
case KEY_ENTER:
// Done with this edit
if( BitTest( mData2, KEY_STATE_DOWN ) )
{
if( e->receivedUnichar == FALSE )
{
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GEM_EDIT_DONE,
(WindowMsgData)window,
0 );
}
}
break;
*/
// --------------------------------------------------------------------
// Don't process these keys
case KEY_ESC:
case KEY_PGUP:
case KEY_PGDN:
case KEY_HOME:
case KEY_END:
case KEY_F1:
case KEY_F2:
case KEY_F3:
case KEY_F4:
case KEY_F5:
case KEY_F6:
case KEY_F7:
case KEY_F8:
case KEY_F9:
case KEY_F10:
case KEY_F11:
case KEY_F12:
case KEY_CAPS:
case KEY_DEL:
return MSG_IGNORED;
// --------------------------------------------------------------------
case KEY_DOWN:
case KEY_RIGHT:
case KEY_TAB:
if( BitTest( mData2, KEY_STATE_DOWN ) )
{
GameWindow *parent;
parent = window->winGetParent();
if(parent && !BitTest(parent->winGetStyle(), GWS_COMBO_BOX))
parent = NULL;
if(parent)
TheWindowManager->winNextTab(parent);
else
TheWindowManager->winNextTab(window);
}
break;
// --------------------------------------------------------------------
case KEY_UP:
case KEY_LEFT:
if( BitTest( mData2, KEY_STATE_DOWN ) )
{
GameWindow *parent;
parent = window->winGetParent();
if(parent && !BitTest(parent->winGetStyle(), GWS_COMBO_BOX))
parent = NULL;
if(parent)
TheWindowManager->winPrevTab(parent);
else
TheWindowManager->winPrevTab(window);
}
break;
// --------------------------------------------------------------------
case KEY_BACKSPACE:
if( BitTest( mData2, KEY_STATE_DOWN ) )
{
// if conCharPos != 0 this will fall through to next case.
// it should be noted that conCharPos can only != 0 in Jap & Kor
if( e->conCharPos == 0 )
{
if( e->charPos > 0 )
{
e->text->removeLastChar();
e->sText->removeLastChar();
e->charPos--;
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GEM_UPDATE_TEXT,
(WindowMsgData)window,
0 );
} // end if
}
}
break;
} // end switch( mData1 )
break;
// ------------------------------------------------------------------------
case GWM_LEFT_DOWN:
BitSet( instData->m_state, WIN_STATE_HILITED );
TheWindowManager->winSetFocus( window );
break;
// ------------------------------------------------------------------------
case GWM_MOUSE_ENTERING:
if (BitTest( instData->getStyle(), GWS_MOUSE_TRACK ) )
{
BitSet( instData->m_state, WIN_STATE_HILITED );
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GBM_MOUSE_ENTERING,
(WindowMsgData)window, 0 );
//TheWindowManager->winSetFocus( window );
}
break;
// ------------------------------------------------------------------------
case GWM_MOUSE_LEAVING:
if( BitTest( instData->getStyle(), GWS_MOUSE_TRACK ) )
{
BitClear( instData->m_state, WIN_STATE_HILITED );
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GBM_MOUSE_LEAVING,
(WindowMsgData)window, 0 );
}
break;
// ------------------------------------------------------------------------
case GWM_LEFT_DRAG:
if( BitTest( instData->getStyle(), GWS_MOUSE_TRACK ) )
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GGM_LEFT_DRAG,
(WindowMsgData)window, 0 );
break;
// ------------------------------------------------------------------------
default:
return MSG_IGNORED;
} // end switch( msg )
return MSG_HANDLED;
} // end GadgetTextEntryInput
// GadgetTextEntrySystem ======================================================
/** Handle system messages for entry field */
//=============================================================================
WindowMsgHandledType GadgetTextEntrySystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
EntryData *e = (EntryData *)window->winGetUserData();
WinInstanceData *instData = window->winGetInstanceData();
switch( msg )
{
// ------------------------------------------------------------------------
case GEM_GET_TEXT:
*(UnicodeString*)mData2 = e->text->getText();
break;
// ------------------------------------------------------------------------
case GEM_SET_TEXT:
{
const UnicodeString* ustr = (const UnicodeString*)mData1;
e->text->setText( *ustr );
e->charPos = ustr->getLength();
e->constructText->setText( UnicodeString::TheEmptyString );
e->conCharPos = 0;
// set our secret text string to be filled with '*' the same length
e->sText->setText( UnicodeString::TheEmptyString );
Int len = ustr->getLength();
for( Int i = 0; i < len; i++ )
e->sText->appendChar( L'*' );
break;
} // end set text
// ------------------------------------------------------------------------
case GWM_CREATE:
break;
// ------------------------------------------------------------------------
case GWM_DESTROY:
// delete the edit display string
TheDisplayStringManager->freeDisplayString( e->text );
TheDisplayStringManager->freeDisplayString( e->sText );
TheDisplayStringManager->freeDisplayString( e->constructText );
// delete construct list
if( e->constructList )
TheWindowManager->winDestroy( e->constructList );
// free all edit data
delete( (EntryData *)window->winGetUserData() );
break;
// ------------------------------------------------------------------------
case GWM_INPUT_FOCUS:
if( mData1 == FALSE )
{
// If we're losing focus
/// @todo need to enable this for IME support
// ourIME->UnActivate();
curWindow = NULL;
BitClear( instData->m_state, WIN_STATE_SELECTED );
BitClear( instData->m_state, WIN_STATE_HILITED );
if( e->constructList )
e->constructList->winHide( TRUE );
e->constructText->setText( UnicodeString::TheEmptyString );
e->conCharPos = 0;
if(TheIMEManager && TheIMEManager->isAttachedTo(window))
TheIMEManager->attach(NULL);
//TheIMEManager->detatch();
}
else
{
curWindow = window;
/// @todo need to enable this for IME support
if (TheIMEManager)
TheIMEManager->attach( window );
// ourIME->Activate( (void *)ApplicationHWnd );
BitSet( instData->m_state, WIN_STATE_SELECTED );
BitSet( instData->m_state, WIN_STATE_HILITED );
}
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GGM_FOCUS_CHANGE,
mData1,
window->winGetWindowId() );
*(Bool*)mData2 = TRUE;
break;
default:
return MSG_IGNORED;
} // end switch( msg )
return MSG_HANDLED;
} // end GadgetTextEntrySystem
/** @todo we might want to do something like this if we use IME for language
* support in this product */
/*
// used to create interface to IME
BoolCode InitializeEntryGadget( void )
{
ourIME = NEW TbIME;
ourIME->Composition_SetMaxLength( 11 );
return TRUE;
}
// used to destroy interface to IME
BoolCode ShutdownEntryGadget( void )
{
delete ourIME;
ourIME = NULL;
return TRUE;
}
void InformEntry( WideChar c )
{
Int i, listCount = 0;
EntryData *e;
if( ourIME == NULL || curWindow == NULL )
return;
e = (EntryData *)curWindow->winGetUserData();
if( ( (OurLanguage == LANGUAGE_ID_JAPANESE) ||
(OurLanguage == LANGUAGE_ID_KOREAN) ) &&
( (e->aSCIIOnly == FALSE ) &&
(e->alphaNumericalOnly == FALSE ) &&
(e->numericalOnly == FALSE ) ) )
{
e->receivedUnichar = TRUE;
// we must eat the following keys
switch( c )
{
case L'\a':
case L'\b':
case L'\f':
case L'\t':
case L'\v':
return;
// we must completely ignore the return key
case L'\r':
case L'\n':
e->receivedUnichar = FALSE;
return;
}
if( e->charPos < e->maxTextLen-1 )
{
e->text[ e->charPos++ ] = c;
e->text[ e->charPos ] = 0;
}
// always update the construction buffer after a key has come through here.
TheWindowManager->winStrcpy( e->constructText, (WideChar *)ourIME->Composition_Get() );
e->conCharPos = NoxStrlen( e->constructText );
// we might need to update our listbox
listCount = ourIME->CandidateList_GetSize();
if( TRUE ) //listCount == 0)
{
// if no entries just hide it and leave
if( e->constructList )
e->constructList->winHide( TRUE );
}
else
{
Int maxWidth = 0;
ListboxData list = NULL;
ICoord2D constructSize, sliderSize;
WinHide( e->constructList, FALSE );
list = (ListBoxData)e->constructList->winGetUserData();
e->constructList->winGetSize( &constructSize.x, &constructSize.y );
list->slider->winGetSize( &sliderSize.x, &sliderSize.y );
TheWindowManager->winSendSystemMsg( e->constructList, GLM_DEL_ALL, 0, 0 );
for( i=0; i<listCount; i++ )
{
Int tempWidth;
WideChar *text = (WideChar *)ourIME->CandidateList_GetItem( i );
TheWindowManager->winGetTextSize( e->constructList->instData.font,
text, NULL, &tempWidth, 0 );
if( tempWidth > maxWidth )
maxWidth = tempWidth;
UnicodeString tmp(text);
TheWindowManager->winSendSystemMsg( e->constructList, GLM_ADD_ENTRY,
(WindowMsgData)&tmp, -1 );
}
e->constructList->winSetSize( maxWidth + sliderSize.y,
constructSize.y );
}
}
}
*/
// GadgetTextEntrySetFont =====================================================
/** Set the font for a text entry control, we need to set the window
* text font, the tooltip font, and the edit text display strings for
* the text data itself and the secret text */
//=============================================================================
void GadgetTextEntrySetFont( GameWindow *g, GameFont *font )
{
EntryData *entryData = (EntryData *)g->winGetUserData();
DisplayString *dString;
// set the font for the display strings all windows have
dString = g->winGetInstanceData()->getTextDisplayString();
if( dString )
dString->setFont( font );
dString = g->winGetInstanceData()->getTooltipDisplayString();
if( dString )
dString->setFont( font );
// text entry specific
if( entryData )
{
dString = entryData->text;
if( dString )
dString->setFont( font );
dString = entryData->sText;
if( dString )
dString->setFont( font );
} // end if
} // end GadgetTextEntrySetFont
// GadgetTextEntryGetText =======================================================
/** Get the text for a Text entry */
//=============================================================================
UnicodeString GadgetTextEntryGetText( GameWindow *textentry )
{
// sanity
if( textentry == NULL )
return UnicodeString::TheEmptyString;
// verify that this is a list box
if( BitTest( textentry->winGetStyle(), GWS_ENTRY_FIELD ) == FALSE )
return UnicodeString::TheEmptyString;
UnicodeString result;
TheWindowManager->winSendSystemMsg( textentry, GEM_GET_TEXT, 0, (WindowMsgData)&result );
return result;
} // end GadgetListBoxGetText

View File

@@ -0,0 +1,472 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: VerticalSlider.cpp ///////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Westwood Studios Pacific.
//
// Confidential Information
// Copyright (C) 2001 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// Project: RTS3
//
// File name: VerticalSlider.cpp
//
// Created: Colin Day, June 2001
//
// Desc: Vertical slider gui control
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
// USER INCLUDES //////////////////////////////////////////////////////////////
#include "Common/Language.h"
#include "Gameclient/GameWindowManager.h"
#include "GameClient/Gadget.h"
// DEFINES ////////////////////////////////////////////////////////////////////
// PRIVATE TYPES //////////////////////////////////////////////////////////////
// PRIVATE DATA ///////////////////////////////////////////////////////////////
// PUBLIC DATA ////////////////////////////////////////////////////////////////
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
// GadgetVerticlaSliderInput ==================================================
/** Handle input for vertical slider */
//=============================================================================
WindowMsgHandledType GadgetVerticalSliderInput( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
SliderData *s = (SliderData *)window->winGetUserData();
WinInstanceData *instData = window->winGetInstanceData();
switch( msg )
{
// ------------------------------------------------------------------------
case GWM_MOUSE_ENTERING:
if( BitTest( instData->getStyle(), GWS_MOUSE_TRACK ) )
{
BitSet( instData->m_state, WIN_STATE_HILITED );
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GBM_MOUSE_ENTERING,
(WindowMsgData)window,
0 );
//TheWindowManager->winSetFocus( window );
}
break;
// ------------------------------------------------------------------------
case GWM_MOUSE_LEAVING:
if( BitTest( instData->getStyle(), GWS_MOUSE_TRACK ) )
{
BitClear( instData->m_state, WIN_STATE_HILITED );
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GBM_MOUSE_LEAVING,
(WindowMsgData)window,
0 );
}
break;
// ------------------------------------------------------------------------
case GWM_LEFT_DRAG:
if( BitTest( instData->getStyle(), GWS_MOUSE_TRACK ) )
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GGM_LEFT_DRAG,
(WindowMsgData)window,
mData1 );
break;
// ------------------------------------------------------------------------
case GWM_LEFT_DOWN:
break;
// ------------------------------------------------------------------------
case GWM_LEFT_UP:
{
Int x, y;
// Int mousex = mData1 & 0xFFFF;
Int mousey = mData1 >> 16;
ICoord2D size, childSize, childCenter;
GameWindow *child = window->winGetChild();
Int pageClickSize, clickPos;
window->winGetScreenPosition( &x, &y );
window->winGetSize( &size.x, &size.y );
child->winGetSize( &childSize.x, &childSize.y );
child->winGetPosition( &childCenter.x, &childCenter.y );
childCenter.x += childSize.x / 2;
childCenter.y += childSize.y / 2;
//
// when you click on the slider, but not the button, we will jump
// the slider position up/down by this much
//
pageClickSize = size.y / 5;
clickPos = mousey - y;
if( clickPos >= childCenter.y )
{
clickPos = childCenter.y + pageClickSize;
if( clickPos > mousey - y )
clickPos = mousey - y;
} // end if
else
{
clickPos = childCenter.y - pageClickSize;
if( clickPos < mousey - y )
clickPos = mousey - y;
} // end else
// keep pos valid on window
if( clickPos > y + size.y - childSize.y / 2 )
clickPos = y + size.y - childSize.y / 2;
if( clickPos < childSize.y / 2 )
clickPos = childSize.y / 2;
child->winSetPosition( 0, clickPos - childSize.y / 2 );
TheWindowManager->winSendSystemMsg( window, GGM_LEFT_DRAG, 0, mData1 );
break;
}
// ------------------------------------------------------------------------
case GWM_CHAR:
{
switch (mData1)
{
// --------------------------------------------------------------------
case KEY_UP:
if( BitTest( mData2, KEY_STATE_DOWN ) )
{
if( s->position < s->maxVal - 1)
{
GameWindow *child = window->winGetChild();
s->position += 2;
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GSM_SLIDER_TRACK,
(WindowMsgData)window,
s->position );
// Translate to window coords
child->winSetPosition( 0, (Int)((s->maxVal - s->position) * s->numTicks) );
}
}
break;
// --------------------------------------------------------------------
case KEY_DOWN:
if( BitTest( mData2, KEY_STATE_DOWN ) )
{
if( s->position > s->minVal + 1 )
{
GameWindow *child = window->winGetChild();
s->position -= 2;
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GSM_SLIDER_TRACK,
(WindowMsgData)window,
s->position );
// Translate to window coords
child->winSetPosition( 0, (Int)((s->maxVal - s->position) * s->numTicks) );
}
}
break;
// --------------------------------------------------------------------
case KEY_RIGHT:
case KEY_TAB:
if( BitTest( mData2, KEY_STATE_DOWN ) )
window->winNextTab();
break;
// --------------------------------------------------------------------
case KEY_LEFT:
if( BitTest( mData2, KEY_STATE_DOWN ) )
window->winPrevTab();
break;
default:
return MSG_IGNORED;
} // end switch( mData1 )
break;
} // end char
default:
return MSG_IGNORED;
} // end switch( msg )
return MSG_HANDLED;
} // end GadgetVerticalSliderInput
// GadgetVerticalSliderSystem =================================================
/** Handle system messages for vertical slider */
//=============================================================================
WindowMsgHandledType GadgetVerticalSliderSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
SliderData *s = (SliderData *)window->winGetUserData();
WinInstanceData *instData = window->winGetInstanceData();
switch( msg )
{
// ------------------------------------------------------------------------
case GBM_SELECTED:
{
// tell owner I've finished moving
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GSM_SLIDER_DONE,
(WindowMsgData)window,
s->position );
break;
}
// ------------------------------------------------------------------------
case GGM_LEFT_DRAG:
{
// Int mousex = mData2 & 0xFFFF;
Int mousey = mData2 >> 16;
Int x, y, delta;
ICoord2D size, childSize, childCenter;
GameWindow *child = window->winGetChild();
window->winGetScreenPosition( &x, &y );
window->winGetSize( &size.x, &size.y );
child->winGetSize( &childSize.x, &childSize.y );
child->winGetScreenPosition( &childCenter.x, &childCenter.y );
childCenter.x += childSize.x / 2;
childCenter.y += childSize.y / 2;
//
// ignore drag attempts when the mouse is below or above the slider totally
// and put the dragging thumb back at the slider pos
//
if( mousey > y + size.y )
{
//s->position = s->minVal;
TheWindowManager->winSendSystemMsg( window, GSM_SET_SLIDER,
s->minVal, 0 );
// tell owner i moved
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GSM_SLIDER_TRACK,
(WindowMsgData)window,
s->position );
break;
} // end if
else if( mousey < y )
{
//s->position = s->maxVal;
TheWindowManager->winSendSystemMsg( window, GSM_SET_SLIDER,
s->maxVal, 0 );
// tell owner i moved
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GSM_SLIDER_TRACK,
(WindowMsgData)window,
s->position );
break;
} // end else if
if( childCenter.y <= y + childSize.y / 2 )
{
child->winSetPosition( 0, 0 );
s->position = s->maxVal;
}
else if( childCenter.y >= y + size.y - childSize.y / 2 )
{
child->winSetPosition( 0, size.y - childSize.y );
s->position = s->minVal;
}
else
{
delta = childCenter.y - y - childSize.y/2;
// Calc slider position
s->position = (Int)(delta / s->numTicks) ;
/*
s->position += s->minVal;
*/
if( s->position > s->maxVal )
s->position = s->maxVal;
// Invert slider position so that maxval is at the top
s->position = s->maxVal - s->position;
}
// tell owner i moved
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GSM_SLIDER_TRACK,
(WindowMsgData)window,
s->position );
break;
}
// ------------------------------------------------------------------------
case GSM_SET_SLIDER:
{
Int newPos = (Int)mData1;
GameWindow *child = window->winGetChild();
if (newPos < s->minVal || newPos > s->maxVal)
break;
s->position = newPos;
// Translate to window coords
newPos = (Int)((s->maxVal - newPos) * s->numTicks);
child->winSetPosition( 0, newPos );
break;
}
// ------------------------------------------------------------------------
case GSM_SET_MIN_MAX:
{
Int newPos;
ICoord2D size;
GameWindow *child = window->winGetChild();
window->winGetSize( &size.x, &size.y );
s->minVal = (Int)mData1;
s->maxVal = (Int)mData2;
s->numTicks = (Real)( size.y-GADGET_SIZE)/(Real)(s->maxVal - s->minVal);
s->position = s->minVal;
// Translate to window coords
newPos = (Int)((s->maxVal - s->minVal) * s->numTicks);
child->winSetPosition( 0, newPos );
break;
}
// ------------------------------------------------------------------------
case GWM_CREATE:
break;
// ------------------------------------------------------------------------
case GWM_DESTROY:
delete( (SliderData *)window->winGetUserData() );
break;
// ------------------------------------------------------------------------
case GWM_INPUT_FOCUS:
// If we're losing focus
if( mData1 == FALSE )
{
BitClear( instData->m_state, WIN_STATE_HILITED );
} else {
BitSet( instData->m_state, WIN_STATE_HILITED );
}
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GGM_FOCUS_CHANGE,
mData1,
window->winGetWindowId() );
*(Bool*)mData2 = TRUE;
break;
// ------------------------------------------------------------------------
case GGM_RESIZED:
{
Int width = (Int)mData1;
// Int height = (Int)mData2;
GameWindow *thumb = window->winGetChild();
if( thumb )
thumb->winSetSize( width, GADGET_SIZE );
break;
} // end resized
default:
return MSG_IGNORED;
} // end switch( msg )
return MSG_HANDLED;
} // end GadgetVerticalSliderSystem

View File

@@ -0,0 +1,228 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: GameFont.cpp /////////////////////////////////////////////////////////////////////////////
// Created: Colin Day, June 2001
// Desc: Access to our representation for fonts
///////////////////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "GameClient/GameFont.h"
// PUBLIC DATA ////////////////////////////////////////////////////////////////////////////////////
FontLibrary *TheFontLibrary = NULL;
///////////////////////////////////////////////////////////////////////////////////////////////////
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------------------------
/** Link a font to the font list */
//-------------------------------------------------------------------------------------------------
void FontLibrary::linkFont( GameFont *font )
{
// sanity
if( font == NULL )
return;
// link it
font->next = m_fontList;
m_fontList = font;
// increment linked count
m_count++;
} // end linkFont
//-------------------------------------------------------------------------------------------------
/** Unlink a font from the font list */
//-------------------------------------------------------------------------------------------------
void FontLibrary::unlinkFont( GameFont *font )
{
GameFont *other = NULL;
// sanity
if( font == NULL )
return;
// sanity check and make sure this font is actually in this library
for( other = m_fontList; other; other = other->next )
if( other == font )
break;
if( other == NULL )
{
DEBUG_CRASH(( "Font '%s' not found in library\n", font->nameString.str() ));
return;
} // end if
// scan for the font pointing to the one we're going to unlink
for( other = m_fontList; other; other = other->next )
if( other->next == font )
break;
//
// if nothing was fount this was at the head of the list, otherwise
// remove from chain
//
if( other == NULL )
m_fontList = font->next;
else
other->next = font->next;
// clean up this font we just unlinked just to be cool!
font->next = NULL;
// we now have one less font on the list
m_count--;
} // end unlinkFont
//-------------------------------------------------------------------------------------------------
/** Delete all font data, DO NOT throw an exception ... the destructor uses this */
//-------------------------------------------------------------------------------------------------
void FontLibrary::deleteAllFonts( void )
{
GameFont *font;
// release all the fonts
while( m_fontList )
{
// get temp pointer to this font
font = m_fontList;
// remove font fron the list, this will change m_fontList
unlinkFont( font );
// release font data
releaseFontData( font );
// delete the font list element
font->deleteInstance();
} // end while
} // deleteAllFonts
///////////////////////////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
FontLibrary::FontLibrary( void )
{
m_fontList = NULL;
m_count = 0;
} // end FontLibrary
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
FontLibrary::~FontLibrary( void )
{
// delete all font data
deleteAllFonts();
} // end ~FontLibrary
//-------------------------------------------------------------------------------------------------
/** Initialize what we need to in the font library */
//-------------------------------------------------------------------------------------------------
void FontLibrary::init( void )
{
} // end init
//-------------------------------------------------------------------------------------------------
/** Reset the fonts for this font library */
//-------------------------------------------------------------------------------------------------
void FontLibrary::reset( void )
{
// delete all font data
deleteAllFonts();
} // end reset
//-------------------------------------------------------------------------------------------------
/** Get a font from our list, if we don't have that font loaded we will
* attempt to load it */
//-------------------------------------------------------------------------------------------------
GameFont *FontLibrary::getFont( AsciiString name, Int pointSize, Bool bold )
{
GameFont *font;
// search for font in list
for( font = m_fontList; font; font = font->next )
{
if( font->pointSize == pointSize &&
font->bold == bold &&
font->nameString == name
)
return font; // found
} // end for font
// font not found, allocate a new font element
font = newInstance(GameFont);
if( font == NULL )
{
DEBUG_CRASH(( "getFont: Unable to allocate new font list element\n" ));
return NULL;
} // end if
// copy font data over to new element
font->nameString = name;
font->pointSize = pointSize;
font->bold = bold;
font->fontData = NULL;
//DEBUG_LOG(("Font: Loading font '%s' %d point\n", font->nameString.str(), font->pointSize));
// load the device specific data pointer
if( loadFontData( font ) == FALSE )
{
DEBUG_CRASH(( "getFont: Unable to load font data pointer '%s'\n", name ));
font->deleteInstance();
return NULL;
} // end if
// tie font into list
linkFont( font );
// all is done and loaded
return font;
} // end getFont

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,238 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: GameWindowGlobal.cpp /////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Westwood Studios Pacific.
//
// Confidential Information
// Copyright (C) 2001 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// Project: RTS3
//
// File name: GameWindowGlobal.cpp
//
// Created: Colin Day, June 2001
//
// Desc: These are some global functions that every game using this
// window system must implement for their current technology
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
// USER INCLUDES //////////////////////////////////////////////////////////////
#include "Common/Language.h"
#include "GameClient/Image.h"
#include "GameClient/Display.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/GameFont.h"
// DEFINES ////////////////////////////////////////////////////////////////////
// PRIVATE TYPES //////////////////////////////////////////////////////////////
// PRIVATE DATA ///////////////////////////////////////////////////////////////
// PUBLIC DATA ////////////////////////////////////////////////////////////////
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// GameWindowManager::winDrawImage ============================================
/** draw image, coord are in screen and should be kepth within
* that box specified */
//=============================================================================
void GameWindowManager::winDrawImage( const Image *image, Int startX, Int startY,
Int endX, Int endY, Color color )
{
TheDisplay->drawImage( image, startX, startY, endX, endY, color );
} // end WinDrawImage
// GameWindowManager::winFillRect =============================================
/** draw filled rect, coords are absolute screen coords */
//=============================================================================
void GameWindowManager::winFillRect( Color color, Real width,
Int startX, Int startY,
Int endX, Int endY )
{
TheDisplay->drawFillRect( startX, startY,
endX - startX, endY - startY,
color );
} // end WinFillRect
// GameWindowManager::winOpenRect =============================================
/** draw rect outline, coords are absolute screen coords */
//=============================================================================
void GameWindowManager::winOpenRect( Color color, Real width,
Int startX, Int startY,
Int endX, Int endY )
{
TheDisplay->drawOpenRect( startX, startY,
endX - startX, endY - startY,
width, color );
} // end WinOpenRect
// GameWindowManager::winDrawLine =============================================
/** draw line, coords are absolute screen coords */
//=============================================================================
void GameWindowManager::winDrawLine( Color color, Real width,
Int startX, Int startY,
Int endX, Int endY )
{
TheDisplay->drawLine( startX, startY, endX, endY, width, color );
} // end WinDrawLine
// GameWindowManager::winFindImage ============================================
/** Given an image name, return an image loc to that image information.
* You may reorganize the image loc structure however you like to suit
* your individual project */
//=============================================================================
const Image *GameWindowManager::winFindImage( const char *name )
{
assert( TheMappedImageCollection );
if( TheMappedImageCollection )
return TheMappedImageCollection->findImageByName( AsciiString( name ) );
return NULL;
} // end WinFindImage
// GameWindowManager::winMakeColor ============================================
/** Given RGBA, make a color, you can change color representation for your
* individual project needs */
//=============================================================================
Color GameWindowManager::winMakeColor( UnsignedByte red,
UnsignedByte green,
UnsignedByte blue,
UnsignedByte alpha )
{
return GameMakeColor( red, green, blue, alpha );
} // end WinMakeColor
// GameWindowManager::winFormatText ===========================================
/** draw text to the screen */
//=============================================================================
void GameWindowManager::winFormatText( GameFont *font, UnicodeString text, Color color,
Int x, Int y, Int width, Int height )
{
/// @todo make all display string rendering go through here!
} // end WinFormatText
// GameWindowManager::winGetTextSize ==========================================
/** get the extent size of text */
//=============================================================================
void GameWindowManager::winGetTextSize( GameFont *font, UnicodeString text,
Int *width, Int *height, Int maxWidth )
{
/// @todo make display string size stuff go through here
if( width )
*width = 0;
if( height )
*height = 0;
} // end WinGetTextSize
// GameWindowManager::winFontHeight ===========================================
/** Return the font height in pixels */
//=============================================================================
Int GameWindowManager::winFontHeight( GameFont *font )
{
return font->height;
} // end WinFontHeight
// GameWindowManager::winIsDigit ==============================================
/** You implementation of whether or not character is a digit */
//=============================================================================
Int GameWindowManager::winIsDigit( Int c )
{
return GameIsDigit( c );
} // end WinIsDigit
// GameWindowManager::winIsAscii ==============================================
/** You implementation of whether or not character is ascii */
//=============================================================================
Int GameWindowManager::winIsAscii( Int c )
{
return GameIsAscii( c );
} // end WinIsDigit
// GameWindowManager::winIsAlNum ==============================================
/** Your implementation of whether or not character is alpha numeric */
//=============================================================================
Int GameWindowManager::winIsAlNum( Int c )
{
return GameIsAlNum( c );
} // end WinIsAlNum
// GameWindowManager::winFindFont =============================================
/** Get a font */
//=============================================================================
GameFont *GameWindowManager::winFindFont( AsciiString fontName,
Int pointSize,
Bool bold )
{
assert( TheFontLibrary );
if( TheFontLibrary )
return TheFontLibrary->getFont( fontName, pointSize, bold );
return NULL;
} // end WinFindFont

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,576 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: GameWindowTransitions.cpp /////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Electronic Arts Pacific.
//
// Confidential Information
// Copyright (C) 2002 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// created: Dec 2002
//
// Filename: GameWindowTransitions.cpp
//
// author: Chris Huybregts
//
// purpose:
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
//-----------------------------------------------------------------------------
// USER INCLUDES //////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
#include "Gamelogic/GameLogic.h"
#include "GameClient/GameWindowTransitions.h"
#include "GameClient/GameWindow.h"
#include "GameClient/GameWindowManager.h"
//-----------------------------------------------------------------------------
// DEFINES ////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
GameWindowTransitionsHandler *TheTransitionHandler = NULL;
const FieldParse GameWindowTransitionsHandler::m_gameWindowTransitionsFieldParseTable[] =
{
{ "Window", GameWindowTransitionsHandler::parseWindow, NULL, NULL },
{ "FireOnce", INI::parseBool, NULL, offsetof( TransitionGroup, m_fireOnce) },
{ NULL, NULL, NULL, 0 } // keep this last
};
void INI::parseWindowTransitions( INI* ini )
{
AsciiString name;
TransitionGroup *g;
// read the name
const char* c = ini->getNextToken();
name.set( c );
// find existing item if present
DEBUG_ASSERTCRASH( TheTransitionHandler, ("parseWindowTransitions: TheTransitionHandler doesn't exist yet\n") );
if( !TheTransitionHandler )
return;
// If we have a previously allocated control bar, this will return a cleared out pointer to it so we
// can overwrite it
g = TheTransitionHandler->getNewGroup( name );
// sanity
DEBUG_ASSERTCRASH( g, ("parseWindowTransitions: Unable to allocate group '%s'\n", name.str()) );
// parse the ini definition
ini->initFromINI( g, TheTransitionHandler->getFieldParse() );
}
//-----------------------------------------------------------------------------
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
Transition *getTransitionForStyle( Int style )
{
switch (style) {
case TRANSITION_FLASH:
return NEW FlashTransition;
case BUTTON_TRANSITION_FLASH:
return NEW ButtonFlashTransition;
case WIN_FADE_TRANSITION:
return NEW FadeTransition;
case WIN_SCALE_UP_TRANSITION:
return NEW ScaleUpTransition;
case MAINMENU_SCALE_UP_TRANSITION:
return NEW MainMenuScaleUpTransition;
case TEXT_TYPE_TRANSITION:
return NEW TextTypeTransition;
case SCREEN_FADE_TRANSITION:
return NEW ScreenFadeTransition;
case COUNT_UP_TRANSITION:
return NEW CountUpTransition;
case FULL_FADE_TRANSITION:
return NEW FullFadeTransition;
case TEXT_ON_FRAME_TRANSITION:
return NEW TextOnFrameTransition;
case REVERSE_SOUND_TRANSITION:
return NEW ReverseSoundTransition;
case MAINMENU_MEDIUM_SCALE_UP_TRANSITION:
return NEW MainMenuMediumScaleUpTransition;
case MAINMENU_SMALL_SCALE_DOWN_TRANSITION:
return NEW MainMenuSmallScaleDownTransition;
case CONTROL_BAR_ARROW_TRANSITION:
return NEW ControlBarArrowTransition;
case SCORE_SCALE_UP_TRANSITION:
return NEW ScoreScaleUpTransition;
default:
DEBUG_ASSERTCRASH(FALSE, ("getTransitionForStyle:: An invalid style was passed in. Style = %d", style));
return NULL;
}
return NULL;
}
TransitionWindow::TransitionWindow( void )
{
m_currentFrameDelay = m_frameDelay = 0;
m_style = 0;
m_winID = NAMEKEY_INVALID;
m_win = NULL;
m_transition = NULL;
}
TransitionWindow::~TransitionWindow( void )
{
m_win = NULL;
if(m_transition)
delete m_transition;
m_transition = NULL;
}
Bool TransitionWindow::init( void )
{
m_winID = TheNameKeyGenerator->nameToKey(m_winName);
m_win = TheWindowManager->winGetWindowFromId(NULL, m_winID);
m_currentFrameDelay = m_frameDelay;
// DEBUG_ASSERTCRASH( m_win, ("TransitionWindow::init Failed to find window %s", m_winName.str()));
// if( !m_win )
// return FALSE;
if(m_transition)
delete m_transition;
m_transition = getTransitionForStyle( m_style );
m_transition->init(m_win);
return TRUE;
}
void TransitionWindow::update( Int frame )
{
if(frame < m_currentFrameDelay || frame > (m_currentFrameDelay + m_transition->getFrameLength()))
return;
if(m_transition)
m_transition->update( frame - m_currentFrameDelay);
}
Bool TransitionWindow::isFinished( void )
{
if(m_transition)
return m_transition->isFinished();
return TRUE;
}
void TransitionWindow::reverse( Int totalFrames )
{
//m_currentFrameDelay = totalFrames - (m_transition->getFrameLength() + m_frameDelay);
if(m_transition)
m_transition->reverse();
}
void TransitionWindow::skip( void )
{
if(m_transition)
m_transition->skip();
}
void TransitionWindow::draw( void )
{
if(m_transition)
m_transition->draw();
}
Int TransitionWindow::getTotalFrames( void )
{
if(m_transition)
{
return m_frameDelay + m_transition->getFrameLength();
}
return m_frameDelay;
}
//-----------------------------------------------------------------------------
TransitionGroup::TransitionGroup( void )
{
m_currentFrame = 0;
m_fireOnce = FALSE;
}
TransitionGroup::~TransitionGroup( void )
{
TransitionWindowList::iterator it = m_transitionWindowList.begin();
while (it != m_transitionWindowList.end())
{
TransitionWindow *tWin = *it;
delete tWin;
tWin = NULL;
it = m_transitionWindowList.erase(it);
}
}
void TransitionGroup::init( void )
{
m_currentFrame = 0;
m_directionMultiplier = 1;
TransitionWindowList::iterator it = m_transitionWindowList.begin();
while (it != m_transitionWindowList.end())
{
TransitionWindow *tWin = *it;
tWin->init();
it++;
}
}
void TransitionGroup::update( void )
{
m_currentFrame += m_directionMultiplier; // we go forward or backwards depending.
TransitionWindowList::iterator it = m_transitionWindowList.begin();
while (it != m_transitionWindowList.end())
{
TransitionWindow *tWin = *it;
tWin->update(m_currentFrame);
it++;
}
}
Bool TransitionGroup::isFinished( void )
{
TransitionWindowList::iterator it = m_transitionWindowList.begin();
while (it != m_transitionWindowList.end())
{
TransitionWindow *tWin = *it;
if(tWin->isFinished() == FALSE)
return FALSE;
it++;
}
return TRUE;
}
void TransitionGroup::reverse( void )
{
Int totalFrames =0;
m_directionMultiplier = -1;
TransitionWindowList::iterator it = m_transitionWindowList.begin();
while (it != m_transitionWindowList.end())
{
TransitionWindow *tWin = *it;
Int winFrames = tWin->getTotalFrames();
if(winFrames > totalFrames)
totalFrames = winFrames;
it++;
}
it = m_transitionWindowList.begin();
while (it != m_transitionWindowList.end())
{
TransitionWindow *tWin = *it;
tWin->reverse(totalFrames);
it++;
}
m_currentFrame = totalFrames;
// m_currentFrame ++;
}
Bool TransitionGroup::isReversed( void )
{
if(m_directionMultiplier < 0)
return TRUE;
return FALSE;
}
void TransitionGroup::skip ( void )
{
TransitionWindowList::iterator it = m_transitionWindowList.begin();
while (it != m_transitionWindowList.end())
{
TransitionWindow *tWin = *it;
tWin->skip();
it++;
}
}
void TransitionGroup::draw ( void )
{
TransitionWindowList::iterator it = m_transitionWindowList.begin();
while (it != m_transitionWindowList.end())
{
TransitionWindow *tWin = *it;
tWin->draw();
it++;
}
}
void TransitionGroup::addWindow( TransitionWindow *transWin )
{
if(!transWin)
return;
m_transitionWindowList.push_back(transWin);
}
//-----------------------------------------------------------------------------
GameWindowTransitionsHandler::GameWindowTransitionsHandler(void)
{
m_currentGroup = NULL;
m_pendingGroup = NULL;
m_drawGroup = NULL;
m_secondaryDrawGroup = NULL;
}
GameWindowTransitionsHandler::~GameWindowTransitionsHandler( void )
{
m_currentGroup = NULL;
m_pendingGroup = NULL;
m_drawGroup = NULL;
m_secondaryDrawGroup = NULL;
TransitionGroupList::iterator it = m_transitionGroupList.begin();
while( it != m_transitionGroupList.end() )
{
TransitionGroup *g = *it;
delete g;
it = m_transitionGroupList.erase(it);
}
}
void GameWindowTransitionsHandler::init(void )
{
m_currentGroup = NULL;
m_pendingGroup = NULL;
m_drawGroup = NULL;
m_secondaryDrawGroup = NULL;
}
void GameWindowTransitionsHandler::load(void )
{
INI ini;
// Read from INI all the ControlBarSchemes
ini.load( AsciiString( "Data\\INI\\WindowTransitions.ini" ), INI_LOAD_OVERWRITE, NULL );
}
void GameWindowTransitionsHandler::reset( void )
{
m_currentGroup = NULL;
m_pendingGroup = NULL;
m_drawGroup = NULL;
m_secondaryDrawGroup = NULL;
}
void GameWindowTransitionsHandler::update( void )
{
if(m_drawGroup != m_currentGroup)
m_secondaryDrawGroup = m_drawGroup;
else
m_secondaryDrawGroup = NULL;
m_drawGroup = m_currentGroup;
if(m_currentGroup && !m_currentGroup->isFinished())
m_currentGroup->update();
if(m_currentGroup && m_currentGroup->isFinished() && m_currentGroup->isFireOnce())
{
m_currentGroup = NULL;
}
if(m_currentGroup && m_pendingGroup && m_currentGroup->isFinished())
{
m_currentGroup = m_pendingGroup;
m_pendingGroup = NULL;
}
if(!m_currentGroup && m_pendingGroup)
{
m_currentGroup = m_pendingGroup;
m_pendingGroup = NULL;
}
if(m_currentGroup && m_currentGroup->isFinished() && m_currentGroup->isReversed())
m_currentGroup = NULL;
}
void GameWindowTransitionsHandler::draw( void )
{
// if( TheGameLogic->getFrame() > 0 )//if( areTransitionsEnabled() ) //KRIS
if(m_drawGroup)
m_drawGroup->draw();
if(m_secondaryDrawGroup)
m_secondaryDrawGroup->draw();
}
void GameWindowTransitionsHandler::setGroup(AsciiString groupName, Bool immidiate )
{
if(groupName.isEmpty() && immidiate)
m_currentGroup = NULL;
if(immidiate && m_currentGroup)
{
m_currentGroup->skip();
m_currentGroup = findGroup(groupName);
if(m_currentGroup)
m_currentGroup->init();
return;
}
if(m_currentGroup)
{
if(!m_currentGroup->isFireOnce() && !m_currentGroup->isReversed())
m_currentGroup->reverse();
m_pendingGroup = findGroup(groupName);
if(m_pendingGroup)
m_pendingGroup->init();
return;
}
m_currentGroup = findGroup(groupName);
if(m_currentGroup)
m_currentGroup->init();
}
void GameWindowTransitionsHandler::reverse( AsciiString groupName )
{
TransitionGroup *g = findGroup(groupName);
if( m_currentGroup == g )
{
m_currentGroup->reverse();
return;
}
if( m_pendingGroup == g)
{
m_pendingGroup = NULL;
return;
}
if(m_currentGroup)
m_currentGroup->skip();
if(m_pendingGroup)
m_pendingGroup->skip();
m_currentGroup = g;
m_currentGroup->init();
m_currentGroup->skip();
m_currentGroup->reverse();
m_pendingGroup = NULL;
}
void GameWindowTransitionsHandler::remove( AsciiString groupName, Bool skipPending )
{
TransitionGroup *g = findGroup(groupName);
if(m_pendingGroup == g)
{
if(skipPending)
m_pendingGroup->skip();
m_pendingGroup = NULL;
}
if(m_currentGroup == g)
{
m_currentGroup->skip();
m_currentGroup = NULL;
if(m_pendingGroup)
m_currentGroup = m_pendingGroup;
}
}
TransitionGroup *GameWindowTransitionsHandler::getNewGroup( AsciiString name )
{
if(name.isEmpty())
return NULL;
// test to see if we're trying to add an already exisitng group.
if(findGroup(name))
{
DEBUG_ASSERTCRASH(FALSE, ("GameWindowTransitionsHandler::getNewGroup - We already have a group %s", name.str()));
return NULL;
}
TransitionGroup *g = NEW TransitionGroup;
g->setName(name);
m_transitionGroupList.push_back(g);
return g;
}
Bool GameWindowTransitionsHandler::isFinished( void )
{
if(m_currentGroup)
return m_currentGroup->isFinished();
return TRUE;
}
//-----------------------------------------------------------------------------
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
TransitionGroup *GameWindowTransitionsHandler::findGroup( AsciiString groupName )
{
if(groupName.isEmpty())
return NULL;
TransitionGroupList::iterator it = m_transitionGroupList.begin();
while( it != m_transitionGroupList.end() )
{
TransitionGroup *g = *it;
if(groupName.compareNoCase(g->getName()) == 0)
return g;
it++;
}
return NULL;
}
void GameWindowTransitionsHandler::parseWindow( INI* ini, void *instance, void *store, const void *userData )
{
static const FieldParse myFieldParse[] =
{
{ "WinName", INI::parseAsciiString, NULL, offsetof( TransitionWindow, m_winName ) },
{ "Style", INI::parseLookupList, TransitionStyleNames, offsetof( TransitionWindow, m_style ) },
{ "FrameDelay", INI::parseInt, NULL, offsetof( TransitionWindow, m_frameDelay ) },
{ NULL, NULL, NULL, 0 } // keep this last
};
TransitionWindow *transWin = NEW TransitionWindow;
ini->initFromINI(transWin, myFieldParse);
((TransitionGroup*)instance)->addWindow(transWin);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,250 @@
/*
** 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 <http://www.gnu.org/licenses/>.
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: HeaderTemplate.cpp /////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Electronic Arts Pacific.
//
// Confidential Information
// Copyright (C) 2002 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// created: Aug 2002
//
// Filename: HeaderTemplate.cpp
//
// author: Chris Huybregts
//
// purpose: The header template system is used to maintain a unified look across
// windows. It also allows Localization to customize the looks based
// on language fonts.
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// USER INCLUDES //////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
#include "PreRTS.h"
#include "Common/INI.h"
#include "Common/Filesystem.h"
#include "Common/Registry.h"
#include "GameClient/HeaderTemplate.h"
#include "GameClient/GameFont.h"
#include "GameClient/GlobalLanguage.h"
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
//-----------------------------------------------------------------------------
// DEFINES ////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
const FieldParse HeaderTemplateManager::m_headerFieldParseTable[] =
{
{ "Font", INI::parseQuotedAsciiString, NULL, offsetof( HeaderTemplate, m_fontName ) },
{ "Point", INI::parseInt, NULL, offsetof( HeaderTemplate, m_point) },
{ "Bold", INI::parseBool, NULL, offsetof( HeaderTemplate, m_bold ) },
{ NULL, NULL, NULL, 0 },
};
HeaderTemplateManager *TheHeaderTemplateManager = NULL;
//-----------------------------------------------------------------------------
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
void INI::parseHeaderTemplateDefinition( INI *ini )
{
AsciiString name;
HeaderTemplate *hTemplate;
// read the name
const char* c = ini->getNextToken();
name.set( c );
// find existing item if present
hTemplate = TheHeaderTemplateManager->findHeaderTemplate( name );
if( hTemplate == NULL )
{
// allocate a new item
hTemplate = TheHeaderTemplateManager->newHeaderTemplate( name );
} // end if
else
{
DEBUG_CRASH(( "[LINE: %d in '%s'] Duplicate header Template %s found!", ini->getLineNum(), ini->getFilename().str(), name.str() ));
}
// parse the ini definition
ini->initFromINI( hTemplate, TheHeaderTemplateManager->getFieldParse() );
} // end parseCommandButtonDefinition
HeaderTemplate::HeaderTemplate( void ) :
m_font(NULL),
m_point(0),
m_bold(FALSE)
{
//Added By Sadullah Nader
//Initializations missing and needed
m_fontName.clear();
m_name.clear();
}
HeaderTemplate::~HeaderTemplate( void ){}
HeaderTemplateManager::HeaderTemplateManager( void )
{}
HeaderTemplateManager::~HeaderTemplateManager( void )
{
HeaderTemplateListIt it = m_headerTemplateList.begin();
while(it != m_headerTemplateList.end())
{
HeaderTemplate *hTemplate = *it;
if(hTemplate)
{
hTemplate->m_font = NULL;
delete hTemplate;
}
it = m_headerTemplateList.erase(it);
}
}
void HeaderTemplateManager::init( void )
{
INI ini;
AsciiString fname;
fname.format("Data\\%s\\HeaderTemplate.ini", GetRegistryLanguage().str());
OSVERSIONINFO osvi;
osvi.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
if (GetVersionEx(&osvi))
{ //check if we're running Win9x variant since they may need different fonts
if (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
{ AsciiString tempName;
tempName.format("Data\\%s\\HeaderTemplate9x.ini", GetRegistryLanguage().str());
if (TheFileSystem->doesFileExist(tempName.str()))
fname = tempName;
}
}
ini.load( fname, INI_LOAD_OVERWRITE, NULL );
populateGameFonts();
}
HeaderTemplate *HeaderTemplateManager::findHeaderTemplate( AsciiString name )
{
HeaderTemplateListIt it = m_headerTemplateList.begin();
while(it != m_headerTemplateList.end())
{
HeaderTemplate *hTemplate = *it;
if(hTemplate->m_name.compare(name) == 0)
return hTemplate;
++it;
}
return NULL;
}
HeaderTemplate *HeaderTemplateManager::newHeaderTemplate( AsciiString name )
{
HeaderTemplate *newHTemplate = NEW HeaderTemplate;
DEBUG_ASSERTCRASH(newHTemplate, ("Unable to create a new Header Template in HeaderTemplateManager::newHeaderTemplate"));
if(!newHTemplate)
return NULL;
newHTemplate->m_name = name;
m_headerTemplateList.push_front(newHTemplate);
return newHTemplate;
}
GameFont *HeaderTemplateManager::getFontFromTemplate( AsciiString name )
{
HeaderTemplate *ht = findHeaderTemplate( name );
if(!ht)
{
//DEBUG_LOG(("HeaderTemplateManager::getFontFromTemplate - Could not find header %s\n", name.str()));
return NULL;
}
return ht->m_font;
}
HeaderTemplate *HeaderTemplateManager::getFirstHeader( void )
{
HeaderTemplateListIt it = m_headerTemplateList.begin();
if( it == m_headerTemplateList.end())
return NULL;
return *it;
}
HeaderTemplate *HeaderTemplateManager::getNextHeader( HeaderTemplate *ht )
{
HeaderTemplateListIt it = m_headerTemplateList.begin();
while(it != m_headerTemplateList.end())
{
if(*it == ht)
{
++it;
if( it == m_headerTemplateList.end())
return NULL;
return *it;
}
++it;
}
return NULL;
}
void HeaderTemplateManager::headerNotifyResolutionChange( void )
{
populateGameFonts();
}
//-----------------------------------------------------------------------------
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
void HeaderTemplateManager::populateGameFonts( void )
{
HeaderTemplateListIt it = m_headerTemplateList.begin();
while(it != m_headerTemplateList.end())
{
HeaderTemplate *hTemplate = *it;
Real pointSize = TheGlobalLanguageData->adjustFontSize(hTemplate->m_point);
GameFont *font = TheFontLibrary->getFont(hTemplate->m_fontName, pointSize,hTemplate->m_bold);
DEBUG_ASSERTCRASH(font,("HeaderTemplateManager::populateGameFonts - Could not find font %s %d",hTemplate->m_fontName, hTemplate->m_point));
hTemplate->m_font = font;
++it;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More