***************************************************************************** Автор : Бесчетнов Михаил Константинович Web : http://extractor.far.ru E-Mail: collapse_forever@mail.ru Источник форматов: Heroes of Might and Magic III ***************************************************************************** *** Формат LOD В начале заголовок: LODHeader: record id: array[1..8]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..4]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 связаны между собой. Связь может быть логической (например, изображения всех видов одной кнопки), и графической, когда спрайты, будучи просмотрены подряд, образуют анимированное изображение. В этом случае, первый спрайт представляет собой полное изображение объекта (ris1.gif), а на остальных спрайтах хранятся только изменяющиеся области изображения (ris2.gif). Обратите внимание, что часть изображения мной выделена розовым цветом. Именно эта часть хранится в виде спрайта, а потом подставляется по определенным коор- динатам в полное изображение. Координаты подстановки указываются в заголовке каждого спрайта, До которых мы ее дойдем. В результате наложения всех спрайтов на первый получается приличная анимация (ris3.gif). 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 - Переписываем последовательность пикселов