Merge remote-tracking branch 'upstream/develop-rando' into soulcalibur

This commit is contained in:
Ralphie Morell 2023-11-16 22:51:16 -05:00
commit aa00765997
85 changed files with 7692 additions and 9571 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);
@ -852,7 +853,7 @@ void GenerateItemPool() {
}
}
if (BombchusInLogic) {
if (ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC)) {
AddItemToMainPool(RG_PROGRESSIVE_BOMBCHUS, 5);
} else {
AddItemToMainPool(RG_BOMBCHU_5);
@ -862,28 +863,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++) {
@ -893,15 +894,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);
@ -915,10 +916,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 {
@ -928,9 +929,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;
}
@ -940,56 +941,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);
@ -997,36 +998,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);
}
@ -1034,7 +1035,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);
}
@ -1057,55 +1058,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;
}
@ -1113,11 +1114,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);
@ -1129,7 +1130,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);
}
@ -1140,10 +1141,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());
}
@ -1154,11 +1155,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) {
@ -1168,7 +1169,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);
@ -1178,54 +1179,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 || (HasBossSoul(RG_KING_DODONGO_SOUL) &&
(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 || (HasBossSoul(RG_BONGO_BONGO_SOUL) &&
((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 {
@ -440,29 +438,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)));
@ -505,7 +504,7 @@ namespace Logic {
}
}
uint8_t GetDifficultyValueFromString(Option& glitchOption) {
uint8_t GetDifficultyValueFromString(Rando::Option& glitchOption) {
return 0;
}
@ -522,11 +521,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
@ -535,6 +535,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);
@ -553,7 +554,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);
@ -570,28 +571,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;
@ -604,34 +606,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;
@ -649,26 +651,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);
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>();
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 = (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) {
@ -769,9 +770,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;
@ -897,7 +901,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;
@ -1018,7 +1022,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;
@ -1036,9 +1040,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;
@ -1070,7 +1074,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

@ -1858,47 +1858,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,
@ -1906,6 +1907,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;
@ -3242,6 +3251,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,
@ -3264,6 +3319,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,
@ -3278,7 +3334,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,
@ -3308,6 +3363,7 @@ typedef enum {
RSK_SCRUB_TEXT_HINT,
RSK_HINT_CLARITY,
RSK_HINT_DISTRIBUTION,
RSK_SHUFFLE_MAPANDCOMPASS,
RSK_KEYSANITY,
RSK_GERUDO_KEYS,
RSK_BOSS_KEYSANITY,
@ -3334,8 +3390,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,
@ -3380,6 +3437,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,
@ -3563,6 +3622,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,
@ -3687,10 +3755,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,
@ -3699,6 +3779,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);