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.
Files changed (139) hide show
  1. crimson/__init__.py +24 -0
  2. crimson/assets_fetch.py +60 -0
  3. crimson/atlas.py +92 -0
  4. crimson/audio_router.py +155 -0
  5. crimson/bonuses.py +167 -0
  6. crimson/camera.py +75 -0
  7. crimson/cli.py +380 -0
  8. crimson/creatures/__init__.py +8 -0
  9. crimson/creatures/ai.py +186 -0
  10. crimson/creatures/anim.py +173 -0
  11. crimson/creatures/damage.py +103 -0
  12. crimson/creatures/runtime.py +1019 -0
  13. crimson/creatures/spawn.py +2871 -0
  14. crimson/debug.py +7 -0
  15. crimson/demo.py +1360 -0
  16. crimson/demo_trial.py +140 -0
  17. crimson/effects.py +1086 -0
  18. crimson/effects_atlas.py +73 -0
  19. crimson/frontend/__init__.py +1 -0
  20. crimson/frontend/assets.py +43 -0
  21. crimson/frontend/boot.py +424 -0
  22. crimson/frontend/menu.py +700 -0
  23. crimson/frontend/panels/__init__.py +1 -0
  24. crimson/frontend/panels/base.py +410 -0
  25. crimson/frontend/panels/controls.py +132 -0
  26. crimson/frontend/panels/mods.py +128 -0
  27. crimson/frontend/panels/options.py +409 -0
  28. crimson/frontend/panels/play_game.py +627 -0
  29. crimson/frontend/panels/stats.py +351 -0
  30. crimson/frontend/transitions.py +31 -0
  31. crimson/game.py +2533 -0
  32. crimson/game_modes.py +15 -0
  33. crimson/game_world.py +652 -0
  34. crimson/gameplay.py +2467 -0
  35. crimson/input_codes.py +176 -0
  36. crimson/modes/__init__.py +1 -0
  37. crimson/modes/base_gameplay_mode.py +219 -0
  38. crimson/modes/quest_mode.py +502 -0
  39. crimson/modes/rush_mode.py +300 -0
  40. crimson/modes/survival_mode.py +792 -0
  41. crimson/modes/tutorial_mode.py +648 -0
  42. crimson/modes/typo_mode.py +472 -0
  43. crimson/paths.py +23 -0
  44. crimson/perks.py +828 -0
  45. crimson/persistence/__init__.py +1 -0
  46. crimson/persistence/highscores.py +385 -0
  47. crimson/persistence/save_status.py +245 -0
  48. crimson/player_damage.py +77 -0
  49. crimson/projectiles.py +1133 -0
  50. crimson/quests/__init__.py +18 -0
  51. crimson/quests/helpers.py +147 -0
  52. crimson/quests/registry.py +49 -0
  53. crimson/quests/results.py +164 -0
  54. crimson/quests/runtime.py +91 -0
  55. crimson/quests/tier1.py +620 -0
  56. crimson/quests/tier2.py +652 -0
  57. crimson/quests/tier3.py +579 -0
  58. crimson/quests/tier4.py +721 -0
  59. crimson/quests/tier5.py +886 -0
  60. crimson/quests/timeline.py +115 -0
  61. crimson/quests/types.py +70 -0
  62. crimson/render/__init__.py +1 -0
  63. crimson/render/terrain_fx.py +88 -0
  64. crimson/render/world_renderer.py +1941 -0
  65. crimson/sim/__init__.py +1 -0
  66. crimson/sim/world_defs.py +67 -0
  67. crimson/sim/world_state.py +422 -0
  68. crimson/terrain_assets.py +19 -0
  69. crimson/tutorial/__init__.py +12 -0
  70. crimson/tutorial/timeline.py +291 -0
  71. crimson/typo/__init__.py +2 -0
  72. crimson/typo/names.py +233 -0
  73. crimson/typo/player.py +43 -0
  74. crimson/typo/spawns.py +73 -0
  75. crimson/typo/typing.py +52 -0
  76. crimson/ui/__init__.py +3 -0
  77. crimson/ui/cursor.py +95 -0
  78. crimson/ui/demo_trial_overlay.py +235 -0
  79. crimson/ui/game_over.py +660 -0
  80. crimson/ui/hud.py +601 -0
  81. crimson/ui/perk_menu.py +388 -0
  82. crimson/views/__init__.py +40 -0
  83. crimson/views/aim_debug.py +276 -0
  84. crimson/views/animations.py +274 -0
  85. crimson/views/arsenal_debug.py +404 -0
  86. crimson/views/audio_bootstrap.py +47 -0
  87. crimson/views/bonuses.py +201 -0
  88. crimson/views/camera_debug.py +359 -0
  89. crimson/views/camera_shake.py +229 -0
  90. crimson/views/corpse_stamp_debug.py +324 -0
  91. crimson/views/decals_debug.py +739 -0
  92. crimson/views/empty.py +19 -0
  93. crimson/views/fonts.py +114 -0
  94. crimson/views/game_over.py +117 -0
  95. crimson/views/ground.py +259 -0
  96. crimson/views/lighting_debug.py +1166 -0
  97. crimson/views/particles.py +293 -0
  98. crimson/views/perk_menu_debug.py +430 -0
  99. crimson/views/perks.py +398 -0
  100. crimson/views/player.py +434 -0
  101. crimson/views/player_sprite_debug.py +314 -0
  102. crimson/views/projectile_fx.py +609 -0
  103. crimson/views/projectile_render_debug.py +393 -0
  104. crimson/views/projectiles.py +221 -0
  105. crimson/views/quest_title_overlay.py +108 -0
  106. crimson/views/registry.py +34 -0
  107. crimson/views/rush.py +16 -0
  108. crimson/views/small_font_debug.py +204 -0
  109. crimson/views/spawn_plan.py +363 -0
  110. crimson/views/sprites.py +214 -0
  111. crimson/views/survival.py +15 -0
  112. crimson/views/terrain.py +132 -0
  113. crimson/views/ui.py +123 -0
  114. crimson/views/wicons.py +166 -0
  115. crimson/weapon_sfx.py +63 -0
  116. crimson/weapons.py +860 -0
  117. crimsonland-0.1.0.dev5.dist-info/METADATA +9 -0
  118. crimsonland-0.1.0.dev5.dist-info/RECORD +139 -0
  119. crimsonland-0.1.0.dev5.dist-info/WHEEL +4 -0
  120. crimsonland-0.1.0.dev5.dist-info/entry_points.txt +4 -0
  121. grim/__init__.py +20 -0
  122. grim/app.py +92 -0
  123. grim/assets.py +231 -0
  124. grim/audio.py +106 -0
  125. grim/config.py +294 -0
  126. grim/console.py +737 -0
  127. grim/fonts/__init__.py +7 -0
  128. grim/fonts/grim_mono.py +111 -0
  129. grim/fonts/small.py +120 -0
  130. grim/input.py +44 -0
  131. grim/jaz.py +103 -0
  132. grim/math.py +17 -0
  133. grim/music.py +403 -0
  134. grim/paq.py +76 -0
  135. grim/rand.py +37 -0
  136. grim/sfx.py +276 -0
  137. grim/sfx_map.py +103 -0
  138. grim/terrain_render.py +840 -0
  139. 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
+