Ocarina Unlocked
Project Co-Creator
N64 Reverse Engineering

A ROM hack of The Legend of Zelda: Ocarina of Time that opens up the progression of the game by making minimal changes to the overworld, dungeon puzzles, and how the game directs the player. The project’s philosophy was to show how minimal, in-context changes could highlight the nonlinear structure already present in Ocarina of Time, while keeping the overall experience authentic to the original release.

Patch on GitHub

Technical Summary

I co-led design and did the full implementation of the ROM hack. My work spanned the following:

  • Progression Logic: Researched Ocarina of Time’s progression systems and identified opportunities to expand dungeon order flexibility.
  • ROM Logic and Event Flags: Analyzed and modified event flags, hard/soft gates, and inventory triggers to support nonlinear dungeon progression.
  • Level Editing: Used tools like SceneNavi to manipulate dungeon and overworld geometry, including object placement, dungeon switch types, and collision flags.
  • Cutscene & Dialogue Modification: Extended existing dialogue and cutscenes to naturally guide players toward new progression paths.
  • Puzzle Modifications: Updated dungeon puzzles (Fire and Water Temples, Spirit Temple) to accommodate alternate progression, including adjusting switch types and Bow target logic.
  • Map Submenu Adjustments: Modified map pins and flashing indicators to align with expanded dungeon access, supporting in-game player guidance without altering original UI behavior.
  • Design Philosophy Stewardship: Ensured all changes were minimal, consistent with the original style, and plausible within the canonical game world.

Ocarina of Time is (Almost) Nonlinear

The Legend of Zelda: Ocarina of Time was a milestone for 3D games and the medium as a whole; confidently translating and advancing the gameplay and narrative ambitions of the previous 2D entries to the Nintendo 64. Over 25 years later one of the most remarkable qualities of the game is how effectively it communicates to the player. Its developers had to walk a fine line between delivering an adventure with a vast scope and not overwhelming an audience unaccustomed to 3D gameplay. However, a common design element of earlier entries in the Zelda series is significantly less present in OoT: nonlinear progression.

While the series at this point was no stranger to linear games—notably, Zelda 2 and Link’s AwakeningA Link to the Past and the original Legend of Zelda give the player a remarkable degree of freedom to how they approach the game. With Ocarina of Time carrying the console game torch forward from A Link to the Past, it would be expected to be similarly structured, and… it actually is! Both games send the player through three smaller scale dungeons before rewarding them with the Master Sword and access to an altered, more open world that houses many full scale dungeons. Yet at the same time it isn’t, at least not to the same extent. Ocarina of Time only lets the player complete a few major sequences out of the intended order naturally and without exploits. Specifically, the Fire Temple and Ice Caverns can be completed immediately upon becoming an adult, and the Water and Spirit Temple can be completed without touching the Fire Temple.

Chart depicting the logical dungeon order in Ocarina of Time. Linearly, it goes Deku Tree, Dodongo's Cavern, Inside Jabu-Jabu, Light Medallion, and then splits into a top and bottom row.  On the top, Forest Temple, then Water Temple, which then either continues on the top to Spirit Temple or splits down to the bottom to Shadow Temple. The bottom starts with Fire Temple, and then progresses to Shadow Temple. At the end, the two lines rejoin.

While the game always has to finish on either the Shadow or Spirit Temple, the only other major choice comes from when the player chooses to complete the Fire temple.

That’s an appreciable degree of nonlinearity, but it doesn’t quite compare to the previous games. Except, OoT is more open than that, only most players would never notice it because the game intentionally guides the player through a linear dungeon order. The game frequently uses Navi to remind the player where they are supposed to go next, but it also enforces that intended path with obstacles that the player cannot clear without following it. Unlike the “hard” gates in the game that require key quest items like Medallions and the Spiritual Stones to progress, Ocarina of Time has many “soft” gates that only require the player to have access to dungeon items like Bombs or the Longshot.

Bombs, for example, act as a soft gate to the player entering Zora’s Domain in addition to the hard gate of Zelda’s Lullaby. If the player simply exits Dodongo’s Cavern after acquiring bombs and then departs for Zora’s River, they can complete Jabu Jabu before Dodongo’s Cavern, and bombs are never needed except at the entrance of Zora’s River! This isn’t the intended progression, as most players would complete Dodongo’s instead of unlocking bombs and then leaving, but it is supported in the strict sense that the developers accounted for it by allowing for it and even provided unique dialogue for doing so.

Screenshot from OoT showing the Goron's Ruby. The text on screen says 'You don't know what he means by 'Sworn Brothers,' but you've collected two Spiritual Stones! You have one more to find!'.Screenshot from OoT showing the Goron's Ruby. The text on screen says 'You don't know what he means by 'Sworn Brothers,' but you've finally collected all three Stones! Go back to see Princess Zelda!'.Screenshot from OoT showing the Zora's Sapphire. The text on screen says 'Her most precious possession? You don't know what she's talking about, but you've collected two Spiritual Stones! Only one to go!'.Screenshot from OoT showing the Zora's Sapphire. The text on screen says 'Her most precious possession? You don't know what she's talking about, but you've finally collected all three Stones!!'.

Both Goron's Ruby and Zora's Sapphire have unique text for whether it was obtained second or third.

There’s a few more instances of this type of progression gating in the game. All are accounted for in the game’s logic, and often supported by either dialogue, or the map screen where the next possible location(s) are marked. However, these ‘alternate routes’ are so far off the simplest path to progress that few players would even think look for them. Combined with the few instances where the game actually does hard gate progression, it creates the illusion for many players that the game is more linear than it actually is. If the game is going out of its way to give the player a path and occasionally making sure they stay on it, why even think to break from it?

Ocarina Unlocked

We set out to create Ocarina Unlocked with two specific goals: opening up possible dungeon progression and providing natural in-game context to our changes.

In this alternate progression order, Child Link can complete either Dodongo’s Cavern or Inside Jabu Jabu as the second dungeon without any soft gates in the way. Adult Link can then tackle the Forest, Fire, and Water Temples in any order. The Shadow Temple becomes accessible after completing Forest and Fire, and conversely, the Spirit Temple becomes accessible after Forest and Water.

Chart depicting the logical dungeon order of the Ocarina Unlocked ROM hack. Linearly, it starts with Deku Tree, then splits to either Dodongo's Cavern or Zora's Domain. After both, it rejoins and goes to Light Medallion. From there, it splits to three options, Fire, Forest, and Water Temple. Fire and Forest rejoin and continue to Shadow Temple, while Water and Forest rejoin and continue to Spirit Temple.  After Shadow and Spirit, the logic rejoins and terminates.

These logical progression changes are then supported by a small number of unintrusive modifications to the game’s original dialogue and map screen logic—just enough to inform the player that other progress options are available that were not already directly stated by the game.

Ocarina Unlocked is compatible with the US 1.0 version of the game. We wanted to support this version of the game since it’s the original official release.

Progression Changes

Jabu Jabu (Zora’s River boulders)

I moved the boulders blocking the path through Zora’s River as Child Link out of the way. This opens Zora’s Domain and Jabu Jabu up to be completed as the second dungeon, since bombs are only necessary to get past the entrance of Zora’s River.

Screenshot from OoT showing the entrance to Zora's River. The path is blocked by several boulders.Screenshot from Ocarina Unlocked showing  the entrance to Zora's River. Some of the boulders are removed.

An interesting note is that Kaepora Gaebora (the owl), can be found at the entrance of Zora’s River immediately meeting Zelda for the first time. Here, they remind the player to use Zelda’s Lullaby to solve the waterfall puzzle ahead–even though you wouldn’t be able to because of the boulders!

For basic level editing, I used SceneNavi. SceneNavi can manipulate actors, spawn points, waypoints, etc., can edit certain data tables in the ROM, and scene metadata. I utilized this in a number of places, like moving boulders around in Zora’s River, or changing the types of switches present for dungeon puzzles. SceneNavi also supports loading individual scene binaries, making it compatible with how ZZRTL dumps the ROM. Nifty!

Screenshot from a OoT map editor called SceneNavi

For Zora’s River, the change was pretty simple. I opted to move the boulders below the level geometry to hide them instead of deleting them. Deleting them would change the output size of the scene data, potentially causing issues.

Fire & Water Temples

In the Fire Temple there is a single Bow target puzzle which the dungeon map is locked behind. I replaced this with a crystal switch. Our philosophy for this hack was that any dungeon that can be accessed should be completable outside of secrets like Gold Skulltulas. After a bit of debate we decided that “complete” should include things that would greatly assist a first time player like the map and compass. The crystal switch also has the benefit of being hit multiple ways, letting the player figure out their own solution! This also fits with the other crystal switch puzzles in the Fire Temple.

Screenshot from OoT showing Link using the Hookshot in the Fire Temple. An Eye switch is on the wall.Screenshot from Ocarina Unlocked showing Link using the Hookshot in the Fire Temple. An crystal switch is on the wall.

In the same way that I modified the Zora’s River boulders, I used SceneNavi to change the dungeon switch type. Dungeon switch actors have an assignable type of either floor switch, rusted floor switch, eye switch, crystal switch, or targetable crystal switch.

Screenshot from a OoT map editor called SceneNavi

For our update, I changed the switch type to crystal, disabled toggling on and off (since you can’t ‘unshoot’ the vanilla eye switch), and then updated the rotation such that the crystal geometry is attached to the wall.

The Water Temple however, incorporates bow target puzzles into its central path. We felt replacing these with crystal switches would also be more in the spirit of the dungeon design, as the distance to hit the crystals would require the Longshot. These bow targets also felt particularly arbitrary to us as they are mid-dungeon, meaning the player could get halfway through and hit an impassable wall without backtracking out and doing the Forest Temple.

Screenshot from OoT showing an eye switch in the Water temple.Screenshot from Ocarina Unlocked showing a crystal switch in the Water temple.

In the central room of the Water Temple, there’s a bow target switch inset into the wall near the bottom floor. I changed this to a crystal switch, but at first glance, this didn’t seem to work like it did in other cases: you couldn’t hit the new crystal switch with the Hookshot, yet the Bow still worked!

It turns out this particular switch has collision geometry in front of it to make the wall collision geometry continuous. Presumably this is so Link can’t swim into the alcove containing the switch.

Screenshot from a OoT map editor called SceneNavi

Anyhow, this collision geometry has a special collision detection flag applied to it. In particular, the flag indicates that the surface should ignore projectile collisions. Projectiles in this case includes slingshot seeds, arrows, Bombchus, and a few other miscellaneous things like the Octorok rocks, but not the Hookshot. Without the Bow, the primary puzzle solving tool for the player here would be the Hookshot, so this poses a problem. Lucky for us, there is an alternative flag that ignores most entities (Hookshot included) that we could use instead.

However, editing the level collision geometry is a lot more of a hassle than most of our other changes. The only tool we’re aware of that can modify and export existing level and collision geometry is Fast64, though like many other tools, it’s designed to work with the Debug Master Quest ROM. Since we are modifying a dungeon, the geometry will have significant differences being a Master Quest dungeon, so this was off the table since we’re working on a 1.0 hack.

Once again Decompiled came to our rescue! Since this geometry is in both Master Quest and 1.0, I was able to locate this particular geometry in the Water Temple’s collision header (located in MIZUsin_scene.c). The collision flags for a collision triangle are stored in the first vertex ID–they are combined together with a logical AND operation.

Vertex A (0x1FFF), Collision Detection Flags (& 0xE000), where the flags may be:

  • & 0x2000; if 1, ignored by Camera collision detection
  • & 0x4000; if 1, ignored by most entities
  • & 0x8000; if 1, ignored by projectiles (slingshot seeds, arrows), bombchus (for bombchu bowling)

In our case, the original hex value in Decompiled was 0x8162, meaning the vertex ID is 0x0162, and the flag is 0x8000.

With that figured out, it was just a matter of finding the 0x8162 hex values in the 1.0 ROM data, then changing the 8 to a 4! Thankfully these two triangles are the only geometry with this flag in the entire Water Temple, it could have been a whole lot more work otherwise.

Shadow Temple

Uniquely, the Shadow Temple is the only dungeon in the main progression to directly require the completion of prior dungeons in the same timeline. The Nocturne of Shadow cutscene with Sheik that precedes the Shadow Temple is a hard gate: it only triggers after the Forest, Fire, and Water medallions are acquired. This stands in contrast to the Spirit Temple which—while requiring the Forest Temple to be completed so the player can return to the past—only gates the player with the Longshot from the Water Temple.

To bring the two “final” dungeons closer together in prerequisites, we decided to remove the Water Temple as a requirement from Shadow. This was one of our most dramatic changes and it came about after a lot of debate over how best to open up the progression in the Adult Link dungeons. We like the symmetry this gives to temples, pairing Fire with Shadow and Water with Spirit, which are also linked geographically. Earlier on in the project, I attempted to give earlier access to Spirit Temple by removing the Longshot requirement from the entrance to the desert, but this proved difficult to modify in a way that felt natural. Instead, giving earlier access to Shadow Temple should allow for more flexibility in progression while maintaining a tiered dungeon difficulty.

Before the Shadow Temple can be accessed, Link has to learn the Nocturne of Shadow from Sheik. This happens in a cutscene at Kakariko Village that is triggered after the Forest, Fire, and Water Temples have been completed. We wanted to remove the Water Temple check from the logic.

The code responsible for triggering this cutscene in Decompiled is in z_demo.c, in the function Cutscene_HandleConditionalTriggers:

else if ((gSaveContext.entranceIndex == ENTR_KAKARIKO_VILLAGE_0) &&
    LINK_IS_ADULT && GET_EVENTCHKINF(EVENTCHKINF_48) &&
    GET_EVENTCHKINF(EVENTCHKINF_49) &&
    GET_EVENTCHKINF(EVENTCHKINF_4A) &&
    !Flags_GetEventChkInf(EVENTCHKINF_AA)) {
        Flags_SetEventChkInf(EVENTCHKINF_AA);
        gSaveContext.cutsceneIndex = 0xFFF0;
}

This conditional check requires the following:

  1. The player has entered Kakariko Village through the main entrance
  2. That Link is an adult
  3. That the following event info flags have been set (see TCRF for event table)
    • 0x38; this is set whenever you use the blue warp out of the Forest Temple
    • 0x39; this is set whenever you use the blue warp out of the Fire Temple
    • 0x3A; this is set whenever you use the blue warp out of the Water Temple
  4. That the event info flag 0xAA has not been set; this is set whenever Bongo Bongo escapes the well in the cutscene these conditions trigger (essentially just checking if the cutscene has already played)

These flags are stored in an array of unsigned 16-bit integers, where each bit of each integer in the array represents a different flag. A breakdown of these flags is available on TCRF. We initially tried to make our logic change by replacing the Water Temple event info flag check with a duplicate Fire Temple check. Whether because of compiler optimizations or the way the boolean logic gets folded together into hexadecimal values, this changed a larger chunk of the resultant hex code than expected.

I ended up getting around this by replacing the Water Temple completion check with a sure to be completed, and still timely check for having opened the Door of Time. This approach yielded a single byte change–much more in line with what I was looking for.

Testing this change in 1.0 after the usual compare-and-copy its own unique challenge. In the MQ Debug ROM, there exists an event editor tool that can toggle the various event info flags. This tool is not present in 1.0 however. I got around this by following the save data documentation of Zelda modders past, and directly modifying the memory contents at runtime the same way the event tool would. Comparatively, this was kind of a pain, as I had to locate the event info flag array in memory, convert the values from base 16 to base 2, change the flags, then convert it back to base 16 just to test, but it all worked out! It was certainly a lot less work than playing through the game up until Shadow Temple!

As a consequence of this change, a small change did need to be made to the Shadow Temple itself. To our surprise, there was only a single target requiring the Longshot in the temple which would need to be modified. However, the various shot targets in the game are not as easily edited as switches since they are actually just geometry flagged to be hookshot-able. Luckily for us, this room contained a chest that could be moved to substitute for the Longshot target and be reachable with the base Hookshot.

Screenshot from OoT showing a room in the Shadow Temple. A chest is at ground level, and behind it there is a raised platform.Screenshot from Ocarina Unlocked showing a room in the Shadow Temple. There is a raised platform with a chest on it.

Fun fact: The room never actually required the Longshot to begin with! Backflipping onto the chest in its original position actually gives the player enough height to Hookshot to the intended target, but we felt this was a bit too much to ask of a player on a potential first playthrough.

Spirit Temple

The Spirit Temple contains two optional rusted switches that require the Megaton Hammer, yet even in the vanilla game, the temple can be accessed without doing the Fire Temple prior. In the original game this works as a way to reward players for completing dungeons in the intended order even if it wasn’t strictly necessary. Within the context of our changes to the Shadow Temple and Fire/Water though, we felt that these should be changed to regular switches.

Screenshot from OoT showing a rusted switch in the Spirit Temple.Screenshot from Ocarina Unlocked showing a normal switch in the Spirit Temple.

Contextual Changes

While the primary goal of the ROM hack is to remove the gates in Ocarina of Time’s progression, we also decided to make minor additional changes to the game’s dialogue, cutscenes, and interface to more naturally integrate modified progression logic into the game. Not making these changes would have technically accomplished our goals for this ROM hack, but we felt that taking these extra steps better fit our philosophy for the hack: not just to make the changes, but to show how simply they could have been a part of the original game.

The main ways the game provides context to progression are dialogue and the map submenu. We updated both for our change, allowing earlier access to Zora’s Domain. We tried to keep these changes minimal, and keep any dialogue updates as close to the original style as possible.

Impa Cutscene

After meeting Zelda for the first time, Link is taught Zelda’s Lullaby by Impa, who then sends them on their way to Death Mountain. This dialogue, and Navi’s subsequent ‘reminder’ dialogue, was our first set of contextual info to modify.

In Impa’s speech to Link, she introduces the player to Death Mountain as a location:

Take a good look at that mountain. That is Death Mountain, home of the Gorons. They hold the Spiritual Stone of Fire.

In Ocarina Unlocked, we follow up this dialogue with a similar mention of the Zora’s and the Spiritual Stone of Water:

The Spiritual Stone of Water is held by the Zora. The river that runs through Hyrule flows from their home, Zora’s Domain.

For dialogue editing, I used Zelda’s Letter. Zelda’s Letter is an in-browser dialogue editor for Ocarina of Time that provides an easy interface to make and preview changes directly to a Zelda 64 text box. It includes both a message find and goto feature (using the message address), which makes finding the dialogue really easy.

Screenshot of the Zelda's Letter dialogue editor.

Zelda’s Letter supports both saving the changes directly to the ROM, or to a separate group of binaries. These binaries can be injected using ZZRTL also!

Impa delivers this dialogue as part of a cutscene, where the Death Mountain mention occurs in a shot particularly framing the mountain in the distance. In order to deliver our added dialogue seamlessly, we incorporated an additional camera shot highlighting the entrance to Zora’s River. Making this change was quite the challenge!

For our update to the Impa cutscene, I added both a new line of dialogue and a camera shot. This is in contrast to our other contextual changes so far, where we have modified a pre-existing set of data.

For the new dialogue, I had a couple options: make the dialogue table larger, or utilize existing empty spaces in the table. I went with the latter since the process is simpler. Like the other dialogue edits, I utilized Zelda’s Letter as our editor. I just went to an empty location in the table (specifically 0x0109) and added our new line.

Actually modifying the cutscene is a lot more work though. We started off by locating the cutscene implementation in Decompiled. Cutscenes in Ocarina of Time are composed of a list of different commands defining different cutscene actions. In the Impa cutscene, we can see commands like actor animation actions, text lists, and camera positions, as well as general commands describing the cutscene duration.

CS_BEGIN_CUTSCENE(15, 1500),
CS_UNK_DATA_LIST(0xD, 1),
    CS_UNK_DATA(0x00010000, 0x05DC0000, 0x00000000, 0x00000000, 0xFFFFFFFE, 0x00000010, 0x00000000, 0xFFFFFFFE,
                0x00000010, 0x00000000, 0x00000000, 0x00000000),
CS_PLAYER_ACTION_LIST(5),
    CS_PLAYER_ACTION(5, 0, 240, 0x0000, 0x4000, 0x0000, 87, 0, 1320, 87, 0, 1320, 0.00000000000e+00f,
                    0.00000000000e+00f, 1.40129846432e-45f),
    CS_PLAYER_ACTION(1, 240, 310, 0x0000, 0x4000, 0x0000, 87, 0, 1320, 186, 0, 1327, 0.00000000000e+00f,
                    0.00000000000e+00f, 1.40129846432e-45f),
    CS_PLAYER_ACTION(5, 310, 457, 0x0000, 0x4000, 0x0000, 186, 0, 1327, 186, 0, 1327, 0.00000000000e+00f,
                    0.00000000000e+00f, 1.40129846432e-45f),
    CS_PLAYER_ACTION(6, 457, 470, 0x0000, 0x4000, 0x0000, 186, 0, 1327, 221, 0, 1327, 0.00000000000e+00f,
                    0.00000000000e+00f, 1.40129846432e-45f),
    CS_PLAYER_ACTION(5, 470, 586, 0x0000, 0xAAAB, 0x0000, 221, 0, 1327, 221, 0, 1327, 0.00000000000e+00f,
                    0.00000000000e+00f, 1.40129846432e-45f),
CS_NPC_ACTION_LIST(0x02C, 4),
    CS_NPC_ACTION(1, 0, 10, 0x0000, 0x4000, 0x0000, 142, 0, 1274, 142, 0, 1274, 0.00000000000e+00f,
                  0.00000000000e+00f, 1.40129846432e-45f),
    CS_NPC_ACTION(2, 10, 421, 0x0000, 0x4000, 0x0000, 142, 0, 1274, 142, 0, 1274, 0.00000000000e+00f,
                  0.00000000000e+00f, 1.40129846432e-45f),
    CS_NPC_ACTION(10, 421, 454, 0x0000, 0x4000, 0x0000, 142, 0, 1274, 142, 0, 1274, 0.00000000000e+00f,
                  0.00000000000e+00f, 1.40129846432e-45f),
    CS_NPC_ACTION(11, 454, 455, 0x0000, 0x0000, 0x0000, 142, 0, 1274, 142, 0, 1274, 0.00000000000e+00f,
                  0.00000000000e+00f, 0.00000000000e+00f),

and so on...

First I had to add our new dialogue into the cutscene. The text content of a cutscene is described by a few different textbox altering commands, like…

// Comments added for readability
CS_TEXT_LIST(8),
    CS_TEXT_NONE(0, 130),
    CS_TEXT_DISPLAY_TEXTBOX(0x2060, 130, 160, 0, 0x0, 0x0), // [IMPA] You brave lad...
    CS_TEXT_NONE(160, 180),
    CS_TEXT_DISPLAY_TEXTBOX(0x204F, 180, 240, 0, 0x0, 0x0), // [IMPA] Take a good look at that mountain...
    CS_TEXT_NONE(240, 280),
    CS_TEXT_DISPLAY_TEXTBOX(0x2062, 280, 340, 0, 0x0, 0x0), // [IMPA] At the foot of Death Mountain...
    CS_TEXT_NONE(340, 370),
    CS_TEXT_DISPLAY_TEXTBOX(0x2063, 370, 410, 0, 0x0, 0x0), // [IMPA] You should talk to some of the villagers...
CS_TERMINATOR(115, 565, 566),

I added an additional set of ‘No Text’ and ‘Display Text’ commands for our new dialogue (represented in Decompiled as CS_TEXT_NONE and CS_TEXT_DISPLAY_TEXTBOX macros), and then added an additional frame duration to the subsequent text command’s frame arguments.

CS_TEXT_LIST(10),
    CS_TEXT_NONE(0, 130),
    CS_TEXT_DISPLAY_TEXTBOX(0x2060, 130, 160, 0, 0x0, 0x0),
    CS_TEXT_NONE(160, 180),
    CS_TEXT_DISPLAY_TEXTBOX(0x204F, 180, 240, 0, 0x0, 0x0),
    CS_TEXT_NONE(160+IMPA_CUTSCENE_EXTENSION, 180+IMPA_CUTSCENE_EXTENSION),                                   // Pause before new dialogue
    CS_TEXT_DISPLAY_TEXTBOX(0x0109, 180+IMPA_CUTSCENE_EXTENSION, 240+IMPA_CUTSCENE_EXTENSION, 0, 0x0, 0x0),   // Display new dialogue
    CS_TEXT_NONE(240+IMPA_CUTSCENE_EXTENSION, 280+IMPA_CUTSCENE_EXTENSION),
    CS_TEXT_DISPLAY_TEXTBOX(0x2062, 280+IMPA_CUTSCENE_EXTENSION, 340+IMPA_CUTSCENE_EXTENSION, 0, 0x0, 0x0),
    CS_TEXT_NONE(340+IMPA_CUTSCENE_EXTENSION, 370+IMPA_CUTSCENE_EXTENSION),
    CS_TEXT_DISPLAY_TEXTBOX(0x2063, 370+IMPA_CUTSCENE_EXTENSION, 410+IMPA_CUTSCENE_EXTENSION, 0, 0x0, 0x0),
CS_TERMINATOR(115, 565+IMPA_CUTSCENE_EXTENSION, 566+IMPA_CUTSCENE_EXTENSION),

To add a new camera shot, I essentially did the same thing but with camera commands. There are camera commands for positions and focus points, with each type being stored in a list of positions or focus points. I used SharpOcarina’s cutscene editing tools to view the original cutscene data (this alone took a bit of work, I had to locate the hex values representing the cutscene in the ROM), and then ‘preview’ our own camera commands. Once I was satisfied, I then wrote our new camera command values back into the Decompiled code.

CS_CAM_POS_LIST(170+IMPA_CUTSCENE_EXTENSION, 431+IMPA_CUTSCENE_EXTENSION), // New shot! Frame Zora's river entrance and pan right
    CS_CAM_POS(CS_CMD_CONTINUE, 0x00, 0, 55.806320f, 2579, 537, 1778, 0x0021),
    CS_CAM_POS(CS_CMD_CONTINUE, 0x00, 0, 55.806320f, 2579, 537, 1778, 0x00B6),
    CS_CAM_POS(CS_CMD_CONTINUE, 0x00, 0, 55.806320f, 2522, 537, 2032, 0x00C7),
    CS_CAM_POS(CS_CMD_CONTINUE, 0x00, 0, 55.806320f, 2522, 537, 2032, 0x00D8),
    CS_CAM_POS(CS_CMD_STOP, 0x00, 0, 55.806320f, 2522, 537, 2032, 0x0115),

I did this because we’d ultimately need to adjust the camera commands even further. This was the one instance in our ROM hack where we explicitly added content, rather than modifying pre-existing content. As described previously, there are technical challenges with increasing the output size of the final program, and adding the new cutscene commands does just that. However, due to the way cutscene lookup works, I can only make the cutscene take up less or equal space, filling any unused space with 0s. To make room for the new commands, I had to ‘optimize’ the existing ones to fit in a smaller footprint. Essentially I just removed some redundant keyframes from other camera pans in the same cutscene.

From there, it’s the usual compare-and-copy to apply the change to 1.0, albeit with a bit more caution since the cutscene is a lot more data than most of our other changes. With our cutscene ‘optimization’, I was able to include our new content and still have 30 bytes of empty space to spare!

One interesting note, Impa closes out her speech by reminding the player to use Zelda’s Lullaby to solve upcoming puzzles:

The song I just taught you has some mysterious power. Only Royal Family members are allowed to learn this song.

This reminder to the player is not only applicable for retrieving the Sun’s Song and speaking to Darunia on Goron City, but also for opening the entrance to Zora’s Domain!

In the base game, after Impa sends you off to Kakariko Village to look for the Spiritual Stone of Fire, Navi will remind the player what Impa said:

Impa said that the Spiritual Stone of Fire is somewhere on Death Mountain.

To support our changes to the Impa cutscene, we modified Navi’s dialogue here to:

Impa said that the Spiritual Stones are somewhere on Death Mountain and in Zora’s Domain.

Sheik Cutscene

Upon becoming an adult, the player is greeted by Sheik, who introduces the concept of the five sages and their temples. Sheik alludes to Saria and the Forest Temple as the next steps in the game’s main plot:

One Sage is waiting for the time of awakening in the Forest Temple. The Sage is a girl I am sure you know… Because of the evil power in the temple, she cannot hear the awakening call from the Sacred Realm… Unfortunately, equipped as you currently are, you cannot even enter the temple… But, if you believe what I’m saying, you should head to Kakariko Village…

In Ocarina Unlocked, the player can tackle the Forest, Fire, or Water temple as their first Adult Link dungeon. We considered modifying the dialogue here to either directly mention Darunia and Ruto and their temples, or making the dialogue more vague as to apply to all three of the Forest, Fire, and Water sages. We ultimately decided not to do so, as either would significantly extend the cutscene and dilute the original emphasis on the Link’s relation to Saria and the Kokiri Forest.

We instead settled on the following change:

Unfortunately, equipped as you currently are, you cannot enter any of the temples… But, if you believe what I’m saying, you should head to Kakariko Village…

Update Map Submenu

Ocarina of Time’s map sub-menu includes location pins that flash when the player should travel there.

Screenshot from OoT showing the map submenu.

Whether or not the location marker is flashing is determined by a sequence of inventory and event checks. One of our goals for this ROM hack was to update these markers to match our changes to the play order of the game. Our main change was to highlight the Zora’s Domain marker after receiving Zelda’s Lullaby, to indicate to the player that they can progress either to Kakariko Village or Zora’s River.

Resources

Tools

References

Related Projects

© Nathan MacAdam, 2025