Formati dei file di Blood Omen

From Blood Wiki
Revision as of 20:55, 21 January 2013 by Makenor13 (Talk | contribs)

Jump to: navigation, search

Contents

Questa pagina è dedicata alle specifiche per i formati dei file usati in Blood Omen. Include il lavoro di esplorazione fatto dalla community da quando Blood Omen è uscito.

La maggior parte dei formati semplici (come la struttura del file BIG, le specifiche del TIM) sono stati resi esplorabili anni fa, ma altri (il formato della mappa, gli sprite) soltanto di recente, durante lo sviluppo di Blood Pill.

File BIG

Questo è un file generale che contiene tutte le risorse di gioco. La sua struttura è molto semplice:

uint32 - numero di entries
Array delle entries:
  uint32 - Nome hash del file
  uint32 - Dimensione del file
  uint32 - Offset del file
Array dei dati della entry:
  bytes - Contenuti del file
Tip: Può esserci dello spazio tra i file

Immagine TIM

Immagini per PlayStation. Usate per contenere gli elementi grafici e i componenti della mappa. Le specifiche dei TIM sono ben conosciute, quindi non verranno elencate qui. Riferimenti per decodificare e codificare sono disponibili nel codice sorgente di Blood Pill.

Consigli:

  • Alcune entries del pill.big possono contenere più file TIM fusi insieme.
  • Alcuni file TIM di Blood Omen possono terminare con dei null.

Suoni

VAG

I file "Very-Audio-Good" per PlayStation (variazione ADPCM di 4-bit) usati nella versione PlayStation di Blood Omen e dal preview di gioco. Non sono usati nella versione PC. Riferimenti per decodificare e codificare sono disponibili nel codice sorgente di Blood Pill.

Consigli:

  • Molti file VAG sono senza header (il loro header è confuso, non c'è neppure il fourCC "VAGb", dunque possono essere individuati solo con un'analisi sintattica).
  • Normalmente andrebbero eseguiti a 11025hz, ma alcuni (le musiche e alcuni effetti sonori) a 22050hz.

IMA ADPCM grezzi

Dei file senza header che contengono flussi grezzi IMA ADPCM che servono a sostituire i file VAG nella versione PC. Usano esattamente gli stessi nomi dei file VAG per la PlayStation.

Tip: I file non hanno alcun header

File audio WAV

Blood Omen per PC ha alcuni effetti sonori in formato WAV (La PlayStation li ha in VAG). Questo formato è largamente conosciuto e non c'è bisogno di spiegarlo.

Tip: Sembra che il gioco non usi gli header dei WAV; alcuni file hanno un play rate alterato e devono essere aggiustati manualmente per poterli eseguire come si sentono in gioco

Video

STR della PSX

Usato nella versione PlayStation di Blood Omen. L'STR è un flusso video MJPEG con l'audio aggiunto come interleave. Si può usare il tool jPsxDec per estrarre e decodificare questo formato dall'immagine del cd per PlayStation del gioco.

Video JAM

JAM è un formato di compressione video scadente sviluppato da Semilogic Entertainment e usato nella versione PC di Blood Omen. Il formato usa una tavolozza in comune con più frame e un tipo di compressione dinamica. La specifica e la decodifica dei JAM sono state scoperte nel 2011 da MisterGrim. Il JAM può solo contenere video, l'audio era contenuto in un file VAG separato (che era, in effetti, un IMA ADPCM grezzo).

I video JAM hanno molte più alterazioni dei STR, e la traccia audio è in mono (gli STR hanno una stereo).

Il codice per decomprimere i JAM è disponibile nel codice sorgente di Blood Pill.

Gli sprite

Gli sprite sono immagini di personaggi o altre cose animate. Ci sono tre estensioni e altrettanti nomi dei file: SHA, SDR, SHD. Tuttavia quando Blood Pill è stato sviluppato non erano noti i veri nomi dei file, quindi questa specifica viene definita "Tipi di sprite" e copre la decompressione di tutti gli sprite, inclusi quelli non utilizzati.

Sprite di tipo 1 - Carte degli oggetti

Ha sempre 1 frame e nessuna compressione.

uint32 - sempre 0x01 0x00 0x00 0x00 
uint32 - dimensione del file
768 bytes - dati della mappa dei colori a 24 bit (256 colori)
int16 - posizione su x
int16 - posizione su y
byte - larghezza
byte - altezza
byte - x
byte - y
larghezza*altezza bytes - contenuto dell'immagine (gli indici nella mappa dei colori)
Tip: In realtà è una versione semplificata dello sprite di tipo 3

Sprite di tipo 2 - Insieme di immagini

Sprite a più frame con tavolozza dedicata ad ogni frame. Usato per le raccolte di immagini dell'interfaccia (come le immagini degli incantesimi e degli oggetti).

uint32 - numero di frame
uint32 - dimensione del file
768 bytes - dati della mappa dei colori a 24 bit (inutilizzato)
Array degli header del frame:
  768 bytes - dati della mappa dei colri a 24 bit
  uint32 - offset dei dati dell'immagine dalla fine degli header
  ubyte - larghezza
  ubyte - altezza
  byte - x
  byte - y
Array dei dati dell'immagine del frame:
  larghezza*altezza bytes - contenuto dell'immagine (gli indici nella mappa dei colori)
Tip: In alcuni file la larghezza e l'altezza reali potrebbero essere doppie di quelle scritte nell'header

Sprite di tipo 3 - Sprite degli oggetti

Sprite a più frame con tavolozza condivisa.

uint32 - numero di frame
uint32 - dimensione del file
768 bytes - dati della mappa dei colori a 24 bit
int16 - offset in x per tutti i frame
int16 - offset in y per tutti i frame
Array degli header del frame:
  uint32 - offset dei dati dell'immagine dalla fine degli header
  ubyte - larghezza
  ubyte - altezza
  byte - x
  byte - y
Array dei dati dell'immagine del frame:
  bytes - contenuti dell'immagine compressa (gli indici nella mappa dei colori) usando un run-length encoding; alcuni file usando colori a 4 bit (vedi #Metodi di compressione)

Consigli:

  • Non si sa come scoprire quale compressione del file sia usata (RLE a 0x00, o 0xFF o entrambe), sembra che l'engine dia questa informazione quando il file viene caricato
  • Alcuni file usano colori a 4 bit invece che RLE

Sprite di tipo 4 - Sprite dei personaggi

Sprite a più frame con tavolozza condivisa, con header dei frame aggiuntivi. Usato dai personaggi. Molto simile al tipo 3.

uint32 - numero di frame
uint32 - dimensione del file
Array degli header aggiuntivi del frame (arrotondati per eccesso al multiplo di 4 più vicino):
   byte - informazioni ignote
768 bytes - dati della mappa dei colori a 24 bit
int16 - offset in x per tutti i frame
int16 - offset in y per tutti i frame
Array dehli header del frame:
  uint32 - offset dei dati dell'immagine dalla fine degli header
  ubyte - larghezza
  ubyte - altezza
  byte - x
  byte - y
Array dei dati dell'immagine del frame:
  bytes - contenuti dell'immagine compressa (gli indici nella mappa dei colori) usando un run-length encoding; alcuni file usando colori a 4 bit (vedi #Metodi di compressione)

Consigli:

  • Non si sa come scoprire quale compressione del file sia usata (RLE a 0x00, o 0xFF o entrambe), sembra che l'engine dia questa informazione quando il file viene caricato
  • Alcuni file usano colori a 4 bit invece che RLE

Sprite di tipo 5

Un'altra variante del tipo 3 senza informazioni sull'offset e (a volte) con larghezza e altezza non valide, da mettere a posto con un particolare trucco.

uint32 - numero di frame
uint32 - dimensione del file
768 bytes - dati della mappa dei colori a 24 bit
Array degli header del frame:
  uint32 - offset dei dati dell'immagine dalla fine degli header
  ubyte - larghezza
  ubyte - altezza
  byte - x
  byte - y
Array dei dati dell'immagine del frame:
  bytes - contenuti dell'immagine compressa (gli indici nella mappa dei colori) che usano RLE  (vedi #Metodi di compressione)

Consigli:

  • Alcuni frame hanno larghezza e altezza non valide perché la loro larghezza è maggiore di 255 e il formato usa 1 bit per codificarle. Per correggere il problema va usato 255 + [larghezza]
  • Non si sa come scoprire quale compressione del file sia usata (RLE a 0x00, o 0xFF o entrambe), sembra che l'engine dia questa informazione quando il file viene caricato

Mappe

Le mappe sono un elemento centrale che mette insieme tutte le risorse (immagini, suoni, mattonelle, sprite). Circa l'80% della struttura della mappa è stata scoperta e questo permette di estrarre una serie di cose, incluse: le texture usate, l'immagine della mappa, posizione di mostri/effetti/oggetti, attivatori, informazioni scritte, porte e bottoni...

Ogni mappa ha un mapnum (numero della mappa) e una sezione inclusa nel nome del file. Quell'informazione viene usata per piazzare la mappa nella mappa globale di un'avventura (vedi TheLost Worlds - May survey per le informazioni complete sui nomi dei livelli).

Mattonelle

Le mattonelle sono immagini TIM a 256 colori compresse con LZ77 (vedi #Metodi di compressione).

La texture di ogni mattonella ha 8x8=64 mattonelle. L'engine renderizza ogni mattonella separatmaente, spostando la texture della mattonella del momento come necessario.

uint32 - dimensione dei dati compressi
bytes - dati compressi

Consigli:

  • Dato che tutte le mattonelle sono dei TIM a 8 bit 256x256, la dimensione dei dati decompressi è sempre la stessa

File della mappa

Il file della mappa è una struttura di lunghezza fissa che contiene la posizione delle mattonelle (80x80), i nemici, le luci, i botoni e altri oggetti che compongono il livellod i Blood Omen. Per via della sua natura statica ha molti limiti, e ogni mappa ha esattamente la stessa dimensione (quindi basta copiarla in memoria).

// map trigger
typedef struct 
{
     unsigned short parm1;    // primo parm, se non definito lo script è 0xFFFF, 0xFFFE è il valore null
                              //  - numero di mappa di destinazione/origine (TRIGGER_EXIT, TRIGGER_ENTRANCE, TRIGGER_TELEPORT)
                              //  - numero del discorso (TRIGGER_INFOMARK, TRIGGER_IMAGEMARK)
     unsigned short parm2;    // secondo parm:
                              //  - numero del pulsante (TRIGGER_BUTTON)
                              //  - numero dell'immagine (TRIGGER_IMAGEMARK)
     byte           parm3;    // sezione della mappa di destinazione/origine (TRIGGER_EXIT, TRIGGER_ENTRANCE, TRIGGER_TELEPORT)
     byte           srcx;     // posizione
     byte           srcy;     // posizione
     byte           type;     // tipo di script, uno dei TRIGGER_
     byte           u2[3];    // ?
     byte           x;        // posizione
     byte           y;        // posizione
     byte           u3[3];    // ?
}bo_trigger_t;

// oggetto della mappa
typedef struct
{
     unsigned short savenum;  // id unico di salvataggio
     byte           itemcode; // uno dei codici MAPITEM_
     byte           x;        // posizione
     byte           y;        // posizione
     byte           hidden;   // vale 1 se l'oggetto viene spawnato da un attivatore (come la distruzione di un barile)
     unsigned short target;   // gruppo di attivatori bersaglio
     byte           u[4];     // ?
}bo_item_t;

// mattonella animata
typedef struct
{
     unsigned short targetnum;// un gruppo di attivatori
     byte x;                  // posizione
     byte u1;                 // ?
     byte y;                  // posizione
     byte u2;                 // ?
     unsigned short tile1;    // numero della mattonella
     unsigned short tile2;    // numero della mattonella allo stato alternativo
     byte contents1;          // contenuti, vedi le definizioni di CONTENTS_ per i possibili valori dei contenuti
     byte contents2;          // contenuti allo stato alternativo
     byte u3[12];             // ?
}bo_atile_t;

// controller del pulsante
typedef struct
{
     unsigned short target;   // un gruppo di attivatori da chiamare
     unsigned short tile1;    // numero della mattonella
     unsigned short tile2;    // numero della mattonella allo stato alternativo
     byte flags;              // vedi le definizioni dei BUTTONFLAG_*
     byte u1;                 // ?
     unsigned short savenum;  // id unico di salvataggio
     byte u2;                 // ?
     byte u3;                 // ?
}bo_button_t;

// effetto
typedef struct
{
     byte x;                  // posizione
     byte y;                  // posizione
     byte lightposx;          // posizione della fonte di luce
     byte lightposy;          // posizione della fonte di luce
     byte sprite;             // indice dello sprite dall'array degli sprite
     byte lightsizex;         // dimensione dei poligoni di luce
     byte lightsizey;         // dimensione dei poligoni di luce
     byte u1;                 // ?
     byte lightform;          // flag della forma della luce
     byte r;                  // quantità di rosso
     byte g;                  // quantità di verde
     byte b;                  // quantità di blu
     unsigned short targetnum;// gruppo di attivatori
     byte start_on;           // 1 se l'effetto parte attivo, 0 se parte disattivo
     byte u3[5];              // ?
}bo_effect_t;

typedef struct
{
     byte data[164];
}bo_object_t;

// definizione dell'oggetto sulla mattonella (barili, forzieri)
typedef struct
{
     byte x;                  // posizione iniziale
     byte y;                  // posizione finale
     byte w;                  // larghezza
     byte h;                  // altezza
     byte ofsx;               // moltiplica per 16 per il vero offset
     byte ofsy;               // moltiplica per 16 per il vero offset
     byte u1;
     byte u2;
}bo_grpobject_t;

// entità dello scenario
typedef struct
{
     byte u1;                 // ?
     byte u2;                 // ?
     byte u3;                 // ?
     byte u4;                 // ?
     unsigned short tile1;    // mattonella base (in realtà l'oggetto gruppo, non la mattonella 32x32 standard
     unsigned short tile2;    // mattonella alternativa (oggetto gruppo)
     unsigned short tile3;    // mattonella distrutta (oggetto gruppo)
     byte u5;                 // ?
     byte u6;                 // ?
     byte pushable;           // una forza necessaria per spingere
     byte toggled;            // l'attivatore che cambia lo stato (significa che c'è la mattonella 2)
     byte u7;                 // ?
     byte spawnitems[3];      // codici dell'oggetto da spawnare quando attivato/distrutto
     byte u8;                 // ?
     byte destructible;       // i flag distruggibili
     unsigned short savenum;  // id unico di salvataggio
     byte u10;                // ?
     byte x;                  // posizione
     byte y;                  // posizione
     byte u11;                // ? 
     byte active;             // 1 è pieno, altrimenti 0
     byte u13;                // ? 
}bo_scenery_t;

// tracciati dei nemici
typedef struct
{
     byte x;                  // posizione
     byte y;                  // posizione
     byte u1;                 // ?
     byte u2;                 // ?
}bo_path_t;

// entità nemica
typedef struct
{
     bo_path_t paths[4];      // tracciati di pattugliamento
     byte u1[12];             // ?
     unsigned short savenum;  // id unico di salvataggio
     byte u2[52];             // ?
     byte charnum;            // classe del mostro (come per lo sprite del personaggio)
     byte u3[10];             // ?
     unsigned short target;   // gruppo di attivatori da chiamare quando viene ucciso
     byte u4[20];             // ?
     byte lastpath;           // ?
     byte u6[18];             // ?
     byte u7[15];             // ?
     byte x;                  // posizione
     byte y;                  // posizione
     byte u8[4];              // ?
     unsigned short speechnum;// un numero di parlato per i discorsi del travestimento
     byte u9[6];              // ?
}bo_monster_t;

// struttura generale del file della mappa
typedef struct
{
     // una catena di numeri della mappa delle mattonelle usati (per creare i nomi dei file)
     // ogni mappa delle mattonelle contiene 64 mattonelle, i cui numeri sono lineari
     // per esempio, una mattonella #131 è la mattonella #3 dalla mappa delle mattonelle #2
     // con flag da 2-byte (abbreviazione senza firma) contenuti nel numero della mattonella (i flag cominciano dal byte 10)
     // vedi le definizioni dei TILEFLAG_ per i possibili flag delle mattonelle
     unsigned short  tilemaps[40];
     // informazione ancora ignota
     byte            u1[12];
     bo_object_t     objects[10];
     bo_monster_t    monsters[32];
     bo_grpobject_t  grpobjects[8][32];
     // mattonelle animate - una mattonella che può essere in 2 stati e che ha contenuti diversi ad ogni stato
     // usato per le porte, le punte che escono dal terreno ecc.
     // le mattonelle animate hanno un gruppo di attivatori da eseguire con degli script
     bo_atile_t      atiles[100];
     // l'array di un pulsante speciale controlla tutti i pulsanti usati nel livello
     // molto simile alle mattonelle animate
     // i pulsanti hanno gruppi di attivatori da eseguire con degli script
     bo_button_t     buttons[20];
     // informazione #2 ancora ignota
     byte            u2[8];
     // oggetti spingibili nella scena - tavoli, sedie, pietre ecc.
     bo_scenery_t    scenery[256];
     // prima mappa delle mattonelle
     unsigned short  backtiles[80][80];
     // seconda mappa delle mattonelle
     unsigned short  foretiles[80][80];
     // mappa dei contenuti - un valore di contenuto per ogni mattonella statica (in gioco vengono sostituite dalle mattonelle modificabili, se presenti)
     // vedi le definizioni dei CONTENTS_  per i possibili valori dei contenuti
     byte            contents[80][80];
     // linear triggers array - all triggers used on map
     bo_trigger_t    triggers[255];
     // triggers are non-solid interaction points, activated when player stands in them
     // this array golds pointers to triggers
     byte            triggertiles[80][80];
     // oggetti piazzati nel livello
     // i codici degli oggetti 0-9 sono potenziamenti, i codici 10, 11, 12, 13 sono riservati per i codici di oggetti unici
     // quindi non possono esserci più di 4 tipi di oggetti unici in ogni livello
     //sono oggetti unici: incantesimi, armi, forme, artefatti, oggetti delle missioni
     byte            uniqueitems[4];
     bo_item_t       items[50];
     // dati ancora sconosciuti
     byte            u4[8];
     byte            u5[8][40];
     byte            u6[24];
     // effetti
     unsigned short  sprites[8];
     bo_effect_t     effects[64];
     // dati ancora sconosciuti
     byte   u7[936];
}bo_map_t;

// cose ancora non capite:
// - come funziona l'illuminazione (luci di vario tipo, luce di notte e giorno, luce ambientale)
// - gli interruttori dei tracciati dei mostri (alcuni tracciati sono incasinati)
// - counter e attivatori dei puzzle?

// flag delle mattonelle
#define TILEFLAG_UNKNOWN1       1024
#define TILEFLAG_NODRAW         2048
#define TILEFLAG_UNKNOWN3       4096
#define TILEFLAG_UNKNOWN4       8192
#define TILEFLAG_ALWAYSONTOP    16384
#define TILEFLAG_UNKNOWN6       32768

// contenuti
#define CONTENTS_SOLID          1
#define CONTENTS_WATER          2
#define CONTENTS_LAVA           3
#define CONTENTS_FIRE           4
#define CONTENTS_SPIKES         5
#define CONTENTS_TRAPTELEPORT   6
#define CONTENTS_JUMPWALL       8
#define CONTENTS_SWAMP          11
#define CONTENTS_JUMPFENCE      10
#define CONTENTS_MISTWALK       12
#define CONTENTS_SACRIFICE      13
#define CONTENTS_ICE            19
#define CONTENTS_SAVEGAM        44
#define CONTENTS_BATMARK        45

// attivatori
#define TRIGGER_EXIT            1
#define TRIGGER_ENTRANCE        2
#define TRIGGER_SPEECHMARK      3
#define TRIGGER_TOUCH           4
#define TRIGGER_TELEPORT        6
#define TRIGGER_IMAGEMARK       7

// flag dei pulsanti
#define BUTTONFLAG_TOGGLE       1
#define BUTTONFLAG_SECRET       2

// codici degli oggetti
#define MAPITEM_SMALLBLOODFLASK 1
#define MAPITEM_BLOODFLASK      2
#define MAPITEM_RUNEPYRAMID     3
#define MAPITEM_PURPLESPHERE    4
#define MAPITEM_BLUESPHERE      5
#define MAPITEM_GREENSPHERE     6
#define MAPITEM_GOLDSPHERE      7
#define MAPITEM_REDSPHERE       8
#define MAPITEM_ANCIENTVIAL     9
#define MAPITEM_UNIQUE1         10 // codici di oggetti unici
#define MAPITEM_UNIQUE2         11 // codici di oggetti unici
#define MAPITEM_UNIQUE3         12 // codici di oggetti unici
#define MAPITEM_UNIQUE4         13 // codici di oggetti unici

// codici degli oggetti unici
#define ITEM_SPELL_INSPIREHATE  10
#define ITEM_SPELL_STUN         11
#define ITEM_SPELL_SPIRITWRACK  12
#define ITEM_SPELL_BLOODGOUT    13
#define ITEM_SPELL_BLOODSHOWER  14
#define ITEM_SPELL_SPIRITDEATH  15
#define ITEM_SPELL_LIGHT        16
#define ITEM_SPELL_LIGHTNING    17
#define ITEM_SPELL_REPEL        18
#define ITEM_SPELL_ENERGYBOLT   19
#define ITEM_SPELL_INCAPACITATE 20
#define ITEM_SPELL_CONTROLMIND  21
#define ITEM_SPELL_SANCTUARY    22
#define ITEM_ARTIFACT_FLAY      23
#define ITEM_ARTIFACT_PENTALICH 24
#define ITEM_ARTIFACT_IMPLODE   25
#define ITEM_ARTIFACT_FONT      26
#define ITEM_ARTIFACT_BANK      27
#define ITEM_ARTIFACT_HEART     28
#define ITEM_ARTIFACT_ANTITOXIN 29
#define ITEM_ARTIFACT_SLOWTIME  30
#define ITEM_TOKEN_MOEBIUS      31
#define ITEM_TOKEN_DEJOULE      32
#define ITEM_TOKEN_DOLL         33
#define ITEM_TOKEN_MALEK        34
#define ITEM_TOKEN_AZIMUTH      35
#define ITEM_TOKEN_MORTANIUS    36
#define ITEM_TOKEN_NUPRAPTOR    37
#define ITEM_TOKEN_BANE         38
#define ITEM_TOKEN_SIGNETRING   39
#define ITEM_TOKEN_TIMEDEVICE   40
#define ITEM_TOKEN_ANACROTHE    41
#define ITEM_WEAPON_MACE        43
#define ITEM_WEAPON_AXES        44
#define ITEM_WEAPON_FLAMESWORD  45
#define ITEM_WEAPON_SOULREAVER  46
#define ITEM_ARMOR_BONE         48
#define ITEM_ARMOR_CHAOS        49
#define ITEM_ARMOR_FLESH        50
#define ITEM_ARMOR_WRAITH       51
#define ITEM_FORM_BAT           53
#define ITEM_FORM_WOLF          54
#define ITEM_FORM_DISGUISE      55
#define ITEM_FORM_MIST          56
#define ITEM_ENDING_1           69
#define ITEM_ENDING_2           70

Metodi di compressione

Run Length Encoding (RLE) basato sull'indice

Usato sui dati degli sprite per comprimere le zone nere che normalmente sono trasparenti. Questa tecnica altera il processo di lettura dei byte 0x0 e 0xFF. Se durante la lettura dei dati dell'immagine si ottiene questo byte, si dovrà leggere un byte in più che conterrà il numero di volte che quel byte va ripetuto. Blood Omen RLE è usato solo per valori di 0x00 o 0xFF.

Esempio:

// output di 32 byte col valore 0xFF
0xFF 0x20

Immagini a 4 bit

Codifica 2 pixel per ogni byte con una tavolozza da 256 colori ma con solo 16 colori usati (gli altri pixel sono neri).

Per ogni byte produce 2 byte, in ordine:

  • byte 1: <byte> - (int)(<byte>/16)*16; // <byte> mod 16
  • byte 2: (int)(<byte>/16) // <byte> div 16

Esempio:

 231 manderà in output 2 pixel coi valori:
 byte 1: 7
 byte 2: 14

Variazione del LZ77

Una variazione degli algoritmi di compressione dei dati del LZ77 (LZ1).

Un decodificatore campione è disponibile a The Lost Worlds e nel codice sorgente di Blood Pill.

Ringraziamenti

  • Andrey [Rackot] Grachev - specifiche del file BIG
  • Pavel [VorteX] Timofeyev - file della mappa, sprite
  • Ben Lincoln - decompressore LZ77
  • Specifiche di decodifica JAM di MisterGrim
  • Balder e Zench dai forum di XentaX (www.xentax.com) - IMA ADPCM

Vedere anche



 Blood Wiki in Italian

Personal tools
Namespaces

Variants
Actions
Navigation
Toolbox