THEME.CPP 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  1. /*
  2. ** Command & Conquer Red Alert(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. /* $Header: /CounterStrike/THEME.CPP 3 3/11/97 4:03p Joe_bostic $ */
  19. /***********************************************************************************************
  20. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  21. ***********************************************************************************************
  22. * *
  23. * Project Name : Command & Conquer *
  24. * *
  25. * File Name : THEME.CPP *
  26. * *
  27. * Programmer : Joe L. Bostic *
  28. * *
  29. * Start Date : August 14, 1994 *
  30. * *
  31. * Last Update : August 12, 1996 [JLB] *
  32. * *
  33. *---------------------------------------------------------------------------------------------*
  34. * Functions: *
  35. * ThemeClass::AI -- Process the theme engine and restart songs. *
  36. * ThemeClass::Base_Name -- Fetches the base filename for the theme specified. *
  37. * ThemeClass::From_Name -- Determines theme number from specified name. *
  38. * ThemeClass::Full_Name -- Retrieves the full score name. *
  39. * ThemeClass::Is_Allowed -- Checks to see if the specified theme is legal. *
  40. * ThemeClass::Next_Song -- Calculates the next song number to play. *
  41. * ThemeClass::Play_Song -- Starts the specified song play NOW. *
  42. * ThemeClass::Queue_Song -- Queues the song to the play queue. *
  43. * ThemeClass::Scan -- Scans all scores for availability. *
  44. * ThemeClass::Set_Theme_Data -- Set the theme data for scenario and owner. *
  45. * ThemeClass::Still_Playing -- Determines if music is still playing. *
  46. * ThemeClass::Stop -- Stops the current theme from playing. *
  47. * ThemeClass::ThemeClass -- Default constructor for the theme manager class. *
  48. * ThemeClass::Theme_File_Name -- Constructs a filename for the specified theme. *
  49. * ThemeClass::Track_Length -- Calculates the length of the song (in seconds). *
  50. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  51. #include "function.h"
  52. #include "theme.h"
  53. #ifndef WIN32
  54. extern short StreamLowImpact;
  55. #endif //WIN32
  56. /*
  57. ** These are the actual filename list for the theme sample files.
  58. */
  59. ThemeClass::ThemeControl ThemeClass::_themes[THEME_COUNT] = {
  60. {"BIGF226M", TXT_THEME_BIGF, 0, 307, true, false, true, HOUSEF_ALLIES},
  61. {"CRUS226M", TXT_THEME_CRUS, 0, 222, true, false, true, HOUSEF_SOVIET},
  62. {"FAC1226M", TXT_THEME_FAC1, 0, 271, true, false, true, HOUSEF_ALLIES},
  63. {"FAC2226M", TXT_THEME_FAC2, 0, 328, true, false, true, HOUSEF_SOVIET},
  64. {"HELL226M", TXT_THEME_HELL, 0, 375, true, false, true, HOUSEF_ALLIES},
  65. {"RUN1226M", TXT_THEME_RUN1, 0, 312, true, false, true, HOUSEF_SOVIET},
  66. {"SMSH226M", TXT_THEME_SMSH, 0, 272, true, false, true, HOUSEF_ALLIES},
  67. {"TREN226M", TXT_THEME_TREN, 0, 312, true, false, true, HOUSEF_SOVIET},
  68. {"WORK226M", TXT_THEME_WORK, 0, 277, true, false, true, HOUSEF_ALLIES},
  69. {"AWAIT", TXT_THEME_AWAIT, 0, 259, true, false, true, HOUSEF_ALLIES},
  70. {"DENSE_R", TXT_THEME_DENSE_R, 0, 294, true, false, true, HOUSEF_ALLIES},
  71. {"FOGGER1A", TXT_THEME_FOGGER1A, 0, 297, true, false, true, HOUSEF_ALLIES},
  72. {"MUD1A", TXT_THEME_MUD1A, 0, 280, true, false, true, HOUSEF_ALLIES},
  73. {"RADIO2", TXT_THEME_RADIO2, 0, 237, true, false, true, HOUSEF_ALLIES},
  74. {"ROLLOUT", TXT_THEME_ROLLOUT, 0, 227, true, false, true, HOUSEF_ALLIES},
  75. {"SNAKE", TXT_THEME_SNAKE, 0, 277, true, false, true, HOUSEF_ALLIES},
  76. {"TERMINAT", TXT_THEME_TERMINAT, 0, 310, true, false, true, HOUSEF_ALLIES},
  77. {"TWIN", TXT_THEME_TWIN, 0, 229, true, false, true, HOUSEF_ALLIES},
  78. {"VECTOR1A", TXT_THEME_VECTOR1A, 0, 252, true, false, true, HOUSEF_ALLIES},
  79. {"MAP", TXT_THEME_MAP, 0, 63, false, true, true, HOUSEF_NONE},
  80. {"SCORE", TXT_THEME_SCORE, 0, 106, false, true, true, HOUSEF_NONE},
  81. {"INTRO", TXT_THEME_INTRO, 0, 205, false, true, true, HOUSEF_NONE},
  82. {"CREDITS", TXT_THEME_CREDITS, 0, 163, false, true, true, HOUSEF_NONE},
  83. {"2ND_HAND", TXT_THEME_2ND_HAND, 0, 268, true, false, true, HOUSEF_ALLIES|HOUSEF_SPAIN},
  84. {"ARAZOID", TXT_THEME_ARAZOID, 0, 257, true, false, true, HOUSEF_SOVIET|HOUSEF_SPAIN},
  85. {"BACKSTAB", TXT_THEME_BACKSTAB, 0, 278, true, false, true, HOUSEF_ALLIES|HOUSEF_SPAIN},
  86. {"CHAOS2", TXT_THEME_CHAOS2, 0, 250, true, false, true, HOUSEF_SOVIET|HOUSEF_SPAIN},
  87. {"SHUT_IT", TXT_THEME_SHUT_IT, 0, 261, true, false, true, HOUSEF_ALLIES|HOUSEF_SPAIN},
  88. {"TWINMIX1", TXT_THEME_TWINMIX1, 0, 222, true, false, true, HOUSEF_SOVIET|HOUSEF_SPAIN},
  89. {"UNDER3", TXT_THEME_UNDER3, 0, 246, true, false, true, HOUSEF_ALLIES|HOUSEF_SPAIN},
  90. {"VR2", TXT_THEME_VR2, 0, 255, true, false, true, HOUSEF_SOVIET|HOUSEF_SPAIN},
  91. #ifdef FIXIT_CSII // checked - ajw 9/28/98
  92. {"BOG", TXT_THEME_BOG, 0, 212, true, false, true, HOUSEF_ALLIES|HOUSEF_SPAIN},
  93. {"FLOAT_V2", TXT_THEME_FLOAT_V2, 0, 274, true, false, true, HOUSEF_SOVIET|HOUSEF_SPAIN},
  94. {"GLOOM", TXT_THEME_GLOOM, 0, 236, true, false, true, HOUSEF_ALLIES|HOUSEF_SPAIN},
  95. {"GRNDWIRE", TXT_THEME_GRNDWIRE, 0, 228, true, false, true, HOUSEF_SOVIET|HOUSEF_SPAIN},
  96. {"RPT", TXT_THEME_RPT, 0, 275, true, false, true, HOUSEF_ALLIES|HOUSEF_SPAIN},
  97. {"SEARCH", TXT_THEME_SEARCH, 0, 276, true, false, true, HOUSEF_SOVIET|HOUSEF_SPAIN},
  98. {"TRACTION", TXT_THEME_TRACTION, 0, 237, true, false, true, HOUSEF_ALLIES|HOUSEF_SPAIN},
  99. {"WASTELND", TXT_THEME_WASTELND, 0, 242, true, false, true, HOUSEF_SOVIET|HOUSEF_SPAIN},
  100. #endif
  101. };
  102. /***********************************************************************************************
  103. * ThemeClass::Base_Name -- Fetches the base filename for the theme specified. *
  104. * *
  105. * This routine is used to retrieve a pointer to the base filename for the theme *
  106. * specified. *
  107. * *
  108. * INPUT: theme -- The theme number to convert into a base filename. *
  109. * *
  110. * OUTPUT: Returns with a pointer to the base filename for the theme specified. If the *
  111. * theme number is invalid, then a pointer to "No Theme" is returned instead. *
  112. * *
  113. * WARNINGS: none *
  114. * *
  115. * HISTORY: *
  116. * 05/29/1995 JLB : Created. *
  117. *=============================================================================================*/
  118. char const * ThemeClass::Base_Name(ThemeType theme) const
  119. {
  120. if (theme != THEME_NONE) {
  121. return(_themes[theme].Name);
  122. }
  123. return("No theme");
  124. }
  125. /***********************************************************************************************
  126. * ThemeClass::ThemeClass -- Default constructor for the theme manager class. *
  127. * *
  128. * This is the default constructor for the theme class object. *
  129. * *
  130. * INPUT: none *
  131. * *
  132. * OUTPUT: none *
  133. * *
  134. * WARNINGS: none *
  135. * *
  136. * HISTORY: *
  137. * 01/16/1995 JLB : Created. *
  138. *=============================================================================================*/
  139. ThemeClass::ThemeClass(void) :
  140. Current(-1),
  141. Score(THEME_NONE),
  142. Pending(THEME_NONE)
  143. {
  144. }
  145. /***********************************************************************************************
  146. * ThemeClass::Full_Name -- Retrieves the full score name. *
  147. * *
  148. * This routine will fetch and return with a pointer to the full name of the theme *
  149. * specified. *
  150. * *
  151. * INPUT: theme -- The theme to fetch the full name for. *
  152. * *
  153. * OUTPUT: Returns with a pointer to the full name for this score. This pointer may point to *
  154. * EMS memory. *
  155. * *
  156. * WARNINGS: none *
  157. * *
  158. * HISTORY: *
  159. * 01/16/1995 JLB : Created. *
  160. *=============================================================================================*/
  161. char const * ThemeClass::Full_Name(ThemeType theme) const
  162. {
  163. if (theme >= THEME_FIRST && theme < THEME_COUNT) {
  164. return(Text_String(_themes[theme].Fullname));
  165. }
  166. return(NULL);
  167. }
  168. /***********************************************************************************************
  169. * ThemeClass::AI -- Process the theme engine and restart songs. *
  170. * *
  171. * This is a maintenance function that will restart an appropriate theme if the current one *
  172. * has finished. This routine should be called frequently. *
  173. * *
  174. * INPUT: none *
  175. * *
  176. * OUTPUT: none *
  177. * *
  178. * WARNINGS: none *
  179. * *
  180. * HISTORY: *
  181. * 09/08/1994 JLB : Created. *
  182. * 01/23/1995 JLB : Picks new song just as it is about to play it. *
  183. *=============================================================================================*/
  184. void ThemeClass::AI(void)
  185. {
  186. if (SampleType && !Debug_Quiet) {
  187. if (ScoresPresent && Options.ScoreVolume != 0 && !Still_Playing() && Pending != THEME_NONE) {
  188. /*
  189. ** If the pending song needs to be picked, then pick it now.
  190. */
  191. if (Pending == THEME_PICK_ANOTHER) {
  192. Pending = Next_Song(Score);
  193. }
  194. /*
  195. ** Start the song playing and then flag it so that a new song will
  196. ** be picked when this one ends.
  197. */
  198. Play_Song(Pending);
  199. Pending = THEME_PICK_ANOTHER;
  200. }
  201. Sound_Callback();
  202. }
  203. }
  204. /***********************************************************************************************
  205. * ThemeClass::Next_Song -- Calculates the next song number to play. *
  206. * *
  207. * use this routine to figure out what song number to play. It examines the option settings *
  208. * for repeat and shuffle so that it can return the correct value. *
  209. * *
  210. * INPUT: theme -- The origin (last) index. The new value is related to this for all but *
  211. * the shuffling method of play. *
  212. * *
  213. * OUTPUT: Returns with the song number for the next song to play. *
  214. * *
  215. * WARNINGS: none *
  216. * *
  217. * HISTORY: *
  218. * 01/16/1995 JLB : Created. *
  219. * 01/19/1995 JLB : Will not play the same song twice when in shuffle mode. *
  220. *=============================================================================================*/
  221. ThemeType ThemeClass::Next_Song(ThemeType theme) const
  222. {
  223. if (theme == THEME_NONE || theme == THEME_PICK_ANOTHER || (theme != THEME_QUIET && !_themes[theme].Repeat && !Options.IsScoreRepeat)) {
  224. if (Options.IsScoreShuffle) {
  225. /*
  226. ** Shuffle the theme, but never pick the same theme that was just
  227. ** playing.
  228. */
  229. ThemeType newtheme;
  230. do {
  231. newtheme = Sim_Random_Pick(THEME_FIRST, THEME_LAST);
  232. } while (newtheme == theme || !Is_Allowed(newtheme));
  233. theme = newtheme;
  234. } else {
  235. /*
  236. ** Sequential score playing.
  237. */
  238. do {
  239. theme++;
  240. if (theme > THEME_LAST) {
  241. theme = THEME_FIRST;
  242. }
  243. } while (!Is_Allowed(theme));
  244. }
  245. }
  246. return(theme);
  247. }
  248. /***********************************************************************************************
  249. * ThemeClass::Queue_Song -- Queues the song to the play queue. *
  250. * *
  251. * This routine will cause the current song to fade and the specified song to start. This *
  252. * is the normal and friendly method of changing the current song. *
  253. * *
  254. * INPUT: theme -- The song to start playing. If -1 is passed in, then just the current song.*
  255. * is faded. *
  256. * *
  257. * OUTPUT: none *
  258. * *
  259. * WARNINGS: none *
  260. * *
  261. * HISTORY: *
  262. * 01/16/1995 JLB : Created. *
  263. *=============================================================================================*/
  264. void ThemeClass::Queue_Song(ThemeType theme)
  265. {
  266. /*
  267. ** If there is no score file present, then abort.
  268. */
  269. if (!ScoresPresent) return;
  270. /*
  271. ** If there is no sound driver or sounds have been specifically
  272. ** turned off, then abort.
  273. */
  274. if (SampleType == 0 || Debug_Quiet) return;
  275. /*
  276. ** If the current score volumne is set to silent, then there is no need to play the
  277. ** specified theme.
  278. */
  279. if (Options.ScoreVolume == 0) return;
  280. /*
  281. ** If the pending theme is available to be set and the specified theme is valid, then
  282. ** set the queued theme accordingly.
  283. */
  284. if (Pending == THEME_NONE || Pending == THEME_PICK_ANOTHER || theme == THEME_NONE || theme == THEME_QUIET) {
  285. Pending = theme;
  286. if (Still_Playing()) {
  287. Fade_Sample(Current, THEME_DELAY);
  288. }
  289. }
  290. }
  291. /***********************************************************************************************
  292. * ThemeClass::Play_Song -- Starts the specified song play NOW. *
  293. * *
  294. * This routine is used to start the specified theme playing right now. If there is already *
  295. * a theme playing, it is cut short so that this one may start. *
  296. * *
  297. * INPUT: theme -- The theme number to start playing. *
  298. * *
  299. * OUTPUT: Returns with the sample play handle. *
  300. * *
  301. * WARNINGS: This cuts off any current song in a abrupt manner. Only use this routine when *
  302. * necessary. *
  303. * *
  304. * HISTORY: *
  305. * 01/16/1995 JLB : Created. *
  306. *=============================================================================================*/
  307. int ThemeClass::Play_Song(ThemeType theme)
  308. {
  309. if (ScoresPresent && SampleType && !Debug_Quiet && Options.ScoreVolume != 0) {
  310. Stop();
  311. Score = theme;
  312. if (theme != THEME_NONE && theme != THEME_QUIET) {
  313. StreamLowImpact = true;
  314. Current = File_Stream_Sample_Vol(Theme_File_Name(theme), 0xFF, true);
  315. StreamLowImpact = false;
  316. }
  317. }
  318. return(Current);
  319. }
  320. /***********************************************************************************************
  321. * ThemeClass::Theme_File_Name -- Constructs a filename for the specified theme. *
  322. * *
  323. * This routine will construct (into a static buffer) a filename that matches the theme *
  324. * number specified. This constructed filename is returned as a pointer. The filename will *
  325. * remain valid until the next call to this routine. *
  326. * *
  327. * INPUT: theme -- The theme number to convert to a filename. *
  328. * *
  329. * OUTPUT: Returns with a pointer to the constructed filename for the specified theme number. *
  330. * *
  331. * WARNINGS: none *
  332. * *
  333. * HISTORY: *
  334. * 01/16/1995 JLB : Created. *
  335. * 05/09/1995 JLB : Theme variation support. *
  336. *=============================================================================================*/
  337. char const * ThemeClass::Theme_File_Name(ThemeType theme)
  338. {
  339. static char name[_MAX_FNAME+_MAX_EXT];
  340. if (theme >= THEME_FIRST && theme < THEME_COUNT) {
  341. _makepath(name, NULL, NULL, _themes[theme].Name, ".AUD");
  342. return((char const *)(&name[0]));
  343. }
  344. return("");
  345. }
  346. /***********************************************************************************************
  347. * ThemeClass::Track_Length -- Calculates the length of the song (in seconds). *
  348. * *
  349. * Use this routine to calculate the length of the song. The length is determined by *
  350. * reading the header of the song and dividing the sample rate into the sample length. *
  351. * *
  352. * INPUT: theme -- The song number to examine to find its length. *
  353. * *
  354. * OUTPUT: Returns with the length of the specified theme. This length is in the form of *
  355. * seconds. *
  356. * *
  357. * WARNINGS: This routine goes to disk to fetch this information. Don't call frivolously. *
  358. * *
  359. * HISTORY: *
  360. * 01/16/1995 JLB : Created. *
  361. *=============================================================================================*/
  362. int ThemeClass::Track_Length(ThemeType theme) const
  363. {
  364. if ((unsigned)theme < THEME_COUNT) {
  365. return(_themes[theme].Duration);
  366. }
  367. return(0);
  368. }
  369. /***********************************************************************************************
  370. * ThemeClass::Stop -- Stops the current theme from playing. *
  371. * *
  372. * Use this routine to stop the current theme. After this routine is called, no more music *
  373. * will play until the Start() function is called. *
  374. * *
  375. * INPUT: none *
  376. * *
  377. * OUTPUT: none *
  378. * *
  379. * WARNINGS: none *
  380. * *
  381. * HISTORY: *
  382. * 09/08/1994 JLB : Created. *
  383. *=============================================================================================*/
  384. void ThemeClass::Stop(void)
  385. {
  386. if (ScoresPresent && SampleType && !Debug_Quiet && Current != -1) {
  387. Stop_Sample(Current);
  388. Current = -1;
  389. Score = THEME_NONE;
  390. Pending = THEME_NONE;
  391. }
  392. }
  393. void ThemeClass::Suspend(void)
  394. {
  395. if (ScoresPresent && SampleType && !Debug_Quiet && Current != -1) {
  396. Stop_Sample(Current);
  397. Current = -1;
  398. Pending = Score;
  399. Score = THEME_NONE;
  400. }
  401. }
  402. /***********************************************************************************************
  403. * ThemeClass::Still_Playing -- Determines if music is still playing. *
  404. * *
  405. * Use this routine to determine if music is still playing. *
  406. * *
  407. * INPUT: none *
  408. * *
  409. * OUTPUT: bool; Is the music still audible? *
  410. * *
  411. * WARNINGS: none *
  412. * *
  413. * HISTORY: *
  414. * 12/20/1994 JLB : Created. *
  415. *=============================================================================================*/
  416. int ThemeClass::Still_Playing(void) const
  417. {
  418. if (ScoresPresent && SampleType && Current != -1 && !Debug_Quiet) {
  419. return(Sample_Status(Current));
  420. }
  421. return(false);
  422. }
  423. /***********************************************************************************************
  424. * ThemeClass::Is_Allowed -- Checks to see if the specified theme is legal. *
  425. * *
  426. * Use this routine to determine if a theme is allowed to be played. A theme is not allowed *
  427. * if the scenario is too early for that score, or the score only is allowed in special *
  428. * cases. *
  429. * *
  430. * INPUT: index -- The score the check to see if it is allowed to play. *
  431. * *
  432. * OUTPUT: Is the specified score allowed to play in the normal score playlist? *
  433. * *
  434. * WARNINGS: none *
  435. * *
  436. * HISTORY: *
  437. * 05/09/1995 JLB : Created. *
  438. * 07/04/1996 JLB : Handles alternate playlist checking. *
  439. *=============================================================================================*/
  440. bool ThemeClass::Is_Allowed(ThemeType index) const
  441. {
  442. if ((unsigned)index >= THEME_COUNT) return(true);
  443. /*
  444. ** If the theme is not present, then it certainly isn't allowed.
  445. */
  446. if (!_themes[index].Available) return(false);
  447. /*
  448. ** Only normal themes (playable during battle) are considered allowed.
  449. */
  450. if (!_themes[index].Normal) return(false);
  451. /*
  452. ** If the theme is not allowed to be played by the player's house, then don't allow
  453. ** it. If the player's house hasn't yet been determined, then presume this test
  454. ** passes.
  455. */
  456. if (PlayerPtr != NULL && ((1 << PlayerPtr->ActLike) & _themes[index].Owner) == 0) return(false);
  457. /*
  458. ** If the scenario doesn't allow this theme yet, then return the failure flag. The
  459. ** scenario check only makes sense for solo play.
  460. */
  461. if (Session.Type == GAME_NORMAL && Scen.Scenario < _themes[index].Scenario) return(false);
  462. /*
  463. ** Since all tests passed, return with the "is allowed" flag.
  464. */
  465. return(true);
  466. }
  467. /***********************************************************************************************
  468. * ThemeClass::From_Name -- Determines theme number from specified name. *
  469. * *
  470. * Use this routine to convert a name (either the base filename of the theme, or a partial *
  471. * substring of the full name) into the matching ThemeType value. Typical use of this is *
  472. * when parsing the INI file for theme control values. *
  473. * *
  474. * INPUT: name -- Pointer to base filename of theme or a partial substring of the full *
  475. * theme name. *
  476. * *
  477. * OUTPUT: Returns with the matching theme number. If no match could be found, then *
  478. * THEME_NONE is returned. *
  479. * *
  480. * WARNINGS: If a filename is specified the comparison is case insensitive. When scanning *
  481. * the full theme name, the comparison is case sensitive. *
  482. * *
  483. * HISTORY: *
  484. * 05/29/1995 JLB : Created. *
  485. *=============================================================================================*/
  486. ThemeType ThemeClass::From_Name(char const * name) const
  487. {
  488. if (name && strlen(name) > 0) {
  489. /*
  490. ** First search for an exact name match with the filename
  491. ** of the theme. This is guaranteed to be unique.
  492. */
  493. for (ThemeType theme = THEME_FIRST; theme < THEME_COUNT; theme++) {
  494. if (stricmp(_themes[theme].Name, name) == 0) {
  495. return(theme);
  496. }
  497. }
  498. /*
  499. ** If the filename scan failed to find a match, then scan for
  500. ** a substring within the full name of the score. This might
  501. ** yield a match, but is not guaranteed to be unique.
  502. */
  503. for (theme = THEME_FIRST; theme < THEME_COUNT; theme++) {
  504. if (strstr(Text_String(_themes[theme].Fullname), name) != NULL) {
  505. return(theme);
  506. }
  507. }
  508. }
  509. return(THEME_NONE);
  510. }
  511. /***********************************************************************************************
  512. * ThemeClass::Scan -- Scans all scores for availability. *
  513. * *
  514. * This routine should be called whenever a score mixfile is registered. It will scan *
  515. * to see if any score is unavailable. If this is the case, then the score will be so *
  516. * flagged in order not to appear on the play list. This condition is likely to occur *
  517. * when expansion mission disks contain a different score mix than the release version. *
  518. * *
  519. * INPUT: none *
  520. * *
  521. * OUTPUT: none *
  522. * *
  523. * WARNINGS: none *
  524. * *
  525. * HISTORY: *
  526. * 01/04/1996 JLB : Created. *
  527. *=============================================================================================*/
  528. void ThemeClass::Scan(void)
  529. {
  530. for (ThemeType theme = THEME_FIRST; theme < THEME_COUNT; theme++) {
  531. _themes[theme].Available = CCFileClass(Theme_File_Name(theme)).Is_Available();
  532. }
  533. }
  534. /***********************************************************************************************
  535. * ThemeClass::Set_Theme_Data -- Set the theme data for scenario and owner. *
  536. * *
  537. * This is an override function used to set a particular theme's initial scenario and *
  538. * owner values. Typically, the rules control file will be the source of calling this *
  539. * routine. *
  540. * *
  541. * INPUT: theme -- The theme to set these override values for. *
  542. * *
  543. * scenario -- The first scenario when this theme becomes available on the play list. *
  544. * *
  545. * owners -- A bitfield representing the owners allowed to play this song. *
  546. * *
  547. * OUTPUT: none *
  548. * *
  549. * WARNINGS: none *
  550. * *
  551. * HISTORY: *
  552. * 08/12/1996 JLB : Created. *
  553. *=============================================================================================*/
  554. void ThemeClass::Set_Theme_Data(ThemeType theme, int scenario, int owners)
  555. {
  556. if (theme != THEME_NONE) {
  557. _themes[theme].Normal = true;
  558. _themes[theme].Scenario = scenario;
  559. _themes[theme].Owner = owners;
  560. }
  561. }