Try   HackMD

Ocarina of Time Gateway changes

Introduction

The build date of the newly-discovered Gateway rom is 99-01-19 11:37:17. This is later than every released Nintendo 64 version (the last of these being in November 1998): the last NTSC version (commonly referred to as 1.2 or NN2) was built on 98-11-12, and the last PAL version (the second PAL version, referred to as NP1) on 98-11-18.

Summary

The vast majority of the rom is the same as NN2. A small number of the changes made between NN2 and NP1 are present, but plenty of others are not (such as the Gerudo who gives you Gerudo card's clothes, which are patched to be stay a single colour in NP1 and later). These are noted below.

  • The most visible change is that the new Gerudo symbol is used instead of the original crescent and star, in both scene model textures and actor model textures. This change was originally thought to come from Majora's Mask first; this rom is now the earliest known build of a Zelda game to use it.[1] Most interestingly, this also includes textures in Dampe's race and Iron Knuckles, which are not patched in any other known rom version.
  • The file choice screen is changed to only display a single file, and no copy/erase functionality. A new file (which we may guess is called gateway_title_static) contains 3 new textures for this, a Start button, and textures for Please Select., Press A button to decide., Press B button to exit.. After entering a name, the game starts immediately END is pressed.
  • The Save option is disabled in the pause menu, and the Game Over screen goes straight to the "Continue playing?" choice, skipping the save screen. Since these are the only way to save, saving is impossible. No text is changed, so the tutorial signs still explain how to save the game.
  • Rumble is completely disabled (so just as in the Virtual Console release, the Stone of Agony is completely useless).
  • The three antipiracy checks are removed, specifically:
    • Fishing would disable catching.
    • Zelda's hair would turn into an afro.
    • The gates in the castle collapse escape sequence would not open.

Detailed analysis

Section titles are the segment name.

Rom header

Region byte is 'G'.

boot

  • z_locale: switch changed to cover 'L' and 'G' as the region byte instead of 'J'/'E'/'P'
  • CIC6105: first two functions stubbed (removing antipiracy checks, the second one is used in ovl_title)
  • bcmp: moved here from code
  • build: build date is different

code

N.B. the segment is called code, but there is executable code in many other segments, this is just the largest one that is always loaded.

  • z_parameter: Changed to not draw the B button if the DoAction is "Save".[2]
  • z_ss_sram: extra function used by the new function in graph (see below):
    ​​void func_80091BC4_neg(u32 addr, void* dramAddr, s32 direction) {
    ​​    SsSram_Init(addr, DEVICE_TYPE_SRAM, PI_DOMAIN2, 
    ​​                HALT_REG_latency, HALT_REG_pageSize, HALT_REG_relDuration,
    ​​                HALT_REG_pulse, 0);
    ​​    SsSram_Dma(dramAddr, 2, direction);
    ​​}
    
    this essentially just writes 2 bytes to the given address.
  • z_play: "Empty Epona cutscene" patch (as in NP1) (https://github.com/zeldaret/oot/blob/8e04ae917f013f3944114fddd1286dfea86a010a/src/code/z_play.c#L1757-L1761 is not present in NN2)
  • audioMgr: AudioMgr_Init as in GC versions (setting SREG(20) is removed).
  • graph: function to conform to the gateway halting requirements, i.e. pause gameplay when joypad Up+Down is pressed and released, resume when joypad Left+Right is pressed and released. This is called near the top of graph_main(Graph_Update)
    ​​void func_800A1EF8_neg(GameState* game) {
    ​​    Input* input = game->input;
    ​​    u16 payload;
    
    ​​    if ((input->cur.button & (U_JPAD | D_JPAD)) == (U_JPAD | D_JPAD)) {
    ​​        SREG(20) = 2;
    
    ​​        // Set halt bit
    ​​        payload = 0xFFFF;
    ​​        func_80091BC4_neg(HALT_REG_START_ADDR, &payload, OS_WRITE);
    
    ​​      // Wait for Up or Down to be released
    ​​        do {
    ​​            usleep(1000000 / 60);
    ​​            game_get_controller(game);
    ​​        } while ((input->cur.button & (U_JPAD | D_JPAD)) == (U_JPAD | D_JPAD));
    
    ​​        // Sit in this loop until Left and Right detected
    ​​        do {
    ​​            usleep(1000000 / 60);
    ​​            game_get_controller(game);
    ​​        } while ((input->cur.button & (L_JPAD | R_JPAD)) != (L_JPAD | R_JPAD));
    
    ​​        // clear halt bit
    ​​        payload = 0;
    ​​        func_80091BC4_neg(HALT_REG_START_ADDR, &payload, OS_WRITE);
    
    ​​        // Wait for Left or Right to be released
    ​​        do {
    ​​            usleep(1000000 / 60);
    ​​            game_get_controller(game);
    ​​        } while ((input->cur.button & (L_JPAD | R_JPAD)) == (L_JPAD | R_JPAD));
    ​​
    ​​        SREG(20) = 0;
    ​​    }
    ​​}
    
    SREG(20) is used to tell the audio thread to not update (see https://github.com/zeldaret/oot/blob/8e04ae917f013f3944114fddd1286dfea86a010a/src/code/audioMgr.c#L11-L44)
  • padmgr: Essentially anything rumble-related removed:
    • PadMgr_UpdateRumble, PadMgr_RumbleStop, PadMgr_RumbleReset are removed.
    • PadMgr_RumbleSetSingle and PadMgr_RumbleSet still exist (presumably because they are used elsewhere).
    • PadMgr_HandleRetrace: PadMgr_RumbleStop block at the bottom is gone. (For some reason IDO unrolled the loop in this version only.)
    • PadMgr_HandlePreNMI: call to PadMgr_RumbleReset removed
  • z_game_over: Nayru's Love timer change from NP1 (https://github.com/zeldaret/oot/blob/8e04ae917f013f3944114fddd1286dfea86a010a/src/code/z_game_over.c#L63 is 0 on versions pre-NP1).

Libultra: most changes are removal of pfs files

  • motor: removed
  • pfsselectbank: removed
  • contramwrite: removed
  • pfsgetstatus: removed
  • contpfs: removed
  • bcmp: moved to boot
  • contramread: removed
  • crc: removed
  • pfsisplug: removed

Overlays

  • ovl_file_choose: changed to only have one file selectable, uses new file textures, etc. Note struct is shifted relative to PAL (but consistent with NTSC)
    • FileSelect_DrawNameEntry
      ​​​​​​​​    Audio_PlaySfxGeneral(NA_SE_SY_FSEL_DECIDE_L, &gSfxDefaultPos, 4,
      ​​​​​​​​                                             &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale,
      ​​​​​​​​                                             &gSfxDefaultReverb);
      ​​​​​​​​-    gSaveContext.fileNum = this->buttonIndex;
      ​​​​​​​​-    dayTime = ((void)0, gSaveContext.dayTime);
      ​​​​​​​​-    Sram_InitSave(this, &this->sramCtx);
      ​​​​​​​​-    gSaveContext.dayTime = dayTime;
      ​​​​​​​​    this->configMode = CM_NAME_ENTRY_TO_MAIN;
      ​​​​​​​​    this->nameBoxAlpha[this->buttonIndex] = this->nameAlpha[this->buttonIndex] = 200;
      ​​​​​​​​-    this->connectorAlpha[this->buttonIndex] = 255;
      ​​​​​​​​-    Rumble_Request(300.0f, 180, 20, 100);
      ​​​​​​​​+    this->actionTimer = 8;
      ​​​​​​​​+    this->selectedFileIndex = this->buttonIndex;
      ​​​​​​​​+    this->menuMode = FS_MENU_MODE_SELECT;
      ​​​​​​​​+    this->nextTitleLabel = FS_TITLE_OPEN_FILE;
      ​​​​​​​​+    this->selectMode = SM_FADE_OUT;
      
    • New file for gateway stuff:
      • func_8080BCC0_neg: duplicate of Sram_InitNewSave
      • func_8080BDEC_neg: stub
      • func_8080BDF4_neg: stub
      • func_8080BDFC_neg: Similar to the top half of Sram_InitSave, (above setting the "ZELDAZ")
      • func_8080BF40_neg: Similar to the bottom half of Sram_InitSave
    • func_8080C290_ne2/func_8080C780_neg (FileSelect_UpdateMainMenu): vast majority of function removed
      ​​​​​​​​-        if (this->buttonIndex <= FS_BTN_MAIN_FILE_3) {
      ​​​​​​​​+        if (this->buttonIndex == FS_BTN_MAIN_FILE_0) {
      ​​​​​​​​-        if (!SLOT_OCCUPIED(sramCtx, this->buttonIndex)) {
      ​​​​​​​​            Audio_PlaySfxGeneral(NA_SE_SY_FSEL_DECIDE_L, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale,
      ​​​​​​​​                                 &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
      
      Below the first MemCpy the rest of the function is just
      ​​​​​​​​    Audio_PlaySfxGeneral(NA_SE_SY_FSEL_DECIDE_L, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale,
      ​​​​​​​​                         &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
      ​​​​​​​​    this->prevConfigMode = this->configMode;
      
      ​​​​​​​​    this->configMode = CM_MAIN_TO_OPTIONS;
      ​​​​​​​​    this->kbdButton = 0;
      ​​​​​​​​    this->kbdX = 0;
      ​​​​​​​​    this->kbdY = 0;
      ​​​​​​​​    this->charBgAlpha = 0;
      ​​​​​​​​    this->newFileNameCharCount = 0;
      ​​​​​​​​    this->nameEntryBoxPosX = 120;
      
      ​​​​​​​​    this->actionTimer = 8;
      ​​​​​​​​} else {
      ​​​​​​​​    if (ABS(this->stickAdjY) > 30) {
      ​​​​​​​​        Audio_PlaySfxGeneral(NA_SE_SY_FSEL_CURSOR, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale,
      ​​​​​​​​                             &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
      
      ​​​​​​​​        this->buttonIndex ^= 1;
      ​​​​​​​​    }
      ​​​​​​​​}
      
    • func_8080D138_ne2/func_8080CFD0_neg (FileSelect_SetWindowContentVtx): phi_t5 is 0x274, or 0x40 if buttonIndex == 0, the other logic is gone. Also an extra set of vertices is set above that block, using VREG(28) and VREG(30).
    • func_8080EB78_ne2/func_8080EA44_neg (FileSelect_DrawWindowContents): large differences throughout
      • sTitleLabels[gSaveContext.language][this->titleLabel] replaced by D_2000800_neg in the first gDPLoadTextureBlock
      • Next block (the nextTitleLabel one) is gone.
      • The file button/box loop is gone, replaced by a single iteration, that uses the Start texture, and all the DD stuff removed.
      • sActionButtonTextures loop is gone.
    • FileSelect_LoadGame: save opening replaced by custom version.
      ​​​​​​​​-Audio_PlaySfxGeneral(NA_SE_SY_FSEL_DECIDE_L, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale,
      ​​​​​​​​-                     &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
      ​​​​​​​​-gSaveContext.fileNum = this->buttonIndex;
      ​​​​​​​​-Sram_OpenSave(&this->sramCtx);
      ​​​​​​​​+func_8080BDFC_neg(this);
      ​​​​​​​​gSaveContext.gameMode = GAMEMODE_NORMAL;
      ​​​​​​​​SET_NEXT_GAMESTATE(&this->state, Play_Init, PlayState);
      ​​​​​​​​this->state.running = false;
      
    • FileSelect_Main:
      ​​​​​​​​FileSelect_PulsateCursor(&this->state);
      ​​​​​​​​sFileSelectUpdateFuncs[this->menuMode](&this->state);
      ​​​​​​​​sFileSelectDrawFuncs[this->menuMode](&this->state);
      
      ​​​​​​-  if ((this->configMode <= CM_NAME_ENTRY_TO_MAIN) || (this->configMode >= CM_UNUSED_DELAY)) {
      ​​​​​​​​    Gfx_SetupDL_39Opa(this->state.gfxCtx);
      
      ​​​​​​​​    gDPSetCombineLERP(POLY_OPA_DISP++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0,
      ​​​​​​​​                      PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0);
      ​​​​​​​​    gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 100, 255, 255, this->controlsAlpha);
      ​​​​​​​​    gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 0);
      
      ​​​​​​-      gDPLoadTextureBlock(POLY_OPA_DISP++, controlsTextures[gSaveContext.language], G_IM_FMT_IA, G_IM_SIZ_8b, 144, 16,
      ​​​​​​-                          0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK,
      ​​​​​​-                          G_TX_NOLOD, G_TX_NOLOD);
      ​​​​​​-      gSPTextureRectangle(POLY_OPA_DISP++, 90 << 2, 204 << 2, 234 << 2, 220 << 2, G_TX_RENDERTILE, 0, 0, 1 << 10,
      ​​​​​​-                          1 << 10);
      ​​​​​​+  if ((this->configMode <= CM_NAME_ENTRY_TO_MAIN) || (this->configMode >= CM_UNUSED_DELAY)) {
      ​​​​​​+      gDPLoadTextureBlock(POLY_OPA_DISP++, D_2001000_neg, G_IM_FMT_IA, G_IM_SIZ_8b, 144, 16,
      ​​​​​​+                          0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK,
      ​​​​​​+                          G_TX_NOLOD, G_TX_NOLOD);
      ​​​​​​+      gSPTextureRectangle(POLY_OPA_DISP++, 90 << 2, 204 << 2, 234 << 2, 220 << 2, G_TX_RENDERTILE, 0, 0, 1 << 10,
      ​​​​​​+                          1 << 10);
      ​​​​​​+  } else if (this->configMode == CM_OPTIONS_MENU) {
      ​​​​​​+      gDPLoadTextureBlock(POLY_OPA_DISP++, D_2001900_neg, G_IM_FMT_IA, G_IM_SIZ_8b, 144, 16,
      ​​​​​​+                          0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK,
      ​​​​​​+                          G_TX_NOLOD, G_TX_NOLOD);
      ​​​​​​+      gSPTextureRectangle(POLY_OPA_DISP++, 90 << 2, 204 << 2, 234 << 2, 220 << 2, G_TX_RENDERTILE, 0, 0, 1 << 10,
      ​​​​​​+                          1 << 10);
      ​​​​​​​​}
      
      ​​​​​​​​gDPPipeSync(POLY_OPA_DISP++);
      ​​​​​​​​gSPDisplayList(POLY_OPA_DISP++, sScreenFillSetupDL);
      ​​​​​​​​gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 0, 0, 0, sScreenFillAlpha);
      ​​​​​​​​gDPFillRectangle(POLY_OPA_DISP++, 0, 0, gScreenWidth - 1, gScreenHeight - 1);
      
    (presumably the new gateway_texture_static images)
    • FileSelect_Init:
      ​​​​​​-    DmaMgr_RequestSync(this->parameterSegment, (uintptr_t)_parameter_staticSegmentRomStart, size);
      ​​​​​​+    DmaMgr_RequestSync(this->parameterSegment, (uintptr_t)_gateway_title_staticSegmentRomStart, size);
      ​​​​​​+    VREG(28) = 0;
      ​​​​​​+    VREG(30) = 35;
      
      ​​​​​​​​    Matrix_Init(&this->state);
      
  • ovl_kaleido_scope:
    • func_80816078_ne2/func_80815B28_neg (Kaleidoscope_DrawDebugEditor):
      ​​​​​​​​                if (CHECK_BTN_ALL(input->press.button, BTN_CUP) || CHECK_BTN_ALL(input->press.button, BTN_CLEFT)) {
      ​​​​​​​​                    gSaveContext.inventory.gsTokens++;
      ​​​​​​-                     if (gSaveContext.inventory.gsTokens >= 100) {
      ​​​​​​-                          gSaveContext.inventory.gsTokens = 100;
      ​​​​​​-                     }
      ​​​​​​​​                } else if (CHECK_BTN_ALL(input->press.button, BTN_CDOWN) ||
      ​​​​​​​​                           CHECK_BTN_ALL(input->press.button, BTN_CRIGHT)) {
      ​​​​​​​​                    gSaveContext.inventory.gsTokens--;
      ​​​​​​​​                    if (gSaveContext.inventory.gsTokens <= 0) {
      ​​​​​​​​                        gSaveContext.inventory.gsTokens = 0;
      ​​​​​​​​                    }
      ​​​​​​​​                }
      
      (present in all other N64 versions, gone in iQue and GC)
    • func_8081F4B8_ne2/func_8081EF48_neg (KaleidoScope_SwitchPage):
      ​​​​​​-    gSaveContext.buttonStatus[0] = D_8082AB6C[pauseCtx->pageIndex + pt][0];
      ​​​​​​+    gSaveContext.buttonStatus[0] = BTN_DISABLED;
      ​​​​​​​​    gSaveContext.buttonStatus[1] = D_8082AB6C[pauseCtx->pageIndex + pt][1];
      ​​​​​​​​    gSaveContext.buttonStatus[2] = D_8082AB6C[pauseCtx->pageIndex + pt][2];
      ​​​​​​​​    gSaveContext.buttonStatus[3] = D_8082AB6C[pauseCtx->pageIndex + pt][3];
      ​​​​​​​​    gSaveContext.buttonStatus[4] = D_8082AB6C[pauseCtx->pageIndex + pt][4];
      
    • func_80825CD0_ne2/func_8082574C_neg (func_808265BC)
      ​​​​​​​​    gSaveContext.buttonStatus[0] = D_8082AB6C[pauseCtx->pageIndex][0];
      ​​​​​​​​    gSaveContext.buttonStatus[1] = D_8082AB6C[pauseCtx->pageIndex][1];
      ​​​​​​​​    gSaveContext.buttonStatus[2] = D_8082AB6C[pauseCtx->pageIndex][2];
      ​​​​​​​​    gSaveContext.buttonStatus[3] = D_8082AB6C[pauseCtx->pageIndex][3];
      ​​​​​​​​    gSaveContext.buttonStatus[4] = D_8082AB6C[pauseCtx->pageIndex][4];
      ​​​​​​​​    pauseCtx->pageIndex = D_8082ABEC[pauseCtx->mode];
      ​​​​​​​​    pauseCtx->unk_1E4 = 0;
      ​​​​​​​​    pauseCtx->state++;
      ​​​​​​​​    pauseCtx->alpha = 255;
      ​​​​​​+    gSaveContext.buttonStatus[0] = BTN_DISABLED
      ​​​​​​​​    Interface_LoadActionLabelB(play, DO_ACTION_SAVE);
      
    • func_808263C0_ne2/func_80825E44_neg (Kaleidoscope_Update)
      ​​​​​​​​            switch (pauseCtx->unk_1E4) {
      ​​​​​​​​            case 0:
      ​​​​​​​​                if (CHECK_BTN_ALL(input->press.button, BTN_START)) {
      ​​​​​​​​                    Interface_SetDoAction(play, DO_ACTION_NONE);
      ​​​​​​​​                    pauseCtx->state = 0x12;
      ​​​​​​​​                    WREG(2) = -6240;
      ​​​​​​​​                    func_800F64E0(0);
      ​​​​​​​​                } else if (CHECK_BTN_ALL(input->press.button, BTN_B)) {
      ​​​​​​-                      pauseCtx->mode = 0;
      ​​​​​​-                      pauseCtx->promptChoice = 0;
      ​​​​​​-                      Audio_PlaySfxGeneral(NA_SE_SY_DECIDE, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale,
      ​​​​​​-                                           &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
      ​​​​​​-                      gSaveContext.buttonStatus[0] = gSaveContext.buttonStatus[1] = gSaveContext.buttonStatus[2] =
      ​​​​​​-                          gSaveContext.buttonStatus[3] = BTN_DISABLED;
      ​​​​​​-                      gSaveContext.buttonStatus[4] = BTN_ENABLED;
      ​​​​​​-                      gSaveContext.hudVisibilityMode = HUD_VISIBILITY_NO_CHANGE;
      ​​​​​​-                      Interface_ChangeHudVisibilityMode(HUD_VISIBILITY_ALL);
      ​​​​​​-                      pauseCtx->unk_1EC = 0;
      ​​​​​​-                      pauseCtx->state = 7;
      ​​​​​​​​                }
      ​​​​​​​​                break;
      
    and similarly in cases 5 and 8.
  • ovl_En_Zl2: antipiracy check removed:
    ​​        Matrix_Push();
    ​​-        if (osCicId != 6105) {
    ​​-            Matrix_Scale(2.0f, 1.0f, 2.0f, MTXMODE_APPLY);
    ​​-        }
    ​​        Matrix_Translate(pos->x, pos->y, pos->z, MTXMODE_APPLY);
    ​​        Matrix_RotateZYX(rot->x, rot->y, rot->z, MTXMODE_APPLY);
    ​​        Matrix_Push();
    
    (famously this turns adult Zelda's hair into an afro).
  • ovl_Fishing: antipiracy check removed (this would check the value at a particular RAM address and prevent reeling a fish in if incorrect)
  • ovl_En_Ganon_Mant (Ganondorf's cape): Gerudo symbol (model is in the data of this actor rather than an object)
  • ovl_Bg_Zg (Gates in Ganon's Tower Collapse): antipiracy check removed (the gate will not open if the check fails)
  • ovl_En_Go2 (Gorons): https://github.com/zeldaret/oot/blob/8e04ae917f013f3944114fddd1286dfea86a010a/src/overlays/actors/ovl_En_Go2/z_en_go2.c#L1581 the flag clear is the same as NP1 on, rather than NN2.

Asset files

  • icon_item_static: Gerudo symbol on Mirror Shield
  • gateway_title_static: New file with textures for a Start button, Please Select., Press A button to decide., Press B button to exit.

Actor Objects

All just have the Gerudo symbol replaced

  • gameplay_dangeon_keep (General dungeon objects)
  • object_link_boy (Adult Link)
  • object_menkuri_objects (Gerudo Training Ground objects)
  • object_haka_objects (Shadow Temple objects)
  • object_heavy_object (Huge liftable pillar)
  • object_mir_ray (Reflected light beam)
  • object_gi_gerudo (Gerudo Card)
  • object_gi_shield_3 (Mirror Shield)
  • object_jya_obj (Spirit Temple objects)
  • object_ik (Iron Knuckle)

object_ik is notable because the change does not exist on any other version.

Scenes

  • spot06_room_0 (Lake Hylia): Water Temple gate and lock moved down 200 units (as in NP1 and later)
  • spot12_scene (Gerudo's Fortress): Gerudo symbol
  • Bmori1_room_11 (Forest Temple): Gerudo symbol
  • men_scene + rooms (Gerudo Training Ground): A palette is a slightly different size. This palette change causes a lot of changes in room files that are unimportant due to colour indexed textures having their indices changed.
  • jyasinzou_scene + rooms (Spirit Temple): A palette is a slightly different size (and shifted) from GC versions.
  • jyasinboss_room_1,3 (Twinrova's lair): Gerudo symbol
  • hakasitarelay_room_06 (Dampe Race ("?")): PolygonType 2 is used instead of 0

hakasitarelay (Dampe race) deserves special mention, RoomShapeCullable is used instead of RoomShapeNormal. For example, in room 0:

All other versions:

RoomShapeNormal hakasitarelay_room_0RoomShapeNormal_0000F0 = { 
    0, 1,
    hakasitarelay_room_0RoomShapeDListsEntry_0000FC,
    hakasitarelay_room_0RoomShapeDListsEntry_0000FC + ARRAY_COUNTU(hakasitarelay_room_0RoomShapeDListsEntry_0000FC)
};

RoomShapeDListsEntry hakasitarelay_room_0RoomShapeDListsEntry_0000FC[1] = {
    { hakasitarelay_room_0DL_003218, hakasitarelay_room_0DL_0062A8 },
};

neg:

RoomShapeCullable hakasitarelay_room_0RoomShapeCullable_0000F0 = { 
    2, 6,
    hakasitarelay_room_0RoomShapeCullableEntry_0000FC,
    hakasitarelay_room_0RoomShapeCullableEntry_0000FC + ARRAY_COUNTU(hakasitarelay_room_0RoomShapeCullableEntry_0000FC)
};

RoomShapeCullableEntry hakasitarelay_room_0RoomShapeCullableEntry_0000FC[6] = {
    { {    -59,   -460,  -1602 },     56, hakasitarelay_room_0DL_000230, NULL },
    { {    -60,   -335,  -1760 },    400, hakasitarelay_room_0DL_0010E8, NULL },
    { {    155,   -355,  -2385 },   1110, hakasitarelay_room_0DL_002610, NULL },
    { {    155,   -540,  -2385 },   1100, hakasitarelay_room_0DL_002EF0, NULL },
    { {    -59,    -80,  -1602 },     82, hakasitarelay_room_0DL_0031C8, NULL },
    { {    -59,   -300,  -1602 },    169, NULL, hakasitarelay_room_0DL_006220 },
};

This is the only known version that is this way. (What does this actually change?)

This is also the only known version of the original where the Gerudo symbol is removed in this scene rather than replaced: GC misses it, VC replaces it with the new one.


  1. This change has a somewhat storied history:
    The symbol was first seen in Majora's Mask in a single place.
    Gamecube releases of Ocarina of Time used it to replace the original crescent and star symbol everywhere; these edits were made in the rom itself.
    Virtual Console releases have also made this change, but the edits are done by the emulators themselves; the roms are identical to NN2 or NP1. This also added the new symbol to Dampe race, whereas Gateway simply removes it.
    Strangest of all is the iQue release, where the symbol is the new one on actors and the old one on scenes; we may speculate that the wrong files were used by accident. ↩︎

  2. Also if the DoAction state is 0x2B, which is well outside the range of normal DoAction states. ↩︎