1313#include < thread>
1414#include < common/config.hh>
1515
16+ #ifdef ENABLE_DEBUG_MENU
17+ #include < debug/base.hh>
18+ #endif
19+
1620class audScriptAudioEntity ;
1721class 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