diff --git a/backend/src/api/schemas/config-schema.ts b/backend/src/api/schemas/config-schema.ts index 3a4fbcb54..9203bed67 100644 --- a/backend/src/api/schemas/config-schema.ts +++ b/backend/src/api/schemas/config-schema.ts @@ -88,7 +88,7 @@ const CONFIG_SCHEMA = joi.object({ alwaysShowWordsHistory: joi.boolean(), singleListCommandLine: joi.string().valid("manual", "on"), capsLockWarning: joi.boolean(), - playSoundOnError: joi.boolean(), + playSoundOnError: joi.string().valid("off", ..._.range(1, 4).map(_.toString)), playSoundOnClick: joi .string() .valid("off", ..._.range(1, 14).map(_.toString)), diff --git a/frontend/src/ts/commandline/lists/sound-on-error.ts b/frontend/src/ts/commandline/lists/sound-on-error.ts index 27024f8f5..8c5628484 100644 --- a/frontend/src/ts/commandline/lists/sound-on-error.ts +++ b/frontend/src/ts/commandline/lists/sound-on-error.ts @@ -8,17 +8,35 @@ const subgroup: MonkeyTypes.CommandsSubgroup = { { id: "setPlaySoundOnErrorOff", display: "off", - configValue: false, + configValue: "off", exec: (): void => { - UpdateConfig.setPlaySoundOnError(false); + UpdateConfig.setPlaySoundOnError("off"); }, }, { - id: "setPlaySoundOnErrorOn", - display: "on", - configValue: true, + id: "setPlaySoundOnError1", + display: "damage", + configValue: "1", exec: (): void => { - UpdateConfig.setPlaySoundOnError(true); + UpdateConfig.setPlaySoundOnError("1"); + SoundController.playError(); + }, + }, + { + id: "setPlaySoundOnError2", + display: "triangle", + configValue: "2", + exec: (): void => { + UpdateConfig.setPlaySoundOnError("2"); + SoundController.playError(); + }, + }, + { + id: "setPlaySoundOnError3", + display: "square", + configValue: "3", + exec: (): void => { + UpdateConfig.setPlaySoundOnError("3"); SoundController.playError(); }, }, diff --git a/frontend/src/ts/config.ts b/frontend/src/ts/config.ts index d53d71817..97ea7d2b7 100644 --- a/frontend/src/ts/config.ts +++ b/frontend/src/ts/config.ts @@ -137,8 +137,13 @@ export function setMode(mode: MonkeyTypes.Mode, nosave?: boolean): boolean { return true; } -export function setPlaySoundOnError(val: boolean, nosave?: boolean): boolean { - if (!isConfigValueValid("play sound on error", val, ["boolean"])) { +export function setPlaySoundOnError( + val: MonkeyTypes.PlaySoundOnError, + nosave?: boolean +): boolean { + if ( + !isConfigValueValid("play sound on error", val, [["off", "1", "2", "3"]]) + ) { return false; } @@ -1985,6 +1990,10 @@ function replaceLegacyValues( configObj.showAverage = "speed"; } + if (typeof configObj.playSoundOnError === "boolean") { + configObj.playSoundOnError = configObj.playSoundOnError ? "1" : "off"; + } + return configObj; } diff --git a/frontend/src/ts/constants/default-config.ts b/frontend/src/ts/constants/default-config.ts index 9ce97f182..352edf770 100644 --- a/frontend/src/ts/constants/default-config.ts +++ b/frontend/src/ts/constants/default-config.ts @@ -59,7 +59,7 @@ export default { alwaysShowWordsHistory: false, singleListCommandLine: "manual", capsLockWarning: true, - playSoundOnError: false, + playSoundOnError: "off", playSoundOnClick: "off", soundVolume: "0.5", startGraphsAtZero: true, diff --git a/frontend/src/ts/controllers/input-controller.ts b/frontend/src/ts/controllers/input-controller.ts index fbb6b4249..37ed38475 100644 --- a/frontend/src/ts/controllers/input-controller.ts +++ b/frontend/src/ts/controllers/input-controller.ts @@ -216,7 +216,7 @@ function handleSpace(): void { } } else { if (!nospace) { - if (!Config.playSoundOnError || Config.blindMode) { + if (Config.playSoundOnError === "off" || Config.blindMode) { Sound.playClick(); } else { Sound.playError(); @@ -550,7 +550,7 @@ function handleChar( if (thisCharCorrect) { Sound.playClick(); } else { - if (!Config.playSoundOnError || Config.blindMode) { + if (Config.playSoundOnError === "off" || Config.blindMode) { Sound.playClick(); } else { Sound.playError(); diff --git a/frontend/src/ts/controllers/sound-controller.ts b/frontend/src/ts/controllers/sound-controller.ts index 4ea7cd850..316e14c5b 100644 --- a/frontend/src/ts/controllers/sound-controller.ts +++ b/frontend/src/ts/controllers/sound-controller.ts @@ -17,12 +17,47 @@ interface ClickSounds { }[]; } -let errorSound: Howler.Howl | null = null; +interface ErrorSounds { + [key: string]: { + sounds: Howler.Howl[]; + counter: number; + }[]; +} + +let errorSounds: ErrorSounds | null = null; let clickSounds: ClickSounds | null = null; function initErrorSound(): void { - if (errorSound !== null) return; - errorSound = new Howl({ src: ["../sound/error.wav"] }); + if (errorSounds !== null) return; + errorSounds = { + 1: [ + { + sounds: [ + new Howl({ src: "../sound/error1/error1_1.wav" }), + new Howl({ src: "../sound/error1/error1_1.wav" }), + ], + counter: 0, + }, + ], + 2: [ + { + sounds: [ + new Howl({ src: "../sound/error2/error2_1.wav" }), + new Howl({ src: "../sound/error2/error2_1.wav" }), + ], + counter: 0, + }, + ], + 3: [ + { + sounds: [ + new Howl({ src: "../sound/error3/error3_1.wav" }), + new Howl({ src: "../sound/error3/error3_1.wav" }), + ], + counter: 0, + }, + ], + }; } function init(): void { @@ -504,10 +539,17 @@ export function playClick(codeOverride?: string): void { } export function playError(): void { - if (!Config.playSoundOnError) return; - if (errorSound === null) initErrorSound(); - (errorSound as Howler.Howl).seek(0); - (errorSound as Howler.Howl).play(); + if (Config.playSoundOnError === "off") return; + if (errorSounds === null) initErrorSound(); + + const randomSound = randomElementFromArray( + (errorSounds as ErrorSounds)[Config.playSoundOnError] + ); + + randomSound.counter++; + if (randomSound.counter === 2) randomSound.counter = 0; + randomSound.sounds[randomSound.counter].seek(0); + randomSound.sounds[randomSound.counter].play(); } function setVolume(val: number): void { diff --git a/frontend/src/ts/pages/settings.ts b/frontend/src/ts/pages/settings.ts index a6fc485aa..d31c68a55 100644 --- a/frontend/src/ts/pages/settings.ts +++ b/frontend/src/ts/pages/settings.ts @@ -251,7 +251,7 @@ async function initGroups(): Promise { UpdateConfig.setPlaySoundOnError, "button", () => { - if (Config.playSoundOnError) Sound.playError(); + if (Config.playSoundOnError !== "off") Sound.playError(); } ) as SettingsGroup; groups["playSoundOnClick"] = new SettingsGroup( diff --git a/frontend/src/ts/test/replay.ts b/frontend/src/ts/test/replay.ts index 5ef88f1c2..e84f81016 100644 --- a/frontend/src/ts/test/replay.ts +++ b/frontend/src/ts/test/replay.ts @@ -87,7 +87,7 @@ export function pauseReplay(): void { function playSound(error = false): void { if (error) { - if (config.playSoundOnError) { + if (config.playSoundOnError !== "off") { Sound.playError(); } else { Sound.playClick(); diff --git a/frontend/src/ts/types/types.d.ts b/frontend/src/ts/types/types.d.ts index 4e45bd533..5a81fe778 100644 --- a/frontend/src/ts/types/types.d.ts +++ b/frontend/src/ts/types/types.d.ts @@ -138,6 +138,8 @@ declare namespace MonkeyTypes { | "12" | "13"; + type PlaySoundOnError = "off" | "1" | "2" | "3"; + type SoundVolume = "0.1" | "0.5" | "1.0"; type PaceCaret = "off" | "average" | "pb" | "last" | "custom" | "daily"; @@ -470,7 +472,7 @@ declare namespace MonkeyTypes { alwaysShowWordsHistory: boolean; singleListCommandLine: SingleListCommandLine; capsLockWarning: boolean; - playSoundOnError: boolean; + playSoundOnError: PlaySoundOnError; playSoundOnClick: PlaySoundOnClick; soundVolume: SoundVolume; startGraphsAtZero: boolean; diff --git a/frontend/static/html/pages/settings.html b/frontend/static/html/pages/settings.html index 9fe203e26..86b7c690e 100644 --- a/frontend/static/html/pages/settings.html +++ b/frontend/static/html/pages/settings.html @@ -1041,7 +1041,7 @@ -
+
play sound on error @@ -1053,7 +1053,7 @@
@@ -1061,11 +1061,27 @@
- on + damage +
+
+ triangle +
+
+ square
diff --git a/frontend/static/sound/error.wav b/frontend/static/sound/error1/error1_1.wav similarity index 100% rename from frontend/static/sound/error.wav rename to frontend/static/sound/error1/error1_1.wav diff --git a/frontend/static/sound/error2/error2_1.wav b/frontend/static/sound/error2/error2_1.wav new file mode 100644 index 000000000..bfe123845 Binary files /dev/null and b/frontend/static/sound/error2/error2_1.wav differ diff --git a/frontend/static/sound/error3/error3_1.wav b/frontend/static/sound/error3/error3_1.wav new file mode 100644 index 000000000..382d7ee34 Binary files /dev/null and b/frontend/static/sound/error3/error3_1.wav differ