cd8d566d82
Порт PoP на Sprinter. Текущий PoC — applications/PoP/roomtest/: комната 1 (фон-композиция тайлов) + Kid с управлением на raw-клавиатуре и коллизией с картой. - roomtest — pop_bg (фон), pop_kid (спрайты Kid, column-major флип, seqtbl-анимация), pop_ctrl (порт control() PoP на held-state kbd_raw), pop_map (коллизия seg004/005: бег/стоп у стены, падение/приземление, отскок seq_47, вертикальный прыжок K4.1). MEMORY=small (DATA сразу за CODE, ~23КБ кода не лезет в huge). - toolchain (PoP) — pop_pack_kid/pop_pack_bg/render_room/extract — распаковка res-графики MSDOS в атласы + композиция комнат. - toolchain/ (корень) — make_hdd.sh (быстрый HDD-тест вместо FDD), png_strip.py / room_compose.py (ассет-пайплайн). - docs — PORT_PLAN, KID_PLAN, форматы ресурсов (Apple II / MSDOS / DAT). - bgtest/coltest/poc — ранние PoC (фон, коллизия, первый прототип). .gitignore: build-артефакты applications/*/*/*; исключены внешние референс-репозитории (SDLPoP/mininim/PR/Apple-II — свои git-клоны) и оригинальные game-данные MSDOS/ (копирайт, только для реверса форматов). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
292 lines
28 KiB
Markdown
292 lines
28 KiB
Markdown
# Формат ресурсов Prince of Persia (MS-DOS, каталог `MSDOS/`)
|
||
|
||
Документ описывает бинарный формат `*.DAT`-файлов ресурсов DOS-версии PoP.
|
||
Исходников для этой версии нет, поэтому всё, что ниже — результат
|
||
структурного (эмпирического) анализа реальных файлов из `MSDOS/`, а не чтения
|
||
кода. Уровень уверенности указан для каждого раздела. Все находки проверены
|
||
скриптами (Python), которые разбирают файл и валидируют согласованность
|
||
(например: смещение+размер последней записи таблицы точно совпадает с
|
||
началом самой таблицы — то есть данные и каталог стыкуются без дыр).
|
||
|
||
Для справки при последующей реализации (порт на ZX Sprinter) стоит держать в
|
||
уме два внешних проекта:
|
||
|
||
- **SDLPoP** (github.com/NagyD/SDLPoP, GPLv3) — open-source реализация
|
||
DOS-версии на основе дизассемблирования оригинального `PRINCE.EXE`. Содержит
|
||
рабочий код чтения `.DAT`-файлов и полный кодек изображений/уровней. Точные
|
||
структуры (`dat_table_type` и т.п.), процитированные ниже, получены через
|
||
автоматический пересказ содержимого файла третьей стороной, а не через
|
||
прямое чтение исходника — поэтому такие детали помечены как "требует сверки
|
||
при реализации", в отличие от эмпирически подтверждённых байтовых оффсетов.
|
||
- **Princed Resources / PR** (github.com/NagyD/PR, princed.org, GPLv2) — это
|
||
профильный инструмент именно для распаковки/запаковки `.DAT`-ресурсов PoP
|
||
(версии DAT 1 и 2), сделанный тем же автором. В его документации
|
||
(`doc/Dataformats.md`) официально описаны экспортные форматы ресурсов —
|
||
это подтверждает и уточняет часть находок ниже (см. §3–4), и является более
|
||
надёжным источником, чем самостоятельная догадка по байтам.
|
||
|
||
**Важная находка:** репозиторий SDLPoP в папке `data/` содержит не только
|
||
код движка, но и **реальные ресурсы игры** — как сырые `.DAT`-контейнеры, так
|
||
и уже распакованные поштучно файлы (PNG-кадры спрайтов, `.pal`-палитры,
|
||
`.bin`-дампы уровней), см. §7. Это готовый источник ассетов и одновременно
|
||
независимая проверка формата, описанного в этом документе.
|
||
|
||
---
|
||
|
||
## 1. Общий контейнер `.DAT` (уверенность: высокая, подтверждено на 28 файлах)
|
||
|
||
Каждый `*.DAT`-файл (кроме служебных `config.dat`/`setup.dat`, см. §5) — это
|
||
простой архив-контейнер: блок данных + оглавление (каталог ресурсов) в конце
|
||
файла.
|
||
|
||
### 1.1 Заголовок файла (6 байт, смещение 0x00)
|
||
|
||
| Смещение | Размер | Поле | Значение |
|
||
|----------|--------|--------------|----------|
|
||
| 0x00 | 4 | `tableOffset`| LE u32. Абсолютное смещение в файле, с которого начинается таблица оглавления. Совпадает с "концом данных". |
|
||
| 0x04 | 2 | `tableSize` | LE u16. Размер таблицы оглавления в байтах. |
|
||
|
||
Инвариант, подтверждённый на всех 28 `.dat`-файлах в каталоге:
|
||
|
||
```
|
||
tableOffset + tableSize == размер файла (без исключений)
|
||
```
|
||
|
||
Данные ресурсов идут сразу после заголовка, начиная с байта 0x06, и
|
||
заканчиваются на `tableOffset`.
|
||
|
||
### 1.2 Таблица оглавления (по смещению `tableOffset`, длиной `tableSize`)
|
||
|
||
Таблица — плоский массив записей по 8 байт. Количество записей:
|
||
`tableSize / 8` (округление вниз; в файле почти всегда остаётся 2 "лишних"
|
||
байта в хвосте таблицы — назначение не установлено, вероятно, служебное поле
|
||
инструмента-упаковщика или паддинг; на итоговый разбор не влияет).
|
||
|
||
Запись (8 байт):
|
||
|
||
| Смещение в записи | Размер | Поле | Описание |
|
||
|---|---|---|---|
|
||
| 0 | 2 | `size` | LE u16 — размер данных ресурса в байтах |
|
||
| 2 | 2 | `id` | LE u16 — идентификатор ресурса |
|
||
| 4 | 2 | `offset` | LE u16 — **абсолютное** смещение данных ресурса в файле (не относительное!) |
|
||
| 6 | 2 | `reserved` | во всех проверенных записях (сотни штук) всегда `0x0000` |
|
||
|
||
Проверено на `levels.dat`: 16 записей, `id`=2000..2015, и `offset[i] + size[i]
|
||
== offset[i+1]` для всех соседних записей, а последняя запись заканчивается
|
||
ровно на `tableOffset` — то есть данные абсолютно плотно упакованы, без
|
||
пробелов, для этого файла. В других файлах (например `guard.dat`) между
|
||
записями изредка есть небольшие зазоры в несколько байт (вероятно, выравнивание
|
||
или "мёртвые" байты от инструмента-компоновщика) — не является нарушением
|
||
формата.
|
||
|
||
### 1.3 Диапазоны `id` по типам файлов (собрано эмпирически)
|
||
|
||
Похоже, что числовые ID образуют условные "пространства имён" по типу
|
||
контента — вероятно, глобальные константы в оригинальном коде:
|
||
|
||
| Файл(ы) | Диапазон `id` | Кол-во записей | Предполагаемое содержимое |
|
||
|---|---|---|---|
|
||
| `levels.dat` | 2000–2015 | 16 | id=2000 — служебный блок (16 байт, см. §3); id=2001..2015 — 15 уровней |
|
||
| `guard.dat`, `fat.dat`, `skel.dat`, `shadow.dat` | 750–784 (варьируется) | ~30–35 | id=751(750) — служебный блок; остальные — кадры анимации спрайта |
|
||
| `vizier.dat` | аналогично guard | — | кадры анимации визиря |
|
||
| `kid.dat` | ~400+ | 220 | кадры анимации игрока (намного больше — герой умеет гораздо больше действий) |
|
||
| `guard1.dat`, `guard2.dat` | 750 (1 запись) | 1 | вероятно, дополнительные/альтернативные кадры/варианты |
|
||
| `title.dat` | 40–55 | 12 | картинки титульного экрана/логотипов |
|
||
| `cpalace.dat`,`epalace.dat`,`vpalace.dat`,`cdungeon.dat`,`edungeon.dat`,`vdungeon.dat` | 200–1343 | 205–238 | фоновые тайлы дворца/подземелья, отдельно для CGA(`c*`)/EGA(`e*`)/VGA(`v*`) |
|
||
| `pv.dat` | 800–981 | 103 | доп. графика (возможно, "Prince/Vizier" катсцены) |
|
||
| `digisnd1/2/3.dat` | 10000+ | 20–44 | оцифрованный звук (Covox/Disney Sound Source) |
|
||
| `midisnd1/2.dat` | 10024+ / аналог | 16 | General MIDI музыка |
|
||
| `mt32snd1/2.dat` | 10000+ | 24/7 | музыка для Roland MT-32 |
|
||
| `ibm_snd1/2.dat` | 10000+ | 44 | музыка/эффекты через PC-спикер |
|
||
| `prince.dat` | — (1 крупный ресурс) | — | MIDI-тема (вероятно, финальная тема "Принц"/титры — см. текстовые события "The Princess awaits") |
|
||
|
||
Во всех файлах первая (наименьшая по `id`) запись — маленький "служебный"
|
||
ресурс (6–44 байта), стоящий перед основным контентом. Скорее всего это
|
||
локальная мини-таблица/палитра/список ссылок для данного набора ресурсов —
|
||
по аналогии с тем, что у уровней id=2000 отдельно от самих уровней (см. §3).
|
||
|
||
---
|
||
|
||
## 2. Формат уровня (`levels.dat`, id=2001..2015) — уверенность: высокая
|
||
|
||
Каждая запись уровня имеет размер **2305 байт** и по данным полностью
|
||
совпадает по объёму с уровнями из Apple II версии (`01 POP Source/Levels/LEVELn`
|
||
— ровно **2304 байта** каждый, см. `docs/APPLEII_RESOURCE_FORMAT.md`).
|
||
|
||
Вывод: формат карты уровня в DOS-версии, судя по всему, **унаследован
|
||
практически без изменений от оригинального Apple II формата** (Джордан
|
||
Мехнер писал игру на 6502 и данные уровней переносились как есть), с добавлением
|
||
одного лишнего байта в DOS-упаковке (2304+1=2305 — вероятно, контрольный байт/
|
||
маркер конца, добавленный DOS-упаковщиком ресурсов, а не часть игровых данных).
|
||
|
||
**Практическое следствие:** байтовая структура самого уровня (тайлы 3×10 на
|
||
экран, 24 экрана, таблицы стражников, дверей и т.д.) должна документироваться
|
||
один раз — по исходникам Apple II (см. соответствующий раздел), и напрямую
|
||
применяться к DOS `levels.dat`, отбросив 1 лишний байт в конце каждой записи.
|
||
Байтовые значения тайлов в дампе (в основном 0x00–0x39) визуально согласуются
|
||
с диапазоном небольших целых кодов тайлов, что для формата карты и ожидается.
|
||
|
||
Первая запись, id=2000, размер 16 байт — не уровень, а отдельный маленький
|
||
блок (возможно: количество уровней, начальный уровень, версия формата,
|
||
стартовые координаты игрока/охраны по умолчанию). Точное назначение не
|
||
установлено — требует сопоставления с дизассемблированным кодом загрузчика
|
||
уровней (в SDLPoP это, по всем признакам, отдельная процедура чтения
|
||
`level` ресурса).
|
||
|
||
**Сверка с независимой распаковкой SDLPoP (`data/LEVELS/`):** там лежат файлы
|
||
`res2000.bin`…`res2015.bin` (16 штук — количество совпадает). Байты
|
||
`res2001.bin` содержательно совпадают с тайловыми данными нашей записи
|
||
id=2001 (та же последовательность значений тайлов) — это подтверждает, что
|
||
нумерация id верна. Но есть нестыковка по размеру: у SDLPoP `res2000.bin` —
|
||
**2305 байт** (как и все остальные), тогда как в нашем локальном
|
||
`levels.dat` запись id=2000 — всего **16 байт**. Скорее всего, это разные
|
||
релизы/сборки игры (см. §7 — размеры некоторых `.dat` у SDLPoP и у нас уже
|
||
отличались), и в версии SDLPoP маленький служебный блок либо отсутствует,
|
||
либо пронумерован иначе. Это не меняет сам формат контейнера, но означает,
|
||
что **точную семантику 16-байтного блока id=2000 в нашей копии игры пока
|
||
нельзя проверить через данные SDLPoP** — открытый вопрос.
|
||
|
||
---
|
||
|
||
### 2.1 Кросс-подтверждение по исходникам Apple II
|
||
|
||
Фоновый анализ исходников Apple II (см. `docs/APPLEII_RESOURCE_FORMAT.md`)
|
||
подтверждает и объясняет структуру уровня напрямую по коду. Уровень на Apple
|
||
II — дамп структуры `blueprnt` (`EQ.S`): `BLUETYPE`(720Б, 24 экрана×30 тайлов)
|
||
+ `BLUESPEC`(720Б) + `LINKLOC`(256Б) + `LINKMAP`(256Б) + `MAP`(96Б, граф
|
||
соседних экранов) + `INFO`(256Б, метаданные/старт Кида/стражников) = ровно
|
||
2304 байта. Учитывая, что DOS-запись уровня — это ровно 2304+1 байт с
|
||
байтовыми значениями тайлов, укладывающимися в диапазон 0–29 (id тайла) плюс
|
||
служебные биты (аналогично `idmask=%00011111`, `reqmask=%00100000` из
|
||
`EQ.S:484-486`), можно с высокой уверенностью считать, что **DOS-версия
|
||
использует ту же самую раскладку `blueprnt`**, лишь с добавлением одного
|
||
байта (вероятно, контрольной суммы) в конце DOS-упаковки. Это снимает
|
||
необходимость отдельно реверсить формат уровня для DOS — таблица тайлов,
|
||
enum id (0=space...29=archtop4), формат `LINKLOC`/`LINKMAP` и `INFO` из
|
||
Apple II документа применимы напрямую.
|
||
|
||
## 3. Графика (спрайты и фоновые тайлы) — уверенность: средняя/низкая
|
||
|
||
Файлы `kid.dat`, `guard.dat`, `fat.dat`, `shadow.dat`, `skel.dat`,
|
||
`vizier.dat`, `title.dat`, `c/e/v-palace.dat`, `c/e/v-dungeon.dat`, `pv.dat`
|
||
хранят по контейнерному формату (§1) множество мелких чанков (десятки—сотни
|
||
байт каждый).
|
||
|
||
Что подтверждено:
|
||
- Наборы `shadow.dat`/`kid.dat` и `fat.dat`/`vizier.dat` содержат **побайтово
|
||
идентичные фрагменты** данных в начале файла — это ожидаемо: "Тень" (Shadow)
|
||
визуально копирует анимацию Кида, а "Толстый страж" (Fat guard, пасхалка)
|
||
переиспользует модель Визиря. Подтверждает, что персонажи одного "типа
|
||
тела" используют общий набор геометрии/анимации.
|
||
- Отдельные чанки *не* имеют очевидного унифицированного заголовка
|
||
(высота/ширина/палитра) фиксированного размера — попытка интерпретировать
|
||
первые байты чанка как `{height:u16, width:u16, flags:u16}` не подтвердилась
|
||
на реальных данных (получаются нереалистичные размеры для маленьких чанков).
|
||
Вероятно, как и в Apple II версии (см. `FRAMEDEF.S`/`SEQTABLE.S`), геометрия
|
||
кадра (ширина, высота, точка привязки) хранится **отдельно от самих
|
||
пиксельных данных** — в таблицах внутри `PRINCE.EXE`, а не в `.DAT`-чанке.
|
||
Сам чанк, вероятно, содержит только упакованные пиксельные данные
|
||
(RLE/дельта-упаковка, по аналогии с `UNPACK.S` в Apple II исходниках).
|
||
- Точный алгоритм упаковки пикселей **не восстановлен** в рамках этого
|
||
анализа по сырым байтам — байт-в-байт разбор распаковщика без
|
||
дизассемблирования `PRINCE.EXE` надёжно не сделать. **Но для практических
|
||
целей это не требуется**: см. §7 — в SDLPoP уже есть тот же самый набор
|
||
изображений в готовом, распакованном виде (PNG), которым можно пользоваться
|
||
напрямую как источником ассетов, не реализуя свой декодер `.DAT`-пикселей.
|
||
Писать собственный декодер имеет смысл только если понадобится читать
|
||
оригинальные `.DAT` "на лету" (например, для точной сверки контента именно
|
||
нашей копии игры) — тогда ориентир — исходник SDLPoP (`src/seg009.c`).
|
||
|
||
---
|
||
|
||
## 4. Звук — уверенность: высокая (по структуре), низкая (по деталям кодека)
|
||
|
||
Обнаружено 4 параллельных набора звуковых ресурсов под разные звуковые
|
||
устройства DOS-эпохи — типично для игр начала 1990-х с "звуковым меню":
|
||
|
||
| Файл | Устройство | Формат чанка |
|
||
|---|---|---|
|
||
| `midisnd1.dat`, `midisnd2.dat` | General MIDI / MPU-401 | каждый чанк = 2-байтовый LE-префикс длины + встроенный Standard MIDI File (`MThd`...`MTrk`...) |
|
||
| `mt32snd1.dat`, `mt32snd2.dat` | Roland MT-32/CM-32L | тот же формат: префикс длины + `MThd`/`MTrk`, с MT-32-специфичными SysEx (видны строки `MT-32.mff`, текстовые мета-события вроде `"The Princess awaits"`) |
|
||
| `prince.dat` | (аналогично MIDI) | отдельный крупный музыкальный ресурс, тот же MIDI-контейнер — вероятно, финальная тема |
|
||
| `digisnd1/2/3.dat` | Covox / Disney Sound Source / Sound Blaster (оцифрованный звук) | чанк начинается с нескольких служебных байт, среди которых слово `0x2AF8` = 11000 — похоже на частоту дискретизации 11 кГц; далее — сырые 8-битные PCM-сэмплы (значения кластеризуются вокруг ~0x7A–0x90, типично для беззнакового 8-бит аудио, смещённого к середине шкалы) |
|
||
| `ibm_snd1.dat`, `ibm_snd2.dat` | PC Speaker | чанк — последовательность троек байт похожих на (длительность, делитель_частоты) — простой формат "бипера", отличный от MIDI |
|
||
|
||
Подтверждено разбором первых чанков в каждом файле (см. байтовые дампы,
|
||
проверялись скриптом). Точная семантика полей внутри `digisnd`/`ibm_snd`
|
||
(разрядность, порядок байт служебного заголовка) не выведена до конца — при
|
||
реализации порта достаточно распознавания по типу файла и (для MIDI-семейства)
|
||
можно напрямую воспроизводить встроенный Standard MIDI File, пропустив
|
||
2-байтовый префикс длины.
|
||
|
||
---
|
||
|
||
## 5. Готовые распакованные ассеты в SDLPoP (`data/`) — практический источник для порта
|
||
|
||
Репозиторий github.com/NagyD/SDLPoP содержит папку `data/`, где, помимо
|
||
самих `.DAT`-контейнеров, каждый ресурс **продублирован в виде отдельно
|
||
распакованного файла**, названного по его `id` из таблицы оглавления (§1.2).
|
||
Проверено через GitHub API (`api.github.com/repos/NagyD/SDLPoP/contents/...`):
|
||
|
||
| Подпапка/файл в `data/` | Содержимое | Соответствие нашему разбору |
|
||
|---|---|---|
|
||
| `GUARD.DAT`, `GUARD1.DAT`, `GUARD2.DAT` | сырые `.DAT` | размер **побайтово совпадает** с нашими локальными `guard.dat`/`guard1.dat`/`guard2.dat` (6950 / 117 / 117 байт) |
|
||
| `DIGISND1.DAT`, `MIDISND2.DAT` и др. | сырые `.DAT` | размер **не совпадает** с нашими локальными файлами (48545 vs 50101, 18408 vs 18958) — другой релиз/сборка игры |
|
||
| `GUARD/res751.png` … `res784.png` | готовые PNG, по одному на кадр анимации, имя = `res<id>.png` | id-диапазон (751-784) точно совпадает с нашим разбором `guard.dat` |
|
||
| `VPALACE/res200.pal`, `res201.png`, `res202.png`, … | палитра (JASC `.pal`) + PNG-кадры фонов дворца, **VGA-вариант (256 цветов)** | id-диапазон (200+) совпадает с `vpalace.dat` |
|
||
| `LEVELS/res2000.bin` … `res2015.bin` | сырые дампы уровней по 2304-2305 байт | id совпадает с `levels.dat`; содержимое `res2001.bin` **сверено побайтово** с нашим id=2001 — тайловые данные совпадают |
|
||
| `KID/`, `PRINCE/`, `SHADOW/`, `SKEL/`, `VIZIER/`, `FAT/`, `TITLE/`, `VDUNGEON/`, `PV/`, `IBM_SND1/`, `IBM_SND2/`, `font/`, `music/` | аналогичные наборы для остальных ресурсов | не проверялись по отдельности, но структура (папка на каждый `.dat`, файлы `res<id>.ext`) наблюдается одинаково |
|
||
|
||
**Вывод:** это данные из немного **другого релиза DOS-версии**, чем те, что
|
||
лежат у нас в `MSDOS/` (см. расхождение в размере `digisnd`/`midisnd`), но
|
||
формат контейнера и нумерация `id` — те же самые. Практически это значит:
|
||
|
||
1. Для получения играбельных PNG-спрайтов и VGA-фонов **не нужно
|
||
реализовывать декодер сжатия пикселей** — можно взять готовые файлы
|
||
`data/<ИМЯ>/res<id>.png` напрямую как исходный материал для конвертации
|
||
под видеорежим ZX Sprinter (в т.ч. `VPALACE`/`VDUNGEON` — уже
|
||
256-цветный VGA-арт, что прямо отвечает на вопрос про полноцветность).
|
||
2. Если в проекте важно использовать именно ту версию контента, что в наших
|
||
`MSDOS/*.dat` (а не версию из SDLPoP) — распаковку своих файлов всё же
|
||
придётся делать (кодек пикселей по-прежнему не восстановлен для сырых
|
||
`.DAT`, см. §3), либо принять решение работать с версией SDLPoP как
|
||
мастер-источником ассетов вместо своей.
|
||
|
||
---
|
||
|
||
## 6. Служебные не-ресурсные файлы
|
||
|
||
- `config.dat`, `setup.dat` — 28 байт, не являются ресурсными контейнерами
|
||
(не проходят проверку §1.1 — "размер" получается больше самого файла).
|
||
Скорее всего простые бинарные структуры настроек (звук/видеорежим,
|
||
выбранный на этапе `SETUP.EXE`/`INSTALL.EXE`), не связаны с игровым
|
||
контентом.
|
||
- `desktopd.cfg`, `setup.cfg` — текстовые/бинарные конфиги DOS-инсталлятора,
|
||
вне скоупа игровых ресурсов.
|
||
- `PRINCE.EXE` / `PRINCE.REM` — почти идентичны (отличие в единичных байтах
|
||
в районе смещения ~0x4ED0), похоже на кряк/патч одного байта проверки —
|
||
не относится к формату ресурсов.
|
||
- `old-games.nfo` — ASCII-арт NFO релиз-группы (old-games.ru), не игровые
|
||
данные.
|
||
|
||
---
|
||
|
||
## 7. Итоговая таблица уверенности
|
||
|
||
| Раздел | Уверенность | Как подтверждено |
|
||
|---|---|---|
|
||
| Контейнер `.DAT` (заголовок + таблица) | Высокая | Проверено скриптом на всех 28 файлах, инвариант offset+size выполняется без исключений; независимо подтверждено именованием `res<id>.*` в SDLPoP `data/` |
|
||
| ID-пространства ресурсов | Средняя-высокая | Наблюдение по диапазонам + сверка с `res<id>` именами файлов SDLPoP и побайтовым содержимым `res2001.bin` |
|
||
| Формат уровня = формату Apple II | Высокая (по размеру и содержимому), служебный блок id=2000 — открытый вопрос | Совпадение размера (2304 vs 2305), тайловые байты сходятся с `res2001.bin` из SDLPoP |
|
||
| Формат изображений/спрайтов (сырой `.DAT`) | Низкая-средняя | Контейнер подтверждён, кодек пикселей — нет; но практически закрыто наличием готовых PNG в SDLPoP `data/` (§5) |
|
||
| Формат звука (тип контейнера) | Высокая для MIDI-семейств, средняя для digisnd/ibm_snd | Явные MIDI-сигнатуры `MThd`/`MTrk` видны в байтах |
|
||
|
||
**Рекомендация для дальнейшей работы:** для получения арт-ассетов (спрайты,
|
||
фоны, палитры) — использовать готовые распакованные файлы из
|
||
`github.com/NagyD/SDLPoP/tree/master/data` (§5), это быстрее и надёжнее
|
||
самостоятельной реализации декодера. Декодер сырого `.DAT`-формата
|
||
изображений и точную семантику служебных полей `digisnd`/`ibm_snd`
|
||
(§3, §4) стоит восстанавливать только если понадобится читать именно нашу
|
||
локальную копию `MSDOS/*.dat` "как есть" — тогда ориентир прежний: исходник
|
||
SDLPoP (`src/seg009.c`, `src/data.c`/`data.h`).
|