Converting Codes

Since there are multiple regions for games (Jap, U.S., Europe) and sometimes multiple versions in a single region (U.S. SSBM v1.0, v1.1, v1.2), there often arises the desire to have the code in one region/version converted to another region/version. This write-up deals with the basics of that conversion process.

Offsets:

The difference in memory address between codes for two versions/regions of a game is called an offset. This just means that the addresses are offset from each other.

Finding an offset is often easy. Making sure its the best one to work with for your code requires more understanding.

How to find an offset:

  1. Take a raw code that exists for both versions/regions. Ideally they should be writing the same value and not be an ASM or (m) code. While it is possible to use ASM codes (eg. 60000000, 38030000; ie. complex looking values) to determine the offset at that area of memory, it can lead to incorrect results.
  2. Remove code type formatting (to pull out just the memory address) and find the difference between the two codes by subtracting.

    Note: If one version is lower than the other version, it will typically stay lower in all converted codes.

Repeat steps 1 and 2 for all codes that exist in both versions/regions. You now know the offsets at those memory addresses. However, offsets increase in abrupt steps as you proceed in memory.

How to convert your code:

  1. Find the memory address (with a known offset) in the region you are converting from that is nearest the code you wish to convert.
  2. Apply that offset and test.

    Note: For 99% of all the plain 8/16/32-bit writes, you should use the value from the original code in your converted code. I am not sure what the 1% would be (outside of ASM, which can easily change the value and is another good reason to not have high expectations of converting it), but I'll leave it open, just in case.

If it works, congratulations! If it doesnt, recognize that offsets increase the farther you are into memory. If the code you want to convert comes after a known offset, increase the guess offset by 4. If it comes before, decrease the guess by 4.

Of course, the closer the known offsets are to the code you wish to convert, the better the chance of actually getting the correct offset.

Here is an example graph showing the relative offsets from SSBM v1.0 of SSBM v1.1 and v1.2. Real, known offsets were used.



Notes: I have found this method to be most applicable to different versions of games (e.g. 1.0, 1.1) and generally the same between regions. However, I'd like to point out some specific examples that "buck the trend."
  1. Region Conversions: In general region conversions still follow the idea of a trending offset through memory. However, sometimes the trend is backwards from what I have seen between versions.

    Example:

    SSBM PAL is lower than SSBM v1.0, but whereas you would normally expect it to be close at lower memory addresses and farther apart at higher addresses, it is actually the opposite. SSBM PAL gets closer to SSBM v1.0 as you go up in memory.
    v1.0 Addr  PAL Offset
    
    00450CAC   -D2A0
    00469722   -D230
    004D9000   -CB60
    Now, it still follows a trend, but it is opposite what I would normally expect that trend to be.


  2. Slight Variations in the "trend": The offset from a lower version to a higher version generally increases in memory. However, I have run into at least one example of a slight variation, and I do mean slight.
    v1.0 Addr  v1.1 Offset
    
    00469722   12E8
    004D473C   1460
    004D9000   1458
    As I said, a slight variation, but I just want you to realize that these instructions will send you in the right direction most of the time. However, there are a few "gotcha's" to keep an eye out for.


  3. Converting between systems: Normally you may not expect to be able to convert a PS2 code to GameCube and vice-versa, but it is possible.

    In Pac-Man World 2, there are a lot of items you can collect in each level. When looking at the decrypted codes for the items between the PS2 and GameCube versions of the games, I realized that the items were all offset from each other the same in both systems. Using that, I was able to successfully port the 999 Pac-Dots codes from the PS2 version to GameCube. In this case, it was a section of memory (the amount of each item collected in a level) that was laid out the same in each system's games. Most of the other Pac-Man World 2 codes weren't transferrable between systems, though.

    When looking for possible codes to convert, don't forget to check out the codes for PS2 (and N64, NES, and SNES, as GameCube has a few of those games, as well.).


Appendix

Background/Foundation

The first thing you need to be able to do is to pull the memory location out of a formatted, unencrypted AR code. (hex familiarity is a must) For simplicity, I will be ignoring the leading 8 on memory addresses. For the GameCube, the max possible memory location is 017FFFFF, because it has 24 MB of memory.

The most common AR code types you will probably see are 8/16/32-bit writes.
8-bit write  - 00000000 + address (value like 000000xx)
16-bit write - 02000000 + address (value like 0000xxxx)
32-bit write - 04000000 + address (value like xxxxxxxx)
where x is a character you wish to write.

Example:
8-bit write  - 0046A428 00000012
16-bit write - 0246A428 00001234
32-bit write - 0446A428 12345678
If you are converting an existing code, it is usually best to use its code type (i.e. if it starts with an 04, you start with an 04).

Important: In most conversions, the code type of the code converting from will be the code type for your code, as well. However, it is necessary to recognize the base address to smartly determine the correct offset.

Quiz:

Q: What is the memory location and bit size to write for this code? 04453238
A: The memory location is 00453238, and the bit size to write is 32-bit.

Q: Is 039F634B a valid address for an AR code?
A: No. A 16-bit write would go up to 037FFFFF and 32-bit writes start at 04000000.

Converting Codes Example: (SSBM v1.1 to v1.2)

  1. Take the code to convert and find its memory location.
    All 293 Trophies v1.1 (addresses only)
    0245B6B0
    0245B6B5
    
    What's the memory location? If you answered 0045B6B0 and 0045B6B5, you are correct.

    What size write is this? If you answered 16-bit, you are correct.

    You now have a v1.1 memory location for "All 293 Trophies."


  2. Find an existing code in v1.1 that is close to the memory location to convert that also exists in v1.2.
    All Bonuses v1.1 (address only)
    0045B668

  3. Find the offset between the two known codes.
    All Bonuses v1.2 (address only)
    0045C348
    
    0045C348 - 0045B668 = CE0

  4. As a first guess, use this offset to convert to v1.2.
    0045B6B0 + CE0 = 0045C390
    0045B6B5 + CE0 = 0045C395
    
    Since this is a 16-bit write, add 02000000 to these values.
    0245C390
    0245C395
    
    These would be the first tries for the memory location for converting "All Trophies" to v1.2.


It happens that these are the correct values for v1.2's "All Trophies," but if they weren't, a next step would be to move around in word sizes (by 4's) to find the correct offset.


Summary

  1. Find the memory location of the code to convert.
  2. Find an existing code that exists in both versions around the same memory location.
  3. Find the offset for the existing code.
  4. Try that offset for a first "guess," and if it doesn't work, try moving around in memory to find the correct offset.