More gap-bridging (#3323)

* Initial StaticData and RandoItem class definitions

* Initial implementation of RandoItem class.

* Rerranges RandoItem Constructor parameters

The parameters were rearranged for easy copy-paste from the GET_ITEM macro calls later on.

* Switches static data from map to static array.

Array is all that is needed, since the item list will be contiguous and indexed by the RandomizerGet Enum values.

* Defines part of the randomizer item list.

* Adds more item class instances to item_list.cpp

Up through bottles, many more items still to go.

* Adds song items

* Adds Maps and Compasses to the item_list

* Added Key Items to item_list

* Added Key Rings to item_list

* Added Dungeon Rewards to item_list

* Adds generic items and refills to item_list

* Adds shop items, triforce, and hints

Also added constructors that put the GET_ITEM_NONE data in for these items, since there is no corresponding GetItemEntry for them.

* Adds in the stages of progressive items

These are present for GetItemEntry purposes, and aren't really meant to be used in seed generation (unless we find a need for it later on.)

* Remove GetItemEntry data from progressive items

* Moves/adds function definitions to item/item_list

* Refactors GetItemEntry data

It's now a pointer to memory instantiated on the heap in the constructor. These are shared pointers so the memory is freed if any of the item instances get deconstructed (which they shouldn't but just in case.)

* Adds item class member for if item is progressive

* Removes unneeded stuff from initializer list macro

* Replaces relevant `uint32_t`s w/ `RandomizerGet`s

Also replaces calls to the ItemTable method with StaticData::RetrieveItem

* Switches our runtime code to use the new itemList.

* Changes just enough hint gen code to compile

* Initial Definition of Location Class

* Initial Implementation of Location

* Fixes some names and definitions.

* Extracts ActorID and SceneID enums to separate files.

This allows importing them without causing weird conflicts in cpp files when importing the z64scene.h and z64actor.h files directly. Now you can just import z64scene_enum.h and z64actor_enum.h instead. The two old files also import these new files so that existing setups still work as expected.

* Replaces the forward definitions with the new imports.

* Adds missing data for RandomizerCheckObjects.

* Definition and first entry of locationTable

* Added Mido's House Locations

* Added locations up through lost woods.

* Adds in Hyrule Field locations.

* Adds Lake Hylia locations

* Adds location name comments

* Adds Gerudo Valley Locations

* Adds Gerudo Fortress locations.

* Adds the Wasteland and Collosus locations

* Adds Market locations

* Adds Hyrule Castle locations.

* Adds Kakariko and Graveyard locations.

* Adds Death Mountain checks.

* Adds Goron City locations

* Adds Death Mountain Crater locations

* Adds Zora's River locations

* Added Zora's Domain Locations.

* Added Zora's Fountain locations

* Adds Lon Lon Ranch locations.

* Adds Deku Tree locations

* Adds Dodongo's Cavern Locations.

* Adds Jabu Jabu's Belly Locations

* Adds Forest Temple Locations

* Adds Fire Temple Locations

* Adds Water Temple Locations

* Added Spirit Temple Locations

* Some of shadow temple locations.

* Adds remaining Shadow Temple locations

* Fixes a leftover merge conflict

* Adds Bottom of the Well locations.

* Adds Ice Cavern locations

* Adds GTG locations.

* Adds Ganon's Castle and Tower locations

* Adds dungeon Gold Skulltula locations.

* Adds Overworld Gold Skulltula locations

* Adds dungeon reward locations

* Adds Heart Container Locations

* Adds Cutscene and Song locations

* Adds Cow locations

* Adds Shop locations.

* Adds hint locations

* Adds function for retrieving the Location data.

* Initial definition of ItemLocation structure for tracking runtime data

* First push on converting code to use new location definitions

* Changes hints to use the new tables

* Further conversion of hints to new definitions.

* Adds new Hint and Location IDs to area tables

* Moves areaTable to use new RandomizerRegion keys

* Removal of 3drando/item_location files.

* Uses new RandomizerRegion keys in entrance.cpp

* Final push for removal of massive keys.hpp enum

* Uses new SceneID Enum Values

* Remove RandomizerCheckObject structs in favor of new location list.

* Fix a few stragglers to successfully build

* Rename of RandoItem to just Item, but in the Rando namespace

* Adds static hints (Light Arrows, Altar text, etc) to the new Hint table.

* More hint related fixes/edits

* small fix for #include path

* Fix various miscellaneous issues related to seed gen and spoiler parsing.

* Handle progressive items correctly.

* Fixes some hint generation logic

* Fix a few GetItemEntry niche bugs.

* Adds missing shop GI Entries

* Formatting fixes

* small formatting fix

* Namespace StaticData under Rando

* Added a note about a potential use-after-free.

I confirmed the actual pointer in question isn't currently being used, but I added the note as a reminder to fix it later and/or as a warning to anyone who changes how the return value is used.

* Fixes missing location table entries

* Fixes LUS submodule and removes now-unused code

* Resolves weird duplicate definition issue

* Fix missing include

It was missed because not being included wasn't an issue on Windows.

* Fixes error present on Linux builds

* Fixes some issues with excluding locations

* Updates the Resolve Exclusion conflicts function

not sure if actually used, will look into that more later

* Removes some duplicate RGs

* More fixes of duplicate RG values.

* Fix a few duplication issues in the check tracker.

* Fix progressive bombchus.

* Minor typo fix, shouldn't really be affecting anything though

* Should fix some of the remaining check tracker issues.

* oops wrong boolean operator

* Fix skulltulas in the check tracker.

* oops, missing comma

* re-formatting of HintStone locations

* Fixes issue when picking up second Progressive Bullet Bag

* Hide bombchu bowling bombchus

* Fixes missed skullScene in location_list

* Reformats shop items

* Re-formats cow checks

* reformat song locations

* reformat "cutscene" checks

* reformat heart container locaitons

* reformat Boss/Dungeon reward checks

* Hide Triforce Completed if not playing Triforce Hunt

* Fixes incorrect chest param

* reformat GS Tokens locations and cuts down on duplicate data

* reformat Ganons Castle checks

* reformat GTG check locations

* Prevents Gift from Raoru from appearing in the check tracker

* more reformatting (botw, ice cavern, shadow temple)

* Should fix a couple more check tracker checks

* reformat spirit temple checks

* reformat water and fire temple checks

* fix RC_ZR_GS_ABOVE_BRIDGE flag typo

* reformat Forest Temple checks

* Fix RC_LW_TRADE_ODD_POTION in check tracker

* reformat child dungeon locations

* reformat overworld locations

* reformat item entries

* New Item Override system

* use new ItemOverrides and use ItemLocations table for getting items

* Saves/Loads directly from/to new ItemLocation table with overrides for traps

* Removes gSaveContext.itemLocations

* Don't load spoiler file on boot automatically.

Currently this means the old spoiler will have to be manually dropped or a new one generated in order to make a new rando file. Next I want to make it so that:
1. The Randomizer Quest button on the file select menu is always unlocked, even if a spoiler is not loaded.
2. If it's selected and a spoiler is not loaded, a menu will appear that asks if you want to generate a new seed or re-generate the previous one (if a spoiler file is present).
3. On choosing to generate a new one, you may also get an in-game menu to quickly apply a preset before generating (not sure if I'm going that far just yet).
4. After that, a seed is generated and you are taken back to the file select screen with the new file present.
5. If a seed is generated via the menu ahead of time, the CVar for loading the spoiler file will be set, but the spoiler file will not be parsed. All the data needed to actually play the randomizer at that point is
already in memory and in the save file (or at least I'll make it so that it is if it isn't already).
6. If a spoiler file is dropped over the window, the spoiler file is loaded, but it will only be parsed to get the seed and the settings, then the playthrough will be generated from scratch with that data. Thus allowing
for hints to be in the user's language of choice no matter what language the spoiler file was generated in.
7. Additionally, there will be a plandomizer mode that, if enabled, causes dragging and dropping a spoiler file to read the entire spoiler file instead of just the seed, and making a new file will use the data from there
instead of generating a new seed. This in particular may be expanded to have a "plando file" that contains more info than a spoiler file would normally have, such as cosmetic data and a more fleshed out
custom message syntax for various types of custom hints and whatnot. But that will be probably much later.

* Auto-gen rando seed when making a new rando file.

Also adds new logic for displaying the seed hash icons. Now, it is displayed in the following situations:
1. On the confirmation page when loading a rando save, the hash icons for *that save* are displayed.
2. On the name select screen after generating a seed, the hash icons for the seed that was just generated will be shown.
3. If you have dragged a spoiler log onto the window, the hash icons for that seed will be displayed while randomizer is selected on the quest select screen.
Currently the spoiler is just ignored, as the logic for pulling the settings from the spoiler file and regenerating the same seed has not been coded yet.

* Fix a few typos/bugs

* Partial conversion to new Settings/Option class

* Further conversion to new settings/options classes

* New settings struct (not fully working, need to wire it up to SaveManager)

* Move save files to new settings struct. Also fixes MQ options to match 3drando

* Fixes some spoilerfile related issues

* Cleans up now unused arrays

* Fixes some unhandled entries in parse settings switch case

* Reimplements parsing of settings on file drop to re-generate seeds

* Move merchantPrices into ItemLocation tables.

* Move hints to new struct

* Fixes a few seed gen bugs surrounding hints

* Fix treasure chest game.

* Relocate Entrance Shuffle code into ctx

* Move entrances to new context at runtime

* Remove now unused code from SaveContext and randomizer.cpp/.h

* Fix non-windows builds?

* Moves Dungeon Quests to new context

* Move trials into new context

* Whoops, forgot to construct the Trials in the context.

* Fixes accidental nullptr reference

* Fixes bug with saving MQ dungeons

* Implements plando mode and removes now unused code.

Largely untested, expect some bugfixes.

* prevent a multiple definition bug

* another attempt to fix the gSeedTextures multiple def error

* Fixes some minor hint issues from conflict resolution

* Some additional glue needed for merge

* Fixes another couple of miscellaneous issues/inconsistencies.

* A few french corrections

* Makes CVar gRandomizeWarpSongText match the checkbox default value.
This commit is contained in:
Christopher Leggett
2023-11-13 13:25:37 -05:00
committed by GitHub
parent 20bb36c164
commit 2698d453bb
85 changed files with 7692 additions and 9551 deletions

View File

@@ -147,11 +147,6 @@ typedef struct {
/* 0x24 */ s32 tempCollectFlags;
} FaroresWindData; // size = 0x28
typedef struct {
RandomizerCheck check;
RandomizerGetData get;
} ItemLocationRando;
typedef struct {
RandomizerCheck check;
RandomizerCheck hintedCheck;
@@ -161,11 +156,6 @@ typedef struct {
char hintText[200];
} HintLocationRando;
typedef struct {
RandomizerSettingKey key;
u8 value;
} RandoSetting;
typedef struct {
/* 0x0000 */ s32 entranceIndex; // start of `save` substruct, originally called "memory"
/* 0x0004 */ s32 linkAge; // 0: Adult; 1: Child (see enum `LinkAge`)
@@ -286,7 +276,6 @@ typedef struct {
/* */ uint8_t questId;
/* */ uint32_t isBossRushPaused;
/* */ uint8_t bossRushOptions[BOSSRUSH_OPTIONS_AMOUNT];
/* */ u8 mqDungeonCount;
/* */ u8 pendingIceTrapCount;
/* */ SohStats sohStats;
/* */ FaroresWindData backupFW;
@@ -294,33 +283,6 @@ typedef struct {
// #endregion
// #region SOH [Randomizer]
// Upstream TODO: Move these to their own struct or name to more obviously specific to Randomizer
/* */ RandoSetting randoSettings[300];
/* */ ItemLocationRando itemLocations[RC_MAX];
/* */ HintLocationRando hintLocations[50];
/* */ EntranceOverride entranceOverrides[ENTRANCE_OVERRIDES_MAX_COUNT];
/* */ char childAltarText[250];
/* */ char adultAltarText[750];
/* */ RandomizerCheck rewardCheck[9];
/* */ char ganonHintText[300];
/* */ char gregHintText[250];
/* */ char ganonText[250];
/* */ char dampeText[150];
/* */ char sheikText[200];
/* */ char sariaText[150];
/* */ char warpMinuetText[100];
/* */ char warpBoleroText[100];
/* */ char warpSerenadeText[100];
/* */ char warpRequiemText[100];
/* */ char warpNocturneText[100];
/* */ char warpPreludeText[100];
/* */ RandomizerCheck masterSwordHintCheck;
/* */ RandomizerCheck lightArrowHintCheck;
/* */ RandomizerCheck sariaCheck;
/* */ RandomizerCheck gregCheck;
/* */ RandomizerCheck dampeCheck;
/* */ char inputSeed[1024];
/* */ u32 finalSeed;
/* */ u8 seedIcons[5];
/* */ u16 randomizerInf[10];
/* */ u16 adultTradeItems;
/* */ u8 triforcePiecesCollected;

View File

@@ -2,6 +2,7 @@
#include "functions.h"
#include "macros.h"
#include "soh/Enhancements/randomizer/3drando/random.hpp"
#include "soh/Enhancements/randomizer/context.h"
#include "soh/Enhancements/enhancementTypes.h"
#include "variables.h"
@@ -234,7 +235,7 @@ extern "C" uint8_t GetRandomizedEnemy(PlayState* play, int16_t *actorId, f32 *po
EnemyEntry GetRandomizedEnemyEntry(uint32_t seed) {
if (CVarGetInteger("gRandomizedEnemies", ENEMY_RANDOMIZER_OFF) == ENEMY_RANDOMIZER_RANDOM_SEEDED) {
uint32_t finalSeed = seed + (IS_RANDO ? gSaveContext.finalSeed : gSaveContext.sohStats.fileCreatedAt);
uint32_t finalSeed = seed + (IS_RANDO ? Rando::Context::GetInstance()->GetSettings()->GetSeed() : gSaveContext.sohStats.fileCreatedAt);
Random_Init(finalSeed);
}

View File

@@ -604,7 +604,8 @@ void UpdateMirrorModeState(int32_t sceneNum) {
(sceneNum == SCENE_GANON_BOSS);
if (mirroredMode == MIRRORED_WORLD_RANDOM_SEEDED || mirroredMode == MIRRORED_WORLD_DUNGEONS_RANDOM_SEEDED) {
uint32_t seed = sceneNum + (IS_RANDO ? gSaveContext.finalSeed : gSaveContext.sohStats.fileCreatedAt);
uint32_t seed = sceneNum + (IS_RANDO ? Rando::Context::GetInstance()->GetSettings()->GetSeed()
: gSaveContext.sohStats.fileCreatedAt);
Random_Init(seed);
}

View File

@@ -1,682 +0,0 @@
#include "dungeon.hpp"
#include "category.hpp"
#include "pool_functions.hpp"
#include "../context.h"
#include "../static_data.h"
namespace Dungeon {
DungeonInfo::DungeonInfo(std::string name_, RandomizerHintTextKey hintKey_, RandomizerGet map_, RandomizerGet compass_,
RandomizerGet smallKey_, RandomizerGet keyRing_, RandomizerGet bossKey_,
uint8_t vanillaKeyCount_, uint8_t mqKeyCount_, std::vector<RandomizerCheck> vanillaLocations_,
std::vector<RandomizerCheck> mqLocations_, std::vector<RandomizerCheck> sharedLocations_,
std::vector<RandomizerCheck> bossRoomLocations_)
: name(std::move(name_)), hintKey(hintKey_), map(map_), compass(compass_), smallKey(smallKey_), keyRing(keyRing_),
bossKey(bossKey_), vanillaKeyCount(vanillaKeyCount_), mqKeyCount(mqKeyCount_),
vanillaLocations(std::move(vanillaLocations_)), mqLocations(std::move(mqLocations_)),
sharedLocations(std::move(sharedLocations_)), bossRoomLocations(std::move(bossRoomLocations_)) {
}
DungeonInfo::~DungeonInfo() = default;
RandomizerHintTextKey DungeonInfo::GetHintKey() const {
return hintKey;
}
RandomizerGet DungeonInfo::GetSmallKey() const {
return smallKey;
}
RandomizerGet DungeonInfo::GetKeyRing() const {
return keyRing;
}
RandomizerGet DungeonInfo::GetMap() const {
return map;
}
RandomizerGet DungeonInfo::GetCompass() const {
return compass;
}
RandomizerGet DungeonInfo::GetBossKey() const {
return bossKey;
}
void DungeonInfo::PlaceVanillaMap() {
if (map == RG_NONE) {
return;
}
auto dungeonLocations = GetDungeonLocations();
auto mapLocation = FilterFromPool(dungeonLocations, [](const RandomizerCheck loc) {
return Rando::StaticData::GetLocation(loc)->IsCategory(Category::cVanillaMap);
})[0];
Rando::Context::GetInstance()->PlaceItemInLocation(mapLocation, map);
}
void DungeonInfo::PlaceVanillaCompass() {
if (compass == RG_NONE) {
return;
}
auto dungeonLocations = GetDungeonLocations();
auto compassLocation = FilterFromPool(dungeonLocations, [](const RandomizerCheck loc) {
return Rando::StaticData::GetLocation(loc)->IsCategory(Category::cVanillaCompass);
})[0];
Rando::Context::GetInstance()->PlaceItemInLocation(compassLocation, compass);
}
void DungeonInfo::PlaceVanillaBossKey() {
if (bossKey == RG_NONE || bossKey == RG_GANONS_CASTLE_BOSS_KEY) {
return;
}
auto dungeonLocations = GetDungeonLocations();
auto bossKeyLocation = FilterFromPool(dungeonLocations, [](const RandomizerCheck loc) {
return Rando::StaticData::GetLocation(loc)->IsCategory(Category::cVanillaBossKey);
})[0];
Rando::Context::GetInstance()->PlaceItemInLocation(bossKeyLocation, bossKey);
}
void DungeonInfo::PlaceVanillaSmallKeys() {
if (smallKey == RG_NONE) {
return;
}
auto dungeonLocations = GetDungeonLocations();
auto smallKeyLocations = FilterFromPool(dungeonLocations, [](const RandomizerCheck loc) {
return Rando::StaticData::GetLocation(loc)->IsCategory(Category::cVanillaSmallKey);
});
for (auto location : smallKeyLocations) {
Rando::Context::GetInstance()->PlaceItemInLocation(location, smallKey);
}
}
// Gets the chosen dungeon locations for a playthrough (so either MQ or Vanilla)
std::vector<RandomizerCheck> DungeonInfo::GetDungeonLocations() const {
auto locations = masterQuest ? mqLocations : vanillaLocations;
AddElementsToPool(locations, sharedLocations);
AddElementsToPool(locations, bossRoomLocations);
return locations;
}
// Gets all dungeon locations (MQ + Vanilla)
std::vector<RandomizerCheck> DungeonInfo::GetEveryLocation() const {
auto locations = vanillaLocations;
AddElementsToPool(locations, mqLocations);
AddElementsToPool(locations, sharedLocations);
AddElementsToPool(locations, bossRoomLocations);
return locations;
}
DungeonInfo DekuTree =
DungeonInfo("Deku Tree", RHT_DEKU_TREE, RG_DEKU_TREE_MAP, RG_DEKU_TREE_COMPASS, RG_NONE, RG_NONE, RG_NONE, 0, 0,
{
// Vanilla Locations
RC_DEKU_TREE_MAP_CHEST,
RC_DEKU_TREE_COMPASS_CHEST,
RC_DEKU_TREE_COMPASS_ROOM_SIDE_CHEST,
RC_DEKU_TREE_BASEMENT_CHEST,
RC_DEKU_TREE_SLINGSHOT_CHEST,
RC_DEKU_TREE_SLINGSHOT_ROOM_SIDE_CHEST,
RC_DEKU_TREE_GS_BASEMENT_BACK_ROOM,
RC_DEKU_TREE_GS_BASEMENT_GATE,
RC_DEKU_TREE_GS_BASEMENT_VINES,
RC_DEKU_TREE_GS_COMPASS_ROOM,
},
{
// MQ Locations
RC_DEKU_TREE_MQ_MAP_CHEST,
RC_DEKU_TREE_MQ_COMPASS_CHEST,
RC_DEKU_TREE_MQ_SLINGSHOT_CHEST,
RC_DEKU_TREE_MQ_SLINGSHOT_ROOM_BACK_CHEST,
RC_DEKU_TREE_MQ_BASEMENT_CHEST,
RC_DEKU_TREE_MQ_BEFORE_SPINNING_LOG_CHEST,
RC_DEKU_TREE_MQ_AFTER_SPINNING_LOG_CHEST,
RC_DEKU_TREE_MQ_DEKU_SCRUB,
RC_DEKU_TREE_MQ_GS_LOBBY,
RC_DEKU_TREE_MQ_GS_COMPASS_ROOM,
RC_DEKU_TREE_MQ_GS_BASEMENT_GRAVES_ROOM,
RC_DEKU_TREE_MQ_GS_BASEMENT_BACK_ROOM,
},
{},
{
// Boss Room Locations
RC_DEKU_TREE_QUEEN_GOHMA_HEART,
RC_QUEEN_GOHMA,
});
DungeonInfo DodongosCavern = DungeonInfo("Dodongo's Cavern", RHT_DODONGOS_CAVERN, RG_DODONGOS_CAVERN_MAP,
RG_DODONGOS_CAVERN_COMPASS, RG_NONE, RG_NONE, RG_NONE, 0, 0,
{
// Vanilla Locations
RC_DODONGOS_CAVERN_MAP_CHEST,
RC_DODONGOS_CAVERN_COMPASS_CHEST,
RC_DODONGOS_CAVERN_BOMB_FLOWER_PLATFORM_CHEST,
RC_DODONGOS_CAVERN_BOMB_BAG_CHEST,
RC_DODONGOS_CAVERN_END_OF_BRIDGE_CHEST,
RC_DODONGOS_CAVERN_DEKU_SCRUB_LOBBY,
RC_DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS,
RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT,
RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT,
RC_DODONGOS_CAVERN_GS_VINES_ABOVE_STAIRS,
RC_DODONGOS_CAVERN_GS_SCARECROW,
RC_DODONGOS_CAVERN_GS_ALCOVE_ABOVE_STAIRS,
RC_DODONGOS_CAVERN_GS_BACK_ROOM,
RC_DODONGOS_CAVERN_GS_SIDE_ROOM_NEAR_LOWER_LIZALFOS,
},
{
// MQ Locations
RC_DODONGOS_CAVERN_MQ_MAP_CHEST,
RC_DODONGOS_CAVERN_MQ_BOMB_BAG_CHEST,
RC_DODONGOS_CAVERN_MQ_COMPASS_CHEST,
RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CHEST,
RC_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_ROOM_CHEST,
RC_DODONGOS_CAVERN_MQ_UNDER_GRAVE_CHEST,
RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR,
RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT,
RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE,
RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS,
RC_DODONGOS_CAVERN_MQ_GS_SCRUB_ROOM,
RC_DODONGOS_CAVERN_MQ_GS_SONG_OF_TIME_BLOCK_ROOM,
RC_DODONGOS_CAVERN_MQ_GS_LIZALFOS_ROOM,
RC_DODONGOS_CAVERN_MQ_GS_LARVAE_ROOM,
RC_DODONGOS_CAVERN_MQ_GS_BACK_AREA,
},
{},
{
// Boss Room Locations
RC_DODONGOS_CAVERN_BOSS_ROOM_CHEST,
RC_DODONGOS_CAVERN_KING_DODONGO_HEART,
RC_KING_DODONGO,
});
DungeonInfo JabuJabusBelly = DungeonInfo("Jabu Jabu's Belly", RHT_JABU_JABUS_BELLY, RG_JABU_JABUS_BELLY_MAP,
RG_JABU_JABUS_BELLY_COMPASS, RG_NONE, RG_NONE, RG_NONE, 0, 0,
{
// Vanilla Locations
RC_JABU_JABUS_BELLY_MAP_CHEST,
RC_JABU_JABUS_BELLY_COMPASS_CHEST,
RC_JABU_JABUS_BELLY_BOOMERANG_CHEST,
RC_JABU_JABUS_BELLY_DEKU_SCRUB,
RC_JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_LOWER,
RC_JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_UPPER,
RC_JABU_JABUS_BELLY_GS_NEAR_BOSS,
RC_JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM,
},
{
// MQ Locations
RC_JABU_JABUS_BELLY_MQ_FIRST_ROOM_SIDE_CHEST,
RC_JABU_JABUS_BELLY_MQ_MAP_CHEST,
RC_JABU_JABUS_BELLY_MQ_SECOND_ROOM_LOWER_CHEST,
RC_JABU_JABUS_BELLY_MQ_COMPASS_CHEST,
RC_JABU_JABUS_BELLY_MQ_SECOND_ROOM_UPPER_CHEST,
RC_JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_SWITCHES_CHEST,
RC_JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_VINES_CHEST,
RC_JABU_JABUS_BELLY_MQ_NEAR_BOSS_CHEST,
RC_JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_ROOM_CHEST,
RC_JABU_JABUS_BELLY_MQ_BOOMERANG_ROOM_SMALL_CHEST,
RC_JABU_JABUS_BELLY_MQ_BOOMERANG_CHEST,
RC_JABU_JABUS_BELLY_MQ_COW,
RC_JABU_JABUS_BELLY_MQ_GS_TAILPASARAN_ROOM,
RC_JABU_JABUS_BELLY_MQ_GS_INVISIBLE_ENEMIES_ROOM,
RC_JABU_JABUS_BELLY_MQ_GS_BOOMERANG_CHEST_ROOM,
RC_JABU_JABUS_BELLY_MQ_GS_NEAR_BOSS,
},
{},
{
// Boss Room Locations
RC_JABU_JABUS_BELLY_BARINADE_HEART,
RC_BARINADE,
});
DungeonInfo ForestTemple =
DungeonInfo("Forest Temple", RHT_FOREST_TEMPLE, RG_FOREST_TEMPLE_MAP, RG_FOREST_TEMPLE_COMPASS,
RG_FOREST_TEMPLE_SMALL_KEY, RG_FOREST_TEMPLE_KEY_RING, RG_FOREST_TEMPLE_BOSS_KEY, 5, 6,
{
// Vanilla Locations
RC_FOREST_TEMPLE_FIRST_ROOM_CHEST,
RC_FOREST_TEMPLE_FIRST_STALFOS_CHEST,
RC_FOREST_TEMPLE_RAISED_ISLAND_COURTYARD_CHEST,
RC_FOREST_TEMPLE_MAP_CHEST,
RC_FOREST_TEMPLE_WELL_CHEST,
RC_FOREST_TEMPLE_FALLING_CEILING_ROOM_CHEST,
RC_FOREST_TEMPLE_EYE_SWITCH_CHEST,
RC_FOREST_TEMPLE_BOSS_KEY_CHEST,
RC_FOREST_TEMPLE_FLOORMASTER_CHEST,
RC_FOREST_TEMPLE_BOW_CHEST,
RC_FOREST_TEMPLE_RED_POE_CHEST,
RC_FOREST_TEMPLE_BLUE_POE_CHEST,
RC_FOREST_TEMPLE_BASEMENT_CHEST,
RC_FOREST_TEMPLE_GS_RAISED_ISLAND_COURTYARD,
RC_FOREST_TEMPLE_GS_FIRST_ROOM,
RC_FOREST_TEMPLE_GS_LEVEL_ISLAND_COURTYARD,
RC_FOREST_TEMPLE_GS_LOBBY,
RC_FOREST_TEMPLE_GS_BASEMENT,
},
{
// MQ Locations
RC_FOREST_TEMPLE_MQ_FIRST_ROOM_CHEST,
RC_FOREST_TEMPLE_MQ_WOLFOS_CHEST,
RC_FOREST_TEMPLE_MQ_BOW_CHEST,
RC_FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_LOWER_CHEST,
RC_FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_UPPER_CHEST,
RC_FOREST_TEMPLE_MQ_WELL_CHEST,
RC_FOREST_TEMPLE_MQ_MAP_CHEST,
RC_FOREST_TEMPLE_MQ_COMPASS_CHEST,
RC_FOREST_TEMPLE_MQ_FALLING_CEILING_ROOM_CHEST,
RC_FOREST_TEMPLE_MQ_BASEMENT_CHEST,
RC_FOREST_TEMPLE_MQ_REDEAD_CHEST,
RC_FOREST_TEMPLE_MQ_BOSS_KEY_CHEST,
RC_FOREST_TEMPLE_MQ_GS_FIRST_HALLWAY,
RC_FOREST_TEMPLE_MQ_GS_BLOCK_PUSH_ROOM,
RC_FOREST_TEMPLE_MQ_GS_RAISED_ISLAND_COURTYARD,
RC_FOREST_TEMPLE_MQ_GS_LEVEL_ISLAND_COURTYARD,
RC_FOREST_TEMPLE_MQ_GS_WELL,
},
{},
{
// Boss Room Locations
RC_FOREST_TEMPLE_PHANTOM_GANON_HEART,
RC_PHANTOM_GANON,
});
DungeonInfo FireTemple = DungeonInfo("Fire Temple", RHT_FIRE_TEMPLE, RG_FIRE_TEMPLE_MAP, RG_FIRE_TEMPLE_COMPASS,
RG_FIRE_TEMPLE_SMALL_KEY, RG_FIRE_TEMPLE_KEY_RING, RG_FIRE_TEMPLE_BOSS_KEY, 8, 5,
{
// Vanilla Locations
RC_FIRE_TEMPLE_NEAR_BOSS_CHEST,
RC_FIRE_TEMPLE_FLARE_DANCER_CHEST,
RC_FIRE_TEMPLE_BOSS_KEY_CHEST,
RC_FIRE_TEMPLE_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST,
RC_FIRE_TEMPLE_BIG_LAVA_ROOM_LOWER_OPEN_DOOR_CHEST,
RC_FIRE_TEMPLE_BOULDER_MAZE_LOWER_CHEST,
RC_FIRE_TEMPLE_BOULDER_MAZE_UPPER_CHEST,
RC_FIRE_TEMPLE_BOULDER_MAZE_SIDE_ROOM_CHEST,
RC_FIRE_TEMPLE_BOULDER_MAZE_SHORTCUT_CHEST,
RC_FIRE_TEMPLE_SCARECROW_CHEST,
RC_FIRE_TEMPLE_MAP_CHEST,
RC_FIRE_TEMPLE_COMPASS_CHEST,
RC_FIRE_TEMPLE_HIGHEST_GORON_CHEST,
RC_FIRE_TEMPLE_MEGATON_HAMMER_CHEST,
RC_FIRE_TEMPLE_GS_SONG_OF_TIME_ROOM,
RC_FIRE_TEMPLE_GS_BOSS_KEY_LOOP,
RC_FIRE_TEMPLE_GS_BOULDER_MAZE,
RC_FIRE_TEMPLE_GS_SCARECROW_TOP,
RC_FIRE_TEMPLE_GS_SCARECROW_CLIMB,
},
{
// MQ Locations
RC_FIRE_TEMPLE_MQ_NEAR_BOSS_CHEST,
RC_FIRE_TEMPLE_MQ_MEGATON_HAMMER_CHEST,
RC_FIRE_TEMPLE_MQ_COMPASS_CHEST,
RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CHEST,
RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CHEST,
RC_FIRE_TEMPLE_MQ_CHEST_ON_FIRE,
RC_FIRE_TEMPLE_MQ_MAP_ROOM_SIDE_CHEST,
RC_FIRE_TEMPLE_MQ_MAP_CHEST,
RC_FIRE_TEMPLE_MQ_BOSS_KEY_CHEST,
RC_FIRE_TEMPLE_MQ_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST,
RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_SIDE_ROOM_CHEST,
RC_FIRE_TEMPLE_MQ_FREESTANDING_KEY,
RC_FIRE_TEMPLE_MQ_GS_ABOVE_FIRE_WALL_MAZE,
RC_FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_CENTER,
RC_FIRE_TEMPLE_MQ_GS_BIG_LAVA_ROOM_OPEN_DOOR,
RC_FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_SIDE_ROOM,
RC_FIRE_TEMPLE_MQ_GS_SKULL_ON_FIRE,
},
{},
{
// Boos Room Locations
RC_FIRE_TEMPLE_VOLVAGIA_HEART,
RC_VOLVAGIA,
});
DungeonInfo WaterTemple =
DungeonInfo("Water Temple", RHT_WATER_TEMPLE, RG_WATER_TEMPLE_MAP, RG_WATER_TEMPLE_COMPASS,
RG_WATER_TEMPLE_SMALL_KEY, RG_WATER_TEMPLE_KEY_RING, RG_WATER_TEMPLE_BOSS_KEY, 6, 2,
{
// Vanilla Locations
RC_WATER_TEMPLE_MAP_CHEST,
RC_WATER_TEMPLE_COMPASS_CHEST,
RC_WATER_TEMPLE_TORCHES_CHEST,
RC_WATER_TEMPLE_DRAGON_CHEST,
RC_WATER_TEMPLE_CENTRAL_BOW_TARGET_CHEST,
RC_WATER_TEMPLE_CENTRAL_PILLAR_CHEST,
RC_WATER_TEMPLE_CRACKED_WALL_CHEST,
RC_WATER_TEMPLE_BOSS_KEY_CHEST,
RC_WATER_TEMPLE_LONGSHOT_CHEST,
RC_WATER_TEMPLE_RIVER_CHEST,
RC_WATER_TEMPLE_GS_BEHIND_GATE,
RC_WATER_TEMPLE_GS_FALLING_PLATFORM_ROOM,
RC_WATER_TEMPLE_GS_CENTRAL_PILLAR,
RC_WATER_TEMPLE_GS_NEAR_BOSS_KEY_CHEST,
RC_WATER_TEMPLE_GS_RIVER,
},
{
// MQ Locations
RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_CHEST,
RC_WATER_TEMPLE_MQ_BOSS_KEY_CHEST,
RC_WATER_TEMPLE_MQ_LONGSHOT_CHEST,
RC_WATER_TEMPLE_MQ_COMPASS_CHEST,
RC_WATER_TEMPLE_MQ_MAP_CHEST,
RC_WATER_TEMPLE_MQ_FREESTANDING_KEY,
RC_WATER_TEMPLE_MQ_GS_BEFORE_UPPER_WATER_SWITCH,
RC_WATER_TEMPLE_MQ_GS_FREESTANDING_KEY_AREA,
RC_WATER_TEMPLE_MQ_GS_LIZALFOS_HALLWAY,
RC_WATER_TEMPLE_MQ_GS_RIVER,
RC_WATER_TEMPLE_MQ_GS_TRIPLE_WALL_TORCH,
},
{},
{
// Boss Room Locations
RC_WATER_TEMPLE_MORPHA_HEART,
RC_MORPHA,
});
DungeonInfo SpiritTemple =
DungeonInfo("Spirit Temple", RHT_SPIRIT_TEMPLE, RG_SPIRIT_TEMPLE_MAP, RG_SPIRIT_TEMPLE_COMPASS,
RG_SPIRIT_TEMPLE_SMALL_KEY, RG_SPIRIT_TEMPLE_KEY_RING, RG_SPIRIT_TEMPLE_BOSS_KEY, 5, 7,
{
// Vanilla Locations
RC_SPIRIT_TEMPLE_CHILD_BRIDGE_CHEST,
RC_SPIRIT_TEMPLE_CHILD_EARLY_TORCHES_CHEST,
RC_SPIRIT_TEMPLE_COMPASS_CHEST,
RC_SPIRIT_TEMPLE_EARLY_ADULT_RIGHT_CHEST,
RC_SPIRIT_TEMPLE_FIRST_MIRROR_LEFT_CHEST,
RC_SPIRIT_TEMPLE_FIRST_MIRROR_RIGHT_CHEST,
RC_SPIRIT_TEMPLE_MAP_CHEST,
RC_SPIRIT_TEMPLE_CHILD_CLIMB_NORTH_CHEST,
RC_SPIRIT_TEMPLE_CHILD_CLIMB_EAST_CHEST,
RC_SPIRIT_TEMPLE_SUN_BLOCK_ROOM_CHEST,
RC_SPIRIT_TEMPLE_STATUE_ROOM_HAND_CHEST,
RC_SPIRIT_TEMPLE_STATUE_ROOM_NORTHEAST_CHEST,
RC_SPIRIT_TEMPLE_NEAR_FOUR_ARMOS_CHEST,
RC_SPIRIT_TEMPLE_HALLWAY_LEFT_INVISIBLE_CHEST,
RC_SPIRIT_TEMPLE_HALLWAY_RIGHT_INVISIBLE_CHEST,
RC_SPIRIT_TEMPLE_BOSS_KEY_CHEST,
RC_SPIRIT_TEMPLE_TOPMOST_CHEST,
RC_SPIRIT_TEMPLE_GS_HALL_AFTER_SUN_BLOCK_ROOM,
RC_SPIRIT_TEMPLE_GS_BOULDER_ROOM,
RC_SPIRIT_TEMPLE_GS_LOBBY,
RC_SPIRIT_TEMPLE_GS_SUN_ON_FLOOR_ROOM,
RC_SPIRIT_TEMPLE_GS_METAL_FENCE,
},
{
// MQ Locations
RC_SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_LEFT_CHEST,
RC_SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_RIGHT_CHEST,
RC_SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_RIGHT_CHEST,
RC_SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_LEFT_CHEST,
RC_SPIRIT_TEMPLE_MQ_CHILD_HAMMER_SWITCH_CHEST,
RC_SPIRIT_TEMPLE_MQ_MAP_CHEST,
RC_SPIRIT_TEMPLE_MQ_MAP_ROOM_ENEMY_CHEST,
RC_SPIRIT_TEMPLE_MQ_CHILD_CLIMB_NORTH_CHEST,
RC_SPIRIT_TEMPLE_MQ_CHILD_CLIMB_SOUTH_CHEST,
RC_SPIRIT_TEMPLE_MQ_COMPASS_CHEST,
RC_SPIRIT_TEMPLE_MQ_STATUE_ROOM_LULLABY_CHEST,
RC_SPIRIT_TEMPLE_MQ_STATUE_ROOM_INVISIBLE_CHEST,
RC_SPIRIT_TEMPLE_MQ_SILVER_BLOCK_HALLWAY_CHEST,
RC_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM_CHEST,
RC_SPIRIT_TEMPLE_MQ_SYMPHONY_ROOM_CHEST,
RC_SPIRIT_TEMPLE_MQ_LEEVER_ROOM_CHEST,
RC_SPIRIT_TEMPLE_MQ_BEAMOS_ROOM_CHEST,
RC_SPIRIT_TEMPLE_MQ_CHEST_SWITCH_CHEST,
RC_SPIRIT_TEMPLE_MQ_BOSS_KEY_CHEST,
RC_SPIRIT_TEMPLE_MQ_MIRROR_PUZZLE_INVISIBLE_CHEST,
RC_SPIRIT_TEMPLE_MQ_GS_SYMPHONY_ROOM,
RC_SPIRIT_TEMPLE_MQ_GS_LEEVER_ROOM,
RC_SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_WEST,
RC_SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_NORTH,
RC_SPIRIT_TEMPLE_MQ_GS_SUN_BLOCK_ROOM,
},
{
// Shared Locations
RC_SPIRIT_TEMPLE_SILVER_GAUNTLETS_CHEST,
RC_SPIRIT_TEMPLE_MIRROR_SHIELD_CHEST,
},
{
// Boss Room Locations
RC_SPIRIT_TEMPLE_TWINROVA_HEART,
RC_TWINROVA,
});
DungeonInfo ShadowTemple =
DungeonInfo("Shadow Temple", RHT_SHADOW_TEMPLE, RG_SHADOW_TEMPLE_MAP, RG_SHADOW_TEMPLE_COMPASS,
RG_SHADOW_TEMPLE_SMALL_KEY, RG_SHADOW_TEMPLE_KEY_RING, RG_SHADOW_TEMPLE_BOSS_KEY, 5, 6,
{
// Vanilla Locations
RC_SHADOW_TEMPLE_MAP_CHEST,
RC_SHADOW_TEMPLE_HOVER_BOOTS_CHEST,
RC_SHADOW_TEMPLE_COMPASS_CHEST,
RC_SHADOW_TEMPLE_EARLY_SILVER_RUPEE_CHEST,
RC_SHADOW_TEMPLE_INVISIBLE_BLADES_VISIBLE_CHEST,
RC_SHADOW_TEMPLE_INVISIBLE_BLADES_INVISIBLE_CHEST,
RC_SHADOW_TEMPLE_FALLING_SPIKES_LOWER_CHEST,
RC_SHADOW_TEMPLE_FALLING_SPIKES_UPPER_CHEST,
RC_SHADOW_TEMPLE_FALLING_SPIKES_SWITCH_CHEST,
RC_SHADOW_TEMPLE_INVISIBLE_SPIKES_CHEST,
RC_SHADOW_TEMPLE_WIND_HINT_CHEST,
RC_SHADOW_TEMPLE_AFTER_WIND_ENEMY_CHEST,
RC_SHADOW_TEMPLE_AFTER_WIND_HIDDEN_CHEST,
RC_SHADOW_TEMPLE_SPIKE_WALLS_LEFT_CHEST,
RC_SHADOW_TEMPLE_BOSS_KEY_CHEST,
RC_SHADOW_TEMPLE_INVISIBLE_FLOORMASTER_CHEST,
RC_SHADOW_TEMPLE_FREESTANDING_KEY,
RC_SHADOW_TEMPLE_GS_SINGLE_GIANT_POT,
RC_SHADOW_TEMPLE_GS_FALLING_SPIKES_ROOM,
RC_SHADOW_TEMPLE_GS_TRIPLE_GIANT_POT,
RC_SHADOW_TEMPLE_GS_LIKE_LIKE_ROOM,
RC_SHADOW_TEMPLE_GS_NEAR_SHIP,
},
{
// MQ Locations
RC_SHADOW_TEMPLE_MQ_COMPASS_CHEST,
RC_SHADOW_TEMPLE_MQ_HOVER_BOOTS_CHEST,
RC_SHADOW_TEMPLE_MQ_EARLY_GIBDOS_CHEST,
RC_SHADOW_TEMPLE_MQ_MAP_CHEST,
RC_SHADOW_TEMPLE_MQ_BEAMOS_SILVER_RUPEES_CHEST,
RC_SHADOW_TEMPLE_MQ_FALLING_SPIKES_SWITCH_CHEST,
RC_SHADOW_TEMPLE_MQ_FALLING_SPIKES_LOWER_CHEST,
RC_SHADOW_TEMPLE_MQ_FALLING_SPIKES_UPPER_CHEST,
RC_SHADOW_TEMPLE_MQ_INVISIBLE_SPIKES_CHEST,
RC_SHADOW_TEMPLE_MQ_BOSS_KEY_CHEST,
RC_SHADOW_TEMPLE_MQ_SPIKE_WALLS_LEFT_CHEST,
RC_SHADOW_TEMPLE_MQ_STALFOS_ROOM_CHEST,
RC_SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_INVISIBLE_CHEST,
RC_SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_VISIBLE_CHEST,
RC_SHADOW_TEMPLE_MQ_BOMB_FLOWER_CHEST,
RC_SHADOW_TEMPLE_MQ_WIND_HINT_CHEST,
RC_SHADOW_TEMPLE_MQ_AFTER_WIND_HIDDEN_CHEST,
RC_SHADOW_TEMPLE_MQ_AFTER_WIND_ENEMY_CHEST,
RC_SHADOW_TEMPLE_MQ_NEAR_SHIP_INVISIBLE_CHEST,
RC_SHADOW_TEMPLE_MQ_FREESTANDING_KEY,
RC_SHADOW_TEMPLE_MQ_GS_FALLING_SPIKES_ROOM,
RC_SHADOW_TEMPLE_MQ_GS_WIND_HINT_ROOM,
RC_SHADOW_TEMPLE_MQ_GS_AFTER_WIND,
RC_SHADOW_TEMPLE_MQ_GS_AFTER_SHIP,
RC_SHADOW_TEMPLE_MQ_GS_NEAR_BOSS,
},
{},
{
// Boss Room Locations
RC_SHADOW_TEMPLE_BONGO_BONGO_HEART,
RC_BONGO_BONGO,
});
DungeonInfo BottomOfTheWell =
DungeonInfo("Bottom of the Well", RHT_BOTTOM_OF_THE_WELL, RG_BOTTOM_OF_THE_WELL_MAP, RG_BOTTOM_OF_THE_WELL_COMPASS,
RG_BOTTOM_OF_THE_WELL_SMALL_KEY, RG_BOTTOM_OF_THE_WELL_KEY_RING, RG_NONE, 3, 2,
{
// Vanilla Locations
RC_BOTTOM_OF_THE_WELL_FRONT_LEFT_FAKE_WALL_CHEST,
RC_BOTTOM_OF_THE_WELL_FRONT_CENTER_BOMBABLE_CHEST,
RC_BOTTOM_OF_THE_WELL_RIGHT_BOTTOM_FAKE_WALL_CHEST,
RC_BOTTOM_OF_THE_WELL_COMPASS_CHEST,
RC_BOTTOM_OF_THE_WELL_CENTER_SKULLTULA_CHEST,
RC_BOTTOM_OF_THE_WELL_BACK_LEFT_BOMBABLE_CHEST,
RC_BOTTOM_OF_THE_WELL_LENS_OF_TRUTH_CHEST,
RC_BOTTOM_OF_THE_WELL_INVISIBLE_CHEST,
RC_BOTTOM_OF_THE_WELL_UNDERWATER_FRONT_CHEST,
RC_BOTTOM_OF_THE_WELL_UNDERWATER_LEFT_CHEST,
RC_BOTTOM_OF_THE_WELL_MAP_CHEST,
RC_BOTTOM_OF_THE_WELL_FIRE_KEESE_CHEST,
RC_BOTTOM_OF_THE_WELL_LIKE_LIKE_CHEST,
RC_BOTTOM_OF_THE_WELL_FREESTANDING_KEY,
RC_BOTTOM_OF_THE_WELL_GS_LIKE_LIKE_CAGE,
RC_BOTTOM_OF_THE_WELL_GS_EAST_INNER_ROOM,
RC_BOTTOM_OF_THE_WELL_GS_WEST_INNER_ROOM,
},
{
// MQ Locations
RC_BOTTOM_OF_THE_WELL_MQ_MAP_CHEST,
RC_BOTTOM_OF_THE_WELL_MQ_LENS_OF_TRUTH_CHEST,
RC_BOTTOM_OF_THE_WELL_MQ_COMPASS_CHEST,
RC_BOTTOM_OF_THE_WELL_MQ_DEAD_HAND_FREESTANDING_KEY,
RC_BOTTOM_OF_THE_WELL_MQ_EAST_INNER_ROOM_FREESTANDING_KEY,
RC_BOTTOM_OF_THE_WELL_MQ_GS_BASEMENT,
RC_BOTTOM_OF_THE_WELL_MQ_GS_COFFIN_ROOM,
RC_BOTTOM_OF_THE_WELL_MQ_GS_WEST_INNER_ROOM,
},
{}, {});
DungeonInfo IceCavern =
DungeonInfo("Ice Cavern", RHT_ICE_CAVERN, RG_ICE_CAVERN_MAP, RG_ICE_CAVERN_COMPASS, RG_NONE, RG_NONE, RG_NONE, 0, 0,
{
// Vanilla Locations
RC_ICE_CAVERN_MAP_CHEST,
RC_ICE_CAVERN_COMPASS_CHEST,
RC_ICE_CAVERN_IRON_BOOTS_CHEST,
RC_ICE_CAVERN_FREESTANDING_POH,
RC_ICE_CAVERN_GS_PUSH_BLOCK_ROOM,
RC_ICE_CAVERN_GS_SPINNING_SCYTHE_ROOM,
RC_ICE_CAVERN_GS_HEART_PIECE_ROOM,
},
{
// MQ Locations
RC_ICE_CAVERN_MQ_IRON_BOOTS_CHEST,
RC_ICE_CAVERN_MQ_COMPASS_CHEST,
RC_ICE_CAVERN_MQ_MAP_CHEST,
RC_ICE_CAVERN_MQ_FREESTANDING_POH,
RC_ICE_CAVERN_MQ_GS_SCARECROW,
RC_ICE_CAVERN_MQ_GS_ICE_BLOCK,
RC_ICE_CAVERN_MQ_GS_RED_ICE,
},
{
// Shared Locations
RC_SHEIK_IN_ICE_CAVERN,
},
{});
DungeonInfo GerudoTrainingGrounds =
DungeonInfo("Gerudo Training Grounds", RHT_GERUDO_TRAINING_GROUND, RG_NONE, RG_NONE,
RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY, RG_GERUDO_TRAINING_GROUNDS_KEY_RING, RG_NONE, 9, 3,
{
// Vanilla Locations
RC_GERUDO_TRAINING_GROUND_LOBBY_LEFT_CHEST,
RC_GERUDO_TRAINING_GROUND_LOBBY_RIGHT_CHEST,
RC_GERUDO_TRAINING_GROUND_STALFOS_CHEST,
RC_GERUDO_TRAINING_GROUND_BEAMOS_CHEST,
RC_GERUDO_TRAINING_GROUND_HIDDEN_CEILING_CHEST,
RC_GERUDO_TRAINING_GROUND_MAZE_PATH_FIRST_CHEST,
RC_GERUDO_TRAINING_GROUND_MAZE_PATH_SECOND_CHEST,
RC_GERUDO_TRAINING_GROUND_MAZE_PATH_THIRD_CHEST,
RC_GERUDO_TRAINING_GROUND_MAZE_PATH_FINAL_CHEST,
RC_GERUDO_TRAINING_GROUND_MAZE_RIGHT_CENTRAL_CHEST,
RC_GERUDO_TRAINING_GROUND_MAZE_RIGHT_SIDE_CHEST,
RC_GERUDO_TRAINING_GROUND_UNDERWATER_SILVER_RUPEE_CHEST,
RC_GERUDO_TRAINING_GROUND_HAMMER_ROOM_CLEAR_CHEST,
RC_GERUDO_TRAINING_GROUND_HAMMER_ROOM_SWITCH_CHEST,
RC_GERUDO_TRAINING_GROUND_EYE_STATUE_CHEST,
RC_GERUDO_TRAINING_GROUND_NEAR_SCARECROW_CHEST,
RC_GERUDO_TRAINING_GROUND_BEFORE_HEAVY_BLOCK_CHEST,
RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_FIRST_CHEST,
RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_SECOND_CHEST,
RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_THIRD_CHEST,
RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_FOURTH_CHEST,
RC_GERUDO_TRAINING_GROUND_FREESTANDING_KEY,
},
{
// MQ Locations
RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_RIGHT_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_LEFT_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_FIRST_IRON_KNUCKLE_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_BEFORE_HEAVY_BLOCK_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_EYE_STATUE_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_FLAME_CIRCLE_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_SECOND_IRON_KNUCKLE_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_DINOLFOS_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_ICE_ARROWS_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_MAZE_RIGHT_CENTRAL_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_FIRST_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_MAZE_RIGHT_SIDE_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_THIRD_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_SECOND_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_HIDDEN_CEILING_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_UNDERWATER_SILVER_RUPEE_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_HEAVY_BLOCK_CHEST,
},
{}, {});
DungeonInfo GanonsCastle =
DungeonInfo("Ganon's Castle", RHT_GANONS_CASTLE, RG_NONE, RG_NONE, RG_GANONS_CASTLE_SMALL_KEY,
RG_GANONS_CASTLE_KEY_RING, RG_GANONS_CASTLE_BOSS_KEY, 2, 3,
{
// Vanilla Locations
RC_GANONS_CASTLE_FOREST_TRIAL_CHEST,
RC_GANONS_CASTLE_WATER_TRIAL_LEFT_CHEST,
RC_GANONS_CASTLE_WATER_TRIAL_RIGHT_CHEST,
RC_GANONS_CASTLE_SHADOW_TRIAL_FRONT_CHEST,
RC_GANONS_CASTLE_SHADOW_TRIAL_GOLDEN_GAUNTLETS_CHEST,
RC_GANONS_CASTLE_SPIRIT_TRIAL_CRYSTAL_SWITCH_CHEST,
RC_GANONS_CASTLE_SPIRIT_TRIAL_INVISIBLE_CHEST,
RC_GANONS_CASTLE_LIGHT_TRIAL_FIRST_LEFT_CHEST,
RC_GANONS_CASTLE_LIGHT_TRIAL_SECOND_LEFT_CHEST,
RC_GANONS_CASTLE_LIGHT_TRIAL_THIRD_LEFT_CHEST,
RC_GANONS_CASTLE_LIGHT_TRIAL_FIRST_RIGHT_CHEST,
RC_GANONS_CASTLE_LIGHT_TRIAL_SECOND_RIGHT_CHEST,
RC_GANONS_CASTLE_LIGHT_TRIAL_THIRD_RIGHT_CHEST,
RC_GANONS_CASTLE_LIGHT_TRIAL_INVISIBLE_ENEMIES_CHEST,
RC_GANONS_CASTLE_LIGHT_TRIAL_LULLABY_CHEST,
RC_GANONS_CASTLE_DEKU_SCRUB_LEFT,
RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT,
RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT,
RC_GANONS_CASTLE_DEKU_SCRUB_RIGHT,
},
{
// MQ Locations
RC_GANONS_CASTLE_MQ_WATER_TRIAL_CHEST,
RC_GANONS_CASTLE_MQ_FOREST_TRIAL_EYE_SWITCH_CHEST,
RC_GANONS_CASTLE_MQ_FOREST_TRIAL_FROZEN_EYE_SWITCH_CHEST,
RC_GANONS_CASTLE_MQ_LIGHT_TRIAL_LULLABY_CHEST,
RC_GANONS_CASTLE_MQ_SHADOW_TRIAL_BOMB_FLOWER_CHEST,
RC_GANONS_CASTLE_MQ_SHADOW_TRIAL_EYE_SWITCH_CHEST,
RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_GOLDEN_GAUNTLETS_CHEST,
RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_RIGHT_CHEST,
RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_LEFT_CHEST,
RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_FRONT_LEFT_CHEST,
RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_FIRST_CHEST,
RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_INVISIBLE_CHEST,
RC_GANONS_CASTLE_MQ_FOREST_TRIAL_FREESTANDING_KEY,
RC_GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT,
RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT,
RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER,
RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT,
RC_GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT,
},
{
// Shared Locations
RC_GANONS_TOWER_BOSS_KEY_CHEST,
RC_GANON,
},
{});
const DungeonArray dungeonList = {
&DekuTree, &DodongosCavern, &JabuJabusBelly, &ForestTemple,
&FireTemple, &WaterTemple, &SpiritTemple, &ShadowTemple,
&BottomOfTheWell, &IceCavern, &GerudoTrainingGrounds, &GanonsCastle,
};
} // namespace Dungeon

View File

@@ -1,109 +0,0 @@
#pragma once
#include <array>
#include <string>
#include <vector>
#include "../randomizerTypes.h"
namespace Dungeon {
class DungeonInfo {
public:
DungeonInfo(std::string name_, RandomizerHintTextKey hintKey_, RandomizerGet map_, RandomizerGet compass_, RandomizerGet smallKey_,
RandomizerGet keyRing_, RandomizerGet bossKey_,
uint8_t vanillaKeyCount_, uint8_t mqKeyCount_,
std::vector<RandomizerCheck> vanillaLocations_,
std::vector<RandomizerCheck> mqLocations_,
std::vector<RandomizerCheck> sharedLocations_,
std::vector<RandomizerCheck> bossRoomLocations_);
~DungeonInfo();
const std::string& GetName() const {
return name;
}
void SetMQ() {
masterQuest = true;
}
void ClearMQ() {
masterQuest = false;
}
bool IsMQ() const {
return masterQuest;
}
void SetKeyRing() {
hasKeyRing = true;
}
void ClearKeyRing() {
hasKeyRing = false;
}
bool HasKeyRing() const {
return hasKeyRing;
}
bool IsVanilla() const {
return !masterQuest;
}
uint8_t GetSmallKeyCount() const {
return (masterQuest) ? mqKeyCount : vanillaKeyCount;
}
RandomizerHintTextKey GetHintKey() const;
RandomizerGet GetSmallKey() const;
RandomizerGet GetKeyRing() const;
RandomizerGet GetMap() const;
RandomizerGet GetCompass() const;
RandomizerGet GetBossKey() const;
void PlaceVanillaMap();
void PlaceVanillaCompass();
void PlaceVanillaBossKey();
void PlaceVanillaSmallKeys();
// Gets the chosen dungeon locations for a playthrough (so either MQ or Vanilla)
std::vector<RandomizerCheck> GetDungeonLocations() const;
// Gets all dungeon locations (MQ + Vanilla)
std::vector<RandomizerCheck> GetEveryLocation() const;
private:
std::string name;
RandomizerHintTextKey hintKey;
RandomizerGet map;
RandomizerGet compass;
RandomizerGet smallKey;
RandomizerGet keyRing;
RandomizerGet bossKey;
uint8_t vanillaKeyCount;
uint8_t mqKeyCount;
bool masterQuest = false;
bool hasKeyRing = false;
std::vector<RandomizerCheck> vanillaLocations;
std::vector<RandomizerCheck> mqLocations;
std::vector<RandomizerCheck> sharedLocations;
std::vector<RandomizerCheck> bossRoomLocations;
};
extern DungeonInfo DekuTree;
extern DungeonInfo DodongosCavern;
extern DungeonInfo JabuJabusBelly;
extern DungeonInfo ForestTemple;
extern DungeonInfo FireTemple;
extern DungeonInfo WaterTemple;
extern DungeonInfo SpiritTemple;
extern DungeonInfo ShadowTemple;
extern DungeonInfo BottomOfTheWell;
extern DungeonInfo IceCavern;
extern DungeonInfo GerudoTrainingGrounds;
extern DungeonInfo GanonsCastle;
using DungeonArray = std::array<DungeonInfo*, 12>;
extern const DungeonArray dungeonList;
} // namespace Dungeon

File diff suppressed because it is too large Load Diff

View File

@@ -1,289 +0,0 @@
#pragma once
#include "location_access.hpp"
#include <string>
#include <list>
#include "../randomizer_entrance.h"
#define ENTRANCE_SHUFFLE_SUCCESS 0
#define ENTRANCE_SHUFFLE_FAILURE 1
extern std::list<EntranceOverride> entranceOverrides;
enum class EntranceType {
None,
OwlDrop,
Spawn,
WarpSong,
Dungeon,
GanonDungeon,
DungeonReverse,
Boss,
ChildBoss,
AdultBoss,
Interior,
InteriorReverse,
SpecialInterior,
GrottoGrave,
GrottoGraveReverse,
Overworld,
Extra,
Mixed,
All,
};
class Entrance {
public:
Entrance(RandomizerRegion connectedRegion_, std::vector<ConditionFn> conditions_met_)
: connectedRegion(connectedRegion_) {
conditions_met.resize(2);
for (size_t i = 0; i < conditions_met_.size(); i++) {
conditions_met[i] = conditions_met_[i];
}
}
// Resets the glitchless condition for the entrance
void SetCondition(ConditionFn newCondition) {
conditions_met[0] = newCondition;
}
bool GetConditionsMet() const {
if (Settings::Logic.Is(LOGIC_NONE) || Settings::Logic.Is(LOGIC_VANILLA)) {
return true;
} else if (Settings::Logic.Is(LOGIC_GLITCHLESS)) {
return conditions_met[0]();
} else if (Settings::Logic.Is(LOGIC_GLITCHED)) {
if (conditions_met[0]()) {
return true;
} else if (conditions_met[1] != NULL) {
return conditions_met[1]();
}
}
return false;
}
std::string to_string() const {
return AreaTable(parentRegion)->regionName + " -> " + AreaTable(connectedRegion)->regionName;
}
void SetName(std::string name_ = "") {
if (name_ == "") {
name = AreaTable(parentRegion)->regionName + " -> " + AreaTable(connectedRegion)->regionName;
} else {
name = std::move(name_);
}
}
std::string GetName() const {
return name;
}
void printAgeTimeAccess() {
//CitraPrint("Name: ");
//CitraPrint(name);
auto message = "Child Day: " + std::to_string(CheckConditionAtAgeTime(Logic::IsChild, Logic::AtDay)) + "\t"
"Child Night: " + std::to_string(CheckConditionAtAgeTime(Logic::IsChild, Logic::AtNight)) + "\t"
"Adult Day: " + std::to_string(CheckConditionAtAgeTime(Logic::IsAdult, Logic::AtDay)) + "\t"
"Adult Night: " + std::to_string(CheckConditionAtAgeTime(Logic::IsAdult, Logic::AtNight));
//CitraPrint(message);
}
bool ConditionsMet(bool allAgeTimes = false) const {
Area* parent = AreaTable(parentRegion);
int conditionsMet = 0;
if (allAgeTimes && !parent->AllAccess()) {
return false;
}
//check all possible day/night condition combinations
conditionsMet = (parent->childDay && CheckConditionAtAgeTime(Logic::IsChild, Logic::AtDay, allAgeTimes)) +
(parent->childNight && CheckConditionAtAgeTime(Logic::IsChild, Logic::AtNight, allAgeTimes)) +
(parent->adultDay && CheckConditionAtAgeTime(Logic::IsAdult, Logic::AtDay, allAgeTimes)) +
(parent->adultNight && CheckConditionAtAgeTime(Logic::IsAdult, Logic::AtNight, allAgeTimes));
return conditionsMet && (!allAgeTimes || conditionsMet == 4);
}
uint32_t Getuint32_t() const {
return connectedRegion;
}
//set the logic to be a specific age and time of day and see if the condition still holds
bool CheckConditionAtAgeTime(bool& age, bool& time, bool passAnyway = false) const {
Logic::IsChild = false;
Logic::IsAdult = false;
Logic::AtDay = false;
Logic::AtNight = false;
time = true;
age = true;
Logic::UpdateHelpers();
return GetConditionsMet() && (connectedRegion != RR_NONE || passAnyway);
}
RandomizerRegion GetConnectedRegionKey() const {
return connectedRegion;
}
Area* GetConnectedRegion() const {
return AreaTable(connectedRegion);
}
void SetParentRegion(RandomizerRegion newParent) {
parentRegion = newParent;
}
RandomizerRegion GetParentRegionKey() const {
return parentRegion;
}
Area* GetParentRegion() const {
return AreaTable(parentRegion);
}
void SetNewEntrance(RandomizerRegion newRegion) {
connectedRegion = newRegion;
}
void SetAsShuffled() {
shuffled = true;
}
bool IsShuffled() const {
return shuffled;
}
bool IsAddedToPool() const {
return addedToPool;
}
void AddToPool() {
addedToPool = true;
}
void RemoveFromPool() {
addedToPool = false;
}
void SetAsPrimary() {
primary = true;
}
bool IsPrimary() const {
return primary;
}
bool IsDecoupled() const {
return decoupled;
}
void SetDecoupled() {
decoupled = true;
}
int16_t GetIndex() const {
return index;
}
void SetIndex(int16_t newIndex) {
index = newIndex;
}
int16_t GetBlueWarp() const {
return blueWarp;
}
void SetBlueWarp(int16_t newBlueWarp) {
blueWarp = newBlueWarp;
}
Entrance* GetAssumed() const {
return assumed;
}
void SetReplacement(Entrance* newReplacement) {
replacement = newReplacement;
}
Entrance* GetReplacement() const {
return replacement;
}
EntranceType GetType() const {
return type;
}
void SetType(EntranceType newType) {
type = newType;
}
Entrance* GetReverse() const {
return reverse;
}
void Connect(RandomizerRegion newConnectedRegion) {
connectedRegion = newConnectedRegion;
AreaTable(newConnectedRegion)->entrances.push_front(this);
}
RandomizerRegion Disconnect() {
AreaTable(connectedRegion)->entrances.remove_if([this](const auto entrance){return this == entrance;});
RandomizerRegion previouslyConnected = connectedRegion;
connectedRegion = RR_NONE;
return previouslyConnected;
}
void BindTwoWay(Entrance* otherEntrance) {
reverse = otherEntrance;
otherEntrance->reverse = this;
}
Entrance* GetNewTarget() {
AreaTable(RR_ROOT)->AddExit(RR_ROOT, connectedRegion, []{return true;});
Entrance* targetEntrance = AreaTable(RR_ROOT)->GetExit(connectedRegion);
targetEntrance->SetReplacement(this);
targetEntrance->SetName(GetParentRegion()->regionName + " -> " + GetConnectedRegion()->regionName);
return targetEntrance;
}
Entrance* AssumeReachable() {
if (assumed == nullptr) {
assumed = GetNewTarget();
Disconnect();
}
return assumed;
}
private:
RandomizerRegion parentRegion;
RandomizerRegion connectedRegion;
std::vector<ConditionFn> conditions_met;
//Entrance Randomizer stuff
EntranceType type = EntranceType::None;
Entrance* target = nullptr;
Entrance* reverse = nullptr;
Entrance* assumed = nullptr;
Entrance* replacement = nullptr;
int16_t index = 0xFFFF;
int16_t blueWarp = 0;
bool shuffled = false;
bool primary = false;
bool addedToPool = false;
bool decoupled = false;
std::string name = "";
};
int ShuffleAllEntrances();
void CreateEntranceOverrides();
extern std::vector<std::list<Entrance*>> playthroughEntrances;
extern bool noRandomEntrances;

View File

@@ -1,7 +1,7 @@
#include "fill.hpp"
#include "custom_messages.hpp"
#include "dungeon.hpp"
#include "../dungeon.h"
#include "../context.h"
#include "item_pool.hpp"
#include "location_access.hpp"
@@ -11,8 +11,9 @@
#include "starting_inventory.hpp"
#include "hints.hpp"
#include "hint_list.hpp"
#include "entrance.hpp"
#include "../entrance.h"
#include "shops.hpp"
#include "pool_functions.hpp"
//#include "debug.hpp"
#include "soh/Enhancements/randomizer/static_data.h"
@@ -22,7 +23,7 @@
using namespace CustomMessages;
using namespace Logic;
using namespace Settings;
using namespace Rando;
static bool placementFailure = false;
@@ -90,14 +91,15 @@ static bool UpdateToDAccess(Entrance* entrance, SearchMode mode) {
// Various checks that need to pass for the world to be validated as completable
static void ValidateWorldChecks(SearchMode& mode, bool checkPoeCollectorAccess, bool checkOtherEntranceAccess, std::vector<RandomizerRegion>& areaPool) {
auto ctx = Rando::Context::GetInstance();
// Condition for validating Temple of Time Access
if (mode == SearchMode::TempleOfTimeAccess && ((Settings::ResolvedStartingAge == AGE_CHILD && AreaTable(RR_TEMPLE_OF_TIME)->Adult()) || (Settings::ResolvedStartingAge == AGE_ADULT && AreaTable(RR_TEMPLE_OF_TIME)->Child()) || !checkOtherEntranceAccess)) {
if (mode == SearchMode::TempleOfTimeAccess && ((ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD && AreaTable(RR_TEMPLE_OF_TIME)->Adult()) || (ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_ADULT && AreaTable(RR_TEMPLE_OF_TIME)->Child()) || !checkOtherEntranceAccess)) {
mode = SearchMode::ValidStartingRegion;
}
// Condition for validating a valid starting region
if (mode == SearchMode::ValidStartingRegion) {
bool childAccess = Settings::ResolvedStartingAge == AGE_CHILD || AreaTable(RR_TOT_BEYOND_DOOR_OF_TIME)->Child();
bool adultAccess = Settings::ResolvedStartingAge == AGE_ADULT || AreaTable(RR_TOT_BEYOND_DOOR_OF_TIME)->Adult();
bool childAccess = ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD || AreaTable(RR_TOT_BEYOND_DOOR_OF_TIME)->Child();
bool adultAccess = ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_ADULT || AreaTable(RR_TOT_BEYOND_DOOR_OF_TIME)->Adult();
Area* kokiri = AreaTable(RR_KOKIRI_FOREST);
Area* kakariko = AreaTable(RR_KAKARIKO_VILLAGE);
@@ -119,7 +121,7 @@ static void ValidateWorldChecks(SearchMode& mode, bool checkPoeCollectorAccess,
Rando::StaticData::RetrieveItem(unplacedItem).ApplyEffect();
}
// Reset access as the non-starting age
if (Settings::ResolvedStartingAge == AGE_CHILD) {
if (ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD) {
for (RandomizerRegion areaKey : areaPool) {
AreaTable(areaKey)->adultDay = false;
AreaTable(areaKey)->adultNight = false;
@@ -142,11 +144,11 @@ static int GetMaxGSCount() {
//If bridge or LACS is set to tokens, get how many are required
int maxBridge = 0;
int maxLACS = 0;
if (Settings::Bridge.Is(RAINBOWBRIDGE_TOKENS)) {
maxBridge = Settings::BridgeTokenCount.Value<uint8_t>();
if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_TOKENS)) {
maxBridge = ctx->GetOption(RSK_RAINBOW_BRIDGE_TOKEN_COUNT).Value<uint8_t>();
}
if (Settings::GanonsBossKey.Is(GANONSBOSSKEY_LACS_TOKENS)) {
maxLACS = Settings::LACSTokenCount.Value<uint8_t>();
if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_TOKENS)) {
maxLACS = ctx->GetOption(RSK_LACS_TOKEN_COUNT).Value<uint8_t>();
}
maxBridge = std::max(maxBridge, maxLACS);
//Get the max amount of GS which could be useful from token reward locations
@@ -171,7 +173,7 @@ static int GetMaxGSCount() {
maxUseful = 10;
}
//Return max of the two possible reasons tokens could be important, minus the tokens in the starting inventory
return std::max(maxUseful, maxBridge) - StartingSkulltulaToken.Value<uint8_t>();
return std::max(maxUseful, maxBridge) - ctx->GetOption(RSK_STARTING_SKULLTULA_TOKEN).Value<uint8_t>();
}
std::string GetShopItemBaseName(std::string itemName) {
@@ -306,7 +308,7 @@ std::vector<RandomizerCheck> GetAccessibleLocations(const std::vector<Randomizer
}
// Add shuffled entrances to the entrance playthrough
if (mode == SearchMode::GeneratePlaythrough && exit.IsShuffled() && !exit.IsAddedToPool() && !noRandomEntrances) {
if (mode == SearchMode::GeneratePlaythrough && exit.IsShuffled() && !exit.IsAddedToPool() && !ctx->GetEntranceShuffler()->HasNoRandomEntrances()) {
entranceSphere.push_back(&exit);
exit.AddToPool();
// Don't list a two-way coupled entrance from both directions
@@ -384,7 +386,8 @@ std::vector<RandomizerCheck> GetAccessibleLocations(const std::vector<Randomizer
}
//Handle buy items
//If ammo drops are off, don't do this step, since buyable ammo becomes logically important
else if (AmmoDrops.IsNot(AMMODROPS_NONE) && !(bombchus && bombchusFound) && type == ITEMTYPE_SHOP) {
// TODO: Reimplement Ammo Drops setting
else if (/*AmmoDrops.IsNot(AMMODROPS_NONE) &&*/ !(bombchus && bombchusFound) && type == ITEMTYPE_SHOP) {
//Only check each buy item once
std::string buyItem = GetShopItemBaseName(itemName);
//Buy item not in list to ignore, add it to list and write to playthrough
@@ -394,7 +397,7 @@ std::vector<RandomizerCheck> GetAccessibleLocations(const std::vector<Randomizer
}
}
//Add all other advancement items
else if (!bombchus && type != ITEMTYPE_TOKEN && (AmmoDrops.Is(AMMODROPS_NONE) || type != ITEMTYPE_SHOP)) {
else if (!bombchus && type != ITEMTYPE_TOKEN && (/*AmmoDrops.Is(AMMODROPS_NONE) ||*/ type != ITEMTYPE_SHOP)) {
exclude = false;
}
//Has not been excluded, add to playthrough
@@ -422,8 +425,8 @@ std::vector<RandomizerCheck> GetAccessibleLocations(const std::vector<Randomizer
if (mode == SearchMode::GeneratePlaythrough && itemSphere.size() > 0) {
ctx->playthroughLocations.push_back(itemSphere);
}
if (mode == SearchMode::GeneratePlaythrough && entranceSphere.size() > 0 && !noRandomEntrances) {
playthroughEntrances.push_back(entranceSphere);
if (mode == SearchMode::GeneratePlaythrough && entranceSphere.size() > 0 && !ctx->GetEntranceShuffler()->HasNoRandomEntrances()) {
ctx->GetEntranceShuffler()->playthroughEntrances.push_back(entranceSphere);
}
}
@@ -605,7 +608,7 @@ static void AssumedFill(const std::vector<RandomizerGet>& items, const std::vect
return;
}
if (Settings::Logic.Is(LOGIC_NONE)) {
if (ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_NO_LOGIC)) {
FastFill(items, GetEmptyLocations(allowedLocations), true);
return;
}
@@ -683,7 +686,7 @@ static void AssumedFill(const std::vector<RandomizerGet>& items, const std::vect
// If ALR is off, then we check beatability after placing the item.
// If the game is beatable, then we can stop placing items with logic.
if (!LocationsReachable) {
if (!ctx->GetOption(RSK_ALL_LOCATIONS_REACHABLE)) {
ctx->playthroughBeatable = false;
LogicReset();
GetAccessibleLocations(ctx->allLocations, SearchMode::CheckBeatable);
@@ -702,22 +705,23 @@ static void AssumedFill(const std::vector<RandomizerGet>& items, const std::vect
//setting, or randomize one dungeon reward to Link's Pocket if that setting is on
static void RandomizeDungeonRewards() {
auto ctx = Rando::Context::GetInstance();
std::array<uint32_t, 9> rDungeonRewardOverrides{};
//quest item bit mask of each stone/medallion for the savefile
static constexpr std::array<uint32_t, 9> bitMaskTable = {
0x00040000, //Kokiri Emerald
0x00080000, //Goron Ruby
0x00100000, //Zora Sapphire
0x00000001, //Forest Medallion
0x00000002, //Fire Medallion
0x00000004, //Water Medallion
0x00000008, //Spirit Medallion
0x00000010, //Shadow Medallion
0x00000020, //Light Medallion
};
// static constexpr std::array<uint32_t, 9> bitMaskTable = {
// 0x00040000, //Kokiri Emerald
// 0x00080000, //Goron Ruby
// 0x00100000, //Zora Sapphire
// 0x00000001, //Forest Medallion
// 0x00000002, //Fire Medallion
// 0x00000004, //Water Medallion
// 0x00000008, //Spirit Medallion
// 0x00000010, //Shadow Medallion
// 0x00000020, //Light Medallion
// };
int baseOffset = Rando::StaticData::RetrieveItem(RG_KOKIRI_EMERALD).GetItemID();
//End of Dungeons includes Link's Pocket
if (ShuffleRewards.Is(REWARDSHUFFLE_END_OF_DUNGEON)) {
if (ctx->GetOption(RSK_SHUFFLE_DUNGEON_REWARDS).Is(RO_DUNGEON_REWARDS_END_OF_DUNGEON)) {
//get stones and medallions
std::vector<RandomizerGet> rewards = FilterAndEraseFromPool(ItemPool, [](const auto i) {return Rando::StaticData::RetrieveItem(i).GetItemType() == ITEMTYPE_DUNGEONREWARD;});
@@ -727,7 +731,7 @@ static void RandomizeDungeonRewards() {
ctx->PlaceItemInLocation(RC_LINKS_POCKET, RG_GREEN_RUPEE);
}
if (Settings::Logic.Is(LOGIC_VANILLA)) { //Place dungeon rewards in vanilla locations
if (ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_VANILLA)) { //Place dungeon rewards in vanilla locations
for (RandomizerCheck loc : Rando::StaticData::dungeonRewardLocations) {
ctx->GetItemLocation(loc)->PlaceVanillaItem();
}
@@ -742,11 +746,11 @@ static void RandomizeDungeonRewards() {
//set the player's dungeon reward on file creation instead of pushing it to them at the start.
//This is done mainly because players are already familiar with seeing their dungeon reward
//before opening up their file
if (i == Rando::StaticData::dungeonRewardLocations.size()-1) {
LinksPocketRewardBitMask = bitMaskTable[index];
}
// if (i == Rando::StaticData::dungeonRewardLocations.size()-1) {
// LinksPocketRewardBitMask = bitMaskTable[index];
// }
}
} else if (LinksPocketItem.Is(LINKSPOCKETITEM_DUNGEON_REWARD)) {
} else if (ctx->GetOption(RSK_LINKS_POCKET).Is(RO_LINKS_POCKET_DUNGEON_REWARD)) {
//get 1 stone/medallion
std::vector<RandomizerGet> rewards = FilterFromPool(
ItemPool, [](const auto i) { return Rando::StaticData::RetrieveItem(i).GetItemType() == ITEMTYPE_DUNGEONREWARD; });
@@ -757,7 +761,7 @@ static void RandomizeDungeonRewards() {
}
RandomizerGet startingReward = RandomElement(rewards, true);
LinksPocketRewardBitMask = bitMaskTable[Rando::StaticData::RetrieveItem(startingReward).GetItemID() - baseOffset];
//LinksPocketRewardBitMask = bitMaskTable[Rando::StaticData::RetrieveItem(startingReward).GetItemID() - baseOffset];
ctx->PlaceItemInLocation(RC_LINKS_POCKET, startingReward);
//erase the stone/medallion from the Item Pool
FilterAndEraseFromPool(ItemPool, [startingReward](const RandomizerGet i) {return i == startingReward;});
@@ -779,7 +783,7 @@ static void FillExcludedLocations() {
}
//Function to handle the Own Dungeon setting
static void RandomizeOwnDungeon(const Dungeon::DungeonInfo* dungeon) {
static void RandomizeOwnDungeon(const Rando::DungeonInfo* dungeon) {
auto ctx = Rando::Context::GetInstance();
std::vector<RandomizerGet> dungeonItems;
@@ -791,24 +795,24 @@ static void RandomizeOwnDungeon(const Dungeon::DungeonInfo* dungeon) {
});
//filter out locations that may be required to have songs placed at them
dungeonLocations = FilterFromPool(dungeonLocations, [](const auto loc){
if (ShuffleSongs.Is(SONGSHUFFLE_SONG_LOCATIONS)) {
dungeonLocations = FilterFromPool(dungeonLocations, [ctx](const auto loc){
if (ctx->GetOption(RSK_SHUFFLE_SONGS).Is(RO_SONG_SHUFFLE_SONG_LOCATIONS)) {
return !(Rando::StaticData::GetLocation(loc)->IsCategory(Category::cSong));
}
if (ShuffleSongs.Is(SONGSHUFFLE_DUNGEON_REWARDS)) {
if (ctx->GetOption(RSK_SHUFFLE_SONGS).Is(RO_SONG_SHUFFLE_SONG_LOCATIONS)) {
return !(Rando::StaticData::GetLocation(loc)->IsCategory(Category::cSongDungeonReward));
}
return true;
});
//Add specific items that need be randomized within this dungeon
if (Keysanity.Is(KEYSANITY_OWN_DUNGEON) && dungeon->GetSmallKey() != RG_NONE) {
if (ctx->GetOption(RSK_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_OWN_DUNGEON) && dungeon->GetSmallKey() != RG_NONE) {
std::vector<RandomizerGet> dungeonSmallKeys = FilterAndEraseFromPool(ItemPool, [dungeon](const RandomizerGet i){ return (i == dungeon->GetSmallKey()) || (i == dungeon->GetKeyRing());});
AddElementsToPool(dungeonItems, dungeonSmallKeys);
}
if ((BossKeysanity.Is(BOSSKEYSANITY_OWN_DUNGEON) && dungeon->GetBossKey() != RG_GANONS_CASTLE_BOSS_KEY) ||
(GanonsBossKey.Is(GANONSBOSSKEY_OWN_DUNGEON) && dungeon->GetBossKey() == RG_GANONS_CASTLE_BOSS_KEY)) {
if ((ctx->GetOption(RSK_BOSS_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_OWN_DUNGEON) && dungeon->GetBossKey() != RG_GANONS_CASTLE_BOSS_KEY) ||
(ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_OWN_DUNGEON) && dungeon->GetBossKey() == RG_GANONS_CASTLE_BOSS_KEY)) {
auto dungeonBossKey = FilterAndEraseFromPool(ItemPool, [dungeon](const RandomizerGet i){ return i == dungeon->GetBossKey();});
AddElementsToPool(dungeonItems, dungeonBossKey);
}
@@ -817,7 +821,7 @@ static void RandomizeOwnDungeon(const Dungeon::DungeonInfo* dungeon) {
AssumedFill(dungeonItems, dungeonLocations);
//randomize map and compass separately since they're not progressive
if (MapsAndCompasses.Is(MAPSANDCOMPASSES_OWN_DUNGEON) && dungeon->GetMap() != RG_NONE && dungeon->GetCompass() != RG_NONE) {
if (ctx->GetOption(RSK_SHUFFLE_MAPANDCOMPASS).Is(RO_DUNGEON_ITEM_LOC_OWN_DUNGEON) && dungeon->GetMap() != RG_NONE && dungeon->GetCompass() != RG_NONE) {
auto dungeonMapAndCompass = FilterAndEraseFromPool(ItemPool, [dungeon](const RandomizerGet i){ return i == dungeon->GetMap() || i == dungeon->GetCompass();});
AssumedFill(dungeonMapAndCompass, dungeonLocations);
}
@@ -833,7 +837,6 @@ static void RandomizeOwnDungeon(const Dungeon::DungeonInfo* dungeon) {
are randomized separately once the dungeon advancement items have all been placed.*/
static void RandomizeDungeonItems() {
auto ctx = Rando::Context::GetInstance();
using namespace Dungeon;
//Get Any Dungeon and Overworld group locations
std::vector<RandomizerCheck> anyDungeonLocations = FilterFromPool(ctx->allLocations, [](const auto loc){return Rando::StaticData::GetLocation(loc)->IsDungeon();});
@@ -843,45 +846,45 @@ static void RandomizeDungeonItems() {
std::vector<RandomizerGet> anyDungeonItems;
std::vector<RandomizerGet> overworldItems;
for (auto dungeon : dungeonList) {
if (Keysanity.Is(KEYSANITY_ANY_DUNGEON)) {
for (auto dungeon : ctx->GetDungeons()->GetDungeonList()) {
if (ctx->GetOption(RSK_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_OWN_DUNGEON)) {
auto dungeonKeys = FilterAndEraseFromPool(ItemPool, [dungeon](const RandomizerGet i){return (i == dungeon->GetSmallKey()) || (i == dungeon->GetKeyRing());});
AddElementsToPool(anyDungeonItems, dungeonKeys);
} else if (Keysanity.Is(KEYSANITY_OVERWORLD)) {
} else if (ctx->GetOption(RSK_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_OVERWORLD)) {
auto dungeonKeys = FilterAndEraseFromPool(ItemPool, [dungeon](const RandomizerGet i){return (i == dungeon->GetSmallKey()) || (i == dungeon->GetKeyRing());});
AddElementsToPool(overworldItems, dungeonKeys);
}
if (BossKeysanity.Is(BOSSKEYSANITY_ANY_DUNGEON) && dungeon->GetBossKey() != RG_GANONS_CASTLE_BOSS_KEY) {
if (ctx->GetOption(RSK_BOSS_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_ANY_DUNGEON) && dungeon->GetBossKey() != RG_GANONS_CASTLE_BOSS_KEY) {
auto bossKey = FilterAndEraseFromPool(ItemPool, [dungeon](const RandomizerGet i){return i == dungeon->GetBossKey();});
AddElementsToPool(anyDungeonItems, bossKey);
} else if (BossKeysanity.Is(BOSSKEYSANITY_OVERWORLD) && dungeon->GetBossKey() != RG_GANONS_CASTLE_BOSS_KEY) {
} else if (ctx->GetOption(RSK_BOSS_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_OVERWORLD) && dungeon->GetBossKey() != RG_GANONS_CASTLE_BOSS_KEY) {
auto bossKey = FilterAndEraseFromPool(ItemPool, [dungeon](const RandomizerGet i){return i == dungeon->GetBossKey();});
AddElementsToPool(overworldItems, bossKey);
}
if (GanonsBossKey.Is(GANONSBOSSKEY_ANY_DUNGEON)) {
if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_ANY_DUNGEON)) {
auto ganonBossKey = FilterAndEraseFromPool(ItemPool, [](const auto i){return i == RG_GANONS_CASTLE_BOSS_KEY;});
AddElementsToPool(anyDungeonItems, ganonBossKey);
} else if (GanonsBossKey.Is(GANONSBOSSKEY_OVERWORLD)) {
} else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_OVERWORLD)) {
auto ganonBossKey = FilterAndEraseFromPool(ItemPool, [](const auto i) { return i == RG_GANONS_CASTLE_BOSS_KEY; });
AddElementsToPool(overworldItems, ganonBossKey);
}
}
if (GerudoKeys.Is(GERUDOKEYS_ANY_DUNGEON)) {
if (ctx->GetOption(RSK_GERUDO_KEYS).Is(RO_GERUDO_KEYS_ANY_DUNGEON)) {
auto gerudoKeys = FilterAndEraseFromPool(ItemPool, [](const auto i) { return i == RG_GERUDO_FORTRESS_SMALL_KEY; });
AddElementsToPool(anyDungeonItems, gerudoKeys);
} else if (GerudoKeys.Is(GERUDOKEYS_OVERWORLD)) {
} else if (ctx->GetOption(RSK_GERUDO_KEYS).Is(RO_GERUDO_KEYS_OVERWORLD)) {
auto gerudoKeys = FilterAndEraseFromPool(ItemPool, [](const auto i) { return i == RG_GERUDO_FORTRESS_SMALL_KEY; });
AddElementsToPool(overworldItems, gerudoKeys);
}
if (ShuffleRewards.Is(REWARDSHUFFLE_ANY_DUNGEON)) {
if (ctx->GetOption(RSK_SHUFFLE_DUNGEON_REWARDS).Is(RO_DUNGEON_REWARDS_ANY_DUNGEON)) {
auto rewards = FilterAndEraseFromPool(
ItemPool, [](const auto i) { return Rando::StaticData::RetrieveItem(i).GetItemType() == ITEMTYPE_DUNGEONREWARD; });
AddElementsToPool(anyDungeonItems, rewards);
} else if (ShuffleRewards.Is(REWARDSHUFFLE_OVERWORLD)) {
} else if (ctx->GetOption(RSK_SHUFFLE_DUNGEON_REWARDS).Is(RO_DUNGEON_REWARDS_OVERWORLD)) {
auto rewards = FilterAndEraseFromPool(
ItemPool, [](const auto i) { return Rando::StaticData::RetrieveItem(i).GetItemType() == ITEMTYPE_DUNGEONREWARD; });
AddElementsToPool(overworldItems, rewards);
@@ -892,11 +895,11 @@ static void RandomizeDungeonItems() {
AssumedFill(overworldItems, Rando::StaticData::overworldLocations, true);
//Randomize maps and compasses after since they're not advancement items
for (auto dungeon : dungeonList) {
if (MapsAndCompasses.Is(MAPSANDCOMPASSES_ANY_DUNGEON)) {
for (auto dungeon : ctx->GetDungeons()->GetDungeonList()) {
if (ctx->GetOption(RSK_SHUFFLE_MAPANDCOMPASS).Is(RO_DUNGEON_ITEM_LOC_ANY_DUNGEON)) {
auto mapAndCompassItems = FilterAndEraseFromPool(ItemPool, [dungeon](const RandomizerGet i){return i == dungeon->GetMap() || i == dungeon->GetCompass();});
AssumedFill(mapAndCompassItems, anyDungeonLocations, true);
} else if (MapsAndCompasses.Is(MAPSANDCOMPASSES_OVERWORLD)) {
} else if (ctx->GetOption(RSK_SHUFFLE_MAPANDCOMPASS).Is(RO_DUNGEON_ITEM_LOC_OVERWORLD)) {
auto mapAndCompassItems = FilterAndEraseFromPool(ItemPool, [dungeon](const RandomizerGet i){return i == dungeon->GetMap() || i == dungeon->GetCompass();});
AssumedFill(mapAndCompassItems, Rando::StaticData::overworldLocations, true);
}
@@ -905,7 +908,7 @@ static void RandomizeDungeonItems() {
static void RandomizeLinksPocket() {
auto ctx = Rando::Context::GetInstance();
if (LinksPocketItem.Is(LINKSPOCKETITEM_ADVANCEMENT)) {
if (ctx->GetOption(RSK_LINKS_POCKET).Is(RO_LINKS_POCKET_ADVANCEMENT)) {
//Get all the advancement items don't include tokens
std::vector<RandomizerGet> advancementItems = FilterAndEraseFromPool(ItemPool, [](const auto i) {
return Rando::StaticData::RetrieveItem(i).IsAdvancement() && Rando::StaticData::RetrieveItem(i).GetItemType() != ITEMTYPE_TOKEN;
@@ -916,7 +919,7 @@ static void RandomizeLinksPocket() {
AddElementsToPool(ItemPool, advancementItems);
ctx->PlaceItemInLocation(RC_LINKS_POCKET, startingItem);
} else if (LinksPocketItem.Is(LINKSPOCKETITEM_NOTHING)) {
} else if (ctx->GetOption(RSK_LINKS_POCKET).Is(RO_LINKS_POCKET_NOTHING)) {
ctx->PlaceItemInLocation(RC_LINKS_POCKET, RG_GREEN_RUPEE);
}
}
@@ -934,14 +937,14 @@ void VanillaFill() {
ctx->GetItemLocation(loc)->PlaceVanillaItem();
}
//If necessary, handle ER stuff
if (ShuffleEntrances) {
if (ctx->GetOption(RSK_SHUFFLE_ENTRANCES)) {
printf("\x1b[7;10HShuffling Entrances...");
ShuffleAllEntrances();
ctx->GetEntranceShuffler()->ShuffleAllEntrances();
printf("\x1b[7;32HDone");
}
//Finish up
ctx->CreateItemOverrides();
CreateEntranceOverrides();
ctx->GetEntranceShuffler()->CreateEntranceOverrides();
CreateWarpSongTexts();
}
@@ -960,7 +963,7 @@ int Fill() {
placementFailure = false;
//showItemProgress = false;
ctx->playthroughLocations.clear();
playthroughEntrances.clear();
ctx->GetEntranceShuffler()->playthroughEntrances.clear();
ctx->wothLocations.clear();
AreaTable_Init(); //Reset the world graph to intialize the proper locations
ctx->ItemReset(); //Reset shops incase of shopsanity random
@@ -973,9 +976,9 @@ int Fill() {
//Temporarily add shop items to the ItemPool so that entrance randomization
//can validate the world using deku/hylian shields
AddElementsToPool(ItemPool, GetMinVanillaShopItems(32)); //assume worst case shopsanity 4
if (ShuffleEntrances) {
if (ctx->GetOption(RSK_SHUFFLE_ENTRANCES)) {
printf("\x1b[7;10HShuffling Entrances");
if (ShuffleAllEntrances() == ENTRANCE_SHUFFLE_FAILURE) {
if (ctx->GetEntranceShuffler()->ShuffleAllEntrances() == ENTRANCE_SHUFFLE_FAILURE) {
retries++;
ClearProgress();
continue;
@@ -988,11 +991,11 @@ int Fill() {
//ctx->showItemProgress = true;
//Place shop items first, since a buy shield is needed to place a dungeon reward on Gohma due to access
NonShopItems = {};
if (Shopsanity.Is(SHOPSANITY_OFF)) {
if (ctx->GetOption(RSK_SHOPSANITY).Is(RO_SHOPSANITY_OFF)) {
PlaceVanillaShopItems(); //Place vanilla shop items in vanilla location
} else {
int total_replaced = 0;
if (Shopsanity.IsNot(SHOPSANITY_ZERO)) { //Shopsanity 1-4, random
if (ctx->GetOption(RSK_SHOPSANITY).IsNot(RO_SHOPSANITY_ZERO_ITEMS)) { //Shopsanity 1-4, random
//Initialize NonShopItems
ItemAndPrice init;
init.Name = Text{"No Item", "Sin objeto", "Pas d'objet"};
@@ -1010,7 +1013,7 @@ int Fill() {
int shopsanityPrice = GetRandomShopPrice();
NonShopItems[TransformShopIndex(i * 8 + itemindex - 1)].Price =
shopsanityPrice; // Set price to be retrieved by the patch and textboxes
ctx->GetItemLocation(Rando::StaticData::shopLocationLists[i][itemindex - 1])->SetShopsanityPrice(shopsanityPrice);
ctx->GetItemLocation(Rando::StaticData::shopLocationLists[i][itemindex - 1])->SetCustomPrice(shopsanityPrice);
}
}
}
@@ -1023,7 +1026,7 @@ int Fill() {
for (size_t i = 0; i < Rando::StaticData::shopLocationLists.size(); i++) {
for (size_t j = 0; j < Rando::StaticData::shopLocationLists[i].size(); j++) {
RandomizerCheck loc = Rando::StaticData::shopLocationLists[i][j];
if (!(ctx->GetItemLocation(loc)->HasShopsanityPrice())) {
if (!(ctx->GetItemLocation(loc)->HasCustomPrice())) {
shopLocations.push_back(loc);
}
}
@@ -1036,12 +1039,12 @@ int Fill() {
RandomizeDungeonRewards();
//Place dungeon items restricted to their Own Dungeon
for (auto dungeon : Dungeon::dungeonList) {
for (auto dungeon : ctx->GetDungeons()->GetDungeonList()) {
RandomizeOwnDungeon(dungeon);
}
//Then Place songs if song shuffle is set to specific locations
if (ShuffleSongs.IsNot(SONGSHUFFLE_ANYWHERE)) {
if (ctx->GetOption(RSK_SHUFFLE_SONGS).IsNot(RO_SONG_SHUFFLE_ANYWHERE)) {
//Get each song
std::vector<RandomizerGet> songs = FilterAndEraseFromPool(
@@ -1049,11 +1052,11 @@ int Fill() {
//Get each song location
std::vector<RandomizerCheck> songLocations;
if (ShuffleSongs.Is(SONGSHUFFLE_SONG_LOCATIONS)) {
if (ctx->GetOption(RSK_SHUFFLE_SONGS).Is(RO_SONG_SHUFFLE_SONG_LOCATIONS)) {
songLocations = FilterFromPool(
ctx->allLocations, [](const auto loc) { return Rando::StaticData::GetLocation(loc)->IsCategory(Category::cSong); });
} else if (ShuffleSongs.Is(SONGSHUFFLE_DUNGEON_REWARDS)) {
} else if (ctx->GetOption(RSK_SHUFFLE_SONGS).Is(RO_SONG_SHUFFLE_DUNGEON_REWARDS)) {
songLocations = FilterFromPool(ctx->allLocations, [](const auto loc) {
return Rando::StaticData::GetLocation(loc)->IsCategory(Category::cSongDungeonReward);
});
@@ -1077,14 +1080,14 @@ int Fill() {
FastFill(remainingPool, GetAllEmptyLocations(), false);
//Add prices for scrubsanity, this is unique to SoH because we write/read scrub prices to/from the spoilerfile.
if (Scrubsanity.Is(SCRUBSANITY_AFFORDABLE)) {
if (ctx->GetOption(RSK_SHUFFLE_SCRUBS).Is(RO_SCRUBS_AFFORDABLE)) {
for (size_t i = 0; i < Rando::StaticData::scrubLocations.size(); i++) {
ctx->GetItemLocation(Rando::StaticData::scrubLocations[i])->SetScrubsanityPrice(10);
ctx->GetItemLocation(Rando::StaticData::scrubLocations[i])->SetCustomPrice(10);
}
} else if (Scrubsanity.Is(SCRUBSANITY_RANDOM_PRICES)) {
} else if (ctx->GetOption(RSK_SHUFFLE_SCRUBS).Is(RO_SCRUBS_RANDOM)) {
for (size_t i = 0; i < Rando::StaticData::scrubLocations.size(); i++) {
int randomPrice = GetRandomScrubPrice();
ctx->GetItemLocation(Rando::StaticData::scrubLocations[i])->SetScrubsanityPrice(randomPrice);
ctx->GetItemLocation(Rando::StaticData::scrubLocations[i])->SetCustomPrice(randomPrice);
}
}
@@ -1097,8 +1100,8 @@ int Fill() {
CalculateWotH();
printf("Done");
ctx->CreateItemOverrides();
CreateEntranceOverrides();
ctx->GetEntranceShuffler()->CreateEntranceOverrides();
//funny ganon line
Text ganonText = RandomElement(GetHintCategory(HintCategory::GanonLine)).GetText();
CreateMessageFromTextObject(0x70CB, 0, 2, 3, AddColorsAndFormat(ganonText));

View File

@@ -2,6 +2,7 @@
#include "custom_messages.hpp"
#include "../randomizerTypes.h"
#include "../context.h"
#include <array>
@@ -3238,58 +3239,61 @@ void HintTable_Init() {
}
int32_t StonesRequiredBySettings() {
auto ctx = Rando::Context::GetInstance();
int32_t stones = 0;
if (Settings::Bridge.Is(RAINBOWBRIDGE_STONES)) {
stones = std::max<int32_t>({ stones, (int32_t)Settings::BridgeStoneCount.Value<uint8_t>() });
if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_STONES)) {
stones = std::max<int32_t>({ stones, (int32_t)ctx->GetOption(RSK_RAINBOW_BRIDGE_STONE_COUNT).Value<uint8_t>() });
}
if (Settings::Bridge.Is(RAINBOWBRIDGE_REWARDS)) {
stones = std::max<int32_t>({ stones, (int32_t)Settings::BridgeRewardCount.Value<uint8_t>() - 6 });
if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_DUNGEON_REWARDS)) {
stones = std::max<int32_t>({ stones, (int32_t)ctx->GetOption(RSK_RAINBOW_BRIDGE_REWARD_COUNT).Value<uint8_t>() - 6 });
}
if ((Settings::Bridge.Is(RAINBOWBRIDGE_DUNGEONS)) && (Settings::ShuffleRewards.Is(REWARDSHUFFLE_END_OF_DUNGEON))) {
stones = std::max<int32_t>({ stones, (int32_t)Settings::BridgeDungeonCount.Value<uint8_t>() - 6 });
if ((ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_DUNGEONS)) && (ctx->GetOption(RSK_SHUFFLE_DUNGEON_REWARDS).Is(RO_DUNGEON_REWARDS_END_OF_DUNGEON))) {
stones = std::max<int32_t>({ stones, (int32_t)ctx->GetOption(RSK_RAINBOW_BRIDGE_DUNGEON_COUNT).Value<uint8_t>() - 6 });
}
if (Settings::GanonsBossKey.Is(GANONSBOSSKEY_LACS_STONES)) {
stones = std::max<int32_t>({ stones, (int32_t)Settings::LACSStoneCount.Value<uint8_t>() });
if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_STONES)) {
stones = std::max<int32_t>({ stones, (int32_t)ctx->GetOption(RSK_LACS_STONE_COUNT).Value<uint8_t>() });
}
if (Settings::GanonsBossKey.Is(GANONSBOSSKEY_LACS_REWARDS)) {
stones = std::max<int32_t>({ stones, (int32_t)Settings::LACSRewardCount.Value<uint8_t>() - 6 });
if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_STONES)) {
stones = std::max<int32_t>({ stones, (int32_t)ctx->GetOption(RSK_LACS_REWARD_COUNT).Value<uint8_t>() - 6 });
}
if (Settings::GanonsBossKey.Is(GANONSBOSSKEY_LACS_DUNGEONS)) {
stones = std::max<int32_t>({ stones, (int32_t)Settings::LACSDungeonCount.Value<uint8_t>() - 6 });
if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_DUNGEONS)) {
stones = std::max<int32_t>({ stones, (int32_t)ctx->GetOption(RSK_LACS_DUNGEON_COUNT).Value<uint8_t>() - 6 });
}
return stones;
}
int32_t MedallionsRequiredBySettings() {
auto ctx = Rando::Context::GetInstance();
int32_t medallions = 0;
if (Settings::Bridge.Is(RAINBOWBRIDGE_MEDALLIONS)) {
medallions = std::max<int32_t>({ medallions, (int32_t)Settings::BridgeMedallionCount.Value<uint8_t>() });
if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_MEDALLIONS)) {
medallions = std::max<int32_t>({ medallions, (int32_t)ctx->GetOption(RSK_RAINBOW_BRIDGE_MEDALLION_COUNT).Value<uint8_t>() });
}
if (Settings::Bridge.Is(RAINBOWBRIDGE_REWARDS)) {
medallions = std::max<int32_t>({ medallions, (int32_t)Settings::BridgeRewardCount.Value<uint8_t>() - 3 });
if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_DUNGEON_REWARDS)) {
medallions = std::max<int32_t>({ medallions, (int32_t)ctx->GetOption(RSK_RAINBOW_BRIDGE_REWARD_COUNT).Value<uint8_t>() - 3 });
}
if ((Settings::Bridge.Is(RAINBOWBRIDGE_DUNGEONS)) && (Settings::ShuffleRewards.Is(REWARDSHUFFLE_END_OF_DUNGEON))) {
medallions = std::max<int32_t>({ medallions, (int32_t)Settings::BridgeDungeonCount.Value<uint8_t>() - 3 });
if ((ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_DUNGEONS)) && (ctx->GetOption(RSK_SHUFFLE_DUNGEON_REWARDS).Is(RO_DUNGEON_REWARDS_END_OF_DUNGEON))) {
medallions = std::max<int32_t>({ medallions, (int32_t)ctx->GetOption(RSK_RAINBOW_BRIDGE_DUNGEON_COUNT).Value<uint8_t>() - 3 });
}
if (Settings::GanonsBossKey.Is(GANONSBOSSKEY_LACS_MEDALLIONS)) {
medallions = std::max<int32_t>({ medallions, (int32_t)Settings::LACSMedallionCount.Value<uint8_t>() });
if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_MEDALLIONS)) {
medallions = std::max<int32_t>({ medallions, (int32_t)ctx->GetOption(RSK_LACS_MEDALLION_COUNT).Value<uint8_t>() });
}
if (Settings::GanonsBossKey.Is(GANONSBOSSKEY_LACS_REWARDS)) {
medallions = std::max<int32_t>({ medallions, (int32_t)Settings::LACSRewardCount.Value<uint8_t>() - 3 });
if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_REWARDS)) {
medallions = std::max<int32_t>({ medallions, (int32_t)ctx->GetOption(RSK_LACS_REWARD_COUNT).Value<uint8_t>() - 3 });
}
if (Settings::GanonsBossKey.Is(GANONSBOSSKEY_LACS_DUNGEONS)) {
medallions = std::max<int32_t>({ medallions, (int32_t)Settings::LACSDungeonCount.Value<uint8_t>() - 3 });
if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_DUNGEONS)) {
medallions = std::max<int32_t>({ medallions, (int32_t)ctx->GetOption(RSK_LACS_DUNGEON_COUNT).Value<uint8_t>() - 3 });
}
return medallions;
}
int32_t TokensRequiredBySettings() {
auto ctx = Rando::Context::GetInstance();
int32_t tokens = 0;
if (Settings::Bridge.Is(RAINBOWBRIDGE_TOKENS)) {
tokens = std::max<int32_t>({ tokens, (int32_t)Settings::BridgeTokenCount.Value<uint8_t>() });
if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_TOKENS)) {
tokens = std::max<int32_t>({ tokens, (int32_t)ctx->GetOption(RSK_RAINBOW_BRIDGE_TOKEN_COUNT).Value<uint8_t>() });
}
if (Settings::GanonsBossKey.Is(GANONSBOSSKEY_LACS_TOKENS)) {
tokens = std::max<int32_t>({ tokens, (int32_t)Settings::LACSTokenCount.Value<uint8_t>() });
if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_TOKENS)) {
tokens = std::max<int32_t>({ tokens, (int32_t)ctx->GetOption(RSK_LACS_TOKEN_COUNT).Value<uint8_t>() });
}
return tokens;
}
@@ -3297,17 +3301,38 @@ int32_t TokensRequiredBySettings() {
std::array<ConditionalAlwaysHint, 10> conditionalAlwaysHints = {
std::make_pair(RC_MARKET_10_BIG_POES,
[]() {
return Settings::BigPoeTargetCount.Value<uint8_t>() >= 3;
auto ctx = Rando::Context::GetInstance();
return ctx->GetOption(RSK_BIG_POE_COUNT).Value<uint8_t>() >= 3;
}), // Remember, the option's value being 3 means 4 are required
std::make_pair(RC_DEKU_THEATER_MASK_OF_TRUTH, []() { return !Settings::CompleteMaskQuest; }),
std::make_pair(RC_DEKU_THEATER_MASK_OF_TRUTH,
[]() {
auto ctx = Rando::Context::GetInstance();
return !ctx->GetOption(RSK_COMPLETE_MASK_QUEST);
}),
std::make_pair(RC_SONG_FROM_OCARINA_OF_TIME, []() { return StonesRequiredBySettings() < 2; }),
std::make_pair(RC_HF_OCARINA_OF_TIME_ITEM, []() { return StonesRequiredBySettings() < 2; }),
std::make_pair(RC_SHEIK_IN_KAKARIKO, []() { return MedallionsRequiredBySettings() < 5; }),
std::make_pair(RC_DMT_TRADE_CLAIM_CHECK, []() { return false; }),
std::make_pair(RC_KAK_30_GOLD_SKULLTULA_REWARD, []() { return TokensRequiredBySettings() < 30 && !Settings::Kak30GSHintText; }),
std::make_pair(RC_KAK_40_GOLD_SKULLTULA_REWARD, []() { return TokensRequiredBySettings() < 40 && !Settings::Kak40GSHintText; }),
std::make_pair(RC_KAK_50_GOLD_SKULLTULA_REWARD, []() { return TokensRequiredBySettings() < 50 && !Settings::Kak50GSHintText; }),
std::make_pair(RC_ZR_FROGS_OCARINA_GAME, []() { return !Settings::FrogsHintText; }),
std::make_pair(RC_KAK_30_GOLD_SKULLTULA_REWARD,
[]() {
auto ctx = Rando::Context::GetInstance();
return TokensRequiredBySettings() < 30 && !ctx->GetOption(RSK_KAK_30_SKULLS_HINT);
}),
std::make_pair(RC_KAK_40_GOLD_SKULLTULA_REWARD,
[]() {
auto ctx = Rando::Context::GetInstance();
return TokensRequiredBySettings() < 40 && !ctx->GetOption(RSK_KAK_40_SKULLS_HINT);
}),
std::make_pair(RC_KAK_50_GOLD_SKULLTULA_REWARD,
[]() {
auto ctx = Rando::Context::GetInstance();
return TokensRequiredBySettings() < 50 && !ctx->GetOption(RSK_KAK_50_SKULLS_HINT);
}),
std::make_pair(RC_ZR_FROGS_OCARINA_GAME,
[]() {
auto ctx = Rando::Context::GetInstance();
return !ctx->GetOption(RSK_FROGS_HINT);
}),
};
const HintText& Hint(const RandomizerHintTextKey hintKey) {

View File

@@ -1,24 +1,45 @@
#include "hints.hpp"
#include "custom_messages.hpp"
#include "dungeon.hpp"
#include "item_pool.hpp"
#include "logic.hpp"
#include "random.hpp"
#include "spoiler_log.hpp"
#include "fill.hpp"
#include "hint_list.hpp"
#include "trial.hpp"
#include "entrance.hpp"
#include "../trial.h"
#include "../entrance.h"
#include "z64item.h"
#include <spdlog/spdlog.h>
#include "../randomizerTypes.h"
#include "../context.h"
#include "pool_functions.hpp"
using namespace CustomMessages;
using namespace Logic;
using namespace Settings;
using namespace Trial;
using namespace Rando;
const Text& HintText::GetText() const {
auto ctx = Rando::Context::GetInstance();
if (ctx->GetOption(RSK_HINT_CLARITY).Is(RO_HINT_CLARITY_OBSCURE)) {
return GetObscure();
} else if (ctx->GetOption(RSK_HINT_CLARITY).Is(RO_HINT_CLARITY_AMBIGUOUS)) {
return GetAmbiguous();
} else {
return GetClear();
}
}
const Text HintText::GetTextCopy() const {
auto ctx = Rando::Context::GetInstance();
if (ctx->GetOption(RSK_HINT_CLARITY).Is(RO_HINT_CLARITY_OBSCURE)) {
return GetObscure();
} else if (ctx->GetOption(RSK_HINT_CLARITY).Is(RO_HINT_CLARITY_AMBIGUOUS)) {
return GetAmbiguous();
} else {
return GetClear();
}
}
std::array<std::string, HINT_TYPE_MAX> hintTypeNames = {
"Static",
@@ -126,6 +147,61 @@ constexpr std::array<HintSetting, 4> hintSettingTable{{
},
}};
Text AutoFormatHintText(Text unformattedHintText) {
std::array<std::string, LANGUAGE_MAX> strings;
for (int i = 0; i < LANGUAGE_MAX; i++) {
std::string textStr = unformattedHintText.GetForLanguage(i);
// RANDOTODO: don't just make manual exceptions
bool needsAutomaicNewlines = true;
if (textStr == "Erreur 0x69a504:&Traduction manquante^C'est de la faute à Purple Hato!&J'vous jure!" ||
textStr == "Mon très cher @:&Viens vite au château, je t'ai préparé&un délicieux gâteau...^À bientôt, Princesse Zelda" ||
textStr == "What about Zelda makes you think&she'd be a better ruler than I?^I saved Lon Lon Ranch,&fed the hungry,&and my castle floats." ||
textStr == "Many tricks are up my sleeve,&to save yourself&you'd better leave!" ||
textStr == "I've learned this spell,&it's really neat,&I'll keep it later&for your treat!" ||
textStr == "Sale petit garnement,&tu fais erreur!&C'est maintenant que marque&ta dernière heure!" ||
textStr == "Gamin, ton destin achève,&sous mon sort tu périras!&Cette partie ne fut pas brève,&et cette mort, tu subiras!" ||
textStr == "Oh! It's @.&I was expecting someone called Sheik.&Do you know what happened to them?" ||
textStr == "Ah, c'est @.&J'attendais un certain Sheik.&Tu sais ce qui lui est arrivé?" ||
textStr == "They say \"Forgive me, but-^Your script will not be used.&....After all...^The one writing the rest of the script...&will be me.\"") {
needsAutomaicNewlines = false;
}
if (needsAutomaicNewlines) {
// insert newlines either manually or when encountering a '&'
constexpr size_t lineLength = 34;
size_t lastNewline = 0;
while (lastNewline + lineLength < textStr.length()) {
size_t carrot = textStr.find('^', lastNewline);
size_t ampersand = textStr.find('&', lastNewline);
size_t lastSpace = textStr.rfind(' ', lastNewline + lineLength);
size_t lastPeriod = textStr.rfind('.', lastNewline + lineLength);
// replace '&' first if it's within the newline range
if (ampersand < lastNewline + lineLength) {
lastNewline = ampersand;
// or move the lastNewline cursor to the next line if a '^' is encountered
} else if (carrot < lastNewline + lineLength) {
lastNewline = carrot + 1;
// some lines need to be split but don't have spaces, look for periods instead
} else if (lastSpace == std::string::npos) {
textStr.replace(lastPeriod, 1, ".&");
lastNewline = lastPeriod + 2;
} else {
textStr.replace(lastSpace, 1, "&");
lastNewline = lastSpace + 1;
}
}
}
// todo add colors (see `AddColorsAndFormat` in `custom_messages.cpp`)
textStr.erase(std::remove(textStr.begin(), textStr.end(), '#'), textStr.end());
strings[i] = textStr;
}
return Text(strings[0], strings[1], strings[2]);
}
std::array<DungeonHintInfo, 10> dungeonInfoData;
Text childAltarText;
Text adultAltarText;
Text ganonText;
@@ -328,7 +404,7 @@ static void AddHint(Text hint, const RandomizerCheck gossipStone, const std::vec
//GetLocation(gossipStone)->SetPlacedItem(gossipStone);
auto ctx = Rando::Context::GetInstance();
ctx->AddHint((RandomizerHintKey)((gossipStone - RC_DMC_GOSSIP_STONE) + 1), hint, hintedLocation, hintType, GetHintRegion(ctx->GetItemLocation(hintedLocation)->GetParentRegionKey())->GetHint().GetText());
ctx->AddHint((RandomizerHintKey)((gossipStone - RC_COLOSSUS_GOSSIP_STONE) + 1), AutoFormatHintText(hint), hintedLocation, hintType, GetHintRegion(ctx->GetItemLocation(hintedLocation)->GetParentRegionKey())->GetHint().GetText());
ctx->GetItemLocation(gossipStone)->SetPlacedItem(RG_HINT);
}
@@ -366,31 +442,31 @@ static bool CreateHint(RandomizerCheck hintedLocation, uint8_t copies, HintType
//make hint text
Text finalHint;
Text prefix = Hint(RHT_PREFIX).GetText();
Text prefix = ::Hint(RHT_PREFIX).GetText();
std::vector<uint8_t> colours = {QM_GREEN, QM_RED};
if (type == HINT_TYPE_WOTH){
Text regionText = GetHintRegion(ctx->GetItemLocation(hintedLocation)->GetParentRegionKey())->GetHint().GetText();
finalHint = prefix + "%r#" + regionText + "#%w" + Hint(RHT_WAY_OF_THE_HERO).GetText();
finalHint = prefix + "%r#" + regionText + "#%w" + ::Hint(RHT_WAY_OF_THE_HERO).GetText();
colours = {QM_LBLUE};
}
else if(type == HINT_TYPE_BARREN){
Text regionText = GetHintRegion(ctx->GetItemLocation(hintedLocation)->GetParentRegionKey())->GetHint().GetText();
finalHint = prefix + Hint(RHT_PLUNDERING).GetText() + "%r#" + regionText + "#%w" + Hint(RHT_FOOLISH).GetText();
finalHint = prefix + ::Hint(RHT_PLUNDERING).GetText() + "%r#" + regionText + "#%w" + ::Hint(RHT_FOOLISH).GetText();
colours = {QM_PINK};
}
else {
Text itemText = ctx->GetItemLocation(hintedLocation)->GetPlacedItem().GetHint().GetText();
if (type >= HINT_TYPE_ALWAYS && type < HINT_TYPE_NAMED_ITEM){
Text locationText = Rando::StaticData::GetLocation(hintedLocation)->GetHint()->GetText();
finalHint = prefix + locationText + " #"+itemText+"#.";
finalHint = prefix + "%r" + locationText + " %g#"+itemText+"#%w.";
}
else if (type == HINT_TYPE_NAMED_ITEM || type == HINT_TYPE_RANDOM){
Text regionText = GetHintRegion(ctx->GetItemLocation(hintedLocation)->GetParentRegionKey())->GetHint().GetText();
// RANDOTODO: reconsider dungeon vs non-dungeon item location hints when boss shuffle mixed pools happens
if (Rando::StaticData::GetLocation(hintedLocation)->IsDungeon()) {
finalHint = prefix+"%r#"+regionText+"#%w "+Hint(RHT_HOARDS).GetText()+" %g#"+itemText+"#%w.";
finalHint = prefix+"%r#"+regionText+"#%w "+::Hint(RHT_HOARDS).GetText()+" %g#"+itemText+"#%w.";
} else {
finalHint = prefix+"%r#"+itemText+"#%w "+Hint(RHT_CAN_BE_FOUND_AT).GetText()+" %g#"+regionText+"#%w.";
finalHint = prefix+"%r#"+itemText+"#%w "+::Hint(RHT_CAN_BE_FOUND_AT).GetText()+" %g#"+regionText+"#%w.";
colours = {QM_RED, QM_GREEN};
}
}
@@ -500,37 +576,40 @@ static std::vector<RandomizerCheck> CalculateBarrenRegions() {
}
static void CreateTrialHints(uint8_t copies) {
Text prefix = Hint(RHT_PREFIX).GetText();
auto ctx = Rando::Context::GetInstance();
Text prefix = ::Hint(RHT_PREFIX).GetText();
//six trials
if (RandomGanonsTrials && GanonsTrialsCount.Is(6)) {
AddHintCopies(copies, prefix + Hint(RHT_SIX_TRIALS).GetText(), {QM_PINK}, HINT_TYPE_TRIAL);
if (ctx->GetOption(RSK_GANONS_TRIALS).IsNot(RO_GANONS_TRIALS_SKIP) && ctx->GetOption(RSK_TRIAL_COUNT).Is(6)) {
AddHintCopies(copies, prefix + ::Hint(RHT_SIX_TRIALS).GetText(), {QM_PINK}, HINT_TYPE_TRIAL);
//zero trials
} else if (RandomGanonsTrials && GanonsTrialsCount.Is(0)) {
AddHintCopies(copies, prefix + Hint(RHT_ZERO_TRIALS).GetText(), {QM_YELLOW}, HINT_TYPE_TRIAL);
} else if (ctx->GetOption(RSK_GANONS_TRIALS).IsNot(RO_GANONS_TRIALS_SKIP) && ctx->GetOption(RSK_TRIAL_COUNT).Is(0)) {
AddHintCopies(copies, prefix + ::Hint(RHT_ZERO_TRIALS).GetText(), {QM_YELLOW}, HINT_TYPE_TRIAL);
//4 or 5 required trials
} else if (GanonsTrialsCount.Is(5) || GanonsTrialsCount.Is(4)) {
} else if (ctx->GetOption(RSK_TRIAL_COUNT).Is(5) || ctx->GetOption(RSK_TRIAL_COUNT).Is(4)) {
//get skipped trials
std::vector<TrialInfo*> trials = {};
auto trialList = ctx->GetTrials()->GetTrialList();
trials.assign(trialList.begin(), trialList.end());
auto skippedTrials = FilterFromPool(trials, [](TrialInfo* trial){return trial->IsSkipped();});
//create a hint for each skipped trial
for (auto& trial : skippedTrials) {
//make hint
auto hint = prefix+"#"+trial->GetName()+"#"+Hint(RHT_FOUR_TO_FIVE_TRIALS).GetText();
auto hint = prefix+"#"+trial->GetName()+"#"+::Hint(RHT_FOUR_TO_FIVE_TRIALS).GetText();
AddHintCopies(copies, hint, {QM_YELLOW}, HINT_TYPE_TRIAL);
}
//1 to 3 trials
} else if (GanonsTrialsCount.Value<uint8_t>() >= 1 && GanonsTrialsCount.Value<uint8_t>() <= 3) {
} else if (ctx->GetOption(RSK_TRIAL_COUNT).Value<uint8_t>() >= 1 && ctx->GetOption(RSK_TRIAL_COUNT).Value<uint8_t>() <= 3) {
//get requried trials
std::vector<TrialInfo*> trials = {};
auto trialList = ctx->GetTrials()->GetTrialList();
trials.assign(trialList.begin(), trialList.end());
auto requiredTrials = FilterFromPool(trials, [](TrialInfo* trial){return trial->IsRequired();});
//create a hint for each required trial
for (auto& trial : requiredTrials) {
//make hint
auto hint = prefix+"#"+trial->GetName()+"#"+Hint(RHT_ONE_TO_THREE_TRIALS).GetText();
auto hint = prefix+"#"+trial->GetName()+"#"+::Hint(RHT_ONE_TO_THREE_TRIALS).GetText();
AddHintCopies(copies, hint, {QM_PINK}, HINT_TYPE_TRIAL);
}
}
@@ -539,7 +618,7 @@ static void CreateTrialHints(uint8_t copies) {
//RANDOTODO clean this mess up once starting items are expanded
void CreateGanonAndSheikText() {
auto ctx = Rando::Context::GetInstance();
if(Settings::LightArrowHintText){
if(ctx->GetOption(RSK_LIGHT_ARROWS_HINT)){
//Get the location of the light arrows
auto lightArrowLocation = FilterFromPool(ctx->allLocations, [ctx](const RandomizerCheck loc) {
return ctx->GetItemLocation(loc)->GetPlacedRandomizerGet() == RG_LIGHT_ARROWS;
@@ -548,9 +627,9 @@ void CreateGanonAndSheikText() {
std::vector<RandomizerCheck> locsToCheck = {RC_GANONDORF_HINT};
//If there is no light arrow location, it was in the player's inventory at the start
auto hint = Hint(RHT_LIGHT_ARROW_LOCATION_HINT);
auto hint = ::Hint(RHT_LIGHT_ARROW_LOCATION_HINT);
if (lightArrowLocation.empty()) {
ganonHintText = hint.GetText()+Hint(RHT_YOUR_POCKET).GetText();
ganonHintText = hint.GetText()+::Hint(RHT_YOUR_POCKET).GetText();
lightArrowHintLoc = "Link's Pocket";
} else {
ganonHintText = hint.GetText() + "%r" + lightArrowArea + "%w";
@@ -564,36 +643,37 @@ void CreateGanonAndSheikText() {
});
Text masterSwordArea = GetHintRegion(ctx->GetItemLocation(masterSwordLocation[0])->GetParentRegionKey())->GetHint().GetText();
if (ShuffleMasterSword) {
if (ctx->GetOption(RSK_SHUFFLE_MASTER_SWORD)) {
// Add second text box
ganonHintText = ganonHintText + "^";
if (masterSwordLocation.empty()) {
ganonHintText = ganonHintText + Hint(RHT_MASTER_SWORD_LOCATION_HINT).GetText() + "%r" + Hint(RHT_YOUR_POCKET).GetText() + "%w";
ganonHintText = ganonHintText + ::Hint(RHT_MASTER_SWORD_LOCATION_HINT).GetText() + "%r" + ::Hint(RHT_YOUR_POCKET).GetText() + "%w";
masterSwordHintLoc = "Link's Pocket";
} else {
ganonHintText = ganonHintText + Hint(RHT_MASTER_SWORD_LOCATION_HINT).GetText() + "%r" + masterSwordArea + "%w";
ganonHintText = ganonHintText + ::Hint(RHT_MASTER_SWORD_LOCATION_HINT).GetText() + "%r" + masterSwordArea + "%w";
masterSwordHintLoc = Rando::StaticData::GetLocation(masterSwordLocation[0])->GetName();
}
ganonHintText = ganonHintText + "!";
}
CreateMessageFromTextObject(0x70CC, 0, 2, 3, AddColorsAndFormat(ganonHintText));
ctx->AddHint(RH_GANONDORF_HINT, ganonHintText, lightArrowLocation[0], HINT_TYPE_STATIC, GetHintRegion(ctx->GetItemLocation(lightArrowLocation[0])->GetParentRegionKey())->GetHint().GetText());
//CreateMessageFromTextObject(0x70CC, 0, 2, 3, AddColorsAndFormat(ganonHintText));
ctx->AddHint(RH_GANONDORF_HINT, AutoFormatHintText(ganonHintText), lightArrowLocation[0], HINT_TYPE_STATIC, GetHintRegion(ctx->GetItemLocation(lightArrowLocation[0])->GetParentRegionKey())->GetHint().GetText());
if (!Settings::GanonsTrialsCount.Is(0)) {
sheikText = Hint(RHT_SHEIK_LIGHT_ARROW_HINT).GetText() + lightArrowArea + "%w.";
if(!ctx->GetOption(RSK_TRIAL_COUNT).Is(0)){
sheikText = ::Hint(RHT_SHEIK_LIGHT_ARROW_HINT).GetText() + lightArrowArea + "%w.";
locsToCheck = {RC_GANONDORF_HINT, RC_SHEIK_HINT_GC, RC_SHEIK_HINT_MQ_GC};
if (ShuffleMasterSword) {
sheikText = sheikText + "^" + Hint(RHT_SHEIK_MASTER_SWORD_LOCATION_HINT).GetText() + masterSwordArea + "%w.";
if (ctx->GetOption(RSK_SHUFFLE_MASTER_SWORD)) {
sheikText = sheikText + "^" + ::Hint(RHT_SHEIK_MASTER_SWORD_LOCATION_HINT).GetText() + masterSwordArea + "%w.";
}
}
if (IsReachableWithout(locsToCheck, lightArrowLocation[0], true)) {
ctx->GetItemLocation(lightArrowLocation[0])->SetAsHinted();
}
ctx->AddHint(RH_SHEIK_LIGHT_ARROWS, AutoFormatHintText(sheikText), lightArrowLocation[0], HINT_TYPE_STATIC, lightArrowArea);
if (ShuffleMasterSword) {
if (ctx->GetOption(RSK_SHUFFLE_MASTER_SWORD)) {
if (IsReachableWithout(locsToCheck, masterSwordLocation[0], true)) {
ctx->GetItemLocation(masterSwordLocation[0])->SetHintKey(RH_GANONDORF_HINT);
ctx->GetItemLocation(masterSwordLocation[0])->SetAsHinted();
@@ -610,7 +690,7 @@ static Text BuildDungeonRewardText(const RandomizerGet itemKey, bool isChild) {
RandomizerCheck location = FilterFromPool(ctx->allLocations, [itemKey, ctx](const RandomizerCheck loc) {
return ctx->GetItemLocation(loc)->GetPlacedRandomizerGet() == itemKey;
})[0];
if (IsReachableWithout({altarLoc}, location, true) || ShuffleRewards.Is(REWARDSHUFFLE_END_OF_DUNGEON)){ //RANDOTODO check if works properly
if (IsReachableWithout({altarLoc}, location, true) || ctx->GetOption(RSK_SHUFFLE_DUNGEON_REWARDS).Is(RO_DUNGEON_REWARDS_END_OF_DUNGEON)){ //RANDOTODO check if works properly
ctx->GetItemLocation(location)->SetAsHinted();
}
@@ -623,28 +703,29 @@ static Text BuildDungeonRewardText(const RandomizerGet itemKey, bool isChild) {
}
static Text BuildDoorOfTimeText() {
auto ctx = Rando::Context::GetInstance();
std::string itemObtained;
Text doorOfTimeText;
if (OpenDoorOfTime.Is(OPENDOOROFTIME_OPEN)) {
if (ctx->GetOption(RSK_DOOR_OF_TIME).Is(RO_DOOROFTIME_OPEN)) {
itemObtained = "$o";
doorOfTimeText = Hint(RHT_CHILD_ALTAR_TEXT_END_DOTOPEN).GetText();
doorOfTimeText = ::Hint(RHT_CHILD_ALTAR_TEXT_END_DOTOPEN).GetText();
} else if (OpenDoorOfTime.Is(OPENDOOROFTIME_SONGONLY)) {
} else if (ctx->GetOption(RSK_DOOR_OF_TIME).Is(RO_DOOROFTIME_SONGONLY)) {
itemObtained = "$c";
doorOfTimeText = Hint(RHT_CHILD_ALTAR_TEXT_END_DOTSONGONLY).GetText();
doorOfTimeText = ::Hint(RHT_CHILD_ALTAR_TEXT_END_DOTSONGONLY).GetText();
} else if (OpenDoorOfTime.Is(OPENDOOROFTIME_CLOSED)) {
} else if (ctx->GetOption(RSK_DOOR_OF_TIME).Is(RO_DOOROFTIME_CLOSED)) {
itemObtained = "$i";
doorOfTimeText = Hint(RHT_CHILD_ALTAR_TEXT_END_DOTCLOSED).GetText();
doorOfTimeText = ::Hint(RHT_CHILD_ALTAR_TEXT_END_DOTCLOSED).GetText();
}
return Text()+itemObtained+doorOfTimeText;
}
//insert the required number into the hint and set the singular/plural form
static Text BuildCountReq(const RandomizerHintTextKey req, const Option& count) {
Text requirement = Hint(req).GetTextCopy();
static Text BuildCountReq(const RandomizerHintTextKey req, const Rando::Option& count) {
Text requirement = ::Hint(req).GetTextCopy();
if (count.Value<uint8_t>() == 1) {
requirement.SetForm(SINGULAR);
} else {
@@ -655,80 +736,82 @@ static Text BuildCountReq(const RandomizerHintTextKey req, const Option& count)
}
static Text BuildBridgeReqsText() {
auto ctx = Rando::Context::GetInstance();
Text bridgeText;
if (Bridge.Is(RAINBOWBRIDGE_OPEN)) {
bridgeText = Hint(RHT_BRIDGE_OPEN_HINT).GetText();
if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_ALWAYS_OPEN)) {
bridgeText = ::Hint(RHT_BRIDGE_OPEN_HINT).GetText();
} else if (Bridge.Is(RAINBOWBRIDGE_VANILLA)) {
bridgeText = Hint(RHT_BRIDGE_VANILLA_HINT).GetText();
} else if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_VANILLA)) {
bridgeText = ::Hint(RHT_BRIDGE_VANILLA_HINT).GetText();
} else if (Bridge.Is(RAINBOWBRIDGE_STONES)) {
bridgeText = BuildCountReq(RHT_BRIDGE_STONES_HINT, BridgeStoneCount);
} else if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_STONES)) {
bridgeText = BuildCountReq(RHT_BRIDGE_STONES_HINT, ctx->GetOption(RSK_RAINBOW_BRIDGE_STONE_COUNT));
} else if (Bridge.Is(RAINBOWBRIDGE_MEDALLIONS)) {
bridgeText = BuildCountReq(RHT_BRIDGE_MEDALLIONS_HINT, BridgeMedallionCount);
} else if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_MEDALLIONS)) {
bridgeText = BuildCountReq(RHT_BRIDGE_MEDALLIONS_HINT, ctx->GetOption(RSK_RAINBOW_BRIDGE_MEDALLION_COUNT));
} else if (Bridge.Is(RAINBOWBRIDGE_REWARDS)) {
bridgeText = BuildCountReq(RHT_BRIDGE_REWARDS_HINT, BridgeRewardCount);
} else if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_DUNGEON_REWARDS)) {
bridgeText = BuildCountReq(RHT_BRIDGE_REWARDS_HINT, ctx->GetOption(RSK_RAINBOW_BRIDGE_REWARD_COUNT));
} else if (Bridge.Is(RAINBOWBRIDGE_DUNGEONS)) {
bridgeText = BuildCountReq(RHT_BRIDGE_DUNGEONS_HINT, BridgeDungeonCount);
} else if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_DUNGEONS)) {
bridgeText = BuildCountReq(RHT_BRIDGE_DUNGEONS_HINT, ctx->GetOption(RSK_RAINBOW_BRIDGE_DUNGEON_COUNT));
} else if (Bridge.Is(RAINBOWBRIDGE_TOKENS)) {
bridgeText = BuildCountReq(RHT_BRIDGE_TOKENS_HINT, BridgeTokenCount);
} else if (Bridge.Is(RAINBOWBRIDGE_GREG)) {
bridgeText = Hint(RHT_BRIDGE_GREG_HINT).GetText();
} else if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_TOKENS)) {
bridgeText = BuildCountReq(RHT_BRIDGE_TOKENS_HINT, ctx->GetOption(RSK_RAINBOW_BRIDGE_TOKEN_COUNT));
} else if (ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_GREG)) {
bridgeText = ::Hint(RHT_BRIDGE_GREG_HINT).GetText();
}
return Text()+"$l"+bridgeText+"^";
}
static Text BuildGanonBossKeyText() {
auto ctx = Rando::Context::GetInstance();
Text ganonBossKeyText;
if (GanonsBossKey.Is(GANONSBOSSKEY_START_WITH)) {
ganonBossKeyText = Hint(RHT_GANON_BK_START_WITH_HINT).GetText();
if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_STARTWITH)) {
ganonBossKeyText = ::Hint(RHT_GANON_BK_START_WITH_HINT).GetText();
} else if (GanonsBossKey.Is(GANONSBOSSKEY_VANILLA)) {
ganonBossKeyText = Hint(RHT_GANON_BK_VANILLA_HINT).GetText();
} else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_VANILLA)) {
ganonBossKeyText = ::Hint(RHT_GANON_BK_VANILLA_HINT).GetText();
} else if (GanonsBossKey.Is(GANONSBOSSKEY_OWN_DUNGEON)) {
ganonBossKeyText = Hint(RHT_GANON_BK_OWN_DUNGEON_HINT).GetText();
} else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_OWN_DUNGEON)) {
ganonBossKeyText = ::Hint(RHT_GANON_BK_OWN_DUNGEON_HINT).GetText();
} else if (GanonsBossKey.Is(GANONSBOSSKEY_ANY_DUNGEON)) {
ganonBossKeyText = Hint(RHT_GANON_BK_ANY_DUNGEON_HINT).GetText();
} else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_ANY_DUNGEON)) {
ganonBossKeyText = ::Hint(RHT_GANON_BK_ANY_DUNGEON_HINT).GetText();
} else if (GanonsBossKey.Is(GANONSBOSSKEY_OVERWORLD)) {
ganonBossKeyText = Hint(RHT_GANON_BK_OVERWORLD_HINT).GetText();
} else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_OVERWORLD)) {
ganonBossKeyText = ::Hint(RHT_GANON_BK_OVERWORLD_HINT).GetText();
} else if (GanonsBossKey.Is(GANONSBOSSKEY_ANYWHERE)) {
ganonBossKeyText = Hint(RHT_GANON_BK_ANYWHERE_HINT).GetText();
} else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_ANYWHERE)) {
ganonBossKeyText = ::Hint(RHT_GANON_BK_ANYWHERE_HINT).GetText();
} else if (GanonsBossKey.Is(GANONSBOSSKEY_FINAL_GS_REWARD)) {
ganonBossKeyText = Hint(RHT_GANON_BK_SKULLTULA_HINT).GetText();
} else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_KAK_TOKENS)) {
ganonBossKeyText = ::Hint(RHT_GANON_BK_SKULLTULA_HINT).GetText();
} else if (GanonsBossKey.Is(GANONSBOSSKEY_LACS_VANILLA)) {
ganonBossKeyText = Hint(RHT_LACS_VANILLA_HINT).GetText();
} else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_VANILLA)) {
ganonBossKeyText = ::Hint(RHT_LACS_VANILLA_HINT).GetText();
} else if (GanonsBossKey.Is(GANONSBOSSKEY_LACS_STONES)) {
ganonBossKeyText = BuildCountReq(RHT_LACS_STONES_HINT, LACSStoneCount);
} else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_STONES)) {
ganonBossKeyText = BuildCountReq(RHT_LACS_STONES_HINT, ctx->GetOption(RSK_LACS_STONE_COUNT));
} else if (GanonsBossKey.Is(GANONSBOSSKEY_LACS_MEDALLIONS)) {
ganonBossKeyText = BuildCountReq(RHT_LACS_MEDALLIONS_HINT, LACSMedallionCount);
} else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_MEDALLIONS)) {
ganonBossKeyText = BuildCountReq(RHT_LACS_MEDALLIONS_HINT, ctx->GetOption(RSK_LACS_MEDALLION_COUNT));
} else if (GanonsBossKey.Is(GANONSBOSSKEY_LACS_REWARDS)) {
ganonBossKeyText = BuildCountReq(RHT_LACS_REWARDS_HINT, LACSRewardCount);
} else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_REWARDS)) {
ganonBossKeyText = BuildCountReq(RHT_LACS_REWARDS_HINT, ctx->GetOption(RSK_LACS_REWARD_COUNT));
} else if (GanonsBossKey.Is(GANONSBOSSKEY_LACS_DUNGEONS)) {
ganonBossKeyText = BuildCountReq(RHT_LACS_DUNGEONS_HINT, LACSDungeonCount);
} else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_DUNGEONS)) {
ganonBossKeyText = BuildCountReq(RHT_LACS_DUNGEONS_HINT, ctx->GetOption(RSK_LACS_DUNGEON_COUNT));
} else if (GanonsBossKey.Is(GANONSBOSSKEY_LACS_TOKENS)) {
ganonBossKeyText = BuildCountReq(RHT_LACS_TOKENS_HINT, LACSTokenCount);
} else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_LACS_TOKENS)) {
ganonBossKeyText = BuildCountReq(RHT_LACS_TOKENS_HINT, ctx->GetOption(RSK_LACS_TOKEN_COUNT));
} else if (GanonsBossKey.Is(GANONSBOSSKEY_TRIFORCE_HUNT)) {
ganonBossKeyText = Hint(RHT_GANON_BK_TRIFORCE_HINT).GetText();
} else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_TRIFORCE_HUNT)) {
ganonBossKeyText = ::Hint(RHT_GANON_BK_TRIFORCE_HINT).GetText();
}
return Text()+"$b"+ganonBossKeyText+"^";
@@ -738,14 +821,15 @@ void CreateAltarText() {
auto ctx = Rando::Context::GetInstance();
//Child Altar Text
if (AltarHintText) {
childAltarText = Hint(RHT_SPIRITUAL_STONE_TEXT_START).GetText()+"^"+
if (ctx->GetOption(RSK_TOT_ALTAR_HINT)) {
childAltarText = ::Hint(RHT_SPIRITUAL_STONE_TEXT_START).GetText()+"^"+
//Spiritual Stones
(StartingKokiriEmerald.Value<uint8_t>() ? Text{ "##", "##", "##" }
// TODO: Starting Inventory Dungeon Rewards
(/*StartingKokiriEmerald.Value<uint8_t>()*/false ? Text{ "##", "##", "##" }
: BuildDungeonRewardText(RG_KOKIRI_EMERALD, true)) +
(StartingGoronRuby.Value<uint8_t>() ? Text{ "##", "##", "##" }
(/*StartingGoronRuby.Value<uint8_t>()*/false ? Text{ "##", "##", "##" }
: BuildDungeonRewardText(RG_GORON_RUBY, true)) +
(StartingZoraSapphire.Value<uint8_t>() ? Text{ "##", "##", "##" }
(/*StartingZoraSapphire.Value<uint8_t>()*/false ? Text{ "##", "##", "##" }
: BuildDungeonRewardText(RG_ZORA_SAPPHIRE, true)) +
//How to open Door of Time, the event trigger is necessary to read the altar multiple times
BuildDoorOfTimeText();
@@ -754,24 +838,24 @@ void CreateAltarText() {
}
ctx->AddHint(RH_ALTAR_CHILD, childAltarText, RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, Text());
CreateMessageFromTextObject(0x7040, 0, 2, 3, AddColorsAndFormat(childAltarText, {QM_GREEN, QM_RED, QM_BLUE}));
//CreateMessageFromTextObject(0x7040, 0, 2, 3, AddColorsAndFormat(childAltarText, {QM_GREEN, QM_RED, QM_BLUE}));
//Adult Altar Text
adultAltarText = Hint(RHT_ADULT_ALTAR_TEXT_START).GetText() + "^";
if (AltarHintText) {
adultAltarText = ::Hint(RHT_ADULT_ALTAR_TEXT_START).GetText() + "^";
if (ctx->GetOption(RSK_TOT_ALTAR_HINT)) {
adultAltarText = adultAltarText +
//Medallion Areas
(StartingLightMedallion.Value<uint8_t>() ? Text{ "##", "##", "##" }
(/*StartingLightMedallion.Value<uint8_t>()*/false ? Text{ "##", "##", "##" }
: BuildDungeonRewardText(RG_LIGHT_MEDALLION, false)) +
(StartingForestMedallion.Value<uint8_t>() ? Text{ "##", "##", "##" }
(/*StartingForestMedallion.Value<uint8_t>()*/false ? Text{ "##", "##", "##" }
: BuildDungeonRewardText(RG_FOREST_MEDALLION, false)) +
(StartingFireMedallion.Value<uint8_t>() ? Text{ "##", "##", "##" }
(/*StartingFireMedallion.Value<uint8_t>()*/false ? Text{ "##", "##", "##" }
: BuildDungeonRewardText(RG_FIRE_MEDALLION, false)) +
(StartingWaterMedallion.Value<uint8_t>() ? Text{ "##", "##", "##" }
(/*StartingWaterMedallion.Value<uint8_t>()*/false ? Text{ "##", "##", "##" }
: BuildDungeonRewardText(RG_WATER_MEDALLION, false)) +
(StartingSpiritMedallion.Value<uint8_t>() ? Text{ "##", "##", "##" }
(/*StartingSpiritMedallion.Value<uint8_t>()*/false ? Text{ "##", "##", "##" }
: BuildDungeonRewardText(RG_SPIRIT_MEDALLION, false)) +
(StartingShadowMedallion.Value<uint8_t>() ? Text{ "##", "##", "##" }
(/*StartingShadowMedallion.Value<uint8_t>()*/false ? Text{ "##", "##", "##" }
: BuildDungeonRewardText(RG_SHADOW_MEDALLION, false));
}
adultAltarText = adultAltarText +
@@ -782,8 +866,8 @@ void CreateAltarText() {
BuildGanonBossKeyText()+
//End
Hint(RHT_ADULT_ALTAR_TEXT_END).GetText();
CreateMessageFromTextObject(0x7088, 0, 2, 3, AddColorsAndFormat(adultAltarText, {QM_RED, QM_YELLOW, QM_GREEN, QM_RED, QM_BLUE, QM_YELLOW, QM_PINK, QM_RED, QM_RED, QM_RED, QM_RED}));
::Hint(RHT_ADULT_ALTAR_TEXT_END).GetText();
//CreateMessageFromTextObject(0x7088, 0, 2, 3, AddColorsAndFormat(adultAltarText, {QM_RED, QM_YELLOW, QM_GREEN, QM_RED, QM_BLUE, QM_YELLOW, QM_PINK, QM_RED, QM_RED, QM_RED, QM_RED}));
ctx->AddHint(RH_ALTAR_ADULT, adultAltarText, RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, Text());
}
@@ -798,25 +882,25 @@ void CreateMerchantsHints() {
Text medigoronText =
Hint(RHT_MEDIGORON_DIALOG_FIRST).GetText() + medigoronItemText + Hint(RHT_MEDIGORON_DIALOG_SECOND).GetText();
Text grannyText = grannyItemText + Hint(RHT_GRANNY_DIALOG).GetText();
Text carpetSalesmanTextOne = Hint(RHT_CARPET_SALESMAN_DIALOG_FIRST).GetText() + carpetSalesmanItemText +
Hint(RHT_CARPET_SALESMAN_DIALOG_SECOND).GetText();
Text carpetSalesmanTextTwo = Hint(RHT_CARPET_SALESMAN_DIALOG_THIRD).GetText() + carpetSalesmanItemClearText +
Hint(RHT_CARPET_SALESMAN_DIALOG_FOURTH).GetText();
::Hint(RHT_MEDIGORON_DIALOG_FIRST).GetText() + medigoronItemText + ::Hint(RHT_MEDIGORON_DIALOG_SECOND).GetText();
Text grannyText = grannyItemText + ::Hint(RHT_GRANNY_DIALOG).GetText();
Text carpetSalesmanTextOne = ::Hint(RHT_CARPET_SALESMAN_DIALOG_FIRST).GetText() + carpetSalesmanItemText +
::Hint(RHT_CARPET_SALESMAN_DIALOG_SECOND).GetText();
Text carpetSalesmanTextTwo = ::Hint(RHT_CARPET_SALESMAN_DIALOG_THIRD).GetText() + carpetSalesmanItemClearText +
::Hint(RHT_CARPET_SALESMAN_DIALOG_FOURTH).GetText();
CreateMessageFromTextObject(0x9120, 0, 2, 3, AddColorsAndFormat(medigoronText, { QM_RED, QM_GREEN }));
CreateMessageFromTextObject(0x9121, 0, 2, 3, AddColorsAndFormat(grannyText, { QM_RED, QM_GREEN }));
CreateMessageFromTextObject(0x6077, 0, 2, 3, AddColorsAndFormat(carpetSalesmanTextOne, { QM_RED, QM_GREEN }));
CreateMessageFromTextObject(0x6078, 0, 2, 3,
AddColorsAndFormat(carpetSalesmanTextTwo, { QM_RED, QM_YELLOW, QM_RED }));
ctx->AddHint(RH_MEDIGORON, medigoronText, RC_GC_MEDIGORON, HINT_TYPE_STATIC, GetHintRegion(RR_GORON_CITY)->GetHint().GetText());
ctx->AddHint(RH_GRANNYS_SHOP, grannyText, RC_KAK_GRANNYS_SHOP, HINT_TYPE_STATIC, GetHintRegion(RR_KAKARIKO_VILLAGE)->GetHint().GetText());
ctx->AddHint(RH_WASTELAND_BOMBCHU_SALESMAN, carpetSalesmanTextOne, RC_WASTELAND_BOMBCHU_SALESMAN, HINT_TYPE_STATIC, GetHintRegion(RR_HAUNTED_WASTELAND)->GetHint().GetText());
// CreateMessageFromTextObject(0x9120, 0, 2, 3, AddColorsAndFormat(medigoronText, { QM_RED, QM_GREEN }));
// CreateMessageFromTextObject(0x9121, 0, 2, 3, AddColorsAndFormat(grannyText, { QM_RED, QM_GREEN }));
// CreateMessageFromTextObject(0x6077, 0, 2, 3, AddColorsAndFormat(carpetSalesmanTextOne, { QM_RED, QM_GREEN }));
// CreateMessageFromTextObject(0x6078, 0, 2, 3,
// AddColorsAndFormat(carpetSalesmanTextTwo, { QM_RED, QM_YELLOW, QM_RED }));
// ctx->AddHint(RH_MEDIGORON, AutoFormatHintText(medigoronText), RC_GC_MEDIGORON, HINT_TYPE_STATIC, GetHintRegion(RR_GORON_CITY)->GetHint().GetText());
// ctx->AddHint(RH_GRANNYS_SHOP, AutoFormatHintText(grannyText), RC_KAK_GRANNYS_SHOP, HINT_TYPE_STATIC, GetHintRegion(RR_KAKARIKO_VILLAGE)->GetHint().GetText());
// ctx->AddHint(RH_WASTELAND_BOMBCHU_SALESMAN, AutoFormatHintText(carpetSalesmanTextOne), RC_WASTELAND_BOMBCHU_SALESMAN, HINT_TYPE_STATIC, GetHintRegion(RR_HAUNTED_WASTELAND)->GetHint().GetText());
}
//RANDOTODO add Better Links Pocket and starting item handling once more starting items are added
void CreateSpecialItemHint(uint32_t item, std::vector<RandomizerCheck> hints, RandomizerHintTextKey text1, RandomizerHintTextKey text2, Text& textLoc, std::string& nameLoc, bool condition, bool yourpocket = false) {
void CreateSpecialItemHint(uint32_t item, RandomizerHintKey hintKey, std::vector<RandomizerCheck> hints, RandomizerHintTextKey text1, RandomizerHintTextKey text2, Text& textLoc, std::string& nameLoc, bool condition, bool yourpocket = false) {
auto ctx = Rando::Context::GetInstance();
if(condition){
RandomizerCheck location = FilterFromPool(ctx->allLocations, [item, ctx](const RandomizerCheck loc) {
@@ -828,8 +912,9 @@ void CreateSpecialItemHint(uint32_t item, std::vector<RandomizerCheck> hints, Ra
}
Text area = GetHintRegion(ctx->GetItemLocation(location)->GetParentRegionKey())->GetHint().GetText();
textLoc = Hint(text1).GetText() + area + Hint(text2).GetText();
textLoc = ::Hint(text1).GetText() + area + ::Hint(text2).GetText();
nameLoc = Rando::StaticData::GetLocation(location)->GetName();
ctx->AddHint(hintKey, AutoFormatHintText(textLoc), location, HINT_TYPE_STATIC, area);
} else {
textLoc = Text();
nameLoc = "";
@@ -838,7 +923,8 @@ void CreateSpecialItemHint(uint32_t item, std::vector<RandomizerCheck> hints, Ra
void CreateWarpSongTexts() {
if (!ShuffleWarpSongs) {
auto ctx = Rando::Context::GetInstance();
if (!ctx->GetOption(RSK_WARP_SONG_HINTS)) {
warpMinuetText = Text();
warpBoleroText = Text();
warpSerenadeText = Text();
@@ -865,21 +951,27 @@ void CreateWarpSongTexts() {
switch (entrance->GetIndex()) {
case 0x0600: // minuet
warpMinuetText = resolvedHint;
ctx->AddHint(RH_MINUET_WARP_LOC, resolvedHint, RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, resolvedHint);
break;
case 0x04F6: // bolero
warpBoleroText = resolvedHint;
ctx->AddHint(RH_BOLERO_WARP_LOC, resolvedHint, RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, resolvedHint);
break;
case 0x0604: // serenade
warpSerenadeText = resolvedHint;
ctx->AddHint(RH_SERENADE_WARP_LOC, resolvedHint, RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, resolvedHint);
break;
case 0x01F1: // requiem
warpRequiemText = resolvedHint;
ctx->AddHint(RH_REQUIEM_WARP_LOC, resolvedHint, RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, resolvedHint);
break;
case 0x0568: // nocturne
warpNocturneText = resolvedHint;
break;
warpNocturneText = resolvedHint;
ctx->AddHint(RH_NOCTURNE_WARP_LOC, resolvedHint, RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, resolvedHint);
break;
case 0x05F4: // prelude
warpPreludeText = resolvedHint;
ctx->AddHint(RH_PRELUDE_WARP_LOC, resolvedHint, RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, resolvedHint);
break;
}
}
@@ -1008,32 +1100,32 @@ uint8_t PlaceHints(std::array<uint8_t, HINT_TYPE_MAX>& selectedHints,
void CreateStoneHints() {
auto ctx = Rando::Context::GetInstance();
SPDLOG_DEBUG("\nNOW CREATING HINTS\n");
const HintSetting& hintSetting = hintSettingTable[Settings::HintDistribution.Value<uint8_t>()];
const HintSetting& hintSetting = hintSettingTable[ctx->GetOption(RSK_HINT_DISTRIBUTION).Value<uint8_t>()];
std::array<HintDistributionSetting, (int)HINT_TYPE_MAX> distTable = hintSetting.distTable;
uint8_t* remainingDungeonWothHints = new uint8_t(hintSetting.dungeonsWothLimit);
uint8_t* remainingDungeonBarrenHints = new uint8_t(hintSetting.dungeonsBarrenLimit);
// Apply Special hint exclusions with no requirements
if (Settings::Kak10GSHintText){
if (ctx->GetOption(RSK_KAK_10_SKULLS_HINT)){
ctx->GetItemLocation(RC_KAK_10_GOLD_SKULLTULA_REWARD)->SetAsHinted();
}
if (Settings::Kak20GSHintText){
if (ctx->GetOption(RSK_KAK_20_SKULLS_HINT)){
ctx->GetItemLocation(RC_KAK_20_GOLD_SKULLTULA_REWARD)->SetAsHinted();
}
if (Settings::Kak30GSHintText){
if (ctx->GetOption(RSK_KAK_30_SKULLS_HINT)){
ctx->GetItemLocation(RC_KAK_30_GOLD_SKULLTULA_REWARD)->SetAsHinted();
}
if (Settings::Kak40GSHintText){
if (ctx->GetOption(RSK_KAK_40_SKULLS_HINT)){
ctx->GetItemLocation(RC_KAK_40_GOLD_SKULLTULA_REWARD)->SetAsHinted();
}
if (Settings::Kak50GSHintText){
if (ctx->GetOption(RSK_KAK_50_SKULLS_HINT)){
ctx->GetItemLocation(RC_KAK_50_GOLD_SKULLTULA_REWARD)->SetAsHinted();
}
if (Settings::FrogsHintText){
if (ctx->GetOption(RSK_FROGS_HINT)){
ctx->GetItemLocation(RC_ZR_FROGS_OCARINA_GAME)->SetAsHinted();
}
if (Settings::skipChildZelda){
if (ctx->GetOption(RSK_SKIP_CHILD_ZELDA)){
ctx->GetItemLocation(RC_SONG_FROM_IMPA)->SetAsHinted();
}
@@ -1045,7 +1137,7 @@ void CreateStoneHints() {
auto alwaysHintLocations = FilterFromPool(ctx->allLocations, [ctx](const RandomizerCheck loc) {
return ((Rando::StaticData::GetLocation(loc)->GetHint()->GetType() == HintCategory::Always) ||
// If we have Rainbow Bridge set to Greg, add a hint for where Greg is
(Bridge.Is(RAINBOWBRIDGE_GREG) &&
(ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_GREG) &&
ctx->GetItemLocation(loc)->GetPlacedRandomizerGet() == RG_GREG_RUPEE)) &&
ctx->GetItemLocation(loc)->IsHintable() && !(ctx->GetItemLocation(loc)->IsHintedAt());
});
@@ -1086,16 +1178,17 @@ void CreateStoneHints() {
}
void CreateAllHints(){
auto ctx = Rando::Context::GetInstance();
CreateGanonAndSheikText();
CreateAltarText();
CreateSpecialItemHint(RG_PROGRESSIVE_HOOKSHOT, {RC_DAMPE_HINT}, RHT_DAMPE_DIARY01, RHT_DAMPE_DIARY02, dampesText, dampeHintLoc, (bool)DampeHintText);
CreateSpecialItemHint(RG_GREG_RUPEE, {RC_GREG_HINT}, RHT_GREG_HINT01, RHT_GREG_HINT02, gregText, gregHintLoc, (bool)GregHintText);
CreateSpecialItemHint(RG_PROGRESSIVE_MAGIC_METER, {RC_SARIA_SONG_HINT, RC_SONG_FROM_SARIA}, RHT_SARIA_TEXT01, RHT_SARIA_TEXT02, sariaText, sariaHintLoc, (bool)SariaHintText);
CreateSpecialItemHint(RG_PROGRESSIVE_HOOKSHOT, RH_DAMPES_DIARY, {RC_DAMPE_HINT}, RHT_DAMPE_DIARY01, RHT_DAMPE_DIARY02, dampesText, dampeHintLoc, (bool)ctx->GetOption(RSK_DAMPES_DIARY_HINT));
CreateSpecialItemHint(RG_GREG_RUPEE, RH_GREG_RUPEE, {RC_GREG_HINT}, RHT_GREG_HINT01, RHT_GREG_HINT02, gregText, gregHintLoc, (bool)ctx->GetOption(RSK_GREG_HINT));
CreateSpecialItemHint(RG_PROGRESSIVE_MAGIC_METER, RH_SARIA, {RC_SARIA_SONG_HINT, RC_SONG_FROM_SARIA}, RHT_SARIA_TEXT01, RHT_SARIA_TEXT02, sariaText, sariaHintLoc, (bool)ctx->GetOption(RSK_SARIA_HINT));
if (ShuffleMerchants.Is(SHUFFLEMERCHANTS_HINTS)) {
if (ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_ON_HINT)) {
CreateMerchantsHints();
}
if (GossipStoneHints.IsNot(HINTS_NO_HINTS)) {
if (ctx->GetOption(RSK_GOSSIP_STONE_HINTS).IsNot(RO_GOSSIP_STONES_NONE)) {
printf("\x1b[10;10HCreating Hints...");
CreateStoneHints();
printf("Done");

View File

@@ -6,10 +6,7 @@
#include "text.hpp"
#include "random.hpp"
#include "settings.hpp"
#include "dungeon.hpp"
#include <functional>
struct HintDistributionSetting {
HintType type;
size_t weight;
@@ -55,7 +52,8 @@ public:
: obscureText(std::move(obscureText_)),
ambiguousText(std::move(ambiguousText_)),
clearText(std::move(clearText_)),
type(type_) {}
type(type_) {
}
static auto Item(std::vector<Text>&& obscureText, std::vector<Text>&& ambiguousText = {}, Text&& clearText = {}) {
return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Item};
@@ -162,25 +160,9 @@ public:
return clearText;
}
const Text& GetText() const {
if (Settings::ClearerHints.Is(HINTMODE_OBSCURE)) {
return GetObscure();
} else if (Settings::ClearerHints.Is(HINTMODE_AMBIGUOUS)){
return GetAmbiguous();
} else {
return GetClear();
}
}
const Text& GetText() const;
const Text GetTextCopy() const {
if (Settings::ClearerHints.Is(HINTMODE_OBSCURE)) {
return GetObscure();
} else if (Settings::ClearerHints.Is(HINTMODE_AMBIGUOUS)){
return GetAmbiguous();
} else {
return GetClear();
}
}
const Text GetTextCopy() const;
HintCategory GetType() const {
return type;
@@ -204,8 +186,15 @@ private:
using ConditionalAlwaysHint = std::pair<RandomizerCheck, std::function<bool()>>;
typedef enum {
DUNGEON_NEITHER,
DUNGEON_BARREN,
DUNGEON_WOTH,
} DungeonHintInfo;
//10 dungeons as GTG and GC are excluded
extern std::array<DungeonInfo, 10> dungeonInfoData;
extern std::array<DungeonHintInfo, 10> dungeonInfoData;
extern std::array<ConditionalAlwaysHint, 10> conditionalAlwaysHints;
extern RandomizerHintTextKey GetHintRegionHintKey(const RandomizerRegion area);

View File

@@ -1,23 +1,17 @@
#include "item_pool.hpp"
#include "dungeon.hpp"
#include "../dungeon.h"
#include "fill.hpp"
#include "../static_data.h"
#include "../context.h"
#include "pool_functions.hpp"
#include "random.hpp"
#include "settings.hpp"
#include "spoiler_log.hpp"
#include "z64item.h"
#include <spdlog/spdlog.h>
using namespace Settings;
using namespace Dungeon;
std::vector<RandomizerGet> ItemPool = {};
std::vector<RandomizerGet> PendingJunkPool = {};
std::vector<uint8_t> IceTrapModels = {};
const std::array<RandomizerGet, 9> dungeonRewards = {
RG_KOKIRI_EMERALD,
RG_GORON_RUBY,
@@ -432,9 +426,10 @@ static void AddRandomBottle(std::vector<RandomizerGet>& bottlePool) {
}
RandomizerGet GetJunkItem() {
if (IceTrapValue.Is(ICETRAPS_MAYHEM) || IceTrapValue.Is(ICETRAPS_ONSLAUGHT)) {
auto ctx = Rando::Context::GetInstance();
if (ctx->GetOption(RSK_ICE_TRAPS).Is(RO_ICE_TRAPS_MAYHEM) || ctx->GetOption(RSK_ICE_TRAPS).Is(RO_ICE_TRAPS_ONSLAUGHT)) {
return RG_ICE_TRAP;
} else if (IceTrapValue.Is(ICETRAPS_EXTRA)) {
} else if (ctx->GetOption(RSK_ICE_TRAPS).Is(RO_ICE_TRAPS_EXTRA)) {
return RandomElement(JunkPoolItems);
}
//Ice Trap is the last item in JunkPoolItems, so subtract 1 to never hit that index
@@ -504,10 +499,10 @@ static void PlaceVanillaDekuScrubItems() {
ctx->PlaceItemInLocation(RC_LLR_DEKU_SCRUB_GROTTO_CENTER, RG_DEKU_SEEDS_30, false, true);
//Dungeon Scrubs
if (DekuTree.IsMQ()) {
if (ctx->GetDungeon(Rando::DEKU_TREE)->IsMQ()) {
ctx->PlaceItemInLocation(RC_DEKU_TREE_MQ_DEKU_SCRUB, RG_DEKU_SHIELD, false, true);
}
if (DodongosCavern.IsMQ()) {
if (ctx->GetDungeon(Rando::DODONGOS_CAVERN)->IsMQ()) {
ctx->PlaceItemInLocation(RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR, RG_DEKU_STICK_1, false, true);
ctx->PlaceItemInLocation(RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT, RG_DEKU_SEEDS_30, false, true);
ctx->PlaceItemInLocation(RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE, RG_DEKU_SHIELD, false, true);
@@ -519,10 +514,10 @@ static void PlaceVanillaDekuScrubItems() {
ctx->PlaceItemInLocation(RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT, RG_DEKU_SEEDS_30, false, true);
ctx->PlaceItemInLocation(RC_DODONGOS_CAVERN_DEKU_SCRUB_LOBBY, RG_DEKU_SHIELD, false, true);
}
if (JabuJabusBelly.IsVanilla()) {
if (ctx->GetDungeon(Rando::JABU_JABUS_BELLY)->IsVanilla()) {
ctx->PlaceItemInLocation(RC_JABU_JABUS_BELLY_DEKU_SCRUB, RG_DEKU_NUTS_5, false, true);
}
if (GanonsCastle.IsMQ()) {
if (ctx->GetDungeon(Rando::GANONS_CASTLE)->IsMQ()) {
ctx->PlaceItemInLocation(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT, RG_GREEN_POTION_REFILL, false, true);
ctx->PlaceItemInLocation(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT, RG_BOMBS_5, false, true);
ctx->PlaceItemInLocation(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER, RG_ARROWS_30, false, true);
@@ -539,23 +534,28 @@ static void PlaceVanillaDekuScrubItems() {
}
static void PlaceVanillaMapsAndCompasses() {
for (auto dungeon : dungeonList) {
auto ctx = Rando::Context::GetInstance();
for (auto dungeon : ctx->GetDungeons()->GetDungeonList()) {
dungeon->PlaceVanillaMap();
dungeon->PlaceVanillaCompass();
}
}
static void PlaceVanillaSmallKeys() {
for (auto dungeon : dungeonList) {
auto ctx = Rando::Context::GetInstance();
for (auto dungeon : ctx->GetDungeons()->GetDungeonList()) {
dungeon->PlaceVanillaSmallKeys();
}
}
static void PlaceVanillaBossKeys() {
for (auto dungeon : dungeonList) {
auto ctx = Rando::Context::GetInstance();
for (auto dungeon : ctx->GetDungeons()->GetDungeonList()) {
dungeon->PlaceVanillaBossKey();
}
}
// TODO: This feels like it could be moved to Dungeons class and probably shorten
// a few function call chains. Needs investigation.
static void PlaceVanillaCowMilk() {
auto ctx = Rando::Context::GetInstance();
@@ -569,7 +569,7 @@ static void PlaceVanillaCowMilk() {
ctx->PlaceItemInLocation(RC_LLR_TOWER_LEFT_COW, RG_MILK, false, true);
ctx->PlaceItemInLocation(RC_LLR_TOWER_RIGHT_COW, RG_MILK, false, true);
if (JabuJabusBelly.IsMQ()) {
if (ctx->GetDungeon(Rando::JABU_JABUS_BELLY)->IsMQ()) {
ctx->PlaceItemInLocation(RC_JABU_JABUS_BELLY_MQ_COW, RG_MILK, false, true);
}
}
@@ -590,6 +590,7 @@ static void SetScarceItemPool() {
}
static void SetMinimalItemPool() {
auto ctx = Rando::Context::GetInstance();
ReplaceMaxItem(RG_PROGRESSIVE_BOMBCHUS, 1);
ReplaceMaxItem(RG_BOMBCHU_5, 1);
ReplaceMaxItem(RG_BOMBCHU_10, 0);
@@ -604,7 +605,7 @@ static void SetMinimalItemPool() {
ReplaceMaxItem(RG_PROGRESSIVE_BOMB_BAG, 1);
ReplaceMaxItem(RG_PIECE_OF_HEART, 0);
// Need an extra heart container when starting with 1 heart to be able to reach 3 hearts
ReplaceMaxItem(RG_HEART_CONTAINER, (StartingHearts.Value<uint8_t>() == 18)? 1 : 0);
ReplaceMaxItem(RG_HEART_CONTAINER, (ctx->GetOption(RSK_STARTING_HEARTS).Value<uint8_t>() == 18)? 1 : 0);
}
void GenerateItemPool() {
@@ -613,63 +614,63 @@ void GenerateItemPool() {
PendingJunkPool.clear();
//Initialize ice trap models to always major items
IceTrapModels = {
GI_SHIELD_MIRROR,
GI_BOOMERANG,
GI_LENS,
GI_HAMMER,
GI_BOOTS_IRON,
GI_BOOTS_HOVER,
GI_STONE_OF_AGONY,
GI_DINS_FIRE,
GI_FARORES_WIND,
GI_NAYRUS_LOVE,
GI_ARROW_FIRE,
GI_ARROW_ICE,
GI_ARROW_LIGHT,
0xB8, //Double defense
GI_CLAIM_CHECK,
0x80, //Progressive hookshot
0x81, //Progressive strength
0x82, //Progressive bomb bag
0x83, //Progressive bow
0x84, //Progressive slingshot
0x85, //Progressive wallet
0x86, //Progressive scale
0x8A, //Progressive magic
ctx->possibleIceTrapModels = {
RG_MIRROR_SHIELD,
RG_BOOMERANG,
RG_LENS_OF_TRUTH,
RG_MEGATON_HAMMER,
RG_IRON_BOOTS,
RG_HOVER_BOOTS,
RG_STONE_OF_AGONY,
RG_DINS_FIRE,
RG_FARORES_WIND,
RG_NAYRUS_LOVE,
RG_FIRE_ARROWS,
RG_ICE_ARROWS,
RG_LIGHT_ARROWS,
RG_DOUBLE_DEFENSE, //Double defense
RG_CLAIM_CHECK,
RG_PROGRESSIVE_HOOKSHOT, //Progressive hookshot
RG_PROGRESSIVE_STRENGTH, //Progressive strength
RG_PROGRESSIVE_BOMB_BAG, //Progressive bomb bag
RG_PROGRESSIVE_BOW, //Progressive bow
RG_PROGRESSIVE_SLINGSHOT, //Progressive slingshot
RG_PROGRESSIVE_WALLET, //Progressive wallet
RG_PROGRESSIVE_SCALE, //Progressive scale
RG_PROGRESSIVE_MAGIC_METER, //Progressive magic
};
//Check song shuffle and dungeon reward shuffle just for ice traps
if (ShuffleSongs.Is(SONGSHUFFLE_ANYWHERE)) {
if (ctx->GetOption(RSK_SHUFFLE_SONGS).Is(RO_SONG_SHUFFLE_ANYWHERE)) {
//Push item ids for songs
IceTrapModels.push_back(0xC1);
IceTrapModels.push_back(0xC2);
IceTrapModels.push_back(0xC3);
IceTrapModels.push_back(0xC4);
IceTrapModels.push_back(0xC5);
IceTrapModels.push_back(0xC6);
IceTrapModels.push_back(0xBB);
IceTrapModels.push_back(0xBC);
IceTrapModels.push_back(0xBD);
IceTrapModels.push_back(0xBE);
IceTrapModels.push_back(0xBF);
IceTrapModels.push_back(0xC0);
ctx->possibleIceTrapModels.push_back(RG_ZELDAS_LULLABY);
ctx->possibleIceTrapModels.push_back(RG_EPONAS_SONG);
ctx->possibleIceTrapModels.push_back(RG_SARIAS_SONG);
ctx->possibleIceTrapModels.push_back(RG_SUNS_SONG);
ctx->possibleIceTrapModels.push_back(RG_SONG_OF_TIME);
ctx->possibleIceTrapModels.push_back(RG_SONG_OF_STORMS);
ctx->possibleIceTrapModels.push_back(RG_MINUET_OF_FOREST);
ctx->possibleIceTrapModels.push_back(RG_BOLERO_OF_FIRE);
ctx->possibleIceTrapModels.push_back(RG_SERENADE_OF_WATER);
ctx->possibleIceTrapModels.push_back(RG_REQUIEM_OF_SPIRIT);
ctx->possibleIceTrapModels.push_back(RG_NOCTURNE_OF_SHADOW);
ctx->possibleIceTrapModels.push_back(RG_PRELUDE_OF_LIGHT);
}
if (ShuffleRewards.Is(REWARDSHUFFLE_ANYWHERE)) {
if (ctx->GetOption(RSK_SHUFFLE_DUNGEON_REWARDS).Is(RO_DUNGEON_REWARDS_ANYWHERE)) {
//Push item ids for dungeon rewards
IceTrapModels.push_back(0xCB);
IceTrapModels.push_back(0xCC);
IceTrapModels.push_back(0xCD);
IceTrapModels.push_back(0xCE);
IceTrapModels.push_back(0xCF);
IceTrapModels.push_back(0xD0);
IceTrapModels.push_back(0xD1);
IceTrapModels.push_back(0xD2);
IceTrapModels.push_back(0xD3);
ctx->possibleIceTrapModels.push_back(RG_KOKIRI_EMERALD);
ctx->possibleIceTrapModels.push_back(RG_GORON_RUBY);
ctx->possibleIceTrapModels.push_back(RG_ZORA_SAPPHIRE);
ctx->possibleIceTrapModels.push_back(RG_FOREST_MEDALLION);
ctx->possibleIceTrapModels.push_back(RG_FIRE_MEDALLION);
ctx->possibleIceTrapModels.push_back(RG_WATER_MEDALLION);
ctx->possibleIceTrapModels.push_back(RG_SPIRIT_MEDALLION);
ctx->possibleIceTrapModels.push_back(RG_SHADOW_MEDALLION);
ctx->possibleIceTrapModels.push_back(RG_LIGHT_MEDALLION);
}
if (TriforceHunt.Is(TRIFORCE_HUNT_ON)) {
IceTrapModels.push_back(0xDF);
AddItemToMainPool(RG_TRIFORCE_PIECE, Settings::TriforceHuntTotal.Value<uint8_t>());
if (ctx->GetOption(RSK_TRIFORCE_HUNT)) {
ctx->possibleIceTrapModels.push_back(RG_TRIFORCE_PIECE);
AddItemToMainPool(RG_TRIFORCE_PIECE, ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_TOTAL).Value<uint8_t>());
ctx->PlaceItemInLocation(RC_TRIFORCE_COMPLETED, RG_TRIFORCE); // Win condition
ctx->PlaceItemInLocation(RC_GANON, GetJunkItem(), false, true);
} else {
@@ -680,66 +681,66 @@ void GenerateItemPool() {
ctx->PlaceItemInLocation(RC_HC_ZELDAS_LETTER, RG_ZELDAS_LETTER);
ctx->PlaceItemInLocation(RC_MARKET_BOMBCHU_BOWLING_BOMBCHUS, RG_BOMBCHU_DROP);
if (ShuffleKokiriSword) {
if (ctx->GetOption(RSK_SHUFFLE_KOKIRI_SWORD)) {
AddItemToMainPool(RG_KOKIRI_SWORD);
IceTrapModels.push_back(GI_SWORD_KOKIRI);
ctx->possibleIceTrapModels.push_back(RG_KOKIRI_SWORD);
} else {
ctx->PlaceItemInLocation(RC_KF_KOKIRI_SWORD_CHEST, RG_KOKIRI_SWORD, false, true);
}
if (ShuffleMasterSword) {
if (ctx->GetOption(RSK_SHUFFLE_MASTER_SWORD)) {
AddItemToMainPool(RG_MASTER_SWORD);
IceTrapModels.push_back(0xE0); //Master Sword without the GI enum
ctx->possibleIceTrapModels.push_back(RG_MASTER_SWORD); //Master Sword without the GI enum
} else {
ctx->PlaceItemInLocation(RC_TOT_MASTER_SWORD, RG_MASTER_SWORD, false, true);
}
if (ShuffleWeirdEgg) {
if (ctx->GetOption(RSK_SHUFFLE_WEIRD_EGG)) {
AddItemToMainPool(RG_WEIRD_EGG);
IceTrapModels.push_back(GI_WEIRD_EGG);
ctx->possibleIceTrapModels.push_back(RG_WEIRD_EGG);
} else {
ctx->PlaceItemInLocation(RC_HC_MALON_EGG, RG_WEIRD_EGG, false, true);
}
if (ShuffleOcarinas) {
if (ctx->GetOption(RSK_SHUFFLE_OCARINA)) {
AddItemToMainPool(RG_PROGRESSIVE_OCARINA, 2);
if (ItemPoolValue.Is(ITEMPOOL_PLENTIFUL)) {
if (ctx->GetOption(RSK_ITEM_POOL).Is(RO_ITEM_POOL_PLENTIFUL)) {
AddItemToPool(PendingJunkPool, RG_PROGRESSIVE_OCARINA);
}
IceTrapModels.push_back(0x8B); //Progressive ocarina
ctx->possibleIceTrapModels.push_back(RG_PROGRESSIVE_OCARINA); //Progressive ocarina
} else {
ctx->PlaceItemInLocation(RC_LW_GIFT_FROM_SARIA, RG_PROGRESSIVE_OCARINA, false, true);
ctx->PlaceItemInLocation(RC_HF_OCARINA_OF_TIME_ITEM, RG_PROGRESSIVE_OCARINA, false, true);
}
if (ShuffleCows) {
if (ctx->GetOption(RSK_SHUFFLE_COWS)) {
//9 total cow locations
for (uint8_t i = 0; i < 9; i++) {
AddItemToMainPool(GetJunkItem());
}
//extra location for Jabu MQ
if (JabuJabusBelly.IsMQ()) {
if (ctx->GetDungeon(Rando::JABU_JABUS_BELLY)->IsMQ()) {
AddItemToMainPool(GetJunkItem());
}
} else {
PlaceVanillaCowMilk();
}
if (ShuffleMagicBeans) {
if (ctx->GetOption(RSK_SHUFFLE_MAGIC_BEANS)) {
AddItemToMainPool(RG_MAGIC_BEAN_PACK);
if (ItemPoolValue.Is(ITEMPOOL_PLENTIFUL)) {
if (ctx->GetOption(RSK_ITEM_POOL).Is(RO_ITEM_POOL_PLENTIFUL)) {
AddItemToPool(PendingJunkPool, RG_MAGIC_BEAN_PACK);
}
IceTrapModels.push_back(0xC9); //Magic bean pack
ctx->possibleIceTrapModels.push_back(RG_MAGIC_BEAN_PACK); //Magic bean pack
} else {
ctx->PlaceItemInLocation(RC_ZR_MAGIC_BEAN_SALESMAN, RG_MAGIC_BEAN, false, true);
}
if (ShuffleMerchants.IsNot(SHUFFLEMERCHANTS_OFF)) {
if (!ProgressiveGoronSword) {
if (ctx->GetOption(RSK_SHUFFLE_MERCHANTS).IsNot(RO_SHUFFLE_MERCHANTS_OFF)) {
if (/*!ProgressiveGoronSword TODO: Implement Progressive Goron Sword*/true) {
AddItemToMainPool(RG_GIANTS_KNIFE);
}
if (BombchusInLogic) {
if (ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC)) {
AddItemToMainPool(RG_PROGRESSIVE_BOMBCHUS);
} else {
AddItemToMainPool(RG_BOMBCHU_10);
@@ -750,7 +751,7 @@ void GenerateItemPool() {
ctx->PlaceItemInLocation(RC_WASTELAND_BOMBCHU_SALESMAN, RG_BOMBCHU_10, false, true);
}
if (ShuffleFrogSongRupees) {
if (ctx->GetOption(RSK_SHUFFLE_FROG_SONG_RUPEES)) {
AddItemToMainPool(RG_PURPLE_RUPEE, 5);
} else {
ctx->PlaceItemInLocation(RC_ZR_FROGS_ZELDAS_LULLABY, RG_PURPLE_RUPEE, false, true);
@@ -760,7 +761,7 @@ void GenerateItemPool() {
ctx->PlaceItemInLocation(RC_ZR_FROGS_SONG_OF_TIME, RG_PURPLE_RUPEE, false, true);
}
if (ShuffleAdultTradeQuest) {
if (ctx->GetOption(RSK_SHUFFLE_ADULT_TRADE)) {
AddItemToMainPool(RG_POCKET_EGG);
AddItemToMainPool(RG_COJIRO);
AddItemToMainPool(RG_ODD_MUSHROOM);
@@ -783,9 +784,9 @@ void GenerateItemPool() {
}
AddItemToMainPool(RG_CLAIM_CHECK);
if (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_SINGLE_KEYS)) {
if (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS)) {
AddItemToMainPool(RG_TREASURE_GAME_SMALL_KEY, 6); // 6 individual keys
} else if (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_PACK)) {
} else if (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK)) {
AddItemToMainPool(RG_TREASURE_GAME_SMALL_KEY); // 1 key which will behave as a pack of 6
} else {
ctx->PlaceItemInLocation(RC_MARKET_TREASURE_CHEST_GAME_ITEM_1, RG_TREASURE_GAME_SMALL_KEY, false, true);
@@ -795,11 +796,11 @@ void GenerateItemPool() {
ctx->PlaceItemInLocation(RC_MARKET_TREASURE_CHEST_GAME_ITEM_5, RG_TREASURE_GAME_SMALL_KEY, false, true);
};
if (Tokensanity.Is(TOKENSANITY_OFF)) {
if (ctx->GetOption(RSK_SHUFFLE_TOKENS).Is(RO_TOKENSANITY_OFF)) {
for (RandomizerCheck loc : ctx->GetLocations(ctx->allLocations, Category::cSkulltula)) {
ctx->PlaceItemInLocation(loc, RG_GOLD_SKULLTULA_TOKEN, false, true);
}
} else if (Tokensanity.Is(TOKENSANITY_DUNGEONS)) {
} else if (ctx->GetOption(RSK_SHUFFLE_TOKENS).Is(RO_TOKENSANITY_DUNGEONS)) {
for (RandomizerCheck loc : ctx->GetLocations(ctx->allLocations, Category::cSkulltula)) {
if (Rando::StaticData::GetLocation(loc)->IsOverworld()) {
ctx->PlaceItemInLocation((RandomizerCheck)loc, RG_GOLD_SKULLTULA_TOKEN, false, true);
@@ -807,7 +808,7 @@ void GenerateItemPool() {
AddItemToMainPool(RG_GOLD_SKULLTULA_TOKEN);
}
}
} else if (Tokensanity.Is(TOKENSANITY_OVERWORLD)) {
} else if (ctx->GetOption(RSK_SHUFFLE_TOKENS).Is(RO_TOKENSANITY_OVERWORLD)) {
for (RandomizerCheck loc : ctx->GetLocations(ctx->allLocations, Category::cSkulltula)) {
if (Rando::StaticData::GetLocation(loc)->IsDungeon()) {
ctx->PlaceItemInLocation((RandomizerCheck)loc, RG_GOLD_SKULLTULA_TOKEN, false, true);
@@ -819,8 +820,8 @@ void GenerateItemPool() {
AddItemToMainPool(RG_GOLD_SKULLTULA_TOKEN, 100);
}
if (Shuffle100GSReward) {
if (Tokensanity.IsNot(TOKENSANITY_OFF) && ItemPoolValue.Is(ITEMPOOL_PLENTIFUL)) {
if (ctx->GetOption(RSK_SHUFFLE_100_GS_REWARD)) {
if (ctx->GetOption(RSK_SHUFFLE_TOKENS).IsNot(RO_TOKENSANITY_OFF) && ctx->GetOption(RSK_ITEM_POOL).Is(RO_ITEM_POOL_PLENTIFUL)) {
AddItemToPool(PendingJunkPool, RG_GOLD_SKULLTULA_TOKEN, 10);
}
AddItemToMainPool(RG_HUGE_RUPEE);
@@ -828,7 +829,7 @@ void GenerateItemPool() {
ctx->PlaceItemInLocation(RC_KAK_100_GOLD_SKULLTULA_REWARD, RG_HUGE_RUPEE, false, true);
}
if (BombchusInLogic) {
if (ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC)) {
AddItemToMainPool(RG_PROGRESSIVE_BOMBCHUS, 5);
} else {
AddItemToMainPool(RG_BOMBCHU_5);
@@ -838,28 +839,28 @@ void GenerateItemPool() {
//Ice Traps
AddItemToMainPool(RG_ICE_TRAP);
if (GerudoTrainingGrounds.IsVanilla()) {
if (ctx->GetDungeon(Rando::GERUDO_TRAINING_GROUNDS)->IsVanilla()) {
AddItemToMainPool(RG_ICE_TRAP);
}
if (GanonsCastle.IsVanilla()) {
if (ctx->GetDungeon(Rando::GANONS_CASTLE)->IsVanilla()) {
AddItemToMainPool(RG_ICE_TRAP, 4);
}
//Gerudo Fortress
if (GerudoFortress.Is(GERUDOFORTRESS_OPEN)) {
if (ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_OPEN)) {
ctx->PlaceItemInLocation(RC_GF_NORTH_F1_CARPENTER, RG_RECOVERY_HEART, false, true);
ctx->PlaceItemInLocation(RC_GF_NORTH_F2_CARPENTER, RG_RECOVERY_HEART, false, true);
ctx->PlaceItemInLocation(RC_GF_SOUTH_F1_CARPENTER, RG_RECOVERY_HEART, false, true);
ctx->PlaceItemInLocation(RC_GF_SOUTH_F2_CARPENTER, RG_RECOVERY_HEART, false, true);
} else if (GerudoKeys.IsNot(GERUDOKEYS_VANILLA)) {
if (GerudoFortress.Is(GERUDOFORTRESS_FAST)) {
} else if (ctx->GetOption(RSK_GERUDO_KEYS).IsNot(RO_GERUDO_KEYS_VANILLA)) {
if (ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_FAST)) {
AddItemToMainPool(RG_GERUDO_FORTRESS_SMALL_KEY);
ctx->PlaceItemInLocation(RC_GF_NORTH_F2_CARPENTER, RG_RECOVERY_HEART, false, true);
ctx->PlaceItemInLocation(RC_GF_SOUTH_F1_CARPENTER, RG_RECOVERY_HEART, false, true);
ctx->PlaceItemInLocation(RC_GF_SOUTH_F2_CARPENTER, RG_RECOVERY_HEART, false, true);
} else {
//Only add key ring if 4 Fortress keys necessary
if (RingFortress) {
if (ctx->GetOption(RSK_KEYRINGS_GERUDO_FORTRESS)) {
AddItemToMainPool(RG_GERUDO_FORTRESS_KEY_RING);
//Add junk to make up for missing keys
for (uint8_t i = 0; i < 3; i++) {
@@ -869,15 +870,15 @@ void GenerateItemPool() {
AddItemToMainPool(RG_GERUDO_FORTRESS_SMALL_KEY, 4);
}
}
if (ItemPoolValue.Is(ITEMPOOL_PLENTIFUL)) {
if (RingFortress && GerudoFortress.Is(GERUDOFORTRESS_NORMAL)) {
if (ctx->GetOption(RSK_ITEM_POOL).Is(RO_ITEM_POOL_PLENTIFUL)) {
if (ctx->GetOption(RSK_KEYRINGS_GERUDO_FORTRESS) && ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_NORMAL)) {
AddItemToPool(PendingJunkPool, RG_GERUDO_FORTRESS_KEY_RING);
} else {
AddItemToPool(PendingJunkPool, RG_GERUDO_FORTRESS_SMALL_KEY);
}
}
} else {
if (GerudoFortress.Is(GERUDOFORTRESS_FAST)) {
if (ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_FAST)) {
ctx->PlaceItemInLocation(RC_GF_NORTH_F1_CARPENTER, RG_GERUDO_FORTRESS_SMALL_KEY, false, true);
ctx->PlaceItemInLocation(RC_GF_NORTH_F2_CARPENTER, RG_RECOVERY_HEART, false, true);
ctx->PlaceItemInLocation(RC_GF_SOUTH_F1_CARPENTER, RG_RECOVERY_HEART, false, true);
@@ -891,10 +892,10 @@ void GenerateItemPool() {
}
//Gerudo Membership Card
if (ShuffleGerudoToken && GerudoFortress.IsNot(GERUDOFORTRESS_OPEN)) {
if (ctx->GetOption(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD) && ctx->GetOption(RSK_GERUDO_FORTRESS).IsNot(RO_GF_OPEN)) {
AddItemToMainPool(RG_GERUDO_MEMBERSHIP_CARD);
IceTrapModels.push_back(GI_GERUDO_CARD);
} else if (ShuffleGerudoToken) {
ctx->possibleIceTrapModels.push_back(RG_GERUDO_MEMBERSHIP_CARD);
} else if (ctx->GetOption(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD)) {
AddItemToPool(PendingJunkPool, RG_GERUDO_MEMBERSHIP_CARD);
ctx->PlaceItemInLocation(RC_GF_GERUDO_MEMBERSHIP_CARD, RG_ICE_TRAP, false, true);
} else {
@@ -904,9 +905,9 @@ void GenerateItemPool() {
//Keys
//For key rings, need to add as many junk items as "missing" keys
if (KeyRings.IsNot(KEYRINGS_OFF)) {
if (ctx->GetOption(RSK_KEYRINGS).IsNot(RO_KEYRINGS_OFF)) {
uint8_t ringJunkAmt = 0;
for (auto dungeon : dungeonList) {
for (auto dungeon : ctx->GetDungeons()->GetDungeonList()) {
if (dungeon->HasKeyRing()) {
ringJunkAmt += dungeon->GetSmallKeyCount() - 1;
}
@@ -916,56 +917,56 @@ void GenerateItemPool() {
}
}
if (ItemPoolValue.Is(ITEMPOOL_PLENTIFUL)) {
if (ShuffleGerudoToken) {
if (ctx->GetOption(RSK_ITEM_POOL).Is(RO_ITEM_POOL_PLENTIFUL)) {
if (ctx->GetOption(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD)) {
AddItemToPool(PendingJunkPool, RG_GERUDO_MEMBERSHIP_CARD);
}
//Plentiful small keys
if (Keysanity.Is(KEYSANITY_ANYWHERE) || Keysanity.Is(KEYSANITY_ANY_DUNGEON) || Keysanity.Is(KEYSANITY_OVERWORLD)) {
if (BottomOfTheWell.HasKeyRing()) {
if (ctx->GetOption(RSK_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_ANYWHERE) || ctx->GetOption(RSK_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_ANY_DUNGEON) || ctx->GetOption(RSK_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_OVERWORLD)) {
if (ctx->GetDungeon(Rando::BOTTOM_OF_THE_WELL)->HasKeyRing()) {
AddItemToPool(PendingJunkPool, RG_BOTTOM_OF_THE_WELL_KEY_RING);
} else {
AddItemToPool(PendingJunkPool, RG_BOTTOM_OF_THE_WELL_SMALL_KEY);
}
if (ForestTemple.HasKeyRing()) {
if (ctx->GetDungeon(Rando::FOREST_TEMPLE)->HasKeyRing()) {
AddItemToPool(PendingJunkPool, RG_FOREST_TEMPLE_KEY_RING);
} else {
AddItemToPool(PendingJunkPool, RG_FOREST_TEMPLE_SMALL_KEY);
}
if (FireTemple.HasKeyRing()) {
if (ctx->GetDungeon(Rando::FIRE_TEMPLE)->HasKeyRing()) {
AddItemToPool(PendingJunkPool, RG_FIRE_TEMPLE_KEY_RING);
} else {
AddItemToPool(PendingJunkPool, RG_FIRE_TEMPLE_SMALL_KEY);
}
if (WaterTemple.HasKeyRing()) {
if (ctx->GetDungeon(Rando::WATER_TEMPLE)->HasKeyRing()) {
AddItemToPool(PendingJunkPool, RG_WATER_TEMPLE_KEY_RING);
} else {
AddItemToPool(PendingJunkPool, RG_WATER_TEMPLE_SMALL_KEY);
}
if (SpiritTemple.HasKeyRing()) {
if (ctx->GetDungeon(Rando::SPIRIT_TEMPLE)->HasKeyRing()) {
AddItemToPool(PendingJunkPool, RG_SPIRIT_TEMPLE_KEY_RING);
} else {
AddItemToPool(PendingJunkPool, RG_SPIRIT_TEMPLE_SMALL_KEY);
}
if (ShadowTemple.HasKeyRing()) {
if (ctx->GetDungeon(Rando::SHADOW_TEMPLE)->HasKeyRing()) {
AddItemToPool(PendingJunkPool, RG_SHADOW_TEMPLE_KEY_RING);
} else {
AddItemToPool(PendingJunkPool, RG_SHADOW_TEMPLE_SMALL_KEY);
}
if (GerudoTrainingGrounds.HasKeyRing()) {
if (ctx->GetDungeon(Rando::GERUDO_TRAINING_GROUNDS)->HasKeyRing()) {
AddItemToPool(PendingJunkPool, RG_GERUDO_TRAINING_GROUNDS_KEY_RING);
} else {
AddItemToPool(PendingJunkPool, RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY);
}
if (GanonsCastle.HasKeyRing()) {
if (ctx->GetDungeon(Rando::GANONS_CASTLE)->HasKeyRing()) {
AddItemToPool(PendingJunkPool, RG_GANONS_CASTLE_KEY_RING);
} else {
AddItemToPool(PendingJunkPool, RG_GANONS_CASTLE_SMALL_KEY);
}
}
if (BossKeysanity.Is(BOSSKEYSANITY_ANYWHERE) || BossKeysanity.Is(BOSSKEYSANITY_ANY_DUNGEON) || BossKeysanity.Is(BOSSKEYSANITY_OVERWORLD)) {
if (ctx->GetOption(RSK_BOSS_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_ANYWHERE) || ctx->GetOption(RSK_BOSS_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_ANY_DUNGEON) || ctx->GetOption(RSK_BOSS_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_OVERWORLD)) {
AddItemToPool(PendingJunkPool, RG_FOREST_TEMPLE_BOSS_KEY);
AddItemToPool(PendingJunkPool, RG_FIRE_TEMPLE_BOSS_KEY);
AddItemToPool(PendingJunkPool, RG_WATER_TEMPLE_BOSS_KEY);
@@ -973,36 +974,36 @@ void GenerateItemPool() {
AddItemToPool(PendingJunkPool, RG_SHADOW_TEMPLE_BOSS_KEY);
}
if (GanonsBossKey.Is(GANONSBOSSKEY_ANYWHERE) || GanonsBossKey.Is(GANONSBOSSKEY_ANY_DUNGEON) || GanonsBossKey.Is(GANONSBOSSKEY_OVERWORLD)) {
if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_ANYWHERE) || ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_ANY_DUNGEON) || ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_OVERWORLD)) {
AddItemToPool(PendingJunkPool, RG_GANONS_CASTLE_BOSS_KEY);
}
}
//Shopsanity
if (Settings::Shopsanity.Is(SHOPSANITY_OFF) || Settings::Shopsanity.Is(SHOPSANITY_ZERO)) {
if (ctx->GetOption(RSK_SHOPSANITY).Is(RO_SHOPSANITY_OFF) || ctx->GetOption(RSK_SHOPSANITY).Is(RO_SHOPSANITY_ZERO_ITEMS)) {
AddItemsToPool(ItemPool, normalRupees);
} else { //Shopsanity 1-4, random
AddItemsToPool(ItemPool, shopsanityRupees); //Shopsanity gets extra large rupees
}
//Scrubsanity
if (Settings::Scrubsanity.IsNot(SCRUBSANITY_OFF)) {
if (ctx->GetOption(RSK_SHUFFLE_SCRUBS).IsNot(RO_SCRUBS_OFF)) {
//Deku Tree
if (DekuTree.IsMQ()) {
if (ctx->GetDungeon(Rando::DEKU_TREE)->IsMQ()) {
AddItemToMainPool(RG_DEKU_SHIELD);
}
//Dodongos Cavern
AddItemToMainPool(RG_DEKU_STICK_1);
AddItemToMainPool(RG_DEKU_SHIELD);
if (DodongosCavern.IsMQ()) {
if (ctx->GetDungeon(Rando::DODONGOS_CAVERN)->IsMQ()) {
AddItemToMainPool(RG_RECOVERY_HEART);
} else {
AddItemToMainPool(RG_DEKU_NUTS_5);
}
//Jabu Jabus Belly
if (JabuJabusBelly.IsVanilla()) {
if (ctx->GetDungeon(Rando::JABU_JABUS_BELLY)->IsVanilla()) {
AddItemToMainPool(RG_DEKU_NUTS_5);
}
@@ -1010,7 +1011,7 @@ void GenerateItemPool() {
AddItemToMainPool(RG_BOMBS_5);
AddItemToMainPool(RG_RECOVERY_HEART);
AddItemToMainPool(RG_BLUE_RUPEE);
if (GanonsCastle.IsMQ()) {
if (ctx->GetDungeon(Rando::GANONS_CASTLE)->IsMQ()) {
AddItemToMainPool(RG_DEKU_NUTS_5);
}
@@ -1033,55 +1034,55 @@ void GenerateItemPool() {
AddItemsToPool(ItemPool, dungeonRewards);
//Dungeon pools
if (DekuTree.IsMQ()) {
if (ctx->GetDungeon(Rando::DEKU_TREE)->IsMQ()) {
AddItemsToPool(ItemPool, DT_MQ);
} else {
AddItemsToPool(ItemPool, DT_Vanilla);
}
if (DodongosCavern.IsMQ()) {
if (ctx->GetDungeon(Rando::DODONGOS_CAVERN)->IsMQ()) {
AddItemsToPool(ItemPool, DC_MQ);
} else {
AddItemsToPool(ItemPool, DC_Vanilla);
}
if (JabuJabusBelly.IsMQ()) {
if (ctx->GetDungeon(Rando::JABU_JABUS_BELLY)->IsMQ()) {
AddItemsToPool(ItemPool, JB_MQ);
}
if (ForestTemple.IsMQ()) {
if (ctx->GetDungeon(Rando::FOREST_TEMPLE)->IsMQ()) {
AddItemsToPool(ItemPool, FoT_MQ);
} else {
AddItemsToPool(ItemPool, FoT_Vanilla);
}
if (FireTemple.IsMQ()) {
if (ctx->GetDungeon(Rando::FIRE_TEMPLE)->IsMQ()) {
AddItemsToPool(ItemPool, FiT_MQ);
} else {
AddItemsToPool(ItemPool, FiT_Vanilla);
}
if (SpiritTemple.IsMQ()) {
if (ctx->GetDungeon(Rando::SPIRIT_TEMPLE)->IsMQ()) {
AddItemsToPool(ItemPool, SpT_MQ);
} else {
AddItemsToPool(ItemPool, SpT_Vanilla);
}
if (ShadowTemple.IsMQ()) {
if (ctx->GetDungeon(Rando::SHADOW_TEMPLE)->IsMQ()) {
AddItemsToPool(ItemPool, ShT_MQ);
} else {
AddItemsToPool(ItemPool, ShT_Vanilla);
}
if (BottomOfTheWell.IsVanilla()) {
if (ctx->GetDungeon(Rando::BOTTOM_OF_THE_WELL)->IsVanilla()) {
AddItemsToPool(ItemPool, BW_Vanilla);
}
if (GerudoTrainingGrounds.IsMQ()) {
if (ctx->GetDungeon(Rando::GERUDO_TRAINING_GROUNDS)->IsMQ()) {
AddItemsToPool(ItemPool, GTG_MQ);
} else {
AddItemsToPool(ItemPool, GTG_Vanilla);
}
if (GanonsCastle.IsMQ()) {
if (ctx->GetDungeon(Rando::GANONS_CASTLE)->IsMQ()) {
AddItemsToPool(ItemPool, GC_MQ);
} else {
AddItemsToPool(ItemPool, GC_Vanilla);
}
uint8_t rutoBottles = 1;
if (ZorasFountain.Is(ZORASFOUNTAIN_OPEN)) {
if (ctx->GetOption(RSK_ZORAS_FOUNTAIN).Is(RO_ZF_OPEN)) {
rutoBottles = 0;
}
@@ -1089,11 +1090,11 @@ void GenerateItemPool() {
uint8_t bottleCount = 4;
std::vector<RandomizerGet> bottles;
bottles.assign(normalBottles.begin(), normalBottles.end());
IceTrapModels.push_back(
Rando::StaticData::RetrieveItem(RandomElement(bottles)).GetItemID()); // Get one random bottle type for ice traps
ctx->possibleIceTrapModels.push_back(
Rando::StaticData::RetrieveItem(RandomElement(bottles)).GetRandomizerGet()); // Get one random bottle type for ice traps
for (uint8_t i = 0; i < bottleCount; i++) {
if (i >= rutoBottles) {
if ((i == bottleCount - 1) && ShuffleMerchants.IsNot(SHUFFLEMERCHANTS_OFF)) {
if ((i == bottleCount - 1) && ctx->GetOption(RSK_SHUFFLE_MERCHANTS).IsNot(RO_SHUFFLE_MERCHANTS_OFF)) {
AddItemToMainPool(RG_BOTTLE_WITH_BLUE_POTION);
} else {
AddRandomBottle(bottles);
@@ -1105,7 +1106,7 @@ void GenerateItemPool() {
//add extra songs only if song shuffle is anywhere
AddItemsToPool(ItemPool, songList);
if (ShuffleSongs.Is(SONGSHUFFLE_ANYWHERE) && ItemPoolValue.Is(ITEMPOOL_PLENTIFUL)) {
if (ctx->GetOption(RSK_SHUFFLE_SONGS).Is(RO_SONG_SHUFFLE_ANYWHERE) && ctx->GetOption(RSK_ITEM_POOL).Is(RO_ITEM_POOL_PLENTIFUL)) {
AddItemsToPool(PendingJunkPool, songList);
}
@@ -1116,10 +1117,10 @@ void GenerateItemPool() {
| advancement items that haven't been placed yet for placing higher priority
| items like stones/medallions.*/
if (MapsAndCompasses.Is(MAPSANDCOMPASSES_VANILLA)) {
if (ctx->GetOption(RSK_SHUFFLE_MAPANDCOMPASS).Is(RO_DUNGEON_ITEM_LOC_VANILLA)) {
PlaceVanillaMapsAndCompasses();
} else {
for (auto dungeon : dungeonList) {
for (auto dungeon : ctx->GetDungeons()->GetDungeonList()) {
if (dungeon->GetMap() != RG_NONE) {
AddItemToMainPool(dungeon->GetMap());
}
@@ -1130,11 +1131,11 @@ void GenerateItemPool() {
}
}
if (Keysanity.Is(KEYSANITY_VANILLA)) {
if (ctx->GetOption(RSK_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_VANILLA)) {
PlaceVanillaSmallKeys();
} else {
for (auto dungeon : dungeonList) {
if (dungeon->HasKeyRing() && Keysanity.IsNot(KEYSANITY_START_WITH)) {
for (auto dungeon : ctx->GetDungeons()->GetDungeonList()) {
if (dungeon->HasKeyRing() && ctx->GetOption(RSK_KEYSANITY).IsNot(RO_DUNGEON_ITEM_LOC_STARTWITH)) {
AddItemToMainPool(dungeon->GetKeyRing());
} else {
if (dungeon->GetSmallKeyCount() > 0) {
@@ -1144,7 +1145,7 @@ void GenerateItemPool() {
}
}
if (BossKeysanity.Is(BOSSKEYSANITY_VANILLA)) {
if (ctx->GetOption(RSK_BOSS_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_VANILLA)) {
PlaceVanillaBossKeys();
} else {
AddItemToMainPool(RG_FOREST_TEMPLE_BOSS_KEY);
@@ -1154,54 +1155,54 @@ void GenerateItemPool() {
AddItemToMainPool(RG_SHADOW_TEMPLE_BOSS_KEY);
}
if (GanonsBossKey.Is(GANONSBOSSKEY_FINAL_GS_REWARD)) {
if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_KAK_TOKENS)) {
ctx->PlaceItemInLocation(RC_KAK_100_GOLD_SKULLTULA_REWARD, RG_GANONS_CASTLE_BOSS_KEY);
} else if (GanonsBossKey.Value<uint8_t>() >= GANONSBOSSKEY_LACS_VANILLA && GanonsBossKey.IsNot(GANONSBOSSKEY_TRIFORCE_HUNT)) {
} else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Value<uint8_t>() >= RO_GANON_BOSS_KEY_LACS_VANILLA && ctx->GetOption(RSK_GANONS_BOSS_KEY).IsNot(RO_GANON_BOSS_KEY_TRIFORCE_HUNT)) {
ctx->PlaceItemInLocation(RC_TOT_LIGHT_ARROWS_CUTSCENE, RG_GANONS_CASTLE_BOSS_KEY);
} else if (GanonsBossKey.Is(GANONSBOSSKEY_VANILLA)) {
} else if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_VANILLA)) {
ctx->PlaceItemInLocation(RC_GANONS_TOWER_BOSS_KEY_CHEST, RG_GANONS_CASTLE_BOSS_KEY);
} else {
AddItemToMainPool(RG_GANONS_CASTLE_BOSS_KEY);
}
if (ItemPoolValue.Is(ITEMPOOL_PLENTIFUL)) {
if (ctx->GetOption(RSK_ITEM_POOL).Is(RO_ITEM_POOL_PLENTIFUL)) {
AddItemsToPool(ItemPool, easyItems);
} else {
AddItemsToPool(ItemPool, normalItems);
}
if (!ShuffleKokiriSword) {
if (!ctx->GetOption(RSK_SHUFFLE_KOKIRI_SWORD)) {
ReplaceMaxItem(RG_KOKIRI_SWORD, 0);
}
if (!ShuffleMasterSword) {
if (!ctx->GetOption(RSK_SHUFFLE_MASTER_SWORD)) {
ReplaceMaxItem(RG_MASTER_SWORD, 0);
}
if (ProgressiveGoronSword) {
if (/*ProgressiveGoronSword TODO: Implement Setting*/false) {
ReplaceMaxItem(RG_BIGGORON_SWORD, 0);
AddItemToMainPool(RG_PROGRESSIVE_GORONSWORD, 2);
IceTrapModels.push_back(0xD4); // Progressive Goron Sword
ctx->possibleIceTrapModels.push_back(RG_PROGRESSIVE_GORONSWORD); // Progressive Goron Sword
} else {
IceTrapModels.push_back(GI_SWORD_BGS);
ctx->possibleIceTrapModels.push_back(RG_BIGGORON_SWORD);
}
//Replace ice traps with junk from the pending junk pool if necessary
if (IceTrapValue.Is(ICETRAPS_OFF)) {
if (ctx->GetOption(RSK_ICE_TRAPS).Is(RO_ICE_TRAPS_OFF)) {
ReplaceMaxItem(RG_ICE_TRAP, 0);
}
//Replace all junk items with ice traps for onslaught mode
else if (IceTrapValue.Is(ICETRAPS_ONSLAUGHT)) {
else if (ctx->GetOption(RSK_ICE_TRAPS).Is(RO_ICE_TRAPS_ONSLAUGHT)) {
for (uint8_t i = 0; i < JunkPoolItems.size() - 3; i++) { // -3 Omits Huge Rupees and Deku Nuts 10
ReplaceMaxItem(JunkPoolItems[i], 0);
}
}
if (ItemPoolValue.Is(ITEMPOOL_SCARCE)) {
if (ctx->GetOption(RSK_ITEM_POOL).Is(RO_ITEM_POOL_SCARCE)) {
SetScarceItemPool();
} else if (ItemPoolValue.Is(ITEMPOOL_MINIMAL)) {
} else if (ctx->GetOption(RSK_ITEM_POOL).Is(RO_ITEM_POOL_MINIMAL)) {
SetMinimalItemPool();
} else if (RemoveDoubleDefense) {
} else if (/*RemoveDoubleDefense TODO: Implement setting*/ false) {
ReplaceMaxItem(RG_DOUBLE_DEFENSE, 0);
}

View File

@@ -14,4 +14,3 @@ void GenerateItemPool();
void AddJunk();
extern std::vector<RandomizerGet> ItemPool;
extern std::vector<uint8_t> IceTrapModels;

View File

@@ -1,20 +1,18 @@
#include "location_access.hpp"
#include "dungeon.hpp"
#include "../dungeon.h"
#include "../static_data.h"
#include "../context.h"
#include "item_pool.hpp"
#include "logic.hpp"
#include "settings.hpp"
#include "spoiler_log.hpp"
#include "trial.hpp"
#include "entrance.hpp"
#include "../trial.h"
#include "../entrance.h"
#include <fstream>
#include <iostream>
using namespace Logic;
using namespace Settings;
//generic grotto event list
std::vector<EventAccess> grottoEvents = {
@@ -80,7 +78,8 @@ bool LocationAccess::CanBuy() const {
}
// If bombchus in logic, need to have found chus to buy; if not just need bomb bag
else if (placed == RG_BUY_BOMBCHU_10 || placed == RG_BUY_BOMBCHU_20) {
OtherCondition = (!BombchusInLogic && Bombs) || (BombchusInLogic && FoundBombchus);
OtherCondition =
(!ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && Bombs) || (ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && FoundBombchus);
}
return SufficientWallet && OtherCondition;
@@ -91,7 +90,7 @@ Area::Area(std::string regionName_, std::string scene_, RandomizerHintTextKey hi
bool timePass_,
std::vector<EventAccess> events_,
std::vector<LocationAccess> locations_,
std::list<Entrance> exits_)
std::list<Rando::Entrance> exits_)
: regionName(std::move(regionName_)),
scene(std::move(scene_)),
hintKey(hintKey_),
@@ -139,13 +138,13 @@ bool Area::UpdateEvents(SearchMode mode) {
}
void Area::AddExit(RandomizerRegion parentKey, RandomizerRegion newExitKey, ConditionFn condition) {
Entrance newExit = Entrance(newExitKey, {condition});
Rando::Entrance newExit = Rando::Entrance(newExitKey, {condition});
newExit.SetParentRegion(parentKey);
exits.push_front(newExit);
}
//The exit will be completely removed from this area
void Area::RemoveExit(Entrance* exitToRemove) {
void Area::RemoveExit(Rando::Entrance* exitToRemove) {
exits.remove_if([exitToRemove](const auto exit){return &exit == exitToRemove;});
}
@@ -158,7 +157,7 @@ void Area::SetAsPrimary(RandomizerRegion exitToBePrimary) {
}
}
Entrance* Area::GetExit(RandomizerRegion exitToReturn) {
Rando::Entrance* Area::GetExit(RandomizerRegion exitToReturn) {
for (auto& exit : exits) {
if (exit.Getuint32_t() == exitToReturn) {
return &exit;
@@ -200,7 +199,7 @@ bool Area::CheckAllAccess(const RandomizerRegion exitKey) {
return false;
}
for (Entrance& exit : exits) {
for (Rando::Entrance& exit : exits) {
if (exit.GetConnectedRegionKey() == exitKey) {
return exit.CheckConditionAtAgeTime(Logic::IsChild, Logic::AtDay) &&
exit.CheckConditionAtAgeTime(Logic::IsChild, Logic::AtNight) &&
@@ -248,9 +247,11 @@ bool HasAccessTo(const RandomizerRegion area) {
return areaTable[area].HasAccess();
}
std::shared_ptr<Rando::Context> randoCtx;
void AreaTable_Init() {
using namespace Rando;
randoCtx = Context::GetInstance();
//Clear the array from any previous playthrough attempts. This is important so that
//locations which appear in both MQ and Vanilla dungeons don't get set in both areas.
areaTable.fill(Area("Invalid Area", "Invalid Area", RHT_NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {}));
@@ -380,18 +381,19 @@ namespace Areas {
}
void AccessReset() {
auto ctx = Rando::Context::GetInstance();
for (const RandomizerRegion area : GetAllAreas()) {
AreaTable(area)->ResetVariables();
}
if(Settings::HasNightStart) {
if(Settings::ResolvedStartingAge == AGE_CHILD) {
if(/*Settings::HasNightStart TODO:: Randomize Starting Time*/ false) {
if(ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD) {
AreaTable(RR_ROOT)->childNight = true;
} else {
AreaTable(RR_ROOT)->adultNight = true;
}
} else {
if(Settings::ResolvedStartingAge == AGE_CHILD) {
if(ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD) {
AreaTable(RR_ROOT)->childDay = true;
} else {
AreaTable(RR_ROOT)->adultDay = true;
@@ -401,6 +403,7 @@ namespace Areas {
//Reset exits and clear items from locations
void ResetAllLocations() {
auto ctx = Rando::Context::GetInstance();
for (const RandomizerRegion area : GetAllAreas()) {
AreaTable(area)->ResetVariables();
//Erase item from every location in this exit
@@ -410,14 +413,14 @@ namespace Areas {
}
}
if(Settings::HasNightStart) {
if(Settings::ResolvedStartingAge == AGE_CHILD) {
if (/*Settings::HasNightStart TODO:: Randomize Starting Time*/ false) {
if(ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD) {
AreaTable(RR_ROOT)->childNight = true;
} else {
AreaTable(RR_ROOT)->adultNight = true;
}
} else {
if(Settings::ResolvedStartingAge == AGE_CHILD) {
} else {
if(ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD) {
AreaTable(RR_ROOT)->childDay = true;
} else {
AreaTable(RR_ROOT)->adultDay = true;
@@ -428,7 +431,7 @@ namespace Areas {
bool HasTimePassAccess(uint8_t age) {
for (const RandomizerRegion areaKey : GetAllAreas()) {
auto area = AreaTable(areaKey);
if (area->timePass && ((age == AGE_CHILD && area->Child()) || (age == AGE_ADULT && area->Adult()))) {
if (area->timePass && ((age == RO_AGE_CHILD && area->Child()) || (age == RO_AGE_ADULT && area->Adult()))) {
return true;
}
}
@@ -495,11 +498,11 @@ Area* AreaTable(const RandomizerRegion areaKey) {
}
//Retrieve all the shuffable entrances of a specific type
std::vector<Entrance*> GetShuffleableEntrances(EntranceType type, bool onlyPrimary /*= true*/) {
std::vector<Entrance*> entrancesToShuffle = {};
std::vector<Rando::Entrance*> GetShuffleableEntrances(Rando::EntranceType type, bool onlyPrimary /*= true*/) {
std::vector<Rando::Entrance*> entrancesToShuffle = {};
for (RandomizerRegion area : Areas::GetAllAreas()) {
for (auto& exit: AreaTable(area)->exits) {
if ((exit.GetType() == type || type == EntranceType::All) && (exit.IsPrimary() || !onlyPrimary) && exit.GetType() != EntranceType::None) {
if ((exit.GetType() == type || type == Rando::EntranceType::All) && (exit.IsPrimary() || !onlyPrimary) && exit.GetType() != Rando::EntranceType::None) {
entrancesToShuffle.push_back(&exit);
}
}

View File

@@ -7,9 +7,13 @@
#include "logic.hpp"
#include "hint_list.hpp"
#include "fill.hpp"
#include "../context.h"
typedef bool (*ConditionFn)();
// I hate this but every alternative I can think of right now is worse
extern std::shared_ptr<Rando::Context> randoCtx;
class EventAccess {
public:
@@ -23,11 +27,12 @@ public:
}
bool ConditionsMet() const {
if (Settings::Logic.Is(LOGIC_NONE) || Settings::Logic.Is(LOGIC_VANILLA)) {
auto ctx = Rando::Context::GetInstance();
if (ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_NO_LOGIC) || ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_VANILLA)) {
return true;
} else if (Settings::Logic.Is(LOGIC_GLITCHLESS)) {
} else if (ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_GLITCHLESS)) {
return conditions_met[0]();
} else if (Settings::Logic.Is(LOGIC_GLITCHED)) {
} else if (ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_GLITCHED)) {
if (conditions_met[0]()) {
return true;
} else if (conditions_met[1] != NULL) {
@@ -77,11 +82,12 @@ public:
}
bool GetConditionsMet() const {
if (Settings::Logic.Is(LOGIC_NONE) || Settings::Logic.Is(LOGIC_VANILLA)) {
auto ctx = Rando::Context::GetInstance();
if (ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_NO_LOGIC) || ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_VANILLA)) {
return true;
} else if (Settings::Logic.Is(LOGIC_GLITCHLESS)) {
} else if (ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_GLITCHLESS)) {
return conditions_met[0]();
} else if (Settings::Logic.Is(LOGIC_GLITCHED)) {
} else if (ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_GLITCHED)) {
if (conditions_met[0]()) {
return true;
} else if (conditions_met[1] != NULL) {
@@ -107,8 +113,10 @@ protected:
bool CanBuy() const;
};
class Entrance;
enum class EntranceType;
namespace Rando {
class Entrance;
enum class EntranceType;
}
class Area {
public:
@@ -117,7 +125,7 @@ public:
bool timePass_,
std::vector<EventAccess> events_,
std::vector<LocationAccess> locations_,
std::list<Entrance> exits_);
std::list<Rando::Entrance> exits_);
~Area();
std::string regionName;
@@ -126,8 +134,8 @@ public:
bool timePass;
std::vector<EventAccess> events;
std::vector<LocationAccess> locations;
std::list<Entrance> exits;
std::list<Entrance*> entrances;
std::list<Rando::Entrance> exits;
std::list<Rando::Entrance*> entrances;
//^ The above exits are now stored in a list instead of a vector because
//the entrance randomization algorithm plays around with pointers to these
//entrances a lot. By putting the entrances in a list, we don't have to
@@ -144,11 +152,11 @@ public:
void AddExit(RandomizerRegion parentKey, RandomizerRegion newExitKey, ConditionFn condition);
void RemoveExit(Entrance* exitToRemove);
void RemoveExit(Rando::Entrance* exitToRemove);
void SetAsPrimary(RandomizerRegion exitToBePrimary);
Entrance* GetExit(RandomizerRegion exit);
Rando::Entrance* GetExit(RandomizerRegion exit);
bool Child() const {
return childDay || childNight;
@@ -240,7 +248,7 @@ namespace Areas {
void AreaTable_Init();
Area* AreaTable(const RandomizerRegion areaKey);
std::vector<Entrance*> GetShuffleableEntrances(EntranceType type, bool onlyPrimary = true);
std::vector<Rando::Entrance*> GetShuffleableEntrances(Rando::EntranceType type, bool onlyPrimary = true);
// Overworld
void AreaTable_Init_LostWoods();

View File

@@ -1,10 +1,10 @@
#include "../location_access.hpp"
#include "../logic.hpp"
#include "../entrance.hpp"
#include "../dungeon.hpp"
#include "../../entrance.h"
#include "../../dungeon.h"
using namespace Logic;
using namespace Settings;
using namespace Rando;
void AreaTable_Init_BottomOfTheWell() {
/*--------------------------
@@ -12,38 +12,38 @@ void AreaTable_Init_BottomOfTheWell() {
---------------------------*/
areaTable[RR_BOTTOM_OF_THE_WELL_ENTRYWAY] = Area("Bottom of the Well Entryway", "Bottom of the Well", RHT_BOTTOM_OF_THE_WELL, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_BOTTOM_OF_THE_WELL_MAIN_AREA, {[]{return Dungeon::BottomOfTheWell.IsVanilla() && IsChild && (CanChildAttack || Nuts);}}),
Entrance(RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER, {[]{return Dungeon::BottomOfTheWell.IsMQ() && IsChild;}}),
Entrance(RR_BOTTOM_OF_THE_WELL_MAIN_AREA, {[]{return randoCtx->GetDungeon(Rando::BOTTOM_OF_THE_WELL)->IsVanilla() && IsChild && (CanChildAttack || Nuts);}}),
Entrance(RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER, {[]{return randoCtx->GetDungeon(Rando::BOTTOM_OF_THE_WELL)->IsMQ() && IsChild;}}),
Entrance(RR_KAKARIKO_VILLAGE, {[]{return true;}}),
});
/*--------------------------
| VANILLA DUNGEON |
---------------------------*/
if (Dungeon::BottomOfTheWell.IsVanilla()) {
if (randoCtx->GetDungeon(Rando::BOTTOM_OF_THE_WELL)->IsVanilla()) {
areaTable[RR_BOTTOM_OF_THE_WELL_MAIN_AREA] = Area("Bottom of the Well Main Area", "Bottom of the Well", RHT_BOTTOM_OF_THE_WELL, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&StickPot, {[]{return true;}}),
EventAccess(&NutPot, {[]{return true;}}),
}, {
//Locations
LocationAccess(RC_BOTTOM_OF_THE_WELL_FRONT_LEFT_FAKE_WALL_CHEST, {[]{return LogicLensBotw || CanUse(RG_LENS_OF_TRUTH);}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_FRONT_LEFT_FAKE_WALL_CHEST, {[]{return randoCtx->GetTrickOption(RT_LENS_BOTW) || CanUse(RG_LENS_OF_TRUTH);}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_FRONT_CENTER_BOMBABLE_CHEST, {[]{return HasExplosives;}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_RIGHT_BOTTOM_FAKE_WALL_CHEST, {[]{return LogicLensBotw || CanUse(RG_LENS_OF_TRUTH);}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_COMPASS_CHEST, {[]{return LogicLensBotw || CanUse(RG_LENS_OF_TRUTH);}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_CENTER_SKULLTULA_CHEST, {[]{return LogicLensBotw || CanUse(RG_LENS_OF_TRUTH);}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_BACK_LEFT_BOMBABLE_CHEST, {[]{return (LogicLensBotw || CanUse(RG_LENS_OF_TRUTH)) && HasExplosives;}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_RIGHT_BOTTOM_FAKE_WALL_CHEST, {[]{return randoCtx->GetTrickOption(RT_LENS_BOTW) || CanUse(RG_LENS_OF_TRUTH);}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_COMPASS_CHEST, {[]{return randoCtx->GetTrickOption(RT_LENS_BOTW) || CanUse(RG_LENS_OF_TRUTH);}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_CENTER_SKULLTULA_CHEST, {[]{return randoCtx->GetTrickOption(RT_LENS_BOTW) || CanUse(RG_LENS_OF_TRUTH);}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_BACK_LEFT_BOMBABLE_CHEST, {[]{return (randoCtx->GetTrickOption(RT_LENS_BOTW) || CanUse(RG_LENS_OF_TRUTH)) && HasExplosives;}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_FREESTANDING_KEY, {[]{return Sticks || CanUse(RG_DINS_FIRE);}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_LENS_OF_TRUTH_CHEST, {[]{return CanPlay(ZeldasLullaby) && (KokiriSword || (Sticks && LogicChildDeadhand));}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_INVISIBLE_CHEST, {[]{return CanPlay(ZeldasLullaby) && (LogicLensBotw || CanUse(RG_LENS_OF_TRUTH));}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_LENS_OF_TRUTH_CHEST, {[]{return CanPlay(ZeldasLullaby) && (KokiriSword || (Sticks && randoCtx->GetTrickOption(RT_BOTW_CHILD_DEADHAND)));}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_INVISIBLE_CHEST, {[]{return CanPlay(ZeldasLullaby) && (randoCtx->GetTrickOption(RT_LENS_BOTW) || CanUse(RG_LENS_OF_TRUTH));}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_UNDERWATER_FRONT_CHEST, {[]{return CanPlay(ZeldasLullaby);}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_UNDERWATER_LEFT_CHEST, {[]{return CanPlay(ZeldasLullaby);}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_MAP_CHEST, {[]{return HasExplosives || (((SmallKeys(RR_BOTTOM_OF_THE_WELL, 3) && (LogicLensBotw || CanUse(RG_LENS_OF_TRUTH))) || CanUse(RG_DINS_FIRE) || (Sticks && LogicBotwBasement)) && GoronBracelet);}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_FIRE_KEESE_CHEST, {[]{return SmallKeys(RR_BOTTOM_OF_THE_WELL, 3) && (LogicLensBotw || CanUse(RG_LENS_OF_TRUTH));}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_LIKE_LIKE_CHEST, {[]{return SmallKeys(RR_BOTTOM_OF_THE_WELL, 3) && (LogicLensBotw || CanUse(RG_LENS_OF_TRUTH));}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_GS_WEST_INNER_ROOM, {[]{return Boomerang && (LogicLensBotw || CanUse(RG_LENS_OF_TRUTH)) && SmallKeys(RR_BOTTOM_OF_THE_WELL, 3);}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_GS_EAST_INNER_ROOM, {[]{return Boomerang && (LogicLensBotw || CanUse(RG_LENS_OF_TRUTH)) && SmallKeys(RR_BOTTOM_OF_THE_WELL, 3);}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_GS_LIKE_LIKE_CAGE, {[]{return SmallKeys(RR_BOTTOM_OF_THE_WELL, 3) && (LogicLensBotw || CanUse(RG_LENS_OF_TRUTH)) && Boomerang;}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_MAP_CHEST, {[]{return HasExplosives || (((SmallKeys(RR_BOTTOM_OF_THE_WELL, 3) && (randoCtx->GetTrickOption(RT_LENS_BOTW) || CanUse(RG_LENS_OF_TRUTH))) || CanUse(RG_DINS_FIRE) || (Sticks && randoCtx->GetTrickOption(RT_BOTW_BASEMENT))) && GoronBracelet);}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_FIRE_KEESE_CHEST, {[]{return SmallKeys(RR_BOTTOM_OF_THE_WELL, 3) && (randoCtx->GetTrickOption(RT_LENS_BOTW) || CanUse(RG_LENS_OF_TRUTH));}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_LIKE_LIKE_CHEST, {[]{return SmallKeys(RR_BOTTOM_OF_THE_WELL, 3) && (randoCtx->GetTrickOption(RT_LENS_BOTW) || CanUse(RG_LENS_OF_TRUTH));}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_GS_WEST_INNER_ROOM, {[]{return Boomerang && (randoCtx->GetTrickOption(RT_LENS_BOTW) || CanUse(RG_LENS_OF_TRUTH)) && SmallKeys(RR_BOTTOM_OF_THE_WELL, 3);}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_GS_EAST_INNER_ROOM, {[]{return Boomerang && (randoCtx->GetTrickOption(RT_LENS_BOTW) || CanUse(RG_LENS_OF_TRUTH)) && SmallKeys(RR_BOTTOM_OF_THE_WELL, 3);}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_GS_LIKE_LIKE_CAGE, {[]{return SmallKeys(RR_BOTTOM_OF_THE_WELL, 3) && (randoCtx->GetTrickOption(RT_LENS_BOTW) || CanUse(RG_LENS_OF_TRUTH)) && Boomerang;}}),
}, {
//Exits
Entrance(RR_BOTTOM_OF_THE_WELL_ENTRYWAY, {[]{return true;}}),
@@ -53,21 +53,21 @@ void AreaTable_Init_BottomOfTheWell() {
/*---------------------------
| MASTER QUEST DUNGEON |
---------------------------*/
if (Dungeon::BottomOfTheWell.IsMQ()) {
if (randoCtx->GetDungeon(Rando::BOTTOM_OF_THE_WELL)->IsMQ()) {
areaTable[RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER] = Area("Bottom of the Well MQ Perimeter", "Bottom of the Well", RHT_BOTTOM_OF_THE_WELL, NO_DAY_NIGHT_CYCLE, {
//Events
//EventAccess(&WallFairy, {[]{return WallFairy || Slingshot;}}),
}, {
//Locations
LocationAccess(RC_BOTTOM_OF_THE_WELL_MQ_COMPASS_CHEST, {[]{return KokiriSword || (Sticks && LogicChildDeadhand);}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_MQ_DEAD_HAND_FREESTANDING_KEY, {[]{return HasExplosives || (LogicBotwMQDeadHandKey && Boomerang);}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_MQ_COMPASS_CHEST, {[]{return KokiriSword || (Sticks && randoCtx->GetTrickOption(RT_BOTW_CHILD_DEADHAND));}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_MQ_DEAD_HAND_FREESTANDING_KEY, {[]{return HasExplosives || (randoCtx->GetTrickOption(RT_BOTW_MQ_DEADHAND_KEY) && Boomerang);}}),
//Trick: HasExplosives || (LogicBotWMQDeadHandKey && Boomerang)
LocationAccess(RC_BOTTOM_OF_THE_WELL_MQ_GS_BASEMENT, {[]{return CanChildAttack;}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_MQ_GS_COFFIN_ROOM, {[]{return CanChildAttack && SmallKeys(RR_BOTTOM_OF_THE_WELL, 2);}}),
}, {
//Exits
Entrance(RR_BOTTOM_OF_THE_WELL_ENTRYWAY, {[]{return true;}}),
Entrance(RR_BOTTOM_OF_THE_WELL_MQ_MIDDLE, {[]{return CanPlay(ZeldasLullaby) || (LogicBotwMQPits && HasExplosives);}}),
Entrance(RR_BOTTOM_OF_THE_WELL_MQ_MIDDLE, {[]{return CanPlay(ZeldasLullaby) || (randoCtx->GetTrickOption(RT_BOTW_MQ_PITS) && HasExplosives);}}),
//Trick: CanPlay(ZeldasLullaby) || (LogicBotWMQPits && HasExplosives)
});
@@ -76,7 +76,7 @@ void AreaTable_Init_BottomOfTheWell() {
LocationAccess(RC_BOTTOM_OF_THE_WELL_MQ_MAP_CHEST, {[]{return true;}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_MQ_LENS_OF_TRUTH_CHEST, {[]{return HasExplosives && SmallKeys(RR_BOTTOM_OF_THE_WELL, 2);}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_MQ_EAST_INNER_ROOM_FREESTANDING_KEY, {[]{return true;}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_MQ_GS_WEST_INNER_ROOM, {[]{return CanChildAttack && (LogicBotwMQPits || HasExplosives);}}),
LocationAccess(RC_BOTTOM_OF_THE_WELL_MQ_GS_WEST_INNER_ROOM, {[]{return CanChildAttack && (randoCtx->GetTrickOption(RT_BOTW_MQ_PITS) || HasExplosives);}}),
//Trick: CanChildAttack && (LogicBotWMQPits || HasExplosives)
}, {
//Exits

View File

@@ -1,9 +1,9 @@
#include "../location_access.hpp"
#include "../logic.hpp"
#include "../entrance.hpp"
#include "../../entrance.h"
using namespace Logic;
using namespace Settings;
using namespace Rando;
void AreaTable_Init_CastleTown() {
areaTable[RR_MARKET_ENTRANCE] = Area("Market Entrance", "Market Entrance", RHT_THE_MARKET, NO_DAY_NIGHT_CYCLE, {}, {}, {
@@ -58,7 +58,7 @@ void AreaTable_Init_CastleTown() {
}, {
//Exits
Entrance(RR_TOT_ENTRANCE, {[]{return true;}}),
Entrance(RR_TOT_BEYOND_DOOR_OF_TIME, {[]{return OpenDoorOfTime.Is(OPENDOOROFTIME_OPEN) || (CanPlay(SongOfTime) && (OpenDoorOfTime.Is(OPENDOOROFTIME_SONGONLY) || (HasAllStones && OcarinaOfTime)));}}),
Entrance(RR_TOT_BEYOND_DOOR_OF_TIME, {[]{return randoCtx->GetOption(RSK_DOOR_OF_TIME).Is(RO_DOOROFTIME_OPEN) || (CanPlay(SongOfTime) && (randoCtx->GetOption(RSK_DOOR_OF_TIME).Is(RO_DOOROFTIME_SONGONLY) || (HasAllStones && OcarinaOfTime)));}}),
});
areaTable[RR_TOT_BEYOND_DOOR_OF_TIME] = Area("Beyond Door of Time", "Beyond Door of Time", RHT_TEMPLE_OF_TIME, NO_DAY_NIGHT_CYCLE, {
@@ -94,7 +94,7 @@ void AreaTable_Init_CastleTown() {
}, {
//Exits
Entrance(RR_CASTLE_GROUNDS, {[]{return true;}}),
Entrance(RR_HC_GARDEN, {[]{return WeirdEgg || !ShuffleWeirdEgg;}}),
Entrance(RR_HC_GARDEN, {[]{return WeirdEgg || !randoCtx->GetOption(RSK_SHUFFLE_WEIRD_EGG);}}),
Entrance(RR_HC_GREAT_FAIRY_FOUNTAIN, {[]{return CanBlastOrSmash;}}),
Entrance(RR_HC_STORMS_GROTTO, {[]{return CanOpenStormGrotto;}}),
});
@@ -125,7 +125,7 @@ void AreaTable_Init_CastleTown() {
EventAccess(&WanderingBugs, {[]{return WanderingBugs || CanBlastOrSmash;}}),
}, {
//Locations
LocationAccess(RC_HC_GS_STORMS_GROTTO, {[]{return (CanBlastOrSmash && HookshotOrBoomerang) || (Boomerang && LogicCastleStormsGS);}}),
LocationAccess(RC_HC_GS_STORMS_GROTTO, {[]{return (CanBlastOrSmash && HookshotOrBoomerang) || (Boomerang && randoCtx->GetTrickOption(RT_HC_STORMS_GS));}}),
LocationAccess(RC_HC_STORMS_GROTTO_GOSSIP_STONE, {[]{return CanBlastOrSmash;}}),
}, {
//Exits
@@ -192,8 +192,8 @@ void AreaTable_Init_CastleTown() {
areaTable[RR_MARKET_MASK_SHOP] = Area("Market Mask Shop", "Market Mask Shop", RHT_NONE, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&SkullMask, {[]{return SkullMask || (ZeldasLetter && (CompleteMaskQuest || ChildCanAccess(RR_KAKARIKO_VILLAGE)));}}),
EventAccess(&MaskOfTruth, {[]{return MaskOfTruth || (SkullMask && (CompleteMaskQuest || (ChildCanAccess(RR_THE_LOST_WOODS) && CanPlay(SariasSong) && AreaTable(RR_THE_GRAVEYARD)->childDay && ChildCanAccess(RR_HYRULE_FIELD) && HasAllStones)));}}),
EventAccess(&SkullMask, {[]{return SkullMask || (ZeldasLetter && (randoCtx->GetOption(RSK_COMPLETE_MASK_QUEST) || ChildCanAccess(RR_KAKARIKO_VILLAGE)));}}),
EventAccess(&MaskOfTruth, {[]{return MaskOfTruth || (SkullMask && (randoCtx->GetOption(RSK_COMPLETE_MASK_QUEST) || (ChildCanAccess(RR_THE_LOST_WOODS) && CanPlay(SariasSong) && AreaTable(RR_THE_GRAVEYARD)->childDay && ChildCanAccess(RR_HYRULE_FIELD) && HasAllStones)));}}),
}, {}, {
//Exits
Entrance(RR_THE_MARKET, {[]{return true;}}),
@@ -235,12 +235,12 @@ void AreaTable_Init_CastleTown() {
areaTable[RR_MARKET_TREASURE_CHEST_GAME] = Area("Market Treasure Chest Game", "Market Treasure Chest Game", RHT_NONE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_GREG_HINT, {[]{return true;}}),
LocationAccess(RC_MARKET_TREASURE_CHEST_GAME_REWARD, {[]{return (CanUse(RG_LENS_OF_TRUTH) && !ShuffleChestMinigame) || (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_SINGLE_KEYS) && SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 6)) || (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_PACK) && SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1));}}),
LocationAccess(RC_MARKET_TREASURE_CHEST_GAME_ITEM_1, {[]{return (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_SINGLE_KEYS) && SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_PACK) && SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (CanUse(RG_LENS_OF_TRUTH) && !ShuffleChestMinigame);}}),
LocationAccess(RC_MARKET_TREASURE_CHEST_GAME_ITEM_2, {[]{return (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_SINGLE_KEYS) && SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 2)) || (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_PACK) && SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (CanUse(RG_LENS_OF_TRUTH) && !ShuffleChestMinigame);}}),
LocationAccess(RC_MARKET_TREASURE_CHEST_GAME_ITEM_3, {[]{return (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_SINGLE_KEYS) && SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 3)) || (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_PACK) && SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (CanUse(RG_LENS_OF_TRUTH) && !ShuffleChestMinigame);}}),
LocationAccess(RC_MARKET_TREASURE_CHEST_GAME_ITEM_4, {[]{return (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_SINGLE_KEYS) && SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 4)) || (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_PACK) && SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (CanUse(RG_LENS_OF_TRUTH) && !ShuffleChestMinigame);}}),
LocationAccess(RC_MARKET_TREASURE_CHEST_GAME_ITEM_5, {[]{return (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_SINGLE_KEYS) && SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 5)) || (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_PACK) && SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (CanUse(RG_LENS_OF_TRUTH) && !ShuffleChestMinigame);}}),
LocationAccess(RC_MARKET_TREASURE_CHEST_GAME_REWARD, {[]{return (CanUse(RG_LENS_OF_TRUTH) && !randoCtx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)) || (randoCtx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 6)) || (randoCtx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1));}}),
LocationAccess(RC_MARKET_TREASURE_CHEST_GAME_ITEM_1, {[]{return (randoCtx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (randoCtx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (CanUse(RG_LENS_OF_TRUTH) && !randoCtx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME));}}),
LocationAccess(RC_MARKET_TREASURE_CHEST_GAME_ITEM_2, {[]{return (randoCtx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 2)) || (randoCtx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (CanUse(RG_LENS_OF_TRUTH) && !randoCtx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME));}}),
LocationAccess(RC_MARKET_TREASURE_CHEST_GAME_ITEM_3, {[]{return (randoCtx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 3)) || (randoCtx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (CanUse(RG_LENS_OF_TRUTH) && !randoCtx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME));}}),
LocationAccess(RC_MARKET_TREASURE_CHEST_GAME_ITEM_4, {[]{return (randoCtx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 4)) || (randoCtx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (CanUse(RG_LENS_OF_TRUTH) && !randoCtx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME));}}),
LocationAccess(RC_MARKET_TREASURE_CHEST_GAME_ITEM_5, {[]{return (randoCtx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 5)) || (randoCtx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (CanUse(RG_LENS_OF_TRUTH) && !randoCtx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME));}}),
}, {
//Exits
Entrance(RR_THE_MARKET, {[]{return true;}}),

View File

@@ -1,26 +1,27 @@
#include "../location_access.hpp"
#include "../logic.hpp"
#include "../entrance.hpp"
#include "../../entrance.h"
using namespace Logic;
using namespace Settings;
using namespace Rando;
void AreaTable_Init_DeathMountain() {
auto ctx = Rando::Context::GetInstance();
areaTable[RR_DEATH_MOUNTAIN_TRAIL] = Area("Death Mountain", "Death Mountain", RHT_DEATH_MOUNTAIN_TRAIL, DAY_NIGHT_CYCLE, {
//Events
EventAccess(&BeanPlantFairy, {[]{return BeanPlantFairy || (CanPlantBean(RR_DEATH_MOUNTAIN_TRAIL) && CanPlay(SongOfStorms) && (HasExplosives || GoronBracelet));}}),
}, {
//Locations
LocationAccess(RC_DMT_CHEST, {[]{return CanBlastOrSmash || (LogicDMTBombable && IsChild && GoronBracelet);}}),
LocationAccess(RC_DMT_CHEST, {[]{return CanBlastOrSmash || (randoCtx->GetTrickOption(RT_DMT_BOMBABLE) && IsChild && GoronBracelet);}}),
LocationAccess(RC_DMT_FREESTANDING_POH, {[]{return CanTakeDamage || CanUse(RG_HOVER_BOOTS) || (IsAdult && CanPlantBean(RR_DEATH_MOUNTAIN_TRAIL) && (HasExplosives || GoronBracelet));}}),
LocationAccess(RC_DMT_GS_BEAN_PATCH, {[]{return CanPlantBugs && (HasExplosives || GoronBracelet || (LogicDMTSoilGS && (CanTakeDamage || CanUse(RG_HOVER_BOOTS)) && CanUse(RG_BOOMERANG)));}}),
LocationAccess(RC_DMT_GS_BEAN_PATCH, {[]{return CanPlantBugs && (HasExplosives || GoronBracelet || (randoCtx->GetTrickOption(RT_DMT_SOIL_GS) && (CanTakeDamage || CanUse(RG_HOVER_BOOTS)) && CanUse(RG_BOOMERANG)));}}),
LocationAccess(RC_DMT_GS_NEAR_KAK, {[]{return CanBlastOrSmash;}}),
LocationAccess(RC_DMT_GS_ABOVE_DODONGOS_CAVERN, {[]{return IsAdult && AtNight && (CanUse(RG_MEGATON_HAMMER) || (LogicDMTGSLowerHookshot && CanUse(RG_HOOKSHOT)) || (LogicDMTGSLowerBean && CanPlantBean(RR_DEATH_MOUNTAIN_TRAIL)) || (LogicDMTGSLowerHovers && CanUse(RG_HOVER_BOOTS)) || LogicDMTGSLowerJS) && CanGetNightTimeGS;}}),
LocationAccess(RC_DMT_GS_ABOVE_DODONGOS_CAVERN, {[]{return IsAdult && AtNight && (CanUse(RG_MEGATON_HAMMER) || (randoCtx->GetTrickOption(RT_DMT_HOOKSHOT_LOWER_GS) && CanUse(RG_HOOKSHOT)) || (randoCtx->GetTrickOption(RT_DMT_BEAN_LOWER_GS) && CanPlantBean(RR_DEATH_MOUNTAIN_TRAIL)) || (randoCtx->GetTrickOption(RT_DMT_HOVERS_LOWER_GS) && CanUse(RG_HOVER_BOOTS)) || randoCtx->GetTrickOption(RT_DMT_JS_LOWER_GS)) && CanGetNightTimeGS;}}),
}, {
//Exits
Entrance(RR_KAK_BEHIND_GATE, {[]{return true;}}),
Entrance(RR_GORON_CITY, {[]{return true;}}),
Entrance(RR_DEATH_MOUNTAIN_SUMMIT, {[]{return Here(RR_DEATH_MOUNTAIN_TRAIL, []{return CanBlastOrSmash;}) || (IsAdult && ((CanPlantBean(RR_DEATH_MOUNTAIN_TRAIL) && GoronBracelet) || (HoverBoots && LogicDMTClimbHovers)));}}),
Entrance(RR_DEATH_MOUNTAIN_SUMMIT, {[]{return Here(RR_DEATH_MOUNTAIN_TRAIL, []{return CanBlastOrSmash;}) || (IsAdult && ((CanPlantBean(RR_DEATH_MOUNTAIN_TRAIL) && GoronBracelet) || (HoverBoots && randoCtx->GetTrickOption(RT_DMT_CLIMB_HOVERS))));}}),
Entrance(RR_DODONGOS_CAVERN_ENTRYWAY, {[]{return HasExplosives || GoronBracelet || IsAdult;}}),
Entrance(RR_DMT_STORMS_GROTTO, {[]{return CanOpenStormGrotto;}}),
});
@@ -35,7 +36,7 @@ void AreaTable_Init_DeathMountain() {
LocationAccess(RC_DMT_TRADE_BROKEN_SWORD, {[]{return IsAdult && BrokenSword;}}),
LocationAccess(RC_DMT_TRADE_EYEDROPS, {[]{return IsAdult && Eyedrops;}}),
LocationAccess(RC_DMT_TRADE_CLAIM_CHECK, {[]{return IsAdult && ClaimCheck;}}),
LocationAccess(RC_DMT_GS_FALLING_ROCKS_PATH, {[]{return IsAdult && AtNight && (CanUse(RG_MEGATON_HAMMER) || LogicDMTGSUpper) && CanGetNightTimeGS;}}),
LocationAccess(RC_DMT_GS_FALLING_ROCKS_PATH, {[]{return IsAdult && AtNight && (CanUse(RG_MEGATON_HAMMER) || randoCtx->GetTrickOption(RT_DMT_UPPER_GS)) && CanGetNightTimeGS;}}),
LocationAccess(RC_DMT_GOSSIP_STONE, {[]{return true;}}),
}, {
//Exits
@@ -85,14 +86,14 @@ void AreaTable_Init_DeathMountain() {
EventAccess(&GoronCityChildFire, {[]{return GoronCityChildFire || (IsChild && CanUse(RG_DINS_FIRE));}}),
EventAccess(&GCWoodsWarpOpen, {[]{return GCWoodsWarpOpen || (CanBlastOrSmash || CanUse(RG_DINS_FIRE) || CanUse(RG_FAIRY_BOW) || GoronBracelet || GoronCityChildFire);}}),
EventAccess(&GCDaruniasDoorOpenChild, {[]{return GCDaruniasDoorOpenChild || (IsChild && CanPlay(ZeldasLullaby));}}),
EventAccess(&StopGCRollingGoronAsAdult, {[]{return StopGCRollingGoronAsAdult || (IsAdult && (GoronBracelet || HasExplosives || Bow || (LogicGoronCityLinkGoronDins && CanUse(RG_DINS_FIRE))));}}),
EventAccess(&StopGCRollingGoronAsAdult, {[]{return StopGCRollingGoronAsAdult || (IsAdult && (GoronBracelet || HasExplosives || Bow || (randoCtx->GetTrickOption(RT_GC_LINK_GORON_DINS) && CanUse(RG_DINS_FIRE))));}}),
}, {
//Locations
LocationAccess(RC_GC_MAZE_LEFT_CHEST, {[]{return CanUse(RG_MEGATON_HAMMER) || CanUse(RG_SILVER_GAUNTLETS) || (LogicGoronCityLeftMost && HasExplosives && CanUse(RG_HOVER_BOOTS));}}),
LocationAccess(RC_GC_MAZE_LEFT_CHEST, {[]{return CanUse(RG_MEGATON_HAMMER) || CanUse(RG_SILVER_GAUNTLETS) || (randoCtx->GetTrickOption(RT_GC_LEFTMOST) && HasExplosives && CanUse(RG_HOVER_BOOTS));}}),
LocationAccess(RC_GC_MAZE_CENTER_CHEST, {[]{return CanBlastOrSmash || CanUse(RG_SILVER_GAUNTLETS);}}),
LocationAccess(RC_GC_MAZE_RIGHT_CHEST, {[]{return CanBlastOrSmash || CanUse(RG_SILVER_GAUNTLETS);}}),
LocationAccess(RC_GC_POT_FREESTANDING_POH, {[]{return IsChild && GoronCityChildFire && (Bombs || (GoronBracelet && LogicGoronCityPotWithStrength) || (HasBombchus && LogicGoronCityPot));}}),
LocationAccess(RC_GC_ROLLING_GORON_AS_CHILD, {[]{return IsChild && (HasExplosives || (GoronBracelet && LogicChildRollingWithStrength));}}),
LocationAccess(RC_GC_POT_FREESTANDING_POH, {[]{return IsChild && GoronCityChildFire && (Bombs || (GoronBracelet && randoCtx->GetTrickOption(RT_GC_POT_STRENGTH)) || (HasBombchus && randoCtx->GetTrickOption(RT_GC_POT)));}}),
LocationAccess(RC_GC_ROLLING_GORON_AS_CHILD, {[]{return IsChild && (HasExplosives || (GoronBracelet && randoCtx->GetTrickOption(RT_GC_ROLLING_STRENGTH)));}}),
LocationAccess(RC_GC_ROLLING_GORON_AS_ADULT, {[]{return StopGCRollingGoronAsAdult;}}),
LocationAccess(RC_GC_GS_BOULDER_MAZE, {[]{return IsChild && CanBlastOrSmash;}}),
LocationAccess(RC_GC_GS_CENTER_PLATFORM, {[]{return CanAdultAttack;}}),
@@ -105,7 +106,7 @@ void AreaTable_Init_DeathMountain() {
Entrance(RR_GC_WOODS_WARP, {[]{return GCWoodsWarpOpen;}}),
Entrance(RR_GC_SHOP, {[]{return (IsAdult && StopGCRollingGoronAsAdult) || (IsChild && (CanBlastOrSmash || GoronBracelet || GoronCityChildFire || CanUse(RG_FAIRY_BOW)));}}),
Entrance(RR_GC_DARUNIAS_CHAMBER, {[]{return (IsAdult && StopGCRollingGoronAsAdult) || GCDaruniasDoorOpenChild;}}),
Entrance(RR_GC_GROTTO_PLATFORM, {[]{return IsAdult && ((CanPlay(SongOfTime) && ((EffectiveHealth > 2) || CanUse(RG_GORON_TUNIC) || CanUse(RG_LONGSHOT) || CanUse(RG_NAYRUS_LOVE))) || (EffectiveHealth > 1 && CanUse(RG_GORON_TUNIC) && CanUse(RG_HOOKSHOT)) || (CanUse(RG_NAYRUS_LOVE) && CanUse(RG_HOOKSHOT)) || (EffectiveHealth > 2 && CanUse(RG_HOOKSHOT) && LogicGoronCityGrotto));}}),
Entrance(RR_GC_GROTTO_PLATFORM, {[]{return IsAdult && ((CanPlay(SongOfTime) && ((EffectiveHealth > 2) || CanUse(RG_GORON_TUNIC) || CanUse(RG_LONGSHOT) || CanUse(RG_NAYRUS_LOVE))) || (EffectiveHealth > 1 && CanUse(RG_GORON_TUNIC) && CanUse(RG_HOOKSHOT)) || (CanUse(RG_NAYRUS_LOVE) && CanUse(RG_HOOKSHOT)) || (EffectiveHealth > 2 && CanUse(RG_HOOKSHOT) && randoCtx->GetTrickOption(RT_GC_GROTTO)));}}),
});
areaTable[RR_GC_WOODS_WARP] = Area("GC Woods Warp", "Goron City", RHT_GORON_CITY, NO_DAY_NIGHT_CYCLE, {
@@ -179,7 +180,7 @@ void AreaTable_Init_DeathMountain() {
//Exits
Entrance(RR_DMC_UPPER_NEARBY, {[]{return true;}}),
Entrance(RR_DMC_LADDER_AREA_NEARBY, {[]{return FireTimer >= 16 || Hearts >= 3;}}),
Entrance(RR_DMC_CENTRAL_NEARBY, {[]{return IsAdult && CanUse(RG_GORON_TUNIC) && CanUse(RG_DISTANT_SCARECROW) && ((EffectiveHealth > 2) || (Fairy && ShuffleDungeonEntrances.IsNot(SHUFFLEDUNGEONS_OFF)) || CanUse(RG_NAYRUS_LOVE));}}),
Entrance(RR_DMC_CENTRAL_NEARBY, {[]{return IsAdult && CanUse(RG_GORON_TUNIC) && CanUse(RG_DISTANT_SCARECROW) && ((EffectiveHealth > 2) || (Fairy && randoCtx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).IsNot(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF)) || CanUse(RG_NAYRUS_LOVE));}}),
Entrance(RR_DMC_LOWER_NEARBY, {[]{return false;}}),
});
@@ -189,7 +190,7 @@ void AreaTable_Init_DeathMountain() {
}, {
//Exits
Entrance(RR_DMC_UPPER_NEARBY, {[]{return Hearts >= 3;}}),
Entrance(RR_DMC_LOWER_NEARBY, {[]{return Hearts >= 3 && (CanUse(RG_HOVER_BOOTS) || (LogicCraterBoulderJS && IsAdult && CanUse(RG_MEGATON_HAMMER)) || (LogicCraterBoulderSkip && IsAdult));}}),
Entrance(RR_DMC_LOWER_NEARBY, {[]{return Hearts >= 3 && (CanUse(RG_HOVER_BOOTS) || (randoCtx->GetTrickOption(RT_DMC_BOULDER_JS) && IsAdult && CanUse(RG_MEGATON_HAMMER)) || (randoCtx->GetTrickOption(RT_DMC_BOULDER_SKIP) && IsAdult));}}),
});
areaTable[RR_DMC_LOWER_NEARBY] = Area("DMC Lower Nearby", "Death Mountain Crater", RHT_DEATH_MOUNTAIN_CRATER, NO_DAY_NIGHT_CYCLE, {}, {}, {
@@ -205,12 +206,12 @@ void AreaTable_Init_DeathMountain() {
Entrance(RR_DMC_LOWER_NEARBY, {[]{return true;}}),
Entrance(RR_DMC_LADDER_AREA_NEARBY, {[]{return FireTimer >= 8 || Hearts >= 3;}}),
Entrance(RR_DMC_CENTRAL_NEARBY, {[]{return (CanUse(RG_HOVER_BOOTS) || CanUse(RG_HOOKSHOT)) && (FireTimer >= 8 || Hearts >= 3);}}),
Entrance(RR_DMC_CENTRAL_LOCAL, {[]{return (CanUse(RG_HOVER_BOOTS) || CanUse(RG_HOOKSHOT) || (IsAdult && CanShield && LogicCraterBoleroJump)) && FireTimer >= 24;}}),
Entrance(RR_DMC_CENTRAL_LOCAL, {[]{return (CanUse(RG_HOVER_BOOTS) || CanUse(RG_HOOKSHOT) || (IsAdult && CanShield && randoCtx->GetTrickOption(RT_DMC_BOLERO_JUMP))) && FireTimer >= 24;}}),
});
areaTable[RR_DMC_CENTRAL_NEARBY] = Area("DMC Central Nearby", "Death Mountain Crater", RHT_DEATH_MOUNTAIN_CRATER, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_DMC_VOLCANO_FREESTANDING_POH, {[]{return IsAdult && Hearts >= 3 && (CanPlantBean(RR_DMC_CENTRAL_LOCAL) || (LogicCraterBeanPoHWithHovers && HoverBoots));}}),
LocationAccess(RC_DMC_VOLCANO_FREESTANDING_POH, {[]{return IsAdult && Hearts >= 3 && (CanPlantBean(RR_DMC_CENTRAL_LOCAL) || (randoCtx->GetTrickOption(RT_DMC_HOVER_BEAN_POH) && HoverBoots));}}),
LocationAccess(RC_SHEIK_IN_CRATER, {[]{return IsAdult && (FireTimer >= 8 || Hearts >= 3);}}),
}, {
//Exits
@@ -228,7 +229,7 @@ void AreaTable_Init_DeathMountain() {
Entrance(RR_DMC_CENTRAL_NEARBY, {[]{return true;}}),
Entrance(RR_DMC_LOWER_NEARBY, {[]{return (IsAdult && CanPlantBean(RR_DMC_CENTRAL_LOCAL)) || CanUse(RG_HOVER_BOOTS) || CanUse(RG_HOOKSHOT);}}),
Entrance(RR_DMC_UPPER_NEARBY, {[]{return IsAdult && CanPlantBean(RR_DMC_CENTRAL_LOCAL);}}),
Entrance(RR_FIRE_TEMPLE_ENTRYWAY, {[]{return (IsChild && Hearts >= 3 && ShuffleDungeonEntrances.IsNot(SHUFFLEDUNGEONS_OFF)) || (IsAdult && FireTimer >= 24);}}),
Entrance(RR_FIRE_TEMPLE_ENTRYWAY, {[]{return (IsChild && Hearts >= 3 && randoCtx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).IsNot(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF)) || (IsAdult && FireTimer >= 24);}}),
});
areaTable[RR_DMC_GREAT_FAIRY_FOUNTAIN] = Area("DMC Great Fairy Fountain", "DMC Great Fairy Fountain", RHT_NONE, NO_DAY_NIGHT_CYCLE, {}, {

View File

@@ -1,10 +1,10 @@
#include "../location_access.hpp"
#include "../logic.hpp"
#include "../entrance.hpp"
#include "../dungeon.hpp"
#include "../../entrance.h"
#include "../../dungeon.h"
using namespace Logic;
using namespace Settings;
using namespace Rando;
void AreaTable_Init_DekuTree() {
/*--------------------------
@@ -12,15 +12,15 @@ void AreaTable_Init_DekuTree() {
---------------------------*/
areaTable[RR_DEKU_TREE_ENTRYWAY] = Area("Deku Tree Entryway", "Deku Tree", RHT_DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_DEKU_TREE_LOBBY, {[]{return Dungeon::DekuTree.IsVanilla();}}),
Entrance(RR_DEKU_TREE_MQ_LOBBY, {[]{return Dungeon::DekuTree.IsMQ();}}),
Entrance(RR_DEKU_TREE_LOBBY, {[]{return randoCtx->GetDungeon(DEKU_TREE)->IsVanilla();}}),
Entrance(RR_DEKU_TREE_MQ_LOBBY, {[]{return randoCtx->GetDungeon(DEKU_TREE)->IsMQ();}}),
Entrance(RR_KF_OUTSIDE_DEKU_TREE, {[]{return true;}}),
});
/*--------------------------
| VANILLA DUNGEON |
---------------------------*/
if (Dungeon::DekuTree.IsVanilla()) {
if (randoCtx->GetDungeon(DEKU_TREE)->IsVanilla()) {
areaTable[RR_DEKU_TREE_LOBBY] = Area("Deku Tree Lobby", "Deku Tree", RHT_DEKU_TREE, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || (CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD) || CanUse(RG_BOOMERANG));}}),
@@ -77,12 +77,12 @@ void AreaTable_Init_DekuTree() {
//Locations
LocationAccess(RC_DEKU_TREE_BASEMENT_CHEST, {[]{return true;}}),
LocationAccess(RC_DEKU_TREE_GS_BASEMENT_GATE, {[]{return CanJumpslash || CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_BOOMERANG) || HasExplosives || CanUse(RG_FAIRY_BOW) || CanUse(RG_HOOKSHOT) || CanUse(RG_DINS_FIRE);}}),
LocationAccess(RC_DEKU_TREE_GS_BASEMENT_VINES, {[]{return CanUseProjectile || CanUse(RG_DINS_FIRE) || (LogicDekuBasementGS && CanJumpslash);}}),
LocationAccess(RC_DEKU_TREE_GS_BASEMENT_VINES, {[]{return CanUseProjectile || CanUse(RG_DINS_FIRE) || (randoCtx->GetTrickOption(RT_DEKU_MQ_COMPASS_GS) && CanJumpslash);}}),
}, {
//Exits
Entrance(RR_DEKU_TREE_LOBBY, {[]{return true;}}),
Entrance(RR_DEKU_TREE_BASEMENT_SCRUB_ROOM, {[]{return Here(RR_DEKU_TREE_BASEMENT_LOWER, []{return HasFireSourceWithTorch || CanUse(RG_FAIRY_BOW);});}}),
Entrance(RR_DEKU_TREE_BASEMENT_UPPER, {[]{return IsAdult || LogicDekuB1Skip || HasAccessTo(RR_DEKU_TREE_BASEMENT_UPPER);}}),
Entrance(RR_DEKU_TREE_BASEMENT_UPPER, {[]{return IsAdult || randoCtx->GetTrickOption(RT_DEKU_B1_SKIP) || HasAccessTo(RR_DEKU_TREE_BASEMENT_UPPER);}}),
Entrance(RR_DEKU_TREE_OUTSIDE_BOSS_ROOM, {[]{return false;}}),
});
@@ -137,7 +137,7 @@ void AreaTable_Init_DekuTree() {
//Exits
Entrance(RR_DEKU_TREE_BASEMENT_LOWER, {[]{return true;}}),
Entrance(RR_DEKU_TREE_BASEMENT_BACK_LOBBY, {[]{return IsChild;}}),
Entrance(RR_DEKU_TREE_OUTSIDE_BOSS_ROOM, {[]{return Here(RR_DEKU_TREE_BASEMENT_UPPER, []{return HasFireSourceWithTorch || (LogicDekuB1WebsWithBow && IsAdult && CanUse(RG_FAIRY_BOW));});}}),
Entrance(RR_DEKU_TREE_OUTSIDE_BOSS_ROOM, {[]{return Here(RR_DEKU_TREE_BASEMENT_UPPER, []{return HasFireSourceWithTorch || (randoCtx->GetTrickOption(RT_DEKU_B1_BOW_WEBS) && IsAdult && CanUse(RG_FAIRY_BOW));});}}),
});
areaTable[RR_DEKU_TREE_OUTSIDE_BOSS_ROOM] = Area("Deku Tree Outside Boss Room", "Deku Tree", RHT_DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, {}, {
@@ -150,7 +150,7 @@ void AreaTable_Init_DekuTree() {
/*---------------------------
| MASTER QUEST DUNGEON |
---------------------------*/
if (Dungeon::DekuTree.IsMQ()) {
if (randoCtx->GetDungeon(DEKU_TREE)->IsMQ()) {
areaTable[RR_DEKU_TREE_MQ_LOBBY] = Area("Deku Tree MQ Lobby", "Deku Tree", RHT_DEKU_TREE, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || (CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD) || CanUse(RG_BOOMERANG));}}),
@@ -169,7 +169,7 @@ void AreaTable_Init_DekuTree() {
Here(RR_DEKU_TREE_MQ_LOBBY, []{return HasFireSourceWithTorch || (IsAdult && CanUse(RG_FAIRY_BOW));});}}),
Entrance(RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT, {[]{return Here(RR_DEKU_TREE_MQ_LOBBY, []{return (IsChild && CanUse(RG_FAIRY_SLINGSHOT)) || (IsAdult && CanUse(RG_FAIRY_BOW));}) &&
Here(RR_DEKU_TREE_MQ_LOBBY, []{return HasFireSourceWithTorch;});}}),
Entrance(RR_DEKU_TREE_MQ_BASEMENT_LEDGE, {[]{return LogicDekuB1Skip || Here(RR_DEKU_TREE_MQ_LOBBY, []{return IsAdult;});}}),
Entrance(RR_DEKU_TREE_MQ_BASEMENT_LEDGE, {[]{return randoCtx->GetTrickOption(RT_DEKU_B1_SKIP) || Here(RR_DEKU_TREE_MQ_LOBBY, []{return IsAdult;});}}),
});
areaTable[RR_DEKU_TREE_MQ_COMPASS_ROOM] = Area("Deku Tree MQ Compass Room", "Deku Tree", RHT_DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, {
@@ -178,7 +178,7 @@ void AreaTable_Init_DekuTree() {
LocationAccess(RC_DEKU_TREE_MQ_GS_COMPASS_ROOM, {[]{return HookshotOrBoomerang &&
Here(RR_DEKU_TREE_MQ_COMPASS_ROOM, []{return HasBombchus ||
(Bombs && (CanPlay(SongOfTime) || IsAdult)) ||
(IsAdult && CanUse(RG_MEGATON_HAMMER) && (CanPlay(SongOfTime) || LogicDekuMQCompassGS));});}}),
(IsAdult && CanUse(RG_MEGATON_HAMMER) && (CanPlay(SongOfTime) || randoCtx->GetTrickOption(RT_DEKU_MQ_COMPASS_GS)));});}}),
}, {
//Exits
Entrance(RR_DEKU_TREE_MQ_LOBBY, {[]{return true;}}),
@@ -189,7 +189,7 @@ void AreaTable_Init_DekuTree() {
LocationAccess(RC_DEKU_TREE_MQ_BEFORE_SPINNING_LOG_CHEST, {[]{return true;}}),
}, {
//Exits
Entrance(RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK, {[]{return LogicDekuMQLog || (IsChild && (DekuShield || HylianShield)) ||
Entrance(RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK, {[]{return randoCtx->GetTrickOption(RT_DEKU_MQ_LOG) || (IsChild && (DekuShield || HylianShield)) ||
(IsAdult && (CanUse(RG_LONGSHOT) || (CanUse(RG_HOOKSHOT) && CanUse(RG_IRON_BOOTS))));}}),
Entrance(RR_DEKU_TREE_MQ_LOBBY, {[]{return true;}}),
});
@@ -244,8 +244,8 @@ void AreaTable_Init_DekuTree() {
Area("Deku Tree Boss Entryway", "Deku Tree", RHT_DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, {},
{
// Exits
Entrance(RR_DEKU_TREE_OUTSIDE_BOSS_ROOM, { [] { return Dungeon::DekuTree.IsVanilla(); } }),
Entrance(RR_DEKU_TREE_MQ_OUTSIDE_BOSS_ROOM, { [] { return Dungeon::DekuTree.IsMQ(); } }),
Entrance(RR_DEKU_TREE_OUTSIDE_BOSS_ROOM, { [] { return randoCtx->GetDungeon(DEKU_TREE)->IsVanilla(); } }),
Entrance(RR_DEKU_TREE_MQ_OUTSIDE_BOSS_ROOM, { [] { return randoCtx->GetDungeon(DEKU_TREE)->IsMQ(); } }),
Entrance(RR_DEKU_TREE_BOSS_ROOM, { [] { return true; } }),
});

View File

@@ -1,10 +1,10 @@
#include "../location_access.hpp"
#include "../logic.hpp"
#include "../entrance.hpp"
#include "../dungeon.hpp"
#include "../../entrance.h"
#include "../../dungeon.h"
using namespace Logic;
using namespace Settings;
using namespace Rando;
void AreaTable_Init_DodongosCavern() {
/*--------------------------
@@ -12,15 +12,15 @@ void AreaTable_Init_DodongosCavern() {
---------------------------*/
areaTable[RR_DODONGOS_CAVERN_ENTRYWAY] = Area("Dodongos Cavern Entryway", "Dodongos Cavern", RHT_DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_DODONGOS_CAVERN_BEGINNING, {[]{return Dungeon::DodongosCavern.IsVanilla();}}),
Entrance(RR_DODONGOS_CAVERN_MQ_BEGINNING, {[]{return Dungeon::DodongosCavern.IsMQ();}}),
Entrance(RR_DODONGOS_CAVERN_BEGINNING, {[]{return randoCtx->GetDungeon(DODONGOS_CAVERN)->IsVanilla();}}),
Entrance(RR_DODONGOS_CAVERN_MQ_BEGINNING, {[]{return randoCtx->GetDungeon(DODONGOS_CAVERN)->IsMQ();}}),
Entrance(RR_DEATH_MOUNTAIN_TRAIL, {[]{return true;}}),
});
/*--------------------------
| VANILLA DUNGEON |
---------------------------*/
if (Dungeon::DodongosCavern.IsVanilla()) {
if (randoCtx->GetDungeon(DODONGOS_CAVERN)->IsVanilla()) {
areaTable[RR_DODONGOS_CAVERN_BEGINNING] = Area("Dodongos Cavern Beginning", "Dodongos Cavern", RHT_DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_DODONGOS_CAVERN_ENTRYWAY, {[]{return true;}}),
@@ -54,7 +54,7 @@ void AreaTable_Init_DodongosCavern() {
areaTable[RR_DODONGOS_CAVERN_SE_CORRIDOR] = Area("Dodongos Cavern SE Corridor", "Dodongos Cavern", RHT_DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_DODONGOS_CAVERN_GS_SCARECROW, {[]{return CanUse(RG_SCARECROW) || (IsAdult && CanUse(RG_LONGSHOT)) || (LogicDCScarecrowGS && (CanAdultAttack || CanChildAttack));}}),
LocationAccess(RC_DODONGOS_CAVERN_GS_SCARECROW, {[]{return CanUse(RG_SCARECROW) || (IsAdult && CanUse(RG_LONGSHOT)) || (randoCtx->GetTrickOption(RT_DC_SCARECROW_GS) && (CanAdultAttack || CanChildAttack));}}),
}, {
//Exits
Entrance(RR_DODONGOS_CAVERN_LOBBY, {[]{return true;}}),
@@ -102,14 +102,14 @@ void AreaTable_Init_DodongosCavern() {
areaTable[RR_DODONGOS_CAVERN_STAIRS_LOWER] = Area("Dodongos Cavern Stairs Lower", "Dodongos Cavern", RHT_DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_DODONGOS_CAVERN_LOBBY, {[]{return true;}}),
Entrance(RR_DODONGOS_CAVERN_STAIRS_UPPER, {[]{return HasExplosives || GoronBracelet || CanUse(RG_DINS_FIRE) || (LogicDCStaircase && CanUse(RG_FAIRY_BOW));}}),
Entrance(RR_DODONGOS_CAVERN_STAIRS_UPPER, {[]{return HasExplosives || GoronBracelet || CanUse(RG_DINS_FIRE) || (randoCtx->GetTrickOption(RT_DC_STAIRCASE) && CanUse(RG_FAIRY_BOW));}}),
Entrance(RR_DODONGOS_CAVERN_COMPASS_ROOM, {[]{return Here(RR_DODONGOS_CAVERN_STAIRS_LOWER, []{return CanBlastOrSmash || GoronBracelet;});}}),
});
areaTable[RR_DODONGOS_CAVERN_STAIRS_UPPER] = Area("Dodongos Cavern Stairs Upper", "Dodongos Cavern", RHT_DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_DODONGOS_CAVERN_GS_ALCOVE_ABOVE_STAIRS, {[]{return Here(RR_DODONGOS_CAVERN_FAR_BRIDGE, []{return HookshotOrBoomerang;}) || CanUse(RG_LONGSHOT);}}),
LocationAccess(RC_DODONGOS_CAVERN_GS_VINES_ABOVE_STAIRS, {[]{return IsAdult || CanChildAttack || (HasAccessTo(RR_DODONGOS_CAVERN_STAIRS_LOWER) && CanUse(RG_LONGSHOT) && LogicDCVinesGS);}}),
LocationAccess(RC_DODONGOS_CAVERN_GS_VINES_ABOVE_STAIRS, {[]{return IsAdult || CanChildAttack || (HasAccessTo(RR_DODONGOS_CAVERN_STAIRS_LOWER) && CanUse(RG_LONGSHOT) && randoCtx->GetTrickOption(RT_DC_VINES_GS));}}),
}, {
//Exits
Entrance(RR_DODONGOS_CAVERN_STAIRS_LOWER, {[]{return true;}}),
@@ -135,9 +135,9 @@ void AreaTable_Init_DodongosCavern() {
LocationAccess(RC_DODONGOS_CAVERN_BOMB_FLOWER_PLATFORM_CHEST, {[]{return true;}}),
}, {
//Exits
Entrance(RR_DODONGOS_CAVERN_2F_SIDE_ROOM, {[]{return Here(RR_DODONGOS_CAVERN_BOMB_ROOM_LOWER, []{return CanBlastOrSmash || (LogicDCScrubRoom && GoronBracelet);});}}),
Entrance(RR_DODONGOS_CAVERN_2F_SIDE_ROOM, {[]{return Here(RR_DODONGOS_CAVERN_BOMB_ROOM_LOWER, []{return CanBlastOrSmash || (randoCtx->GetTrickOption(RT_DC_SCRUB_ROOM) && GoronBracelet);});}}),
Entrance(RR_DODONGOS_CAVERN_FIRST_SLINGSHOT_ROOM, {[]{return Here(RR_DODONGOS_CAVERN_BOMB_ROOM_LOWER, []{return CanBlastOrSmash || GoronBracelet;});}}),
Entrance(RR_DODONGOS_CAVERN_BOMB_ROOM_UPPER, {[]{return (IsAdult && LogicDCJump) || CanUse(RG_HOVER_BOOTS) || (IsAdult && CanUse(RG_LONGSHOT));}}),
Entrance(RR_DODONGOS_CAVERN_BOMB_ROOM_UPPER, {[]{return (IsAdult && randoCtx->GetTrickOption(RT_DC_JUMP)) || CanUse(RG_HOVER_BOOTS) || (IsAdult && CanUse(RG_LONGSHOT));}}),
});
areaTable[RR_DODONGOS_CAVERN_2F_SIDE_ROOM] = Area("Dodongos Cavern 2F Side Room", "Dodongos Cavern", RHT_DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {
@@ -152,7 +152,7 @@ void AreaTable_Init_DodongosCavern() {
areaTable[RR_DODONGOS_CAVERN_FIRST_SLINGSHOT_ROOM] = Area("Dodongos Cavern First Slingshot Room", "Dodongos Cavern", RHT_DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_DODONGOS_CAVERN_BOMB_ROOM_LOWER, {[]{return true;}}),
Entrance(RR_DODONGOS_CAVERN_UPPER_LIZALFOS, {[]{return CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_FAIRY_BOW) || LogicDCSlingshotSkip;}}),
Entrance(RR_DODONGOS_CAVERN_UPPER_LIZALFOS, {[]{return CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_FAIRY_BOW) || randoCtx->GetTrickOption(RT_DC_SLINGSHOT_SKIP);}}),
});
areaTable[RR_DODONGOS_CAVERN_UPPER_LIZALFOS] = Area("Dodongos Cavern Upper Lizalfos", "Dodongos Cavern", RHT_DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, {
@@ -167,7 +167,7 @@ void AreaTable_Init_DodongosCavern() {
areaTable[RR_DODONGOS_CAVERN_SECOND_SLINGSHOT_ROOM] = Area("Dodongos Cavern Second Slingshot Room", "Dodongos Cavern", RHT_DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_DODONGOS_CAVERN_UPPER_LIZALFOS, {[]{return true;}}),
Entrance(RR_DODONGOS_CAVERN_BOMB_ROOM_UPPER, {[]{return CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_FAIRY_BOW) || LogicDCSlingshotSkip;}}),
Entrance(RR_DODONGOS_CAVERN_BOMB_ROOM_UPPER, {[]{return CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_FAIRY_BOW) || randoCtx->GetTrickOption(RT_DC_SLINGSHOT_SKIP);}}),
});
areaTable[RR_DODONGOS_CAVERN_BOMB_ROOM_UPPER] = Area("Dodongos Cavern Bomb Room Upper", "Dodongos Cavern", RHT_DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {
@@ -211,7 +211,7 @@ void AreaTable_Init_DodongosCavern() {
/*---------------------------
| MASTER QUEST DUNGEON |
---------------------------*/
if (Dungeon::DodongosCavern.IsMQ()) {
if (randoCtx->GetDungeon(DODONGOS_CAVERN)->IsMQ()) {
areaTable[RR_DODONGOS_CAVERN_MQ_BEGINNING] = Area("Dodongos Cavern MQ Beginning", "Dodongos Cavern", RHT_DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_DODONGOS_CAVERN_ENTRYWAY, {[]{return true;}}),
@@ -227,7 +227,7 @@ void AreaTable_Init_DodongosCavern() {
LocationAccess(RC_DODONGOS_CAVERN_MQ_MAP_CHEST, {[]{return true;}}),
LocationAccess(RC_DODONGOS_CAVERN_MQ_COMPASS_CHEST, {[]{return CanAdultAttack || CanChildAttack || Nuts;}}),
LocationAccess(RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CHEST, {[]{return (IsChild && CanUse(RG_STICKS)) || HasFireSource;}}),
LocationAccess(RC_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_ROOM_CHEST, {[]{return CanBlastOrSmash || (IsChild && CanUse(RG_STICKS)) || CanUse(RG_DINS_FIRE) || (IsAdult && (LogicDCJump || HoverBoots || Hookshot));}}),
LocationAccess(RC_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_ROOM_CHEST, {[]{return CanBlastOrSmash || (IsChild && CanUse(RG_STICKS)) || CanUse(RG_DINS_FIRE) || (IsAdult && (randoCtx->GetTrickOption(RT_DC_JUMP) || HoverBoots || Hookshot));}}),
LocationAccess(RC_DODONGOS_CAVERN_MQ_GS_SONG_OF_TIME_BLOCK_ROOM, {[]{return CanPlay(SongOfTime) && (CanChildAttack || CanAdultAttack);}}),
LocationAccess(RC_DODONGOS_CAVERN_MQ_GS_LARVAE_ROOM, {[]{return (IsChild && CanUse(RG_STICKS)) || HasFireSource;}}),
LocationAccess(RC_DODONGOS_CAVERN_MQ_GS_LIZALFOS_ROOM, {[]{return CanBlastOrSmash;}}),
@@ -238,9 +238,9 @@ void AreaTable_Init_DodongosCavern() {
}, {
//Exits
Entrance(RR_DODONGOS_CAVERN_MQ_LOWER_RIGHT_SIDE, {[]{return Here(RR_DODONGOS_CAVERN_MQ_LOBBY, []{return CanBlastOrSmash || (((IsChild && CanUse(RG_STICKS)) || CanUse(RG_DINS_FIRE)) && CanTakeDamage);});}}),
Entrance(RR_DODONGOS_CAVERN_MQ_BOMB_BAG_AREA, {[]{return IsAdult || (Here(RR_DODONGOS_CAVERN_MQ_LOBBY, []{return IsAdult;}) && HasExplosives) || (LogicDCMQChildBombs && CanJumpslash && CanTakeDamage);}}),
Entrance(RR_DODONGOS_CAVERN_MQ_BOMB_BAG_AREA, {[]{return IsAdult || (Here(RR_DODONGOS_CAVERN_MQ_LOBBY, []{return IsAdult;}) && HasExplosives) || (randoCtx->GetTrickOption(RT_DC_MQ_CHILD_BOMBS) && CanJumpslash && CanTakeDamage);}}),
//Trick: IsAdult || HasExplosives || (LogicDCMQChildBombs && (KokiriSword || Sticks) && DamageMultiplier.IsNot(DAMAGEMULTIPLIER_OHKO))
Entrance(RR_DODONGOS_CAVERN_MQ_BOSS_AREA, {[]{return HasExplosives || (GoronBracelet && ((IsAdult && LogicDCMQEyesAdult) || (IsChild && LogicDCMQEyesChild)) && ((IsChild && (CanUse(RG_STICKS))) || CanUse(RG_DINS_FIRE) || (IsAdult && (LogicDCJump || Hammer || HoverBoots || Hookshot))));}}),
Entrance(RR_DODONGOS_CAVERN_MQ_BOSS_AREA, {[]{return HasExplosives || (GoronBracelet && ((IsAdult && randoCtx->GetTrickOption(RT_DC_MQ_ADULT_EYES)) || (IsChild && randoCtx->GetTrickOption(RT_DC_MQ_CHILD_EYES))) && ((IsChild && (CanUse(RG_STICKS))) || CanUse(RG_DINS_FIRE) || (IsAdult && (randoCtx->GetTrickOption(RT_DC_JUMP) || Hammer || HoverBoots || Hookshot))));}}),
//Trick: HasExplosives || (LogicDCMQEyes && GoronBracelet && (IsAdult || LogicDCMQChildBack) && ((IsChild && CanUse(RG_STICKS)) || CanUse(RG_DINS_FIRE) || (IsAdult && (LogicDCJump || Hammer || HoverBoots || Hookshot))))
});
@@ -283,8 +283,8 @@ void AreaTable_Init_DodongosCavern() {
Area("Dodongos Cavern Boss Entryway", "Dodongos Cavern", RHT_DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {},
{
// Exits
Entrance(RR_DODONGOS_CAVERN_BOSS_AREA, { [] { return Dungeon::DodongosCavern.IsVanilla(); } }),
Entrance(RR_DODONGOS_CAVERN_MQ_BOSS_AREA, { [] { return Dungeon::DodongosCavern.IsMQ(); } }),
Entrance(RR_DODONGOS_CAVERN_BOSS_AREA, { [] { return randoCtx->GetDungeon(DODONGOS_CAVERN)->IsVanilla(); } }),
Entrance(RR_DODONGOS_CAVERN_MQ_BOSS_AREA, { [] { return randoCtx->GetDungeon(DODONGOS_CAVERN)->IsMQ(); } }),
Entrance(RR_DODONGOS_CAVERN_BOSS_ROOM, { [] { return true; } }),
});
@@ -296,7 +296,7 @@ void AreaTable_Init_DodongosCavern() {
{ [] {
return DodongosCavernClear ||
(Here(RR_DODONGOS_CAVERN_BOSS_ROOM,
[] { return HasExplosives || (CanUse(RG_MEGATON_HAMMER) && LogicDCHammerFloor); }) &&
[] { return HasExplosives || (CanUse(RG_MEGATON_HAMMER) && randoCtx->GetTrickOption(RT_DC_HAMMER_FLOOR)); }) &&
(Bombs || GoronBracelet) && CanJumpslash); /*todo add chu kill to tricks*/
}}),
},

View File

@@ -1,10 +1,10 @@
#include "../location_access.hpp"
#include "../logic.hpp"
#include "../entrance.hpp"
#include "../dungeon.hpp"
#include "../../entrance.h"
#include "../../dungeon.h"
using namespace Logic;
using namespace Settings;
using namespace Rando;
void AreaTable_Init_FireTemple() {
/*--------------------------
@@ -12,15 +12,15 @@ void AreaTable_Init_FireTemple() {
---------------------------*/
areaTable[RR_FIRE_TEMPLE_ENTRYWAY] = Area("Fire Temple Entryway", "Fire Temple", RHT_FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_FIRE_TEMPLE_FIRST_ROOM, {[]{return Dungeon::FireTemple.IsVanilla();}}),
Entrance(RR_FIRE_TEMPLE_MQ_LOWER, {[]{return Dungeon::FireTemple.IsMQ();}}),
Entrance(RR_FIRE_TEMPLE_FIRST_ROOM, {[]{return randoCtx->GetDungeon(FIRE_TEMPLE)->IsVanilla();}}),
Entrance(RR_FIRE_TEMPLE_MQ_LOWER, {[]{return randoCtx->GetDungeon(FIRE_TEMPLE)->IsMQ();}}),
Entrance(RR_DMC_CENTRAL_LOCAL, {[]{return true;}}),
});
/*--------------------------
| VANILLA DUNGEON |
---------------------------*/
if (Dungeon::FireTemple.IsVanilla()) {
if (randoCtx->GetDungeon(FIRE_TEMPLE)->IsVanilla()) {
areaTable[RR_FIRE_TEMPLE_FIRST_ROOM] = Area("Fire Temple First Room", "Fire Temple", RHT_FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
}, {
//Exits
@@ -40,7 +40,7 @@ void AreaTable_Init_FireTemple() {
}, {
//Exits
Entrance(RR_FIRE_TEMPLE_FIRST_ROOM, {[]{return true;}}),
Entrance(RR_FIRE_TEMPLE_BOSS_ENTRYWAY, {[]{return BossKeyFireTemple && ((IsAdult && LogicFireBossDoorJump) || CanUse(RG_HOVER_BOOTS) || Here(RR_FIRE_TEMPLE_FIRE_MAZE_UPPER, []{return CanUse(RG_MEGATON_HAMMER);}));}}),
Entrance(RR_FIRE_TEMPLE_BOSS_ENTRYWAY, {[]{return BossKeyFireTemple && ((IsAdult && randoCtx->GetTrickOption(RT_FIRE_BOSS_DOOR_JUMP)) || CanUse(RG_HOVER_BOOTS) || Here(RR_FIRE_TEMPLE_FIRE_MAZE_UPPER, []{return CanUse(RG_MEGATON_HAMMER);}));}}),
});
areaTable[RR_FIRE_TEMPLE_LOOP_ENEMIES] = Area("Fire Temple Loop Enemies", "Fire Temple", RHT_FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, {
@@ -96,7 +96,7 @@ void AreaTable_Init_FireTemple() {
//Exits
Entrance(RR_FIRE_TEMPLE_FIRST_ROOM, {[]{return SmallKeys(RR_FIRE_TEMPLE, 2);}}),
Entrance(RR_FIRE_TEMPLE_BIG_LAVA_ROOM_NORTH_GORON, {[]{return true;}}),
Entrance(RR_FIRE_TEMPLE_BIG_LAVA_ROOM_NORTH_TILES, {[]{return IsAdult && (CanPlay(SongOfTime) || LogicFireSongOfTime);}}),
Entrance(RR_FIRE_TEMPLE_BIG_LAVA_ROOM_NORTH_TILES, {[]{return IsAdult && (CanPlay(SongOfTime) || randoCtx->GetTrickOption(RT_FIRE_SOT));}}),
Entrance(RR_FIRE_TEMPLE_BIG_LAVA_ROOM_SOUTH_GORON, {[]{return IsAdult && HasExplosives;}}),
Entrance(RR_FIRE_TEMPLE_FIRE_PILLAR_ROOM, {[]{return SmallKeys(RR_FIRE_TEMPLE, 3);}}),
});
@@ -138,7 +138,7 @@ void AreaTable_Init_FireTemple() {
//Exits
Entrance(RR_FIRE_TEMPLE_FIRE_PILLAR_ROOM, {[]{return SmallKeys(RR_FIRE_TEMPLE, 4);}}),
Entrance(RR_FIRE_TEMPLE_SHORTCUT_CLIMB, {[]{return Here(RR_FIRE_TEMPLE_SHORTCUT_CLIMB, []{return true;});}}),
Entrance(RR_FIRE_TEMPLE_BOULDER_MAZE_LOWER, {[]{return IsAdult && (GoronBracelet || LogicFireStrength) && (HasExplosives || CanUse(RG_FAIRY_BOW) || CanUse(RG_HOOKSHOT) || CanUse(RG_FAIRY_SLINGSHOT));}}),
Entrance(RR_FIRE_TEMPLE_BOULDER_MAZE_LOWER, {[]{return IsAdult && (GoronBracelet || randoCtx->GetTrickOption(RT_FIRE_STRENGTH)) && (HasExplosives || CanUse(RG_FAIRY_BOW) || CanUse(RG_HOOKSHOT) || CanUse(RG_FAIRY_SLINGSHOT));}}),
});
areaTable[RR_FIRE_TEMPLE_SHORTCUT_CLIMB] = Area("Fire Temple Shortcut Climb", "Fire Temple", RHT_FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, {
@@ -199,7 +199,7 @@ void AreaTable_Init_FireTemple() {
Entrance(RR_FIRE_TEMPLE_SHORTCUT_CLIMB, {[]{return HasExplosives;}}),
Entrance(RR_FIRE_TEMPLE_BOULDER_MAZE_LOWER, {[]{return true;}}),
Entrance(RR_FIRE_TEMPLE_FIRE_WALL_CHASE, {[]{return true;}}),
Entrance(RR_FIRE_TEMPLE_SCARECROW_ROOM, {[]{return CanUse(RG_SCARECROW) || (LogicFireScarecrow && IsAdult && CanUse(RG_LONGSHOT));}}),
Entrance(RR_FIRE_TEMPLE_SCARECROW_ROOM, {[]{return CanUse(RG_SCARECROW) || (randoCtx->GetTrickOption(RT_FIRE_SCARECROW) && IsAdult && CanUse(RG_LONGSHOT));}}),
});
areaTable[RR_FIRE_TEMPLE_SCARECROW_ROOM] = Area("Fire Temple Scarecrow Room", "Fire Temple", RHT_FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
@@ -233,7 +233,7 @@ void AreaTable_Init_FireTemple() {
Entrance(RR_FIRE_TEMPLE_FIRE_MAZE_UPPER, {[]{return CanUse(RG_HOVER_BOOTS);}}),
Entrance(RR_FIRE_TEMPLE_FIRE_MAZE_SIDE_ROOM, {[]{return true;}}),
Entrance(RR_FIRE_TEMPLE_WEST_CENTRAL_LOWER, {[]{return SmallKeys(RR_FIRE_TEMPLE, 8);}}),
Entrance(RR_FIRE_TEMPLE_LATE_FIRE_MAZE, {[]{return LogicFireFlameMaze || false;}}),
Entrance(RR_FIRE_TEMPLE_LATE_FIRE_MAZE, {[]{return randoCtx->GetTrickOption(RT_FIRE_FLAME_MAZE) || false;}}),
});
areaTable[RR_FIRE_TEMPLE_FIRE_MAZE_UPPER] = Area("Fire Temple Fire Maze Upper", "Fire Temple", RHT_FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, {
@@ -253,7 +253,7 @@ void AreaTable_Init_FireTemple() {
areaTable[RR_FIRE_TEMPLE_WEST_CENTRAL_LOWER] = Area("Fire Temple West Central Lower", "Fire Temple", RHT_FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_FIRE_TEMPLE_HIGHEST_GORON_CHEST, {[]{return Here(RR_FIRE_TEMPLE_WEST_CENTRAL_UPPER, []{return (CanPlay(SongOfTime) || LogicRustedSwitches) && CanUse(RG_MEGATON_HAMMER);});}}),
LocationAccess(RC_FIRE_TEMPLE_HIGHEST_GORON_CHEST, {[]{return Here(RR_FIRE_TEMPLE_WEST_CENTRAL_UPPER, []{return (CanPlay(SongOfTime) || randoCtx->GetTrickOption(RT_RUSTED_SWITCHES)) && CanUse(RG_MEGATON_HAMMER);});}}),
}, {
//Exits
Entrance(RR_FIRE_TEMPLE_FIRE_MAZE_ROOM, {[]{return SmallKeys(RR_FIRE_TEMPLE, 8);}}),
@@ -314,16 +314,16 @@ void AreaTable_Init_FireTemple() {
/*---------------------------
| MASTER QUEST DUNGEON |
---------------------------*/
if (Dungeon::FireTemple.IsMQ()) {
if (randoCtx->GetDungeon(FIRE_TEMPLE)->IsMQ()) {
areaTable[RR_FIRE_TEMPLE_MQ_LOWER] = Area("Fire Temple MQ Lower", "Fire Temple", RHT_FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_FIRE_TEMPLE_MQ_MAP_ROOM_SIDE_CHEST, {[]{return CanJumpslash || CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_FAIRY_BOW) || Bombs || CanUse(RG_DINS_FIRE);}}),
LocationAccess(RC_FIRE_TEMPLE_MQ_NEAR_BOSS_CHEST, {[]{return IsAdult && (LogicFewerTunicRequirements || CanUse(RG_GORON_TUNIC)) && (((CanUse(RG_HOVER_BOOTS) || (LogicFireMQNearBoss && CanUse(RG_FAIRY_BOW))) && HasFireSource) || (CanUse(RG_HOOKSHOT) && CanUse(RG_FIRE_ARROWS) || (CanUse(RG_DINS_FIRE) && ((DamageMultiplier.IsNot(DAMAGEMULTIPLIER_OHKO) && DamageMultiplier.IsNot(DAMAGEMULTIPLIER_QUADRUPLE) && DamageMultiplier.IsNot(DAMAGEMULTIPLIER_OCTUPLE) && DamageMultiplier.IsNot(DAMAGEMULTIPLIER_SEXDECUPLE)) || CanUse(RG_GORON_TUNIC) || CanUse(RG_FAIRY_BOW) || CanUse(RG_LONGSHOT)))));}}),
LocationAccess(RC_FIRE_TEMPLE_MQ_NEAR_BOSS_CHEST, {[]{return IsAdult && (randoCtx->GetTrickOption(RT_FEWER_TUNIC_REQUIREMENTS) || CanUse(RG_GORON_TUNIC)) && (((CanUse(RG_HOVER_BOOTS) || (randoCtx->GetTrickOption(RT_FIRE_MQ_NEAR_BOSS) && CanUse(RG_FAIRY_BOW))) && HasFireSource) || (CanUse(RG_HOOKSHOT) && CanUse(RG_FIRE_ARROWS) || (CanUse(RG_DINS_FIRE) && ((randoCtx->GetOption(RSK_DAMAGE_MULTIPLIER).IsNot(RO_DAMAGE_MULTIPLIER_OHKO) && randoCtx->GetOption(RSK_DAMAGE_MULTIPLIER).IsNot(RO_DAMAGE_MULTIPLIER_QUADRUPLE) && randoCtx->GetOption(RSK_DAMAGE_MULTIPLIER).IsNot(RO_DAMAGE_MULTIPLIER_OCTUPLE) && randoCtx->GetOption(RSK_DAMAGE_MULTIPLIER).IsNot(RO_DAMAGE_MULTIPLIER_SEXDECUPLE)) || CanUse(RG_GORON_TUNIC) || CanUse(RG_FAIRY_BOW) || CanUse(RG_LONGSHOT)))));}}),
//Trick: IsAdult && (LogicFewerTunicRequirements || CanUse(RG_GORON_TUNIC)) && (((CanUse(RG_HOVER_BOOTS) || (LogicFireMQNearBoss && CanUse(RG_FAIRY_BOW))) && HasFireSource) || (CanUse(RG_HOOKSHOT) && CanUse(RG_FIRE_ARROWS) || (CanUse(RG_DINS_FIRE) && ((DamageMultiplier.IsNot(DAMAGEMULTIPLIER_OHKO) && DamageMultiplier.IsNot(DAMAGEMULTIPLIER_QUADRUPLE) && DamageMultiplier.IsNot(DAMAGEMULTIPLIER_OCTUPLE) && DamageMultiplier.IsNot(DAMAGEMULTIPLIER_SEXDECUPLE)) || CanUse(RG_GORON_TUNIC) || CanUse(RG_FAIRY_BOW) || CanUse(RG_LONGSHOT)))))
}, {
//Exits
Entrance(RR_FIRE_TEMPLE_ENTRYWAY, {[]{return true;}}),
Entrance(RR_FIRE_TEMPLE_BOSS_ENTRYWAY, {[]{return IsAdult && CanUse(RG_GORON_TUNIC) && CanUse(RG_MEGATON_HAMMER) && BossKeyFireTemple && ((HasFireSource && (LogicFireBossDoorJump || HoverBoots)) || HasAccessTo(RR_FIRE_TEMPLE_MQ_UPPER));}}),
Entrance(RR_FIRE_TEMPLE_BOSS_ENTRYWAY, {[]{return IsAdult && CanUse(RG_GORON_TUNIC) && CanUse(RG_MEGATON_HAMMER) && BossKeyFireTemple && ((HasFireSource && (randoCtx->GetTrickOption(RT_FIRE_BOSS_DOOR_JUMP) || HoverBoots)) || HasAccessTo(RR_FIRE_TEMPLE_MQ_UPPER));}}),
Entrance(RR_FIRE_TEMPLE_MQ_LOWER_LOCKED_DOOR, {[]{return SmallKeys(RR_FIRE_TEMPLE, 5) && (CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD));}}),
Entrance(RR_FIRE_TEMPLE_MQ_BIG_LAVA_ROOM, {[]{return IsAdult && FireTimer >= 24 && CanUse(RG_MEGATON_HAMMER);}}),
});
@@ -339,29 +339,29 @@ void AreaTable_Init_FireTemple() {
areaTable[RR_FIRE_TEMPLE_MQ_BIG_LAVA_ROOM] = Area("Fire Temple MQ Big Lava Room", "Fire Temple", RHT_FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&FairyPot, {[]{return FairyPot || (HasFireSource && (Bow || LogicFireMQBKChest) && IsAdult && (CanUse(RG_HOOKSHOT) || LogicFireSongOfTime));}}),
EventAccess(&FairyPot, {[]{return FairyPot || (HasFireSource && (Bow || randoCtx->GetTrickOption(RT_FIRE_MQ_BK_CHEST)) && IsAdult && (CanUse(RG_HOOKSHOT) || randoCtx->GetTrickOption(RT_FIRE_SOT)));}}),
//Trick: HasFireSource && (Bow || LogicFireMQBKChest) && IsAdult && (CanUse(RG_HOOKSHOT) || LogicFireSongOfTime)
}, {
//Locations
LocationAccess(RC_FIRE_TEMPLE_MQ_BOSS_KEY_CHEST, {[]{return HasFireSource && (Bow || LogicFireMQBKChest) && IsAdult && CanUse(RG_HOOKSHOT);}}),
LocationAccess(RC_FIRE_TEMPLE_MQ_BOSS_KEY_CHEST, {[]{return HasFireSource && (Bow || randoCtx->GetTrickOption(RT_FIRE_MQ_BK_CHEST)) && IsAdult && CanUse(RG_HOOKSHOT);}}),
//Trick: HasFireSource && (Bow || LogicFireMQBKChest) && IsAdult && CanUse(RG_HOOKSHOT)
LocationAccess(RC_FIRE_TEMPLE_MQ_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST, {[]{return HasFireSource && HasExplosives && IsAdult && (CanUse(RG_HOOKSHOT) || LogicFireMQBlockedChest);}}),
LocationAccess(RC_FIRE_TEMPLE_MQ_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST, {[]{return HasFireSource && HasExplosives && IsAdult && (CanUse(RG_HOOKSHOT) || randoCtx->GetTrickOption(RT_FIRE_MQ_BLOCKED_CHEST));}}),
//Trick: HasFireSource && HasExplosives && IsAdult && (CanUse(RG_HOOKSHOT) || LogicFireMQBlockedChest)
LocationAccess(RC_FIRE_TEMPLE_MQ_GS_BIG_LAVA_ROOM_OPEN_DOOR, {[]{return true;}}),
}, {
//Exits
Entrance(RR_FIRE_TEMPLE_MQ_LOWER_MAZE, {[]{return IsAdult && CanUse(RG_GORON_TUNIC) && SmallKeys(RR_FIRE_TEMPLE, 2) && (HasFireSource || (LogicFireMQClimb && HoverBoots));}}),
Entrance(RR_FIRE_TEMPLE_MQ_LOWER_MAZE, {[]{return IsAdult && CanUse(RG_GORON_TUNIC) && SmallKeys(RR_FIRE_TEMPLE, 2) && (HasFireSource || (randoCtx->GetTrickOption(RT_FIRE_MQ_CLIMB) && HoverBoots));}}),
//Trick: IsAdult && CanUse(RG_GORON_TUNIC) && SmallKeys(RR_FIRE_TEMPLE, 2) && (HasFireSource || (LogicFireMQClimb && HoverBoots))
});
areaTable[RR_FIRE_TEMPLE_MQ_LOWER_MAZE] = Area("Fire Temple MQ Lower Maze", "Fire Temple", RHT_FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CHEST, {[]{return CanUse(RG_MASTER_SWORD) || CanUse(RG_KOKIRI_SWORD) || CanUse(RG_BIGGORON_SWORD);}}),
LocationAccess(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_SIDE_ROOM_CHEST, {[]{return HasExplosives && (LogicFireMQMazeSideRoom || HasAccessTo(RR_FIRE_TEMPLE_MQ_UPPER_MAZE));}}),
LocationAccess(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_SIDE_ROOM_CHEST, {[]{return HasExplosives && (randoCtx->GetTrickOption(RT_FIRE_MQ_MAZE_SIDE_ROOM) || HasAccessTo(RR_FIRE_TEMPLE_MQ_UPPER_MAZE));}}),
//Trick: HasExplosives && (LogicFireMQMazeSideRoom || FIRE_TEMPLE_MQ_UPPER_MAZE.Adult())
}, {
//Exits
Entrance(RR_FIRE_TEMPLE_MQ_UPPER_MAZE, {[]{return (IsAdult && ((HasExplosives && CanUse(RG_HOOKSHOT)) || (LogicFireMQMazeHovers && CanUse(RG_HOVER_BOOTS)))) || LogicFireMQMazeJump;}}),
Entrance(RR_FIRE_TEMPLE_MQ_UPPER_MAZE, {[]{return (IsAdult && ((HasExplosives && CanUse(RG_HOOKSHOT)) || (randoCtx->GetTrickOption(RT_FIRE_MQ_MAZE_HOVERS) && CanUse(RG_HOVER_BOOTS)))) || randoCtx->GetTrickOption(RT_FIRE_MQ_MAZE_JUMP);}}),
//Trick: (IsAdult && ((HasExplosives && CanUse(RG_HOOKSHOT)) || (LogicFireMQMazeHovers && CanUse(RG_HOVER_BOOTS)))) || LogicFireMQMazeJump
});
@@ -381,14 +381,14 @@ void AreaTable_Init_FireTemple() {
areaTable[RR_FIRE_TEMPLE_MQ_UPPER] = Area("Fire Temple MQ Upper", "Fire Temple", RHT_FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_FIRE_TEMPLE_MQ_FREESTANDING_KEY, {[]{return ((CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD) || CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_BOOMERANG)) && CanUse(RG_HOOKSHOT)) || LogicFireMQFlameMaze;}}),
LocationAccess(RC_FIRE_TEMPLE_MQ_FREESTANDING_KEY, {[]{return ((CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD) || CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_BOOMERANG)) && CanUse(RG_HOOKSHOT)) || randoCtx->GetTrickOption(RT_FIRE_MQ_FLAME_MAZE);}}),
//Trick: (IsAdult && CanUse(RG_HOOKSHOT)) || LogicFireMQFlameMaze
LocationAccess(RC_FIRE_TEMPLE_MQ_CHEST_ON_FIRE, {[]{return ((IsAdult && CanUse(RG_HOOKSHOT)) || LogicFireMQFlameMaze) && SmallKeys(RR_FIRE_TEMPLE, 4);}}),
LocationAccess(RC_FIRE_TEMPLE_MQ_CHEST_ON_FIRE, {[]{return ((IsAdult && CanUse(RG_HOOKSHOT)) || randoCtx->GetTrickOption(RT_FIRE_MQ_FLAME_MAZE)) && SmallKeys(RR_FIRE_TEMPLE, 4);}}),
//Trick: ((IsAdult && CanUse(RG_HOOKSHOT)) || LogicFireMQFlameMaze) && SmallKeys(RR_FIRE_TEMPLE, 4)
LocationAccess(RC_FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_SIDE_ROOM, {[]{return CanPlay(SongOfTime) || HoverBoots || LogicFireMQFlameMaze;}}),
LocationAccess(RC_FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_SIDE_ROOM, {[]{return CanPlay(SongOfTime) || HoverBoots || randoCtx->GetTrickOption(RT_FIRE_MQ_FLAME_MAZE);}}),
//Trick: CanPlay(SongOfTime) || HoverBoots || LogicFireMQFlameMaze
LocationAccess(RC_FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_CENTER, {[]{return HasExplosives;}}),
LocationAccess(RC_FIRE_TEMPLE_MQ_GS_ABOVE_FIRE_WALL_MAZE, {[]{return (IsAdult && CanUse(RG_HOOKSHOT) && SmallKeys(RR_FIRE_TEMPLE, 5)) || (LogicFireMQAboveMazeGS && IsAdult && CanUse(RG_LONGSHOT));}}),
LocationAccess(RC_FIRE_TEMPLE_MQ_GS_ABOVE_FIRE_WALL_MAZE, {[]{return (IsAdult && CanUse(RG_HOOKSHOT) && SmallKeys(RR_FIRE_TEMPLE, 5)) || (randoCtx->GetTrickOption(RT_FIRE_MQ_ABOVE_MAZE_GS) && IsAdult && CanUse(RG_LONGSHOT));}}),
//Trick: (IsAdult && CanUse(RG_HOOKSHOT) && SmallKeys(RR_FIRE_TEMPLE, 5)) || (LogicFireMQAboveMazeGS && IsAdult && CanUse(RG_LONGSHOT))
}, {});
}
@@ -400,8 +400,8 @@ void AreaTable_Init_FireTemple() {
Area("Fire Temple Boss Entryway", "Fire Temple", RHT_FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {},
{
// Exits
Entrance(RR_FIRE_TEMPLE_NEAR_BOSS_ROOM, { [] { return Dungeon::FireTemple.IsVanilla() && false; } }),
Entrance(RR_FIRE_TEMPLE_MQ_LOWER, { [] { return Dungeon::FireTemple.IsMQ() && false; } }),
Entrance(RR_FIRE_TEMPLE_NEAR_BOSS_ROOM, { [] { return randoCtx->GetDungeon(FIRE_TEMPLE)->IsVanilla() && false; } }),
Entrance(RR_FIRE_TEMPLE_MQ_LOWER, { [] { return randoCtx->GetDungeon(FIRE_TEMPLE)->IsMQ() && false; } }),
Entrance(RR_FIRE_TEMPLE_BOSS_ROOM, { [] { return true; } }),
});

View File

@@ -1,10 +1,10 @@
#include "../location_access.hpp"
#include "../logic.hpp"
#include "../entrance.hpp"
#include "../dungeon.hpp"
#include "../../entrance.h"
#include "../../dungeon.h"
using namespace Logic;
using namespace Settings;
using namespace Rando;
void AreaTable_Init_ForestTemple() {
/*--------------------------
@@ -12,19 +12,19 @@ void AreaTable_Init_ForestTemple() {
---------------------------*/
areaTable[RR_FOREST_TEMPLE_ENTRYWAY] = Area("Forest Temple Entryway", "Forest Temple", RHT_FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_FOREST_TEMPLE_FIRST_ROOM, {[]{return Dungeon::ForestTemple.IsVanilla();}}),
Entrance(RR_FOREST_TEMPLE_MQ_LOBBY, {[]{return Dungeon::ForestTemple.IsMQ();}}),
Entrance(RR_FOREST_TEMPLE_FIRST_ROOM, {[]{return randoCtx->GetDungeon(FOREST_TEMPLE)->IsVanilla();}}),
Entrance(RR_FOREST_TEMPLE_MQ_LOBBY, {[]{return randoCtx->GetDungeon(FOREST_TEMPLE)->IsMQ();}}),
Entrance(RR_SACRED_FOREST_MEADOW, {[]{return true;}}),
});
/*--------------------------
| VANILLA DUNGEON |
---------------------------*/
if (Dungeon::ForestTemple.IsVanilla()) {
if (randoCtx->GetDungeon(FOREST_TEMPLE)->IsVanilla()) {
areaTable[RR_FOREST_TEMPLE_FIRST_ROOM] = Area("Forest Temple First Room", "Forest Temple", RHT_FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_FOREST_TEMPLE_FIRST_ROOM_CHEST, {[]{return true;}}),
LocationAccess(RC_FOREST_TEMPLE_GS_FIRST_ROOM, {[]{return (IsAdult && Bombs) || CanUse(RG_FAIRY_BOW) || CanUse(RG_HOOKSHOT) || CanUse(RG_BOOMERANG) || CanUse(RG_FAIRY_SLINGSHOT) || HasBombchus || CanUse(RG_DINS_FIRE) || (LogicForestFirstGS && (CanJumpslash || (IsChild && Bombs)));}}),
LocationAccess(RC_FOREST_TEMPLE_GS_FIRST_ROOM, {[]{return (IsAdult && Bombs) || CanUse(RG_FAIRY_BOW) || CanUse(RG_HOOKSHOT) || CanUse(RG_BOOMERANG) || CanUse(RG_FAIRY_SLINGSHOT) || HasBombchus || CanUse(RG_DINS_FIRE) || (randoCtx->GetTrickOption(RT_FOREST_FIRST_GS) && (CanJumpslash || (IsChild && Bombs)));}}),
}, {
//Exits
Entrance(RR_FOREST_TEMPLE_ENTRYWAY, {[]{return true;}}),
@@ -106,12 +106,12 @@ void AreaTable_Init_ForestTemple() {
EventAccess(&DekuBabaNuts, {[]{return DekuBabaNuts || (CanJumpslash || CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_FAIRY_BOW) || CanUse(RG_MEGATON_HAMMER) || HasExplosives || CanUse(RG_DINS_FIRE));}}),
}, {
//Locations
LocationAccess(RC_FOREST_TEMPLE_RAISED_ISLAND_COURTYARD_CHEST, {[]{return CanUse(RG_HOOKSHOT) || HasAccessTo(RR_FOREST_TEMPLE_FALLING_ROOM) || (HasAccessTo(RR_FOREST_TEMPLE_NE_OUTDOORS_UPPER) && IsAdult && LogicForestOutdoorsLedge && HoverBoots);}}),
LocationAccess(RC_FOREST_TEMPLE_GS_RAISED_ISLAND_COURTYARD, {[]{return CanUse(RG_HOOKSHOT) || (LogicForestOutdoorEastGS && CanUse(RG_BOOMERANG)) || Here(RR_FOREST_TEMPLE_FALLING_ROOM, []{return CanUse(RG_FAIRY_BOW) || CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_DINS_FIRE) || HasExplosives;});}}),
LocationAccess(RC_FOREST_TEMPLE_RAISED_ISLAND_COURTYARD_CHEST, {[]{return CanUse(RG_HOOKSHOT) || HasAccessTo(RR_FOREST_TEMPLE_FALLING_ROOM) || (HasAccessTo(RR_FOREST_TEMPLE_NE_OUTDOORS_UPPER) && IsAdult && randoCtx->GetTrickOption(RT_FOREST_OUTDOORS_LEDGE) && HoverBoots);}}),
LocationAccess(RC_FOREST_TEMPLE_GS_RAISED_ISLAND_COURTYARD, {[]{return CanUse(RG_HOOKSHOT) || (randoCtx->GetTrickOption(RT_FOREST_OUTDOORS_EAST_GS) && CanUse(RG_BOOMERANG)) || Here(RR_FOREST_TEMPLE_FALLING_ROOM, []{return CanUse(RG_FAIRY_BOW) || CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_DINS_FIRE) || HasExplosives;});}}),
}, {
//Exits
Entrance(RR_FOREST_TEMPLE_LOBBY, {[]{return true;}}),
Entrance(RR_FOREST_TEMPLE_NE_OUTDOORS_UPPER, {[]{return CanUse(RG_LONGSHOT) || (LogicForestVines && CanUse(RG_HOOKSHOT));}}),
Entrance(RR_FOREST_TEMPLE_NE_OUTDOORS_UPPER, {[]{return CanUse(RG_LONGSHOT) || (randoCtx->GetTrickOption(RT_FOREST_VINES) && CanUse(RG_HOOKSHOT));}}),
Entrance(RR_FOREST_TEMPLE_SEWER, {[]{return GoldScale || CanUse(RG_IRON_BOOTS) || HasAccessTo(RR_FOREST_TEMPLE_NE_OUTDOORS_UPPER);}}),
Entrance(RR_FOREST_TEMPLE_FALLING_ROOM, {[]{return false;}}),
});
@@ -124,7 +124,7 @@ void AreaTable_Init_ForestTemple() {
//Exits
Entrance(RR_FOREST_TEMPLE_NE_OUTDOORS_LOWER, {[]{return true;}}),
Entrance(RR_FOREST_TEMPLE_MAP_ROOM, {[]{return true;}}),
Entrance(RR_FOREST_TEMPLE_FALLING_ROOM, {[]{return LogicForestDoorFrame && CanJumpslash && CanUse(RG_HOVER_BOOTS) && CanUse(RG_SCARECROW);}}),
Entrance(RR_FOREST_TEMPLE_FALLING_ROOM, {[]{return randoCtx->GetTrickOption(RT_FOREST_DOORFRAME) && CanJumpslash && CanUse(RG_HOVER_BOOTS) && CanUse(RG_SCARECROW);}}),
});
areaTable[RR_FOREST_TEMPLE_MAP_ROOM] = Area("Forest Temple Map Room", "Forest Temple", RHT_FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
@@ -170,7 +170,7 @@ void AreaTable_Init_ForestTemple() {
}, {
//Exits
Entrance(RR_FOREST_TEMPLE_WEST_CORRIDOR, {[]{return true;}}),
Entrance(RR_FOREST_TEMPLE_NW_OUTDOORS_UPPER, {[]{return CanUse(RG_HOVER_BOOTS) || (LogicForestOutsideBackdoor && CanJumpslash && GoronBracelet);}}),
Entrance(RR_FOREST_TEMPLE_NW_OUTDOORS_UPPER, {[]{return CanUse(RG_HOVER_BOOTS) || (randoCtx->GetTrickOption(RT_FOREST_OUTSIDE_BACKDOOR) && CanJumpslash && GoronBracelet);}}),
Entrance(RR_FOREST_TEMPLE_NW_CORRIDOR_TWISTED, {[]{return IsAdult && GoronBracelet && SmallKeys(RR_FOREST_TEMPLE, 2);}}),
Entrance(RR_FOREST_TEMPLE_NW_CORRIDOR_STRAIGHTENED, {[]{return (CanUse(RG_FAIRY_BOW) || CanUse(RG_FAIRY_SLINGSHOT)) && GoronBracelet && SmallKeys(RR_FOREST_TEMPLE, 2);}}),
});
@@ -279,7 +279,7 @@ void AreaTable_Init_ForestTemple() {
/*---------------------------
| MASTER QUEST DUNGEON |
---------------------------*/
if (Dungeon::ForestTemple.IsMQ()) {
if (randoCtx->GetDungeon(FOREST_TEMPLE)->IsMQ()) {
areaTable[RR_FOREST_TEMPLE_MQ_LOBBY] = Area("Forest Temple MQ Lobby", "Forest Temple", RHT_FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_FOREST_TEMPLE_MQ_FIRST_ROOM_CHEST, {[]{return CanJumpslash || Bombs || CanUse(RG_STICKS) || Nuts || HookshotOrBoomerang || CanUse(RG_DINS_FIRE) || KokiriSword || CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_FAIRY_BOW) || CanUse(RG_HOVER_BOOTS);}}),
@@ -301,9 +301,9 @@ void AreaTable_Init_ForestTemple() {
//Exits
Entrance(RR_FOREST_TEMPLE_MQ_NW_OUTDOORS, {[]{return CanUse(RG_FAIRY_BOW) || CanUse(RG_FAIRY_SLINGSHOT);}}),
Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS, {[]{return CanUse(RG_FAIRY_BOW) || CanUse(RG_FAIRY_SLINGSHOT);}}), //This is as far as child can get
Entrance(RR_FOREST_TEMPLE_MQ_AFTER_BLOCK_PUZZLE, {[]{return IsAdult && (GoronBracelet || (LogicForestMQBlockPuzzle && HasBombchus && IsAdult && CanUse(RG_HOOKSHOT)));}}),
Entrance(RR_FOREST_TEMPLE_MQ_AFTER_BLOCK_PUZZLE, {[]{return IsAdult && (GoronBracelet || (randoCtx->GetTrickOption(RT_FOREST_MQ_BLOCK_PUZZLE) && HasBombchus && IsAdult && CanUse(RG_HOOKSHOT)));}}),
//Trick: IsAdult && (GoronBracelet || (LogicForestMQBlockPuzzle && HasBombchus && IsAdult && CanUse(RG_HOOKSHOT)))
Entrance(RR_FOREST_TEMPLE_MQ_OUTDOOR_LEDGE, {[]{return (LogicForestMQHallwaySwitchJS && IsAdult && CanUse(RG_HOVER_BOOTS)) || (LogicForestMQHallwaySwitchBoomerang && CanUse(RG_BOOMERANG)) || (LogicForestMQHallwaySwitchHookshot && IsAdult && CanUse(RG_HOOKSHOT));}}),
Entrance(RR_FOREST_TEMPLE_MQ_OUTDOOR_LEDGE, {[]{return (randoCtx->GetTrickOption(RT_FOREST_MQ_JS_HALLWAY_SWITCH) && IsAdult && CanUse(RG_HOVER_BOOTS)) || (randoCtx->GetTrickOption(RT_FOREST_MQ_RANG_HALLWAY_SWITCH) && CanUse(RG_BOOMERANG)) || (randoCtx->GetTrickOption(RT_FOREST_MQ_HOOKSHOT_HALLWAY_SWITCH) && IsAdult && CanUse(RG_HOOKSHOT));}}),
//Trick (Hookshot trick not added to either n64 or oot3d rando as of yet, to enable in SoH needs uncommenting in randomizer_tricks.cpp): (LogicForestMQHallwaySwitchJS && IsAdult && CanUse(RG_HOVER_BOOTS)) || (LogicForestMQHallwaySwitchHookshot && IsAdult && CanUse(RG_HOOKSHOT))
Entrance(RR_FOREST_TEMPLE_MQ_BOSS_REGION, {[]{return ForestTempleJoAndBeth && ForestTempleAmyAndMeg;}}),
});
@@ -314,7 +314,7 @@ void AreaTable_Init_ForestTemple() {
}, {
//Exits
Entrance(RR_FOREST_TEMPLE_MQ_BOW_REGION, {[]{return SmallKeys(RR_FOREST_TEMPLE, 4);}}),
Entrance(RR_FOREST_TEMPLE_MQ_OUTDOOR_LEDGE, {[]{return SmallKeys(RR_FOREST_TEMPLE, 3) || (LogicForestMQHallwaySwitchJS && ((IsAdult && CanUse(RG_HOOKSHOT)) || (LogicForestOutsideBackdoor && (IsAdult || (IsChild && CanUse(RG_STICKS))))));}}),
Entrance(RR_FOREST_TEMPLE_MQ_OUTDOOR_LEDGE, {[]{return SmallKeys(RR_FOREST_TEMPLE, 3) || (randoCtx->GetTrickOption(RT_FOREST_MQ_JS_HALLWAY_SWITCH) && ((IsAdult && CanUse(RG_HOOKSHOT)) || (randoCtx->GetTrickOption(RT_FOREST_OUTSIDE_BACKDOOR) && (IsAdult || (IsChild && CanUse(RG_STICKS))))));}}),
//Trick (Doing the hallway switch jumpslash as child requires sticks and has been added above): SmallKeys(RR_FOREST_TEMPLE, 3) || (LogicForestMQHallwaySwitchJS && ((IsAdult && CanUse(RG_HOOKSHOT)) || LogicForestOutsideBackdoor))
Entrance(RR_FOREST_TEMPLE_MQ_NW_OUTDOORS, {[]{return SmallKeys(RR_FOREST_TEMPLE, 2);}}),
});
@@ -332,7 +332,7 @@ void AreaTable_Init_ForestTemple() {
LocationAccess(RC_FOREST_TEMPLE_MQ_GS_LEVEL_ISLAND_COURTYARD, {[]{return CanAdultAttack || CanChildAttack;}}),
}, {
//Exits
Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS, {[]{return (IsAdult && (CanUse(RG_IRON_BOOTS) || CanUse(RG_LONGSHOT) || (LogicForestMQWellSwim && CanUse(RG_HOOKSHOT)))) || ProgressiveScale >= 2;}}),
Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS, {[]{return (IsAdult && (CanUse(RG_IRON_BOOTS) || CanUse(RG_LONGSHOT) || (randoCtx->GetTrickOption(RT_FOREST_MQ_WELL_SWIM) && CanUse(RG_HOOKSHOT)))) || ProgressiveScale >= 2;}}),
//Trick: (IsAdult && (CanUse(RG_IRON_BOOTS) || CanUse(RG_LONGSHOT) || (LogicForestMQWellSwim && CanUse(RG_HOOKSHOT)))) || ProgressiveScale >= 2
Entrance(RR_FOREST_TEMPLE_MQ_OUTDOORS_TOP_LEDGES, {[]{return IsAdult && CanUse(RG_FIRE_ARROWS);}}),
});
@@ -344,7 +344,7 @@ void AreaTable_Init_ForestTemple() {
}, {
//Locations
LocationAccess(RC_FOREST_TEMPLE_MQ_WELL_CHEST, {[]{return (IsAdult && CanUse(RG_FAIRY_BOW)) || (IsChild && CanUse(RG_FAIRY_SLINGSHOT));}}),
LocationAccess(RC_FOREST_TEMPLE_MQ_GS_RAISED_ISLAND_COURTYARD, {[]{return HookshotOrBoomerang || (IsAdult && CanUse(RG_FIRE_ARROWS) && (CanPlay(SongOfTime) || (CanUse(RG_HOVER_BOOTS) && LogicForestDoorFrame)));}}),
LocationAccess(RC_FOREST_TEMPLE_MQ_GS_RAISED_ISLAND_COURTYARD, {[]{return HookshotOrBoomerang || (IsAdult && CanUse(RG_FIRE_ARROWS) && (CanPlay(SongOfTime) || (CanUse(RG_HOVER_BOOTS) && randoCtx->GetTrickOption(RT_FOREST_DOORFRAME))));}}),
LocationAccess(RC_FOREST_TEMPLE_MQ_GS_WELL, {[]{return (IsAdult && ((CanUse(RG_IRON_BOOTS) && CanUse(RG_HOOKSHOT)) || CanUse(RG_FAIRY_BOW))) || (IsChild && CanUse(RG_FAIRY_SLINGSHOT));}}),
}, {
//Exits
@@ -358,7 +358,7 @@ void AreaTable_Init_ForestTemple() {
}, {
//Exits
Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS, {[]{return true;}}),
Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE, {[]{return LogicForestOutdoorsLedge && IsAdult && CanUse(RG_HOVER_BOOTS);}}),
Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE, {[]{return randoCtx->GetTrickOption(RT_FOREST_OUTDOORS_LEDGE) && IsAdult && CanUse(RG_HOVER_BOOTS);}}),
//Trick: LogicForestOutdoorsLedge && IsAdult && CanUse(RG_HOVER_BOOTS)
});
@@ -411,8 +411,8 @@ void AreaTable_Init_ForestTemple() {
Area("Forest Temple Boss Entryway", "Forest Temple", RHT_FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {},
{
// Exits
Entrance(RR_FOREST_TEMPLE_BOSS_REGION, { [] { return Dungeon::ForestTemple.IsVanilla() && false; } }),
Entrance(RR_FOREST_TEMPLE_MQ_BOSS_REGION, { [] { return Dungeon::ForestTemple.IsMQ() && false; } }),
Entrance(RR_FOREST_TEMPLE_BOSS_REGION, { [] { return randoCtx->GetDungeon(FOREST_TEMPLE)->IsVanilla() && false; } }),
Entrance(RR_FOREST_TEMPLE_MQ_BOSS_REGION, { [] { return randoCtx->GetDungeon(FOREST_TEMPLE)->IsMQ() && false; } }),
Entrance(RR_FOREST_TEMPLE_BOSS_ROOM, { [] { return true; } }),
});

View File

@@ -1,11 +1,11 @@
#include "../location_access.hpp"
#include "../logic.hpp"
#include "../entrance.hpp"
#include "../dungeon.hpp"
#include "../trial.hpp"
#include "../../entrance.h"
#include "../../dungeon.h"
#include "../../trial.h"
using namespace Logic;
using namespace Settings;
using namespace Rando;
void AreaTable_Init_GanonsCastle() {
/*--------------------------
@@ -13,15 +13,15 @@ void AreaTable_Init_GanonsCastle() {
---------------------------*/
areaTable[RR_GANONS_CASTLE_ENTRYWAY] = Area("Ganon's Castle Entryway", "Ganon's Castle", RHT_GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_GANONS_CASTLE_LOBBY, {[]{return Dungeon::GanonsCastle.IsVanilla();}}),
Entrance(RR_GANONS_CASTLE_MQ_LOBBY, {[]{return Dungeon::GanonsCastle.IsMQ();}}),
Entrance(RR_GANONS_CASTLE_LOBBY, {[]{return randoCtx->GetDungeon(GANONS_CASTLE)->IsVanilla();}}),
Entrance(RR_GANONS_CASTLE_MQ_LOBBY, {[]{return randoCtx->GetDungeon(GANONS_CASTLE)->IsMQ();}}),
Entrance(RR_CASTLE_GROUNDS_FROM_GANONS_CASTLE, {[]{return true;}}),
});
/*--------------------------
| VANILLA DUNGEON |
---------------------------*/
if (Dungeon::GanonsCastle.IsVanilla()) {
if (randoCtx->GetDungeon(GANONS_CASTLE)->IsVanilla()) {
areaTable[RR_GANONS_CASTLE_LOBBY] = Area("Ganon's Castle Lobby", "Ganon's Castle", RHT_GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_SHEIK_HINT_GC, {[]{return true;}}),
@@ -34,13 +34,13 @@ void AreaTable_Init_GanonsCastle() {
Entrance(RR_GANONS_CASTLE_SHADOW_TRIAL, {[]{return true;}}),
Entrance(RR_GANONS_CASTLE_SPIRIT_TRIAL, {[]{return true;}}),
Entrance(RR_GANONS_CASTLE_LIGHT_TRIAL, {[]{return CanUse(RG_GOLDEN_GAUNTLETS);}}),
Entrance(RR_GANONS_CASTLE_TOWER, {[]{return (ForestTrialClear || Trial::ForestTrial.IsSkipped()) &&
(FireTrialClear || Trial::FireTrial.IsSkipped()) &&
(WaterTrialClear || Trial::WaterTrial.IsSkipped()) &&
(ShadowTrialClear || Trial::ShadowTrial.IsSkipped()) &&
(SpiritTrialClear || Trial::SpiritTrial.IsSkipped()) &&
(LightTrialClear || Trial::LightTrial.IsSkipped());}}),
Entrance(RR_GANONS_CASTLE_DEKU_SCRUBS, {[]{return LogicLensCastle || CanUse(RG_LENS_OF_TRUTH);}}),
Entrance(RR_GANONS_CASTLE_TOWER, {[]{return (ForestTrialClear || randoCtx->GetTrial(Rando::FOREST_TRIAL)->IsSkipped()) &&
(FireTrialClear || randoCtx->GetTrial(Rando::FIRE_TRIAL)->IsSkipped()) &&
(WaterTrialClear || randoCtx->GetTrial(Rando::WATER_TRIAL)->IsSkipped()) &&
(ShadowTrialClear || randoCtx->GetTrial(Rando::SHADOW_TRIAL)->IsSkipped()) &&
(SpiritTrialClear || randoCtx->GetTrial(Rando::SPIRIT_TRIAL)->IsSkipped()) &&
(LightTrialClear || randoCtx->GetTrial(Rando::LIGHT_TRIAL)->IsSkipped());}}),
Entrance(RR_GANONS_CASTLE_DEKU_SCRUBS, {[]{return randoCtx->GetTrickOption(RT_LENS_GANON) || CanUse(RG_LENS_OF_TRUTH);}}),
});
areaTable[RR_GANONS_CASTLE_DEKU_SCRUBS] = Area("Ganon's Castle Deku Scrubs", "Ganon's Castle", RHT_GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, {
@@ -80,7 +80,7 @@ void AreaTable_Init_GanonsCastle() {
areaTable[RR_GANONS_CASTLE_SHADOW_TRIAL] = Area("Ganon's Castle Shadow Trial", "Ganon's Castle", RHT_GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&ShadowTrialClear, {[]{return CanUse(RG_LIGHT_ARROWS) && CanUse(RG_MEGATON_HAMMER) && ((FireArrows && (LogicLensCastle || CanUse(RG_LENS_OF_TRUTH))) || (CanUse(RG_LONGSHOT) && (CanUse(RG_HOVER_BOOTS) || (DinsFire && (LogicLensCastle || CanUse(RG_LENS_OF_TRUTH))))));}}),
EventAccess(&ShadowTrialClear, {[]{return CanUse(RG_LIGHT_ARROWS) && CanUse(RG_MEGATON_HAMMER) && ((FireArrows && (randoCtx->GetTrickOption(RT_LENS_GANON) || CanUse(RG_LENS_OF_TRUTH))) || (CanUse(RG_LONGSHOT) && (CanUse(RG_HOVER_BOOTS) || (DinsFire && (randoCtx->GetTrickOption(RT_LENS_GANON) || CanUse(RG_LENS_OF_TRUTH))))));}}),
}, {
//Locations
LocationAccess(RC_GANONS_CASTLE_SHADOW_TRIAL_FRONT_CHEST, {[]{return CanUse(RG_FIRE_ARROWS) || CanUse(RG_HOOKSHOT) || CanUse(RG_HOVER_BOOTS) || CanPlay(SongOfTime) || IsChild;}}),
@@ -89,17 +89,17 @@ void AreaTable_Init_GanonsCastle() {
areaTable[RR_GANONS_CASTLE_SPIRIT_TRIAL] = Area("Ganon's Castle Spirit Trial", "Ganon's Castle", RHT_GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&NutPot, {[]{return NutPot || (((LogicSpiritTrialHookshot && CanJumpslash) || CanUse(RG_HOOKSHOT)) && HasBombchus && CanUse(RG_FAIRY_BOW) && (CanUse(RG_MIRROR_SHIELD) || (SunlightArrows && CanUse(RG_LIGHT_ARROWS))));}}),
EventAccess(&SpiritTrialClear, {[]{return CanUse(RG_LIGHT_ARROWS) && (CanUse(RG_MIRROR_SHIELD) || SunlightArrows) && HasBombchus && ((LogicSpiritTrialHookshot && CanJumpslash) || CanUse(RG_HOOKSHOT));}}),
EventAccess(&NutPot, {[]{return NutPot || (((randoCtx->GetTrickOption(RT_GANON_SPIRIT_TRIAL_HOOKSHOT) && CanJumpslash) || CanUse(RG_HOOKSHOT)) && HasBombchus && CanUse(RG_FAIRY_BOW) && (CanUse(RG_MIRROR_SHIELD) || (randoCtx->GetOption(RSK_SUNLIGHT_ARROWS) && CanUse(RG_LIGHT_ARROWS))));}}),
EventAccess(&SpiritTrialClear, {[]{return CanUse(RG_LIGHT_ARROWS) && (CanUse(RG_MIRROR_SHIELD) || randoCtx->GetOption(RSK_SUNLIGHT_ARROWS)) && HasBombchus && ((randoCtx->GetTrickOption(RT_GANON_SPIRIT_TRIAL_HOOKSHOT) && CanJumpslash) || CanUse(RG_HOOKSHOT));}}),
}, {
//Locations
LocationAccess(RC_GANONS_CASTLE_SPIRIT_TRIAL_CRYSTAL_SWITCH_CHEST, {[]{return (LogicSpiritTrialHookshot || CanUse(RG_HOOKSHOT)) && CanJumpslash;}}),
LocationAccess(RC_GANONS_CASTLE_SPIRIT_TRIAL_INVISIBLE_CHEST, {[]{return (LogicSpiritTrialHookshot || CanUse(RG_HOOKSHOT)) && HasBombchus && (LogicLensCastle || CanUse(RG_LENS_OF_TRUTH));}}),
LocationAccess(RC_GANONS_CASTLE_SPIRIT_TRIAL_CRYSTAL_SWITCH_CHEST, {[]{return (randoCtx->GetTrickOption(RT_GANON_SPIRIT_TRIAL_HOOKSHOT) || CanUse(RG_HOOKSHOT)) && CanJumpslash;}}),
LocationAccess(RC_GANONS_CASTLE_SPIRIT_TRIAL_INVISIBLE_CHEST, {[]{return (randoCtx->GetTrickOption(RT_GANON_SPIRIT_TRIAL_HOOKSHOT) || CanUse(RG_HOOKSHOT)) && HasBombchus && (randoCtx->GetTrickOption(RT_LENS_GANON) || CanUse(RG_LENS_OF_TRUTH));}}),
}, {});
areaTable[RR_GANONS_CASTLE_LIGHT_TRIAL] = Area("Ganon's Castle Light Trial", "Ganon's Castle", RHT_GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&LightTrialClear, {[]{return CanUse(RG_LIGHT_ARROWS) && CanUse(RG_HOOKSHOT) && SmallKeys(RR_GANONS_CASTLE, 2) && (LogicLensCastle || CanUse(RG_LENS_OF_TRUTH));}}),
EventAccess(&LightTrialClear, {[]{return CanUse(RG_LIGHT_ARROWS) && CanUse(RG_HOOKSHOT) && SmallKeys(RR_GANONS_CASTLE, 2) && (randoCtx->GetTrickOption(RT_LENS_GANON) || CanUse(RG_LENS_OF_TRUTH));}}),
}, {
//Locations
LocationAccess(RC_GANONS_CASTLE_LIGHT_TRIAL_FIRST_LEFT_CHEST, {[]{return true;}}),
@@ -108,7 +108,7 @@ void AreaTable_Init_GanonsCastle() {
LocationAccess(RC_GANONS_CASTLE_LIGHT_TRIAL_FIRST_RIGHT_CHEST, {[]{return true;}}),
LocationAccess(RC_GANONS_CASTLE_LIGHT_TRIAL_SECOND_RIGHT_CHEST, {[]{return true;}}),
LocationAccess(RC_GANONS_CASTLE_LIGHT_TRIAL_THIRD_RIGHT_CHEST, {[]{return true;}}),
LocationAccess(RC_GANONS_CASTLE_LIGHT_TRIAL_INVISIBLE_ENEMIES_CHEST, {[]{return LogicLensCastle || CanUse(RG_LENS_OF_TRUTH);}}),
LocationAccess(RC_GANONS_CASTLE_LIGHT_TRIAL_INVISIBLE_ENEMIES_CHEST, {[]{return randoCtx->GetTrickOption(RT_LENS_GANON) || CanUse(RG_LENS_OF_TRUTH);}}),
LocationAccess(RC_GANONS_CASTLE_LIGHT_TRIAL_LULLABY_CHEST, {[]{return CanPlay(ZeldasLullaby) && SmallKeys(RR_GANONS_CASTLE, 1);}}),
}, {});
}
@@ -123,7 +123,7 @@ void AreaTable_Init_GanonsCastle() {
/*---------------------------
| MASTER QUEST DUNGEON |
---------------------------*/
if (Dungeon::GanonsCastle.IsMQ()) {
if (randoCtx->GetDungeon(GANONS_CASTLE)->IsMQ()) {
areaTable[RR_GANONS_CASTLE_MQ_LOBBY] = Area("Ganon's Castle MQ Lobby", "Ganons Castle", RHT_GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_SHEIK_HINT_MQ_GC, {[]{return true;}}),
@@ -136,13 +136,13 @@ void AreaTable_Init_GanonsCastle() {
Entrance(RR_GANONS_CASTLE_MQ_SHADOW_TRIAL, {[]{return true;}}),
Entrance(RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL, {[]{return true;}}),
Entrance(RR_GANONS_CASTLE_MQ_LIGHT_TRIAL, {[]{return CanUse(RG_GOLDEN_GAUNTLETS);}}),
Entrance(RR_GANONS_CASTLE_TOWER, {[]{return (ForestTrialClear || Trial::ForestTrial.IsSkipped()) &&
(FireTrialClear || Trial::FireTrial.IsSkipped()) &&
(WaterTrialClear || Trial::WaterTrial.IsSkipped()) &&
(ShadowTrialClear || Trial::ShadowTrial.IsSkipped()) &&
(SpiritTrialClear || Trial::SpiritTrial.IsSkipped()) &&
(LightTrialClear || Trial::LightTrial.IsSkipped());}}),
Entrance(RR_GANONS_CASTLE_MQ_DEKU_SCRUBS, {[]{return LogicLensCastleMQ || CanUse(RG_LENS_OF_TRUTH);}}),
Entrance(RR_GANONS_CASTLE_TOWER, {[]{return (ForestTrialClear || randoCtx->GetTrial(Rando::FOREST_TRIAL)->IsSkipped()) &&
(FireTrialClear || randoCtx->GetTrial(Rando::FIRE_TRIAL)->IsSkipped()) &&
(WaterTrialClear || randoCtx->GetTrial(Rando::WATER_TRIAL)->IsSkipped()) &&
(ShadowTrialClear || randoCtx->GetTrial(Rando::SHADOW_TRIAL)->IsSkipped()) &&
(SpiritTrialClear || randoCtx->GetTrial(Rando::SPIRIT_TRIAL)->IsSkipped()) &&
(LightTrialClear || randoCtx->GetTrial(Rando::LIGHT_TRIAL)->IsSkipped());}}),
Entrance(RR_GANONS_CASTLE_MQ_DEKU_SCRUBS, {[]{return randoCtx->GetTrickOption(RT_LENS_GANON_MQ) || CanUse(RG_LENS_OF_TRUTH);}}),
});
areaTable[RR_GANONS_CASTLE_MQ_DEKU_SCRUBS] = Area("Ganon's Castle MQ Deku Scrubs", "Ganon's Castle", RHT_GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, {
@@ -169,7 +169,7 @@ void AreaTable_Init_GanonsCastle() {
areaTable[RR_GANONS_CASTLE_MQ_FIRE_TRIAL] = Area("Ganon's Castle MQ Fire Trial", "Ganons Castle", RHT_GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&FireTrialClear, {[]{return CanUse(RG_GORON_TUNIC) && CanUse(RG_GOLDEN_GAUNTLETS) && CanUse(RG_LIGHT_ARROWS) && (CanUse(RG_LONGSHOT) || HoverBoots || (LogicFireTrialMQ && CanUse(RG_HOOKSHOT)));}}),
EventAccess(&FireTrialClear, {[]{return CanUse(RG_GORON_TUNIC) && CanUse(RG_GOLDEN_GAUNTLETS) && CanUse(RG_LIGHT_ARROWS) && (CanUse(RG_LONGSHOT) || HoverBoots || (randoCtx->GetTrickOption(RT_GANON_MQ_FIRE_TRIAL) && CanUse(RG_HOOKSHOT)));}}),
//Trick: CanUse(RG_GORON_TUNIC) && CanUse(RG_GOLDEN_GAUNTLETS) && CanUse(RG_LIGHT_ARROWS) && (CanUse(RG_LONGSHOT) || HoverBoots || (LogicFireTrialMQ && CanUse(RG_HOOKSHOT)))
}, {}, {});
@@ -184,32 +184,32 @@ void AreaTable_Init_GanonsCastle() {
areaTable[RR_GANONS_CASTLE_MQ_SHADOW_TRIAL] = Area("Ganon's Castle MQ Shadow Trial", "Ganons Castle", RHT_GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&ShadowTrialClear, {[]{return IsAdult && CanUse(RG_LIGHT_ARROWS) && (LogicLensCastleMQ || CanUse(RG_LENS_OF_TRUTH)) && (HoverBoots || (Hookshot && (HasFireSource || LogicShadowTrialMQ)));}}),
EventAccess(&ShadowTrialClear, {[]{return IsAdult && CanUse(RG_LIGHT_ARROWS) && (randoCtx->GetTrickOption(RT_LENS_GANON_MQ) || CanUse(RG_LENS_OF_TRUTH)) && (HoverBoots || (Hookshot && (HasFireSource || randoCtx->GetTrickOption(RT_GANON_MQ_SHADOW_TRIAL))));}}),
//Trick: IsAdult && CanUse(RG_LIGHT_ARROWS) && (LogicLensCastleMQ || CanUse(RG_LENS_OF_TRUTH)) && (HoverBoots || (Hookshot && (HasFireSource || LogicShadowTrialMQ)))
}, {
//Locations
LocationAccess(RC_GANONS_CASTLE_MQ_SHADOW_TRIAL_BOMB_FLOWER_CHEST, {[]{return IsAdult && ((Bow && (CanUse(RG_HOOKSHOT) || CanUse(RG_HOVER_BOOTS))) || (CanUse(RG_HOVER_BOOTS) && (LogicLensCastleMQ || CanUse(RG_LENS_OF_TRUTH)) && (HasExplosives || GoronBracelet || CanUse(RG_DINS_FIRE))));}}),
LocationAccess(RC_GANONS_CASTLE_MQ_SHADOW_TRIAL_EYE_SWITCH_CHEST, {[]{return IsAdult && Bow && (LogicLensCastleMQ || CanUse(RG_LENS_OF_TRUTH)) && (HoverBoots || (Hookshot && (HasFireSource || LogicShadowTrialMQ)));}}),
LocationAccess(RC_GANONS_CASTLE_MQ_SHADOW_TRIAL_BOMB_FLOWER_CHEST, {[]{return IsAdult && ((Bow && (CanUse(RG_HOOKSHOT) || CanUse(RG_HOVER_BOOTS))) || (CanUse(RG_HOVER_BOOTS) && (randoCtx->GetTrickOption(RT_LENS_GANON_MQ) || CanUse(RG_LENS_OF_TRUTH)) && (HasExplosives || GoronBracelet || CanUse(RG_DINS_FIRE))));}}),
LocationAccess(RC_GANONS_CASTLE_MQ_SHADOW_TRIAL_EYE_SWITCH_CHEST, {[]{return IsAdult && Bow && (randoCtx->GetTrickOption(RT_LENS_GANON_MQ) || CanUse(RG_LENS_OF_TRUTH)) && (HoverBoots || (Hookshot && (HasFireSource || randoCtx->GetTrickOption(RT_GANON_MQ_SHADOW_TRIAL))));}}),
//Trick: IsAdult && Bow && (LogicLensCastleMQ || CanUse(RG_LENS_OF_TRUTH)) && (HoverBoots || (Hookshot && (HasFireSource || LogicShadowTrialMQ)))
}, {});
areaTable[RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL] = Area("Ganon's Castle MQ Spirit Castle", "Ganons Castle", RHT_GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&SpiritTrialClear, {[]{return IsAdult && CanUse(RG_LIGHT_ARROWS) && Hammer && HasBombchus && ((FireArrows && MirrorShield) || SunlightArrows);}}),
EventAccess(&NutPot, {[]{return NutPot || (Hammer && HasBombchus && IsAdult && ((CanUse(RG_FIRE_ARROWS) && MirrorShield) || (SunlightArrows && CanUse(RG_LIGHT_ARROWS))));}}),
EventAccess(&SpiritTrialClear, {[]{return IsAdult && CanUse(RG_LIGHT_ARROWS) && Hammer && HasBombchus && ((FireArrows && MirrorShield) || randoCtx->GetOption(RSK_SUNLIGHT_ARROWS));}}),
EventAccess(&NutPot, {[]{return NutPot || (Hammer && HasBombchus && IsAdult && ((CanUse(RG_FIRE_ARROWS) && MirrorShield) || (randoCtx->GetOption(RSK_SUNLIGHT_ARROWS) && CanUse(RG_LIGHT_ARROWS))));}}),
}, {
//Locations
LocationAccess(RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_FIRST_CHEST, {[]{return IsAdult && (Bow || LogicRustedSwitches) && Hammer;}}),
LocationAccess(RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_INVISIBLE_CHEST, {[]{return IsAdult && (Bow || LogicRustedSwitches) && Hammer && HasBombchus && (LogicLensCastleMQ || CanUse(RG_LENS_OF_TRUTH));}}),
LocationAccess(RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_FRONT_LEFT_CHEST, {[]{return IsAdult && Hammer && HasBombchus && ((CanUse(RG_FIRE_ARROWS) && CanUse(RG_MIRROR_SHIELD)) || (SunlightArrows && CanUse(RG_LIGHT_ARROWS)));}}),
LocationAccess(RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_LEFT_CHEST, {[]{return IsAdult && Hammer && HasBombchus && ((CanUse(RG_FIRE_ARROWS) && CanUse(RG_MIRROR_SHIELD)) || (SunlightArrows && CanUse(RG_LIGHT_ARROWS)));}}),
LocationAccess(RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_GOLDEN_GAUNTLETS_CHEST, {[]{return IsAdult && Hammer && HasBombchus && ((CanUse(RG_FIRE_ARROWS) && CanUse(RG_MIRROR_SHIELD)) || (SunlightArrows && CanUse(RG_LIGHT_ARROWS)));}}),
LocationAccess(RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_RIGHT_CHEST, {[]{return IsAdult && Hammer && HasBombchus && ((CanUse(RG_FIRE_ARROWS) && CanUse(RG_MIRROR_SHIELD)) || (SunlightArrows && CanUse(RG_LIGHT_ARROWS)));}}),
LocationAccess(RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_FIRST_CHEST, {[]{return IsAdult && (Bow || randoCtx->GetTrickOption(RT_RUSTED_SWITCHES)) && Hammer;}}),
LocationAccess(RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_INVISIBLE_CHEST, {[]{return IsAdult && (Bow || randoCtx->GetTrickOption(RT_RUSTED_SWITCHES)) && Hammer && HasBombchus && (randoCtx->GetTrickOption(RT_LENS_GANON_MQ) || CanUse(RG_LENS_OF_TRUTH));}}),
LocationAccess(RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_FRONT_LEFT_CHEST, {[]{return IsAdult && Hammer && HasBombchus && ((CanUse(RG_FIRE_ARROWS) && CanUse(RG_MIRROR_SHIELD)) || (randoCtx->GetOption(RSK_SUNLIGHT_ARROWS) && CanUse(RG_LIGHT_ARROWS)));}}),
LocationAccess(RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_LEFT_CHEST, {[]{return IsAdult && Hammer && HasBombchus && ((CanUse(RG_FIRE_ARROWS) && CanUse(RG_MIRROR_SHIELD)) || (randoCtx->GetOption(RSK_SUNLIGHT_ARROWS) && CanUse(RG_LIGHT_ARROWS)));}}),
LocationAccess(RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_GOLDEN_GAUNTLETS_CHEST, {[]{return IsAdult && Hammer && HasBombchus && ((CanUse(RG_FIRE_ARROWS) && CanUse(RG_MIRROR_SHIELD)) || (randoCtx->GetOption(RSK_SUNLIGHT_ARROWS) && CanUse(RG_LIGHT_ARROWS)));}}),
LocationAccess(RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_RIGHT_CHEST, {[]{return IsAdult && Hammer && HasBombchus && ((CanUse(RG_FIRE_ARROWS) && CanUse(RG_MIRROR_SHIELD)) || (randoCtx->GetOption(RSK_SUNLIGHT_ARROWS) && CanUse(RG_LIGHT_ARROWS)));}}),
}, {});
areaTable[RR_GANONS_CASTLE_MQ_LIGHT_TRIAL] = Area("Ganon's Castle MQ Light Trial", "Ganons Castle", RHT_GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&LightTrialClear, {[]{return IsAdult && (CanUse(RG_MASTER_SWORD) || CanUse(RG_KOKIRI_SWORD) || CanUse(RG_BIGGORON_SWORD)) && CanUse(RG_LIGHT_ARROWS) && SmallKeys(RR_GANONS_CASTLE, 3) && (LogicLensCastleMQ || CanUse(RG_LENS_OF_TRUTH)) && (Hookshot || LogicLightTrialMQ);}}),
EventAccess(&LightTrialClear, {[]{return IsAdult && (CanUse(RG_MASTER_SWORD) || CanUse(RG_KOKIRI_SWORD) || CanUse(RG_BIGGORON_SWORD)) && CanUse(RG_LIGHT_ARROWS) && SmallKeys(RR_GANONS_CASTLE, 3) && (randoCtx->GetTrickOption(RT_LENS_GANON_MQ) || CanUse(RG_LENS_OF_TRUTH)) && (Hookshot || randoCtx->GetTrickOption(RT_GANON_MQ_LIGHT_TRIAL));}}),
//Trick: IsAdult && CanUse(RG_LIGHT_ARROWS) && SmallKeys(RR_GANONS_CASTLE, 3) && (LogicLensCastleMQ || CanUse(RG_LENS_OF_TRUTH)) && (Hookshot || LogicLightTrialMQ)
}, {
//Locations

View File

@@ -1,10 +1,10 @@
#include "../location_access.hpp"
#include "../logic.hpp"
#include "../entrance.hpp"
#include "../dungeon.hpp"
#include "../../entrance.h"
#include "../../dungeon.h"
using namespace Logic;
using namespace Settings;
using namespace Rando;
void AreaTable_Init_GerudoTrainingGrounds() {
/*--------------------------
@@ -12,15 +12,15 @@ void AreaTable_Init_GerudoTrainingGrounds() {
---------------------------*/
areaTable[RR_GERUDO_TRAINING_GROUNDS_ENTRYWAY] = Area("Gerudo Training Grounds Entryway", "Gerudo Training Grounds", RHT_GERUDO_TRAINING_GROUND, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUNDS_LOBBY, {[]{return Dungeon::GerudoTrainingGrounds.IsVanilla();}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_LOBBY, {[]{return Dungeon::GerudoTrainingGrounds.IsMQ();}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_LOBBY, {[]{return randoCtx->GetDungeon(GERUDO_TRAINING_GROUNDS)->IsVanilla();}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_LOBBY, {[]{return randoCtx->GetDungeon(GERUDO_TRAINING_GROUNDS)->IsMQ();}}),
Entrance(RR_GERUDO_FORTRESS, {[]{return true;}}),
});
/*--------------------------
| VANILLA DUNGEON |
---------------------------*/
if (Dungeon::GerudoTrainingGrounds.IsVanilla()) {
if (randoCtx->GetDungeon(GERUDO_TRAINING_GROUNDS)->IsVanilla()) {
areaTable[RR_GERUDO_TRAINING_GROUNDS_LOBBY] = Area("Gerudo Training Grounds Lobby", "Gerudo Training Grounds", RHT_GERUDO_TRAINING_GROUND, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_GERUDO_TRAINING_GROUND_LOBBY_LEFT_CHEST, {[]{return CanUse(RG_FAIRY_BOW) || CanUse(RG_FAIRY_SLINGSHOT);}}),
@@ -30,14 +30,14 @@ void AreaTable_Init_GerudoTrainingGrounds() {
}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUNDS_ENTRYWAY, {[]{return true;}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_ROOM, {[]{return (CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD)) && (CanUse(RG_HOOKSHOT) || LogicGtgWithoutHookshot);}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_ROOM, {[]{return (CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD)) && (CanUse(RG_HOOKSHOT) || randoCtx->GetTrickOption(RT_GTG_WITHOUT_HOOKSHOT));}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_LAVA_ROOM, {[]{return Here(RR_GERUDO_TRAINING_GROUNDS_LOBBY, []{return (CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD)) && HasExplosives;});}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_CENTRAL_MAZE, {[]{return true;}}),
});
areaTable[RR_GERUDO_TRAINING_GROUNDS_CENTRAL_MAZE] = Area("Gerudo Training Grounds Central Maze", "Gerudo Training Grounds", RHT_GERUDO_TRAINING_GROUND, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_GERUDO_TRAINING_GROUND_HIDDEN_CEILING_CHEST, {[]{return SmallKeys(RR_GERUDO_TRAINING_GROUNDS, 3) && (LogicLensGtg || CanUse(RG_LENS_OF_TRUTH));}}),
LocationAccess(RC_GERUDO_TRAINING_GROUND_HIDDEN_CEILING_CHEST, {[]{return SmallKeys(RR_GERUDO_TRAINING_GROUNDS, 3) && (randoCtx->GetTrickOption(RT_LENS_GTG) || CanUse(RG_LENS_OF_TRUTH));}}),
LocationAccess(RC_GERUDO_TRAINING_GROUND_MAZE_PATH_FIRST_CHEST, {[]{return SmallKeys(RR_GERUDO_TRAINING_GROUNDS, 4);}}),
LocationAccess(RC_GERUDO_TRAINING_GROUND_MAZE_PATH_SECOND_CHEST, {[]{return SmallKeys(RR_GERUDO_TRAINING_GROUNDS, 6);}}),
LocationAccess(RC_GERUDO_TRAINING_GROUND_MAZE_PATH_THIRD_CHEST, {[]{return SmallKeys(RR_GERUDO_TRAINING_GROUNDS, 7);}}),
@@ -70,7 +70,7 @@ void AreaTable_Init_GerudoTrainingGrounds() {
areaTable[RR_GERUDO_TRAINING_GROUNDS_HAMMER_ROOM] = Area("Gerudo Training Grounds Hammer Room", "Gerudo Training Grounds", RHT_GERUDO_TRAINING_GROUND, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_GERUDO_TRAINING_GROUND_HAMMER_ROOM_CLEAR_CHEST, {[]{return CanAdultAttack || CanChildAttack;}}),
LocationAccess(RC_GERUDO_TRAINING_GROUND_HAMMER_ROOM_SWITCH_CHEST, {[]{return CanUse(RG_MEGATON_HAMMER) || (CanTakeDamage && LogicFlamingChests);}}),
LocationAccess(RC_GERUDO_TRAINING_GROUND_HAMMER_ROOM_SWITCH_CHEST, {[]{return CanUse(RG_MEGATON_HAMMER) || (CanTakeDamage && randoCtx->GetTrickOption(RT_FLAMING_CHESTS));}}),
}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUNDS_EYE_STATUE_LOWER, {[]{return CanUse(RG_MEGATON_HAMMER) && CanUse(RG_FAIRY_BOW);}}),
@@ -98,8 +98,8 @@ void AreaTable_Init_GerudoTrainingGrounds() {
LocationAccess(RC_GERUDO_TRAINING_GROUND_BEFORE_HEAVY_BLOCK_CHEST, {[]{return CanJumpslash;}}),
}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUNDS_EYE_STATUE_UPPER, {[]{return (LogicLensGtg || CanUse(RG_LENS_OF_TRUTH)) && (CanUse(RG_HOOKSHOT) || (LogicGtgFakeWall && CanUse(RG_HOVER_BOOTS)));}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_LIKE_LIKE_ROOM, {[]{return (LogicLensGtg || CanUse(RG_LENS_OF_TRUTH)) && (CanUse(RG_HOOKSHOT) || (LogicGtgFakeWall && CanUse(RG_HOVER_BOOTS))) && CanUse(RG_SILVER_GAUNTLETS);}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_EYE_STATUE_UPPER, {[]{return (randoCtx->GetTrickOption(RT_LENS_GTG) || CanUse(RG_LENS_OF_TRUTH)) && (CanUse(RG_HOOKSHOT) || (randoCtx->GetTrickOption(RT_GTG_FAKE_WALL) && CanUse(RG_HOVER_BOOTS)));}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_LIKE_LIKE_ROOM, {[]{return (randoCtx->GetTrickOption(RT_LENS_GTG) || CanUse(RG_LENS_OF_TRUTH)) && (CanUse(RG_HOOKSHOT) || (randoCtx->GetTrickOption(RT_GTG_FAKE_WALL) && CanUse(RG_HOVER_BOOTS))) && CanUse(RG_SILVER_GAUNTLETS);}}),
});
areaTable[RR_GERUDO_TRAINING_GROUNDS_LIKE_LIKE_ROOM] = Area("Gerudo Training Grounds Like Like Room", "Gerudo Training Grounds", RHT_GERUDO_TRAINING_GROUND, NO_DAY_NIGHT_CYCLE, {}, {
@@ -114,12 +114,12 @@ void AreaTable_Init_GerudoTrainingGrounds() {
/*---------------------------
| MASTER QUEST DUNGEON |
---------------------------*/
if (Dungeon::GerudoTrainingGrounds.IsMQ()) {
if (randoCtx->GetDungeon(GERUDO_TRAINING_GROUNDS)->IsMQ()) {
areaTable[RR_GERUDO_TRAINING_GROUNDS_MQ_LOBBY] = Area("Gerudo Training Grounds MQ Lobby", "Gerudo Training Grounds", RHT_GERUDO_TRAINING_GROUND, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_LEFT_CHEST, {[]{return true;}}),
LocationAccess(RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_RIGHT_CHEST, {[]{return true;}}),
LocationAccess(RC_GERUDO_TRAINING_GROUND_MQ_HIDDEN_CEILING_CHEST, {[]{return LogicLensGtgMQ || CanUse(RG_LENS_OF_TRUTH);}}),
LocationAccess(RC_GERUDO_TRAINING_GROUND_MQ_HIDDEN_CEILING_CHEST, {[]{return randoCtx->GetTrickOption(RT_LENS_GTG_MQ) || CanUse(RG_LENS_OF_TRUTH);}}),
LocationAccess(RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_FIRST_CHEST, {[]{return true;}}),
LocationAccess(RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_SECOND_CHEST, {[]{return true;}}),
LocationAccess(RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_THIRD_CHEST, {[]{return SmallKeys(RR_GERUDO_TRAINING_GROUNDS, 1);}}),
@@ -151,7 +151,7 @@ void AreaTable_Init_GerudoTrainingGrounds() {
LocationAccess(RC_GERUDO_TRAINING_GROUND_MQ_FIRST_IRON_KNUCKLE_CHEST, {[]{return CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD) || HasExplosives;}}),
}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_STALFOS_ROOM, {[]{return (IsAdult && CanUse(RG_LONGSHOT)) || LogicGtgMQWithoutHookshot || (LogicGtgMQWithHookshot && IsAdult && CanUse(RG_HOOKSHOT));}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_STALFOS_ROOM, {[]{return (IsAdult && CanUse(RG_LONGSHOT)) || randoCtx->GetTrickOption(RT_GTG_MQ_WIHTOUT_HOOKSHOT) || (randoCtx->GetTrickOption(RT_GTG_MQ_WITH_HOOKSHOT) && IsAdult && CanUse(RG_HOOKSHOT));}}),
//Trick: (IsAdult && CanUse(RG_LONGSHOT)) || LogicGtgMQWithoutHookshot || (LogicGtgMQWithHookshot && IsAdult && CanUse(RG_HOOKSHOT))
});
@@ -164,7 +164,7 @@ void AreaTable_Init_GerudoTrainingGrounds() {
LocationAccess(RC_GERUDO_TRAINING_GROUND_MQ_HEAVY_BLOCK_CHEST, {[]{return CanUse(RG_SILVER_GAUNTLETS) && (CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD));}}),
}, {
//Exits
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_BACK_AREAS, {[]{return IsAdult && (CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD)) && (LogicLensGtgMQ || CanUse(RG_LENS_OF_TRUTH)) && BlueFire && (CanPlay(SongOfTime) || (LogicGtgFakeWall && IsAdult && CanUse(RG_HOVER_BOOTS)));}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_MQ_BACK_AREAS, {[]{return IsAdult && (CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD)) && (randoCtx->GetTrickOption(RT_LENS_GTG_MQ) || CanUse(RG_LENS_OF_TRUTH)) && BlueFire && (CanPlay(SongOfTime) || (randoCtx->GetTrickOption(RT_GTG_FAKE_WALL) && IsAdult && CanUse(RG_HOVER_BOOTS)));}}),
//Trick: IsAdult && (LogicLensGtgMQ || CanUse(RG_LENS_OF_TRUTH)) && BlueFire && (CanPlay(SongOfTime) || (LogicGtgFakeWall && IsAdult && CanUse(RG_HOVER_BOOTS)))
});

View File

@@ -1,9 +1,9 @@
#include "../location_access.hpp"
#include "../logic.hpp"
#include "../entrance.hpp"
#include "../../entrance.h"
using namespace Logic;
using namespace Settings;
using namespace Rando;
void AreaTable_Init_GerudoValley() {
areaTable[RR_GERUDO_VALLEY] = Area("Gerudo Valley", "Gerudo Valley", RHT_GERUDO_VALLEY, DAY_NIGHT_CYCLE, {
@@ -18,7 +18,7 @@ void AreaTable_Init_GerudoValley() {
Entrance(RR_GV_UPPER_STREAM, {[]{return true;}}),
Entrance(RR_GV_CRATE_LEDGE, {[]{return IsChild || CanUse(RG_LONGSHOT);}}),
Entrance(RR_GV_GROTTO_LEDGE, {[]{return true;}}),
Entrance(RR_GV_FORTRESS_SIDE, {[]{return (IsAdult && (CanRideEpona || CanUse(RG_LONGSHOT) || GerudoFortress.Is(GERUDOFORTRESS_OPEN) || CarpenterRescue)) || (IsChild && CanUse(RG_HOOKSHOT));}}),
Entrance(RR_GV_FORTRESS_SIDE, {[]{return (IsAdult && (CanRideEpona || CanUse(RG_LONGSHOT) || randoCtx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_OPEN) || CarpenterRescue)) || (IsChild && CanUse(RG_HOOKSHOT));}}),
});
areaTable[RR_GV_UPPER_STREAM] = Area("GV Upper Stream", "Gerudo Valley", RHT_GERUDO_VALLEY, DAY_NIGHT_CYCLE, {
@@ -69,7 +69,7 @@ void AreaTable_Init_GerudoValley() {
//Exits
Entrance(RR_GERUDO_FORTRESS, {[]{return true;}}),
Entrance(RR_GV_UPPER_STREAM, {[]{return true;}}),
Entrance(RR_GERUDO_VALLEY, {[]{return IsChild || CanRideEpona || CanUse(RG_LONGSHOT) || GerudoFortress.Is(GERUDOFORTRESS_OPEN) || CarpenterRescue;}}),
Entrance(RR_GERUDO_VALLEY, {[]{return IsChild || CanRideEpona || CanUse(RG_LONGSHOT) || randoCtx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_OPEN) || CarpenterRescue;}}),
Entrance(RR_GV_CARPENTER_TENT, {[]{return IsAdult;}}),
Entrance(RR_GV_STORMS_GROTTO, {[]{return IsAdult && CanOpenStormGrotto;}}),
Entrance(RR_GV_CRATE_LEDGE, {[]{return false;}}),
@@ -105,26 +105,26 @@ void AreaTable_Init_GerudoValley() {
LocationAccess(RC_GF_HBA_1000_POINTS, {[]{return GerudoToken && CanRideEpona && Bow && AtDay;}}),
LocationAccess(RC_GF_HBA_1500_POINTS, {[]{return GerudoToken && CanRideEpona && Bow && AtDay;}}),
LocationAccess(RC_GF_NORTH_F1_CARPENTER, {[]{return CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD);}}),
LocationAccess(RC_GF_NORTH_F2_CARPENTER, {[]{return (CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD)) && (GerudoToken || CanUse(RG_FAIRY_BOW) || CanUse(RG_HOOKSHOT) || CanUse(RG_HOVER_BOOTS) || LogicGerudoKitchen);}}),
LocationAccess(RC_GF_NORTH_F2_CARPENTER, {[]{return (CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD)) && (GerudoToken || CanUse(RG_FAIRY_BOW) || CanUse(RG_HOOKSHOT) || CanUse(RG_HOVER_BOOTS) || randoCtx->GetTrickOption(RT_GF_KITCHEN));}}),
LocationAccess(RC_GF_SOUTH_F1_CARPENTER, {[]{return CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD);}}),
LocationAccess(RC_GF_SOUTH_F2_CARPENTER, {[]{return CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD);}}),
LocationAccess(RC_GF_GERUDO_MEMBERSHIP_CARD, {[]{return CanFinishGerudoFortress;}}),
LocationAccess(RC_GF_GS_ARCHERY_RANGE, {[]{return IsAdult && HookshotOrBoomerang && GerudoToken && AtNight && CanGetNightTimeGS;}}),
LocationAccess(RC_GF_GS_TOP_FLOOR, {[]{return IsAdult && AtNight && (CanJumpslash || CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_BOOMERANG) || HasExplosives || CanUse(RG_FAIRY_BOW) || CanUse(RG_HOOKSHOT) || CanUse(RG_DINS_FIRE)) && (GerudoToken || CanUse(RG_FAIRY_BOW) || CanUse(RG_HOOKSHOT) || CanUse(RG_HOVER_BOOTS) || LogicGerudoKitchen || LogicGFJump) && CanGetNightTimeGS;}}),
LocationAccess(RC_GF_GS_TOP_FLOOR, {[]{return IsAdult && AtNight && (CanJumpslash || CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_BOOMERANG) || HasExplosives || CanUse(RG_FAIRY_BOW) || CanUse(RG_HOOKSHOT) || CanUse(RG_DINS_FIRE)) && (GerudoToken || CanUse(RG_FAIRY_BOW) || CanUse(RG_HOOKSHOT) || CanUse(RG_HOVER_BOOTS) || randoCtx->GetTrickOption(RT_GF_KITCHEN) || randoCtx->GetTrickOption(RT_GF_JUMP)) && CanGetNightTimeGS;}}),
}, {
//Exits
Entrance(RR_GV_FORTRESS_SIDE, {[]{return true;}}),
Entrance(RR_GF_OUTSIDE_GATE, {[]{return GF_GateOpen;}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_ENTRYWAY, {[]{return GtG_GateOpen && (IsAdult || ShuffleDungeonEntrances);}}),
Entrance(RR_GERUDO_TRAINING_GROUNDS_ENTRYWAY, {[]{return GtG_GateOpen && (IsAdult || randoCtx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES));}}),
Entrance(RR_GF_STORMS_GROTTO, {[]{return IsAdult && CanOpenStormGrotto;}}),
});
areaTable[RR_GF_OUTSIDE_GATE] = Area("GF Outside Gate", "Gerudo Fortress", RHT_GERUDO_FORTRESS, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&GF_GateOpen, {[]{return IsAdult && GerudoToken && (ShuffleGerudoToken || ShuffleOverworldEntrances /*|| ShuffleSpecialIndoorEntrances*/);}}),
EventAccess(&GF_GateOpen, {[]{return IsAdult && GerudoToken && (randoCtx->GetOption(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD) || randoCtx->GetOption(RSK_SHUFFLE_OVERWORLD_ENTRANCES) /*|| ShuffleSpecialIndoorEntrances*/);}}),
}, {}, {
//Exits
Entrance(RR_GERUDO_FORTRESS, {[]{return (IsAdult && (Hookshot || !ShuffleOverworldEntrances)) || GF_GateOpen;}}),
Entrance(RR_GERUDO_FORTRESS, {[]{return (IsAdult && (Hookshot || !randoCtx->GetOption(RSK_SHUFFLE_OVERWORLD_ENTRANCES))) || GF_GateOpen;}}),
Entrance(RR_WASTELAND_NEAR_FORTRESS, {[]{return true;}}),
});
@@ -139,7 +139,7 @@ void AreaTable_Init_GerudoValley() {
areaTable[RR_WASTELAND_NEAR_FORTRESS] = Area("Wasteland Near Fortress", "Haunted Wasteland", RHT_HAUNTED_WASTELAND, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_GF_OUTSIDE_GATE, {[]{return true;}}),
Entrance(RR_HAUNTED_WASTELAND, {[]{return CanUse(RG_HOVER_BOOTS) || CanUse(RG_LONGSHOT) || LogicWastelandCrossing;}}),
Entrance(RR_HAUNTED_WASTELAND, {[]{return CanUse(RG_HOVER_BOOTS) || CanUse(RG_LONGSHOT) || randoCtx->GetTrickOption(RT_HW_CROSSING);}}),
});
areaTable[RR_HAUNTED_WASTELAND] = Area("Haunted Wasteland", "Haunted Wasteland", RHT_HAUNTED_WASTELAND, NO_DAY_NIGHT_CYCLE, {
@@ -153,14 +153,14 @@ void AreaTable_Init_GerudoValley() {
LocationAccess(RC_WASTELAND_GS, {[]{return HookshotOrBoomerang;}}),
}, {
//Exits
Entrance(RR_WASTELAND_NEAR_COLOSSUS, {[]{return LogicLensWasteland || CanUse(RG_LENS_OF_TRUTH);}}),
Entrance(RR_WASTELAND_NEAR_FORTRESS, {[]{return CanUse(RG_HOVER_BOOTS) || CanUse(RG_LONGSHOT) || LogicWastelandCrossing;}}),
Entrance(RR_WASTELAND_NEAR_COLOSSUS, {[]{return randoCtx->GetTrickOption(RT_LENS_HW) || CanUse(RG_LENS_OF_TRUTH);}}),
Entrance(RR_WASTELAND_NEAR_FORTRESS, {[]{return CanUse(RG_HOVER_BOOTS) || CanUse(RG_LONGSHOT) || randoCtx->GetTrickOption(RT_HW_CROSSING);}}),
});
areaTable[RR_WASTELAND_NEAR_COLOSSUS] = Area("Wasteland Near Colossus", "Haunted Wasteland", RHT_HAUNTED_WASTELAND, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_DESERT_COLOSSUS, {[]{return true;}}),
Entrance(RR_HAUNTED_WASTELAND, {[]{return LogicReverseWasteland || false;}}),
Entrance(RR_HAUNTED_WASTELAND, {[]{return randoCtx->GetTrickOption(RT_HW_REVERSE) || false;}}),
});
areaTable[RR_DESERT_COLOSSUS] = Area("Desert Colossus", "Desert Colossus", RHT_DESERT_COLOSSUS, DAY_NIGHT_CYCLE, {
@@ -172,7 +172,7 @@ void AreaTable_Init_GerudoValley() {
LocationAccess(RC_COLOSSUS_FREESTANDING_POH, {[]{return IsAdult && CanPlantBean(RR_DESERT_COLOSSUS);}}),
LocationAccess(RC_COLOSSUS_GS_BEAN_PATCH, {[]{return CanPlantBugs && CanChildAttack;}}),
LocationAccess(RC_COLOSSUS_GS_TREE, {[]{return IsAdult && HookshotOrBoomerang && AtNight && CanGetNightTimeGS;}}),
LocationAccess(RC_COLOSSUS_GS_HILL, {[]{return IsAdult && AtNight && ((CanPlantBean(RR_DESERT_COLOSSUS) && CanAdultAttack) || CanUse(RG_LONGSHOT) || (LogicColossusGS && CanUse(RG_HOOKSHOT))) && CanGetNightTimeGS;}}),
LocationAccess(RC_COLOSSUS_GS_HILL, {[]{return IsAdult && AtNight && ((CanPlantBean(RR_DESERT_COLOSSUS) && CanAdultAttack) || CanUse(RG_LONGSHOT) || (randoCtx->GetTrickOption(RT_COLOSSUS_GS) && CanUse(RG_HOOKSHOT))) && CanGetNightTimeGS;}}),
LocationAccess(RC_COLOSSUS_GOSSIP_STONE, {[]{return true;}}),
}, {
//Exits

View File

@@ -1,9 +1,9 @@
#include "../location_access.hpp"
#include "../logic.hpp"
#include "../entrance.hpp"
#include "../../entrance.h"
using namespace Logic;
using namespace Settings;
using namespace Rando;
void AreaTable_Init_HyruleField() {
areaTable[RR_HYRULE_FIELD] = Area("Hyrule Field", "Hyrule Field", RHT_HYRULE_FIELD, DAY_NIGHT_CYCLE, {
@@ -115,7 +115,7 @@ void AreaTable_Init_HyruleField() {
LocationAccess(RC_LH_SUN, {[]{return IsAdult && WaterTempleClear && CanUse(RG_FAIRY_BOW);}}),
LocationAccess(RC_LH_FREESTANDING_POH, {[]{return IsAdult && (CanUse(RG_SCARECROW) || CanPlantBean(RR_LAKE_HYLIA));}}),
LocationAccess(RC_LH_GS_BEAN_PATCH, {[]{return CanPlantBugs && CanChildAttack;}}),
LocationAccess(RC_LH_GS_LAB_WALL, {[]{return IsChild && (HookshotOrBoomerang || (LogicLabWallGS && CanJumpslash)) && AtNight && CanGetNightTimeGS;}}),
LocationAccess(RC_LH_GS_LAB_WALL, {[]{return IsChild && (HookshotOrBoomerang || (randoCtx->GetTrickOption(RT_LH_LAB_WALL_GS) && CanJumpslash)) && AtNight && CanGetNightTimeGS;}}),
LocationAccess(RC_LH_GS_SMALL_ISLAND, {[]{return IsChild && CanChildAttack && AtNight && CanGetNightTimeGS;}}),
LocationAccess(RC_LH_GS_TREE, {[]{return IsAdult && CanUse(RG_LONGSHOT) && AtNight && CanGetNightTimeGS;}}),
LocationAccess(RC_LH_LAB_GOSSIP_STONE, {[]{return true;}}),
@@ -128,7 +128,7 @@ void AreaTable_Init_HyruleField() {
Entrance(RR_LH_OWL_FLIGHT, {[]{return IsChild;}}),
Entrance(RR_LH_FISHING_ISLAND, {[]{return IsChild || CanUse(RG_SCARECROW) || CanPlantBean(RR_LAKE_HYLIA) || WaterTempleClear;}}),
Entrance(RR_LH_LAB, {[]{return true;}}),
Entrance(RR_WATER_TEMPLE_ENTRYWAY, {[]{return CanUse(RG_HOOKSHOT) && ((CanUse(RG_IRON_BOOTS) || (LogicWaterHookshotEntry && ProgressiveScale >= 2)) || (IsAdult && CanUse(RG_LONGSHOT) && ProgressiveScale >= 2));}}),
Entrance(RR_WATER_TEMPLE_ENTRYWAY, {[]{return CanUse(RG_HOOKSHOT) && ((CanUse(RG_IRON_BOOTS) || (randoCtx->GetTrickOption(RT_LH_WATER_HOOKSHOT) && ProgressiveScale >= 2)) || (IsAdult && CanUse(RG_LONGSHOT) && ProgressiveScale >= 2));}}),
Entrance(RR_LH_GROTTO, {[]{return true;}}),
});
@@ -148,7 +148,7 @@ void AreaTable_Init_HyruleField() {
EventAccess(&EyedropsAccess, {[]{return EyedropsAccess || (IsAdult && (EyeballFrogAccess || (EyeballFrog && DisableTradeRevert)));}}),
}, {
//Locations
LocationAccess(RC_LH_LAB_DIVE, {[]{return ProgressiveScale >= 2 || (LogicLabDiving && CanUse(RG_IRON_BOOTS) && CanUse(RG_HOOKSHOT));}}),
LocationAccess(RC_LH_LAB_DIVE, {[]{return ProgressiveScale >= 2 || (randoCtx->GetTrickOption(RT_LH_LAB_DIVING) && CanUse(RG_IRON_BOOTS) && CanUse(RG_HOOKSHOT));}}),
LocationAccess(RC_LH_TRADE_FROG, {[]{return IsAdult && EyeballFrog;}}),
LocationAccess(RC_LH_GS_LAB_CRATE, {[]{return CanUse(RG_IRON_BOOTS) && CanUse(RG_HOOKSHOT);}}),
}, {

View File

@@ -1,10 +1,10 @@
#include "../location_access.hpp"
#include "../logic.hpp"
#include "../entrance.hpp"
#include "../dungeon.hpp"
#include "../../entrance.h"
#include "../../dungeon.h"
using namespace Logic;
using namespace Settings;
using namespace Rando;
void AreaTable_Init_IceCavern() {
/*--------------------------
@@ -12,15 +12,15 @@ void AreaTable_Init_IceCavern() {
---------------------------*/
areaTable[RR_ICE_CAVERN_ENTRYWAY] = Area("Ice Cavern Entryway", "Ice Cavern", RHT_ICE_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_ICE_CAVERN_BEGINNING, {[]{return Dungeon::IceCavern.IsVanilla();}}),
Entrance(RR_ICE_CAVERN_MQ_BEGINNING, {[]{return Dungeon::IceCavern.IsMQ() && CanUseProjectile;}}),
Entrance(RR_ICE_CAVERN_BEGINNING, {[]{return randoCtx->GetDungeon(ICE_CAVERN)->IsVanilla();}}),
Entrance(RR_ICE_CAVERN_MQ_BEGINNING, {[]{return randoCtx->GetDungeon(ICE_CAVERN)->IsMQ() && CanUseProjectile;}}),
Entrance(RR_ZORAS_FOUNTAIN, {[]{return true;}}),
});
/*--------------------------
| VANILLA DUNGEON |
---------------------------*/
if (Dungeon::IceCavern.IsVanilla()) {
if (randoCtx->GetDungeon(ICE_CAVERN)->IsVanilla()) {
areaTable[RR_ICE_CAVERN_BEGINNING] = Area("Ice Cavern Beginning", "Ice Cavern", RHT_ICE_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_ICE_CAVERN_ENTRYWAY, {[]{return true;}}),
@@ -39,14 +39,14 @@ void AreaTable_Init_IceCavern() {
LocationAccess(RC_ICE_CAVERN_FREESTANDING_POH, {[]{return BlueFire;}}),
LocationAccess(RC_ICE_CAVERN_GS_SPINNING_SCYTHE_ROOM, {[]{return HookshotOrBoomerang;}}),
LocationAccess(RC_ICE_CAVERN_GS_HEART_PIECE_ROOM, {[]{return BlueFire && HookshotOrBoomerang;}}),
LocationAccess(RC_ICE_CAVERN_GS_PUSH_BLOCK_ROOM, {[]{return BlueFire && (HookshotOrBoomerang || (LogicIceBlockGS && IsAdult && CanUse(RG_HOVER_BOOTS)));}}),
LocationAccess(RC_ICE_CAVERN_GS_PUSH_BLOCK_ROOM, {[]{return BlueFire && (HookshotOrBoomerang || (randoCtx->GetTrickOption(RT_ICE_BLOCK_GS) && IsAdult && CanUse(RG_HOVER_BOOTS)));}}),
}, {});
}
/*---------------------------
| MASTER QUEST DUNGEON |
---------------------------*/
if (Dungeon::IceCavern.IsMQ()) {
if (randoCtx->GetDungeon(ICE_CAVERN)->IsMQ()) {
areaTable[RR_ICE_CAVERN_MQ_BEGINNING] = Area("Ice Cavern MQ Beginning", "Ice Cavern", RHT_ICE_CAVERN, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&FairyPot, {[]{return true;}}),
@@ -71,7 +71,7 @@ void AreaTable_Init_IceCavern() {
LocationAccess(RC_ICE_CAVERN_MQ_IRON_BOOTS_CHEST, {[]{return IsAdult && (CanJumpslash || CanUse(RG_MEGATON_HAMMER));}}),
LocationAccess(RC_SHEIK_IN_ICE_CAVERN, {[]{return IsAdult && (CanJumpslash || CanUse(RG_MEGATON_HAMMER));}}),
LocationAccess(RC_ICE_CAVERN_MQ_GS_ICE_BLOCK, {[]{return CanAdultAttack || CanChildAttack;}}),
LocationAccess(RC_ICE_CAVERN_MQ_GS_SCARECROW, {[]{return CanUse(RG_SCARECROW) || (HoverBoots && CanUse(RG_LONGSHOT)) || (LogicIceMQScarecrow && IsAdult);}}),
LocationAccess(RC_ICE_CAVERN_MQ_GS_SCARECROW, {[]{return CanUse(RG_SCARECROW) || (HoverBoots && CanUse(RG_LONGSHOT)) || (randoCtx->GetTrickOption(RT_ICE_MQ_SCARECROW) && IsAdult);}}),
//Tricks: (CanUse(RG_SCARECROW) || (HoverBoots && CanUse(RG_LONGSHOT)) || LogicIceMQScarecrow) && IsAdult
}, {});
@@ -79,7 +79,7 @@ void AreaTable_Init_IceCavern() {
//Locations
LocationAccess(RC_ICE_CAVERN_MQ_COMPASS_CHEST, {[]{return true;}}),
LocationAccess(RC_ICE_CAVERN_MQ_FREESTANDING_POH, {[]{return HasExplosives;}}),
LocationAccess(RC_ICE_CAVERN_MQ_GS_RED_ICE, {[]{return CanPlay(SongOfTime) || LogicIceMQRedIceGS;}}),
LocationAccess(RC_ICE_CAVERN_MQ_GS_RED_ICE, {[]{return CanPlay(SongOfTime) || randoCtx->GetTrickOption(RT_ICE_MQ_RED_ICE_GS);}}),
//Trick: CanPlay(SongOfTime) || LogicIceMQRedIceGS
}, {});
}

View File

@@ -1,10 +1,10 @@
#include "../location_access.hpp"
#include "../logic.hpp"
#include "../entrance.hpp"
#include "../dungeon.hpp"
#include "../../entrance.h"
#include "../../dungeon.h"
using namespace Logic;
using namespace Settings;
using namespace Rando;
void AreaTable_Init_JabuJabusBelly() {
/*--------------------------
@@ -12,15 +12,15 @@ void AreaTable_Init_JabuJabusBelly() {
---------------------------*/
areaTable[RR_JABU_JABUS_BELLY_ENTRYWAY] = Area("Jabu Jabus Belly Entryway", "Jabu Jabus Belly", RHT_JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_JABU_JABUS_BELLY_BEGINNING, {[]{return Dungeon::JabuJabusBelly.IsVanilla();}}),
Entrance(RR_JABU_JABUS_BELLY_MQ_BEGINNING, {[]{return Dungeon::JabuJabusBelly.IsMQ();}}),
Entrance(RR_JABU_JABUS_BELLY_BEGINNING, {[]{return randoCtx->GetDungeon(JABU_JABUS_BELLY)->IsVanilla();}}),
Entrance(RR_JABU_JABUS_BELLY_MQ_BEGINNING, {[]{return randoCtx->GetDungeon(JABU_JABUS_BELLY)->IsMQ();}}),
Entrance(RR_ZORAS_FOUNTAIN, {[]{return true;}}),
});
/*--------------------------
| VANILLA DUNGEON |
---------------------------*/
if (Dungeon::JabuJabusBelly.IsVanilla()) {
if (randoCtx->GetDungeon(JABU_JABUS_BELLY)->IsVanilla()) {
areaTable[RR_JABU_JABUS_BELLY_BEGINNING] = Area("Jabu Jabus Belly Beginning", "Jabu Jabus Belly", RHT_JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_JABU_JABUS_BELLY_ENTRYWAY, {[]{return true;}}),
@@ -32,7 +32,7 @@ void AreaTable_Init_JabuJabusBelly() {
Entrance(RR_JABU_JABUS_BELLY_BEGINNING, {[]{return true;}}),
Entrance(RR_JABU_JABUS_BELLY_MAIN_UPPER, {[]{return true;}}),
Entrance(RR_JABU_JABUS_BELLY_LIFT_LOWER, {[]{return true;}}),
Entrance(RR_JABU_JABUS_BELLY_NEAR_BOSS_ROOM, {[]{return HasAccessTo(RR_JABU_JABUS_BELLY_LIFT_UPPER) || (LogicJabuBossHover && IsAdult && CanUse(RG_HOVER_BOOTS));}}),
Entrance(RR_JABU_JABUS_BELLY_NEAR_BOSS_ROOM, {[]{return HasAccessTo(RR_JABU_JABUS_BELLY_LIFT_UPPER) || (randoCtx->GetTrickOption(RT_JABU_BOSS_HOVER) && IsAdult && CanUse(RG_HOVER_BOOTS));}}),
});
areaTable[RR_JABU_JABUS_BELLY_MAIN_UPPER] = Area("Jabu Jabus Belly Main Upper", "Jabu Jabus Belly", RHT_JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, {
@@ -76,7 +76,7 @@ void AreaTable_Init_JabuJabusBelly() {
areaTable[RR_JABU_JABUS_BELLY_LIFT_LOWER] = Area("Jabu Jabus Belly Lift Lower", "Jabu Jabus Belly", RHT_JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_JABU_JABUS_BELLY_DEKU_SCRUB, {[]{return (IsChild || CanDive || LogicJabuAlcoveJumpDive || CanUse(RG_IRON_BOOTS)) && CanStunDeku;}}),
LocationAccess(RC_JABU_JABUS_BELLY_DEKU_SCRUB, {[]{return (IsChild || CanDive || randoCtx->GetTrickOption(RT_JABU_ALCOVE_JUMP_DIVE) || CanUse(RG_IRON_BOOTS)) && CanStunDeku;}}),
}, {
//Exits
Entrance(RR_JABU_JABUS_BELLY_SHABOMB_CORRIDOR, {[]{return true;}}),
@@ -154,14 +154,14 @@ void AreaTable_Init_JabuJabusBelly() {
}, {
//Exits
Entrance(RR_JABU_JABUS_BELLY_LIFT_MIDDLE, {[]{return true;}}),
Entrance(RR_JABU_JABUS_BELLY_BOSS_ENTRYWAY, {[]{return CanUse(RG_BOOMERANG) || (LogicJabuNearBossRanged && ((IsAdult && (CanUse(RG_HOOKSHOT) || CanUse(RG_FAIRY_BOW))) || (IsChild && CanUse(RG_FAIRY_SLINGSHOT)))) || (LogicJabuNearBossExplosives && (HasBombchus || (IsAdult && CanUse(RG_HOVER_BOOTS) && Bombs)));}}),
Entrance(RR_JABU_JABUS_BELLY_BOSS_ENTRYWAY, {[]{return CanUse(RG_BOOMERANG) || (randoCtx->GetTrickOption(RT_JABU_NEAR_BOSS_RANGED) && ((IsAdult && (CanUse(RG_HOOKSHOT) || CanUse(RG_FAIRY_BOW))) || (IsChild && CanUse(RG_FAIRY_SLINGSHOT)))) || (randoCtx->GetTrickOption(RT_JABU_NEAR_BOSS_EXPLOSIVES) && (HasBombchus || (IsAdult && CanUse(RG_HOVER_BOOTS) && Bombs)));}}),
});
}
/*---------------------------
| MASTER QUEST DUNGEON |
---------------------------*/
if (Dungeon::JabuJabusBelly.IsMQ()) {
if (randoCtx->GetDungeon(JABU_JABUS_BELLY)->IsMQ()) {
areaTable[RR_JABU_JABUS_BELLY_MQ_BEGINNING] = Area("Jabu Jabus Belly MQ Beginning", "Jabu Jabus Belly", RHT_JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&NutPot, {[]{return true;}}),
@@ -184,7 +184,7 @@ void AreaTable_Init_JabuJabusBelly() {
LocationAccess(RC_JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_SWITCHES_CHEST, {[]{return true;}}),
LocationAccess(RC_JABU_JABUS_BELLY_MQ_BOOMERANG_ROOM_SMALL_CHEST, {[]{return true;}}),
LocationAccess(RC_JABU_JABUS_BELLY_MQ_BOOMERANG_CHEST, {[]{return true;}}),
LocationAccess(RC_JABU_JABUS_BELLY_MQ_GS_BOOMERANG_CHEST_ROOM, {[]{return CanPlay(SongOfTime) || (LogicJabuMQSoTGS && IsChild && CanUse(RG_BOOMERANG));}}),
LocationAccess(RC_JABU_JABUS_BELLY_MQ_GS_BOOMERANG_CHEST_ROOM, {[]{return CanPlay(SongOfTime) || (randoCtx->GetTrickOption(RT_JABU_MQ_SOT_GS) && IsChild && CanUse(RG_BOOMERANG));}}),
//Trick: CanPlay(SongOfTime) || (LogicJabuMQSoTGS && IsChild && CanUse(RG_BOOMERANG))
}, {
//Exits
@@ -196,7 +196,7 @@ void AreaTable_Init_JabuJabusBelly() {
//Locations
LocationAccess(RC_JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_ROOM_CHEST, {[]{return true;}}),
LocationAccess(RC_JABU_JABUS_BELLY_MQ_GS_TAILPASARAN_ROOM, {[]{return Sticks || CanUse(RG_DINS_FIRE);}}),
LocationAccess(RC_JABU_JABUS_BELLY_MQ_GS_INVISIBLE_ENEMIES_ROOM, {[]{return (LogicLensJabuMQ || CanUse(RG_LENS_OF_TRUTH)) || Here(RR_JABU_JABUS_BELLY_MQ_MAIN, []{return IsAdult && CanUse(RG_HOVER_BOOTS) && CanUse(RG_HOOKSHOT);});}}),
LocationAccess(RC_JABU_JABUS_BELLY_MQ_GS_INVISIBLE_ENEMIES_ROOM, {[]{return (randoCtx->GetTrickOption(RT_LENS_JABU_MQ) || CanUse(RG_LENS_OF_TRUTH)) || Here(RR_JABU_JABUS_BELLY_MQ_MAIN, []{return IsAdult && CanUse(RG_HOVER_BOOTS) && CanUse(RG_HOOKSHOT);});}}),
}, {
//Exits
Entrance(RR_JABU_JABUS_BELLY_MQ_MAIN, {[]{return true;}}),
@@ -225,8 +225,8 @@ void AreaTable_Init_JabuJabusBelly() {
Area("Jabu Jabus Belly Boss Entryway", "Jabu Jabus Belly", RHT_JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {},
{
// Exits
Entrance(RR_JABU_JABUS_BELLY_NEAR_BOSS_ROOM, { [] { return Dungeon::JabuJabusBelly.IsVanilla(); } }),
Entrance(RR_JABU_JABUS_BELLY_MQ_BOSS_AREA, { [] { return Dungeon::JabuJabusBelly.IsMQ(); } }),
Entrance(RR_JABU_JABUS_BELLY_NEAR_BOSS_ROOM, { [] { return randoCtx->GetDungeon(JABU_JABUS_BELLY)->IsVanilla(); } }),
Entrance(RR_JABU_JABUS_BELLY_MQ_BOSS_AREA, { [] { return randoCtx->GetDungeon(JABU_JABUS_BELLY)->IsMQ(); } }),
Entrance(RR_JABU_JABUS_BELLY_BOSS_ROOM, { [] { return true; } }),
});

View File

@@ -1,16 +1,16 @@
#include "../location_access.hpp"
#include "../logic.hpp"
#include "../entrance.hpp"
#include "../../entrance.h"
using namespace Logic;
using namespace Settings;
using namespace Rando;
void AreaTable_Init_Kakariko() {
areaTable[RR_KAKARIKO_VILLAGE] = Area("Kakariko Village", "Kakariko Village", RHT_KAKARIKO_VILLAGE, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&CojiroAccess, {[]{return CojiroAccess || (IsAdult && WakeUpAdultTalon);}}),
EventAccess(&BugRock, {[]{return true;}}),
EventAccess(&KakarikoVillageGateOpen, {[]{return KakarikoVillageGateOpen || (IsChild && (ZeldasLetter || OpenKakariko.Is(OPENKAKARIKO_OPEN)));}}),
EventAccess(&KakarikoVillageGateOpen, {[]{return KakarikoVillageGateOpen || (IsChild && (ZeldasLetter || randoCtx->GetOption(RSK_KAK_GATE).Is(RO_KAK_GATE_OPEN)));}}),
}, {
//Locations
LocationAccess(RC_SHEIK_IN_KAKARIKO, {[]{return IsAdult && ForestMedallion && FireMedallion && WaterMedallion;}}),
@@ -21,7 +21,7 @@ void AreaTable_Init_Kakariko() {
LocationAccess(RC_KAK_GS_SKULLTULA_HOUSE, {[]{return IsChild && AtNight && CanGetNightTimeGS;}}),
LocationAccess(RC_KAK_GS_GUARDS_HOUSE, {[]{return IsChild && AtNight && CanGetNightTimeGS;}}),
LocationAccess(RC_KAK_GS_TREE, {[]{return IsChild && AtNight && CanGetNightTimeGS;}}),
LocationAccess(RC_KAK_GS_WATCHTOWER, {[]{return IsChild && (Slingshot || HasBombchus || CanUse(RG_FAIRY_BOW) || CanUse(RG_LONGSHOT) || (LogicKakarikoTowerGS && CanJumpslash)) && AtNight && CanGetNightTimeGS;}}),
LocationAccess(RC_KAK_GS_WATCHTOWER, {[]{return IsChild && (Slingshot || HasBombchus || CanUse(RG_FAIRY_BOW) || CanUse(RG_LONGSHOT) || (randoCtx->GetTrickOption(RT_KAK_TOWER_GS) && CanJumpslash)) && AtNight && CanGetNightTimeGS;}}),
}, {
//Exits
Entrance(RR_HYRULE_FIELD, {[]{return true;}}),
@@ -31,12 +31,12 @@ void AreaTable_Init_Kakariko() {
Entrance(RR_KAK_WINDMILL, {[]{return true;}}),
Entrance(RR_KAK_BAZAAR, {[]{return IsAdult && AtDay;}}),
Entrance(RR_KAK_SHOOTING_GALLERY, {[]{return IsAdult && AtDay;}}),
Entrance(RR_BOTTOM_OF_THE_WELL_ENTRYWAY, {[]{return DrainWell && (IsChild || ShuffleDungeonEntrances.IsNot(SHUFFLEDUNGEONS_OFF));}}),
Entrance(RR_BOTTOM_OF_THE_WELL_ENTRYWAY, {[]{return DrainWell && (IsChild || randoCtx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).IsNot(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF));}}),
Entrance(RR_KAK_POTION_SHOP_FRONT, {[]{return AtDay || IsChild;}}),
Entrance(RR_KAK_REDEAD_GROTTO, {[]{return CanOpenBombGrotto;}}),
Entrance(RR_KAK_IMPAS_LEDGE, {[]{return (IsChild && AtDay) || CanUse(RG_HOOKSHOT) || (IsAdult && LogicVisibleCollision);}}),
Entrance(RR_KAK_ROOFTOP, {[]{return CanUse(RG_HOOKSHOT) || (LogicManOnRoof && (IsAdult || AtDay || Slingshot || HasBombchus || CanUse(RG_FAIRY_BOW) || CanUse(RG_LONGSHOT)));}}),
Entrance(RR_KAK_IMPAS_ROOFTOP, {[]{return CanUse(RG_HOOKSHOT) || (LogicKakarikoRooftopGS && CanUse(RG_HOVER_BOOTS));}}),
Entrance(RR_KAK_IMPAS_LEDGE, {[]{return (IsChild && AtDay) || CanUse(RG_HOOKSHOT) || (IsAdult && randoCtx->GetTrickOption(RT_VISIBLE_COLLISION));}}),
Entrance(RR_KAK_ROOFTOP, {[]{return CanUse(RG_HOOKSHOT) || (randoCtx->GetTrickOption(RT_KAK_MAN_ON_ROOF) && (IsAdult || AtDay || Slingshot || HasBombchus || CanUse(RG_FAIRY_BOW) || CanUse(RG_LONGSHOT)));}}),
Entrance(RR_KAK_IMPAS_ROOFTOP, {[]{return CanUse(RG_HOOKSHOT) || (randoCtx->GetTrickOption(RT_KAK_ROOFTOP_GS) && CanUse(RG_HOVER_BOOTS));}}),
Entrance(RR_THE_GRAVEYARD, {[]{return true;}}),
Entrance(RR_KAK_BEHIND_GATE, {[]{return IsAdult || (KakarikoVillageGateOpen);}}),
});
@@ -118,7 +118,7 @@ void AreaTable_Init_Kakariko() {
EventAccess(&DrainWell, {[]{return DrainWell || (IsChild && CanPlay(SongOfStorms));}}),
}, {
//Locations
LocationAccess(RC_KAK_WINDMILL_FREESTANDING_POH, {[]{return CanUse(RG_BOOMERANG) || DampesWindmillAccess || (IsAdult && LogicAdultWindmillPoH) || (IsChild && CanJumpslash && LogicChildWindmillPoH);}}),
LocationAccess(RC_KAK_WINDMILL_FREESTANDING_POH, {[]{return CanUse(RG_BOOMERANG) || DampesWindmillAccess || (IsAdult && randoCtx->GetTrickOption(RT_KAK_ADULT_WINDMILL_POH)) || (IsChild && CanJumpslash && randoCtx->GetTrickOption(RT_KAK_CHILD_WINDMILL_POH));}}),
//PoH as child not added to trick options yet (needs uncommenting in randomizer_tricks.cpp)
LocationAccess(RC_SONG_FROM_WINDMILL, {[]{return IsAdult && Ocarina;}}),
}, {
@@ -212,7 +212,7 @@ void AreaTable_Init_Kakariko() {
EventAccess(&BugRock, {[]{return true;}}),
}, {
//Locations
LocationAccess(RC_GRAVEYARD_FREESTANDING_POH, {[]{return (IsAdult && CanPlantBean(RR_THE_GRAVEYARD)) || CanUse(RG_LONGSHOT) || (LogicGraveyardPoH && CanUse(RG_BOOMERANG));}}),
LocationAccess(RC_GRAVEYARD_FREESTANDING_POH, {[]{return (IsAdult && CanPlantBean(RR_THE_GRAVEYARD)) || CanUse(RG_LONGSHOT) || (randoCtx->GetTrickOption(RT_GY_POH) && CanUse(RG_BOOMERANG));}}),
LocationAccess(RC_GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR, {[]{return IsChild && AtNight;}}), //TODO: This needs to change
LocationAccess(RC_GRAVEYARD_GS_WALL, {[]{return IsChild && HookshotOrBoomerang && AtNight && CanGetNightTimeGS;}}),
LocationAccess(RC_GRAVEYARD_GS_BEAN_PATCH, {[]{return CanPlantBugs && CanChildAttack;}}),
@@ -260,7 +260,7 @@ void AreaTable_Init_Kakariko() {
}, {
//Locations
LocationAccess(RC_GRAVEYARD_HOOKSHOT_CHEST, {[]{return true;}}),
LocationAccess(RC_GRAVEYARD_DAMPE_RACE_FREESTANDING_POH, {[]{return IsAdult || LogicChildDampeRacePoH;}}),
LocationAccess(RC_GRAVEYARD_DAMPE_RACE_FREESTANDING_POH, {[]{return IsAdult || randoCtx->GetTrickOption(RT_GY_CHILD_DAMPE_RACE_POH);}}),
}, {
//Exits
Entrance(RR_THE_GRAVEYARD, {[]{return true;}}),
@@ -284,12 +284,12 @@ void AreaTable_Init_Kakariko() {
}, {
//Exits
Entrance(RR_THE_GRAVEYARD, {[]{return true;}}),
Entrance(RR_SHADOW_TEMPLE_ENTRYWAY, {[]{return CanUse(RG_DINS_FIRE) || (LogicShadowFireArrowEntry && IsAdult && CanUse(RG_FIRE_ARROWS));}}),
Entrance(RR_SHADOW_TEMPLE_ENTRYWAY, {[]{return CanUse(RG_DINS_FIRE) || (randoCtx->GetTrickOption(RT_GY_SHADOW_FIRE_ARROWS) && IsAdult && CanUse(RG_FIRE_ARROWS));}}),
});
areaTable[RR_KAK_BEHIND_GATE] = Area("Kak Behind Gate", "Kakariko Village", RHT_KAKARIKO_VILLAGE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_KAKARIKO_VILLAGE, {[]{return IsAdult || LogicVisibleCollision || KakarikoVillageGateOpen || OpenKakariko.Is(OPENKAKARIKO_OPEN);}}),
Entrance(RR_KAKARIKO_VILLAGE, {[]{return IsAdult || randoCtx->GetTrickOption(RT_VISIBLE_COLLISION) || KakarikoVillageGateOpen || randoCtx->GetOption(RSK_KAK_GATE).Is(RO_KAK_GATE_OPEN);}}),
Entrance(RR_DEATH_MOUNTAIN_TRAIL, {[]{return true;}}),
});
}

View File

@@ -1,9 +1,9 @@
#include "../location_access.hpp"
#include "../logic.hpp"
#include "../entrance.hpp"
#include "../../entrance.h"
using namespace Logic;
using namespace Settings;
using namespace Rando;
void AreaTable_Init_LostWoods() {
areaTable[RR_KOKIRI_FOREST] = Area("Kokiri Forest", "Kokiri Forest", RHT_KOKIRI_FOREST, NO_DAY_NIGHT_CYCLE, {
@@ -14,9 +14,9 @@ void AreaTable_Init_LostWoods() {
}, {
//Locations
LocationAccess(RC_KF_KOKIRI_SWORD_CHEST, {[]{return IsChild;}}),
LocationAccess(RC_KF_GS_KNOW_IT_ALL_HOUSE, {[]{return IsChild && CanChildAttack && AtNight && (HasNightStart || CanLeaveForest || CanPlay(SunsSong)) && CanGetNightTimeGS;}}),
LocationAccess(RC_KF_GS_KNOW_IT_ALL_HOUSE, {[]{return IsChild && CanChildAttack && AtNight && (/*TODO: HasNightStart ||*/ CanLeaveForest || CanPlay(SunsSong)) && CanGetNightTimeGS;}}),
LocationAccess(RC_KF_GS_BEAN_PATCH, {[]{return CanPlantBugs && CanChildAttack;}}),
LocationAccess(RC_KF_GS_HOUSE_OF_TWINS, {[]{return IsAdult && AtNight && (HookshotOrBoomerang || (LogicAdultKokiriGS && CanUse(RG_HOVER_BOOTS))) && CanGetNightTimeGS;}}),
LocationAccess(RC_KF_GS_HOUSE_OF_TWINS, {[]{return IsAdult && AtNight && (HookshotOrBoomerang || (randoCtx->GetTrickOption(RT_KF_ADULT_GS) && CanUse(RG_HOVER_BOOTS))) && CanGetNightTimeGS;}}),
LocationAccess(RC_KF_GOSSIP_STONE, {[]{return true;}}),
}, {
//Exits
@@ -26,16 +26,16 @@ void AreaTable_Init_LostWoods() {
Entrance(RR_KF_HOUSE_OF_TWINS, {[]{return true;}}),
Entrance(RR_KF_KNOW_IT_ALL_HOUSE, {[]{return true;}}),
Entrance(RR_KF_KOKIRI_SHOP, {[]{return true;}}),
Entrance(RR_KF_OUTSIDE_DEKU_TREE, {[]{return IsAdult || OpenForest.Is(OPENFOREST_OPEN) || ShowedMidoSwordAndShield;}}),
Entrance(RR_KF_OUTSIDE_DEKU_TREE, {[]{return IsAdult || randoCtx->GetOption(RSK_FOREST).Is(RO_FOREST_OPEN) || ShowedMidoSwordAndShield;}}),
Entrance(RR_THE_LOST_WOODS, {[]{return true;}}),
Entrance(RR_LW_BRIDGE_FROM_FOREST, {[]{return IsAdult || OpenForest.IsNot(OPENFOREST_CLOSED) || DekuTreeClear;}}),
Entrance(RR_LW_BRIDGE_FROM_FOREST, {[]{return IsAdult || randoCtx->GetOption(RSK_FOREST).IsNot(RO_FOREST_CLOSED) || DekuTreeClear;}}),
Entrance(RR_KF_STORMS_GROTTO, {[]{return CanOpenStormGrotto;}}),
});
areaTable[RR_KF_OUTSIDE_DEKU_TREE] = Area("KF Outside Deku Tree", "Kokiri Forest", RHT_KOKIRI_FOREST, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || ((IsAdult && (CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD) || CanUse(RG_KOKIRI_SWORD)) && !ShuffleEntrances) || (IsChild && (CanUse(RG_KOKIRI_SWORD) || CanUse(RG_BIGGORON_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BOOMERANG))));}}),
EventAccess(&DekuBabaNuts, {[]{return DekuBabaNuts || ((IsAdult && (CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD) || CanUse(RG_KOKIRI_SWORD)) && !ShuffleEntrances) || (IsChild && (CanJumpslash || CanUse(RG_FAIRY_SLINGSHOT) || HasExplosives || CanUse(RG_DINS_FIRE))));}}),
EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || ((IsAdult && (CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD) || CanUse(RG_KOKIRI_SWORD)) && !randoCtx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES)) || (IsChild && (CanUse(RG_KOKIRI_SWORD) || CanUse(RG_BIGGORON_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BOOMERANG))));}}),
EventAccess(&DekuBabaNuts, {[]{return DekuBabaNuts || ((IsAdult && (CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD) || CanUse(RG_KOKIRI_SWORD)) && !randoCtx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES)) || (IsChild && (CanJumpslash || CanUse(RG_FAIRY_SLINGSHOT) || HasExplosives || CanUse(RG_DINS_FIRE))));}}),
EventAccess(&ShowedMidoSwordAndShield, {[]{return ShowedMidoSwordAndShield || (IsChild && KokiriSword && DekuShield);}}),
}, {
//Locations
@@ -43,8 +43,8 @@ void AreaTable_Init_LostWoods() {
LocationAccess(RC_KF_DEKU_TREE_RIGHT_GOSSIP_STONE, {[]{return true;}}),
}, {
//Exits
Entrance(RR_DEKU_TREE_ENTRYWAY, {[]{return IsChild || (ShuffleDungeonEntrances.IsNot(SHUFFLEDUNGEONS_OFF) && (OpenForest.Is(OPENFOREST_OPEN) || ShowedMidoSwordAndShield));}}),
Entrance(RR_KOKIRI_FOREST, {[]{return IsAdult || OpenForest.Is(OPENFOREST_OPEN) || ShowedMidoSwordAndShield;}}),
Entrance(RR_DEKU_TREE_ENTRYWAY, {[]{return IsChild || (randoCtx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).IsNot(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF) && (randoCtx->GetOption(RSK_FOREST).Is(RO_FOREST_OPEN) || ShowedMidoSwordAndShield));}}),
Entrance(RR_KOKIRI_FOREST, {[]{return IsAdult || randoCtx->GetOption(RSK_FOREST).Is(RO_FOREST_OPEN) || ShowedMidoSwordAndShield;}}),
});
areaTable[RR_KF_LINKS_HOUSE] = Area("KF Link's House", "KF Link's House", RHT_NONE, NO_DAY_NIGHT_CYCLE, {}, {
@@ -131,9 +131,9 @@ void AreaTable_Init_LostWoods() {
//Exits
Entrance(RR_LW_FOREST_EXIT, {[]{return true;}}),
Entrance(RR_GC_WOODS_WARP, {[]{return true;}}),
Entrance(RR_LW_BRIDGE, {[]{return CanLeaveForest && ((IsAdult && (CanPlantBean(RR_THE_LOST_WOODS) || LogicLostWoodsBridge)) || CanUse(RG_HOVER_BOOTS) || CanUse(RG_LONGSHOT));}}),
Entrance(RR_LW_BRIDGE, {[]{return CanLeaveForest && ((IsAdult && (CanPlantBean(RR_THE_LOST_WOODS) || randoCtx->GetTrickOption(RT_LW_BRIDGE))) || CanUse(RG_HOVER_BOOTS) || CanUse(RG_LONGSHOT));}}),
Entrance(RR_ZORAS_RIVER, {[]{return CanLeaveForest && (CanDive || CanUse(RG_IRON_BOOTS));}}),
Entrance(RR_LW_BEYOND_MIDO, {[]{return IsChild || CanPlay(SariasSong) || LogicMidoBackflip;}}),
Entrance(RR_LW_BEYOND_MIDO, {[]{return IsChild || CanPlay(SariasSong) || randoCtx->GetTrickOption(RT_LW_MIDO_BACKFLIP);}}),
Entrance(RR_LW_NEAR_SHORTCUTS_GROTTO, {[]{return Here(RR_THE_LOST_WOODS, []{return CanBlastOrSmash;});}}),
});
@@ -144,8 +144,8 @@ void AreaTable_Init_LostWoods() {
//Locations
LocationAccess(RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, {[]{return IsChild && CanStunDeku;}}),
LocationAccess(RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, {[]{return IsChild && CanStunDeku;}}),
LocationAccess(RC_LW_GS_ABOVE_THEATER, {[]{return IsAdult && AtNight && ((CanPlantBean(RR_LW_BEYOND_MIDO) && CanAdultAttack) || (LogicLostWoodsGSBean && CanUse(RG_HOOKSHOT) && (CanUse(RG_LONGSHOT) || CanUse(RG_FAIRY_BOW) || CanUse(RG_FAIRY_SLINGSHOT) || HasBombchus || CanUse(RG_DINS_FIRE)))) && CanGetNightTimeGS;}}),
LocationAccess(RC_LW_GS_BEAN_PATCH_NEAR_THEATER, {[]{return CanPlantBugs && (CanChildAttack || (Scrubsanity.Is(SCRUBSANITY_OFF) && DekuShield));}}),
LocationAccess(RC_LW_GS_ABOVE_THEATER, {[]{return IsAdult && AtNight && ((CanPlantBean(RR_LW_BEYOND_MIDO) && CanAdultAttack) || (randoCtx->GetTrickOption(RT_LW_GS_BEAN) && CanUse(RG_HOOKSHOT) && (CanUse(RG_LONGSHOT) || CanUse(RG_FAIRY_BOW) || CanUse(RG_FAIRY_SLINGSHOT) || HasBombchus || CanUse(RG_DINS_FIRE)))) && CanGetNightTimeGS;}}),
LocationAccess(RC_LW_GS_BEAN_PATCH_NEAR_THEATER, {[]{return CanPlantBugs && (CanChildAttack || (randoCtx->GetOption(RSK_SHUFFLE_SCRUBS).Is(RO_SCRUBS_OFF) && DekuShield));}}),
}, {
//Exits
Entrance(RR_LW_FOREST_EXIT, {[]{return true;}}),

View File

@@ -1,10 +1,10 @@
#include "../location_access.hpp"
#include "../logic.hpp"
#include "../entrance.hpp"
#include "../dungeon.hpp"
#include "../../entrance.h"
#include "../../dungeon.h"
using namespace Logic;
using namespace Settings;
using namespace Rando;
void AreaTable_Init_ShadowTemple() {
/*--------------------------
@@ -12,15 +12,15 @@ void AreaTable_Init_ShadowTemple() {
---------------------------*/
areaTable[RR_SHADOW_TEMPLE_ENTRYWAY] = Area("Shadow Temple Entryway", "Shadow Temple", RHT_SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_SHADOW_TEMPLE_BEGINNING, {[]{return Dungeon::ShadowTemple.IsVanilla() && (LogicLensShadow || CanUse(RG_LENS_OF_TRUTH)) && (CanUse(RG_HOVER_BOOTS) || CanUse(RG_HOOKSHOT));}}),
Entrance(RR_SHADOW_TEMPLE_MQ_BEGINNING, {[]{return Dungeon::ShadowTemple.IsMQ() && (LogicLensShadowMQ || CanUse(RG_LENS_OF_TRUTH)) && (CanUse(RG_HOVER_BOOTS) || CanUse(RG_HOOKSHOT));}}),
Entrance(RR_SHADOW_TEMPLE_BEGINNING, {[]{return randoCtx->GetDungeon(SHADOW_TEMPLE)->IsVanilla() && (randoCtx->GetTrickOption(RT_LENS_SHADOW) || CanUse(RG_LENS_OF_TRUTH)) && (CanUse(RG_HOVER_BOOTS) || CanUse(RG_HOOKSHOT));}}),
Entrance(RR_SHADOW_TEMPLE_MQ_BEGINNING, {[]{return randoCtx->GetDungeon(SHADOW_TEMPLE)->IsMQ() && (randoCtx->GetTrickOption(RT_LENS_SHADOW_MQ) || CanUse(RG_LENS_OF_TRUTH)) && (CanUse(RG_HOVER_BOOTS) || CanUse(RG_HOOKSHOT));}}),
Entrance(RR_GRAVEYARD_WARP_PAD_REGION, {[]{return true;}}),
});
/*--------------------------
| VANILLA DUNGEON |
---------------------------*/
if (Dungeon::ShadowTemple.IsVanilla()) {
if (randoCtx->GetDungeon(SHADOW_TEMPLE)->IsVanilla()) {
areaTable[RR_SHADOW_TEMPLE_BEGINNING] = Area("Shadow Temple Beginning", "Shadow Temple", RHT_SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {
//Events
EventAccess(&NutPot, {[]{return true;}}),
@@ -53,16 +53,16 @@ void AreaTable_Init_ShadowTemple() {
LocationAccess(RC_SHADOW_TEMPLE_INVISIBLE_BLADES_VISIBLE_CHEST, {[]{return CanJumpslash;}}),
LocationAccess(RC_SHADOW_TEMPLE_INVISIBLE_BLADES_INVISIBLE_CHEST, {[]{return CanJumpslash;}}),
LocationAccess(RC_SHADOW_TEMPLE_FALLING_SPIKES_LOWER_CHEST, {[]{return true;}}),
LocationAccess(RC_SHADOW_TEMPLE_FALLING_SPIKES_UPPER_CHEST, {[]{return (LogicShadowUmbrella && HoverBoots) || GoronBracelet;}}),
LocationAccess(RC_SHADOW_TEMPLE_FALLING_SPIKES_SWITCH_CHEST, {[]{return (LogicShadowUmbrella && HoverBoots) || GoronBracelet;}}),
LocationAccess(RC_SHADOW_TEMPLE_INVISIBLE_SPIKES_CHEST, {[]{return SmallKeys(RR_SHADOW_TEMPLE, 2, 3) && ((LogicLensShadowPlatform && LogicLensShadow) || CanUse(RG_LENS_OF_TRUTH));}}),
LocationAccess(RC_SHADOW_TEMPLE_FREESTANDING_KEY, {[]{return SmallKeys(RR_SHADOW_TEMPLE, 2, 3) && ((LogicLensShadowPlatform && LogicLensShadow) || CanUse(RG_LENS_OF_TRUTH)) && Hookshot && (Bombs || GoronBracelet || (LogicShadowFreestandingKey && HasBombchus));}}),
LocationAccess(RC_SHADOW_TEMPLE_FALLING_SPIKES_UPPER_CHEST, {[]{return (randoCtx->GetTrickOption(RT_SHADOW_UMBRELLA) && HoverBoots) || GoronBracelet;}}),
LocationAccess(RC_SHADOW_TEMPLE_FALLING_SPIKES_SWITCH_CHEST, {[]{return (randoCtx->GetTrickOption(RT_SHADOW_UMBRELLA) && HoverBoots) || GoronBracelet;}}),
LocationAccess(RC_SHADOW_TEMPLE_INVISIBLE_SPIKES_CHEST, {[]{return SmallKeys(RR_SHADOW_TEMPLE, 2, 3) && ((randoCtx->GetTrickOption(RT_LENS_SHADOW_PLATFORM) && randoCtx->GetTrickOption(RT_LENS_SHADOW)) || CanUse(RG_LENS_OF_TRUTH));}}),
LocationAccess(RC_SHADOW_TEMPLE_FREESTANDING_KEY, {[]{return SmallKeys(RR_SHADOW_TEMPLE, 2, 3) && ((randoCtx->GetTrickOption(RT_LENS_SHADOW_PLATFORM) && randoCtx->GetTrickOption(RT_LENS_SHADOW)) || CanUse(RG_LENS_OF_TRUTH)) && Hookshot && (Bombs || GoronBracelet || (randoCtx->GetTrickOption(RT_SHADOW_FREESTANDING_KEY) && HasBombchus));}}),
LocationAccess(RC_SHADOW_TEMPLE_GS_LIKE_LIKE_ROOM, {[]{return CanJumpslash;}}),
LocationAccess(RC_SHADOW_TEMPLE_GS_FALLING_SPIKES_ROOM, {[]{return Hookshot || (LogicShadowUmbrellaGS && HoverBoots);}}),
LocationAccess(RC_SHADOW_TEMPLE_GS_SINGLE_GIANT_POT, {[]{return SmallKeys(RR_SHADOW_TEMPLE, 2, 3) && ((LogicLensShadowPlatform && LogicLensShadow) || CanUse(RG_LENS_OF_TRUTH)) && Hookshot;}}),
LocationAccess(RC_SHADOW_TEMPLE_GS_FALLING_SPIKES_ROOM, {[]{return Hookshot || (randoCtx->GetTrickOption(RT_SHADOW_UMBRELLA_GS) && HoverBoots);}}),
LocationAccess(RC_SHADOW_TEMPLE_GS_SINGLE_GIANT_POT, {[]{return SmallKeys(RR_SHADOW_TEMPLE, 2, 3) && ((randoCtx->GetTrickOption(RT_LENS_SHADOW_PLATFORM) && randoCtx->GetTrickOption(RT_LENS_SHADOW)) || CanUse(RG_LENS_OF_TRUTH)) && Hookshot;}}),
}, {
//Exits
Entrance(RR_SHADOW_TEMPLE_WIND_TUNNEL, {[]{return ((LogicLensShadowPlatform && LogicLensShadow) || CanUse(RG_LENS_OF_TRUTH)) && Hookshot && SmallKeys(RR_SHADOW_TEMPLE, 3, 4);}}),
Entrance(RR_SHADOW_TEMPLE_WIND_TUNNEL, {[]{return ((randoCtx->GetTrickOption(RT_LENS_SHADOW_PLATFORM) && randoCtx->GetTrickOption(RT_LENS_SHADOW)) || CanUse(RG_LENS_OF_TRUTH)) && Hookshot && SmallKeys(RR_SHADOW_TEMPLE, 3, 4);}}),
});
areaTable[RR_SHADOW_TEMPLE_WIND_TUNNEL] = Area("Shadow Temple Wind Tunnel", "Shadow Temple", RHT_SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
@@ -84,18 +84,18 @@ void AreaTable_Init_ShadowTemple() {
LocationAccess(RC_SHADOW_TEMPLE_GS_TRIPLE_GIANT_POT, {[]{return CanAdultAttack;}}),
}, {
//Exits
Entrance(RR_SHADOW_TEMPLE_BOSS_ENTRYWAY, {[]{return (CanUse(RG_FAIRY_BOW) || CanUse(RG_DISTANT_SCARECROW) || (LogicShadowStatue && HasBombchus)) && SmallKeys(RR_SHADOW_TEMPLE, 5) && CanUse(RG_HOVER_BOOTS) && BossKeyShadowTemple;}})
Entrance(RR_SHADOW_TEMPLE_BOSS_ENTRYWAY, {[]{return (CanUse(RG_FAIRY_BOW) || CanUse(RG_DISTANT_SCARECROW) || (randoCtx->GetTrickOption(RT_SHADOW_STATUE) && HasBombchus)) && SmallKeys(RR_SHADOW_TEMPLE, 5) && CanUse(RG_HOVER_BOOTS) && BossKeyShadowTemple;}})
});
}
/*---------------------------
| MASTER QUEST DUNGEON |
---------------------------*/
if (Dungeon::ShadowTemple.IsMQ()) {
if (randoCtx->GetDungeon(SHADOW_TEMPLE)->IsMQ()) {
areaTable[RR_SHADOW_TEMPLE_MQ_BEGINNING] = Area("Shadow Temple MQ Beginning", "Shadow Temple", RHT_SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_SHADOW_TEMPLE_ENTRYWAY, {[]{return true;}}),
Entrance(RR_SHADOW_TEMPLE_MQ_FIRST_BEAMOS, {[]{return IsAdult && (CanUse(RG_FIRE_ARROWS) || HoverBoots || (LogicShadowMQGap && CanUse(RG_LONGSHOT)));}}),
Entrance(RR_SHADOW_TEMPLE_MQ_FIRST_BEAMOS, {[]{return IsAdult && (CanUse(RG_FIRE_ARROWS) || HoverBoots || (randoCtx->GetTrickOption(RT_SHADOW_MQ_GAP) && CanUse(RG_LONGSHOT)));}}),
//Trick: IsAdult && (CanUse(RG_FIRE_ARROWS) || HoverBoots || (LogicShadowMQGap && CanUse(RG_LONGSHOT)))
Entrance(RR_SHADOW_TEMPLE_MQ_DEAD_HAND_AREA, {[]{return HasExplosives && SmallKeys(RR_SHADOW_TEMPLE, 6);}}),
});
@@ -118,13 +118,13 @@ void AreaTable_Init_ShadowTemple() {
areaTable[RR_SHADOW_TEMPLE_MQ_UPPER_HUGE_PIT] = Area("Shadow Temple MQ Upper Huge Pit", "Shadow Temple", RHT_SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_VISIBLE_CHEST, {[]{return CanPlay(SongOfTime) || (LogicShadowMQInvisibleBlades && DamageMultiplier.IsNot(DAMAGEMULTIPLIER_OHKO));}}),
LocationAccess(RC_SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_VISIBLE_CHEST, {[]{return CanPlay(SongOfTime) || (randoCtx->GetTrickOption(RT_SHADOW_MQ_INVISIBLE_BLADES) && randoCtx->GetOption(RSK_DAMAGE_MULTIPLIER).IsNot(RO_DAMAGE_MULTIPLIER_OHKO));}}),
//Trick: CanPlay(SongOfTime) || (LogicShadowMQInvisibleBlades && DamageMultiplier.IsNot(DAMAGEMULTIPLIER_OHKO))
LocationAccess(RC_SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_INVISIBLE_CHEST, {[]{return CanPlay(SongOfTime) || (LogicShadowMQInvisibleBlades && DamageMultiplier.IsNot(DAMAGEMULTIPLIER_OHKO));}}),
LocationAccess(RC_SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_INVISIBLE_CHEST, {[]{return CanPlay(SongOfTime) || (randoCtx->GetTrickOption(RT_SHADOW_MQ_INVISIBLE_BLADES) && randoCtx->GetOption(RSK_DAMAGE_MULTIPLIER).IsNot(RO_DAMAGE_MULTIPLIER_OHKO));}}),
//Trick: CanPlay(SongOfTime) || (LogicShadowMQInvisibleBlades && DamageMultiplier.IsNot(DAMAGEMULTIPLIER_OHKO))
}, {
//Exits
Entrance(RR_SHADOW_TEMPLE_MQ_LOWER_HUGE_PIT, {[]{return HasFireSource || LogicShadowMQHugePit;}}),
Entrance(RR_SHADOW_TEMPLE_MQ_LOWER_HUGE_PIT, {[]{return HasFireSource || randoCtx->GetTrickOption(RT_SHADOW_MQ_HUGE_PIT);}}),
//Trick: HasFireSource || LogicShadowMQHugePit
});
@@ -132,15 +132,15 @@ void AreaTable_Init_ShadowTemple() {
//Locations
LocationAccess(RC_SHADOW_TEMPLE_MQ_BEAMOS_SILVER_RUPEES_CHEST, {[]{return IsAdult && CanUse(RG_LONGSHOT);}}),
LocationAccess(RC_SHADOW_TEMPLE_MQ_FALLING_SPIKES_LOWER_CHEST, {[]{return true;}}),
LocationAccess(RC_SHADOW_TEMPLE_MQ_FALLING_SPIKES_UPPER_CHEST, {[]{return (LogicShadowUmbrella && HoverBoots) || GoronBracelet;}}),
LocationAccess(RC_SHADOW_TEMPLE_MQ_FALLING_SPIKES_SWITCH_CHEST, {[]{return (LogicShadowUmbrella && HoverBoots) || GoronBracelet;}}),
LocationAccess(RC_SHADOW_TEMPLE_MQ_INVISIBLE_SPIKES_CHEST, {[]{return CanJumpslash && HoverBoots && SmallKeys(RR_SHADOW_TEMPLE, 3) && ((LogicLensShadowMQ && LogicLensShadowMQPlatform) || CanUse(RG_LENS_OF_TRUTH));}}),
LocationAccess(RC_SHADOW_TEMPLE_MQ_STALFOS_ROOM_CHEST, {[]{return (CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD)) && HoverBoots && SmallKeys(RR_SHADOW_TEMPLE, 3) && Hookshot && ((LogicLensShadowMQ &&
LogicLensShadowMQInvisibleBlades && LogicLensShadowMQPlatform) || CanUse(RG_LENS_OF_TRUTH));}}),
LocationAccess(RC_SHADOW_TEMPLE_MQ_GS_FALLING_SPIKES_ROOM, {[]{return Hookshot || (LogicShadowUmbrellaGS && HoverBoots);}}),
LocationAccess(RC_SHADOW_TEMPLE_MQ_FALLING_SPIKES_UPPER_CHEST, {[]{return (randoCtx->GetTrickOption(RT_SHADOW_UMBRELLA) && HoverBoots) || GoronBracelet;}}),
LocationAccess(RC_SHADOW_TEMPLE_MQ_FALLING_SPIKES_SWITCH_CHEST, {[]{return (randoCtx->GetTrickOption(RT_SHADOW_UMBRELLA) && HoverBoots) || GoronBracelet;}}),
LocationAccess(RC_SHADOW_TEMPLE_MQ_INVISIBLE_SPIKES_CHEST, {[]{return CanJumpslash && HoverBoots && SmallKeys(RR_SHADOW_TEMPLE, 3) && ((randoCtx->GetTrickOption(RT_LENS_SHADOW_MQ) && randoCtx->GetTrickOption(RT_LENS_SHADOW_MQ_PLATFORM)) || CanUse(RG_LENS_OF_TRUTH));}}),
LocationAccess(RC_SHADOW_TEMPLE_MQ_STALFOS_ROOM_CHEST, {[]{return (CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD)) && HoverBoots && SmallKeys(RR_SHADOW_TEMPLE, 3) && Hookshot && ((randoCtx->GetTrickOption(RT_LENS_SHADOW_MQ) &&
randoCtx->GetTrickOption(RT_LENS_SHADOW_MQ_INVISIBLE_BLADES) && randoCtx->GetTrickOption(RT_LENS_SHADOW_MQ_PLATFORM)) || CanUse(RG_LENS_OF_TRUTH));}}),
LocationAccess(RC_SHADOW_TEMPLE_MQ_GS_FALLING_SPIKES_ROOM, {[]{return Hookshot || (randoCtx->GetTrickOption(RT_SHADOW_UMBRELLA_GS) && HoverBoots);}}),
}, {
//Exits
Entrance(RR_SHADOW_TEMPLE_MQ_WIND_TUNNEL, {[]{return HoverBoots && ((LogicLensShadowMQ && LogicLensShadowMQPlatform) || CanUse(RG_LENS_OF_TRUTH)) && Hookshot && SmallKeys(RR_SHADOW_TEMPLE, 4);}}),
Entrance(RR_SHADOW_TEMPLE_MQ_WIND_TUNNEL, {[]{return HoverBoots && ((randoCtx->GetTrickOption(RT_LENS_SHADOW_MQ) && randoCtx->GetTrickOption(RT_LENS_SHADOW_MQ_PLATFORM)) || CanUse(RG_LENS_OF_TRUTH)) && Hookshot && SmallKeys(RR_SHADOW_TEMPLE, 4);}}),
});
areaTable[RR_SHADOW_TEMPLE_MQ_WIND_TUNNEL] = Area("Shadow Temple MQ Wind Tunnel", "Shadow Temple", RHT_SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {
@@ -161,11 +161,11 @@ void AreaTable_Init_ShadowTemple() {
areaTable[RR_SHADOW_TEMPLE_MQ_BEYOND_BOAT] = Area("Shadow Temple MQ Beyond Boat", "Shadow Temple", RHT_SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_SHADOW_TEMPLE_MQ_GS_AFTER_SHIP, {[]{return true;}}),
LocationAccess(RC_SHADOW_TEMPLE_MQ_GS_NEAR_BOSS, {[]{return Bow || (LogicShadowStatue && HasBombchus);}}),
LocationAccess(RC_SHADOW_TEMPLE_MQ_GS_NEAR_BOSS, {[]{return Bow || (randoCtx->GetTrickOption(RT_SHADOW_STATUE) && HasBombchus);}}),
}, {
//Exits
Entrance(RR_SHADOW_TEMPLE_MQ_INVISIBLE_MAZE, {[]{return Bow && CanPlay(SongOfTime) && IsAdult && CanUse(RG_LONGSHOT);}}),
Entrance(RR_SHADOW_TEMPLE_BOSS_ENTRYWAY, {[]{return (CanUse(RG_FAIRY_BOW) || (LogicShadowStatue && HasBombchus)) && CanUse(RG_HOVER_BOOTS) && BossKeyShadowTemple;}}),
Entrance(RR_SHADOW_TEMPLE_BOSS_ENTRYWAY, {[]{return (CanUse(RG_FAIRY_BOW) || (randoCtx->GetTrickOption(RT_SHADOW_STATUE) && HasBombchus)) && CanUse(RG_HOVER_BOOTS) && BossKeyShadowTemple;}}),
});
areaTable[RR_SHADOW_TEMPLE_MQ_INVISIBLE_MAZE] = Area("Shadow Temple MQ Invisible Maze", "Shadow Temple", RHT_SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
@@ -173,7 +173,7 @@ void AreaTable_Init_ShadowTemple() {
LocationAccess(RC_SHADOW_TEMPLE_MQ_SPIKE_WALLS_LEFT_CHEST, {[]{return CanUse(RG_DINS_FIRE) && SmallKeys(RR_SHADOW_TEMPLE, 6);}}),
LocationAccess(RC_SHADOW_TEMPLE_MQ_BOSS_KEY_CHEST, {[]{return CanUse(RG_DINS_FIRE) && SmallKeys(RR_SHADOW_TEMPLE, 6);}}),
//below previously returned true
LocationAccess(RC_SHADOW_TEMPLE_MQ_BOMB_FLOWER_CHEST, {[]{return CanUse(RG_LENS_OF_TRUTH) || LogicLensShadowMQDeadHand;}}),
LocationAccess(RC_SHADOW_TEMPLE_MQ_BOMB_FLOWER_CHEST, {[]{return CanUse(RG_LENS_OF_TRUTH) || randoCtx->GetTrickOption(RT_LENS_SHADOW_MQ_DEADHAND);}}),
LocationAccess(RC_SHADOW_TEMPLE_MQ_FREESTANDING_KEY, {[]{return true;}}),
}, {});
}
@@ -185,8 +185,8 @@ void AreaTable_Init_ShadowTemple() {
Area("Shadow Temple Boss Entryway", "Shadow Temple", RHT_SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {},
{
// Exits
Entrance(RR_SHADOW_TEMPLE_BEYOND_BOAT, { [] { return Dungeon::ShadowTemple.IsVanilla() && false; } }),
Entrance(RR_SHADOW_TEMPLE_MQ_BEYOND_BOAT, { [] { return Dungeon::ShadowTemple.IsMQ() && false; } }),
Entrance(RR_SHADOW_TEMPLE_BEYOND_BOAT, { [] { return randoCtx->GetDungeon(SHADOW_TEMPLE)->IsVanilla() && false; } }),
Entrance(RR_SHADOW_TEMPLE_MQ_BEYOND_BOAT, { [] { return randoCtx->GetDungeon(SHADOW_TEMPLE)->IsMQ() && false; } }),
Entrance(RR_SHADOW_TEMPLE_BOSS_ROOM, { [] { return true; } }),
});
@@ -196,9 +196,9 @@ void AreaTable_Init_ShadowTemple() {
// Events
EventAccess(&ShadowTempleClear, { [] {
return ShadowTempleClear ||
((CanUse(RG_LENS_OF_TRUTH) || LogicLensBongo) &&
((CanUse(RG_LENS_OF_TRUTH) || randoCtx->GetTrickOption(RT_LENS_BONGO)) &&
(CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD)) &&
(CanUse(RG_HOOKSHOT) || CanUse(RG_FAIRY_BOW) || CanUse(RG_FAIRY_SLINGSHOT) || LogicShadowBongo));
(CanUse(RG_HOOKSHOT) || CanUse(RG_FAIRY_BOW) || CanUse(RG_FAIRY_SLINGSHOT) || randoCtx->GetTrickOption(RT_SHADOW_BONGO)));
} }),
},
{

View File

@@ -1,10 +1,10 @@
#include "../location_access.hpp"
#include "../logic.hpp"
#include "../entrance.hpp"
#include "../dungeon.hpp"
#include "../../entrance.h"
#include "../../dungeon.h"
using namespace Logic;
using namespace Settings;
using namespace Rando;
void AreaTable_Init_SpiritTemple() {
/*--------------------------
@@ -12,15 +12,15 @@ void AreaTable_Init_SpiritTemple() {
---------------------------*/
areaTable[RR_SPIRIT_TEMPLE_ENTRYWAY] = Area("Spirit Temple Entryway", "Spirit Temple", RHT_SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_SPIRIT_TEMPLE_LOBBY, {[]{return Dungeon::SpiritTemple.IsVanilla();}}),
Entrance(RR_SPIRIT_TEMPLE_MQ_LOBBY, {[]{return Dungeon::SpiritTemple.IsMQ();}}),
Entrance(RR_SPIRIT_TEMPLE_LOBBY, {[]{return randoCtx->GetDungeon(SPIRIT_TEMPLE)->IsVanilla();}}),
Entrance(RR_SPIRIT_TEMPLE_MQ_LOBBY, {[]{return randoCtx->GetDungeon(SPIRIT_TEMPLE)->IsMQ();}}),
Entrance(RR_DESERT_COLOSSUS_FROM_SPIRIT_ENTRYWAY, {[]{return true;}}),
});
/*--------------------------
| VANILLA DUNGEON |
---------------------------*/
if (Dungeon::SpiritTemple.IsVanilla()) {
if (randoCtx->GetDungeon(SPIRIT_TEMPLE)->IsVanilla()) {
areaTable[RR_SPIRIT_TEMPLE_LOBBY] = Area("Spirit Temple Lobby", "Spirit Temple", RHT_SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_SPIRIT_TEMPLE_ENTRYWAY, {[]{return true;}}),
@@ -33,9 +33,9 @@ void AreaTable_Init_SpiritTemple() {
EventAccess(&NutCrate, {[]{return true;}}),
}, {
//Locations
LocationAccess(RC_SPIRIT_TEMPLE_CHILD_BRIDGE_CHEST, {[]{return (Boomerang || Slingshot || (HasBombchus && LogicSpiritChildBombchu)) && (HasExplosives || ((Nuts || Boomerang) && (Sticks || KokiriSword || Slingshot)));}}),
LocationAccess(RC_SPIRIT_TEMPLE_CHILD_EARLY_TORCHES_CHEST, {[]{return (Boomerang || Slingshot || (HasBombchus && LogicSpiritChildBombchu)) && (HasExplosives || ((Nuts || Boomerang) && (Sticks || KokiriSword || Slingshot))) && (Sticks || CanUse(RG_DINS_FIRE));}}),
LocationAccess(RC_SPIRIT_TEMPLE_GS_METAL_FENCE, {[]{return (Boomerang || Slingshot || (HasBombchus && LogicSpiritChildBombchu)) && (HasExplosives || ((Nuts || Boomerang) && (Sticks || KokiriSword || Slingshot)));}}),
LocationAccess(RC_SPIRIT_TEMPLE_CHILD_BRIDGE_CHEST, {[]{return (Boomerang || Slingshot || (HasBombchus && randoCtx->GetTrickOption(RT_SPIRIT_CHILD_CHU))) && (HasExplosives || ((Nuts || Boomerang) && (Sticks || KokiriSword || Slingshot)));}}),
LocationAccess(RC_SPIRIT_TEMPLE_CHILD_EARLY_TORCHES_CHEST, {[]{return (Boomerang || Slingshot || (HasBombchus && randoCtx->GetTrickOption(RT_SPIRIT_CHILD_CHU))) && (HasExplosives || ((Nuts || Boomerang) && (Sticks || KokiriSword || Slingshot))) && (Sticks || CanUse(RG_DINS_FIRE));}}),
LocationAccess(RC_SPIRIT_TEMPLE_GS_METAL_FENCE, {[]{return (Boomerang || Slingshot || (HasBombchus && randoCtx->GetTrickOption(RT_SPIRIT_CHILD_CHU))) && (HasExplosives || ((Nuts || Boomerang) && (Sticks || KokiriSword || Slingshot)));}}),
}, {
//Exits
Entrance(RR_SPIRIT_TEMPLE_CHILD_CLIMB, {[]{return SmallKeys(RR_SPIRIT_TEMPLE, 1);}}),
@@ -43,24 +43,24 @@ void AreaTable_Init_SpiritTemple() {
areaTable[RR_SPIRIT_TEMPLE_CHILD_CLIMB] = Area("Child Spirit Temple Climb", "Spirit Temple", RHT_SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_SPIRIT_TEMPLE_CHILD_CLIMB_NORTH_CHEST, {[]{return HasProjectile(HasProjectileAge::Both) || ((SmallKeys(RR_SPIRIT_TEMPLE, 3) || (SmallKeys(RR_SPIRIT_TEMPLE, 2) && BombchusInLogic && ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_OFF))) && CanUse(RG_SILVER_GAUNTLETS) && HasProjectile(HasProjectileAge::Adult)) || (SmallKeys(RR_SPIRIT_TEMPLE, 5) && IsChild && HasProjectile(HasProjectileAge::Child));}}),
LocationAccess(RC_SPIRIT_TEMPLE_CHILD_CLIMB_EAST_CHEST, {[]{return HasProjectile(HasProjectileAge::Both) || ((SmallKeys(RR_SPIRIT_TEMPLE, 3) || (SmallKeys(RR_SPIRIT_TEMPLE, 2) && BombchusInLogic && ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_OFF))) && CanUse(RG_SILVER_GAUNTLETS) && HasProjectile(HasProjectileAge::Adult)) || (SmallKeys(RR_SPIRIT_TEMPLE, 5) && IsChild && HasProjectile(HasProjectileAge::Child));}}),
LocationAccess(RC_SPIRIT_TEMPLE_CHILD_CLIMB_NORTH_CHEST, {[]{return HasProjectile(HasProjectileAge::Both) || ((SmallKeys(RR_SPIRIT_TEMPLE, 3) || (SmallKeys(RR_SPIRIT_TEMPLE, 2) && randoCtx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && randoCtx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF))) && CanUse(RG_SILVER_GAUNTLETS) && HasProjectile(HasProjectileAge::Adult)) || (SmallKeys(RR_SPIRIT_TEMPLE, 5) && IsChild && HasProjectile(HasProjectileAge::Child));}}),
LocationAccess(RC_SPIRIT_TEMPLE_CHILD_CLIMB_EAST_CHEST, {[]{return HasProjectile(HasProjectileAge::Both) || ((SmallKeys(RR_SPIRIT_TEMPLE, 3) || (SmallKeys(RR_SPIRIT_TEMPLE, 2) && randoCtx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && randoCtx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF))) && CanUse(RG_SILVER_GAUNTLETS) && HasProjectile(HasProjectileAge::Adult)) || (SmallKeys(RR_SPIRIT_TEMPLE, 5) && IsChild && HasProjectile(HasProjectileAge::Child));}}),
LocationAccess(RC_SPIRIT_TEMPLE_GS_SUN_ON_FLOOR_ROOM, {[]{return HasProjectile(HasProjectileAge::Both) || CanUse(RG_DINS_FIRE) ||
(CanTakeDamage && (CanJumpslash || HasProjectile(HasProjectileAge::Child))) ||
(IsChild && SmallKeys(RR_SPIRIT_TEMPLE, 5) && HasProjectile(HasProjectileAge::Child)) ||
((SmallKeys(RR_SPIRIT_TEMPLE, 3) || (SmallKeys(RR_SPIRIT_TEMPLE, 2) && BombchusInLogic && ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_OFF))) && CanUse(RG_SILVER_GAUNTLETS) && (HasProjectile(HasProjectileAge::Adult) || (CanTakeDamage && CanJumpslash)));}}),
((SmallKeys(RR_SPIRIT_TEMPLE, 3) || (SmallKeys(RR_SPIRIT_TEMPLE, 2) && randoCtx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && randoCtx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF))) && CanUse(RG_SILVER_GAUNTLETS) && (HasProjectile(HasProjectileAge::Adult) || (CanTakeDamage && CanJumpslash)));}}),
}, {
//Exits
Entrance(RR_SPIRIT_TEMPLE_CENTRAL_CHAMBER, {[]{return HasExplosives || (SunlightArrows && CanUse(RG_LIGHT_ARROWS));}}),
Entrance(RR_SPIRIT_TEMPLE_CENTRAL_CHAMBER, {[]{return HasExplosives || (randoCtx->GetOption(RSK_SUNLIGHT_ARROWS) && CanUse(RG_LIGHT_ARROWS));}}),
});
areaTable[RR_SPIRIT_TEMPLE_EARLY_ADULT] = Area("Early Adult Spirit Temple", "Spirit Temple", RHT_SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_SPIRIT_TEMPLE_COMPASS_CHEST, {[]{return CanUse(RG_HOOKSHOT) && CanPlay(ZeldasLullaby);}}),
LocationAccess(RC_SPIRIT_TEMPLE_EARLY_ADULT_RIGHT_CHEST, {[]{return (CanUse(RG_FAIRY_BOW) || CanUse(RG_HOOKSHOT) || CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_BOOMERANG) || HasBombchus || (Bombs && IsAdult && LogicSpiritLowerAdultSwitch)) && (CanUse(RG_HOVER_BOOTS) || CanJumpslash);}}),
LocationAccess(RC_SPIRIT_TEMPLE_EARLY_ADULT_RIGHT_CHEST, {[]{return (CanUse(RG_FAIRY_BOW) || CanUse(RG_HOOKSHOT) || CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_BOOMERANG) || HasBombchus || (Bombs && IsAdult && randoCtx->GetTrickOption(RT_SPIRIT_LOWER_ADULT_SWITCH))) && (CanUse(RG_HOVER_BOOTS) || CanJumpslash);}}),
LocationAccess(RC_SPIRIT_TEMPLE_FIRST_MIRROR_LEFT_CHEST, {[]{return SmallKeys(RR_SPIRIT_TEMPLE, 3);}}),
LocationAccess(RC_SPIRIT_TEMPLE_FIRST_MIRROR_RIGHT_CHEST, {[]{return SmallKeys(RR_SPIRIT_TEMPLE, 3);}}),
LocationAccess(RC_SPIRIT_TEMPLE_GS_BOULDER_ROOM, {[]{return CanPlay(SongOfTime) && (Bow || Hookshot || HasBombchus || (Bombs && LogicSpiritLowerAdultSwitch));}}),
LocationAccess(RC_SPIRIT_TEMPLE_GS_BOULDER_ROOM, {[]{return CanPlay(SongOfTime) && (Bow || Hookshot || HasBombchus || (Bombs && randoCtx->GetTrickOption(RT_SPIRIT_LOWER_ADULT_SWITCH)));}}),
}, {
//Exits
Entrance(RR_SPIRIT_TEMPLE_CENTRAL_CHAMBER, {[]{return SmallKeys(RR_SPIRIT_TEMPLE, 1);}}),
@@ -68,34 +68,34 @@ void AreaTable_Init_SpiritTemple() {
areaTable[RR_SPIRIT_TEMPLE_CENTRAL_CHAMBER] = Area("Spirit Temple Central Chamber", "Spirit Temple", RHT_SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_SPIRIT_TEMPLE_MAP_CHEST, {[]{return ((HasExplosives || SmallKeys(RR_SPIRIT_TEMPLE, 3) || (SmallKeys(RR_SPIRIT_TEMPLE, 2) && BombchusInLogic && ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_OFF))) &&
LocationAccess(RC_SPIRIT_TEMPLE_MAP_CHEST, {[]{return ((HasExplosives || SmallKeys(RR_SPIRIT_TEMPLE, 3) || (SmallKeys(RR_SPIRIT_TEMPLE, 2) && randoCtx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && randoCtx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF))) &&
(CanUse(RG_DINS_FIRE) ||
(((MagicMeter && FireArrows) || LogicSpiritMapChest) && Bow && Sticks))) ||
(((MagicMeter && FireArrows) || randoCtx->GetTrickOption(RT_SPIRIT_MAP_CHEST)) && Bow && Sticks))) ||
(SmallKeys(RR_SPIRIT_TEMPLE, 5) && HasExplosives &&
CanUse(RG_STICKS)) ||
(SmallKeys(RR_SPIRIT_TEMPLE, 3) &&
(CanUse(RG_FIRE_ARROWS) || (LogicSpiritMapChest && Bow)) &&
(CanUse(RG_FIRE_ARROWS) || (randoCtx->GetTrickOption(RT_SPIRIT_MAP_CHEST) && Bow)) &&
CanUse(RG_SILVER_GAUNTLETS));}}),
LocationAccess(RC_SPIRIT_TEMPLE_SUN_BLOCK_ROOM_CHEST, {[]{return ((HasExplosives || SmallKeys(RR_SPIRIT_TEMPLE, 3) || (SmallKeys(RR_SPIRIT_TEMPLE, 2) && BombchusInLogic && ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_OFF))) &&
LocationAccess(RC_SPIRIT_TEMPLE_SUN_BLOCK_ROOM_CHEST, {[]{return ((HasExplosives || SmallKeys(RR_SPIRIT_TEMPLE, 3) || (SmallKeys(RR_SPIRIT_TEMPLE, 2) && randoCtx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && randoCtx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF))) &&
(CanUse(RG_DINS_FIRE) ||
(((MagicMeter && FireArrows) || LogicSpiritSunChest) && Bow && Sticks))) ||
(((MagicMeter && FireArrows) || randoCtx->GetTrickOption(RT_SPIRIT_SUN_CHEST)) && Bow && Sticks))) ||
(SmallKeys(RR_SPIRIT_TEMPLE, 5) && HasExplosives &&
CanUse(RG_STICKS)) ||
(SmallKeys(RR_SPIRIT_TEMPLE, 3) &&
(CanUse(RG_FIRE_ARROWS) || (LogicSpiritSunChest && Bow)) &&
(CanUse(RG_FIRE_ARROWS) || (randoCtx->GetTrickOption(RT_SPIRIT_SUN_CHEST) && Bow)) &&
CanUse(RG_SILVER_GAUNTLETS));}}),
LocationAccess(RC_SPIRIT_TEMPLE_STATUE_ROOM_HAND_CHEST, {[]{return SmallKeys(RR_SPIRIT_TEMPLE, 3) && CanUse(RG_SILVER_GAUNTLETS) && CanPlay(ZeldasLullaby);}}),
LocationAccess(RC_SPIRIT_TEMPLE_STATUE_ROOM_NORTHEAST_CHEST, {[]{return SmallKeys(RR_SPIRIT_TEMPLE, 3) && CanUse(RG_SILVER_GAUNTLETS) && CanPlay(ZeldasLullaby) && (Hookshot || HoverBoots || LogicSpiritLobbyJump);}}),
LocationAccess(RC_SPIRIT_TEMPLE_STATUE_ROOM_NORTHEAST_CHEST, {[]{return SmallKeys(RR_SPIRIT_TEMPLE, 3) && CanUse(RG_SILVER_GAUNTLETS) && CanPlay(ZeldasLullaby) && (Hookshot || HoverBoots || randoCtx->GetTrickOption(RT_SPIRIT_LOBBY_JUMP));}}),
LocationAccess(RC_SPIRIT_TEMPLE_GS_HALL_AFTER_SUN_BLOCK_ROOM, {[]{return (HasExplosives && Boomerang && Hookshot) ||
(CanUse(RG_BOOMERANG) && SmallKeys(RR_SPIRIT_TEMPLE, 5) && HasExplosives) ||
(Hookshot && CanUse(RG_SILVER_GAUNTLETS) &&
(SmallKeys(RR_SPIRIT_TEMPLE, 3) ||
(SmallKeys(RR_SPIRIT_TEMPLE, 2) && Boomerang && BombchusInLogic && ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_OFF))));}}),
LocationAccess(RC_SPIRIT_TEMPLE_GS_LOBBY, {[]{return ((HasExplosives || SmallKeys(RR_SPIRIT_TEMPLE, 3) || (SmallKeys(RR_SPIRIT_TEMPLE, 2) && BombchusInLogic && ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_OFF))) &&
LogicSpiritLobbyGS && Boomerang && (Hookshot || HoverBoots || LogicSpiritLobbyJump)) ||
(LogicSpiritLobbyGS && SmallKeys(RR_SPIRIT_TEMPLE, 5) && HasExplosives && CanUse(RG_BOOMERANG)) ||
(SmallKeys(RR_SPIRIT_TEMPLE, 3) && CanUse(RG_SILVER_GAUNTLETS) && (Hookshot || HoverBoots || LogicSpiritLobbyJump));}}),
(SmallKeys(RR_SPIRIT_TEMPLE, 2) && Boomerang && randoCtx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && randoCtx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF))));}}),
LocationAccess(RC_SPIRIT_TEMPLE_GS_LOBBY, {[]{return ((HasExplosives || SmallKeys(RR_SPIRIT_TEMPLE, 3) || (SmallKeys(RR_SPIRIT_TEMPLE, 2) && randoCtx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && randoCtx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF))) &&
randoCtx->GetTrickOption(RT_SPIRIT_LOBBY_GS) && Boomerang && (Hookshot || HoverBoots || randoCtx->GetTrickOption(RT_SPIRIT_LOBBY_JUMP))) ||
(randoCtx->GetTrickOption(RT_SPIRIT_LOBBY_GS) && SmallKeys(RR_SPIRIT_TEMPLE, 5) && HasExplosives && CanUse(RG_BOOMERANG)) ||
(SmallKeys(RR_SPIRIT_TEMPLE, 3) && CanUse(RG_SILVER_GAUNTLETS) && (Hookshot || HoverBoots || randoCtx->GetTrickOption(RT_SPIRIT_LOBBY_JUMP)));}}),
}, {
//Exits
Entrance(RR_SPIRIT_TEMPLE_OUTDOOR_HANDS, {[]{return CanJumpslash || HasExplosives;}}),
@@ -114,18 +114,18 @@ void AreaTable_Init_SpiritTemple() {
areaTable[RR_SPIRIT_TEMPLE_BEYOND_CENTRAL_LOCKED_DOOR] = Area("Spirit Temple Beyond Central Locked Door", "Spirit Temple", RHT_SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_SPIRIT_TEMPLE_NEAR_FOUR_ARMOS_CHEST, {[]{return (MirrorShield || (SunlightArrows && CanUse(RG_LIGHT_ARROWS))) && HasExplosives;}}),
LocationAccess(RC_SPIRIT_TEMPLE_HALLWAY_LEFT_INVISIBLE_CHEST, {[]{return (LogicLensSpirit || CanUse(RG_LENS_OF_TRUTH)) && HasExplosives;}}),
LocationAccess(RC_SPIRIT_TEMPLE_HALLWAY_RIGHT_INVISIBLE_CHEST, {[]{return (LogicLensSpirit || CanUse(RG_LENS_OF_TRUTH)) && HasExplosives;}}),
LocationAccess(RC_SPIRIT_TEMPLE_NEAR_FOUR_ARMOS_CHEST, {[]{return (MirrorShield || (randoCtx->GetOption(RSK_SUNLIGHT_ARROWS) && CanUse(RG_LIGHT_ARROWS))) && HasExplosives;}}),
LocationAccess(RC_SPIRIT_TEMPLE_HALLWAY_LEFT_INVISIBLE_CHEST, {[]{return (randoCtx->GetTrickOption(RT_LENS_SPIRIT) || CanUse(RG_LENS_OF_TRUTH)) && HasExplosives;}}),
LocationAccess(RC_SPIRIT_TEMPLE_HALLWAY_RIGHT_INVISIBLE_CHEST, {[]{return (randoCtx->GetTrickOption(RT_LENS_SPIRIT) || CanUse(RG_LENS_OF_TRUTH)) && HasExplosives;}}),
}, {
//Exits
Entrance(RR_SPIRIT_TEMPLE_BEYOND_FINAL_LOCKED_DOOR, {[]{return SmallKeys(RR_SPIRIT_TEMPLE, 5) && (LogicSpiritWall || CanUse(RG_LONGSHOT) || HasBombchus || ((Bombs || Nuts || CanUse(RG_DINS_FIRE)) && (Bow || CanUse(RG_HOOKSHOT) || Hammer)));}}),
Entrance(RR_SPIRIT_TEMPLE_BEYOND_FINAL_LOCKED_DOOR, {[]{return SmallKeys(RR_SPIRIT_TEMPLE, 5) && (randoCtx->GetTrickOption(RT_SPIRIT_WALL) || CanUse(RG_LONGSHOT) || HasBombchus || ((Bombs || Nuts || CanUse(RG_DINS_FIRE)) && (Bow || CanUse(RG_HOOKSHOT) || Hammer)));}}),
});
areaTable[RR_SPIRIT_TEMPLE_BEYOND_FINAL_LOCKED_DOOR] = Area("Spirit Temple Beyond Final Locked Door", "Spirit Temple", RHT_SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_SPIRIT_TEMPLE_BOSS_KEY_CHEST, {[]{return CanPlay(ZeldasLullaby) && ((CanTakeDamage && LogicFlamingChests) || (Bow && Hookshot));}}),
LocationAccess(RC_SPIRIT_TEMPLE_TOPMOST_CHEST, {[]{return (MirrorShield && CanAdultAttack) || (SunlightArrows && CanUse(RG_LIGHT_ARROWS));}}),
LocationAccess(RC_SPIRIT_TEMPLE_BOSS_KEY_CHEST, {[]{return CanPlay(ZeldasLullaby) && ((CanTakeDamage && randoCtx->GetTrickOption(RT_FLAMING_CHESTS)) || (Bow && Hookshot));}}),
LocationAccess(RC_SPIRIT_TEMPLE_TOPMOST_CHEST, {[]{return (MirrorShield && CanAdultAttack) || (randoCtx->GetOption(RSK_SUNLIGHT_ARROWS) && CanUse(RG_LIGHT_ARROWS));}}),
}, {
//Exits
Entrance(RR_SPIRIT_TEMPLE_INSIDE_STATUE_HEAD, {[]{return MirrorShield && HasExplosives && Hookshot;}}),
@@ -143,7 +143,7 @@ void AreaTable_Init_SpiritTemple() {
/*---------------------------
| MASTER QUEST DUNGEON |
---------------------------*/
if (Dungeon::SpiritTemple.IsMQ()) {
if (randoCtx->GetDungeon(SPIRIT_TEMPLE)->IsMQ()) {
areaTable[RR_SPIRIT_TEMPLE_MQ_LOBBY] = Area("Spirit Temple MQ Lobby", "Spirit Temple", RHT_SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_LEFT_CHEST, {[]{return true;}}),
@@ -164,7 +164,7 @@ void AreaTable_Init_SpiritTemple() {
LocationAccess(RC_SPIRIT_TEMPLE_MQ_CHILD_HAMMER_SWITCH_CHEST, {[]{return Here(RR_SPIRIT_TEMPLE_MQ_ADULT, []{return SmallKeys(RR_SPIRIT_TEMPLE, 7) && Hammer;});}}),
LocationAccess(RC_SPIRIT_TEMPLE_MQ_MAP_ROOM_ENEMY_CHEST, {[]{return KokiriSword && HasBombchus && Slingshot && CanUse(RG_DINS_FIRE);}}),
LocationAccess(RC_SPIRIT_TEMPLE_MQ_MAP_CHEST, {[]{return KokiriSword || Bombs;}}),
LocationAccess(RC_SPIRIT_TEMPLE_MQ_SILVER_BLOCK_HALLWAY_CHEST, {[]{return HasBombchus && SmallKeys(RR_SPIRIT_TEMPLE, 7) && Slingshot && (CanUse(RG_DINS_FIRE) || (Here(RR_SPIRIT_TEMPLE_MQ_ADULT, []{return IsAdult && (CanUse(RG_FIRE_ARROWS) || (LogicSpiritMQFrozenEye && CanUse(RG_FAIRY_BOW) && CanPlay(SongOfTime)));})));}}),
LocationAccess(RC_SPIRIT_TEMPLE_MQ_SILVER_BLOCK_HALLWAY_CHEST, {[]{return HasBombchus && SmallKeys(RR_SPIRIT_TEMPLE, 7) && Slingshot && (CanUse(RG_DINS_FIRE) || (Here(RR_SPIRIT_TEMPLE_MQ_ADULT, []{return IsAdult && (CanUse(RG_FIRE_ARROWS) || (randoCtx->GetTrickOption(RT_SPIRIT_MQ_FROZEN_EYE) && CanUse(RG_FAIRY_BOW) && CanPlay(SongOfTime)));})));}}),
//Trick: HasBombchus && SmallKeys(RR_SPIRIT_TEMPLE, 7) && Slingshot && (CanUse(RG_DINS_FIRE) || (SPIRIT_TEMPLE_MQ_ADULT.Adult() && IsAdult && (CanUse(RG_FIRE_ARROWS) || (LogicSpiritMQFrozenEye && CanUse(RG_FAIRY_BOW) && CanPlay(SongOfTime)))))
}, {
//Exits
@@ -175,34 +175,34 @@ void AreaTable_Init_SpiritTemple() {
//Locations
LocationAccess(RC_SPIRIT_TEMPLE_MQ_CHILD_CLIMB_SOUTH_CHEST, {[]{return SmallKeys(RR_SPIRIT_TEMPLE, 7);}}),
LocationAccess(RC_SPIRIT_TEMPLE_MQ_STATUE_ROOM_LULLABY_CHEST, {[]{return CanPlay(ZeldasLullaby) && (CanJumpslash || CanUse(RG_HOVER_BOOTS));}}),
LocationAccess(RC_SPIRIT_TEMPLE_MQ_STATUE_ROOM_INVISIBLE_CHEST, {[]{return (LogicLensSpiritMQ || CanUse(RG_LENS_OF_TRUTH));}}),
LocationAccess(RC_SPIRIT_TEMPLE_MQ_STATUE_ROOM_INVISIBLE_CHEST, {[]{return (randoCtx->GetTrickOption(RT_LENS_SPIRIT_MQ) || CanUse(RG_LENS_OF_TRUTH));}}),
LocationAccess(RC_SPIRIT_TEMPLE_MQ_BEAMOS_ROOM_CHEST, {[]{return SmallKeys(RR_SPIRIT_TEMPLE, 5);}}),
LocationAccess(RC_SPIRIT_TEMPLE_MQ_CHEST_SWITCH_CHEST, {[]{return SmallKeys(RR_SPIRIT_TEMPLE, 5) && CanPlay(SongOfTime);}}),
LocationAccess(RC_SPIRIT_TEMPLE_MQ_BOSS_KEY_CHEST, {[]{return SmallKeys(RR_SPIRIT_TEMPLE, 5) && CanPlay(SongOfTime) && (MirrorShield || (SunlightArrows && CanUse(RG_LIGHT_ARROWS)));}}),
LocationAccess(RC_SPIRIT_TEMPLE_MQ_BOSS_KEY_CHEST, {[]{return SmallKeys(RR_SPIRIT_TEMPLE, 5) && CanPlay(SongOfTime) && (MirrorShield || (randoCtx->GetOption(RSK_SUNLIGHT_ARROWS) && CanUse(RG_LIGHT_ARROWS)));}}),
LocationAccess(RC_SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_WEST, {[]{return SmallKeys(RR_SPIRIT_TEMPLE, 7);}}),
LocationAccess(RC_SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_NORTH, {[]{return SmallKeys(RR_SPIRIT_TEMPLE, 7);}}),
}, {
//Exits
Entrance(RR_SPIRIT_TEMPLE_MQ_LOWER_ADULT, {[]{return MirrorShield && IsAdult && (CanUse(RG_FIRE_ARROWS) || (LogicSpiritMQLowerAdult && CanUse(RG_DINS_FIRE) && Bow));}}),
Entrance(RR_SPIRIT_TEMPLE_MQ_LOWER_ADULT, {[]{return MirrorShield && IsAdult && (CanUse(RG_FIRE_ARROWS) || (randoCtx->GetTrickOption(RT_SPIRIT_MQ_LOWER_ADULT) && CanUse(RG_DINS_FIRE) && Bow));}}),
//Trick: MirrorShield && IsAdult && (CanUse(RG_FIRE_ARROWS) || (LogicSpiritMQLowerAdult && CanUse(RG_DINS_FIRE) && Bow))
Entrance(RR_SPIRIT_TEMPLE_MQ_SHARED, {[]{return true;}}),
Entrance(RR_SPIRIT_TEMPLE_MQ_BOSS_AREA, {[]{return SmallKeys(RR_SPIRIT_TEMPLE, 6) && CanPlay(ZeldasLullaby) && Hammer;}}),
Entrance(RR_SPIRIT_TEMPLE_MQ_MIRROR_SHIELD_HAND, {[]{return SmallKeys(RR_SPIRIT_TEMPLE, 5) && CanPlay(SongOfTime) && CanJumpslash && (LogicLensSpiritMQ || CanUse(RG_LENS_OF_TRUTH));}}),
Entrance(RR_SPIRIT_TEMPLE_MQ_MIRROR_SHIELD_HAND, {[]{return SmallKeys(RR_SPIRIT_TEMPLE, 5) && CanPlay(SongOfTime) && CanJumpslash && (randoCtx->GetTrickOption(RT_LENS_SPIRIT_MQ) || CanUse(RG_LENS_OF_TRUTH));}}),
});
areaTable[RR_SPIRIT_TEMPLE_MQ_SHARED] = Area("Spirit Temple MQ Shared", "Spirit Temple", RHT_SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_SPIRIT_TEMPLE_MQ_CHILD_CLIMB_NORTH_CHEST, {[]{return SmallKeys(RR_SPIRIT_TEMPLE, 6);}}),
LocationAccess(RC_SPIRIT_TEMPLE_MQ_COMPASS_CHEST, {[]{return (IsChild && CanUse(RG_FAIRY_SLINGSHOT) && SmallKeys(RR_SPIRIT_TEMPLE, 7)) || (IsAdult && CanUse(RG_FAIRY_BOW)) || (Bow && Slingshot);}}),
LocationAccess(RC_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM_CHEST, {[]{return CanPlay(SongOfTime) || LogicSpiritMQSunBlockSoT || IsAdult;}}),
LocationAccess(RC_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM_CHEST, {[]{return CanPlay(SongOfTime) || randoCtx->GetTrickOption(RT_SPIRIT_MQ_SUN_BLOCK_SOT) || IsAdult;}}),
//Trick: CanPlay(SongOfTime) || LogicSpiritMQSunBlockSoT || IsAdult
LocationAccess(RC_SPIRIT_TEMPLE_MQ_GS_SUN_BLOCK_ROOM, {[]{return (LogicSpiritMQSunBlockGS && Boomerang && (CanPlay(SongOfTime) || LogicSpiritMQSunBlockSoT)) || IsAdult;}}),
LocationAccess(RC_SPIRIT_TEMPLE_MQ_GS_SUN_BLOCK_ROOM, {[]{return (randoCtx->GetTrickOption(RT_SPIRIT_MQ_SUN_BLOCK_GS) && Boomerang && (CanPlay(SongOfTime) || randoCtx->GetTrickOption(RT_SPIRIT_MQ_SUN_BLOCK_SOT))) || IsAdult;}}),
//Trick: (LogicSpiritMQSunBlockGS && Boomerang && (CanPlay(SongOfTime) || LogicSpiritMQSunBlockSoT)) || IsAdult
}, {
//Exits
Entrance(RR_SPIRIT_TEMPLE_MQ_SILVER_GAUNTLETS_HAND, {[]{return (SmallKeys(RR_SPIRIT_TEMPLE, 7) && (CanPlay(SongOfTime) || LogicSpiritMQSunBlockSoT || IsAdult)) || (SmallKeys(RR_SPIRIT_TEMPLE, 4) && CanPlay(SongOfTime) && CanJumpslash && (LogicLensSpiritMQ || CanUse(RG_LENS_OF_TRUTH)));}}),
Entrance(RR_SPIRIT_TEMPLE_MQ_SILVER_GAUNTLETS_HAND, {[]{return (SmallKeys(RR_SPIRIT_TEMPLE, 7) && (CanPlay(SongOfTime) || randoCtx->GetTrickOption(RT_SPIRIT_MQ_SUN_BLOCK_SOT) || IsAdult)) || (SmallKeys(RR_SPIRIT_TEMPLE, 4) && CanPlay(SongOfTime) && CanJumpslash && (randoCtx->GetTrickOption(RT_LENS_SPIRIT_MQ) || CanUse(RG_LENS_OF_TRUTH)));}}),
//Trick: (SmallKeys(RR_SPIRIT_TEMPLE, 7) && (CanPlay(SongOfTime) || LogicSpiritMQSunBlockSoT || IsAdult)) || (SmallKeys(RR_SPIRIT_TEMPLE, 4) && CanPlay(SongOfTime) && (LogicLensSpiritMQ || CanUse(RG_LENS_OF_TRUTH)))
Entrance(RR_DESERT_COLOSSUS, {[]{return (SmallKeys(RR_SPIRIT_TEMPLE, 7) && (CanPlay(SongOfTime) || LogicSpiritMQSunBlockSoT || IsAdult)) || (SmallKeys(RR_SPIRIT_TEMPLE, 4) && CanPlay(SongOfTime) && CanJumpslash && (LogicLensSpiritMQ || CanUse(RG_LENS_OF_TRUTH)) && IsAdult);}}),
Entrance(RR_DESERT_COLOSSUS, {[]{return (SmallKeys(RR_SPIRIT_TEMPLE, 7) && (CanPlay(SongOfTime) || randoCtx->GetTrickOption(RT_SPIRIT_MQ_SUN_BLOCK_SOT) || IsAdult)) || (SmallKeys(RR_SPIRIT_TEMPLE, 4) && CanPlay(SongOfTime) && CanJumpslash && (randoCtx->GetTrickOption(RT_LENS_SPIRIT_MQ) || CanUse(RG_LENS_OF_TRUTH)) && IsAdult);}}),
//Trick: (SmallKeys(RR_SPIRIT_TEMPLE, 7) && (CanPlay(SongOfTime) || LogicSpiritMQSunBlockSoT || IsAdult)) || (SmallKeys(RR_SPIRIT_TEMPLE, 4) && CanPlay(SongOfTime) && (LogicLensSpiritMQ || CanUse(RG_LENS_OF_TRUTH)) && IsAdult)
});
@@ -217,7 +217,7 @@ void AreaTable_Init_SpiritTemple() {
areaTable[RR_SPIRIT_TEMPLE_MQ_BOSS_AREA] = Area("Spirit Temple MQ Boss Area", "Spirit Temple", RHT_SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_SPIRIT_TEMPLE_MQ_MIRROR_PUZZLE_INVISIBLE_CHEST, {[]{return LogicLensSpiritMQ || CanUse(RG_LENS_OF_TRUTH);}}),
LocationAccess(RC_SPIRIT_TEMPLE_MQ_MIRROR_PUZZLE_INVISIBLE_CHEST, {[]{return randoCtx->GetTrickOption(RT_LENS_SPIRIT_MQ) || CanUse(RG_LENS_OF_TRUTH);}}),
}, {
//Exits
Entrance(RR_SPIRIT_TEMPLE_MQ_INSIDE_STATUE_HEAD, {[]{return MirrorShield && Hookshot;}}),
@@ -249,8 +249,8 @@ void AreaTable_Init_SpiritTemple() {
"Spirit Temple Boss Entryway", "Spirit Temple", RHT_SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {},
{
// Exits
Entrance(RR_SPIRIT_TEMPLE_INSIDE_STATUE_HEAD, { [] { return Dungeon::SpiritTemple.IsVanilla() && false; } }),
Entrance(RR_SPIRIT_TEMPLE_MQ_INSIDE_STATUE_HEAD, { [] { return Dungeon::SpiritTemple.IsMQ() && false; } }),
Entrance(RR_SPIRIT_TEMPLE_INSIDE_STATUE_HEAD, { [] { return randoCtx->GetDungeon(SPIRIT_TEMPLE)->IsVanilla() && false; } }),
Entrance(RR_SPIRIT_TEMPLE_MQ_INSIDE_STATUE_HEAD, { [] { return randoCtx->GetDungeon(SPIRIT_TEMPLE)->IsMQ() && false; } }),
Entrance(RR_SPIRIT_TEMPLE_BOSS_ROOM, { [] { return true; } }),
});

View File

@@ -1,10 +1,10 @@
#include "../location_access.hpp"
#include "../logic.hpp"
#include "../entrance.hpp"
#include "../dungeon.hpp"
#include "../../entrance.h"
#include "../../dungeon.h"
using namespace Logic;
using namespace Settings;
using namespace Rando;
void AreaTable_Init_WaterTemple() {
/*--------------------------
@@ -12,29 +12,29 @@ void AreaTable_Init_WaterTemple() {
---------------------------*/
areaTable[RR_WATER_TEMPLE_ENTRYWAY] = Area("Water Temple Entryway", "Water Temple", RHT_WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_WATER_TEMPLE_LOBBY, {[]{return Dungeon::WaterTemple.IsVanilla();}}),
Entrance(RR_WATER_TEMPLE_MQ_LOBBY, {[]{return Dungeon::WaterTemple.IsMQ();}}),
Entrance(RR_WATER_TEMPLE_LOBBY, {[]{return randoCtx->GetDungeon(WATER_TEMPLE)->IsVanilla();}}),
Entrance(RR_WATER_TEMPLE_MQ_LOBBY, {[]{return randoCtx->GetDungeon(WATER_TEMPLE)->IsMQ();}}),
Entrance(RR_LAKE_HYLIA, {[]{return true;}}),
});
/*--------------------------
| VANILLA DUNGEON |
---------------------------*/
if (Dungeon::WaterTemple.IsVanilla()) {
if (randoCtx->GetDungeon(WATER_TEMPLE)->IsVanilla()) {
//Water Temple logic currently assumes that the locked door leading to the upper water raising location is unlocked from the start
areaTable[RR_WATER_TEMPLE_LOBBY] = Area("Water Temple Lobby", "Water Temple", RHT_WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_WATER_TEMPLE_ENTRYWAY, {[]{return true;}}),
Entrance(RR_WATER_TEMPLE_EAST_LOWER, {[]{return WaterTempleLow || ((LogicFewerTunicRequirements || CanUse(RG_ZORA_TUNIC)) && (CanUse(RG_IRON_BOOTS) || (CanUse(RG_LONGSHOT) && LogicWaterTempleTorchLongshot)));}}),
Entrance(RR_WATER_TEMPLE_NORTH_LOWER, {[]{return WaterTempleLow || ((LogicFewerTunicRequirements || CanUse(RG_ZORA_TUNIC)) && CanUse(RG_IRON_BOOTS));}}),
Entrance(RR_WATER_TEMPLE_SOUTH_LOWER, {[]{return WaterTempleLow && HasExplosives && (CanDive || CanUse(RG_IRON_BOOTS)) && (LogicFewerTunicRequirements || CanUse(RG_ZORA_TUNIC));}}),
Entrance(RR_WATER_TEMPLE_WEST_LOWER, {[]{return WaterTempleLow && GoronBracelet && (IsChild || CanDive || CanUse(RG_IRON_BOOTS)) && (LogicFewerTunicRequirements || CanUse(RG_ZORA_TUNIC));}}),
Entrance(RR_WATER_TEMPLE_EAST_LOWER, {[]{return WaterTempleLow || ((randoCtx->GetTrickOption(RT_FEWER_TUNIC_REQUIREMENTS) || CanUse(RG_ZORA_TUNIC)) && (CanUse(RG_IRON_BOOTS) || (CanUse(RG_LONGSHOT) && randoCtx->GetTrickOption(RT_WATER_LONGSHOT_TORCH))));}}),
Entrance(RR_WATER_TEMPLE_NORTH_LOWER, {[]{return WaterTempleLow || ((randoCtx->GetTrickOption(RT_FEWER_TUNIC_REQUIREMENTS) || CanUse(RG_ZORA_TUNIC)) && CanUse(RG_IRON_BOOTS));}}),
Entrance(RR_WATER_TEMPLE_SOUTH_LOWER, {[]{return WaterTempleLow && HasExplosives && (CanDive || CanUse(RG_IRON_BOOTS)) && (randoCtx->GetTrickOption(RT_FEWER_TUNIC_REQUIREMENTS) || CanUse(RG_ZORA_TUNIC));}}),
Entrance(RR_WATER_TEMPLE_WEST_LOWER, {[]{return WaterTempleLow && GoronBracelet && (IsChild || CanDive || CanUse(RG_IRON_BOOTS)) && (randoCtx->GetTrickOption(RT_FEWER_TUNIC_REQUIREMENTS) || CanUse(RG_ZORA_TUNIC));}}),
Entrance(RR_WATER_TEMPLE_CENTRAL_PILLAR_LOWER, {[]{return WaterTempleLow && SmallKeys(RR_WATER_TEMPLE, 5);}}),
Entrance(RR_WATER_TEMPLE_CENTRAL_PILLAR_UPPER, {[]{return (WaterTempleLow || WaterTempleMiddle) && (HasFireSourceWithTorch || CanUse(RG_FAIRY_BOW));}}),
Entrance(RR_WATER_TEMPLE_EAST_MIDDLE, {[]{return (WaterTempleLow || WaterTempleMiddle || (CanUse(RG_IRON_BOOTS) && WaterTimer >= 16)) && CanUse(RG_HOOKSHOT);}}),
Entrance(RR_WATER_TEMPLE_WEST_MIDDLE, {[]{return WaterTempleMiddle;}}),
Entrance(RR_WATER_TEMPLE_HIGH_WATER, {[]{return IsAdult && (CanUse(RG_HOVER_BOOTS) || (LogicDamageBoost && Bombs && CanTakeDamage));}}),
Entrance(RR_WATER_TEMPLE_BLOCK_CORRIDOR, {[]{return (WaterTempleLow || WaterTempleMiddle) && (CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_FAIRY_BOW)) && (CanUse(RG_LONGSHOT) || CanUse(RG_HOVER_BOOTS) || (LogicWaterCentralBow && (IsAdult || WaterTempleMiddle)));}}),
Entrance(RR_WATER_TEMPLE_HIGH_WATER, {[]{return IsAdult && (CanUse(RG_HOVER_BOOTS) || (randoCtx->GetTrickOption(RT_DAMAGE_BOOST) && Bombs && CanTakeDamage));}}),
Entrance(RR_WATER_TEMPLE_BLOCK_CORRIDOR, {[]{return (WaterTempleLow || WaterTempleMiddle) && (CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_FAIRY_BOW)) && (CanUse(RG_LONGSHOT) || CanUse(RG_HOVER_BOOTS) || (randoCtx->GetTrickOption(RT_WATER_CENTRAL_BOW) && (IsAdult || WaterTempleMiddle)));}}),
Entrance(RR_WATER_TEMPLE_FALLING_PLATFORM_ROOM, {[]{return WaterTempleHigh && SmallKeys(RR_WATER_TEMPLE, 4);}}),
Entrance(RR_WATER_TEMPLE_PRE_BOSS_ROOM, {[]{return WaterTempleHigh && CanUse(RG_LONGSHOT);}}),
});
@@ -44,9 +44,9 @@ void AreaTable_Init_WaterTemple() {
EventAccess(&WaterTempleLow, {[]{return WaterTempleLow || CanPlay(ZeldasLullaby);}}),
}, {}, {
//Exits
Entrance(RR_WATER_TEMPLE_LOBBY, {[]{return WaterTempleLow || ((LogicFewerTunicRequirements || CanUse(RG_ZORA_TUNIC)) && CanUse(RG_IRON_BOOTS));}}),
Entrance(RR_WATER_TEMPLE_LOBBY, {[]{return WaterTempleLow || ((randoCtx->GetTrickOption(RT_FEWER_TUNIC_REQUIREMENTS) || CanUse(RG_ZORA_TUNIC)) && CanUse(RG_IRON_BOOTS));}}),
Entrance(RR_WATER_TEMPLE_MAP_ROOM, {[]{return WaterTempleHigh;}}),
Entrance(RR_WATER_TEMPLE_CRACKED_WALL, {[]{return WaterTempleMiddle || (WaterTempleHigh && WaterTempleLow && ((CanUse(RG_HOVER_BOOTS) && LogicWaterCrackedWallHovers) || LogicWaterCrackedWallNothing));}}),
Entrance(RR_WATER_TEMPLE_CRACKED_WALL, {[]{return WaterTempleMiddle || (WaterTempleHigh && WaterTempleLow && ((CanUse(RG_HOVER_BOOTS) && randoCtx->GetTrickOption(RT_WATER_CRACKED_WALL_HOVERS)) || randoCtx->GetTrickOption(RT_WATER_CRACKED_WALL)));}}),
Entrance(RR_WATER_TEMPLE_TORCH_ROOM, {[]{return WaterTempleLow && (HasFireSourceWithTorch || CanUse(RG_FAIRY_BOW));}}),
});
@@ -77,7 +77,7 @@ void AreaTable_Init_WaterTemple() {
areaTable[RR_WATER_TEMPLE_NORTH_LOWER] = Area("Water Temple North Lower", "Water Temple", RHT_WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_WATER_TEMPLE_LOBBY, {[]{return true;}}),
Entrance(RR_WATER_TEMPLE_BOULDERS_LOWER, {[]{return (CanUse(RG_LONGSHOT) || (LogicWaterBossKeyRegion && CanUse(RG_HOVER_BOOTS))) && SmallKeys(RR_WATER_TEMPLE, 4);}}),
Entrance(RR_WATER_TEMPLE_BOULDERS_LOWER, {[]{return (CanUse(RG_LONGSHOT) || (randoCtx->GetTrickOption(RT_WATER_BK_REGION) && CanUse(RG_HOVER_BOOTS))) && SmallKeys(RR_WATER_TEMPLE, 4);}}),
});
areaTable[RR_WATER_TEMPLE_BOULDERS_LOWER] = Area("Water Temple Boulders Lower", "Water Temple", RHT_WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
@@ -87,7 +87,7 @@ void AreaTable_Init_WaterTemple() {
//Exits
Entrance(RR_WATER_TEMPLE_NORTH_LOWER, {[]{return SmallKeys(RR_WATER_TEMPLE, 4);}}),
Entrance(RR_WATER_TEMPLE_BLOCK_ROOM, {[]{return true;}}),
Entrance(RR_WATER_TEMPLE_BOULDERS_UPPER, {[]{return (IsAdult && (CanUse(RG_HOVER_BOOTS) || LogicWaterNorthBasementLedgeJump)) || (CanUse(RG_HOVER_BOOTS) && CanUse(RG_IRON_BOOTS));}}),
Entrance(RR_WATER_TEMPLE_BOULDERS_UPPER, {[]{return (IsAdult && (CanUse(RG_HOVER_BOOTS) || randoCtx->GetTrickOption(RT_WATER_NORTH_BASEMENT_LEDGE_JUMP))) || (CanUse(RG_HOVER_BOOTS) && CanUse(RG_IRON_BOOTS));}}),
});
areaTable[RR_WATER_TEMPLE_BLOCK_ROOM] = Area("Water Temple Block Room", "Water Temple", RHT_WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, {
@@ -106,7 +106,7 @@ void AreaTable_Init_WaterTemple() {
//Exits
Entrance(RR_WATER_TEMPLE_BOULDERS_LOWER, {[]{return true;}}),
Entrance(RR_WATER_TEMPLE_JETS_ROOM, {[]{return IsAdult;}}),
Entrance(RR_WATER_TEMPLE_BOSS_KEY_ROOM, {[]{return (CanUse(RG_IRON_BOOTS) || (IsAdult && LogicWaterBKJumpDive)) && SmallKeys(RR_WATER_TEMPLE, 5);}}),
Entrance(RR_WATER_TEMPLE_BOSS_KEY_ROOM, {[]{return (CanUse(RG_IRON_BOOTS) || (IsAdult && randoCtx->GetTrickOption(RT_WATER_BK_JUMP_DIVE))) && SmallKeys(RR_WATER_TEMPLE, 5);}}),
});
areaTable[RR_WATER_TEMPLE_BOSS_KEY_ROOM] = Area("Water Temple Boss Key Room", "Water Temple", RHT_WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {
@@ -117,7 +117,7 @@ void AreaTable_Init_WaterTemple() {
LocationAccess(RC_WATER_TEMPLE_BOSS_KEY_CHEST, {[]{return true;}}),
}, {
//Exits
Entrance(RR_WATER_TEMPLE_BOULDERS_UPPER, {[]{return (CanUse(RG_IRON_BOOTS) || (IsAdult && LogicWaterBKJumpDive) || IsChild || CanDive) && SmallKeys(RR_WATER_TEMPLE, 5);}}),
Entrance(RR_WATER_TEMPLE_BOULDERS_UPPER, {[]{return (CanUse(RG_IRON_BOOTS) || (IsAdult && randoCtx->GetTrickOption(RT_WATER_BK_JUMP_DIVE)) || IsChild || CanDive) && SmallKeys(RR_WATER_TEMPLE, 5);}}),
});
areaTable[RR_WATER_TEMPLE_SOUTH_LOWER] = Area("Water Temple South Lower", "Water Temple", RHT_WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
@@ -136,8 +136,8 @@ void AreaTable_Init_WaterTemple() {
areaTable[RR_WATER_TEMPLE_DRAGON_ROOM] = Area("Water Temple Dragon Room", "Water Temple", RHT_WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_WATER_TEMPLE_DRAGON_CHEST, {[]{return (CanUse(RG_HOOKSHOT) && CanUse(RG_IRON_BOOTS)) || (((IsAdult && LogicWaterDragonAdult && (CanUse(RG_HOOKSHOT) || CanUse(RG_FAIRY_BOW) || HasBombchus)) || (IsChild && LogicWaterDragonChild && (CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_BOOMERANG) || HasBombchus))) && (CanDive || CanUse(RG_IRON_BOOTS))) ||
Here(RR_WATER_TEMPLE_RIVER, []{return IsAdult && CanUse(RG_FAIRY_BOW) && ((LogicWaterDragonAdult && (CanDive || CanUse(RG_IRON_BOOTS))) || LogicWaterDragonJumpDive);});}}),
LocationAccess(RC_WATER_TEMPLE_DRAGON_CHEST, {[]{return (CanUse(RG_HOOKSHOT) && CanUse(RG_IRON_BOOTS)) || (((IsAdult && randoCtx->GetTrickOption(RT_WATER_ADULT_DRAGON) && (CanUse(RG_HOOKSHOT) || CanUse(RG_FAIRY_BOW) || HasBombchus)) || (IsChild && randoCtx->GetTrickOption(RT_WATER_CHILD_DRAGON) && (CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_BOOMERANG) || HasBombchus))) && (CanDive || CanUse(RG_IRON_BOOTS))) ||
Here(RR_WATER_TEMPLE_RIVER, []{return IsAdult && CanUse(RG_FAIRY_BOW) && ((randoCtx->GetTrickOption(RT_WATER_ADULT_DRAGON) && (CanDive || CanUse(RG_IRON_BOOTS))) || randoCtx->GetTrickOption(RT_WATER_DRAGON_JUMP_DIVE));});}}),
}, {
//Exits
Entrance(RR_WATER_TEMPLE_WEST_LOWER, {[]{return true;}}),
@@ -155,7 +155,7 @@ void AreaTable_Init_WaterTemple() {
EventAccess(&WaterTempleMiddle, {[]{return WaterTempleMiddle || CanPlay(ZeldasLullaby);}}),
}, {
//Locations
LocationAccess(RC_WATER_TEMPLE_GS_CENTRAL_PILLAR, {[]{return CanUse(RG_LONGSHOT) || (((LogicWaterCentralGSFW && CanUse(RG_FARORES_WIND) && (CanUse(RG_FAIRY_BOW) || CanUse(RG_DINS_FIRE) || SmallKeys(RR_WATER_TEMPLE, 5))) || (LogicWaterCentralGSIrons && CanUse(RG_IRON_BOOTS) && ((CanUse(RG_HOOKSHOT) && CanUse(RG_FAIRY_BOW)) || (CanUse(RG_DINS_FIRE))))) && WaterTempleHigh && HookshotOrBoomerang);}}),
LocationAccess(RC_WATER_TEMPLE_GS_CENTRAL_PILLAR, {[]{return CanUse(RG_LONGSHOT) || (((randoCtx->GetTrickOption(RT_WATER_FW_CENTRAL_GS) && CanUse(RG_FARORES_WIND) && (CanUse(RG_FAIRY_BOW) || CanUse(RG_DINS_FIRE) || SmallKeys(RR_WATER_TEMPLE, 5))) || (randoCtx->GetTrickOption(RT_WATER_IRONS_CENTRAL_GS) && CanUse(RG_IRON_BOOTS) && ((CanUse(RG_HOOKSHOT) && CanUse(RG_FAIRY_BOW)) || (CanUse(RG_DINS_FIRE))))) && WaterTempleHigh && HookshotOrBoomerang);}}),
}, {
//Exits
Entrance(RR_WATER_TEMPLE_LOBBY, {[]{return true;}}),
@@ -202,7 +202,7 @@ void AreaTable_Init_WaterTemple() {
areaTable[RR_WATER_TEMPLE_FALLING_PLATFORM_ROOM] = Area("Water Temple Falling Platform Room", "Water Temple", RHT_WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_WATER_TEMPLE_GS_FALLING_PLATFORM_ROOM, {[]{return CanUse(RG_LONGSHOT) || (LogicWaterFallingPlatformGSBoomerang && IsChild && CanUse(RG_BOOMERANG)) || (LogicWaterFallingPlatformGSHookshot && IsAdult && CanUse(RG_HOOKSHOT));}}),
LocationAccess(RC_WATER_TEMPLE_GS_FALLING_PLATFORM_ROOM, {[]{return CanUse(RG_LONGSHOT) || (randoCtx->GetTrickOption(RT_WATER_RANG_FALLING_PLATFORM_GS) && IsChild && CanUse(RG_BOOMERANG)) || (randoCtx->GetTrickOption(RT_WATER_HOOKSHOT_FALLING_PLATFORM_GS) && IsAdult && CanUse(RG_HOOKSHOT));}}),
}, {
//Exits
Entrance(RR_WATER_TEMPLE_LOBBY, {[]{return CanUse(RG_HOOKSHOT) && SmallKeys(RR_WATER_TEMPLE, 4);}}),
@@ -233,7 +233,7 @@ void AreaTable_Init_WaterTemple() {
areaTable[RR_WATER_TEMPLE_RIVER] = Area("Water Temple River", "Water Temple", RHT_WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_WATER_TEMPLE_RIVER_CHEST, {[]{return (CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_FAIRY_BOW)) && (IsAdult || CanUse(RG_HOVER_BOOTS) || CanUse(RG_HOOKSHOT));}}),
LocationAccess(RC_WATER_TEMPLE_GS_RIVER, {[]{return (CanUse(RG_IRON_BOOTS) && CanUse(RG_HOOKSHOT)) || (LogicWaterRiverGS && CanUse(RG_LONGSHOT));}}),
LocationAccess(RC_WATER_TEMPLE_GS_RIVER, {[]{return (CanUse(RG_IRON_BOOTS) && CanUse(RG_HOOKSHOT)) || (randoCtx->GetTrickOption(RT_WATER_RIVER_GS) && CanUse(RG_LONGSHOT));}}),
}, {
//Exits
Entrance(RR_WATER_TEMPLE_DRAGON_ROOM, {[]{return (CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_FAIRY_BOW)) && (IsAdult || CanUse(RG_HOVER_BOOTS) || CanUse(RG_HOOKSHOT));}}),
@@ -252,7 +252,7 @@ void AreaTable_Init_WaterTemple() {
/*---------------------------
| MASTER QUEST DUNGEON |
---------------------------*/
if (Dungeon::WaterTemple.IsMQ()) {
if (randoCtx->GetDungeon(WATER_TEMPLE)->IsMQ()) {
areaTable[RR_WATER_TEMPLE_MQ_LOBBY] = Area("Water Temple MQ Lobby", "Water Temple", RHT_WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_WATER_TEMPLE_ENTRYWAY, {[]{return true;}}),
@@ -264,7 +264,7 @@ void AreaTable_Init_WaterTemple() {
areaTable[RR_WATER_TEMPLE_MQ_DIVE] = Area("Water Temple MQ Dive", "Water Temple", RHT_WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_WATER_TEMPLE_MQ_MAP_CHEST, {[]{return HasFireSource && IsAdult && CanUse(RG_HOOKSHOT);}}),
LocationAccess(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_CHEST, {[]{return IsAdult && CanUse(RG_ZORA_TUNIC) && CanUse(RG_HOOKSHOT) && ((LogicWaterMQCentralPillar && CanUse(RG_FIRE_ARROWS)) || (CanUse(RG_DINS_FIRE) && CanPlay(SongOfTime)));}}),
LocationAccess(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_CHEST, {[]{return IsAdult && CanUse(RG_ZORA_TUNIC) && CanUse(RG_HOOKSHOT) && ((randoCtx->GetTrickOption(RT_WATER_MQ_CENTRAL_PILLAR) && CanUse(RG_FIRE_ARROWS)) || (CanUse(RG_DINS_FIRE) && CanPlay(SongOfTime)));}}),
//Trick: IsAdult && CanUse(RG_ZORA_TUNIC) && CanUse(RG_HOOKSHOT) && ((LogicWaterMQCentralPillar && CanUse(RG_FIRE_ARROWS)) || (CanUse(RG_DINS_FIRE) && CanPlay(SongOfTime)))
}, {
//Exits
@@ -286,7 +286,7 @@ void AreaTable_Init_WaterTemple() {
EventAccess(&NutPot, {[]{return true;}}),
}, {
//Locations
LocationAccess(RC_WATER_TEMPLE_MQ_BOSS_KEY_CHEST, {[]{return IsAdult && WaterTimer >= 24 && CanUse(RG_DINS_FIRE) && (LogicWaterDragonJumpDive || CanDive || CanUse(RG_IRON_BOOTS));}}),
LocationAccess(RC_WATER_TEMPLE_MQ_BOSS_KEY_CHEST, {[]{return IsAdult && WaterTimer >= 24 && CanUse(RG_DINS_FIRE) && (randoCtx->GetTrickOption(RT_WATER_DRAGON_JUMP_DIVE) || CanDive || CanUse(RG_IRON_BOOTS));}}),
LocationAccess(RC_WATER_TEMPLE_MQ_GS_RIVER, {[]{return true;}}),
}, {
//Exits
@@ -295,9 +295,9 @@ void AreaTable_Init_WaterTemple() {
areaTable[RR_WATER_TEMPLE_MQ_BASEMENT_GATED_AREAS] = Area("Water Temple MQ Basement Gated Areas", "Water Temple", RHT_WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {
//Locations
LocationAccess(RC_WATER_TEMPLE_MQ_FREESTANDING_KEY, {[]{return HoverBoots || CanUse(RG_SCARECROW) || LogicWaterNorthBasementLedgeJump;}}),
LocationAccess(RC_WATER_TEMPLE_MQ_FREESTANDING_KEY, {[]{return HoverBoots || CanUse(RG_SCARECROW) || randoCtx->GetTrickOption(RT_WATER_NORTH_BASEMENT_LEDGE_JUMP);}}),
LocationAccess(RC_WATER_TEMPLE_MQ_GS_TRIPLE_WALL_TORCH, {[]{return CanUse(RG_FIRE_ARROWS) && (HoverBoots || CanUse(RG_SCARECROW));}}),
LocationAccess(RC_WATER_TEMPLE_MQ_GS_FREESTANDING_KEY_AREA, {[]{return LogicWaterMQLockedGS || (SmallKeys(RR_WATER_TEMPLE, 2) && (HoverBoots || CanUse(RG_SCARECROW) || LogicWaterNorthBasementLedgeJump) && CanJumpslash);}}),
LocationAccess(RC_WATER_TEMPLE_MQ_GS_FREESTANDING_KEY_AREA, {[]{return randoCtx->GetTrickOption(RT_WATER_MQ_LOCKED_GS) || (SmallKeys(RR_WATER_TEMPLE, 2) && (HoverBoots || CanUse(RG_SCARECROW) || randoCtx->GetTrickOption(RT_WATER_NORTH_BASEMENT_LEDGE_JUMP)) && CanJumpslash);}}),
//Trick: LogicWaterMQLockedGS || (SmallKeys(RR_WATER_TEMPLE, 2) && (HoverBoots || CanUse(RG_SCARECROW) || LogicWaterNorthBasementLedgeJump))
}, {});
}
@@ -309,8 +309,8 @@ void AreaTable_Init_WaterTemple() {
Area("Water Temple Boss Entryway", "Water Temple", RHT_WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {},
{
// Exits
Entrance(RR_WATER_TEMPLE_PRE_BOSS_ROOM, { [] { return Dungeon::WaterTemple.IsVanilla() && false; } }),
Entrance(RR_WATER_TEMPLE_MQ_LOBBY, { [] { return Dungeon::WaterTemple.IsMQ() && false; } }),
Entrance(RR_WATER_TEMPLE_PRE_BOSS_ROOM, { [] { return randoCtx->GetDungeon(WATER_TEMPLE)->IsVanilla() && false; } }),
Entrance(RR_WATER_TEMPLE_MQ_LOBBY, { [] { return randoCtx->GetDungeon(WATER_TEMPLE)->IsMQ() && false; } }),
Entrance(RR_WATER_TEMPLE_BOSS_ROOM, { [] { return true; } }),
});

View File

@@ -1,9 +1,9 @@
#include "../location_access.hpp"
#include "../logic.hpp"
#include "../entrance.hpp"
#include "../../entrance.h"
using namespace Logic;
using namespace Settings;
using namespace Rando;
void AreaTable_Init_ZorasDomain() {
areaTable[RR_ZR_FRONT] = Area("ZR Front", "Zora River", RHT_ZORAS_RIVER, DAY_NIGHT_CYCLE, {}, {
@@ -31,8 +31,8 @@ void AreaTable_Init_ZorasDomain() {
LocationAccess(RC_ZR_FROGS_SARIAS_SONG, {[]{return IsChild && CanPlay(SariasSong);}}),
LocationAccess(RC_ZR_FROGS_SUNS_SONG, {[]{return IsChild && CanPlay(SunsSong);}}),
LocationAccess(RC_ZR_FROGS_SONG_OF_TIME, {[]{return IsChild && CanPlay(SongOfTime);}}),
LocationAccess(RC_ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH, {[]{return IsChild || CanUse(RG_HOVER_BOOTS) || (IsAdult && LogicZoraRiverLower);}}),
LocationAccess(RC_ZR_NEAR_DOMAIN_FREESTANDING_POH, {[]{return IsChild || CanUse(RG_HOVER_BOOTS) || (IsAdult && LogicZoraRiverUpper);}}),
LocationAccess(RC_ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH, {[]{return IsChild || CanUse(RG_HOVER_BOOTS) || (IsAdult && randoCtx->GetTrickOption(RT_ZR_LOWER));}}),
LocationAccess(RC_ZR_NEAR_DOMAIN_FREESTANDING_POH, {[]{return IsChild || CanUse(RG_HOVER_BOOTS) || (IsAdult && randoCtx->GetTrickOption(RT_ZR_UPPER));}}),
LocationAccess(RC_ZR_GS_LADDER, {[]{return IsChild && AtNight && CanChildAttack && CanGetNightTimeGS;}}),
LocationAccess(RC_ZR_GS_NEAR_RAISED_GROTTOS, {[]{return IsAdult && HookshotOrBoomerang && AtNight && CanGetNightTimeGS;}}),
LocationAccess(RC_ZR_GS_ABOVE_BRIDGE, {[]{return IsAdult && CanUse(RG_HOOKSHOT) && AtNight && CanGetNightTimeGS;}}),
@@ -45,7 +45,7 @@ void AreaTable_Init_ZorasDomain() {
Entrance(RR_ZR_FAIRY_GROTTO, {[]{return Here(RR_ZORAS_RIVER, []{return CanBlastOrSmash;});}}),
Entrance(RR_THE_LOST_WOODS, {[]{return CanDive || CanUse(RG_IRON_BOOTS);}}),
Entrance(RR_ZR_STORMS_GROTTO, {[]{return CanOpenStormGrotto;}}),
Entrance(RR_ZR_BEHIND_WATERFALL, {[]{return CanPlay(ZeldasLullaby) || (IsChild && LogicZoraWithCucco) || (IsAdult && CanUse(RG_HOVER_BOOTS) && LogicZoraWithHovers);}}),
Entrance(RR_ZR_BEHIND_WATERFALL, {[]{return CanPlay(ZeldasLullaby) || (IsChild && randoCtx->GetTrickOption(RT_ZR_CUCCO)) || (IsAdult && CanUse(RG_HOVER_BOOTS) && randoCtx->GetTrickOption(RT_ZR_HOVERS));}}),
});
areaTable[RR_ZR_BEHIND_WATERFALL] = Area("ZR Behind Waterfall", "Zora River", RHT_ZORAS_RIVER, DAY_NIGHT_CYCLE, {}, {}, {
@@ -88,27 +88,27 @@ void AreaTable_Init_ZorasDomain() {
EventAccess(&StickPot, {[]{return StickPot || IsChild;}}),
EventAccess(&FishGroup, {[]{return FishGroup || IsChild;}}),
EventAccess(&KingZoraThawed, {[]{return KingZoraThawed || (IsAdult && BlueFire);}}),
EventAccess(&DeliverLetter, {[]{return DeliverLetter || (RutosLetter && IsChild && ZorasFountain.IsNot(ZORASFOUNTAIN_OPEN));}}),
EventAccess(&DeliverLetter, {[]{return DeliverLetter || (RutosLetter && IsChild && randoCtx->GetOption(RSK_ZORAS_FOUNTAIN).IsNot(RO_ZF_OPEN));}}),
}, {
//Locations
LocationAccess(RC_ZD_DIVING_MINIGAME, {[]{return IsChild;}}),
LocationAccess(RC_ZD_CHEST, {[]{return IsChild && CanUse(RG_STICKS);}}),
LocationAccess(RC_ZD_KING_ZORA_THAWED, {[]{return KingZoraThawed;}}),
LocationAccess(RC_ZD_TRADE_PRESCRIPTION, {[]{return KingZoraThawed && Prescription;}}),
LocationAccess(RC_ZD_GS_FROZEN_WATERFALL, {[]{return IsAdult && AtNight && (HookshotOrBoomerang || CanUse(RG_FAIRY_SLINGSHOT) || Bow || (MagicMeter && (CanUse(RG_MASTER_SWORD) || CanUse(RG_KOKIRI_SWORD) || CanUse(RG_BIGGORON_SWORD))) || (LogicDomainGS && CanJumpslash)) && CanGetNightTimeGS;}}),
LocationAccess(RC_ZD_GS_FROZEN_WATERFALL, {[]{return IsAdult && AtNight && (HookshotOrBoomerang || CanUse(RG_FAIRY_SLINGSHOT) || Bow || (MagicMeter && (CanUse(RG_MASTER_SWORD) || CanUse(RG_KOKIRI_SWORD) || CanUse(RG_BIGGORON_SWORD))) || (randoCtx->GetTrickOption(RT_ZD_GS) && CanJumpslash)) && CanGetNightTimeGS;}}),
LocationAccess(RC_ZD_GOSSIP_STONE, {[]{return true;}}),
}, {
//Exits
Entrance(RR_ZR_BEHIND_WATERFALL, {[]{return true;}}),
Entrance(RR_LAKE_HYLIA, {[]{return IsChild && (CanDive || CanUse(RG_IRON_BOOTS));}}),
Entrance(RR_ZD_BEHIND_KING_ZORA, {[]{return DeliverLetter || ZorasFountain.Is(ZORASFOUNTAIN_OPEN) || (ZorasFountain.Is(ZORASFOUNTAIN_ADULT) && IsAdult) || (LogicKingZoraSkip && IsAdult);}}),
Entrance(RR_ZD_BEHIND_KING_ZORA, {[]{return DeliverLetter || randoCtx->GetOption(RSK_ZORAS_FOUNTAIN).Is(RO_ZF_OPEN) || (randoCtx->GetOption(RSK_ZORAS_FOUNTAIN).Is(RO_ZF_CLOSED_CHILD) && IsAdult) || (randoCtx->GetTrickOption(RT_ZD_KING_ZORA_SKIP) && IsAdult);}}),
Entrance(RR_ZD_SHOP, {[]{return IsChild || BlueFire;}}),
Entrance(RR_ZD_STORMS_GROTTO, {[]{return CanOpenStormGrotto;}}),
});
areaTable[RR_ZD_BEHIND_KING_ZORA] = Area("ZD Behind King Zora", "Zoras Domain", RHT_ZORAS_DOMAIN, NO_DAY_NIGHT_CYCLE, {}, {}, {
//Exits
Entrance(RR_ZORAS_DOMAIN, {[]{return DeliverLetter || ZorasFountain.Is(ZORASFOUNTAIN_OPEN) || (ZorasFountain.Is(ZORASFOUNTAIN_ADULT) && IsAdult);}}),
Entrance(RR_ZORAS_DOMAIN, {[]{return DeliverLetter || randoCtx->GetOption(RSK_ZORAS_FOUNTAIN).Is(RO_ZF_OPEN) || (randoCtx->GetOption(RSK_ZORAS_FOUNTAIN).Is(RO_ZF_CLOSED_CHILD) && IsAdult);}}),
Entrance(RR_ZORAS_FOUNTAIN, {[]{return true;}}),
});

View File

@@ -6,10 +6,8 @@
#include <string_view>
#include <vector>
#include "settings.hpp"
#include "dungeon.hpp"
using namespace Settings;
#include "../dungeon.h"
#include "../context.h"
namespace Logic {
@@ -430,29 +428,30 @@ namespace Logic {
switch (itemName) {
// Adult items
case RG_FAIRY_BOW: return IsAdult || BowAsChild;
case RG_MEGATON_HAMMER: return IsAdult || HammerAsChild;
case RG_IRON_BOOTS: return IsAdult || IronBootsAsChild;
case RG_HOVER_BOOTS: return IsAdult || HoverBootsAsChild;
case RG_HOOKSHOT: return IsAdult || HookshotAsChild;
case RG_LONGSHOT: return IsAdult || HookshotAsChild;
// TODO: Uncomment those if we ever implement more item usability settings
case RG_FAIRY_BOW: return IsAdult;// || BowAsChild;
case RG_MEGATON_HAMMER: return IsAdult;// || HammerAsChild;
case RG_IRON_BOOTS: return IsAdult;// || IronBootsAsChild;
case RG_HOVER_BOOTS: return IsAdult;// || HoverBootsAsChild;
case RG_HOOKSHOT: return IsAdult;// || HookshotAsChild;
case RG_LONGSHOT: return IsAdult;// || HookshotAsChild;
case RG_SILVER_GAUNTLETS: return IsAdult;
case RG_GOLDEN_GAUNTLETS: return IsAdult;
case RG_GORON_TUNIC: return IsAdult || GoronTunicAsChild;
case RG_ZORA_TUNIC: return IsAdult || ZoraTunicAsChild;
case RG_SCARECROW: return IsAdult || HookshotAsChild;
case RG_DISTANT_SCARECROW: return IsAdult || HookshotAsChild;
case RG_GORON_TUNIC: return IsAdult;// || GoronTunicAsChild;
case RG_ZORA_TUNIC: return IsAdult;// || ZoraTunicAsChild;
case RG_SCARECROW: return IsAdult;// || HookshotAsChild;
case RG_DISTANT_SCARECROW: return IsAdult;// || HookshotAsChild;
case RG_HYLIAN_SHIELD: return IsAdult;
case RG_MIRROR_SHIELD: return IsAdult || MirrorShieldAsChild;
case RG_MASTER_SWORD: return IsAdult || MasterSwordAsChild;
case RG_BIGGORON_SWORD: return IsAdult || BiggoronSwordAsChild;
case RG_MIRROR_SHIELD: return IsAdult;// || MirrorShieldAsChild;
case RG_MASTER_SWORD: return IsAdult;// || MasterSwordAsChild;
case RG_BIGGORON_SWORD: return IsAdult;// || BiggoronSwordAsChild;
// Child items
case RG_FAIRY_SLINGSHOT: return IsChild || SlingshotAsAdult;
case RG_BOOMERANG: return IsChild || BoomerangAsAdult;
case RG_KOKIRI_SWORD: return IsChild || KokiriSwordAsAdult;
case RG_STICKS: return IsChild || StickAsAdult;
case RG_DEKU_SHIELD: return IsChild || DekuShieldAsAdult;
case RG_FAIRY_SLINGSHOT: return IsChild;// || SlingshotAsAdult;
case RG_BOOMERANG: return IsChild;// || BoomerangAsAdult;
case RG_KOKIRI_SWORD: return IsChild;// || KokiriSwordAsAdult;
case RG_STICKS: return IsChild;// || StickAsAdult;
case RG_DEKU_SHIELD: return IsChild;// || DekuShieldAsAdult;
// Magic items
default: return MagicMeter && (IsMagicItem(itemName) || (IsMagicArrow(itemName) && CanUse(RG_FAIRY_BOW)));
@@ -467,7 +466,7 @@ namespace Logic {
(age == HasProjectileAge::Either && (Slingshot || Boomerang || Hookshot || Bow));
}
uint8_t GetDifficultyValueFromString(Option& glitchOption) {
uint8_t GetDifficultyValueFromString(Rando::Option& glitchOption) {
return 0;
}
@@ -484,11 +483,12 @@ namespace Logic {
}
bool CanDoGlitch(GlitchType glitch) {
// TODO: Uncomment when glitches are implemented
switch(glitch) {
case GlitchType::EquipSwapDins:
return ((IsAdult && HasItem(RG_DINS_FIRE)) || (IsChild && (HasItem(RG_STICKS) || HasItem(RG_DINS_FIRE)))) && GlitchEquipSwapDins;
return ((IsAdult && HasItem(RG_DINS_FIRE)) || (IsChild && (HasItem(RG_STICKS) || HasItem(RG_DINS_FIRE)))) && false;//GlitchEquipSwapDins;
case GlitchType::EquipSwap: // todo: add bunny hood to adult item equippable list and child trade item to child item equippable list
return ((IsAdult && (HasItem(RG_DINS_FIRE) || HasItem(RG_FARORES_WIND) || HasItem(RG_NAYRUS_LOVE))) || (IsChild && (HasItem(RG_STICKS) || HasItem(RG_FAIRY_SLINGSHOT) || HasItem(RG_BOOMERANG) || HasBottle || Nuts || Ocarina || HasItem(RG_LENS_OF_TRUTH) || HasExplosives || (MagicBean || MagicBeanPack) || HasItem(RG_DINS_FIRE) || HasItem(RG_FARORES_WIND) || HasItem(RG_NAYRUS_LOVE)))) && GlitchEquipSwap;
return ((IsAdult && (HasItem(RG_DINS_FIRE) || HasItem(RG_FARORES_WIND) || HasItem(RG_NAYRUS_LOVE))) || (IsChild && (HasItem(RG_STICKS) || HasItem(RG_FAIRY_SLINGSHOT) || HasItem(RG_BOOMERANG) || HasBottle || Nuts || Ocarina || HasItem(RG_LENS_OF_TRUTH) || HasExplosives || (MagicBean || MagicBeanPack) || HasItem(RG_DINS_FIRE) || HasItem(RG_FARORES_WIND) || HasItem(RG_NAYRUS_LOVE)))) && false;//GlitchEquipSwap;
}
//Shouldn't be reached
@@ -497,6 +497,7 @@ namespace Logic {
//Updates all logic helpers. Should be called whenever a non-helper is changed
void UpdateHelpers() {
auto ctx = Rando::Context::GetInstance();
NumBottles = ((NoBottles) ? 0 : (Bottles + ((DeliverLetter) ? 1 : 0)));
HasBottle = NumBottles >= 1;
Slingshot = (ProgressiveBulletBag >= 1) && (BuySeed || AmmoCanDrop);
@@ -515,7 +516,7 @@ namespace Logic {
AdultsWallet = ProgressiveWallet >= 1;
BiggoronSword = BiggoronSword || ProgressiveGiantKnife >= 2;
ScarecrowSong = ScarecrowSong || FreeScarecrow || (ChildScarecrow && AdultScarecrow);
ScarecrowSong = ScarecrowSong || ctx->GetOption(RSK_SKIP_SCARECROWS_SONG) || (ChildScarecrow && AdultScarecrow);
Scarecrow = Hookshot && CanPlay(ScarecrowSong);
DistantScarecrow = Longshot && CanPlay(ScarecrowSong);
@@ -532,28 +533,29 @@ namespace Logic {
Nuts = DekuNutDrop || Nuts;
Sticks = DekuStickDrop || Sticks;
Bugs = HasBottle && BugsAccess;
BlueFire = (HasBottle && BlueFireAccess) || (BlueFireArrows && CanUse(RG_ICE_ARROWS));
BlueFire = (HasBottle && BlueFireAccess) || (ctx->GetOption(RSK_BLUE_FIRE_ARROWS) && CanUse(RG_ICE_ARROWS));
Fish = HasBottle && FishAccess;
Fairy = HasBottle && FairyAccess;
FoundBombchus = (BombchuDrop || Bombchus || Bombchus5 || Bombchus10 || Bombchus20);
CanPlayBowling = (BombchusInLogic && FoundBombchus) || (!BombchusInLogic && BombBag);
HasBombchus = (BuyBombchus10 || BuyBombchus20 || (AmmoDrops.Is(AMMODROPS_BOMBCHU) && FoundBombchus));
CanPlayBowling = (ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && FoundBombchus) || (!ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && BombBag);
// TODO: Implement Ammo Drop Setting in place of bombchu drops
HasBombchus = (BuyBombchus10 || BuyBombchus20 || (ctx->GetOption(RSK_ENABLE_BOMBCHU_DROPS).Is(RO_AMMO_DROPS_ON_PLUS_BOMBCHU) && FoundBombchus));
HasExplosives = Bombs || (BombchusInLogic && HasBombchus);
HasExplosives = Bombs || (ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && HasBombchus);
HasBoots = IronBoots || HoverBoots;
//Unshuffled adult trade quest
Eyedrops = Eyedrops || (!ShuffleAdultTradeQuest && ClaimCheck);
EyeballFrog = EyeballFrog || (!ShuffleAdultTradeQuest && Eyedrops);
Prescription = Prescription || (!ShuffleAdultTradeQuest && EyeballFrog);
BrokenSword = BrokenSword || (!ShuffleAdultTradeQuest && Prescription);
PoachersSaw = PoachersSaw || (!ShuffleAdultTradeQuest && BrokenSword);
OddPoultice = OddPoultice || (!ShuffleAdultTradeQuest && PoachersSaw);
OddMushroom = OddMushroom || (!ShuffleAdultTradeQuest && OddPoultice);
Cojiro = Cojiro || (!ShuffleAdultTradeQuest && OddMushroom);
PocketEgg = PocketEgg || (!ShuffleAdultTradeQuest && Cojiro);
Eyedrops = Eyedrops || (!ctx->GetOption(RSK_SHUFFLE_ADULT_TRADE) && ClaimCheck);
EyeballFrog = EyeballFrog || (!ctx->GetOption(RSK_SHUFFLE_ADULT_TRADE) && Eyedrops);
Prescription = Prescription || (!ctx->GetOption(RSK_SHUFFLE_ADULT_TRADE) && EyeballFrog);
BrokenSword = BrokenSword || (!ctx->GetOption(RSK_SHUFFLE_ADULT_TRADE) && Prescription);
PoachersSaw = PoachersSaw || (!ctx->GetOption(RSK_SHUFFLE_ADULT_TRADE) && BrokenSword);
OddPoultice = OddPoultice || (!ctx->GetOption(RSK_SHUFFLE_ADULT_TRADE) && PoachersSaw);
OddMushroom = OddMushroom || (!ctx->GetOption(RSK_SHUFFLE_ADULT_TRADE) && OddPoultice);
Cojiro = Cojiro || (!ctx->GetOption(RSK_SHUFFLE_ADULT_TRADE) && OddMushroom);
PocketEgg = PocketEgg || (!ctx->GetOption(RSK_SHUFFLE_ADULT_TRADE) && Cojiro);
// IsChild = Age == AGE_CHILD;
// IsAdult = Age == AGE_ADULT;
@@ -566,34 +568,34 @@ namespace Logic {
CanStunDeku = CanAdultAttack || CanChildAttack || Nuts || HasShield;
CanCutShrubs = CanUse(RG_KOKIRI_SWORD) || CanUse(RG_BOOMERANG) || HasExplosives || CanUse(RG_MASTER_SWORD) || CanUse(RG_MEGATON_HAMMER) || CanUse(RG_BIGGORON_SWORD);
CanDive = ProgressiveScale >= 1;
CanLeaveForest = OpenForest.IsNot(OPENFOREST_CLOSED) || IsAdult || DekuTreeClear || ShuffleInteriorEntrances || ShuffleOverworldEntrances;
CanLeaveForest = ctx->GetOption(RSK_FOREST).IsNot(RO_FOREST_CLOSED) || IsAdult || DekuTreeClear || ctx->GetOption(RSK_SHUFFLE_INTERIOR_ENTRANCES) || ctx->GetOption(RSK_SHUFFLE_OVERWORLD_ENTRANCES);
CanPlantBugs = IsChild && Bugs;
CanRideEpona = IsAdult && Epona && CanPlay(EponasSong);
CanSummonGossipFairy = Ocarina && (ZeldasLullaby || EponasSong || SongOfTime || SunsSong);
CanSummonGossipFairyWithoutSuns = Ocarina && (ZeldasLullaby || EponasSong || SongOfTime);
Hearts = BaseHearts + HeartContainer + (PieceOfHeart >> 2);
EffectiveHealth = ((Hearts << (2 + DoubleDefense)) >> Multiplier) + ((Hearts << (2 + DoubleDefense)) % (1 << Multiplier) > 0); //Number of half heart hits to die, ranges from 1 to 160
FireTimer = CanUse(RG_GORON_TUNIC) ? 255 : (LogicFewerTunicRequirements) ? (Hearts * 8) : 0;
WaterTimer = CanUse(RG_ZORA_TUNIC) ? 255 : (LogicFewerTunicRequirements) ? (Hearts * 8) : 0;
FireTimer = CanUse(RG_GORON_TUNIC) ? 255 : (ctx->GetTrickOption(RT_FEWER_TUNIC_REQUIREMENTS)) ? (Hearts * 8) : 0;
WaterTimer = CanUse(RG_ZORA_TUNIC) ? 255 : (ctx->GetTrickOption(RT_FEWER_TUNIC_REQUIREMENTS)) ? (Hearts * 8) : 0;
NeedNayrusLove = (EffectiveHealth == 1);
CanSurviveDamage = !NeedNayrusLove || CanUse(RG_NAYRUS_LOVE);
CanTakeDamage = Fairy || CanSurviveDamage;
CanTakeDamageTwice = (Fairy && NumBottles >= 2) || ((EffectiveHealth == 2) && (CanUse(RG_NAYRUS_LOVE) || Fairy)) || (EffectiveHealth > 2);
//CanPlantBean = IsChild && (MagicBean || MagicBeanPack);
CanOpenBombGrotto = CanBlastOrSmash && (ShardOfAgony || LogicGrottosWithoutAgony);
CanOpenStormGrotto = CanPlay(SongOfStorms) && (ShardOfAgony || LogicGrottosWithoutAgony);
CanOpenBombGrotto = CanBlastOrSmash && (ShardOfAgony || ctx->GetTrickOption(RT_GROTTOS_WITHOUT_AGONY));
CanOpenStormGrotto = CanPlay(SongOfStorms) && (ShardOfAgony || ctx->GetTrickOption(RT_GROTTOS_WITHOUT_AGONY));
HookshotOrBoomerang = CanUse(RG_HOOKSHOT) || CanUse(RG_BOOMERANG);
CanGetNightTimeGS = (CanPlay(SunsSong) || !NightGSExpectSuns);
CanGetNightTimeGS = (CanPlay(SunsSong) || !ctx->GetOption(RSK_SKULLS_SUNS_SONG));
GuaranteeTradePath = ShuffleInteriorEntrances || ShuffleOverworldEntrances || LogicBiggoronBolero || CanBlastOrSmash || StopGCRollingGoronAsAdult;
GuaranteeTradePath = ctx->GetOption(RSK_SHUFFLE_INTERIOR_ENTRANCES) || ctx->GetOption(RSK_SHUFFLE_OVERWORLD_ENTRANCES) || ctx->GetTrickOption(RT_DMT_BOLERO_BIGGORON) || CanBlastOrSmash || StopGCRollingGoronAsAdult;
//GuaranteeHint = (hints == "Mask" && MaskofTruth) || (hints == "Agony") || (hints != "Mask" && hints != "Agony");
HasFireSource = CanUse(RG_DINS_FIRE) || CanUse(RG_FIRE_ARROWS);
HasFireSourceWithTorch = HasFireSource || CanUse(RG_STICKS);
//Gerudo Fortress
CanFinishGerudoFortress = (GerudoFortress.Is(GERUDOFORTRESS_NORMAL) && GerudoFortressKeys >= 4 && (CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD)) && (GerudoToken || CanUse(RG_FAIRY_BOW) || CanUse(RG_HOOKSHOT) || CanUse(RG_HOVER_BOOTS) || LogicGerudoKitchen)) ||
(GerudoFortress.Is(GERUDOFORTRESS_FAST) && GerudoFortressKeys >= 1 && (CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD))) ||
(GerudoFortress.IsNot(GERUDOFORTRESS_NORMAL) && GerudoFortress.IsNot(GERUDOFORTRESS_FAST));
CanFinishGerudoFortress = (ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_NORMAL) && GerudoFortressKeys >= 4 && (CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD)) && (GerudoToken || CanUse(RG_FAIRY_BOW) || CanUse(RG_HOOKSHOT) || CanUse(RG_HOVER_BOOTS) || ctx->GetTrickOption(RT_GF_KITCHEN))) ||
(ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_FAST) && GerudoFortressKeys >= 1 && (CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD))) ||
(ctx->GetOption(RSK_GERUDO_FORTRESS).IsNot(RO_GF_NORMAL) && ctx->GetOption(RSK_GERUDO_FORTRESS).IsNot(RO_GF_FAST));
HasShield = CanUse(RG_HYLIAN_SHIELD) || CanUse(RG_DEKU_SHIELD); //Mirror shield can't reflect attacks
CanShield = CanUse(RG_MIRROR_SHIELD) || HasShield;
@@ -611,25 +613,25 @@ namespace Logic {
DungeonCount = (DekuTreeClear ? 1:0) + (DodongosCavernClear ? 1:0) + (JabuJabusBellyClear ? 1:0) + (ForestTempleClear ? 1:0) + (FireTempleClear ? 1:0) + (WaterTempleClear ? 1:0) + (SpiritTempleClear ? 1:0) + (ShadowTempleClear ? 1:0);
HasAllStones = StoneCount == 3;
HasAllMedallions = MedallionCount == 6;
GregInBridgeLogic = BridgeRewardOptions.Is(BRIDGE_OPTION_GREG);
GregInLacsLogic = LACSRewardOptions.Is(LACS_OPTION_GREG);
GregInBridgeLogic = ctx->GetOption(RSK_BRIDGE_OPTIONS).Is(RO_BRIDGE_GREG);
GregInLacsLogic = ctx->GetOption(RSK_LACS_OPTIONS).Is(RO_LACS_GREG_REWARD);
CanBuildRainbowBridge = Bridge.Is(RAINBOWBRIDGE_OPEN) ||
(Bridge.Is(RAINBOWBRIDGE_VANILLA) && ShadowMedallion && SpiritMedallion && LightArrows) ||
(Bridge.Is(RAINBOWBRIDGE_STONES) && StoneCount + (Greg && GregInBridgeLogic ? 1 : 0) >= BridgeStoneCount.Value<uint8_t>()) ||
(Bridge.Is(RAINBOWBRIDGE_MEDALLIONS) && MedallionCount + (Greg && GregInBridgeLogic ? 1 : 0) >= BridgeMedallionCount.Value<uint8_t>()) ||
(Bridge.Is(RAINBOWBRIDGE_REWARDS) && StoneCount + MedallionCount + (Greg && GregInBridgeLogic ? 1 : 0) >= BridgeRewardCount.Value<uint8_t>()) ||
(Bridge.Is(RAINBOWBRIDGE_DUNGEONS) && DungeonCount + (Greg && GregInBridgeLogic ? 1 : 0) >= BridgeDungeonCount.Value<uint8_t>()) ||
(Bridge.Is(RAINBOWBRIDGE_TOKENS) && GoldSkulltulaTokens >= BridgeTokenCount.Value<uint8_t>()) ||
(Bridge.Is(RAINBOWBRIDGE_GREG) && Greg);
CanBuildRainbowBridge = ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_ALWAYS_OPEN) ||
(ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_VANILLA) && ShadowMedallion && SpiritMedallion && LightArrows) ||
(ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_STONES) && StoneCount + (Greg && GregInBridgeLogic ? 1 : 0) >= ctx->GetOption(RSK_RAINBOW_BRIDGE_STONE_COUNT).Value<uint8_t>()) ||
(ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_MEDALLIONS) && MedallionCount + (Greg && GregInBridgeLogic ? 1 : 0) >= ctx->GetOption(RSK_RAINBOW_BRIDGE_MEDALLION_COUNT).Value<uint8_t>()) ||
(ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_DUNGEON_REWARDS) && StoneCount + MedallionCount + (Greg && GregInBridgeLogic ? 1 : 0) >= ctx->GetOption(RSK_RAINBOW_BRIDGE_REWARD_COUNT).Value<uint8_t>()) ||
(ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_DUNGEONS) && DungeonCount + (Greg && GregInBridgeLogic ? 1 : 0) >= ctx->GetOption(RSK_RAINBOW_BRIDGE_DUNGEON_COUNT).Value<uint8_t>()) ||
(ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_TOKENS) && GoldSkulltulaTokens >= ctx->GetOption(RSK_RAINBOW_BRIDGE_TOKEN_COUNT).Value<uint8_t>()) ||
(ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_GREG) && Greg);
CanTriggerLACS = (LACSCondition == LACSCONDITION_VANILLA && ShadowMedallion && SpiritMedallion) ||
(LACSCondition == LACSCONDITION_STONES && StoneCount + (Greg && GregInLacsLogic ? 1 : 0) >= LACSStoneCount.Value<uint8_t>()) ||
(LACSCondition == LACSCONDITION_MEDALLIONS && MedallionCount + (Greg && GregInLacsLogic ? 1 : 0) >= LACSMedallionCount.Value<uint8_t>()) ||
(LACSCondition == LACSCONDITION_REWARDS && StoneCount + MedallionCount + (Greg && GregInLacsLogic ? 1 : 0) >= LACSRewardCount.Value<uint8_t>()) ||
(LACSCondition == LACSCONDITION_DUNGEONS && DungeonCount + (Greg && GregInLacsLogic ? 1 : 0) >= LACSDungeonCount.Value<uint8_t>()) ||
(LACSCondition == LACSCONDITION_TOKENS && GoldSkulltulaTokens >= LACSTokenCount.Value<uint8_t>());
CanCompleteTriforce = TriforcePieces >= TriforceHuntRequired.Value<uint8_t>();
CanTriggerLACS = (ctx->GetSettings()->LACSCondition() == RO_LACS_VANILLA && ShadowMedallion && SpiritMedallion) ||
(ctx->GetSettings()->LACSCondition() == RO_LACS_STONES && StoneCount + (Greg && GregInLacsLogic ? 1 : 0) >= ctx->GetOption(RSK_LACS_STONE_COUNT).Value<uint8_t>()) ||
(ctx->GetSettings()->LACSCondition() == RO_LACS_MEDALLIONS && MedallionCount + (Greg && GregInLacsLogic ? 1 : 0) >= ctx->GetOption(RSK_LACS_MEDALLION_COUNT).Value<uint8_t>()) ||
(ctx->GetSettings()->LACSCondition() == RO_LACS_REWARDS && StoneCount + MedallionCount + (Greg && GregInLacsLogic ? 1 : 0) >= ctx->GetOption(RSK_LACS_REWARD_COUNT).Value<uint8_t>()) ||
(ctx->GetSettings()->LACSCondition() == RO_LACS_DUNGEONS && DungeonCount + (Greg && GregInLacsLogic ? 1 : 0) >= ctx->GetOption(RSK_LACS_DUNGEON_COUNT).Value<uint8_t>()) ||
(ctx->GetSettings()->LACSCondition() == RO_LACS_TOKENS && GoldSkulltulaTokens >= ctx->GetOption(RSK_LACS_TOKEN_COUNT).Value<uint8_t>());
CanCompleteTriforce = TriforcePieces >= ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_REQUIRED).Value<uint8_t>();
}
bool SmallKeys(RandomizerRegion dungeon, uint8_t requiredAmount) {
@@ -730,9 +732,12 @@ namespace Logic {
//Reset All Logic to false
void LogicReset() {
auto ctx = Rando::Context::GetInstance();
//Settings-dependent variables
IsKeysanity = Keysanity.Is(KEYSANITY_ANYWHERE) || Keysanity.Is(KEYSANITY_OVERWORLD) || Keysanity.Is(KEYSANITY_ANY_DUNGEON);
AmmoCanDrop = AmmoDrops.IsNot(AMMODROPS_NONE);
IsKeysanity = ctx->GetOption(RSK_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_ANYWHERE) ||
ctx->GetOption(RSK_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_ANYWHERE) ||
ctx->GetOption(RSK_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_ANYWHERE);
AmmoCanDrop = /*AmmoDrops.IsNot(AMMODROPS_NONE) TODO: AmmoDrop setting*/ true;
//Child item logic
KokiriSword = false;
@@ -858,7 +863,7 @@ namespace Logic {
//Keys
ForestTempleKeys = 0;
//If not keysanity, start with 1 logical key to account for automatically unlocking the basement door in vanilla FiT
FireTempleKeys = IsKeysanity || Dungeon::FireTemple.IsMQ() ? 0 : 1;
FireTempleKeys = IsKeysanity || ctx->GetDungeon(Rando::FIRE_TEMPLE)->IsMQ() ? 0 : 1;
WaterTempleKeys = 0;
SpiritTempleKeys = 0;
ShadowTempleKeys = 0;
@@ -968,7 +973,7 @@ namespace Logic {
HasBoots = false;
IsChild = false;
IsAdult = false;
IsGlitched = Settings::Logic.Is(LOGIC_GLITCHED);
IsGlitched = ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_GLITCHED);
CanBlastOrSmash = false;
CanChildAttack = false;
CanChildDamage = false;
@@ -986,9 +991,9 @@ namespace Logic {
BigPoeKill = false;
HookshotOrBoomerang = false;
BaseHearts = StartingHearts.Value<uint8_t>() + 1;
BaseHearts = ctx->GetOption(RSK_STARTING_HEARTS).Value<uint8_t>() + 1;
Hearts = 0;
Multiplier = (DamageMultiplier.Value<uint8_t>() < 6) ? DamageMultiplier.Value<uint8_t>() : 10;
Multiplier = (ctx->GetOption(RSK_DAMAGE_MULTIPLIER).Value<uint8_t>() < 6) ? ctx->GetOption(RSK_DAMAGE_MULTIPLIER).Value<uint8_t>() : 10;
EffectiveHealth = 0;
FireTimer = 0;
WaterTimer = 0;
@@ -1020,7 +1025,7 @@ namespace Logic {
//Other
AtDay = false;
AtNight = false;
Age = Settings::ResolvedStartingAge;
Age = ctx->GetSettings()->ResolvedStartingAge();
//Events
ShowedMidoSwordAndShield = false;

View File

@@ -8,7 +8,6 @@
#include "menu.hpp"
#include "playthrough.hpp"
#include "randomizer.hpp"
#include "settings.hpp"
#include "spoiler_log.hpp"
#include "location_access.hpp"
#include <spdlog/spdlog.h>
@@ -19,11 +18,12 @@ namespace {
bool seedChanged;
uint16_t pastSeedLength;
std::vector<std::string> presetEntries;
Option* currentSetting;
Rando::Option* currentSetting;
} // namespace
std::string GenerateRandomizer(std::unordered_map<RandomizerSettingKey, uint8_t> cvarSettings, std::set<RandomizerCheck> excludedLocations, std::set<RandomizerTrick> enabledTricks,
std::string seedString) {
auto ctx = Rando::Context::GetInstance();
srand(time(NULL));
// if a blank seed was entered, make a random one
@@ -42,11 +42,11 @@ std::string GenerateRandomizer(std::unordered_map<RandomizerSettingKey, uint8_t>
return "";
}
Settings::seedString = seedString;
uint32_t seedHash = boost::hash_32<std::string>{}(Settings::seedString);
Settings::seed = seedHash & 0xFFFFFFFF;
ctx->GetSettings()->SetSeedString(seedString);
uint32_t seedHash = boost::hash_32<std::string>{}(ctx->GetSettings()->GetSeedString());
ctx->GetSettings()->SetSeed(seedHash & 0xFFFFFFFF);
int ret = Playthrough::Playthrough_Init(Settings::seed, cvarSettings, excludedLocations, enabledTricks);
int ret = Playthrough::Playthrough_Init(ctx->GetSettings()->GetSeed(), cvarSettings, excludedLocations, enabledTricks);
if (ret < 0) {
if (ret == -1) { // Failed to generate after 5 tries
printf("\n\nFailed to generate after 5 tries.\nPress B to go back to the menu.\nA different seed might be "
@@ -60,21 +60,21 @@ std::string GenerateRandomizer(std::unordered_map<RandomizerSettingKey, uint8_t>
}
// Restore settings that were set to a specific value for vanilla logic
if (Settings::Logic.Is(LOGIC_VANILLA)) {
for (Option* setting : Settings::vanillaLogicDefaults) {
if (ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_VANILLA)) {
for (Rando::Option* setting : ctx->GetSettings()->VanillaLogicDefaults) {
setting->RestoreDelayedOption();
}
Settings::Keysanity.RestoreDelayedOption();
ctx->GetOption(RSK_KEYSANITY).RestoreDelayedOption();
}
std::ostringstream fileNameStream;
for (int i = 0; i < Settings::hashIconIndexes.size(); i++) {
for (int i = 0; i < ctx->hashIconIndexes.size(); i++) {
if (i) {
fileNameStream << '-';
}
if (Settings::hashIconIndexes[i] < 10) {
if (ctx->hashIconIndexes[i] < 10) {
fileNameStream << '0';
}
fileNameStream << std::to_string(Settings::hashIconIndexes[i]);
fileNameStream << std::to_string(ctx->hashIconIndexes[i]);
}
std::string fileName = fileNameStream.str();
return "./Randomizer/" + fileName + ".json";

View File

@@ -8,6 +8,8 @@
#include "random.hpp"
#include "spoiler_log.hpp"
#include "soh/Enhancements/randomizer/randomizerTypes.h"
#include <variables.h>
#include "../option.h"
namespace Playthrough {
@@ -23,30 +25,29 @@ int Playthrough_Init(uint32_t seed, std::unordered_map<RandomizerSettingKey, uin
ctx->HintReset();
Areas::AccessReset();
Settings::UpdateSettings(cvarSettings, excludedLocations, enabledTricks);
ctx->GetSettings()->UpdateSettings(cvarSettings, excludedLocations, enabledTricks);
// once the settings have been finalized turn them into a string for hashing
std::string settingsStr;
for (Menu* menu : Settings::GetAllOptionMenus()) {
for (const Rando::OptionGroup& optionGroup : ctx->GetSettings()->GetOptionGroups()) {
// don't go through non-menus
if (menu->mode != OPTION_SUB_MENU) {
if (optionGroup.GetContainsType() != Rando::OptionGroupType::SUBGROUP) {
continue;
}
for (size_t i = 0; i < menu->settingsList->size(); i++) {
Option* setting = menu->settingsList->at(i);
if (setting->IsCategory(OptionCategory::Setting)) {
settingsStr += setting->GetSelectedOptionText();
for (Rando::Option* option : optionGroup.GetOptions()) {
if (option->IsCategory(Rando::OptionCategory::Setting)) {
settingsStr += option->GetSelectedOptionText();
}
}
}
uint32_t finalHash = boost::hash_32<std::string>{}(std::to_string(Settings::seed) + settingsStr);
uint32_t finalHash = boost::hash_32<std::string>{}(std::to_string(ctx->GetSettings()->GetSeed()) + settingsStr);
Random_Init(finalHash);
Settings::hash = std::to_string(finalHash);
ctx->GetSettings()->SetHash(std::to_string(finalHash));
Logic::UpdateHelpers();
if (Settings::Logic.Is(LOGIC_VANILLA)) {
if (ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_VANILLA)) {
VanillaFill(); // Just place items in their vanilla locations
} else { // Fill locations with logic
int ret = Fill();
@@ -58,7 +59,7 @@ int Playthrough_Init(uint32_t seed, std::unordered_map<RandomizerSettingKey, uin
GenerateHash();
WriteIngameSpoilerLog();
if (Settings::GenerateSpoilerLog) {
if (/*Settings::GenerateSpoilerLog TODO: do we ever not want to write a spoiler log?*/ true) {
// write logs
printf("\x1b[11;10HWriting Spoiler Log...");
if (SpoilerLog_Write(cvarSettings[RSK_LANGUAGE])) {
@@ -86,14 +87,15 @@ int Playthrough_Init(uint32_t seed, std::unordered_map<RandomizerSettingKey, uin
// used for generating a lot of seeds at once
int Playthrough_Repeat(std::unordered_map<RandomizerSettingKey, uint8_t> cvarSettings, std::set<RandomizerCheck> excludedLocations, std::set<RandomizerTrick> enabledTricks, int count /*= 1*/) {
printf("\x1b[0;0HGENERATING %d SEEDS", count);
auto ctx = Rando::Context::GetInstance();
uint32_t repeatedSeed = 0;
for (int i = 0; i < count; i++) {
Settings::seedString = std::to_string(rand() % 0xFFFFFFFF);
repeatedSeed = boost::hash_32<std::string>{}(Settings::seedString);
Settings::seed = repeatedSeed % 0xFFFFFFFF;
ctx->GetSettings()->SetSeedString(std::to_string(rand() % 0xFFFFFFFF));
repeatedSeed = boost::hash_32<std::string>{}(ctx->GetSettings()->GetSeedString());
ctx->GetSettings()->SetSeed(repeatedSeed % 0xFFFFFFFF);
//CitraPrint("testing seed: " + std::to_string(Settings::seed));
ClearProgress();
Playthrough_Init(Settings::seed, cvarSettings, excludedLocations, enabledTricks);
Playthrough_Init(ctx->GetSettings()->GetSeed(), cvarSettings, excludedLocations, enabledTricks);
printf("\x1b[15;15HSeeds Generated: %d\n", i + 1);
}

View File

@@ -4,6 +4,7 @@
#include "../item_location.h"
#include "location_access.hpp"
#include "rando_main.hpp"
#include "../context.h"
// #include <soh/Enhancements/randomizer.h>
#include <libultraship/bridge.h>
#include <Context.h>
@@ -17,9 +18,10 @@ void RandoMain::GenerateRando(std::unordered_map<RandomizerSettingKey, u8> cvarS
// CVarSetString("gLoadedPreset", settingsFileName.c_str());
std::string fileName = LUS::Context::GetPathRelativeToAppDirectory(GenerateRandomizer(cvarSettings, excludedLocations, enabledTricks, seedString).c_str());
CVarSetString("gSpoilerLog", fileName.c_str());
CVarSave();
CVarLoad();
CVarSetInteger("gNewSeedGenerated", 1);
Rando::Context::GetInstance()->SetSeedGenerated();
Rando::Context::GetInstance()->SetSpoilerLoaded(false);
Rando::Context::GetInstance()->SetPlandoLoaded(false);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,6 @@
#include <map>
#include "z64item.h"
using namespace Settings;
std::vector<ItemAndPrice> NonShopItems = {};
@@ -134,13 +133,14 @@ int GetPriceFromMax(int max) {
// Get random price out of available "affordable prices", or just return 10 if Starter wallet is selected (no need to randomly select
// from a single element)
int GetPriceAffordable() {
if (Settings::ShopsanityPrices.Is(RO_SHOPSANITY_PRICE_STARTER)) {
auto ctx = Rando::Context::GetInstance();
if (ctx->GetOption(RSK_SHOPSANITY_PRICES).Is(RO_SHOPSANITY_PRICE_STARTER)) {
return 10;
}
static const std::vector<int> affordablePrices = { 10, 105, 205, 505 };
std::vector<int> priceList;
uint8_t maxElements = Settings::ShopsanityPrices.Value<uint8_t>();
uint8_t maxElements = ctx->GetOption(RSK_SHOPSANITY_PRICES).Value<uint8_t>();
for (int i = 0; i < maxElements; i++) {
priceList.push_back(affordablePrices.at(i));
}
@@ -148,8 +148,9 @@ int GetPriceAffordable() {
}
int GetRandomShopPrice() {
auto ctx = Rando::Context::GetInstance();
// If Shopsanity prices aren't Balanced, but Affordable is on, don't GetPriceFromMax
if (Settings::ShopsanityPricesAffordable.Is(true) && Settings::ShopsanityPrices.IsNot(RO_SHOPSANITY_PRICE_BALANCED)) {
if (ctx->GetOption(RSK_SHOPSANITY_PRICES_AFFORDABLE).Is(true) && ctx->GetOption(RSK_SHOPSANITY_PRICES).IsNot(RO_SHOPSANITY_PRICE_BALANCED)) {
return GetPriceAffordable();
}
@@ -157,16 +158,16 @@ int GetRandomShopPrice() {
int max = 0;
// check settings for a wallet tier selection and set max amount as method for setting true randomization
if(Settings::ShopsanityPrices.Is(RO_SHOPSANITY_PRICE_STARTER)) {
if(ctx->GetOption(RSK_SHOPSANITY_PRICES).Is(RO_SHOPSANITY_PRICE_STARTER)) {
max = 19; // 95/5
}
else if (Settings::ShopsanityPrices.Is(RO_SHOPSANITY_PRICE_ADULT)) {
else if (ctx->GetOption(RSK_SHOPSANITY_PRICES).Is(RO_SHOPSANITY_PRICE_ADULT)) {
max = 40; // 200/5
}
else if (Settings::ShopsanityPrices.Is(RO_SHOPSANITY_PRICE_GIANT)) {
else if (ctx->GetOption(RSK_SHOPSANITY_PRICES).Is(RO_SHOPSANITY_PRICE_GIANT)) {
max = 100; // 500/5
}
else if (Settings::ShopsanityPrices.Is(RO_SHOPSANITY_PRICE_TYCOON)) {
else if (ctx->GetOption(RSK_SHOPSANITY_PRICES).Is(RO_SHOPSANITY_PRICE_TYCOON)) {
max = 199; // 995/5
}
if (max != 0) {
@@ -205,13 +206,14 @@ int16_t GetRandomScrubPrice() {
//Get 1 to 4, or a random number from 1-4 depending on shopsanity setting
int GetShopsanityReplaceAmount() {
if (Settings::Shopsanity.Is(SHOPSANITY_ONE)) {
auto ctx = Rando::Context::GetInstance();
if (ctx->GetOption(RSK_SHOPSANITY).Is(RO_SHOPSANITY_ONE_ITEM)) {
return 1;
} else if (Settings::Shopsanity.Is(SHOPSANITY_TWO)) {
} else if (ctx->GetOption(RSK_SHOPSANITY).Is(RO_SHOPSANITY_TWO_ITEMS)) {
return 2;
} else if (Settings::Shopsanity.Is(SHOPSANITY_THREE)) {
} else if (ctx->GetOption(RSK_SHOPSANITY).Is(RO_SHOPSANITY_THREE_ITEMS)) {
return 3;
} else if (Settings::Shopsanity.Is(SHOPSANITY_FOUR)) {
} else if (ctx->GetOption(RSK_SHOPSANITY).Is(RO_SHOPSANITY_FOUR_ITEMS)) {
return 4;
} else { //Random, get number in [1, 4]
return Random(1, 5);
@@ -220,195 +222,195 @@ int GetShopsanityReplaceAmount() {
//Initialize the table of trick names with an easy, medium, and hard name for each language
void InitTrickNames() {
trickNameTable[GI_SWORD_KOKIRI] = {
trickNameTable[RG_KOKIRI_SWORD] = {
Text{"Korok Sword", "Épée Korok", "Espada Korok"},
Text{"Hero's Sword", "Épée du Héros", "Espada del héroe"},
Text{"Razor Sword", "Lame Rasoir", "Espada de esmeril"}};
trickNameTable[0xE0] = { //Master Sword without the GI enum
trickNameTable[RG_MASTER_SWORD] = { //Master Sword without the GI enum
Text{"Goddess Sword", "Épée de la déesse", "Espada Divina"},
Text{"Gilded Sword", "Excalibur", "Espada de los Sabios"},
Text{"Magical Sword", "Lame dorée", "Fay"}};
trickNameTable[GI_SWORD_KNIFE] = {
trickNameTable[RG_GIANTS_KNIFE] = {
Text{"Medigoron's Sword", "l'Épée de Medigoron", "La espada de Medigoron"},
Text{"Razor Sword", "Lame Rasoir", "Espada de esmeril"},
Text{"Royal Claymore", "Claymore Royale", "Royal Claymore"}};
trickNameTable[GI_SWORD_BGS] = {
trickNameTable[RG_BIGGORON_SWORD] = {
Text{"Power Sword", "Épée de Puissance", "Espada de poder"},
Text{"Fierce Deity Sword", "Épée du dieu démon", "Espada de la Fiera Deidad"},
Text{"Tempered Sword", "Épée de Légende Nv.2", "Espada Maestra mejorada"},
Text{"Biggoron's Knife", "Lame de Grogoron", "Daga de Biggoron"}};
trickNameTable[GI_SHIELD_DEKU] = {
trickNameTable[RG_DEKU_SHIELD] = {
Text{"Boko Shield", "Bouclier Boko", "Escudo Boko"},
Text{"Ordon Shield", "Bouclier de Toal", "Escudo de Ordon"},
Text{"Wooden Shield", "Bouclier de Bois", "Escudo de madera"}};
trickNameTable[GI_SHIELD_HYLIAN] = {
trickNameTable[RG_HYLIAN_SHIELD] = {
Text{"Hyrule Shield", "Bouclier d'Hyrule", "Escudo Hylian"},
Text{"Goddess Shield", "Bouclier Sacré", "Escudo Divino"},
Text{"Hero's Shield", "Bouclier du Héros", "Escudo del héroe"}};
trickNameTable[GI_SHIELD_MIRROR] = {
trickNameTable[RG_MIRROR_SHIELD] = {
Text{"Magic Mirror", "Miroir Magique", "Escudo mágico"},
Text{"Magical Shield", "Bouclier Magique", "Escudo arcano"},
Text{"Mirror of Twilight", "Miroir des Ombres", "Espejo del Crepúsculo"}};
trickNameTable[GI_TUNIC_GORON] = {
trickNameTable[RG_GORON_TUNIC] = {
Text{"Gerudo Top", "Tunique Gerudo", "Pechera gerudo"},
Text{"Flamebreaker Armor", "Armure de Pierre", " Armadura ignífuga"},
Text{"Red Mail", "Habits Rouges", "Ropas rojas"}};
trickNameTable[GI_TUNIC_ZORA] = {
trickNameTable[RG_ZORA_TUNIC] = {
Text{"Rito Tunic", "Tunique Rito", "Sayo rito"},
Text{"Mermaid Suit", "Costume de sirène", "Costume de sirène"},
Text{"Zora Armor", "Armure Zora", "Túnica Zora"},
Text{"Blue Mail", "Habits Bleus", "Ropas azules"}};
trickNameTable[GI_BOOTS_IRON] = {
trickNameTable[RG_IRON_BOOTS] = {
Text{"Iron Hoofs", "Patins de Plomb", "Botas férreas"},
Text{"Snow Boots", "Bottes de Neige", "Botas de nieve"},
Text{"Red Boots", "Bottes rouges", "Botas rojas"},
Text{"Zora Greaves", "Bottes Zora", "Zora Greaves"},
Text{"Boots of Power", "Bottes de Puissance", "Botas de plomo"}};
trickNameTable[GI_BOOTS_HOVER] = {
trickNameTable[RG_HOVER_BOOTS] = {
Text{"Hover Hoofs", "Patins des airs", "Botas flotadoras"},
Text{"Golden Boots", "Bottes dorées", "Botas de Oro"},
Text{"Pegasus Boots", "Bottes pégase", "Botas de Pegaso"},
Text{"Boots of Speed", "Bottes de vitesse", "Botas del desierto"}};
trickNameTable[GI_WEIRD_EGG] = {
trickNameTable[RG_WEIRD_EGG] = {
Text{"Poached Egg", "Oeuf à la coque", "Huevo pasado"},
Text{"Lon Lon Egg", "Oeuf Lon Lon", "Huevo Lon Lon"},
Text{"Zora Egg", "Oeuf Zora", "Huevo Zora"}};
trickNameTable[GI_LETTER_ZELDA] = {
trickNameTable[RG_ZELDAS_LETTER] = {
Text{"Ruto's Letter", "Lettre de Ruto", "Carta de Ruto"},
Text{"Royal Letter", "Lettre Eoyale", "Carta para Kafei"},
Text{"Zelda's Business Card", "Carte d'affaires de Zelda", "Carta"},
Text{"Letter to Kafei", "Lettre pour Kafei", "Carta para Kafei "},
Text{"Goat's Letter", "Lettre de la Chèvre", "Carta de la Cabra"},
Text{"Maggie's Letter", "Lettre de Maggy", "Carta de Dolores"}};
trickNameTable[GI_BOOMERANG] = {
trickNameTable[RG_BOOMERANG] = {
Text{"Banana", "Banane", "Plátano"},
Text{"Prank Fetch Toy", "Inséparable Bâtonnet", "Bumerang"},
Text{"Gale Boomerang", "Boomerang Tornade", "Bumerán tornado"},
Text{"Magic Boomerang", "Boomerang Magique", "Bumerán mágico"}};
trickNameTable[GI_LENS] = {
trickNameTable[RG_LENS_OF_TRUTH] = {
Text{"Sheikah-leidoscope", "Sheikah-léidoscope", "Monóculo de la Verdad"},
Text{"Sheikah Sensor", "Sonar Sheikah", "Sensor Sheikah"},
Text{"Crystal of Vision", "Cristal de Vision", "Cristal de Visión"},
Text{"Magnifying Lens", "Loupe", "Lente Aumentadora"}};
trickNameTable[GI_HAMMER] = {
trickNameTable[RG_MEGATON_HAMMER] = {
Text{"Goron Gavel", "Masse Perforatrice", "Mazo Goron"},
Text{"Magic Hammer", "Marteau Magique", "Martillo mágico"},
Text{"Skull Hammer", "Maillet Ressort", "Martillo de hierro"}};
trickNameTable[GI_STONE_OF_AGONY] = {
trickNameTable[RG_STONE_OF_AGONY] = {
Text{"Cave Charm", "Charme de grotte", "Amuleto de la cueva"},
Text{"Stone of Agahnim", "Fragment d'Agahnim", "Piedra de Agahnim"},
Text{"Shard of Agony", "Fragment de Souffrance", "Piedra de la Agonía"},
Text{"Pirate's Charm", "Pierre de Pirate", "Amuleto Pirata"}};
trickNameTable[GI_DINS_FIRE] = {
trickNameTable[RG_DINS_FIRE] = {
Text{"Eldin's Fire", "Feu d'Eldin", "Fuego de Eldin"},
Text{"Din's Blaze", "Flamme de Din", "Poder de Din"},
Text{"Magic Lantern", "Lanterne Magique", "Linterna mágica"},
Text{"Ether Medallion", "Médaillon d'Éther", "Medallón de Tesoro"},
Text{"Bombos Medallion", "Médaillon des Flammes", "Medallón del Temblor"}};
trickNameTable[GI_FARORES_WIND] = {
trickNameTable[RG_FARORES_WIND] = {
Text{"Faron's Wind", "Vent de Firone", "Viento de Farone"},
Text{"Farore's Windfall", "Zéphyr de Farore", "Valor de Farore"},
Text{"Tingle Air", "Tingle Air", "Tingle de aire"},
Text{"Travel Medallion", "Amulette de téléportation", "Medallón Maligno"},
Text{"Irene's Taxi", "Le taxi d'Aëline", "El taxi de Airín"}};
trickNameTable[GI_NAYRUS_LOVE] = {
trickNameTable[RG_NAYRUS_LOVE] = {
Text{"Lanayru's Love", "Amour de Lanelle", "Amor de Lanayru"},
Text{"Nayru's Passion", "Passion de Nayru", "Sabiduría de Nayru"},
Text{"Tingle Shield", "Bouclier Tingle", "Escudo de hormigueo"},
Text{"Shield Spell", "Bouclier Magique", "Hechizo de Protección"},
Text{"Magic Armor", "Armure Magique", "Armadura mágica"}};
trickNameTable[GI_ARROW_FIRE] = {
trickNameTable[RG_FIRE_ARROWS] = {
Text{"Fire Rod", "Baguette de feu", "Cetro de fuego"},
Text{"Bomb Arrow", "Flèche-Bombe", "Flecha bomba"},
Text{"Red Candle", "Bougie Rouge", "Vela roja"}};
trickNameTable[GI_ARROW_ICE] = {
trickNameTable[RG_ICE_ARROWS] = {
Text{"Ice Rod", "Baguette des Glaces", "Cetro de Hielo"},
Text{"Ancient Arrow", "Flèche Archéonique", "Flecha ancestral"},
Text{"Ice Trap Arrow", "Flèche de Piège de Glace", "Cetro de hielo"}};
trickNameTable[GI_ARROW_LIGHT] = {
trickNameTable[RG_LIGHT_ARROWS] = {
Text{"Wind Arrow", "Flèche de Vent", "Flecha del Viento"},
Text{"Wand of Gamelon", "Baguette de Gamelon", "Varita de Gamelón"},
Text{"Shock Arrow", "Flèches Électriques", "Flecha eléctrica"},
Text{"Silver Arrow", "Flèches d'Argent", "Flecha de plata"}};
trickNameTable[GI_GERUDO_CARD] = {
trickNameTable[RG_GERUDO_MEMBERSHIP_CARD] = {
Text{"Desert Title Deed", "Abonnement Gerudo", "Escritura del desierto"},
Text{"Sickle Moon Flag", "Drapeau du croissant de lune", "Bandera de la Luna Creciente"},
Text{"Complimentary ID", "Bon de félicitation", "Cupón especial"},
Text{"Gerudo's Card", "Carte Goron", "Tóken Gerudo"},
Text{"Gerudo's Membership Card", "Autographe de Nabooru", "Tarjeta Gerudo"}};
trickNameTable[0xC9] = {
trickNameTable[RG_MAGIC_BEAN_PACK] = {
Text{"Funky Bean Pack", "Paquet de Fèves Magiques", "Lote de frijoles mágicos"},
Text{"Grapple Berries", "Baies de grappin", "Bayas de garfio"},
Text{"Crenel Bean Pack", "Paquet de Haricots Gonggle", "Lote de alubias mágicas"},
Text{"Mystical Seed Pack", "Pack de graines mystiques", "Paquete de semillas místicas"}};
trickNameTable[0xB8] = {
trickNameTable[RG_DOUBLE_DEFENSE] = {
Text{"Diamond Hearts", "Coeurs de Diamant", "Contenedor de diamante"},
Text{"Double Damage", "Double Souffrance", "Doble daño receptivo"},
Text{"Quadruple Defence", "Quadruple Défence", "Defensa cuádruple"}};
trickNameTable[GI_POCKET_EGG] = {
trickNameTable[RG_POCKET_EGG] = {
Text{"Arpagos Egg", "Oeuf d'Arpagos", "Huevo de Arpagos"},
Text{"Lon Lon Egg", "oeuf Lon Lon", "Huevo Lon Lon"},
Text{"Zora Egg", "oeuf Zora", "Huevo del Pez Viento"}};
trickNameTable[GI_POCKET_CUCCO] = {
trickNameTable[RG_POCKET_EGG] = {
Text{"D.I.Y. Alarm Clock", "Réveille-matin improvisé", "Alarma emplumada portátil"},
Text{"Kakariko Cucco", "Cocotte Cocorico", "Cuco de Kakariko"},
Text{"Hatched Cucco", "Cocotte éclose", "Pollo de bolsillo"}};
trickNameTable[GI_COJIRO] = {
trickNameTable[RG_COJIRO] = {
Text{"Blucco", "Chair-Qui-Poule", "Cucazul"},
Text{"Piyoko", "Piyoko", "Piyoko"},
Text{"Dark Cucco", "Cocotte Sombre", "Cucco oscuro"},
Text{"Grog's Cucco", "Cocotte de Grog", "Cuco de Grog"}};
trickNameTable[GI_ODD_MUSHROOM] = {
trickNameTable[RG_ODD_MUSHROOM] = {
Text{"Magic Mushroom", "Champignon magique", "Champiñón mágico"},
Text{"Endura Shroom", "Champi Vigueur", "Champiñón del bosque"},
Text{"Sleepy Toadstool", "Crapaud Fatigué", "Seta durmiente"},
Text{"Mushroom", "Champignon", "Seta"}};
trickNameTable[GI_ODD_POTION] = {
trickNameTable[RG_ODD_POTION] = {
Text{"Odd Medicine", "Élixir suspect", "Poción rara"},
Text{"Granny's Poultice", "Mixture de Granny", "Medicina de la abuela"},
Text{"Mushroom Poultice", "Mixture de champignon", "Medicina de champiñones"},
Text{"Secret Medicine", "Médicament", "Pócima secreta"},
Text{"Mushroom Spores", "Spores de Champignons", "Esporas de hongos"},
Text{"Hanyu Spore", "Hanyu Spore", "Espora Hanyu"}};
trickNameTable[GI_SAW] = {
trickNameTable[RG_POACHERS_SAW] = {
Text{"Carpenter's Saw", "Scie du charpentier", "Sierra del carpintero"},
Text{"Poacher's Sword", "Hache du chasseur", "Espada del capataz"},
Text{"Ancient Bladesaw", "Longue Épée Archéonique", "Mandoble ancestral"},
Text{"Woodcutter's Axe", "Hache du Bûcheron", "Hacha de leñador"},
Text{"Grog's Saw", "Scie de Grog", "Sierra del Cazador Furtivo"}};
trickNameTable[GI_SWORD_BROKEN] = {
trickNameTable[RG_BROKEN_SWORD] = {
Text{"Broken Biggoron's Sword", "Épée brisée de Grogoron", "Espada de Biggoron rota"},
Text{"Broken Giant's Knife", "Lame des Géants brisée", "Daga gigante rota"},
Text{"Broken Noble Sword", "Épée noble brisée", "Espada noble rota"},
Text{"Broken Picori Blade", "Épée Minish brisée", "Espada minish rota"},
Text{"Decayed Master Sword", "Épée de légende pourrie", "Espada decadente de leyenda"}};
trickNameTable[GI_PRESCRIPTION] = {
trickNameTable[RG_PRESCRIPTION] = {
Text{"Biggoron's Prescription", "Ordonnance de Grogoron", "Receta de Biggoron"},
Text{"Eyedrop Prescription", "Ordonnance de gouttes", "Receta ocular"},
Text{"Urgent Prescription", "Ordonnance urgente", "Prescripción"},
Text{"Swordsman's Scroll", "Précis d'escrime", "Esgrimidorium"},
Text{"Portrait of Oren", "Portrait d'Orlène", "Retrato de Oren"},
Text{"Letter to King Zora", "Lettre au roi Zora", "Carta al Rey Zora"}};
trickNameTable[GI_FROG] = {
trickNameTable[RG_EYEBALL_FROG] = {
Text{"Don Gero", "Don Gero", "Don Gero"},
Text{"Hot-Footed Frog", "Grenouille à pieds chauds", "Rana de patas calientes"},
Text{"Lost Swordsmith", "Forgeron perdu", "Espadachín perdido"},
Text{"Eyedrop Frog", "Grenouille-qui-louche", "Globo Ocular de Rana"}};
trickNameTable[GI_EYEDROPS] = {
trickNameTable[RG_EYEDROPS] = {
Text{"Biggoron's Eyedrops", "Gouttes de Grogoron", "Gotas de Biggoron"},
Text{"Hyrule's Finest Eyedrops", "Eau du Lac Hylia", "Gotas oculares"},
Text{"Moon's Tear", "Larme de Lune", "Lágrima de Luna"},
Text{"Engine Grease", "Graisse moteur", "Grasa del motor"},
Text{"Zora Perfume", "Parfum Zora", "Perfume Zora"}};
trickNameTable[GI_CLAIM_CHECK] = {
trickNameTable[RG_CLAIM_CHECK] = {
Text{"Clay Check", "Certificat Grogoron", "Comprobante de Reclamación"},
Text{"Ancient Tablet", "Stèle ancienne", "Litografía arcana"},
Text{"Sheikah Slate", "Tablette Sheikah", "Piedra Sheikah"},
Text{"Cyclone Slate", "Ardoise des tornades", "Pizarra de los Torbellinos"}};
trickNameTable[GI_SKULL_TOKEN] = {
trickNameTable[RG_GOLD_SKULLTULA_TOKEN] = {
Text{"Skulltula Token", "Bon de Skulltula dorée", "Símbolo de Skulltula"},
Text{"Golden Skulltula Spirit", "Pièce de Skulltula dorée", "Tóken de Skulltula Dorada"},
Text{"Gold Walltula Token", "Jeton de Walltula dorée", "Skulltula dorada"},
@@ -416,75 +418,75 @@ void InitTrickNames() {
Text{"Gratitude Crystal", "Cristal de gratitude", "Gema de gratitud"},
Text{"Korok Seed", "Noix korogu", "Semilla de kolog"}};
trickNameTable[0x80] = {
trickNameTable[RG_PROGRESSIVE_HOOKSHOT] = {
Text{"Progressive Grappling Hook", "Lance-chaîne (prog.)", "Garra progresiva"},
Text{"Progressive Clawshot", "Grappin-griffe (prog.)", "Zarpa progresiva"},
Text{"Progressive Gripshot", "Grappince (prog.)", "Enganchador progresivo"},
Text{"Progressive Rope", "Corde (prog.)", "Cuerda progresivo"}};
trickNameTable[0x81] = {
trickNameTable[RG_PROGRESSIVE_STRENGTH] = {
Text{"Power Glove", "Gant de Puissance (prog.)", "Guanteletes progresivos"},
Text{"Power Bracelet", "Bracelet de Force (prog.)", "Brasaletes progresivos"},
Text{"Magic Bracelet", "Bracelet Magique (prog.)", "Manoplas progresivas"}};
trickNameTable[0x82] = {
trickNameTable[RG_PROGRESSIVE_BOMB_BAG] = {
Text{"Progressive Bomb Capacity", "Capacité de bombes (prog.)", "Mayor capacidad de bombas"},
Text{"Progressive Bomb Pack", "Paquet de bombes (prog.)", "Zurrón de bombas progresivo"},
Text{"Progressive Bomb Box", "Boîte à bombes (prog.)", "Bolsa de bombas progresiva"},
Text{"Progressive Blast Mask", "Masque d'Explosion (prog.)", "Máscara explosiva progresiva"},
Text{"Progressive Powder Kegs", "Baril de Poudre (prog.)", "Barril de polvo progresivo"},
Text{"Progressive Remote Bombs", "Bombes à distance (prog.)", "Bombas remotas progresivas"}};
trickNameTable[0x83] = {
trickNameTable[RG_PROGRESSIVE_BOW] = {
Text{"Progressive Arrow Capacity", "Capacité de flèches (prog.)", "Mayor capacidad de flechas"},
Text{"Progressive Hero's Bow", "Arc du héros (prog.)", "Arco del héroe progresivo"},
Text{"Progressive Arrow Holder", "Arbalète (prog.)", "Ballesta progresiva"},
Text{"Progressive Crossbow", "Arbalète (prog.)", "Ballesta progresiva"},
Text{"Progressive Sacred Bow", "Arc sacré (prog)", "Arco Sagrado Progresivo"},
Text{"Progressive Lynel Bow", "Arc de Lynel (prog.)", "Arco de centaleón Progresivo"}};
trickNameTable[0x84] = {
trickNameTable[RG_PROGRESSIVE_SLINGSHOT] = {
Text{"Progressive Seed Capacity", "Capacité de graines (prog.)", "Mayor capacidad de semillas"},
Text{"Progressive Catapult", "Catapulte (prog.)", "Catapulta progresiva"},
Text{"Progressive Scattershot", "Lance-Pierre rafale (prog.)", "Resortera múltiple progresiva"},
Text{"Progressive Seed Launcher", "Lanceur de semences (prog.)", "Lanzador de semillas progresivo"},
Text{"Progressive Seed Satchel", "Sac de graines (prog.)", "Bolsa de semillas progresiva"}};
trickNameTable[0x85] = {
trickNameTable[RG_PROGRESSIVE_WALLET] = {
Text{"Progressive Rupee Capacity", "Capacité de rubis (prog.)", "Mayor capacidad de rupias"},
Text{"Progressive Purse", "Sacoche (prog.)", "Cartera de rupias progresiva"},
Text{"Progressive Rupee Bag", "Sac à rubis (prog.)", "Zurrón de rupias progresivo"},
Text{"Progressive Rupoor Capacity", "Capacité de Roupir (prog.)", "Capacidad progresiva Rupobre"},
Text{"Progressive Spoils Bag", "Sac à Butin (prog.)", "Bolsa de trofeos progresiva"},
Text{"Progressive Ruby Bag", "Capacité du sac Ruby (prog.)", "Bolso Ruby progresivo"}};
trickNameTable[0x86] = {
trickNameTable[RG_PROGRESSIVE_SCALE] = {
Text{"Progressive Flippers", "Palmes de Zora (prog.)", "Aletas de zora progresiva"},
Text{"Progressive Dragon's Scale", "Écaille du dragon d'eau (prog.)", "Escama dragón acuático progresiva"},
Text{"Progressive Diving Ability", "Plongée (prog.)", "Buceo progresivo"},
Text{"Progressive Pearl", "Perle (prog.)", "Perla progresiva"},
Text{"Progressive Scute", "Bulle (prog.)", "Fragmento Zora progresivo"}};
trickNameTable[0x87] = {
trickNameTable[RG_PROGRESSIVE_NUT_UPGRADE] = {
Text{"Progressive Nut Pack", "Paquet de noix (prog.)", "Mayor capacidad de semillas"},
Text{"Progressive Bait Bag", "Sac à Appâts (prog.)", "Bolsa de cebo progresiva"},
Text{"Progressive Pear Capacity", "Capacité de poire (prog.)", "Capacidad progresiva de pera"},
Text{"Progressive Nut Bag", "Sac de noix (prog.)", "Bolsa de nueces progresiva"},
Text{"Progressive Husk Capacity", "Capacité de noisettes (prog.)", "Mayor capacidad de castañas"}};
trickNameTable[0x88] = {
trickNameTable[RG_PROGRESSIVE_STICK_UPGRADE] = {
Text{"Progressive Stick Bag", "Sac de bâtons (prog.)", "Mayor capacidad de ramas deku"},
Text{"Progressive Stick Pack", "Paquet de bâtons Mojo (prog.)", "Mayor capacidad de bastones"},
Text{"Progressive Branch Capacity", "Capacité de la succursale (prog.)", "Capacidad progresiva de la sucursal"},
Text{"Progressive Rod Capacity", "Capacité de tiges (prog.)", "Mayor capacidad de cetros deku"}};
trickNameTable[0x89] = {
trickNameTable[RG_PROGRESSIVE_BOMBCHUS] = {
Text{"Progressive Bomblings", "Bombinsectes (prog.)", "Bombinsectos progresivos"},
Text{"Progressive Sentrobe Bombs", "Bombe de Sphérodrone (prog.)", "Bomba de helicobot progresivo"},
Text{"Progressive Bomb-ombs", "Bombe Soldat (prog.)", "Soldado bomba progresivo"},
Text{"Progressive Missiles", "Missiles (prog.)", "Misiles progresivos"},
Text{"Progressive Bombchu Bag", "Sac à Bombchu (prog.)", "Bombachus progresivos"}};
trickNameTable[0x8A] = {
trickNameTable[RG_PROGRESSIVE_MAGIC_METER] = {
Text{"Progressive Stamina Meter", "Jauge d'endurance (prog.)", "Medidor de vigor progresivo"},
Text{"Progressive Energy Gauge", "Jauge d'énergie (prog.)", "Medidor de energía progresivo"},
Text{"Progressive Magic Powder", "Poudre magique (prog.)", "Medidor de carga progresivo"}};
trickNameTable[0x8B] = {
trickNameTable[RG_PROGRESSIVE_OCARINA] = {
Text{"Progressive Memento", "Souvenir (prog.)", "Silbato progresivo"},
Text{"Progressive Whistle", "Siffler (prog.)", "Silbido progresivo"},
Text{"Progressive Flute", "Flûte (prog.)", "Flauta progresiva"},
Text{"Progressive Recorder", "Harmonica (prog.)", "Armónica progresiva"}};
trickNameTable[0xD4] = {
trickNameTable[RG_PROGRESSIVE_GORONSWORD] = {
Text{"Progressive Titan Blade", "Lame des Titans (prog.)", "Hoja del Titán progresiva"},
Text{"Progressive Goron Knife", "Lame Goron (prog.)", "Daga Goron progresiva"},
Text{"Progressive Giant Sword", "Épée géante (prog.)", "Espada gigante progresiva"},
@@ -492,212 +494,212 @@ void InitTrickNames() {
Text{"Progressive Power Sword", "Épée de Puissance (prog.)", "Espada de poder progresiva"},
Text{"Progressive Big Stabby", "Gros coup de poignard (prog.)", "Gran puñalada progresiva"}};
trickNameTable[0x0F] = {
trickNameTable[RG_EMPTY_BOTTLE] = {
Text{"Empty Canteen", "Cantine vide", "cantimplora vacía"},
Text{"Vial of Winds", "Fiole de vents", "Vial de Vientos"},
Text{"Tingle Bottle", "Flacon de Tingle", "Botella de Tingle"},
Text{"Magic Bottle", "Flacon magique", "Frasco feérico"},
Text{"Glass Bottle", "Flacon de verre", "Botella de cristal"},
Text{"Bottle with Water", "Flacon d'eau", "Botella Tingle"}};
trickNameTable[0x14] = {
trickNameTable[RG_BOTTLE_WITH_MILK] = {
Text{"Bottle with Chateau Romani", "Flacon de cuvée Romani", "Botella de Reserva Romani"},
Text{"Bottle with Premium Milk", "Flacon avec lait de qualité supérieure", "Biberón con leche Premium"},
Text{"Bottle with Mystery Milk", "Flacon de lait grand cru", "Botella de leche extra"},
Text{"Bottle with Fresh Milk", "Flacon de lait frais", "Botella de leche fresca"},};
trickNameTable[0x8C] = {
trickNameTable[RG_BOTTLE_WITH_RED_POTION] = {
Text{"Bottle with Red Chu Jelly", "Flacon de gelée Chuchu rouge", "Jugo de Chuchu Rojo"},
Text{"Bottle with Hibiscus Potion", "Flacon de potion de Hibiscus", "Botella de poción de Hibisco"},
Text{"Bottle with Medicine of Life", "Flacon d'élixir rouge", "Botella de medicina de la vida"},
Text{"Bottle with Heart Potion", "Flacon de potion de soin", "Botella de poción de salud"}};
trickNameTable[0x8D] = {
trickNameTable[RG_BOTTLE_WITH_GREEN_POTION] = {
Text{"Bottle with Green Chu Jelly", "Flacon de gelée Chuchu verte", "Jugo de Chuchu Verde"},
Text{"Bottle with Lamp Oil", "Flacon de Huile à lanterne", "Botella de Aceite de candil "},
Text{"Bottle with Medicine of Magic", "Flacon d'élixir vert", "Botella de medicina mágica"},
Text{"Bottle with Stamina Potion", "Flacon d'Endurol", "Botella de elixir vigorizante"}};
trickNameTable[0x8E] = {
trickNameTable[RG_BOTTLE_WITH_BLUE_POTION] = {
Text{"Bottle with Blue Chu Jelly", "Flacon de gelée Chuchu bleue", "Jugo de Chuchu Azul"},
Text{"Bottle with Water of Life", "Flacon d'élixir bleu", "Botella de agua de la vida"},
Text{"Bottle with Air Potion", "Flacon de potion d'oxygène", "Botella de oxígeno"}};
trickNameTable[0x8F] = {
trickNameTable[RG_BOTTLE_WITH_FAIRY] = {
Text{"Bottle with Forest Firefly", "Flacon avec une luciole", "Luciérnaga del bosque"},
Text{"Bottle with Deku Princess", "Flacon avec Deku Princess", "Botella con Deku Princess"},
Text{"Bottle with Stray Fairy", "Flacon avec une fée perdue", "Hada perdida en una botella"}};
trickNameTable[0x90] = {
trickNameTable[RG_BOTTLE_WITH_FISH] = {
Text{"Bottle with Small Jabu-Jabu", "Flacon avec mini Jabu-Jabu", "Lord Chapu-Chapu embotellado"},
Text{"Bottle with Reekfish", "Flacon avec Reekfish", "Reekfish embotellada"},
Text{"Bottle with Hyrule Bass", "Flacon avec perche d'Hyrule", "Locha de Hyrule embotellada"},
Text{"Bottle with Hyrule Loach", "Flacon avec loche d'Hyrule", "Perca de Términa embotellada"}};
trickNameTable[0x91] = {
trickNameTable[RG_BOTTLE_WITH_BLUE_FIRE] = {
Text{"Bottle with Will-O-Wisp", "Flacon avec feu follet", "Botella de llama azul"},
Text{"Bottle with Ancient Flame", "Flacon de flamme ancienne", "Botella de fuego ancestral"},
Text{"Bottle with a Blue Candle", "Flacon avec une bougie bleue", "Botella con una vela azul"},
Text{"Bottle with Red Ice", "Flacon de Glace Rouge", "Botella de Hielo rojo"},
Text{"Bottle with Nayru's Flame", "Flacon de flamme de Nayru", "Botella de llamas de Nayru"}};
trickNameTable[0x92] = {
trickNameTable[RG_BOTTLE_WITH_BUGS] = {
Text{"Bottle with Baby Tektites", "Flacon de bébé Araknon", "Tektites en una botella"},
Text{"Bottle with A Beetle", "Flacon avec un scarabée", "Botella con un escarabajo"},
Text{"Bottle with Lanayru Ants", "Flacon de fourmis de Lanelle", "Celestarabajo embotellado"},
Text{"Bottle with Insects", "Flacon de bibittes", "Saltabosques embotellados"},
Text{"Bottle with a Golden Bee", "Flacon avec une abeille dorée", "Botella con una abeja dorada"}};
trickNameTable[0x94] = {
trickNameTable[RG_BOTTLE_WITH_POE] = {
Text{"Bottle with Ghini", "Flacon avec Ghini", "Ghini en una botella"},
Text{"Bottle with Reapling", "Flacon avec Âme Damnée", "Reapling en una botella"},
Text{"Bottle with Imp Poe", "Flacon avec Spectre", "Espectro en una botella"},
Text{"Bottle with Anti-Fairy", "Flacon avec Tetdoss", "Whisp en una botella"}};
trickNameTable[0x15] = {
trickNameTable[RG_RUTOS_LETTER] = {
Text{"Bottle with Maggie's Letter", "Flacon avec lettre de Maggy", "Carta de Dolores"},
Text{"Bottle with Letter to Kafei", "Flacon avec lettre pour Kafei", "Carta para Kafei"},
Text{"Bottle with Zelda's Letter", "Flacon avec Lettre de Zelda", "Carta náutica"}};
trickNameTable[0x93] = {
trickNameTable[RG_BOTTLE_WITH_BIG_POE] = {
Text{"Bottle with Composer Brother", "Flacon avec un compositeur", "Hermana Poe embotellada"},
Text{"Bottle with Jalhalla", "Flacon avec Jalhalla", "Yaihalla embotellado"},
Text{"Bottle with Grim Repoe", "Flacon avec le Faucheur", "Bubble en una botella"}};
trickNameTable[0xC1] = {
trickNameTable[RG_ZELDAS_LULLABY] = {
Text{"Ballad of the Goddess", "Chant de la déesse", "Cántico de la Diosa"},
Text{"Song of Healing", "Chant de l'apaisement", "Canción de curación"},
Text{"Song of the Hero", "Chant du héros", "Canción del héroe"}};
trickNameTable[0xC2] = {
trickNameTable[RG_EPONAS_SONG] = {
Text{"Song of Birds","Chant des oiseaux","Cantar del ave"},
Text{"Song of Soaring", "Chant de l'envol", "Canción del viento"},
Text{"Song of Horse", "Chant du cheval", "Chant du cheval"}};
trickNameTable[0xC3] = {
trickNameTable[RG_SARIAS_SONG] = {
Text{"Mido's Song", "La chanson de Mido", "La canción de Mido"},
Text{"Kass' Theme", "Le thème de Kass", "El tema de Kass"},
Text{"Tune of Echoes", "Chant des Échos ", "Melodía del Eco "}};
trickNameTable[0xC4] = {
trickNameTable[RG_SUNS_SONG] = {
Text{"Song of Passing", "Mambo de Manbo", "Melodía del transcurrir"},
Text{"Command Melody", "Air du marionnettiste", "Cara al Sol"},
Text{"Moon's Song", "La chanson de Moon", "La canción de la luna"}};
trickNameTable[0xC5] = {
trickNameTable[RG_SONG_OF_TIME] = {
Text{"Song of Double Time", "Chant accéléré", "Canción del doble tiempo"},
Text{"Inverted Song of Time", "Chant du temps inversé", "Canción del tiempo invertida"},
Text{"Tune of Ages", "Chant du Temps", "Melodía del Tiempo"}};
trickNameTable[0xC6] = {
trickNameTable[RG_SONG_OF_STORMS] = {
Text{"Ballad of Gales", "Requiem de la tornade", "Melodía del Tornado"},
Text{"Frog's Song of Soul", "Rap des grenouilles", "Canción del alma de la rana"},
Text{"Wind's Requiem", "Mélodie du vent", "Melodía del Viento"}};
trickNameTable[0xBB] = {
trickNameTable[RG_MINUET_OF_FOREST] = {
Text{"Saria's Karaoke", "Karaoké de Saria", "Dueto del bosque"},
Text{"Sonata of Awakening", "Sonate de l'éveil", "Sonata del despertar"},
Text{"Wind God's Aria", "Hymne du dieu du vent", "Melodía del Espíritu del Viento"}};
trickNameTable[0xBC] = {
trickNameTable[RG_BOLERO_OF_FIRE] = {
Text{"Darunia's Tango", "Tango de Darunia", "Coro del fuego"},
Text{"Tune of Currents", "Chants des Flux", "Melodía de las Corrientes"},
Text{"Goron Lullaby", "Berceuse des Gorons", "Nana goron"}};
trickNameTable[0xBD] = {
trickNameTable[RG_SERENADE_OF_WATER] = {
Text{"Ruto's Blues", "Blues de Ruto", "Sonata del agua"},
Text{"New Wave Bossa Nova", "Bossa-nova des flots", "Bossanova de las olas"},
Text{"Manbo's Mambo", "Mambo de Manbo", "Mambo de Manbo"}};
trickNameTable[0xBE] = {
trickNameTable[RG_REQUIEM_OF_SPIRIT] = {
Text{"Nabooru's Reggae", "Reggae de Nabooru", "Reggae del espíritu"},
Text{"Elegy of Emptiness", "Hymne du vide", "Elegía al vacío"},
Text{"Earth God's Lyric", "Hymne du dieu de la terre", "Melodía del Espíritu de la Tierra"}};
trickNameTable[0xBF] = {
trickNameTable[RG_NOCTURNE_OF_SHADOW] = {
Text{"Impa's Death Metal", "Death métal d'Impa", "Diurno de la sombra"},
Text{"Oath to Order", "Ode de l'appel", "Oda al orden"},
Text{"Song of Discovery", "Chant des secrets", "Canto revelador"}};
trickNameTable[0xC0] = {
trickNameTable[RG_PRELUDE_OF_LIGHT] = {
Text{"Rauru's Sing-Along", "Chansonnette de Rauru", "Predulio de luz"},
Text{"Ballad of the Wind Fish", "Ballade sur Poisson-Rêve", "Balada del Piez Viento"},
Text{"Song of Light", "Chant de la lumière", "Sonidos de la luz"}};
trickNameTable[0xCB] = {
trickNameTable[RG_KOKIRI_EMERALD] = {
Text{"Pendant of Courage", "Pendentif du courage", "Colgante del valor"},
Text{"Farore's Pearl", "Perle de Farore", "Orbe de Farore"},
Text{"Aquanine", "Smaragdine", "Yerbánida"},
Text{"Farore's Emerald", "Émeraude de Farore", "Esmeralda de Farore"},
Text{"Kokiri's Peridot", "Péridot Kokiri", "Ágata de los Kokiri"}};
trickNameTable[0xCC] = {
trickNameTable[RG_GORON_RUBY] = {
Text{"Pendant of Power", "Pendentif de la force", "Colgante del poder"},
Text{"Din's Pearl", "Perle de Din", "Orbe de Din"},
Text{"Crimsonine", "Alzanine", "Bermellina"},
Text{"Din's Ruby", "Rubis de Din", "Rubí de Din"},
Text{"Goron's Garnet", "Grenat Goron", "Topacio de los Goron"}};
trickNameTable[0xCD] = {
trickNameTable[RG_ZORA_SAPPHIRE] = {
Text{"Pendant of Wisdom", "Pendentif de la sagesse", "Colgante de la sabiduría"},
Text{"Nayru's Pearl", "Perle de Nayru", "Orbe de Nayru"},
Text{"Azurine", "Aquanine", "Azurina"},
Text{"Nayru's Sapphire", "Saphir de Nayru", "Zafiro de Nayru"},
Text{"Zora's Aquamarine", "Aquamarine Zora", "Lapislázuli de los Zora"}};
trickNameTable[0xCE] = {
trickNameTable[RG_FOREST_MEDALLION] = {
Text{"Wind Medallion", "Médaillon du vent", "Medallón del Viento"},
Text{"Wind Element", "Elément Vent", "Elemento de aire"},
Text{"Saria's Medallion", "Médaillon de Saria", "Medallón de Saria"},
Text{"Sign of Air", "Glyphe de l'air", "Glifo de aire"},
Text{"Medallion of Forest", "Médaillon du Temple de la Forêt", "Medalla del Bosque"}};
trickNameTable[0xCF] = {
trickNameTable[RG_FIRE_MEDALLION] = {
Text{"Fire Element", "Elément Feu", "Elemento de fuego"},
Text{"Darunia's Medallion", "Médaillon de Darunia", "Medallón de Darunia"},
Text{"Sign of Fire", "Glyphe de feu", "Glifo de fuego"},
Text{"Medallion of Fire", "Médaillon du Temple du Feu", "Medalla del Fuego"}};
trickNameTable[0xD0] = {
trickNameTable[RG_WATER_MEDALLION] = {
Text{"Water Element", "Elément Eau", "Elemento de agua"},
Text{"Ice Medallion", "Médaillon de glace", "Medallón Helado"},
Text{"Ruto's Medallion", "Médaillon de Ruto", "Medallón de Ruto"},
Text{"Sign of Water", "Glyphe de l'eau", "Glifo de agua"},
Text{"Medallion of Water", "Médaillon du Temple de l'Eau", "Medalla del Agua"}};
trickNameTable[0xD1] = {
trickNameTable[RG_SPIRIT_MEDALLION] = {
Text{"Earth Element", "Elément Terre", "Elemento de tierra"},
Text{"Nabooru's Medallion", "Médaillon de Nabooru", "Medallón de Nabooru"},
Text{"Sign of Earth", "Glyphe de la Terre", "Glifo de la tierra"},
Text{"Medallion of Spirit", "Médaillon du Temple de l'Esprit", "Medalla del Espíritu"}};
trickNameTable[0xD2] = {
trickNameTable[RG_SHADOW_MEDALLION] = {
Text{"Fused Shadow", "Cristal d'ombre", "Sombra Fundida"},
Text{"Impa's Medallion", "Médaillon d'Impa", "Medallón de Impa"},
Text{"Sign of Illusion", "Glyphe de l'illusion", "Glifo de ilusión"},
Text{"Medallion of Shadow", "Médaillon du Temple de l'Ombre", "Medalla de la Sombra"}};
trickNameTable[0xD3] = {
trickNameTable[RG_LIGHT_MEDALLION] = {
Text{"Compass of Light", "Boussole de lumière", "Brújula de Luz"},
Text{"Rauru's Medallion", "Médaillon de Rauru", "Medallón de Rauru"},
Text{"Sign of Destiny", "Glyphe du destin", "Glifo del destino"},
Text{"Medallion of Light", "Médaillon du temple de lumière", "Medalla de la Luz"}};
trickNameTable[GI_HEART] = {
trickNameTable[RG_RECOVERY_HEART] = {
Text{"Love", "Bisou", "Te amo"},
Text{"Life", "Vie", "vida"},
Text{"HP", "VP", "VP"}};
trickNameTable[GI_RUPEE_GREEN] = {
trickNameTable[RG_GREEN_RUPEE] = {
Text{"False Greg", "Faux Greg", "Falso Greg"},
Text{"One Ruby", "Un rubis", "Un rubí"},
Text{"Rupoor (1)", "Roupir (1)", "Rupobre (1)"},
Text{"One Rupee", "Un rubis", "Guaraní hyliano"},
Text{"Rupee (1)", "Rubis (1)", "Peso hyliano"}};
trickNameTable[GI_RUPEE_BLUE] = {
trickNameTable[RG_BLUE_RUPEE] = {
Text{"Blupee", "Bleubi", "Azupia"},
Text{"Five Rubies", "Cinq Rubys", "Cinco rubíes"},
Text{"Five Rupees", "Cinq rubis", "Bolívar hyliano"},
Text{"Rupee (5)", "Rubis (5)", "Peso hyliano"},
Text{"Rupoor (5)", "Roupir (5)", "Rupobre (5)"}};
trickNameTable[GI_RUPEE_RED] = {
trickNameTable[RG_RED_RUPEE] = {
Text{"Big 20", "Grand 20", "Los 20 grandes"},
Text{"Twenty Rubies", "vingt rubis", "Veinte rubíes"},
Text{"Rupoor (20)", "Roupir (20)", "Rupobre (20)"},
Text{"Twenty Rupees", "Vingt rubis", "Colon hyliano"},
Text{"Rupee (20)", "Rubis (20)", "Peso hyliano"}};
trickNameTable[GI_RUPEE_PURPLE] = {
trickNameTable[RG_PURPLE_RUPEE] = {
Text{"Purpee", "pourbi", "morupiua"},
Text{"Fifty Rubies", "cinquante rubis", "Cincuenta rubíes"},
Text{"Rupoor (50)", "Roupir (50)", "Rupobre (50)"},
Text{"Fifty Rupees", "Cinquante rubis", "Balboa hyliano"},
Text{"Rupee (50)", "Rubis (50)", "Peso hyliano"}};
trickNameTable[GI_RUPEE_GOLD] = {
trickNameTable[RG_HUGE_RUPEE] = {
Text{"Hugo", "Or Rubi", "Oro Rubi"},
Text{"Two Hundred Rubies", "deux cents rubis", "Doscientos rubíes"},
Text{"Diamond", "Diamant", "Diamante"},
Text{"Huge Ruby", "Énorme rubis", "Rubi gigante"},
Text{"Two Hundred Rupees", "Deux cent rubis", "Euro hyliano"},
Text{"Rupee (200)", "Rubis (200)", "Dólar hyliano"}};
trickNameTable[GI_HEART_PIECE] = {
trickNameTable[RG_PIECE_OF_HEART] = {
Text{"Pizza Heart", "Fromage de cœur", "Pieza de Chorizo"},
Text{"Little Bit Of Love", "Un peu d'amour", "Un poco de amor"},
Text{"Rare Peach Stone", "Pierre de pêche rare", "Pierre de pêche rare"}};
trickNameTable[GI_HEART_CONTAINER_2] = {
trickNameTable[RG_HEART_CONTAINER] = {
Text{"Crystal Heart", "Cœur de cristal", "Corazón de cristal"},
Text{"Life Heart", "Cœur de vie", "Vida Corazón"},
Text{"Lots of Love", "Beaucoup d'amour", "Mucho amor"}};
trickNameTable[0xDF] = {
trickNameTable[RG_TRIFORCE_PIECE] = {
Text{"Piece of Cheese", "Morceau de Fromage", "Piece of Cheese"},
Text{"Triforce Shard", "Éclat de Triforce", "Triforce Shard"},
Text{"Shiny Rock", "Caiiloux Brillant", "Shiny Rock"}};

View File

@@ -1,12 +1,11 @@
#include "spoiler_log.hpp"
#include "dungeon.hpp"
#include "../dungeon.h"
#include "../static_data.h"
#include "../context.h"
#include "entrance.hpp"
#include "../entrance.h"
#include "random.hpp"
#include "settings.hpp"
#include "trial.hpp"
#include "../trial.h"
#include "tinyxml2.h"
#include "utils.hpp"
#include "shops.hpp"
@@ -33,6 +32,7 @@
#include <Context.h>
using json = nlohmann::ordered_json;
using namespace Rando;
json jsonData;
std::map<RandomizerHintTextKey, Rando::ItemLocation*> hintedLocations;
@@ -48,14 +48,15 @@ std::string placementtxt;
static SpoilerData spoilerData;
void GenerateHash() {
std::string hash = Settings::hash;
auto ctx = Rando::Context::GetInstance();
std::string hash = ctx->GetSettings()->GetHash();
// adds leading 0s to the hash string if it has less than 10 digits.
while (hash.length() < 10) {
hash = "0" + hash;
}
for (size_t i = 0, j = 0; i < Settings::hashIconIndexes.size(); i++, j += 2) {
for (size_t i = 0, j = 0; i < ctx->hashIconIndexes.size(); i++, j += 2) {
int number = std::stoi(hash.substr(j, 2));
Settings::hashIconIndexes[i] = number;
ctx->hashIconIndexes[i] = number;
}
// Clear out spoiler log data here, in case we aren't going to re-generate it
@@ -114,26 +115,26 @@ void WriteIngameSpoilerLog() {
// continue;
// }
// Cows
if (!Settings::ShuffleCows && loc->IsCategory(Category::cCow)) {
if (!ctx->GetOption(RSK_SHUFFLE_COWS) && loc->IsCategory(Category::cCow)) {
continue;
}
// Merchants
else if (Settings::ShuffleMerchants.Is(SHUFFLEMERCHANTS_OFF) && loc->IsCategory(Category::cMerchant)) {
else if (ctx->GetOption(RSK_SHUFFLE_MERCHANTS).Is(RO_SHUFFLE_MERCHANTS_OFF) && loc->IsCategory(Category::cMerchant)) {
continue;
}
// Adult Trade
else if (!Settings::ShuffleAdultTradeQuest && loc->IsCategory(Category::cAdultTrade)) {
else if (!ctx->GetOption(RSK_SHUFFLE_ADULT_TRADE) && loc->IsCategory(Category::cAdultTrade)) {
continue;
}
// Chest Minigame
else if (Settings::ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_OFF) &&
else if (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_GENERIC_OFF) &&
loc->IsCategory(Category::cChestMinigame)) {
continue;
}
// Gerudo Fortress
else if ((Settings::GerudoFortress.Is(GERUDOFORTRESS_OPEN) &&
else if ((ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_NORMAL) &&
(loc->IsCategory(Category::cVanillaGFSmallKey) || loc->GetHintKey() == RHT_GF_GERUDO_MEMBERSHIP_CARD)) ||
(Settings::GerudoFortress.Is(GERUDOFORTRESS_FAST) && loc->IsCategory(Category::cVanillaGFSmallKey) &&
(ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_FAST) && loc->IsCategory(Category::cVanillaGFSmallKey) &&
loc->GetHintKey() != RHT_GF_NORTH_F1_CARPENTER)) {
continue;
}
@@ -186,7 +187,7 @@ void WriteIngameSpoilerLog() {
}
// Shops
else if (loc->IsShop()) {
if (Settings::Shopsanity.Is(SHOPSANITY_OFF)) {
if (ctx->GetOption(RSK_SHOPSANITY).Is(RO_SHOPSANITY_OFF)) {
spoilerData.ItemLocations[spoilerItemIndex].RevealType = REVEALTYPE_ALWAYS;
} else {
spoilerData.ItemLocations[spoilerItemIndex].RevealType = REVEALTYPE_SCENE;
@@ -199,14 +200,14 @@ void WriteIngameSpoilerLog() {
}
// Gold Skulltulas
else if (loc->IsCategory(Category::cSkulltula) &&
((Settings::Tokensanity.Is(TOKENSANITY_OFF)) ||
(Settings::Tokensanity.Is(TOKENSANITY_DUNGEONS) && !loc->IsDungeon()) ||
(Settings::Tokensanity.Is(TOKENSANITY_OVERWORLD) && loc->IsDungeon()))) {
((ctx->GetOption(RSK_SHUFFLE_TOKENS).Is(RO_TOKENSANITY_OFF)) ||
(ctx->GetOption(RSK_SHUFFLE_TOKENS).Is(RO_TOKENSANITY_DUNGEONS) && !loc->IsDungeon()) ||
(ctx->GetOption(RSK_SHUFFLE_TOKENS).Is(RO_TOKENSANITY_OVERWORLD) && loc->IsDungeon()))) {
spoilerData.ItemLocations[spoilerItemIndex].RevealType = REVEALTYPE_ALWAYS;
}
// Deku Scrubs
else if (loc->IsCategory(Category::cDekuScrub) && !loc->IsCategory(Category::cDekuScrubUpgrades) &&
Settings::Scrubsanity.Is(SCRUBSANITY_OFF)) {
ctx->GetOption(RSK_SHUFFLE_SCRUBS).Is(RO_SCRUBS_OFF)) {
spoilerData.ItemLocations[spoilerItemIndex].CollectType = COLLECTTYPE_REPEATABLE;
spoilerData.ItemLocations[spoilerItemIndex].RevealType = REVEALTYPE_ALWAYS;
}
@@ -226,7 +227,7 @@ void WriteIngameSpoilerLog() {
}
spoilerData.ItemLocationsCount = spoilerItemIndex;
if (Settings::IngameSpoilers) {
if (/*Settings::IngameSpoilers TODO: Remove: don't think we have any need for this*/ false) {
bool playthroughItemNotFound = false;
// Write playthrough data to in-game spoiler log
if (!spoilerOutOfSpace) {
@@ -357,76 +358,47 @@ static void WriteShuffledEntrance(std::string sphereString, Entrance* entrance)
// Writes the settings (without excluded locations, starting inventory and tricks) to the spoilerLog document.
static void WriteSettings(const bool printAll = false) {
// auto parentNode = spoilerLog.NewElement("settings");
std::vector<Menu*> allMenus = Settings::GetAllOptionMenus();
for (const Menu* menu : allMenus) {
if (menu->name == "Item Usability Settings" ||
menu->name == "Multiplayer Settings") continue;
if (menu->name == "Timesaver Settings") {
for (const Option* setting : *menu->settingsList) {
if (setting->GetName() == "Big Poe Target Count" ||
setting->GetName() == "Cuccos to return" ||
setting->GetName() == "Skip Epona Race" ||
setting->GetName() == "Skip Tower Escape" ||
setting->GetName() == "Skip Child Stealth" ||
setting->GetName() == "Complete Mask Quest" ||
setting->GetName() == "Skip Scarecrow's Song" ||
setting->GetName() == "Enable Glitch-Useful Cutscenes") {
std::string settingName = menu->name + ":" + setting->GetName();
jsonData["settings"][settingName] = setting->GetSelectedOptionText();
// auto parentNode = spoilerLog.NewElement("settings");
auto ctx = Rando::Context::GetInstance();
auto allOptionGroups = ctx->GetSettings()->GetOptionGroups();
for (const Rando::OptionGroup& optionGroup : allOptionGroups) {
if (optionGroup.GetName() == "Timesaver Settings") {
for (const Rando::Option* option : optionGroup.GetOptions()) {
if (option->GetName() == "Big Poe Target Count" || option->GetName() == "Cuccos to return" ||
option->GetName() == "Skip Epona Race" || option->GetName() == "Skip Tower Escape" ||
option->GetName() == "Skip Child Stealth" || option->GetName() == "Complete Mask Quest" ||
option->GetName() == "Skip Scarecrow's Song" ||
option->GetName() == "Enable Glitch-Useful Cutscenes") {
std::string settingName = optionGroup.GetName() + ":" + option->GetName();
jsonData["settings"][settingName] = option->GetSelectedOptionText();
}
}
continue;
}
if (optionGroup.GetContainsType() == Rando::OptionGroupType::DEFAULT && optionGroup.PrintInSpoiler()) {
for (const Rando::Option* option : optionGroup.GetOptions()) {
std::string settingName = optionGroup.GetName() + ":" + option->GetName();
jsonData["settings"][settingName] = option->GetSelectedOptionText();
}
}
}
continue;
}
//This is a menu of settings, write them
if (menu->mode == OPTION_SUB_MENU && menu->printInSpoiler) {
for (const Option* setting : *menu->settingsList) {
std::string settingName = menu->name + ":" + setting->GetName();
jsonData["settings"][settingName] = setting->GetSelectedOptionText();
}
// spoilerLog.RootElement()->InsertEndChild(parentNode);
// for (const Option* setting : *menu->settingsList) {
// if (printAll || (!setting->IsHidden() && setting->IsCategory(OptionCategory::Setting))) {
// auto node = parentNode->InsertNewChildElement("setting");
// node->SetAttribute("name", RemoveLineBreaks(setting->GetName()).c_str());
// node->SetText(setting->GetSelectedOptionText().c_str());
// }
// }
}
}
// 3drando doesn't have a "skip child zelda" setting, manually add it to the spoilerfile
jsonData["settings"]["Skip Child Zelda"] = Settings::skipChildZelda;
// 3drando uses an MQ dungeon count of 13 to mean random, manually add that to the spoilerfile as a bool
if (Settings::MQDungeonCount.GetSelectedOptionIndex() == 0) {
jsonData["settings"]["World Settings:MQ Dungeons"] = "None";
} else if (Settings::MQDungeonCount.GetSelectedOptionIndex() == 13) {
jsonData["settings"]["World Settings:MQ Dungeons"] = "Random Number";
} else {
jsonData["settings"]["World Settings:MQ Dungeons"] = "Set Number";
}
// spoilerLog.RootElement()->InsertEndChild(parentNode);
// for (const uint32_t key : allLocations) {
// ItemLocation* location = GetLocation(key);
// settingsJsonData["locations"][location->GetName()] = location->GetPlacedItemName().english;
// }
// for (const uint32_t key : allLocations) {
// ItemLocation* location = GetLocation(key);
// settingsJsonData["locations"][location->GetName()] = location->GetPlacedItemName().english;
// }
}
// Writes the excluded locations to the spoiler log, if there are any.
static void WriteExcludedLocations() {
// auto parentNode = spoilerLog.NewElement("excluded-locations");
auto ctx = Rando::Context::GetInstance();
for (size_t i = 1; i < Settings::excludeLocationsOptionsVector.size(); i++) {
for (const auto& location : Settings::excludeLocationsOptionsVector[i]) {
if (location->GetSelectedOptionIndex() == INCLUDE) {
for (size_t i = 1; i < ctx->GetSettings()->GetExcludeLocationsOptions().size(); i++) {
for (const auto& location : ctx->GetSettings()->GetExcludeLocationsOptions()[i]) {
if (location->GetSelectedOptionIndex() == RO_LOCATION_INCLUDE) {
continue;
}
@@ -445,61 +417,24 @@ static void WriteExcludedLocations() {
// Writes the starting inventory to the spoiler log, if there is any.
static void WriteStartingInventory() {
std::vector<std::vector<Option *>*> startingInventoryOptions = {
&Settings::startingItemsOptions,
&Settings::startingSongsOptions,
&Settings::startingEquipmentOptions,
&Settings::startingStonesMedallionsOptions,
&Settings::startingOthersOptions
};
for (std::vector<Option*>* menu : startingInventoryOptions) {
for (size_t i = 0; i < menu->size(); ++i) {
const auto setting = menu->at(i);
// Starting Songs
if (setting->GetName() == "Start with Zelda's Lullaby" ||
setting->GetName() == "Start with Epona's Song" ||
setting->GetName() == "Start with Saria's Song" ||
setting->GetName() == "Start with Sun's Song" ||
setting->GetName() == "Start with Song of Time" ||
setting->GetName() == "Start with Song of Storms" ||
setting->GetName() == "Start with Minuet of Forest" ||
setting->GetName() == "Start with Bolero of Fire" ||
setting->GetName() == "Start with Serenade of Water" ||
setting->GetName() == "Start with Requiem of Spirit" ||
setting->GetName() == "Start with Nocturne of Shadow" ||
setting->GetName() == "Start with Prelude of Light") {
jsonData["settings"][setting->GetName()] = setting->GetSelectedOptionText();
}
}
}
for (std::vector<Option *>* menu : startingInventoryOptions) {
for (size_t i = 0; i < menu->size(); ++i) {
const auto setting = menu->at(i);
// we need to write these every time because we're not clearing jsondata, so
// the default logic of only writing it when we aren't using the default value
// doesn't work, and because it'd be bad to set every single possible starting
// inventory item as "false" in the json, we're just going to check
// to see if the name is one of the 3 we're using rn
if (setting->GetName() == "Start with Consumables" ||
setting->GetName() == "Start with Max Rupees" ||
setting->GetName() == "Gold Skulltula Tokens" ||
setting->GetName() == "Start with Fairy Ocarina" ||
setting->GetName() == "Start with Kokiri Sword" ||
setting->GetName() == "Start with Deku Shield") {
jsonData["settings"][setting->GetName()] = setting->GetSelectedOptionText();
}
auto ctx = Rando::Context::GetInstance();
const Rando::OptionGroup& optionGroup = ctx->GetSettings()->GetOptionGroup(RSG_STARTING_INVENTORY);
for (const Rando::OptionGroup* subGroup : optionGroup.GetSubGroups()) {
if (subGroup->GetContainsType() == Rando::OptionGroupType::DEFAULT) {
for (const Rando::Option* option : subGroup->GetOptions()) {
jsonData["settings"][option->GetName()] = option->GetSelectedOptionText();
}
}
}
}
}
// Writes the enabled tricks to the spoiler log, if there are any.
static void WriteEnabledTricks(tinyxml2::XMLDocument& spoilerLog) {
//auto parentNode = spoilerLog.NewElement("enabled-tricks");
auto ctx = Rando::Context::GetInstance();
for (const auto& setting : Settings::trickOptions) {
if (setting->GetSelectedOptionIndex() != TRICK_ENABLED/* || !setting->IsCategory(OptionCategory::Setting)*/) {
for (const auto& setting : ctx->GetSettings()->GetOptionGroup(RSG_TRICKS).GetOptions()) {
if (setting->GetSelectedOptionIndex() != RO_GENERIC_ON/* || !setting->IsCategory(OptionCategory::Setting)*/) {
continue;
}
jsonData["enabledTricks"].push_back(RemoveLineBreaks(RandomizerTricks::GetRTName((RandomizerTrick)std::stoi(setting->GetName()))).c_str());
@@ -513,36 +448,38 @@ static void WriteEnabledTricks(tinyxml2::XMLDocument& spoilerLog) {
}
// Writes the enabled glitches to the spoiler log, if there are any.
static void WriteEnabledGlitches(tinyxml2::XMLDocument& spoilerLog) {
auto parentNode = spoilerLog.NewElement("enabled-glitches");
// TODO: Implement Glitches
// static void WriteEnabledGlitches(tinyxml2::XMLDocument& spoilerLog) {
// auto parentNode = spoilerLog.NewElement("enabled-glitches");
for (const auto& setting : Settings::glitchCategories) {
if (setting->Value<uint8_t>() == 0) {
continue;
}
// for (const auto& setting : Settings::glitchCategories) {
// if (setting->Value<uint8_t>() == 0) {
// continue;
// }
auto node = parentNode->InsertNewChildElement("glitch-category");
node->SetAttribute("name", setting->GetName().c_str());
node->SetText(setting->GetSelectedOptionText().c_str());
}
// auto node = parentNode->InsertNewChildElement("glitch-category");
// node->SetAttribute("name", setting->GetName().c_str());
// node->SetText(setting->GetSelectedOptionText().c_str());
// }
for (const auto& setting : Settings::miscGlitches) {
if (!setting->Value<bool>()) {
continue;
}
// for (const auto& setting : Settings::miscGlitches) {
// if (!setting->Value<bool>()) {
// continue;
// }
auto node = parentNode->InsertNewChildElement("misc-glitch");
node->SetAttribute("name", RemoveLineBreaks(setting->GetName()).c_str());
}
// auto node = parentNode->InsertNewChildElement("misc-glitch");
// node->SetAttribute("name", RemoveLineBreaks(setting->GetName()).c_str());
// }
if (!parentNode->NoChildren()) {
spoilerLog.RootElement()->InsertEndChild(parentNode);
}
}
// if (!parentNode->NoChildren()) {
// spoilerLog.RootElement()->InsertEndChild(parentNode);
// }
// }
// Writes the Master Quest dungeons to the spoiler log, if there are any.
static void WriteMasterQuestDungeons(tinyxml2::XMLDocument& spoilerLog) {
for (const auto* dungeon : Dungeon::dungeonList) {
auto ctx = Rando::Context::GetInstance();
for (const auto* dungeon : ctx->GetDungeons()->GetDungeonList()) {
std::string dungeonName;
if (dungeon->IsVanilla()) {
continue;
@@ -553,7 +490,8 @@ static void WriteMasterQuestDungeons(tinyxml2::XMLDocument& spoilerLog) {
// Writes the required trials to the spoiler log, if there are any.
static void WriteRequiredTrials() {
for (const auto& trial : Trial::trialList) {
auto ctx = Rando::Context::GetInstance();
for (const auto& trial : ctx->GetTrials()->GetTrialList()) {
if (trial->IsRequired()) {
std::string trialName;
switch (gSaveContext.language) {
@@ -590,13 +528,14 @@ static void WritePlaythrough() {
//Write the randomized entrance playthrough to the spoiler log, if applicable
static void WriteShuffledEntrances() {
for (uint32_t i = 0; i < playthroughEntrances.size(); ++i) {
auto ctx = Rando::Context::GetInstance();
for (uint32_t i = 0; i < ctx->GetEntranceShuffler()->playthroughEntrances.size(); ++i) {
auto sphereNum = std::to_string(i);
std::string sphereString = "sphere ";
if (i < 10) sphereString += "0";
sphereString += sphereNum;
for (Entrance* entrance : playthroughEntrances[i]) {
WriteShuffledEntrance(sphereString, entrance);
for (Entrance* entrance : ctx->GetEntranceShuffler()->playthroughEntrances[i]) {
WriteShuffledEntrance(sphereString, entrance);
}
}
}
@@ -673,6 +612,7 @@ Rando::ItemLocation* GetItemLocation(RandomizerGet item) {
// Writes the hints to the spoiler log, if they are enabled.
static void WriteHints(int language) {
auto ctx = Rando::Context::GetInstance();
std::string unformattedGanonText;
std::string unformattedGanonHintText;
std::string unformattedDampesText;
@@ -690,7 +630,7 @@ static void WriteHints(int language) {
unformattedSheikText = GetSheikHintText().GetEnglish();
unformattedSariaText = GetSariaHintText().GetEnglish();
if (Settings::ShuffleWarpSongs){
if (ctx->GetOption(RSK_SHUFFLE_WARP_SONGS)){
jsonData["warpMinuetText"] = GetWarpMinuetText().GetEnglish();
jsonData["warpBoleroText"] = GetWarpBoleroText().GetEnglish();
jsonData["warpSerenadeText"] = GetWarpSerenadeText().GetEnglish();
@@ -709,7 +649,7 @@ static void WriteHints(int language) {
unformattedSheikText = GetSheikHintText().GetFrench();
unformattedSariaText = GetSariaHintText().GetFrench();
if (Settings::ShuffleWarpSongs){
if (ctx->GetOption(RSK_SHUFFLE_WARP_SONGS)){
jsonData["warpMinuetText"] = GetWarpMinuetText().GetFrench();
jsonData["warpBoleroText"] = GetWarpBoleroText().GetFrench();
jsonData["warpSerenadeText"] = GetWarpSerenadeText().GetFrench();
@@ -762,48 +702,51 @@ static void WriteHints(int language) {
std::string sariaText = AutoFormatHintTextString(unformattedSariaText);
jsonData["ganonText"] = ganonText;
if (Settings::LightArrowHintText){
if (ctx->GetOption(RSK_LIGHT_ARROWS_HINT)){
jsonData["ganonHintText"] = ganonHintText;
jsonData["lightArrowHintLoc"] = GetLightArrowHintLoc();
jsonData["lightArrowRegion"] = ctx->GetHint(RH_GANONDORF_HINT)->GetHintedRegion();
jsonData["masterSwordHintLoc"] = GetMasterSwordHintLoc();
if (!Settings::GanonsTrialsCount.Is(0)){
jsonData["sheikText"] = sheikText;
if (!ctx->GetOption(RSK_TRIAL_COUNT).Is(0)) {
jsonData["sheikText"] = sheikText;
}
}
if (Settings::DampeHintText){
if (ctx->GetOption(RSK_DAMPES_DIARY_HINT)){
jsonData["dampeText"] = dampesText;
jsonData["dampeHintLoc"] = GetDampeHintLoc();
jsonData["dampeRegion"] = ctx->GetHint(RH_DAMPES_DIARY)->GetHintedRegion();
}
if (Settings::GregHintText){
if (ctx->GetOption(RSK_GREG_HINT)){
jsonData["gregText"] = gregText;
jsonData["gregLoc"] = GetGregHintLoc();
jsonData["gregRegion"] = ctx->GetHint(RH_GREG_RUPEE)->GetHintedRegion();
}
if (Settings::SariaHintText){
if (ctx->GetOption(RSK_SARIA_HINT)){
jsonData["sariaText"] = sariaText;
jsonData["sariaHintLoc"] = GetSariaHintLoc();
jsonData["sariaRegion"] = ctx->GetHint(RH_SARIA)->GetHintedRegion();
}
if (Settings::GossipStoneHints.Is(HINTS_NO_HINTS)) {
if (ctx->GetOption(RSK_GOSSIP_STONE_HINTS).Is(RO_GOSSIP_STONES_NONE)) {
return;
}
auto ctx = Rando::Context::GetInstance();
for (const RandomizerCheck key : Rando::StaticData::gossipStoneLocations) {
Rando::Hint* hint = ctx->GetHint((RandomizerHintKey)(key - RC_DMC_GOSSIP_STONE + 1));
Rando::Hint* hint = ctx->GetHint((RandomizerHintKey)(key - RC_COLOSSUS_GOSSIP_STONE + 1));
Rando::ItemLocation* hintedLocation = ctx->GetItemLocation(hint->GetHintedLocation());
std::string unformattedHintTextString;
std::string hintTextString;
switch (language) {
case 0:
default:
unformattedHintTextString = hint->GetText().GetEnglish();
hintTextString = hint->GetText().GetEnglish();
break;
case 2:
unformattedHintTextString = hint->GetText().GetFrench();
hintTextString = hint->GetText().GetFrench();
break;
}
HintType hintType = hint->GetHintType();
std::string textStr = AutoFormatHintTextString(unformattedHintTextString);
std::string textStr = hintTextString;
jsonData["hints"][Rando::StaticData::GetLocation(key)->GetName()]["hint"] = textStr;
jsonData["hints"][Rando::StaticData::GetLocation(key)->GetName()]["type"] = hintTypeNames[(int)hintType];
if ((hintType >= HINT_TYPE_ALWAYS && hintType < HINT_TYPE_JUNK) || hintType == HINT_TYPE_WOTH) {
@@ -837,8 +780,7 @@ static void WriteAllLocations(int language) {
// If it's a simple item (not an ice trap, doesn't have a price)
// just add the name of the item and move on
if (!location->HasScrubsanityPrice() &&
!location->HasShopsanityPrice() &&
if (!location->HasCustomPrice() &&
location->GetPlacedRandomizerGet() != RG_ICE_TRAP) {
jsonData["locations"][Rando::StaticData::GetLocation(location->GetRandomizerCheck())->GetName()] = placedItemName;
@@ -848,7 +790,7 @@ static void WriteAllLocations(int language) {
// We're dealing with a complex item, build out the json object for it
jsonData["locations"][Rando::StaticData::GetLocation(location->GetRandomizerCheck())->GetName()]["item"] = placedItemName;
if (location->HasScrubsanityPrice() || location->HasShopsanityPrice()) {
if (location->HasCustomPrice()) {
jsonData["locations"][Rando::StaticData::GetLocation(location->GetRandomizerCheck())->GetName()]["price"] =
location->GetPrice();
}
@@ -861,15 +803,15 @@ static void WriteAllLocations(int language) {
case 0:
default:
jsonData["locations"][Rando::StaticData::GetLocation(location->GetRandomizerCheck())->GetName()]["model"] =
Rando::StaticData::ItemFromGIID(ctx->iceTrapModels[location->GetRandomizerCheck()]).GetName().english;
Rando::StaticData::RetrieveItem(ctx->overrides[location->GetRandomizerCheck()].LooksLike()).GetName().english;
jsonData["locations"][Rando::StaticData::GetLocation(location->GetRandomizerCheck())->GetName()]["trickName"] =
GetIceTrapName(ctx->iceTrapModels[location->GetRandomizerCheck()]).english;
ctx->overrides[location->GetRandomizerCheck()].GetTrickName().english;
break;
case 2:
jsonData["locations"][Rando::StaticData::GetLocation(location->GetRandomizerCheck())->GetName()]["model"] =
Rando::StaticData::ItemFromGIID(ctx->iceTrapModels[location->GetRandomizerCheck()]).GetName().french;
Rando::StaticData::RetrieveItem(ctx->overrides[location->GetRandomizerCheck()].LooksLike()).GetName().french;
jsonData["locations"][Rando::StaticData::GetLocation(location->GetRandomizerCheck())->GetName()]["trickName"] =
GetIceTrapName(ctx->iceTrapModels[location->GetRandomizerCheck()]).french;
ctx->overrides[location->GetRandomizerCheck()].GetTrickName().french;
break;
}
}
@@ -877,6 +819,7 @@ static void WriteAllLocations(int language) {
}
const char* SpoilerLog_Write(int language) {
auto ctx = Rando::Context::GetInstance();
auto spoilerLog = tinyxml2::XMLDocument(false);
spoilerLog.InsertEndChild(spoilerLog.NewDeclaration());
@@ -886,12 +829,12 @@ const char* SpoilerLog_Write(int language) {
jsonData.clear();
jsonData["version"] = (char*) gBuildVersion;
jsonData["seed"] = Settings::seedString;
jsonData["finalSeed"] = Settings::seed;
jsonData["seed"] = ctx->GetSettings()->GetSeedString();
jsonData["finalSeed"] = ctx->GetSettings()->GetSeed();
// Write Hash
int index = 0;
for (uint8_t seed_value : Settings::hashIconIndexes) {
for (uint8_t seed_value : ctx->hashIconIndexes) {
jsonData["file_hash"][index] = seed_value;
index++;
}
@@ -908,7 +851,6 @@ const char* SpoilerLog_Write(int language) {
WritePlaythrough();
//WriteWayOfTheHeroLocation(spoilerLog);
auto ctx = Rando::Context::GetInstance();
ctx->playthroughLocations.clear();
ctx->playthroughBeatable = false;
ctx->wothLocations.clear();
@@ -923,14 +865,14 @@ const char* SpoilerLog_Write(int language) {
std::string jsonString = jsonData.dump(4);
std::ostringstream fileNameStream;
for (int i = 0; i < Settings::hashIconIndexes.size(); i ++) {
for (int i = 0; i < ctx->hashIconIndexes.size(); i ++) {
if (i) {
fileNameStream << '-';
}
if (Settings::hashIconIndexes[i] < 10) {
if (ctx->hashIconIndexes[i] < 10) {
fileNameStream << '0';
}
fileNameStream << std::to_string(Settings::hashIconIndexes[i]);
fileNameStream << std::to_string(ctx->hashIconIndexes[i]);
}
std::string fileName = fileNameStream.str();
std::ofstream jsonFile(LUS::Context::GetPathRelativeToAppDirectory(
@@ -960,14 +902,15 @@ bool PlacementLog_Write() {
auto rootNode = placementLog.NewElement("placement-log");
placementLog.InsertEndChild(rootNode);
rootNode->SetAttribute("version", Settings::version.c_str());
rootNode->SetAttribute("seed", Settings::seed);
// rootNode->SetAttribute("version", Settings::version.c_str());
// rootNode->SetAttribute("seed", Settings::seed);
// TODO: Do we even use this?
// WriteSettings(placementLog, true); // Include hidden settings.
// WriteExcludedLocations(placementLog);
// WriteStartingInventory(placementLog);
WriteEnabledTricks(placementLog);
WriteEnabledGlitches(placementLog);
//WriteEnabledGlitches(placementLog);
WriteMasterQuestDungeons(placementLog);
//WriteRequiredTrials(placementLog);

View File

@@ -1,12 +1,10 @@
#include "starting_inventory.hpp"
#include "dungeon.hpp"
#include "settings.hpp"
#include "../dungeon.h"
#include "../context.h"
#include "pool_functions.hpp"
#include "soh/Enhancements/randomizer/static_data.h"
using namespace Settings;
using namespace Dungeon;
std::vector<RandomizerGet> StartingInventory;
uint8_t AdditionalHeartContainers;
@@ -15,10 +13,11 @@ static void AddItemToInventory(RandomizerGet item, size_t count = 1) {
}
void GenerateStartingInventory() {
auto ctx = Rando::Context::GetInstance();
StartingInventory.clear();
if (MapsAndCompasses.Is(MAPSANDCOMPASSES_START_WITH)) {
for (auto* dungeon : dungeonList) {
if (ctx->GetOption(RSK_SHUFFLE_MAPANDCOMPASS).Is(RO_DUNGEON_ITEM_LOC_STARTWITH)) {
for (auto* dungeon : ctx->GetDungeons()->GetDungeonList()) {
if (dungeon->GetMap() != RG_NONE) {
AddItemToInventory(dungeon->GetMap());
}
@@ -29,24 +28,24 @@ void GenerateStartingInventory() {
}
}
if (Keysanity.Is(KEYSANITY_START_WITH)) {
for (auto* dungeon : dungeonList) {
if (ctx->GetOption(RSK_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_STARTWITH)) {
for (auto* dungeon : ctx->GetDungeons()->GetDungeonList()) {
if (dungeon->GetSmallKeyCount() > 0) {
AddItemToInventory(dungeon->GetSmallKey(), dungeon->GetSmallKeyCount());
}
}
} else if (Keysanity.Is(KEYSANITY_VANILLA)) {
} else if (ctx->GetOption(RSK_KEYSANITY).Is(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
// - OoT Randomizer
if (SpiritTemple.IsMQ()) {
if (ctx->GetDungeon(Rando::SPIRIT_TEMPLE)->IsMQ()) {
AddItemToInventory(RG_SPIRIT_TEMPLE_SMALL_KEY, 3);
}
}
if (BossKeysanity.Is(BOSSKEYSANITY_START_WITH)) {
if (ctx->GetOption(RSK_BOSS_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_STARTWITH)) {
AddItemToInventory(RG_FOREST_TEMPLE_BOSS_KEY);
AddItemToInventory(RG_FIRE_TEMPLE_BOSS_KEY);
AddItemToInventory(RG_WATER_TEMPLE_BOSS_KEY);
@@ -56,11 +55,12 @@ void GenerateStartingInventory() {
// Add Ganon's Boss key with Triforce Hunt so the game thinks it's obtainable from the start.
// During save init, the boss key isn't actually given and it's instead given when completing the triforce.
if (GanonsBossKey.Is(GANONSBOSSKEY_START_WITH) || GanonsBossKey.Is(GANONSBOSSKEY_TRIFORCE_HUNT)) {
AddItemToInventory(RG_GANONS_CASTLE_BOSS_KEY);
if (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_STARTWITH) ||
ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_TRIFORCE_HUNT)) {
AddItemToInventory(RG_GANONS_CASTLE_BOSS_KEY);
}
if (GerudoFortress.Is(GERUDOFORTRESS_OPEN) && !ShuffleGerudoToken) {
if (ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_OPEN) && !ctx->GetOption(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD)) {
AddItemToInventory(RG_GERUDO_MEMBERSHIP_CARD);
}
@@ -68,103 +68,104 @@ void GenerateStartingInventory() {
//Values are associated so that the count of items matches the index of
//the option selected. If None is selected, the value will be zero and
//zero of the item will be added to the starting inventory.
AddItemToInventory(RG_PROGRESSIVE_STICK_UPGRADE, StartingStickCapacity.Value<uint8_t>());
AddItemToInventory(RG_PROGRESSIVE_NUT_UPGRADE, StartingNutCapacity.Value<uint8_t>());
AddItemToInventory(RG_PROGRESSIVE_BOMB_BAG, StartingBombBag.Value<uint8_t>());
AddItemToInventory((BombchusInLogic ? RG_PROGRESSIVE_BOMBCHUS : RG_BOMBCHU_20), StartingBombchus.Value<uint8_t>());
AddItemToInventory(RG_PROGRESSIVE_BOW, StartingBow.Value<uint8_t>());
AddItemToInventory(RG_FIRE_ARROWS, StartingFireArrows.Value<uint8_t>());
AddItemToInventory(RG_ICE_ARROWS, StartingIceArrows.Value<uint8_t>());
AddItemToInventory(RG_LIGHT_ARROWS, StartingLightArrows.Value<uint8_t>());
AddItemToInventory(RG_DINS_FIRE, StartingDinsFire.Value<uint8_t>());
AddItemToInventory(RG_FARORES_WIND, StartingFaroresWind.Value<uint8_t>());
AddItemToInventory(RG_NAYRUS_LOVE, StartingNayrusLove.Value<uint8_t>());
AddItemToInventory(RG_PROGRESSIVE_SLINGSHOT, StartingSlingshot.Value<uint8_t>());
AddItemToInventory(RG_BOOMERANG, StartingBoomerang.Value<uint8_t>());
AddItemToInventory(RG_LENS_OF_TRUTH, StartingLensOfTruth.Value<uint8_t>());
AddItemToInventory(RG_MAGIC_BEAN_PACK, StartingMagicBean.Value<uint8_t>());
AddItemToInventory(RG_MEGATON_HAMMER, StartingMegatonHammer.Value<uint8_t>());
AddItemToInventory(RG_PROGRESSIVE_HOOKSHOT, StartingHookshot.Value<uint8_t>());
AddItemToInventory(RG_IRON_BOOTS, StartingIronBoots.Value<uint8_t>());
AddItemToInventory(RG_HOVER_BOOTS, StartingHoverBoots.Value<uint8_t>());
// TODO: Uncomment when these options are implemented.
// AddItemToInventory(RG_PROGRESSIVE_STICK_UPGRADE, StartingStickCapacity.Value<uint8_t>());
// AddItemToInventory(RG_PROGRESSIVE_NUT_UPGRADE, StartingNutCapacity.Value<uint8_t>());
// AddItemToInventory(RG_PROGRESSIVE_BOMB_BAG, StartingBombBag.Value<uint8_t>());
// AddItemToInventory((BombchusInLogic ? RG_PROGRESSIVE_BOMBCHUS : RG_BOMBCHU_20), StartingBombchus.Value<uint8_t>());
// AddItemToInventory(RG_PROGRESSIVE_BOW, StartingBow.Value<uint8_t>());
// AddItemToInventory(RG_FIRE_ARROWS, StartingFireArrows.Value<uint8_t>());
// AddItemToInventory(RG_ICE_ARROWS, StartingIceArrows.Value<uint8_t>());
// AddItemToInventory(RG_LIGHT_ARROWS, StartingLightArrows.Value<uint8_t>());
// AddItemToInventory(RG_DINS_FIRE, StartingDinsFire.Value<uint8_t>());
// AddItemToInventory(RG_FARORES_WIND, StartingFaroresWind.Value<uint8_t>());
// AddItemToInventory(RG_NAYRUS_LOVE, StartingNayrusLove.Value<uint8_t>());
// AddItemToInventory(RG_PROGRESSIVE_SLINGSHOT, StartingSlingshot.Value<uint8_t>());
// AddItemToInventory(RG_BOOMERANG, StartingBoomerang.Value<uint8_t>());
// AddItemToInventory(RG_LENS_OF_TRUTH, StartingLensOfTruth.Value<uint8_t>());
// AddItemToInventory(RG_MAGIC_BEAN_PACK, StartingMagicBean.Value<uint8_t>());
// AddItemToInventory(RG_MEGATON_HAMMER, StartingMegatonHammer.Value<uint8_t>());
// AddItemToInventory(RG_PROGRESSIVE_HOOKSHOT, StartingHookshot.Value<uint8_t>());
// AddItemToInventory(RG_IRON_BOOTS, StartingIronBoots.Value<uint8_t>());
// AddItemToInventory(RG_HOVER_BOOTS, StartingHoverBoots.Value<uint8_t>());
//For starting bottles, we need to check if they are a big poe and add that if so
// since a big poe bottle is not logically equivalent to an empty bottle.
if (StartingBottle1.Value<uint8_t>() == STARTINGBOTTLE_BIG_POE) {
AddItemToInventory(RG_BOTTLE_WITH_BIG_POE, 1);
} else if (StartingBottle1.Value<uint8_t>()) {
AddItemToInventory(RG_EMPTY_BOTTLE, 1);
}
if (StartingBottle2.Value<uint8_t>() == STARTINGBOTTLE_BIG_POE) {
AddItemToInventory(RG_BOTTLE_WITH_BIG_POE, 1);
} else if (StartingBottle2.Value<uint8_t>()) {
AddItemToInventory(RG_EMPTY_BOTTLE, 1);
}
if (StartingBottle3.Value<uint8_t>() == STARTINGBOTTLE_BIG_POE) {
AddItemToInventory(RG_BOTTLE_WITH_BIG_POE, 1);
} else if (StartingBottle3.Value<uint8_t>()) {
AddItemToInventory(RG_EMPTY_BOTTLE, 1);
}
if (StartingBottle4.Value<uint8_t>() == STARTINGBOTTLE_BIG_POE) {
AddItemToInventory(RG_BOTTLE_WITH_BIG_POE, 1);
} else if (StartingBottle4.Value<uint8_t>()) {
AddItemToInventory(RG_EMPTY_BOTTLE, 1);
}
AddItemToInventory(RG_RUTOS_LETTER, StartingRutoBottle.Value<uint8_t>());
AddItemToInventory(RG_PROGRESSIVE_OCARINA, StartingOcarina.Value<uint8_t>());
AddItemToInventory(RG_ZELDAS_LULLABY, StartingZeldasLullaby.Value<uint8_t>());
AddItemToInventory(RG_EPONAS_SONG, StartingEponasSong.Value<uint8_t>());
AddItemToInventory(RG_SARIAS_SONG, StartingSariasSong.Value<uint8_t>());
AddItemToInventory(RG_SUNS_SONG, StartingSunsSong.Value<uint8_t>());
AddItemToInventory(RG_SONG_OF_TIME, StartingSongOfTime.Value<uint8_t>());
AddItemToInventory(RG_SONG_OF_STORMS, StartingSongOfStorms.Value<uint8_t>());
AddItemToInventory(RG_MINUET_OF_FOREST, StartingMinuetOfForest.Value<uint8_t>());
AddItemToInventory(RG_BOLERO_OF_FIRE, StartingBoleroOfFire.Value<uint8_t>());
AddItemToInventory(RG_SERENADE_OF_WATER, StartingSerenadeOfWater.Value<uint8_t>());
AddItemToInventory(RG_REQUIEM_OF_SPIRIT, StartingRequiemOfSpirit.Value<uint8_t>());
AddItemToInventory(RG_NOCTURNE_OF_SHADOW, StartingNocturneOfShadow.Value<uint8_t>());
AddItemToInventory(RG_PRELUDE_OF_LIGHT, StartingPreludeOfLight.Value<uint8_t>());
AddItemToInventory(RG_KOKIRI_SWORD, StartingKokiriSword.Value<uint8_t>());
if (ProgressiveGoronSword) {
AddItemToInventory(RG_PROGRESSIVE_GORONSWORD, StartingBiggoronSword.Value<uint8_t>());
} else {
AddItemToInventory(RG_GIANTS_KNIFE, (StartingBiggoronSword.Is(STARTINGBGS_GIANTS_KNIFE)) ? 1 : 0);
AddItemToInventory(RG_BIGGORON_SWORD, (StartingBiggoronSword.Is(STARTINGBGS_BIGGORON_SWORD)) ? 1 : 0);
}
AddItemToInventory(RG_DEKU_SHIELD, StartingDekuShield.Value<uint8_t>());
AddItemToInventory(RG_HYLIAN_SHIELD, StartingHylianShield.Value<uint8_t>());
AddItemToInventory(RG_MIRROR_SHIELD, StartingMirrorShield.Value<uint8_t>());
AddItemToInventory(RG_GORON_TUNIC, StartingGoronTunic.Value<uint8_t>());
AddItemToInventory(RG_ZORA_TUNIC, StartingZoraTunic.Value<uint8_t>());
AddItemToInventory(RG_PROGRESSIVE_MAGIC_METER, StartingMagicMeter.Value<uint8_t>());
AddItemToInventory(RG_PROGRESSIVE_STRENGTH, StartingStrength.Value<uint8_t>());
AddItemToInventory(RG_PROGRESSIVE_SCALE, StartingScale.Value<uint8_t>());
AddItemToInventory(RG_PROGRESSIVE_WALLET, StartingWallet.Value<uint8_t>());
AddItemToInventory(RG_STONE_OF_AGONY, StartingShardOfAgony.Value<uint8_t>());
AddItemToInventory(RG_DOUBLE_DEFENSE, StartingDoubleDefense.Value<uint8_t>());
AddItemToInventory(RG_KOKIRI_EMERALD, StartingKokiriEmerald.Value<uint8_t>());
AddItemToInventory(RG_GORON_RUBY, StartingGoronRuby.Value<uint8_t>());
AddItemToInventory(RG_ZORA_SAPPHIRE, StartingZoraSapphire.Value<uint8_t>());
AddItemToInventory(RG_FOREST_MEDALLION, StartingForestMedallion.Value<uint8_t>());
AddItemToInventory(RG_FIRE_MEDALLION, StartingFireMedallion.Value<uint8_t>());
AddItemToInventory(RG_WATER_MEDALLION, StartingWaterMedallion.Value<uint8_t>());
AddItemToInventory(RG_SPIRIT_MEDALLION, StartingSpiritMedallion.Value<uint8_t>());
AddItemToInventory(RG_SHADOW_MEDALLION, StartingShadowMedallion.Value<uint8_t>());
AddItemToInventory(RG_LIGHT_MEDALLION, StartingLightMedallion.Value<uint8_t>());
AddItemToInventory(RG_GOLD_SKULLTULA_TOKEN, StartingSkulltulaToken.Value<uint8_t>());
// if (StartingBottle1.Value<uint8_t>() == STARTINGBOTTLE_BIG_POE) {
// AddItemToInventory(RG_BOTTLE_WITH_BIG_POE, 1);
// } else if (StartingBottle1.Value<uint8_t>()) {
// AddItemToInventory(RG_EMPTY_BOTTLE, 1);
// }
// if (StartingBottle2.Value<uint8_t>() == STARTINGBOTTLE_BIG_POE) {
// AddItemToInventory(RG_BOTTLE_WITH_BIG_POE, 1);
// } else if (StartingBottle2.Value<uint8_t>()) {
// AddItemToInventory(RG_EMPTY_BOTTLE, 1);
// }
// if (StartingBottle3.Value<uint8_t>() == STARTINGBOTTLE_BIG_POE) {
// AddItemToInventory(RG_BOTTLE_WITH_BIG_POE, 1);
// } else if (StartingBottle3.Value<uint8_t>()) {
// AddItemToInventory(RG_EMPTY_BOTTLE, 1);
// }
// if (StartingBottle4.Value<uint8_t>() == STARTINGBOTTLE_BIG_POE) {
// AddItemToInventory(RG_BOTTLE_WITH_BIG_POE, 1);
// } else if (StartingBottle4.Value<uint8_t>()) {
// AddItemToInventory(RG_EMPTY_BOTTLE, 1);
// }
// AddItemToInventory(RG_RUTOS_LETTER, StartingRutoBottle.Value<uint8_t>());
AddItemToInventory(RG_PROGRESSIVE_OCARINA, ctx->GetOption(RSK_STARTING_OCARINA).Value<uint8_t>());
AddItemToInventory(RG_ZELDAS_LULLABY, ctx->GetOption(RSK_STARTING_ZELDAS_LULLABY) ? 1 : 0);
AddItemToInventory(RG_EPONAS_SONG, ctx->GetOption(RSK_STARTING_EPONAS_SONG) ? 1 : 0);
AddItemToInventory(RG_SARIAS_SONG, ctx->GetOption(RSK_STARTING_SARIAS_SONG) ? 1 : 0);
AddItemToInventory(RG_SUNS_SONG, ctx->GetOption(RSK_STARTING_SUNS_SONG) ? 1 : 0);
AddItemToInventory(RG_SONG_OF_TIME, ctx->GetOption(RSK_STARTING_SONG_OF_TIME) ? 1 : 0);
AddItemToInventory(RG_SONG_OF_STORMS, ctx->GetOption(RSK_STARTING_SONG_OF_STORMS) ? 1 : 0);
AddItemToInventory(RG_MINUET_OF_FOREST, ctx->GetOption(RSK_STARTING_MINUET_OF_FOREST) ? 1 : 0);
AddItemToInventory(RG_BOLERO_OF_FIRE, ctx->GetOption(RSK_STARTING_BOLERO_OF_FIRE) ? 1 : 0);
AddItemToInventory(RG_SERENADE_OF_WATER, ctx->GetOption(RSK_STARTING_SERENADE_OF_WATER) ? 1 : 0);
AddItemToInventory(RG_REQUIEM_OF_SPIRIT, ctx->GetOption(RSK_STARTING_REQUIEM_OF_SPIRIT) ? 1 : 0);
AddItemToInventory(RG_NOCTURNE_OF_SHADOW, ctx->GetOption(RSK_STARTING_NOCTURNE_OF_SHADOW) ? 1 : 0);
AddItemToInventory(RG_PRELUDE_OF_LIGHT, ctx->GetOption(RSK_STARTING_PRELUDE_OF_LIGHT) ? 1 : 0);
AddItemToInventory(RG_KOKIRI_SWORD, ctx->GetOption(RSK_STARTING_KOKIRI_SWORD) ? 1 : 0);
// if (ProgressiveGoronSword) {
// AddItemToInventory(RG_PROGRESSIVE_GORONSWORD, StartingBiggoronSword.Value<uint8_t>());
// } else {
// AddItemToInventory(RG_GIANTS_KNIFE, (StartingBiggoronSword.Is(STARTINGBGS_GIANTS_KNIFE)) ? 1 : 0);
// AddItemToInventory(RG_BIGGORON_SWORD, (StartingBiggoronSword.Is(STARTINGBGS_BIGGORON_SWORD)) ? 1 : 0);
// }
AddItemToInventory(RG_DEKU_SHIELD, ctx->GetOption(RSK_STARTING_DEKU_SHIELD) ? 1 : 0);
// AddItemToInventory(RG_HYLIAN_SHIELD, StartingHylianShield.Value<uint8_t>());
// AddItemToInventory(RG_MIRROR_SHIELD, StartingMirrorShield.Value<uint8_t>());
// AddItemToInventory(RG_GORON_TUNIC, StartingGoronTunic.Value<uint8_t>());
// AddItemToInventory(RG_ZORA_TUNIC, StartingZoraTunic.Value<uint8_t>());
// AddItemToInventory(RG_PROGRESSIVE_MAGIC_METER, StartingMagicMeter.Value<uint8_t>());
// AddItemToInventory(RG_PROGRESSIVE_STRENGTH, StartingStrength.Value<uint8_t>());
// AddItemToInventory(RG_PROGRESSIVE_SCALE, StartingScale.Value<uint8_t>());
// AddItemToInventory(RG_PROGRESSIVE_WALLET, StartingWallet.Value<uint8_t>());
// AddItemToInventory(RG_STONE_OF_AGONY, StartingShardOfAgony.Value<uint8_t>());
// AddItemToInventory(RG_DOUBLE_DEFENSE, StartingDoubleDefense.Value<uint8_t>());
// AddItemToInventory(RG_KOKIRI_EMERALD, StartingKokiriEmerald.Value<uint8_t>());
// AddItemToInventory(RG_GORON_RUBY, StartingGoronRuby.Value<uint8_t>());
// AddItemToInventory(RG_ZORA_SAPPHIRE, StartingZoraSapphire.Value<uint8_t>());
// AddItemToInventory(RG_FOREST_MEDALLION, StartingForestMedallion.Value<uint8_t>());
// AddItemToInventory(RG_FIRE_MEDALLION, StartingFireMedallion.Value<uint8_t>());
// AddItemToInventory(RG_WATER_MEDALLION, StartingWaterMedallion.Value<uint8_t>());
// AddItemToInventory(RG_SPIRIT_MEDALLION, StartingSpiritMedallion.Value<uint8_t>());
// AddItemToInventory(RG_SHADOW_MEDALLION, StartingShadowMedallion.Value<uint8_t>());
// AddItemToInventory(RG_LIGHT_MEDALLION, StartingLightMedallion.Value<uint8_t>());
AddItemToInventory(RG_GOLD_SKULLTULA_TOKEN, ctx->GetOption(RSK_STARTING_SKULLTULA_TOKEN).Value<uint8_t>());
int8_t hearts = StartingHearts.Value<uint8_t>() - 2;
int8_t hearts = ctx->GetOption(RSK_STARTING_HEARTS).Value<uint8_t>() - 2;
AdditionalHeartContainers = 0;
if (hearts < 0) {
AddItemToInventory(RG_PIECE_OF_HEART, 4);
// Plentiful and minimal have less than 4 standard pieces of heart so also replace the winner heart
if (ItemPoolValue.Value<uint8_t>() == 0 || ItemPoolValue.Value<uint8_t>() == 3) {
if (ctx->GetOption(RSK_ITEM_POOL).Value<uint8_t>() == 0 || ctx->GetOption(RSK_ITEM_POOL).Value<uint8_t>() == 3) {
AddItemToInventory(RG_TREASURE_GAME_HEART);
}
AdditionalHeartContainers = 1 - hearts;
} else if (hearts > 0) {
// 16 containers in plentiful, 8 in balanced and 0 in the others
uint8_t maxContainers = 8 * std::max(0, 2 - ItemPoolValue.Value<uint8_t>());
uint8_t maxContainers = 8 * std::max(0, 2 - ctx->GetOption(RSK_ITEM_POOL).Value<uint8_t>());
if (hearts <= maxContainers) {
AddItemToInventory(RG_HEART_CONTAINER, hearts);

View File

@@ -1,6 +1,7 @@
#pragma once
#include <string>
#include "z64.h"
#define PLURAL 0
#define SINGULAR 1
@@ -12,6 +13,7 @@ public:
: english(std::move(english_)),
french(std::move(french_)),
spanish(std::move(spanish_)) {}
Text(std::string english_) : english(std::move(english_)), french(std::move("")), spanish(std::move("")) {}
const std::string& GetEnglish() const {
return english;
@@ -31,6 +33,18 @@ public:
return english;
}
const std::string& GetForLanguage(uint8_t language) const {
switch (language) {
case LANGUAGE_ENG:
return english;
case LANGUAGE_FRA:
return french;
case LANGUAGE_GER:
default:
return english; // TODO: German
}
}
Text operator+ (const Text& right) const {
return Text{english + right.GetEnglish(), french + right.GetFrench(), spanish + right.GetSpanish()};
}
@@ -43,6 +57,10 @@ public:
return english == right.english;
}
bool operator==(const std::string& right) const {
return english == right || french == right || spanish == right;
}
bool operator!=(const Text& right) const {
return !operator==(right);
}

View File

@@ -1,26 +0,0 @@
#include "trial.hpp"
namespace Trial {
TrialInfo::TrialInfo(Text name_)
: name(std::move(name_)) {}
TrialInfo::~TrialInfo() = default;
TrialInfo ForestTrial = TrialInfo(Text{"the Forest Trial", /*french*/"l'épreuve de la Forêt", /*spanish*/"la prueba del bosque"});
TrialInfo FireTrial = TrialInfo(Text{"the Fire Trial", /*french*/"l'épreuve du Feu", /*spanish*/"la prueba del fuego"});
TrialInfo WaterTrial = TrialInfo(Text{"the Water Trial", /*french*/"l'épreuve de l'Eau", /*spanish*/"la prueba del agua"});
TrialInfo SpiritTrial = TrialInfo(Text{"the Spirit Trial", /*french*/"l'épreuve de l'Esprit", /*spanish*/"la prueba del espíritu"});
TrialInfo ShadowTrial = TrialInfo(Text{"the Shadow Trial", /*french*/"l'épreuve de l'Ombre", /*spanish*/"la prueba de las sombras"});
TrialInfo LightTrial = TrialInfo(Text{"the Light Trial", /*french*/"l'épreuve de la Lumière", /*spanish*/"la prueba de la luz"});
const TrialArray trialList = {
&ForestTrial,
&FireTrial,
&WaterTrial,
&SpiritTrial,
&ShadowTrial,
&LightTrial,
};
} //namespace Trial

View File

@@ -1,51 +0,0 @@
#pragma once
#include <array>
#include "text.hpp"
//This is probably overkill for a small amount of information, but we can add
//stuff later if we want
namespace Trial {
class TrialInfo {
public:
TrialInfo(const Text name_);
~TrialInfo();
Text GetName() const {
return name;
}
bool IsSkipped() const {
return skipped;
}
bool IsRequired() const {
return !skipped;
}
void SetAsRequired() {
skipped = false;
}
void SetAsSkipped() {
skipped = true;
}
private:
Text name;
bool skipped = true;
};
extern TrialInfo ForestTrial;
extern TrialInfo FireTrial;
extern TrialInfo WaterTrial;
extern TrialInfo SpiritTrial;
extern TrialInfo ShadowTrial;
extern TrialInfo LightTrial;
using TrialArray = std::array<TrialInfo*, 6>;
extern const TrialArray trialList;
} //namespace Trial

View File

@@ -1,17 +1,58 @@
#include "context.h"
#include "static_data.h"
#include "soh/OTRGlobals.h"
#include "soh/Enhancements/item-tables/ItemTableManager.h"
#include "3drando/shops.hpp"
#include "3drando/dungeon.hpp"
#include "dungeon.h"
#include "trial.h"
#include "entrance.h"
#include "settings.h"
#include "rando_hash.h"
#include <fstream>
#include <spdlog/spdlog.h>
namespace Rando {
std::weak_ptr<Context> Context::mContext;
Context::Context() {
for (auto& location : StaticData::GetLocationTable()) {
mSpoilerfileCheckNameToEnum[location.GetName()] = location.GetRandomizerCheck();
}
mSpoilerfileCheckNameToEnum["Invalid Location"] = RC_UNKNOWN_CHECK;
mSpoilerfileCheckNameToEnum["Link's Pocket"] = RC_LINKS_POCKET;
for (auto& item : StaticData::GetItemTable()) {
// Easiest way to filter out all the empty values from the array, since we still technically want the 0/RG_NONE
// entry
if (item.GetName().english.empty())
continue;
mSpoilerfileGetNameToEnum[item.GetName().english] = item.GetRandomizerGet();
mSpoilerfileGetNameToEnum[item.GetName().french] = item.GetRandomizerGet();
}
mSpoilerfileHintTypeNameToEnum = {
{ "Trial", HINT_TYPE_TRIAL },
{ "Always", HINT_TYPE_ALWAYS },
{ "WotH", HINT_TYPE_WOTH },
{ "Barren", HINT_TYPE_BARREN },
{ "Entrance", HINT_TYPE_ENTRANCE },
{ "Sometimes", HINT_TYPE_SOMETIMES },
{ "Random", HINT_TYPE_RANDOM },
{ "Static", HINT_TYPE_STATIC },
{ "Song", HINT_TYPE_SONG },
{ "Overworld", HINT_TYPE_OVERWORLD },
{ "Dungeon", HINT_TYPE_DUNGEON },
{ "Junk", HINT_TYPE_JUNK },
{ "Named Item", HINT_TYPE_NAMED_ITEM },
{ "Random", HINT_TYPE_RANDOM }
};
for (int i = 0; i < RC_MAX; i++) {
itemLocationTable[i] = ItemLocation((RandomizerCheck)i);
}
mEntranceShuffler = std::make_shared<EntranceShuffler>();
mDungeons = std::make_shared<Dungeons>();
mTrials = std::make_shared<Trials>();
mSettings = std::make_shared<Settings>();
}
std::shared_ptr<Context> Context::CreateInstance() {
@@ -27,7 +68,7 @@ std::shared_ptr<Context> Context::GetInstance() {
return mContext.lock();
}
Hint *Context::GetHint(RandomizerHintKey hintKey) {
Hint* Context::GetHint(RandomizerHintKey hintKey) {
return &hintTable[hintKey];
}
@@ -37,10 +78,14 @@ void Context::AddHint(RandomizerHintKey hintId, Text text, RandomizerCheck hinte
GetItemLocation(hintedLocation)->SetHintKey(hintId);
}
ItemLocation *Context::GetItemLocation(RandomizerCheck locKey) {
ItemLocation* Context::GetItemLocation(RandomizerCheck locKey) {
return &(itemLocationTable[locKey]);
}
ItemLocation* Context::GetItemLocation(size_t locKey) {
return &(itemLocationTable[static_cast<RandomizerCheck>(locKey)]);
}
void Context::PlaceItemInLocation(RandomizerCheck locKey, RandomizerGet item, bool applyEffectImmediately,
bool setHidden) {
auto loc = GetItemLocation(locKey);
@@ -50,19 +95,20 @@ void Context::PlaceItemInLocation(RandomizerCheck locKey, RandomizerGet item, bo
SPDLOG_DEBUG(StaticData::GetLocation(locKey)->GetName());
SPDLOG_DEBUG("\n\n");
if (applyEffectImmediately || Settings::Logic.Is(LOGIC_NONE) || Settings::Logic.Is(LOGIC_VANILLA)) {
if (applyEffectImmediately || mSettings->Setting(RSK_LOGIC_RULES).Is(RO_LOGIC_GLITCHLESS) || mSettings->Setting(RSK_LOGIC_RULES).Is(RO_LOGIC_VANILLA)) {
Rando::StaticData::RetrieveItem(item).ApplyEffect();
}
//TODO? Show Progress
// TODO? Show Progress
// If we're placing a non-shop item in a shop location, we want to record it for custom messages
if (StaticData::RetrieveItem(item).GetItemType() != ITEMTYPE_SHOP &&
Rando::StaticData::GetLocation(locKey)->IsCategory(Category::cShop)) {
int index = TransformShopIndex(GetShopIndex(locKey));
NonShopItems[index].Name = Rando::StaticData::RetrieveItem(item).GetName();
NonShopItems[index].Repurchaseable = Rando::StaticData::RetrieveItem(item).GetItemType() == ITEMTYPE_REFILL ||
Rando::StaticData::RetrieveItem(item).GetHintKey() == RHT_PROGRESSIVE_BOMBCHUS;
NonShopItems[index].Repurchaseable =
Rando::StaticData::RetrieveItem(item).GetItemType() == ITEMTYPE_REFILL ||
Rando::StaticData::RetrieveItem(item).GetHintKey() == RHT_PROGRESSIVE_BOMBCHUS;
}
loc->SetPlacedItem(item);
@@ -78,7 +124,7 @@ void Context::AddLocation(RandomizerCheck loc, std::vector<RandomizerCheck>* des
destination->push_back(loc);
}
template<typename Container>
template <typename Container>
void Context::AddLocations(const Container& locations, std::vector<RandomizerCheck>* destination) {
if (destination == nullptr) {
destination = &allLocations;
@@ -89,19 +135,19 @@ void Context::AddLocations(const Container& locations, std::vector<RandomizerChe
void Context::GenerateLocationPool() {
allLocations.clear();
AddLocation(RC_LINKS_POCKET);
if (Settings::TriforceHunt.Is(TRIFORCE_HUNT_ON)) {
if (mSettings->Setting(RSK_TRIFORCE_HUNT)) {
AddLocation(RC_TRIFORCE_COMPLETED);
}
AddLocations(StaticData::overworldLocations);
for (auto dungeon : Dungeon::dungeonList) {
for (auto dungeon : mDungeons->GetDungeonList()) {
AddLocations(dungeon->GetDungeonLocations());
}
}
void Context::AddExcludedOptions() {
AddLocations(StaticData::overworldLocations, &everyPossibleLocation);
for (auto dungeon : Dungeon::dungeonList) {
for (auto dungeon : mDungeons->GetDungeonList()) {
AddLocations(dungeon->GetEveryLocation(), &everyPossibleLocation);
}
for (RandomizerCheck rc : everyPossibleLocation) {
@@ -144,15 +190,13 @@ void Context::LocationReset() {
GetItemLocation(il)->RemoveFromPool();
}
for (RandomizerCheck il : Rando::StaticData::otherHintLocations) {
GetItemLocation(il)->RemoveFromPool();
}
GetItemLocation(RC_GANONDORF_HINT)->RemoveFromPool();
}
void Context::HintReset() {
for (RandomizerCheck il : Rando::StaticData::gossipStoneLocations) {
GetItemLocation(il)->ResetVariables();
GetHint((RandomizerHintKey)(il - RC_DMC_GOSSIP_STONE + 1))->ResetVariables();
GetHint((RandomizerHintKey)(il - RC_COLOSSUS_GOSSIP_STONE + 1))->ResetVariables();
}
}
@@ -161,24 +205,17 @@ void Context::CreateItemOverrides() {
for (RandomizerCheck locKey : allLocations) {
auto loc = Rando::StaticData::GetLocation(locKey);
auto itemLoc = GetItemLocation(locKey);
ItemOverride_Value val = Rando::StaticData::RetrieveItem(itemLoc->GetPlacedRandomizerGet()).Value();
// If this is an ice trap, store the disguise model in iceTrapModels
if (itemLoc->GetPlacedRandomizerGet() == RG_ICE_TRAP) {
iceTrapModels[loc->GetRandomizerCheck()] = val.looksLikeItemId;
ItemOverride val(locKey, RandomElement(possibleIceTrapModels));
iceTrapModels[locKey] = val.LooksLike();
val.SetTrickName(GetIceTrapName(val.LooksLike()));
// If this is ice trap is in a shop, change the name based on what the model will look like
if (loc->IsCategory(Category::cShop)) {
NonShopItems[TransformShopIndex(GetShopIndex(locKey))].Name = GetIceTrapName(val.looksLikeItemId);
NonShopItems[TransformShopIndex(GetShopIndex(locKey))].Name = val.GetTrickName();
}
overrides[locKey] = val;
}
overrides.insert({
.key = itemLoc->Key(),
.value = val,
});
SPDLOG_DEBUG("\tScene: ");
SPDLOG_DEBUG(std::to_string(itemLoc->Key().scene));
SPDLOG_DEBUG("\tType: ");
SPDLOG_DEBUG(std::to_string(itemLoc->Key().type));
SPDLOG_DEBUG("\t");
SPDLOG_DEBUG(loc->GetName());
SPDLOG_DEBUG(": ");
SPDLOG_DEBUG(itemLoc->GetPlacedItemName().GetEnglish());
@@ -187,4 +224,339 @@ void Context::CreateItemOverrides() {
SPDLOG_DEBUG("Overrides Created: ");
SPDLOG_DEBUG(std::to_string(overrides.size()));
}
bool Context::IsSeedGenerated() {
return mSeedGenerated;
}
void Context::SetSeedGenerated(bool seedGenerated) {
mSeedGenerated = seedGenerated;
}
bool Context::IsSpoilerLoaded() {
return mSpoilerLoaded;
}
void Context::SetSpoilerLoaded(bool spoilerLoaded) {
mSpoilerLoaded = spoilerLoaded;
}
bool Context::IsPlandoLoaded() {
return mPlandoLoaded;
}
void Context::SetPlandoLoaded(bool plandoLoaded) {
mPlandoLoaded = plandoLoaded;
}
GetItemEntry Context::GetFinalGIEntry(RandomizerCheck rc, bool checkObtainability, GetItemID ogItemId) {
auto itemLoc = GetItemLocation(rc);
if (itemLoc->GetPlacedRandomizerGet() == RG_NONE) {
if (ogItemId != GI_NONE) {
return ItemTableManager::Instance->RetrieveItemEntry(MOD_NONE, ogItemId);
}
return ItemTableManager::Instance->RetrieveItemEntry(
MOD_NONE, StaticData::RetrieveItem(StaticData::GetLocation(rc)->GetVanillaItem()).GetItemID());
}
if (checkObtainability && OTRGlobals::Instance->gRandomizer->GetItemObtainabilityFromRandomizerGet(
itemLoc->GetPlacedRandomizerGet()) != CAN_OBTAIN) {
return ItemTableManager::Instance->RetrieveItemEntry(MOD_NONE, GI_RUPEE_BLUE);
}
GetItemEntry giEntry = itemLoc->GetPlacedItem().GetGIEntry_Copy();
if (overrides.contains(rc)) {
auto fakeGiEntry = StaticData::RetrieveItem(overrides[rc].LooksLike()).GetGIEntry();
giEntry.gid = fakeGiEntry->gid;
giEntry.gi = fakeGiEntry->gi;
giEntry.drawItemId = fakeGiEntry->drawItemId;
giEntry.drawModIndex = fakeGiEntry->drawModIndex;
giEntry.drawFunc = fakeGiEntry->drawFunc;
}
return giEntry;
}
std::string sanitize(std::string stringValue) {
// Add backslashes.
for (auto i = stringValue.begin();;) {
auto const pos =
std::find_if(i, stringValue.end(), [](char const c) { return '\\' == c || '\'' == c || '"' == c; });
if (pos == stringValue.end()) {
break;
}
i = std::next(stringValue.insert(pos, '\\'), 2);
}
// Removes others.
stringValue.erase(std::remove_if(stringValue.begin(), stringValue.end(),
[](char const c) { return '\n' == c || '\r' == c || '\0' == c || '\x1A' == c; }),
stringValue.end());
return stringValue;
}
void Context::ParseSpoiler(const char* spoilerFileName, bool plandoMode) {
std::ifstream spoilerFileStream(sanitize(spoilerFileName));
if (!spoilerFileStream) {
return;
}
mSeedGenerated = false;
mSpoilerLoaded = false;
mPlandoLoaded = false;
try {
nlohmann::json spoilerFileJson;
spoilerFileStream >> spoilerFileJson;
ParseHashIconIndexesJson(spoilerFileJson);
mSettings->ParseJson(spoilerFileJson);
if (plandoMode) {
ParseItemLocationsJson(spoilerFileJson);
ParseHintJson(spoilerFileJson);
mEntranceShuffler->ParseJson(spoilerFileJson);
mDungeons->ParseJson(spoilerFileJson);
mTrials->ParseJson(spoilerFileJson);
mPlandoLoaded = true;
}
mSpoilerLoaded = true;
mSeedGenerated = false;
} catch (std::exception& e) {
throw e;
}
}
void Context::ParseHashIconIndexesJson(nlohmann::json spoilerFileJson) {
nlohmann::json hashJson = spoilerFileJson["file_hash"];
int index = 0;
for (auto it = hashJson.begin(); it != hashJson.end(); ++it) {
hashIconIndexes[index] = gSeedTextures[it.value()].id;
index++;
}
}
void Context::ParseItemLocationsJson(nlohmann::json spoilerFileJson) {
nlohmann::json locationsJson = spoilerFileJson["locations"];
for (auto it = locationsJson.begin(); it != locationsJson.end(); ++it) {
RandomizerCheck rc = mSpoilerfileCheckNameToEnum[it.key()];
if (it->is_structured()) {
nlohmann::json itemJson = *it;
for (auto itemit = itemJson.begin(); itemit != itemJson.end(); ++itemit) {
if (itemit.key() == "item") {
itemLocationTable[rc].SetPlacedItem(mSpoilerfileGetNameToEnum[itemit.value().template get<std::string>()]);
} else if (itemit.key() == "price") {
itemLocationTable[rc].SetCustomPrice(itemit.value().template get<uint16_t>());
} else if (itemit.key() == "model") {
overrides[rc] = ItemOverride(rc, mSpoilerfileGetNameToEnum[itemit.value().template get<std::string>()]);
} else if (itemit.key() == "trickName") {
overrides[rc].SetTrickName(Text(itemit.value().template get<std::string>()));
}
}
} else {
itemLocationTable[rc].SetPlacedItem(mSpoilerfileGetNameToEnum[it.value().template get<std::string>()]);
}
}
}
std::string AltarIconString(char iconChar) {
std::string iconString = "";
switch (iconChar) {
case '0':
// Kokiri Emerald
iconString += 0x13;
iconString += 0x6C;
break;
case '1':
// Goron Ruby
iconString += 0x13;
iconString += 0x6D;
break;
case '2':
// Zora Sapphire
iconString += 0x13;
iconString += 0x6E;
break;
case '3':
// Forest Medallion
iconString += 0x13;
iconString += 0x66;
break;
case '4':
// Fire Medallion
iconString += 0x13;
iconString += 0x67;
break;
case '5':
// Water Medallion
iconString += 0x13;
iconString += 0x68;
break;
case '6':
// Spirit Medallion
iconString += 0x13;
iconString += 0x69;
break;
case '7':
// Shadow Medallion
iconString += 0x13;
iconString += 0x6A;
break;
case '8':
// Light Medallion
iconString += 0x13;
iconString += 0x6B;
break;
case 'o':
// Open DOT (master sword)
iconString += 0x13;
iconString += 0x3C;
break;
case 'c':
// Closed DOT (fairy ocarina)
iconString += 0x13;
iconString += 0x07;
break;
case 'i':
// Intended DOT (oot)
iconString += 0x13;
iconString += 0x08;
break;
case 'l':
// Light Arrow (for bridge reqs)
iconString += 0x13;
iconString += 0x12;
break;
case 'b':
// Boss Key (ganon boss key location)
iconString += 0x13;
iconString += 0x74;
break;
case 'L':
// Bow with Light Arrow
iconString += 0x13;
iconString += 0x3A;
break;
case 'k':
// Kokiri Tunic
iconString += 0x13;
iconString += 0x41;
break;
}
return iconString;
}
std::string FormatJsonHintText(std::string jsonHint) {
std::string formattedHintMessage = jsonHint;
// add icons to altar text
for (char iconChar : { '0', '1', '2', '3', '4', '5', '6', '7', '8', 'o', 'c', 'i', 'l', 'b', 'L', 'k' }) {
std::string textToReplace = "$";
textToReplace += iconChar;
size_t start_pos = formattedHintMessage.find(textToReplace);
if (!(start_pos == std::string::npos)) {
std::string iconString = AltarIconString(iconChar);
formattedHintMessage.replace(start_pos, textToReplace.length(), iconString);
}
}
return formattedHintMessage;
}
void Context::ParseHintJson(nlohmann::json spoilerFileJson) {
// Child Altar
std::string childAltarJsonText = spoilerFileJson["childAltar"]["hintText"].template get<std::string>();
std::string formattedChildAltarText = FormatJsonHintText(childAltarJsonText);
AddHint(RH_ALTAR_CHILD, Text(formattedChildAltarText), RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, Text());
mEmeraldLoc = mSpoilerfileCheckNameToEnum[spoilerFileJson["childAltar"]["rewards"]["emeraldLoc"]];
mRubyLoc = mSpoilerfileCheckNameToEnum[spoilerFileJson["childAltar"]["rewards"]["rubyLoc"]];
mSapphireLoc = mSpoilerfileCheckNameToEnum[spoilerFileJson["childAltar"]["rewards"]["sapphireLoc"]];
// Adult Altar
std::string adultAltarJsonText = spoilerFileJson["adultAltar"]["hintText"].template get<std::string>();
std::string formattedAdultAltarText = FormatJsonHintText(adultAltarJsonText);
AddHint(RH_ALTAR_ADULT, Text(formattedAdultAltarText), RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, Text());
mForestMedallionLoc = mSpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["forestMedallionLoc"].template get<std::string>()];
mFireMedallionLoc = mSpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["fireMedallionLoc"].template get<std::string>()];
mWaterMedallionLoc = mSpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["waterMedallionLoc"].template get<std::string>()];
mShadowMedallionLoc = mSpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["shadowMedallionLoc"].template get<std::string>()];
mSpiritMedallionLoc = mSpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["spiritMedallionLoc"].template get<std::string>()];
mLightMedallionLoc = mSpoilerfileCheckNameToEnum[spoilerFileJson["adultAltar"]["rewards"]["lightMedallionLoc"].template get<std::string>()];
// Ganondorf and Sheik Light Arrow Hints
std::string ganonHintText = FormatJsonHintText(spoilerFileJson["ganonHintText"].template get<std::string>());
RandomizerCheck lightArrowLoc = mSpoilerfileCheckNameToEnum[spoilerFileJson["lightArrowHintLoc"].template get<std::string>()];
std::string lightArrowRegion = spoilerFileJson["lightArrowHintRegion"].template get<std::string>();
AddHint(RH_GANONDORF_HINT, Text(ganonHintText), lightArrowLoc, HINT_TYPE_STATIC, Text(lightArrowRegion));
std::string sheikText = FormatJsonHintText(spoilerFileJson["sheikText"].template get<std::string>());
AddHint(RH_SHEIK_LIGHT_ARROWS, Text(sheikText), lightArrowLoc, HINT_TYPE_STATIC, lightArrowRegion);
std::string ganonText = FormatJsonHintText(spoilerFileJson["ganonText"].template get<std::string>());
AddHint(RH_GANONDORF_NOHINT, Text(ganonText), RC_UNKNOWN_CHECK, HINT_TYPE_JUNK, Text());
// Dampe Hookshot Hint
std::string dampeText = FormatJsonHintText(spoilerFileJson["dampeText"].template get<std::string>());
std::string dampeRegion = spoilerFileJson["dampeRegion"].template get<std::string>();
RandomizerCheck dampeHintLoc = mSpoilerfileCheckNameToEnum[spoilerFileJson["dampeHintLoc"].template get<std::string>()];
AddHint(RH_DAMPES_DIARY, Text(dampeText), dampeHintLoc, HINT_TYPE_STATIC, Text(dampeRegion));
// Greg Hint
std::string gregText = FormatJsonHintText(spoilerFileJson["gregText"].template get<std::string>());
std::string gregRegion = spoilerFileJson["gregRegion"].template get<std::string>();
RandomizerCheck gregLoc = mSpoilerfileCheckNameToEnum[spoilerFileJson["gregLoc"].template get<std::string>()];
AddHint(RH_GREG_RUPEE, Text(gregText), gregLoc, HINT_TYPE_STATIC, Text(gregRegion));
// Saria Magic Hint
std::string sariaText = FormatJsonHintText(spoilerFileJson["sariaText"].template get<std::string>());
std::string sariaRegion = spoilerFileJson["sariaRegion"].template get<std::string>();
RandomizerCheck sariaHintLoc = mSpoilerfileCheckNameToEnum[spoilerFileJson["sariaHintLoc"].template get<std::string>()];
AddHint(RH_SARIA, Text(sariaText), sariaHintLoc, HINT_TYPE_STATIC, Text(sariaRegion));
// Warp Songs
std::string warpMinuetText = FormatJsonHintText(spoilerFileJson["warpMinuetText"].template get<std::string>());
AddHint(RH_MINUET_WARP_LOC, Text(warpMinuetText), RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, Text(warpMinuetText));
std::string warpBoleroText = FormatJsonHintText(spoilerFileJson["warpBoleroText"].template get<std::string>());
AddHint(RH_BOLERO_WARP_LOC, Text(warpBoleroText), RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, Text(warpBoleroText));
std::string warpSerenadeText = FormatJsonHintText(spoilerFileJson["warpSerenadeText"].template get<std::string>());
AddHint(RH_SERENADE_WARP_LOC, Text(warpSerenadeText), RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, Text(warpSerenadeText));
std::string warpRequiemText = FormatJsonHintText(spoilerFileJson["warpRequiemText"].template get<std::string>());
AddHint(RH_REQUIEM_WARP_LOC, Text(warpRequiemText), RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, Text(warpRequiemText));
std::string warpNocturneText = FormatJsonHintText(spoilerFileJson["warpNocturneText"].template get<std::string>());
AddHint(RH_NOCTURNE_WARP_LOC, Text(warpNocturneText), RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, Text(warpNocturneText));
std::string warpPreludeText = FormatJsonHintText(spoilerFileJson["warpPreludeText"].template get<std::string>());
AddHint(RH_PRELUDE_WARP_LOC, Text(warpPreludeText), RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, Text(warpPreludeText));
// Gossip Stones
nlohmann::json hintsJson = spoilerFileJson["hints"];
for (auto it = hintsJson.begin(); it != hintsJson.end(); it++) {
RandomizerCheck gossipStoneLoc = mSpoilerfileCheckNameToEnum[it.key()];
nlohmann::json hintInfo = it.value();
std::string hintText = FormatJsonHintText(hintInfo["hint"].template get<std::string>());
HintType hintType = mSpoilerfileHintTypeNameToEnum[hintInfo["type"].template get<std::string>()];
RandomizerCheck hintedLocation = mSpoilerfileCheckNameToEnum[hintInfo["location"]];
std::string hintedArea = hintInfo["area"].template get<std::string>();
AddHint(RandomizerHintKey(gossipStoneLoc - RC_COLOSSUS_GOSSIP_STONE + 1), Text(hintText), hintedLocation, hintType, hintedArea);
}
}
std::shared_ptr<Settings> Context::GetSettings() {
return mSettings;
}
const std::shared_ptr<EntranceShuffler> Context::GetEntranceShuffler() {
return mEntranceShuffler;
}
std::shared_ptr<Dungeons> Context::GetDungeons() {
return mDungeons;
}
DungeonInfo* Context::GetDungeon(size_t key) {
return mDungeons->GetDungeon(DungeonKey(key));
}
std::shared_ptr<Trials> Context::GetTrials() {
return mTrials;
}
TrialInfo* Context::GetTrial(size_t key) {
return mTrials->GetTrial(TrialKey(key));
}
Sprite* Context::GetSeedTexture(uint8_t index) {
return &gSeedTextures[index];
}
Rando::Option& Context::GetOption(RandomizerSettingKey key) {
return mSettings->Setting(key);
}
Rando::Option& Context::GetTrickOption(RandomizerTrick key) {
return mSettings->GetTrickOption(key);
}
} // namespace Rando

View File

@@ -2,11 +2,14 @@
#include "randomizerTypes.h"
#include "item_location.h"
#include "item_override.h"
#include "3drando/text.hpp"
#include "hint.h"
#include <memory>
#include <array>
#include <map>
#include <nlohmann/json.hpp>
/**
* @brief Singleton for storing and accessing dynamic Randomizer-related data
@@ -17,6 +20,13 @@
* used as a Singleton.
*/
namespace Rando {
class EntranceShuffler;
class Settings;
class Dungeons;
class DungeonInfo;
class TrialInfo;
class Trials;
class Context {
public:
Context();
@@ -26,6 +36,7 @@ class Context {
void AddHint(RandomizerHintKey hintId, Text text, RandomizerCheck hintedLocation, HintType hintType,
Text hintedRegion);
ItemLocation* GetItemLocation(RandomizerCheck locKey);
ItemLocation* GetItemLocation(size_t locKey);
void PlaceItemInLocation(RandomizerCheck locKey, RandomizerGet item, bool applyEffectImmediately = false,
bool setHidden = false);
std::vector<RandomizerCheck> allLocations;
@@ -40,17 +51,58 @@ class Context {
void ItemReset();
void HintReset();
void CreateItemOverrides();
std::set<ItemOverride, ItemOverride_Compare> overrides = {};
bool IsSeedGenerated();
void SetSeedGenerated(bool seedGenerated = true);
bool IsSpoilerLoaded();
void SetSpoilerLoaded(bool spoilerLoaded = true);
bool IsPlandoLoaded();
void SetPlandoLoaded(bool plandoLoaded = true);
std::shared_ptr<Settings> GetSettings();
const std::shared_ptr<EntranceShuffler> GetEntranceShuffler();
std::shared_ptr<Dungeons> GetDungeons();
DungeonInfo* GetDungeon(size_t key);
std::shared_ptr<Trials> GetTrials();
TrialInfo* GetTrial(size_t key);
Sprite* GetSeedTexture(uint8_t index);
Option& GetOption(RandomizerSettingKey key);
Option& GetTrickOption(RandomizerTrick key);
GetItemEntry GetFinalGIEntry(RandomizerCheck rc, bool checkObtainability = true, GetItemID ogItemId = GI_NONE);
void ParseSpoiler(const char* spoilerFileName, bool plandoMode);
void ParseHashIconIndexesJson(nlohmann::json spoilerFileJson);
void ParseItemLocationsJson(nlohmann::json spoilerFileJson);
void ParseHintJson(nlohmann::json spoilerFileJson);
std::map<RandomizerCheck, ItemOverride> overrides = {};
std::vector<std::vector<RandomizerCheck>> playthroughLocations = {};
std::vector<RandomizerCheck> everyPossibleLocation = {};
std::vector<RandomizerCheck> wothLocations = {};
std::unordered_map<RandomizerCheck, uint8_t> iceTrapModels = {};
std::vector<RandomizerGet> possibleIceTrapModels = {};
std::unordered_map<RandomizerCheck, RandomizerGet> iceTrapModels = {};
std::array<uint8_t, 5> hashIconIndexes = {};
std::unordered_map<std::string, RandomizerCheck> mSpoilerfileCheckNameToEnum;
bool playthroughBeatable = false;
bool allLocationsReachable = false;
private:
static std::weak_ptr<Context> mContext;
std::unordered_map<std::string, RandomizerGet> mSpoilerfileGetNameToEnum;
std::unordered_map<std::string, HintType> mSpoilerfileHintTypeNameToEnum;
std::array<Hint, RH_MAX> hintTable = {};
RandomizerCheck mEmeraldLoc;
RandomizerCheck mRubyLoc;
RandomizerCheck mSapphireLoc;
RandomizerCheck mForestMedallionLoc;
RandomizerCheck mFireMedallionLoc;
RandomizerCheck mWaterMedallionLoc;
RandomizerCheck mShadowMedallionLoc;
RandomizerCheck mSpiritMedallionLoc;
RandomizerCheck mLightMedallionLoc;
std::array<ItemLocation, RC_MAX> itemLocationTable = {};
std::shared_ptr<Settings> mSettings;
std::shared_ptr<EntranceShuffler> mEntranceShuffler;
std::shared_ptr<Dungeons> mDungeons;
std::shared_ptr<Trials> mTrials;
bool mSeedGenerated = false;
bool mSpoilerLoaded = false;
bool mPlandoLoaded = false;
};
} // namespace Rando

View File

@@ -0,0 +1,783 @@
#include "dungeon.h"
#include "3drando/pool_functions.hpp"
#include "static_data.h"
#include "context.h"
namespace Rando {
DungeonInfo::DungeonInfo(std::string name_, RandomizerHintTextKey hintKey_, RandomizerGet map_, RandomizerGet compass_,
RandomizerGet smallKey_, RandomizerGet keyRing_, RandomizerGet bossKey_,
uint8_t vanillaKeyCount_, uint8_t mqKeyCount_, std::vector<RandomizerCheck> vanillaLocations_,
std::vector<RandomizerCheck> mqLocations_, std::vector<RandomizerCheck> sharedLocations_,
std::vector<RandomizerCheck> bossRoomLocations_)
: name(std::move(name_)), hintKey(hintKey_), map(map_), compass(compass_), smallKey(smallKey_), keyRing(keyRing_),
bossKey(bossKey_), vanillaKeyCount(vanillaKeyCount_), mqKeyCount(mqKeyCount_),
vanillaLocations(std::move(vanillaLocations_)), mqLocations(std::move(mqLocations_)),
sharedLocations(std::move(sharedLocations_)), bossRoomLocations(std::move(bossRoomLocations_)) {
}
DungeonInfo::DungeonInfo() = default;
DungeonInfo::~DungeonInfo() = default;
const std::string& DungeonInfo::GetName() const {
return name;
}
void DungeonInfo::SetMQ() {
masterQuest = true;
}
void DungeonInfo::ClearMQ() {
masterQuest = false;
}
bool DungeonInfo::IsMQ() const {
return masterQuest;
}
void DungeonInfo::SetKeyRing() {
hasKeyRing = true;
}
void DungeonInfo::ClearKeyRing() {
hasKeyRing = false;
}
bool DungeonInfo::HasKeyRing() const {
return hasKeyRing;
}
bool DungeonInfo::IsVanilla() const {
return !masterQuest;
}
uint8_t DungeonInfo::GetSmallKeyCount() const {
return (masterQuest) ? mqKeyCount : vanillaKeyCount;
}
RandomizerHintTextKey DungeonInfo::GetHintKey() const {
return hintKey;
}
RandomizerGet DungeonInfo::GetSmallKey() const {
return smallKey;
}
RandomizerGet DungeonInfo::GetKeyRing() const {
return keyRing;
}
RandomizerGet DungeonInfo::GetMap() const {
return map;
}
RandomizerGet DungeonInfo::GetCompass() const {
return compass;
}
RandomizerGet DungeonInfo::GetBossKey() const {
return bossKey;
}
void DungeonInfo::PlaceVanillaMap() {
if (map == RG_NONE) {
return;
}
auto dungeonLocations = GetDungeonLocations();
auto mapLocation = FilterFromPool(dungeonLocations, [](const RandomizerCheck loc) {
return StaticData::GetLocation(loc)->IsCategory(Category::cVanillaMap);
})[0];
Context::GetInstance()->PlaceItemInLocation(mapLocation, map);
}
void DungeonInfo::PlaceVanillaCompass() {
if (compass == RG_NONE) {
return;
}
auto dungeonLocations = GetDungeonLocations();
auto compassLocation = FilterFromPool(dungeonLocations, [](const RandomizerCheck loc) {
return StaticData::GetLocation(loc)->IsCategory(Category::cVanillaCompass);
})[0];
Context::GetInstance()->PlaceItemInLocation(compassLocation, compass);
}
void DungeonInfo::PlaceVanillaBossKey() {
if (bossKey == RG_NONE || bossKey == RG_GANONS_CASTLE_BOSS_KEY) {
return;
}
auto dungeonLocations = GetDungeonLocations();
auto bossKeyLocation = FilterFromPool(dungeonLocations, [](const RandomizerCheck loc) {
return StaticData::GetLocation(loc)->IsCategory(Category::cVanillaBossKey);
})[0];
Context::GetInstance()->PlaceItemInLocation(bossKeyLocation, bossKey);
}
void DungeonInfo::PlaceVanillaSmallKeys() {
if (smallKey == RG_NONE) {
return;
}
auto dungeonLocations = GetDungeonLocations();
auto smallKeyLocations = FilterFromPool(dungeonLocations, [](const RandomizerCheck loc) {
return StaticData::GetLocation(loc)->IsCategory(Category::cVanillaSmallKey);
});
for (auto location : smallKeyLocations) {
Context::GetInstance()->PlaceItemInLocation(location, smallKey);
}
}
// Gets the chosen dungeon locations for a playthrough (so either MQ or Vanilla)
std::vector<RandomizerCheck> DungeonInfo::GetDungeonLocations() const {
auto locations = masterQuest ? mqLocations : vanillaLocations;
AddElementsToPool(locations, sharedLocations);
AddElementsToPool(locations, bossRoomLocations);
return locations;
}
// Gets all dungeon locations (MQ + Vanilla)
std::vector<RandomizerCheck> DungeonInfo::GetEveryLocation() const {
auto locations = vanillaLocations;
AddElementsToPool(locations, mqLocations);
AddElementsToPool(locations, sharedLocations);
AddElementsToPool(locations, bossRoomLocations);
return locations;
}
Dungeons::Dungeons() {
dungeonList[DEKU_TREE] =
DungeonInfo("Deku Tree", RHT_DEKU_TREE, RG_DEKU_TREE_MAP, RG_DEKU_TREE_COMPASS, RG_NONE, RG_NONE, RG_NONE, 0, 0,
{
// Vanilla Locations
RC_DEKU_TREE_MAP_CHEST,
RC_DEKU_TREE_COMPASS_CHEST,
RC_DEKU_TREE_COMPASS_ROOM_SIDE_CHEST,
RC_DEKU_TREE_BASEMENT_CHEST,
RC_DEKU_TREE_SLINGSHOT_CHEST,
RC_DEKU_TREE_SLINGSHOT_ROOM_SIDE_CHEST,
RC_DEKU_TREE_GS_BASEMENT_BACK_ROOM,
RC_DEKU_TREE_GS_BASEMENT_GATE,
RC_DEKU_TREE_GS_BASEMENT_VINES,
RC_DEKU_TREE_GS_COMPASS_ROOM,
},
{
// MQ Locations
RC_DEKU_TREE_MQ_MAP_CHEST,
RC_DEKU_TREE_MQ_COMPASS_CHEST,
RC_DEKU_TREE_MQ_SLINGSHOT_CHEST,
RC_DEKU_TREE_MQ_SLINGSHOT_ROOM_BACK_CHEST,
RC_DEKU_TREE_MQ_BASEMENT_CHEST,
RC_DEKU_TREE_MQ_BEFORE_SPINNING_LOG_CHEST,
RC_DEKU_TREE_MQ_AFTER_SPINNING_LOG_CHEST,
RC_DEKU_TREE_MQ_DEKU_SCRUB,
RC_DEKU_TREE_MQ_GS_LOBBY,
RC_DEKU_TREE_MQ_GS_COMPASS_ROOM,
RC_DEKU_TREE_MQ_GS_BASEMENT_GRAVES_ROOM,
RC_DEKU_TREE_MQ_GS_BASEMENT_BACK_ROOM,
},
{},
{
// Boss Room Locations
RC_DEKU_TREE_QUEEN_GOHMA_HEART,
RC_QUEEN_GOHMA,
});
dungeonList[DODONGOS_CAVERN] = DungeonInfo("Dodongo's Cavern", RHT_DODONGOS_CAVERN, RG_DODONGOS_CAVERN_MAP,
RG_DODONGOS_CAVERN_COMPASS, RG_NONE, RG_NONE, RG_NONE, 0, 0,
{
// Vanilla Locations
RC_DODONGOS_CAVERN_MAP_CHEST,
RC_DODONGOS_CAVERN_COMPASS_CHEST,
RC_DODONGOS_CAVERN_BOMB_FLOWER_PLATFORM_CHEST,
RC_DODONGOS_CAVERN_BOMB_BAG_CHEST,
RC_DODONGOS_CAVERN_END_OF_BRIDGE_CHEST,
RC_DODONGOS_CAVERN_DEKU_SCRUB_LOBBY,
RC_DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS,
RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT,
RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT,
RC_DODONGOS_CAVERN_GS_VINES_ABOVE_STAIRS,
RC_DODONGOS_CAVERN_GS_SCARECROW,
RC_DODONGOS_CAVERN_GS_ALCOVE_ABOVE_STAIRS,
RC_DODONGOS_CAVERN_GS_BACK_ROOM,
RC_DODONGOS_CAVERN_GS_SIDE_ROOM_NEAR_LOWER_LIZALFOS,
},
{
// MQ Locations
RC_DODONGOS_CAVERN_MQ_MAP_CHEST,
RC_DODONGOS_CAVERN_MQ_BOMB_BAG_CHEST,
RC_DODONGOS_CAVERN_MQ_COMPASS_CHEST,
RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CHEST,
RC_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_ROOM_CHEST,
RC_DODONGOS_CAVERN_MQ_UNDER_GRAVE_CHEST,
RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR,
RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT,
RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE,
RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS,
RC_DODONGOS_CAVERN_MQ_GS_SCRUB_ROOM,
RC_DODONGOS_CAVERN_MQ_GS_SONG_OF_TIME_BLOCK_ROOM,
RC_DODONGOS_CAVERN_MQ_GS_LIZALFOS_ROOM,
RC_DODONGOS_CAVERN_MQ_GS_LARVAE_ROOM,
RC_DODONGOS_CAVERN_MQ_GS_BACK_AREA,
},
{},
{
// Boss Room Locations
RC_DODONGOS_CAVERN_BOSS_ROOM_CHEST,
RC_DODONGOS_CAVERN_KING_DODONGO_HEART,
RC_KING_DODONGO,
});
dungeonList[JABU_JABUS_BELLY] = DungeonInfo("Jabu Jabu's Belly", RHT_JABU_JABUS_BELLY, RG_JABU_JABUS_BELLY_MAP,
RG_JABU_JABUS_BELLY_COMPASS, RG_NONE, RG_NONE, RG_NONE, 0, 0,
{
// Vanilla Locations
RC_JABU_JABUS_BELLY_MAP_CHEST,
RC_JABU_JABUS_BELLY_COMPASS_CHEST,
RC_JABU_JABUS_BELLY_BOOMERANG_CHEST,
RC_JABU_JABUS_BELLY_DEKU_SCRUB,
RC_JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_LOWER,
RC_JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_UPPER,
RC_JABU_JABUS_BELLY_GS_NEAR_BOSS,
RC_JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM,
},
{
// MQ Locations
RC_JABU_JABUS_BELLY_MQ_FIRST_ROOM_SIDE_CHEST,
RC_JABU_JABUS_BELLY_MQ_MAP_CHEST,
RC_JABU_JABUS_BELLY_MQ_SECOND_ROOM_LOWER_CHEST,
RC_JABU_JABUS_BELLY_MQ_COMPASS_CHEST,
RC_JABU_JABUS_BELLY_MQ_SECOND_ROOM_UPPER_CHEST,
RC_JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_SWITCHES_CHEST,
RC_JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_VINES_CHEST,
RC_JABU_JABUS_BELLY_MQ_NEAR_BOSS_CHEST,
RC_JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_ROOM_CHEST,
RC_JABU_JABUS_BELLY_MQ_BOOMERANG_ROOM_SMALL_CHEST,
RC_JABU_JABUS_BELLY_MQ_BOOMERANG_CHEST,
RC_JABU_JABUS_BELLY_MQ_COW,
RC_JABU_JABUS_BELLY_MQ_GS_TAILPASARAN_ROOM,
RC_JABU_JABUS_BELLY_MQ_GS_INVISIBLE_ENEMIES_ROOM,
RC_JABU_JABUS_BELLY_MQ_GS_BOOMERANG_CHEST_ROOM,
RC_JABU_JABUS_BELLY_MQ_GS_NEAR_BOSS,
},
{},
{
// Boss Room Locations
RC_JABU_JABUS_BELLY_BARINADE_HEART,
RC_BARINADE,
});
dungeonList[FOREST_TEMPLE] =
DungeonInfo("Forest Temple", RHT_FOREST_TEMPLE, RG_FOREST_TEMPLE_MAP, RG_FOREST_TEMPLE_COMPASS,
RG_FOREST_TEMPLE_SMALL_KEY, RG_FOREST_TEMPLE_KEY_RING, RG_FOREST_TEMPLE_BOSS_KEY, 5, 6,
{
// Vanilla Locations
RC_FOREST_TEMPLE_FIRST_ROOM_CHEST,
RC_FOREST_TEMPLE_FIRST_STALFOS_CHEST,
RC_FOREST_TEMPLE_RAISED_ISLAND_COURTYARD_CHEST,
RC_FOREST_TEMPLE_MAP_CHEST,
RC_FOREST_TEMPLE_WELL_CHEST,
RC_FOREST_TEMPLE_FALLING_CEILING_ROOM_CHEST,
RC_FOREST_TEMPLE_EYE_SWITCH_CHEST,
RC_FOREST_TEMPLE_BOSS_KEY_CHEST,
RC_FOREST_TEMPLE_FLOORMASTER_CHEST,
RC_FOREST_TEMPLE_BOW_CHEST,
RC_FOREST_TEMPLE_RED_POE_CHEST,
RC_FOREST_TEMPLE_BLUE_POE_CHEST,
RC_FOREST_TEMPLE_BASEMENT_CHEST,
RC_FOREST_TEMPLE_GS_RAISED_ISLAND_COURTYARD,
RC_FOREST_TEMPLE_GS_FIRST_ROOM,
RC_FOREST_TEMPLE_GS_LEVEL_ISLAND_COURTYARD,
RC_FOREST_TEMPLE_GS_LOBBY,
RC_FOREST_TEMPLE_GS_BASEMENT,
},
{
// MQ Locations
RC_FOREST_TEMPLE_MQ_FIRST_ROOM_CHEST,
RC_FOREST_TEMPLE_MQ_WOLFOS_CHEST,
RC_FOREST_TEMPLE_MQ_BOW_CHEST,
RC_FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_LOWER_CHEST,
RC_FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_UPPER_CHEST,
RC_FOREST_TEMPLE_MQ_WELL_CHEST,
RC_FOREST_TEMPLE_MQ_MAP_CHEST,
RC_FOREST_TEMPLE_MQ_COMPASS_CHEST,
RC_FOREST_TEMPLE_MQ_FALLING_CEILING_ROOM_CHEST,
RC_FOREST_TEMPLE_MQ_BASEMENT_CHEST,
RC_FOREST_TEMPLE_MQ_REDEAD_CHEST,
RC_FOREST_TEMPLE_MQ_BOSS_KEY_CHEST,
RC_FOREST_TEMPLE_MQ_GS_FIRST_HALLWAY,
RC_FOREST_TEMPLE_MQ_GS_BLOCK_PUSH_ROOM,
RC_FOREST_TEMPLE_MQ_GS_RAISED_ISLAND_COURTYARD,
RC_FOREST_TEMPLE_MQ_GS_LEVEL_ISLAND_COURTYARD,
RC_FOREST_TEMPLE_MQ_GS_WELL,
},
{},
{
// Boss Room Locations
RC_FOREST_TEMPLE_PHANTOM_GANON_HEART,
RC_PHANTOM_GANON,
});
dungeonList[FIRE_TEMPLE] =
DungeonInfo("Fire Temple", RHT_FIRE_TEMPLE, RG_FIRE_TEMPLE_MAP, RG_FIRE_TEMPLE_COMPASS,
RG_FIRE_TEMPLE_SMALL_KEY, RG_FIRE_TEMPLE_KEY_RING, RG_FIRE_TEMPLE_BOSS_KEY, 8, 5,
{
// Vanilla Locations
RC_FIRE_TEMPLE_NEAR_BOSS_CHEST,
RC_FIRE_TEMPLE_FLARE_DANCER_CHEST,
RC_FIRE_TEMPLE_BOSS_KEY_CHEST,
RC_FIRE_TEMPLE_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST,
RC_FIRE_TEMPLE_BIG_LAVA_ROOM_LOWER_OPEN_DOOR_CHEST,
RC_FIRE_TEMPLE_BOULDER_MAZE_LOWER_CHEST,
RC_FIRE_TEMPLE_BOULDER_MAZE_UPPER_CHEST,
RC_FIRE_TEMPLE_BOULDER_MAZE_SIDE_ROOM_CHEST,
RC_FIRE_TEMPLE_BOULDER_MAZE_SHORTCUT_CHEST,
RC_FIRE_TEMPLE_SCARECROW_CHEST,
RC_FIRE_TEMPLE_MAP_CHEST,
RC_FIRE_TEMPLE_COMPASS_CHEST,
RC_FIRE_TEMPLE_HIGHEST_GORON_CHEST,
RC_FIRE_TEMPLE_MEGATON_HAMMER_CHEST,
RC_FIRE_TEMPLE_GS_SONG_OF_TIME_ROOM,
RC_FIRE_TEMPLE_GS_BOSS_KEY_LOOP,
RC_FIRE_TEMPLE_GS_BOULDER_MAZE,
RC_FIRE_TEMPLE_GS_SCARECROW_TOP,
RC_FIRE_TEMPLE_GS_SCARECROW_CLIMB,
},
{
// MQ Locations
RC_FIRE_TEMPLE_MQ_NEAR_BOSS_CHEST,
RC_FIRE_TEMPLE_MQ_MEGATON_HAMMER_CHEST,
RC_FIRE_TEMPLE_MQ_COMPASS_CHEST,
RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CHEST,
RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CHEST,
RC_FIRE_TEMPLE_MQ_CHEST_ON_FIRE,
RC_FIRE_TEMPLE_MQ_MAP_ROOM_SIDE_CHEST,
RC_FIRE_TEMPLE_MQ_MAP_CHEST,
RC_FIRE_TEMPLE_MQ_BOSS_KEY_CHEST,
RC_FIRE_TEMPLE_MQ_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST,
RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_SIDE_ROOM_CHEST,
RC_FIRE_TEMPLE_MQ_FREESTANDING_KEY,
RC_FIRE_TEMPLE_MQ_GS_ABOVE_FIRE_WALL_MAZE,
RC_FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_CENTER,
RC_FIRE_TEMPLE_MQ_GS_BIG_LAVA_ROOM_OPEN_DOOR,
RC_FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_SIDE_ROOM,
RC_FIRE_TEMPLE_MQ_GS_SKULL_ON_FIRE,
},
{},
{
// Boos Room Locations
RC_FIRE_TEMPLE_VOLVAGIA_HEART,
RC_VOLVAGIA,
});
dungeonList[WATER_TEMPLE] =
DungeonInfo("Water Temple", RHT_WATER_TEMPLE, RG_WATER_TEMPLE_MAP, RG_WATER_TEMPLE_COMPASS,
RG_WATER_TEMPLE_SMALL_KEY, RG_WATER_TEMPLE_KEY_RING, RG_WATER_TEMPLE_BOSS_KEY, 6, 2,
{
// Vanilla Locations
RC_WATER_TEMPLE_MAP_CHEST,
RC_WATER_TEMPLE_COMPASS_CHEST,
RC_WATER_TEMPLE_TORCHES_CHEST,
RC_WATER_TEMPLE_DRAGON_CHEST,
RC_WATER_TEMPLE_CENTRAL_BOW_TARGET_CHEST,
RC_WATER_TEMPLE_CENTRAL_PILLAR_CHEST,
RC_WATER_TEMPLE_CRACKED_WALL_CHEST,
RC_WATER_TEMPLE_BOSS_KEY_CHEST,
RC_WATER_TEMPLE_LONGSHOT_CHEST,
RC_WATER_TEMPLE_RIVER_CHEST,
RC_WATER_TEMPLE_GS_BEHIND_GATE,
RC_WATER_TEMPLE_GS_FALLING_PLATFORM_ROOM,
RC_WATER_TEMPLE_GS_CENTRAL_PILLAR,
RC_WATER_TEMPLE_GS_NEAR_BOSS_KEY_CHEST,
RC_WATER_TEMPLE_GS_RIVER,
},
{
// MQ Locations
RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_CHEST,
RC_WATER_TEMPLE_MQ_BOSS_KEY_CHEST,
RC_WATER_TEMPLE_MQ_LONGSHOT_CHEST,
RC_WATER_TEMPLE_MQ_COMPASS_CHEST,
RC_WATER_TEMPLE_MQ_MAP_CHEST,
RC_WATER_TEMPLE_MQ_FREESTANDING_KEY,
RC_WATER_TEMPLE_MQ_GS_BEFORE_UPPER_WATER_SWITCH,
RC_WATER_TEMPLE_MQ_GS_FREESTANDING_KEY_AREA,
RC_WATER_TEMPLE_MQ_GS_LIZALFOS_HALLWAY,
RC_WATER_TEMPLE_MQ_GS_RIVER,
RC_WATER_TEMPLE_MQ_GS_TRIPLE_WALL_TORCH,
},
{},
{
// Boss Room Locations
RC_WATER_TEMPLE_MORPHA_HEART,
RC_MORPHA,
});
dungeonList[SPIRIT_TEMPLE] =
DungeonInfo("Spirit Temple", RHT_SPIRIT_TEMPLE, RG_SPIRIT_TEMPLE_MAP, RG_SPIRIT_TEMPLE_COMPASS,
RG_SPIRIT_TEMPLE_SMALL_KEY, RG_SPIRIT_TEMPLE_KEY_RING, RG_SPIRIT_TEMPLE_BOSS_KEY, 5, 7,
{
// Vanilla Locations
RC_SPIRIT_TEMPLE_CHILD_BRIDGE_CHEST,
RC_SPIRIT_TEMPLE_CHILD_EARLY_TORCHES_CHEST,
RC_SPIRIT_TEMPLE_COMPASS_CHEST,
RC_SPIRIT_TEMPLE_EARLY_ADULT_RIGHT_CHEST,
RC_SPIRIT_TEMPLE_FIRST_MIRROR_LEFT_CHEST,
RC_SPIRIT_TEMPLE_FIRST_MIRROR_RIGHT_CHEST,
RC_SPIRIT_TEMPLE_MAP_CHEST,
RC_SPIRIT_TEMPLE_CHILD_CLIMB_NORTH_CHEST,
RC_SPIRIT_TEMPLE_CHILD_CLIMB_EAST_CHEST,
RC_SPIRIT_TEMPLE_SUN_BLOCK_ROOM_CHEST,
RC_SPIRIT_TEMPLE_STATUE_ROOM_HAND_CHEST,
RC_SPIRIT_TEMPLE_STATUE_ROOM_NORTHEAST_CHEST,
RC_SPIRIT_TEMPLE_NEAR_FOUR_ARMOS_CHEST,
RC_SPIRIT_TEMPLE_HALLWAY_LEFT_INVISIBLE_CHEST,
RC_SPIRIT_TEMPLE_HALLWAY_RIGHT_INVISIBLE_CHEST,
RC_SPIRIT_TEMPLE_BOSS_KEY_CHEST,
RC_SPIRIT_TEMPLE_TOPMOST_CHEST,
RC_SPIRIT_TEMPLE_GS_HALL_AFTER_SUN_BLOCK_ROOM,
RC_SPIRIT_TEMPLE_GS_BOULDER_ROOM,
RC_SPIRIT_TEMPLE_GS_LOBBY,
RC_SPIRIT_TEMPLE_GS_SUN_ON_FLOOR_ROOM,
RC_SPIRIT_TEMPLE_GS_METAL_FENCE,
},
{
// MQ Locations
RC_SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_LEFT_CHEST,
RC_SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_RIGHT_CHEST,
RC_SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_RIGHT_CHEST,
RC_SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_LEFT_CHEST,
RC_SPIRIT_TEMPLE_MQ_CHILD_HAMMER_SWITCH_CHEST,
RC_SPIRIT_TEMPLE_MQ_MAP_CHEST,
RC_SPIRIT_TEMPLE_MQ_MAP_ROOM_ENEMY_CHEST,
RC_SPIRIT_TEMPLE_MQ_CHILD_CLIMB_NORTH_CHEST,
RC_SPIRIT_TEMPLE_MQ_CHILD_CLIMB_SOUTH_CHEST,
RC_SPIRIT_TEMPLE_MQ_COMPASS_CHEST,
RC_SPIRIT_TEMPLE_MQ_STATUE_ROOM_LULLABY_CHEST,
RC_SPIRIT_TEMPLE_MQ_STATUE_ROOM_INVISIBLE_CHEST,
RC_SPIRIT_TEMPLE_MQ_SILVER_BLOCK_HALLWAY_CHEST,
RC_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM_CHEST,
RC_SPIRIT_TEMPLE_MQ_SYMPHONY_ROOM_CHEST,
RC_SPIRIT_TEMPLE_MQ_LEEVER_ROOM_CHEST,
RC_SPIRIT_TEMPLE_MQ_BEAMOS_ROOM_CHEST,
RC_SPIRIT_TEMPLE_MQ_CHEST_SWITCH_CHEST,
RC_SPIRIT_TEMPLE_MQ_BOSS_KEY_CHEST,
RC_SPIRIT_TEMPLE_MQ_MIRROR_PUZZLE_INVISIBLE_CHEST,
RC_SPIRIT_TEMPLE_MQ_GS_SYMPHONY_ROOM,
RC_SPIRIT_TEMPLE_MQ_GS_LEEVER_ROOM,
RC_SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_WEST,
RC_SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_NORTH,
RC_SPIRIT_TEMPLE_MQ_GS_SUN_BLOCK_ROOM,
},
{
// Shared Locations
RC_SPIRIT_TEMPLE_SILVER_GAUNTLETS_CHEST,
RC_SPIRIT_TEMPLE_MIRROR_SHIELD_CHEST,
},
{
// Boss Room Locations
RC_SPIRIT_TEMPLE_TWINROVA_HEART,
RC_TWINROVA,
});
dungeonList[SHADOW_TEMPLE] =
DungeonInfo("Shadow Temple", RHT_SHADOW_TEMPLE, RG_SHADOW_TEMPLE_MAP, RG_SHADOW_TEMPLE_COMPASS,
RG_SHADOW_TEMPLE_SMALL_KEY, RG_SHADOW_TEMPLE_KEY_RING, RG_SHADOW_TEMPLE_BOSS_KEY, 5, 6,
{
// Vanilla Locations
RC_SHADOW_TEMPLE_MAP_CHEST,
RC_SHADOW_TEMPLE_HOVER_BOOTS_CHEST,
RC_SHADOW_TEMPLE_COMPASS_CHEST,
RC_SHADOW_TEMPLE_EARLY_SILVER_RUPEE_CHEST,
RC_SHADOW_TEMPLE_INVISIBLE_BLADES_VISIBLE_CHEST,
RC_SHADOW_TEMPLE_INVISIBLE_BLADES_INVISIBLE_CHEST,
RC_SHADOW_TEMPLE_FALLING_SPIKES_LOWER_CHEST,
RC_SHADOW_TEMPLE_FALLING_SPIKES_UPPER_CHEST,
RC_SHADOW_TEMPLE_FALLING_SPIKES_SWITCH_CHEST,
RC_SHADOW_TEMPLE_INVISIBLE_SPIKES_CHEST,
RC_SHADOW_TEMPLE_WIND_HINT_CHEST,
RC_SHADOW_TEMPLE_AFTER_WIND_ENEMY_CHEST,
RC_SHADOW_TEMPLE_AFTER_WIND_HIDDEN_CHEST,
RC_SHADOW_TEMPLE_SPIKE_WALLS_LEFT_CHEST,
RC_SHADOW_TEMPLE_BOSS_KEY_CHEST,
RC_SHADOW_TEMPLE_INVISIBLE_FLOORMASTER_CHEST,
RC_SHADOW_TEMPLE_FREESTANDING_KEY,
RC_SHADOW_TEMPLE_GS_SINGLE_GIANT_POT,
RC_SHADOW_TEMPLE_GS_FALLING_SPIKES_ROOM,
RC_SHADOW_TEMPLE_GS_TRIPLE_GIANT_POT,
RC_SHADOW_TEMPLE_GS_LIKE_LIKE_ROOM,
RC_SHADOW_TEMPLE_GS_NEAR_SHIP,
},
{
// MQ Locations
RC_SHADOW_TEMPLE_MQ_COMPASS_CHEST,
RC_SHADOW_TEMPLE_MQ_HOVER_BOOTS_CHEST,
RC_SHADOW_TEMPLE_MQ_EARLY_GIBDOS_CHEST,
RC_SHADOW_TEMPLE_MQ_MAP_CHEST,
RC_SHADOW_TEMPLE_MQ_BEAMOS_SILVER_RUPEES_CHEST,
RC_SHADOW_TEMPLE_MQ_FALLING_SPIKES_SWITCH_CHEST,
RC_SHADOW_TEMPLE_MQ_FALLING_SPIKES_LOWER_CHEST,
RC_SHADOW_TEMPLE_MQ_FALLING_SPIKES_UPPER_CHEST,
RC_SHADOW_TEMPLE_MQ_INVISIBLE_SPIKES_CHEST,
RC_SHADOW_TEMPLE_MQ_BOSS_KEY_CHEST,
RC_SHADOW_TEMPLE_MQ_SPIKE_WALLS_LEFT_CHEST,
RC_SHADOW_TEMPLE_MQ_STALFOS_ROOM_CHEST,
RC_SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_INVISIBLE_CHEST,
RC_SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_VISIBLE_CHEST,
RC_SHADOW_TEMPLE_MQ_BOMB_FLOWER_CHEST,
RC_SHADOW_TEMPLE_MQ_WIND_HINT_CHEST,
RC_SHADOW_TEMPLE_MQ_AFTER_WIND_HIDDEN_CHEST,
RC_SHADOW_TEMPLE_MQ_AFTER_WIND_ENEMY_CHEST,
RC_SHADOW_TEMPLE_MQ_NEAR_SHIP_INVISIBLE_CHEST,
RC_SHADOW_TEMPLE_MQ_FREESTANDING_KEY,
RC_SHADOW_TEMPLE_MQ_GS_FALLING_SPIKES_ROOM,
RC_SHADOW_TEMPLE_MQ_GS_WIND_HINT_ROOM,
RC_SHADOW_TEMPLE_MQ_GS_AFTER_WIND,
RC_SHADOW_TEMPLE_MQ_GS_AFTER_SHIP,
RC_SHADOW_TEMPLE_MQ_GS_NEAR_BOSS,
},
{},
{
// Boss Room Locations
RC_SHADOW_TEMPLE_BONGO_BONGO_HEART,
RC_BONGO_BONGO,
});
dungeonList[BOTTOM_OF_THE_WELL] = DungeonInfo(
"Bottom of the Well", RHT_BOTTOM_OF_THE_WELL, RG_BOTTOM_OF_THE_WELL_MAP, RG_BOTTOM_OF_THE_WELL_COMPASS,
RG_BOTTOM_OF_THE_WELL_SMALL_KEY, RG_BOTTOM_OF_THE_WELL_KEY_RING, RG_NONE, 3, 2,
{
// Vanilla Locations
RC_BOTTOM_OF_THE_WELL_FRONT_LEFT_FAKE_WALL_CHEST,
RC_BOTTOM_OF_THE_WELL_FRONT_CENTER_BOMBABLE_CHEST,
RC_BOTTOM_OF_THE_WELL_RIGHT_BOTTOM_FAKE_WALL_CHEST,
RC_BOTTOM_OF_THE_WELL_COMPASS_CHEST,
RC_BOTTOM_OF_THE_WELL_CENTER_SKULLTULA_CHEST,
RC_BOTTOM_OF_THE_WELL_BACK_LEFT_BOMBABLE_CHEST,
RC_BOTTOM_OF_THE_WELL_LENS_OF_TRUTH_CHEST,
RC_BOTTOM_OF_THE_WELL_INVISIBLE_CHEST,
RC_BOTTOM_OF_THE_WELL_UNDERWATER_FRONT_CHEST,
RC_BOTTOM_OF_THE_WELL_UNDERWATER_LEFT_CHEST,
RC_BOTTOM_OF_THE_WELL_MAP_CHEST,
RC_BOTTOM_OF_THE_WELL_FIRE_KEESE_CHEST,
RC_BOTTOM_OF_THE_WELL_LIKE_LIKE_CHEST,
RC_BOTTOM_OF_THE_WELL_FREESTANDING_KEY,
RC_BOTTOM_OF_THE_WELL_GS_LIKE_LIKE_CAGE,
RC_BOTTOM_OF_THE_WELL_GS_EAST_INNER_ROOM,
RC_BOTTOM_OF_THE_WELL_GS_WEST_INNER_ROOM,
},
{
// MQ Locations
RC_BOTTOM_OF_THE_WELL_MQ_MAP_CHEST,
RC_BOTTOM_OF_THE_WELL_MQ_LENS_OF_TRUTH_CHEST,
RC_BOTTOM_OF_THE_WELL_MQ_COMPASS_CHEST,
RC_BOTTOM_OF_THE_WELL_MQ_DEAD_HAND_FREESTANDING_KEY,
RC_BOTTOM_OF_THE_WELL_MQ_EAST_INNER_ROOM_FREESTANDING_KEY,
RC_BOTTOM_OF_THE_WELL_MQ_GS_BASEMENT,
RC_BOTTOM_OF_THE_WELL_MQ_GS_COFFIN_ROOM,
RC_BOTTOM_OF_THE_WELL_MQ_GS_WEST_INNER_ROOM,
},
{}, {});
dungeonList[ICE_CAVERN] = DungeonInfo("Ice Cavern", RHT_ICE_CAVERN, RG_ICE_CAVERN_MAP, RG_ICE_CAVERN_COMPASS,
RG_NONE, RG_NONE, RG_NONE, 0, 0,
{
// Vanilla Locations
RC_ICE_CAVERN_MAP_CHEST,
RC_ICE_CAVERN_COMPASS_CHEST,
RC_ICE_CAVERN_IRON_BOOTS_CHEST,
RC_ICE_CAVERN_FREESTANDING_POH,
RC_ICE_CAVERN_GS_PUSH_BLOCK_ROOM,
RC_ICE_CAVERN_GS_SPINNING_SCYTHE_ROOM,
RC_ICE_CAVERN_GS_HEART_PIECE_ROOM,
},
{
// MQ Locations
RC_ICE_CAVERN_MQ_IRON_BOOTS_CHEST,
RC_ICE_CAVERN_MQ_COMPASS_CHEST,
RC_ICE_CAVERN_MQ_MAP_CHEST,
RC_ICE_CAVERN_MQ_FREESTANDING_POH,
RC_ICE_CAVERN_MQ_GS_SCARECROW,
RC_ICE_CAVERN_MQ_GS_ICE_BLOCK,
RC_ICE_CAVERN_MQ_GS_RED_ICE,
},
{
// Shared Locations
RC_SHEIK_IN_ICE_CAVERN,
},
{});
dungeonList[GERUDO_TRAINING_GROUNDS] =
DungeonInfo("Gerudo Training Grounds", RHT_GERUDO_TRAINING_GROUND, RG_NONE, RG_NONE,
RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY, RG_GERUDO_TRAINING_GROUNDS_KEY_RING, RG_NONE, 9, 3,
{
// Vanilla Locations
RC_GERUDO_TRAINING_GROUND_LOBBY_LEFT_CHEST,
RC_GERUDO_TRAINING_GROUND_LOBBY_RIGHT_CHEST,
RC_GERUDO_TRAINING_GROUND_STALFOS_CHEST,
RC_GERUDO_TRAINING_GROUND_BEAMOS_CHEST,
RC_GERUDO_TRAINING_GROUND_HIDDEN_CEILING_CHEST,
RC_GERUDO_TRAINING_GROUND_MAZE_PATH_FIRST_CHEST,
RC_GERUDO_TRAINING_GROUND_MAZE_PATH_SECOND_CHEST,
RC_GERUDO_TRAINING_GROUND_MAZE_PATH_THIRD_CHEST,
RC_GERUDO_TRAINING_GROUND_MAZE_PATH_FINAL_CHEST,
RC_GERUDO_TRAINING_GROUND_MAZE_RIGHT_CENTRAL_CHEST,
RC_GERUDO_TRAINING_GROUND_MAZE_RIGHT_SIDE_CHEST,
RC_GERUDO_TRAINING_GROUND_UNDERWATER_SILVER_RUPEE_CHEST,
RC_GERUDO_TRAINING_GROUND_HAMMER_ROOM_CLEAR_CHEST,
RC_GERUDO_TRAINING_GROUND_HAMMER_ROOM_SWITCH_CHEST,
RC_GERUDO_TRAINING_GROUND_EYE_STATUE_CHEST,
RC_GERUDO_TRAINING_GROUND_NEAR_SCARECROW_CHEST,
RC_GERUDO_TRAINING_GROUND_BEFORE_HEAVY_BLOCK_CHEST,
RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_FIRST_CHEST,
RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_SECOND_CHEST,
RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_THIRD_CHEST,
RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_FOURTH_CHEST,
RC_GERUDO_TRAINING_GROUND_FREESTANDING_KEY,
},
{
// MQ Locations
RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_RIGHT_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_LEFT_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_FIRST_IRON_KNUCKLE_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_BEFORE_HEAVY_BLOCK_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_EYE_STATUE_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_FLAME_CIRCLE_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_SECOND_IRON_KNUCKLE_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_DINOLFOS_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_ICE_ARROWS_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_MAZE_RIGHT_CENTRAL_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_FIRST_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_MAZE_RIGHT_SIDE_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_THIRD_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_SECOND_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_HIDDEN_CEILING_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_UNDERWATER_SILVER_RUPEE_CHEST,
RC_GERUDO_TRAINING_GROUND_MQ_HEAVY_BLOCK_CHEST,
},
{}, {});
dungeonList[GANONS_CASTLE] =
DungeonInfo("Ganon's Castle", RHT_GANONS_CASTLE, RG_NONE, RG_NONE, RG_GANONS_CASTLE_SMALL_KEY,
RG_GANONS_CASTLE_KEY_RING, RG_GANONS_CASTLE_BOSS_KEY, 2, 3,
{
// Vanilla Locations
RC_GANONS_CASTLE_FOREST_TRIAL_CHEST,
RC_GANONS_CASTLE_WATER_TRIAL_LEFT_CHEST,
RC_GANONS_CASTLE_WATER_TRIAL_RIGHT_CHEST,
RC_GANONS_CASTLE_SHADOW_TRIAL_FRONT_CHEST,
RC_GANONS_CASTLE_SHADOW_TRIAL_GOLDEN_GAUNTLETS_CHEST,
RC_GANONS_CASTLE_SPIRIT_TRIAL_CRYSTAL_SWITCH_CHEST,
RC_GANONS_CASTLE_SPIRIT_TRIAL_INVISIBLE_CHEST,
RC_GANONS_CASTLE_LIGHT_TRIAL_FIRST_LEFT_CHEST,
RC_GANONS_CASTLE_LIGHT_TRIAL_SECOND_LEFT_CHEST,
RC_GANONS_CASTLE_LIGHT_TRIAL_THIRD_LEFT_CHEST,
RC_GANONS_CASTLE_LIGHT_TRIAL_FIRST_RIGHT_CHEST,
RC_GANONS_CASTLE_LIGHT_TRIAL_SECOND_RIGHT_CHEST,
RC_GANONS_CASTLE_LIGHT_TRIAL_THIRD_RIGHT_CHEST,
RC_GANONS_CASTLE_LIGHT_TRIAL_INVISIBLE_ENEMIES_CHEST,
RC_GANONS_CASTLE_LIGHT_TRIAL_LULLABY_CHEST,
RC_GANONS_CASTLE_DEKU_SCRUB_LEFT,
RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT,
RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT,
RC_GANONS_CASTLE_DEKU_SCRUB_RIGHT,
},
{
// MQ Locations
RC_GANONS_CASTLE_MQ_WATER_TRIAL_CHEST,
RC_GANONS_CASTLE_MQ_FOREST_TRIAL_EYE_SWITCH_CHEST,
RC_GANONS_CASTLE_MQ_FOREST_TRIAL_FROZEN_EYE_SWITCH_CHEST,
RC_GANONS_CASTLE_MQ_LIGHT_TRIAL_LULLABY_CHEST,
RC_GANONS_CASTLE_MQ_SHADOW_TRIAL_BOMB_FLOWER_CHEST,
RC_GANONS_CASTLE_MQ_SHADOW_TRIAL_EYE_SWITCH_CHEST,
RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_GOLDEN_GAUNTLETS_CHEST,
RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_RIGHT_CHEST,
RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_LEFT_CHEST,
RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_FRONT_LEFT_CHEST,
RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_FIRST_CHEST,
RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_INVISIBLE_CHEST,
RC_GANONS_CASTLE_MQ_FOREST_TRIAL_FREESTANDING_KEY,
RC_GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT,
RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT,
RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER,
RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT,
RC_GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT,
},
{
// Shared Locations
RC_GANONS_TOWER_BOSS_KEY_CHEST,
RC_GANON,
},
{});
}
Dungeons::~Dungeons() = default;
DungeonInfo* Dungeons::GetDungeon(DungeonKey key) {
return &dungeonList[key];
}
DungeonInfo* Dungeons::GetDungeonFromScene(uint16_t scene) {
switch (scene) {
case SCENE_DEKU_TREE:
return &dungeonList[DEKU_TREE];
case SCENE_DODONGOS_CAVERN:
return &dungeonList[DODONGOS_CAVERN];
case SCENE_JABU_JABU:
return &dungeonList[JABU_JABUS_BELLY];
case SCENE_FOREST_TEMPLE:
return &dungeonList[FOREST_TEMPLE];
case SCENE_FIRE_TEMPLE:
return &dungeonList[FIRE_TEMPLE];
case SCENE_WATER_TEMPLE:
return &dungeonList[WATER_TEMPLE];
case SCENE_SPIRIT_TEMPLE:
return &dungeonList[SPIRIT_TEMPLE];
case SCENE_SHADOW_TEMPLE:
return &dungeonList[SHADOW_TEMPLE];
case SCENE_BOTTOM_OF_THE_WELL:
return &dungeonList[BOTTOM_OF_THE_WELL];
case SCENE_ICE_CAVERN:
return &dungeonList[ICE_CAVERN];
case SCENE_GERUDO_TRAINING_GROUND:
return &dungeonList[GERUDO_TRAINING_GROUNDS];
case SCENE_INSIDE_GANONS_CASTLE:
return &dungeonList[GANONS_CASTLE];
default:
return nullptr;
}
}
size_t Dungeons::CountMQ() {
size_t count = 0;
for (DungeonInfo& dungeon : dungeonList) {
if (dungeon.IsMQ()) {
count++;
}
}
return count;
}
void Dungeons::ClearAllMQ() {
for (DungeonInfo& dungeon : dungeonList) {
dungeon.ClearMQ();
}
}
std::array<DungeonInfo*, 12> Dungeons::GetDungeonList() {
std::array<DungeonInfo*, 12> dungeonList_;
for (size_t i = 0; i < dungeonList.size(); i++) {
dungeonList_[i] = &dungeonList[i];
}
return dungeonList_;
}
size_t Dungeons::GetDungeonListSize() {
return dungeonList.size();
}
void Dungeons::ParseJson(nlohmann::json spoilerFileJson) {
try {
nlohmann::json mqDungeonsJson = spoilerFileJson["masterQuestDungeons"];
for (auto it = mqDungeonsJson.begin(); it != mqDungeonsJson.end(); it++) {
std::string dungeonName = it.value().template get<std::string>();
for (auto& dungeon : dungeonList) {
if (dungeon.GetName() == dungeonName) {
dungeon.SetMQ();
} else {
dungeon.ClearMQ();
}
}
}
} catch (const std::exception& e) {
throw e;
}
}
} // namespace Rando

View File

@@ -0,0 +1,96 @@
#pragma once
#include "randomizerTypes.h"
#include <array>
#include <vector>
#include <string>
#include "nlohmann/json.hpp"
namespace Rando {
class DungeonInfo {
public:
DungeonInfo(std::string name_, RandomizerHintTextKey hintKey_, RandomizerGet map_, RandomizerGet compass_,
RandomizerGet smallKey_, RandomizerGet keyRing_, RandomizerGet bossKey_, uint8_t vanillaKeyCount_,
uint8_t mqKeyCount_, std::vector<RandomizerCheck> vanillaLocations_,
std::vector<RandomizerCheck> mqLocations_, std::vector<RandomizerCheck> sharedLocations_,
std::vector<RandomizerCheck> bossRoomLocations_);
DungeonInfo();
~DungeonInfo();
const std::string& GetName() const;
void SetMQ();
void ClearMQ();
bool IsMQ() const;
void SetKeyRing();
void ClearKeyRing();
bool HasKeyRing() const;
bool IsVanilla() const;
uint8_t GetSmallKeyCount() const;
RandomizerHintTextKey GetHintKey() const;
RandomizerGet GetSmallKey() const;
RandomizerGet GetKeyRing() const;
RandomizerGet GetMap() const;
RandomizerGet GetCompass() const;
RandomizerGet GetBossKey() const;
void PlaceVanillaMap();
void PlaceVanillaCompass();
void PlaceVanillaBossKey();
void PlaceVanillaSmallKeys();
std::vector<RandomizerCheck> GetDungeonLocations() const;
std::vector<RandomizerCheck> GetEveryLocation() const;
private:
std::string name;
RandomizerHintTextKey hintKey;
RandomizerGet map;
RandomizerGet compass;
RandomizerGet smallKey;
RandomizerGet keyRing;
RandomizerGet bossKey;
uint8_t vanillaKeyCount;
uint8_t mqKeyCount;
bool masterQuest = false;
bool hasKeyRing = false;
std::vector<RandomizerCheck> vanillaLocations;
std::vector<RandomizerCheck> mqLocations;
std::vector<RandomizerCheck> sharedLocations;
std::vector<RandomizerCheck> bossRoomLocations;
};
typedef enum {
DEKU_TREE,
DODONGOS_CAVERN,
JABU_JABUS_BELLY,
FOREST_TEMPLE,
FIRE_TEMPLE,
WATER_TEMPLE,
SPIRIT_TEMPLE,
SHADOW_TEMPLE,
BOTTOM_OF_THE_WELL,
ICE_CAVERN,
GERUDO_TRAINING_GROUNDS,
GANONS_CASTLE
} DungeonKey;
class Dungeons {
public:
Dungeons();
~Dungeons();
DungeonInfo* GetDungeon(DungeonKey key);
DungeonInfo* GetDungeonFromScene(uint16_t scene);
size_t CountMQ();
void ClearAllMQ();
/// @brief Returns a new array of pointers to the DungeonInfo entries.
/// It returns an array of pointers rather than a pointer to an array so that
/// this new array can be shuffled for the purposes of randomizing MQ dungeons.
/// If you want an individual DungeonInfo entry you should use the GetDungeon
/// function from either here or the Context class.
/// @return
std::array<DungeonInfo*, 12> GetDungeonList();
size_t GetDungeonListSize();
void ParseJson(nlohmann::json spoilerFileJson);
private:
std::array<DungeonInfo, 12> dungeonList;
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,151 @@
#pragma once
#ifdef __cplusplus
#include "randomizerTypes.h"
#include "3drando/location_access.hpp"
#include <nlohmann/json.hpp>
#define ENTRANCE_SHUFFLE_SUCCESS 0
#define ENTRANCE_SHUFFLE_FAILURE 1
namespace Rando {
enum class EntranceType {
None,
OwlDrop,
Spawn,
WarpSong,
Dungeon,
GanonDungeon,
DungeonReverse,
Boss,
ChildBoss,
AdultBoss,
Interior,
InteriorReverse,
SpecialInterior,
GrottoGrave,
GrottoGraveReverse,
Overworld,
Extra,
Mixed,
All,
};
class Entrance {
public:
Entrance(RandomizerRegion connectedRegion_, std::vector<ConditionFn> conditions_met_);
void SetCondition(ConditionFn newCondition);
bool GetConditionsMet() const;
std::string to_string() const;
void SetName(std::string name_ = "");
std::string GetName() const;
void printAgeTimeAccess();
bool ConditionsMet(bool allAgeTimes = false) const;
uint32_t Getuint32_t() const;
bool CheckConditionAtAgeTime(bool& age, bool& time, bool passAnyway = false) const;
RandomizerRegion GetConnectedRegionKey() const;
Area* GetConnectedRegion() const;
void SetParentRegion(RandomizerRegion newParent);
RandomizerRegion GetParentRegionKey() const;
Area* GetParentRegion() const;
void SetNewEntrance(RandomizerRegion newRegion);
void SetAsShuffled();
bool IsShuffled() const;
bool IsAddedToPool() const;
void AddToPool();
void RemoveFromPool();
void SetAsPrimary();
bool IsPrimary() const;
bool IsDecoupled() const;
void SetDecoupled();
int16_t GetIndex() const;
void SetIndex(int16_t newIndex);
int16_t GetBlueWarp() const;
void SetBlueWarp(int16_t newBlueWarp);
Entrance* GetAssumed() const;
void SetReplacement(Entrance* newReplacement);
Entrance* GetReplacement() const;
EntranceType GetType() const;
void SetType(EntranceType newType);
Entrance* GetReverse() const;
void Connect(RandomizerRegion newConnectedRegion);
RandomizerRegion Disconnect();
void BindTwoWay(Entrance* otherEntrance);
Entrance* GetNewTarget();
Entrance* AssumeReachable();
private:
RandomizerRegion parentRegion;
RandomizerRegion connectedRegion;
std::vector<ConditionFn> conditions_met;
EntranceType type = EntranceType::None;
Entrance* target = nullptr;
Entrance* reverse = nullptr;
Entrance* assumed = nullptr;
Entrance* replacement = nullptr;
int16_t index = 0xFFFF;
int16_t blueWarp = 0;
bool shuffled = false;
bool primary = false;
bool addedToPool = false;
bool decoupled = false;
std::string name = "";
};
typedef struct {
EntranceType type;
RandomizerRegion parentRegion;
RandomizerRegion connectedRegion;
int16_t index;
int16_t blueWarp;
} EntranceLinkInfo;
typedef struct {
std::list<RandomizerRegion> targetRegions;
std::list<EntranceType> allowedTypes;
} PriorityEntrance;
// primary, secondary
using EntranceInfoPair = std::pair<EntranceLinkInfo, EntranceLinkInfo>;
using EntrancePair = std::pair<Entrance*, Entrance*>;
using EntrancePools = std::map<EntranceType, std::vector<Entrance*>>;
class EntranceShuffler {
public:
std::array<EntranceOverride, ENTRANCE_OVERRIDES_MAX_COUNT> entranceOverrides;
std::vector<std::list<Entrance*>> playthroughEntrances;
bool HasNoRandomEntrances();
void SetNoRandomEntrances(bool noRandomEntrances);
int ShuffleAllEntrances();
void CreateEntranceOverrides();
void UnshuffleAllEntrances();
void ParseJson(nlohmann::json spoilerFileJson);
private:
std::vector<Entrance*> AssumeEntrancePool(std::vector<Entrance*>& entrancePool);
bool ShuffleOneWayPriorityEntrances(std::map<std::string, PriorityEntrance>& oneWayPriorities,
EntrancePools oneWayEntrancePools, EntrancePools oneWayTargetEntrancePools,
int retryCount = 2);
bool PlaceOneWayPriorityEntrance(std::string priorityName, std::list<RandomizerRegion>& allowedRegions,
std::list<EntranceType>& allowedTypes, std::vector<EntrancePair>& rollbacks,
EntrancePools oneWayEntrancePools, EntrancePools oneWayTargetEntrancePools);
bool ReplaceEntrance(Entrance* entrance, Entrance* target, std::vector<EntrancePair>& rollbacks);
void ShuffleEntrancePool(std::vector<Entrance*>& entrancePool, std::vector<Entrance*>& targetEntrances,
int retryCount = 20);
bool ShuffleEntrances(std::vector<Entrance*>& entrances, std::vector<Entrance*>& targetEntrances,
std::vector<EntrancePair>& rollbacks);
bool PlaceOtherImpasHouseEntrance(std::vector<Entrance*> entrances, std::vector<Entrance*> targetEntrances,
std::vector<EntrancePair>& rollbacks);
bool mNoRandomEntrances;
int mTotalRandomizableEntrances = 0;
int mCurNumRandomizedEntrances = 0;
bool mEntranceShuffleFailure = false;
};
} // namespace Rando
extern "C" {
#endif
EntranceOverride* Randomizer_GetEntranceOverrides();
#ifdef __cplusplus
}
#endif

View File

@@ -1,7 +1,7 @@
#include "hint.h"
namespace Rando {
Hint::Hint() {}
Hint::Hint() : text(std::move(Text())) {}
Hint::Hint(Text text_): text(std::move(text_)) {}
Hint::Hint(Text text_, RandomizerCheck hintedLocation_, HintType hintType_, Text hintedRegion_)
: text(std::move(text_)), hintedLocation(hintedLocation_), hintType(hintType_),
@@ -36,6 +36,10 @@ std::string Hint::GetHintedRegion() {
return hintedRegion.GetEnglish();
}
const Text& Hint::GetHintedRegionText() {
return hintedRegion;
};
void Hint::ResetVariables() {
hintedLocation = RC_UNKNOWN_CHECK;
addedToPool = false;

View File

@@ -15,16 +15,17 @@ class Hint {
HintType GetHintType();
void SetHintType (HintType type);
std::string GetHintedRegion();
const Text& GetHintedRegionText();
void SetHintedRegion (Text region);
void ResetVariables();
bool IsAddedToPool();
void AddToPool();
private:
Text text;
RandomizerCheck hintedLocation;
HintType hintType;
Text hintedRegion;
bool addedToPool;
Text text = Text();
RandomizerCheck hintedLocation = RC_UNKNOWN_CHECK;
HintType hintType = HINT_TYPE_STATIC;
Text hintedRegion = Text();
bool addedToPool = false;
};
}

View File

@@ -83,29 +83,6 @@ void Item::UndoEffect() {
Logic::UpdateHelpers();
}
Rando::ItemOverride_Value Item::Value() const {
Rando::ItemOverride_Value val;
val.all = 0;
val.itemId = getItemId;
if (getItemId == RG_ICE_TRAP) {
val.looksLikeItemId = RandomElement(IceTrapModels);
}
if ((getItemId >= 0x95 && getItemId <= 0x9A)) { // Boss keys
val.looksLikeItemId = GI_KEY_BOSS;
}
if ((getItemId >= 0xAF && getItemId <= 0xB7)) { // Small keys
val.looksLikeItemId = GI_KEY_SMALL;
}
if (type == ITEMTYPE_SHOP) {
// With the current shopsanity implementation, we need a way to detect
// regular shop items. This method should have no unintended side effects
// unless there was a multiworld with 256 players... so, it should be fine.
val.player = 0xFF;
}
return val;
}
const Text& Item::GetName() const {
return name;
}
@@ -286,7 +263,7 @@ std::shared_ptr<GetItemEntry> Item::GetGIEntry() const {
return Rando::StaticData::RetrieveItem(actual).GetGIEntry();
}
GetItemEntry Item::GetGIEntry_Copy() {
GetItemEntry Item::GetGIEntry_Copy() const {
return *GetGIEntry();
}
@@ -313,9 +290,9 @@ bool Item::IsBottleItem() const {
}
bool Item::IsMajorItem() const {
using namespace Settings;
auto ctx = Rando::Context::GetInstance();
if (type == ITEMTYPE_TOKEN) {
return Bridge.Is(RAINBOWBRIDGE_TOKENS) || LACSCondition == LACSCONDITION_TOKENS;
return ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_TOKENS) || ctx->GetSettings()->LACSCondition() == RO_LACS_TOKENS;
}
if (type == ITEMTYPE_DROP || type == ITEMTYPE_EVENT || type == ITEMTYPE_SHOP || type == ITEMTYPE_MAP ||
@@ -323,12 +300,12 @@ bool Item::IsMajorItem() const {
return false;
}
if (type == ITEMTYPE_DUNGEONREWARD && (ShuffleRewards.Is(REWARDSHUFFLE_END_OF_DUNGEON))) {
if (type == ITEMTYPE_DUNGEONREWARD && (ctx->GetOption(RSK_SHUFFLE_DUNGEON_REWARDS).Is(RO_DUNGEON_REWARDS_END_OF_DUNGEON))) {
return false;
}
if ((randomizerGet == RG_BOMBCHU_5 || randomizerGet == RG_BOMBCHU_10 || randomizerGet == RG_BOMBCHU_20) &&
!BombchusInLogic) {
!ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC)) {
return false;
}
@@ -337,25 +314,25 @@ bool Item::IsMajorItem() const {
return false;
}
if (type == ITEMTYPE_SMALLKEY && (Keysanity.Is(KEYSANITY_VANILLA) || Keysanity.Is(KEYSANITY_OWN_DUNGEON))) {
if (type == ITEMTYPE_SMALLKEY && (ctx->GetOption(RSK_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_VANILLA) || ctx->GetOption(RSK_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_OWN_DUNGEON))) {
return false;
}
if (type == ITEMTYPE_FORTRESS_SMALLKEY && GerudoKeys.Is(GERUDOKEYS_VANILLA)) {
if (type == ITEMTYPE_FORTRESS_SMALLKEY && ctx->GetOption(RSK_GERUDO_KEYS).Is(RO_GERUDO_KEYS_VANILLA)) {
return false;
}
if ((type == ITEMTYPE_BOSSKEY && getItemId != 0xAD) &&
(BossKeysanity.Is(BOSSKEYSANITY_VANILLA) || BossKeysanity.Is(BOSSKEYSANITY_OWN_DUNGEON))) {
(ctx->GetOption(RSK_BOSS_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_VANILLA) || ctx->GetOption(RSK_BOSS_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_OWN_DUNGEON))) {
return false;
}
// Ganons Castle Boss Key
if (getItemId == 0xAD && (GanonsBossKey.Is(GANONSBOSSKEY_VANILLA) || GanonsBossKey.Is(GANONSBOSSKEY_OWN_DUNGEON))) {
if (getItemId == 0xAD && (ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_VANILLA) || ctx->GetOption(RSK_GANONS_BOSS_KEY).Is(RO_GANON_BOSS_KEY_OWN_DUNGEON))) {
return false;
}
if (randomizerGet == RG_GREG_RUPEE) {
return Bridge.Is(RAINBOWBRIDGE_GREG);
return ctx->GetOption(RSK_RAINBOW_BRIDGE).Is(RO_BRIDGE_GREG);
}
return IsAdvancement();

View File

@@ -5,15 +5,10 @@
#include <memory>
#include "3drando/text.hpp"
#include "3drando/settings.hpp"
#include "3drando/hint_list.hpp"
#include "randomizerTypes.h"
#include "soh/Enhancements/item-tables/ItemTableTypes.h"
namespace Rando {
union ItemOverride_Value;
}
enum ItemType {
ITEMTYPE_ITEM,
ITEMTYPE_MAP,
@@ -51,7 +46,6 @@ class Item {
void ApplyEffect();
void UndoEffect();
Rando::ItemOverride_Value Value() const;
const Text& GetName() const;
bool IsAdvancement() const;
@@ -60,7 +54,7 @@ class Item {
RandomizerGet GetRandomizerGet();
uint16_t GetPrice() const;
std::shared_ptr<GetItemEntry> GetGIEntry() const;
GetItemEntry GetGIEntry_Copy();
GetItemEntry GetGIEntry_Copy() const;
void SetPrice(uint16_t price_);
void SetAsPlaythrough();
void SetCustomDrawFunc(CustomDrawFunc);

View File

@@ -145,7 +145,7 @@ void Rando::StaticData::InitItemTable() {
itemTable[RG_GERUDO_FORTRESS_SMALL_KEY].SetCustomDrawFunc(Randomizer_DrawSmallKey);
itemTable[RG_GANONS_CASTLE_SMALL_KEY] = Item(RG_GANONS_CASTLE_SMALL_KEY, Text{ "Ganon's Castle Small Key", "Petite Clé du Château de Ganon", "Ganons Schloss Kleiner Schlüssel" }, ITEMTYPE_SMALLKEY, 0xB7, true, &Logic::GanonsCastleKeys, RHT_GANONS_CASTLE_SMALL_KEY,RG_GANONS_CASTLE_SMALL_KEY, OBJECT_GI_KEY, GID_KEY_SMALL, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_SHORT, ITEM_CATEGORY_SMALL_KEY,MOD_RANDOMIZER);
itemTable[RG_GANONS_CASTLE_SMALL_KEY].SetCustomDrawFunc(Randomizer_DrawSmallKey);
itemTable[RG_TREASURE_GAME_SMALL_KEY] = Item(RG_TREASURE_GAME_SMALL_KEY, Text{ "Chest Game Small Key", "Petite Clé du jeu la Chasse-aux-Trésors", "Truhenspiel Kleiner Schlüssel" }, ITEMTYPE_SMALLKEY, 0xDE, true, &Logic::TreasureGameKeys, RHT_TREASURE_GAME_SMALL_KEY,RG_TREASURE_GAME_SMALL_KEY, OBJECT_GI_KEY, GID_KEY_SMALL, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_SHORT, ITEM_CATEGORY_SMALL_KEY,MOD_RANDOMIZER);
itemTable[RG_TREASURE_GAME_SMALL_KEY] = Item(RG_TREASURE_GAME_SMALL_KEY, Text{ "Chest Game Small Key", "Petite Clé du jeu la Chasse-aux-Trésors", "Truhenspiel Kleiner Schlüssel" }, ITEMTYPE_SMALLKEY, GI_DOOR_KEY, true, &Logic::TreasureGameKeys, RHT_TREASURE_GAME_SMALL_KEY,ITEM_KEY_SMALL, OBJECT_GI_KEY, GID_KEY_SMALL, 0xF3, 0x80, CHEST_ANIM_SHORT, ITEM_CATEGORY_SMALL_KEY,MOD_NONE);
// Key Rings
itemTable[RG_FOREST_TEMPLE_KEY_RING] = Item(RG_FOREST_TEMPLE_KEY_RING, Text{ "Forest Temple Key Ring", "Trousseau du Temple de la Forêt", "Waldtempel Schlüsselanhänger" }, ITEMTYPE_SMALLKEY, 0xD5, true, &Logic::ForestTempleKeys, RHT_FOREST_TEMPLE_KEY_RING, RG_FOREST_TEMPLE_KEY_RING, OBJECT_GI_KEY, GID_KEY_SMALL, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_SHORT, ITEM_CATEGORY_SMALL_KEY,MOD_RANDOMIZER);
itemTable[RG_FOREST_TEMPLE_KEY_RING].SetCustomDrawFunc(Randomizer_DrawKeyRing);

View File

@@ -1,4 +1,5 @@
#include "item_location.h"
#include "context.h"
namespace Rando {
ItemLocation::ItemLocation(RandomizerCheck rc_) : rc(rc_) {}
@@ -23,6 +24,10 @@ const Item& ItemLocation::GetPlacedItem() const {
return Rando::StaticData::RetrieveItem(placedItem);
}
RandomizerGet& ItemLocation::RefPlacedItem() {
return placedItem;
}
const Text& ItemLocation::GetPlacedItemName() const {
return Rando::StaticData::RetrieveItem(placedItem).GetName();
}
@@ -69,28 +74,19 @@ uint16_t ItemLocation::GetPrice() const {
}
void ItemLocation::SetPrice(uint16_t price_) {
if (hasShopsanityPrice || hasScrubsanityPrice) {
if (hasCustomPrice) {
return;
}
price = price_;
}
bool ItemLocation::HasShopsanityPrice() const {
return hasShopsanityPrice;
bool ItemLocation::HasCustomPrice() const {
return hasCustomPrice;
}
void ItemLocation::SetShopsanityPrice(uint16_t price_) {
void ItemLocation::SetCustomPrice(uint16_t price_) {
price = price_;
hasShopsanityPrice = true;
}
bool ItemLocation::HasScrubsanityPrice() const {
return hasScrubsanityPrice;
}
void ItemLocation::SetScrubsanityPrice(uint16_t price_) {
price = price_;
hasScrubsanityPrice = true;
hasCustomPrice = true;
}
bool ItemLocation::IsHintable() const {
@@ -129,31 +125,31 @@ bool ItemLocation::IsExcluded() const {
return excludedOption.Value<bool>();
}
Option* ItemLocation::GetExcludedOption() {
Rando::Option* ItemLocation::GetExcludedOption() {
return &excludedOption;
}
void ItemLocation::AddExcludeOption() {
const std::string name = StaticData::GetLocation(rc)->GetName();
if (name.length() < 23) {
excludedOption = Option::Bool(name, {"Include", "Exclude"});
excludedOption = Rando::Option::Bool(name, {"Include", "Exclude"});
} else {
size_t lastSpace = name.rfind(' ', 23);
std::string settingText = name;
settingText.replace(lastSpace, 1, "\n ");
excludedOption = Option::Bool(settingText, {"Include", "Exclude"});
excludedOption = Rando::Option::Bool(settingText, {"Include", "Exclude"});
}
// RANDOTODO: this without string compares and loops
bool alreadyAdded = false;
Rando::Location* loc = StaticData::GetLocation(rc);
for (const Option* location : Settings::excludeLocationsOptionsVector[loc->GetCollectionCheckGroup()]) {
for (const Rando::Option* location : Rando::Context::GetInstance()->GetSettings()->GetExcludeOptionsForGroup(loc->GetCollectionCheckGroup())) {
if (location->GetName() == excludedOption.GetName()) {
alreadyAdded = true;
}
}
if (!alreadyAdded) {
Settings::excludeLocationsOptionsVector[loc->GetCollectionCheckGroup()].push_back(&excludedOption);
Rando::Context::GetInstance()->GetSettings()->GetExcludeOptionsForGroup(loc->GetCollectionCheckGroup()).push_back(&excludedOption);
}
}
@@ -165,15 +161,6 @@ void ItemLocation::SetVisible(bool visibleInImGui_) {
}
ItemOverride_Key ItemLocation::Key() const {
ItemOverride_Key key;
key.all = 0;
key.scene = Rando::StaticData::GetLocation(rc)->GetScene();
key.type = static_cast<uint8_t>(StaticData::GetLocation(rc)->GetLocationType()); // TODO make sure these match up
return key;
}
void ItemLocation::ResetVariables() {
addedToPool = false;
placedItem = RG_NONE;
@@ -182,8 +169,7 @@ void ItemLocation::ResetVariables() {
hintedAt = false;
hintedBy = RH_NONE;
price = 0;
hasShopsanityPrice = false;
hasScrubsanityPrice = false;
hasCustomPrice = false;
hidden = false;
}
}

View File

@@ -1,51 +1,11 @@
#pragma once
#include "randomizerTypes.h"
#include "item.h"
#include "3drando/text.hpp"
#include "static_data.h"
#include "settings.h"
namespace Rando {
enum ItemOverride_Type {
OVR_BASE_ITEM = 0,
OVR_CHEST = 1,
OVR_COLLECTABLE = 2,
OVR_SKULL = 3,
OVR_GROTTO_SCRUB = 4,
OVR_DELAYED = 5,
OVR_TEMPLE = 6,
};
typedef union ItemOverride_Key {
uint32_t all;
struct {
char pad_;
uint8_t scene;
uint8_t type;
};
} ItemOverride_Key;
typedef union ItemOverride_Value {
uint32_t all;
struct {
uint16_t itemId;
uint8_t player;
uint8_t looksLikeItemId;
};
} ItemOverride_Value;
typedef struct ItemOverride {
ItemOverride_Key key;
ItemOverride_Value value;
} ItemOverride;
class ItemOverride_Compare {
public:
bool operator()(ItemOverride lhs, ItemOverride rhs) const {
return lhs.key.all < rhs.key.all;
}
};
class ItemLocation {
public:
ItemLocation() = default;
@@ -58,6 +18,7 @@ class ItemLocation {
const Text& GetPlacedItemName() const;
RandomizerGet GetPlacedRandomizerGet() const;
void SetPlacedItem(const RandomizerGet item);
RandomizerGet& RefPlacedItem();
void SetDelayedItem(const RandomizerGet item);
RandomizerRegion GetParentRegionKey() const;
void SetParentRegion (RandomizerRegion region);
@@ -66,10 +27,8 @@ class ItemLocation {
void SaveDelayedItem();
uint16_t GetPrice() const;
void SetPrice(uint16_t price_);
bool HasShopsanityPrice() const;
void SetShopsanityPrice(uint16_t price_);
bool HasScrubsanityPrice() const;
void SetScrubsanityPrice(uint16_t price_);
bool HasCustomPrice() const;
void SetCustomPrice(uint16_t price_);
bool IsHintable() const;
void SetAsHintable();
bool IsHintedAt() const;
@@ -83,7 +42,6 @@ class ItemLocation {
void SetHidden(const bool hidden_);
bool IsVisible() const;
void SetVisible(bool visibleInImGui_);
Rando::ItemOverride_Key Key() const;
void ResetVariables();
private:
@@ -97,8 +55,7 @@ class ItemLocation {
Option excludedOption = Option::Bool(StaticData::GetLocation(rc)->GetName(), {"Include", "Exclude"});
uint16_t price = 0;
RandomizerRegion parentRegion = RR_NONE;
bool hasShopsanityPrice = false;
bool hasScrubsanityPrice = false;
bool hasCustomPrice = false;
bool hidden = false;
bool visibleInImGui = false;
};

View File

@@ -0,0 +1,30 @@
#include "item_override.h"
namespace Rando {
ItemOverride::ItemOverride(RandomizerCheck location_, RandomizerGet looksLike_)
: location(location_), looksLike(looksLike_) {};
RandomizerCheck ItemOverride::GetLocation() const {
return location;
}
void ItemOverride::SetLocation(RandomizerCheck location_) {
location = location_;
}
RandomizerGet ItemOverride::LooksLike() const {
return looksLike;
}
RandomizerGet& ItemOverride::RefLooksLike() {
return looksLike;
}
Text& ItemOverride::GetTrickName() {
return trickName;
}
void ItemOverride::SetTrickName(Text trickName_) {
trickName = trickName_;
}
} // namespace Rando

View File

@@ -0,0 +1,23 @@
#pragma once
#include "randomizerTypes.h"
#include "3drando/text.hpp"
namespace Rando {
/// @brief Class representing overrides of individual items. Used for trick names and models for ice traps.
class ItemOverride {
public:
ItemOverride() = default;
ItemOverride(RandomizerCheck location_, RandomizerGet looksLike_);
RandomizerCheck GetLocation() const;
void SetLocation(RandomizerCheck);
RandomizerGet LooksLike() const;
RandomizerGet& RefLooksLike();
Text& GetTrickName();
void SetTrickName (Text trickName);
private:
RandomizerCheck location;
RandomizerGet looksLike;
Text trickName;
};
} // namespace Rando

View File

@@ -1,5 +1,6 @@
#include "location.h"
#include "3drando/hint_list.hpp"
#include <algorithm>
RandomizerCheck Rando::Location::GetRandomizerCheck() const {
return rc;

View File

@@ -0,0 +1,144 @@
#include "option.h"
namespace Rando {
Option Option::Bool(std::string name_, std::vector<std::string> options_, OptionCategory category_,
uint8_t defaultOption_, bool defaultHidden_) {
return Option(false, std::move(name_), std::move(options_), category_, defaultOption_, defaultHidden_);
}
Option Option::U8(std::string name_, std::vector<std::string> options_, OptionCategory category_,
uint8_t defaultOption_, bool defaultHidden_) {
return Option(uint8_t(0), std::move(name_), std::move(options_), category_, defaultOption_, defaultHidden_);
}
Option Option::LogicTrick(std::string name_) {
return Option(false, std::move(name_), { "Disabled", "Enabled" }, OptionCategory::Setting, 0, 0);
}
Option::operator bool() const {
if (std::holds_alternative<bool>(var)) {
return Value<bool>();
} else {
return Value<uint8_t>() != 0;
}
}
size_t Option::GetOptionCount() const {
return options.size();
}
const std::string& Option::GetName() const {
return name;
}
uint8_t Option::GetSelectedOptionIndex() const {
return selectedOption;
}
const std::string& Option::GetSelectedOptionText() const {
return options[selectedOption];
}
void Option::SetVariable() {
if (std::holds_alternative<bool>(var)) {
var.emplace<bool>(selectedOption != 0);
} else {
var.emplace<uint8_t>(selectedOption);
}
}
void Option::SetDelayedOption() {
delayedOption = selectedOption;
}
void Option::RestoreDelayedOption() {
selectedOption = delayedOption;
SetVariable();
}
void Option::SetSelectedIndex(size_t idx) {
selectedOption = idx;
if (selectedOption >= options.size()) {
selectedOption = 0;
}
SetVariable();
}
void Option::Hide() {
hidden = true;
}
void Option::Unhide() {
hidden = false;
}
bool Option::IsHidden() const {
return hidden;
}
bool Option::IsCategory(OptionCategory category) const {
return category == this->category;
}
Option::Option(uint8_t var_, std::string name_, std::vector<std::string> options_, OptionCategory category_,
uint8_t defaultOption_, bool defaultHidden_)
: var(var_), name(std::move(name_)), options(std::move(options_)), category(category_),
defaultOption(defaultOption_), defaultHidden(defaultHidden_) {
selectedOption = defaultOption;
hidden = defaultHidden;
SetVariable();
}
Option::Option(bool var_, std::string name_, std::vector<std::string> options_, OptionCategory category_,
uint8_t defaultOption_, bool defaultHidden_)
: var(var_), name(std::move(name_)), options(std::move(options_)), category(category_),
defaultOption(defaultOption_), defaultHidden(defaultHidden_) {
selectedOption = defaultOption;
hidden = defaultHidden;
SetVariable();
}
OptionGroup::OptionGroup(std::string name, std::vector<Option*> options, OptionGroupType groupType, bool printInSpoiler,
OptionGroupType containsType)
: mName(std::move(name)), mOptions(std::move(options)), mGroupType(groupType), mPrintInSpoiler(printInSpoiler),
mContainsType(containsType) {
}
OptionGroup::OptionGroup(std::string name, std::vector<OptionGroup*> subGroups, OptionGroupType groupType,
bool printInSpoiler, OptionGroupType containsType)
: mName(std::move(name)), mSubGroups(std::move(subGroups)), mGroupType(groupType), mPrintInSpoiler(printInSpoiler),
mContainsType(containsType) {
}
OptionGroup OptionGroup::SubGroup(std::string name, std::vector<Option*> options, bool printInSpoiler) {
return OptionGroup(std::move(name), std::move(options), OptionGroupType::SUBGROUP, printInSpoiler);
}
OptionGroup OptionGroup::SubGroup(std::string name, std::vector<OptionGroup*> subGroups, bool printInSpoiler) {
return OptionGroup(std::move(name), std::move(subGroups), OptionGroupType::SUBGROUP, printInSpoiler,
OptionGroupType::SUBGROUP);
}
const std::string& OptionGroup::GetName() const {
return mName;
}
const std::vector<Option*>& OptionGroup::GetOptions() const {
return mOptions;
}
const std::vector<OptionGroup*>& OptionGroup::GetSubGroups() const {
return mSubGroups;
}
bool OptionGroup::PrintInSpoiler() const {
return mPrintInSpoiler;
}
OptionGroupType OptionGroup::GetGroupType() const {
return mGroupType;
}
OptionGroupType OptionGroup::GetContainsType() const {
return mContainsType;
}
} // namespace Rando

View File

@@ -0,0 +1,100 @@
#pragma once
#include <stdint.h>
#include <string>
#include <vector>
#include <variant>
#include <type_traits>
namespace Rando {
enum class OptionCategory {
Setting,
Toggle,
};
class Option {
public:
Option() = default;
static Option Bool(std::string name_, std::vector<std::string> options_ = { "Off", "On" },
OptionCategory category_ = OptionCategory::Setting, uint8_t defaultOption_ = 0,
bool defaultHidden_ = false);
static Option U8(std::string name_, std::vector<std::string> options_,
OptionCategory category_ = OptionCategory::Setting, uint8_t defaultOption = 0,
bool defaultHidden = false);
static Option LogicTrick(std::string name_);
template <typename T> T Value() const {
return std::get<T>(var);
}
template <typename T> bool Is(T other) const {
static_assert(std::is_integral_v<T> || std::is_enum_v<T>, "T must be an integral type or an enum.");
if constexpr ((std::is_integral_v<T> && !std::is_same_v<bool, T>) || std::is_enum_v<T>) {
return Value<uint8_t>() == static_cast<uint8_t>(other);
} else {
return Value<bool>() == static_cast<bool>(other);
}
}
template <typename T> bool IsNot(T other) const {
return !Is(other);
}
explicit operator bool() const;
size_t GetOptionCount() const;
const std::string& GetName() const;
const std::string& GetSelectedOptionText() const;
uint8_t GetSelectedOptionIndex() const;
void SetVariable();
void SetDelayedOption();
void RestoreDelayedOption();
void SetSelectedIndex(size_t idx);
void Hide();
void Unhide();
bool IsHidden() const;
bool IsCategory(OptionCategory category) const;
private:
Option(uint8_t var_, std::string name_, std::vector<std::string> options_, OptionCategory category_,
uint8_t defaultOption_, bool defaultHidden_);
Option(bool var_, std::string name_, std::vector<std::string> options_, OptionCategory category_,
uint8_t defaultOption_, bool defaultHidden_);
std::variant<bool, uint8_t> var;
std::string name;
std::vector<std::string> options;
uint8_t selectedOption = 0;
uint8_t delayedOption = 0;
bool hidden = false;
OptionCategory category;
uint8_t defaultOption = false;
bool defaultHidden = false;
};
enum class OptionGroupType {
DEFAULT,
SUBGROUP,
};
class OptionGroup {
public:
OptionGroup() = default;
OptionGroup(std::string name, std::vector<Option*> options, OptionGroupType groupType = OptionGroupType::DEFAULT, bool printInSpoiler = true, OptionGroupType containsType = OptionGroupType::DEFAULT);
OptionGroup(std::string name, std::vector<OptionGroup*> subGroups, OptionGroupType groupType = OptionGroupType::DEFAULT, bool printInSpoiler = true, OptionGroupType containsType = OptionGroupType::SUBGROUP);
static OptionGroup SubGroup(std::string name, std::vector<Option*> options, bool printInSpoiler = true);
static OptionGroup SubGroup(std::string name, std::vector<OptionGroup*> subGroups, bool printInSpoiler = true);
const std::string& GetName() const;
const std::vector<Option*>& GetOptions() const;
const std::vector<OptionGroup*>& GetSubGroups() const;
bool PrintInSpoiler() const;
OptionGroupType GetGroupType() const;
OptionGroupType GetContainsType() const;
private:
std::string mName;
std::vector<Option*> mOptions;
std::vector<OptionGroup*> mSubGroups;
OptionGroupType mGroupType = OptionGroupType::DEFAULT;
bool mPrintInSpoiler;
OptionGroupType mContainsType = OptionGroupType::DEFAULT;
};
} // namespace Rando

View File

@@ -1,5 +1,8 @@
#pragma once
#ifndef RANDOHASH_H
#define RANDOHASH_H
#include "randomizerTypes.h"
#include <array>
#include "variables.h"
@@ -108,4 +111,5 @@ std::array<Sprite, 100> gSeedTextures = { {
{ dgQuestIconSmallKeyTex, 24, 24, G_IM_FMT_RGBA, G_IM_SIZ_32b, 97 },
{ dgQuestIconMagicJarSmallTex, 24, 24, G_IM_FMT_RGBA, G_IM_SIZ_32b, 98 },
{ dgQuestIconMagicJarBigTex, 24, 24, G_IM_FMT_RGBA, G_IM_SIZ_32b, 99 },
} };
} };
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -22,24 +22,8 @@
class Randomizer {
private:
std::unordered_map<RandomizerCheck, RandomizerGetData> itemLocations;
std::unordered_map<RandomizerCheck, std::string> hintLocations;
std::string childAltarText;
std::string adultAltarText;
std::string ganonHintText;
std::string ganonText;
std::string dampeText;
std::string sheikText;
std::string sariaText;
std::unordered_map<RandomizerSettingKey, u8> randoSettings;
void ParseRandomizerSettingsFile(const char* spoilerFileName);
void ParseHintLocationsFile(const char* spoilerFileName);
void ParseRequiredTrialsFile(const char* spoilerFileName);
void ParseMasterQuestDungeonsFile(const char* spoilerFileName);
void ParseItemLocationsFile(const char* spoilerFileName, bool silent);
void ParseEntranceDataFile(const char* spoilerFileName, bool silent);
bool IsItemVanilla(RandomizerGet randoGet);
int16_t GetVanillaMerchantPrice(RandomizerCheck check);
public:
Randomizer();
@@ -55,37 +39,17 @@ class Randomizer {
static const std::string randoMiscHintsTableID;
// Public for now to be accessed by SaveManager, will be made private again soon :tm:
std::unordered_map<RandomizerInf, bool> trialsRequired;
std::unordered_set<uint16_t> masterQuestDungeons;
std::unordered_map<RandomizerCheck, u16> merchantPrices;
std::unordered_map<RandomizerGet, std::array<std::string, 3>> EnumToSpoilerfileGetName;
static Sprite* GetSeedTexture(uint8_t index);
s16 GetItemModelFromId(s16 itemId);
s32 GetItemIDFromGetItemID(s32 getItemId);
bool SpoilerFileExists(const char* spoilerFileName);
void LoadRandomizerSettings(const char* spoilerFileName);
void LoadHintLocations(const char* spoilerFileName);
void LoadMerchantMessages(const char* spoilerFileName);
void LoadItemLocations(const char* spoilerFileName, bool silent);
void LoadRequiredTrials(const char* spoilerFileName);
void LoadMasterQuestDungeons(const char* spoilerFileName);
void LoadMerchantMessages();
void LoadHintMessages();
bool IsTrialRequired(RandomizerInf trial);
void LoadEntranceOverrides(const char* spoilerFileName, bool silent);
u8 GetRandoSettingValue(RandomizerSettingKey randoSettingKey);
RandomizerCheck GetCheckFromActor(s16 actorId, s16 sceneNum, s16 actorParams);
RandomizerCheck GetCheckFromRandomizerInf(RandomizerInf randomizerInf);
RandomizerInf GetRandomizerInfFromCheck(RandomizerCheck rc);
RandomizerGetData GetRandomizerGetDataFromActor(s16 actorId, s16 sceneNum, s16 actorParams);
RandomizerGetData GetRandomizerGetDataFromKnownCheck(RandomizerCheck randomizerCheck);
GetItemEntry GetItemEntryFromRGData(RandomizerGetData rgData, GetItemID ogItemId, bool checkObtainability = true);
std::string GetChildAltarText() const;
std::string GetAdultAltarText() const;
std::string GetGanonText() const;
std::string GetGanonHintText() const;
std::string GetDampeText() const;
std::string GetSheikText() const;
std::string GetSariaText() const;
Rando::Location* GetCheckObjectFromActor(s16 actorId, s16 sceneNum, s32 actorParams);
ScrubIdentity IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respawnData);
ShopItemIdentity IdentifyShopItem(s32 sceneNum, u8 slotIndex);

View File

@@ -1849,47 +1849,48 @@ typedef enum {
typedef enum {
RH_NONE,
RH_DMC_GOSSIP_STONE,
RH_DMT_GOSSIP_STONE,
RH_COLOSSUS_GOSSIP_STONE,
RH_DMC_GOSSIP_STONE,
RH_DMC_UPPER_GROTTO_GOSSIP_STONE,
RH_DMT_GOSSIP_STONE,
RH_DMT_STORMS_GROTTO_GOSSIP_STONE,
RH_DODONGOS_CAVERN_GOSSIP_STONE,
RH_GV_GOSSIP_STONE,
RH_ZF_FAIRY_GOSSIP_STONE,
RH_GC_MAZE_GOSSIP_STONE,
RH_GC_MEDIGORON_GOSSIP_STONE,
RH_GV_GOSSIP_STONE,
RH_GRAVEYARD_GOSSIP_STONE,
RH_HC_MALON_GOSSIP_STONE,
RH_HC_ROCK_WALL_GOSSIP_STONE,
RH_HC_STORMS_GROTTO_GOSSIP_STONE,
RH_HF_COW_GROTTO_GOSSIP_STONE,
RH_HF_NEAR_MARKET_GROTTO_GOSSIP_STONE,
RH_HF_OPEN_GROTTO_GOSSIP_STONE,
RH_HF_SOUTHEAST_GROTTO_GOSSIP_STONE,
RH_ZF_JABU_GOSSIP_STONE,
RH_KF_DEKU_TREE_GOSSIP_STONE_LEFT,
RH_KF_DEKU_TREE_GOSSIP_STONE_RIGHT,
RH_KF_GOSSIP_STONE,
RH_KF_STORMS_GROTTO_GOSSIP_STONE,
RH_KAK_OPEN_GROTTO_GOSSIP_STONE,
RH_LH_LAB_GOSSIP_STONE,
RH_LH_GOSSIP_STONE_SOUTHEAST,
RH_LH_GOSSIP_STONE_SOUTHWEST,
RH_LW_GOSSIP_STONE,
RH_LW_NEAR_SHORTCUTS_GROTTO_GOSSIP_STONE,
RH_SFM_MAZE_GOSSIP_STONE_LOWER,
RH_SFM_MAZE_GOSSIP_STONE_UPPER,
RH_SFM_SARIA_GOSSIP_STONE,
RH_TOT_GOSSIP_STONE_LEFT,
RH_TOT_GOSSIP_STONE_RIGHT,
RH_TOT_GOSSIP_STONE_RIGHT_CENTER,
RH_TOT_GOSSIP_STONE_LEFT_CENTER,
RH_TOT_GOSSIP_STONE_LEFT,
RH_TOT_GOSSIP_STONE_RIGHT_CENTER,
RH_TOT_GOSSIP_STONE_RIGHT,
RH_ZD_GOSSIP_STONE,
RH_ZF_FAIRY_GOSSIP_STONE,
RH_ZF_JABU_GOSSIP_STONE,
RH_ZR_NEAR_GROTTOS_GOSSIP_STONE,
RH_ZR_NEAR_DOMAIN_GOSSIP_STONE,
RH_HF_COW_GROTTO_GOSSIP_STONE,
RH_HF_NEAR_MARKET_GROTTO_GOSSIP_STONE,
RH_HF_SOUTHEAST_GROTTO_GOSSIP_STONE,
RH_HF_OPEN_GROTTO_GOSSIP_STONE,
RH_KAK_OPEN_GROTTO_GOSSIP_STONE,
RH_ZR_NEAR_GROTTOS_GOSSIP_STONE,
RH_ZR_OPEN_GROTTO_GOSSIP_STONE,
RH_KF_STORMS_GROTTO_GOSSIP_STONE,
RH_LW_NEAR_SHORTCUTS_GROTTO_GOSSIP_STONE,
RH_DMT_STORMS_GROTTO_GOSSIP_STONE,
RH_DMC_UPPER_GROTTO_GOSSIP_STONE,
RH_GANONDORF_HINT,
RH_GANONDORF_NOHINT,
RH_DAMPES_DIARY,
RH_GREG_RUPEE,
RH_MEDIGORON,
@@ -1897,6 +1898,14 @@ typedef enum {
RH_WASTELAND_BOMBCHU_SALESMAN,
RH_ALTAR_CHILD,
RH_ALTAR_ADULT,
RH_SARIA,
RH_SHEIK_LIGHT_ARROWS,
RH_MINUET_WARP_LOC,
RH_BOLERO_WARP_LOC,
RH_SERENADE_WARP_LOC,
RH_REQUIEM_WARP_LOC,
RH_NOCTURNE_WARP_LOC,
RH_PRELUDE_WARP_LOC,
RH_MAX,
} RandomizerHintKey;
@@ -3224,6 +3233,52 @@ typedef struct {
char trickName[MAX_TRICK_NAME_SIZE];
} RandomizerGetData;
typedef enum {
RSG_NONE,
RSG_LOGIC,
RSG_EXCLUDES_KOKIRI_FOREST,
RSG_EXCLUDES_LOST_WOODS,
RSG_EXCLUDES_DEKU_TREE,
RSG_EXCLUDES_FOREST_TEMPLE,
RSG_EXCLUDES_KAKARIKO_VILLAGE,
RSG_EXCLUDES_BOTTOM_OF_THE_WELL,
RSG_EXCLUDES_SHADOW_TEMPLE,
RSG_EXCLUDES_DEATH_MOUNTAIN,
RSG_EXCLUDES_GORON_CITY,
RSG_EXCLUDES_DODONGOS_CAVERN,
RSG_EXCLUDES_FIRE_TEMPLE,
RSG_EXCLUDES_ZORAS_RIVER,
RSG_EXCLUDES_ZORAS_DOMAIN,
RSG_EXCLUDES_JABU_JABU,
RSG_EXCLUDES_ICE_CAVERN,
RSG_EXCLUDES_HYRULE_FIELD,
RSG_EXCLUDES_LON_LON_RANCH,
RSG_EXCLUDES_LAKE_HYLIA,
RSG_EXCLUDES_WATER_TEMPLE,
RSG_EXCLUDES_GERUDO_VALLEY,
RSG_EXCLUDES_GERUDO_TRAINING_GROUNDS,
RSG_EXCLUDES_SPIRIT_TEMPLE,
RSG_EXCLUDES_HYRULE_CASTLE,
RSG_EXCLUDES_GANONS_CASTLE,
RSG_EXCLUDES,
RSG_TRICKS,
RSG_GLITCHES,
RSG_OPEN,
RSG_WORLD,
RSG_SHUFFLE,
RSG_SHUFFLE_DUNGEON_ITEMS,
RSG_SHUFFLE_DUNGEON_QUESTS,
RSG_DETAILED_LOGIC,
RSG_STARTING_ITEMS,
RSG_STARTING_SONGS,
RSG_STARTING_OTHER,
RSG_STARTING_INVENTORY,
RSG_TIMESAVERS,
RSG_MISC,
RSG_ITEM_POOL,
RSG_MAX,
} RandomizerSettingGroupKey;
typedef enum {
RSK_NONE,
RSK_LOGIC_RULES,
@@ -3246,6 +3301,7 @@ typedef enum {
RSK_SHUFFLE_OCARINA,
RSK_STARTING_DEKU_SHIELD,
RSK_STARTING_KOKIRI_SWORD,
RSK_STARTING_MASTER_SWORD,
RSK_STARTING_ZELDAS_LULLABY,
RSK_STARTING_EPONAS_SONG,
RSK_STARTING_SARIAS_SONG,
@@ -3260,7 +3316,6 @@ typedef enum {
RSK_STARTING_PRELUDE_OF_LIGHT,
RSK_SHUFFLE_KOKIRI_SWORD,
RSK_SHUFFLE_MASTER_SWORD,
RSK_STARTING_MAPS_COMPASSES,
RSK_SHUFFLE_DUNGEON_REWARDS,
RSK_SHUFFLE_SONGS,
RSK_SHUFFLE_TOKENS,
@@ -3290,6 +3345,7 @@ typedef enum {
RSK_SCRUB_TEXT_HINT,
RSK_HINT_CLARITY,
RSK_HINT_DISTRIBUTION,
RSK_SHUFFLE_MAPANDCOMPASS,
RSK_KEYSANITY,
RSK_GERUDO_KEYS,
RSK_BOSS_KEYSANITY,
@@ -3316,8 +3372,9 @@ typedef enum {
RSK_ENABLE_BOMBCHU_DROPS,
RSK_BOMBCHUS_IN_LOGIC,
RSK_LINKS_POCKET,
RSK_RANDOM_MQ_DUNGEONS,
RSK_MQ_DUNGEON_RANDOM,
RSK_MQ_DUNGEON_COUNT,
RSK_MQ_DUNGEON_SET,
RSK_MQ_DEKU_TREE,
RSK_MQ_DODONGOS_CAVERN,
RSK_MQ_JABU_JABU,
@@ -3362,6 +3419,8 @@ typedef enum {
RSK_MIX_GROTTO_ENTRANCES,
RSK_DECOUPLED_ENTRANCES,
RSK_STARTING_SKULLTULA_TOKEN,
RSK_STARTING_HEARTS,
RSK_DAMAGE_MULTIPLIER,
RSK_ALL_LOCATIONS_REACHABLE,
RSK_SHUFFLE_BOSS_ENTRANCES,
RSK_SHUFFLE_100_GS_REWARD,
@@ -3538,6 +3597,15 @@ typedef enum {
RO_GANON_BOSS_KEY_TRIFORCE_HUNT,
} RandoOptionGanonsBossKey;
typedef enum {
RO_LACS_VANILLA,
RO_LACS_STONES,
RO_LACS_MEDALLIONS,
RO_LACS_REWARDS,
RO_LACS_DUNGEONS,
RO_LACS_TOKENS,
} RandoOptionLACSCondition;
// LACS Reward Options settings (Standard rewards, Greg as reward, Greg as wildcard)
typedef enum {
RO_LACS_STANDARD_REWARD,
@@ -3662,10 +3730,22 @@ typedef enum {
// Logic (glitchless/no logic)
typedef enum {
RO_LOGIC_GLITCHLESS,
//RO_LOGIC_GLITCHED,
RO_LOGIC_GLITCHED,
RO_LOGIC_NO_LOGIC,
RO_LOGIC_VANILLA
} RandoOptionLogic;
// Damage Multiplier
typedef enum {
RO_DAMAGE_MULTIPLIER_HALF,
RO_DAMAGE_MULTIPLIER_DEFAULT,
RO_DAMAGE_MULTIPLIER_DOUBLE,
RO_DAMAGE_MULTIPLIER_QUADRUPLE,
RO_DAMAGE_MULTIPLIER_OCTUPLE,
RO_DAMAGE_MULTIPLIER_SEXDECUPLE,
RO_DAMAGE_MULTIPLIER_OHKO,
} RandoOptionDamageMultiplier;
// MQ Dungeons
typedef enum {
RO_MQ_DUNGEONS_NONE,
@@ -3674,6 +3754,23 @@ typedef enum {
RO_MQ_DUNGEONS_SELECTION,
} RandoOptionMQDungeons;
typedef enum {
RO_LOCATION_INCLUDE,
RO_LOCATION_EXCLUDE,
} RandoOptionLocationInclusion;
typedef enum {
RO_CHEST_GAME_OFF,
RO_CHEST_GAME_SINGLE_KEYS,
RO_CHEST_GAME_PACK,
} RandoOptionChestGame;
typedef enum {
RO_MQ_SET_VANILLA,
RO_MQ_SET_MQ,
RO_MQ_SET_RANDOM,
} RandoOptionMQSet;
typedef enum {
CAN_OBTAIN,
CANT_OBTAIN_MISC,

View File

@@ -2,6 +2,7 @@
#include "randomizer_entrance_tracker.h"
#include "randomizer_item_tracker.h"
#include "randomizerTypes.h"
#include "dungeon.h"
#include "../../OTRGlobals.h"
#include "../../UIWidgets.hpp"
@@ -732,8 +733,8 @@ void LoadFile() {
areaChecksGotten[startingArea]++;
}
showVOrMQ = (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_RANDOM_MQ_DUNGEONS) == RO_MQ_DUNGEONS_RANDOM_NUMBER ||
(OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_RANDOM_MQ_DUNGEONS) == RO_MQ_DUNGEONS_SET_NUMBER &&
showVOrMQ = (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_MQ_DUNGEON_RANDOM) == RO_MQ_DUNGEONS_RANDOM_NUMBER ||
(OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_MQ_DUNGEON_RANDOM) == RO_MQ_DUNGEONS_SET_NUMBER &&
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_MQ_DUNGEON_COUNT) < 12));
LinksPocket();
SongFromImpa();
@@ -926,7 +927,7 @@ void CheckTrackerWindow::DrawElement() {
if (isThisAreaSpoiled) {
if (showVOrMQ && RandomizerCheckObjects::AreaIsDungeon(rcArea)) {
if (OTRGlobals::Instance->gRandomizer->masterQuestDungeons.contains(DungeonSceneLookupByArea(rcArea)))
if (OTRGlobals::Instance->gRandoContext->GetDungeons()->GetDungeonFromScene(DungeonSceneLookupByArea(rcArea))->IsMQ())
ImGui::Text("(%d/%d) - MQ", areaChecksGotten[rcArea], areaChecksTotal);
else
ImGui::Text("(%d/%d) - Vanilla", areaChecksGotten[rcArea], areaChecksTotal);
@@ -1033,7 +1034,7 @@ void LoadSettings() {
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_FROG_SONG_RUPEES) == RO_GENERIC_YES
: false;
showStartingMapsCompasses = IS_RANDO ?
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_STARTING_MAPS_COMPASSES) != RO_DUNGEON_ITEM_LOC_VANILLA
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_MAPANDCOMPASS) != RO_DUNGEON_ITEM_LOC_VANILLA
: false;
showKeysanity = IS_RANDO ?
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_KEYSANITY) != RO_DUNGEON_ITEM_LOC_VANILLA
@@ -1111,8 +1112,8 @@ bool IsVisibleInCheckTracker(RandomizerCheck rc) {
(rc != RC_LINKS_POCKET || showLinksPocket) &&
(!RandomizerCheckObjects::AreaIsDungeon(loc->GetArea()) ||
loc->GetQuest() == RCQUEST_BOTH ||
loc->GetQuest() == RCQUEST_MQ && OTRGlobals::Instance->gRandomizer->masterQuestDungeons.contains(loc->GetScene()) ||
loc->GetQuest() == RCQUEST_VANILLA && !OTRGlobals::Instance->gRandomizer->masterQuestDungeons.contains(loc->GetScene())
loc->GetQuest() == RCQUEST_MQ && OTRGlobals::Instance->gRandoContext->GetDungeons()->GetDungeonFromScene(loc->GetScene())->IsMQ() ||
loc->GetQuest() == RCQUEST_VANILLA && OTRGlobals::Instance->gRandoContext->GetDungeons()->GetDungeonFromScene(loc->GetScene())->IsVanilla()
) &&
(loc->GetRCType() != RCTYPE_SHOP || (showShops && (!hideShopRightChecks || hideShopRightChecks && loc->GetActorParams() > 0x03))) &&
(loc->GetRandomizerCheck() != RC_MARKET_BOMBCHU_BOWLING_BOMBCHUS) &&
@@ -1154,8 +1155,8 @@ bool IsVisibleInCheckTracker(RandomizerCheck rc) {
}
else if (loc->IsVanillaCompletion()) {
return (loc->GetQuest() == RCQUEST_BOTH ||
loc->GetQuest() == RCQUEST_MQ && OTRGlobals::Instance->gRandomizer->masterQuestDungeons.contains(loc->GetScene()) ||
loc->GetQuest() == RCQUEST_VANILLA && !OTRGlobals::Instance->gRandomizer->masterQuestDungeons.contains(loc->GetScene()) ||
loc->GetQuest() == RCQUEST_MQ && OTRGlobals::Instance->gRandoContext->GetDungeons()->GetDungeonFromScene(loc->GetScene())->IsMQ() ||
loc->GetQuest() == RCQUEST_VANILLA && OTRGlobals::Instance->gRandoContext->GetDungeons()->GetDungeonFromScene(loc->GetScene())->IsVanilla() ||
rc == RC_GIFT_FROM_SAGES) && rc != RC_LINKS_POCKET;
}
return false;
@@ -1242,6 +1243,7 @@ void DrawLocation(RandomizerCheck rc) {
std::string txt;
bool showHidden = CVarGetInteger("gCheckTrackerOptionShowHidden", 0);
Rando::Location* loc = Rando::StaticData::GetLocation(rc);
Rando::ItemLocation* itemLoc = OTRGlobals::Instance->gRandoContext->GetItemLocation(rc);
RandomizerCheckTrackerData checkData = gSaveContext.checkTrackerData[rc];
RandomizerCheckStatus status = checkData.status;
bool skipped = checkData.skipped;
@@ -1335,7 +1337,7 @@ void DrawLocation(RandomizerCheck rc) {
case RCSHOW_COLLECTED:
case RCSHOW_SCUMMED:
if (IS_RANDO) {
txt = OTRGlobals::Instance->gRandomizer->EnumToSpoilerfileGetName[gSaveContext.itemLocations[rc].get.rgID][gSaveContext.language];
txt = itemLoc->GetPlacedItem().GetName().GetForLanguage(gSaveContext.language);
} else {
if (IsHeartPiece((GetItemID)Rando::StaticData::RetrieveItem(loc->GetVanillaItem()).GetItemID())) {
if (gSaveContext.language == LANGUAGE_ENG || gSaveContext.language == LANGUAGE_GER) {
@@ -1349,14 +1351,14 @@ void DrawLocation(RandomizerCheck rc) {
case RCSHOW_IDENTIFIED:
case RCSHOW_SEEN:
if (IS_RANDO) {
if (gSaveContext.itemLocations[rc].get.rgID == RG_ICE_TRAP) {
if (itemLoc->GetPlacedRandomizerGet() == RG_ICE_TRAP) {
if (status == RCSHOW_IDENTIFIED) {
txt = gSaveContext.itemLocations[rc].get.trickName;
txt = OTRGlobals::Instance->gRandoContext->overrides[rc].GetTrickName().GetForLanguage(gSaveContext.language);
} else {
txt = OTRGlobals::Instance->gRandomizer->EnumToSpoilerfileGetName[gSaveContext.itemLocations[rc].get.fakeRgID][gSaveContext.language];
txt = Rando::StaticData::RetrieveItem(OTRGlobals::Instance->gRandoContext->overrides[rc].LooksLike()).GetName().GetForLanguage(gSaveContext.language);
}
} else {
txt = OTRGlobals::Instance->gRandomizer->EnumToSpoilerfileGetName[gSaveContext.itemLocations[rc].get.rgID][gSaveContext.language];
txt = itemLoc->GetPlacedItem().GetName().GetForLanguage(gSaveContext.language);
}
if (status == RCSHOW_IDENTIFIED) {
txt += fmt::format(" - {}", gSaveContext.checkTrackerData[rc].price);

View File

@@ -12,6 +12,7 @@
#include <string.h>
#include "global.h"
#include "entrance.h"
extern PlayState* gPlayState;
@@ -114,6 +115,7 @@ void Entrance_ResetEntranceTable(void) {
}
void Entrance_Init(void) {
EntranceOverride* entranceOverrides = Randomizer_GetEntranceOverrides();
s32 index;
size_t blueWarpRemapIdx = 0;
@@ -153,13 +155,13 @@ void Entrance_Init(void) {
// Then overwrite the indices which are shuffled
for (size_t i = 0; i < ENTRANCE_OVERRIDES_MAX_COUNT; i++) {
if (Entrance_EntranceIsNull(&gSaveContext.entranceOverrides[i])) {
if (Entrance_EntranceIsNull(&entranceOverrides[i])) {
break;
}
s16 originalIndex = gSaveContext.entranceOverrides[i].index;
s16 blueWarpIndex = gSaveContext.entranceOverrides[i].blueWarp;
s16 overrideIndex = gSaveContext.entranceOverrides[i].override;
s16 originalIndex = entranceOverrides[i].index;
s16 blueWarpIndex = entranceOverrides[i].blueWarp;
s16 overrideIndex = entranceOverrides[i].override;
//Overwrite grotto related indices
if (originalIndex >= ENTRANCE_RANDO_GROTTO_EXIT_START) {
@@ -785,6 +787,7 @@ u8 Entrance_GetIsEntranceDiscovered(u16 entranceIndex) {
}
void Entrance_SetEntranceDiscovered(u16 entranceIndex) {
EntranceOverride* entranceOverrides = Randomizer_GetEntranceOverrides();
// Skip if already set to save time from setting the connected entrance or
// if this entrance is outside of the randomized entrance range (i.e. is a dynamic entrance)
if (entranceIndex > MAX_ENTRANCE_RANDO_USED_INDEX || Entrance_GetIsEntranceDiscovered(entranceIndex)) {
@@ -798,8 +801,8 @@ void Entrance_SetEntranceDiscovered(u16 entranceIndex) {
gSaveContext.sohStats.entrancesDiscovered[idx] |= entranceBit;
// Set connected
for (size_t i = 0; i < ENTRANCE_OVERRIDES_MAX_COUNT; i++) {
if (entranceIndex == gSaveContext.entranceOverrides[i].index) {
Entrance_SetEntranceDiscovered(gSaveContext.entranceOverrides[i].overrideDestination);
if (entranceIndex == entranceOverrides[i].index) {
Entrance_SetEntranceDiscovered(entranceOverrides[i].overrideDestination);
break;
}
}

View File

@@ -19,6 +19,7 @@ extern PlayState* gPlayState;
}
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include "entrance.h"
#define COLOR_ORANGE IM_COL32(230, 159, 0, 255)
#define COLOR_GREEN IM_COL32(0, 158, 115, 255)
@@ -459,6 +460,7 @@ void SortEntranceListByType(EntranceOverride* entranceList, u8 byDest) {
}
void SortEntranceListByArea(EntranceOverride* entranceList, u8 byDest) {
auto entranceCtx = Rando::Context::GetInstance()->GetEntranceShuffler();
EntranceOverride tempList[ENTRANCE_OVERRIDES_MAX_COUNT] = { 0 };
// Store to temp
@@ -498,10 +500,10 @@ void SortEntranceListByArea(EntranceOverride* entranceList, u8 byDest) {
// and otherwise by group
for (size_t group = ENTRANCE_GROUP_KOKIRI_FOREST; group < SPOILER_ENTRANCE_GROUP_COUNT; group++) {
for (size_t i = 0; i < ENTRANCE_OVERRIDES_MAX_COUNT; i++) {
if (Entrance_EntranceIsNull(&gSaveContext.entranceOverrides[i])) {
if (Entrance_EntranceIsNull(&entranceCtx->entranceOverrides[i])) {
continue;
}
const EntranceData* curEntrance = GetEntranceData(gSaveContext.entranceOverrides[i].index);
const EntranceData* curEntrance = GetEntranceData(entranceCtx->entranceOverrides[i].index);
if (curEntrance->srcGroup != group) {
continue;
}
@@ -561,6 +563,7 @@ void ClearEntranceTrackingData() {
}
void InitEntranceTrackingData() {
auto entranceCtx = Rando::Context::GetInstance()->GetEntranceShuffler();
gEntranceTrackingData = {0};
// Check if entrance randomization is disabled
@@ -570,11 +573,11 @@ void InitEntranceTrackingData() {
// Set total and group counts
for (size_t i = 0; i < ENTRANCE_OVERRIDES_MAX_COUNT; i++) {
if (Entrance_EntranceIsNull(&gSaveContext.entranceOverrides[i])) {
if (Entrance_EntranceIsNull(&entranceCtx->entranceOverrides[i])) {
break;
}
const EntranceData* index = GetEntranceData(gSaveContext.entranceOverrides[i].index);
const EntranceData* override = GetEntranceData(gSaveContext.entranceOverrides[i].override);
const EntranceData* index = GetEntranceData(entranceCtx->entranceOverrides[i].index);
const EntranceData* override = GetEntranceData(entranceCtx->entranceOverrides[i].override);
if (index->srcGroup == ENTRANCE_GROUP_ONE_WAY) {
gEntranceTrackingData.GroupEntranceCounts[ENTRANCE_SOURCE_AREA][ENTRANCE_GROUP_ONE_WAY]++;
@@ -616,10 +619,10 @@ void InitEntranceTrackingData() {
// Sort entrances by group and type in entranceData
for (size_t i = 0; i < ENTRANCE_OVERRIDES_MAX_COUNT; i++) {
srcListSortedByArea[i] = gSaveContext.entranceOverrides[i];
destListSortedByArea[i] = gSaveContext.entranceOverrides[i];
srcListSortedByType[i] = gSaveContext.entranceOverrides[i];
destListSortedByType[i] = gSaveContext.entranceOverrides[i];
srcListSortedByArea[i] = entranceCtx->entranceOverrides[i];
destListSortedByArea[i] = entranceCtx->entranceOverrides[i];
srcListSortedByType[i] = entranceCtx->entranceOverrides[i];
destListSortedByType[i] = entranceCtx->entranceOverrides[i];
}
SortEntranceListByArea(srcListSortedByArea, 0);
SortEntranceListByArea(destListSortedByArea, 1);

View File

@@ -150,7 +150,7 @@ void SetStartingItems() {
GiveLinkRupees(9001);
}
if (Randomizer_GetSettingValue(RSK_STARTING_MAPS_COMPASSES) == RO_DUNGEON_ITEM_LOC_STARTWITH) {
if (Randomizer_GetSettingValue(RSK_SHUFFLE_MAPANDCOMPASS) == RO_DUNGEON_ITEM_LOC_STARTWITH) {
uint32_t mapBitMask = 1 << 1;
uint32_t compassBitMask = 1 << 2;
uint32_t startingDungeonItemsBitMask = mapBitMask | compassBitMask;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,49 @@
#pragma once
#include "option.h"
#include "randomizerTypes.h"
#include "3drando/spoiler_log.hpp"
#include <array>
#include <set>
#include <unordered_map>
#include <nlohmann/json.hpp>
namespace Rando {
class Settings {
public:
Settings();
void CreateOptions();
Option& Setting(RandomizerSettingKey key);
Option& GetTrickOption(RandomizerTrick key);
const std::array<Option, RSK_MAX>& GetAllOptions() const;
std::vector<Option*>& GetExcludeOptionsForGroup(SpoilerCollectionCheckGroup group);
const std::vector<std::vector<Option*>>& GetExcludeLocationsOptions() const;
RandoOptionStartingAge ResolvedStartingAge() const;
RandoOptionLACSCondition LACSCondition() const;
std::string GetHash() const;
const std::string& GetSeedString() const;
void SetSeedString(std::string seedString);
const uint32_t GetSeed() const;
void SetSeed(uint32_t seed);
void SetHash(std::string hash);
const std::array<OptionGroup, RSG_MAX>& GetOptionGroups();
const OptionGroup& GetOptionGroup(RandomizerSettingGroupKey key);
void UpdateSettings(std::unordered_map<RandomizerSettingKey, uint8_t> cvarSettings,
std::set<RandomizerCheck> excludedLocations, std::set<RandomizerTrick> enabledTricks);
void ParseJson(nlohmann::json spoilerFileJson);
std::vector<Option*> VanillaLogicDefaults = {};
private:
std::array<Option, RSK_MAX> mOptions = {};
std::array<OptionGroup, RSG_MAX> mOptionGroups = {};
std::array<Option, RT_MAX> mTrickOptions;
std::vector<std::vector<Option*>> mExcludeLocationsOptionsGroups;
std::unordered_map<std::string, RandomizerSettingKey> mSpoilerfileSettingNameToEnum;
RandoOptionStartingAge mResolvedStartingAge;
RandoOptionLACSCondition mLACSCondition;
std::string mHash;
std::string mSeedString;
uint32_t mFinalSeed;
};
} // namespace Rando

View File

@@ -0,0 +1,82 @@
#include "trial.h"
namespace Rando {
TrialInfo::TrialInfo(const Text name_) : name(std::move(name_)) {}
TrialInfo::TrialInfo() = default;
TrialInfo::~TrialInfo() = default;
Text TrialInfo::GetName() const {
return name;
}
bool TrialInfo::IsSkipped() const {
return skipped;
}
bool TrialInfo::IsRequired() const {
return !skipped;
}
void TrialInfo::SetAsRequired() {
skipped = false;
}
void TrialInfo::SetAsSkipped() {
skipped = true;
}
Trials::Trials() {
mTrials[FOREST_TRIAL] = TrialInfo(Text{"the Forest Trial", "l'épreuve de la Forêt", "la prueba del bosque"});
mTrials[FIRE_TRIAL] = TrialInfo(Text{"the Fire Trial", "l'épreuve du Feu", "la prueba del fuego"});
mTrials[WATER_TRIAL] = TrialInfo(Text{"the Water Trial", "l'épreuve de l'Eau", "la prueba del agua"});
mTrials[SPIRIT_TRIAL] = TrialInfo(Text{"the Spirit Trial", "l'épreuve de l'Esprit", "la prueba del espíritu"});
mTrials[SHADOW_TRIAL] = TrialInfo(Text{"the Shadow Trial", "l'épreuve de l'Ombre", "la prueba de las sombras"});
mTrials[LIGHT_TRIAL] = TrialInfo(Text{"the Light Trial", "l'épreuve de la Lumière", "la prueba de la luz"});
}
Trials::~Trials() = default;
TrialInfo* Trials::GetTrial(TrialKey key) {
return &mTrials[key];
}
void Trials::SkipAll() {
for (TrialInfo& trial : mTrials) {
trial.SetAsSkipped();
}
}
void Trials::RequireAll() {
for (TrialInfo& trial : mTrials) {
trial.SetAsRequired();
}
}
std::array<TrialInfo*, 6> Trials::GetTrialList() {
std::array<TrialInfo*, 6> trialList;
for (size_t i = 0; i < mTrials.size(); i++) {
trialList[i] = &mTrials[i];
}
return trialList;
}
size_t Trials::GetTrialListSize() {
return mTrials.size();
}
void Trials::ParseJson(nlohmann::json spoilerFileJson) {
try {
nlohmann::json trialsJson = spoilerFileJson["requiredTrials"];
for (auto it = trialsJson.begin(); it != trialsJson.end(); it++) {
std::string trialName = it.value().template get<std::string>();
for (auto& trial : mTrials) {
if (trial.GetName() == trialName) {
trial.SetAsRequired();
} else {
trial.SetAsSkipped();
}
}
}
} catch (const std::exception& e) {
throw e;
}
}
} // namespace Rando

View File

@@ -0,0 +1,47 @@
#pragma once
#include "3drando/text.hpp"
#include <array>
#include <nlohmann/json.hpp>
namespace Rando {
class TrialInfo {
public:
TrialInfo(const Text name_);
TrialInfo();
~TrialInfo();
Text GetName() const;
bool IsSkipped() const;
bool IsRequired() const;
void SetAsRequired();
void SetAsSkipped();
private:
Text name;
bool skipped = true;
};
typedef enum {
LIGHT_TRIAL,
FOREST_TRIAL,
FIRE_TRIAL,
WATER_TRIAL,
SPIRIT_TRIAL,
SHADOW_TRIAL,
} TrialKey;
class Trials {
public:
Trials();
~Trials();
TrialInfo* GetTrial(TrialKey key);
void SkipAll();
void RequireAll();
std::array<TrialInfo*, 6> GetTrialList();
size_t GetTrialListSize();
void ParseJson(nlohmann::json spoilerFileJson);
private:
std::array<TrialInfo, 6> mTrials;
};
}

View File

@@ -41,6 +41,7 @@
#include "Enhancements/randomizer/randomizer_check_tracker.h"
#include "Enhancements/randomizer/3drando/random.hpp"
#include "Enhancements/randomizer/static_data.h"
#include "Enhancements/randomizer/dungeon.h"
#include "Enhancements/gameplaystats.h"
#include "Enhancements/n64_weird_frame_data.inc"
#include "frame_interpolation.h"
@@ -295,6 +296,8 @@ OTRGlobals::OTRGlobals() {
gSaveStateMgr = std::make_shared<SaveStateMgr>();
gRandoContext = Rando::Context::CreateInstance();
gRandoContext->AddExcludedOptions();
gRandoContext->GetSettings()->CreateOptions();
gRandomizer = std::make_shared<Randomizer>();
hasMasterQuest = hasOriginal = false;
@@ -1144,10 +1147,11 @@ uint32_t IsSceneMasterQuest(s16 sceneNum) {
value = 1;
} else {
value = 0;
if (IS_RANDO &&
!OTRGlobals::Instance->gRandomizer->masterQuestDungeons.empty() &&
OTRGlobals::Instance->gRandomizer->masterQuestDungeons.contains(sceneNum)) {
value = 1;
if (IS_RANDO) {
auto dungeon = OTRGlobals::Instance->gRandoContext->GetDungeons()->GetDungeonFromScene(sceneNum);
if (dungeon != nullptr && dungeon->IsMQ()) {
value = 1;
}
}
}
}
@@ -1316,7 +1320,12 @@ extern "C" char* ResourceMgr_LoadIfDListByName(const char* filePath) {
}
extern "C" Sprite* GetSeedTexture(uint8_t index) {
return OTRGlobals::Instance->gRandomizer->GetSeedTexture(index);
return OTRGlobals::Instance->gRandoContext->GetSeedTexture(index);
}
extern "C" uint8_t GetSeedIconIndex(uint8_t index) {
return OTRGlobals::Instance->gRandoContext->hashIconIndexes[index];
}
extern "C" char* ResourceMgr_LoadPlayerAnimByName(const char* animPath) {
@@ -1938,44 +1947,28 @@ extern "C" int GetEquipNowMessage(char* buffer, char* src, const int maxBufferSi
return 0;
}
extern "C" void Randomizer_LoadSettings(const char* spoilerFileName) {
OTRGlobals::Instance->gRandomizer->LoadRandomizerSettings(spoilerFileName);
extern "C" void Randomizer_ParseSpoiler(const char* fileLoc) {
OTRGlobals::Instance->gRandoContext->ParseSpoiler(fileLoc, CVarGetInteger("gPlandoMode", 0));
}
extern "C" void Randomizer_LoadHintLocations(const char* spoilerFileName) {
OTRGlobals::Instance->gRandomizer->LoadHintLocations(spoilerFileName);
extern "C" void Randomizer_LoadHintMessages() {
OTRGlobals::Instance->gRandomizer->LoadHintMessages();
}
extern "C" void Randomizer_LoadMerchantMessages(const char* spoilerFileName) {
OTRGlobals::Instance->gRandomizer->LoadMerchantMessages(spoilerFileName);
}
extern "C" void Randomizer_LoadRequiredTrials(const char* spoilerFileName) {
OTRGlobals::Instance->gRandomizer->LoadRequiredTrials(spoilerFileName);
}
extern "C" void Randomizer_LoadMasterQuestDungeons(const char* spoilerFileName) {
OTRGlobals::Instance->gRandomizer->LoadMasterQuestDungeons(spoilerFileName);
}
extern "C" void Randomizer_LoadItemLocations(const char* spoilerFileName, bool silent) {
OTRGlobals::Instance->gRandomizer->LoadItemLocations(spoilerFileName, silent);
extern "C" void Randomizer_LoadMerchantMessages() {
OTRGlobals::Instance->gRandomizer->LoadMerchantMessages();
}
extern "C" bool Randomizer_IsTrialRequired(RandomizerInf trial) {
return OTRGlobals::Instance->gRandomizer->IsTrialRequired(trial);
}
extern "C" void Randomizer_LoadEntranceOverrides(const char* spoilerFileName, bool silent) {
OTRGlobals::Instance->gRandomizer->LoadEntranceOverrides(spoilerFileName, silent);
}
extern "C" u32 SpoilerFileExists(const char* spoilerFileName) {
return OTRGlobals::Instance->gRandomizer->SpoilerFileExists(spoilerFileName);
}
extern "C" u8 Randomizer_GetSettingValue(RandomizerSettingKey randoSettingKey) {
return OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(randoSettingKey);
return OTRGlobals::Instance->gRandoContext->GetOption(randoSettingKey).GetSelectedOptionIndex();
}
extern "C" RandomizerCheck Randomizer_GetCheckFromActor(s16 actorId, s16 sceneNum, s16 actorParams) {
@@ -2023,6 +2016,38 @@ extern "C" ItemObtainability Randomizer_GetItemObtainabilityFromRandomizerCheck(
return OTRGlobals::Instance->gRandomizer->GetItemObtainabilityFromRandomizerCheck(randomizerCheck);
}
extern "C" void Randomizer_GenerateSeed() {
std::string seed = "";
if (OTRGlobals::Instance->gRandoContext->IsSpoilerLoaded()) {
seed = OTRGlobals::Instance->gRandoContext->GetSettings()->GetSeedString();
}
GenerateRandomizer(seed);
}
extern "C" uint8_t Randomizer_IsSeedGenerated() {
return OTRGlobals::Instance->gRandoContext->IsSeedGenerated() ? 1 : 0;
}
extern "C" void Randomizer_SetSeedGenerated(bool seedGenerated) {
OTRGlobals::Instance->gRandoContext->SetSeedGenerated(seedGenerated);
}
extern "C" uint8_t Randomizer_IsSpoilerLoaded() {
return OTRGlobals::Instance->gRandoContext->IsSpoilerLoaded() ? 1 : 0;
}
extern "C" void Randomizer_SetSpoilerLoaded(bool spoilerLoaded) {
OTRGlobals::Instance->gRandoContext->SetSpoilerLoaded(spoilerLoaded);
}
extern "C" uint8_t Randomizer_IsPlandoLoaded() {
return OTRGlobals::Instance->gRandoContext->IsPlandoLoaded() ? 1 : 0;
}
extern "C" void Randomizer_SetPlandoLoaded(bool plandoLoaded) {
OTRGlobals::Instance->gRandoContext->SetPlandoLoaded(plandoLoaded);
}
CustomMessage Randomizer_GetCustomGetItemMessage(Player* player) {
s16 giid;
if (player->getItemEntry.objectId != OBJECT_INVALID) {
@@ -2057,7 +2082,7 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) {
messageEntry = Randomizer_GetCustomGetItemMessage(player);
}
} else if (textId == TEXT_ITEM_DUNGEON_MAP || textId == TEXT_ITEM_COMPASS) {
if (DUNGEON_ITEMS_CAN_BE_OUTSIDE_DUNGEON(RSK_STARTING_MAPS_COMPASSES)) {
if (DUNGEON_ITEMS_CAN_BE_OUTSIDE_DUNGEON(RSK_SHUFFLE_MAPANDCOMPASS)) {
if (textId == TEXT_ITEM_DUNGEON_MAP) {
messageEntry = OTRGlobals::Instance->gRandomizer->GetMapGetItemMessageWithHint(player->getItemEntry);
} else {

View File

@@ -127,24 +127,28 @@ void* getN64WeirdFrame(s32 i);
int GetEquipNowMessage(char* buffer, char* src, const int maxBufferSize);
u32 SpoilerFileExists(const char* spoilerFileName);
Sprite* GetSeedTexture(uint8_t index);
void Randomizer_LoadSettings(const char* spoilerFileName);
uint8_t GetSeedIconIndex(uint8_t index);
u8 Randomizer_GetSettingValue(RandomizerSettingKey randoSettingKey);
RandomizerCheck Randomizer_GetCheckFromActor(s16 actorId, s16 sceneNum, s16 actorParams);
ScrubIdentity Randomizer_IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respawnData);
ShopItemIdentity Randomizer_IdentifyShopItem(s32 sceneNum, u8 slotIndex);
CowIdentity Randomizer_IdentifyCow(s32 sceneNum, s32 posX, s32 posZ);
void Randomizer_LoadHintLocations(const char* spoilerFileName);
void Randomizer_LoadMerchantMessages(const char* spoilerFileName);
void Randomizer_LoadRequiredTrials(const char* spoilerFileName);
void Randomizer_LoadMasterQuestDungeons(const char* spoilerFileName);
void Randomizer_LoadItemLocations(const char* spoilerFileName, bool silent);
void Randomizer_LoadEntranceOverrides(const char* spoilerFileName, bool silent);
void Randomizer_ParseSpoiler(const char* fileLoc);
void Randomizer_LoadHintMessages();
void Randomizer_LoadMerchantMessages();
bool Randomizer_IsTrialRequired(RandomizerInf trial);
GetItemEntry Randomizer_GetItemFromActor(s16 actorId, s16 sceneNum, s16 actorParams, GetItemID ogId);
GetItemEntry Randomizer_GetItemFromActorWithoutObtainabilityCheck(s16 actorId, s16 sceneNum, s16 actorParams, GetItemID ogId);
GetItemEntry Randomizer_GetItemFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId);
GetItemEntry Randomizer_GetItemFromKnownCheckWithoutObtainabilityCheck(RandomizerCheck randomizerCheck, GetItemID ogId);
ItemObtainability Randomizer_GetItemObtainabilityFromRandomizerCheck(RandomizerCheck randomizerCheck);
void Randomizer_GenerateSeed();
uint8_t Randomizer_IsSeedGenerated();
void Randomizer_SetSeedGenerated(bool seedGenerated);
uint8_t Randomizer_IsSpoilerLoaded();
void Randomizer_SetSpoilerLoaded(bool spoilerLoaded);
uint8_t Randomizer_IsPlandoLoaded();
void Randomizer_SetPlandoLoaded(bool plandoLoaded);
int CustomMessage_RetrieveIfExists(PlayState* play);
void Overlay_DisplayText(float duration, const char* text);
void Overlay_DisplayText_Seconds(int seconds, const char* text);

View File

@@ -1,6 +1,10 @@
#include "SaveManager.h"
#include "OTRGlobals.h"
#include "Enhancements/game-interactor/GameInteractor.h"
#include "Enhancements/randomizer/context.h"
#include "Enhancements/randomizer/entrance.h"
#include "Enhancements/randomizer/dungeon.h"
#include "Enhancements/randomizer/trial.h"
#include "soh/util.h"
#include "z64.h"
@@ -61,7 +65,8 @@ SaveManager::SaveManager() {
AddLoadFunction("randomizer", 1, LoadRandomizerVersion1);
AddLoadFunction("randomizer", 2, LoadRandomizerVersion2);
AddSaveFunction("randomizer", 2, SaveRandomizer, true, SECTION_PARENT_NONE);
AddLoadFunction("randomizer", 3, LoadRandomizerVersion3);
AddSaveFunction("randomizer", 3, SaveRandomizer, true, SECTION_PARENT_NONE);
AddInitFunction(InitFileImpl);
@@ -92,47 +97,65 @@ SaveManager::SaveManager() {
}
void SaveManager::LoadRandomizerVersion1() {
for (int i = 0; i < ARRAY_COUNT(gSaveContext.itemLocations); i++) {
auto randoContext = Rando::Context::GetInstance();
RandomizerCheck location = RC_UNKNOWN_CHECK;
for (int i = 0; i < RC_MAX; i++) {
SaveManager::Instance->LoadData("check" + std::to_string(i), location);
SaveManager::Instance->LoadStruct("get" + std::to_string(i), [&]() {
SaveManager::Instance->LoadData("rgID", gSaveContext.itemLocations[i].get.rgID);
SaveManager::Instance->LoadData("fakeRgID", gSaveContext.itemLocations[i].get.fakeRgID);
SaveManager::Instance->LoadCharArray("trickName", gSaveContext.itemLocations[i].get.trickName,
MAX_TRICK_NAME_SIZE);
SaveManager::Instance->LoadData("rgID", randoContext->GetItemLocation(location)->RefPlacedItem());
if (randoContext->GetItemLocation(location)->GetPlacedRandomizerGet() == RG_ICE_TRAP) {
randoContext->overrides[location].SetLocation(location);
SaveManager::Instance->LoadData("fakeRgID", randoContext->overrides[location].RefLooksLike());
SaveManager::Instance->LoadData("trickName", randoContext->overrides[location].GetTrickName().english);
SaveManager::Instance->LoadData("trickName", randoContext->overrides[location].GetTrickName().french);
}
});
SaveManager::Instance->LoadData("check" + std::to_string(i), gSaveContext.itemLocations[i].check);
}
for (int i = 0; i < ARRAY_COUNT(gSaveContext.seedIcons); i++) {
SaveManager::Instance->LoadData("seed" + std::to_string(i), gSaveContext.seedIcons[i]);
for (int i = 0; i < randoContext->hashIconIndexes.size(); i++) {
SaveManager::Instance->LoadData("seed" + std::to_string(i), randoContext->hashIconIndexes[i]);
}
for (int i = 0; i < ARRAY_COUNT(gSaveContext.randoSettings); i++) {
SaveManager::Instance->LoadData("sk" + std::to_string(i), gSaveContext.randoSettings[i].key);
SaveManager::Instance->LoadData("sv" + std::to_string(i), gSaveContext.randoSettings[i].value);
for (int i = 0; i < RSK_MAX; i++) {
int key, value;
SaveManager::Instance->LoadData("sk" + std::to_string(i), key);
SaveManager::Instance->LoadData("sv" + std::to_string(i), value);
randoContext->GetOption(RandomizerSettingKey(key)).SetSelectedIndex(value);
}
for (int i = 0; i < ARRAY_COUNT(gSaveContext.hintLocations); i++) {
SaveManager::Instance->LoadData("hc" + std::to_string(i), gSaveContext.hintLocations[i].check);
for (int j = 0; j < ARRAY_COUNT(gSaveContext.hintLocations[i].hintText); j++) {
SaveManager::Instance->LoadData("ht" + std::to_string(i) + "-" + std::to_string(j), gSaveContext.hintLocations[i].hintText[j]);
for (int i = 0; i < 50; i++) {
RandomizerCheck check;
char hintText[200];
SaveManager::Instance->LoadData("hc" + std::to_string(i), check);
for (int j = 0; j < ARRAY_COUNT(hintText); j++) {
SaveManager::Instance->LoadData("ht" + std::to_string(i) + "-" + std::to_string(j), hintText[j]);
}
randoContext->AddHint(RandomizerHintKey(check - RC_COLOSSUS_GOSSIP_STONE + 1), Text(hintText), RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, Text());
}
for (int i = 0; i < ARRAY_COUNT(gSaveContext.childAltarText); i++) {
SaveManager::Instance->LoadData("cat" + std::to_string(i), gSaveContext.childAltarText[i]);
char childAltarText[250];
for (int i = 0; i < ARRAY_COUNT(childAltarText); i++) {
SaveManager::Instance->LoadData("cat" + std::to_string(i), childAltarText[i]);
}
randoContext->AddHint(RH_ALTAR_CHILD, Text(childAltarText), RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, Text());
for (int i = 0; i < ARRAY_COUNT(gSaveContext.adultAltarText); i++) {
SaveManager::Instance->LoadData("aat" + std::to_string(i), gSaveContext.adultAltarText[i]);
char adultAltarText[750];
for (int i = 0; i < ARRAY_COUNT(adultAltarText); i++) {
SaveManager::Instance->LoadData("aat" + std::to_string(i), adultAltarText[i]);
}
randoContext->AddHint(RH_ALTAR_ADULT, Text(adultAltarText), RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, Text());
for (int i = 0; i < ARRAY_COUNT(gSaveContext.ganonHintText); i++) {
SaveManager::Instance->LoadData("ght" + std::to_string(i), gSaveContext.ganonHintText[i]);
char ganonHintText[150];
for (int i = 0; i < ARRAY_COUNT(ganonHintText); i++) {
SaveManager::Instance->LoadData("ght" + std::to_string(i), ganonHintText[i]);
}
randoContext->AddHint(RH_GANONDORF_HINT, Text(ganonHintText), RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, Text());
for (int i = 0; i < ARRAY_COUNT(gSaveContext.ganonText); i++) {
SaveManager::Instance->LoadData("gt" + std::to_string(i), gSaveContext.ganonText[i]);
char ganonText[250];
for (int i = 0; i < ARRAY_COUNT(ganonText); i++) {
SaveManager::Instance->LoadData("gt" + std::to_string(i), ganonText[i]);
}
randoContext->AddHint(RH_GANONDORF_NOHINT, Text(ganonText), RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, Text());
SaveManager::Instance->LoadData("adultTradeItems", gSaveContext.adultTradeItems);
@@ -140,14 +163,12 @@ void SaveManager::LoadRandomizerVersion1() {
SaveManager::Instance->LoadData("pendingIceTrapCount", gSaveContext.pendingIceTrapCount);
std::shared_ptr<Randomizer> randomizer = OTRGlobals::Instance->gRandomizer;
randomizer->LoadRandomizerSettings("");
size_t merchantPricesSize = 0;
if (randomizer->GetRandoSettingValue(RSK_SHUFFLE_SCRUBS) != RO_SCRUBS_OFF) {
if (randoContext->GetOption(RSK_SHUFFLE_SCRUBS).Is(RO_SCRUBS_OFF)) {
merchantPricesSize += NUM_SCRUBS;
}
if (randomizer->GetRandoSettingValue(RSK_SHOPSANITY) != RO_SHOPSANITY_OFF) {
if (randoContext->GetOption(RSK_SHOPSANITY).Is(RO_SHOPSANITY_OFF)) {
merchantPricesSize += NUM_SHOP_ITEMS;
}
@@ -157,84 +178,107 @@ void SaveManager::LoadRandomizerVersion1() {
SaveManager::Instance->LoadData("check", rc);
uint32_t price;
SaveManager::Instance->LoadData("price", price);
randomizer->merchantPrices[rc] = price;
randoContext->GetItemLocation(rc)->SetCustomPrice(price);
});
});
}
void SaveManager::LoadRandomizerVersion2() {
auto randoContext = Rando::Context::GetInstance();
SaveManager::Instance->LoadArray("itemLocations", RC_MAX, [&](size_t i) {
gSaveContext.itemLocations[i].check = RandomizerCheck(i);
SaveManager::Instance->LoadStruct("", [&]() {
SaveManager::Instance->LoadData("rgID", gSaveContext.itemLocations[i].get.rgID);
SaveManager::Instance->LoadData("fakeRgID", gSaveContext.itemLocations[i].get.fakeRgID);
SaveManager::Instance->LoadCharArray("trickName", gSaveContext.itemLocations[i].get.trickName,
MAX_TRICK_NAME_SIZE);
SaveManager::Instance->LoadData("rgID", randoContext->GetItemLocation(i)->RefPlacedItem());
RandomizerGet rg = RG_NONE;
SaveManager::Instance->LoadData("fakeRgID", rg, RG_NONE);
if (rg != RG_NONE) {
randoContext->overrides[static_cast<RandomizerCheck>(i)] = Rando::ItemOverride(static_cast<RandomizerCheck>(i), rg);
SaveManager::Instance->LoadData("trickName", randoContext->overrides[static_cast<RandomizerCheck>(i)].GetTrickName().english);
SaveManager::Instance->LoadData("trickName", randoContext->overrides[static_cast<RandomizerCheck>(i)].GetTrickName().french);
}
});
});
SaveManager::Instance->LoadArray("entrances", ARRAY_COUNT(gSaveContext.entranceOverrides), [&](size_t i) {
auto entranceCtx = randoContext->GetEntranceShuffler();
SaveManager::Instance->LoadArray("entrances", ARRAY_COUNT(entranceCtx->entranceOverrides), [&](size_t i) {
SaveManager::Instance->LoadStruct("", [&]() {
SaveManager::Instance->LoadData("index", gSaveContext.entranceOverrides[i].index);
SaveManager::Instance->LoadData("destination", gSaveContext.entranceOverrides[i].destination);
SaveManager::Instance->LoadData("blueWarp", gSaveContext.entranceOverrides[i].blueWarp);
SaveManager::Instance->LoadData("override", gSaveContext.entranceOverrides[i].override);
SaveManager::Instance->LoadData("overrideDestination", gSaveContext.entranceOverrides[i].overrideDestination);
SaveManager::Instance->LoadData("index", entranceCtx->entranceOverrides[i].index);
SaveManager::Instance->LoadData("destination", entranceCtx->entranceOverrides[i].destination);
SaveManager::Instance->LoadData("blueWarp", entranceCtx->entranceOverrides[i].blueWarp);
SaveManager::Instance->LoadData("override", entranceCtx->entranceOverrides[i].override);
SaveManager::Instance->LoadData("overrideDestination", entranceCtx->entranceOverrides[i].overrideDestination);
});
});
SaveManager::Instance->LoadArray("seed", ARRAY_COUNT(gSaveContext.seedIcons), [&](size_t i) {
SaveManager::Instance->LoadData("", gSaveContext.seedIcons[i]);
SaveManager::Instance->LoadArray("seed", randoContext->hashIconIndexes.size(), [&](size_t i) {
SaveManager::Instance->LoadData("", randoContext->hashIconIndexes[i]);
});
std::string inputSeed;
SaveManager::Instance->LoadCharArray("inputSeed", gSaveContext.inputSeed, ARRAY_COUNT(gSaveContext.inputSeed));
SaveManager::Instance->LoadData("inputSeed", inputSeed);
randoContext->GetSettings()->SetSeedString(inputSeed);
SaveManager::Instance->LoadData("finalSeed", gSaveContext.finalSeed);
uint32_t finalSeed;
SaveManager::Instance->LoadData("finalSeed", finalSeed);
randoContext->GetSettings()->SetSeed(finalSeed);
SaveManager::Instance->LoadArray("randoSettings", RSK_MAX, [&](size_t i) {
gSaveContext.randoSettings[i].key = RandomizerSettingKey(i);
SaveManager::Instance->LoadData("", gSaveContext.randoSettings[i].value);
int value = 0;
SaveManager::Instance->LoadData("", value);
randoContext->GetOption(RandomizerSettingKey(i)).SetSelectedIndex(value);
});
SaveManager::Instance->LoadArray("hintLocations", ARRAY_COUNT(gSaveContext.hintLocations), [&](size_t i) {
SaveManager::Instance->LoadArray("hintLocations", RH_ZR_OPEN_GROTTO_GOSSIP_STONE + 1, [&](size_t i) {
SaveManager::Instance->LoadStruct("", [&]() {
SaveManager::Instance->LoadData("check", gSaveContext.hintLocations[i].check);
SaveManager::Instance->LoadCharArray("hintText", gSaveContext.hintLocations[i].hintText,
ARRAY_COUNT(gSaveContext.hintLocations[i].hintText));
RandomizerCheck rc = RC_UNKNOWN_CHECK;
SaveManager::Instance->LoadData("check", rc);
std::string hintText;
SaveManager::Instance->LoadData("hintText", hintText);
randoContext->AddHint(RandomizerHintKey(rc - RC_COLOSSUS_GOSSIP_STONE + 1), Text(hintText), RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, Text());
});
});
SaveManager::Instance->LoadCharArray("childAltarText", gSaveContext.childAltarText,
ARRAY_COUNT(gSaveContext.childAltarText));
SaveManager::Instance->LoadCharArray("adultAltarText", gSaveContext.adultAltarText,
ARRAY_COUNT(gSaveContext.adultAltarText));
SaveManager::Instance->LoadCharArray("ganonHintText", gSaveContext.ganonHintText,
ARRAY_COUNT(gSaveContext.ganonHintText));
SaveManager::Instance->LoadCharArray("ganonText", gSaveContext.ganonText, ARRAY_COUNT(gSaveContext.ganonText));
SaveManager::Instance->LoadCharArray("dampeText", gSaveContext.dampeText, ARRAY_COUNT(gSaveContext.dampeText));
SaveManager::Instance->LoadCharArray("gregHintText", gSaveContext.gregHintText,
ARRAY_COUNT(gSaveContext.gregHintText));
SaveManager::Instance->LoadCharArray("sheikText", gSaveContext.sheikText, ARRAY_COUNT(gSaveContext.sheikText));
SaveManager::Instance->LoadCharArray("sariaText", gSaveContext.sariaText, ARRAY_COUNT(gSaveContext.sariaText));
SaveManager::Instance->LoadCharArray("warpMinuetText", gSaveContext.warpMinuetText,
ARRAY_COUNT(gSaveContext.warpMinuetText));
SaveManager::Instance->LoadCharArray("warpBoleroText", gSaveContext.warpBoleroText,
ARRAY_COUNT(gSaveContext.warpBoleroText));
SaveManager::Instance->LoadCharArray("warpSerenadeText", gSaveContext.warpSerenadeText,
ARRAY_COUNT(gSaveContext.warpSerenadeText));
SaveManager::Instance->LoadCharArray("warpRequiemText", gSaveContext.warpRequiemText,
ARRAY_COUNT(gSaveContext.warpRequiemText));
SaveManager::Instance->LoadCharArray("warpNocturneText", gSaveContext.warpNocturneText,
ARRAY_COUNT(gSaveContext.warpNocturneText));
SaveManager::Instance->LoadCharArray("warpPreludeText", gSaveContext.warpPreludeText,
ARRAY_COUNT(gSaveContext.warpPreludeText));
std::string childAltarText;
SaveManager::Instance->LoadData("childAltarText", childAltarText);
randoContext->AddHint(RH_ALTAR_CHILD, Text(childAltarText), RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, Text());
std::string adultAltarText;
SaveManager::Instance->LoadData("adultAltarText", adultAltarText);
randoContext->AddHint(RH_ALTAR_ADULT, Text(adultAltarText), RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, Text());
std::string ganonHintText;
SaveManager::Instance->LoadData("ganonHintText", ganonHintText);
randoContext->AddHint(RH_GANONDORF_HINT, Text(ganonHintText), RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, Text());
std::string ganonText;
SaveManager::Instance->LoadData("ganonText", ganonText);
randoContext->AddHint(RH_GANONDORF_NOHINT, Text(ganonText), RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, Text());
std::string dampeText;
SaveManager::Instance->LoadData("dampeText", dampeText);
randoContext->AddHint(RH_DAMPES_DIARY, Text(dampeText), RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, Text());
std::string gregHintText;
SaveManager::Instance->LoadData("gregHintText", gregHintText);
randoContext->AddHint(RH_GREG_RUPEE, Text(gregHintText), RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, Text());
std::string sheikText;
SaveManager::Instance->LoadData("sheikText", sheikText);
randoContext->AddHint(RH_SHEIK_LIGHT_ARROWS, Text(sheikText), RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, Text());
std::string sariaText;
SaveManager::Instance->LoadData("sariaText", sariaText);
randoContext->AddHint(RH_SARIA, Text(sariaText), RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, Text());
std::string warpMinuetText;
SaveManager::Instance->LoadData("warpMinuetText", warpMinuetText);
randoContext->AddHint(RH_MINUET_WARP_LOC, Text(warpMinuetText), RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, Text(warpMinuetText));
std::string warpBoleroText;
SaveManager::Instance->LoadData("warpBoleroText", warpBoleroText);
randoContext->AddHint(RH_BOLERO_WARP_LOC, Text(warpBoleroText), RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, Text(warpBoleroText));
std::string warpSerenadeText;
SaveManager::Instance->LoadData("warpSerenadeText", warpSerenadeText);
randoContext->AddHint(RH_SERENADE_WARP_LOC, Text(warpSerenadeText), RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, Text(warpSerenadeText));
std::string warpRequiemText;
SaveManager::Instance->LoadData("warpRequiemText", warpRequiemText);
randoContext->AddHint(RH_REQUIEM_WARP_LOC, Text(warpRequiemText), RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, Text(warpRequiemText));
std::string warpNocturneText;
SaveManager::Instance->LoadData("warpNocturneText", warpNocturneText);
randoContext->AddHint(RH_NOCTURNE_WARP_LOC, Text(warpNocturneText), RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, Text(warpNocturneText));
std::string warpPreludeText;
SaveManager::Instance->LoadData("warpPreludeText", warpPreludeText);
randoContext->AddHint(RH_PRELUDE_WARP_LOC, Text(warpPreludeText), RC_UNKNOWN_CHECK, HINT_TYPE_STATIC, Text(warpPreludeText));
SaveManager::Instance->LoadData("adultTradeItems", gSaveContext.adultTradeItems);
@@ -244,8 +288,6 @@ void SaveManager::LoadRandomizerVersion2() {
std::shared_ptr<Randomizer> randomizer = OTRGlobals::Instance->gRandomizer;
randomizer->LoadRandomizerSettings("");
size_t merchantPricesSize = 0;
SaveManager::Instance->LoadData("merchantPricesSize", merchantPricesSize);
@@ -255,76 +297,194 @@ void SaveManager::LoadRandomizerVersion2() {
SaveManager::Instance->LoadData("check", rc);
uint32_t price;
SaveManager::Instance->LoadData("price", price);
randomizer->merchantPrices[rc] = price;
randoContext->GetItemLocation(rc)->SetCustomPrice(price);
});
});
SaveManager::Instance->LoadData("masterQuestDungeonCount", gSaveContext.mqDungeonCount, (uint8_t)0);
size_t mqDungeonCount;
SaveManager::Instance->LoadData("masterQuestDungeonCount", mqDungeonCount, (size_t)0);
OTRGlobals::Instance->gRandomizer->masterQuestDungeons.clear();
SaveManager::Instance->LoadArray("masterQuestDungeons", gSaveContext.mqDungeonCount, [&](size_t i) {
randoContext->GetDungeons()->ClearAllMQ();
SaveManager::Instance->LoadArray("masterQuestDungeons", mqDungeonCount, [&](size_t i) {
uint16_t scene;
SaveManager::Instance->LoadData("", scene);
randomizer->masterQuestDungeons.emplace(scene);
randoContext->GetDungeons()->GetDungeonFromScene(SceneID(scene))->SetMQ();
});
}
void SaveManager::LoadRandomizerVersion3() {
auto randoContext = Rando::Context::GetInstance();
SaveManager::Instance->LoadArray("itemLocations", RC_MAX, [&](size_t i) {
SaveManager::Instance->LoadStruct("", [&]() {
SaveManager::Instance->LoadData("rgID", randoContext->GetItemLocation(i)->RefPlacedItem());
RandomizerGet rg = RG_NONE;
SaveManager::Instance->LoadData("fakeRgID", rg, RG_NONE);
if (rg != RG_NONE) {
randoContext->overrides[static_cast<RandomizerCheck>(i)] =
Rando::ItemOverride(static_cast<RandomizerCheck>(i), rg);
SaveManager::Instance->LoadStruct("trickName", [&]() {
SaveManager::Instance->LoadData(
"english", randoContext->overrides[static_cast<RandomizerCheck>(i)].GetTrickName().english);
SaveManager::Instance->LoadData(
"french", randoContext->overrides[static_cast<RandomizerCheck>(i)].GetTrickName().french);
});
}
uint16_t price = 0;
SaveManager::Instance->LoadData("price", price, (uint16_t)0);
if (price > 0) {
// Technically an item with a custom price (scrub/shopsanity) could have
// a 0 rupee price, meaning it would not be loaded after the first save and
// disappear from the save file. However, this is fine, as the default price on
// all ItemLocations is 0 anyway.
randoContext->GetItemLocation(i)->SetCustomPrice(price);
}
});
});
auto entranceCtx = randoContext->GetEntranceShuffler();
SaveManager::Instance->LoadArray("entrances", ARRAY_COUNT(entranceCtx->entranceOverrides), [&](size_t i) {
SaveManager::Instance->LoadStruct("", [&]() {
SaveManager::Instance->LoadData("index", entranceCtx->entranceOverrides[i].index);
SaveManager::Instance->LoadData("destination", entranceCtx->entranceOverrides[i].destination);
SaveManager::Instance->LoadData("blueWarp", entranceCtx->entranceOverrides[i].blueWarp);
SaveManager::Instance->LoadData("override", entranceCtx->entranceOverrides[i].override);
SaveManager::Instance->LoadData("overrideDestination",
entranceCtx->entranceOverrides[i].overrideDestination);
});
});
SaveManager::Instance->LoadArray("seed", randoContext->hashIconIndexes.size(), [&](size_t i) {
SaveManager::Instance->LoadData("", randoContext->hashIconIndexes[i]);
});
std::string inputSeed;
SaveManager::Instance->LoadData("inputSeed", inputSeed);
randoContext->GetSettings()->SetSeedString(inputSeed);
uint32_t finalSeed;
SaveManager::Instance->LoadData("finalSeed", finalSeed);
randoContext->GetSettings()->SetSeed(finalSeed);
SaveManager::Instance->LoadArray("randoSettings", RSK_MAX, [&](size_t i) {
int value = 0;
SaveManager::Instance->LoadData("", value);
randoContext->GetOption(RandomizerSettingKey(i)).SetSelectedIndex(value);
});
SaveManager::Instance->LoadArray("hintLocations", RH_MAX, [&](size_t i) {
SaveManager::Instance->LoadStruct("", [&]() {
RandomizerHintKey rhk = RH_NONE;
SaveManager::Instance->LoadData("hintKey", rhk);
std::string english, french;
SaveManager::Instance->LoadStruct("hintText", [&]() {
SaveManager::Instance->LoadData("english", english);
SaveManager::Instance->LoadData("french", french);
// TODO: German Hint Translations
});
RandomizerCheck rc = RC_UNKNOWN_CHECK;
SaveManager::Instance->LoadData("hintedCheck", rc);
HintType ht = HINT_TYPE_STATIC;
SaveManager::Instance->LoadData("hintType", ht);
std::string englishRegion, frenchRegion;
SaveManager::Instance->LoadStruct("hintedRegion", [&]() {
SaveManager::Instance->LoadData("english", englishRegion);
SaveManager::Instance->LoadData("french", frenchRegion);
});
randoContext->AddHint(rhk, Text(english, french, english), rc, ht, Text(englishRegion, frenchRegion, englishRegion));
});
});
SaveManager::Instance->LoadData("adultTradeItems", gSaveContext.adultTradeItems);
SaveManager::Instance->LoadData("triforcePiecesCollected", gSaveContext.triforcePiecesCollected);
SaveManager::Instance->LoadData("pendingIceTrapCount", gSaveContext.pendingIceTrapCount);
std::shared_ptr<Randomizer> randomizer = OTRGlobals::Instance->gRandomizer;
size_t mqDungeonCount;
SaveManager::Instance->LoadData("masterQuestDungeonCount", mqDungeonCount, (size_t)0);
randoContext->GetDungeons()->ClearAllMQ();
SaveManager::Instance->LoadArray("masterQuestDungeons", mqDungeonCount, [&](size_t i) {
size_t dungeonId;
SaveManager::Instance->LoadData("", dungeonId);
randoContext->GetDungeon(dungeonId)->SetMQ();
});
randoContext->GetTrials()->SkipAll();
SaveManager::Instance->LoadArray("requiredTrials", randoContext->GetOption(RSK_TRIAL_COUNT).GetSelectedOptionIndex()+1, [&](size_t i) {
size_t trialId;
SaveManager::Instance->LoadData("", trialId);
randoContext->GetTrial(trialId)->SetAsRequired();
});
}
void SaveManager::SaveRandomizer(SaveContext* saveContext, int sectionID, bool fullSave) {
if(saveContext->questId != QUEST_RANDOMIZER) return;
auto randoContext = Rando::Context::GetInstance();
SaveManager::Instance->SaveArray("itemLocations", RC_MAX, [&](size_t i) {
SaveManager::Instance->SaveStruct("", [&]() {
SaveManager::Instance->SaveData("rgID", saveContext->itemLocations[i].get.rgID);
SaveManager::Instance->SaveData("fakeRgID", saveContext->itemLocations[i].get.fakeRgID);
SaveManager::Instance->SaveData("trickName", saveContext->itemLocations[i].get.trickName);
SaveManager::Instance->SaveData("rgID", randoContext->GetItemLocation(i)->GetPlacedRandomizerGet());
if (randoContext->GetItemLocation(i)->GetPlacedRandomizerGet() == RG_ICE_TRAP) {
SaveManager::Instance->SaveData("fakeRgID", randoContext->overrides[static_cast<RandomizerCheck>(i)].LooksLike());
SaveManager::Instance->SaveStruct("trickName", [&]() {
SaveManager::Instance->SaveData("english", randoContext->overrides[static_cast<RandomizerCheck>(i)].GetTrickName().GetEnglish());
SaveManager::Instance->SaveData("french", randoContext->overrides[static_cast<RandomizerCheck>(i)].GetTrickName().GetFrench());
// TODO: German (trick names don't have german translations yet)
});
}
if (randoContext->GetItemLocation(i)->HasCustomPrice()) {
SaveManager::Instance->SaveData("price", randoContext->GetItemLocation(i)->GetPrice());
}
});
});
SaveManager::Instance->SaveArray("entrances", ARRAY_COUNT(saveContext->entranceOverrides), [&](size_t i) {
auto entranceCtx = randoContext->GetEntranceShuffler();
SaveManager::Instance->SaveArray("entrances", ARRAY_COUNT(entranceCtx->entranceOverrides), [&](size_t i) {
SaveManager::Instance->SaveStruct("", [&]() {
SaveManager::Instance->SaveData("index", saveContext->entranceOverrides[i].index);
SaveManager::Instance->SaveData("destination", saveContext->entranceOverrides[i].destination);
SaveManager::Instance->SaveData("blueWarp", saveContext->entranceOverrides[i].blueWarp);
SaveManager::Instance->SaveData("override", saveContext->entranceOverrides[i].override);
SaveManager::Instance->SaveData("overrideDestination", saveContext->entranceOverrides[i].overrideDestination);
SaveManager::Instance->SaveData("index", entranceCtx->entranceOverrides[i].index);
SaveManager::Instance->SaveData("destination", entranceCtx->entranceOverrides[i].destination);
SaveManager::Instance->SaveData("blueWarp", entranceCtx->entranceOverrides[i].blueWarp);
SaveManager::Instance->SaveData("override", entranceCtx->entranceOverrides[i].override);
SaveManager::Instance->SaveData("overrideDestination", entranceCtx->entranceOverrides[i].overrideDestination);
});
});
SaveManager::Instance->SaveArray("seed", ARRAY_COUNT(saveContext->seedIcons), [&](size_t i) {
SaveManager::Instance->SaveData("", saveContext->seedIcons[i]);
SaveManager::Instance->SaveArray("seed", randoContext->hashIconIndexes.size(), [&](size_t i) {
SaveManager::Instance->SaveData("", randoContext->hashIconIndexes[i]);
});
SaveManager::Instance->SaveData("inputSeed", saveContext->inputSeed);
SaveManager::Instance->SaveData("inputSeed", randoContext->GetSettings()->GetSeedString());
SaveManager::Instance->SaveData("finalSeed", saveContext->finalSeed);
SaveManager::Instance->SaveData("finalSeed", randoContext->GetSettings()->GetSeed());
SaveManager::Instance->SaveArray("randoSettings", RSK_MAX, [&](size_t i) {
SaveManager::Instance->SaveData("", saveContext->randoSettings[i].value);
SaveManager::Instance->SaveData("", randoContext->GetOption((RandomizerSettingKey(i))).GetSelectedOptionIndex());
});
SaveManager::Instance->SaveArray("hintLocations", ARRAY_COUNT(saveContext->hintLocations), [&](size_t i) {
SaveManager::Instance->SaveArray("hintLocations", RH_MAX, [&](size_t i) {
SaveManager::Instance->SaveStruct("", [&]() {
SaveManager::Instance->SaveData("check", saveContext->hintLocations[i].check);
SaveManager::Instance->SaveData("hintText", saveContext->hintLocations[i].hintText);
auto hint = randoContext->GetHint(RandomizerHintKey(i));
SaveManager::Instance->SaveData("hintKey", RandomizerHintKey(i));
SaveManager::Instance->SaveStruct("hintText", [&]() {
SaveManager::Instance->SaveData("english", hint->GetText().GetEnglish());
SaveManager::Instance->SaveData("french", hint->GetText().GetFrench());
SaveManager::Instance->SaveData("german", hint->GetText().GetEnglish());
// TODO: German Translation of hints
});
SaveManager::Instance->SaveData("hintedCheck", hint->GetHintedLocation());
SaveManager::Instance->SaveData("hintType", hint->GetHintType());
SaveManager::Instance->SaveStruct("hintedRegion", [&]() {
SaveManager::Instance->SaveData("english", hint->GetHintedRegionText().GetEnglish());
SaveManager::Instance->SaveData("french", hint->GetHintedRegionText().GetFrench());
SaveManager::Instance->SaveData("german", hint->GetHintedRegionText().GetEnglish());
});
});
});
SaveManager::Instance->SaveData("childAltarText", saveContext->childAltarText);
SaveManager::Instance->SaveData("adultAltarText", saveContext->adultAltarText);
SaveManager::Instance->SaveData("ganonHintText", saveContext->ganonHintText);
SaveManager::Instance->SaveData("ganonText", saveContext->ganonText);
SaveManager::Instance->SaveData("dampeText", saveContext->dampeText);
SaveManager::Instance->SaveData("gregHintText", saveContext->gregHintText);
SaveManager::Instance->SaveData("sheikText", saveContext->sheikText);
SaveManager::Instance->SaveData("sariaText", saveContext->sariaText);
SaveManager::Instance->SaveData("warpMinuetText", saveContext->warpMinuetText);
SaveManager::Instance->SaveData("warpBoleroText", saveContext->warpBoleroText);
SaveManager::Instance->SaveData("warpSerenadeText", saveContext->warpSerenadeText);
SaveManager::Instance->SaveData("warpRequiemText", saveContext->warpRequiemText);
SaveManager::Instance->SaveData("warpNocturneText", saveContext->warpNocturneText);
SaveManager::Instance->SaveData("warpPreludeText", saveContext->warpPreludeText);
SaveManager::Instance->SaveData("adultTradeItems", saveContext->adultTradeItems);
SaveManager::Instance->SaveData("triforcePiecesCollected", saveContext->triforcePiecesCollected);
@@ -333,27 +493,18 @@ void SaveManager::SaveRandomizer(SaveContext* saveContext, int sectionID, bool f
std::shared_ptr<Randomizer> randomizer = OTRGlobals::Instance->gRandomizer;
std::vector<std::pair<RandomizerCheck, u16>> merchantPrices;
for (const auto & [ check, price ] : randomizer->merchantPrices) {
merchantPrices.push_back(std::make_pair(check, price));
}
SaveManager::Instance->SaveData("masterQuestDungeonCount", randoContext->GetDungeons()->CountMQ());
SaveManager::Instance->SaveData("merchantPricesSize", merchantPrices.size());
SaveManager::Instance->SaveArray("merchantPrices", merchantPrices.size(), [&](size_t i) {
SaveManager::Instance->SaveStruct("", [&]() {
SaveManager::Instance->SaveData("check", merchantPrices[i].first);
SaveManager::Instance->SaveData("price", merchantPrices[i].second);
});
SaveManager::Instance->SaveArray("masterQuestDungeons", randoContext->GetDungeons()->GetDungeonListSize(), [&](size_t i) {
if (randoContext->GetDungeon(i)->IsMQ()) {
SaveManager::Instance->SaveData("", i);
}
});
SaveManager::Instance->SaveData("masterQuestDungeonCount", saveContext->mqDungeonCount);
std::vector<uint16_t> masterQuestDungeons;
for (const auto scene : randomizer->masterQuestDungeons) {
masterQuestDungeons.push_back(scene);
}
SaveManager::Instance->SaveArray("masterQuestDungeons", masterQuestDungeons.size(), [&](size_t i) {
SaveManager::Instance->SaveData("", masterQuestDungeons[i]);
SaveManager::Instance->SaveArray("requiredTrials", randoContext->GetTrials()->GetTrialListSize(), [&](size_t i) {
if (randoContext->GetTrial(i)->IsRequired()) {
SaveManager::Instance->SaveData("", i);
}
});
}
@@ -436,17 +587,18 @@ void SaveManager::InitMeta(int fileNum) {
fileMetaInfo[fileNum].gregFound = Flags_GetRandomizerInf(RAND_INF_GREG_FOUND);
fileMetaInfo[fileNum].defense = gSaveContext.inventory.defenseHearts;
fileMetaInfo[fileNum].health = gSaveContext.health;
auto randoContext = Rando::Context::GetInstance();
for (int i = 0; i < ARRAY_COUNT(fileMetaInfo[fileNum].seedHash); i++) {
fileMetaInfo[fileNum].seedHash[i] = gSaveContext.seedIcons[i];
for (int i = 0; i < ARRAY_COUNT(fileMetaInfo[fileNum].seedHash); i++) {
fileMetaInfo[fileNum].seedHash[i] = randoContext->hashIconIndexes[i];
}
fileMetaInfo[fileNum].randoSave = IS_RANDO;
// If the file is marked as a Master Quest file or if we're randomized and have at least one master quest dungeon, we need the mq otr.
fileMetaInfo[fileNum].requiresMasterQuest = IS_MASTER_QUEST || (IS_RANDO && gSaveContext.mqDungeonCount > 0);
fileMetaInfo[fileNum].requiresMasterQuest = IS_MASTER_QUEST || (IS_RANDO && randoContext->GetDungeons()->CountMQ() > 0);
// If the file is not marked as Master Quest, it could still theoretically be a rando save with all 12 MQ dungeons, in which case
// we don't actually require a vanilla OTR.
fileMetaInfo[fileNum].requiresOriginal = !IS_MASTER_QUEST && (!IS_RANDO || gSaveContext.mqDungeonCount < 12);
fileMetaInfo[fileNum].requiresOriginal = !IS_MASTER_QUEST && (!IS_RANDO || randoContext->GetDungeons()->CountMQ() < 12);
fileMetaInfo[fileNum].buildVersionMajor = gSaveContext.sohStats.buildVersionMajor;
fileMetaInfo[fileNum].buildVersionMinor = gSaveContext.sohStats.buildVersionMinor;

View File

@@ -157,6 +157,7 @@ class SaveManager {
static void LoadRandomizerVersion1();
static void LoadRandomizerVersion2();
static void LoadRandomizerVersion3();
static void SaveRandomizer(SaveContext* saveContext, int sectionID, bool fullSave);
static void LoadBaseVersion1();

View File

@@ -1472,6 +1472,14 @@ extern std::shared_ptr<CheckTracker::CheckTrackerSettingsWindow> mCheckTrackerSe
void DrawRandomizerMenu() {
if (ImGui::BeginMenu("Randomizer")) {
UIWidgets::EnhancementCheckbox("Plando Mode", "gPlandoMode");
UIWidgets::Tooltip(
"When dropping a spoiler file on the game window, parse the full spoiler file instead of just the "
"necessary "
"parts to regenerate a seed.\n\nKeep in mind if you do this, all custom text will only be available in the "
"language present in the spoilerfile. You can use this to edit a previously generated spoilerfile that has "
"been edited with custom hint text and item locations. May be useful for debugging.");
UIWidgets::PaddedSeparator();
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(12.0f, 6.0f));
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0, 0));
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);

View File

@@ -221,8 +221,7 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) {
gSaveContext.n64ddFlag = fileChooseCtx->n64ddFlag;
if (fileChooseCtx->questType[fileChooseCtx->buttonIndex] == QUEST_RANDOMIZER &&
strnlen(CVarGetString("gSpoilerLog", ""), 1) != 0) {
if (Randomizer_IsSeedGenerated()) {
gSaveContext.questId = QUEST_RANDOMIZER;
Randomizer_InitSaveFile();

View File

@@ -65,6 +65,7 @@ typedef enum {
CM_BOSS_RUSH_MENU,
CM_START_BOSS_RUSH_MENU,
CM_BOSS_RUSH_TO_QUEST,
CM_GENERATE_SEED,
} ConfigMode;
typedef enum {

View File

@@ -671,13 +671,6 @@ static void DrawMoreInfo(FileChooseContext* this, s16 fileIndex, u8 alpha) {
void Sram_InitDebugSave(void);
void Sram_InitBossRushSave();
u8 hasRandomizerQuest() {
if (strnlen(CVarGetString("gSpoilerLog", ""), 1) != 0) {
return 1;
}
return 0;
}
void FileChoose_DrawTextureI8(GraphicsContext* gfxCtx, const void* texture, s16 texWidth, s16 texHeight, s16 rectLeft, s16 rectTop,
s16 rectWidth, s16 rectHeight, s16 dsdx, s16 dtdy) {
OPEN_DISPS(gfxCtx);
@@ -953,17 +946,15 @@ void SpriteDraw(FileChooseContext* this, Sprite* sprite, int left, int top, int
CLOSE_DISPS(this->state.gfxCtx);
}
bool fileSelectSpoilerFileLoaded = false;
void DrawSeedHashSprites(FileChooseContext* this) {
OPEN_DISPS(this->state.gfxCtx);
gDPPipeSync(POLY_OPA_DISP++);
gDPSetCombineMode(POLY_OPA_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM);
// Draw icons on the main menu, when a rando file is selected, and when quest selection is set to rando
if ((this->configMode == CM_MAIN_MENU &&
(this->selectMode != SM_CONFIRM_FILE || Save_GetSaveMetaInfo(this->selectedFileIndex)->randoSave == 1)) ||
(this->configMode == CM_QUEST_MENU && this->questType[this->buttonIndex] == QUEST_RANDOMIZER)) {
// Draw icons on the main menu, when a rando file is selected, and on name entry when quest selection is set to rando
if (this->configMode == CM_MAIN_MENU &&
(this->selectMode != SM_CONFIRM_FILE || Save_GetSaveMetaInfo(this->selectedFileIndex)->randoSave == 1)) {
if (this->fileInfoAlpha[this->selectedFileIndex] > 0) {
// Use file info alpha to match fading
@@ -972,30 +963,32 @@ void DrawSeedHashSprites(FileChooseContext* this) {
u16 xStart = 64;
// Draw Seed Icons for specific file
for (unsigned int i = 0; i < 5; i++) {
if (Save_GetSaveMetaInfo(this->selectedFileIndex)->randoSave == 1) {
SpriteLoad(this, GetSeedTexture(Save_GetSaveMetaInfo(this->selectedFileIndex)->seedHash[i]));
SpriteDraw(this, GetSeedTexture(Save_GetSaveMetaInfo(this->selectedFileIndex)->seedHash[i]),
xStart + (40 * i), 10, 24, 24);
}
SpriteLoad(this, GetSeedTexture(Save_GetSaveMetaInfo(this->selectedFileIndex)->seedHash[i]));
SpriteDraw(this, GetSeedTexture(Save_GetSaveMetaInfo(this->selectedFileIndex)->seedHash[i]),
xStart + (40 * i), 10, 24, 24);
}
}
}
// Draw Seed Icons for spoiler log:
// 1. On Name Entry if a rando seed has been generated
// 2. On Quest Menu if a spoiler has been dropped and the Randomizer quest option is currently hovered.
if ((Randomizer_IsSeedGenerated() ||
(strnlen(CVarGetString("gSpoilerLog", ""), 1) != 0 && Randomizer_IsSpoilerLoaded())) &&
((this->configMode == CM_NAME_ENTRY && gSaveContext.questId == QUEST_RANDOMIZER) ||
(this->configMode == CM_QUEST_MENU && this->questType[this->buttonIndex] == QUEST_RANDOMIZER))) {
// Fade top seed icons based on main menu fade and if save supports rando
u8 alpha = MAX(this->optionButtonAlpha, Save_GetSaveMetaInfo(this->selectedFileIndex)->randoSave == 1 ? 0xFF : 0);
u8 alpha =
MAX(this->optionButtonAlpha, Save_GetSaveMetaInfo(this->selectedFileIndex)->randoSave == 1 ? 0xFF : 0);
if (alpha >= 200) {
alpha = 0xFF;
}
gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 0xFF, 0xFF, 0xFF, alpha);
// Draw Seed Icons for spoiler log
if (this->configMode == CM_QUEST_MENU && this->questType[this->buttonIndex] == QUEST_RANDOMIZER &&
strnlen(CVarGetString("gSpoilerLog", ""), 1) != 0 && fileSelectSpoilerFileLoaded) {
u16 xStart = 64;
for (unsigned int i = 0; i < 5; i++) {
SpriteLoad(this, GetSeedTexture(gSaveContext.seedIcons[i]));
SpriteDraw(this, GetSeedTexture(gSaveContext.seedIcons[i]), xStart + (40 * i), 10, 24, 24);
}
u16 xStart = 64;
for (unsigned int i = 0; i < 5; i++) {
SpriteLoad(this, GetSeedTexture(GetSeedIconIndex(i)));
SpriteDraw(this, GetSeedTexture(GetSeedIconIndex(i)), xStart + (40 * i), 10, 24, 24);
}
}
@@ -1012,7 +1005,7 @@ void FileChoose_UpdateRandomizer() {
func_800F5E18(SEQ_PLAYER_BGM_MAIN, NA_BGM_HORSE, 0, 7, 1);
return;
} else if (CVarGetInteger("gRandoGenerating", 0) == 0 && generating) {
if (SpoilerFileExists(CVarGetString("gSpoilerLog", ""))) {
if (SpoilerFileExists(CVarGetString("gSpoilerLog", "")) || Randomizer_IsSeedGenerated()) {
Audio_PlayFanfare(NA_BGM_HORSE_GOAL);
} else {
func_80078884(NA_SE_SY_OCARINA_ERROR);
@@ -1026,31 +1019,15 @@ void FileChoose_UpdateRandomizer() {
if (!SpoilerFileExists(CVarGetString("gSpoilerLog", ""))) {
CVarSetString("gSpoilerLog", "");
fileSelectSpoilerFileLoaded = false;
}
if ((CVarGetInteger("gNewFileDropped", 0) != 0) || (CVarGetInteger("gNewSeedGenerated", 0) != 0) ||
(!fileSelectSpoilerFileLoaded && SpoilerFileExists(CVarGetString("gSpoilerLog", "")))) {
if (CVarGetInteger("gNewFileDropped", 0) != 0) {
CVarSetString("gSpoilerLog", CVarGetString("gDroppedFile", "None"));
}
bool silent = true;
if ((CVarGetInteger("gNewFileDropped", 0) != 0) || (CVarGetInteger("gNewSeedGenerated", 0) != 0)) {
silent = false;
}
if ((CVarGetInteger("gNewFileDropped", 0) != 0)) {
CVarSetString("gSpoilerLog", CVarGetString("gDroppedFile", ""));
CVarSetInteger("gNewSeedGenerated", 0);
CVarSetInteger("gNewFileDropped", 0);
CVarSetString("gDroppedFile", "");
fileSelectSpoilerFileLoaded = false;
const char* fileLoc = CVarGetString("gSpoilerLog", "");
Randomizer_LoadSettings(fileLoc);
Randomizer_LoadHintLocations(fileLoc);
Randomizer_LoadRequiredTrials(fileLoc);
Randomizer_LoadItemLocations(fileLoc, silent);
Randomizer_LoadMerchantMessages(fileLoc);
Randomizer_LoadMasterQuestDungeons(fileLoc);
Randomizer_LoadEntranceOverrides(fileLoc, silent);
fileSelectSpoilerFileLoaded = true;
Randomizer_ParseSpoiler(fileLoc);
}
}
@@ -1300,8 +1277,10 @@ void FileChoose_UpdateQuestMenu(GameState* thisx) {
this->prevConfigMode = this->configMode;
this->configMode = CM_ROTATE_TO_BOSS_RUSH_MENU;
return;
} else if (this->questType[this->buttonIndex] == QUEST_RANDOMIZER && !hasRandomizerQuest()) {
Audio_PlaySoundGeneral(NA_SE_SY_FSEL_ERROR, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8);
} else if (this->questType[this->buttonIndex] == QUEST_RANDOMIZER) {
Audio_PlaySoundGeneral(NA_SE_SY_FSEL_DECIDE_L, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8);
this->prevConfigMode = this->configMode;
this->configMode = CM_GENERATE_SEED;
} else {
Audio_PlaySoundGeneral(NA_SE_SY_FSEL_DECIDE_L, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8);
osSyncPrintf("Selected Dungeon Quest: %d\n", IS_MASTER_QUEST);
@@ -1330,6 +1309,33 @@ void FileChoose_UpdateQuestMenu(GameState* thisx) {
}
}
void FileChoose_GenerateRandoSeed(GameState* thisx) {
FileChooseContext* this = (FileChooseContext*)thisx;
FileChoose_UpdateRandomizer();
if (Randomizer_IsSeedGenerated() || Randomizer_IsPlandoLoaded()) {
static u8 emptyName[] = { 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E };
static u8 linkName[] = { 0x15, 0x2C, 0x31, 0x2E, 0x3E, 0x3E, 0x3E, 0x3E };
this->prevConfigMode = this->configMode;
this->configMode = CM_ROTATE_TO_NAME_ENTRY;
this->logoAlpha = 0;
CVarSetInteger("gOnFileSelectNameEntry", 1);
this->kbdButton = FS_KBD_BTN_NONE;
this->charPage = FS_CHAR_PAGE_ENG;
this->kbdX = 0;
this->kbdY = 0;
this->charIndex = 0;
this->charBgAlpha = 0;
this->newFileNameCharCount = CVarGetInteger("gLinkDefaultName", 0) ? 4 : 0;
this->nameEntryBoxPosX = 120;
this->nameEntryBoxAlpha = 0;
memcpy(Save_GetSaveMetaInfo(this->buttonIndex)->playerName,
CVarGetInteger("gLinkDefaultName", 0) ? &linkName : &emptyName, 8);
return;
} else {
Randomizer_GenerateSeed();
}
}
static s8 sLastBossRushOptionIndex = -1;
static s8 sLastBossRushOptionValue = -1;
@@ -1562,6 +1568,7 @@ static void (*gConfigModeUpdateFuncs[])(GameState*) = {
FileChoose_RotateToMain, FileChoose_RotateToQuest,
FileChoose_RotateToBossRush, FileChoose_UpdateBossRushMenu,
FileChoose_StartBossRushMenu, FileChoose_RotateToQuest,
FileChoose_GenerateRandoSeed,
};
/**
@@ -2161,6 +2168,7 @@ void FileChoose_DrawWindowContents(GameState* thisx) {
case CM_QUEST_TO_MAIN:
case CM_NAME_ENTRY_TO_QUEST_MENU:
case CM_ROTATE_TO_BOSS_RUSH_MENU:
case CM_GENERATE_SEED:
tex = FileChoose_GetQuestChooseTitleTexName(gSaveContext.language);
break;
case CM_BOSS_RUSH_MENU:
@@ -2174,6 +2182,7 @@ void FileChoose_DrawWindowContents(GameState* thisx) {
}
OPEN_DISPS(this->state.gfxCtx);
DrawSeedHashSprites(this);
// draw title label
gDPPipeSync(POLY_OPA_DISP++);
@@ -2189,32 +2198,34 @@ void FileChoose_DrawWindowContents(GameState* thisx) {
// draw next title label
if ((this->configMode == CM_QUEST_MENU) || (this->configMode == CM_START_QUEST_MENU) ||
this->configMode == CM_NAME_ENTRY_TO_QUEST_MENU) {
this->configMode == CM_NAME_ENTRY_TO_QUEST_MENU || this->configMode == CM_GENERATE_SEED) {
// draw control stick prompts.
Gfx_SetupDL_39Opa(this->state.gfxCtx);
gDPSetCombineMode(POLY_OPA_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM);
gDPLoadTextureBlock(POLY_OPA_DISP++, gArrowCursorTex, G_IM_FMT_IA, G_IM_SIZ_8b, 16, 24, 0,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 4, G_TX_NOMASK, G_TX_NOLOD,
G_TX_NOLOD);
FileChoose_DrawTextRec(this->state.gfxCtx, this->stickLeftPrompt.arrowColorR,
this->stickLeftPrompt.arrowColorG, this->stickLeftPrompt.arrowColorB,
this->stickLeftPrompt.arrowColorA, this->stickLeftPrompt.arrowTexX,
this->stickLeftPrompt.arrowTexY, this->stickLeftPrompt.z, 0, 0, -1.0f, 1.0f);
FileChoose_DrawTextRec(this->state.gfxCtx, this->stickRightPrompt.arrowColorR,
this->stickRightPrompt.arrowColorG, this->stickRightPrompt.arrowColorB,
this->stickRightPrompt.arrowColorA, this->stickRightPrompt.arrowTexX,
this->stickRightPrompt.arrowTexY, this->stickRightPrompt.z, 0, 0, 1.0f, 1.0f);
gDPLoadTextureBlock(POLY_OPA_DISP++, gControlStickTex, G_IM_FMT_IA, G_IM_SIZ_8b, 16, 16, 0,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 4, G_TX_NOMASK, G_TX_NOLOD,
G_TX_NOLOD);
FileChoose_DrawTextRec(this->state.gfxCtx, this->stickLeftPrompt.stickColorR,
this->stickLeftPrompt.stickColorG, this->stickLeftPrompt.stickColorB,
this->stickLeftPrompt.stickColorA, this->stickLeftPrompt.stickTexX,
this->stickLeftPrompt.stickTexY, this->stickLeftPrompt.z, 0, 0, -1.0f, 1.0f);
FileChoose_DrawTextRec(this->state.gfxCtx, this->stickRightPrompt.stickColorR,
this->stickRightPrompt.stickColorG, this->stickRightPrompt.stickColorB,
this->stickRightPrompt.stickColorA, this->stickRightPrompt.stickTexX,
this->stickRightPrompt.stickTexY, this->stickRightPrompt.z, 0, 0, 1.0f, 1.0f);
if (this->configMode != CM_GENERATE_SEED) {
Gfx_SetupDL_39Opa(this->state.gfxCtx);
gDPSetCombineMode(POLY_OPA_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM);
gDPLoadTextureBlock(POLY_OPA_DISP++, gArrowCursorTex, G_IM_FMT_IA, G_IM_SIZ_8b, 16, 24, 0,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 4, G_TX_NOMASK, G_TX_NOLOD,
G_TX_NOLOD);
FileChoose_DrawTextRec(this->state.gfxCtx, this->stickLeftPrompt.arrowColorR,
this->stickLeftPrompt.arrowColorG, this->stickLeftPrompt.arrowColorB,
this->stickLeftPrompt.arrowColorA, this->stickLeftPrompt.arrowTexX,
this->stickLeftPrompt.arrowTexY, this->stickLeftPrompt.z, 0, 0, -1.0f, 1.0f);
FileChoose_DrawTextRec(this->state.gfxCtx, this->stickRightPrompt.arrowColorR,
this->stickRightPrompt.arrowColorG, this->stickRightPrompt.arrowColorB,
this->stickRightPrompt.arrowColorA, this->stickRightPrompt.arrowTexX,
this->stickRightPrompt.arrowTexY, this->stickRightPrompt.z, 0, 0, 1.0f, 1.0f);
gDPLoadTextureBlock(POLY_OPA_DISP++, gControlStickTex, G_IM_FMT_IA, G_IM_SIZ_8b, 16, 16, 0,
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 4, G_TX_NOMASK, G_TX_NOLOD,
G_TX_NOLOD);
FileChoose_DrawTextRec(this->state.gfxCtx, this->stickLeftPrompt.stickColorR,
this->stickLeftPrompt.stickColorG, this->stickLeftPrompt.stickColorB,
this->stickLeftPrompt.stickColorA, this->stickLeftPrompt.stickTexX,
this->stickLeftPrompt.stickTexY, this->stickLeftPrompt.z, 0, 0, -1.0f, 1.0f);
FileChoose_DrawTextRec(this->state.gfxCtx, this->stickRightPrompt.stickColorR,
this->stickRightPrompt.stickColorG, this->stickRightPrompt.stickColorB,
this->stickRightPrompt.stickColorA, this->stickRightPrompt.stickTexX,
this->stickRightPrompt.stickTexY, this->stickRightPrompt.z, 0, 0, 1.0f, 1.0f);
}
switch (this->questType[this->buttonIndex]) {
case QUEST_NORMAL:
default:
@@ -2233,11 +2244,10 @@ void FileChoose_DrawWindowContents(GameState* thisx) {
break;
case QUEST_RANDOMIZER:
DrawSeedHashSprites(this);
if (hasRandomizerQuest()) {
gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, this->logoAlpha);
if (this->configMode == CM_GENERATE_SEED) {
gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, this->logoAlpha / 2);
} else {
gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 0x40, 0x40, 0x40, this->logoAlpha);
gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, this->logoAlpha);
}
FileChoose_DrawTextureI8(this->state.gfxCtx, gTitleTheLegendOfTextTex, 72, 8, 156, 108, 72, 8, 1024, 1024);
FileChoose_DrawTextureI8(this->state.gfxCtx, gTitleOcarinaOfTimeTMTextTex, 96, 8, 154, 163, 96, 8, 1024, 1024);
@@ -2658,7 +2668,8 @@ void FileChoose_ConfigModeDraw(GameState* thisx) {
// draw quest menu
if ((this->configMode == CM_QUEST_MENU) || (this->configMode == CM_ROTATE_TO_QUEST_MENU) ||
(this->configMode == CM_ROTATE_TO_NAME_ENTRY) || this->configMode == CM_QUEST_TO_MAIN ||
this->configMode == CM_NAME_ENTRY_TO_QUEST_MENU || this->configMode == CM_ROTATE_TO_BOSS_RUSH_MENU) {
this->configMode == CM_NAME_ENTRY_TO_QUEST_MENU || this->configMode == CM_ROTATE_TO_BOSS_RUSH_MENU ||
this->configMode == CM_GENERATE_SEED) {
// window
gDPPipeSync(POLY_OPA_DISP++);
gDPSetCombineMode(POLY_OPA_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM);
@@ -2964,13 +2975,8 @@ void FileChoose_LoadGame(GameState* thisx) {
this->state.running = false;
Randomizer_LoadSettings("");
Randomizer_LoadHintLocations("");
Randomizer_LoadItemLocations("", true);
Randomizer_LoadRequiredTrials("");
Randomizer_LoadMerchantMessages("");
Randomizer_LoadMasterQuestDungeons("");
Randomizer_LoadEntranceOverrides("", true);
Randomizer_LoadHintMessages();
Randomizer_LoadMerchantMessages();
gSaveContext.respawn[0].entranceIndex = -1;
gSaveContext.respawnFlag = 0;
@@ -3182,25 +3188,25 @@ void FileChoose_DrawRandoSaveVersionWarning(GameState* thisx) {
static const char* noRandoGeneratedText[] = {
// English
"No Randomizer seed currently available.\nGenerate one in the Randomizer Settings"
"Open Randomizer Settings to change your settings,\nthen press A to generate a new seed"
#if defined(__WIIU__) || defined(__SWITCH__)
".",
#else
",\nor drop a spoiler log on the game window.",
#endif
// German
"No Randomizer seed currently available.\nGenerate one in the Randomizer Settings"
"Open Randomizer Settings to change your settings,\nthen press A to generate a new seed"
#if defined(__WIIU__) || defined(__SWITCH__)
".",
#else
",\nor drop a spoiler log on the game window.",
#endif
// French
"Aucune Seed de Randomizer actuellement disponible.\nGénérez-en une dans les \"Randomizer Settings\""
"Ouvrez le menu \"Randomizer Settings\" pour modifier\nvos paramètres, appuyez sur A pour générer\nune nouvelle seed"
#if (defined(__WIIU__) || defined(__SWITCH__))
"."
#else
"\nou glissez un spoilerlog sur la fenêtre du jeu."
" ou glissez un spoilerlog sur la\nfenêtre du jeu."
#endif
};
@@ -3210,7 +3216,7 @@ void FileChoose_DrawNoRandoGeneratedWarning(GameState* thisx) {
OPEN_DISPS(this->state.gfxCtx);
// Draw rando seed warning when build version doesn't match for Major or Minor number
if (this->configMode == CM_QUEST_MENU && this->questType[this->buttonIndex] == QUEST_RANDOMIZER && !hasRandomizerQuest()) {
if (this->configMode == CM_QUEST_MENU && this->questType[this->buttonIndex] == QUEST_RANDOMIZER && !(Randomizer_IsSeedGenerated() || Randomizer_IsSpoilerLoaded())) {
uint8_t textAlpha = 225;
uint8_t textboxAlpha = 170;
float textboxScale = 0.7f;
@@ -3223,12 +3229,18 @@ void FileChoose_DrawNoRandoGeneratedWarning(GameState* thisx) {
uint16_t textboxWidth = 256 * textboxScale;
uint16_t textboxHeight = 64 * textboxScale;
uint8_t leftOffset = 72;
uint8_t bottomOffset = 84;
uint8_t bottomOffset = 132;
uint8_t textVerticalOffset;
#if defined(__WIIU__) || defined(__SWITCH__)
textVerticalOffset = 127; // 2 lines
textVerticalOffset = 80; // 2 lines
if (gSaveContext.language == LANGUAGE_FRA) {
textVerticalOffset = 75; // 3 lines
}
#else
textVerticalOffset = 122; // 3 lines
textVerticalOffset = 75; // 3 lines
if (gSaveContext.language == LANGUAGE_FRA) {
textVerticalOffset = 70; // 4 lines
}
#endif
Gfx_SetupDL_39Opa(this->state.gfxCtx);
@@ -3664,7 +3676,6 @@ void FileChoose_Init(GameState* thisx) {
this->questType[0] = MIN_QUEST;
this->questType[1] = MIN_QUEST;
this->questType[2] = MIN_QUEST;
fileSelectSpoilerFileLoaded = false;
isFastFileIdIncompatible = 0;
CVarSetInteger("gOnFileSelectNameEntry", 0);

View File

@@ -375,6 +375,7 @@ void FileChoose_DrawNameEntry(GameState* thisx) {
this->newFileNameCharCount = 0;
if (this->prevConfigMode == CM_QUEST_MENU) {
this->configMode = CM_NAME_ENTRY_TO_QUEST_MENU;
Randomizer_SetSeedGenerated(false);
} else {
this->configMode = CM_NAME_ENTRY_TO_MAIN;
}
@@ -457,6 +458,9 @@ void FileChoose_DrawNameEntry(GameState* thisx) {
this->configMode = CM_NAME_ENTRY_TO_MAIN;
CVarSetInteger("gOnFileSelectNameEntry", 0);
CVarSetInteger("gNewFileDropped", 0);
Randomizer_SetSeedGenerated(false);
Randomizer_SetSpoilerLoaded(false);
Randomizer_SetPlandoLoaded(false);
this->nameBoxAlpha[this->buttonIndex] = this->nameAlpha[this->buttonIndex] = 200;
this->connectorAlpha[this->buttonIndex] = 255;
func_800AA000(300.0f, 0xB4, 0x14, 0x64);