« Quotable Quotes | Main | Don't Come Monday »

January 02, 2004

TechTip: Cheat (Civ III Mac)

Wednesday night I got an email from some dude asking about a hack I did a couple of years back for Civilization III (the game) running on the Mac. One of the small pleasures I enjoy is to write little bits of code for hacking save files for games. In this case the dude can't find my instructions (neither can I for that matter) and he mentioned that the latest patch uses compressed files. No worries, there is an uncompression program (JMapstat) which runs in Java but now how about that save file? Well it looks like the number he wants to fiddle (the amount of gold) is encoded. I can fiddle the science settings but the gold is really well disguised (with some kind of check sum) to make sure it can't be edited. That's not too much of a problem because I can insert a known good value - if I can find one.

Well I can generate a save game with $2,500 in the appropriate place, grab that value and reinsert it. Hmmm. Now I need to get a save file with more money in it......

If you want to see the code, check the extended entry....

[For the search engines: civ3 mac civIII save file cheat trainer macintosh civilization]

use IO::Seekable ;
# Change the next line to where you installed JMapstat
chdir '/tmp/JMapstat' ;
# I am too chicken to edit the file live
`/bin/cp Mapstat.tmp zzz.SAV` ;
open(FH, "+<./zzz.SAV") or die ;
$/ = "" ;
# Guess a starting address (this works for normal size maps)
my $Guess = 0x1de90 ;
seek(FH, $Guess, SEEK_SET) ;
read(FH, $b, 4) ;
my @Fields = unpack('CCCC', $b) ;
until ($Fields[0] == 76 and $Fields[1] == 69
and $Fields[2] == 65 and $Fields[3] == 68)
$Guess++ ;
shift @Fields ;
read(FH, $b, 1) ;
push @Fields, unpack('C', $b) ;
# We now know where the LEADt bit starts.
# 48 bytes later is the cash
$Guess += 48 ;
seek(FH, $Guess, SEEK_SET) ;
read(FH, $b, 6) == 6 or die ;
@Fields = unpack('C6', $b) ;
print "Found at $Guess => @Fieldsn" ;
# $2500 => @Fields = (164, 210, 255, 255, 32, 55) ;
@Fields = (164, 210, 255, 255, 32, 55) ;
$b = pack('C6', @Fields) ;
seek(FH, -6, SEEK_CUR) ;
print FH $b ;
close FH ;

How To Use:
1. Save your game (say blah.SAV)
2. Run JMapstat and open the file BUT do not choose an action
3. Run the script above
4. You now have a file zzz.SAV which can be loaded into Civ3 as a saved game
5. There is no step 5

Posted by Ozguru at January 2, 2004 06:00 AM


Any maths genius who want to have a go at cracking the encoding (instead of just plastering another one over the top) should get in touch. I have about 40 sets of numbers (from 10 up to 2500). Mind you, it would be more helpful if you could solve my probability questions.....

Posted by: ozguru at January 2, 2004 08:01 PM