Outpost 2 Dateiformate · bei.pm

Die auf dieser Seite beschriebenen Dateiformate basieren auf der technischen Analyse geistigem Eigentums von Dynamix, Inc. und Sierra Entertainment.
Das geistige Eigentum ist heute Teil der Activision Publishing, Inc.- / Activision Blizzard, Inc.-Masse und derzeit im Besitz von Microsoft Corp..

Die Informationen wurden durch Reverse Engineering und Datenanalyse zum Zwecke der Archivierung und Interoperabilität mit historischen Daten zusammengetragen.
Es wurden keine proprietären oder vertraulichen Spezifikationen verwendet.

Das Spiel kann derzeit bei gog.com käuflich als Download erworben werden.

Artwork des Spiels

Die folgende Artikel-Reihe dokumentiert meine Erkenntnisse zu den Datenformaten im Echtzeit-Strategiespiel "Outpost 2: Geteilte Bestimmung", welches 1997 durch Sierra veröffentlicht und von Dynamix entwickelt wurde.

Ich habe mich etwa vom 01. November 2015 bis zum 14. November 2015 vorranging mit der Analyse der Daten des Spieles - und was es damit anfängt - beschäftigt.

Den Informationen, die ich bislang gewinnen konnte, zufolge hat Dynamix - wie so viele kommerzielle Unternehmen - einige Datenformate nicht speziell für Outpost 2 entwickelt, sondern auch in anderen Entwicklungen wie zum Beispiel der Mechwarrior-Serie (abgewandelt) verwendet.
Unabhängig davon lässt sich zudem feststellen, dass sich die Innovationskraft der Dateiformate praktisch in Grenzen hält und häufig auf länger bestehenden Konzepte aus üblichen Formaten wie JFIF und RIFF aufgebaut wird.

Zur Interpretation der Tabellen und Datenformate stehen weitere Informationen unter Was ist was? bereit.
Die hier angegebenen Daten sind im Allgemeinen als Little Endian zu verstehen.

Abschließend lässt sich sagen, dass das Reverse Engineering sehr viel Spaß bereitete, auch wenn es nicht vollständig ist.
Natürlich kann ich auch nur empfehlen, das Spiel selbst zu spielen, da es interessante Spielmechaniken bietet.

Einführung

Die von Outpost 2 verwendeten Datenformate haben einen an JFIF / PNG erinnernden Aufbau - die einzelnen Datenblöcke verfügen dabei immer über einen 8 Byte Header. Daher spare ich es mir, die einzelnen Header an den entsprechenden spezifischen Stellen zu dokumentieren und dokumentiere dort nur Abweichungen.

Das Format ist immer das folgende; die eigentlichen Nutzdaten sind dann darin eingebettet:

Adr x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF char
0x0000 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- . . . . . . . . . . . . . . . .
Offset Datentyp Bezeichnung Erklärung
0x0000 uint(32) Magic Bytes

Enthält die Information darüber, was im nächsten Datenblock zu erwarten ist.

Bekannte Werte:

  • 0x204C4F56 ('VOL '):
    Volume
  • 0x686C6F76 ('VOLH'):
    Volume-Header
  • 0x736C6F76 ('VOLS'):
    Volume-Strings
  • 0x696C6F76 ('VOLI'):
    Volume-Informationen
  • 0x4B4C4256 ('BLCK'):
    Volume-Block
  • 0x504D4250 ('PBMP'):
    Grafikdaten
  • 0x4C415050 ('PPAL'):
    Farbpalette
  • 0x4C415043 ('CPAL'):
    Farbpaletten-Container
  • 0x64616568 ('head'):
    Header
  • 0x61746164 ('data'):
    Nutzdaten
0x0004 uint(24) Block-Länge

Enthält die Information darüber, wie groß (in Byte) der folgende Datenblock ist.

Dabei sind die reinen Nutzdaten gemeint - die 8 Header-Byte sind darin nicht enthalten.

0x0007 uint(8) Flags?

Es ist unbekannt, wozu dieser Block genau dient.

In den Volumes ist dieser Wert häufig 0x80, in anderen Dateien häufig 0x00. Das legt nahe, dass es sich um ein Flag-Set handelt.

Volumes

Bei den Volumes handelt es sich um einen Datencontainer für das Spiel, ähnlich zu einem Archivformat wie z.B. Tarball. Zumindest in Outpost 2 kennt das Format dabei lediglich Dateien - keine Ordner. Wahrscheinlich ließen sich diese allerdings über entsprechende Dateinamen simulieren.

Ein Volume besteht dabei aus dem Volume-Header sowie aus mehreren Volume Blöcken, die den konkreten Dateien entsprechen.

"Volumes" sind die Dateien mit der Endung 'vol' im Spielverzeichnis.

Adr x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF char
0x0000 56 4f 4c 20 -- -- -- -- -- -- -- -- -- -- -- -- V O L . . . . . . . . . . . .
Offset Datentyp Bezeichnung Erklärung
0x0000 uint(32) Magic Bytes
0x0004 uint(24) Block-Länge
0x0007 uint(8) Flags

Volume Header

Adr x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF char
0x0000 76 6f 6c 68 -- -- -- -- -- -- -- -- -- -- -- -- v o l h . . . . . . . . . . . .
Offset Datentyp Bezeichnung Erklärung
0x0000 uint(32) Magic Bytes
0x0004 uint(24) Block-Länge
0x0007 uint(8) Flags

Der Volume Header enthält seinerseits keinerlei Nutzdaten.
Er dient lediglich als Container.

Als erstes Datum im Volume Header sollten sich die Volume Strings finden; darauf folgen dann die Volume-Informationen.

Volume Strings

Adr x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF char
0x0000 76 6f 6c 69 -- -- -- -- -- -- -- -- -- -- -- -- v o l i . . . . . . . . . . . .
Offset Datentyp Bezeichnung Erklärung
0x0000 uint(32) Magic Bytes
0x0004 uint(24) Block-Länge
0x0007 uint(8) Flags
Adr x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF char
0x0000 76 6f 6c 73 -- -- -- -- -- -- -- -- -- -- -- -- v o l s . . . . . . . . . . . .
Offset Datentyp Bezeichnung Erklärung
0x0000 uint(32) Magic Bytes
0x0004 uint(24) Block-Länge
0x0007 uint(8) Flags
0x0008 uint(32) Payload-Länge

Gibt an, wieviele Bytes der folgenden Daten tatsächlich Nutzdaten sind.

Die restlichen, verbleibenden Daten der Volume-Strings-Liste sind offenbar als garbage zu werten.

In Dateien mit späterem Datum sind diese 'verbleibenden Daten' 0x00, was auf Unzulänglichkeiten mit der Toolchain während der Entwicklung des Spieles deuten könnte, sprich, dass sich erst sehr spät ein Entwickler um die korrekte Initialisierung der Puffer gekümmert hat, da es keinen Einfluss auf das Spiel hat, ob die Daten initialisiert sind oder nicht.

0x000c uint(8)[] Dateinamen-Liste

Hierbei handelt es sich um eine 0-Byte-Terminierte Liste von Dateinamen, die - zumindest im vorliegenden Datenbestandteil - lediglich ASCII-Zeichen erwarten lässt.

Es ist nicht nötig, beim Parsen der Daten diesen Datenblock genauer auszuwerten, da in den Volume-Informationen ohnehin direkt die Offsets der Dateinamen referenziert werden.

Bei den Volume Strings handelt es sich um eine Liste von Dateinamen, die innerhalb des Volumes enthalten sind.

Volume Informationen

Adr x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF char
0x0000 76 6f 6c 69 -- -- -- -- -- -- -- -- -- -- -- -- v o l i . . . . . . . . . . . .
Offset Datentyp Bezeichnung Erklärung
0x0000 uint(32) Magic Bytes
0x0004 uint(24) Block-Länge
0x0007 uint(8) Flags

Die Volume-Informationen nehmen detailliertere Informationen zu den Dateien auf. Dabei handelt es sich in gewisser Weise um eine Art FAT-Verzeichniseintrag (FAT = File Allocation Table)

Die Anzahl an Dateien ergibt sich aus der Blockgröße geteilt durch die Länge der Verzeichniseinträge - 14 Byte.

Die einzelnen Verzeichniseinträge haben dabei jeweils folgenden Aufbau:

Adr x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF char
0x0000 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- . . . . . . . . . . . . . . . .
Offset Datentyp Bezeichnung Erklärung
0x0000 uint(32) Dateinamen-Offset

Gibt an, an welchem Offset (!) innerhalb der Dateinamensliste (Volume-Strings) der Dateiname der Datei findet.

Bezieht sich dabei auf den Anfang des Nutzdatenblocks.

0x0004 uint(32) Datei-Offset

Gibt an, an welchem Offset innerhalb der gesamten Volume-Datei sich die Datei befindet.

0x0008 uint(32) Datei-Größe

Gibt an, wie groß die Datei in Byte ist.

0x000c uint(16) Flags?

Gibt offenbar zusätzliche Informationen über die Dateikodierung an.

  • 0x03 ist gesetzt, wenn die Datei komprimiert ist. Hier kommt offenbar ein Huffmann-Baum zum Einsatz.
  • 0x80 ist scheinbar immer gesetzt.

Volume Block

Adr x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF char
0x0000 56 42 4c 48 -- -- -- -- -- -- -- -- -- -- -- -- V B L H . . . . . . . . . . . .
Offset Datentyp Bezeichnung Erklärung
0x0000 uint(32) Magic Bytes
0x0004 uint(24) Block-Länge
0x0007 uint(8) Flags

Bei einem Volume-Block handelt es sich um einen Container, der Dateien aufnimmt. Er enthält lediglich noch einmal - aufgrund des Blockformates - redundant die Dateigröße und anschließend folgen direkt die Nutzdaten.

Tiles

Adr x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF char
0x0000 50 42 4d 50 -- -- -- -- -- -- -- -- -- -- -- -- P B M P . . . . . . . . . . . .
Offset Datentyp Bezeichnung Erklärung
0x0000 uint(32) Magic Bytes
0x0004 uint(24) Block-Länge
0x0007 uint(8) Flags

Bei den Tiles handelt es sich um ein Outpost-2-Spezifisches Bitmap-Grafikformat. Sie erstrecken sich über 13 Tilesets, "wells" genannt (well0000.bmp bis well0012.bmp), die sich innerhalb des Volumes maps.vol befinden.

Dabei enthalten die Tilesets / Wells folgendes:

Dateiname Inhalt
well0000.bmp Eine 32x32px große, blaue Grafik - ideal als Test, ob der eigene Image-Loader funktioniert
well0001.bmp Enthält helles Gestein, Gebirgszüge auf hellem Gestein und unzählige Varianten von Einschlagskratern in helles Gestein
well0002.bmp Enthält helles-Gestein-'Doodads' - also Elemente, die zur Auflockerung (oder bewusst als Struktur, wie zB Mauern) auf hellem Gestein platziert werden können, darunter auch Vegetation
well0003.bmp Enthält eine krustenartige Struktur auf hellem Gestein
well0004.bmp Enthält dunkles Gestein, Gebirgszüge auf dunklem Gestein und unzählige Varianten von Einschlagskratern in dunkles Gestein
well0005.bmp Enthält dunkles-Gestein-'Doodads' - also Elemente, die zur Auflockerung (oder bewusst als Struktur, wie zB Mauern) auf dunklem Gestein platziert werden können
well0006.bmp Enthält eine Krustenartige Struktur auf dunklem Gestein, sowie Übergänge zwischen hellem und dunklem Gestein
well0007.bmp Enthält Lava inklusive jeweils 4-5 Frames Animation der selbigen
well0008.bmp Enthält Sand und unzählige Varianten von Einschlagskratern in Sand
well0009.bmp Enthält Sand-'Doodads' - also Elemente, die zur Auflockerung (oder bewusst als Struktur, wie zB Mauern) auf Sand platziert werden können
well0010.bmp Enthält je 48 Übergänge von Sand zu hellem und dunklem Gestein
well0011.bmp Enthält die Polarkappen der Map, mit dunklem Gestein als Untergrund
well0012.bmp Enthält die Polarkappen der Map, mit hellem Gestein als Untergrund

Es erschreit ratsam für eine akkurate Umsetzung, die Tiles nicht im Vorraus zu rendern um diese zu cachen, da die Daten für den Tag/Nacht-Zyklus noch bearbeitet werden müssen - und sehr sehr viele Daten anfallen würden.

Die Tiles sind 8bpp-Grafiken mit indexierter Palette zu je 32x32 Pixel Auflösung, welche untereinander angeordnet sind. In einem so entstandenen Tileset können allerdings weitaus mehr

Der Haupt-Container besteht aus 2 Sektionen: head und data.

Tiles Header

Adr x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF char
0x0000 68 65 61 64 -- -- -- -- -- -- -- -- -- -- -- -- h e a d . . . . . . . . . . . .
0x0010 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- . . . . . . . . . . . . . . . .
Offset Datentyp Bezeichnung Erklärung
0x0000 uint(32) Magic Bytes
0x0004 uint(24) Block-Länge
0x0007 uint(8) Flags
0x0008 uint(32) Version / Flags?

Hierbei könnte es sich um eine Versionsangabe des Dateiformates handeln; in allen mir vorliegenden Dateien stand hier der Wert 0x02

0x000c uint(32) Breite (Horizontale Auflösung)

Gibt an, wie breit die Bilddatei ist (in Pixel).

Bei allen Wells von Outpost 2 wird hier der Wert 0x20 bzw 32 zu erwarten sein.

0x0010 uint(32) Höhe (Vertikale Auflösung)

Gibt an, wie hoch die Bilddatei ist (in Pixel).

Bei allen Wells von Outpost 2 wird hier der Wert 0x20 bzw 32 zu erwarten sein.

0x0014 uint(32) Farbtiefe?

Die Bedeutung dieses Wertes ist unbekannt.

Da er in allen geprüften Dateien den Wert 8 enthält, könnte es sich um eine Farbtiefenangabe handeln.

0x0018 uint(32) Farbtiefe 2?

Die Bedeutung dieses Wertes ist unbekannt.

Möglicherweise handelt es sich um eine 'Ziel'-Farbtiefe.

Nach diesen Angaben erfolgt noch eine im standardisierten RIFF-Format vorliegende Palettendatei. Die genaue Spezifikation findet sich - da die Paletten auch anderswo auftauchen - unter Paletten.

Tiles Daten

Adr x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF char
0x0000 64 61 74 61 -- -- -- -- -- -- -- -- -- -- -- -- d a t a . . . . . . . . . . . .
Offset Datentyp Bezeichnung Erklärung
0x0000 uint(32) Magic Bytes
0x0004 uint(24) Block-Länge
0x0007 uint(8) Flags

Schließlich folgen bereits die blanken Pixeldaten, von links-oben zeilenweise nach rechtsunten.
Der Datenwert bei den in aller Regel als 8bpp-Bitmaps vorliegenden Grafiken entspricht dabei dem Index der Farbe in der Farbpalette.

Pixeldaten beginnen oben links und enden unten rechts.

Die Spiel-Engine zeichnet die Tiles dabei *wahrscheinlich* on-demand.
Dies scheint unter anderem dem Tag-Nacht-Zyklus geschuldet zu sein, der 32 Abstufungen einzelner Tiles kennt. Dabei wird offenbar vom Helligkeitswert jeweils 'ein wenig' abgezogen. Genaue Werte ließen sich noch nicht ermitteln, ich arbeite auf der Berechnungsgrundlage

v *= (daylight / 48) + 0.25;

mit den HSV-Daten der Pixel, wobei daylight ein Wert von 0-31 ist und v ein Wert zwischen 0-1. Darüber hinaus ist zu berücksichtigen, dass auf der Map jeweils noch ein Rand von 16 Tiles nach links und rechts (der dient dem unsichtbaren Spawnen von Einheiten) existiert.

Zusätzlich scheint der Tag-Nacht-Zyklus pro Gamecycle jeweils nur eine Spalte der Map zu aktualisieren.
Ein beschleunigter Tag-Nacht-Zyklus sieht daher wie folgt aus:

Visualisierung des Tag-Nacht-Zyklus

PRT

Adr x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF char
0x0000 43 50 41 4c -- -- -- -- -- -- -- -- -- -- -- -- C P A L . . . . . . . . . . . .
Offset Datentyp Bezeichnung Erklärung
0x0000 uint(32) Magic Bytes
0x0004 uint(24) Paletten-Länge

Gibt, entgegen zum normalen Blockformat, die Anzahl an in dieser Datei zu findenden Paletten an - nicht die Länge des Blocks in Byte.

0x0007 uint(8) Flags

Wahrscheinlich, wie üblich, Flags.

Mir sind allerdings keine Flags bekannt; da alle mir bekannten Werte 0x00 entsprechen, wäre es auch potentiell denkbar, dass die Paletten-Anzahl schlicht ein uint(32) wäre.

Wofür PRT genau steht ist mir nicht bekannt; denkbar wäre beispielsweise 'Palette and Ressource Table' - da es sich bei dieser Datei - zu finden als op2_art.prt in der maps.vol - um eine solche handelt, bzw dies die Funktion ganz gut beschreiben würde.

Diese Datei enthält dabei eine Liste von Paletten, eine Tabelle über alle verwendeten Bitmaps, alle Animationsdefinitionen und noch eine Reihe von unbekannten Daten. Sie folgt dem bisherigen Containerformat lose, da nicht alle Datensätze diesem Schema folgen.

Die CPAL-Sektion (steht wahrscheinlich für Paletten-Container) umschließt dabei lediglich die Palettendaten, indem es angibt, wieviele der jeweils üblicherweise 1052 Byte großen 8-Bit-Paletten vorhanden sind.

Die 1052-Byte-Angabe gilt dabei nicht als verbindlich, da das Palettenformat potentiell unterschiedliche Palettengrößen vorsähe. Sie gilt lediglich für den Datenbestand, mit dem Outpost 2 ausgeliefert wird.

Nach den Paletten-Listen folgt unmittelbar und ohne einleitenden Header, bereits die Liste der Bitmaps; genauso unmittelbar folgen darauf die Animationslisten.
Beide werden dabei jeweils mit einem uint(32) (oder wieder uint24+uint8 flags?) eingeleitet, der die Anzahl an Datensätzen enthält.

Paletten

Adr x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF char
0x0000 50 50 41 4c -- -- -- -- -- -- -- -- -- -- -- -- P P A L . . . . . . . . . . . .
Offset Datentyp Bezeichnung Erklärung
0x0000 uint(32) Magic Bytes
0x0004 uint(24) Paletten-Länge

Gibt, entgegen zum normalen Blockformat, die Anzahl an in dieser Datei zu findenden Paletten an - nicht die Länge des Blocks in Byte.

0x0007 uint(8) Flags

Wahrscheinlich, wie üblich, Flags.

Mir sind allerdings keine Flags bekannt; da alle mir bekannten Werte 0x00 entsprechen, wäre es auch potentiell denkbar, dass die Paletten-Anzahl schlicht ein uint(32) wäre.

Die Paletten-Informationen sind sehr einfach einzulesen.
Sie bestehen jeweils aus einem Header und einem Data-Segment.

Paletten-Header

Adr x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF char
0x0000 68 65 61 64 -- -- -- -- -- -- -- -- -- -- -- -- h e a d . . . . . . . . . . . .
Offset Datentyp Bezeichnung Erklärung
0x0000 uint(32) Magic Bytes
0x0004 uint(24) Paletten-Länge

Gibt, entgegen zum normalen Blockformat, die Anzahl an in dieser Datei zu findenden Paletten an - nicht die Länge des Blocks in Byte.

0x0007 uint(8) Flags

Wahrscheinlich, wie üblich, Flags.

Mir sind allerdings keine Flags bekannt; da alle mir bekannten Werte 0x00 entsprechen, wäre es auch potentiell denkbar, dass die Paletten-Anzahl schlicht ein uint(32) wäre.

0x0008 uint(32) Palettenformat-Version?

Definiert wahrscheinlich, welcher Palettenformats-Version die Palette folgt.

Alle Outpost2-Paletten scheinen dabei Version 0x01 zu besitzen.

Paletten-Daten

Adr x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF char
0x0000 64 61 74 61 -- -- -- -- -- -- -- -- -- -- -- -- d a t a . . . . . . . . . . . .
Offset Datentyp Bezeichnung Erklärung
0x0000 uint(32) Magic Bytes
0x0004 uint(24) Block-Länge
0x0007 uint(8) Flags

Die Datensektion nimmt die einzelnen Paletten-Einträge auf. Die Anzahl an Paletten-Einträge ergibt sich aus der Block-Länge / 4.

Die einzelnen Einträge haben dabei folgenden, schlichten Aufbau;

Adr x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF char
0x0000 -- -- -- 04 -- -- -- -- -- -- -- -- -- -- -- -- . . . . . . . . . . . . . . . .
Offset Datentyp Bezeichnung Erklärung
0x0000 uint(8) Rot-Komponente

Gibt den Rot-Anteil der Farbe an

0x0001 uint(8) Grün-Komponente

Gibt den Grün-Anteil der Farbe an

0x0002 uint(8) Blau-Komponente

Gibt den Blau-Anteil der Farbe an

0x0003 uint(8) Unbekannt - Flags?

Es ist unklar, was dieser Wert bedeutet, da er scheinbar grundsätzlich 0x04 ist.

Zu den Paletten ist ansonsten nur noch zu sagen, dass bei für Animationen zu verwendende Paletten folgende Regeln gelten:

  • Die erste Farbe ist IMMER transparent, egal was für ein Wert dort angegeben ist.
  • Die Paletten-Einträge 1-24 sind in den Paletten 1-8 als Spielerfarbe zu werten.
    Wo die Farben abseits von Spieler 1 genau herkommen, ist mir unklar.
    ich vermute, dass die restlichen Farben hardcoded sind

Paletten-Referenz

Bitmaps

Adr x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF char
0x0000 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- . . . . . . . . . . . . . . . .
0x0010 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- . . . . . . . . . . . . . . . .
Offset Datentyp Bezeichnung Erklärung
0x0000 uint(32) Ausgerichtete Breite

Gibt die Breite der Pixeldatenzeilen in Byte an - da diese an die 4-Byte-Grenzen ausgerichtet sind.

So ist es schnell möglich, eine bestimmte Bildzeile anzuspringen.

Warum dieser Wert separat gespeichert wird, obwohl er berechnet werden könnte, ist unklar.
Möglicherweise handelt es sich um eine Optimierung für den Render-Code.

0x0004 uint(32) Offset

Gibt den Offset der ersten Zeile in der Bitmap an

0x0008 uint(32) Höhe

Gibt die Höhe des Bildes in Pixel an

0x000c uint(32) Breite

Gibt die Breite des Bildes in Pixel an

0x0010 uint(16) Typ

Gibt die Art des Bildes an. Hierbei scheint es sich um eine Bitmaske zu handeln:

  • 0x04 ist gesetzt, wenn es sich um eine 1bpp-Grafik handelt.
  • 0x40 ist gesetzt, wenn es sich um eine Grafik handelt, die Windowing umsetzen muss
0x0012 uint(16) Palette

Definiert, welche Palette aus der PRT-Datei verwendet werden soll

Diese Datenstruktur der PRT-Datei gibt an, wie die für die Sprites verwendeten Bitmaps aufgebaut sind. Diese Bitmaps dienen dabei als einzelner Bestandteil, von dem mehrere zu einem Animationsframe eines Sprites zusammengebaut werden.

Die konkreten Bilddaten verbergen sich dagegen in der op2_art.BMP im Spielverzeichnis.
Warum diese Bitmapdatei über einen (überwiegend korrekten) RIFF-Bitmapheader verfügt, ist unklar. Wahrscheinlich verwendet Outpost 2 System-APIs zum Laden der Grafiken, indem dieser Header temporär übernommen wird und die entsprechenden, variierenden Felder überschrieben werden.

Die Pixeldaten sind dabei in der BMP-Datei an der Position Offset + dem uint32-Offset, das in der BMP-Datei an Adresse 0x000A zu finden ist (RIFF-Bitmap-Datenoffset), zu finden - und entsprechen wieder der zeilenweisen Anordnung von oben links nach rechts unten.

Monochrome 1bpp-Grafiken können dabei so gezeichnet werden, dass Farbe 0 vollständiger Transparenz, sowie Farbe 1 ein halbtransparentes schwarz/grau ist, da die Monochrom-Grafiken üblicherweise für Fahrzeug- und Gebäudeschatten in den Animationen verwendet werden.

Damit kann man bereits viele Grafiken zusammensetzen.

Geschütztes Wohnmodul (Plymouth)

Animationen

Nun kommen wir zur Königsklasse der Disziplinen innerhalb der Outpost 2 Datenformate:
Den Animationen.

Die Animationslisten werden mit einem globalen Header, der primär der Datenverifikation dient, eingeleitet. Daraufhin folgen die konkreten Animationsedefinitionen, die sich in 3 Stufen gliedern:

  1. Animation
    Eine Animation ist die oberste Instanz; sie stellt eine Animation einer Einheit, eines Gebäudes oder einer 'Partikel-Animation' (Kometenschlag, Wetter, Explosion) in einem bestimmten Ausgangslage dar.
  2. Frame
    Ein Frame ist ein einzelnes Bild innerhalb einer Animation. Eine Animation kann ein oder mehrere Frames beinhalten.
  3. Subframe
    Ein Subframe ist die Information darüber, dass eine bestimmte Bitmap unter bestimmten Kriterien an eine bestimmte Position eines Frames gezeichnet werden soll. Ein Frame kann ein oder mehrere Subframes beinhalten.

Anschließend folgen schon direkt die einzelnen Animationsdefinitionen.

Adr x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF char
0x0000 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- . . . . . . . . . . . . . . . .
Offset Datentyp Bezeichnung Erklärung
0x0000 uint(32) Anzahl Animationen

Wieviele Animationsdatensätze vorhanden sind

0x0004 uint(32) Anzahl Frames

Wieviele Frames insgesamt vorhanden sein sollten

0x0008 uint(32) Anzahl Subframes

Wieviele Subframes insgesamt vorhanden sein sollten

0x000c uint(32) Anzahl optionaler Einträge

Wieviele "optionale Einträge" vorhanden sind.

Animation

Adr x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF char
0x0000 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- . . . . . . . . . . . . . . . .
0x0010 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- . . . . . . . . . . . . . . . .
0x0020 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- . . . . . . . . . . . . . . . .
Offset Datentyp Bezeichnung Erklärung
0x0000 uint(32) Unbekannt 1

Unbekannte Informationen

0x0004 uint(32) Bounding Box: Links

Gibt den linken Anfang (in Pixel) der Bounding Box an.

0x0008 uint(32) Bounding Box: Oben

Gibt den oberen Anfang (in Pixel) der Bounding Box an.

0x000c uint(32) Bounding Box: Breite

Gibt die Breite (in Pixel) der Bounding Box an.

0x0010 uint(32) Bounding Box: Höhe

Gibt die Höhe (in Pixel) der Bounding Box an.

0x0014 uint(32) Offset: X

Gibt den horizontalen Mittelpunkt der Animation an

0x0018 uint(32) Offset: Y

Gibt den vertikalen Mittelpunkt der Animation an

0x001c uint(32) Unbekannt 2

Unbekannte Information

0x0020 uint(32) Anzahl Frames

Gibt an, wieviele Animationsframes in dieser Animation enthalten sind

0x0024 uint(32) Anzahl Windows

Gibt an, wieviele Fenster beim Zeichnen anzuwenden sind

Die Daten der obersten Schicht, der Animation, sind dabei vorrangig Verwaltungsdaten - die Boundingbox bezeichnet dabei die Koordinaten der Markierung um das Fahrzeug/Gebäude, wenn das selbige ausgewählt ist und gibt auch gleichzeitig an, welcher Bereich anklickbar sein soll.

Das Offset bestimmt vorrangig den "Nullpunkt"; den Punkt, der auf spielinterne Koordinaten aufzurechnen beziehungsweise abzuziehen ist. Man könnte auch mathematischer sagen: das Offset bezeichnet hier den Koordinatenursprung.

Bei den Windows handelt es sich, genauso wie beim Offset, um jeweils (pro Window) 4 uint(32)-Werte, die einen Bereich angeben, der für einzelne Subframes als verwendbar gilt. Ausserhalb der Windows darf, sofern es für die Bitmap entsprechend vorgesehene ist, nicht gezeichnet werden.

Frame

Adr x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF char
0x0000 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- . . . . . . . . . . . . . . . .
Offset Datentyp Bezeichnung Erklärung
0x0000 uint(8) Subframe-Anzahl und Toggle für Optional 1, 2

Dieser Wert enthält:

  • 0x7F (Bitmaske): Die Anzahl an Subframes, die in diesem Frame verwendet werden
  • 0x80: Die Information darüber, ob Optional 1 und 2 vorhanden sind
0x0001 uint(8) Unbekannt 1 und Toggle für Optional 3, 4

Dieser Wert enthält:

  • 0x7F (Bitmaske): Unbekannt - Ich vermute stark, dass es sich hierbei um die Anzahl an Gameticks handelt, die vergehen, bis das nächste Frame angezeigt wird
  • 0x80: Die Information darüber, ob Optional 3 und 4 vorhanden sind
0x0002 uint(8) Optional 1

Unbekannt

0x0003 uint(8) Optional 2

Unbekannt

0x0004 uint(8) Optional 3

Unbekannt

0x0005 uint(8) Optional 4

Unbekannt

Subframe

Adr x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF char
0x0000 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- . . . . . . . . . . . . . . . .
Offset Datentyp Bezeichnung Erklärung
0x0000 uint(16) Bitmap-Id

Gibt an, welche Bitmap für diesen Subframe verwendet werden soll

0x0002 uint(8) Unbekannt 1

Ist unbekannt - ich vermute allerdings stark, das es sich hierbei um eine Render-Priorität (Z-Layer) handelt.

0x0003 uint(8) Subframe-Id

Gibt an, in welchem Subframe wir uns befinden

0x0004 sint(16) Offset - Horizontal

Gibt an, wo innerhalb des Frames das Subframe platziert werden soll, bzw. um wieviele Pixel die Bitmap horizontal verschoben werden soll

0x0006 sint(16) Offset - Vertikal

Gibt an, wo innerhalb des Frames das Subframe platziert werden soll, bzw. um wieviele Pixel die Bitmap vertikal verschoben werden soll

Damit können wir nun einzelne Frames, als auch komplette Animationen entsprechend zusammensetzen, hier einmal exemplarisch an einer komplexeren Animation, der Animation mit dem Index 500, demonstriert

Animation 500

Animation 500 zeigt, wie ein Plymouth-Transporter, der mit gewöhnlichem Erz beladen ist, entladen wird. Dabei handelt es sich um eine der wenigen Animationen, die die Windowing-Funktionalität nutzt.

Und so lässt sich die komplette Animation zusammenfügen.
Leider gibt es noch ein Problem mit der oberen Ladeluke, da hier das entsprechende Bit in der Grafiktyp-Information nicht gesetzt ist.

Hier noch ein paar weitere, wunderschön animierte Sprites aus dem Spiel:

Rendering von Animation 500 illustriiert

Animation 500 fertig zusammengefügt

Plymouth Gebäude-Fabrik

Eden Weltraumhafen

Eden Medizinisches Zentrum

SCAT

Plymouth Weltraumhafen

Easteregg:
Weihnachtsmann

Easteregg:
Dans Dog

User-Interface

Nun fehlt noch das User-Interface des Spieles, welches in einem gebürstetem Metall-Look gehalten ist.

Aber auch hier ist erkennbar, dass Dynamix das Rad nicht neu erfinden musste; hier werden nicht nur schlicht die durch die von Windows bereitgestellten User32- und GDI32-APIs genutzt - insbesondere wird auch das Ressourcen-Management von User32 verwendet.

Diese lassen sich beispielsweise durch Programme wie das von Angus Johnson als Freeware entwickelte Resource Hacker, oder - falls man unter Linux / Mac OS den Einsatz von Wine scheut - mithilfe des in icoutils enthaltenen wrestool extrahieren.

Dateiname Inhalt
Outpost2.exe Enthält lediglich das Icon des Spieles, welches die Weltraumstation vor Neu Terra zeigt
op2shres.dll Enthält neben Grafiken für Bedienelemente wie Umrandungen, Buttons, Radio-Buttons und Checkboxen auch Dialog-Hintergründe, die Begleit-Bilder für die Story-Missionstexte und die Hauptmenü-Hintergrundgrafik
out2res.dll Enthält die Ingame-Fensterdekoration, Icons für gewöhnliches und spezielles Metall, den Lade-Bildschirm, Grafiken für Dialoge sowie weitere Cursor-Grafiken, zusätzlich zu den animierten im Spielverzeichnis