JXF (Jetset eXchange Format) is a common file format intended to store JetSet Willy game data.
JXF was created because there are several variants of the JetSet engine (JSW48, JSW2, JSW128, JSW-PC, JSW2-Unix, ...). Each of these implements its own set of extensions to JSW48, and there is no portable way of storing the data separately from the engine. The nearest approach to a common data format has been a memory dump of JSW48 data (which can be converted into some of the other formats), but this does not allow the storage of any extra information required by enhanced engines.
JXF is an IFF FORM type. The full IFF specification is online at http://www.cica.indiana.edu/graphics/image_specs/ilbm.format.txt , but it is not necessary to go into the level of detail supplied therein.
In common with IFF practice, DWORDS, WORDS and LONGS are stored in network byte order (big-endian).
All screen coordinates are given in pixels. The standard JSW playing area is 256 pixels wide by 128 pixels high.
Some chunks can have multiple formats (eg: the TITL chunk). The format ID used is:
More format IDs could of course be added if several higher levels of compatibility were needed.
; ;IFF header ; DB 'FORM' ;IFF file LONG n ;FORM length (file length - 8) DB 'JXF ' ;FORM type ; ;Chunks, each formed: ; DB 'id ' ;Form ID, 4 bytes LONG l ;Length of data to follow ... ;Data. If it has an odd length, it is packed to a word ;boundary with a 0 byte (not included in the length).
It is allowable for a JXF file to have a +3DOS header before the IFF header. The header is only checked for its +3DOS signature and checksum, and if present is skipped.
If a JXF file is written with a +3DOS header, it is recommended that the 8-byte "BASIC header" is set to the ASCII string:
DB 'IFF FORM'
The following types may also appear in any IFF FORM:
No chunk type is compulsory, though if you don't include any chunks of any type, the file won't be up to much :-)
Specifies the character set to use for display.
DB 'FONT' LONG length WORD id ;Font ID. 0 => use for all text display WORD type ;0 => no data follow, length=4 ;1 => Spectrum-format, 768 bytes mono bitmap ;2 => PNG image, 8 pixels wide x 768 pixels high <data>
The FONT chunk is optional; if it is absent, the Spectrum ROM font is assumed. There is no reason ever to write a FONT chunk of type 0, because JSW48 uses the ROM font. Multiple FONT chunks may be included, provided their id fields are different.
Currently, FONT id 0 is defined as the font to use for all text display. Other id's have no defined meaning.
Specifies Willy's start position.
DB 'SPOS' LONG length ;=6 WORD Room_ID WORD X_Position WORD Y_Position
There must be at most one SPOS block per file. If it is omitted, the default start position is assumed. For JSW48, this is Room = 33; Y = 104; X = 180.
Defines teleporters.
DB 'TELE' LONG length WORD Room_from ;Repeated (length/12) times... WORD X_from WORD Y_from WORD Room_to WORD X_to WORD Y_to
There must be at most one TELE block in a JXF file. There is no need to include it if a game does not use teleporters.
The title screen graphic.
DB 'TITL' ;Title screen, at most one of each type per file LONG length WORD type ;0 => JSW48. 512 bytes of attributes. ;1 => JSW128. 4096 bytes of data and 1536 ; of attributes (3 x 512) ;2 => PNG-format graphic. <data>
There can be at most one title screen of each type in the file.
JSW-PC has a flashing title screen. This is currently not supported. Possibly multiple TITL blocks representing multiple frames are needed. It also has an animation on the title screen, but that isn't really something portable enough to go in this spec.
The scrolling message on the title screen. The first 32 characters are those shown when the game starts.
DB 'SCRL' ;Scrolling message, one per file LONG length DB text ;ASCII, not zero-terminated
There can be at most one SCRL block in the file.
Defines a sprite page (a 128x16 bitmap containing 8 sprite frames)
DB 'SPRI' LONG length WORD id ;Special IDs: 9Dh for Willy ; 9Ch for barrel, foot and Maria ;all others arbitrary WORD type ;0 => JSW48: 128x16 two-colour. ;1 => JSW128: as JSW48 ;2 => 128x16 PNG file. <data>
There can be as many sprite page chunks as you like, providing that no two have the same type and ID.
Some JSW engines may support colour substitution (ie: one sprite bitmap can be used for the same sprite in multiple colours). See the section below on colour substitution for details of how this is stored in a .JXF file.
The transparency support in PNG files should be used for sprite masks. Therefore, when converting a Spectrum graphic to PNG, the black bits become transparent.
A list of graphics used for drawing rooms.
DB 'UDGS' LONG length WORD type ;UDG record type. 0 => attr + 8 bytes data ; 1 => as 0 ; 2 => (count*8)x8 PNG file WORD count ;Number of UDGs stored <data>
There can be at most one UDGS chunk of each type per file. The type 0/1 record stores data as one Spectrum attribute byte, followed by 8 bytes of bitmap, repeated <count> times.
DB 'ROOM' ;Room. As many as you want per file LONG length +8 WORD id ;0-63 for JSW48 compatibility ;0-255 for JSW128 compatibility +10 DS 512 ;Room data, 1 byte / cell ; 0 = air ; 1 = water ; 2 = earth ; 3 = fire ; 4 = ramp going northeast ("/") ; 5 = conveyor going left ; 6 = object ; 7 = ramp going northwest ("\") ; 8 = conveyor going right ; ; Types above 8 reserved for future expansion ; +522 DS 32 ;Room name +554 WORD u,d,l,r ;Room IDs of exits +562 DWORD border ;Border colour. Bits 0-2 give Spectrum ;colour; top 3 bytes give R,G,B respectively. +566 WORD flags ;Special flags. Bit 0 set to override Willy's ;sprite. Bit 1 set to enable Superjump. +568 WORD sprite ;Willy's sprite, if overridden; else 0. +570 WORD nudgs ;Number of UDG IDs +572 WORD ud0 ;UDG for Air WORD ud1 ;UDG for Water ... WORD udn ;UDG for last type WORD nguards ;No. of guardian IDs WORD g0,gx0,gf0 ;Guardian 0; its X parameter; its start frame WORD g1,gx1,gf1 ;Guardian 1; its X parameter; its start frame ... WORD gn,gxn,gfn ;Last guardian There can be as many rooms as you want.
GUAR defines the list of guardians in the game.
DB 'GUAR' ;Guardian table, one per file LONG length ;20 * no. of guardians WORD type ;Guardian type... ; 1 = L/R ; 2 = U/D ; 3 = Rope ; 4 = Arrow ; 5 = Diagonal NW/SE ; 6 = Diagonal NE/SW ; Types 0 and 7-15 must not be used ;all others reserved for the future WORD options ;Bit 0 set for "fast" animation ;Bit 1 set for L->R, else R->L ;Bits 2-15 reserved. DWORD colour ;Bits 0-2 give Spectrum colour. ;Bit 3 set for Spectrum bright. ;Bit 4 set to cycle colours. ;Bits 5-7 reserved ;Top 3 bytes give R,G,B respectively. WORD mask ;Animation "&" mask. WORD height ;Y coordinate (for all except rope). WORD speed ;Movement speed. WORD sprite ;Sprite ID. WORD bound,bound ;Bounds for movement. (repeated as many times as necessary)
There can be at most one GUAR table per file. For JSW2 compatibility, arrows can have sprites. An arrow bitmap should also be included in the first "bound" field, for JSW48 compatibility.
These three chunks are all formed:
DB 'id ' ;'AUTH', '(c) ' or 'ANNO' LONG length DB 7-bit ASCII text (no zero terminator) AUTH holds the author's name or username. (c) holds a copyright message (date and holder, no (c) symbol) ANNO holds any textual annotation that the user or writing program sees fit to include.
There should be at most one AUTH or (c) chunk per file.
If a colour in a sprite has Red=Green=Blue (ie, it is white or grey) then
the colour from the guardian table may be substituted in instead. For instance,
if the colour in the sprite is Red=128, Green=128, Blue=128 and the colour
in the guardian table is Red=0 Green=192 Blue=255, we end up with:
Red = (128 * 0) / 255 = 0
Green = (128 * 192) / 255 = 96
Blue = (128 * 255) / 255 = 128