Credits.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: Credits.cpp /////////////////////////////////////////////////
  24. //-----------------------------------------------------------------------------
  25. //
  26. // Electronic Arts Pacific.
  27. //
  28. // Confidential Information
  29. // Copyright (C) 2002 - All Rights Reserved
  30. //
  31. //-----------------------------------------------------------------------------
  32. //
  33. // created: Dec 2002
  34. //
  35. // Filename: Credits.cpp
  36. //
  37. // author: Chris Huybregts
  38. //
  39. // purpose: This is where all the credit texts is going to be held.
  40. //
  41. //-----------------------------------------------------------------------------
  42. ///////////////////////////////////////////////////////////////////////////////
  43. //-----------------------------------------------------------------------------
  44. // SYSTEM INCLUDES ////////////////////////////////////////////////////////////
  45. //-----------------------------------------------------------------------------
  46. #include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine
  47. //-----------------------------------------------------------------------------
  48. // USER INCLUDES //////////////////////////////////////////////////////////////
  49. //-----------------------------------------------------------------------------
  50. #include "Common/INI.h"
  51. #include "GameClient/Credits.h"
  52. #include "GameClient/DisplayStringManager.h"
  53. #include "GameClient/Display.h"
  54. #include "GameClient/GameText.h"
  55. #include "GameClient/GlobalLanguage.h"
  56. #ifdef _INTERNAL
  57. // for occasional debugging...
  58. //#pragma optimize("", off)
  59. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  60. #endif
  61. //-----------------------------------------------------------------------------
  62. // DEFINES ////////////////////////////////////////////////////////////////////
  63. //-----------------------------------------------------------------------------
  64. CreditsManager *TheCredits = NULL;
  65. const FieldParse CreditsManager::m_creditsFieldParseTable[] =
  66. {
  67. { "ScrollRate", INI::parseInt, NULL, offsetof( CreditsManager, m_scrollRate ) },
  68. { "ScrollRateEveryFrames", INI::parseInt, NULL, offsetof( CreditsManager, m_scrollRatePerFrames ) },
  69. { "ScrollDown", INI::parseBool, NULL, offsetof( CreditsManager, m_scrollDown ) },
  70. { "TitleColor", INI::parseColorInt, NULL, offsetof( CreditsManager, m_titleColor ) },
  71. { "MinorTitleColor", INI::parseColorInt, NULL, offsetof( CreditsManager, m_positionColor ) },
  72. { "NormalColor", INI::parseColorInt, NULL, offsetof( CreditsManager, m_normalColor ) },
  73. { "Style", INI::parseLookupList, CreditStyleNames, offsetof( CreditsManager, m_currentStyle ) },
  74. { "Blank", CreditsManager::parseBlank, NULL, NULL },
  75. { "Text", CreditsManager::parseText, NULL, NULL },
  76. { NULL, NULL, NULL, 0 } // keep this last
  77. };
  78. //-----------------------------------------------------------------------------
  79. // PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
  80. //-----------------------------------------------------------------------------
  81. void INI::parseCredits( INI *ini )
  82. {
  83. // find existing item if present
  84. DEBUG_ASSERTCRASH( TheCredits, ("parseCredits: TheCredits has not been ininialized yet.\n") );
  85. if( !TheCredits )
  86. return;
  87. // parse the ini definition
  88. ini->initFromINI( TheCredits, TheCredits->getFieldParse() );
  89. } // end parseCommandButtonDefinition
  90. CreditsLine::CreditsLine()
  91. {
  92. m_useSecond = FALSE;
  93. m_done = FALSE;
  94. m_style = CREDIT_STYLE_BLANK;
  95. m_displayString = NULL;
  96. m_secondDisplayString = NULL;
  97. }
  98. CreditsLine::~CreditsLine()
  99. {
  100. if(m_displayString)
  101. TheDisplayStringManager->freeDisplayString(m_displayString);
  102. if(m_secondDisplayString)
  103. TheDisplayStringManager->freeDisplayString(m_secondDisplayString);
  104. m_displayString = NULL;
  105. m_secondDisplayString = NULL;
  106. }
  107. CreditsManager::CreditsManager(void)
  108. {
  109. m_scrollRate = 1; // in pixels
  110. m_scrollRatePerFrames = 1;
  111. m_scrollDown = TRUE; // if TRUE text will come from the top to the bottom if False, it will go from the bottom up
  112. m_framesSinceStarted = 0;
  113. m_titleColor = m_positionColor = m_normalColor = GameMakeColor(255,255,255,255);
  114. m_currentStyle = CREDIT_STYLE_NORMAL;
  115. m_isFinished = FALSE;
  116. m_normalFontHeight = 10;
  117. }
  118. CreditsManager::~CreditsManager(void)
  119. {
  120. m_displayedCreditLineList.clear();
  121. CreditsLineList::iterator it =m_creditLineList.begin();
  122. while (it != m_creditLineList.end())
  123. {
  124. CreditsLine *cLine = *it;
  125. delete cLine;
  126. it = m_creditLineList.erase(it);
  127. }
  128. }
  129. void CreditsManager::init(void )
  130. {
  131. m_isFinished = FALSE;
  132. m_creditLineListIt = m_creditLineList.begin();
  133. m_framesSinceStarted = 0;
  134. }
  135. void CreditsManager::load(void )
  136. {
  137. INI ini;
  138. // Read from INI all the ControlBarSchemes
  139. ini.load( AsciiString( "Data\\INI\\Credits.ini" ), INI_LOAD_OVERWRITE, NULL );
  140. if(m_scrollRatePerFrames <=0)
  141. m_scrollRatePerFrames = 1;
  142. if(m_scrollRate <=0)
  143. m_scrollRate = 1;
  144. GameFont *font = TheFontLibrary->getFont(TheGlobalLanguageData->m_creditsNormalFont.name,
  145. TheGlobalLanguageData->adjustFontSize(TheGlobalLanguageData->m_creditsNormalFont.size),
  146. TheGlobalLanguageData->m_creditsNormalFont.bold);
  147. m_normalFontHeight = font->height;
  148. }
  149. void CreditsManager::reset( void )
  150. {
  151. m_displayedCreditLineList.clear();
  152. m_isFinished = FALSE;
  153. m_creditLineListIt = m_creditLineList.begin();
  154. m_framesSinceStarted = 0;
  155. }
  156. void CreditsManager::update( void )
  157. {
  158. if(m_isFinished)
  159. return;
  160. m_framesSinceStarted++;
  161. if(m_framesSinceStarted%m_scrollRatePerFrames != 0)
  162. return;
  163. Int y = 0;
  164. Int yTest = 0;
  165. Int lastHeight = 0;
  166. Int start = m_scrollDown? 0:TheDisplay->getHeight();
  167. Int end =m_scrollDown? TheDisplay->getHeight():0;
  168. Int offsetStartMultiplyer = m_scrollDown? -1:0; // if we're scrolling from the top, we need to subtract the height
  169. Int offsetEndMultiplyer = m_scrollDown? 0:1;
  170. Int directionMultiplyer = m_scrollDown? 1:-1;
  171. CreditsLineList::iterator drawIt = m_displayedCreditLineList.begin();
  172. while (drawIt != m_displayedCreditLineList.end())
  173. {
  174. CreditsLine *cLine = *drawIt;
  175. y = cLine->m_pos.y = cLine->m_pos.y + (m_scrollRate * directionMultiplyer);
  176. lastHeight = cLine->m_height;
  177. yTest = y + ((lastHeight + CREDIT_SPACE_OFFSET) * offsetEndMultiplyer);
  178. if(((m_scrollDown && (yTest > end)) || (!m_scrollDown && (yTest < end))))
  179. {
  180. TheDisplayStringManager->freeDisplayString(cLine->m_displayString);
  181. TheDisplayStringManager->freeDisplayString(cLine->m_secondDisplayString);
  182. cLine->m_displayString = NULL;
  183. cLine->m_secondDisplayString = NULL;
  184. drawIt = m_displayedCreditLineList.erase(drawIt);
  185. }
  186. else
  187. drawIt++;
  188. }
  189. y= y + ((lastHeight + CREDIT_SPACE_OFFSET) * offsetStartMultiplyer);
  190. // is it time to add a new string?
  191. if(!((m_scrollDown && (yTest >= start)) || (!m_scrollDown && (yTest <= start))))
  192. return;
  193. if(m_displayedCreditLineList.size() == 0 && m_creditLineListIt == m_creditLineList.end())
  194. m_isFinished = TRUE;
  195. if(m_creditLineListIt == m_creditLineList.end())
  196. return;
  197. CreditsLine *cLine = *m_creditLineListIt;
  198. ICoord2D pos;
  199. switch (cLine->m_style)
  200. {
  201. case CREDIT_STYLE_TITLE:
  202. {
  203. cLine->m_color = m_titleColor;
  204. if(TheGlobalLanguageData&& !cLine->m_text.isEmpty())
  205. {
  206. DisplayString *ds = TheDisplayStringManager->newDisplayString();
  207. if(!ds)
  208. return;
  209. ds->setFont(TheFontLibrary->getFont(TheGlobalLanguageData->m_creditsTitleFont.name,
  210. TheGlobalLanguageData->adjustFontSize(TheGlobalLanguageData->m_creditsTitleFont.size),
  211. TheGlobalLanguageData->m_creditsTitleFont.bold));
  212. ds->setText(cLine->m_text);
  213. ds->getSize(&pos.x,&pos.y);
  214. cLine->m_height = pos.y;
  215. cLine->m_pos.x = TheDisplay->getWidth()/2 - pos.x/2 ;
  216. cLine->m_pos.y = start + (cLine->m_height * offsetStartMultiplyer);
  217. cLine->m_displayString = ds;
  218. }
  219. }
  220. break;
  221. case CREDIT_STYLE_POSITION:
  222. {
  223. cLine->m_color = m_positionColor;
  224. if(TheGlobalLanguageData && !cLine->m_text.isEmpty())
  225. {
  226. DisplayString *ds = TheDisplayStringManager->newDisplayString();
  227. if(!ds)
  228. return;
  229. ds->setFont(TheFontLibrary->getFont(TheGlobalLanguageData->m_creditsPositionFont.name,
  230. TheGlobalLanguageData->adjustFontSize(TheGlobalLanguageData->m_creditsPositionFont.size),
  231. TheGlobalLanguageData->m_creditsPositionFont.bold));
  232. ds->setText(cLine->m_text);
  233. ds->getSize(&pos.x,&pos.y);
  234. cLine->m_height = pos.y;
  235. cLine->m_pos.x = TheDisplay->getWidth()/2 - pos.x/2 ;
  236. cLine->m_pos.y = start + (cLine->m_height * offsetStartMultiplyer);
  237. cLine->m_displayString = ds;
  238. }
  239. }
  240. break;
  241. case CREDIT_STYLE_NORMAL:
  242. {
  243. cLine->m_color = m_normalColor;
  244. if(TheGlobalLanguageData && !cLine->m_text.isEmpty())
  245. {
  246. DisplayString *ds = TheDisplayStringManager->newDisplayString();
  247. if(!ds)
  248. return;
  249. ds->setFont(TheFontLibrary->getFont(TheGlobalLanguageData->m_creditsNormalFont.name,
  250. TheGlobalLanguageData->adjustFontSize(TheGlobalLanguageData->m_creditsNormalFont.size),
  251. TheGlobalLanguageData->m_creditsNormalFont.bold));
  252. ds->setText(cLine->m_text);
  253. ds->getSize(&pos.x,&pos.y);
  254. cLine->m_height = pos.y;
  255. cLine->m_pos.x = TheDisplay->getWidth()/2 - pos.x/2 ;
  256. cLine->m_pos.y = start + (cLine->m_height * offsetStartMultiplyer);
  257. cLine->m_displayString = ds;
  258. }
  259. }
  260. break;
  261. case CREDIT_STYLE_COLUMN:
  262. {
  263. cLine->m_color = m_normalColor;
  264. if(TheGlobalLanguageData && !cLine->m_text.isEmpty())
  265. {
  266. DisplayString *ds = TheDisplayStringManager->newDisplayString();
  267. if(!ds)
  268. return;
  269. ds->setFont(TheFontLibrary->getFont(TheGlobalLanguageData->m_creditsNormalFont.name,
  270. TheGlobalLanguageData->adjustFontSize(TheGlobalLanguageData->m_creditsNormalFont.size),
  271. TheGlobalLanguageData->m_creditsNormalFont.bold));
  272. ds->setText(cLine->m_text);
  273. ds->getSize(&pos.x,&pos.y);
  274. cLine->m_height = pos.y;
  275. cLine->m_pos.x = TheDisplay->getWidth()/2 - pos.x/2 ;
  276. cLine->m_pos.y = start + (cLine->m_height * offsetStartMultiplyer);
  277. cLine->m_displayString = ds;
  278. }
  279. if(TheGlobalLanguageData && !cLine->m_secondText.isEmpty())
  280. {
  281. DisplayString *ds = TheDisplayStringManager->newDisplayString();
  282. if(!ds)
  283. return;
  284. ds->setFont(TheFontLibrary->getFont(TheGlobalLanguageData->m_creditsNormalFont.name,
  285. TheGlobalLanguageData->adjustFontSize(TheGlobalLanguageData->m_creditsNormalFont.size),
  286. TheGlobalLanguageData->m_creditsNormalFont.bold));
  287. ds->setText(cLine->m_secondText);
  288. ds->getSize(&pos.x,&pos.y);
  289. cLine->m_height = pos.y;
  290. cLine->m_pos.x = TheDisplay->getWidth()/2 - pos.x/2 ;
  291. cLine->m_pos.y = start + (cLine->m_height * offsetStartMultiplyer);
  292. cLine->m_secondDisplayString = ds;
  293. }
  294. }
  295. break;
  296. case CREDIT_STYLE_BLANK:
  297. {
  298. cLine->m_height = m_normalFontHeight;
  299. cLine->m_pos.y = start + (cLine->m_height * offsetStartMultiplyer);
  300. }
  301. break;
  302. }
  303. m_displayedCreditLineList.push_back(cLine);
  304. if(m_creditLineListIt != m_creditLineList.end())
  305. m_creditLineListIt++;
  306. }
  307. void CreditsManager::draw( void )
  308. {
  309. CreditsLineList::iterator drawIt = m_displayedCreditLineList.begin();
  310. while (drawIt != m_displayedCreditLineList.end())
  311. {
  312. CreditsLine *cLine = *drawIt;
  313. Int heightChunk = TheDisplay->getHeight()/3;
  314. Real perc = 0.0f;
  315. if(cLine->m_pos.y < heightChunk || cLine->m_pos.y > heightChunk * 2)
  316. {
  317. // adjust the color
  318. if( cLine->m_pos.y < 0 || cLine->m_pos.y > TheDisplay->getHeight())
  319. perc = 0.0f;
  320. else if( cLine->m_pos.y < heightChunk)
  321. perc = INT_TO_REAL(cLine->m_pos.y) / heightChunk;
  322. else
  323. perc = 1 - INT_TO_REAL(cLine->m_pos.y - 2*heightChunk) / heightChunk;
  324. }
  325. else
  326. perc = 1.0f;
  327. UnsignedByte r,g,b,a;
  328. GameGetColorComponents(cLine->m_color, &r, &g, &b, &a);
  329. Int color = GameMakeColor( r,g,b, a * perc);
  330. Int bColor= GameMakeColor( 0,0,0, a * perc);
  331. switch (cLine->m_style) {
  332. case CREDIT_STYLE_TITLE:
  333. case CREDIT_STYLE_POSITION:
  334. case CREDIT_STYLE_NORMAL:
  335. {
  336. if(cLine->m_displayString)
  337. cLine->m_displayString->draw(cLine->m_pos.x,cLine->m_pos.y,color, bColor, 1,1 );
  338. }
  339. break;
  340. case CREDIT_STYLE_COLUMN:
  341. {
  342. Int chunk = TheDisplay->getWidth()/3;
  343. ICoord2D pos;
  344. if(cLine->m_displayString)
  345. {
  346. cLine->m_displayString->getSize(&pos.x, &pos.y);
  347. cLine->m_displayString->draw(chunk - (pos.x/2),cLine->m_pos.y,color, bColor, 1,1 );
  348. }
  349. if(cLine->m_secondDisplayString)
  350. {
  351. cLine->m_secondDisplayString->getSize(&pos.x, &pos.y);
  352. cLine->m_secondDisplayString->draw(2*chunk - (pos.x/2),cLine->m_pos.y,color, bColor, 1,1 );
  353. }
  354. }
  355. break;
  356. }
  357. drawIt++;
  358. }
  359. }
  360. void CreditsManager::addBlank( void )
  361. {
  362. CreditsLine *cLine = new CreditsLine;
  363. cLine->m_style = CREDIT_STYLE_BLANK;
  364. m_creditLineList.push_back(cLine);
  365. }
  366. void CreditsManager::parseBlank( INI* ini, void *instance, void *store, const void *userData )
  367. {
  368. CreditsManager *cManager = (CreditsManager *)instance;
  369. cManager->addBlank();
  370. }
  371. void CreditsManager::parseText( INI* ini, void *instance, void *store, const void *userData )
  372. {
  373. AsciiString asciiString = ini->getNextQuotedAsciiString();
  374. CreditsManager *cManager = (CreditsManager *)instance;
  375. cManager->addText(asciiString);
  376. }
  377. void CreditsManager::addText( AsciiString text )
  378. {
  379. CreditsLine *cLine = new CreditsLine;
  380. switch (m_currentStyle)
  381. {
  382. case CREDIT_STYLE_TITLE:
  383. case CREDIT_STYLE_POSITION:
  384. case CREDIT_STYLE_NORMAL:
  385. {
  386. cLine->m_text = getUnicodeString(text);
  387. cLine->m_style = m_currentStyle;
  388. m_creditLineList.push_back(cLine);
  389. }
  390. break;
  391. case CREDIT_STYLE_COLUMN:
  392. {
  393. CreditsLineList::reverse_iterator rIt = m_creditLineList.rbegin();
  394. CreditsLine *rcLine = *rIt;
  395. if(rIt == m_creditLineList.rend() || rcLine->m_style != CREDIT_STYLE_COLUMN
  396. || (rcLine->m_style == CREDIT_STYLE_COLUMN && rcLine->m_done == TRUE))
  397. {
  398. cLine->m_text = getUnicodeString(text);
  399. cLine->m_style = CREDIT_STYLE_COLUMN;
  400. cLine->m_useSecond = TRUE;
  401. m_creditLineList.push_back(cLine);
  402. }
  403. else
  404. {
  405. rcLine->m_secondText = getUnicodeString(text);
  406. rcLine->m_done = TRUE;
  407. delete cLine;
  408. }
  409. }
  410. break;
  411. default:
  412. DEBUG_ASSERTCRASH( FALSE, ("CreditsManager::addText we tried to add a credit text with the wrong style before it. Style is %d\n", m_currentStyle) );
  413. delete cLine;
  414. }
  415. }
  416. //-----------------------------------------------------------------------------
  417. // PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
  418. //-----------------------------------------------------------------------------
  419. UnicodeString CreditsManager::getUnicodeString(AsciiString str)
  420. {
  421. UnicodeString uStr;
  422. if(str.compare("<BLANK>") == 0)
  423. return UnicodeString::TheEmptyString;
  424. if(str.find(':'))
  425. uStr = TheGameText->fetch(str);
  426. else
  427. uStr.translate(str);
  428. return uStr;
  429. }