Shipwright/soh/soh/Enhancements/randomizer/savefile.cpp

450 lines
21 KiB
C++

#include "savefile.h"
#include "soh/OTRGlobals.h"
#include "soh/Enhancements/game-interactor/GameInteractor.h"
extern "C" {
#include <z64.h>
#include "variables.h"
#include "functions.h"
#include "macros.h"
uint32_t ResourceMgr_IsSceneMasterQuest(s16 sceneNum);
uint8_t Randomizer_GetSettingValue(RandomizerSettingKey randoSettingKey);
GetItemEntry Randomizer_GetItemFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId);
}
void StartingItemGive(GetItemEntry getItemEntry) {
if (getItemEntry.modIndex == MOD_NONE) {
if (getItemEntry.getItemId == GI_SWORD_BGS) {
gSaveContext.bgsFlag = true;
}
Item_Give(NULL, getItemEntry.itemId);
} else if (getItemEntry.modIndex == MOD_RANDOMIZER) {
if (getItemEntry.getItemId == RG_ICE_TRAP) {
gSaveContext.pendingIceTrapCount++;
} else {
Randomizer_Item_Give(NULL, getItemEntry);
}
}
}
// RANDOTODO replace most of these GiveLink functions with calls to
// Item_Give in z_parameter, we'll need to update Item_Give to ensure
// nothing breaks when calling it without a valid play first
void GiveLinkRupees(int numOfRupees) {
int maxRupeeCount;
if (CUR_UPG_VALUE(UPG_WALLET) == 0) {
maxRupeeCount = 99;
} else if (CUR_UPG_VALUE(UPG_WALLET) == 1) {
maxRupeeCount = 200;
} else if (CUR_UPG_VALUE(UPG_WALLET) == 2) {
maxRupeeCount = 500;
}
int newRupeeCount = gSaveContext.rupees;
newRupeeCount += numOfRupees;
if (newRupeeCount > maxRupeeCount) {
gSaveContext.rupees = maxRupeeCount;
} else {
gSaveContext.rupees = newRupeeCount;
}
}
void GiveLinkDekuSticks(int howManySticks) {
int maxStickCount;
if (CUR_UPG_VALUE(UPG_STICKS) == 0) {
INV_CONTENT(ITEM_STICK) = ITEM_STICK;
Inventory_ChangeUpgrade(UPG_STICKS, 1);
maxStickCount = 10;
} else if (CUR_UPG_VALUE(UPG_STICKS) == 1) {
maxStickCount = 10;
} else if (CUR_UPG_VALUE(UPG_STICKS) == 2) {
maxStickCount = 20;
} else if (CUR_UPG_VALUE(UPG_STICKS) == 3) {
maxStickCount = 30;
}
if ((AMMO(ITEM_STICK) + howManySticks) > maxStickCount) {
AMMO(ITEM_STICK) = maxStickCount;
} else {
AMMO(ITEM_STICK) += howManySticks;
}
}
void GiveLinkDekuNuts(int howManyNuts) {
int maxNutCount;
if (CUR_UPG_VALUE(UPG_NUTS) == 0) {
INV_CONTENT(ITEM_NUT) = ITEM_NUT;
Inventory_ChangeUpgrade(UPG_NUTS, 1);
maxNutCount = 20;
} else if (CUR_UPG_VALUE(UPG_NUTS) == 1) {
maxNutCount = 20;
} else if (CUR_UPG_VALUE(UPG_NUTS) == 2) {
maxNutCount = 30;
} else if (CUR_UPG_VALUE(UPG_NUTS) == 3) {
maxNutCount = 40;
}
if ((AMMO(ITEM_NUT) + howManyNuts) > maxNutCount) {
AMMO(ITEM_NUT) = maxNutCount;
} else {
AMMO(ITEM_NUT) += howManyNuts;
}
}
void GiveLinksPocketItem() {
if (Randomizer_GetSettingValue(RSK_LINKS_POCKET) != RO_LINKS_POCKET_NOTHING) {
GetItemEntry getItemEntry = Randomizer_GetItemFromKnownCheck(RC_LINKS_POCKET, (GetItemID)RG_NONE);
StartingItemGive(getItemEntry);
}
}
void SetStartingItems() {
if (Randomizer_GetSettingValue(RSK_STARTING_KOKIRI_SWORD))
Item_Give(NULL, ITEM_SWORD_KOKIRI);
if (Randomizer_GetSettingValue(RSK_STARTING_DEKU_SHIELD))
Item_Give(NULL, ITEM_SHIELD_DEKU);
// Songs
if (Randomizer_GetSettingValue(RSK_STARTING_ZELDAS_LULLABY))
Item_Give(NULL, ITEM_SONG_LULLABY);
if (Randomizer_GetSettingValue(RSK_STARTING_EPONAS_SONG))
Item_Give(NULL, ITEM_SONG_EPONA);
if (Randomizer_GetSettingValue(RSK_STARTING_SARIAS_SONG))
Item_Give(NULL, ITEM_SONG_SARIA);
if (Randomizer_GetSettingValue(RSK_STARTING_SUNS_SONG))
Item_Give(NULL, ITEM_SONG_SUN);
if (Randomizer_GetSettingValue(RSK_STARTING_SONG_OF_TIME))
Item_Give(NULL, ITEM_SONG_TIME);
if (Randomizer_GetSettingValue(RSK_STARTING_SONG_OF_STORMS))
Item_Give(NULL, ITEM_SONG_STORMS);
if (Randomizer_GetSettingValue(RSK_STARTING_MINUET_OF_FOREST))
Item_Give(NULL, ITEM_SONG_MINUET);
if (Randomizer_GetSettingValue(RSK_STARTING_BOLERO_OF_FIRE))
Item_Give(NULL, ITEM_SONG_BOLERO);
if (Randomizer_GetSettingValue(RSK_STARTING_SERENADE_OF_WATER))
Item_Give(NULL, ITEM_SONG_SERENADE);
if (Randomizer_GetSettingValue(RSK_STARTING_REQUIEM_OF_SPIRIT))
Item_Give(NULL, ITEM_SONG_REQUIEM);
if (Randomizer_GetSettingValue(RSK_STARTING_NOCTURNE_OF_SHADOW))
Item_Give(NULL, ITEM_SONG_NOCTURNE);
if (Randomizer_GetSettingValue(RSK_STARTING_PRELUDE_OF_LIGHT))
Item_Give(NULL, ITEM_SONG_PRELUDE);
if (Randomizer_GetSettingValue(RSK_STARTING_SKULLTULA_TOKEN)) {
gSaveContext.inventory.questItems |= gBitFlags[QUEST_SKULL_TOKEN];
gSaveContext.inventory.gsTokens = Randomizer_GetSettingValue(RSK_STARTING_SKULLTULA_TOKEN);
}
if (Randomizer_GetSettingValue(RSK_STARTING_OCARINA)) {
INV_CONTENT(ITEM_OCARINA_FAIRY) = ITEM_OCARINA_FAIRY;
}
if (Randomizer_GetSettingValue(RSK_STARTING_CONSUMABLES)) {
GiveLinkDekuSticks(10);
GiveLinkDekuNuts(20);
}
if (Randomizer_GetSettingValue(RSK_FULL_WALLETS)) {
GiveLinkRupees(9001);
}
if (Randomizer_GetSettingValue(RSK_STARTING_MAPS_COMPASSES) == RO_DUNGEON_ITEM_LOC_STARTWITH) {
uint32_t mapBitMask = 1 << 1;
uint32_t compassBitMask = 1 << 2;
uint32_t startingDungeonItemsBitMask = mapBitMask | compassBitMask;
for (int scene = SCENE_DEKU_TREE; scene <= SCENE_ICE_CAVERN; scene++) {
gSaveContext.inventory.dungeonItems[scene] |= startingDungeonItemsBitMask;
}
}
if (Randomizer_GetSettingValue(RSK_KEYSANITY) == RO_DUNGEON_ITEM_LOC_STARTWITH) {
gSaveContext.inventory.dungeonKeys[SCENE_FOREST_TEMPLE] = FOREST_TEMPLE_SMALL_KEY_MAX; // Forest
gSaveContext.sohStats.dungeonKeys[SCENE_FOREST_TEMPLE] = FOREST_TEMPLE_SMALL_KEY_MAX; // Forest
gSaveContext.inventory.dungeonKeys[SCENE_FIRE_TEMPLE] = FIRE_TEMPLE_SMALL_KEY_MAX; // Fire
gSaveContext.sohStats.dungeonKeys[SCENE_FIRE_TEMPLE] = FIRE_TEMPLE_SMALL_KEY_MAX; // Fire
gSaveContext.inventory.dungeonKeys[SCENE_WATER_TEMPLE] = WATER_TEMPLE_SMALL_KEY_MAX; // Water
gSaveContext.sohStats.dungeonKeys[SCENE_WATER_TEMPLE] = WATER_TEMPLE_SMALL_KEY_MAX; // Water
gSaveContext.inventory.dungeonKeys[SCENE_SPIRIT_TEMPLE] = SPIRIT_TEMPLE_SMALL_KEY_MAX; // Spirit
gSaveContext.sohStats.dungeonKeys[SCENE_SPIRIT_TEMPLE] = SPIRIT_TEMPLE_SMALL_KEY_MAX; // Spirit
gSaveContext.inventory.dungeonKeys[SCENE_SHADOW_TEMPLE] = SHADOW_TEMPLE_SMALL_KEY_MAX; // Shadow
gSaveContext.sohStats.dungeonKeys[SCENE_SHADOW_TEMPLE] = SHADOW_TEMPLE_SMALL_KEY_MAX; // Shadow
gSaveContext.inventory.dungeonKeys[SCENE_BOTTOM_OF_THE_WELL] = BOTTOM_OF_THE_WELL_SMALL_KEY_MAX; // BotW
gSaveContext.sohStats.dungeonKeys[SCENE_BOTTOM_OF_THE_WELL] = BOTTOM_OF_THE_WELL_SMALL_KEY_MAX; // BotW
gSaveContext.inventory.dungeonKeys[SCENE_GERUDO_TRAINING_GROUND] = GERUDO_TRAINING_GROUNDS_SMALL_KEY_MAX; // GTG
gSaveContext.sohStats.dungeonKeys[SCENE_GERUDO_TRAINING_GROUND] = GERUDO_TRAINING_GROUNDS_SMALL_KEY_MAX; // GTG
gSaveContext.inventory.dungeonKeys[SCENE_INSIDE_GANONS_CASTLE] = GANONS_CASTLE_SMALL_KEY_MAX; // Ganon
gSaveContext.sohStats.dungeonKeys[SCENE_INSIDE_GANONS_CASTLE] = GANONS_CASTLE_SMALL_KEY_MAX; // Ganon
} else if (Randomizer_GetSettingValue(RSK_KEYSANITY) == RO_DUNGEON_ITEM_LOC_VANILLA) {
// Logic cannot handle vanilla key layout in some dungeons
// this is because vanilla expects the dungeon major item to be
// locked behind the keys, which is not always true in rando.
// We can resolve this by starting with some extra keys
if (ResourceMgr_IsSceneMasterQuest(SCENE_SPIRIT_TEMPLE)) {
// MQ Spirit needs 3 keys
gSaveContext.inventory.dungeonKeys[SCENE_SPIRIT_TEMPLE] = 3;
gSaveContext.sohStats.dungeonKeys[SCENE_SPIRIT_TEMPLE] = 3;
}
}
if (Randomizer_GetSettingValue(RSK_BOSS_KEYSANITY) == RO_DUNGEON_ITEM_LOC_STARTWITH) {
gSaveContext.inventory.dungeonItems[SCENE_FOREST_TEMPLE] |= 1; // Forest
gSaveContext.inventory.dungeonItems[SCENE_FIRE_TEMPLE] |= 1; // Fire
gSaveContext.inventory.dungeonItems[SCENE_WATER_TEMPLE] |= 1; // Water
gSaveContext.inventory.dungeonItems[SCENE_SPIRIT_TEMPLE] |= 1; // Spirit
gSaveContext.inventory.dungeonItems[SCENE_SHADOW_TEMPLE] |= 1; // Shadow
}
if (Randomizer_GetSettingValue(RSK_GANONS_BOSS_KEY) == RO_GANON_BOSS_KEY_STARTWITH) {
gSaveContext.inventory.dungeonItems[SCENE_GANONS_TOWER] |= 1;
}
}
extern "C" void Randomizer_InitSaveFile() {
// Sets all rando flags to false
for (s32 i = 0; i < ARRAY_COUNT(gSaveContext.randomizerInf); i++) {
gSaveContext.randomizerInf[i] = 0;
}
// Reset triforce pieces collected
gSaveContext.triforcePiecesCollected = 0;
gSaveContext.cutsceneIndex = 0; // no intro cutscene
// Starts pending ice traps out at 0 before potentially incrementing them down the line.
gSaveContext.pendingIceTrapCount = 0;
// Set Cutscene flags and texts to skip them
Flags_SetInfTable(INFTABLE_GREETED_BY_SARIA);
Flags_SetEventChkInf(EVENTCHKINF_FIRST_SPOKE_TO_MIDO);
Flags_SetEventChkInf(EVENTCHKINF_MET_DEKU_TREE);
Flags_SetEventChkInf(EVENTCHKINF_DEKU_TREE_OPENED_MOUTH);
Flags_SetInfTable(INFTABLE_SPOKE_TO_KAEPORA_IN_LAKE_HYLIA);
Flags_SetEventChkInf(EVENTCHKINF_ENTERED_MASTER_SWORD_CHAMBER);
Flags_SetEventChkInf(EVENTCHKINF_PULLED_MASTER_SWORD_FROM_PEDESTAL);
Flags_SetEventChkInf(EVENTCHKINF_SHEIK_SPAWNED_AT_MASTER_SWORD_PEDESTAL);
Flags_SetEventChkInf(EVENTCHKINF_RETURNED_TO_TEMPLE_OF_TIME_WITH_ALL_MEDALLIONS);
Flags_SetEventChkInf(EVENTCHKINF_RENTED_HORSE_FROM_INGO);
Flags_SetInfTable(INFTABLE_SPOKE_TO_POE_COLLECTOR_IN_RUINED_MARKET);
Flags_SetEventChkInf(EVENTCHKINF_WATCHED_GANONS_CASTLE_COLLAPSE_CAUGHT_BY_GERUDO);
Flags_SetEventChkInf(EVENTCHKINF_SPOKE_TO_NABOORU_IN_SPIRIT_TEMPLE);
Flags_SetInfTable(INFTABLE_MET_CHILD_MALON_AT_CASTLE_OR_MARKET);
Flags_SetEventChkInf(EVENTCHKINF_SPOKE_TO_CHILD_MALON_AT_CASTLE_OR_MARKET);
Flags_SetEventChkInf(EVENTCHKINF_SPOKE_TO_INGO_AT_RANCH_BEFORE_TALON_RETURNS);
Flags_SetEventChkInf(EVENTCHKINF_SPOKE_TO_CHILD_MALON_AT_RANCH);
Flags_SetEventChkInf(EVENTCHKINF_INVITED_TO_SING_WITH_CHILD_MALON);
Flags_SetInfTable(INFTABLE_CHILD_MALON_SAID_EPONA_WAS_AFRAID_OF_YOU);
Flags_SetInfTable(INFTABLE_SPOKE_TO_INGO_ONCE_AS_ADULT);
// Ruto already met in jabu and spawns down the hole immediately
Flags_SetInfTable(INFTABLE_RUTO_IN_JJ_MEET_RUTO);
Flags_SetInfTable(INFTABLE_RUTO_IN_JJ_TALK_FIRST_TIME);
Flags_SetInfTable(INFTABLE_RUTO_IN_JJ_WANTS_TO_BE_TOSSED_TO_SAPPHIRE);
// Skip cutscenes before Nabooru fight
Flags_SetEventChkInf(EVENTCHKINF_BEGAN_NABOORU_BATTLE);
Flags_SetEventChkInf(EVENTCHKINF_NABOORU_ORDERED_TO_FIGHT_BY_TWINROVA);
// Skip boss cutscenes
Flags_SetEventChkInf(EVENTCHKINF_BEGAN_GOHMA_BATTLE);
Flags_SetEventChkInf(EVENTCHKINF_BEGAN_KING_DODONGO_BATTLE);
Flags_SetEventChkInf(EVENTCHKINF_BEGAN_PHANTOM_GANON_BATTLE);
Flags_SetEventChkInf(EVENTCHKINF_BEGAN_VOLVAGIA_BATTLE);
Flags_SetEventChkInf(EVENTCHKINF_BEGAN_MORPHA_BATTLE);
Flags_SetEventChkInf(EVENTCHKINF_BEGAN_TWINROVA_BATTLE);
Flags_SetEventChkInf(EVENTCHKINF_BEGAN_BARINA_BATTLE);
Flags_SetEventChkInf(EVENTCHKINF_BEGAN_BONGO_BONGO_BATTLE);
// Entered areas
Flags_SetEventChkInf(EVENTCHKINF_ENTERED_HYRULE_FIELD);
Flags_SetEventChkInf(EVENTCHKINF_ENTERED_DEATH_MOUNTAIN_TRAIL);
Flags_SetEventChkInf(EVENTCHKINF_ENTERED_KAKARIKO_VILLAGE);
Flags_SetEventChkInf(EVENTCHKINF_ENTERED_ZORAS_DOMAIN);
Flags_SetEventChkInf(EVENTCHKINF_ENTERED_HYRULE_CASTLE);
Flags_SetEventChkInf(EVENTCHKINF_ENTERED_GORON_CITY);
Flags_SetEventChkInf(EVENTCHKINF_ENTERED_TEMPLE_OF_TIME);
Flags_SetEventChkInf(EVENTCHKINF_ENTERED_DEKU_TREE);
Flags_SetEventChkInf(EVENTCHKINF_ENTERED_DODONGOS_CAVERN);
Flags_SetEventChkInf(EVENTCHKINF_ENTERED_LAKE_HYLIA);
Flags_SetEventChkInf(EVENTCHKINF_ENTERED_GERUDO_VALLEY);
Flags_SetEventChkInf(EVENTCHKINF_ENTERED_GERUDOS_FORTRESS);
Flags_SetEventChkInf(EVENTCHKINF_ENTERED_LON_LON_RANCH);
Flags_SetEventChkInf(EVENTCHKINF_ENTERED_JABU_JABUS_BELLY);
Flags_SetEventChkInf(EVENTCHKINF_ENTERED_GRAVEYARD);
Flags_SetEventChkInf(EVENTCHKINF_ENTERED_ZORAS_FOUNTAIN);
Flags_SetEventChkInf(EVENTCHKINF_ENTERED_DESERT_COLOSSUS);
Flags_SetEventChkInf(EVENTCHKINF_ENTERED_DEATH_MOUNTAIN_CRATER);
Flags_SetEventChkInf(EVENTCHKINF_ENTERED_GANONS_CASTLE_EXTERIOR);
Flags_SetInfTable(INFTABLE_ENTERED_HYRULE_CASTLE);
// skip the z target talk instructions by the kokiri shop
gSaveContext.sceneFlags[SCENE_KOKIRI_FOREST].swch |= (1 << 0x1F);
// Go away ruto (water temple first cutscene)
gSaveContext.sceneFlags[SCENE_WATER_TEMPLE].swch |= (1 << 0x10);
// no more kaepora
gSaveContext.sceneFlags[SCENE_HYRULE_FIELD].swch |= (1 << 0xC); // hyrule field kaepora outside kokiri forest
gSaveContext.sceneFlags[SCENE_HYRULE_FIELD].swch |= (1 << 0xB); // hyrule field kaepora outside lake hylia
gSaveContext.sceneFlags[SCENE_LOST_WOODS].swch |= (1 << 0x7); // lost woods kaepora pre-saria
gSaveContext.sceneFlags[SCENE_LOST_WOODS].swch |= (1 << 0x8); // lost woods kaepora post-saria
gSaveContext.sceneFlags[SCENE_DESERT_COLOSSUS].swch |= (1 << 0x1F); // desert colossus kaepora
gSaveContext.sceneFlags[SCENE_HYRULE_CASTLE].swch |= (1 << 0x5); // hyrule castle kaepora
if (!Randomizer_GetSettingValue(RSK_ENABLE_GLITCH_CUTSCENES)) {
Flags_SetInfTable(INFTABLE_SPOKE_TO_DARUNIA_IN_FIRE_TEMPLE); // Darunia in Fire Temple
}
// Give Link's pocket item
GiveLinksPocketItem();
// shuffle adult trade quest
if (Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE)) {
gSaveContext.adultTradeItems = 0;
}
int startingAge = Randomizer_GetSettingValue(RSK_STARTING_AGE);
switch (startingAge) {
case RO_AGE_ADULT: // Adult
gSaveContext.linkAge = LINK_AGE_ADULT;
gSaveContext.entranceIndex = 0x5F4;
gSaveContext.savedSceneNum = SCENE_LON_LON_RANCH; // Set scene num manually to ToT
break;
case RO_AGE_CHILD: // Child
gSaveContext.linkAge = LINK_AGE_CHILD;
gSaveContext.savedSceneNum = -1;
break;
default:
break;
}
if (Randomizer_GetSettingValue(RSK_SHUFFLE_OVERWORLD_SPAWNS)) {
// Override the spawn entrance so entrance rando can take control,
// and to prevent remember save location from breaking inital spawn
gSaveContext.entranceIndex = -1;
}
// If any trials aren't required, set them as completed
for (u16 i = RAND_INF_TRIALS_DONE_LIGHT_TRIAL; i <= RAND_INF_TRIALS_DONE_SHADOW_TRIAL; i++) {
if (!OTRGlobals::Instance->gRandomizer->IsTrialRequired((RandomizerInf)i)) {
Flags_SetRandomizerInf((RandomizerInf)i);
}
}
if (Randomizer_GetSettingValue(RSK_SKIP_CHILD_ZELDA)) {
GetItemEntry getItemEntry = Randomizer_GetItemFromKnownCheck(RC_SONG_FROM_IMPA, (GetItemID)RG_ZELDAS_LULLABY);
StartingItemGive(getItemEntry);
// malon/talon back at ranch
Flags_SetEventChkInf(EVENTCHKINF_OBTAINED_POCKET_EGG);
Flags_SetEventChkInf(EVENTCHKINF_TALON_WOKEN_IN_CASTLE);
Flags_SetEventChkInf(EVENTCHKINF_TALON_RETURNED_FROM_CASTLE);
// Set "Got Zelda's Letter" flag. Also ensures Saria is back at SFM.
Flags_SetEventChkInf(EVENTCHKINF_OBTAINED_ZELDAS_LETTER);
// Got item from impa
Flags_SetEventChkInf(EVENTCHKINF_LEARNED_ZELDAS_LULLABY);
gSaveContext.sceneFlags[SCENE_HYRULE_CASTLE].swch |= (1 << 0x4); // move milk crates in hyrule castle to moat
// set this at the end to ensure we always start with the letter
// this is for the off chance we got the weird egg from impa (which should never happen)
INV_CONTENT(ITEM_LETTER_ZELDA) = ITEM_LETTER_ZELDA;
}
if (Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) && startingAge == RO_AGE_ADULT) {
GetItemEntry getItemEntry = Randomizer_GetItemFromKnownCheck(RC_TOT_MASTER_SWORD, GI_NONE);
StartingItemGive(getItemEntry);
Flags_SetRandomizerInf(RAND_INF_TOT_MASTER_SWORD);
}
HIGH_SCORE(HS_POE_POINTS) = 1000 - (100 * Randomizer_GetSettingValue(RSK_BIG_POE_COUNT));
if (Randomizer_GetSettingValue(RSK_SKIP_EPONA_RACE)) {
Flags_SetEventChkInf(EVENTCHKINF_EPONA_OBTAINED);
}
// Open lowest Vanilla Fire Temple locked door (to prevent key logic lockouts)
// Not done on keysanity since this lockout is a non issue when Fire keys can be found outside the temple
u8 keysanity = Randomizer_GetSettingValue(RSK_KEYSANITY) == RO_DUNGEON_ITEM_LOC_ANYWHERE ||
Randomizer_GetSettingValue(RSK_KEYSANITY) == RO_DUNGEON_ITEM_LOC_OVERWORLD ||
Randomizer_GetSettingValue(RSK_KEYSANITY) == RO_DUNGEON_ITEM_LOC_ANY_DUNGEON;
if (!ResourceMgr_IsSceneMasterQuest(SCENE_FIRE_TEMPLE) && !keysanity) {
gSaveContext.sceneFlags[SCENE_FIRE_TEMPLE].swch |= (1 << 0x17);
}
// Opens locked Water Temple door in vanilla to prevent softlocks
// West door on the middle level that leads to the water raising thing
// Happens in 3DS rando and N64 rando as well
if (!ResourceMgr_IsSceneMasterQuest(SCENE_WATER_TEMPLE)) {
gSaveContext.sceneFlags[SCENE_WATER_TEMPLE].swch |= (1 << 0x15);
}
int openForest = Randomizer_GetSettingValue(RSK_FOREST);
switch (openForest) {
case RO_FOREST_OPEN:
Flags_SetEventChkInf(EVENTCHKINF_SHOWED_MIDO_SWORD_SHIELD);
// Fallthrough
case RO_FOREST_CLOSED_DEKU:
Flags_SetEventChkInf(EVENTCHKINF_OBTAINED_KOKIRI_EMERALD_DEKU_TREE_DEAD);
break;
}
int doorOfTime = Randomizer_GetSettingValue(RSK_DOOR_OF_TIME);
switch (doorOfTime) {
case RO_DOOROFTIME_OPEN:
Flags_SetEventChkInf(EVENTCHKINF_OPENED_THE_DOOR_OF_TIME);
break;
}
if (Randomizer_GetSettingValue(RSK_KAK_GATE) == RO_KAK_GATE_OPEN) {
Flags_SetInfTable(INFTABLE_SHOWED_ZELDAS_LETTER_TO_GATE_GUARD);
}
if (Randomizer_GetSettingValue(RSK_GERUDO_FORTRESS) == RO_GF_FAST ||
Randomizer_GetSettingValue(RSK_GERUDO_FORTRESS) == RO_GF_OPEN) {
Flags_SetEventChkInf(EVENTCHKINF_CARPENTERS_FREE(1));
Flags_SetEventChkInf(EVENTCHKINF_CARPENTERS_FREE(2));
Flags_SetEventChkInf(EVENTCHKINF_CARPENTERS_FREE(3));
gSaveContext.sceneFlags[SCENE_THIEVES_HIDEOUT].swch |= (1 << 0x02); // heard yells and unlocked doors
gSaveContext.sceneFlags[SCENE_THIEVES_HIDEOUT].swch |= (1 << 0x03);
gSaveContext.sceneFlags[SCENE_THIEVES_HIDEOUT].swch |= (1 << 0x04);
gSaveContext.sceneFlags[SCENE_THIEVES_HIDEOUT].swch |= (1 << 0x06);
gSaveContext.sceneFlags[SCENE_THIEVES_HIDEOUT].swch |= (1 << 0x07);
gSaveContext.sceneFlags[SCENE_THIEVES_HIDEOUT].swch |= (1 << 0x08);
gSaveContext.sceneFlags[SCENE_THIEVES_HIDEOUT].swch |= (1 << 0x10);
gSaveContext.sceneFlags[SCENE_THIEVES_HIDEOUT].swch |= (1 << 0x12);
gSaveContext.sceneFlags[SCENE_THIEVES_HIDEOUT].swch |= (1 << 0x13);
gSaveContext.sceneFlags[SCENE_THIEVES_HIDEOUT].collect |= (1 << 0x0A); // picked up keys
gSaveContext.sceneFlags[SCENE_THIEVES_HIDEOUT].collect |= (1 << 0x0E);
gSaveContext.sceneFlags[SCENE_THIEVES_HIDEOUT].collect |= (1 << 0x0F);
}
if (Randomizer_GetSettingValue(RSK_GERUDO_FORTRESS) == RO_GF_OPEN) {
Flags_SetEventChkInf(EVENTCHKINF_CARPENTERS_FREE(0));
gSaveContext.sceneFlags[SCENE_THIEVES_HIDEOUT].swch |= (1 << 0x01); // heard yell and unlocked door
gSaveContext.sceneFlags[SCENE_THIEVES_HIDEOUT].swch |= (1 << 0x05);
gSaveContext.sceneFlags[SCENE_THIEVES_HIDEOUT].swch |= (1 << 0x11);
gSaveContext.sceneFlags[SCENE_THIEVES_HIDEOUT].collect |= (1 << 0x0C); // picked up key
if (!Randomizer_GetSettingValue(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD)) {
Item_Give(NULL, ITEM_GERUDO_CARD);
}
}
// complete mask quest
if (Randomizer_GetSettingValue(RSK_COMPLETE_MASK_QUEST)) {
Flags_SetInfTable(INFTABLE_GATE_GUARD_PUT_ON_KEATON_MASK);
Flags_SetEventChkInf(EVENTCHKINF_PAID_BACK_BUNNY_HOOD_FEE);
gSaveContext.itemGetInf[3] |= 0x100; // Sold Keaton Mask
gSaveContext.itemGetInf[3] |= 0x200; // Sold Skull Mask
gSaveContext.itemGetInf[3] |= 0x400; // Sold Spooky Mask
gSaveContext.itemGetInf[3] |= 0x800; // bunny hood related
gSaveContext.itemGetInf[3] |= 0x8000; // Obtained Mask of Truth
}
SetStartingItems();
}