Sacred: Difference between revisions

From XentaxWiki
Jump to navigation Jump to search
imported>Paul Siramy
(PAK, type MDL : differentiate Models and Motions, and minor edit)
imported>Ikskoks
(Redirected page to Sacred PAK)
 
(23 intermediate revisions by 2 users not shown)
Line 1: Line 1:
* [[GRAFs|Return to the list of games]]
#REDIRECT [[Sacred PAK]]
 
Choose archive extension:
 
== PAK ==
 
* ''' Format Type ''':    Archive <br>
* ''' [http://en.wikipedia.org/wiki/Endianness Endian Order] ''': Little Endian <br>
 
 
=== Format Specifications ===
 
<tt><b>
byte {3}&nbsp;&nbsp;&nbsp;&nbsp; - Header <br>
byte {1}&nbsp;&nbsp;&nbsp;&nbsp; - Version <br>
<br>
<font color="blue"> ''' if (header == TEX && version == 3){ ''' </font> <br>
: <font color="purple"> '' // PAK\Texture*.pak '' </font> <br>
: uint32 {4}&nbsp;&nbsp; - Number Of Files <br>
: uint32 {4}&nbsp;&nbsp; - <font color="red"> '' Unknown '' </font> <br>
: byte {244}&nbsp;&nbsp; - null <br>
<br>
: <font color="blue"> ''' // for each file ''' </font> <br>
:: uint32 {4}&nbsp;&nbsp; - Type ID <br>
:: uint32 {4}&nbsp;&nbsp; - Offset <br>
:: uint32 {4}&nbsp;&nbsp; - Compressed Size <br>
<br>
: <font color="blue"> ''' // for each file ''' </font> <br>
:: char {32}&nbsp;&nbsp;&nbsp; - Filename <font color="purple">(null)</font> <br>
:: uint16 {2}&nbsp;&nbsp; - X Image Size <br>
:: uint16 {2}&nbsp;&nbsp; - Y Image Size <br>
:: byte {1}&nbsp;&nbsp;&nbsp;&nbsp; - Type ID <br>
:: uint32 {4}&nbsp;&nbsp; - Compressed Size <br>
:: byte {39}&nbsp;&nbsp;&nbsp; - null Padding <br>
:: byte {X}&nbsp;&nbsp;&nbsp;&nbsp; - File Data <br>
<font color="blue"> ''' } ''' </font> <br>
<font color="blue"> ''' else if (header == ISO && version == 3){ ''' </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 <font color="purple"> '' Yep, again '' </font> <br>
: byte {244}&nbsp;&nbsp; - null <br>
<br>
: <font color="blue"> ''' // for each file ''' </font> <br>
:: uint32 {4}&nbsp;&nbsp; - Header Type <font color="purple"> '' Always == 66 '' </font> <br>
:: uint32 {4}&nbsp;&nbsp; - Offset <br>
:: uint32 {4}&nbsp;&nbsp; - Header Byte Size <font color="purple"> '' Always == 64 '' </font> <br>
<br>
: <font color="blue"> ''' // for each file ''' </font> <br>
:: char {32}&nbsp;&nbsp;&nbsp; - Filename <font color="purple">(null)</font> <br>
:: uint32 {4}&nbsp;&nbsp; - Entry Index within the file PAK\Texture.pak (Header == TEX) <br>
:: uint32 {4}&nbsp;&nbsp; - Tile position within texture image <font color="purple"> '' Range from 0 to 17 '' </font> <br>
:: byte {6}&nbsp;&nbsp;&nbsp;&nbsp; - null <br>
:: byte {1}&nbsp;&nbsp;&nbsp;&nbsp; - Tag_1 <font color="purple"> '' Always == 1 '' </font> <br>
:: byte {17}&nbsp;&nbsp;&nbsp; - null <br>
<font color="blue"> ''' } ''' </font> <br>
<font color="blue"> ''' else if (header == CIF && version == 0){ ''' </font> <br>
: <font color="purple"> '' // PAK\Creature.pak '' </font> <br>
: uint32 {4}&nbsp;&nbsp; - Number Of Files <br>
: uint32 {4}&nbsp;&nbsp; - <font color="red"> '' Unknown '' </font> <br>
: byte {244}&nbsp;&nbsp; - null <br>
<br>
: <font color="blue"> ''' // for each file ''' </font> <br>
:: byte {64}&nbsp;&nbsp;&nbsp; - File Data <br>
<font color="blue"> ''' } ''' </font> <br>
<font color="blue"> ''' else if (header == WPN && version == 8){ ''' </font> <br>
: <font color="purple"> '' // PAK\Weapon.pak '' </font> <br>
: uint32 {4}&nbsp;&nbsp; - Number Of Files <br>
: uint32 {4}&nbsp;&nbsp; - <font color="red"> '' Unknown '' </font> <br>
<br>
: <font color="blue"> ''' // for each file ''' </font> <br>
:: byte {322}&nbsp;&nbsp; - File Data <br>
<font color="blue"> ''' } ''' </font> <br>
<font color="blue"> ''' else if (header == SND && version == 1){ ''' </font> <br>
: <font color="purple"> '' // PAK\Sound.pak '' </font> <br>
: uint32 {4}&nbsp;&nbsp; - Number Of Files <br>
: uint32 {4}&nbsp;&nbsp; - <font color="red"> '' Unknown '' </font> <br>
: byte {244}&nbsp;&nbsp; - null <br>
<br>
: <font color="blue"> ''' // for each file ''' </font> <br>
:: uint32 {4}&nbsp;&nbsp; - Type ID <br>
:: uint32 {4}&nbsp;&nbsp; - Offset <br>
:: uint32 {4}&nbsp;&nbsp; - Compressed Size <br>
<font color="blue"> ''' } ''' </font> <br>
<font color="blue"> ''' else if (header == ITM && version == 5){ ''' </font> <br>
: <font color="purple"> '' // PAK\Items*.pak '' </font> <br>
: uint32 {4}&nbsp;&nbsp; - Number Of Files <br>
: uint32 {4}&nbsp;&nbsp; - <font color="red"> '' Unknown '' </font> <br>
: byte {244}&nbsp;&nbsp; - null <br>
<br>
: <font color="blue"> ''' // for each file ''' </font> <br>
:: uint32 {4}&nbsp;&nbsp; - Type ID <br>
:: uint32 {4}&nbsp;&nbsp; - Offset <br>
:: uint32 {4}&nbsp;&nbsp; - Compressed Size <br>
<br>
: <font color="blue"> ''' // for each file ''' </font> <br>
:: byte {56}&nbsp;&nbsp;&nbsp; - <font color="red"> '' Unknown '' </font> <br>
:: char {32}&nbsp;&nbsp;&nbsp; - Filename <font color="purple">(null)</font> <br>
:: byte {X}&nbsp;&nbsp;&nbsp;&nbsp; - File Data <br>
<font color="blue"> ''' } ''' </font> <br>
<font color="blue"> ''' else if (header == ITM && version == 3){ ''' </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; - <font color="red"> '' Unknown '' </font> <br>
: byte {244}&nbsp;&nbsp; - null <br>
<br>
: <font color="blue"> ''' // for each file ''' </font> <br>
:: uint32 {4}&nbsp;&nbsp; - Type ID <br>
:: uint32 {4}&nbsp;&nbsp; - Offset <br>
:: uint32 {4}&nbsp;&nbsp; - Compressed Size <br>
<br>
: <font color="blue"> ''' // for each file ''' </font> <br>
:: char {32}&nbsp;&nbsp;&nbsp; - Filename <font color="purple">(null)</font> <br>
:: byte {X}&nbsp;&nbsp;&nbsp;&nbsp; - File Data <br>
<font color="blue"> ''' } ''' </font> <br>
<font color="blue"> ''' else if (header == MDL && version == 3){ ''' </font> <br>
: <font color="purple"> '' // PAK\Models*.pak '' </font> <br>
: uint32 {4} - Number Of Files <br>
: uint32 {4} - File index where to find the first Motion <br>
: uint32 {4} - <font color="red"> '' Unknown '' </font> <br>
: uint32 {4} - Tag_4AA <font color="purple"> '' Always 0x000004AA '' </font> <br>
: uint32 {4} - Offsets Table Start <font color="purple"> '' File Offset where start the Offsets Table '' </font> <br>
: uint32 {4} - <font color="red"> '' Unknown '' </font> <br>
: byte {X}&nbsp;&nbsp; - null <font color="purple"> '' Normally 228 bytes '' </font> <br>
<br>
: <font color="blue"> ''' // (Offsets table) for each file ''' </font> <br>
: <font color="purple"> '' // First comes all the Models, only after comes all the Motions '' </font> <br>
:: uint32 {4} - File Type <font color="purple"> '' 64 = Model, 65 = Motion '' </font><br>
:: uint32 {4} - Offset <br>
:: uint32 {4} - Size <br>
<br>
: <font color="blue"> ''' // for each file ''' </font> <br>
:: byte {X} - File Data <br>
<font color="blue"> ''' } ''' </font> <br>
<font color="blue"> ''' else if (header == MHP && version == 1){ ''' </font> <br>
: <font color="purple"> '' // PAK\Motions.pak '' </font> <br>
: <font color="red"> '' Unknown '' </font>
<font color="blue"> ''' } ''' </font> <br>
<font color="blue"> ''' else if (header == MIX && version == 0){ ''' </font> <br>
: <font color="purple"> '' // PAK\Mixed.pak '' </font> <br>
: <font color="red"> '' Unknown '' </font>
<font color="blue"> ''' } ''' </font> <br>
<font color="blue"> ''' else if (header == OBJ && version == 1){ ''' </font> <br>
: uint32 {4}&nbsp;&nbsp; - Number Of Files <br>
: uint32 {4}&nbsp;&nbsp; - null <br>
: uint32 {4}&nbsp;&nbsp; - null <br>
: byte {240}&nbsp;&nbsp; - padding <font color="purple"> '' All set to 0xCC '' </font> <br>
<br>
: <font color="blue"> ''' // for each file ''' </font> <br>
:: uint32 {4}&nbsp;&nbsp; - Header Type <font color="purple"> '' 135 in World\Floor.pak, 134 in World\Static.pak '' </font> <br>
:: uint32 {4}&nbsp;&nbsp; - Offset <br>
:: uint32 {4}&nbsp;&nbsp; - Header Byte Size <font color="purple"> '' 16 in World\Floor.pak, 64 in World\Static.pak'' </font> <br>
<br>
: <font color="blue"> ''' // for each file ''' </font> <br>
:: <font color="blue"> ''' if (Header Type == 135){ ''' </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; - <font color="red"> '' Unknown '' </font> <br>
::: uint32 {4}&nbsp;&nbsp; - Tag_CDCDCDCD <font color="purple"> '' Always == 0xCDCDCDCD '' </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"> ''' else if (Header Type == 134){ ''' </font> <br>
::: <font color="purple"> '' // World\Static.pak '' </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"> ''' else if (header == SPF && version == 1){ ''' </font> <br>
: <font color="purple"> '' // PAK\sndProfiles.pak '' </font> <br>
: <font color="red"> '' Unknown '' </font>
<font color="blue"> ''' } ''' </font> <br>
<font color="blue"> ''' else if (header == TRG && version == 1){ ''' </font> <br>
: <font color="purple"> '' // World\Triggers.pak '' </font> <br>
: <font color="red"> '' Unknown '' </font>
<font color="blue"> ''' } ''' </font> <br>
</b></tt>
<br>
 
=== File Data Format in TEX (textures) PAK ===
 
<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>
:: <b>Uncompressed File Data Size = (X Image Size) * (Y Image Size) * 2</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>
:: <b>(highest bit) AAAARRRRGGGGBBBB (lowest bit)</b><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>
<font color="blue"> ''' } ''' </font> <br>
<font color="blue"> ''' else if (Type ID == 6){ ''' </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>
:: <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>
<br>
 
=== File Data Format in MDL (models) PAK ===
 
<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 found :<br>
&nbsp;&nbsp;&nbsp; * <b>INVALID_MODEL</b><br>
&nbsp;&nbsp;&nbsp; * <b>BEAR.GRN</b><br>
&nbsp;&nbsp;&nbsp; * <b>DARKELVE_HELMET_METAL.GRN</b><br>
&nbsp;&nbsp;&nbsp; * <b>AMAZONE_ARMOUR_LHARNISCH.GRN</b><br>
&nbsp;&nbsp;&nbsp; * <b>DRAGON_SIRITHCAM.GRN</b><br>
&nbsp;&nbsp;&nbsp; * <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>
<br>
</tt>
 
=== Some notes and ideas about World / Tiles relations ===
 
<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>
<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>
: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>
: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>
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>
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>
<br>
</tt>
 
=== MultiEx BMS Script ===
 
Not written yet<br><br>
 
=== Compatible Programs ===
 
* [[Game Extractor|Game Extractor]]<br>

Latest revision as of 19:19, 25 July 2021

Redirect to: