The FXT format contains language specific texts of the game in a slightly encrypted manner.
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.
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).
The file is decrypted byte-by-byte, with this code system:
0x00 xx yy does not print any character. Theory: Is this the 0xC3
equivalent for unmapped Japanese characters?!0x01 becomes a new-line0x84 xx becomes xx+0xBF.
This is done by GTA London for Non-English characters, but GTA 1 can also
read it.0xC3 xx is a special case found in the original French translation,
where œ is converted to C3 9D, and printed as "!", since œ is not existing
in the game font.xx gets encoded as
C3 xx+1, making sure the game will print "!", but the editor
itself (or TXT-to-FXT converter) can display the original character that
was intended by the translator.0xC4 xx becomes xx+0x3F. This is done by GTA 1 for
Non-English characters, but GTA London can also read it.[0xE0..0xFF] xx yy encrypt Japanese characters.
Only 0xE9 and 0xEA are used in GTA 1. Details how
to encode/decode: See below.0xFF is NOT to be ignored! This is a
misconception by many converters that 0xFF means "ignore".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).
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)
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 ï ! ! ò ó ô ! ö ! ! ù ú û ü ! !
The FXT format encodes Japanese characters (originally stored as Shift-JIS) into 3-byte sequences with a prefix byte of 0xE9 or 0xEA.
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.
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 ✓
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:
63 F3 → FXT Code E9 12 34
→ IDX Offset 01 08 E6 → IDX Contents 90 03 → BIT Index
00 72 0081 5B → FXT Code E9 86 9C
→ IDX Offset ?? ?? ?? → IDX Contents ?? ?? → BIT Index ?? ?? ?? (ー)82 CC → FXT Code E9 8C 8D
→ IDX Offset ?? ?? ?? → IDX Contents ?? ?? → BIT Index ?? ?? ?? (の)83 4E → FXT Code E9 8E 8F
→ IDX Offset ?? ?? ?? → IDX Contents ?? ?? → BIT Index ?? ?? ?? (ク)83 8C → FXT Code E9 8F 8D
→ IDX Offset 01 07 18 → IDX Contents A9 02 → BIT Index
00 55 20 (レ)83 8D → FXT Code E9 8F 8E
→ IDX Offset 01 07 1A → IDX Contents AA 02 → BIT Index
00 55 40 (ロ)Lookup process:
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.
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.