Majora's Mask

Beta Quest

ROM HACK by JIMMIE1717

Go to Website
About Beta Quest

So how does the Seed work?

Well I'm glad you asked. Whether you know a thing or not this is an interesting question.

The seed is set from the name of file being played on. When the file is loaded the file name is read and then used to randomize everything. The file name is 8 characters long. Each character is 1 byte which makes for a total of 8 bytes or a 64 bit value. The RNG value the game uses, however, is a 32 bit value. So now you might be wondering "How did you turn the 64 bit value into a 32 bit value?". Well initially I had an idea of how I wanted to do this but I decided to look and see if I could get some inspiration from others. I looked at both DeathBasket's old Majora's Mask Item Randomizer that's based on file name and mzxrules Ocarina of Time Beta Quest to see how they approached it. mzxrules way of doing it was actually very similar to what I had in mind so I ended up using a combination of his and mine. Take a look at the following code.

 
// fn1 is the upper 32 bits of the file name, fn2 is the lower 32 bits.
1
function setSeed(fn1, fn2){
2
var n1 = fn1 >> 17, n2 = fn2 << 17; // yes that's right, I put in the 1717.
3
rng_value = n1 | n2;
4
randZeroOne(); // game's built in RNG generation. rng_value = rng_value * 1664525 + 1013904223;
5
n1 = fn1 << 14; // 14 + 18 = 32 bits total.
6
n2 = fn2 >> 18;
7
rng_value += (n1 | n2);
8
}

The file name is split into two different 32 bit values. These are both bit shifted then they are bitwise or'd together. The seed is then set to this value and I run the RNG function which updates it. I then take the two 32 bit values of the name and shift them again. This time however I shift the upper 32 bits to extract the lower 18 bits of it and I shift the lower 32 bits to extract the upper 14 bits of it. These are then bitwise or'd together and then added to the seed. This is now the final seed.

How does the exit calculation work?

Each exit actually works as a key into the table. They work the same as they do for the external scene table actually.

 
(exit & 0xFE00) >> 9 = Scene Index
 
(exit & 0x01F0) >> 4 = Entrance Index

You might notice that this allows for 32 entrances into a scene though. Most scenes don't actually use this many. In the normal game the Grotto scene uses the most which is 17 entrances. For Beta Quest I added entrances for all the grottos so that they can work like a normal exit. So in the case of Beta Quest Termina Field now has the most with 25 entrances.

At any rate having 32 entrances per scene for the exit table, especially when most of them wouldn't be used, wastes a lot of space. To simplify this and conserve space I created an offset table that works based on the Scene Index. So using the Scene Index an offset is gotten as to where to begin in the shuffled table. Then the entrance index is added on to the offset. At this point it is now at the index in the table for the next exit.

Some additional checks are in place for certain things. Such as the Fairy's Fountains. If the player has not yet obtained the magic if the new exit they are suppose to go to is any of the 5 Fairy's Fountains they get redirected to the Clock Town Fountain instead. Additionally if the player is going to an entrance that is in deep water or even underwater then their form is changed. The Chamber of Fate is actually the first thing checked because of how it's intended to work.

 
// 'shuffled' is the copied exit table that got shuffled around.
 
// 'offsets' is the table of offsets based on the Scene Index.
1
function getNewExit(old) {
2
var CoF = getCoFExit(); // get the exit that was randomly selected for Chamber of Fate.
3
if (old == CoF) {
4
return 0xE200; // send the player to Chamber of Fate.
5
} else if (old == 0xE200) {
6
old = CoF; // use the randomly selected exit to get the new one.
7
}
8
// note: there is logic here to check if CoF is already completed that I've omitted here.
8
9
var new = shuffled[(offsets[(old & 0xFE00) >> 9]) + ((old & 0x01F0) >> 4)];
10
// new = shuffled[scene index offset + entrance index];
11
if (new == 0xFFFF) { // exits not meant to be random have value 0xFFFF.
12
return old; // so just return the original.
13
}
14
15
if (!magicPower && (new >> 9) == 0x23) { // don't have magic power, going to a Fountain.
16
new = 0x4600; // set new exit to Clock Town Fountain.
17
}
18
19
var waterExits = [0x4090,0x4400,0x4410,0x6830,0x6850,0x6A10,0x7000,0x7020,0x7030,0x8610,0x8630];
20
if (LINK.form == 'deku' || LINK.form == 'goron') { // in Deku or Goron Link form.
21
var change = false;
22
for(var i = 0;i < waterExits.length; i++) {
23
if (new == waterExits[i]) change = true;
24
}
25
if (change) LINK.form = 'child'; // one of the exits matched, change form.
26
}
27
28
onEpona = false; // disable Epona.
29
30
return new;
31
}

How do the Tunic & Tatl colors work? What colors can I get?

The colors used are randomly generated. Each color channel randomly gets a value ranging from 0 to 255. A total of 27 colors are generated.

For Tatl there are 13 total different Tatl color slots used for different things. Which color used depends on the type of actor such as NPCs, props, enemies, etc…

Why is only Child Link's Tunic colored and not the other forms?

Changing Child Link's tunic is actually pretty easy. There are just 9 different parts of the tunic that need to be found in RAM and change the RGB color for them. All of the other forms of Link are not like this. They instead use textures or a color palette. This would require going through all of the textures or palettes RGB colors for each pixel and adjusting it's hue and/or lightness to change the color. Not impossible but nowhere near as simple as just swapping out a single RGB value in 9 places. So I chose not to bother changing them.

How does the Chamber of Fate work?

Part of the function that runs when a file is loaded that shuffles the table of exits around also generates 3 indexes to use for the Chamber of Fate. These indexes represent which spawn orientation to use, which chest to place the item in, and which item to use.

Within the Room file's actor list all of the chests are actually set to have blue rupees in them. When a scene is being loaded it is checked whether it is the Chamber of Fate. If it is then the selected chest get's the selected item placed into it. This means that two of the chests are always a blue rupee.

What if I already have the item that was selected for Chamber of Fate? Will it pick a different one I don't have?

Once the item is selected it will always be that specific item. This means that, just like in the regular game, even if the player opens the correct chest with the item in it they will just get a blue rupee instead.

What items can be gotten from the Chamber of Fate?

The item list consists of those usually at a single location meaning to normally get them the player has to find that single exit. Several of them also require either other items or other exits which may make them difficult to get. The following is the complete list.

    Item List:

  • Mirror Shield
  • Gilded Sword
  • Great Fairy's Sword
  • Hookshot
  • Lens of Truth
  • Pictograph Box
  • Fierce Deity Mask