Skip to content

About

Let's Make A Soccer Team Reverse Engineering Project (AI-Powered)

Resources

Code of conduct

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Let's Make A Soccer Team Reverse Engineering Project

Reverse-engineering notes and tools for the PAL PS2 release of Let's Make a Soccer Team! (SLES_541.51), and the mod built with them, the LMASTER Mod: fixes for what the release cut or broke, real names, a hidden third tier and a harder economy.

The repo has two halves:

  • DOC/: one spec per file format, recording what each field means and how it was worked out.
  • SRC/: standalone Python tools that parse, check and convert those formats.

Every layout claim in the docs is labelled either confirmed, with the game-code address of the routine that proves it, or empirical, meaning it was inferred from the data and checked against every file on the disc.

No game data is included. You need your own copy of the disc.

Where to start:

You want to Read
play a mod someone made INSTALL.md: checking your disc, applying a patch, keeping your saves safe
make a mod, or edit a career USAGE.md: the mod editor and the save editor, tab by tab
know what a file or system does the documentation index below
help CONTRIBUTING.md, and "Next up" in TODO.md

Sister project: VPF-Reverse reverse-engineers Virtua Pro Football (SLES_541.53), which runs on the same engine and whose edit players this game imports (PMPLAYER_FORMAT.md). Formats the two games share are documented here first, and VPF-Reverse builds on them.

The long-term aim is GUI tools for editing the game's data to build mods, and most of that is here now: every file on the disc is documented, the data a starting-season mod changes has writers and editor tabs, and edited files go back on a disc that boots. See GOALS.md for the plan and where each stage stands, TODO.md for the next tasks and DONE.md for what's finished.

Disclaimer

100% of the reverse engineering has been done using Claude Opus 5.5. I'm neither anti-AI nor pro-AI, and I am pro user choice. If you hate genAI with the passion of a thousand suns, this project is not for you. If you're a far-right techbro chud, this project is ALSO not for you.

Requirements

  • Python 3, standard library only for most commands (editor.py uses tkinter, which ships with Python)
  • pip install pillow for the PNG commands (svr, csp, zbf) and the textures in ninja.py's exports
  • pip install capstone for disassembly (sles_disasm, snr2 dis)

Setup

The tools expect this layout. Everything built from the disc is git-ignored, and none of it may be committed.

ISO/      the disc filesystem (SLES_541.51, DLL/, AUDIO/, DATA.CVM, ...)
          + the decrypted DATA.ISO                              (ignored)
DAT/      the contents of DATA.ISO, which is what most tools read (ignored)
ISO_JP/, DAT_JP/   the same for the Japanese release, optional   (ignored)
mod/      the editor's default mod folder                       (ignored)
.regress/ regress.py's baselines; .cache/ save.py's field list  (ignored)
SRC/      tools
DOC/      format and system documentation
PNACH/    PCSX2 patches (widescreen)

Put a dump of the disc that matches Redump (disc 12334, SLES-54151 v1.01) in the repo root, then run:

python SRC/extract_disc.py all "Let's Make a Soccer Team! (Europe, Australia) (En,Fr,De,Es,It).iso"

extract_disc.py checks the image's size, CRC-32, MD5 and SHA-1 against Redump, extracts the disc filesystem into ISO/, decrypts ISO/DATA.CVM into ISO/DATA.ISO, and extracts that into DAT/. Nothing is mounted. Re-running skips files that are already there. *.iso files in the repo root are git-ignored.

To do the same by hand:

  1. Copy the disc's files, including DATA.CVM, into ISO/. Leave DATA.CVM unmodified.

  2. Decrypt the archive. Only its ISO9660 table of contents is encrypted, and the key recovered from the running game is the default:

    python SRC/rofs_decrypt.py ISO/DATA.CVM ISO/DATA.ISO
  3. Extract it into DAT/ (or mount it and copy its contents):

    python SRC/extract_disc.py extract ISO/DATA.ISO DAT

The decryption and key recovery are covered in DATA_CVM_EXTRACTION.md and LMAST_DATA_CVM_INFO.md.

The Japanese release (optional)

The tools also read the Japanese release, Pro Soccer Club o Tsukurou! Europe Championship (disc 30266, SLPM-66316 v1.05). extract_disc.py recognises its dump and extracts it to ISO_JP/ and DAT_JP/ (git-ignored):

python SRC/extract_disc.py all "Pro Soccer Club o Tsukurou! Europe Championship (Japan).iso"

Pass those folders to any tool. The PAL files in ISO/ must be there too: tools give PAL addresses, and gamever.py finds them in the Japanese executable and overlays. patch_disc.py patches a Japanese disc too, with every --mod switch but third-tier. See JAPANESE_RELEASE.md.

Tools

All tools run from the repo root as python SRC/<tool>.py <command> .... Running a tool with no arguments prints its full usage. Most commands accept either files or directories, and info parses every matching file and marks anything that doesn't fit the documented layout with !!. Search for them with, for example, python SRC/tbb.py info DAT | grep '!!'.

Disc image

Tool Reads Does
extract_disc.py a disc image checks it against Redump (PAL or Japanese), extracts its files, decrypts DATA.CVM and extracts DATA.ISO, without mounting anything (all; verify, list and extract do one step each)
rofs_decrypt.py ISO/DATA.CVM decrypts the table of contents into a plain DATA.ISO, with the key derived from the CVMH header

Game code

Tool Reads Does
sles_disasm.py ISO/SLES_541.51 recovers about 12,600 symbol names from the .sndata export table and disassembles with labels, naming the 323 sites that call or reference overlay code (relocs), and lists the developers' field table: the source names, ranges and offsets of about 170 structures' members (fields)
snr2.py ISO/DLL/*.REL parses the SN Systems overlays: header, symbols, relocations, xrefs, annotated disassembly; C++ classes from their type information (classes) and which class makes each call to a function (callers)
gamever.py ISO/, ISO_JP/ tells the builds apart and finds a PAL address or constant in another build's executable or overlay; check lists every address the tools use
python SRC/sles_disasm.py ISO/SLES_541.51 dis TblData
python SRC/sles_disasm.py ISO/SLES_541.51 relocs Talk_
python SRC/snr2.py dis ISO/DLL/SIMPRG.REL 12e000 40 --sles ISO/SLES_541.51

--sles resolves an overlay's imports to their addresses in the main executable.

Capstone has no R5900 mode, so a few EE-only opcodes (lq/sq, MMI) disassemble as unrelated MIPS instructions.

Archives and tables

Tool Formats Doc
pac.py BINPAC .PAC/.MRG/.HED, KC@P headers, PRSH (Sega PRS); rebuilds BINPACs and KC@P packs byte for byte (roundtrip, replace), and compresses PRS (prs, prscheck, replace --prs) PAC_FORMAT.md
tbb.py TBB1/TBL1 parameter tables; reads and writes (all 70 files round-trip) TBB_FORMAT.md
packdata.py etc::PackData inside KC@P entries (face packs, licensed kits, edit face, cut-ins); names lists each head's model and texture name PLAYER_DIR.md
pbdata.py player database PBDATA_*.PAC: 27,950 players, 3,000 managers, 1,000 scouts (bit-packed records); list, show, CSV; writes edits (set, CSV import; every record round-trips; --sles re-sorts the ranking and patches the executable for rank, position and nationality edits) PBDATA_FORMAT.md
initteam.py starting divisions, last season's order and computer-team squads (PLRRSRC_INITTEAMDATA.TBB, OTEAMMEMBER.TBB), with club names; club records, nations and stadiums; edits squad slots (set), club records (setteam), nations (setnation) and stadiums (setstadium), and swaps two clubs' places in the starting divisions and last season's results (swap); all five files round-trip. Also --mod real-grounds' writer, from SRC/grounds.csv (each club's real 2005-06 ground and capacity) INITTEAM_FORMAT.md
teaminit.py the player's new club (TEAM_INIT_DATA.TBB) by league and team style: squad, youth team, staff, staff lists and the rival club, named from the player database; edits records (set), round-trips; decodes the game's salary, transfer-fee and loan-fee limits from the executable (limits) TEAMINIT_FORMAT.md
clubresult.py how a final place is reported (CLUBRESULT.TBB), one row per schedule: league, cup or not ranked, the third-place match, and the clubs a cup's round names depend on ("Champion" to "Defeated 1st Rnd"); edits fields (set), round-trips CLUBRESULT_FORMAT.md
training.py the training tables (TRAINING_LIST.TBB): what each of the 139 practice menus trains and how tiring it is, the facility and camp bonuses, match growth by position, ability groups, the coaching staff ability per ability, and decline with age; edits values (set), round-trips TRAINING_FORMAT.md
camp.py the training camps (CAMP_LIST.TBB, CAMP_EXPLANE.TBB): each camp's city, nation and type, the clubs of its area and its description; edits fields (set), and fixes the camp types (fixtypes) and PAL's seven misplaced English camps (fixcities), round-trips CAMP_FORMAT.md
formset.py the tactics screen's eight national presets (TACTICS_FORMATION_SET.TBB): seven team tactics and a formation each; edits them (set), round-trips PARAM_DIR.md
tour.py tour opponents by region (TOUR_LIST.TBB); edits pairs (set), round-trips PARAM_DIR.md
clubrank.py the club ranking's tables (CLUB_RANK_SYSTEM.TBB): the nation groups, the points each competition gives for each final place, the world rank points by club rank, the club rank by position in each nation or division (with the positions each rank gets) and the year-end leagues; edits the points, world rank points and positions (set), adds rows for divisions of a new size (addrows), round-trips PARAM_DIR.md
clubevent.py the 46 PR events (club events) in the executable, named from MES.PAC: when each is offered, its cost, its chance in each business cycle and what success brings; edits every field into a copy of the executable (set), round-trips, on both releases CLUBEVENT_FORMAT.md
natcal.py the national-team calendar (SCHEDULE_LIST.TBB): for each year of the 4-year cycle, the turns national teams play, call their squads up and release them, and which are for a finals tournament; checks the calendar against the national cups' schedule, edits the call-up, release and finals flags (set), round-trips PARAM_DIR.md
regulation.py match regulations (REGULATION.TBB), one row per schedule: clubs, match grade, win bonus, prizes by position, yellow-card ban, matchday squad, foreign-player limit, substitutions, and the places up and down; edits fields (set), round-trips REGULATION_FORMAT.md
gamedata.py GAME/GAMEDATA.BIN: checks the 4,131 records (body part and surface of each ball contact) and prints them with the fields the match engine is known to read GAMEDATA_FORMAT.md
bpb.py the play books GAME/PLAYBOOK.BPB and COMBINATION.BPB: checks every play and prints one's starting spots and paths (players by role, and ball, in metres); checks and prints the COMBINATION2.CBB records (blocks, slots, areas) BPB_FORMAT.md
plrcommon.py the common pack PLRESOURCECOMMON.PAC: checks all 25 tables (facilities, formations, nations, competitions) and prints any one, with the facility records' named fields; set edits a facility's build cost, second cost, upkeep, build time or stadium capacity, and roundtrip checks every field's edit PLRESOURCECOMMON_FORMAT.md
plrsim.py the season-mode pack PLRESOURCESIM.PAC: checks all 16 entries (cities and weather, nations, affiliations, scouts' exclusives, combinations, free agents, colours, ...) and prints any one, named from the player database; replaces free agents (setfree) and overseas bases' costs (setbranch), edits the affiliations, scouts' exclusives and combinations (setgroup), and checks that the pack rebuilds byte for byte (roundtrip) PLRESOURCESIM_FORMAT.md
leaguesize.py a nation's two divisions: checks that the first season plays out with each club once (nations), and changes the first division's size, moving clubs to or from the second (plan, which also gives the sizes each nation allows; build, for one or more leagues: the slots, last season's records, the games, the game days, the club counts in REGULATION.TBB and CLUBRESULT.TBB, and the club ranking's rows for a new size) SCHEDULE_FORMAT.md
schedule.py season schedule packs SCHEDULE_{SYSTEM,COMPETITION,TEAM_ENTRY}.PAC: turns, games, pairings, team sources; re-encodes all three packs and their .HED byte for byte (roundtrip); builds and checks league schedules of 2–32 clubs (league) and cup brackets of 2–128 (knockout) and finds free turns for their game days (turns); moves schedules' game days (shift); rebuilds the badly balanced leagues at their own size (balance) SCHEDULE_FORMAT.md
sqb.py SQB1 sequencer scripts: the root flow scripts in SEQ/ and the PwkScript formulas in PSC*.PAC; checks every command and label, disassembles with command, module and field names, prints and edits a PwkScript's data tables (tables, settable, one script or several in a pack), re-encodes every script byte for byte (roundtrip) and patches a command (setcmd); SQBFILENAME, GLOBALMEMORY SQB_FORMAT.md
uniform.py club kits UNIFORM_LIST.TBB (designs and colours of every club's kits), the colour clash table COLOR_TBL.TBB, the 116 licensed kits' descriptors (PLPACK and the executable's copy), and the keeper kit table UNIFORM_GK.TBB; edits kits (set, setlicence, setexe, setgk; every row round-trips) UNIFORM_FORMAT.md
stadium.py DAT/STADIUM: .PRI draw priorities, BUILD_STADIUM.TBB (which model each of the 119 stadiums uses), packs per model; setlook builds a stadium like another and setboards sets its 12 advert boards, and roundtrip checks each row's edit STADIUM_DIR.md
system.py DAT/0SYSTEM: the 77 UI colours, DETAILFLAG, the 8 crest, badge and sponsor texture packs (which entry a team id picks), icons 0SYSTEM_DIR.md
emblem.py DAT/EMBLEM: the club editor's 96-colour palette and its 32/16-colour maps, crest masks, patterns and accessories, the sample, starting and rival crests field by field (crests), flag parts, and how the tables and packs line up. Writer: set edits the crests, presets, layer records and flag records, roundtrip re-encodes them EMBLEM_DIR.md
news.py DAT/NEWS: the newspaper's picture packs (mastheads by league, article pictures, ads) and NEWSMONTHFLAG (which months print the best-player rankings) NEWS_DIR.md
acrobata.py DAT/ACROBATA: the 875 Acroarts event scenes (ABDA/ABRS, POF0 pointers, the Ninja and texture resources inside), and the executable's index copy and scene-id table ACROBATA_DIR.md
humanid.py BG/HUMANID.BIN, the human database: for each human id, the search function and the person (object) shown on a warm, mild or cold day; the executable's object table BG_DIR.md
cvs.py the developers' CVS/ folders: each file's original name, revision and date, and which files the build added CVS_DIR.md
python SRC/pac.py info DAT
python SRC/pac.py extract DAT/BG/BG_OF_01.MRG out/ --prs
python SRC/tbb.py dump DAT/0SYSTEM/SCHEDULE.TBB 0 --rows 10
python SRC/tbb.py replace DAT/PARAM/REGULATION.TBB 0 edited.bin out/REGULATION.TBB
python SRC/packdata.py list DAT/PLAYER/PLPACK_HOME.HED 0
python SRC/schedule.py compe DAT/PARAM 6
python SRC/sqb.py dis DAT/SEQ/ROOTMAINSEQ.SQB
python SRC/initteam.py leagues DAT/PARAM
python SRC/pbdata.py list DAT/PARAM/PBDATA_EU.PAC --find terry
python SRC/pbdata.py set DAT/PARAM/PBDATA_EU.PAC out/PBDATA_EU.PAC 101 age=30 ability.13=99

Graphics

Tool Formats Doc
svr.py Ninja textures .SVR/.SVM/.SVP, including GS unswizzling SVR_FORMAT.md
csp.py .CSP/.CSE 2D screen layouts (sprites, node tree, animation) CSE_FORMAT.md
zbf.py .zbf depth buffers for pre-rendered rooms ZBF_FORMAT.md
ninja.py Ninja models and motions .SNJ/.SNO/.SNM/.SNP/.SNA, loose and inside archives; OBJ export, animated glTF export NINJA_FORMAT.md
python SRC/svr.py png DAT out/textures
python SRC/csp.py png DAT/CSE out/cse --crops
python SRC/zbf.py png DAT/BG out/depth
python SRC/ninja.py obj DAT/TEST3D/CAMERON.SNO out/cameron.obj
python SRC/ninja.py obj "DAT/PLAYER/FC_EURO_FACEPACK_00.HED#0.0" out/face.obj
python SRC/ninja.py gltf out/player.gltf DAT/PLAYER/M_PLAYER.SNO "DAT/GAME/PLAYERMOTION.PAC#68:snm"

Sound

Tool Formats Doc
sounddat.py SOUNDDAT.PAC, commentary .TBL, ps2_DTPK banks (samples, instruments, and songs as MIDI files or rendered WAVs), FNAME* clip names; the executable's sound-bank and music-id tables (music) GAME_DIR.md, SOUND_DIR.md
afs.py ISO/AUDIO/*.AFS: music, commentary, crowd chants and ambience (CRI AFS + ADX); checks every entry, decodes to WAV with loop points AUDIO_DIR.md
python SRC/sounddat.py info DAT/GAME/SOUNDDAT.PAC
python SRC/sounddat.py extract DAT/GAME/SOUNDDAT.PAC out/sound --wav
python SRC/sounddat.py songs DAT/SOUND
python SRC/sounddat.py midi DAT/SOUND/MAP01.DAT out/midi
python SRC/sounddat.py music ISO/SLES_541.51 DAT/SOUND
python SRC/afs.py list ISO/AUDIO/BGM.AFS
python SRC/afs.py wav ISO/AUDIO/BGM.AFS out/bgm

The MIDI files carry the note data only, with loopStart/loopEnd markers. wav renders the songs with the banks' own instruments instead.

Text

Tool Formats Doc
mbb.py MESSAGE/MES.PAC and its MBB1 message files, all 7 language slots; vars reads what fills each variable from SLES_541.51 and SIMPRG.REL; names writes the club, national team and competition names with their copies as a table to fill in with real names MBB_FORMAT.md
realnames.py SRC/realnames.csv, the real club, stadium, national team and competition names for --mod real-names, and SRC/realnames_phrases.csv, the hand edits of the other languages' mentions: import from the mbb.py names table, info checks them against MES.PAC, apply writes them LMASTER_MOD.md
python SRC/mbb.py info DAT/MESSAGE/MES.PAC
python SRC/mbb.py dump DAT/MESSAGE/MES.PAC --cat 35002 --lang 1
python SRC/mbb.py csv DAT/MESSAGE/MES.PAC messages.csv
python SRC/mbb.py import DAT/MESSAGE/MES.PAC messages.csv out/MES.PAC
python SRC/mbb.py set DAT/MESSAGE/MES.PAC out/MES.PAC 3 2007 1 "Chelsea FC" 3 2007 2 "Chelsea"

The CSV has one row per message and one column per language. Control codes appear as tags such as {var:1:7} and {color:4}. import writes an edited CSV back (and set one or more messages). A file that gets longer grows into the spare room after it in MES.PAC (a median of 1,544 bytes per category and language), and the archive keeps its size (details).

Event data

Tool Formats Doc
evsdatabin.py EvsDataBin_{EVENT,NEWS,MAIL}.bin (the shipping event tables) EVSDATABIN_FORMAT.md
eventdata_turn.py EVENTDATA_TURN.TBB (unused prototype) EVENTDATA_TURN.md

Both write CSV to a file, or to stdout if no output path is given:

python SRC/evsdatabin.py DAT/EVENT/EVSDATABIN_EVENT.BIN event.csv
python SRC/evsdatabin.py DAT/EVENT/EVSDATABIN_MAIL.BIN mail.csv --text DAT/MESSAGE/MES.PAC

With --text, each message reference (event dialogue, news headline and body, mail sender/subject/body) gets a column with its text from MES.PAC.

The tables aren't the whole event system. Scouting, transfers and loans run as code-only "procedures" that send MAIL records; see EVS_PROCEDURES.md. What an EVENT does after its dialogue (open a screen, start a talk, chain another event) is its scene type; see EVSDATABIN_FORMAT.md.

Patching the disc

Tool Reads Does
patch_disc.py the disc image, ISO/DATA.CVM or ISO/DATA.ISO writes edited DAT/ files, archive entries and files outside DATA.CVM (disc:SLES_541.51) back onto the disc, with their copies (below), and applies named switches (--mod; --mod lmaster-lite, --mod lmaster-full and --mod lmaster-max for the LMASTER Mod); locate, copies and verify find where a file lives, where its copies are, and check an image holds given bytes; switches prints the editions, groups and switches
preload.py DAT/PRELOAD, ISO/SLES_541.51, ISO/DLL/*.REL checks every PRELOAD pack entry against the file it copies, gives each pack's free room for a rebuild, prints the game's load lists, and says which packs hold a file and which screen loads each (who), i.e. where the game reads that file from
python SRC/pbdata.py set DAT/PARAM/PBDATA_EU.PAC out/PBDATA_EU.PAC 101 age=30
python SRC/patch_disc.py patch disc.iso modded.iso PARAM/PBDATA_EU.PAC=out/PBDATA_EU.PAC --copies
python SRC/preload.py who DAT 3_1.mbb       # the English club names: read from STATIONMES1.PAC

What patch_disc.py patch handles (REBUILD.md):

  • Size changes. Only the table of contents of DATA.CVM is encrypted, so a file that keeps its size is written over the original without re-encrypting anything. A file can grow or shrink inside its last sector. One that needs more sectors is moved to the end of DATA.ISO, which re-keys the table of contents and grows the disc image if it has to.
  • Archives. An entry that changes size rebuilds its archive: a PRELOAD pack, any other BINPAC with its .HED copies, and for MES.PAC and the Acrobata pack the executable's index of it. KC@P packs are rebuilt by pac.py replace (REBUILD.md).
  • Copies. Many files have a copy in a PRELOAD pack, and the game reads that copy whenever the pack is loaded, so an edit must reach both. --copies updates every copy and rebuilds the packs around entries that change size (PRELOAD_DIR.md).
  • Switches (--mod <name>,..., or each as a flag of its own). The LMASTER Mod (LMASTER_MOD.md) comes in three editions, --mod lmaster-lite (the fixes), --mod lmaster-full (the fixes, the third tier, the restored injury lines, real names and grounds, with the modded disc's own saves in -F) and --mod lmaster-max (full and the difficulty groups, saves in -M; both keep VS data in -V), made of groups of switches; --mod takes a name of any level (the switch levels), and python SRC/patch_disc.py switches prints the tree with a line on each switch; LMASTER_MOD.md has the details of each. The test tools, in no edition, are skip-tutorial (skips the opening playoffs; --skip-nation picks the league) and launcher (boots into the developers' debug menu).
  • --rename renames a file outside DATA.CVM. Every patch of a whole image prints the executable's PCSX2 CRC.
Tool Reads Does
vcdiff.py two disc images, or an image and a patch makes and applies xdelta patches (VCDIFF, RFC 3284) in plain Python, for sharing a mod against the Redump image; applies patches xdelta3 made, with its LZMA or DJW secondary compression; images may be CSO or ZSO
cso.py a CSO or ZSO image reads compressed disc images (CSO v0–v2, ZSO; deflate and LZ4) for vcdiff.py and patch_disc.py, and hands CHDs to chd.py; info checks the index, check gives the ISO's SHA-1 and whether it is the Redump dump, extract writes the ISO
chd.py a CHD image reads MAME's CHD v5 (DVD, raw and one-track CD CHDs; zlib, LZMA, Huffman, FLAC and the CD codecs, zstd with Python 3.14) for the same tools; info shows the header, codecs and metadata, check decodes every hunk against its CRC and the header's data SHA-1 and gives the ISO's SHA-1, extract writes the ISO
python SRC/vcdiff.py make disc.iso modded.iso mymod.xdelta

Saves

Tool Reads Does
save.py a memory-card save folder, ISO/SLES_541.51, ISO/DLL/SAVEPRG.REL decrypts and decodes a saved game by running the game's own serializers and re-encodes it byte for byte. Shows the club, squad, youth team, staff, pair combinations (combi), candidate lists (candidates), accounts and season plan (finances), the other clubs (clubs) and the imported Virtua Pro Football player (editplayer). set edits money, club status, players' abilities, condition, salary and contract, the combinations, staff and dissatisfaction, the season plan, other clubs' friendship and rank, and the edit player (edit:<field>). rename copies a save to a modded disc's name, copy to the card's next free slot, convert re-encodes one for a disc with --mod third-tier. --iso ISO_JP reads and writes the Japanese release's saves
ps2mc.py a PCSX2 memory card image (.ps2 file) lists and checks the card (every page's ECC, every chain), copies saves off it (get), and writes a new image with a file replaced or added (put) or a folder added (mkdir) or copied (copy), with the ECC and FAT kept right; roundtrip writes every file back to an identical image
pmplayer.py Virtua Pro Football's pmplayer.bin, ISO/DLL/SAVEPRG.REL the edit players a career can import: decrypts and checks the file, shows each field and what the import makes of it, edits names, height, weight, abilities, skills, styles and the rest (set), round-trips byte for byte, and compares a career's imported player with its record (check)
python SRC/save.py show <card>/BESLES-54151-G003
python SRC/save.py player <card>/BESLES-54151-G003 3
python SRC/save.py set <card>/BESLES-54151-G003 edited.bin money=2000000000 0:all=99
python SRC/save.py rename <card>/BESLES-54151-G003 <card> F  # to BESLES-54151-F003, for LMASTER full (M for max)
python SRC/pmplayer.py show <card>/BESLES-54153FASYS00/pmplayer.bin

See SAVE_FORMAT.md and PMPLAYER_FORMAT.md.

Editor

Tool Reads Does
editor.py DAT/, ISO/, a mod folder the mod editor: one window with a tab per kind of data (USAGE.md), saving to a mod folder (mod/ by default) and writing the matching python SRC/... command to mod/editor.log; File > Build disc makes the modded image or patch
saveedit.py a career save on a PCSX2 folder memory card or card file (.ps2) the save editor: a separate window for one save, through save.py (USAGE.md, SAVE_EDITOR_PLAN.md)
python SRC/editor.py open             # the mod folder mod/
python SRC/editor.py open mods/terry  # another mod folder
python SRC/saveedit.py open <card>/BESLES-54151-G000   # a save on a folder memory card
python SRC/saveedit.py open <card>.ps2                 # a card file: pick a save from it

USAGE.md is the guide to both windows: the mod editor's tabs, Build disc and the save editor's pages. Each tab edits through a writer's own functions and takes the field names and ranges from it (pbdata.edit_spec), so a file saved by the editor is byte for byte what the logged command gives. The mod folder keeps each file under its DAT/ path, and files from outside DATA.CVM under disc/ (mod/disc/SLES_541.51), which matches patch_disc.py's targets.

How the tools fit together

Tools reuse each other by importing the sibling script. The ones not listed (afs.py, bpb.py, chd.py, cvs.py, gamedata.py, pac.py, ps2mc.py, rofs_decrypt.py, svr.py, tbb.py) stand alone, and regress.py runs the others as commands.

Tool Builds on
sles_disasm.py, snr2.py each other: the executable's symbols name an overlay's imports
gamever.py sles_disasm.py, snr2.py; and every tool that reads the executable or an overlay uses it to find PAL addresses in another build
extract_disc.py rofs_decrypt.py
csp.py svr.py for the textures inside CSP packs
zbf.py pac.py, to read depth buffers straight from BG_*.MRG
humanid.py pac.py for the PRELOAD copies; sles_disasm.py and gamever.py for the object table
eventdata_turn.py tbb.py
evsdatabin.py mbb.py for --text
packdata.py, ninja.py pac.py (KC@P entries, PRSH) and each other; ninja.py also svr.py for its exports
stadium.py, system.py, schedule.py pac.py, tbb.py
emblem.py, news.py pac.py, tbb.py, svr.py
mbb.py pac.py for MES.PAC; sles_disasm.py, snr2.py, gamever.py for vars
sqb.py pac.py, packdata.py for COMBINATION2.CSB, pbdata.py for field and ability names
pbdata.py pac.py, tbb.py, initteam.py (club names), mbb.py (Japanese names), sles_disasm.py and gamever.py (--sles)
initteam.py pac.py, tbb.py, pbdata.py and mbb.py for names
teaminit.py, plrcommon.py, plrsim.py tbb.py and pbdata.py for names; the last two pac.py; teaminit.py limits sles_disasm.py and gamever.py
regulation.py tbb.py, schedule.py for the team-entry check and leaguesize.py for the schedules' names
clubresult.py tbb.py, and regulation.py and schedule.py for the club-count checks
training.py tbb.py, pbdata.py for the ability names and mbb.py for the practice names
camp.py pac.py, tbb.py, and mbb.py for city and club names
formset.py, tour.py tbb.py, and pbdata.py (formations) or camp.py and initteam.py (club names)
clubrank.py tbb.py, and camp.py for the competitions' names
leaguesize.py schedule.py, initteam.py, regulation.py, clubresult.py, clubrank.py
uniform.py pac.py, tbb.py, packdata.py and svr.py (licensed kits), sles_disasm.py (the executable's copy), initteam.py (club names)
clubevent.py sles_disasm.py and gamever.py for the tables, camp.py for the names
natcal.py tbb.py, and schedule.py for the national cups' turns
acrobata.py pac.py, ninja.py, svr.py, snr2.py, sles_disasm.py
sounddat.py sles_disasm.py for music
preload.py pac.py, and sles_disasm.py for the load lists
save.py sles_disasm.py and snr2.py to run the game's serializers; pbdata.py, initteam.py, tbb.py for field layouts, names and tables; teaminit.py for the salary limits
patch_disc.py extract_disc.py and rofs_decrypt.py (finding files, rewriting directory records), cso.py (a CSO, ZSO or CHD input), pac.py (rebuilding archives), tbb.py, sles_disasm.py and gamever.py (the executable, the Japanese build), sqb.py (--skip-tutorial), schedule.py (national-cups, league-balance, third-tier), regulation.py, clubresult.py, initteam.py and pbdata.py (third-tier), camp.py (the camp switches), training.py and mbb.py (drill-names, injury-lines), plrcommon.py (facility-tiers), plrsim.py (overseas-bases)
editor.py the writers it edits through: pbdata.py (People), initteam.py (Clubs, Season), leaguesize.py (Season), natcal.py (National calendar), teaminit.py (New club), plrsim.py (Free agents, Player links, Overseas bases), initteam.py (Nations & stadiums), stadium.py (Stadiums), regulation.py and clubresult.py (Regulations), clubrank.py (Club ranking), training.py (Training), camp.py (Camps), tour.py (Tours), plrcommon.py (Facilities), clubevent.py (PR events), formset.py (Tactics), uniform.py (Kits), emblem.py (Crests), mbb.py (Text), sqb.py (Comments); extract_disc.py and patch_disc.py for Build disc, sles_disasm.py and pac.py for the executable and pack headers
saveedit.py save.py, editor.py (widgets), ps2mc.py (card files), pbdata.py and initteam.py for names
pmplayer.py save.py (cipher, CRC, and career saves for check), pbdata.py for field names, gamever.py
cso.py, vcdiff.py chd.py for CHD images; vcdiff.py reads images through cso.py

The disassemblers connect to the format tools through the docs: a format is found in the code, documented in DOC/, implemented in SRC/ and checked over all of DAT/ (the full workflow is in AGENTS.md). Every tool's check then goes into regress.py, which compares the output with a saved baseline:

python SRC/regress.py bless        # once, from a known-good state
python SRC/regress.py run          # after every change; exit 1 on any difference

Baselines are kept in .regress/, which is git-ignored because they list file names and counts from your disc. When an output change is intended, bless <name> accepts it.

Documentation index

Every format and folder doc labels its claims confirmed or empirical and has a "Still unknown" section. For players, INSTALL.md covers checking the disc, applying a patch and saves.

Disc, rebuilding and sharing

Doc Covers
DATA_CVM_EXTRACTION.md the DATA.CVM container, how the ROFS key is derived from its header, regenerating DATA.ISO
REBUILD.md putting edited files back on the disc (in-place patching, size changes, moved files, a grown disc, copies and rebuilt archives), sharing mods as xdelta patches, compressed images (CSO, ZSO, CHD)
PRELOAD_DIR.md DAT/PRELOAD: the bulk-load packs, the load lists and folder ids, and which copy of a file the game reads, and rebuilding a pack
JAPANESE_RELEASE.md the Japanese release (SLPM-66316): setting it up, how gamever.py finds addresses in it, and how its code and data differ from PAL
LMAST_DATA_CVM_INFO.md the original ROFS key recovery in PCSX2 and cvm_tool workflow (historical)

Game code and game systems

Doc Covers
SNR2_FORMAT.md DLL/*.REL overlay format, the SN DLL loader, SLES_541.51's imports, which overlay each sequencer module lives in, the wild-card module, C++ classes from their type information
SQB_FORMAT.md SEQ/*.SQB and PSC*.PAC sequencer scripts: command encoding, argument types, labels, the root and PwkScript command sets, what the PwkScripts compute (only the detail-screen comments run), global memory, the tutorial skip and the developer launcher
GAME_FLOW.md the root scripts as a flow chart: title routes, new game, loading, the season loop, year start, main menu, match day, game over, the event timings
EVS_PROCEDURES.md the scouting, transfer and loan procedures (code-only events), scout-list search criteria, squad and loan limits, the 13 regions
INJURIES.md how injuries are rolled (fatigue and age pick the kind), the value table, recovery, and the condition-line messages, two of which were cut
ECONOMY.md the club's economy: what a build costs (record cost × business cycle × sponsor discount), the plan screen's limits, attendance, tickets and season tickets, popularity, sponsors and TV, merchandise, transfer fees, PR events, camps and tours, and the switches that change them
CLUBEVENT_FORMAT.md the PR events in the executable: the offer, chance and success records field by field, the names in MES.PAC, when each event is offered, the cut Renew Mobile Site, and the Japanese differences
CLUB_LIMITS.md where the code fixes the clubs at 441 (resident clubs 1–441, the non-resident 442–459): every site of 440–442, sorted into club loops, resident checks, buffers and the rest, and how the third tier makes 442–459 full clubs
UID_LIMITS.md where the game fixes the schedules at 164: UID 164 as the default rules, the files that set the count, the code that names it, the save pools the schedules share, and the third tier's leagues and seasons
SAVE_FORMAT.md memory-card saves: Blowfish key, header and layout CRC, the ten Pwork blocks, money, date and squad fields, separate saves and the PCSX2 CRC for a modded disc
PS2MC_FORMAT.md PCSX2's memory card image files: pages and their ECC, the superblock, the FAT, directory entries, and how ps2mc.py writes a card
PMPLAYER_FORMAT.md Virtua Pro Football's edit players (pmplayer.bin): file layout, CRC, each record field and what the career import makes of it, and its play-style bug
SAVE_EDITOR_PLAN.md the save editor's design on top of save.py: its pages, the steps it was built in, the decisions made, and what is tested in the game

Mods and patches

Doc Covers
LMASTER_MOD.md the LMASTER Mod: its editions, groups and switches, each fix and improvement with its evidence and test status, the third tier, the real names, the real grounds, and the candidates still to build
SPONSOR_NEGOTIATION.md the Sponsor screen's main sponsor negotiation, switched off in PAL by a stub check, and the patch_disc.py --sponsor-negotiation patch that restores it
WIDESCREEN.md the PCSX2 16:9 patch (PNACH/): Hor+ 3D, and the UI fix that draws the HUD, menus and season-mode backdrops at 4:3

Containers

Doc Covers
PAC_FORMAT.md BINPAC, KC@P, PRSH, and how the packer laid BINPACs out (the writer)
TBB_FORMAT.md TBB1/TBL1 tables, symbol recovery from SLES_541.51

Folders of DAT/ (and ISO/AUDIO)

Doc Covers
0SYSTEM_DIR.md DAT/0SYSTEM: UI colours, crest/badge/sponsor texture packs and how an id picks an entry, fonts by language, icons, leftovers
ACROBATA_DIR.md DAT/ACROBATA: the Acroarts event scenes, their chunk layout and resources, the executable's copy of the pack index, scene ids by language
BG_DIR.md DAT/BG: the rooms' archives and room codes, the 103 people and their heads, hair and palettes, hands and props, trophies, HUMANID.BIN
CVS_DIR.md the CVS/ folders left on the disc: original file names, commit dates, which files the build made
EMBLEM_DIR.md DAT/EMBLEM: the club editor's crest and flag parts, its colour palette, the edit tables, and the player-editor tables
GAME_DIR.md DAT/GAME: commentary, sound banks, models, motions, the match AI's files and its leftovers
NEWS_DIR.md DAT/NEWS: newspaper mastheads, article pictures, ads and cartoons, and the monthly ranking flags
PARAM_DIR.md DAT/PARAM: which code loads each file, record sizes, and the tables without a doc of their own
PLAYER_DIR.md DAT/PLAYER: face packs, licensed kits, etc::PackData
SEQ_DIR.md DAT/SEQ: the root sequencer scripts, which are loaded, their CVS history
SOUND_DIR.md DAT/SOUND: which bank is which, the executable's bank table, and the music table (music id → song or stream)
STADIUM_DIR.md DAT/STADIUM: the 10 stadium models, .PRI draw priorities, crowds, adverts, BUILD_STADIUM and its writer
TEST3D_DIR.md DAT/TEST3D: test models, debug shapes, test kits, the launcher viewers' data
AUDIO_DIR.md ISO/AUDIO: the AFS archives (music, commentary, chants, ambience), AFS and ADX layouts, 0FLIST.DIR

The starting season and parameter tables (PARAM/)

Doc Covers
PBDATA_FORMAT.md the player database: header, bit-packed player/manager/scout records, ability and money tables, the match's player parameters and which AI classes read each
INITTEAM_FORMAT.md starting leagues and divisions, last season's order, computer-team squads, where club names come from
TEAMINIT_FORMAT.md the player's new club: what the league and team style choose (squad, youth team, staff, rival club)
SCHEDULE_FORMAT.md the season calendar: schedule UIDs, turns, games, pairings, where entrants come from
REGULATION_FORMAT.md match regulations per schedule: prizes and win bonus, bans, squad, foreigners and substitution limits, promotion and relegation places
CLUBRESULT_FORMAT.md how each schedule reports a final place: a number, a cup round's name or nothing
TRAINING_FORMAT.md the training tables: practices, facilities, camps, match growth and decline with age
CAMP_FORMAT.md the training camps: cities, types, clubs and descriptions, and two bugs in the data
PLRESOURCECOMMON_FORMAT.md the common resource pack: facility records (build time, upkeep, stadium capacity), formation and nation tables, and which code reads each
PLRESOURCESIM_FORMAT.md the season-mode resource pack: what each of its 16 entries holds and which code reads it

Text and events

Doc Covers
MBB_FORMAT.md message text, encodings and escape codes, talk-scene body reactions ({react:N})
EVSDATABIN_FORMAT.md club-management event tables, event ID types, scene types (what happens after a scene), talk types
EVENTDATA_TURN.md the unused turn-event prototype

Graphics and the match

Doc Covers
SVR_FORMAT.md textures and GS swizzling
CSE_FORMAT.md DAT/CSE 2D layouts
ZBF_FORMAT.md pre-rendered Z buffers
NINJA_FORMAT.md Ninja (NN) models, skeletons, motions, VU/PX Plus vertex streams
UNIFORM_FORMAT.md club kits: UNIFORM_LIST bit layout, kit designs and colours, the 96 colours, the COLOR_TBL clash table, UNIFORM_GK keeper kits
BPB_FORMAT.md the match AI's play books: records of player and ball paths, point coordinates, play ids; the COMBINATION2.CBB records and the 29 combination commands
GAMEDATA_FORMAT.md GAME/GAMEDATA.BIN's 0x30-byte ball-contact records (partial) and the unread AI_PARAM.BIN

Working on the project

CONTRIBUTING.md explains how to report a bug, test something in the game, or send a change, and what a change needs before it is merged. Everyone taking part follows the CODE_OF_CONDUCT.md.

AGENTS.md has the conventions for docs and tools, the workflow for a new format or writer, and where each kind of record goes: facts and open questions in DOC/, tasks by stage in TODO.md, finished items in DONE.md. It is written for AI assistants but applies to anyone.

The project is run by Nexxus (Pyra Drake, Nexxus Drako Multimedia), who directs the research and makes the in-game tests; the docs record those results as "Nexxus's report".

License

The code in SRC/ and the documentation in DOC/ and this repository are licensed under the GNU General Public License, version 3 or (at your option) any later version. See LICENSE. Each file carries an SPDX-License-Identifier: GPL-3.0-or-later header.

This covers only the work in this repository. The game, its disc image and its data files are not part of it and are not covered by this license.

Contributors

See CONTRIBUTORS.md for everyone who has worked on the project, the community it is made for (the LMAST/SFCC English Fan Discord), the first decryption of DATA.CVM by @tw09627, and the software it builds on.

Acknowledgements

Neither the maintainer nor the community are equipped to deal with mental health or other crises. Please use findahelpline.com to find a local helpline, or if the crisis is life-threatening, contact your local emergency services.

Nexxus Drako Multimedia was created on the stolen lands of the Jagera and Turrbal peoples, in what is now called Brisbane. Sovereignty was never ceded. This always was, and always will be, Aboriginal land. I pay my respects to Jagera and Turrbal Elders past and present, and to all Aboriginal and Torres Strait Islander peoples.

Colonisation didn't end; it's ongoing, and I back First Nations-led fights for land back, treaty and truth-telling.

Nexxus Drako Multimedia is queer-run and queer-made. Trans, nonbinary, intersex, asexual, aromantic, bi, pan, lesbian, gay and every other queer voice is welcome here, and actively backed: not tolerated, backed.

Transphobia, intersexphobia, homophobia, biphobia, acephobia and any other bigotry get you removed, no warnings and no debate.

Trans rights are human rights.

About

Let's Make A Soccer Team Reverse Engineering Project (AI-Powered)

Resources

Code of conduct

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages