I am a huge fan of the game Rock 'N Roll Racing, by Silicon & Synapse (now better known as Blizzard Entertainment). I must have spent twice the price of the cart on rentals. One of my good friends landed me the actual copy of the game I used to rent all the time when the rental store closed down their SNES section. Having beat the game innumerable times, I decided to take up a new challenge - to see if I couldn't reverse-engineer the password-encoding system. The result was this:
Hand-written notes about password system. |
Rock N' Roll Racing password codec application. |
You can download the codec here (probably requires some antiquated .NET runtime, it was written just as .NET was coming to be):
Rock N' Roll Racing Codec
It was a pretty fun experiment, and I had initially written it up as a project hosted on the Waterloo Engineering student website server. Here is a slightly adapted copy of that post.
In my codec, I arbitrarily chose to use a simple numeric encoding as if the symbols were placed in rows:
Rock N' Roll Racing Codec
It was a pretty fun experiment, and I had initially written it up as a project hosted on the Waterloo Engineering student website server. Here is a slightly adapted copy of that post.
-----
The Basics
Passwords are encoded as three groups of four symbols each - twelve symbols total. On the password entry screen, the symbol table is laid out as such:
B C D F G H J K
L M N P Q R S T
V W X Y Z 0 1 2
3 4 5 6 7 8 9 !
If you count those, you’ll notice there’s thirty-two symbols. (If you’ve ever played the game, you’ve also probably noticed that both 5 and S are symbols in that table and that yes, if you have chicken-scratch handwriting, you’re likely to write down or read your password back wrong, oh damnations of damnations.) Each symbol represents one of 32 possibilities; 32 is 2^5, which that means each symbol encodes five bits of data. Since each password is twelve symbols long, this means there are 60 bits of data in a password.
In my codec, I arbitrarily chose to use a simple numeric encoding as if the symbols were placed in rows:
00 01 02 03 04 05 06 07
08 09 10 11 12 13 14 15
16 17 18 19 20 21 22 23
24 25 26 27 28 29 30 31
Or, in hex:
00 01 02 03 04 05 06 07
08 09 0A 0B 0C 0D 0E 0F
10 11 12 13 14 15 16 17
18 19 1A 1B 1C 1D 1E 1F
As it turns out this maps in quite a straightforward fashion to the encoded information, and it seems somewhat likely the developers assigned a similar layout internally. Now, what we need to figure out now is how all the game state information is encoded in 60 bits.
As it turns out, plain data is clearly segregated from the error detection bits. But first, let me explain how the bit layout works (or how it works with my codec, anyway). Here’s an example password:
Each symbol represents 5 bits. By convention (it seems the original programmers saw it this way too), let’s say bit 0 is on the left, so the X contains bits 0 to 4. Likewise, the last symbol, the M, contains bits 55 to 59. If we adopt this view of things, the 16 error detection bits occupy message bits 0 through 15, while data bits occupy message bits 16 through 59.
We are close to being able to assemble a complete password from this information, but there are a few more crannies to deal with. Certain bits are logically inverted - they use negative logic. This is noted in the following table, where the left column refers to this ficticious password:
What’s encoded...
The game encodes the following state information:Information | # of Bits | Notes |
---|---|---|
Money | 3x4 | Binary Coded Decimal (BCD) |
Difficulty Level | 2 | 0: Rookie 1: Veteran 2: Warrior 3: "Password" |
Character | 3 | 0: Snake Sanders 1: Cyberhawk 2: Ivanzypher 3: Katarina Lyons 4: Jake Badlands 5: Tarquinn 6: Olaf 7: ??? |
Planet | 3 | 0: Chem VI 1: Drakonis 2: Bogmire 3: New Mojave 4: NHO 5: Inferno 6: ??? 7: ??? (music) |
Division | 1 | 0: Division B 1: Division A |
Vehicle | 3 | 0: Marauder 1: Dirt Devil 2: Havac 3: Battle Trak 4: Havac “X” 5: Battle Trak “X” 6: ??? 7: Air Blade |
Color | 3 | 0: Black 1: Blue 2: Red 3: Green 4: Yellow 5: Aqua/Purple 6: Orange/Green 7: Green/Green (duotone type deal) |
Tires | 2 | 0: Track Masters 1: Road Warriors 2: Super Mudwhumpers 3: Atlas Power Claws |
Engine | 2 | 0: Cobra Mark VII 1: War Hammer 2: Super Charger 3: Atlas Power Boss |
Suspension | 2 | 0: Grasshoppers 1: Hydrosprings 2: Hydro Twinpacks 3: Atlas Power Lifts |
Armor | 2 | 0: Defender 1: Rhino Skin 2: Saber Tooth 3: Atlas Powerplate |
Front weaponry | 3 | VK Plasma Rifle, Rogue Missile, Sundog Beam (0 to 7) |
Middle charges | 3 | Lightning Nitro, Locust Jump Jets (0 to 7) |
Rear weaponry | 3 | BF's Slipsauce, Bear Claw Mine, K.OS Scatterpack (0 to 7) |
...and in what format
So how does the game get all this information into 60 bits? If you add up the bits, it doesn’t even make it to 60 bits - only 44. The extra 16 bits are used for error detection, but not correction. This is what causes the game to know when you just input random characters as a password and hope for $500,000 in funds… ;-) instead you just get a beep and an “INVALID PASSWORD” error.As it turns out, plain data is clearly segregated from the error detection bits. But first, let me explain how the bit layout works (or how it works with my codec, anyway). Here’s an example password:
XGL0 RS2V WS6M
0-4 54-59
We are close to being able to assemble a complete password from this information, but there are a few more crannies to deal with. Certain bits are logically inverted - they use negative logic. This is noted in the following table, where the left column refers to this ficticious password:
ABCD EFGH IJKL
Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 | |
---|---|---|---|---|---|
A | !(!Char0 ^ !Diff1 ^ !Tire0) | Engine1 ^ Diff0 ^ Div0 | !(Engine0 ^ !$23 ^ !Planet2) | !(!$22 ^ !Middle2 ^ !Planet1) | !($21 ^ Middle1 ^ Planet0) |
B | !Color2 ^ $20 ^ Middle0 | !Color1 ^ $13 ^ Rear2 | !Color0 ^ !$12 ^ Rear1 | $11 ^ Car2 ^ Rear0 | Front2 ^ !$10 ^ Car1 |
C | Front1 ^ !$03 ^ Car0 | !Armor1 ^ Front0 ^ $02 | Armor0 ^ $01 | $00 ^ Susp1 | Char2 ^ !Susp0 |
D | !Char1 ^ !Tire1 | Diff1 | !Diff0 | $23 | !$22 |
E | $21 | !$20 | !$13 | $12 | !$11 |
F | $10 | !$03 | !$02 | $01 | $00 |
G | !Char2 | !Char1 | !Char0 | Div0 | !Planet2 |
H | !Planet1 | Planet0 | Color2 | !Color1 | Color0 |
I | !Car2 | Car1 | Car0 | Armor1 | !Armor0 |
J | Susp1 | !Susp0 | !Tire1 | !Tire0 | Engine1 |
K | !Engine0 | !Middle2 | Middle1 | Middle0 | !Rear2 |
L | Rear1 | Rear0 | Front2 | Front1 | Front0 |
- Money is encoded as three separate digits, representing thousands of dollars. For example, $293,000 is encoded as 293. In the above table these three digits are represented as $2, $1, and $0 (2, 9, and 3 respectively in this example). Since each digit can range from 0 to 9, four bits are required to represent each digit. These are denoted as $23 (MSB), $22, $21, and $20 (LSB) for the hundreds of thousands; $13, $12, etc. for the tens of thousands, and so on.
- Char is the character index.
- Car is the vehicle index.
- Color is the color scheme index.
- Planet is the planet index.
- Front is the front-facing weapon count.
- Middle is the center charge count (nitro or jump jet).
- Rear is the rear charge count.
- Susp is the suspension level.
- Engine is the engine level.
- Tire is the tire level.
- Armor is the armor level.
No comments:
Post a Comment