JXF proposed file format, v0.1

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.

Data formats

a 32-bit unsigned value;
a 32-bit signed value;
a 16-bit unsigned value.

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.

File structure

The file structure is that of an IFF FORM, ie:
;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:


Chunk types

Room data
Sprite data
Scrolling message for title screen
Title screen
Start position
Text font
User-defined graphics

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 :-)

Format of each chunk


Specifies the character set to use for display.

	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

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.

	LONG	length	;=6
	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.

	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.

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)

	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.

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.

	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

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.

AUTH / (c) / ANNO

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.

Colour substitution

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