Files
2026-09-24 17:57:54 +02:00

88 lines
3.7 KiB
JavaScript

/**
* Klangdateien (Kenney, CC0) und Abspieloptionen je Effekt.
*
* Mehrere Dateien pro Effekt werden zufällig abgewechselt, damit Dauerfeuer nicht
* monoton klingt. Fehlt eine Datei oder kann der Browser OGG nicht dekodieren,
* springt der Synthesizer in `Synth.js` ein.
* @module systems/AudioAssets
*/
/** Pfad relativ zu `static/assets/`. */
export const AUDIO_PATH = 'kenney/audio/';
/** @type {Readonly<Record<string, readonly string[]>>} */
export const SOUND_FILES = Object.freeze({
'shot-carbine': ['laserSmall_000.ogg', 'laserSmall_001.ogg', 'laserSmall_002.ogg'],
'shot-shotgun': ['laserLarge_000.ogg', 'laserLarge_001.ogg'],
'shot-pistol': ['laserRetro_000.ogg', 'laserRetro_001.ogg'],
'turret-shot': ['laserRetro_002.ogg'],
'enemy-shot': ['laserSmall_003.ogg', 'laserSmall_004.ogg'],
'hit-flesh': ['impactSoft_medium_000.ogg', 'impactSoft_medium_001.ogg', 'impactSoft_medium_002.ogg'],
'hit-metal': ['impactMetal_light_000.ogg', 'impactMetal_light_001.ogg', 'impactMetal_light_002.ogg'],
'death-swarm': ['slime_000.ogg', 'slime_001.ogg'],
'death-legion': ['explosionCrunch_000.ogg', 'explosionCrunch_001.ogg'],
'explosion-small': ['explosionCrunch_002.ogg', 'explosionCrunch_003.ogg'],
'explosion-big': ['lowFrequency_explosion_000.ogg'],
'player-hit': ['impactPunch_heavy_000.ogg', 'impactPunch_heavy_001.ogg'],
'player-death': ['lowFrequency_explosion_001.ogg'],
reload: ['impactPlate_light_000.ogg'],
'reload-done': ['click_001.ogg'],
switch: ['select_001.ogg'],
'combo-step': ['tick_001.ogg'],
'combo-fail': ['error_001.ogg'],
'orbital-call': ['confirmation_001.ogg'],
pickup: ['maximize_001.ogg'],
brood: ['slime_001.ogg'],
'ui-click': ['click_001.ogg'],
'ui-confirm': ['confirmation_002.ogg'],
'wave-start': ['jingles_HIT15.ogg'],
'wave-cleared': ['jingles_STEEL07.ogg'],
alarm: ['jingles_HIT11.ogg'],
'game-over': ['jingles_PIZZI07.ogg'],
// Nur synthetisch (kein passendes kurzes Sample): Ausweichrolle, Mörserpfeifen.
dodge: [],
mortar: [],
});
/**
* Lautstärke (0..1), Tonhöhe (1 = original) und Tonhöhenstreuung je Effekt.
* Jingles laufen über den Musikkanal, damit „Musik leiser“ auch sie betrifft.
* @type {Readonly<Record<string, {volume?: number, rate?: number, spread?: number, channel?: 'sfx'|'music'}>>}
*/
export const SOUND_OPTIONS = Object.freeze({
'shot-carbine': { volume: 0.35, spread: 0.08 },
'shot-shotgun': { volume: 0.5, rate: 0.8, spread: 0.06 },
'shot-pistol': { volume: 0.4, spread: 0.06 },
'turret-shot': { volume: 0.22, rate: 1.4, spread: 0.1 },
'enemy-shot': { volume: 0.22, rate: 0.7, spread: 0.1 },
'hit-flesh': { volume: 0.35, spread: 0.15 },
'hit-metal': { volume: 0.3, spread: 0.15 },
'death-swarm': { volume: 0.5, spread: 0.15 },
'death-legion': { volume: 0.4, rate: 1.2, spread: 0.1 },
'explosion-small': { volume: 0.6, spread: 0.1 },
'explosion-big': { volume: 1 },
'player-hit': { volume: 0.6, spread: 0.1 },
'player-death': { volume: 1, rate: 0.8 },
reload: { volume: 0.45 },
'reload-done': { volume: 0.4 },
switch: { volume: 0.4 },
'combo-step': { volume: 0.5 },
'combo-fail': { volume: 0.5 },
'orbital-call': { volume: 0.6 },
pickup: { volume: 0.6 },
brood: { volume: 0.5, rate: 0.7 },
'ui-click': { volume: 0.4 },
'ui-confirm': { volume: 0.5 },
'wave-start': { volume: 0.8, channel: 'music' },
'wave-cleared': { volume: 0.8, channel: 'music' },
alarm: { volume: 0.8, channel: 'music' },
'game-over': { volume: 0.9, channel: 'music' },
dodge: { volume: 0.35 },
mortar: { volume: 0.3 },
});
/** @returns {string[]} Alle benötigten Dateien ohne Duplikate. */
export function allSoundFiles() {
return [...new Set(Object.values(SOUND_FILES).flat())];
}