Files
Adminator 1e51ef7def Nachtrag: alle bisher untracked Ordner + hängende Änderungen mit-committen
- Konzept/, didaktik_geografie/, didaktik_simulation/, v2-modules/, v2-platform/
- 12 code-workspace-Files
- STATUS-*.md
- viele M/D/R-Änderungen an bereits getrackten Files
- .gitignore verstärkt: **/.humaninput/, **/secret_keys.txt

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-08 02:27:02 +02:00

129 lines
3.8 KiB
JavaScript

/**
* Flussmanagement Audio-Modul
* ------------------------------------------------------------------
* Kleines SFX-System auf Basis von <audio>-Elementen mit Pooling.
* Die MP3-Dateien werden zentral via `App/scripts/generate-sounds.py fluss`
* generiert und liegen unter ./assets/sounds/*.mp3.
*
* Nutzung:
* flAudio.play('ui-click');
* flAudio.play('build-deich');
* flAudio.setVolume(0.5);
* flAudio.toggleMute();
*
* Fehlende Dateien lassen sich still schlucken — das Spiel laeuft weiter
* auch wenn MP3s noch nicht generiert sind.
*/
(function () {
'use strict';
var BASE = 'assets/sounds/';
var POOL_SIZE = 3;
var LS_VOL = 'fl-sfx-volume';
var LS_MUTE = 'fl-sfx-muted';
// Key → File
var SOUNDS = {
// UI + Meta
'ui-click': 'ui-click.mp3',
'ui-error': 'ui-error.mp3',
'ui-confirm': 'ui-confirm.mp3',
'achievement': 'achievement.mp3',
'sim-start': 'sim-start.mp3',
// Bau-Sounds
'build-deich': 'build-deich.mp3',
'build-feld': 'build-feld.mp3',
'build-siedlung': 'build-siedlung.mp3',
'build-wald': 'build-wald.mp3',
'build-begradigen': 'build-begradigen.mp3',
'demolish': 'demolish.mp3',
// Wirtschaft / Zeit
'harvest': 'harvest.mp3',
'year-tick': 'year-tick.mp3',
// Wetter / Ereignisse
'event-rain': 'event-rain.mp3',
'event-storm': 'event-storm.mp3',
'event-drought': 'event-drought.mp3',
'event-flood-settlement': 'event-flood-settlement.mp3',
'event-flood-field': 'event-flood-field.mp3',
'event-levee-break': 'event-levee-break.mp3',
'event-tree-die': 'event-tree-die.mp3',
// Durchgangs-Ende
'level-won': 'level-won.mp3',
'level-lost': 'level-lost.mp3',
};
// Werkzeug → Build-Sound
var BUILD_MAP = {
'deich': 'build-deich',
'feld': 'build-feld',
'siedlung': 'build-siedlung',
'wald': 'build-wald',
'begradigen': 'build-begradigen',
'abriss': 'demolish',
};
var _pools = {}, _poolIdx = {};
var _missing = {};
var _volume = parseFloat(localStorage.getItem(LS_VOL));
if (isNaN(_volume)) _volume = 0.55;
var _muted = localStorage.getItem(LS_MUTE) === '1';
function _getPool(key) {
if (_pools[key]) return _pools[key];
var file = SOUNDS[key];
if (!file || _missing[key]) return null;
var arr = [];
for (var i = 0; i < POOL_SIZE; i++) {
var a = new Audio(BASE + file);
a.preload = 'auto';
a.volume = _volume;
a.addEventListener('error', function () { _missing[key] = true; });
arr.push(a);
}
_pools[key] = arr;
_poolIdx[key] = 0;
return arr;
}
function play(key) {
if (_muted) return;
var pool = _getPool(key);
if (!pool) return;
var idx = _poolIdx[key];
var a = pool[idx];
_poolIdx[key] = (idx + 1) % POOL_SIZE;
try { a.currentTime = 0; a.volume = _volume; a.play().catch(function(){}); } catch (e) {}
}
function setVolume(v) {
_volume = Math.max(0, Math.min(1, v));
localStorage.setItem(LS_VOL, _volume + '');
Object.keys(_pools).forEach(function (k) {
_pools[k].forEach(function (a) { a.volume = _volume; });
});
}
function toggleMute() {
_muted = !_muted;
localStorage.setItem(LS_MUTE, _muted ? '1' : '0');
return _muted;
}
function isMuted() { return _muted; }
function getVolume() { return _volume; }
// Tool-Sound passend zum Werkzeug
function playBuild(toolId) {
var key = BUILD_MAP[toolId];
if (key) play(key); else play('ui-click');
}
window.flAudio = {
play: play,
playBuild: playBuild,
setVolume: setVolume,
getVolume: getVolume,
toggleMute: toggleMute,
isMuted: isMuted,
};
})();