Skip to content

RAM Address Map

Samuel Costa edited this page Jul 27, 2026 · 1 revision

RAM Address Map — Ocarina of Time 3D (USA)

Every memory address OcarinaCTRComposer reads or writes, in one place. Game: The Legend of Zelda: Ocarina of Time 3D · Region: USA only · Title ID: 0004000000033500.

All addresses are absolute 32-bit (e.g. 0x0587958), read/written directly with R8/R16/R32/W8/W16/W32 — no pointer chasing except where noted (base+offset patterns). They were confirmed on hardware unless flagged otherwise. These addresses are USA-version-specific — on EUR/JPN they are very likely at different offsets; re-anchor before reusing this map on another region.

If this map saves you time, a credit back to this repo is appreciated. Corrections and additions are welcome — open an issue or a PR against the wiki.

The plugin's own Hex Editor tool, used to spot-check addresses on hardware

Table of contents


Base pointers

Symbol Address Type Notes
Link actor pointer 0x005A2E3C u32* → Player struct Dereference to get the live Player base; 0 when not in-game (menus, loading). All player-relative offsets below are [this] + offset.
gSaveContext 0x0587958 struct base Confirmed by matching the inventory array byte-for-byte against the save file (RAM = file_offset + 0x587958). Everything under "gSaveContext" below is 0x587958 + offset.
GlobalContext 0x0871E840 struct base Candidate, guarded at every use by a sanity check (GctxValid() below) rather than trusted blindly. Confirmed via a working "reload current scene" on hardware.

gSaveContext — core save block

Base 0x0587958. Offsets shown as base+N and the resolved absolute address.

Field Offset Address Type Notes
entranceIndex +0x00 0x0587958 s32 Current entrance index
linkAge +0x04 0x058795C s32 0 = Adult, 1 = Child (the live/current age)
cutsceneIndex +0x08 0x0587960 s32
dayTime +0x0C 0x0587964 u16 0x0000 = midnight … 0x8001 = sunrise … 0xC001 = sunset
Current Health 0x058799A u16 "Unlock/Max Hearts" write target (0x140 = 20 hearts)
Current Health (keep-full) 0x058799C u16 Same field, written every frame for "Keep Hearts Full" / one-shot heart refill
Magic amount 0x058799F u8 0x30 normal magic, 0x60 with Magic Upgrade
Magic capacity / unlock 0x05879A6 u8 0x60 = unlocked
Double Defense flag 0x05879A9 u8 bit0
Large Magic unlock 0x05879A8 u8 0x01 = unlocked; also gates the refill-magic amount
Sticks count 0x05879FE u8 max 0x63 (99)
Nuts count 0x05879FF u8 max 0x63
Rupees 0x05879A0 u16 max 0x3E7 (999)
Knife/sword durability(?) 0x05879A2 u8 0xFF = "no break"
respawn[0] (RESPAWN_MODE_DOWN) +0x14F0 0x0588E48 struct, 0x1C bytes See Respawn struct
respawnFlag +0x14EC 0x0588E44 u8 1 before a scene reload → spawn at respawn[0] instead of the entrance's default point
nextCutsceneIndex +0x15A0 0x0588EF8 u16 0xFFEF = "no cutscene" sentinel used by the warp routine
Nayru's Love timer 0x0588EAA u16 0xFFFF = always active
Bottle #1/#2/#3 contents 0x05879F6 / 0x05879F7 / 0x05879F8 u8 each Item ID per bottle slot; Bottle #3 slot doubles as the "Inventory Modifier" picker target

Quest-status word (medallions, songs, stones)

A packed bitfield starting at 0x0587A14 (3 bytes). Mapped by save-diffing 48 progressive community save files (see Methodology) — no guessed bits.

Byte 0x0587A14:

Bit Item
0x01 Forest Medallion
0x02 Fire Medallion
0x04 Water Medallion
0x08 Spirit Medallion
0x10 Shadow Medallion
0x20 Light Medallion
0x40 Minuet of Forest
0x80 Bolero of Fire

Byte 0x0587A15:

Bit Item
0x01 Serenade of Water
0x02 Requiem of Spirit
0x04 Nocturne of Shadow
0x08 Prelude of Light
0x10 Zelda's Lullaby
0x20 Epona's Song
0x40 Saria's Song
0x80 Sun's Song

Byte 0x0587A16:

Bit Item
0x01 Song of Time
0x02 Song of Storms
0x04 Kokiri Emerald
0x08 Goron Ruby
0x10 Zora Sapphire
(upper bits: Gerudo card and other flags — see caveat below)

Quick unlock-all writes used by the plugin: W8(0x0587A14, 0x3F) (all 6 medallions), W8(0x0587A16, 0x7C) (all 3 stones, mask includes adjacent unrelated bits — verify before reuse), W8(0x0587A14 | 0xC0) + W8(0x0587A15, 0xFF) + W8(0x0587A16 | 0x03) (all 10 songs).

⚠️ Gerudo card: reported elsewhere as bit 22 of this word, but in the 48-save diff set that bit only ever appears on already-100% saves — ambiguous, left undetected on purpose rather than risk a false positive.

Upgrade word 0x0587A10 (u32) — packed multi-bit capacity fields (bow/bomb bag/quiver/etc. and gauntlet color). Example writes: W32(0x0587A10, 0x184D8) = "best equipment" bundle; W16(0x0587A10, 0xE500 + 0xDB/0x9B/0x5B/0x1B) = Golden/Silver/Silver/Golden gauntlets (see source for the exact 4 values — Black/Blue/Green/Silver gauntlet upgrade tiers).

Skulltula token count0x0587A40 (separate from the per-token flags below).


Inventory array

Fixed 24-slot array, base 0x005879E4, one byte per slot, empty = 0xFF, otherwise the item ID. Confirmed by matching this array byte-for-byte against the save file's inventory bytes.

Slot index Item
+3 Bow
+4 Fire Arrow
+5 Din's Fire
+6 Slingshot
+7 Ocarina
+8 Bombchu
+9 Hookshot / Longshot (shared slot; ID 0x0A vs 0x0B)
+10 Ice Arrow
+11 Farore's Wind
+12 Boomerang
+13 Lens of Truth
+14 Magic Beans
+15 Megaton Hammer
+16 Light Arrow
+17 Nayru's Love
+18..21 Bottles #1-4
+22 Adult trade-sequence item
+23 Child trade-sequence item

"Unlock All Items" writes a full 30-byte buffer to 0x5879E4 in one shot (see source for the exact byte sequence — it's a curated "one of everything" loadout, not derived from a formula).

Trade-sequence complete check: adult trade slot 0x05879FA == 0x37 (Claim Check item ID).


Equipment byte (swords / shields / tunics / boots)

Two adjacent bytes, 0x0587A0E (swords + shields, low/high nibble) and 0x0587A0F (tunics + boots). Each equipment slot is a nibble bit, toggled independently (TriggerNibble = XOR one bit within the nibble, so re-selecting removes it).

0x0587A0E:

Bit Item
0x01 Kokiri Sword
0x02 Master Sword
0x04 Biggoron's Sword
0x10 Deku Shield
0x20 Hylian Shield
0x40 Mirror Shield

0x0587A0F:

Bit Item
0x01 Kokiri Tunic
0x02 Goron Tunic
0x04 Zora Tunic
0x10 Kokiri Boots
0x20 Iron Boots
0x40 Hover Boots (& 0x40 = Hover Boots owned check)

Ammo / consumables

Item Address Max write
Deku Nuts 0x05879FF 0x63
Deku Sticks 0x05879FE 0x63
Arrows 0x0587A01 0x63
Bombs (save + HUD mirror) 0x0587A00 + 0x08001AB4 0x63 each
Bombchu (save + HUD mirror) 0x0587A06 + 0x08001AD0 0x63 each
Slingshot seeds 0x0587A04 0x63
Rupees 0x05879A0 0x3E7
Gold Skulltula token count 0x0587A40 (+ HUD mirror 0x05C2280) 0x64
Skulltula-house price-halved flag via 0x0FFFE538[q]+0x910 = 0 pointer-chased, see source

Player (Link actor) offsets

Relative to the Link actor pointer [0x005A2E3C].

Offset Field Notes
+0x18 / +0x1C / +0x20 Position X / Y / Z raw float bits, used by both the waypoint save and the debug scale hack
+0x64 Actor scale f32; 0x3AD3D70A ≈ Paper Link scale
+0x77 Vertical velocity u16; 0xCB40 = an instant strong upward pop (MoonJump / the jump component of Fast Move)
+0x134 Epona pointer dereference for horse-relative offsets
+0xE9C (Epona) carrots-full field offset from the Epona pointer, not Link
+0x66 (Epona) horse jump-boost field offset from the Epona pointer
+0x2237 Sword-glitch state byte 0x01 = enabled
+0x2252 Spin-attack charge f32; 0x3F80 (as u16 write) = fully charged
+0x2258 Deku Stick lit flag 0xFF = always on fire
+0x222C Horizontal speed cap (during Fast Move's post-jump phase) f32; 0x41A00000 = 20.0

GlobalContext (scene / warp control)

Base 0x0871E840 (candidate — always gate a write with the validity check below; a wrong base here can crash the game).

Field Offset Address Type Notes
sceneNum +0x104 0x0871E944 s16 Current scene ID (see Scene ID table)
linkAgeOnLoad +0x5C00 0x0871E5F0* u8 0 = Adult, 1 = Child — the pending age applied on the next scene load (Toggle Age writes here)
sceneLoadFlag / transitionTrigger +0x5C2D s8 Writing 0x14 triggers the load — this is the final write in any warp
nextEntranceIndex +0x5C32 s16 Idle/no-pending-transition reads 0xFFFF
transitionType / fadeOutTransition +0x5C76 u8 3 used for the fade in this plugin's warp routine

(offsets are added to 0x0871E840, not restated as absolute addresses above except sceneNum for illustration — always compute GCTX_BASE + offset.)

Validity guard (run before every write to this block):

sceneNum < 0x6A   AND   nextEntranceIndex == 0xFFFF   AND   the Link pointer is non-zero

If any check fails, the plugin refuses to warp rather than writing to a possibly-wrong base.


Entrance-warp mechanism

The full write sequence a "teleport" performs (mirrors the retail game's own EntranceWarp, no function call — pure memory writes, order matters, last write triggers the load):

  1. linkAgeOnLoad (GlobalContext +0x5C00) ← target age (0/1), or the pending age read back if "keep current age" was requested — this makes a Toggle Age done just before a warp carry through.
  2. gSaveContext.cutsceneIndex (0x0587960) ← 0
  3. gSaveContext.nextCutsceneIndex (0x0588EF8) ← 0xFFEF (the "no cutscene" sentinel)
  4. nextEntranceIndex (GlobalContext +0x5C32) ← the target entrance index
  5. transitionType (GlobalContext +0x5C76) ← 3
  6. sceneLoadFlag (GlobalContext +0x5C2D) ← 0x14this is what actually starts the load

"Reload current scene" = the same sequence with the entrance index re-read live from gSaveContext.entranceIndex (0x0587958) instead of a fixed target.


Respawn struct (reliable position warp)

gSaveContext.respawn[0] (RESPAWN_MODE_DOWN), base 0x0588E48, 0x1C bytes. Writing this and setting respawnFlag (0x0588E44 = 1) before triggering an entrance-warp (above) makes the game spawn Link at this exact position + room instead of the entrance's default point — the mechanism this plugin uses for "Warp to Saved Position" (reliable across rooms/dungeons, unlike a raw coordinate write).

Offset Field Type
+0x00 pos X f32 (raw bits)
+0x04 pos Y f32
+0x08 pos Z f32
+0x0C yaw u16 (not saved by this plugin — Link faces the default direction on arrival)
+0x0E playerParams u16 — 0x0DFF = a normal standing spawn
+0x10 entrance index u16
+0x12 room index u8
+0x13 (padding/data byte) u8
+0x14 tempSwch (copied from actorCtx, see below) u32
+0x18 tempCollect (copied from actorCtx, see below) u32

actorCtx flags (temp switches / collectibles)

Live per-room flags, read at warp time and copied into the respawn struct so a warp doesn't reset switches/collectibles you already triggered in the destination room:

Field Address Notes
tempSwch (actorCtx.flags +0x1A0) 0x08720C44 current room's temporary switch flags
tempCollect (actorCtx.flags +0x1BC) 0x08720C60 current room's temporary collectible flags
Chest-opened flags (bulk clear) 0x08720A78 u32 write of 0 = "many chests" reset for the current room
Heart-piece-taken flags (bulk clear) 0x08720A84 u16 write of 0
Rain toggle 0x08721AAF u8; 0xFF = force rain
Song-playing message mode 0x087212D0 u8; game values 18/19 = playing an ocarina song, forced to 23 to skip the cutscene once recognized
roomCtx.curRoom.num 0x08723470 u8; current room index (used to auto-suffix waypoint names in dungeons, e.g. "R2")

Room / scene flags (chests, switches, collect)

gSaveContext.sceneFlags[124], base offset +0xEC from 0x0587958 (i.e. 0x0587A44), 0x1C bytes per scene (scene index = the game's own scene number):

Sub-offset Field
+0x00 chest flags
+0x04 switch flags
+0x08 clear flags
+0x0C collect flags (heart pieces / misc collectibles)
+0x14 rooms1
+0x18 rooms2

These are per-scene bitfields — isolating exactly which collectible a given bit represents requires either the decomp's own token/flag tables or a save where only one flag changes between two otherwise-identical saves (most progressive test saves gain several at once, which makes this genuinely hard — see the caveat in Methodology).


Gold Skulltula tokens

gsFlags[22], base 0x0058880C (⚠️ not 0x0EB4+gSaveContext naively — some public references list the wrong start offset; this is the value that matches a 100-token popcount on a 100%-complete save). One bit per token; which bit maps to which physical Skulltula is fixed by the game but not derivable from save-diffing alone (progressive saves gain many tokens in one block, so the per-bit identity can't be isolated this way — only the decomp's own 100-entry scene+bit token table resolves that). Byte-index-to-area mapping (bit position within each byte is a fixed-but-unidentified token of that area):

Byte Area
0 Deku Tree / Kokiri Forest
1 Dodongo's Cavern / Death Mountain
2 Hyrule Field / Lost Woods (adult)
3 Forest Temple
4 Fire Temple
5 Water Temple
6 Spirit Temple
7 Shadow Temple
8 Bottom of the Well
9 Ice Cavern
10..21 Overworld areas

Event / item-get flags

All monotonic (bits only ever turn on) across the 48-save diff set — safe to treat "bit set" as "confirmed", but see the block-grant caveat below before relying on them for fine-grained tracking.

Field Address Size
eventChkInf 0x0588844 14 × u16
itemGetInf 0x0588860 4 × u16
infTable 0x0588868 30 × u16
eventInf (not in the 5340-byte save file — RAM-only, offset +0x158A from 0x587958) 4 × u16

Misc single addresses

Purpose Address
Config file version-check magic (this plugin's own, not the game's) n/a — 'ZOOT' blob magic in Settings.cfg
Rain toggle 0x08721AAF
Freeze-time capture/hold target 0x0587964 (same as dayTime above)
Ocarina song-recognition message mode 0x087212D0

Code-patch addresses (Invincible)

Four instructions patched (not just data) — the only code-patch cheat in this plugin. Requires svcControlProcess(..., PROCESSOP_SET_MMU_TO_RWX, ...) once before the first write, and the original bytes are saved so the patch can be reverted when the cheat is turned off.

Address Original (typical) Patched to Purpose
0x0035D398 (damage-apply instruction) 0xE3A00000 (mov r0, #0) zero the incoming damage argument
0x0035D3A8 (branch) 0xEA000000 (unconditional branch, offset 0 = no-op the following block) short-circuit the damage-apply path
0x00352E24 (load) 0xE1D504B2 part of the same patch — see source for full context
0x00352E28 (move) 0xE1A00000 (mov r0, r0, effectively nop)

These 4 addresses are proven on hardware but are the most fragile entries in this map — a game update could shift them. If Invincible stops working after a game-version change, this is the first thing to re-verify with Cheat Search or a fresh disassembly.


Scene ID table

gGlobalContext->sceneNum (also matches the N64 OoT scene numbering). Sourced from the OoT decomp scene_table.h; range 0x000x64 are reachable in the retail game, 0x65+ are unused debug/dev scenes.

ID Scene ID Scene
0x00 Inside the Deku Tree 0x34 Link's House
0x01 Dodongo's Cavern 0x35 Back Alley House (Dog Lady)
0x02 Inside Jabu-Jabu's Belly 0x36 Stable
0x03 Forest Temple 0x37 Impa's House
0x04 Fire Temple 0x38 Lakeside Laboratory
0x05 Water Temple 0x39 Carpenters' Tent
0x06 Spirit Temple 0x3A Dampe's Gravekeeper's Hut
0x07 Shadow Temple 0x3B Great Fairy's Fountain (Magic)
0x08 Bottom of the Well 0x3C Fairy's Fountain
0x09 Ice Cavern 0x3D Great Fairy's Fountain (Spells)
0x0A Ganon's Tower 0x3E Grottos (generic)
0x0B Gerudo Training Ground 0x3F Grave (ReDead)
0x0C Thieves' Hideout 0x40 Grave w/ Fairy's Fountain
0x0D Inside Ganon's Castle 0x41 Royal Family's Tomb
0x0E Ganon's Tower (Collapsing) — interior 0x42 Shooting Gallery
0x0F Inside Ganon's Castle (Collapsing) 0x43 Temple of Time (interior)
0x10 Treasure Box Shop 0x44 Chamber of the Sages
0x11 Gohma's Lair 0x45 Hyrule Castle Courtyard — Guards (Day)
0x12 King Dodongo's Lair 0x46 Hyrule Castle Courtyard — Guards (Night)
0x13 Barinade's Lair 0x47 Cutscene Map
0x14 Phantom Ganon's Lair 0x48 Windmill & Dampe's Grave
0x15 Volvagia's Lair 0x49 Fishing Pond
0x16 Morpha's Lair 0x4A Hyrule Castle Courtyard — Zelda's Meeting
0x17 Twinrova's Lair 0x4B Bombchu Bowling Alley
0x18 Bongo Bongo's Lair 0x4C Lon Lon Ranch buildings
0x19 Ganondorf's Lair 0x4D Market Guard House
0x1A Ganon's Tower (Collapsing) — exterior 0x4E Granny's Potion Shop (Kakariko)
0x1B Market Entrance (Day) 0x4F Ganon Battle Arena
0x1C Market Entrance (Night) 0x50 House of Skulltula
0x1D Market Entrance (Ruins) 0x51 Hyrule Field
0x1E Back Alley (Day) 0x52 Kakariko Village
0x1F Back Alley (Night) 0x53 Graveyard
0x20 Market (Day) 0x54 Zora's River
0x21 Market (Night) 0x55 Kokiri Forest
0x22 Market (Ruins) 0x56 Sacred Forest Meadow
0x23 Temple of Time Exterior (Day) 0x57 Lake Hylia
0x24 Temple of Time Exterior (Night) 0x58 Zora's Domain
0x25 Temple of Time Exterior (Ruins) 0x59 Zora's Fountain
0x26 Know-It-All Brothers' House 0x5A Gerudo Valley
0x27 House of Twins 0x5B Lost Woods
0x28 Mido's House 0x5C Desert Colossus
0x29 Saria's House 0x5D Gerudo's Fortress
0x2A Kakariko Village House 0x5E Haunted Wasteland
0x2B Kakariko Back Alley House 0x5F Hyrule Castle (exterior)
0x2C Bazaar 0x60 Death Mountain Trail
0x2D Kokiri Shop 0x61 Death Mountain Crater
0x2E Goron Shop 0x62 Goron City
0x2F Zora Shop 0x63 Lon Lon Ranch
0x30 Kakariko Potion Shop 0x64 Outside Ganon's Castle
0x31 Market Potion Shop 0x65–0x6D (debug/dev, unreachable in retail)
0x32 Bombchu Shop
0x33 Happy Mask Shop

Entrance index examples

nextEntranceIndex targets used by the warp mechanism (from gamestabled/oot3d_practice_menu's entrances.c, cross-checked on hardware for both ages). Each real location has 4 parallel indices (child-day / child-night / adult-day / adult-night); child-day is the canonical base listed here — the game resolves the right variant automatically based on the pending age/time.

Entrance Index (child-day base)
Deku Tree 0x0000
Dodongo's Cavern 0x0004
Jabu-Jabu's Belly 0x0028
Water Temple 0x0010
Shadow Temple 0x0037
Ice Cavern 0x0088
Gerudo Training Ground 0x0008
Forest Temple 0x0169
Fire Temple 0x0165
Spirit Temple 0x0082
Ganon's Castle 0x0467
Kokiri Forest 0x00EE
Lost Woods 0x011E
Link's House 0x0272
Hyrule Field 0x00CD
Market 0x00B1
Temple of Time 0x0053
Lon Lon Ranch 0x0157
Kakariko Village 0x00DB
Death Mountain Trail 0x013D
Death Mountain Crater 0x0147
Goron City 0x014D
Zora's River 0x00EA
Zora's Domain 0x0108
Zora's Fountain 0x010E
Lake Hylia 0x0102
Gerudo Valley 0x0117
Haunted Wasteland 0x0130
Desert Colossus 0x0123

Full per-scene tables (every room's every door, ~1500 entries) live in the practice-menu project's entrances.c — this list is only the plugin's own curated Teleport destinations.


Methodology notes

How the quest-word / inventory / flag map was derived — by diffing 48 progressive save files from a community "start-to-finish" save collection (each save is one small, documented step further into the game). Method:

  1. Anchor the file to RAM. A field in the .bin save file was matched byte-for-byte against a known in-RAM buffer (the inventory array) — that single match pins the constant offset between file and RAM (RAM = file_offset + 0x587958), because the save is a raw serialization of the same struct, so bit order is identical in both.
  2. Diff consecutive saves. For each step, the bits that flip on correspond to exactly what that save gained. Lining the diffs up against the collection's own written progress notes gives each bit a name.
  3. Cross-check. Bits already confirmed by other means (e.g. medallions, independently testable in-game) reproduce exactly via this method — when they do, the rest of what the same method found is trustworthy too.

Known limitation: progressive saves sometimes gain several flags in one step (e.g. a save that nets 15 Gold Skulltulas at once, or several event flags together) — when that happens, the individual bit-to-item mapping can't be isolated from diffing alone, only the fact that a bit in that byte turned on. Per-Skulltula and per-heart-piece identity ultimately needs the decomp's own token tables, not save-diffing. Where this map says "byte→area" instead of "bit→item", that's this limitation showing — treat those as approximate, not exact.


Compiled from source-code comments and dev notes in OcarinaCTRComposer/RawPlugin/sources/main.c. Corrections welcome.