Outpost 2 Формати файлів · bei.pm
Описані на цій сторінці формати файлів базуються на технічному аналізі інтелектуальної власності Dynamix, Inc. та Sierra Entertainment.
Інтелектуальна власність сьогодні є частиною маси Activision Publishing, Inc. / Activision Blizzard, Inc. і наразі належить Microsoft Corp..
Інформація була зібрана за допомогою реверс-інженерії та аналізу даних з метою архівування та взаємодії з історичними даними.
Не використовувалися жодні власницькі або конфіденційні специфікації.
Гру наразі можна придбати на gog.com як завантаження.
Наступна серія статей документує мої знання про формати даних у грі в реальному часі "Outpost 2: Divided Destiny", яка була випущена Sierra у 1997 році і розроблена компанією Dynamix.
Я займався аналізом даних гри приблизно з 1 листопада 2015 року по 14 листопада 2015 року, а також тим, як їх використовувати.
З інформації, яку я зміг отримати до цього моменту, випливає, що Dynamix - як і багато інших комерційних компаній - не розробляла деякі формати даних спеціально для Outpost 2, а також використовувала їх в інших проектах, таких як серія Mechwarrior (модифіковані).
Незалежно від цього, можна також зазначити, що інноваційність форматів даних практично обмежена, і часто вони спираються на вже існуючі концепції звичних форматів, таких як JFIF та RIFF.
Для інтерпретації таблиць і форматів даних доступні додаткові відомості за адресою Що таке що?.
Вказані тут дані загалом слід розуміти як Little Endian.
На завершення можна сказати, що реверс-інжиніринг приніс багато задоволення, хоча й не є повним.
Звісно, я також рекомендую просто грати в гру, оскільки вона пропонує цікаві ігрові механіки.
Вступ
Формати даних, що використовуються в Outpost 2, мають структуру, схожу на JFIF / PNG - окремі блоки даних завжди мають заголовок на 8 байт. Тому я утримаюся від документування окремих заголовків у відповідних специфічних місцях і задокументую тільки відхилення.
Формат завжди такий; фактичні корисні дані в ньому вбудовані:
Адр | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | симв. | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . |
Зсув | Тип даних | Назва | Пояснення |
---|---|---|---|
0x0000 | uint(32) | Магічні байти | Містить інформацію про те, чого очікувати в наступному блокові даних. Відомі значення:
|
0x0004 | uint(24) | Блок-довжина | Містить інформацію про те, який розмір (в байтах) має наступний блок даних. При цьому маються на увазі лише корисні дані - 8 байтів заголовка в них не включені. |
0x0007 | uint(8) | Прапори? | Невідомо, для чого саме призначений цей блок. У томах це значення часто становить 0x80, а в інших файлах - 0x00. Це свідчить про те, що йдеться про набір прапорців. |
Том
Обсяги - це контейнери даних для гри, схожі на архівний формат, наприклад, Tarball. Принаймні в Outpost 2 цей формат містить лише файли - без папок. Напевно, їх можна було б симулювати за допомогою відповідних імен файлів.
Обсяг складається з заголовка обсягу та кількох блоків обсягу, які відповідають конкретним файлам.
"Обсяги" - це файли з розширенням 'vol'
у директорії гри.
Адр | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | симв. | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | 56 | 4f | 4c | 20 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | V | O | L | . | . | . | . | . | . | . | . | . | . | . | . |
Зсув | Тип даних | Назва | Пояснення |
---|---|---|---|
0x0000 | uint(32) | Магічні байти | |
0x0004 | uint(24) | Довжина блоку | |
0x0007 | uint(8) | Прапори |
Заголовок обсягу
Адр | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | симв. | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | 76 | 6f | 6c | 68 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | v | o | l | h | . | . | . | . | . | . | . | . | . | . | . | . |
Зсув | Тип даних | Назва | Пояснення |
---|---|---|---|
0x0000 | uint(32) | Магічні байти | |
0x0004 | uint(24) | Довжина блоку | |
0x0007 | uint(8) | Прапори |
Обсяг заголовка не містить жодних корисних даних.
Він слугує лише як контейнер.
Першими даними в обсязі заголовка повинні бути рядки обсягу; далі слідують інформація про обсяг.
Об'ємні рядки
Адр | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | симв. | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | 76 | 6f | 6c | 69 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | v | o | l | i | . | . | . | . | . | . | . | . | . | . | . | . |
Зсув | Тип даних | Назва | Пояснення |
---|---|---|---|
0x0000 | uint(32) | Магічні байти | |
0x0004 | uint(24) | Довжина блоку | |
0x0007 | uint(8) | Прапори |
Адр | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | симв. | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | 76 | 6f | 6c | 73 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | v | o | l | s | . | . | . | . | . | . | . | . | . | . | . | . |
Зсув | Тип даних | Назва | Пояснення |
---|---|---|---|
0x0000 | uint(32) | Магічні байти | |
0x0004 | uint(24) | Довжина блоку | |
0x0007 | uint(8) | Прапори | |
0x0008 | uint(32) | Довжина корисного навантаження | Вказує, скільки байтів з наступних даних насправді є корисними даними. Залишкові дані списку рядків обсягу, очевидно, слід вважати сміттям. У файлах з пізніми датами ці 'залишкові дані' мають значення 0x00, що може вказувати на недоліки в інструментарії під час розробки гри, а саме на те, що розробник звернув увагу на правильну ініціалізацію буферів вже дуже пізно, оскільки це не впливає на гру, чи дані ініціалізовані, чи ні. |
0x000c | uint(8)[] | Список імен файлів | Йдеться про список імен файлів, термінований 0-байтом, який - принаймні в даному елементі даних - очікує лише символи ASCII. Немає необхідності при парсингу даних детальніше аналізувати цей блок даних, оскільки в інформації томів безпосередньо вказуються зсуви імен файлів. |
Обсягові рядки є списком імен файлів, які містяться в обсязі.
Інформація про об'єм
Адр | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | симв. | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | 76 | 6f | 6c | 69 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | v | o | l | i | . | . | . | . | . | . | . | . | . | . | . | . |
Зсув | Тип даних | Назва | Пояснення |
---|---|---|---|
0x0000 | uint(32) | Магічні байти | |
0x0004 | uint(24) | Довжина блоку | |
0x0007 | uint(8) | Прапори |
Інформація про том містить більш детальні відомості про файли. Це, певним чином, є своєрідним записом у FAT-довіднику (FAT = таблиця розподілу файлів).
Кількість файлів визначається шляхом ділення розміру блоку на довжину записів у довіднику - 14 байт.
Окремі записи в довіднику мають наступну структуру:
Адр | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | симв. | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . |
Зсув | Тип даних | Назва | Пояснення |
---|---|---|---|
0x0000 | uint(32) | Індекс імен файлів | Вказує, на якому зсуві (!) у списку імен файлів (Volume-Strings) розташоване ім'я файлу. Це стосується початку блоку корисних даних. |
0x0004 | uint(32) | Файл-офсет | Вказує, на якому зсуві в межах усієї об'ємної файлу знаходиться файл. |
0x0008 | uint(32) | Розмір файлу | Вказує, який розмір файлу в байтах. |
0x000c | uint(16) | Прапори? | Здається, є додаткова інформація про кодування файлів.
|
Об'ємний блок
Адр | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | симв. | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | 56 | 42 | 4c | 48 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | V | B | L | H | . | . | . | . | . | . | . | . | . | . | . | . |
Зсув | Тип даних | Назва | Пояснення |
---|---|---|---|
0x0000 | uint(32) | Магічні байти | |
0x0004 | uint(24) | Довжина блоку | |
0x0007 | uint(8) | Прапори |
Об'ємний блок - це контейнер, який містить файли. Він містить лише ще раз - через формат блоку - редундантний розмір файлу, а потім безпосередньо слідують корисні дані.
Плитки
Адр | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | симв. | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | 50 | 42 | 4d | 50 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | P | B | M | P | . | . | . | . | . | . | . | . | . | . | . | . |
Зсув | Тип даних | Назва | Пояснення |
---|---|---|---|
0x0000 | uint(32) | Магічні байти | |
0x0004 | uint(24) | Довжина блоку | |
0x0007 | uint(8) | Прапори |
Тайли є специфічним для Outpost-2 форматом
bitmap-графіки. Вони охоплюють 13 тайлсетів,
названих "колодязями" (well0000.bmp
до well0012.bmp
),
які містяться у обсязі maps.vol.
При цьому тайлсети / колодязі містять наступне:
Ім'я файлу | Зміст |
---|---|
well0000.bmp | Графіка розміром 32x32px, синя - ідеальна для тестування роботи вашого завантажувача зображень |
well0001.bmp | Містить світле каміння, гірські хребти на світлому камінні та безліч варіантів кратерів від ударів на світлому камінні |
well0002.bmp | Містить "Doodads" зі світлого каміння - елементи, які можуть бути розміщені для розбавлення (або свідомо як структура, наприклад, стіни) на світлому камінні, серед яких також є рослинність |
well0003.bmp | Містить структуру, схожу на корку, на світлому камінні |
well0004.bmp | Містить темне каміння, гірські хребти на темному камінні і безліч варіантів кратерів від ударів на темному камінні |
well0005.bmp | Містить "Doodads" з темного каміння - елементи, які можуть бути розміщені для розбавлення (або свідомо як структура, наприклад, стіни) на темному камінні |
well0006.bmp | Містить структуру, схожу на корку, на темному камінні, а також переходи між світлим і темним камінням |
well0007.bmp | Містить лаву, включаючи по 4-5 кадрів анімації для неї |
well0008.bmp | Містить пісок і безліч варіантів кратерів від ударів у пісок |
well0009.bmp | Містить "Doodads" з піску - елементи, які можуть бути розміщені для розбавлення (або свідомо як структура, наприклад, стіни) на піску |
well0010.bmp | Містить по 48 переходів від піску до світлого і темного каміння |
well0011.bmp | Містить полярні шапки карти, з темним камінням як основою |
well0012.bmp | Містить полярні шапки карти, з світлим камінням як основою |
Рекомендується для точної реалізації не рендерити тайли заздалегідь для кешування, оскільки дані для циклу день/ніч ще потрібно обробити - і виникне дуже-дуже багато даних.
Тайли - це 8bpp-графіки з індексованою палітрою розміром 32x32 пікселя, які розташовані один над одним. У такому утвореному тайлсеті, однак, може бути значно більше
Головний контейнер складається з 2 секцій: head
та data
.
Заголовок плитки
Адр | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | симв. | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | 68 | 65 | 61 | 64 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | h | e | a | d | . | . | . | . | . | . | . | . | . | . | . | . |
0x0010 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . |
Зсув | Тип даних | Назва | Пояснення |
---|---|---|---|
0x0000 | uint(32) | Магічні байти | |
0x0004 | uint(24) | Довжина блоку | |
0x0007 | uint(8) | Прапори | |
0x0008 | uint(32) | Версія / Прапори? | Це може бути вказівкою версії формату файлу; у всіх наявних у мене файлах тут було значення |
0x000c | uint(32) | Ширина (Горизонтальний розділ) | Вказує, наскільки широка файл зображення (в пікселях). У всіх колодязях з Outpost 2 тут очікується значення |
0x0010 | uint(32) | Висота (Вертикальне розділення) | Вказує, яка висота зображення (в пікселях). У всіх колодязях Outpost 2 тут слід очікувати значення |
0x0014 | uint(32) | Глибина кольору? | Значення цього параметра невідоме. Оскільки він містить значення |
0x0018 | uint(32) | Глибина кольору 2? | Значення цього значення невідоме. Можливо, це 'цільова' глибина кольору. |
Після цих даних буде надано ще файл палітри у стандартизованому форматі RIFF. Точну специфікацію можна знайти - оскільки палітри з'являються і в інших місцях - за посиланням Палітри.
Дані плитки
Адр | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | симв. | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | 64 | 61 | 74 | 61 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | d | a | t | a | . | . | . | . | . | . | . | . | . | . | . | . |
Зсув | Тип даних | Назва | Пояснення |
---|---|---|---|
0x0000 | uint(32) | Магічні байти | |
0x0004 | uint(24) | Довжина блоку | |
0x0007 | uint(8) | Прапори |
Нарешті йдуть чисті піксельні дані, зліва зверху рядками донизу справа.
Значення даних у графіках, які зазвичай представлені у форматі 8bpp-бітмапи, відповідає індексу кольору в палітрі кольорів.
Ігровий движок, ймовірно, малює тайли *на вимогу*.
Це, зокрема, пов'язано з циклом день-ніч, який має 32 ступені окремих тайлів. При цьому, очевидно, від значення яскравості 'трохи' віднімається. Точні значення ще не вдалося визначити, я працюю на основі розрахунків
v *= (daylight / 48) + 0.25;
з HSV-даними пікселів, де daylight – це значення від 0 до 31, а v – це значення між 0 і 1. Крім того, слід врахувати, що на карті є ще край з 16 тайлів зліва і справа (він служить для невидимого спавну одиниць).
Додатково, здається, що цикл день-ніч оновлює лише один стовпець карти за кожен ігровий цикл.
Прискорений цикл день-ніч виглядає наступним чином:
ПРТ
Адр | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | симв. | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | 43 | 50 | 41 | 4c | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | C | P | A | L | . | . | . | . | . | . | . | . | . | . | . | . |
Зсув | Тип даних | Назва | Пояснення |
---|---|---|---|
0x0000 | uint(32) | Магічні байти | |
0x0004 | uint(24) | Довжина палет | Вказує, на відміну від звичайного блочного формату, кількість палет, що можна знайти в цьому файлі - не довжину блоку в байтах. |
0x0007 | uint(8) | Прапори | Напевно, як звичайно, флаги. Однак мені не відомі ніякі флаги; оскільки всі відомі мені значення відповідають |
Що саме означає PRT
мені невідомо; можливо, це може бути 'Таблиця палітри та ресурсів' - оскільки цей файл, який можна знайти як op2_art.prt у maps.vol, насправді є таким, тобто це досить добре описує його функцію.
Цей файл містить список палітр, таблицю всіх використаних бітмапів, всі визначення анімацій та ще ряд невідомих даних. Він слідує попередньому формату контейнерів у загальних рисах, оскільки не всі записи відповідають цій схемі.
Розділ CPAL
(імовірно, означає контейнер палітри) охоплює лише дані палітри, вказуючи, скільки з них зазвичай містять 1052 байти великі 8-бітні палітри.
Вказівка на 1052 байти не є обов’язковою, оскільки формат палітри потенційно передбачає різні розміри палітр. Вона стосується лише даних, з якими постачається Outpost 2.
Після списків палітр безпосередньо і без вступного заголовка йде список бітмапів; так само безпосередньо йдуть списки анімацій.
Обидва вони починаються з uint(32) (або знову uint24+uint8 прапорці?), який містить кількість записів.
Палітри
Адр | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | симв. | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | 50 | 50 | 41 | 4c | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | P | P | A | L | . | . | . | . | . | . | . | . | . | . | . | . |
Зсув | Тип даних | Назва | Пояснення |
---|---|---|---|
0x0000 | uint(32) | Магічні байти | |
0x0004 | uint(24) | Довжина палет | Вказує, на відміну від звичайного блочного формату, кількість палет, які можна знайти у цьому файлі, а не довжину блоку в байтах. |
0x0007 | uint(8) | Прапори | Ймовірно, як зазвичай, це прапори. Проте мені не відомі жодні прапори; оскільки всі відомі мені значення відповідають |
Інформацію про палети дуже легко прочитати.
Вона складається з заголовка та сегмента даних.
Заголовок палет
Адр | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | симв. | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | 68 | 65 | 61 | 64 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | h | e | a | d | . | . | . | . | . | . | . | . | . | . | . | . |
Зсув | Тип даних | Назва | Пояснення |
---|---|---|---|
0x0000 | uint(32) | Магічні байти | |
0x0004 | uint(24) | Довжина палет | Вказує, на відміну від звичайного блочного формату, кількість палет, які можна знайти у цьому файлі, а не довжину блоку в байтах. |
0x0007 | uint(8) | Прапори | Ймовірно, як зазвичай, це прапори. Проте мені не відомі жодні прапори; оскільки всі відомі мені значення відповідають |
0x0008 | uint(32) | Версія формату палет? | Ймовірно, визначає, якій версії формату палет відповідає палета. Усі палети Outpost2, здається, мають версію |
Дані палет
Адр | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | симв. | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | 64 | 61 | 74 | 61 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | d | a | t | a | . | . | . | . | . | . | . | . | . | . | . | . |
Зсув | Тип даних | Назва | Пояснення |
---|---|---|---|
0x0000 | uint(32) | Магічні байти | |
0x0004 | uint(24) | Довжина блоку | |
0x0007 | uint(8) | Прапори |
Секція даних містить окремі записи палет. Кількість записів палет визначається за формулою: довжина блоку / 4.
Окремі записи мають наступну, просту структуру;
Адр | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | симв. | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | -- | -- | -- | 04 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . |
Зсув | Тип даних | Назва | Пояснення |
---|---|---|---|
0x0000 | uint(8) | Червоний компонент | Вказує на червоний відсоток кольору |
0x0001 | uint(8) | Зелена компонента | Вказує на частку зеленого кольору |
0x0002 | uint(8) | Синя компонента | Вказує на частку синього кольору |
0x0003 | uint(8) | Невідомо - Прапори? | Невідомо, що означає це значення, оскільки воно, здається, в основному |
Щодо палітри, слід зазначити, що для палітр, які використовуються в анімаціях, діють такі правила:
- Перший колір завжди є прозорим, незалежно від вказаного значення.
-
Записи палітри з 1 по 24 слід вважати кольорами гравців у палітрах з 1 по 8.
Де саме походять кольори, окрім кольору гравця 1, мені не зовсім зрозуміло.
Я припускаю, що решта кольорів закодовані.
Бітмапи
Адр | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | симв. | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . |
0x0010 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . |
Зсув | Тип даних | Назва | Пояснення |
---|---|---|---|
0x0000 | uint(32) | Орієнтована ширина | Вказує ширину піксельних даних у байтах - оскільки вони вирівняні по 4-байтових межах. Таким чином, швидко можна перейти до конкретного рядка зображення. Чому це значення зберігається окремо, хоча його можна було б обчислити, залишається незрозумілим. |
0x0004 | uint(32) | Зсув | Вказує зсув першого рядка у бітовій мапі |
0x0008 | uint(32) | Висота | Вказує висоту зображення в пікселях |
0x000c | uint(32) | Ширина | Вказує ширину зображення в пікселях |
0x0010 | uint(16) | Тип | Вказує тип зображення. Йдеться, ймовірно, про бітову маску:
|
0x0012 | uint(16) | Палета | Визначає, яка палітра з файлу PRT повинна бути використана |
Ця структура даних PRT-файлу вказує на те, як побудовані бітмапи, що використовуються для спрайтів. Ці бітмапи служать окремим елементом, з якого кілька збираються в анімаційний кадр спрайта.
Конкретні зображення даних приховані в
op2_art.BMP в каталозі гри.
Чому цей файл бітмапи має (в основному правильний) заголовок RIFF-бітмапа,
залишається незрозумілим. Ймовірно, Outpost 2 використовує системні API для завантаження графіки,
тимчасово приймаючи цей заголовок і перезаписуючи відповідні, змінні поля.
Піксельні дані в BMP-файлі можна знайти за позначкою Offset + uint32-Offset, який можна знайти в BMP-файлі за адресою 0x000A (RIFF-офсет даних бітмапа) - і вони знову відповідають рядковій структурі зліва направо зверху вниз.
Монохромні графіки 1bpp можуть бути намальовані так, що колір 0 є повністю прозорим, а колір 1 є напівпрозорим чорним/сірим, оскільки монохромні графіки звичайно використовуються для тіней автомобілів і будівель в анімаціях.
Таким чином, можна скласти вже багато графіків.
Анімації
Тепер ми переходимо до королівського класу дисциплін серед форматів даних Outpost 2:
Анімацій.
Списки анімацій починаються з глобального заголовка, який в основному слугує для перевірки даних. Потім слідують конкретні визначення анімацій, які поділяються на 3 рівні:
-
Анімація
Анімація є найвищою інстанцією; вона представляє анімацію одиниці, будівлі або "частинкову анімацію" (удар комети, погода, вибух) у певній початковій ситуації. -
Кадр
Кадр — це окреме зображення в межах анімації. Анімація може містити один або кілька кадрів. -
Субкадр
Субкадр — це інформація про те, що певна бітмап під певними критеріями має бути намальована на певній позиції кадру. Кадр може містити один або кілька субкадрів.
Наступними йдуть безпосередньо окремі визначення анімацій.
Адр | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | симв. | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . |
Зсув | Тип даних | Назва | Пояснення |
---|---|---|---|
0x0000 | uint(32) | Кількість анімацій | Скільки наявних анімаційних наборів даних |
0x0004 | uint(32) | Кількість кадрів | Скільки загалом повинно бути кадрів |
0x0008 | uint(32) | Кількість підрамок | Скільки підрамок повинно бути в цілому |
0x000c | uint(32) | Кількість необов'язкових записів | Скільки "додаткових записів" існує. |
Анімація
Адр | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | симв. | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . |
0x0010 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . |
0x0020 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . |
Зсув | Тип даних | Назва | Пояснення |
---|---|---|---|
0x0000 | uint(32) | Невідомий 1 | Невідомі відомості |
0x0004 | uint(32) | Обмежуючий прямокутник: Зліва | Вказує лівий початок (в пікселях) Bounding Box. |
0x0008 | uint(32) | Обмежувальний прямокутник: Верхня частина | Вказує верхній початок (в пікселях) Bounding Box. |
0x000c | uint(32) | Обмежувальна рамка: Ширина | Вказує ширину (в пікселях) обмежувальної рамки. |
0x0010 | uint(32) | Обмежувальний прямокутник: висота | Вказує висоту (в пікселях) Bounding Box. |
0x0014 | uint(32) | Зсув: X | Вказує горизонтальний центр анімації |
0x0018 | uint(32) | Зсув: Y | Вказує вертикальний центр анімації |
0x001c | uint(32) | Невідомо 2 | Невідома інформація |
0x0020 | uint(32) | Кількість кадрів | Вказує, скільки анімаційних кадрів міститься в цій анімації |
0x0024 | uint(32) | Кількість вікон | Вказує, скільки вікон слід використовувати під час малювання |
Дані верхнього шару, анімації, є переважно адміністративними даними - Boundingbox позначає координати мітки навколо транспортного засобу/будівлі, коли вона вибрана, і також вказує, яка область має бути активною для кліку.
Зміщення (offset) в основному визначає "нулеву точку"; точку, яку потрібно враховувати або віднімати для внутрішніх координат гри. Можна також сказати більш математично: зміщення тут позначає координатний початок.
Вікна аналогічно до зміщення складаються з 4-х uint(32) значень (для кожного вікна), які визначають область, що вважається придатною для окремих субкадрів. За межами вікон не повинно малюватися, якщо це не передбачено для растрового зображення.
Рамка
Адр | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | симв. | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . |
Зсув | Тип даних | Назва | Пояснення |
---|---|---|---|
0x0000 | uint(8) | Кількість підрамників та перемикач для Опціонал 1, 2 | Це значення містить:
|
0x0001 | uint(8) | Невідомий 1 та перемикач для необов'язкових 3, 4 | Це значення містить:
|
0x0002 | uint(8) | Необов'язковий 1 | Невідомо |
0x0003 | uint(8) | Необов'язковий 2 | Невідомо |
0x0004 | uint(8) | Необов'язковий 3 | Невідомо |
0x0005 | uint(8) | Необов'язковий 4 | Невідомо |
Підрамник
Адр | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | xA | xB | xC | xD | xE | xF | симв. | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0000 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . |
Зсув | Тип даних | Назва | Пояснення |
---|---|---|---|
0x0000 | uint(16) | Bitmap-Ідентифікатор | Вказує, яка бітова мапа має використовуватися для цього підфрейму |
0x0002 | uint(8) | Невідомий 1 | Невідомо - проте я сильно підозрюю, що це стосується пріоритету рендерингу (Z-слой). |
0x0003 | uint(8) | Підрамник-Ідентифікатор | Вказує, у якому підфреймі ми знаходимося |
0x0004 | sint(16) | Зсув - Горизонтальний | Вказує, де всередині фрейма має бути розміщено підфрейм, або на скільки пікселів бітмап має бути горизонтально зсунуто. |
0x0006 | sint(16) | Зсув - Вертикальний | Вказує, де всередині фрейму слід розмістити підфрейм, або на скільки пікселів бітмапу потрібно змістити вертикально. |
Тепер ми можемо складати окремі кадри, а також цілі анімації відповідно, на прикладі більш складної анімації з індексом 500, продемонстровано
Анімація 500
Анімація 500 показує, як вантажівка Plymouth, завантажена звичайною рудою, розвантажується. Це одна з небагатьох анімацій, яка використовує функціональність вікон.
Отже, можна зібрати всю анімацію разом.
На жаль, є ще одна проблема з верхнім люком, оскільки відповідний біт у інформації про тип графіки не встановлений.
Ось ще кілька інших, чудово анімованих спрайтів з гри:
Користувацький інтерфейс
Тепер залишилося ще інтерфейс користувача гри, який виконаний у стилі шліфованого металу.
Але й тут видно, що Dynamix не потрібно було винаходити велосипед заново; тут використовуються не лише прості функції, надані API User32 та GDI32 від Windows - зокрема, також використовується управління ресурсами User32.
Ці ресурси можна, наприклад, витягнути за допомогою програм, таких як Resource Hacker, що розроблений Angus Johnson як безкоштовне програмне забезпечення, або - якщо ви уникаєте використання Wine під Linux / Mac OS - за допомогою wrestool, що входить до складу icoutils.
Ім'я файлу | Вміст |
---|---|
Outpost2.exe | Містить лише іконку гри, яка зображує космічну станцію перед New Terra |
op2shres.dll | Містить крім графіки для елементів управління, таких як обрамлення, кнопки, радіокнопки та прапорці, також фонові зображення для діалогів, супутні зображення для текстів сюжетних місій і фонову графіку головного меню |
out2res.dll | Містить оформлення вікон у грі, іконки для звичайного та спеціального металу, екран завантаження, графіки для діалогів, а також додаткові графіки курсора, окрім анімованих у каталозі гри |