Breaking Secrets in Oracle of Ages and Seasons

People who know me online know that I love the Oracle games, that is, The Legend of Zelda: Oracle of Ages and Seasons for the gameboy. I used to have speedrun records for both games, though my only record still standing today is my 100% record. I wonder why…

These days, though, rather than speedrunning, I’ve been hacking and reverse-engineering the oracles with my disassembly. And an interesting question came to me while reversing the secret-parsing code: How can I break this?

I don’t mean crack the code; that’s been done. I mean, can I craft secrets that break the game somehow?

Background on Secrets

For the unfamiliar, the Oracle games were two separate games released simultaneously, which were able to communicate with each other through a unique password system. The game calls these passwords “secrets”.

There were 3 types of secrets:

  • Game secrets: Upon completing a game, a secret was given for you to continue the playthrough in the next game. The file created with this secret would be a “linked game” with extra events that wouldn’t normally occur.
  • Ring secrets: Secrets could be used to transfer rings, a collectable, between any two files linked with a password.
  • Event secrets: Secrets were used for special events, which involved getting a secret from an NPC in one game, telling it to an NPC in the other game, and getting a reward after completing some sidequest.

Each secret is encoded with a “Game ID” which is unique to that “lineage” of files. What this means is that every secret is uniquely tailor-made for your file; you can’t give your secrets to your friend, because your friend will have a different GameID. At least, that’s what we thought, until…

Universal Secrets

There is, in fact, a set of secrets that works on all files. They’re all listed here. No matter what secret you used to create your file, the secrets listed here will work. This is an incredibly cheap way to get all of the rings!

Why does this work? I think this was purposely put in by the developers, so they could have a master “cheat-sheet” that they could use for testing purposes. If it were written in C, the code would amount to this:

bool isValidSecret(secret) {
    if (secret.gameID == 0)
        return true;
    if (game.gameID == secret.gameID)
        return true;
    return false;
}

If the encoded GameID is zero, the secret is valid on all files. It seems pretty obvious that they explicitly wanted these secrets to work all the time. Maybe they forgot to disable this before shipping.

It’s normally impossible for the GameID to be zero in a secret; zero means “uninitialized”, so if the GameID is zero, the game will assign a random number to it before generating a secret. These secrets were generated by modifying kabili207’s excellent secrets generator.

So, that’s cool and all, but how can we break the game?

Attack Vectors

Game secrets were the most promising type to pursue. They encode all of the information needed to initialize a file. Here is a complete list of the data encoded in these secrets:

  • Player name
  • Child’s name (Bipin & Blossom sidequest)
  • Child’s personality
  • Animal Companion
  • Game type (ages or seasons, linked or hero)
  • Whether or not Link got the friendship ring from Vasu

Let’s look at each of these in turn, excluding the last two.

Player/Child name

The first thing I tried was to replace the null-terminator with a character. The game breaks in some very interesting ways when text goes past the end of the line, so I wanted to make this happen.

Unfortunately, the game always resets the null-terminator to 0 after loading the secret, so that didn’t work.

The next thing I tried was to insert control codes into the name. Basically, specific bytes will do things like “play a sound effect” or “insert another piece of text here” when inserted into text. These are deactivated when names are being printed, though - it just displays placeholder characters instead.

So, there was really nothing I could do here, aside from insert some funky characters into my name.

Child’s personality

At the time I was reversing the secret-parsing code, I had no idea how the child worked. This was as good a time as any to look into it. In terms of secrets, there wasn’t really anything I could do to break it. The child’s behaviour is just a number from 0-63. His personality depends on what range the number falls in.

This wasn’t fruitless, however. While reversing the child’s code, I found a rather interesting game-crashing glitch which isn’t directly related to secrets. This may be worthy of a future blog post.

A glitch which
almost could have been...
A glitch which almost could have been...

Animal Companion

Now we’re getting into the good stuff. There are 3 companions which Link can choose from, and which carry over through secrets - Ricky the Kangaroo, Dimitri the Dodongo, and Moosh the One Nobody Likes.

In secrets, the companion is a number from 0-15. Ricky is 11, Dimitri is 12, Moosh is 13. They clearly didn’t need this high a range of values; this is just a case of laziness. These numbers are their Object IDs.

The really fun realization I had, was that I could replace this with any other number from 0-15, and my companion would become an object with that number! Well, in the case of Ages, that was basically correct; when you meet your companion in the lost woods, the object that appears will correspond to that number. But it’s very difficult to get to that point, because Nuun Highlands gets completely messed up, and you need to briefly pass through it first. Remember how it changes based on who your companion is? Yeah… it’s a real shame, because I wanted a minecart as my companion.

I made a whole video on this, click below to see.

This trick doesn’t really work on Seasons. This is because, unlike in Ages, the circumstances around reuniting with the 3 companions are all different, so the game specifically checks that you have one of those 3 companions. If you don’t, no companion appears. Technically you can still enter Natzu Prairie from two points, and see a tiny bit of corruption, but there’s really nothing interesting to see.

They wised up to this for the PAL release; they added code to verify that the companion is valid, and they also made a whitelist of characters you could put in a name.

This is all that can be done with game secrets. But, we have one more secret type to corrupt…

Telling Corrupted Secrets to Farore

Farore accepts “return secrets” in the linked game. These are 5-letter secrets which give you an item of some kind. These have an index number which normally ranges from 0-10, but the secret can be hacked to go up to 15. You know what that means…

Unfortunately most of the hacked values don’t do anything. Although they do give you a specific item, there is a notorious issue (to oracles hackers) which causes softlocks when items which aren’t meant to go in a chest go in a chest.

As hilarious as this is, it's still a softlock.
As hilarious as this is, it's still a softlock.

There are exactly two secrets which don’t cause this softlock. They must be given to Farore in a linked file. (The secrets given are universal secrets, again made by modifying the secret generator.)

Ages: @♣♦92

  • Prerequisite: Must have entered the return secret for the pirate secret.
  • Gives you: Nothing. It says you get bombchus, but you actually get treasure 0x7C, which doesn’t exist.

Seasons: qs↑5&

  • Prerequisite: Must have entered the return secret for the library secret.
  • Gives you: The X-shaped jewel. This works! (But the prerequisite can’t be satisfied until after the jewel is needed…)

If you fail to meet the prerequisite, Farore says that the secret “isn’t in her memory”, which means she thinks you haven’t started the sidequest yet. Obviously since there is no sidequest for these corrupted secrets, she’s a bit confused.

As a bonus, here’s the secret for the chicken book:

Seasons: y▲←2D

  • Prerequisite: Must have entered the return secret for the plen secret. You’re never actually given this secret, since you’re supposed to use ring secrets instead. You need to use the secret from here after talking to the golden subrosian who starts the quest.
  • Gives you: A cuccodex and a softlock.

Conclusion

All in all, I’m pretty satisfied with how much I’ve managed to break secrets. Have fun sharing these secrets for uncompletable games with your friends!

Seasons:

w6●@H w!B■3
=25gG b38w=

Ages:

tmm♥t G●J6j
?$!Fb ●$s~2
Written on March 3, 2018