For education purposes only · no game files included · bring your own THUG2
Chapter 6
thug2 · eb60480 · "Save games fixed"

The .SKA Files

Eight THUG2 PC saves, made between 2008 and 2022, were sitting in an old install's Save folder: newf.ska, maxim.SKA, tricky.SKA and friends. The port didn't even see them. It was still saving the Xbox way, one folder per save with an icon inside. The mission: make the port read THUG2's files, write THUG2's files, and lose nothing in between.

"Story: 9875 of 11000 points / Classic: 112 of 140 goals."a save from 2022, finally saying hello

1Open one up

Every .SKA is exactly 90112 bytes. The first 20 look like a header: two checksums, two sizes, a version (37, which is THUG2's VERSION_OPTIONSANDPROS). Then a short block with readable bits, Max and newf. Then a long one, then 0x69 until the end. That's THUG1's own save layout, the one the engine already writes, with the sizes as 4 bytes instead of the 8 a 64-bit build gives a size_t. A small Python script checked the checksums on all eight files before anything else got written. Eight out of eight. Good start.

excerptxxd newf.ska | head -4

2Ask the oracle for the file names

THUG2.exe has the answers in plain text: Save/%s.SKA, Save/%s.PRK, .CAT, .GOA, .GRF, .NWS, .REP, one per save type, plus a listing function that compares extensions to decide what's what. The memory card backend lost its folders, its SaveMeta.txt and its icons, and became what THUG2 PC always was: a folder of files. Details in the Saves guide.

3First load: straight into a wall

The newest save autoloaded at boot, its checksum matched, the data parsed, and the game crashed in the goal manager. THUG1 keeps sponsor, team, cash and chapter in GoalManager_Params, and asserts that they're there. THUG2 keeps one thing there: difficulty_levels. The missing team left a pointer pointing nowhere, and the next line copied from it. Read what's there, skip what isn't, and the main menu showed the save's skater for the first time: white hair, white tee, the one from 2022.

4Read THUG2's homework

To save like THUG2, the port had to know exactly what THUG2 saves. THUG2.exe's career writer was read key by key from the disassembly. The keys are CRC checksums, so their names had to be guessed: a small brute force over a word list found careerTotalScore, classicScores, classicStats and highestChapter. The port had been saving the same numbers under names it invented, which THUG2 would never read. Now it writes THUG2's.

excerptbrute-forcing CRC32 names

5The case of the renamed save

Custom_Skater.SKA says "Custom Skater" inside. THUG2 loads a save by the name inside, so it would look for Custom Skater.SKA, not find it, and give up. Somebody renamed that file by hand, years ago. The port forgives them: if the name doesn't match a file, it opens every file of that type and asks who it is.

6Load, save, diff, repeat

The real test: load each retail save, save it back, decode both and compare every field. The first round found the small stuff hiding behind the big stuff. The chapter came back as 0, because loading the story reset the goal manager after the career had set it. The player's display name came back as the literal word Unimplemented, from a getter in the source that was never filled in. A level with no gaps came back as "never checked". The menu said 22 KB, because the port used 4 KB blocks where THUG2.exe's block size table says 1 KB. Each one got fixed, and the loop went again.

The only differences left are the ones that should be there: the last level played (the copies were made from the main menu), and the save's own name.

Where it landed

Drop THUG2 PC's Save folder into the port, and the Load menu lists every save with its story points and classic goals, 88 KB each, like 2004. Load one and keep playing. Save, and the file is the kind THUG2 writes.

THUG2's Load menu listing seven retail saves.
Old saves, new port. The summary line comes straight from each file's header block.