Skip to content

Commit 13eab05

Browse files
committed
Merge branch 'tts'
2 parents 02adace + 195c67a commit 13eab05

File tree

8 files changed

+164
-29
lines changed

8 files changed

+164
-29
lines changed

CactbotOverlay/CactbotOverlay.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public class CactbotOverlay : OverlayBase<CactbotOverlayConfig>, ILogger {
4747
private StringBuilder dispatch_string_builder_ = new StringBuilder(1000);
4848
JsonTextWriter dispatch_json_writer_;
4949
JsonSerializer dispatch_serializer_;
50+
JsonSerializer message_serializer_;
5051

5152
private System.Timers.Timer fast_update_timer_;
5253
// Held while the |fast_update_timer_| is running.
@@ -107,6 +108,7 @@ public CactbotOverlay(CactbotOverlayConfig config)
107108
wipe_detector_ = new WipeDetector(this);
108109
dispatch_json_writer_ = new JsonTextWriter(new System.IO.StringWriter(dispatch_string_builder_));
109110
dispatch_serializer_ = JsonSerializer.CreateDefault();
111+
message_serializer_ = JsonSerializer.CreateDefault();
110112

111113

112114
// Our own timer with a higher frequency than OverlayPlugin since we want to see
@@ -639,6 +641,16 @@ public void LogInfo(string format, params object[] args) {
639641
null);
640642
}
641643

644+
// This is an overlayMessage() function call from javascript. We accept a json object of
645+
// (command, argument) pairs. Commands are:
646+
// - say: The argument is a string which is read as text-to-speech.
647+
public override void OverlayMessage(string message) {
648+
var reader = new JsonTextReader(new StringReader(message));
649+
var obj = message_serializer_.Deserialize<Dictionary<string, string>>(reader);
650+
if (obj.ContainsKey("say"))
651+
Advanced_Combat_Tracker.ActGlobals.oFormActMain.TTS(obj["say"]);
652+
}
653+
642654
// State that is tracked and sent to JS when it changes.
643655
private class NotifyState {
644656
public bool sent_data_dir = false;

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,22 @@ Options.DisabledTriggers = {
170170
}
171171
```
172172

173+
If you dislike the built-in sound info, alert, and alarm noises that cactbot uses and would
174+
prefer to use text to speech (tts), you can set a global option by including this line
175+
in your **user/raidboss.js** file:
176+
177+
```
178+
// Including this line will make any trigger with text to speech use that instead of other
179+
// noises.
180+
Options.SpokenAlertsEnabled = true;
181+
182+
// If you don't like the on screen text, you can turn that off with this line too:
183+
Options.TextAlertsEnabled = false;
184+
```
185+
186+
See [this options documentation](ui/raidboss/raidboss.js) for a full list of options and
187+
how to configure text, sound, and tts options on a per trigger basis.
188+
173189
To add a sound alert that can be activated in any zone, for example, add the following to **user/raidboss.js**:
174190

175191
```

ui/raidboss/data/triggers/README.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,5 @@ The full order of evaluation of functions in a trigger is:
7171
4. infoText
7272
5. alertText
7373
6. alarmText
74-
7. run
74+
7. tts
75+
8. run

ui/raidboss/data/triggers/test.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,12 @@
5656
},
5757
tts: 'hahahahaha',
5858
},
59+
{
60+
id: 'Test Clap',
61+
regex: /:You clap for the striking dummy/,
62+
sound: '../../resources/sounds/WeakAuras/Applause.ogg',
63+
soundVolume: 0.3,
64+
tts: 'clapity clap',
65+
},
5966
],
6067
}]

ui/raidboss/popup-text.js

Lines changed: 54 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ class PopupText {
179179
}
180180

181181
OnTrigger(trigger, matches) {
182-
if (!this.options.PopupTextEnabled)
182+
if (!this.options.AlertsEnabled)
183183
return;
184184
if ('disabled' in trigger && trigger.disabled)
185185
return;
@@ -193,13 +193,27 @@ class PopupText {
193193
return (typeof(f) == "function") ? f(that.data, matches) : f;
194194
}
195195

196+
var showText = this.options.TextAlertsEnabled;
197+
var playSounds = this.options.SoundAlertsEnabled;
198+
var playSpeech = this.options.SpokenAlertsEnabled;
196199
var userDisabled = trigger.id && this.options.DisabledTriggers[trigger.id];
197200
var delay = 'delaySeconds' in trigger ? ValueOrFunction(trigger.delaySeconds) : 0;
198201
var duration = 'durationSeconds' in trigger ? ValueOrFunction(trigger.durationSeconds) : 3;
199202

203+
var triggerOptions = trigger.id && this.options.PerTriggerOptions[trigger.id];
204+
if (triggerOptions) {
205+
if ('SpeechAlert' in triggerOptions)
206+
playSpeech = triggerOptions.SpeechAlert;
207+
if ('SoundAlert' in triggerOptions)
208+
playSounds = triggerOptions.SoundAlert;
209+
if ('TextAlert' in triggerOptions)
210+
showText = triggerOptions.TextAlert;
211+
}
212+
200213
var f = function() {
201-
var textSound = '';
202-
var textVol = 1;
214+
var soundUrl = '';
215+
var soundVol = 1;
216+
var ttsText = '';
203217

204218
var addText = function(container, e) {
205219
container.appendChild(e);
@@ -224,72 +238,87 @@ class PopupText {
224238

225239
if ('infoText' in trigger) {
226240
var text = ValueOrFunction(trigger.infoText);
227-
if (text && !userDisabled) {
241+
if (text && !userDisabled && showText) {
228242
var holder = that.infoText.getElementsByClassName('holder')[0];
229243
var div = makeTextElement(text, 'info-text');
230244
addText.bind(that)(holder, div);
231245
window.setTimeout(removeText.bind(that, holder, div), duration * 1000);
232246

233247
if (!('sound' in trigger)) {
234-
textSound = that.options.InfoSound;
235-
textVol = that.options.InfoSoundVolume;
248+
soundUrl = that.options.InfoSound;
249+
soundVol = that.options.InfoSoundVolume;
236250
}
237251
}
238252
}
239253
if ('alertText' in trigger) {
240254
var text = ValueOrFunction(trigger.alertText);
241-
if (text && !userDisabled) {
255+
if (text && !userDisabled && showText) {
242256
var holder = that.alertText.getElementsByClassName('holder')[0];
243257
var div = makeTextElement(text, 'alert-text');
244258
addText.bind(that)(holder, div);
245259
window.setTimeout(removeText.bind(that, holder, div), duration * 1000);
246260

247261
if (!('sound' in trigger)) {
248-
textSound = that.options.AlertSound;
249-
textVol = that.options.AlertSoundVolume;
262+
soundUrl = that.options.AlertSound;
263+
soundVol = that.options.AlertSoundVolume;
250264
}
251265
}
252266
}
253267
if ('alarmText' in trigger) {
254268
var text = ValueOrFunction(trigger.alarmText);
255-
if (text && !userDisabled) {
269+
if (text && !userDisabled && showText) {
256270
var holder = that.alarmText.getElementsByClassName('holder')[0];
257271
var div = makeTextElement(text, 'alarm-text');
258272
addText.bind(that)(holder, div);
259273
window.setTimeout(removeText.bind(that, holder, div), duration * 1000);
260274

261275
if (!('sound' in trigger)) {
262-
textSound = that.options.AlarmSound;
263-
textVol = that.options.AlarmSoundVolume;
276+
soundUrl = that.options.AlarmSound;
277+
soundVol = that.options.AlarmSoundVolume;
264278
}
265279
}
266280
}
267-
268-
if (textSound) {
269-
var audio = new Audio(textSound);
270-
audio.volume = textVol;
271-
audio.play();
281+
if ('tts' in trigger && playSpeech) {
282+
var text = ValueOrFunction(trigger.tts);
283+
if (text && !userDisabled)
284+
ttsText = text;
272285
}
273286

274-
if (trigger.sound && !userDisabled) {
275-
var url = trigger.sound;
276-
var volume = 1;
287+
if (trigger.sound) {
288+
soundUrl = trigger.sound;
277289

278290
var namedSound = trigger.sound + 'Sound';
279291
var namedSoundVolume = trigger.sound + 'SoundVolume';
280292
if (namedSound in that.options) {
281-
url = that.options[namedSound];
293+
soundUrl = that.options[namedSound];
282294
if (namedSoundVolume in that.options)
283-
volume = that.options[namedSoundVolume];
295+
soundVol = that.options[namedSoundVolume];
284296
}
285297
if ('soundVolume' in trigger)
286-
volume = trigger.soundVolume;
298+
soundVol = trigger.soundVolume;
299+
}
287300

288-
var audio = new Audio(url);
289-
audio.volume = volume;
301+
if (triggerOptions) {
302+
soundUrl = triggerOptions.SoundOverride || soundUrl;
303+
soundVol = triggerOptions.VolumeOverride || soundVol;
304+
}
305+
306+
// Text to speech overrides all other sounds. This is so
307+
// that a user who prefers tts can still get the benefit
308+
// of infoText triggers without tts entries by turning
309+
// on (speech=true, text=true, sound=true) but this will
310+
// not cause tts to play over top of sounds or noises.
311+
if (soundUrl && playSounds && !userDisabled && !ttsText) {
312+
var audio = new Audio(soundUrl);
313+
audio.volume = soundVol;
290314
audio.play();
291315
}
292316

317+
if (ttsText && !userDisabled) {
318+
var cmd = { 'say': ttsText };
319+
OverlayPluginApi.overlayMessage(OverlayPluginApi.overlayName, JSON.stringify(cmd));
320+
}
321+
293322
if ('run' in trigger)
294323
trigger.run(that.data, matches);
295324
};

ui/raidboss/raidboss.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77
// See user/raidboss-example.js for documentation.
88
var Options = {
99
TimelineEnabled: true,
10-
PopupTextEnabled: true,
10+
AlertsEnabled: true,
11+
TextAlertsEnabled: true,
12+
SoundAlertsEnabled: true,
13+
SpokenAlertsEnabled: false,
1114

1215
ShowTimerBarsAtSeconds: 30,
1316
KeepExpiredTimerBarsForSeconds: 0.7,
@@ -25,6 +28,9 @@ var Options = {
2528
LongSoundVolume: 1,
2629

2730
DisabledTriggers: {},
31+
32+
PerTriggerOptions: {},
33+
2834
Triggers: [],
2935
};
3036

ui/test/cactbot_test.html

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,14 @@
115115
document.addEventListener("onBossFightEnd", function(e) {
116116
document.getElementById('event').innerText = "BossFight End";
117117
});
118+
document.addEventListener("onLogEvent", function(e) {
119+
for (var i = 0; i < e.detail.logs.length; i++) {
120+
// Match "/echo tts:<stuff>"
121+
var r = e.detail.logs[i].match('00:0038:tts:(.*)');
122+
if (r)
123+
OverlayPluginApi.overlayMessage(OverlayPluginApi.overlayName, JSON.stringify({ 'say': r[1] }));
124+
}
125+
});
118126
</script>
119127
</head>
120128
<body>

user/raidboss-example.js

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,21 @@
99
// If false, no timeline of upcoming events will be displayed during fights.
1010
Options.TimelineEnabled = true
1111

12-
// If false, no text will be shown or spoken, or sounds played, for triggers and timeline events.
13-
Options.PopupTextEnabled = true
12+
// If false, triggers and timelines will not show or speak text, nor play
13+
// sounds.
14+
Options.AlertsEnabled = true
15+
16+
// If false, then visual text alerts are not shown for triggers.
17+
Options.TextAlertsEnabled = true
18+
19+
// If false, then sound alerts are not played.
20+
Options.SoundAlertsEnabled = true,
21+
22+
// If true, then text-to-speech alerts are read aloud. Text-to-speech takes
23+
// priority over custom sounds and text noises. If a trigger does not have
24+
// a tts entry then it will fall back on text and sound (if turned on).
25+
Options.SpokenAlertsEnabled = false
26+
1427

1528
// Show timer bars for events that will happen in this many seconds or less.
1629
Options.ShowTimerBarsAtSeconds = 30
@@ -153,3 +166,46 @@ Options.Triggers = [
153166
},
154167

155168
]
169+
170+
// Per trigger options. By default, each trigger uses the global options
171+
// of TextAlertsEnabled, SoundAlertsEnabled, and SpokenAlertsEnabled.
172+
// These global options are set up top in this file.
173+
//
174+
// If a per trigger entry is present (regardless if true/false), it will
175+
// override whatever the global option is set to.
176+
//
177+
// SoundOverride (if present) behaves like 'sound' on an individual trigger, in
178+
// that it will take the place of the info/alert/alarm noise if no sound has
179+
// been specified. SoundAlert (or SoundAlertsEnabled) must still be true for
180+
// that override to be played.
181+
//
182+
// Here's some example per trigger options that modify the test triggers
183+
// in Summerford Farms:
184+
// https://github.com/quisquous/cactbot/blob/master/ui/raidboss/data/triggers/test.js
185+
186+
Options.PerTriggerOptions = {
187+
// Just like Options.DisabledTriggers, this is the trigger id to apply to.
188+
// This overrides the settings for the "/laugh" trigger from the test
189+
// triggers. You can try this out by teleporting to Summerford Farms
190+
// and /laugh at a striking dummy. It will use these settings and moo.
191+
'Test Laugh': {
192+
// Play the text to speech.
193+
SpeechAlert: false,
194+
// Play the sound alert.
195+
SoundAlert: true,
196+
// Show the info/alert/alarm text on screen.
197+
TextAlert: false,
198+
// Play this sound (replacing any sound from the original).
199+
SoundOverride: '../../resources/sounds/WeakAuras/CowMooing.ogg',
200+
// Play the sound (if any) at this volume.
201+
VolumeOverride: 0.3,
202+
},
203+
204+
// This makes /poke-ing a striking dummy in Summerford Farms only
205+
// use text to speech with no visual text indicator or other sound.
206+
'Test Poke': {
207+
SpeechAlert: true,
208+
SoundAlert: false,
209+
TextAlert: false,
210+
},
211+
}

0 commit comments

Comments
 (0)