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.
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.
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.
