GTA 1 FXT Format

Back to main page

Description

The FXT format contains language specific texts of the game in a slightly encrypted manner.

FXT↔TXT Converter

This converter tool allows you to convert FXT files to TXT and vice versa.
It fully supports all languages, including Japanese, and corrects many issues that other converters handle incorrectly.
It has been thoroughly tested with all official FXT files, and converting from TXT back to FXT reproduces the original file exactly, bit for bit.
For this reason, this converter is as accurate and reliable as possible.

Download for Windows

Source code for Embarcadero Delphi

Usage: Just drag'n'drop an FXT or TXT file into the EXE. It will then create an converted FXT/TXT file in the same directory. Alternatively, use it via command line (cmd.exe).


Technical notes about the FXT Format

Decrypt process (FXT to TXT)

The file is decrypted byte-by-byte, with this code system:

8 Byte Header mask

The first 8 bytes in the FXT file are masked. The decoding is performed as follows:

For i = 0..7:
Unmasked[i] := (Input[i] + 256 - K[i]) mod 256

(Note: The addition of 256 ensures consistent non-negative results across programming languages where the modulo operation on negative values differs.)

The sequence K[i] is generated by a linear congruential generator (LCG):

K[0] := 100
K[i+1] := (2 * K[i] - 1) mod 256

Hence:

K = { 0x64, 0xC7, 0x8D, 0x19, 0x31, 0x61, 0xC1, 0x81 }

After unmasking, the resulting bytes are processed according to the code system described above.
In other words, this header handlings are to be COMBINED with the code system (Most converters don't do this!).

All operations are performed in the ring ℤ/256ℤ (8-bit arithmetic).

Search for other code prefixes

00 xx yy = displays as "!"  (not tested for all xx yy) -- added above
01 = does not print anything and stops output (= new line) -- added above
02..09 = displays "!"
Test with Japanese:
- E0 [00..FF] all print character "!", except for E0 27, which prints "&"
- [E1..FF] xx yy print Japanese characters or "!"

(TODO: Continue)

European Charset

        0 1 2 3 4 5 6 7 8 9 A B C D E F
C4 0x  ! À Á Â ! Ä ! Æ Ç È É Ê Ë Ì Í Î
C4 1x  Ï ! ! Ò Ó Ô ! Ö ! ! Ù Ú Û Ü ! !
C4 2x  ß à á â ! ä ! æ ç è é ê ë ì í î
C4 3x  ï ! ! ò ó ô ! ö ! ! ù ú û ü ! !
C4 4x  ! À Á Â ! Ä ! Æ Ç È É Ê Ë Ì Í Î
C4 5x  Ï ! ! Ò Ó Ô ! Ö ! ! Ù Ú Û Ü ! !
C4 6x  ß à á â ! ä ! æ ç è é ê ë ì í î
C4 7x  ï ! ! ò ó ô ! ö ! ! ù ú û ü ! !
C4 8x  ! À Á Â ! Ä ! Æ Ç È É Ê Ë Ì Í Î  (used in GTA 1)
C4 9x  Ï ! ! Ò Ó Ô ! Ö ! ! Ù Ú Û Ü ! !  (used in GTA 1)
C4 Ax  ß à á â ! ä ! æ ç è é ê ë ì í î  (used in GTA 1)
C4 Bx  ï ! ! ò ó ô ! ö ! ! ù ú û ü ! !  (used in GTA 1)
C4 Cx  ! À Á Â ! Ä ! Æ Ç È É Ê Ë Ì Í Î
C4 Dx  Ï ! ! Ò Ó Ô ! Ö ! ! Ù Ú Û Ü ! !
C4 Ex  ß à á â ! ä ! æ ç è é ê ë ì í î
C4 Fx  ï ! ! ò ó ô ! ö ! ! ù ú û ü ! !

       0 1 2 3 4 5 6 7 8 9 A B C D E F
84 0x  ! À Á Â ! Ä ! Æ Ç È É Ê Ë Ì Í Î  (used in GTA London)
84 1x  Ï ! ! Ò Ó Ô ! Ö ! ! Ù Ú Û Ü ! !  (used in GTA London)
84 2x  ß à á â ! ä ! æ ç è é ê ë ì í î  (used in GTA London)
84 3x  ï ! ! ò ó ô ! ö ! ! ù ú û ü ! !  (used in GTA London)
84 4x  ! À Á Â ! Ä ! Æ Ç È É Ê Ë Ì Í Î
84 5x  Ï ! ! Ò Ó Ô ! Ö ! ! Ù Ú Û Ü ! !
84 6x  ß à á â ! ä ! æ ç è é ê ë ì í î
84 7x  ï ! ! ò ó ô ! ö ! ! ù ú û ü ! !
84 8x  ! À Á Â ! Ä ! Æ Ç È É Ê Ë Ì Í Î
84 9x  Ï ! ! Ò Ó Ô ! Ö ! ! Ù Ú Û Ü ! !
84 Ax  ß à á â ! ä ! æ ç è é ê ë ì í î
84 Bx  ï ! ! ò ó ô ! ö ! ! ù ú û ü ! !
84 Cx  ! À Á Â ! Ä ! Æ Ç È É Ê Ë Ì Í Î
84 Dx  Ï ! ! Ò Ó Ô ! Ö ! ! Ù Ú Û Ü ! !
84 Ex  ß à á â ! ä ! æ ç è é ê ë ì í î
84 Fx  ï ! ! ò ó ô ! ö ! ! ù ú û ü ! !

Japanese translation

Converting FXT to Shift-JIS, and vice-versa

Background

The FXT format encodes Japanese characters (originally stored as Shift-JIS) into 3-byte sequences with a prefix byte of 0xE9 or 0xEA.

Forward Formula (FXT → Shift-JIS)

Prefix 0xE9: ShiftJIS(0xE9 B0 B1) = 0x9FFE − 0x40*(0xFF−B0) − (0xFF−B1)
Prefix 0xEA: ShiftJIS(0xEA B0 B1) = 0xAFFE − 0x40*(0xFF−B0) − (0xFF−B1)

Theoretically possible (not tested):

Prefix 0xEZ: ShiftJIS(0xEZ B0 B1) = 0xZFFE − 0x40*(0xFF−B0) − (0xFF−B1)

The game accepts the prefix Fz which behaves exactly like Ez. Hence, you could F9 instead of E9 and FA instead of EA.

Inverse Formula (Shift-JIS → FXT)

Step 1 — Determine prefix from Shift-JIS value:

| Shift-JIS range | Prefix | Base   |
| --------------- | ------ | ------ |
| 0x8141 – 0x8FFF | 0xE9   | 0x9FFE |
| 0x9000 – 0x9FAD | 0xEA   | 0xAFFE |

The two ranges are non-overlapping, so the prefix is determined unambiguously by the Shift-JIS value alone. No lookup table is needed.

Step 2 — Compute B0 and B1:

D := Base − ShiftJIS

Y := D mod 0x40
if Y < 0x3F then Y := Y + 0x40 // correction: Y always lies in [0x3F..0x7E]
X := (D − Y) div 0x40

B0 := 0xFF − X
B1 := 0xFF − Y

Why the correction?

The formula D = 0x40*X + Y is not a standard positional system because Y can exceed the factor 0x40. Analysis of all 1091 known FXT codes shows that 0xFF − B1 (i.e. Y) always falls in the range [0x3F..0x7E]. A raw D mod 0x40 yields values in [0..0x3F], which means values in [0x40..0x7E] get incorrectly folded down. Adding 0x40 when Y < 0x3F restores the correct value.

Step 3 — Output:

Output: Prefix, B0, B1

Example

Encode Shift-JIS 0x8345 (ウ):

Prefix = 0xE9 (since 0x8345 < 0x9000), Base = 0x9FFE
D = 0x9FFE − 0x8345 = 0x1CB9
Y = 0x1CB9 mod 0x40 = 0x39 → 0x39 < 0x3F → Y = 0x39 + 0x40 = 0x79
X = (0x1CB9 − 0x79) div 0x40 = 0x1C40 div 0x40 = 0x71
B0 = 0xFF − 0x71 = 0x8E
B1 = 0xFF − 0x79 = 0x86

Result: E9 8E 86 ✓

Displaying Japanese Text

The index becomes transformed (unknown) and looked up in KANJI.IDX (which is a Int16 → Int16 Lookup Table), and then gather the graphics from KANJI.BIT which has 5040 glyphs á 16x16 pixels.

KANJI.BIT is a raw graphics file where 1 bit is 1 pixel.  (See the file being converted to PNG here. Your browser might not display this 16x80640 pixels picture correct, though.)

Examples by manual testing:

Lookup process:

  1. FXT to IDX
    1. Unknown. E9 8F 8E becomes IDX offset 01 07 1A Help wanted
  2. IDX to BIT
    1. At the IDX offset, a 16 bit value will be read, for example at offset 01 07 1A you will find AA 02.
    2. Swap the bytes.  AA 02 becomes 0x2AA, which means: Read glyph # 682.
    3. Multiply by 0x20 (because each 16x16 glyph occupies 32 bytes).  0x2AA * 0x20 = 0x5540
    4. This is the offset in the KANJI.BIT file. At 0x5540, read 0x20 bytes, and render it as raw binary data, 1 bit per pixel, 16x16 pixels.
    5. You will see the symbol ロ rendered.

Decoded contents

The decoded contents look like this:

[1001]Answer the South Park phones to get jobs. Keep your eyes open for opportunities. Remember - you mess up, we mess you up.
[1002]Crazy Jimmy's dumped a car in North East Park. Find it before the cops do - or die.
[1003]Bring the car to Dulli's in West Park. Move it! We got some fresh pussy here!

The number at the beginning is the brief number that can be used in mission.ini scripts.

Encrypt process (TXT to FXT)

The encrypt process is similar to the decrypt process, just vice-versa.

For the extended charset, you can decide if you want to encode it with 0x84 (GTA London style) or 0xC4 (GTA1 style), since both London and GTA1 can read each other's encodings.
The GTA London style 0x84 is recommended, because you have more usable space in the extended characters.