Refactor audio module to use built-in music and sound effect identifiers
- Introduced BuiltInMusicModule and BuiltInSfxModule to replace RetailMusicModule and RetailSfxModule. - Updated RetailAssetRegistry and SharewareAssetRegistry to utilize the new built-in modules. - Removed deprecated MusicKey and SfxKey classes, replacing them with Music and SoundEffect enums for better clarity and maintainability. - Adjusted music and sound effect resolution methods to align with the new structure. - Updated audio playback methods in WolfAudio and FlutterAudioAdapter to accept the new Music and SoundEffect types. - Refactored tests to accommodate changes in audio event handling and ensure compatibility with the new identifiers. Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
@@ -9,7 +9,7 @@ import 'package:wolf_3d_dart/src/registry/modules/sfx_module.dart';
|
||||
/// Access version-specific asset IDs through the five typed modules:
|
||||
///
|
||||
/// ```dart
|
||||
/// data.registry.sfx.resolve(SfxKey.pistolFire)
|
||||
/// data.registry.sfx.resolve(SoundEffect.pistolFire)
|
||||
/// data.registry.music.musicForLevel(episode, level)
|
||||
/// data.registry.entities.resolve(EntityKey.guard)
|
||||
/// data.registry.hud.faceForHealth(player.health)
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import 'package:wolf_3d_dart/src/data_types/game_version.dart';
|
||||
import 'package:wolf_3d_dart/src/registry/keys/music.dart';
|
||||
import 'package:wolf_3d_dart/src/registry/modules/music_module.dart';
|
||||
|
||||
/// Built-in music router backed directly by [Music] metadata.
|
||||
class BuiltInMusicModule extends MusicModule {
|
||||
const BuiltInMusicModule(this.version);
|
||||
|
||||
final GameVersion version;
|
||||
|
||||
@override
|
||||
MusicRoute get menuMusic =>
|
||||
MusicRoute(Music.menuTheme.trackIndexFor(version)!);
|
||||
|
||||
@override
|
||||
MusicRoute musicForLevel(int episodeIndex, int levelIndex) {
|
||||
return MusicRoute(
|
||||
Music.trackIndexForLevel(version, episodeIndex, levelIndex)!,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
MusicRoute? resolve(Music key) {
|
||||
final index = key.trackIndexFor(version);
|
||||
return index != null ? MusicRoute(index) : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import 'package:wolf_3d_dart/src/data_types/game_version.dart';
|
||||
import 'package:wolf_3d_dart/src/registry/keys/sound_effect.dart';
|
||||
import 'package:wolf_3d_dart/src/registry/modules/sfx_module.dart';
|
||||
|
||||
/// Built-in sound-slot resolver backed directly by [SoundEffect] metadata.
|
||||
class BuiltInSfxModule extends SfxModule {
|
||||
const BuiltInSfxModule(this.version);
|
||||
|
||||
final GameVersion version;
|
||||
|
||||
@override
|
||||
SoundAssetRef? resolve(SoundEffect key) => SoundAssetRef(key.idFor(version));
|
||||
}
|
||||
@@ -1,20 +1,21 @@
|
||||
import 'package:wolf_3d_dart/src/data_types/game_version.dart';
|
||||
import 'package:wolf_3d_dart/src/registry/asset_registry.dart';
|
||||
import 'package:wolf_3d_dart/src/registry/built_in/built_in_music_module.dart';
|
||||
import 'package:wolf_3d_dart/src/registry/built_in/built_in_sfx_module.dart';
|
||||
import 'package:wolf_3d_dart/src/registry/built_in/retail_entity_module.dart';
|
||||
import 'package:wolf_3d_dart/src/registry/built_in/retail_hud_module.dart';
|
||||
import 'package:wolf_3d_dart/src/registry/built_in/retail_menu_module.dart';
|
||||
import 'package:wolf_3d_dart/src/registry/built_in/retail_music_module.dart';
|
||||
import 'package:wolf_3d_dart/src/registry/built_in/retail_sfx_module.dart';
|
||||
|
||||
/// The canonical [AssetRegistry] for all retail Wolf3D releases.
|
||||
///
|
||||
/// Composes the five retail built-in modules and preserves the original
|
||||
/// id Software asset layout exactly. All other registries and tests that
|
||||
/// id Software asset layout exactly. All other registries and tests that
|
||||
/// need a stable reference should start from this factory.
|
||||
class RetailAssetRegistry extends AssetRegistry {
|
||||
RetailAssetRegistry()
|
||||
: super(
|
||||
sfx: const RetailSfxModule(),
|
||||
music: const RetailMusicModule(),
|
||||
sfx: const BuiltInSfxModule(GameVersion.retail),
|
||||
music: const BuiltInMusicModule(GameVersion.retail),
|
||||
entities: const RetailEntityModule(),
|
||||
hud: const RetailHudModule(),
|
||||
menu: const RetailMenuPicModule(),
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
import 'package:wolf_3d_dart/src/registry/keys/music_key.dart';
|
||||
import 'package:wolf_3d_dart/src/registry/modules/music_module.dart';
|
||||
|
||||
/// Built-in music module for all retail Wolf3D releases (v1.0, v1.1, v1.4).
|
||||
///
|
||||
/// Encodes the original id Software level-to-track routing table and sets
|
||||
/// track index 1 as the menu music, exactly matching the original engine.
|
||||
class RetailMusicModule extends MusicModule {
|
||||
const RetailMusicModule();
|
||||
|
||||
// Original WL_INTER.C music table — 60 entries (6 episodes × 10 levels).
|
||||
static const List<int> _levelMap = [
|
||||
2, 3, 4, 5, 2, 3, 4, 5, 6, 7, // Episode 1
|
||||
8, 9, 10, 11, 8, 9, 11, 10, 6, 12, // Episode 2
|
||||
13, 14, 15, 16, 13, 14, 15, 16, 17, 18, // Episode 3
|
||||
2, 3, 4, 5, 2, 3, 4, 5, 6, 7, // Episode 4
|
||||
8, 9, 10, 11, 8, 9, 11, 10, 6, 12, // Episode 5
|
||||
13, 14, 15, 16, 13, 14, 15, 16, 17, 19, // Episode 6
|
||||
];
|
||||
|
||||
// Named MusicKey → track index for keyed lookups.
|
||||
static final Map<MusicKey, int> _named = {
|
||||
MusicKey.menuTheme: 1,
|
||||
MusicKey.level01: 2,
|
||||
MusicKey.level02: 3,
|
||||
MusicKey.level03: 4,
|
||||
MusicKey.level04: 5,
|
||||
MusicKey.level05: 6,
|
||||
MusicKey.level06: 7,
|
||||
MusicKey.level07: 8,
|
||||
MusicKey.level08: 9,
|
||||
MusicKey.level09: 10,
|
||||
MusicKey.level10: 11,
|
||||
MusicKey.level11: 12,
|
||||
MusicKey.level12: 13,
|
||||
MusicKey.level13: 14,
|
||||
MusicKey.level14: 15,
|
||||
MusicKey.level15: 16,
|
||||
MusicKey.level16: 17,
|
||||
MusicKey.level17: 18,
|
||||
MusicKey.level18: 19,
|
||||
};
|
||||
|
||||
@override
|
||||
MusicRoute get menuMusic => const MusicRoute(1);
|
||||
|
||||
@override
|
||||
MusicRoute musicForLevel(int episodeIndex, int levelIndex) {
|
||||
final flat = episodeIndex * 10 + levelIndex;
|
||||
if (flat >= 0 && flat < _levelMap.length) {
|
||||
return MusicRoute(_levelMap[flat]);
|
||||
}
|
||||
// Wrap for custom episode counts beyond the built-in 6.
|
||||
return MusicRoute(_levelMap[flat % _levelMap.length]);
|
||||
}
|
||||
|
||||
@override
|
||||
MusicRoute? resolve(MusicKey key) {
|
||||
final index = _named[key];
|
||||
return index != null ? MusicRoute(index) : null;
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
import 'package:wolf_3d_dart/src/data_types/sound.dart';
|
||||
import 'package:wolf_3d_dart/src/registry/keys/sfx_key.dart';
|
||||
import 'package:wolf_3d_dart/src/registry/modules/sfx_module.dart';
|
||||
|
||||
/// Built-in SFX module for all retail Wolf3D releases (v1.0, v1.1, v1.4).
|
||||
///
|
||||
/// Maps every [SfxKey] to the corresponding numeric slot from [WolfSound],
|
||||
/// preserving the original id Software audio index layout exactly.
|
||||
class RetailSfxModule extends SfxModule {
|
||||
const RetailSfxModule();
|
||||
|
||||
static final Map<SfxKey, int> _slots = {
|
||||
// --- Doors & Environment ---
|
||||
SfxKey.openDoor: WolfSound.openDoor,
|
||||
SfxKey.closeDoor: WolfSound.closeDoor,
|
||||
SfxKey.pushWall: WolfSound.pushWall,
|
||||
// --- Weapons ---
|
||||
SfxKey.knifeAttack: WolfSound.knifeAttack,
|
||||
SfxKey.pistolFire: WolfSound.pistolFire,
|
||||
SfxKey.machineGunFire: WolfSound.machineGunFire,
|
||||
SfxKey.chainGunFire: WolfSound.gatlingFire,
|
||||
SfxKey.enemyFire: WolfSound.naziFire,
|
||||
// --- Pickups ---
|
||||
SfxKey.getMachineGun: WolfSound.getMachineGun,
|
||||
SfxKey.getAmmo: WolfSound.getAmmo,
|
||||
SfxKey.getChainGun: WolfSound.getGatling,
|
||||
SfxKey.healthSmall: WolfSound.healthSmall,
|
||||
SfxKey.healthLarge: WolfSound.healthLarge,
|
||||
SfxKey.treasure1: WolfSound.treasure1,
|
||||
SfxKey.treasure2: WolfSound.treasure2,
|
||||
SfxKey.treasure3: WolfSound.treasure3,
|
||||
SfxKey.treasure4: WolfSound.treasure4,
|
||||
SfxKey.extraLife: WolfSound.extraLife,
|
||||
// --- Standard Enemies ---
|
||||
SfxKey.guardHalt: WolfSound.guardHalt,
|
||||
SfxKey.dogBark: WolfSound.dogBark,
|
||||
SfxKey.dogDeath: WolfSound.dogDeath,
|
||||
SfxKey.dogAttack: WolfSound.dogAttack,
|
||||
SfxKey.deathScream1: WolfSound.deathScream1,
|
||||
SfxKey.deathScream2: WolfSound.deathScream2,
|
||||
SfxKey.deathScream3: WolfSound.deathScream3,
|
||||
SfxKey.ssAlert: WolfSound.ssSchutzstaffel,
|
||||
SfxKey.ssDeath: WolfSound.ssMeinGott,
|
||||
// --- Bosses ---
|
||||
SfxKey.bossActive: WolfSound.bossActive,
|
||||
SfxKey.hansGrosseDeath: WolfSound.mutti,
|
||||
SfxKey.schabbs: WolfSound.schabbsHas,
|
||||
SfxKey.schabbsDeath: WolfSound.eva,
|
||||
SfxKey.hitlerGreeting: WolfSound.gutenTag,
|
||||
SfxKey.hitlerDeath: WolfSound.scheist,
|
||||
SfxKey.mechaSteps: WolfSound.mechSteps,
|
||||
SfxKey.ottoAlert: WolfSound.spion,
|
||||
SfxKey.gretelDeath: WolfSound.neinSoVass,
|
||||
// --- UI & Progression ---
|
||||
SfxKey.levelComplete: WolfSound.levelDone,
|
||||
SfxKey.endBonus1: WolfSound.endBonus1,
|
||||
SfxKey.endBonus2: WolfSound.endBonus2,
|
||||
SfxKey.noBonus: WolfSound.noBonus,
|
||||
SfxKey.percent100: WolfSound.percent100,
|
||||
};
|
||||
|
||||
@override
|
||||
SoundAssetRef? resolve(SfxKey key) {
|
||||
final slot = _slots[key];
|
||||
return slot != null ? SoundAssetRef(slot) : null;
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,15 @@
|
||||
import 'package:wolf_3d_dart/src/data_types/game_version.dart';
|
||||
import 'package:wolf_3d_dart/src/registry/asset_registry.dart';
|
||||
import 'package:wolf_3d_dart/src/registry/built_in/retail_sfx_module.dart';
|
||||
import 'package:wolf_3d_dart/src/registry/built_in/built_in_music_module.dart';
|
||||
import 'package:wolf_3d_dart/src/registry/built_in/built_in_sfx_module.dart';
|
||||
import 'package:wolf_3d_dart/src/registry/built_in/shareware_entity_module.dart';
|
||||
import 'package:wolf_3d_dart/src/registry/built_in/shareware_hud_module.dart';
|
||||
import 'package:wolf_3d_dart/src/registry/built_in/shareware_menu_module.dart';
|
||||
import 'package:wolf_3d_dart/src/registry/built_in/shareware_music_module.dart';
|
||||
|
||||
/// The [AssetRegistry] for the Wolfenstein 3D v1.4 Shareware release.
|
||||
///
|
||||
/// - SFX slots are identical to retail (same AUDIOT layout).
|
||||
/// - Music routing uses the 10-level shareware table.
|
||||
/// - SFX slots are resolved through version-aware [SoundEffect.idFor].
|
||||
/// - Music routing uses [Music.levelFor] for the 10-level shareware table.
|
||||
/// - Entity definitions are limited to the three shareware enemies.
|
||||
/// - HUD indices are shareware-aware and offset from retail layout.
|
||||
/// - Menu picture indices are resolved via runtime heuristic offset; call
|
||||
@@ -17,8 +18,8 @@ import 'package:wolf_3d_dart/src/registry/built_in/shareware_music_module.dart';
|
||||
class SharewareAssetRegistry extends AssetRegistry {
|
||||
SharewareAssetRegistry({bool strictOriginalShareware = false})
|
||||
: super(
|
||||
sfx: const RetailSfxModule(),
|
||||
music: const SharewareMusicModule(),
|
||||
sfx: const BuiltInSfxModule(GameVersion.shareware),
|
||||
music: const BuiltInMusicModule(GameVersion.shareware),
|
||||
entities: const SharewareEntityModule(),
|
||||
hud: SharewareHudModule(
|
||||
useOriginalWl1Map: strictOriginalShareware,
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
import 'package:wolf_3d_dart/src/registry/keys/music_key.dart';
|
||||
import 'package:wolf_3d_dart/src/registry/modules/music_module.dart';
|
||||
|
||||
/// Built-in music module for the Wolfenstein 3D v1.4 Shareware release.
|
||||
///
|
||||
/// Uses the original id Software shareware level-to-track routing table
|
||||
/// (10 levels, 1 episode) as opposed to the 60-entry retail table.
|
||||
class SharewareMusicModule extends MusicModule {
|
||||
const SharewareMusicModule();
|
||||
|
||||
// Original WL_INTER.C shareware music table (Episode 1 only).
|
||||
static const List<int> _levelMap = [
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
];
|
||||
|
||||
static final Map<MusicKey, int> _named = {
|
||||
MusicKey.menuTheme: 1,
|
||||
MusicKey.level01: 2,
|
||||
MusicKey.level02: 3,
|
||||
MusicKey.level03: 4,
|
||||
MusicKey.level04: 5,
|
||||
MusicKey.level05: 6,
|
||||
MusicKey.level06: 7,
|
||||
};
|
||||
|
||||
@override
|
||||
MusicRoute get menuMusic => const MusicRoute(1);
|
||||
|
||||
@override
|
||||
MusicRoute musicForLevel(int episodeIndex, int levelIndex) {
|
||||
final flat = levelIndex % _levelMap.length;
|
||||
return MusicRoute(_levelMap[flat]);
|
||||
}
|
||||
|
||||
@override
|
||||
MusicRoute? resolve(MusicKey key) {
|
||||
final index = _named[key];
|
||||
return index != null ? MusicRoute(index) : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
import 'package:wolf_3d_dart/src/data_types/game_version.dart';
|
||||
|
||||
/// Canonical music identifiers used by built-in registries.
|
||||
enum Music {
|
||||
// --- Menus & UI ---
|
||||
menuTheme(retailTrackIndex: 1, sharewareTrackIndex: 1),
|
||||
|
||||
// --- Gameplay ---
|
||||
// Generic level-slot keys used when routing by episode+floor index.
|
||||
level01(retailTrackIndex: 2, sharewareTrackIndex: 2),
|
||||
level02(retailTrackIndex: 3, sharewareTrackIndex: 3),
|
||||
level03(retailTrackIndex: 4, sharewareTrackIndex: 4),
|
||||
level04(retailTrackIndex: 5, sharewareTrackIndex: 5),
|
||||
level05(retailTrackIndex: 6, sharewareTrackIndex: 6),
|
||||
level06(retailTrackIndex: 7, sharewareTrackIndex: 7),
|
||||
level07(retailTrackIndex: 8),
|
||||
level08(retailTrackIndex: 9),
|
||||
level09(retailTrackIndex: 10),
|
||||
level10(retailTrackIndex: 11),
|
||||
level11(retailTrackIndex: 12),
|
||||
level12(retailTrackIndex: 13),
|
||||
level13(retailTrackIndex: 14),
|
||||
level14(retailTrackIndex: 15),
|
||||
level15(retailTrackIndex: 16),
|
||||
level16(retailTrackIndex: 17),
|
||||
level17(retailTrackIndex: 18),
|
||||
level18(retailTrackIndex: 19),
|
||||
level19(),
|
||||
level20(),
|
||||
;
|
||||
|
||||
const Music({this.retailTrackIndex, this.sharewareTrackIndex});
|
||||
|
||||
final int? retailTrackIndex;
|
||||
final int? sharewareTrackIndex;
|
||||
|
||||
int? trackIndexFor(GameVersion version) {
|
||||
switch (version) {
|
||||
case GameVersion.shareware:
|
||||
return sharewareTrackIndex;
|
||||
case GameVersion.retail:
|
||||
case GameVersion.spearOfDestiny:
|
||||
case GameVersion.spearOfDestinyDemo:
|
||||
return retailTrackIndex;
|
||||
}
|
||||
}
|
||||
|
||||
static Music levelFor(GameVersion version, int episodeIndex, int levelIndex) {
|
||||
final route = switch (version) {
|
||||
GameVersion.shareware => _sharewareLevelRoute,
|
||||
GameVersion.retail ||
|
||||
GameVersion.spearOfDestiny ||
|
||||
GameVersion.spearOfDestinyDemo => _retailLevelRoute,
|
||||
};
|
||||
|
||||
final flatIndex = switch (version) {
|
||||
GameVersion.shareware => levelIndex,
|
||||
GameVersion.retail ||
|
||||
GameVersion.spearOfDestiny ||
|
||||
GameVersion.spearOfDestinyDemo => episodeIndex * 10 + levelIndex,
|
||||
};
|
||||
|
||||
final normalizedIndex = flatIndex >= 0
|
||||
? flatIndex % route.length
|
||||
: (flatIndex % route.length + route.length) % route.length;
|
||||
|
||||
return route[normalizedIndex];
|
||||
}
|
||||
|
||||
static int? trackIndexForLevel(
|
||||
GameVersion version,
|
||||
int episodeIndex,
|
||||
int levelIndex,
|
||||
) {
|
||||
return levelFor(version, episodeIndex, levelIndex).trackIndexFor(version);
|
||||
}
|
||||
|
||||
static Music? fromTrackIndex(GameVersion version, int trackIndex) {
|
||||
for (final music in values) {
|
||||
if (music.trackIndexFor(version) == trackIndex) {
|
||||
return music;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static const List<Music> _sharewareLevelRoute = [
|
||||
level01,
|
||||
level02,
|
||||
level03,
|
||||
level04,
|
||||
level01,
|
||||
level02,
|
||||
level03,
|
||||
level04,
|
||||
level05,
|
||||
level06,
|
||||
];
|
||||
|
||||
static const List<Music> _retailLevelRoute = [
|
||||
level01,
|
||||
level02,
|
||||
level03,
|
||||
level04,
|
||||
level01,
|
||||
level02,
|
||||
level03,
|
||||
level04,
|
||||
level05,
|
||||
level06,
|
||||
level07,
|
||||
level08,
|
||||
level09,
|
||||
level10,
|
||||
level07,
|
||||
level08,
|
||||
level10,
|
||||
level09,
|
||||
level05,
|
||||
level11,
|
||||
level12,
|
||||
level13,
|
||||
level14,
|
||||
level15,
|
||||
level12,
|
||||
level13,
|
||||
level14,
|
||||
level15,
|
||||
level16,
|
||||
level17,
|
||||
level01,
|
||||
level02,
|
||||
level03,
|
||||
level04,
|
||||
level01,
|
||||
level02,
|
||||
level03,
|
||||
level04,
|
||||
level05,
|
||||
level06,
|
||||
level07,
|
||||
level08,
|
||||
level09,
|
||||
level10,
|
||||
level07,
|
||||
level08,
|
||||
level10,
|
||||
level09,
|
||||
level05,
|
||||
level11,
|
||||
level12,
|
||||
level13,
|
||||
level14,
|
||||
level15,
|
||||
level12,
|
||||
level13,
|
||||
level14,
|
||||
level15,
|
||||
level16,
|
||||
level18,
|
||||
];
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
/// Extensible typed key for music tracks.
|
||||
///
|
||||
/// Built-in Wolf3D music contexts are exposed as named static constants.
|
||||
/// Custom modules can define new keys with `const MusicKey('myTrack')`
|
||||
/// without modifying this class.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// registry.music.resolve(MusicKey.menuTheme)
|
||||
/// ```
|
||||
final class MusicKey {
|
||||
const MusicKey(this._id);
|
||||
|
||||
final String _id;
|
||||
|
||||
// --- Menus & UI ---
|
||||
static const menuTheme = MusicKey('menuTheme');
|
||||
|
||||
// --- Gameplay ---
|
||||
// Generic level-slot keys used when routing by episode+floor index.
|
||||
// The MusicModule maps these to actual IMF track indices.
|
||||
static const level01 = MusicKey('level01');
|
||||
static const level02 = MusicKey('level02');
|
||||
static const level03 = MusicKey('level03');
|
||||
static const level04 = MusicKey('level04');
|
||||
static const level05 = MusicKey('level05');
|
||||
static const level06 = MusicKey('level06');
|
||||
static const level07 = MusicKey('level07');
|
||||
static const level08 = MusicKey('level08');
|
||||
static const level09 = MusicKey('level09');
|
||||
static const level10 = MusicKey('level10');
|
||||
static const level11 = MusicKey('level11');
|
||||
static const level12 = MusicKey('level12');
|
||||
static const level13 = MusicKey('level13');
|
||||
static const level14 = MusicKey('level14');
|
||||
static const level15 = MusicKey('level15');
|
||||
static const level16 = MusicKey('level16');
|
||||
static const level17 = MusicKey('level17');
|
||||
static const level18 = MusicKey('level18');
|
||||
static const level19 = MusicKey('level19');
|
||||
static const level20 = MusicKey('level20');
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) => other is MusicKey && other._id == _id;
|
||||
|
||||
@override
|
||||
int get hashCode => _id.hashCode;
|
||||
|
||||
@override
|
||||
String toString() => 'MusicKey($_id)';
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
/// Extensible typed key for sound effects.
|
||||
///
|
||||
/// Built-in Wolf3D sound effects are exposed as named static constants.
|
||||
/// Custom modules can define new keys with `const SfxKey('myCustomId')`
|
||||
/// without modifying this class.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// registry.sfx.resolve(SfxKey.pistolFire)
|
||||
/// ```
|
||||
final class SfxKey {
|
||||
const SfxKey(this._id);
|
||||
|
||||
final String _id;
|
||||
|
||||
// --- Doors & Environment ---
|
||||
static const openDoor = SfxKey('openDoor');
|
||||
static const closeDoor = SfxKey('closeDoor');
|
||||
static const pushWall = SfxKey('pushWall');
|
||||
|
||||
// --- Weapons ---
|
||||
static const knifeAttack = SfxKey('knifeAttack');
|
||||
static const pistolFire = SfxKey('pistolFire');
|
||||
static const machineGunFire = SfxKey('machineGunFire');
|
||||
static const chainGunFire = SfxKey('chainGunFire');
|
||||
static const enemyFire = SfxKey('enemyFire');
|
||||
|
||||
// --- Pickups ---
|
||||
static const getMachineGun = SfxKey('getMachineGun');
|
||||
static const getAmmo = SfxKey('getAmmo');
|
||||
static const getChainGun = SfxKey('getChainGun');
|
||||
static const healthSmall = SfxKey('healthSmall');
|
||||
static const healthLarge = SfxKey('healthLarge');
|
||||
static const treasure1 = SfxKey('treasure1');
|
||||
static const treasure2 = SfxKey('treasure2');
|
||||
static const treasure3 = SfxKey('treasure3');
|
||||
static const treasure4 = SfxKey('treasure4');
|
||||
static const extraLife = SfxKey('extraLife');
|
||||
|
||||
// --- Standard Enemies ---
|
||||
static const guardHalt = SfxKey('guardHalt');
|
||||
static const dogBark = SfxKey('dogBark');
|
||||
static const dogDeath = SfxKey('dogDeath');
|
||||
static const dogAttack = SfxKey('dogAttack');
|
||||
static const deathScream1 = SfxKey('deathScream1');
|
||||
static const deathScream2 = SfxKey('deathScream2');
|
||||
static const deathScream3 = SfxKey('deathScream3');
|
||||
static const ssAlert = SfxKey('ssAlert');
|
||||
static const ssDeath = SfxKey('ssDeath');
|
||||
|
||||
// --- Bosses ---
|
||||
static const bossActive = SfxKey('bossActive');
|
||||
static const hansGrosseDeath = SfxKey('hansGrosseDeath');
|
||||
static const schabbs = SfxKey('schabbs');
|
||||
static const schabbsDeath = SfxKey('schabbsDeath');
|
||||
static const hitlerGreeting = SfxKey('hitlerGreeting');
|
||||
static const hitlerDeath = SfxKey('hitlerDeath');
|
||||
static const mechaSteps = SfxKey('mechaSteps');
|
||||
static const ottoAlert = SfxKey('ottoAlert');
|
||||
static const gretelDeath = SfxKey('gretelDeath');
|
||||
|
||||
// --- UI & Progression ---
|
||||
static const levelComplete = SfxKey('levelComplete');
|
||||
static const endBonus1 = SfxKey('endBonus1');
|
||||
static const endBonus2 = SfxKey('endBonus2');
|
||||
static const noBonus = SfxKey('noBonus');
|
||||
static const percent100 = SfxKey('percent100');
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) => other is SfxKey && other._id == _id;
|
||||
|
||||
@override
|
||||
int get hashCode => _id.hashCode;
|
||||
|
||||
@override
|
||||
String toString() => 'SfxKey($_id)';
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
import 'package:wolf_3d_dart/src/data_types/game_version.dart';
|
||||
|
||||
/// Canonical sound-effect identifiers used by built-in registries.
|
||||
enum SoundEffect {
|
||||
// --- Doors & Environment ---
|
||||
openDoor(retailId: 8),
|
||||
closeDoor(retailId: 9),
|
||||
pushWall(retailId: 46),
|
||||
|
||||
// --- Weapons ---
|
||||
knifeAttack(retailId: 23),
|
||||
pistolFire(retailId: 24),
|
||||
machineGunFire(retailId: 26),
|
||||
chainGunFire(retailId: 32),
|
||||
enemyFire(retailId: 58),
|
||||
|
||||
// --- Pickups ---
|
||||
getMachineGun(retailId: 30),
|
||||
getAmmo(retailId: 31),
|
||||
getChainGun(retailId: 38),
|
||||
healthSmall(retailId: 33),
|
||||
healthLarge(retailId: 34),
|
||||
treasure1(retailId: 35),
|
||||
treasure2(retailId: 36),
|
||||
treasure3(retailId: 37),
|
||||
treasure4(retailId: 45),
|
||||
extraLife(retailId: 44),
|
||||
|
||||
// --- Standard Enemies ---
|
||||
guardHalt(retailId: 21),
|
||||
dogBark(retailId: 41),
|
||||
dogDeath(retailId: 62),
|
||||
dogAttack(retailId: 68),
|
||||
deathScream1(retailId: 29),
|
||||
deathScream2(retailId: 22),
|
||||
deathScream3(retailId: 25),
|
||||
ssAlert(retailId: 51),
|
||||
ssDeath(retailId: 63),
|
||||
|
||||
// --- Bosses ---
|
||||
bossActive(retailId: 49),
|
||||
hansGrosseDeath(retailId: 50),
|
||||
schabbs(retailId: 64),
|
||||
schabbsDeath(retailId: 54),
|
||||
hitlerGreeting(retailId: 55),
|
||||
hitlerDeath(retailId: 57),
|
||||
mechaSteps(retailId: 70),
|
||||
ottoAlert(retailId: 66),
|
||||
gretelDeath(retailId: 67),
|
||||
|
||||
// --- UI & Progression ---
|
||||
levelComplete(retailId: 40),
|
||||
endBonus1(retailId: 42),
|
||||
endBonus2(retailId: 43),
|
||||
noBonus(retailId: 47),
|
||||
percent100(retailId: 48),
|
||||
;
|
||||
|
||||
const SoundEffect({required this.retailId, int? sharewareId})
|
||||
: sharewareId = sharewareId ?? retailId;
|
||||
|
||||
final int retailId;
|
||||
final int sharewareId;
|
||||
|
||||
int idFor(GameVersion version) {
|
||||
switch (version) {
|
||||
case GameVersion.shareware:
|
||||
return sharewareId;
|
||||
case GameVersion.retail:
|
||||
case GameVersion.spearOfDestiny:
|
||||
case GameVersion.spearOfDestinyDemo:
|
||||
return retailId;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:wolf_3d_dart/src/registry/keys/music_key.dart';
|
||||
import 'package:wolf_3d_dart/src/registry/keys/music.dart';
|
||||
|
||||
/// The resolved reference for a music track: a numeric index into
|
||||
/// [WolfensteinData.music].
|
||||
@@ -19,10 +19,10 @@ class MusicRoute {
|
||||
abstract class MusicModule {
|
||||
const MusicModule();
|
||||
|
||||
/// Resolves a named [MusicKey] to a [MusicRoute].
|
||||
/// Resolves a named [Music] to a [MusicRoute].
|
||||
///
|
||||
/// Returns `null` if the key is not supported by this module.
|
||||
MusicRoute? resolve(MusicKey key);
|
||||
MusicRoute? resolve(Music key);
|
||||
|
||||
/// Resolves the level music track for a given [episodeIndex] and
|
||||
/// zero-based [levelIndex].
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:wolf_3d_dart/src/registry/keys/sfx_key.dart';
|
||||
import 'package:wolf_3d_dart/src/registry/keys/sound_effect.dart';
|
||||
|
||||
/// The resolved reference for a sound effect: a numeric slot index into
|
||||
/// [WolfensteinData.sounds].
|
||||
@@ -11,7 +11,7 @@ class SoundAssetRef {
|
||||
String toString() => 'SoundAssetRef($slotIndex)';
|
||||
}
|
||||
|
||||
/// Owns the mapping from symbolic [SfxKey] identifiers to numeric sound slots.
|
||||
/// Owns the mapping from symbolic [SoundEffect] identifiers to numeric sound slots.
|
||||
///
|
||||
/// Implement this class to provide a custom sound layout for a modded or
|
||||
/// alternate game version. Pass the implementation inside a custom
|
||||
@@ -22,5 +22,5 @@ abstract class SfxModule {
|
||||
/// Resolves [key] to a [SoundAssetRef] containing the numeric slot index.
|
||||
///
|
||||
/// Returns `null` if the key is not supported by this module.
|
||||
SoundAssetRef? resolve(SfxKey key);
|
||||
SoundAssetRef? resolve(SoundEffect key);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user