多くのロシアのゲームを覚えていますか? 定性的? 忘れられない? はい、そうでした。 あなたが35歳以上であるか、ロシアのゲーム業界のファンなら、おそらく呪われた土地に精通しているでしょう。
物語は非常に普遍的に始まりました:夏、暑さ。 特別なことは何もありません。ラップトップのハードドライブのコンテンツをゆっくりと閲覧するとき、私の視線は数年の間アイドル状態だったおなじみのドラゴンのアイコンが付いたフォルダーをつかみました。
ゲームのどのファンが中身を知りたがらないのでしょうか?
はじめに
ゲーム情報
Cursed Lands-または、CISの外で呼ばれたように、 Evil Islands:Curse of the Lost Soul 、2000年にリリースされたステルスRPGゲーム。 このゲームはNival Interactiveによって開発されました。NivalInteractiveは、当時すでに一連のAllodaゲーム(海外のRage of Mages)として確立されていました。 モスクワ州立大学のほとんどの卒業生はそこで働いていました-彼らは完全に3次元の世界を持つ最初のゲームの1つを実現することができました。
2010年、Mail.Ru( information )がタイトルを譲渡しましたが、ゲームはNivalに代わってGOGストアで販売されています。
比較的最近、ゲームは18歳になりました-CISでのリリース日である10月26日の誕生日と見なされます。 時代にもかかわらず、公式のマスターサーバーはまだ使用中です。定期的に、誰かがGipatの森をい回り、仲間のチームで12個または2個のスケルトンを攻撃することにします。
記事について簡単に
当初、私の目標は、標準ライブラリのみを使用して、Python 3で「自分用」の一方向コンバータを作成することだけでした。 しかし、その過程で、フォーマットに関する文書化がスムーズに始まり、何らかの形で出力を標準化しようとしました。 一部の形式では、構造はKaitai Structを使用して記述されました。 その結果、すべてがこの記事とwikiを形式で書くことになりました。
すぐに注意します。ほとんどの場合、ゲームファイルは既に調査されており、ファンエディターが作成されています。 ただし、情報は非常に断片化されており、パブリックドメインの形式の完全な説明はほとんどありません。また、変更を作成するための適切なセットもありません。
...そしてそれを読む方法
スキーム(.ksyファイル)はすべての形式で提供され、2回クリックするだけでいくつかの最も一般的な言語のコードに変換できます。
残念ながら、すでにこの記事を書いている最後の段階で、尊敬されるHabrはYAML(およびJSON)を強調表示する方法を知らず、すべてのスキームがそれを使用していることがわかりました。 これは大きな問題ではありませんが、スキームを読むのが不便な場合は、NPPなどのサードパーティのエディターにコピーすることをお勧めします。
リソースとその場所
このゲームは、ライブラリ、ランチャー、および実際にはリソースが詰め込まれたエンジンを含むポータブルアプリケーションです。
これは興味深いです 。ゲームの設定は、ほぼ完全にレジストリに保存されます。 GOGバージョンのカメラのバグは、インストーラーが正しいデフォルト値を登録しないという事実によるものです。
ゲームフォルダの内容を一見すると、ASIとREGという2つの新しいファイル拡張子がすぐにわかります。
1つ目は動的ライブラリであり、これは考慮しません(これはリバースエンジニアリングの専門家によって行われます)が、2つ目はゲームの最初のネイティブファイル形式です。
REG
このタイプのファイルは、既知のテキストINIファイルのバイナリシリアル化です。
コンテンツは、キーとその値を格納するセクションに分割されます。 REGファイルはこの階層を保持しますが、データの読み取りと解析を高速化します-2000年には、これは明らかに重要でした。
一般に、この図の構造を説明できます。
meta: 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
これは興味深いものです 。2002年、Nivalはゲームのコミュニティといくつかのツールを共有しました( サイトスナップショット )-それらの1つはREGのINIシリアライザーでした。 ご想像のとおり、デシリアライザーは公式ではありませんが、ほとんどすぐに登場しました。
開始フォルダが整理されたら、サブディレクトリに進みましょう。
最初の外観は、CAMファイルを含むカメラフォルダーにあります。
カム
非常に単純な形式は、時間の経過とともにカメラの位置を単純にパックすることです。 カメラは位置と回転によって記述されます。 他の2つのフィールドは、おそらく移動シーケンスの時間とステップです。
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
次のフォルダー-Res、(予想外!)アーカイブであるRESファイルが保存されます。
RES
この形式は他の拡張機能の下に隠されている場合がありますが、元の形式はまだRESです。
データ構造は、ファイルへのランダムアクセスを持つアーカイブの非常に典型的なものです。内部のファイルに関する情報を保存するためのテーブル、名前のテーブル、ファイルの内容があります。
ディレクトリ構造は名前に直接含まれています。
2つの非常に興味深い事実に注目する価値があります。
- アーカイブは、ファイル情報をクローズドハッシュのリンクリストにロードするために最適化されています。
- ファイルの内容は一度保存できますが、別の名前で参照します。 私の知る限り、この事実はファンのリパックで使用されていました。これにより、ゲームのサイズが大幅に縮小されました。 元のディストリビューションでは、アーカイブの最適化は使用されませんでした。
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
これは興味深いものです。ロシア語版のゲームでは、Speech.resアーカイブに2つのサブディレクトリsとtが含まれ、内容がまったく同じです。そのため、アーカイブサイズが2倍になります。
これで、すべてのアーカイブを解凍できます(ネスト可能):
- RESは単なるアーカイブです。
- MPR-ゲームレベルの風景、
- MQ-マルチプレイヤーのタスクに関する情報、
- ANM-アニメーションのセット、
- MOD-3Dモデル、
- BON-モデルのボーンの位置。
アーカイブ内のファイルに拡張子がない場合は、BONおよびANMアーカイブ用に親拡張子を付けます。
受信したすべてのファイルを4つのグループに分割することもできます。
- テクスチャー
- データベース
- モデル
- レベルファイル。
シンプルから始めましょう-テクスチャを使って。
MMP
実際には、テクスチャ。 画像パラメータ、MIPレベルの数、使用されている圧縮を示す小さな見出しがあります。 ヘッダーの後に、サイズの降順でMIPイメージレベルがあります。
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
可能なピクセルパッケージ形式:
fourcc | 説明 |
---|---|
44 44 00 00 | ARGB4 |
44 58 54 31 | Dxt1 |
44 58 54 33 | Dxt3 |
50 4E 54 33 | PNT3-RLE圧縮ARGB8 |
50 56 00 00 | R5G5B5 |
51 55 00 00 | A1R5G5B5 |
88 88 00 00 | ARGB8 |
画像形式がPNT3の場合、解凍後のピクセル構造はARGB8です。 bits_per_pixel
圧縮画像のサイズ(バイト単位)。
PNT3の開梱
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
これは興味深いです。テクスチャの一部は垂直に反映されます(または一部は反映されませんか?)。
そして、ゲームは透明性に非常にjeしています-画像にアルファチャンネルがある場合、透明ピクセルの色は正確に黒でなければなりません。 または白-なんて幸運。
単純なフォーマットは終了しました。より厳格なフォーマットに移りましょう-かつて、MODメーカーのランクは次のフォーマット用の独自の編集ツールを猛烈に保持しましたが、無駄ではありませんでした。 私はあなたに警告しました。
データベース(* DBなど)
この形式は説明するのが非常に不便です-基本的に、これはノード(またはレコードテーブル)のシリアル化されたツリーです。 ファイルは、指定されたフィールドタイプを持つ複数のテーブルで構成されます。 一般構造:テーブルは共通の「ルート」ノードにネストされ、レコードはテーブル内のノードです。
各ノードで、そのタイプとサイズが指定されます:
unsigned char type_index; unsigned char raw_size; // unsigned length; // read(raw_size); if (raw_size & 1) { length = raw_size >> 1; for (int i = 0; i < 3; i++) length <<= 8; read(raw_size); length += raw_size; } else length = raw_size >> 1;
テーブルフィールドのタイプは、テーブルのフォーマット文字列からインデックスによって取得され、実際のタイプは取得された値によって決定されます。
指定 | 説明 |
---|---|
S | ひも |
私は | 4b int |
うん | 4b符号なし |
F | 4bフロート |
X | ビットバイト |
f | 浮動小数点配列 |
私は | int配列 |
B | ブール |
b | ブール配列 |
H | 不明な16進バイト |
T | 時間 |
0 | 記載なし |
1 | 0FII
|
2 | SUFF
|
3 | FFFF
|
4 | 0SISS
|
5 | 0SISS00000U
|
アイテム(.idb)
テーブル | 構造 |
---|---|
素材 | SSSIFFFIFIFfIX
|
武器 | SSISIIIFFFFIFIXB00000IHFFFfHHFF
|
アーマー | SSISIIIFFFFIFIXB00000ffBiHH
|
クイックアイテム | SSISIIIFFFFIFIXB00000IIFFSbH
|
クエストアイテム | SSISIIIFFFFIFIXB00000Is
|
アイテムの販売 | SSISIIIFFFFIFIXB00000IHI
|
スイッチ(.ldb)
テーブル | 構造 |
---|---|
スイッチのプロトタイプ | SfIFTSSS
|
スキルとスキル(.pdb)
テーブル | 構造 |
---|---|
能力 | SSI0000000s
|
スキル | SSI0000000SSIIIFFFIIIIBI
|
フットプリント(prints.db)
テーブル | 構造 |
---|---|
血痕 | 0S11
|
炎の痕跡 | 0S110000001
|
足跡 | 0S11
|
スペル(.sdb)
テーブル | 構造 |
---|---|
プロトタイプ | SSSFIFIFFFFIIIIUSSIIbIXFFFFF
|
修飾子 | SSFIFFISX
|
パターン | 0SssSX
|
アーマーテンプレート | 0SssSX
|
武器のパターン | 0SssSX
|
クリーチャー(.udb)
テーブル | 構造 |
---|---|
破損部品 | SffUU
|
人種 | SUFFUUFfFUUf222222000000000000SssFSsfUUfUUIUSBFUUUU
|
モンスターのプロトタイプ | SSIUIFFFSFFFFFFFFFUFFFFFFff33sfssSFFFFFUFUSF
|
NPC | SUFFFFbbssssFUB
|
叫び声(acks.db)
テーブル | 構造 |
---|---|
答え | 0S0000000044444444444444444444445444444444444
|
悲鳴 | 0S0000000044444
|
その他 | 0S0000000044
|
クエスト(.qdb)
テーブル | 構造 |
---|---|
タスク | SFIISIIs
|
ブリーフィング | SFFsSsssssI
|
これは興味深いです。 2002年1月16日、Nivalはcsv形式のマルチプレイヤーのソースベースと、ゲーム形式のユーティリティコンバーター( サイトスナップショット )を投稿しました。 当然、逆コンバーターの表示は遅くありませんでした。 また、modmakerからフィールドとそのタイプを説明するドキュメントが少なくとも2つありますが、それらを読むことは非常に困難です。
Adb
特定のタイプのユニットのアニメーションデータベース。 上記の* DBとは対照的に、これは非常に「人間」です。これは、静的フィールドサイズの単一レベルのテーブルです。
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'
これは興味深いものです。いくつかのユニットでは、部分的に切り捨てられたデータベース形式が使用されますが、ほとんど検討されていません。
データベースを扱ったので、商業的な休憩を宣言します。 しかし、我々は何も宣伝しません-私たちの方法ではありません。 次に便利なもの、クリーチャーファイルの名前の付け方をより適切に示します。
モデル名の形式
名前は2文字のグループ-論理「レベル」の略語から収集されます。
たとえば、女性キャラクターはunhufe
- Unit > Human > Female
であり、 initwesp
- Inventory > Item > Weapon > Spear
、つまり在庫の槍(背中ではなく、それは良い)です。
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
これは興味深いです。この分類によれば、キノコは木であり、ゴブリンを持つゴーレムは兄弟であり、Tka-Rickはモンスターです。 また、ここでは、怪物の「働く」名前を見ることができます。これは、D&Dの名前と疑わしく似ています-見る人(邪眼)、サキュブ(ハーピー)、鬼(人食い人種)、ドリアド(森の人)。
道徳的に休んで、私たちは真っ向からモデルに飛び込みます。 それらは、互いにリンクされたいくつかの形式で表示されます。
Lnk
論理的に-モデルの基礎。 モデルのパーツの階層を、現代の3Dモデリングの観点から説明します-ボーンの階層。
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
親ボーンの親名は空の文字列(長さ0)です。
骨はありますが、名前を付けて組み立てるだけでは十分ではありません。骨に組み立てる必要があります。
ボン
前述のように、この形式(アーカイブでない場合)は、親パーツに対するモデルのパーツ(ボーン)の位置を設定します。 回転せずにオフセットのみが保存されます-最新のフォーマットとの違いの1つです。
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
ご覧のとおり、1つのオフセットには数が多すぎます-実際、ここで最初にゲームエンジンの重要な機能の1つであるトリリニアモデル補間に出会いました。
仕組み:モデルには、条件、強度、器用さ、成長という3つの補間パラメーターがあります。 モデルには8つの極端な状態もあります。 パラメータを使用して、トライリニア補間により最終モデルを取得できます。
def trilinear(val, coefs=[0, 0, 0]): # Linear interpolation by str t1 = val[0] + (val[1] - val[0]) * coefs[1] t2 = val[2] + (val[3] - val[2]) * coefs[1] # Bilinear interpolation by dex v1 = t1 + (t2 - t1) * coefs[0] # Linear interpolation by str t1 = val[4] + (val[5] - val[4]) * coefs[1] t2 = val[6] + (val[7] - val[6]) * coefs[1] # Bilinear interpolation by dex v2 = t1 + (t2 - t1) * coefs[0] # Trilinear interpolation by height return v1 + (v2 - v1) * coefs[2]
これは興味深いです。たとえば、石のドアやチェストを開くなど、一部のオブジェクトをアニメーション化するために、トライリニアモデルの補間が使用されます。
今こそ、モデル自体の一部を見るときです。
図
おそらく、この集会は理解することが不可能です。 彼の説明とブレンダーのプラグインはネット上で見つけることができますが、それらを知っていてもすぐには気づきません。 ご覧ください:
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
難しさは何ですか? したがって、法線と頂点のデータは4つのブロックに格納され、頂点も補間のために8つのブロックに配置されます。
これは興味深いです。おそらく、1999年以降Intelプロセッサに登場したSSE命令の助けを借りて処理を高速化するために、このようなグループ化が行われました。
さて、私たちはモデルを読んで構成しましたが、何かが欠けています。 まさに-アニメーション!
あん
アニメーションは、キーの状態としてコンポーネント形式で保存されます。 興味深い事実は、骨格アニメーションだけでなく頂点モーフィングもサポートされていることです。
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
それだけです-これで本格的なモデルができました。新しくレンダリングされたヤドカリを賞賛できます:
トカゲに必要なものを見つける
彼の家でトカゲとの会話
隠者リザード:あなたは来た、男。 これはいいです。
ザック:あなたが私に伝えたかったことはそれだけですか?
隠者リザード:あなたは再び急いでいます。 私はあなたの質問を覚えており、それらに答えます。 取引をするために鉄の人々に来ました。 しかし、私は彼らがあなたにどうしたかを見ました。 彼らは言葉を持ちません、私は彼らを信じることを止めました。 あなたは言葉を守りました。 取引があなたに提供されます。
隠者リザード:人々は金が大好きです。 金のトカゲは面白くない。 あなたは私の仕事を完了します、そして私はあなたに私が持っている金を与えます。 たくさんの金があります。
ザック(思慮深く、あまり興味がない) :うーん...ゴールド...それは確かに傷つけないだろう...
ザック:私が長年探していた老魔術師の居場所を見つけてくれるといいのですが。 結局のところ、トカゲは古代の人々であり、あなたはそれを知ることができます!
隠者リザード:そのとおりです。 トカゲは古代の人々です。 私たちは老人について知っているすべてを集めることができます。 私のミッションを完了することに同意しますか?
ザック:なんて話だ! すべてがすでに行われていることを考慮してください。
Hermit Lizard (まじめに) :もうやったの? 私をだましますか?
ザック:実際、私は冗談を言いたかった。そうでなければ、あなたは本当に真剣だった。
隠者トカゲ:なるほど。 これは冗談です。 私も冗談を言うことができると思います。 それから。 そして今、運河に水を戻す必要があります。 オークは私たちから水を盗みました。
隠者トカゲ:水に沿って南に行きます。 ダムと運河が見えます。 ダムを上げる必要があります。 レバレッジ。 あげます チャネルをブロックする必要があります。 石。 石をあげません 彼はすでに運河の端に横たわっています。 ダムの上流。 石は重いです。 オークが掘ったとき、彼らは長い間彼を持ち上げました。 あなたが彼を押すと、彼はすぐに後退します。
隠者リザード:その後、戻ってきてください。 昔の魔術師について学んだことをすべてお話しします。
ザック:手に! しかし、ちなみに、ストーリーに少しコインを追加しても、私はまったく気分を害することはありません。
隠者のトカゲ:さらに南の浅瀬に住んでいる私の親relativeにコインを求めてください。 3番目に並んでいる最も遠い砂浜の島に行きます。 宝物はあなたのものになります!
トカゲの隠者(彼自身へ) :奇妙な。 この男はユーモアが大好きです。 私は冗談を言っていました。 男は笑いませんでした。 とても奇妙です。
さて、最も興味深いのは、マップの保存方法です。
MP
これはマップヘッダーファイルです。 不幸な偶然の一致により、拡張子はマルチプレイヤーの保存ファイルの拡張子と一致しますが、これは考慮しません。
最初に、風景の一般的な説明をする必要があります。
- 「チャンク」の数-32x32メートルのカードの破片。
- 最大高さ(頂点の高さは整数スケールで保存されるため);
- タイルアトラスの数。
さらに、マップマテリアルの説明と、アニメーションタイル(水や溶岩など)があります。
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
terrain type | 種類 |
---|---|
0 | |
1 | |
2 | |
3 |
material 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 |
, 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;
33 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 | ||
ひも | ||
StringArray | >4 | |
StringEncrypted | >4 | |
UnitStats | 180 | |
Unknown |
type_id | ||
---|---|---|
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 | ひも | VSS_TITLE |
0x00001E09 | ひも | VSS_COMMANDS |
0x00001E0A | Byte | VSS_ISSTART |
0x00001E0B | Record | VSS_LINK |
0x00001E0C | ひも | VSS_GROUP |
0x00001E0D | Byte | VSS_IS_USE_GROUP |
0x00001E0E | Record | VSS_VARIABLE |
0x00001E0F | StringArray | VSS_BS_CHECK |
0x00001E10 | StringArray | VSS_BS_COMMANDS |
0x00001E11 | ひも | VSS_CUSTOM_SRIPT |
0x0000A000 | Record | OBJECTDBFILE |
0x0000AA00 | Null | LIGHT_SECTION |
0x0000AA01 | Record | 軽い |
0x0000AA02 | Float | LIGHT_RANGE |
0x0000AA03 | ひも | LIGHT_NAME |
0x0000AA04 | Plot | LIGHT_POSITION |
0x0000AA05 | Dword | LIGHT_ID |
0x0000AA06 | Byte | LIGHT_SHADOW |
0x0000AA07 | Plot | LIGHT_COLOR |
0x0000AA08 | ひも | 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 | ひも | OBJNAME |
0x0000B005 | Null | OBJINDEX |
0x0000B006 | ひも | OBJTEMPLATE |
0x0000B007 | ひも | OBJPRIMTXTR |
0x0000B008 | ひも | OBJSECTXTR |
0x0000B009 | Plot | OBJPOSITION |
0x0000B00A | Quaternion | OBJROTATION |
0x0000B00B | Null | OBJTEXTURE |
0x0000B00C | Plot | OBJCOMPLECTION |
0x0000B00D | StringArray | OBJBODYPARTS |
0x0000B00E | ひも | PARENTTEMPLATE |
0x0000B00F | ひも | 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 | ひも | 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 | ひも | SOUND_NAME |
0x0000CC06 | Dword | SOUND_MIN |
0x0000CC07 | Dword | SOUND_MAX |
0x0000CC08 | ひも | 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 | ひも | PARTICL_COMMENTS |
0x0000DD05 | ひも | PARTICL_NAME |
0x0000DD06 | Dword | PARTICL_TYPE |
0x0000DD07 | Float | PARTICL_SCALE |
0x0000E000 | Record | DIRICTORY |
0x0000E001 | Record | FOLDER |
0x0000E002 | ひも | 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 | ひも | SS_TEXT_OLD |
0xACCEECCB | StringEncrypted | SS_TEXT |
0xBBAB0000 | Record | MAGIC_TRAP |
0xBBAB0001 | Dword | MT_DIPLOMACY |
0xBBAB0002 | ひも | 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 | ひも | 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 | ひも | TORCH_SOUND |
0xDDDDDDD1 | Record | DIPLOMATION |
0xDDDDDDD2 | Diplomacy | DIPLOMATION_FOF |
0xDDDDDDD3 | StringArray | DIPLOMATION_PL_NAMES |
0xFFFFFFFF | Unknown | UNKNOWN |
— , , 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://ru.nival.com/games/history/zemli —
- https://ru.wikipedia.org/wiki/_ —
- https://allods.gipat.ru/index.php?p=ei — " "
- https://evil-islands.github.io — ,
- 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 — ,
- https://vk.com/evil.islands —
- http://allods.gipat.ru — " "
- http://gipat.ru — " "
- http://gipatgroup.org/forum — GipatGroup ( — )
- http://honestgroup.net/forum — HonestGroup