Skip to content

Commit e88c8eb

Browse files
committed
[TD] Adds support for [ThemeControl] section in rules.ini.
1 parent f9f4aba commit e88c8eb

File tree

7 files changed

+232
-43
lines changed

7 files changed

+232
-43
lines changed

tiberiandawn/conquer.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3947,6 +3947,41 @@ void Blit_Hid_Page_To_Seen_Buff(void)
39473947
HidPage.Blit(SeenBuff);
39483948
}
39493949

3950+
/***********************************************************************************************
3951+
* Owner_From_Name -- Convert an owner name into a bitfield. *
3952+
* *
3953+
* This will take an owner specification and convert it into a bitfield that represents *
3954+
* it. Sometimes this will be just a single house bit, but other times it could be *
3955+
* all the allies or soviet house bits combined. *
3956+
* *
3957+
* INPUT: text -- Pointer to the text to convert into a house bitfield. *
3958+
* *
3959+
* OUTPUT: Returns with the houses specified. The value is in the form of a bit field with *
3960+
* one bit per house type. *
3961+
* *
3962+
* WARNINGS: none *
3963+
* *
3964+
* HISTORY: *
3965+
* 08/12/1996 JLB : Created. *
3966+
*=============================================================================================*/
3967+
int Owner_From_Name(char const* text)
3968+
{
3969+
int ownable = 0;
3970+
if (stricmp(text, "nod") == 0) {
3971+
ownable |= HOUSEF_BAD;
3972+
} else {
3973+
if (stricmp(text, "gdi") == 0) {
3974+
ownable |= HOUSEF_GOOD;
3975+
} else {
3976+
HousesType h = HouseTypeClass::From_Name(text);
3977+
if (h != HOUSE_NONE && (h < HOUSE_MULTI1 || h > HOUSE_MULTI6)) {
3978+
ownable |= (1 << h);
3979+
}
3980+
}
3981+
}
3982+
return (ownable);
3983+
}
3984+
39503985
/***********************************************************************************************
39513986
* Shake_The_Screen -- Dispatcher that shakes the screen. *
39523987
* *

tiberiandawn/defines.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,9 @@ typedef enum HousesType : signed char
685685
#define HOUSEF_MULTI4 (1 << HOUSE_MULTI4)
686686
#define HOUSEF_MULTI5 (1 << HOUSE_MULTI5)
687687
#define HOUSEF_MULTI6 (1 << HOUSE_MULTI6)
688+
#define HOUSEF_OTHERS \
689+
(HOUSEF_NEUTRAL | HOUSEF_JP | HOUSEF_MULTI1 | HOUSEF_MULTI2 | HOUSEF_MULTI3 | HOUSEF_MULTI4 | HOUSEF_MULTI5 \
690+
| HOUSEF_MULTI6)
688691

689692
typedef enum PlayerColorType : signed char
690693
{

tiberiandawn/function.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ void Explosion_Damage(COORDINATE coord, unsigned strength, TechnoClass* source,
301301
/*
302302
** CONQUER.CPP
303303
*/
304+
int Owner_From_Name(char const* text);
304305
void Center_About_Objects(void);
305306
bool Force_CD_Available(int cd);
306307
void Handle_View(int view, int action = 0);

tiberiandawn/rules.cpp

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,82 @@ bool RulesClass::Export_AI(CCINIClass& ini)
504504
ini.Put_Fixed(AI, "PowerEmergency", PowerEmergencyFraction);
505505
return (true);
506506
}
507+
/***********************************************************************************************
508+
* RulesClass::Themes -- Fetches the theme control values from the INI database. *
509+
* *
510+
* The musical theme availability is controlled by the scenario and the player's house *
511+
* choice. These controls can be specified in the theme control section of the INI *
512+
* database. *
513+
* *
514+
* INPUT: ini -- Reference to the INI database to process. *
515+
* *
516+
* OUTPUT: bool; Was the theme section found and processed? *
517+
* *
518+
* WARNINGS: none *
519+
* *
520+
* HISTORY: *
521+
* 08/11/1996 JLB : Created. *
522+
*=============================================================================================*/
523+
bool RulesClass::Themes(CCINIClass& ini)
524+
{
525+
static char const* const THEMECONTROL = "ThemeControl";
526+
527+
if (ini.Is_Present(THEMECONTROL)) {
528+
for (ThemeType theme = THEME_FIRST; theme < THEME_COUNT; theme++) {
529+
if (ini.Is_Present(THEMECONTROL, Theme.Base_Name(theme))) {
530+
531+
char buffer[128];
532+
int scen = 1;
533+
int owners = HOUSEF_GOOD | HOUSEF_BAD | HOUSEF_OTHERS;
534+
535+
ini.Get_String(THEMECONTROL, Theme.Base_Name(theme), "", buffer, sizeof(buffer));
536+
char const* token = strtok(buffer, ",");
537+
if (token != NULL) {
538+
scen = atoi(token);
539+
}
540+
541+
token = strtok(NULL, ",");
542+
if (token != NULL) {
543+
owners = Owner_From_Name(token);
544+
}
545+
546+
Theme.Set_Theme_Data(theme, scen, owners);
547+
}
548+
}
549+
return (true);
550+
}
551+
return (false);
552+
}
553+
554+
bool RulesClass::Export_Themes(CCINIClass& ini)
555+
{
556+
static char const* const THEMECONTROL = "ThemeControl";
557+
558+
for (ThemeType theme = THEME_FIRST; theme < THEME_COUNT; theme++) {
559+
560+
char buffer[128];
561+
int scen = Theme.Scenario(theme);
562+
int owners = Theme.Owner(theme);
563+
564+
const char* owner_name;
565+
switch (owners) {
566+
case HOUSEF_GOOD:
567+
owner_name = ",GDI";
568+
break;
569+
case HOUSEF_BAD:
570+
owner_name = ",Nod";
571+
break;
572+
default:
573+
owner_name = "";
574+
break;
575+
}
576+
577+
snprintf(buffer, sizeof(buffer), "%d,%s", scen, owner_name);
578+
ini.Put_String(THEMECONTROL, Theme.Base_Name(theme), buffer);
579+
}
580+
581+
return true;
582+
}
507583

508584
/***********************************************************************************************
509585
* RulesClass::IQ -- Fetches the IQ control values from the INI database. *

tiberiandawn/rules.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,14 @@ class RulesClass
6969
bool General(CCINIClass& ini);
7070
bool Recharge(CCINIClass& ini);
7171
bool AI(CCINIClass& ini);
72+
bool Themes(CCINIClass& ini);
7273
bool IQ(CCINIClass& ini);
7374
bool Difficulty(CCINIClass& ini);
7475
bool Export(CCINIClass& file);
7576
bool Export_General(CCINIClass& ini);
7677
bool Export_Recharge(CCINIClass& ini);
7778
bool Export_AI(CCINIClass& ini);
79+
bool Export_Themes(CCINIClass& ini);
7880
bool Export_IQ(CCINIClass& ini);
7981
bool Export_Difficulty(CCINIClass& ini);
8082

tiberiandawn/theme.cpp

Lines changed: 103 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -54,44 +54,44 @@
5454
** These are the actual filename list for the theme sample files.
5555
*/
5656
ThemeClass::ThemeControl ThemeClass::_themes[THEME_COUNT] = {
57-
{"AIRSTRIK", TXT_THEME_AIRSTRIKE, 0, 200, false, false, false, true},
58-
{"80MX226M", TXT_THEME_80MX, 0, 248, false, false, false, true},
59-
{"CHRG226M", TXT_THEME_CHRG, 0, 256, true, false, false, true},
60-
{"CREP226M", TXT_THEME_CREP, 0, 222, true, false, false, true},
61-
{"DRIL226M", TXT_THEME_DRIL, 0, 272, true, false, false, true},
62-
{"DRON226M", TXT_THEME_DRON, 0, 275, true, false, false, true},
63-
{"FIST226M", TXT_THEME_FIST, 0, 212, true, false, false, true},
64-
{"RECN226M", TXT_THEME_RECON, 0, 261, true, false, false, true},
65-
{"VOIC226M", TXT_THEME_VOICE, 0, 306, true, false, false, true},
66-
{"HEAVYG", TXT_THEME_HEAVYG, 0, 180, true, false, false, true},
67-
{"J1", TXT_THEME_J1, 4, 187, true, false, false, true},
57+
{"AIRSTRIK", TXT_THEME_AIRSTRIKE, 0, 200, false, false, false, true, HOUSEF_GOOD | HOUSEF_BAD},
58+
{"80MX226M", TXT_THEME_80MX, 0, 248, false, false, false, true, HOUSEF_GOOD | HOUSEF_BAD},
59+
{"CHRG226M", TXT_THEME_CHRG, 0, 256, true, false, false, true, HOUSEF_GOOD | HOUSEF_BAD},
60+
{"CREP226M", TXT_THEME_CREP, 0, 222, true, false, false, true, HOUSEF_GOOD | HOUSEF_BAD},
61+
{"DRIL226M", TXT_THEME_DRIL, 0, 272, true, false, false, true, HOUSEF_GOOD | HOUSEF_BAD},
62+
{"DRON226M", TXT_THEME_DRON, 0, 275, true, false, false, true, HOUSEF_GOOD | HOUSEF_BAD},
63+
{"FIST226M", TXT_THEME_FIST, 0, 212, true, false, false, true, HOUSEF_GOOD | HOUSEF_BAD},
64+
{"RECN226M", TXT_THEME_RECON, 0, 261, true, false, false, true, HOUSEF_GOOD | HOUSEF_BAD},
65+
{"VOIC226M", TXT_THEME_VOICE, 0, 306, true, false, false, true, HOUSEF_GOOD | HOUSEF_BAD},
66+
{"HEAVYG", TXT_THEME_HEAVYG, 0, 180, true, false, false, true, HOUSEF_GOOD | HOUSEF_BAD},
67+
{"J1", TXT_THEME_J1, 4, 187, true, false, false, true, HOUSEF_GOOD | HOUSEF_BAD},
6868
// {"J1", TXT_THEME_J1, 4, 187, false, false,false,true},
69-
{"JDI_V2", TXT_THEME_JDI_V2, 5, 183, true, false, false, true},
70-
{"RADIO", TXT_THEME_RADIO, 6, 183, true, false, false, true},
71-
{"RAIN", TXT_THEME_RAIN, 7, 156, true, false, false, true},
72-
{"AOI", TXT_THEME_AOI, 0, 168, true, true, false, true},
73-
{"CCTHANG", TXT_THEME_CCTHANG, 12, 193, true, false, false, true},
74-
{"DIE", TXT_THEME_DIE, 11, 162, false, false, false, true},
75-
{"FWP", TXT_THEME_FWP, 10, 53, true, false, false, true},
76-
{"IND", TXT_THEME_IND, 1, 175, true, false, false, true},
77-
{"IND2", TXT_THEME_IND2, 1, 38, true, false, false, true},
78-
{"JUSTDOIT", TXT_THEME_JUSTDOIT, 9, 142, true, false, false, true},
79-
{"LINEFIRE", TXT_THEME_LINEFIRE, 8, 125, true, false, false, true},
80-
{"MARCH", TXT_THEME_MARCH, 7, 157, true, false, false, true},
81-
{"TARGET", TXT_THEME_TARGET, 0, 173, true, false, false, true},
82-
{"NOMERCY", TXT_THEME_NOMERCY, 2, 204, true, false, false, true},
83-
{"OTP", TXT_THEME_OTP, 3, 182, true, false, false, true},
84-
{"PRP", TXT_THEME_PRP, 4, 211, true, false, false, true},
85-
{"ROUT", TXT_THEME_ROUT, 12, 121, false, true, false, true},
86-
{"HEART", TXT_THEME_HEART, 5, 206, false, true, false, true},
87-
{"STOPTHEM", TXT_THEME_STOPTHEM, 0, 190, true, false, false, true},
88-
{"TROUBLE", TXT_THEME_TROUBLE, 6, 191, true, true, false, true},
89-
{"WARFARE", TXT_THEME_WARFARE, 0, 182, true, false, false, true},
90-
{"BEFEARED", TXT_THEME_BEFEARED, 13, 164, false, true, false, true},
91-
{"I_AM", TXT_THEME_IAM, 6, 161, false, false, false, true},
92-
{"WIN1", TXT_THEME_WIN1, 0, 41, false, true, true, true},
93-
{"MAP1", TXT_THEME_WIN1, 0, 61, false, false, true, true},
94-
{"VALKYRIE", TXT_THEME_VALK, 0, 306, false, false, true, true},
69+
{"JDI_V2", TXT_THEME_JDI_V2, 5, 183, true, false, false, true, HOUSEF_GOOD | HOUSEF_BAD},
70+
{"RADIO", TXT_THEME_RADIO, 6, 183, true, false, false, true, HOUSEF_GOOD | HOUSEF_BAD},
71+
{"RAIN", TXT_THEME_RAIN, 7, 156, true, false, false, true, HOUSEF_GOOD | HOUSEF_BAD},
72+
{"AOI", TXT_THEME_AOI, 0, 168, true, true, false, true, HOUSEF_GOOD | HOUSEF_BAD},
73+
{"CCTHANG", TXT_THEME_CCTHANG, 12, 193, true, false, false, true, HOUSEF_GOOD | HOUSEF_BAD},
74+
{"DIE", TXT_THEME_DIE, 11, 162, false, false, false, true, HOUSEF_GOOD | HOUSEF_BAD},
75+
{"FWP", TXT_THEME_FWP, 10, 53, true, false, false, true, HOUSEF_GOOD | HOUSEF_BAD},
76+
{"IND", TXT_THEME_IND, 1, 175, true, false, false, true, HOUSEF_GOOD | HOUSEF_BAD},
77+
{"IND2", TXT_THEME_IND2, 1, 38, true, false, false, true, HOUSEF_GOOD | HOUSEF_BAD},
78+
{"JUSTDOIT", TXT_THEME_JUSTDOIT, 9, 142, true, false, false, true, HOUSEF_GOOD | HOUSEF_BAD},
79+
{"LINEFIRE", TXT_THEME_LINEFIRE, 8, 125, true, false, false, true, HOUSEF_GOOD | HOUSEF_BAD},
80+
{"MARCH", TXT_THEME_MARCH, 7, 157, true, false, false, true, HOUSEF_GOOD | HOUSEF_BAD},
81+
{"TARGET", TXT_THEME_TARGET, 0, 173, true, false, false, true, HOUSEF_GOOD | HOUSEF_BAD},
82+
{"NOMERCY", TXT_THEME_NOMERCY, 2, 204, true, false, false, true, HOUSEF_GOOD | HOUSEF_BAD},
83+
{"OTP", TXT_THEME_OTP, 3, 182, true, false, false, true, HOUSEF_GOOD | HOUSEF_BAD},
84+
{"PRP", TXT_THEME_PRP, 4, 211, true, false, false, true, HOUSEF_GOOD | HOUSEF_BAD},
85+
{"ROUT", TXT_THEME_ROUT, 12, 121, false, true, false, true, HOUSEF_GOOD | HOUSEF_BAD},
86+
{"HEART", TXT_THEME_HEART, 5, 206, false, true, false, true, HOUSEF_GOOD | HOUSEF_BAD},
87+
{"STOPTHEM", TXT_THEME_STOPTHEM, 0, 190, true, false, false, true, HOUSEF_GOOD | HOUSEF_BAD},
88+
{"TROUBLE", TXT_THEME_TROUBLE, 6, 191, true, true, false, true, HOUSEF_GOOD | HOUSEF_BAD},
89+
{"WARFARE", TXT_THEME_WARFARE, 0, 182, true, false, false, true, HOUSEF_GOOD | HOUSEF_BAD},
90+
{"BEFEARED", TXT_THEME_BEFEARED, 13, 164, false, true, false, true, HOUSEF_GOOD | HOUSEF_BAD},
91+
{"I_AM", TXT_THEME_IAM, 6, 161, false, false, false, true, HOUSEF_GOOD | HOUSEF_BAD},
92+
{"WIN1", TXT_THEME_WIN1, 0, 41, false, true, true, true, HOUSEF_GOOD | HOUSEF_BAD},
93+
{"MAP1", TXT_THEME_WIN1, 0, 61, false, false, true, true, HOUSEF_GOOD | HOUSEF_BAD},
94+
{"VALKYRIE", TXT_THEME_VALK, 0, 306, false, false, true, true, HOUSEF_GOOD | HOUSEF_BAD},
9595
};
9696

9797
/***********************************************************************************************
@@ -467,12 +467,43 @@ bool ThemeClass::Is_Allowed(ThemeType index) const
467467
}
468468
}
469469

470-
return (_themes[index].Available
471-
&& (_themes[index].Normal ||
472-
// (index == THEME_MAP1 && ScenarioInit) ||
473-
((Special.IsVariation && _themes[index].Variation && index != THEME_WIN1)
474-
&& (!Is_Demo() || (GameToPlay != GAME_NORMAL || _themes[index].Scenario <= (int)Scen.Scenario))
475-
&& (index != THEME_J1 || Special.IsJurassic))));
470+
if ((unsigned)index >= THEME_COUNT)
471+
return (true);
472+
473+
/*
474+
** If the theme is not present, then it certainly isn't allowed.
475+
*/
476+
if (!_themes[index].Available)
477+
return (false);
478+
479+
/*
480+
** Only normal themes (playable during battle) are considered allowed.
481+
*/
482+
if (!_themes[index].Normal)
483+
return (false);
484+
485+
/*
486+
** If the theme is not allowed to be played by the player's house, then don't allow
487+
** it. If the player's house hasn't yet been determined, then presume this test
488+
** passes.
489+
*/
490+
if (PlayerPtr != NULL && ((1 << PlayerPtr->ActLike) & _themes[index].Owner) == 0)
491+
return (false);
492+
493+
if (!Special.IsVariation || !_themes[index].Variation || index == THEME_WIN1)
494+
return (false);
495+
496+
/*
497+
** If the scenario doesn't allow this theme yet, then return the failure flag. The
498+
** scenario check only makes sense for solo play.
499+
*/
500+
if (Is_Demo() || (GameToPlay == GAME_NORMAL && Scen.Scenario < _themes[index].Scenario))
501+
return (false);
502+
503+
/*
504+
** Since all otehr tests passed, return if its not the special dino theme.
505+
*/
506+
return (index != THEME_J1 || Special.IsJurassic);
476507
}
477508

478509
/***********************************************************************************************
@@ -551,3 +582,32 @@ void ThemeClass::Scan(void)
551582
// }
552583
}
553584
}
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+
}

tiberiandawn/theme.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ class ThemeClass
5454
bool Variation; // Is there a variation to the score?
5555
bool Repeat; // Always repeat this score?
5656
bool Available; // Is the score available?
57+
int Owner; // What houses are allowed to play this theme (bit field)?
5758
} ThemeControl;
5859

5960
static ThemeControl _themes[THEME_COUNT];
@@ -89,8 +90,19 @@ class ThemeClass
8990
};
9091
int Still_Playing(void);
9192
ThemeType Next_Song(ThemeType index);
93+
void Set_Theme_Data(ThemeType theme, int scenario, int owners);
9294
bool Is_Allowed(ThemeType index) const;
9395
static void /*_pascal*/ Scan(void);
96+
97+
static int Scenario(ThemeType index)
98+
{
99+
return _themes[index].Scenario;
100+
}
101+
102+
static int Owner(ThemeType index)
103+
{
104+
return _themes[index].Owner;
105+
}
94106
};
95107

96108
#endif

0 commit comments

Comments
 (0)