Files
UnheardCity/REPORT.md

8.8 KiB

Report — full-game audio, subtitles and menu text (mission 3)

Brief: docs/history/mission3_audio_text_prompt.md. Earlier missions: the WAD/WEM toolkit (mission 1) and the editor Unheard City (mission 2).

What works (verified)

  • Every sound of the game is cataloged and editable: the speech WADs (5 languages x 10,816), the SFX WAD (651) and, new, the 15,355 in-memory sounds stored inside soundbanks (archive BANK: footsteps, foley, combat, weapons, UI, efforts; 8,092 shared by all languages, ~1,450 localized speech lines per voice language, 6 shared by several) in 65 loose .bnk files and 975 .upk packages. ackit reads and patches the LZO-compressed UE3 packages itself (ackit/upk.py, lzo.py; no external tools). A replacement goes into every copy (93,826 copies). 445 WAD voice recordings (89 lines) also have bank copies (396 prefetch heads, 49 whole copies; 2,185 copies), which are rewritten with them. Names: 13,501 BANK sounds are named after the Wwise event that plays them (Play_..., Speech_...), the other 1,854 after their bank.
  • Catalog check: ackit verify --catalog compares the catalog with a fresh scan of the game (missing, extra, duplicate, size/checksum, category, character, language, bank copies, subtitle copies/texts) and re-derives every relation from the game files (lines, names, subtitle links, prefetch heads, copies): catalog OK on the full game.
  • Subtitles: found in RDialogueEvent objects inside the packages (9,032 speech lines x 11 languages) and in 41 scripted RSubtitle objects (radio, encryption cards, Riddler; linked through RSubtitleLookup), parsed, cataloged (SUB_<LANG>.csv) and linked to their voice recordings through the soundbanks: 103,304 of 103,658 strings in 11 languages (INT 9,373 of 9,404), each on the same line in every language; an event that plays two versions of a line links both. Edited in place in every copy (168,688 copies).
  • One recording per language, from the game data alone (docs/formats/banks.md, Lines): every voice recording is tied to its line by the game's Wwise Sound objects (same IDs in every language), and each WAD recording to its media by its own language's BKPK table (10,816 / 10,816 in each language). Result: 12,434 lines (WAD + in-memory) with exactly one recording in each of the 5 voice languages, no gap and no conflict; recordings stored twice (5 per language) are written together. Independent checks: every WAD recording is a source in a bank of its own language (54,055 / 54,055), every prefetch head or whole bank copy is the start of its recording (2,185 / 2,185). Each line has one name in every language and carries its identity (line): speaker labels (3,366 in every language), subtitles and mod packages (another language: the same line) follow it. Speaker labels vs the game's dialogue speaker field: 2,766 agree, 19 differ (categories.md).
  • Menu text: the localization files (BmGame\Localization\<LANG>\*.int, ~7,000 strings per language), edited value by value; everything else in the files stays byte-identical.
  • Editor: one Language setting (default: the game's language) for voices, subtitles and menu text (languages without voices use the INT ones, like the game); tabs Sounds / Subtitles / Menu text. The sound editor shows Listen / Replace / Subtitle side by side (resizable columns, no scrolling at usual window sizes); the subtitle list links back to the sound. Search, filters (character, category, file, modified), room counter, apply/revert/revert all, find & replace on the filtered rows, mod export/import with texts, changed-outside banner for sounds and texts.
  • Safety: every changed file (WAD, bank, package, localization file) is rebuilt from a verified original copy in the store + the edits applied now; reverting the last edit restores it byte-for-byte; files changed by another tool or Steam are detected (whole-file SHA-1) and not overwritten without confirmation.
  • Tests: 135 automated tests (unit, synthetic game with packages/banks/dialogues/localization, a two-language game for the lines (incl. a recording also stored whole in a bank), the shipped catalog's cross-references, real-game read-only (every name of every language's catalog resolves to its own sound), offscreen GUI incl. list order, selection and loading overlays) pass. ackit verify PASS (incl. 300/300 in-memory WEMs rebuilt byte-identically).
  • Real game (2026-10-10), all reverting and checking byte-identity themselves: tools/e2e_features.py --lang all 89/89 PASS in all 11 languages (every copy of an in-memory sound, each language's localized line, prefetch heads, a line also stored whole in banks, a multi-copy subtitle, a scripted subtitle, a menu text, sound + subtitle in one package, a mod moved to another voice language and matched to the same line at another position); ackit verify --ingame PASS (music heard, ncc 1.0); --banks PASS (77 in-memory sounds of the front-end packages replaced in 54 files: the game loads them, 71 probes found in its memory, no crash); --texts PASS (12/12 menu texts and 23/23 subtitles of Startup.upk found in the game's memory, no crash); tools/e2e_editor.py PASS. Game files original at the end (ackit status). The catalog builder refuses to run on a modified game, so the catalog always describes the original files.
  • Package: dist/UnheardCity-3.2.2-windows-amd64.zip (86 MB, catalogs included). With PATH reduced to the Windows folders the packaged exe passes its smoke test (in the game's language - Italian on the test PC: 21,015 sounds loaded, encode + inject, 9,377 subtitles and 7,020 menu texts loaded, an in-memory sound decoded from a package) and the GUI starts and quits cleanly. The installer is unchanged since mission 2 (install/upgrade/uninstall verified then).

Unresolved / limitations

  • Checked by a person in game (2026-10-10), not automatically (nothing of this plays or shows on the title screen without input, findings 18): replaced voice lines and edited subtitles are heard and shown; replaced footsteps play on every step. That test found the one defect the automatic checks could not: in-memory replacements followed by zero padding in their slot played as silence (fixed in 3.2.2, findings 24).
  • Size limits: in-memory sounds and speech must fit their original size; subtitles must fit the original text's length ("room"); cp1252 subtitles accept cp1252 characters only. Lifting these limits means moving objects inside the packages (new export offsets/sizes, added chunks): designed but not done, because it could not be verified automatically in the game (decisions 4c).
  • Unlinked subtitles: 24 speech names (24-36 strings per language, INT 31: Riddler trophy texts, Arkham City Stories, radio reports and tapes) have no event in any bank; they are listed and editable but not linked.
  • Subtitle coverage is uneven in the game itself (INT voice lines with a subtitle): none for efforts/grunts, few for combat barks (9 %), cinematics and boss fights (23 %; most cutscene lines are not played through speech events and have no dialogue object), 89-97 % for story, predator, character and open-world lines. No other subtitle storage was found in the packages (all classes with subtitle data checked).
  • 637 voice lines are played by no event whose name the game stores; they are named after their English recording's position (the same name in every language). Mod packages from versions before 3.1 carry no line identity: their voice lines are not moved to another language (listed instead of guessed).
  • Speaker labels: 2 names of the curated lists match two recordings each (wemscan name collision), both are labelled; 19 labels differ from the game's dialogue speaker field (to be checked by listening).
  • Unnamed sounds: 1,854 BANK sounds are reached by no event whose name the game stores and are named <Bank>_<n>.
  • 25 SFX originals (music seek tables and sample counts, looping ambience) are not reproduced byte-for-byte by the WEM rules (docs/formats/wem.md); writing is not affected (replaced music plays in game).
  • Two copies of media 1C898731 differ; its checksum is left empty. Channel order for 4-6 channel sounds is unverified. M4A/AAC/WMA input needs an ffmpeg on the system.
  • Another game build is scanned at first start (WADs: seconds; banks, lines and subtitles: a few minutes, cached); it gets the same line identities, but no original checksums.

Next steps

  1. Optional: lift the subtitle length limit by relocating dialogue objects (checked in game by a person).
  2. Build and smoke-test the Linux package once on a Linux machine.
  3. Listen to the 19 lines whose speaker label differs from the game's dialogue speaker field (docs/categories.md) and fix the curated lists if needed; extend them (data/catalog/source/<lang>/*.txt) and rebuild the catalog.