A command-line toolkit that converts the files of the PC releases of Metal Gear and Metal Gear 2: Solid Snake, on GOG and in the Steam Master Collection, to editable forms and back, for translations and mods.
Every conversion is lossless: a file exported and imported back unchanged gives the very same bytes, which the tests
check on every file of both releases. Texts go to translation tools as XLIFF 2.0, XLIFF 1.2 or Gettext PO, pictures and
glyphs become PNG images, structures JSON, and data the tools do not decode stays in .bin files.
| Release | Games |
|---|---|
| Metal Gear (GOG) | Metal Gear |
| METAL GEAR & METAL GEAR 2: Solid Snake (Steam, part of Master Collection Vol. 1) | Metal Gear, Metal Gear 2: Solid Snake |
Both releases run the MSX2 games from resource files, one per language, that hold their texts, fonts, pictures and game data. The Master Collection runs them inside the engine of Bluepoint's Metal Gear Solid HD Collection, whose own files hold the scripts, layouts, textures and texts around the games. The tools read and write these formats:
| Files | Format versions |
|---|---|
| Resource files | One format in both releases and every language: 77 sections in Metal Gear, 49 in Metal Gear 2; the Japanese files have sized font pages |
| GCX scripts | Plain and Bluepoint (LCGB); the game reads the Bluepoint copies |
| Textures | Versions 5 (console.ctxr) and 7 |
| 2D layouts | Version 7 |
| Sprite atlases, console font, TNOF fonts, keepfonts, string tables, sound banks | One format each |
GOG: MetalGear.exe reads Resource\<language>.bin, where <language> is the language of the [metalgear]
section of settings.ini (english by default), and falls back to Resource\English.bin. A translation can therefore
ship as a file of its own, such as Resource\Polish.bin with language=polish. settings.exe only lists the five
shipped languages, so saving its dialog sets English again.
Steam: the launcher starts METAL GEAR.exe with the language chosen for the game and the region eu (jp for
Japanese). The engine takes the file lists of each stage and slot page (manifest.txt and bp_assets.txt) from the
data folder of the language, fr for English and French, gr, it, sp or jp, and loads each line of the 60 Hz
video mode. It reads a script
from the _bp folder beside its path when there is one there, a texture from the _win folder beside it, and each
file from the first override folder that holds it (such as ovr_stm/ and the region's ovr_eu/), down to the listed
path. In English, the games read:
| Data | Files |
|---|---|
| Metal Gear resources | fr/stage/mg1/cache/ovr_stm/ovr_eu/english.raw |
| Metal Gear 2 resources | fr/stage/mg2/cache/ovr_stm/ovr_eu/english.raw |
| Scripts | fr/stage/{mg1,mg2}/cache/_bp/00180720.gcx, assets/gcx/fr/_bp/*.gcx |
| Layouts | fr/stage/{mg1,mg2}/cache/*.la2, assets/la2/us/*.la2, assets/la2/fr/time_paradox.la2 |
| Sprite atlases | assets/tri/us/*.tri |
| Keepfont | assets/raw/us/keepfont_stage_r_sna01_r.raw |
| Textures | textures/flatlist/_win/*.ctxr and their overrides, such as textures/flatlist/ovr_stm/_win/ |
| String tables | EngineSupport/stovc.bin (controllers), EngineSupport/stovk.bin (keyboard) |
| Sound banks | us/stage/{mg1,mg2,r_sna01}/pk0*.sdx (jp/stage/... in Japanese) |
The other copies, such as cache/english.raw and cache/00180720.gcx, are never read, and cache/ovr_stm/english.raw
only in the region us, which the launcher never passes. French, German and Italian are read from
<folder>/stage/{mg1,mg2}/cache/ovr_stm/<language>.raw, Spanish from
sp/stage/{mg1,mg2}/cache/ovr_stm/ovr_eu/spanish.raw and Japanese from jp/stage/{mg1,mg2}/cache/ovr_stm/japanese.raw.
A translation therefore replaces the copy the game reads, which mgtools files names for any language,
region and controller.
This repository and its releases contain no files of the games. You need your own copy of a game:
- Metal Gear: GOG
- METAL GEAR & METAL GEAR 2: Solid Snake, also part of the Master Collection Vol. 1: Steam
The tools only read and write the games' data files. They neither make piracy easier nor bypass or remove any DRM.
Metal Gear and Metal Gear 2: Solid Snake are trademarks of Konami Digital Entertainment. MGTools is not affiliated with or endorsed by Konami.
- Resource files (
resource)- Show which game a resource file belongs to and what each section holds, with its number of leaves and its size
- Export the texts to one translation document, a unit per string with notes on where the game shows it, how many bytes the original takes and which limits apply
- Export the font as a PNG image per page or per glyph and
font.json, and import glyphs added for letters the game lacks - Export the pictures as indexed PNG images with the colours the game shows, and import them back also from RGB and RGBA copies
- Export the palettes, Metal Gear's sprite frame rectangles and Metal Gear 2's cell atlas as JSON, and the data
MGTools does not decode as
.binfiles - Refuse on import what the game cannot show, naming each string and the reason: characters without a glyph, words, lines and pages longer than the message window, and Metal Gear's HUD labels outside its HUD font
- GCX scripts (
gcx)- Export a script's code and resources as a GCL listing to read and edit, and compile it back
- Name more strcodes in the listing from a dictionary file, skipping with a warning the lines whose names would not compile back to their code
- Export the UTF-8 texts of a Bluepoint script to a translation document, with the PS2 text as a note where it differs
- Export the script's glyphs as a PNG image
- String tables (
stov): decryptstovc.binandstovk.binto translation documents, and build and encrypt them back from the units of the document - Textures (
ctxr): convert a texture's full-size level to a PNG image and back, keeping the alpha as stored and remaking the mipmaps, colour range and alpha flag as the game's converter did; one texture, a folder or a wildcard pattern at a time - 2D layouts (
la2): edit the node tree, items, animations, sprites, colours and fonts of a HUD or menu as JSON, with each text checked against the glyphs of its font - Sprite atlases (
tri): edit each sprite's GS registers as JSON, with its texture coordinates derived from them - Console font (
cfon): edit the glyph boxes and the glyph of each character as JSON - TNOF fonts (
tnof): export a font as a greyscale PNG image per glyph and JSON of the metrics, and import changed and added glyphs - Keepfonts (
keepfont): export a PNG image per Latin glyph, one of the kana and JSON of the flags, and import glyphs as wide as their images - Sound banks (
sdx): unpack the sound effects of a stage to SPU-ADPCM waves, MIDI files and JSON, and pack them back, also with waves and MIDI files of another size - Game files (
files): list which file the Master Collection reads for each line of its file lists, for any language, region and controller - All commands: never replace an exported file or folder that may hold edits, and keep the first file an import
replaces as
.orig
Not covered: the Unity launcher of the Master Collection (launcher.exe, launcher_Data), the executables and
libraries (MetalGear.exe, settings.exe, METAL GEAR.exe, Engine.dll, mg1.dll, mg2.dll), audio codecs (the
waves stay SPU-ADPCM, the .sdt music and voice streams are not read), shaders and icons (.ico).
- Python 3.14+ (the portable builds include it)
Download the portable build for your system from the Releases page:
MGTools_v<version>_Windows.exe (code-signed), MGTools_v<version>_Linux or MGTools_v<version>_macOS. Each is a
single executable that needs no Python; run it in place of mgtools in the commands below, on Linux and macOS after
making it executable with chmod +x. The macOS build is not notarised, so macOS keeps a copy downloaded with a browser
from running until its quarantine flag is cleared with xattr -d com.apple.quarantine MGTools_v<version>_macOS.
To install the command with Python instead, give pipx or uv the repository's URL:
pipx install git+https://github.com/GrzybDev/MGToolsuv tool install takes the same URL.
The mgtools command has a group of commands for each kind of file, and the files command. --help lists them,
and after any group or command it shows what that takes:
mgtools --help
mgtools resource export --helppython -m mgtools runs the same commands in a Python environment the package is installed in, and uv run mgtools
in a clone of the repository.
Each group has an export and an import command, and resource also has info. Every output argument is optional.
Without one, a command writes next to its input, named after it: the exports of resource files, scripts, TNOF fonts,
keepfonts and sound banks create a folder, the other exports a file with the extension of what they write, and the
imports a file with the extension of the game file (.raw for resource files, TNOF fonts and keepfonts).
--format picks the format of the texts for translation that resource export, gcx export and stov export write:
xliff-2.0 (.xlf, the default), xliff-1.2 (.xliff) or po. Imports tell the formats apart by their content,
and untranslated units keep the original text. Translation documents describes what each
format holds.
Exports never replace a file that may hold edits: when the file to write exists, the folder to write is not empty, or the settings JSON that a texture export writes next to its PNG image exists, the export names it, writes nothing and stops. Move it away or choose another output. A texture export into a folder checks only the files it writes there.
Imports replace their output. The first time one replaces a file, it keeps that file beside the new one as
<name>.orig, such as english.raw.orig, and prints Kept the original as .... Once the .orig file exists, imports
replace the output without another copy. Rename the .orig file back to restore the original.
Every file is written through a temporary file in the same folder, so a failed import leaves the file it would replace as it was. A command that fails prints the reason to the standard error and exits with code 1, or with code 2 when an argument or option is missing or invalid.
mgtools resource info path/to/english.raw
mgtools resource export path/to/english.raw [path/to/output_dir] [--format xliff-2.0] [--charmap path/to/font.json] [--separate-glyphs]
mgtools resource import path/to/english [path/to/english.raw]info names the game, Metal Gear or Metal Gear 2: Solid Snake, and lists what each section holds with its number of
leaves and its size in bytes.
export writes a resource file to a new or empty folder, by default next to the file and named after it: its texts
for translation, its font, pictures, palettes and sprite rectangles, and the data MGTools does not decode as .bin files (see
Resource folders). It tells Metal Gear from Metal Gear 2, and a Japanese file from a European one,
by the file itself.
import builds a resource file from such a folder, by default next to the folder with the .raw extension. GOG's
files end in .bin, so name the output for them: mgtools resource import English English.bin. The folder holds one
translation document, in any of the three formats. Import refuses texts the game cannot show and names each of them
with the reason (see Translating the games).
The game files store no names for the letters a translation adds to the fonts. To export a translated file again, give
it the font.json of the folder it was imported from with --charmap.
--separate-glyphs saves each glyph of the font as its own image, named after its character, in a folder per page
instead of an image per page: font/page0/U+0041.png holds the A of page 0. font.json names the image of each
glyph, and import reads the font in whichever form font.json gives (see
MSX fonts).
| Option | Description | Default |
|---|---|---|
--format, -f |
The format of the texts to translate: xliff-2.0 (.xlf), xliff-1.2 (.xliff) or po |
xliff-2.0 |
--charmap |
The font.json of an earlier export, whose charmap names the characters of the codes |
the characters the game shipped with |
--separate-glyphs, -s |
Save each glyph of the font as its own image instead of an image per page | off |
mgtools resource info English.bin
mgtools resource export English.bin
mgtools resource import English English.binThe first command prints Metal Gear, 77 sections and a table of the sections. The second writes the folder
English/. The third builds English.bin from the folder and keeps the file it replaces as English.bin.orig.
mgtools gcx export path/to/00180720.gcx [path/to/output_dir] [--format xliff-2.0] [--source-language en] [--dictionary path/to/names.txt]
mgtools gcx import path/to/00180720 [path/to/00180720.gcx]export writes a script to a folder, by default next to it and named after it: the listing of its code and resources,
the UTF-8 texts of a Bluepoint script as a translation document, a unit res:N per string, and its glyphs (see
GCX folders). --source-language names the language of the texts in XLIFF documents; PO has no field
for it. The scripts of the fr folder hold the French and the English texts: the listing shows which resources
(res:N) each language uses. Button icons are private-use characters, which translation tools may show as nothing; a
note names those of each unit.
The listing writes a strcode as its name where MGTools knows one, else as # and six hex digits. --dictionary gives
it more names: a text file with a strcode in hex and a name on each line, such as 379210 lamp. Its names replace the
built-in ones of the same codes, and words after a name are ignored. Import compiles each name back to its strcode
and needs no dictionary, so export skips a dictionary line that would not compile back to its code and warns with the
number of skipped lines and the line number and reason of the first three (see
Strcode dictionaries).
import compiles the folder back, by default next to it with the .gcx extension. The translation document must hold
a unit for each string and no other, and glyphs.png must have the size that the number of glyphs in the listing
gives.
| Option | Description | Default |
|---|---|---|
--format, -f |
The format of the texts to translate: xliff-2.0 (.xlf), xliff-1.2 (.xliff) or po |
xliff-2.0 |
--source-language, -l |
The language of the texts as a BCP 47 tag, written to XLIFF documents | en |
--dictionary |
A text file of strcodes and their names, whose names the listing writes for those codes | the built-in names |
mgtools gcx export 00180720.gcx --format po
mgtools gcx import 00180720The first command writes 00180720/script.gcl, 00180720/text.po and, for a script with glyphs,
00180720/glyphs.png. The second builds 00180720.gcx from the folder and keeps the original as 00180720.gcx.orig.
mgtools stov export path/to/stovc.bin [path/to/stovc.xlf] [--format xliff-2.0]
mgtools stov import path/to/stovc.xlf [path/to/stovc.bin]export decrypts a table to a translation document, by default next to it with the extension of the format. Each
string is a unit named after its id and language, such as 000e66b2.en; the units mix the table's languages, and the
document gives English as its source language.
import builds the table from the units of the document alone, by default next to the document with the .bin
extension: a unit removed from the document removes its string. A table is encrypted with its name up to the first
dot, so the output must be named stovc or stovk up to its first dot; import refuses any other name.
| Option | Description | Default |
|---|---|---|
--format, -f |
The format of the texts to translate: xliff-2.0 (.xlf), xliff-1.2 (.xliff) or po |
xliff-2.0 |
mgtools stov export stovc.bin --format po
mgtools stov import stovc.poThe first command writes stovc.po. Once it is translated, the second builds stovc.bin from it and keeps the table
it replaces as stovc.bin.orig.
mgtools ctxr export path/to/texture.ctxr [path/to/texture.png]
mgtools ctxr export path/to/textures_dir [path/to/output_dir]
mgtools ctxr export "path/to/textures/*.ctxr" [path/to/output_dir]
mgtools ctxr import path/to/texture.png [path/to/texture.ctxr]
mgtools ctxr import path/to/images_dir [path/to/output_dir]
mgtools ctxr import "path/to/images/*.png" [path/to/output_dir]export writes a texture's full-size level as an RGBA PNG image, with the alpha as stored, and its settings as JSON
of the same name next to it. import reads both and builds the texture at the size of the image, remaking its
mipmaps, colour range and alpha flag as the game's converter did. Many textures use the PS2 alpha scale, where 128 is
opaque; the alpha is never rescaled.
In place of one file, both commands take a folder or a wildcard pattern and convert every texture it names:
- A folder:
exportconverts each.ctxrfile in it, andimporteach.pngimage with its settings.jsonbeside it. Files in its subfolders are left out. - A pattern:
*stands for any part of a name,?for one character,[...]for one of the characters listed and**for any number of folders, as intextures/**/*.ctxr. Everything it matches must be a.ctxrfile forexport, or a.pngimage with its.jsonbeside it forimport, and a file it matches by several paths, astextures/*/../*.ctxrcan, is converted once. MGTools expands the pattern itself, as PowerShell and cmd pass it on unchanged; in bash, zsh and other POSIX shells, put it in quotes, as they would expand it first. A path that exists is always read as a path, never as a pattern.
The output of a folder or pattern is a folder. Without one, each file is written next to its input. With one, the
files keep their layout below the folder or below the part of the pattern before its first wildcard: with the pattern
textures/**/*.ctxr and the output out, textures/flatlist/_win/x.ctxr is exported to out/flatlist/_win/x.png.
Every texture is read and converted, and every file an export would write is checked, before anything is written, so
one texture that cannot be converted stops the command with nothing written. Each converted file gets a line of its
own. A folder without textures, a pattern that matches nothing or a file of another kind, an output that is a file
and an output that two textures would be written to are refused before anything is read. So is an output of one
texture with the extension of its input, such as b.png in mgtools ctxr import a.png b.png, which is what a POSIX
shell passes for an unquoted pattern that matches two images.
mgtools ctxr export console.ctxr
mgtools ctxr import console.pngThe first command writes console.png and console.json. The second builds console.ctxr from them and keeps the
original as console.ctxr.orig.
mgtools ctxr export "textures/**/*.ctxr" textures_png
mgtools ctxr import "textures_png/**/*.png" texturesRun from the game's folder, the first command writes the textures of textures/ as PNG images and JSON files in
textures_png/, such as textures_png/flatlist/_win/000237d1.png. Once they are edited, the second builds each
texture back in its place in textures/ and keeps each texture it replaces as <name>.orig.
mgtools la2 export path/to/memcard.la2 [path/to/memcard.json]
mgtools la2 import path/to/memcard.json [path/to/memcard.la2]export writes a layout as JSON, with its texts in Latin-1 and its offsets replaced by indices. import computes the
counts, sizes and offsets again, so a text may change length, and refuses a text whose font has no glyph for one of
its characters.
mgtools la2 export memcard.la2
mgtools la2 import memcard.jsonThe first command writes memcard.json. The second builds memcard.la2 from it and keeps the original as
memcard.la2.orig.
mgtools tri export path/to/atlas.tri [path/to/atlas.json]
mgtools tri import path/to/atlas.json [path/to/atlas.tri]export writes each sprite's strcode and GS registers as JSON. import derives each sprite's texture coordinates
from its TEX0 and CLAMP registers, so a changed clamp rectangle moves or resizes the sprite on its page.
mgtools tri export scope_0_stage_r_sna01_r.tri
mgtools tri import scope_0_stage_r_sna01_r.jsonThe first command writes scope_0_stage_r_sna01_r.json. The second builds scope_0_stage_r_sna01_r.tri from it and
keeps the original as scope_0_stage_r_sna01_r.tri.orig.
mgtools cfon export path/to/console.cfon [path/to/console.json]
mgtools cfon import path/to/console.json [path/to/console.cfon]export writes the glyph boxes of the font and the glyph of each character as JSON. The glyphs are drawn in
EngineSupport/Fonts/_win/console.ctxr: to give a character a glyph of its own, draw it in that texture with
mgtools ctxr, add its box to glyphs and map the character to the new index.
mgtools cfon export console.cfon
mgtools cfon import console.jsonThe first command writes console.json. The second builds console.cfon from it and keeps the original as
console.cfon.orig.
mgtools tnof export path/to/MGS_Font.raw [path/to/output_dir]
mgtools tnof import path/to/MGS_Font [path/to/MGS_Font.raw]export writes a font to a folder, by default next to it and named after it. import takes the size of each glyph
from its image and sorts the glyphs by code point, so a row added to font.json with its image adds a glyph. The
engine draws with a font built into METAL GEAR.exe, and EngineSupport/Fonts/MGS_Font.raw does not appear to be
used (see Known limitations); TNOF fonts shows how to extract
the font it draws with.
mgtools tnof export MGS_Font.raw
mgtools tnof import MGS_FontThe first command writes MGS_Font/font.json and an image per glyph, such as MGS_Font/glyphs/U+0041.png. The second
builds MGS_Font.raw from the folder and keeps the original as MGS_Font.raw.orig.
mgtools keepfont export path/to/keepfont.raw [path/to/output_dir]
mgtools keepfont import path/to/keepfont [path/to/keepfont.raw]export writes a keepfont to a folder, by default next to it and named after it. import makes each Latin glyph as
wide as its image, 1 to 64 pixels, and 24 pixels high.
mgtools keepfont export keepfont_stage_r_sna01_r.raw
mgtools keepfont import keepfont_stage_r_sna01_rThe first command writes keepfont_stage_r_sna01_r/keepfont.json, an image per Latin glyph, such as
keepfont_stage_r_sna01_r/latin/41.png for A, and keepfont_stage_r_sna01_r/kana.png. The second builds
keepfont_stage_r_sna01_r.raw from the folder and keeps the original as keepfont_stage_r_sna01_r.raw.orig.
mgtools sdx export path/to/pk0001a1.sdx [path/to/output_dir]
mgtools sdx import path/to/pk0001a1 [path/to/pk0001a1.sdx]export unpacks a sound bank file to a folder, by default next to it and named after it. import rebuilds the sizes,
offsets and block counts, so a wave or a MIDI file may change size.
mgtools sdx export pk0001a1.sdx
mgtools sdx import pk0001a1The first command writes pk0001a1/sdx.json, the waves of each bank, such as pk0001a1/bank0/waves/000.adpcm, and
its sound effects, such as pk0001a1/bank0/sounds/0000.mid. The second builds pk0001a1.sdx from the folder and
keeps the original as pk0001a1.sdx.orig.
mgtools files "path/to/MG and MG2" [--language en] [--region eu] [--controller xbox] [--keyboard-layout a]files reads the file lists of an install of METAL GEAR & METAL GEAR 2: Solid Snake and prints the data folder, then
each list with, per line, the id of the file and the file the engine reads for it. A line whose file exists nowhere
is shown as missing, and a warning at the end counts such lines. The command only reads the install.
| Option | Description | Default |
|---|---|---|
--language, -l |
The game's language: en, jp, fr, gr, it, pr, sp, du or ru |
en |
--region, -r |
The game's region: us, jp or eu |
jp for Japanese, else eu |
--controller, -c |
The controller type: ps5, ps4, xbox, nx, stmd or kbd |
xbox |
--keyboard-layout |
The keyboard layout setting of the kbd controller: a or b |
a |
mgtools files "path/to/MG and MG2" --language frThe command prints Data folder: fr and the lists of that folder, among them:
fr/stage/mg1/manifest.txt
cache/00861cbc.raw fr/stage/mg1/cache/ovr_stm/french.raw
French Metal Gear therefore reads its resources from fr/stage/mg1/cache/ovr_stm/french.raw.
-
Find the file the game reads: on GOG
Resource\<language>.bin, in the Master Collection the onemgtools filesnames (see Files the games read). -
Export it to a folder of your own:
mgtools resource export "path/to/MG and MG2/fr/stage/mg1/cache/ovr_stm/ovr_eu/english.raw" mg1 --format po
-
Translate
mg1/text.poin a translation tool. Each string is a unit named after its block and number, such asmg1.b03.e000. Its notes say where the game shows it, how many bytes the original takes and which limits apply. Keep placeholders such as{wait}or{btn:1}; untranslated units keep the original text. -
Give each letter the font lacks a code: name it in the
charmapofmg1/font.jsonat a code the charmap does not use (7F,A0toDF; the European releases leaveA0toA6,AEandAFfree) or instead of a letter the translation does not need. Give the code a width in thewidthsof page 0, the font of the texts, and draw the glyph inmg1/font/page0.png: each code has a cell 64 pixels wide and as high as the page, 16 a row from code20, and the glyph takes the first columns of it, in the four greys of the image. In a folder exported with--separate-glyphs, draw the glyph instead as an image of its own inmg1/font/page0/, as wide as its width and 24 pixels high, and name the image in theimagesof page 0. -
Metal Gear draws its HUD and menu labels (
mg1.b15.e003toe008,e013toe015ande141) with an 8 × 8 sprite font of capitals, digits and the codesB0toDF, 8 pixels a character. Letters beyond A to Z in these labels need a code fromB0toDF, and a glyph inmg1/images/62.000.png, whose 8 × 8 cells go 16 a row from codeB0. -
Import the folder and put the new file in place of the one the game reads:
mgtools resource import mg1 english.raw
-
Translate the texts around the games the same way: the scripts with
mgtools gcx, the string tables withmgtools stovand the texts of the layouts in the JSON ofmgtools la2, within the letters their fonts can draw (see Known limitations).
Japanese texts take double-byte characters too: a character the font lacks needs to be listed in the double_byte of
font.json and drawn in font/page4.png, or with --separate-glyphs drawn as a 24 × 24 image in font/page4/ and
named in double_byte_images.
Import refuses what the engine cannot show:
- The game finds each string by its position: units cannot be added or removed.
- Metal Gear's message window takes 48 bytes a line, wrapped at spaces, and a blank line starts a page.
- Metal Gear 2's takes 45 bytes a line and 10 lines a page;
{wait}and{autowait}start a page. The opening story and the credits are laid out freely. - Japanese lines are never wrapped and take 48 (Metal Gear) or 47 bytes (Metal Gear 2). In Metal Gear 2,
{wait}hides the byte after it, so a line break or a space follows it. - Every character needs a glyph: on page 0 for single bytes, on page 4 for double-byte characters.
- RGB copies of pictures can only use colours of their palette, and sprite rectangles go up to 255 pixels.
Menu strings are not wrapped either: keep them about as wide as the original, whose width in pixels their note gives. MSX texts gives every rule.
- The engine draws the UTF-8 texts of the scripts and string tables with a TNOF font built into
METAL GEAR.exe;EngineSupport/Fonts/MGS_Font.rawdoes not appear to be used. The built-in font has no Polish letters but Ó and ó, and MGTools does not patch executables. Layouts store Latin-1 texts, which lack them too. - Metal Gear's pause menu items are inside the script of section 71 of its resource file, which MGTools does not decode.
- Metal Gear 2's sprite fonts are not mapped, so its HUD labels are not checked like Metal Gear's.
- Import does not check that a script or string table keeps its button icons.
- A texture's PNG image saved without alpha imports as fully opaque.
The formats of the games' own files are described in docs/:
| Page | Covers |
|---|---|
| MSX resource files | The node tree of the resource files, the sections of each game and the resource folder |
| MSX texts | Text blocks, string records, the character set, placeholders and the limits import checks |
| MSX fonts | The five font pages, how glyphs are packed, and font.json |
| MSX graphics | Palettes, pictures, screens, the colours the games show and the frame rectangles |
| GCX scripts | The script file, GCL bytecode, the PS2 text encoding, strcodes and the listing |
| String tables | The encryption, the table and its translation units |
| Textures | The texture file, its versions, how the mipmaps are made and the settings JSON |
| 2D layouts | The header, node tree, items, animations, sprites, colours and fonts, and their JSON |
| Sprite atlases | The sprite entries, their GS registers and texture coordinates |
| Console font | The glyph boxes and the arrays that map characters to them |
| TNOF fonts | The glyph table and records, and the font built into METAL GEAR.exe |
| Keepfonts | The glyph table, the 2-bit Latin and kana glyphs |
| Sound banks | The banks and their chunks, waves and sound effect records |
| File lists | The lines of the lists, the data folders and how the engine picks the file it reads |
A unit per string, named by an id that tells import where its text belongs, with notes on how the game shows it.
Placeholders are plain text, never inline codes, as OmegaT 6.1 numbers the third and later inline codes of a segment
wrongly. Those of the MSX games: {wait} and {autowait} (wait for a button or half a second, then clear the window),
{r} and {s} (the speaker), {e}, {f}, {speed:N}, {bgm:NN}, {se:NN}, {btn:N} (a controller button), and
{x:HH} and {sjis:HHHH} for bytes that are no character.
- XLIFF 2.0 and 1.2: a unit (
trans-unit) per string with its notes. A non-empty target is used whatever its state, since OmegaT marks none in XLIFF 2.0, and segments a tool split are joined back. - PO: the id is the context and the notes are
#.comments. Lines are never wrapped; fuzzy translations are not used.
OmegaT 6.1 hands every .xlf and .xliff file to its legacy XLIFF filter, which only translates existing targets. In
Project > Properties... > Local File Filters..., tick Use local file filter settings and untick XLIFF (legacy
filter), or untick it for every project in Options > Global File Filters....
| Path | Contents |
|---|---|
resource.json |
The game, the containers without leaves and the indices of colours several indices show |
text.xlf |
The strings for translation (text.xliff or text.po in the other formats) |
text.json |
Metal Gear's style byte of each string and debug warp points; Metal Gear 2's string counts |
text/bNN.bin |
The text blocks that hold no strings |
font.json |
The charmap and the layout of the five font pages |
font/pageN.png |
The glyphs of each page |
font/pageN/*.png |
With --separate-glyphs, instead of font/pageN.png: an image per glyph of the page |
images/SS.NNN.png |
The pictures, named by section and number |
palettes.json |
The palettes, as lists of #rrggbb |
actors.json |
Metal Gear: the rectangles of the actors' frames in the sprite sheets |
cells.json |
Metal Gear 2: the cell atlas of the sprite sheets |
raw/SS.NNN.bin |
Everything else, named by its position in the file |
font.json:charmapgives the character of each code from7FandA0toDFthat has one. Pages 0 to 3 (24, 12, 18 and 24 pixels high) give thewidthsof their glyphs, from 1 to 64 pixels;floor_packedmarks a page whose glyphs drop their last two pixels, which the engine draws from the next glyph, andvandpad_bitskeep the bytes the Japanese pages and some glyphs carry.double_bytelists the characters of page 4's 24 × 24 glyphs in order. With--separate-glyphs, each page names its folder inglyphsand the image of each glyph by code inimages, anddouble_byte_glyphsanddouble_byte_imagesdo the same for page 4; a glyph without a character is named after its code, such ascode-FF.png, and a glyph of page 4 without a code isfallback.png(glyph 0) orunused-N.png(glyph N; see MSX fonts).- Pictures are indexed PNG images whose palette holds the colours the game shows, index 0 transparent and every unused index a colour of its own. Import takes the indices of such images as they are, and maps the colours of RGB and RGBA copies back to indices (alpha 0 to index 0). Metal Gear 2 changes palettes as the screen does, so its pictures show the colours of where they are drawn. The two screens of each game are RGB PNG images.
script.gcl: the listing of the code and the resources. Statements end with a semicolon; whitespace and//comments are free. Strings are in the PS2 text encoding, with codes it has no character for in hex between braces, such as{8C01}for the first glyph.text.xlf: the UTF-8 text of each string of a Bluepoint script, as unitres:N, with the PS2 text as a note where it differs.glyphs.png: the script's glyphs, 24 × 24 pixels, 16 a row.
- Textures: an RGBA PNG image of the full-size level, with the alpha as stored, and JSON of the version, whether the texture has mipmaps and the texels the game's converter rounded otherwise.
- Layouts: JSON of the node tree, the items, the animations, the sprites, the colours and the fonts. Items and animations are named by their index from 0; node parents and the sprite and font of an item keep the file's indices from 1.
- Sprite atlases: JSON of each sprite's strcode and GS registers; texture coordinates follow from TEX0 and CLAMP.
- Console font: JSON of the glyph boxes in its texture and the glyph of each character.
- TNOF fonts:
font.jsonwith the metrics of each glyph and a greyscale image per glyph inglyphs/U+XXXX.png. - Keepfonts:
keepfont.jsonwith the flags of each Latin glyph (codes0x20to0xFFin the Mac OS Roman layout), its image inlatin/XX.png, 24 pixels high, and the kana inkana.png. - Sound banks:
sdx.jsonof the banks, waves and sound effects; per bank the waves aswaves/NNN.adpcm, a MIDI file per sound effect insounds/and the other chunks as.binfiles.
uv sync
uv run pytest
uv run ruff check
uv run ruff format --check
uv run mypyThe tests on the game files export and import every file of each format and expect the very same bytes.
MGTOOLS_STEAM_DIR names the install of METAL GEAR & METAL GEAR 2: Solid Snake and MGTOOLS_GOG_DIR that of Metal
Gear on GOG; the tests of a release are skipped while its variable is unset. They only read the game folders and write
to pytest's temporary folders:
MGTOOLS_STEAM_DIR="path/to/MG and MG2" MGTOOLS_GOG_DIR="path/to/Metal Gear" uv run pytestSpecial thanks to:
- Konami (for making the games)