crimsonland 0.1.0.dev5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- crimson/__init__.py +24 -0
- crimson/assets_fetch.py +60 -0
- crimson/atlas.py +92 -0
- crimson/audio_router.py +155 -0
- crimson/bonuses.py +167 -0
- crimson/camera.py +75 -0
- crimson/cli.py +380 -0
- crimson/creatures/__init__.py +8 -0
- crimson/creatures/ai.py +186 -0
- crimson/creatures/anim.py +173 -0
- crimson/creatures/damage.py +103 -0
- crimson/creatures/runtime.py +1019 -0
- crimson/creatures/spawn.py +2871 -0
- crimson/debug.py +7 -0
- crimson/demo.py +1360 -0
- crimson/demo_trial.py +140 -0
- crimson/effects.py +1086 -0
- crimson/effects_atlas.py +73 -0
- crimson/frontend/__init__.py +1 -0
- crimson/frontend/assets.py +43 -0
- crimson/frontend/boot.py +424 -0
- crimson/frontend/menu.py +700 -0
- crimson/frontend/panels/__init__.py +1 -0
- crimson/frontend/panels/base.py +410 -0
- crimson/frontend/panels/controls.py +132 -0
- crimson/frontend/panels/mods.py +128 -0
- crimson/frontend/panels/options.py +409 -0
- crimson/frontend/panels/play_game.py +627 -0
- crimson/frontend/panels/stats.py +351 -0
- crimson/frontend/transitions.py +31 -0
- crimson/game.py +2533 -0
- crimson/game_modes.py +15 -0
- crimson/game_world.py +652 -0
- crimson/gameplay.py +2467 -0
- crimson/input_codes.py +176 -0
- crimson/modes/__init__.py +1 -0
- crimson/modes/base_gameplay_mode.py +219 -0
- crimson/modes/quest_mode.py +502 -0
- crimson/modes/rush_mode.py +300 -0
- crimson/modes/survival_mode.py +792 -0
- crimson/modes/tutorial_mode.py +648 -0
- crimson/modes/typo_mode.py +472 -0
- crimson/paths.py +23 -0
- crimson/perks.py +828 -0
- crimson/persistence/__init__.py +1 -0
- crimson/persistence/highscores.py +385 -0
- crimson/persistence/save_status.py +245 -0
- crimson/player_damage.py +77 -0
- crimson/projectiles.py +1133 -0
- crimson/quests/__init__.py +18 -0
- crimson/quests/helpers.py +147 -0
- crimson/quests/registry.py +49 -0
- crimson/quests/results.py +164 -0
- crimson/quests/runtime.py +91 -0
- crimson/quests/tier1.py +620 -0
- crimson/quests/tier2.py +652 -0
- crimson/quests/tier3.py +579 -0
- crimson/quests/tier4.py +721 -0
- crimson/quests/tier5.py +886 -0
- crimson/quests/timeline.py +115 -0
- crimson/quests/types.py +70 -0
- crimson/render/__init__.py +1 -0
- crimson/render/terrain_fx.py +88 -0
- crimson/render/world_renderer.py +1941 -0
- crimson/sim/__init__.py +1 -0
- crimson/sim/world_defs.py +67 -0
- crimson/sim/world_state.py +422 -0
- crimson/terrain_assets.py +19 -0
- crimson/tutorial/__init__.py +12 -0
- crimson/tutorial/timeline.py +291 -0
- crimson/typo/__init__.py +2 -0
- crimson/typo/names.py +233 -0
- crimson/typo/player.py +43 -0
- crimson/typo/spawns.py +73 -0
- crimson/typo/typing.py +52 -0
- crimson/ui/__init__.py +3 -0
- crimson/ui/cursor.py +95 -0
- crimson/ui/demo_trial_overlay.py +235 -0
- crimson/ui/game_over.py +660 -0
- crimson/ui/hud.py +601 -0
- crimson/ui/perk_menu.py +388 -0
- crimson/views/__init__.py +40 -0
- crimson/views/aim_debug.py +276 -0
- crimson/views/animations.py +274 -0
- crimson/views/arsenal_debug.py +404 -0
- crimson/views/audio_bootstrap.py +47 -0
- crimson/views/bonuses.py +201 -0
- crimson/views/camera_debug.py +359 -0
- crimson/views/camera_shake.py +229 -0
- crimson/views/corpse_stamp_debug.py +324 -0
- crimson/views/decals_debug.py +739 -0
- crimson/views/empty.py +19 -0
- crimson/views/fonts.py +114 -0
- crimson/views/game_over.py +117 -0
- crimson/views/ground.py +259 -0
- crimson/views/lighting_debug.py +1166 -0
- crimson/views/particles.py +293 -0
- crimson/views/perk_menu_debug.py +430 -0
- crimson/views/perks.py +398 -0
- crimson/views/player.py +434 -0
- crimson/views/player_sprite_debug.py +314 -0
- crimson/views/projectile_fx.py +609 -0
- crimson/views/projectile_render_debug.py +393 -0
- crimson/views/projectiles.py +221 -0
- crimson/views/quest_title_overlay.py +108 -0
- crimson/views/registry.py +34 -0
- crimson/views/rush.py +16 -0
- crimson/views/small_font_debug.py +204 -0
- crimson/views/spawn_plan.py +363 -0
- crimson/views/sprites.py +214 -0
- crimson/views/survival.py +15 -0
- crimson/views/terrain.py +132 -0
- crimson/views/ui.py +123 -0
- crimson/views/wicons.py +166 -0
- crimson/weapon_sfx.py +63 -0
- crimson/weapons.py +860 -0
- crimsonland-0.1.0.dev5.dist-info/METADATA +9 -0
- crimsonland-0.1.0.dev5.dist-info/RECORD +139 -0
- crimsonland-0.1.0.dev5.dist-info/WHEEL +4 -0
- crimsonland-0.1.0.dev5.dist-info/entry_points.txt +4 -0
- grim/__init__.py +20 -0
- grim/app.py +92 -0
- grim/assets.py +231 -0
- grim/audio.py +106 -0
- grim/config.py +294 -0
- grim/console.py +737 -0
- grim/fonts/__init__.py +7 -0
- grim/fonts/grim_mono.py +111 -0
- grim/fonts/small.py +120 -0
- grim/input.py +44 -0
- grim/jaz.py +103 -0
- grim/math.py +17 -0
- grim/music.py +403 -0
- grim/paq.py +76 -0
- grim/rand.py +37 -0
- grim/sfx.py +276 -0
- grim/sfx_map.py +103 -0
- grim/terrain_render.py +840 -0
- grim/view.py +16 -0
grim/sfx.py
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
import random
|
|
6
|
+
from typing import Iterable
|
|
7
|
+
|
|
8
|
+
import pyray as rl
|
|
9
|
+
|
|
10
|
+
from .console import ConsoleState
|
|
11
|
+
from . import paq
|
|
12
|
+
from . import sfx_map
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
SFX_PAK_NAME = "sfx.paq"
|
|
16
|
+
DEFAULT_VOICE_COUNT = 4
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass(slots=True)
|
|
20
|
+
class SfxSample:
|
|
21
|
+
entry_name: str
|
|
22
|
+
source: rl.Sound
|
|
23
|
+
aliases: list[rl.Sound]
|
|
24
|
+
next_voice: int = 0
|
|
25
|
+
|
|
26
|
+
def voices(self) -> Iterable[rl.Sound]:
|
|
27
|
+
yield self.source
|
|
28
|
+
yield from self.aliases
|
|
29
|
+
|
|
30
|
+
def acquire_voice(self) -> rl.Sound:
|
|
31
|
+
for voice in self.voices():
|
|
32
|
+
if not rl.is_sound_playing(voice):
|
|
33
|
+
return voice
|
|
34
|
+
voices = [self.source, *self.aliases]
|
|
35
|
+
idx = self.next_voice % len(voices)
|
|
36
|
+
self.next_voice += 1
|
|
37
|
+
return voices[idx]
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass(slots=True)
|
|
41
|
+
class SfxState:
|
|
42
|
+
ready: bool
|
|
43
|
+
enabled: bool
|
|
44
|
+
volume: float
|
|
45
|
+
voice_count: int
|
|
46
|
+
entries: dict[str, bytes]
|
|
47
|
+
directory: Path | None
|
|
48
|
+
key_to_entry: dict[str, str]
|
|
49
|
+
variants: dict[str, tuple[str, ...]]
|
|
50
|
+
samples: dict[str, SfxSample]
|
|
51
|
+
missing_keys: set[str]
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def init_sfx_state(
|
|
55
|
+
*,
|
|
56
|
+
ready: bool,
|
|
57
|
+
enabled: bool,
|
|
58
|
+
volume: float,
|
|
59
|
+
voice_count: int = DEFAULT_VOICE_COUNT,
|
|
60
|
+
) -> SfxState:
|
|
61
|
+
return SfxState(
|
|
62
|
+
ready=ready,
|
|
63
|
+
enabled=enabled,
|
|
64
|
+
volume=float(volume),
|
|
65
|
+
voice_count=max(1, int(voice_count)),
|
|
66
|
+
entries={},
|
|
67
|
+
directory=None,
|
|
68
|
+
key_to_entry={},
|
|
69
|
+
variants={},
|
|
70
|
+
samples={},
|
|
71
|
+
missing_keys=set(),
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _derive_sfx_key(entry_name: str) -> str:
|
|
76
|
+
return "sfx_" + Path(entry_name).stem.lower()
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _derive_sfx_base(key: str) -> str | None:
|
|
80
|
+
if not key.startswith("sfx_"):
|
|
81
|
+
return None
|
|
82
|
+
stem = key[4:]
|
|
83
|
+
if len(stem) < 3:
|
|
84
|
+
return None
|
|
85
|
+
if "_" not in stem:
|
|
86
|
+
return None
|
|
87
|
+
base, suffix = stem.rsplit("_", 1)
|
|
88
|
+
if not suffix.isdigit():
|
|
89
|
+
return None
|
|
90
|
+
return "sfx_" + base
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _build_variants(keys: Iterable[str]) -> dict[str, tuple[str, ...]]:
|
|
94
|
+
base_to_keys: dict[str, list[str]] = {}
|
|
95
|
+
for key in keys:
|
|
96
|
+
base = _derive_sfx_base(key)
|
|
97
|
+
if base is None:
|
|
98
|
+
continue
|
|
99
|
+
base_to_keys.setdefault(base, []).append(key)
|
|
100
|
+
return {base: tuple(sorted(values)) for base, values in base_to_keys.items()}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def load_sfx_index(state: SfxState, assets_dir: Path, console: ConsoleState) -> None:
|
|
104
|
+
if not state.ready or not state.enabled:
|
|
105
|
+
return
|
|
106
|
+
|
|
107
|
+
sfx_dir = assets_dir / "sfx"
|
|
108
|
+
if sfx_dir.exists() and sfx_dir.is_dir():
|
|
109
|
+
entry_names: list[str] = []
|
|
110
|
+
for path in sorted(sfx_dir.iterdir()):
|
|
111
|
+
if not path.is_file():
|
|
112
|
+
continue
|
|
113
|
+
if path.suffix.lower() not in {".ogg", ".wav"}:
|
|
114
|
+
continue
|
|
115
|
+
entry_names.append(path.name)
|
|
116
|
+
|
|
117
|
+
state.directory = sfx_dir
|
|
118
|
+
state.entries.clear()
|
|
119
|
+
available = set(entry_names)
|
|
120
|
+
state.key_to_entry = {_derive_sfx_key(name): name for name in entry_names}
|
|
121
|
+
for key, name in sfx_map.SFX_ENTRY_BY_KEY.items():
|
|
122
|
+
if name in available:
|
|
123
|
+
state.key_to_entry[key] = name
|
|
124
|
+
state.variants = _build_variants(state.key_to_entry.keys())
|
|
125
|
+
console.log.log(f"audio: sfx indexed {len(entry_names)} files from {sfx_dir}")
|
|
126
|
+
console.log.flush()
|
|
127
|
+
return
|
|
128
|
+
|
|
129
|
+
paq_path = assets_dir / SFX_PAK_NAME
|
|
130
|
+
if not paq_path.exists():
|
|
131
|
+
raise FileNotFoundError(f"audio: missing {SFX_PAK_NAME} in {assets_dir}")
|
|
132
|
+
entries: dict[str, bytes] = {}
|
|
133
|
+
for name, data in paq.iter_entries(paq_path):
|
|
134
|
+
entries[name.replace("\\", "/")] = data
|
|
135
|
+
state.directory = None
|
|
136
|
+
state.entries = entries
|
|
137
|
+
available = set(entries.keys())
|
|
138
|
+
state.key_to_entry = {_derive_sfx_key(name): name for name in entries.keys()}
|
|
139
|
+
for key, name in sfx_map.SFX_ENTRY_BY_KEY.items():
|
|
140
|
+
if name in available:
|
|
141
|
+
state.key_to_entry[key] = name
|
|
142
|
+
state.variants = _build_variants(state.key_to_entry.keys())
|
|
143
|
+
console.log.log(f"audio: sfx indexed {len(entries)} entries from {SFX_PAK_NAME}")
|
|
144
|
+
console.log.flush()
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def _normalize_sfx_key(state: SfxState, key: str) -> str | None:
|
|
148
|
+
key = key.strip().lstrip("_")
|
|
149
|
+
if not key:
|
|
150
|
+
return None
|
|
151
|
+
key = sfx_map.SFX_KEY_ALIASES.get(key, key)
|
|
152
|
+
if "_alias_" in key:
|
|
153
|
+
key = key.split("_alias_", 1)[0]
|
|
154
|
+
if key in state.key_to_entry:
|
|
155
|
+
return key
|
|
156
|
+
if key.endswith("_alt"):
|
|
157
|
+
cand = key[: -len("_alt")]
|
|
158
|
+
if cand in state.key_to_entry:
|
|
159
|
+
return cand
|
|
160
|
+
return None
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _load_sample(state: SfxState, key: str) -> SfxSample | None:
|
|
164
|
+
resolved = _normalize_sfx_key(state, key)
|
|
165
|
+
if resolved is None:
|
|
166
|
+
return None
|
|
167
|
+
existing = state.samples.get(resolved)
|
|
168
|
+
if existing is not None:
|
|
169
|
+
return existing
|
|
170
|
+
|
|
171
|
+
entry_name = state.key_to_entry.get(resolved)
|
|
172
|
+
if entry_name is None:
|
|
173
|
+
return None
|
|
174
|
+
|
|
175
|
+
if state.directory is not None:
|
|
176
|
+
path = state.directory / entry_name
|
|
177
|
+
source = rl.load_sound(str(path))
|
|
178
|
+
else:
|
|
179
|
+
data = state.entries.get(entry_name)
|
|
180
|
+
if data is None:
|
|
181
|
+
return None
|
|
182
|
+
file_type = Path(entry_name).suffix.lower()
|
|
183
|
+
wave = rl.load_wave_from_memory(file_type, data, len(data))
|
|
184
|
+
source = rl.load_sound_from_wave(wave)
|
|
185
|
+
rl.unload_wave(wave)
|
|
186
|
+
|
|
187
|
+
aliases = [rl.load_sound_alias(source) for _ in range(max(1, state.voice_count) - 1)]
|
|
188
|
+
|
|
189
|
+
sample = SfxSample(entry_name=entry_name, source=source, aliases=aliases)
|
|
190
|
+
for voice in sample.voices():
|
|
191
|
+
rl.set_sound_volume(voice, state.volume)
|
|
192
|
+
state.samples[resolved] = sample
|
|
193
|
+
return sample
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def play_sfx(
|
|
197
|
+
state: SfxState | None,
|
|
198
|
+
key: str | None,
|
|
199
|
+
*,
|
|
200
|
+
rng: random.Random | None = None,
|
|
201
|
+
allow_variants: bool = True,
|
|
202
|
+
) -> None:
|
|
203
|
+
if state is None or not state.ready or not state.enabled:
|
|
204
|
+
return
|
|
205
|
+
if not key:
|
|
206
|
+
return
|
|
207
|
+
|
|
208
|
+
resolved = _normalize_sfx_key(state, key)
|
|
209
|
+
if resolved is None:
|
|
210
|
+
state.missing_keys.add(key)
|
|
211
|
+
return
|
|
212
|
+
|
|
213
|
+
if allow_variants:
|
|
214
|
+
base = _derive_sfx_base(resolved) or resolved
|
|
215
|
+
variants = state.variants.get(base)
|
|
216
|
+
if variants:
|
|
217
|
+
rng = rng or random
|
|
218
|
+
resolved = rng.choice(variants)
|
|
219
|
+
|
|
220
|
+
sample = _load_sample(state, resolved)
|
|
221
|
+
if sample is None:
|
|
222
|
+
state.missing_keys.add(resolved)
|
|
223
|
+
return
|
|
224
|
+
rl.play_sound(sample.acquire_voice())
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def sfx_key_for_id(sfx_id: int) -> str | None:
|
|
228
|
+
if sfx_id < 0:
|
|
229
|
+
return None
|
|
230
|
+
if sfx_id >= len(sfx_map.SFX_KEY_BY_ID):
|
|
231
|
+
return None
|
|
232
|
+
return sfx_map.SFX_KEY_BY_ID[sfx_id]
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def play_sfx_id(state: SfxState | None, sfx_id: int, *, rng: random.Random | None = None) -> None:
|
|
236
|
+
key = sfx_key_for_id(int(sfx_id))
|
|
237
|
+
if key is None:
|
|
238
|
+
return
|
|
239
|
+
play_sfx(state, key, rng=rng, allow_variants=False)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def set_sfx_volume(state: SfxState | None, volume: float) -> None:
|
|
243
|
+
if state is None:
|
|
244
|
+
return
|
|
245
|
+
volume = float(volume)
|
|
246
|
+
if volume < 0.0:
|
|
247
|
+
volume = 0.0
|
|
248
|
+
if volume > 1.0:
|
|
249
|
+
volume = 1.0
|
|
250
|
+
state.volume = volume
|
|
251
|
+
for sample in state.samples.values():
|
|
252
|
+
for voice in sample.voices():
|
|
253
|
+
rl.set_sound_volume(voice, state.volume)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def shutdown_sfx(state: SfxState) -> None:
|
|
257
|
+
if not state.ready:
|
|
258
|
+
return
|
|
259
|
+
for sample in state.samples.values():
|
|
260
|
+
for alias in sample.aliases:
|
|
261
|
+
try:
|
|
262
|
+
rl.stop_sound(alias)
|
|
263
|
+
rl.unload_sound_alias(alias)
|
|
264
|
+
except Exception:
|
|
265
|
+
pass
|
|
266
|
+
try:
|
|
267
|
+
rl.stop_sound(sample.source)
|
|
268
|
+
rl.unload_sound(sample.source)
|
|
269
|
+
except Exception:
|
|
270
|
+
pass
|
|
271
|
+
state.samples.clear()
|
|
272
|
+
state.entries.clear()
|
|
273
|
+
state.key_to_entry.clear()
|
|
274
|
+
state.variants.clear()
|
|
275
|
+
state.missing_keys.clear()
|
|
276
|
+
state.directory = None
|
grim/sfx_map.py
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Final
|
|
4
|
+
|
|
5
|
+
# Extracted from `audio_init_sfx` (FUN_0043caa0) in `crimsonland.exe`.
|
|
6
|
+
# `sfx_load_sample()` allocates the first free slot, so the load order defines stable ids.
|
|
7
|
+
|
|
8
|
+
SFX_LOAD_ORDER: Final[tuple[tuple[str, str], ...]] = (
|
|
9
|
+
("sfx_trooper_inpain_01", "trooper_inPain_01.ogg"),
|
|
10
|
+
("sfx_trooper_inpain_02", "trooper_inPain_02.ogg"),
|
|
11
|
+
("sfx_trooper_inpain_03", "trooper_inPain_03.ogg"),
|
|
12
|
+
("sfx_trooper_die_01", "trooper_die_01.ogg"),
|
|
13
|
+
("sfx_trooper_die_02", "trooper_die_02.ogg"),
|
|
14
|
+
("sfx_trooper_die_03", "trooper_die_03.ogg"),
|
|
15
|
+
("sfx_zombie_die_01", "zombie_die_01.ogg"),
|
|
16
|
+
("sfx_zombie_die_02", "zombie_die_02.ogg"),
|
|
17
|
+
("sfx_zombie_die_03", "zombie_die_03.ogg"),
|
|
18
|
+
("sfx_zombie_die_04", "zombie_die_04.ogg"),
|
|
19
|
+
("sfx_zombie_attack_01", "zombie_attack_01.ogg"),
|
|
20
|
+
("sfx_zombie_attack_02", "zombie_attack_02.ogg"),
|
|
21
|
+
("sfx_alien_die_01", "alien_die_01.ogg"),
|
|
22
|
+
("sfx_alien_die_02", "alien_die_02.ogg"),
|
|
23
|
+
("sfx_alien_die_03", "alien_die_03.ogg"),
|
|
24
|
+
("sfx_alien_die_04", "alien_die_04.ogg"),
|
|
25
|
+
("sfx_alien_attack_01", "alien_attack_01.ogg"),
|
|
26
|
+
("sfx_alien_attack_02", "alien_attack_02.ogg"),
|
|
27
|
+
("sfx_lizard_die_01", "lizard_die_01.ogg"),
|
|
28
|
+
("sfx_lizard_die_02", "lizard_die_02.ogg"),
|
|
29
|
+
("sfx_lizard_die_03", "lizard_die_03.ogg"),
|
|
30
|
+
("sfx_lizard_die_04", "lizard_die_04.ogg"),
|
|
31
|
+
("sfx_lizard_attack_01", "lizard_attack_01.ogg"),
|
|
32
|
+
("sfx_lizard_attack_02", "lizard_attack_02.ogg"),
|
|
33
|
+
("sfx_spider_die_01", "spider_die_01.ogg"),
|
|
34
|
+
("sfx_spider_die_02", "spider_die_02.ogg"),
|
|
35
|
+
("sfx_spider_die_03", "spider_die_03.ogg"),
|
|
36
|
+
("sfx_spider_die_04", "spider_die_04.ogg"),
|
|
37
|
+
("sfx_spider_attack_01", "spider_attack_01.ogg"),
|
|
38
|
+
("sfx_spider_attack_02", "spider_attack_02.ogg"),
|
|
39
|
+
("sfx_pistol_fire", "pistol_fire.ogg"),
|
|
40
|
+
("sfx_pistol_reload", "pistol_reload.ogg"),
|
|
41
|
+
("sfx_shotgun_fire", "shotgun_fire.ogg"),
|
|
42
|
+
("sfx_shotgun_reload", "shotgun_reload.ogg"),
|
|
43
|
+
("sfx_autorifle_fire", "autorifle_fire.ogg"),
|
|
44
|
+
("sfx_autorifle_reload", "autorifle_reload.ogg"),
|
|
45
|
+
("sfx_gauss_fire", "gauss_fire.ogg"),
|
|
46
|
+
("sfx_hrpm_fire", "hrpm_fire.ogg"),
|
|
47
|
+
("sfx_shock_fire", "shock_fire.ogg"),
|
|
48
|
+
("sfx_plasmaminigun_fire", "plasmaMinigun_fire.ogg"),
|
|
49
|
+
("sfx_plasmashotgun_fire", "plasmaShotgun_fire.ogg"),
|
|
50
|
+
("sfx_pulse_fire", "pulse_fire.ogg"),
|
|
51
|
+
("sfx_flamer_fire_01", "flamer_fire_01.ogg"),
|
|
52
|
+
("sfx_flamer_fire_02", "flamer_fire_02.ogg"),
|
|
53
|
+
("sfx_shock_reload", "shock_reload.ogg"),
|
|
54
|
+
("sfx_shock_fire_alt", "shock_fire.ogg"),
|
|
55
|
+
("sfx_shockminigun_fire", "shockMinigun_fire.ogg"),
|
|
56
|
+
("sfx_rocket_fire", "rocket_fire.ogg"),
|
|
57
|
+
("sfx_rocketmini_fire", "rocketmini_fire.ogg"),
|
|
58
|
+
("sfx_autorifle_reload_alt", "autorifle_reload.ogg"),
|
|
59
|
+
("sfx_bullet_hit_01", "bullet_hit_01.ogg"),
|
|
60
|
+
("sfx_bullet_hit_02", "bullet_hit_02.ogg"),
|
|
61
|
+
("sfx_bullet_hit_03", "bullet_hit_03.ogg"),
|
|
62
|
+
("sfx_bullet_hit_04", "bullet_hit_04.ogg"),
|
|
63
|
+
("sfx_bullet_hit_05", "bullet_hit_05.ogg"),
|
|
64
|
+
("sfx_bullet_hit_06", "bullet_hit_06.ogg"),
|
|
65
|
+
("sfx_shock_hit_01", "shock_hit_01.ogg"),
|
|
66
|
+
("sfx_explosion_small", "explosion_small.ogg"),
|
|
67
|
+
("sfx_explosion_medium", "explosion_medium.ogg"),
|
|
68
|
+
("sfx_explosion_large", "explosion_large.ogg"),
|
|
69
|
+
("sfx_shockwave", "shockwave.ogg"),
|
|
70
|
+
("sfx_questhit", "questHit.ogg"),
|
|
71
|
+
("sfx_ui_bonus", "ui_bonus.ogg"),
|
|
72
|
+
("sfx_ui_buttonclick", "ui_buttonClick.ogg"),
|
|
73
|
+
("sfx_ui_panelclick", "ui_panelClick.ogg"),
|
|
74
|
+
("sfx_ui_levelup", "ui_levelUp.ogg"),
|
|
75
|
+
("sfx_ui_typeclick_01", "ui_typeClick_01.ogg"),
|
|
76
|
+
("sfx_ui_typeclick_02", "ui_typeClick_02.ogg"),
|
|
77
|
+
("sfx_ui_typeenter", "ui_typeEnter.ogg"),
|
|
78
|
+
("sfx_ui_clink_01", "ui_clink_01.ogg"),
|
|
79
|
+
("sfx_bloodspill_01", "bloodSpill_01.ogg"),
|
|
80
|
+
("sfx_bloodspill_02", "bloodSpill_02.ogg"),
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
SFX_KEY_ALIASES: Final[dict[str, str]] = {
|
|
84
|
+
"sfx_trooper_inpain_01_alias_0": "sfx_trooper_inpain_01",
|
|
85
|
+
"sfx_trooper_inpain_01_alias_1": "sfx_trooper_inpain_01",
|
|
86
|
+
"sfx_trooper_inpain_01_alias_2": "sfx_trooper_inpain_01",
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
# Present in `sfx.paq`, but not loaded by `audio_init_sfx` in 1.9.93 (unused or runtime-loaded).
|
|
90
|
+
SFX_UNREFERENCED: Final[tuple[tuple[str, str], ...]] = (
|
|
91
|
+
("sfx_trooper_inpain_04", "trooper_inPain_04.ogg"),
|
|
92
|
+
("sfx_trooper_die_04", "trooper_die_04.ogg"),
|
|
93
|
+
("sfx_flamer_fire_start", "flamer_fire_start.ogg"),
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
SFX_KEY_BY_ID: Final[tuple[str, ...]] = tuple(key for key, _entry in SFX_LOAD_ORDER)
|
|
97
|
+
SFX_ID_BY_KEY: Final[dict[str, int]] = {key: idx for idx, (key, _entry) in enumerate(SFX_LOAD_ORDER)}
|
|
98
|
+
|
|
99
|
+
SFX_ENTRY_BY_KEY: Final[dict[str, str]] = {
|
|
100
|
+
**{key: entry for key, entry in SFX_LOAD_ORDER},
|
|
101
|
+
**{key: entry for key, entry in SFX_UNREFERENCED},
|
|
102
|
+
}
|
|
103
|
+
|