Skip to content

Commit 807d7ed

Browse files
committed
Voice Line Randomizer: New Randomization methods
* New randomization modes that get randomly chosen for every dialogue sequence. * Check config file for more information
1 parent 7fbd134 commit 807d7ed

File tree

4 files changed

+235
-29
lines changed

4 files changed

+235
-29
lines changed

config.toml

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
# Refer to the readme to get the description of all the randomizers.
2323
[Randomizers]
2424

25-
RainbomizerNews = true
2625
RainbomizerCredits = true
2726

2827
TrafficRandomizer = true
@@ -42,6 +41,41 @@ SwitchSceneRandomizer = false
4241
RespawnRandomizer = true
4342
LightRandomizer = true
4443

44+
#######################################################
45+
[VoiceLineRandomizer]
46+
47+
# Whether to include DLC lines in randomization. Set to false if you don't want to hear
48+
# DLC voice lines.
49+
IncludeDLCLines = true
50+
51+
# Voice Line Randomizer has 4 states it can be in:
52+
# It can either be:
53+
#
54+
# 1. Completely Random (voice lines have a completely random order)
55+
# 2. Ordered Random (consecutive voice lines are from the same dialogue sequence)
56+
# 3. Some Random (voice lines are normal except some random lines)
57+
# 4. No Random (all voice lines are normal).
58+
#
59+
# Each of these 4 state is randomly chosen and stays for a duration which can be
60+
# configured. This duration also decides how likely they are to be chosen. (i.e longer
61+
# durations means more likely to be chosen).
62+
#
63+
# All durations are in seconds
64+
65+
TrulyRandomDuration = 15
66+
OrderedRandomDuration = 45
67+
SomeRandomDuration = 15
68+
NoRandomDuration = 15
69+
70+
# During Some Random state, this option decides how likely a voice line is to be randomized.
71+
# If you set this to 100, it behaves the same as TrulyRandom.
72+
# 0 is the same as NoRandom
73+
PercentageRandomOnSomeRandom = 65
74+
75+
# How many seconds before the ordered dialogue is re-randomized to a different sequence.
76+
# If you set this to 0, it behaves the same as TrulyRandom.
77+
OrderedDialogueChangeFrequency = 20
78+
4579
#######################################################
4680
[TimecycleRandomizer]
4781

@@ -101,11 +135,6 @@ TunableFile = "Timecyc/Default.txt"
101135

102136
RandomizeEveryFade = true
103137

104-
#######################################################
105-
[VoiceLineRandomizer]
106-
107-
IncludeDLCLines = true # Includes DLC lines in randomization
108-
109138
#######################################################
110139
[MissionRandomizer]
111140

src/common/configDefault.hh

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ const char configDefault[] = R"(
2323
# Refer to the readme to get the description of all the randomizers.
2424
[Randomizers]
2525
26-
RainbomizerNews = true
2726
RainbomizerCredits = true
2827
2928
TrafficRandomizer = true
@@ -43,6 +42,41 @@ SwitchSceneRandomizer = false
4342
RespawnRandomizer = true
4443
LightRandomizer = true
4544
45+
#######################################################
46+
[VoiceLineRandomizer]
47+
48+
# Whether to include DLC lines in randomization. Set to false if you don't want to hear
49+
# DLC voice lines.
50+
IncludeDLCLines = true
51+
52+
# Voice Line Randomizer has 4 states it can be in:
53+
# It can either be:
54+
#
55+
# 1. Completely Random (voice lines have a completely random order)
56+
# 2. Ordered Random (consecutive voice lines are from the same dialogue sequence)
57+
# 3. Some Random (voice lines are normal except some random lines)
58+
# 4. No Random (all voice lines are normal).
59+
#
60+
# Each of these 4 state is randomly chosen and stays for a duration which can be
61+
# configured. This duration also decides how likely they are to be chosen. (i.e longer
62+
# durations means more likely to be chosen).
63+
#
64+
# All durations are in seconds
65+
66+
TrulyRandomDuration = 15
67+
OrderedRandomDuration = 45
68+
SomeRandomDuration = 15
69+
NoRandomDuration = 15
70+
71+
# During Some Random state, this option decides how likely a voice line is to be randomized.
72+
# If you set this to 100, it behaves the same as TrulyRandom.
73+
# 0 is the same as NoRandom
74+
PercentageRandomOnSomeRandom = 65
75+
76+
# How many seconds before the ordered dialogue is re-randomized to a different sequence.
77+
# If you set this to 0, it behaves the same as TrulyRandom.
78+
OrderedDialogueChangeFrequency = 20
79+
4680
#######################################################
4781
[TimecycleRandomizer]
4882
@@ -102,11 +136,6 @@ TunableFile = "Timecyc/Default.txt"
102136
103137
RandomizeEveryFade = true
104138
105-
#######################################################
106-
[VoiceLineRandomizer]
107-
108-
IncludeDLCLines = true # Includes DLC lines in randomization
109-
110139
#######################################################
111140
[MissionRandomizer]
112141

src/misc/news.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,8 @@ class NewsRandomizer
5555
"0f 44 ca 41 8b d0 ? 8d 05 ? ? ? ? e8 ? ? ? ? ? 83 c4 38 c3 ", 13,
5656
MoveCloudCache, void, char *, int, char *, const char *, char *);
5757
}
58-
} news;
58+
}
59+
#ifdef BUILD_NEWS_RANDOMIZER
60+
news
61+
#endif
62+
;

src/sounds/voicelines.cc

Lines changed: 160 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
#include <thread>
1414
#include <common/config.hh>
1515

16+
#ifdef ENABLE_DEBUG_MENU
17+
#include <debug/base.hh>
18+
#endif
19+
1620
class audScriptAudioEntity;
1721
class audSpeechSound;
1822

@@ -39,26 +43,152 @@ class VoiceLineRandomizer
3943
inline static std::unordered_map<uint32_t, std::string> mSubtitles;
4044
inline static std::vector<SoundPair> mSounds;
4145

42-
static auto &
43-
Config ()
46+
struct State
4447
{
45-
static struct Config
48+
enum
4649
{
47-
bool IncludeDLCLines = true;
48-
} m_Config;
50+
TrulyRandom,
51+
OrderedRandom,
52+
SomeRandom,
53+
EasterEgg,
54+
NoRandom
55+
} inline static Type;
56+
57+
inline static size_t NextTypeUpdate = 0;
58+
59+
// Ordered Random state variables
60+
inline static size_t CurrentSeq;
61+
inline static uint64_t PrevSeqUpdate = 0;
62+
63+
const SoundPair *CurrentPair = nullptr;
64+
const SoundPair *EasterEggVoiceLine = nullptr;
65+
66+
void
67+
SetState (decltype (Type) type, int duration)
68+
{
69+
Type = type;
70+
NextTypeUpdate = time (NULL) + duration;
71+
}
72+
73+
State (){};
74+
75+
} inline static sm_State;
76+
77+
// Read config file for descriptions
78+
RB_C_CONFIG_START
79+
{
80+
int TrulyRandomDuration = 15;
81+
int OrderedRandomDuration = 45;
82+
int SomeRandomDuration = 15;
83+
int NoRandomDuration = 15;
84+
85+
int PercentageRandomOnSomeRandom = 65;
86+
int OrderedDialogueChangeFrequency = 20;
4987

50-
return m_Config;
88+
bool IncludeDLCLines = true;
5189
}
90+
RB_C_CONFIG_END
5291

5392
/*******************************************************/
5493
static bool
5594
ShouldRandomizeVoiceLine (uint32_t hash)
5695
{
57-
return std::find_if (std::begin (mSounds), std::end (mSounds),
58-
[hash] (const SoundPair &sound) {
59-
return sound.soundHash == hash;
60-
})
61-
!= std::end (mSounds);
96+
const auto &res
97+
= std::find_if (std::begin (mSounds), std::end (mSounds),
98+
[hash] (const SoundPair &sound) {
99+
return sound.soundHash == hash;
100+
});
101+
102+
if (res != std::end (mSounds))
103+
sm_State.CurrentPair = &*res;
104+
105+
return sm_State.CurrentPair != nullptr;
106+
}
107+
108+
/*******************************************************/
109+
static void
110+
UpdateState ()
111+
{
112+
const float EASTER_EGG_ODDS = 0.5f; // 1 in 200
113+
const int EASTER_EGG_DURATION = 60;
114+
115+
// Wait for next update
116+
if (time (NULL) < sm_State.NextTypeUpdate)
117+
return;
118+
119+
if (RandomBool (EASTER_EGG_ODDS))
120+
return sm_State.SetState (State::EasterEgg, EASTER_EGG_DURATION);
121+
122+
// Initialise weights from duration for now
123+
static std::vector<double> Weights
124+
= {{static_cast<double> (Config ().TrulyRandomDuration),
125+
static_cast<double> (Config ().OrderedRandomDuration),
126+
static_cast<double> (Config ().SomeRandomDuration),
127+
static_cast<double> (Config ().NoRandomDuration)}};
128+
129+
#define SET_STATE_CASE(idx, name) \
130+
case idx: sm_State.SetState (State::name, Config ().name##Duration); break
131+
132+
switch (RandomWeighed (Weights))
133+
{
134+
SET_STATE_CASE (0, TrulyRandom);
135+
SET_STATE_CASE (1, OrderedRandom);
136+
SET_STATE_CASE (2, SomeRandom);
137+
SET_STATE_CASE (3, NoRandom);
138+
}
139+
#undef SET_STATE_CASE
140+
}
141+
142+
/*******************************************************/
143+
static const auto &
144+
GetRandomSoundPair ()
145+
{
146+
UpdateState ();
147+
148+
switch (sm_State.Type)
149+
{
150+
/* Return a completely random voice line */
151+
case State::TrulyRandom: {
152+
return GetRandomElement (mSounds);
153+
}
154+
155+
/* Return random dialogues in order defined in VoiceLines.txt */
156+
case State::OrderedRandom: {
157+
if (time (NULL) - sm_State.PrevSeqUpdate
158+
> Config ().OrderedDialogueChangeFrequency)
159+
{
160+
sm_State.CurrentSeq = RandomSize (mSounds.size ());
161+
sm_State.PrevSeqUpdate = time (NULL);
162+
}
163+
else
164+
{
165+
sm_State.CurrentSeq
166+
= (sm_State.CurrentSeq + 1) % mSounds.size ();
167+
}
168+
return mSounds[sm_State.CurrentSeq];
169+
}
170+
171+
/* Random a percentage of time */
172+
case State::SomeRandom: {
173+
if (RandomBool (Config ().PercentageRandomOnSomeRandom))
174+
return GetRandomElement (mSounds);
175+
[[fallthrough]];
176+
}
177+
178+
/* Not random */
179+
case State::NoRandom: {
180+
return *sm_State.CurrentPair;
181+
}
182+
183+
/* Same voice line repeating */
184+
case State::EasterEgg: {
185+
if (!sm_State.EasterEggVoiceLine)
186+
sm_State.EasterEggVoiceLine
187+
= &GetRandomElement (mSounds);
188+
189+
return *sm_State.EasterEggVoiceLine;
190+
}
191+
}
62192
}
63193

64194
/*******************************************************/
@@ -71,7 +201,7 @@ class VoiceLineRandomizer
71201
if (mSounds.size () > 0
72202
&& ShouldRandomizeVoiceLine (rage::atPartialStringHash (sound)))
73203
{
74-
auto &newSound = GetRandomElement (mSounds);
204+
auto &newSound = GetRandomSoundPair ();
75205

76206
subtitle = newSound.subtitle.c_str ();
77207
mAudioPairs[rage::atPartialStringHash (sound)] = &newSound;
@@ -256,10 +386,11 @@ class VoiceLineRandomizer
256386
/*******************************************************/
257387
VoiceLineRandomizer ()
258388
{
259-
if (!ConfigManager::ReadConfig (
260-
"VoiceLineRandomizer", // ----------------------------------
261-
std::pair ("IncludeDLCLines", &Config ().IncludeDLCLines)))
262-
return;
389+
RB_C_DO_CONFIG ("VoiceLineRandomizer", IncludeDLCLines,
390+
TrulyRandomDuration, OrderedRandomDuration,
391+
SomeRandomDuration, NoRandomDuration,
392+
PercentageRandomOnSomeRandom,
393+
OrderedDialogueChangeFrequency);
263394

264395
InitialiseAllComponents ();
265396
InitialiseHooks ();
@@ -268,5 +399,18 @@ class VoiceLineRandomizer
268399
if (session)
269400
InitialiseSoundsList ();
270401
};
402+
403+
#ifdef ENABLE_DEBUG_MENU
404+
#define ADD_SET_STATE_ACTIONS(action) \
405+
DebugInterfaceManager::AddAction ("Set State to " #action, [] (bool) { \
406+
sm_State.SetState (State::action, 60); \
407+
});
408+
409+
ADD_SET_STATE_ACTIONS (TrulyRandom);
410+
ADD_SET_STATE_ACTIONS (SomeRandom);
411+
ADD_SET_STATE_ACTIONS (EasterEgg);
412+
ADD_SET_STATE_ACTIONS (NoRandom);
413+
ADD_SET_STATE_ACTIONS (OrderedRandom);
414+
#endif
271415
}
272416
} voices;

0 commit comments

Comments
 (0)