The Legend of Zelda: A Link to the Past and Four Swords/Notes

From Data Crystal
Jump to navigation Jump to search

Chip tiny.png The following article is a Notes Page for The Legend of Zelda: A Link to the Past and Four Swords.

A Link to the Past

Message Storage Differences

Compared to the SNES version of A Link to the Past, the message format differs quite a bit in several ways:

  • The SNES text banks are split up across the rom with most in-game text residing between 0xE00000-0xE7356 and 0x75F40-0x76E20 for the English ROM while the Japanese ROM has a single large text bank between 0xE0000-0xE7356. The GBA rom contains a single encrypted text bank found in the range provided in the table below..
  • The decrypted bank yields a primitive version of the BMG message format that contains MSEGbmg1 (+0x00), INF1, and DAT1 segment (+0x760).
  • Control codes are prefixed with BMG format style escape sequences 0x1a and many of the escape sequence suffixes utilize the same control codes from the SNES era.
Message Bank Information
Version (CRC) Decryption Password Bank Range
JP (81E42BEE) P9uD4FwcX6s+ALMr 0x00184c68-0x00197608
US (8E91CD13) l0ZxE8SjYv3#RhaX 0x001820E8-0x00195D88

Reading Messages

In order to read messages within the A Link to the Past portion of the ROM, a password and simple algorithm are required. Using a method like the below, you read the entire block and "decrypt" the region using the algorithms below.

private static readonly byte[] DecodeKey = Encoding.ASCII.GetBytes("<password>");
public static byte[] DecodeRegion(byte[] rom, int start, int length, int baseOffset)
{
    var output = new byte[length];

    for (int i = 0; i < length; i++)
    {
        output[i] = DecodeByteAt(rom, start + i, baseOffset);
    }

    return output;
}

public static byte DecodeByteAt(byte[] rom, int absoluteOffset, int baseOffset)
{
    int relative = absoluteOffset - baseOffset;
    if (relative < 0)
        throw new ArgumentOutOfRangeException(nameof(absoluteOffset), "Offset is before base.");

    uint offset = (uint)relative;
    uint low8 = offset & 0xFF;
    int nibble = (int)(offset & 0x0F);

    uint value = (low8 - DecodeKey[15 - nibble]) ^ rom[absoluteOffset];

    if (offset >= 0x2B)
    {
        value -= rom[absoluteOffset - 0x2B];
    }

    value = ((value - low8) ^ DecodeKey[nibble]) & 0xFF;
    return (byte)value;
}

Once complete, you can parse the actual message format, which appears to be a very early version of the BMG format, seen in games as early as Pikmin 2. The BMG format and its headers, while descriptive of the text, don't need to be parsed in order to make sense of the text inside. To parse message, simply start at the bank offset begin + 0x770 and read each byte of the decrypted text bank until you reach a message terminator 0x7f. The native storage format for messages in the GBA version of A Link to the Past is ASCII + BMG style control code branching. The message terminator is the same in English and Japanese.