Cite as
zeldaret/mm
Original
https://github.com/zeldaret/mm
Pinned
zeldaret/mm @ 710e1a7d50a1f987f5fc55abca37f7fdcc8ee43d
Accessed
2026-10-22
Licence
none stated (no license file at the pinned commit); the game is Nintendo's
Credit
The Zelda Reverse Engineering Team's (zeldaret) C decompilation of Majora's Mask, which builds the N64 US 1.0 ROM. Names and comments quoted in mm claims are theirs.
Notes
The README's title is "Legend of Zelda: Majora's Mask (US) 1.0"; it says N64 US is the only version supported, gives the MD5 of the ROM it builds, and says the repo holds no assets. Some files have MM_VERSION conditionals for the Japanese builds; spec/spec links z_sram_NES.c and z_message_nes.c only when MM_VERSION >= N64_US. mm claims read the code US 1.0 compiles. Of the cited files, z_kankyo.c, z_scene.c, game.c, z_sram_NES.c, z_play.c, and z_en_test4.c have no version #if and z_parameter.c only an AVOID_UB block; the cited ranges of z_message.c and graph.c sit outside their version blocks. The time speed each scene sets is in its scene header, ROM data the repo doesn't hold.

Cited on

Claims (5)

In the N64 US 1.0 code the clock is a 16-bit count in which a day is 0x10000 units, so a game minute is about 45.5 units (computed; the macro CLOCK_TIME_MINUTE truncates it to 45). Each play update, Environment_UpdateTime adds the time speed R_TIME_SPEED and then, if that speed isn't 0, the save's timeSpeedOffset. It adds only when time isn't stopped, the game isn't paused or over, no textbox is open (or its message id is 0xF7, 0x20D2, 0x140C, or 0x100 through 0x200, or the game mode is the end credits), the debug frame advance (FrameAdvance_IsEnabled) is off, no transition is under way (transitionMode off, or a game mode other than normal) and none has been triggered, and no cutscene runs. From 18:00 until 6:00 it sets the save's isNight flag.include/macros.h L23–26include/z64save.h L334–338src/code/z_kankyo.c L1203–1214src/code/z_kankyo.c L1227–1230src/code/z_kankyo.c L1774–1779src/code/z_play.c L1051Code
In the N64 US 1.0 code each scene's header sets its time speed, and a header value of 0xFF gives 0, a scene where time stands still. While Link's ocarina slot is empty, a nonzero scene speed becomes 5, under a decompilers' comment that reads "Increase time speed during first cycle"; the scene's speed becomes R_TIME_SPEED only while Sun's Song is inactive. The Inverted Song of Time is offered only where the scene's restriction flags allow it (otherwise text 0x1B95 and nothing) and the speed isn't 0; accepting it sets the offset to −2, or back to 0 if it was already set, and the update adds the offset only while the speed isn't 0. The game updates once every 3 video frames, set by GameState_SetFramerateDivisor(3) into a field whose comment reads "how many VIs should elapse before next swap". Assuming NTSC's 59.94 video frames a second (the atlas's assumption, not in the code), that is about 20 updates a second, and at speed 5 a game minute takes about 0.46 s, a day about 656 s, and the three days about 33 minutes (computed). The usual speed of a scene is in its header, ROM data the decompilation doesn't hold.src/code/z_scene.c L393–406src/code/z_message.c L5890–5906src/code/z_kankyo.c L1212–1214src/code/z_message.c L5683–5694src/code/game.c L40–43src/code/game.c L243src/code/graph.c L236include/scheduler.h L25Code
In the N64 US 1.0 code, answering yes to the Song of Time's prompt runs Sram_SaveEndOfCycle, whose comment says it is "Used by Song of Time (when clicking "Yes") and (indirectly) by the "Dawn of the New Day" cutscene". The function sets the day counter to 0 and the clock one unit before 6:00, clears the Inverted Song's offset, and adds one to a reset count capped at 999, but on the song's path the message code saves the day, the time, and the cutscene index before the call and puts them back right after it; where the cycle returns to the first dawn is untraced. It sets the rupees Link carries to 0 and every ammo count to 0 except the pictograph box's, and turns any bottle holding an item from ITEM_POTION_RED through ITEM_OBABA_DRINK back into an empty bottle. It sets a sword at or below the Razor Sword back to the Kokiri Sword (or the Gilded Sword if a stolen-item slot holds it), removes dungeon keys, boss keys, stray fairies, and the pictograph, and clears the event-info flags. Scene flags (switches, chests, collectibles) and week-event flags survive only where a per-scene or per-flag persistence table marks them. Among the rest, it resets five minigame high scores and the three Deku Playground scores, but not the bank balance, which is kept in the high-score slot HS_BANK_RUPEES.src/code/z_message.c L5881–5884src/code/z_message.c L5668–5673src/code/z_message.c L6022–6034src/code/z_sram_NES.c L427–444src/code/z_sram_NES.c L450–464src/code/z_sram_NES.c L486–499src/code/z_sram_NES.c L536–556src/code/z_sram_NES.c L561–573src/code/z_sram_NES.c L637–645src/code/z_sram_NES.c L404–413include/z64save.h L613–614spec/spec L694–696Code
In the N64 US 1.0 code, accepting the Song of Double Time's prompt sets the clock to 6:00 if the save's isNight flag is set and to 18:00 if not, and turns off the moon's countdown timer; this code doesn't change the day counter. The three-day events actor (En_Test4) then sees the clock cross 6:00 and, in its no-cutscene branch, adds a day; that the jump to exactly 6:00 trips its crossing test is the atlas's reading. The song isn't offered on the third night (day 3 with isNight set) or where a scene's restriction flags forbid it.src/overlays/actors/ovl_En_Test4/z_en_test4.c L419–429src/overlays/actors/ovl_En_Test4/z_en_test4.c L115–118src/code/z_message.c L5908–5919src/code/z_message.c L5702–5713src/code/z_message.c L5305–5313Code
In the N64 US 1.0 code, the actor En_Test4, which its file's comment describes as "Three-Day Events: day-night transitions", compares each update the clock with the next transition time (6:00 by night, 18:00 by day) by multiplying the 16-bit differences of the current and previous times from it and treating a product of 0 or less as a crossing (the atlas's reading of the test), unless a transition, a cutscene, setup actors, a room load, or the debug camera is under way. When the clock crosses 6:00 with the day counter at 3, it calls Interface_StartMoonCrash, which sets the day to 4 and the clock to 6:00 plus 10 units and starts a white fade to a Termina Field entrance. On days 1 and 2 the same crossing adds a day when no transition cutscene is set or the telescope is on; the other branch (z_en_test4.c L446-L470), which sets a flag the decomp names EVENTINF_TRIGGER_DAYTELOP for the Dawn of a New Day screen, is untraced. Play_Init spawns this actor in dungeon and boss rooms on any day but 0; elsewhere it comes from scene data the atlas hasn't read.src/overlays/actors/ovl_En_Test4/z_en_test4.c L4src/overlays/actors/ovl_En_Test4/z_en_test4.c L404–445src/overlays/actors/ovl_En_Test4/z_en_test4.c L446–470src/overlays/actors/ovl_En_Test4/z_en_test4.c L115–118src/code/z_sram_NES.c L655–658src/code/z_parameter.c L5612–5623src/code/z_play.c L2316–2318Code