491 lines
16 KiB
C++
491 lines
16 KiB
C++
![]() |
/*
|
||
|
** 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;
|
||
|
}
|