using System.Collections.Frozen; using System.Collections.Generic; namespace AcDream.Core.Audio; /// /// Retail's AdminEnvirons code → interface table, /// from the switch in CPlayerSystem::Handle_Admin__Environs @ /// 0x0055DE20 (0x0055E07F..0x0055E2C7). Each case plays /// SoundManager::PlaySoundFromCenter(Sound_UI_*, GetUISoundTable()) after /// checking that the local player physics object and the UI table both exist. /// /// /// This is what players remember as dungeon "music": the server drives the /// chanting, drums, whispers and thunder through these codes. It is not a music /// system — retail has none — but it is the atmosphere channel. /// /// /// /// An explicit table, deliberately. The environ code and the SoundType /// differ by 0x11 for most of the run, but NOT uniformly: codes 0x73 and /// 0x74 have no case at all (retail falls through and plays nothing), so /// 0x75 lands on UI_Squeal (0x84) rather than the 0x86 arithmetic /// would give. Retail's switch is explicit; porting it as an offset would /// mis-map every code from 0x75 up. /// /// public static class EnvironSoundCueMap { private static readonly FrozenDictionary Map = new Dictionary { [0x65u] = SoundId.UI_Roar, [0x66u] = SoundId.UI_Bell, [0x67u] = SoundId.UI_Chant1, [0x68u] = SoundId.UI_Chant2, [0x69u] = SoundId.UI_DarkWhispers1, [0x6Au] = SoundId.UI_DarkWhispers2, [0x6Bu] = SoundId.UI_DarkLaugh, [0x6Cu] = SoundId.UI_DarkWind, [0x6Du] = SoundId.UI_DarkSpeech, [0x6Eu] = SoundId.UI_Drums, [0x6Fu] = SoundId.UI_GhostSpeak, [0x70u] = SoundId.UI_Breathing, [0x71u] = SoundId.UI_Howl, [0x72u] = SoundId.UI_LostSouls, // 0x73 and 0x74: no case in retail's switch — nothing plays. [0x75u] = SoundId.UI_Squeal, [0x76u] = SoundId.UI_Thunder1, [0x77u] = SoundId.UI_Thunder2, [0x78u] = SoundId.UI_Thunder3, [0x79u] = SoundId.UI_Thunder4, [0x7Au] = SoundId.UI_Thunder5, [0x7Bu] = SoundId.UI_Thunder6, }.ToFrozenDictionary(); /// /// Map an AdminEnvirons change type to its interface sound, or false /// when retail's switch has no case for it (including 0x73/0x74 /// inside the run, and every code outside it). /// public static bool TryGetSound(uint changeType, out SoundId sound) => Map.TryGetValue(changeType, out sound); /// Every code retail has a case for. Diagnostic and test use. public static IReadOnlyCollection Codes => Map.Keys; }