Difference between revisions of "Sacred PAK"

From XentaxWiki
Jump to: navigation, search
(new Sacred PAK page. New template used, should be ok)
(re-edit the page, not using the precedent template (buggy for edits))
Line 1: Line 1:
{{GRAFTemplate1|
+
== PAK ==
file_extension=PAK|
+
 
format_type=Archive|
+
* ''' Format Type ''': Archive <br>
endian_order=Little Endian|
+
* ''' [http://en.wikipedia.org/wiki/Endianness Endian Order] ''': Little Endian <br>
date_posted=09:20, 17 May 2006 (EDT)|
+
* ''' Date Posted ''': 02:20, 18 May 2006 (EDT) <br>
format_specifications=
+
 
 +
 
 +
=== Format Specifications ===
 
<tt><b>
 
<tt><b>
byte {3}&nbsp;&nbsp;&nbsp;&nbsp; - Header <br>  
+
byte {3} - Header <br>  
byte {1}&nbsp;&nbsp;&nbsp;&nbsp; - Version <br>  
+
byte {1} - Version <br>  
 
<br>
 
<br>
<font color="blue"> ''' if (header == TEX && version == 3){ ''' </font> <br>
+
<font color="blue"> ''' if (header == TEX && version == 3) ''' </font> <br>
 +
<font color="blue"> ''' { ''' </font> <br>
 
: <font color="purple"> '' // PAK\Texture*.pak '' </font> <br>
 
: <font color="purple"> '' // PAK\Texture*.pak '' </font> <br>
 
: uint32 {4}&nbsp;&nbsp; - Number Of Files <br>  
 
: uint32 {4}&nbsp;&nbsp; - Number Of Files <br>  
Line 29: Line 32:
 
:: byte {X}&nbsp;&nbsp;&nbsp;&nbsp; - File Data <br>  
 
:: byte {X}&nbsp;&nbsp;&nbsp;&nbsp; - File Data <br>  
 
<font color="blue"> ''' } ''' </font> <br>  
 
<font color="blue"> ''' } ''' </font> <br>  
<font color="blue"> ''' else if (header == ISO && version == 3){ ''' </font> <br>  
+
<font color="blue"> ''' else if (header == ISO && version == 3) ''' </font> <br>
 +
<font color="blue"> ''' { ''' </font> <br>
 
: <font color="purple"> '' // PAK\Tiles.pak '' </font> <br>
 
: <font color="purple"> '' // PAK\Tiles.pak '' </font> <br>
 
: uint32 {4}&nbsp;&nbsp; - Number Of Files <br>  
 
: uint32 {4}&nbsp;&nbsp; - Number Of Files <br>  
Line 48: Line 52:
 
:: byte {17}&nbsp;&nbsp;&nbsp; - null <br>  
 
:: byte {17}&nbsp;&nbsp;&nbsp; - null <br>  
 
<font color="blue"> ''' } ''' </font> <br>  
 
<font color="blue"> ''' } ''' </font> <br>  
<font color="blue"> ''' else if (header == CIF && version == 0){ ''' </font> <br>  
+
<font color="blue"> ''' else if (header == CIF && version == 0) ''' </font> <br>
 +
<font color="blue"> ''' { ''' </font> <br>
 
: <font color="purple"> '' // PAK\Creature.pak '' </font> <br>
 
: <font color="purple"> '' // PAK\Creature.pak '' </font> <br>
 
: uint32 {4}&nbsp;&nbsp; - Number Of Files <br>  
 
: uint32 {4}&nbsp;&nbsp; - Number Of Files <br>  
Line 57: Line 62:
 
:: byte {64}&nbsp;&nbsp;&nbsp; - File Data <br>  
 
:: byte {64}&nbsp;&nbsp;&nbsp; - File Data <br>  
 
<font color="blue"> ''' } ''' </font> <br>  
 
<font color="blue"> ''' } ''' </font> <br>  
<font color="blue"> ''' else if (header == WPN && version == 8){ ''' </font> <br>  
+
<font color="blue"> ''' else if (header == WPN && version == 8) ''' </font> <br>
 +
<font color="blue"> ''' { ''' </font> <br>
 
: <font color="purple"> '' // PAK\Weapon.pak '' </font> <br>
 
: <font color="purple"> '' // PAK\Weapon.pak '' </font> <br>
 
: uint32 {4}&nbsp;&nbsp; - Number Of Files <br>  
 
: uint32 {4}&nbsp;&nbsp; - Number Of Files <br>  
Line 65: Line 71:
 
:: byte {322}&nbsp;&nbsp; - File Data <br>  
 
:: byte {322}&nbsp;&nbsp; - File Data <br>  
 
<font color="blue"> ''' } ''' </font> <br>  
 
<font color="blue"> ''' } ''' </font> <br>  
<font color="blue"> ''' else if (header == SND && version == 1){ ''' </font> <br>  
+
<font color="blue"> ''' else if (header == SND && version == 1) ''' </font> <br>
 +
<font color="blue"> ''' { ''' </font> <br>
 
: <font color="purple"> '' // PAK\Sound.pak '' </font> <br>
 
: <font color="purple"> '' // PAK\Sound.pak '' </font> <br>
 
: uint32 {4}&nbsp;&nbsp; - Number Of Files <br>  
 
: uint32 {4}&nbsp;&nbsp; - Number Of Files <br>  
Line 76: Line 83:
 
:: uint32 {4}&nbsp;&nbsp; - Compressed Size <br>  
 
:: uint32 {4}&nbsp;&nbsp; - Compressed Size <br>  
 
<font color="blue"> ''' } ''' </font> <br>  
 
<font color="blue"> ''' } ''' </font> <br>  
<font color="blue"> ''' else if (header == ITM && version == 5){ ''' </font> <br>  
+
<font color="blue"> ''' else if (header == ITM && version == 5) ''' </font> <br>
 +
<font color="blue"> ''' { ''' </font> <br>
 
: <font color="purple"> '' // PAK\Items*.pak '' </font> <br>
 
: <font color="purple"> '' // PAK\Items*.pak '' </font> <br>
 
: uint32 {4}&nbsp;&nbsp; - Number Of Files <br>  
 
: uint32 {4}&nbsp;&nbsp; - Number Of Files <br>  
Line 92: Line 100:
 
:: byte {X}&nbsp;&nbsp;&nbsp;&nbsp; - File Data <br>  
 
:: byte {X}&nbsp;&nbsp;&nbsp;&nbsp; - File Data <br>  
 
<font color="blue"> ''' } ''' </font> <br>  
 
<font color="blue"> ''' } ''' </font> <br>  
<font color="blue"> ''' else if (header == ITM && version == 3){ ''' </font> <br>  
+
<font color="blue"> ''' else if (header == ITM && version == 3) ''' </font> <br>
 +
<font color="blue"> ''' { ''' </font> <br>
 
: <font color="purple"> '' // PAK\Items*.pak ? There's no ITM file(s) with version == 3 in Sacred+'' </font> <br>
 
: <font color="purple"> '' // PAK\Items*.pak ? There's no ITM file(s) with version == 3 in Sacred+'' </font> <br>
 
: uint32 {4}&nbsp;&nbsp; - Number Of Files <br>  
 
: uint32 {4}&nbsp;&nbsp; - Number Of Files <br>  
Line 107: Line 116:
 
:: byte {X}&nbsp;&nbsp;&nbsp;&nbsp; - File Data <br>  
 
:: byte {X}&nbsp;&nbsp;&nbsp;&nbsp; - File Data <br>  
 
<font color="blue"> ''' } ''' </font> <br>  
 
<font color="blue"> ''' } ''' </font> <br>  
<font color="blue"> ''' else if (header == MDL && version == 3){ ''' </font> <br>  
+
<font color="blue"> ''' else if (header == MDL && version == 3) ''' </font> <br>
 +
<font color="blue"> ''' { ''' </font> <br>
 
: <font color="purple"> '' // PAK\Models*.pak '' </font> <br>
 
: <font color="purple"> '' // PAK\Models*.pak '' </font> <br>
 
: uint32 {4} - Number Of Files <br>  
 
: uint32 {4} - Number Of Files <br>  
Line 126: Line 136:
 
:: byte {X} - File Data <br>  
 
:: byte {X} - File Data <br>  
 
<font color="blue"> ''' } ''' </font> <br>  
 
<font color="blue"> ''' } ''' </font> <br>  
<font color="blue"> ''' else if (header == MHP && version == 1){ ''' </font> <br>  
+
<font color="blue"> ''' else if (header == MHP && version == 1) ''' </font> <br>
 +
<font color="blue"> ''' { ''' </font> <br>
 
: <font color="purple"> '' // PAK\Motions.pak '' </font> <br>
 
: <font color="purple"> '' // PAK\Motions.pak '' </font> <br>
 
: <font color="red"> '' Unknown '' </font>
 
: <font color="red"> '' Unknown '' </font>
 
<font color="blue"> ''' } ''' </font> <br>  
 
<font color="blue"> ''' } ''' </font> <br>  
<font color="blue"> ''' else if (header == MIX && version == 0){ ''' </font> <br>  
+
<font color="blue"> ''' else if (header == MIX && version == 0) ''' </font> <br>
 +
<font color="blue"> ''' { ''' </font> <br>
 
: <font color="purple"> '' // PAK\Mixed.pak '' </font> <br>
 
: <font color="purple"> '' // PAK\Mixed.pak '' </font> <br>
 
: uint32 {4}&nbsp;&nbsp; - Number Of Files <br>  
 
: uint32 {4}&nbsp;&nbsp; - Number Of Files <br>  
Line 143: Line 155:
 
:: byte {X}&nbsp;&nbsp;&nbsp;&nbsp; - File Data <br>  
 
:: byte {X}&nbsp;&nbsp;&nbsp;&nbsp; - File Data <br>  
 
<font color="blue"> ''' } ''' </font> <br>  
 
<font color="blue"> ''' } ''' </font> <br>  
<font color="blue"> ''' else if (header == OBJ && version == 1){ ''' </font> <br>  
+
<font color="blue"> ''' else if (header == OBJ && version == 1) ''' </font> <br>
 +
<font color="blue"> ''' { ''' </font> <br>
 
: uint32 {4}&nbsp;&nbsp; - Number Of Files <br>
 
: uint32 {4}&nbsp;&nbsp; - Number Of Files <br>
 
: uint32 {4}&nbsp;&nbsp; - null <br>  
 
: uint32 {4}&nbsp;&nbsp; - null <br>  
Line 155: Line 168:
 
<br>
 
<br>
 
: <font color="blue"> ''' // for each file ''' </font> <br>
 
: <font color="blue"> ''' // for each file ''' </font> <br>
:: <font color="blue"> ''' if (Header Type == 135){ ''' </font> <br>
+
:: <font color="blue"> ''' if (Header Type == 135) ''' </font> <br>
 +
:: <font color="blue"> ''' { ''' </font> <br>
 
::: <font color="purple"> '' // World\Floor.pak '' </font> <br>
 
::: <font color="purple"> '' // World\Floor.pak '' </font> <br>
 
::: uint32 {4}&nbsp;&nbsp; - File Index <font color="purple"> '' Always same as current file entry '' </font> <br>  
 
::: uint32 {4}&nbsp;&nbsp; - File Index <font color="purple"> '' Always same as current file entry '' </font> <br>  
Line 162: Line 176:
 
::: uint32 {4}&nbsp;&nbsp; - Next File Index <font color="purple"> '' Either 0, or File Index + 1 '' </font> <br>  
 
::: uint32 {4}&nbsp;&nbsp; - Next File Index <font color="purple"> '' Either 0, or File Index + 1 '' </font> <br>  
 
::<font color="blue"> ''' } ''' </font> <br>  
 
::<font color="blue"> ''' } ''' </font> <br>  
:: <font color="blue"> ''' else if (Header Type == 134){ ''' </font> <br>
+
:: <font color="blue"> ''' else if (Header Type == 134) ''' </font> <br>
 +
:: <font color="blue"> ''' { ''' </font> <br>
 
::: <font color="purple"> '' // World\Static.pak '' </font> <br>
 
::: <font color="purple"> '' // World\Static.pak '' </font> <br>
 
::: byte {64}&nbsp;&nbsp;&nbsp; - <font color="red"> '' Unknown '' </font> <br>  
 
::: byte {64}&nbsp;&nbsp;&nbsp; - <font color="red"> '' Unknown '' </font> <br>  
 
::<font color="blue"> ''' } ''' </font> <br>  
 
::<font color="blue"> ''' } ''' </font> <br>  
 
<font color="blue"> ''' } ''' </font> <br>  
 
<font color="blue"> ''' } ''' </font> <br>  
<font color="blue"> ''' else if (header == SPF && version == 0){ ''' </font> <br>  
+
<font color="blue"> ''' else if (header == SPF && version == 0) ''' </font> <br>
 +
<font color="blue"> ''' { ''' </font> <br>
 
: <font color="purple"> '' // PAK\sndProfiles.pak '' </font> <br>
 
: <font color="purple"> '' // PAK\sndProfiles.pak '' </font> <br>
 
: uint32 {4}&nbsp;&nbsp; - Number Of Files <br>  
 
: uint32 {4}&nbsp;&nbsp; - Number Of Files <br>  
Line 180: Line 196:
 
:: byte {X}&nbsp;&nbsp;&nbsp;&nbsp; - File Data <br>  
 
:: byte {X}&nbsp;&nbsp;&nbsp;&nbsp; - File Data <br>  
 
<font color="blue"> ''' } ''' </font> <br>  
 
<font color="blue"> ''' } ''' </font> <br>  
<font color="blue"> ''' else if (header == TRG && version == 1){ ''' </font> <br>  
+
<font color="blue"> ''' else if (header == TRG && version == 1) ''' </font> <br>
 +
<font color="blue"> ''' { ''' </font> <br>
 
: <font color="purple"> '' // World\Triggers.pak '' </font> <br>
 
: <font color="purple"> '' // World\Triggers.pak '' </font> <br>
 
: <font color="red"> '' Unknown '' </font>
 
: <font color="red"> '' Unknown '' </font>
 
<font color="blue"> ''' } ''' </font> <br>  
 
<font color="blue"> ''' } ''' </font> <br>  
 
</b></tt>
 
</b></tt>
|
+
<br>
notes=
+
=== Notes and Comments ===
 +
<br>
 
==== File Data Format in TEX (textures) PAK ====
 
==== File Data Format in TEX (textures) PAK ====
 
+
<tt>
<tt><font color="blue"> ''' if (Type ID == 4){ ''' </font> <br>
+
: <font color="blue"> ''' if (Type ID == 4) ''' </font> <br>
: This is a simple zlib-compressed image, as the first character of the File Data indicates (it's an 'x'). The size of this File Data is 'Compressed Size' bytes, the size of the uncompressed file is :<br><br>
+
: <font color="blue"> ''' { ''' </font> <br>
:: <b>Uncompressed File Data Size = (X Image Size) * (Y Image Size) * 2</b><br><br>
+
:: This is a simple zlib-compressed image, as the first character of the File Data indicates (it's an 'x'). The size of this File Data is 'Compressed Size' bytes, the size of the uncompressed file is :<br><br>
: Once uncompressed, you have directly the pixels. Each pixel is an unsigned word (16 bits). It contains Alpha, Red, Green and Blue componant values, and each are 4 bits. A mapping of these bits would give :<br><br>
+
::: <b>Uncompressed File Data Size = (X Image Size) * (Y Image Size) * 2</b><br><br>
:: <b>(highest bit) AAAARRRRGGGGBBBB (lowest bit)</b><br><br>
+
:: Once uncompressed, you have directly the pixels. Each pixel is an unsigned word (16 bits). It contains Alpha, Red, Green and Blue componant values, and each are 4 bits. A mapping of these bits would give :<br><br>
: The encoding of the pixel is Top to Bottom, and for each line is Left to Right. Note : the Alpha channel IS really used (it's not just for padding), check H_KEULE_02_1.TGA from texture00.pak for a good example (16 levels of alpha here)<br>
+
::: <b>(highest bit) AAAARRRRGGGGBBBB (lowest bit)</b><br><br>
<font color="blue"> ''' } ''' </font> <br>
+
:: The encoding of the pixel is Top to Bottom, and for each line is Left to Right. Note : the Alpha channel IS really used (it's not just for padding), check H_KEULE_02_1.TGA from texture00.pak for a good example (16 levels of alpha here)<br>
<font color="blue"> ''' else if (Type ID == 6){ ''' </font> <br>
+
: <font color="blue"> ''' } ''' </font> <br>
: This is a raw 32bpp image (not compressed). Each pixel is an unsigned dword (32 bits). It contains Alpha, Red, Green and Blue componant values, and each are 8 bits. A mapping of these bits would give :<br><br>
+
: <font color="blue"> ''' else if (Type ID == 6) ''' </font> <br>
:: <b>(highest bit) AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB (lowest bit)</b><br><br>
+
: <font color="blue"> ''' { ''' </font> <br>
: The encoding of the pixel is Top to Bottom, and for each line is Left to Right.<br>
+
:: This is a raw 32bpp image (not compressed). Each pixel is an unsigned dword (32 bits). It contains Alpha, Red, Green and Blue componant values, and each are 8 bits. A mapping of these bits would give :<br><br>
<font color="blue"> ''' } ''' </font> <br>
+
::: <b>(highest bit) AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB (lowest bit)</b><br><br>
 +
:: The encoding of the pixel is Top to Bottom, and for each line is Left to Right.<br>
 +
: <font color="blue"> ''' } ''' </font> <br>
 +
</tt>
 
<br>
 
<br>
</tt>
 
 
==== MDL (models) PAK, a note about the SIZE ====
 
==== MDL (models) PAK, a note about the SIZE ====
 
<tt>
 
<tt>
The size may need adjustement, as follow :<br>
+
: The size may need adjustement, as follow :<br>
&nbsp;&nbsp;&nbsp; * If type == 64 (Models), <b>TRUE_SIZE = (SIZE + 1194) / 2</b><br>
+
:: * If type == 64 (Models), <b>TRUE_SIZE = (SIZE + 1194) / 2</b><br>
&nbsp;&nbsp;&nbsp; * For type == 65 (Motions), SIZE don't have to be changed<br>
+
:: * For type == 65 (Motions), SIZE don't have to be changed<br>
 
<br>
 
<br>
1194 is certainly not a random value. It's the size of the very first entry in Models*.PAK files, which is INVALID_MODEL and has a size of 1194.<br>
+
: 1194 is certainly not a random value. It's the size of the very first entry in Models*.PAK files, which is INVALID_MODEL and has a size of 1194.<br>
 
<br>
 
<br>
Two Examples :<br>
+
: Two Examples :<br>
&nbsp;&nbsp;&nbsp; * Models.pak, Entry 10 (RABBIT.GRN) has a type of 64 and a size of 94226. Its true size is in fact (94226 + 1194) / 2 = 47710 bytes. If you compare with the file offsets of this file and the one of the next entry, it's the same result.<br>
+
:: * Models.pak, Entry 10 (RABBIT.GRN) has a type of 64 and a size of 94226. Its true size is in fact (94226 + 1194) / 2 = 47710 bytes. If you compare with the file offsets of this file and the one of the next entry, it's the same result.<br>
 
<br>
 
<br>
&nbsp;&nbsp;&nbsp; * Models.pak, Entry 1035 (RABT_IDLE_BH.GRN) has a type of 65 and a size of 35464. As having type of 65, it's already the correct size. If you compare with the file offsets of this file and the one of the next entry, it's the same result.<br>
+
:: * Models.pak, Entry 1035 (RABT_IDLE_BH.GRN) has a type of 65 and a size of 35464. As having type of 65, it's already the correct size. If you compare with the file offsets of this file and the one of the next entry, it's the same result.<br>
 +
</tt>
 
<br>
 
<br>
</tt>
 
 
==== File Data Format in MDL (models) PAK ====
 
==== File Data Format in MDL (models) PAK ====
 
<tt>
 
<tt>
The format is still unknown, but we have a strong hint : each <b>File Data</b> start with a string of the original filename. For instance we find :<br>
+
: The format is still unknown, but we have a strong hint : each <b>File Data</b> start with a string of the original filename. For instance we find :<br>
&nbsp;&nbsp;&nbsp; * <b>INVALID_MODEL</b><br>
+
:: * <b>INVALID_MODEL</b><br>
&nbsp;&nbsp;&nbsp; * <b>BEAR.GRN</b><br>
+
:: * <b>BEAR.GRN</b><br>
&nbsp;&nbsp;&nbsp; * <b>DARKELVE_HELMET_METAL.GRN</b><br>
+
:: * <b>DARKELVE_HELMET_METAL.GRN</b><br>
&nbsp;&nbsp;&nbsp; * <b>AMAZONE_ARMOUR_LHARNISCH.GRN</b><br>
+
:: * <b>AMAZONE_ARMOUR_LHARNISCH.GRN</b><br>
&nbsp;&nbsp;&nbsp; * <b>DRAGON_SIRITHCAM.GRN</b><br>
+
:: * <b>DRAGON_SIRITHCAM.GRN</b><br>
&nbsp;&nbsp;&nbsp; * <b>GIGANT_SPIDER.GRN</b><br>
+
:: * <b>GIGANT_SPIDER.GRN</b><br>
And <b>GRN</b> is the extention of <i>Granny</i> files, by RAD Game Tools : ([http://www.radgametools.com/#granny])<br>
+
: And <b>GRN</b> is the extention of <i>Granny</i> files, by RAD Game Tools : ([http://www.radgametools.com/#granny])<br>
 +
</tt>
 
<br>
 
<br>
</tt>
 
 
==== Some notes and ideas about World / Tiles relations ====
 
==== Some notes and ideas about World / Tiles relations ====
 
 
<tt>
 
<tt>
For the purpose of only extracting images, PAK\Tiles.pak is useless. It has nothing really more than what the files PAK\Texture*.pak contain. Tiles.pak looks like just a huge collection of tiles reference... That's why it's maybe related to the system the game use to build its world.<br>
+
: For the purpose of only extracting images, PAK\Tiles.pak is useless. It has nothing really more than what the files PAK\Texture*.pak contain. Tiles.pak looks like just a huge collection of tiles reference... That's why it's maybe related to the system the game use to build its world.<br>
 
<br>
 
<br>
Take 1 image from Texture.pak, name ISOxxxx.TGA. It's an image of 256*256 pixels, containing up to 18 tiles of 100*50 pixels each. In Tiles.pak, we have enties for all such tiles of each image, so for an image with 18 tiles we have 1 entry in Texture.pak but 18 entries in Tiles.pak. Let's take an example :<br>
+
: Take 1 image from Texture.pak, name ISOxxxx.TGA. It's an image of 256*256 pixels, containing up to 18 tiles of 100*50 pixels each. In Tiles.pak, we have enties for all such tiles of each image, so for an image with 18 tiles we have 1 entry in Texture.pak but 18 entries in Tiles.pak. Let's take an example :<br>
 
<br>
 
<br>
:In Texture.pak, the entry 1257 is ISO01.TGA. Once extracted, we have an image of 256*256 pixels, that contains 18 tiles (rock, earth and 2 kind of grass).<br>
+
:: In Texture.pak, the entry 1257 is ISO01.TGA. Once extracted, we have an image of 256*256 pixels, that contains 18 tiles (rock, earth and 2 kind of grass).<br>
 
<br>
 
<br>
:In Tiles.pak, the entries 18 to 35 use all the same filename (iso01.tga), but each entry has a diferent Tile position (from 0 to 17).<br>
+
:: In Tiles.pak, the entries 18 to 35 use all the same filename (iso01.tga), but each entry has a diferent Tile position (from 0 to 17).<br>
 
<br>
 
<br>
So here's how it is *maybe* working... When a map tells to the game that a certain tile is to be displayed at coordinate X & Y, it's a uint16 number (16 bits). This is the index entry in Tiles.pak. The game look in Tiles.pak, in the offset table, at the entry. It find an offset and go there. It then extract the block of data for that tile. It learns the Texture.pak index entry, and the Tile position within that image. Now it open Texture.pak, read the appropriate offset and go there, and find the datas of the image. It extract the image (256*256), and use only 1 tile within this image (using the Tile position).<br>
+
: So here's how it is *maybe* working... When a map tells to the game that a certain tile is to be displayed at coordinate X & Y, it's a uint16 number (16 bits). This is the index entry in Tiles.pak. The game look in Tiles.pak, in the offset table, at the entry. It find an offset and go there. It then extract the block of data for that tile. It learns the Texture.pak index entry, and the Tile position within that image. Now it open Texture.pak, read the appropriate offset and go there, and find the datas of the image. It extract the image (256*256), and use only 1 tile within this image (using the Tile position).<br>
 
<br>
 
<br>
In sumary, there are chances that the world map format use only 16bits number for the floors. Using Tiles.pak and Texture.pak one after the other, it knows which tile image to display. By the way, in Sacred+, Tiles.pak contains 47099 entries, Texture.pak 17400, Texture00.pak 64 and Texture01.pak 346 entries.<br>
+
: In sumary, there are chances that the world map format use only 16bits number for the floors. Using Tiles.pak and Texture.pak one after the other, it knows which tile image to display. By the way, in Sacred+, Tiles.pak contains 47099 entries, Texture.pak 17400, Texture00.pak 64 and Texture01.pak 346 entries.<br>
 +
</tt>
 
<br>
 
<br>
</tt>
+
=== MultiEx BMS Script ===
|
+
Not written yet
bms_script=Not written yet|
+
<br>
programs=
+
=== Supported by Programs ===
* [[Game Extractor|Game Extractor]]<br>
 
 
* sacred_tex_extractor [http://paul.siramy.free.fr/_divers/sacred_tex_extractor]<br>
 
* sacred_tex_extractor [http://paul.siramy.free.fr/_divers/sacred_tex_extractor]<br>
|
+
<br>
documentation=None|
+
=== Documentation ===
games=None
+
None
}}
+
<br>
 +
=== Games ===
 +
None

Revision as of 08:20, 18 May 2006

PAK

  • Format Type : Archive
  • Endian Order : Little Endian
  • Date Posted : 02:20, 18 May 2006 (EDT)


Format Specifications

byte {3} - Header
byte {1} - Version

if (header == TEX && version == 3)
{

// PAK\Texture*.pak
uint32 {4}   - Number Of Files
uint32 {4}   - Unknown
byte {244}   - null


// for each file
uint32 {4}   - Type ID
uint32 {4}   - Offset
uint32 {4}   - Compressed Size


// for each file
char {32}    - Filename (null)
uint16 {2}   - X Image Size
uint16 {2}   - Y Image Size
byte {1}     - Type ID
uint32 {4}   - Compressed Size
byte {39}    - null Padding
byte {X}     - File Data

}
else if (header == ISO && version == 3)
{

// PAK\Tiles.pak
uint32 {4}   - Number Of Files
uint32 {4}   - Number Of Files Yep, again
byte {244}   - null


// for each file
uint32 {4}   - Header Type Always == 66
uint32 {4}   - Offset
uint32 {4}   - Header Byte Size Always == 64


// for each file
char {32}    - Filename (null)
uint32 {4}   - Entry Index within the file PAK\Texture.pak (Header == TEX)
uint32 {4}   - Tile position within texture image Range from 0 to 17
byte {6}     - null
byte {1}     - Tag_1 Always == 1
byte {17}    - null

}
else if (header == CIF && version == 0)
{

// PAK\Creature.pak
uint32 {4}   - Number Of Files
uint32 {4}   - Unknown
byte {244}   - null


// for each file
byte {64}    - File Data

}
else if (header == WPN && version == 8)
{

// PAK\Weapon.pak
uint32 {4}   - Number Of Files
uint32 {4}   - Unknown


// for each file
byte {322}   - File Data

}
else if (header == SND && version == 1)
{

// PAK\Sound.pak
uint32 {4}   - Number Of Files
uint32 {4}   - Unknown
byte {244}   - null


// for each file
uint32 {4}   - Type ID
uint32 {4}   - Offset
uint32 {4}   - Compressed Size

}
else if (header == ITM && version == 5)
{

// PAK\Items*.pak
uint32 {4}   - Number Of Files
uint32 {4}   - Unknown
byte {244}   - null


// for each file
uint32 {4}   - Type ID
uint32 {4}   - Offset
uint32 {4}   - Compressed Size


// for each file
byte {55}    - Unknown
char {32}    - Filename (null)
byte {X}     - File Data

}
else if (header == ITM && version == 3)
{

// PAK\Items*.pak ? There's no ITM file(s) with version == 3 in Sacred+
uint32 {4}   - Number Of Files
uint32 {4}   - Unknown
byte {244}   - null


// for each file
uint32 {4}   - Type ID
uint32 {4}   - Offset
uint32 {4}   - Compressed Size


// for each file
char {32}    - Filename (null)
byte {X}     - File Data

}
else if (header == MDL && version == 3)
{

// PAK\Models*.pak
uint32 {4} - Number Of Files
uint32 {4} - File index where to find the first Motion
uint32 {4} - Unknown
uint32 {4} - Tag_4AA Always 0x000004AA
uint32 {4} - Offsets Table Start File Offset where start the Offsets Table
uint32 {4} - Unknown
byte {X}   - null Normally 228 bytes


// (Offsets table) for each file
// First comes all the Models, only after comes all the Motions
uint32 {4} - File Type 64 = Model, 65 = Motion
uint32 {4} - Offset
uint32 {4} - Size Must be corrected, see note below


// for each file
byte {X} - File Data

}
else if (header == MHP && version == 1)
{

// PAK\Motions.pak
Unknown

}
else if (header == MIX && version == 0)
{

// PAK\Mixed.pak
uint32 {4}   - Number Of Files
byte {248}   - null


// for each file
uint32 {4}   - Type ? All set to 99
uint32 {4}   - Offset
uint32 {4}   - Length


// for each file
byte {X}     - File Data

}
else if (header == OBJ && version == 1)
{

uint32 {4}   - Number Of Files
uint32 {4}   - null
uint32 {4}   - null
byte {240}   - padding All set to 0xCC


// for each file
uint32 {4}   - Header Type 135 in World\Floor.pak, 134 in World\Static.pak
uint32 {4}   - Offset
uint32 {4}   - Header Byte Size 16 in World\Floor.pak, 64 in World\Static.pak


// for each file
if (Header Type == 135)
{
// World\Floor.pak
uint32 {4}   - File Index Always same as current file entry
uint32 {4}   - Unknown
uint32 {4}   - Tag_CDCDCDCD Always == 0xCDCDCDCD
uint32 {4}   - Next File Index Either 0, or File Index + 1
}
else if (Header Type == 134)
{
// World\Static.pak
byte {64}    - Unknown
}

}
else if (header == SPF && version == 0)
{

// PAK\sndProfiles.pak
uint32 {4}   - Number Of Files
byte {248}   - null


// for each file
uint32 {4}   - Type ? All set to 35
uint32 {4}   - Offset
uint32 {4}   - Length All set to 184


// for each file
byte {X}     - File Data

}
else if (header == TRG && version == 1)
{

// World\Triggers.pak
Unknown

}

Notes and Comments


File Data Format in TEX (textures) PAK

if (Type ID == 4)
{
This is a simple zlib-compressed image, as the first character of the File Data indicates (it's an 'x'). The size of this File Data is 'Compressed Size' bytes, the size of the uncompressed file is :

Uncompressed File Data Size = (X Image Size) * (Y Image Size) * 2

Once uncompressed, you have directly the pixels. Each pixel is an unsigned word (16 bits). It contains Alpha, Red, Green and Blue componant values, and each are 4 bits. A mapping of these bits would give :

(highest bit) AAAARRRRGGGGBBBB (lowest bit)

The encoding of the pixel is Top to Bottom, and for each line is Left to Right. Note : the Alpha channel IS really used (it's not just for padding), check H_KEULE_02_1.TGA from texture00.pak for a good example (16 levels of alpha here)
}
else if (Type ID == 6)
{
This is a raw 32bpp image (not compressed). Each pixel is an unsigned dword (32 bits). It contains Alpha, Red, Green and Blue componant values, and each are 8 bits. A mapping of these bits would give :

(highest bit) AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB (lowest bit)

The encoding of the pixel is Top to Bottom, and for each line is Left to Right.
}


MDL (models) PAK, a note about the SIZE

The size may need adjustement, as follow :
* If type == 64 (Models), TRUE_SIZE = (SIZE + 1194) / 2
* For type == 65 (Motions), SIZE don't have to be changed


1194 is certainly not a random value. It's the size of the very first entry in Models*.PAK files, which is INVALID_MODEL and has a size of 1194.


Two Examples :
* Models.pak, Entry 10 (RABBIT.GRN) has a type of 64 and a size of 94226. Its true size is in fact (94226 + 1194) / 2 = 47710 bytes. If you compare with the file offsets of this file and the one of the next entry, it's the same result.


* Models.pak, Entry 1035 (RABT_IDLE_BH.GRN) has a type of 65 and a size of 35464. As having type of 65, it's already the correct size. If you compare with the file offsets of this file and the one of the next entry, it's the same result.


File Data Format in MDL (models) PAK

The format is still unknown, but we have a strong hint : each File Data start with a string of the original filename. For instance we find :
* INVALID_MODEL
* BEAR.GRN
* DARKELVE_HELMET_METAL.GRN
* AMAZONE_ARMOUR_LHARNISCH.GRN
* DRAGON_SIRITHCAM.GRN
* GIGANT_SPIDER.GRN
And GRN is the extention of Granny files, by RAD Game Tools : ([1])


Some notes and ideas about World / Tiles relations

For the purpose of only extracting images, PAK\Tiles.pak is useless. It has nothing really more than what the files PAK\Texture*.pak contain. Tiles.pak looks like just a huge collection of tiles reference... That's why it's maybe related to the system the game use to build its world.


Take 1 image from Texture.pak, name ISOxxxx.TGA. It's an image of 256*256 pixels, containing up to 18 tiles of 100*50 pixels each. In Tiles.pak, we have enties for all such tiles of each image, so for an image with 18 tiles we have 1 entry in Texture.pak but 18 entries in Tiles.pak. Let's take an example :


In Texture.pak, the entry 1257 is ISO01.TGA. Once extracted, we have an image of 256*256 pixels, that contains 18 tiles (rock, earth and 2 kind of grass).


In Tiles.pak, the entries 18 to 35 use all the same filename (iso01.tga), but each entry has a diferent Tile position (from 0 to 17).


So here's how it is *maybe* working... When a map tells to the game that a certain tile is to be displayed at coordinate X & Y, it's a uint16 number (16 bits). This is the index entry in Tiles.pak. The game look in Tiles.pak, in the offset table, at the entry. It find an offset and go there. It then extract the block of data for that tile. It learns the Texture.pak index entry, and the Tile position within that image. Now it open Texture.pak, read the appropriate offset and go there, and find the datas of the image. It extract the image (256*256), and use only 1 tile within this image (using the Tile position).


In sumary, there are chances that the world map format use only 16bits number for the floors. Using Tiles.pak and Texture.pak one after the other, it knows which tile image to display. By the way, in Sacred+, Tiles.pak contains 47099 entries, Texture.pak 17400, Texture00.pak 64 and Texture01.pak 346 entries.


MultiEx BMS Script

Not written yet

Supported by Programs

  • sacred_tex_extractor [2]


Documentation

None

Games

None