PWT File Specification
This is the specification for the exported case file that is used by the player
to run user made cases. The file is broken up into chunks, which are basically
groups of data that make up certain elements, like characters, backgrounds, etc.
Each chunk contains several data types, which are discussed in the coming sections.
The PWT file format is actually really simple. It may resemble the Quake 3 model and map formats for
those of you who have worked with them. Regardless, this is the basic structure of the file:
Header |
First Chunk |
Second Chunk |
... |
Chunks will be discussed in the next section, but before we go that far, it's necessary to discuss a few
things. First, you'll notice that the amount of chunks in the file is variable. This allows for the file
to be extended without breaking compatability with older players and editors. New chunks that may be
added in future versions will always have their own offset registered in the header, and so there is no
need to worry about having to read the file in a different order. Furthermore, if you are going to try to
load this file, make sure you don't do it in a linear fashion. Instead, use the offsets in the header to
skip to the different chunks.
Each chunk is made up of data that is specific to a certain element of a case. For example, the chunk that
stores data about characters will include names, descriptions, etc. If you don't grasp this concept, think of
chunks as building blocks, where each one adds something to the case.
Before you try to read the separate chunks, you need to know the different data types that are present. Here is
a basic rundown of the data types, their sizes, and their uses:
Type | Size (bytes) | Uses |
int | 4 | Stores various integer amounts |
uchar | 4 | UNICODE character, used primarily in strings |
bool | 1 | A Boolean value; holds true or false |
string | (see below) |
image | (see below) |
String
A string is a series of uchars, and it can contain any amount of characters. Strings are saved in
a specific format, where each string begins with an int that defines the length. Afterwards, that amount
of uchar values exist. Take the string 'Hello World!' for example. This is how it looks in the file:
int | uchar | uchar | uchar | uchar | uchar | uchar | uchar | uchar | uchar | uchar | uchar | uchar |
11 | H | e | l | l | o | | W | o | r | l | d | ! |
Image
Images are stored as highly compressed PNGs. Each image has a size saved with it, that determines the size of the
PNG data buffer. Loading the actual PNG data is up to you.
Data Type | Value | Description |
int | length | The size of the image buffer |
char | length | The actual image data buffer |
The header stores the file's magic number and version, along with offsets into the chunk sections. This is
the format of the header:
Data Type | Value | Description |
int | ident | Magic number, should always be equal to 'PWT' |
int | version | The file's revision number |
int | overviewOffset | Offset into overview |
int | overridesOffset | Offset into overrides |
int | charOffset | Offset into characters |
int | imgOffset | Offset into images |
int | bgOffset | Offset into backgrounds |
int | evidenceOffset | Offset into evidence |
int | locationOffset | Offset into locations |
int | audioOffset | Offset into audio |
int | testimonyOffset | Offset into testimonies |
int | blockOffset | Offset into text blocks |
This section describes the chunks that are present in the file.
The Overview chunk provides basic data about the case itself. Its format is as follows.
Data Type | Value | Description |
string | name | The name of the case |
string | author | The author's name |
int | lawSys | The law system, describing amount of trial days |
Overrides let the user customize otherwise internal elements of the player. This includes the transparency
of text box, the title screen, and other things.
Data Type | Value | Description |
int | tbAlpha | The text box transparency value |
string | titleScreen | ID of the image to use for the title screen |
string | initialBlock | ID of the block where to start parsing the script |
The Characters chunk holds data about all of the characters present in the case. This does not include the
characters that are included in the player's resource file.
Data Type | Value | Description |
int | count | The amount of characters |
string | internalName | The internal name |
string | displayName | The display name |
int | gender | Gender of the character |
string | caption | Text to display in Court Record in the green box |
string | description | Text to display in Court Record below the profile |
string | spriteName | File name of sprite, or "null" if none |
bool | hasTextBoxTag | Whether or not this character has a tag for the text box |
image | textBoxTag | If hasTextBoxTag is TRUE, then this is the text box tag image |
bool | headshot | Whether or not this character has a profile image |
image | profileImg | If headshot is TRUE, then this is the image for the Court Record profiles |
image | sProfileImg | If headshot is TRUE, then this is the scaled profile image |
The only things that are important to note are the hasTextBoxTag and headshot Booleans. If, and ONLY if they are TRUE,
should you read the following images. So if hasTextBoxTag is FALSE, you should proceed right to the headshot value,
bypassing the image altogether.
The Images chunk stores miscellaneous images and other pictures that are used in specific areas of the case. Such
include the images used for the characters positioned in the courtroom overview scene. Also, these images can be
used for the set_temp_image trigger, among others.
Data Type | Value | Description |
int | count | Amount of images |
string | id | Internal ID for this image |
image | texture | The actual image |
This chunk stores the data about the backgrounds used for other locations.
Data Type | Value | Description |
int | count | Amount of backgrounds |
string | id | ID of the background |
int | bgType | How many screens does the background span |
image | texture | The actual image for the background |
All of the case evidence is stored in this chunk.
Data Type | Value | Description |
int | count | Amount of evidence |
string | id | ID of this evidence |
string | name | Display name |
string | caption | Short text to describe the evidence |
string | description | Text displayed below entry in Court Record |
string | checkID | ID of image that can be checked, or "null" if none |
image | texture | The actual image of the evidence |
image | sTexture | Scaled image used in Court Record |
The checkID contains the ID of an image that the user can examine when he or she clicks the Check button
in the Court Record. Of course, most evidence won't have such an image, and so this value may be "null" in
that case.
All of the user made locations are stored in this chunk. Each location has a set of examinable hotspots, along
with variable states. These are all described in this section. First, here is the format of this chunk:
Data Type | Value | Description |
int | count | Amount of locations |
string | id | Internal ID |
string | name | Display name |
int | hcount | Amount of hotspots |
Hotspot | - | (see relevant info below) |
int | scount | Amount of location states |
State | - | (see relevant info below) |
Here is the format of the hotspots, known in the code as the Hotspot struct:
Data Type | Value | Description |
int | x | Top-left x coordinate of the bounding box |
int | y | Top-left y coordinate of the bounding box |
int | w | Width of bounding box |
int | h | Height of bounding box |
string | target | ID of the target text block to execute |
Finally, here is the format for a location state. Note that in the code, the states are stored as
a key:value map of the state ID to the background ID for that state.
Data Type | Value | Description |
string | stateID | ID of this state |
string | bgID | ID of background for this state |
Although none of the audio, apart from sound effects, is stored in memory when the player loads,
this chunk specifies user included sound effects and music for this case. All audio file paths are
relevant to where the actual *.pwt case file is.
Data Type | Value | Description |
int | count | Amount of audio samples |
string | id | Internal ID |
string | filename | Path to the sample, relative to case root path |
This chunk stores all the data about the testimonies present in the case. Testimonies have some general
data, along with the actual contents of the testimony. They are comprised of pieces, and each piece can
have evidence presented, be pressed, and be hidden.
Data Type | Value | Description |
int | count | Amount of testimonies |
string | id | The internal ID |
string | displayName | Display name of testimony |
string | speaker | ID of speaking character |
string | nextBlock | ID of block to follow once testimony is spoken |
string | followLocation | ID of location to go once testimony is spoken |
string | xExamineEndBlock | ID of block to follow once user completes cross examination |
int | tPieceCount | Amount of pieces |
TestimonyPiece | - | (see relevant info below) |
Finally, here is the format of testimony pieces, known in the code as the TestimonyPiece struct:
Data Type | Value | Description |
string | text | The actual text content of the testimony piece |
string | presentID | ID of evidence that can be presented, or "null" for none |
string | presentBlock | ID of block to follow if correct evidence is presented, or "null" for none |
string | pressBlock | ID of block to follow if witness is pressed |
bool | hidden | Whether or not this piece is initially hidden |
Finally, this is the meat and bones of the case file. The text blocks are stored here, along with IDs to reference them
from within the script.
Data Type | Value | Description |
string | id | ID of the block |
string | text | Actual text contents of this block |
Hosted on Sourceforge.net. All Phoenix Wright trademarks and other property are
copyright Capcom.
|
|