Вернуться к списку описаний

Heroes of Might and Magic III
Описание формата .LOD

В начале заголовок:

LODHeader: record
  id: array[1..4]of char; //Идентификатор формата
  Files: LongInt; //Количество файлов
End;

Таблица размещения файлов располагается по смещению $5C. Описание формата записи о файле:

FATRecord: record
  Name: array[1..12]of char //Имя файла
  Junk: array[1..4]of char; //Хлам
  Offset: LongInt; //Смещение до файла
  RealSize: LongInt; //Реальный размер файла
  Junk: array[1..8]of char; //Хлам
  Size: LongInt; //Размер файла
End;

Описание формата .SND

В начале заголовок:

SNDHeader: record
  Files: LongInt; //Количество файлов
End;

Таблица размещения файлов располагается по адресу $04. Описание формата записи о файле:

FATRecord: record
  Name: array[1..12]of char //Имя файла
  Junk: array[1..28]of char //Хлам
  Offset: LongInt; //Смещение до файла
  Size: LongInt; //Размер файла
End;

Описание формата .VID

В начале заголовок:

VIDHeader: record
  Files: LongInt; //Количество файлов
End;

Таблица размещения файлов располагается по адресу $04. Описание формата записи о файле:

FATRecord: record
  Name: array[1..12]of char //Имя файла
  Junk: array[1..28]of char //Хлам
  Offset: LongInt; //Смещение до файла
End;

Описание формата .PCX

Заголовок:

PCXHeader: record
  Size: LongInt; //Размер данных
  Width: LongInt; //Ширина изображения
  Height: LongInt; //Высота изображения
End;

    По полю PCXHeader.Size можно определить тип изображения: 8bit или 24bit. Не знаю, кто как, а я произвожу две проверки:
1. Если PCXHeader.Size=PCXHeader.Width*PCXHeader.Height то изображение 8-ми битное.
2. Если PCXHeader.Size=3*PCXHeader.Width*PCXHeader.Height то изображение 24-х битное.
3. Если не то, и не другое, значит это вообще не .pcx

    По адресу $0C находятся сами графические данные. Тут все просто: если изображение 8-ми битное, то читаем строки длиной PCXHeader.Width, в противном случае - PCXHeader.Width*3. Заметьте: к 8-ми битным изображениям должна прилагаться палитра! Так оно и есть - отсчитайте 256*3 байт от конца файла и попадете на RGB описание нулевого цвета. В 24-х битных изображениях палитра, разумеется, отсутствует.

Описание формата .DEF

Один из самых навороченых из встреченых мной форматов. Представляет из себя "сборник" нескольких (от одного до нескольких десятков) спрайтов. По сему, будем файл DEF называть условно Архивом (хотя, по большому счету, он таковым не является). В общих чертах, структура его такова:
  I. Заголовок
  II. Палитра 256x3 (BGR)
  III. Таблица расположения спрайтов внутри архива DEF
  IV. Спрайты

I. Заголовок

DEFHeader: record
  ID: LongInt; //Идентификатор изображения. При распаковке его значение не играет никакой роли. Нужен по-видимому, только самой игре.
  FullWidth: LongInt; //Полная ширина изображения
  FullHeight: LongInt; //Полная высота изображения
  TotalBlocks: LongInt; //Общее количество блоков спрайтов
End;

Все изображения в архиве DEF связаны между собой. Связь может быть логической (например, изображения всех видов одной кнопки), и графической, когда спрайты, будучи просмотрены подряд, образуют анимированное изображение. В этом случае, первый спрайт представляет собой полное изображение объекта (Рис.1), а на остальных спрайтах хранятся только изменяющиеся области изображения (Рис.2). Обратите внимание, что часть изображения мной выделена розовым цветом. Именно эта часть хранится в виде спрайта, а потом подставляется по определенным координатам в полное изображение. Координаты подстановки указываются в заголовке каждого спрайта, До которых мы ее дойдем. В результате наложения всех спрайтов на первый получается приличная анимация (Рис.3).

Рис.1
Рис.2
Рис.3

II. Палитра

Палитра располагается по смещению $10 и представляет собой массив записей формата RGB общим размером 256x3 байт.
III. Таблица расположения спрайтов

Смещение таблицы - $310. Таблица представляет собой не сплошную последовательностей записей, а несколько блоков записей. Количество блоков определяется переменной DEFHeader.TotalBlocks. Ниже записана структура каждого блока:

BlockHeader: record
  Junk_1: array[1..4]of char; //Хлам
  TotalSprites: LongInt; //Количество спрайтов в блоке
  Junk_2: array[1..8]of char; //Хлам
  Names: array of array[1..13]of char; //Таблица имен спрайтов. Количество записей = TotalSprites
  Offsets: array of LongInt; //Таблица адресов спрайтов. Количество записей = TotalSprites
End;

IV. Спрайты


Заголовок:

SpriteHeader: record
  Junk_1: array[1..4]of char; //Хлам (иногда - размер данных спрайта)
  SpriteType: LongInt; //Тип спрайта
  FullWidth: LongInt; //Полная ширина изображения
  FullHeight: LongInt; //Полная высота изображения
  SpriteWidth: LongInt; //Ширина спрайта
  SpriteHeight: LongInt; //Высота спрайта
  LeftMargin: LongInt; //Смещение спрайта от левого края изображения
  TopMargin: LongInt; //Смещение спрайта от верхнего края изображения
End;

Дальше действуем в зависимости от типа спрайта. Всего их четыре, но я разобрался только с тремя.

Тип 0:

  Просто читаем матрицу пикселов размером SpriteWidth*SpriteHeight

Тип 1:

  Читаем таблицу смещений на каждую строку. Каждая запись - типа LongInt. Смещение отсчитывается от начала этой таблицы.
  В данном типе каждая строка записывается в виде отдельных сегментов. Каждый сегмент состоит из байта - типа сегмента, байта - длины сегмента, и последовательности байтов - пикселей. Типа сегментов всего два: $00 - обозначает последовательность прозрачных пикселов; $FF - обозначает последовательность обычных пикселов. Например, запись 00 20 FF 02 78 01 означает, что сначала следует последовательность из 32 ($20) прозрачных пикселов, а затем следует прочитать 2 обычных пиксела, т.е. строку 78 01

Тип 3:

  Читаем таблицу смещений на каждую строку. Каждая запись - типа Word. Смещение отсчитывается от начала этой таблицы.
  Здесь система таже, что и у типа 1, типов сегментов побольше. Байт-тип сегмента и байт-длина сегмента совмещены в один байт-описатель, где левые три бита определяют тип сегмента, а остальные пять - его длину. Фактически, после определения длины надо ее значение увеличить на 1. Ниже приведена таблица с описанием всех типов сегмента.
  $00 - Пишем блок прозрачных пикселов. Цвет пиксела выбирается произвольно
  $01 - Пишем блок полупрозрачных пикселов (тень). Цвет пиксела выбирается произвольно
  $04 - Пишем блок полупрозрачных пикселов (густая тень). Цвет пиксела выбирается произвольно
  $05 - Пишем блок прозрачных пикселов (в игре на их месте будут пикселы цвета игрока, которому принадлежит объект (например - флаг в изображениях героев)). Цвет пиксела выбирается произвольно
  $07 - Переписываем последовательность пикселов

Составление:Бесчетнов Михаил
Вернуться к списку описаний