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