
Erinnerst du dich an viele russische Spiele? Qualitativ? Denkwürdig? Ja, das waren sie. Wenn Sie über 35 Jahre alt sind oder ein Fan der russischen Spielebranche sind, sind Sie wahrscheinlich mit den verfluchten Ländern vertraut.
Die Geschichte begann sehr prosaisch: Sommer, Hitze. Es gibt nichts Besonderes zu tun, und als ich träge den Inhalt der Festplatte des Laptops durchsuchte, ergriff mein Blick einen Ordner mit dem bekannten Drachensymbol, das seit einigen Jahren nicht mehr verwendet wurde.
Welcher Fan des Spiels wird nicht daran interessiert sein zu wissen, was drin ist?
Einführung
Cursed Lands - oder, wie sie außerhalb der GUS genannt wurden, Evil Islands: Curse of the Lost Soul , ein Stealth-RPG-Spiel, das im Jahr 2000 veröffentlicht wurde. Das Spiel wurde von Nival Interactive entwickelt, das sich zu diesem Zeitpunkt bereits als eine Reihe von Alloda-Spielen (Rage of Mages im Ausland) etabliert hatte. Meistens arbeiteten Absolventen der Moskauer Staatsuniversität daran - sie waren durchaus in der Lage, eines der ersten Spiele mit einer vollständig dreidimensionalen Welt zu realisieren.
Im Jahr 2010 hat Mail.Ru ( Information ) den Titel übertragen, aber das Spiel wird weiterhin im Auftrag von Nival im GOG-Store verkauft.
Vor relativ kurzer Zeit wurde das Spiel 18 Jahre alt - der Geburtstag gilt als 26. Oktober, das Erscheinungsdatum in der GUS. Trotz seines Alters ist der offizielle Master-Server immer noch in Betrieb: In regelmäßigen Abständen beschließt jemand, durch die Wälder von Gipat zu kriechen und ein oder zwei Dutzend Skelette mit einer Gruppe von Kameraden zu treffen.
Kurz zum Artikel
Anfangs war es mein Ziel, in Python 3 nur einen Einwegkonverter "für mich" zu schreiben, der ausschließlich Standardbibliotheken verwendet. Dabei begann die Dokumentation der Formate jedoch reibungslos und versuchte, die Ausgabe irgendwie zu standardisieren. Für einige Formate wurde die Struktur mit Kaitai Struct beschrieben . Infolgedessen führte alles zum Schreiben dieses Artikels und des Wikis in Formaten.
Ich stelle sofort fest: Zum größten Teil wurden bereits Spieledateien recherchiert und Fan-Editoren für sie geschrieben. Die Informationen sind jedoch extrem fragmentiert, und es gibt weder eine mehr oder weniger vollständige Beschreibung der Formate im öffentlichen Bereich noch einen angemessenen Satz zum Erstellen von Änderungen.
... und wie man es liest
Für alle Formate werden Schemata (.ksy-Dateien) bereitgestellt, die in zwei der beliebtesten Sprachen in Code mit zwei Klicks in den Code konvertiert werden können.
Leider stellte ich bereits in den letzten Phasen des Schreibens dieses Artikels fest, dass der geschätzte Habr YAML (und JSON) nicht hervorheben kann und alle Schemata es verwenden. Dies sollte kein großes Problem sein, aber wenn es unpraktisch ist, das Schema zu lesen, kann ich Ihnen raten, es in einen Drittanbieter-Editor zu kopieren, z. B. NPP.
Ressourcen und wo sie leben
Das Spiel ist eine tragbare Anwendung, die eine Engine mit Bibliotheken, einem Launcher und tatsächlich gepackten Ressourcen enthält.
Das ist interessant: Die Einstellungen des Spiels werden fast vollständig in der Registrierung gespeichert. Der Kamerafehler in der GOG-Version ist darauf zurückzuführen, dass das Installationsprogramm nicht die richtigen Standardwerte registriert.
Auf den ersten Blick auf den Inhalt des Spielordners fallen uns sofort einige neue Dateierweiterungen auf: ASI und REG.
Die erste ist eine dynamische Bibliothek, die wir nicht berücksichtigen werden (dies wird von Spezialisten für Reverse Engineering durchgeführt), aber die zweite ist das erste native Dateiformat des Spiels.
REG
Dateien dieses Typs sind binäre Serialisierungen bekannter Text-INI-Dateien.
Der Inhalt ist in Abschnitte unterteilt, in denen Schlüssel und ihre Werte gespeichert sind. Eine REG-Datei behält diese Hierarchie bei, beschleunigt jedoch das Lesen und Parsen von Daten - im Jahr 2000 war dies anscheinend kritisch.
Im Allgemeinen können Sie die Struktur dieses Diagramms beschreiben:

Strukturbeschreibungmeta: id: reg title: Evil Islands, REG file (packed INI) application: Evil Islands file-extension: reg license: MIT endian: le doc: Packed INI file seq: - id: magic contents: [0xFB, 0x3E, 0xAB, 0x45] doc: Magic bytes - id: sections_count type: u2 doc: Number of sections - id: sections_offsets type: section_offset doc: Sections offset table repeat: expr repeat-expr: sections_count types: section_offset: doc: Section position in file seq: - id: order type: s2 doc: Section order number - id: offset type: u4 doc: Global offset of section in file instances: section: pos: offset type: section types: section: doc: Section representation seq: - id: keys_count type: u2 doc: Number of keys in section - id: name_len type: u2 doc: Section name lenght - id: name type: str encoding: cp1251 size: name_len doc: Section name - id: keys type: key doc: Section's keys repeat: expr repeat-expr: keys_count types: key: doc: Named key seq: - id: order type: s2 doc: Key order in section - id: offset type: u4 doc: Key offset in section instances: key_record: pos: _parent._parent.offset + offset type: key_data key_data: seq: - id: packed_type type: u1 doc: Key value info - id: name_len type: u2 doc: Key name lenght - id: name type: str encoding: cp1251 size: name_len doc: Key name - id: value type: value doc: Key value instances: is_array: value: packed_type > 127 doc: Is this key contain array value_type: value: packed_type & 0x7F doc: Key value type types: value: doc: Key value seq: - id: array_size type: u2 if: _parent.is_array doc: Value array size - id: data type: switch-on: _parent.value_type cases: 0: s4 1: f4 2: string repeat: expr repeat-expr: '_parent.is_array ? array_size : 1' doc: Key value data string: doc: Sized string seq: - id: len type: u2 doc: String lenght - id: value type: str encoding: cp1251 size: len doc: String
Das ist interessant: Im Jahr 2002 teilte Nival einige Tools mit der Community des Spiels ( Site-Snapshot ) - einer davon war der INI-Serializer in REG. Wie Sie sich vorstellen können, erschien fast sofort ein Deserialisierer, wenn auch kein offizieller.
Nachdem der Startordner aussortiert ist, gehen wir zu den Unterverzeichnissen über.
Der erste Blick fällt auf den Ordner "Kameras", der die CAM-Dateien enthält.
Cam
Ein sehr einfaches Format ist einfach das Packen der Positionen der Kameras im Laufe der Zeit. Die Kamera wird durch Position und Drehung beschrieben. Die beiden anderen Felder sind vermutlich Zeit und Schritt in der Abfolge der Bewegungen.

Strukturbeschreibung meta: id: cam title: Evil Islands, CAM file (cameras) application: Evil Islands file-extension: cam license: MIT endian: le doc: Camera representation seq: - id: cams type: camera repeat: eos types: vec3: doc: 3d vector seq: - id: x type: f4 doc: x axis - id: y type: f4 doc: y axis - id: z type: f4 doc: z axis quat: doc: quaternion seq: - id: w type: f4 doc: w component - id: x type: f4 doc: x component - id: y type: f4 doc: y component - id: z type: f4 doc: z component camera: doc: Camera parameters seq: - id: unkn0 type: u4 doc: unknown - id: unkn1 type: u4 doc: unknown - id: position type: vec3 doc: camera's position - id: rotation type: quat doc: camera's rotation
Im nächsten Ordner - Res werden (unerwartet!) RES-Dateien, die Archive sind, gespeichert.
RES
Dieses Format wird manchmal unter anderen Erweiterungen ausgeblendet, aber das Original ist immer noch genau RES.
Die Datenstruktur ist sehr typisch für ein Archiv mit wahlfreiem Zugriff auf Dateien: Es gibt Tabellen zum Speichern von Informationen zu darin enthaltenen Dateien, eine Tabelle mit Namen und den Inhalt von Dateien.
Die Verzeichnisstruktur ist direkt in den Namen enthalten.
Es lohnt sich, zwei äußerst interessante Fakten zu erwähnen:
- Das Archiv ist für das Laden von Dateiinformationen in eine verknüpfte Liste mit geschlossenem Hashing optimiert.
- Sie können den Inhalt der Datei einmal speichern, aber unter verschiedenen Namen darauf verweisen. Soweit ich weiß, wurde diese Tatsache in einem Fan-Repack verwendet, bei dem die Größe des Spiels aufgrund dessen stark reduziert wurde. In der ursprünglichen Distribution wurde die Archivoptimierung nicht verwendet.

Strukturbeschreibung meta: id: res title: Evil Islands, RES file (resources archive) application: Evil Islands file-extension: res license: MIT endian: le doc: Resources archive seq: - id: magic contents: [0x3C, 0xE2, 0x9C, 0x01] doc: Magic bytes - id: files_count type: u4 doc: Number of files in archive - id: filetable_offset type: u4 doc: Filetable offset - id: nametable_size type: u4 doc: Size of filenames instances: nametable_offset: value: filetable_offset + 22 * files_count doc: Offset of filenames table filetable: pos: filetable_offset type: file_record repeat: expr repeat-expr: files_count doc: Files metadata table types: file_record: doc: File metadata seq: - id: next_index type: s4 doc: Next file index - id: file_size type: u4 doc: Size of file in bytes - id: file_offset type: u4 doc: File data offset - id: last_change type: u4 doc: Unix timestamp of last change time - id: name_len type: u2 doc: Lenght of filename - id: name_offset type: u4 doc: Filename offset in name array instances: name: io: _root._io pos: name_offset + _parent.nametable_offset type: str encoding: cp1251 size: name_len doc: File name data: io: _root._io pos: file_offset size: file_size doc: Content of file
Das ist interessant: In der russischen Version des Spiels enthält das Speech.res-Archiv zwei Unterverzeichnisse s und t mit völlig identischen Inhalten, weshalb die Archivgröße doppelt so groß ist - weshalb das Spiel nicht auf eine CD passt.
Jetzt können Sie alle Archive entpacken (verschachtelt werden):
- RES ist nur ein Archiv,
- MPR - Landschaft der Spielebenen,
- MQ - Informationen zu den Aufgaben des Multiplayers,
- ANM - eine Reihe von Animationen,
- MOD - 3D Modell,
- BON - die Position der Knochen des Modells.
Wenn die Dateien im Archiv keine Erweiterung haben, setzen wir die übergeordnete Erweiterung - für BON- und ANM-Archive.
Sie können auch alle empfangenen Dateien in vier Gruppen aufteilen:
- Texturen
- Datenbanken
- Modelle
- Level-Dateien.
Beginnen wir mit dem Einfachen - mit den Texturen.
MMP
Eigentlich die Textur. Es hat eine kleine Überschrift, die die Bildparameter, die Anzahl der MIP-Pegel und die verwendete Komprimierung angibt. Nach dem Header werden die MIP-Bildebenen in absteigender Reihenfolge der Größe angezeigt.

Strukturbeschreibung meta: id: mmp title: Evil Islands, MMP file (texture) application: Evil Islands file-extension: mmp license: MIT endian: le doc: MIP-mapping texture seq: - id: magic contents: [0x4D, 0x4D, 0x50, 0x00] doc: Magic bytes - id: width type: u4 doc: Texture width - id: height type: u4 doc: Texture height - id: mip_levels_count type: u4 doc: Number of MIP-mapping stored levels - id: fourcc type: u4 enum: pixel_formats doc: FourCC label of pixel format - id: bits_per_pixel type: u4 doc: Number of bits per pixel - id: alpha_format type: channel_format doc: Description of alpha bits - id: red_format type: channel_format doc: Description of red bits - id: green_format type: channel_format doc: Description of green bits - id: blue_format type: channel_format doc: Description of blue bits - id: unused size: 4 doc: Empty space - id: base_texture type: switch-on: fourcc cases: 'pixel_formats::argb4': block_custom 'pixel_formats::dxt1': block_dxt1 'pixel_formats::dxt3': block_dxt3 'pixel_formats::pnt3': block_pnt3 'pixel_formats::r5g6b5': block_custom 'pixel_formats::a1r5g5b5': block_custom 'pixel_formats::argb8': block_custom _: block_custom types: block_pnt3: seq: - id: raw size: _root.bits_per_pixel block_dxt1: seq: - id: raw size: _root.width * _root.height >> 1 block_dxt3: seq: - id: raw size: _root.width * _root.height block_custom: seq: - id: lines type: line_custom repeat: expr repeat-expr: _root.height types: line_custom: seq: - id: pixels type: pixel_custom repeat: expr repeat-expr: _root.width types: pixel_custom: seq: - id: raw type: switch-on: _root.bits_per_pixel cases: 8: u1 16: u2 32: u4 instances: alpha: value: '_root.alpha_format.count == 0 ? 255 : 255 * ((raw & _root.alpha_format.mask) >> _root.alpha_format.shift) / (_root.alpha_format.mask >> _root.alpha_format.shift)' red: value: '255 * ((raw & _root.red_format.mask) >> _root.red_format.shift) / (_root.red_format.mask >> _root.red_format.shift)' green: value: '255 * ((raw & _root.green_format.mask) >> _root.green_format.shift) / (_root.green_format.mask >> _root.green_format.shift)' blue: value: '255 * ((raw & _root.blue_format.mask) >> _root.blue_format.shift) / (_root.blue_format.mask >> _root.blue_format.shift)' channel_format: doc: Description of bits for color channel seq: - id: mask type: u4 doc: Binary mask for channel bits - id: shift type: u4 doc: Binary shift for channel bits - id: count type: u4 doc: Count of channel bits enums: pixel_formats: 0x00004444: argb4 0x31545844: dxt1 0x33545844: dxt3 0x33544E50: pnt3 0x00005650: r5g6b5 0x00005551: a1r5g5b5 0x00008888: argb8
Mögliche Pixelverpackungsformate:
fourcc | Beschreibung |
---|
44 44 00 00 | ARGB4 |
44 58 54 31 | Dxt1 |
44 58 54 33 | Dxt3 |
50 4E 54 33 | PNT3 - RLE Compressed ARGB8 |
50 56 00 00 | R5G5B5 |
51 55 00 00 | A1R5G5B5 |
88 88 00 00 | ARGB8 |
Über PNT3Wenn das Bildformat PNT3 ist , ist die Pixelstruktur nach dem Entpacken ARGB8; bits_per_pixel
- Größe des komprimierten Bildes in Bytes.
PNT3 auspacken
n = 0 destination = b"" while src < size: v = int.from_bytes(source[src:src + 4], byteorder='little') src += 4 if v > 1000000 or v == 0: n += 1 else: destination += source[src - (1 + n) * 4:src - 4] destination += b"\x00" * v n = 0
Das ist interessant: Einige der Texturen werden vertikal reflektiert (oder andere werden nicht reflektiert?).
Und das Spiel ist sehr eifersüchtig auf Transparenz - wenn das Bild einen Alphakanal hat, muss die Farbe der transparenten Pixel genau schwarz sein. Oder weiß - so viel Glück.
Einfache Formate sind vorbei, lassen Sie uns zu starreren übergehen - zu einer Zeit behielten die Reihen der Mod-Hersteller wütend ihre eigenen Bearbeitungswerkzeuge für die folgenden Formate bei, und das nicht umsonst. Ich habe dich gewarnt.
Datenbanken (* DB und andere)
Die Beschreibung dieses Formats ist äußerst unpraktisch. Im Wesentlichen handelt es sich hierbei um einen serialisierten Baum von Knoten (oder Datensatztabellen). Eine Datei besteht aus mehreren Tabellen mit den angegebenen Feldtypen. Allgemeine Struktur: Tabellen sind in einem gemeinsamen "Root" -Knoten verschachtelt, Datensätze sind Knoten innerhalb einer Tabelle.
In jedem Knoten werden Typ und Größe angegeben:
unsigned char type_index; unsigned char raw_size;
Der Typ des Tabellenfeldes wird vom Index aus der Formatzeichenfolge für die Tabelle übernommen, der reale Typ wird durch den erhaltenen Wert bestimmt.
FeldtypenBezeichnung | die Beschreibung |
---|
S. | Zeichenfolge |
Ich | 4b int |
U. | 4b ohne Vorzeichen |
F. | 4b float |
X. | Bits Byte |
f | Float-Array |
ich | int Array |
B. | Bool |
b | Bool-Array |
H. | unbekannte Hex-Bytes |
T. | Zeit |
0 | nicht angegeben |
1 | 0FII |
2 | SUFF |
3 | FFFF |
4 | 0SISS |
5 | 0SISS00000U |
Beschreibung der BasenGegenstände (.idb)
Tabelle | die Struktur |
---|
Material | SSSIFFFIFIFfIX |
Waffe | SSISIIIFFFFIFIXB00000IHFFFfHHFF |
Rüstung | SSISIIIFFFFIFIXB00000ffBiHH |
Schnelle Gegenstände | SSISIIIFFFFIFIXB00000IIFFSbH |
Questgegenstände | SSISIIIFFFFIFIXB00000Is |
Artikel verkaufen | SSISIIIFFFFIFIXB00000IHI |
Schalter (.ldb)
Tabelle | die Struktur |
---|
Prototyp wechseln | SfIFTSSS |
Fähigkeiten und Fertigkeiten (.pdb)
Tabelle | die Struktur |
---|
Fähigkeiten | SSI0000000s |
Fähigkeiten | SSI0000000SSIIIFFFIIIIBI |
Fußabdrücke (Drucke.db)
Tabelle | die Struktur |
---|
Blutspuren | 0S11 |
Flammenspuren | 0S110000001 |
Fußabdrücke | 0S11 |
Zauber (.sdb)
Tabelle | die Struktur |
---|
Prototypen | SSSFIFIFFFFIIIIUSSIIbIXFFFFF |
Modifikatoren | SSFIFFISX |
Muster | 0SssSX |
Rüstungsvorlagen | 0SssSX |
Waffenmuster | 0SssSX |
Kreaturen (.udb)
Tabelle | die Struktur |
---|
Beschädigte Teile | SffUU |
Rennen | SUFFUUFfFUUf222222000000000000SssFSsfUUfUUIUSBFUUUU |
Monster-Prototypen | SSIUIFFFSFFFFFFFFFUFFFFFFff33sfssSFFFFFUFUSF |
Npc | SUFFFFbbssssFUB |
Rufe (acks.db)
Tabelle | die Struktur |
---|
Die Antworten | 0S0000000044444444444444444444445444444444444 |
Schreie | 0S0000000044444 |
Andere | 0S0000000044 |
Quests (.qdb)
Tabelle | die Struktur |
---|
Missionen | SFIISIIs |
Briefings | SFFsSsssssI |
Das ist interessant: 16. Januar 2002 Nival hat die Quelldatenbanken für den Multiplayer im CSV-Format sowie einen Utility-Konverter im Spielformat ( Site-Snapshot ) veröffentlicht. Natürlich erschien der inverse Konverter nicht langsam. Es gibt auch mindestens zwei Dokumente, die die Felder und ihre Typen von den Modmachern beschreiben, aber das Lesen ist sehr schwierig.
Adb
Animationsdatenbank für einen bestimmten Einheitentyp. Im Gegensatz zu der oben erwähnten * DB ist sie ziemlich "menschlich" - es ist eine einstufige Tabelle mit statischen Feldgrößen.

Strukturbeschreibung meta: id: adb title: Evil Islands, ADB file (animations database) application: Evil Islands file-extension: adb license: MIT endian: le doc: Animations database seq: - id: magic contents: [0x41, 0x44, 0x42, 0x00] doc: Magic bytes - id: animations_count type: u4 doc: Number of animations in base - id: unit_name type: str encoding: cp1251 size: 24 doc: Name of unit - id: min_height type: f4 doc: Minimal height of unit - id: mid_height type: f4 doc: Middle height of unit - id: max_height type: f4 doc: Maximal height of unit - id: animations type: animation doc: Array of animations repeat: expr repeat-expr: animations_count types: animation: doc: Animation's parameters seq: - id: name type: str encoding: cp1251 size: 16 doc: Animation's name - id: number type: u4 doc: Index in animations array - id: additionals type: additional doc: Packed structure with animation parameters - id: action_probability type: u4 doc: Percents of action probability - id: animation_length type: u4 doc: Lenght of animation in game ticks - id: movement_speed type: f4 doc: Movement speed - id: start_show_hide1 type: u4 - id: start_show_hide2 type: u4 - id: start_step_sound1 type: u4 - id: start_step_sound2 type: u4 - id: start_step_sound3 type: u4 - id: start_step_sound4 type: u4 - id: start_hit_frame type: u4 - id: start_special_sound type: u4 - id: spec_sound_id1 type: u4 - id: spec_sound_id2 type: u4 - id: spec_sound_id3 type: u4 - id: spec_sound_id4 type: u4 types: additional: seq: - id: packed type: u8 instances: weapons: value: 'packed & 127' allowed_states: value: '(packed >> 15) & 7' action_type: value: '(packed >> 18) & 15' action_modifyer: value: '(packed >> 22) & 255' animation_stage: value: '(packed >> 30) & 3' action_forms: value: '(packed >> 36) & 63'
Das ist interessant: Für mehrere Einheiten wird ein teilweise abgeschnittenes Datenbankformat verwendet, das bisher kaum untersucht wurde.
Nachdem wir uns mit den Datenbanken befasst haben, erklären wir eine Werbepause. Aber wir werden nichts bewerben - nicht unsere Methode. Bezeichnen Sie besser, was als nächstes nützlich ist - wie Kreaturendateien benannt werden.
Der Name wird aus Gruppen von zwei Zeichen gesammelt - Abkürzungen der logischen "Ebene".
Zum Beispiel ist die weibliche Figur unhufe
- Unit > Human > Female
und initwesp
- Inventory > Item > Weapon > Spear
, initwesp
ein Speer im Inventar (nicht der Rücken, und das ist gut so).
Vollständiger Baum der Namenselemente: un: # unit an: # animal wi: # wild ti # tiger ba # bat bo # boar hy # hyen de # deer gi # rat ra # rat cr # crawler wo # wolf ho: # home co # cow pi # pig do # dog ho # horse ha # hare or: # orc fe # female ma # male mo: # monster co # column (menu) un # unicorn cu # Curse be # beholder tr # troll el # elemental su # succub (harpie) ba # banshee dr # driad sh # shadow li # lizard sk # skeleton sp # spider go # golem, goblin ri # Rick og # ogre zo # zombie bi # Rik's dragon cy # cyclope dg # dragon wi # willwisp mi # octopus to # toad hu: # human fe # female ma # male in: # inventory it: # item qu # quest qi # interactive ar: # armor pl # plate gl # gloves lg # leggins bt # boots sh # shirt hl # helm pt # pants li: # loot mt # material tr # trade we: # weapon hm # hammer dg # dagger sp # spear cb # crossbow sw # sword ax # axe bw # bow gm # game menu fa: # faces un: # unit an: # animal wi: # wild ti: # tiger face # face ba: # bat face # face bo: # boar face # face de: # deer face # face ra: # rat face # face cr: # crawler face # face wo: # wolf face # face ho: # home co: # cow face # face pi: # pig face # face do: # dog face # face ho: # horse face # face ha: # hare face # face hu: # human fe: # female fa # me # th # ma: # male fa # me # th # mo: # monster to: # toad face # face tr: # troll face # face or: # orc face # face sp: # spider face # face li: # lizard face # face na: # nature fl: # flora bu # bush te # termitary tr # tree li # waterplant wa # waterfall sk # sky st # stone ef: # effects cu # ar # co # components st: # static si # switch bu: # building to # tower ho # house tr # trap br # bridge ga # gate we # well (waterhole) wa: # wall me # medium li # light to # torch st # static
Das ist interessant: Nach dieser Klassifizierung sind Pilze Bäume, Golems mit Goblins sind Brüder und Tka-Rick ist ein Monster. Auch hier können Sie die "funktionierenden" Namen von Monstern sehen, die denen von D & D verdächtig ähnlich sind - Betrachter (böser Blick), Succub (Harpyie), Oger (Kannibale), Driad (Förster).
Nachdem wir uns moralisch ausgeruht haben, stürzen wir uns kopfüber in das Modell. Sie werden in verschiedenen Formaten dargestellt, die miteinander verknüpft sind.
Lnk
Logisch - die Basis des Modells. Beschreibt die Hierarchie von Teilen des Modells im Sinne der modernen 3D-Modellierung - die Hierarchie der Knochen.

Strukturbeschreibung meta: id: lnk title: Evil Islands, LNK file (bones hierarchy) application: Evil Islands file-extension: lnk license: MIT endian: le doc: Bones hierarchy seq: - id: bones_count type: u4 doc: Number of bones - id: bones_array type: bone repeat: expr repeat-expr: bones_count doc: Array of bones types: bone: doc: Bone node seq: - id: bone_name_len type: u4 doc: Length of bone's name - id: bone_name type: str encoding: cp1251 size: bone_name_len doc: Bone's name - id: parent_name_len type: u4 doc: Length of bone's parent name - id: parent_name type: str encoding: cp1251 size: parent_name_len doc: Bone's parent name
Der übergeordnete Name des übergeordneten Knochens ist eine leere Zeichenfolge (Länge 0).
Es gibt Knochen, aber es reicht nicht aus, sie zu benennen und zusammenzusetzen - Sie müssen sie zu einem Skelett zusammensetzen.
Bon
Dieses Format (sofern es sich nicht um ein Archiv handelt) legt die Position der Teile (Bones) des Modells relativ zum übergeordneten Teil fest. Nur der Offset wird ohne Drehung gespeichert - einer der Unterschiede zu modernen Formaten.

Strukturbeschreibung meta: id: bon title: Evil Islands, BON file (bone position) application: Evil Islands file-extension: bon license: MIT endian: le doc: Bone position seq: - id: position type: vec3 doc: Bone translation repeat: eos types: vec3: doc: 3d vector seq: - id: x type: f4 doc: x axis - id: y type: f4 doc: y axis - id: z type: f4 doc: z axis
Wie Sie sehen können, gibt es zu viele Zahlen für einen Versatz - Tatsache ist, dass wir hier zuerst auf eines der Hauptmerkmale der Spiel-Engine gestoßen sind - die trilineare Modellinterpolation.
So funktioniert es: Das Modell verfügt über drei Interpolationsparameter - bedingt, Stärke, Geschicklichkeit, Wachstum. Es gibt auch 8 extreme Zustände des Modells. Mit den Parametern können wir das endgültige Modell durch trilineare Interpolation erhalten.
Der Algorithmus selbst def trilinear(val, coefs=[0, 0, 0]):
Dies ist interessant: Die trilineare Modellinterpolation wird verwendet, um einige Objekte zu animieren, z. B. das Öffnen einer Steintür und von Truhen.
Jetzt ist es an der Zeit, sich die Teile des Modells selbst anzusehen.
FIG
Vielleicht ist diese Kundgebung nicht zu verstehen. Sie können seine Beschreibung und das Plug-In für den Mixer im Internet finden, aber selbst mit ihnen kommt das Bewusstsein nicht sofort. Schauen Sie mal rein:

Strukturbeschreibung meta: id: fig title: Evil Islands, FIG file (figure) application: Evil Islands file-extension: fig license: MIT endian: le doc: 3d mesh seq: - id: magic contents: [0x46, 0x49, 0x47, 0x38] doc: Magic bytes - id: vertex_count type: u4 doc: Number of vertices blocks - id: normal_count type: u4 doc: Number of normals blocks - id: texcoord_count type: u4 doc: Number of UV pairs - id: index_count type: u4 doc: Number of indeces - id: vertex_components_count type: u4 doc: Number of vertex components - id: morph_components_count type: u4 doc: Number of morphing components - id: unknown contents: [0, 0, 0, 0] doc: Unknown (aligment) - id: group type: u4 doc: Render group - id: texture_index type: u4 doc: Texture offset - id: center type: vec3 doc: Center of mesh repeat: expr repeat-expr: 8 - id: aabb_min type: vec3 doc: AABB point of mesh repeat: expr repeat-expr: 8 - id: aabb_max type: vec3 doc: AABB point of mesh repeat: expr repeat-expr: 8 - id: radius type: f4 doc: Radius of boundings repeat: expr repeat-expr: 8 - id: vertex_array type: vertex_block doc: Blocks of raw vertex data repeat: expr repeat-expr: 8 - id: normal_array type: vec4x4 doc: Packed normal data repeat: expr repeat-expr: normal_count - id: texcoord_array type: vec2 doc: Texture coordinates data repeat: expr repeat-expr: texcoord_count - id: index_array type: u2 doc: Triangles indeces repeat: expr repeat-expr: index_count - id: vertex_components_array type: vertex_component doc: Vertex components array repeat: expr repeat-expr: vertex_components_count - id: morph_components_array type: morph_component doc: Morphing components array repeat: expr repeat-expr: morph_components_count types: morph_component: doc: Morphing components indeces seq: - id: morph_index type: u2 doc: Index of morphing data - id: vertex_index type: u2 doc: Index of vertex vertex_component: doc: Vertex components indeces seq: - id: position_index type: u2 doc: Index of position data - id: normal_index type: u2 doc: Index of normal data - id: texture_index type: u2 doc: Index of texcoord data vec2: doc: 2d vector seq: - id: u type: f4 doc: u axis - id: v type: f4 doc: v axis vec3: doc: 3d vector seq: - id: x type: f4 doc: x axis - id: y type: f4 doc: y axis - id: z type: f4 doc: z axis vec3x4: doc: 3d vector with 4 values per axis seq: - id: x type: f4 doc: x axis repeat: expr repeat-expr: 4 - id: y type: f4 doc: y axis repeat: expr repeat-expr: 4 - id: z type: f4 doc: z axis repeat: expr repeat-expr: 4 vertex_block: doc: Vertex raw block seq: - id: block type: vec3x4 doc: Vertex data repeat: expr repeat-expr: _root.vertex_count vec4x4: doc: 4d vector with 4 values per axis seq: - id: x type: f4 doc: x axis repeat: expr repeat-expr: 4 - id: y type: f4 doc: y axis repeat: expr repeat-expr: 4 - id: z type: f4 doc: z axis repeat: expr repeat-expr: 4 - id: w type: f4 doc: w axis repeat: expr repeat-expr: 4
Was ist die Schwierigkeit? Schließlich werden die Daten von Normalen und Scheitelpunkten in 4er-Blöcken gespeichert, und die Scheitelpunkte werden zur Interpolation auch in 8 Blöcken angeordnet.
Das ist interessant: Vermutlich wurde eine solche Gruppierung vorgenommen, um die Verarbeitung mithilfe von SSE-Anweisungen zu beschleunigen, die seit 1999 auf Intel-Prozessoren verfügbar sind.
Nun, wir haben das Modell gelesen und komponiert, aber es fehlt etwas. Genau - Animationen!
Anm
Die Animation wird in Komponentenform als Schlüsselzustände gespeichert. Eine interessante Tatsache ist, dass es nicht nur Skelettanimationen, sondern auch Vertex-Morphing unterstützt.

Strukturbeschreibung meta: id: anm title: Evil Islands, ANM file (bone animation) application: Evil Islands file-extension: anm license: MIT endian: le doc: Bone animation seq: - id: rotation_frames_count type: u4 doc: Number of rotation frames - id: rotation_frames type: quat repeat: expr repeat-expr: rotation_frames_count doc: Bone rotations - id: translation_frames_count type: u4 doc: Number of translation frames - id: translation_frames type: vec3 repeat: expr repeat-expr: translation_frames_count doc: Bone translation - id: morphing_frames_count type: u4 doc: Number of morphing frames - id: morphing_vertex_count type: u4 doc: Number of vertices with morphing - id: morphing_frames type: morphing_frame repeat: expr repeat-expr: morphing_frames_count doc: Array of morphing frames types: vec3: doc: 3d vector seq: - id: x type: f4 doc: x axis - id: y type: f4 doc: y axis - id: z type: f4 doc: z axis quat: doc: quaternion seq: - id: w type: f4 doc: w component - id: x type: f4 doc: x component - id: y type: f4 doc: y component - id: z type: f4 doc: z component morphing_frame: doc: Array of verteces morphing seq: - id: vertex_shift type: vec3 repeat: expr repeat-expr: _parent.morphing_vertex_count doc: Morphing shift per vertex
Das war's - jetzt haben wir ein vollwertiges Modell, Sie können die frisch gerenderte Einsiedeleidechse bewundern:

Ein Moment der NostalgieFinde heraus, was die Eidechse braucht
Gespräch mit der Eidechse in seinem Haus
Einsiedler-Eidechse: Du bist gekommen, Mann. Das ist gut.
Zach: Ist das alles was du mir sagen wolltest?
Hermit Lizard: Du hast es wieder eilig. Ich erinnere mich an Ihre Fragen und werde sie beantworten. Ich kam zu Leuten in Eisen, um einen Deal zu machen. Aber ich habe gesehen, wie sie dir angetan haben. Sie halten kein Wort, ich hörte auf, ihnen zu glauben. Du hast dein Wort gehalten. Ein Angebot wird Ihnen angeboten.
Einsiedler-Eidechse: Die Leute lieben Gold. Gold Eidechsen sind uninteressant. Du wirst meine Aufgabe erfüllen und ich werde dir das Gold geben, das ich habe. Es gibt viel Gold.
Zach (nachdenklich und ohne großes Interesse) : Hmm ... Gold ... Es wird bestimmt nicht weh tun ...
Zach: Es wäre besser, wenn Sie mir helfen könnten herauszufinden, wo der alte Zauberer, nach dem ich gesucht habe, so lange lebt. Eidechsen sind schließlich ein altes Volk, und Sie können es wissen!
Einsiedler-Eidechse: Du hast recht. Eidechsen sind ein altes Volk. Ich kann alles sammeln, was wir über den alten Mann wissen. Stimmen Sie zu, meine Mission zu erfüllen?
Zach: Was für ein Gespräch! Bedenken Sie, dass bereits alles erledigt ist.
Einsiedler-Eidechse (ernst) : Schon fertig? Willst du mich betrügen?
Zach: Eigentlich wollte ich einen Witz machen, sonst warst du wirklich ernst.
Die Einsiedeleidechse: Ich verstehe. Das ist ein Witz. Ich denke, ich kann auch einen Witz machen. Dann. Und jetzt musst du das Wasser zum Kanal zurückbringen. Orks haben uns Wasser gestohlen.
Einsiedler-Eidechse: Gehe am Wasser entlang nach Süden. Sie sehen den Damm und den Kanal. Der Damm muss angehoben werden. Hebelwirkung. Ich werde es geben. Der Kanal muss blockiert werden. Der Stein. Ich werde keinen Stein geben. Er liegt bereits am Rande des Kanals. Stromaufwärts des Dammes. Der Stein ist schwer. Als die Orks gruben, hoben sie es für eine lange Zeit auf. Wenn Sie ihn schieben, fällt er schnell zurück.
Hermit Lizard: Danach komm zurück. Ich werde dir alles erzählen, was ich über den alten Magier lerne.
Zach: Hand in Hand! Übrigens, wenn Sie der Geschichte ein paar Münzen hinzufügen, werde ich überhaupt nicht beleidigt sein.
Die Einsiedeleidechse: Für Münzen gehen Sie zu meinen Verwandten, die in den Untiefen weiter im Süden leben. Gehe zur am weitesten entfernten Sandinsel, der dritten in Folge. Schätze gehören dir!
Lizard Hermit (zu sich selbst) : Seltsam. Dieser Mann liebt Humor. Ich habe gescherzt. Der Mann lachte nicht. Sehr seltsam.
Nun - das Interessanteste: wie die Karte gespeichert wird.
MP
Dies ist die Map-Header-Datei. Aufgrund eines unglücklichen Zufalls stimmt die Erweiterung mit der der Mehrspieler-Sicherungsdateien überein, die wir nicht berücksichtigen werden.
Zunächst müssen Sie eine allgemeine Beschreibung der Landschaft geben:
- die Anzahl der "Brocken" - Teile der Karte 32x32 Meter;
- maximale Höhe (da die Höhe der Eckpunkte in einer ganzzahligen Skala gespeichert ist);
- Anzahl der Kachelatlanten.
, — , .

meta: id: mp title: Evil Islands, MP file (map header) application: Evil Islands file-extension: mp license: MIT endian: le doc: Map header seq: - id: magic contents: [0x72, 0xF6, 0x4A, 0xCE] doc: Magic bytes - id: max_altitude type: f4 doc: Maximal height of terrain - id: x_chunks_count type: u4 doc: Number of sectors by x - id: y_chunks_count type: u4 doc: Number of sectors by y - id: textures_count type: u4 doc: Number of texture files - id: texture_size type: u4 doc: Size of texture in pixels by side - id: tiles_count type: u4 doc: Number of tiles - id: tile_size type: u4 doc: Size of tile in pixels by side - id: materials_count type: u2 doc: Number of materials - id: animated_tiles_count type: u4 doc: Number of animated tiles - id: materials type: material doc: Map materials repeat: expr repeat-expr: materials_count - id: id_array type: u4 doc: Tile type repeat: expr repeat-expr: tiles_count enum: tile_type - id: animated_tiles type: animated_tile doc: Animated tiles repeat: expr repeat-expr: animated_tiles_count types: material: doc: Material parameters seq: - id: type type: u4 doc: Material type by enum: terrain_type - id: color type: rgba doc: RGBA diffuse color - id: self_illumination type: f4 doc: Self illumination - id: wave_multiplier type: f4 doc: Wave speed multiplier - id: warp_speed type: f4 doc: Warp speed multiplier - id: unknown size: 12 types: rgba: doc: RGBA color seq: - id: r type: f4 doc: Red channel - id: g type: f4 doc: Green channel - id: b type: f4 doc: Blue channel - id: a type: f4 doc: Alpha channel enums: terrain_type: 0: base 1: water_notexture 2: grass 3: water animated_tile: doc: Animated tile parameters seq: - id: start_index type: u2 doc: First tile of animation - id: length type: u2 doc: Animation frames count enums: tile_type: 0: grass 1: ground 2: stone 3: sand 4: rock 5: field 6: water 7: road 8: empty 9: snow 10: ice 11: drygrass 12: snowballs 13: lava 14: swamp 15: highrock
material type | Typ |
---|
0 | grass |
1 | ground |
2 | stone |
3 | sand |
4 | rock |
5 | field |
6 | water |
7 | road |
8 | (empty) |
9 | snow |
10 | ice |
11 | drygrass |
12 | snowballs |
13 | lava |
14 | swamp |
15 | highrock |
, Res/aiinfo.res/tileDesc.reg
.
: , — .
: .
. !
SEC
— 3232 . , ZonenameXXXYYY
.

meta: id: sec title: Evil Islands, SEC file (map sector) application: Evil Islands file-extension: sec license: MIT endian: le doc: Map sector seq: - id: magic contents: [0x74, 0xF7, 0x4B, 0xCF] doc: Magic bytes - id: liquids type: u1 doc: Liquids layer indicator - id: vertexes type: vertex doc: Vertex array 33x33 repeat: expr repeat-expr: 1089 - id: liquid_vertexes type: vertex doc: Vertex array 33x33 if: liquids != 0 repeat: expr repeat-expr: 'liquids != 0 ? 1089 : 0' - id: tiles type: tile doc: Tile array 16x16 repeat: expr repeat-expr: 256 - id: liquid_tiles type: tile doc: Tile array 16x16 if: liquids != 0 repeat: expr repeat-expr: 'liquids != 0 ? 256 : 0' - id: liquid_material type: u2 doc: Index of material if: liquids != 0 repeat: expr repeat-expr: 'liquids != 0 ? 256 : 0' types: vertex: doc: Vertex data seq: - id: x_shift type: s1 doc: Shift by x axis - id: y_shift type: s1 doc: Shift by y axis - id: altitude type: u2 doc: Height (z position) - id: packed_normal type: normal doc: Packed normal normal: doc: Normal (3d vector) seq: - id: packed type: u4 doc: Normal packed in 4b instances: x: doc: Unpacked x component value: packed >> 11 & 0x7FF y: doc: Unpacked y component value: packed & 0x7FF z: doc: Unpacked z component value: packed >> 22 tile: doc: Tile parameters seq: - id: packed type: u2 doc: Tile information packed in 2b instances: index: doc: Tile index in texture value: packed & 63 texture: doc: Texture index value: packed >> 6 & 255 rotation: doc: Tile rotation (*90 degrees) value: packed >> 14 & 3
— .
10 z, 11 x y
unsigned packed_normal; float x = ((float)((packed_normal >> 11) & 0x7FF) - 1000.0f) / 1000.0f; float y = ((float)(packed_normal & 0x7FF) - 1000.0f) / 1000.0f; float z = (float)(packed_normal >> 22) / 1000.0f;
6 , 8 , 2
unsigned short texture; unsigned char tile_index = f & 63; unsigned char texture_index = (f >> 6) & 255; unsigned char rotation = (f >> 14) & 3;
3d33 33 , , 3232 . — 1 .
:
x = x + x_offset / 254
y = y + y_offset / 254
z = altitude / 65535 * max_altitude ( .mp )
"", :
0 1 2 *-*-* |\|\| ~ 33 *-*-* |\|\| ~ 66 *-*-* ~ ~ ~
, , 1616 . — 2 . , 90 .
. , , ID , MP .
: MP, , : ID , - .
ID — .
— :

- — , .
MOB
( ) , , : . — " ", .
, ( ).
:
typedef structure { unsigned type_id; unsigned size; byte data[size - 8]; } node;
(, !)
( , )
meta: id: mob title: Evil Islands, MOB file (map entities) application: Evil Islands file-extension: mob license: MIT endian: le doc: Map entities tree seq: - id: root_node type: node doc: Root node types: node: doc: Entity node seq: - id: type_id type: u4 doc: Node children type ID - id: size type: u4 doc: Node full size - id: data type: node_data size: size - 8 doc: Node stored data node_data: doc: Node data seq: - id: value type: switch-on: _parent.type_id cases: 0xA000: node 0x00001E00: node 0x00001E01: node 0x00001E02: node 0x00001E03: node 0x00001E0B: node 0x00001E0E: node 0x0000A000: node 0x0000AA01: node 0x0000ABD0: node 0x0000B000: node 0x0000B001: node 0x0000CC01: node 0x0000DD01: node 0x0000E000: node 0x0000E001: node 0x0000F000: node 0x0000FF00: node 0x0000FF01: node 0x0000FF02: node 0xBBAB0000: node 0xBBAC0000: node 0xBBBB0000: node 0xBBBC0000: node 0xBBBD0000: node 0xBBBE0000: node 0xBBBF0000: node 0xDDDDDDD1: node _: u1 doc: Node elements repeat: eos
| () | |
---|
AiGraph | | |
AreaArray | | |
Byte | 1 | 1 |
Diplomacy | 4096 | 32x32 2 |
Dword | 4 | 4 |
Float | 4 | 4 |
LeverStats | 12 | |
Null | 0 | |
Plot | 12 | 3 floats (vec3) |
Plot2DArray | | |
Quaternion | 16 | 4 floats (vec4) |
Record | >8 | |
Rectangle | | |
String | | |
StringArray | >4 | |
StringEncrypted | >4 | |
UnitStats | 180 | |
Unbekannt | | |
type_idtype_id | Datentyp | |
---|
0x00000000 | Record | ROOT |
0x00001E00 | Record | VSS_SECTION |
0x00001E01 | Record | VSS_TRIGER |
0x00001E02 | Record | VSS_CHECK |
0x00001E03 | Record | VSS_PATH |
0x00001E04 | Dword | VSS_ID |
0x00001E05 | Rectangle | VSS_RECT |
0x00001E06 | Dword | VSS_SRC_ID |
0x00001E07 | Dword | VSS_DST_ID |
0x00001E08 | String | VSS_TITLE |
0x00001E09 | String | VSS_COMMANDS |
0x00001E0A | Byte | VSS_ISSTART |
0x00001E0B | Record | VSS_LINK |
0x00001E0C | String | VSS_GROUP |
0x00001E0D | Byte | VSS_IS_USE_GROUP |
0x00001E0E | Record | VSS_VARIABLE |
0x00001E0F | StringArray | VSS_BS_CHECK |
0x00001E10 | StringArray | VSS_BS_COMMANDS |
0x00001E11 | String | VSS_CUSTOM_SRIPT |
0x0000A000 | Record | OBJECTDBFILE |
0x0000AA00 | Null | LIGHT_SECTION |
0x0000AA01 | Record | Licht |
0x0000AA02 | Float | LIGHT_RANGE |
0x0000AA03 | String | LIGHT_NAME |
0x0000AA04 | Plot | LIGHT_POSITION |
0x0000AA05 | Dword | LIGHT_ID |
0x0000AA06 | Byte | LIGHT_SHADOW |
0x0000AA07 | Plot | LIGHT_COLOR |
0x0000AA08 | String | LIGHT_COMMENTS |
0x0000ABD0 | Record | WORLD_SET |
0x0000ABD1 | Plot | WS_WIND_DIR |
0x0000ABD2 | Float | WS_WIND_STR |
0x0000ABD3 | Float | WS_TIME |
0x0000ABD4 | Float | WS_AMBIENT |
0x0000ABD5 | Float | WS_SUN_LIGHT |
0x0000B000 | Record | OBJECTSECTION |
0x0000B001 | Record | OBJECT |
0x0000B002 | Dword | NID |
0x0000B003 | Dword | OBJTYPE |
0x0000B004 | String | OBJNAME |
0x0000B005 | Null | OBJINDEX |
0x0000B006 | String | OBJTEMPLATE |
0x0000B007 | String | OBJPRIMTXTR |
0x0000B008 | String | OBJSECTXTR |
0x0000B009 | Plot | OBJPOSITION |
0x0000B00A | Quaternion | OBJROTATION |
0x0000B00B | Null | OBJTEXTURE |
0x0000B00C | Plot | OBJCOMPLECTION |
0x0000B00D | StringArray | OBJBODYPARTS |
0x0000B00E | String | PARENTTEMPLATE |
0x0000B00F | String | OBJCOMMENTS |
0x0000B010 | Null | OBJ_DEF_LOGIC |
0x0000B011 | Byte | OBJ_PLAYER |
0x0000B012 | Dword | OBJ_PARENT_ID |
0x0000B013 | Byte | OBJ_USE_IN_SCRIPT |
0x0000B014 | Byte | OBJ_IS_SHADOW |
0x0000B015 | Null | OBJ_R |
0x0000B016 | String | OBJ_QUEST_INFO |
0x0000C000 | Null | SC_OBJECTDBFILE |
0x0000CC00 | Null | SOUND_SECTION |
0x0000CC01 | Record | SOUND |
0x0000CC02 | Dword | SOUND_ID |
0x0000CC03 | Plot | SOUND_POSITION |
0x0000CC04 | Dword | SOUND_RANGE |
0x0000CC05 | String | SOUND_NAME |
0x0000CC06 | Dword | SOUND_MIN |
0x0000CC07 | Dword | SOUND_MAX |
0x0000CC08 | String | SOUND_COMMENTS |
0x0000CC09 | Null | SOUND_VOLUME |
0x0000CC0A | StringArray | SOUND_RESNAME |
0x0000CC0B | Dword | SOUND_RANGE2 |
0x0000CC0D | Byte | SOUND_AMBIENT |
0x0000CC0E | Byte | SOUND_IS_MUSIC |
0x0000D000 | Null | PR_OBJECTDBFILE |
0x0000DD00 | Null | PARTICL_SECTION |
0x0000DD01 | Record | PARTICL |
0x0000DD02 | Dword | PARTICL_ID |
0x0000DD03 | Plot | PARTICL_POSITION |
0x0000DD04 | String | PARTICL_COMMENTS |
0x0000DD05 | String | PARTICL_NAME |
0x0000DD06 | Dword | PARTICL_TYPE |
0x0000DD07 | Float | PARTICL_SCALE |
0x0000E000 | Record | DIRICTORY |
0x0000E001 | Record | FOLDER |
0x0000E002 | String | DIR_NAME |
0x0000E003 | Dword | DIR_NINST |
0x0000E004 | Dword | DIR_PARENT_FOLDER |
0x0000E005 | Byte | DIR_TYPE |
0x0000F000 | Record | DIRICTORY_ELEMENTS |
0x0000FF00 | Record | SEC_RANGE |
0x0000FF01 | Record | MAIN_RANGE |
0x0000FF02 | Record | RANGE |
0x0000FF05 | Dword | MIN_ID |
0x0000FF06 | Dword | MAX_ID |
0x31415926 | AiGraph | AIGRAPH |
0xACCEECCA | String | SS_TEXT_OLD |
0xACCEECCB | StringEncrypted | SS_TEXT |
0xBBAB0000 | Record | MAGIC_TRAP |
0xBBAB0001 | Dword | MT_DIPLOMACY |
0xBBAB0002 | String | MT_SPELL |
0xBBAB0003 | AreaArray | MT_AREAS |
0xBBAB0004 | Plot2DArray | MT_TARGETS |
0xBBAB0005 | Dword | MT_CAST_INTERVAL |
0xBBAC0000 | Record | LEVER |
0xBBAC0001 | Null | LEVER_SCIENCE_STATS |
0xBBAC0002 | Byte | LEVER_CUR_STATE |
0xBBAC0003 | Byte | LEVER_TOTAL_STATE |
0xBBAC0004 | Byte | LEVER_IS_CYCLED |
0xBBAC0005 | Byte | LEVER_CAST_ONCE |
0xBBAC0006 | LeverStats | LEVER_SCIENCE_STATS_NEW |
0xBBAC0007 | Byte | LEVER_IS_DOOR |
0xBBAC0008 | Byte | LEVER_RECALC_GRAPH |
0xBBBB0000 | Record | UNIT |
0xBBBB0001 | Null | UNIT_R |
0xBBBB0002 | String | UNIT_PROTOTYPE |
0xBBBB0003 | Null | UNIT_ITEMS |
0xBBBB0004 | UnitStats | UNIT_STATS |
0xBBBB0005 | StringArray | UNIT_QUEST_ITEMS |
0xBBBB0006 | StringArray | UNIT_QUICK_ITEMS |
0xBBBB0007 | StringArray | UNIT_SPELLS |
0xBBBB0008 | StringArray | UNIT_WEAPONS |
0xBBBB0009 | StringArray | UNIT_ARMORS |
0xBBBB000A | Byte | UNIT_NEED_IMPORT |
0xBBBC0000 | Record | UNIT_LOGIC |
0xBBBC0001 | Null | UNIT_LOGIC_AGRESSIV |
0xBBBC0002 | Byte | UNIT_LOGIC_CYCLIC |
0xBBBC0003 | Dword | UNIT_LOGIC_MODEL |
0xBBBC0004 | Float | UNIT_LOGIC_GUARD_R |
0xBBBC0005 | Plot | UNIT_LOGIC_GUARD_PT |
0xBBBC0006 | Byte | UNIT_LOGIC_NALARM |
0xBBBC0007 | Byte | UNIT_LOGIC_USE |
0xBBBC0008 | Null | UNIT_LOGIC_REVENGE |
0xBBBC0009 | Null | UNIT_LOGIC_FEAR |
0xBBBC000A | Float | UNIT_LOGIC_WAIT |
0xBBBC000B | Byte | UNIT_LOGIC_ALARM_CONDITION |
0xBBBC000C | Float | UNIT_LOGIC_HELP |
0xBBBC000D | Byte | UNIT_LOGIC_ALWAYS_ACTIVE |
0xBBBC000E | Byte | UNIT_LOGIC_AGRESSION_MODE |
0xBBBD0000 | Record | GUARD_PT |
0xBBBD0001 | Plot | GUARD_PT_POSITION |
0xBBBD0002 | Null | GUARD_PT_ACTION |
0xBBBE0000 | Record | ACTION_PT |
0xBBBE0001 | Plot | ACTION_PT_LOOK_PT |
0xBBBE0002 | Dword | ACTION_PT_WAIT_SEG |
0xBBBE0003 | Dword | ACTION_PT_TURN_SPEED |
0xBBBE0004 | Byte | ACTION_PT_FLAGS |
0xBBBF0000 | Record | TORCH |
0xBBBF0001 | Float | TORCH_STRENGHT |
0xBBBF0002 | Plot | TORCH_PTLINK |
0xBBBF0003 | String | TORCH_SOUND |
0xDDDDDDD1 | Record | DIPLOMATION |
0xDDDDDDD2 | Diplomacy | DIPLOMATION_FOF |
0xDDDDDDD3 | StringArray | DIPLOMATION_PL_NAMES |
0xFFFFFFFF | Unbekannt | UNBEKANNT |
— , , Nival, — , ( , ).
unsigned key; for (size_t i = 0; i < size; i++) { key += (((((key * 13) << 4) + key) << 8) - key) * 4 + 2531011; data[i] ^= key >> 16; }
: , ( ) . , , , .
( , , — Windows 98):

: , . , ( , , " : ", ).
, , - - , , Collada :

. , .
, . - , — - , . , -...
— !
UPD (23.01.2019):
, : github .
, (, "" ).
- http://gipatgroup.org/utilities — EiEdit (.res, .*db), MobSurgeon (.mob)
- http://svn.gipat.org/trac/GGWiki — EiEdit (.res, .*db), MobSurgeon (.mob), .mp, .sec, .*db
- https://github.com/demothorg/eifixer —
- https://github.com/konstvest/ei_figer — Blender .lnk, .fig, .bon, .anm
- https://github.com/demothorg/ei-tools — (.mob, .lnk, .mpr, .res) +
- https://github.com/konstvest/ei_maper — (.mpr, .mp, .sec, .mob)
- https://github.com/chemmalion/EIDBEditor — (.*db)
- https://gitlab.com/ykurganov/open-evil-islands — ,