mirror of
https://github.com/HarbourMasters/Shipwright
synced 2026-06-23 09:39:54 -04:00
Fix numerous Small Key Tracking bugs, excess items now more reliably turn into Blupees (#6750)
This commit is contained in:
@@ -319,16 +319,6 @@ extern GraphicsContext* __gfxCtx;
|
||||
#define NUM_TRIALS 6
|
||||
#define NUM_SHOP_ITEMS 64
|
||||
#define NUM_SCRUBS 46
|
||||
#define FOREST_TEMPLE_SMALL_KEY_MAX (ResourceMgr_IsSceneMasterQuest(SCENE_FOREST_TEMPLE) ? 6 : 5)
|
||||
#define FIRE_TEMPLE_SMALL_KEY_MAX (ResourceMgr_IsSceneMasterQuest(SCENE_FIRE_TEMPLE) ? 5 : 8)
|
||||
#define WATER_TEMPLE_SMALL_KEY_MAX (ResourceMgr_IsSceneMasterQuest(SCENE_WATER_TEMPLE) ? 2 : 6)
|
||||
#define SPIRIT_TEMPLE_SMALL_KEY_MAX (ResourceMgr_IsSceneMasterQuest(SCENE_SPIRIT_TEMPLE) ? 7 : 5)
|
||||
#define SHADOW_TEMPLE_SMALL_KEY_MAX (ResourceMgr_IsSceneMasterQuest(SCENE_SHADOW_TEMPLE) ? 6 : 5)
|
||||
#define BOTTOM_OF_THE_WELL_SMALL_KEY_MAX (ResourceMgr_IsSceneMasterQuest(SCENE_BOTTOM_OF_THE_WELL) ? 2 : 3)
|
||||
#define GERUDO_TRAINING_GROUND_SMALL_KEY_MAX (ResourceMgr_IsSceneMasterQuest(SCENE_GERUDO_TRAINING_GROUND) ? 3 : 9)
|
||||
#define GERUDO_FORTRESS_SMALL_KEY_MAX 4
|
||||
#define GANONS_CASTLE_SMALL_KEY_MAX (ResourceMgr_IsSceneMasterQuest(SCENE_INSIDE_GANONS_CASTLE) ? 3 : 2)
|
||||
#define TREASURE_GAME_SMALL_KEY_MAX 6
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define DUNGEON_ITEMS_CAN_BE_OUTSIDE_DUNGEON(rsk) \
|
||||
|
||||
@@ -690,10 +690,31 @@ void GameplayStatsWindow::DrawElement() {
|
||||
ImGui::Text("Note: Gameplay stats are saved to the current file and will be\nlost if you quit without saving.");
|
||||
}
|
||||
void InitStats(bool isDebug) {
|
||||
gSaveContext.ship.stats.heartPieces = isDebug ? 8 : 0;
|
||||
gSaveContext.ship.stats.heartContainers = isDebug ? 8 : 0;
|
||||
for (int dungeon = 0; dungeon < ARRAY_COUNT(gSaveContext.ship.stats.dungeonKeys); dungeon++) {
|
||||
gSaveContext.ship.stats.dungeonKeys[dungeon] = isDebug ? 8 : 0;
|
||||
int debugFile = isDebug ? CVarGetInteger(CVAR_DEVELOPER_TOOLS("DebugSaveFileMode"), 1) : 0;
|
||||
switch (debugFile) {
|
||||
case 1:
|
||||
gSaveContext.ship.stats.heartPieces = 8;
|
||||
gSaveContext.ship.stats.heartContainers = 8;
|
||||
for (int dungeon = 0; dungeon < ARRAY_COUNT(gSaveContext.ship.stats.dungeonKeys); dungeon++) {
|
||||
gSaveContext.ship.stats.dungeonKeys[dungeon] = 8;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
gSaveContext.ship.stats.heartPieces = 36;
|
||||
gSaveContext.ship.stats.heartContainers = 8;
|
||||
for (int dungeon = 0; dungeon < ARRAY_COUNT(gSaveContext.ship.stats.dungeonKeys); dungeon++) {
|
||||
// 9 for maxed, 0 for none
|
||||
gSaveContext.ship.stats.dungeonKeys[dungeon] = 9;
|
||||
}
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
gSaveContext.ship.stats.heartPieces = 0;
|
||||
gSaveContext.ship.stats.heartContainers = 0;
|
||||
for (int dungeon = 0; dungeon < ARRAY_COUNT(gSaveContext.ship.stats.dungeonKeys); dungeon++) {
|
||||
gSaveContext.ship.stats.dungeonKeys[dungeon] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
gSaveContext.ship.stats.rtaTiming = CVarGetInteger(CVAR_GAMEPLAY_STATS("RTATiming"), 0);
|
||||
gSaveContext.ship.stats.fileCreatedAt = GetUnixTimestamp();
|
||||
|
||||
@@ -1056,7 +1056,7 @@ static void InitTrickNames() {
|
||||
trickNameTable[RG_SPEAK_HYLIAN] = {
|
||||
// TODO_TRANSLATE
|
||||
Text{ "Human Jingle Nut" },
|
||||
Text{ "Sheikah Jabber nut" },
|
||||
Text{ "Sheikah Jabber Nut" },
|
||||
Text{ "Lorulean Blabber Nut" },
|
||||
};
|
||||
trickNameTable[RG_SPEAK_KOKIRI] = {
|
||||
|
||||
@@ -5,14 +5,20 @@
|
||||
#include "SeedContext.h"
|
||||
|
||||
namespace Rando {
|
||||
extern "C" PlayState* gPlayState;
|
||||
extern "C" SaveContext gSaveContext;
|
||||
|
||||
DungeonInfo::DungeonInfo(std::string name_, const RandomizerHintTextKey hintKey_, const RandomizerGet map_,
|
||||
const RandomizerGet compass_, const RandomizerGet smallKey_, const RandomizerGet keyRing_,
|
||||
const RandomizerGet bossKey_, RandomizerGet reward_, RandomizerArea area_,
|
||||
const uint8_t vanillaKeyCount_, const uint8_t mqKeyCount_,
|
||||
const RandomizerSettingKey mqSetting_)
|
||||
const RandomizerSettingKey mqSetting_, const SceneID scene_,
|
||||
const std::vector<uint8_t> vanillaDoorFlags_, const std::vector<uint8_t> randoDoorFlags_,
|
||||
const std::vector<uint8_t> MQDoorFlags_)
|
||||
: name(std::move(name_)), hintKey(hintKey_), map(map_), compass(compass_), smallKey(smallKey_), keyRing(keyRing_),
|
||||
bossKey(bossKey_), reward(reward_), area(area_), vanillaKeyCount(vanillaKeyCount_), mqKeyCount(mqKeyCount_),
|
||||
mqSetting(mqSetting_) {
|
||||
mqSetting(mqSetting_), scene(scene_), vanillaDoorFlags(vanillaDoorFlags_), randoDoorFlags(randoDoorFlags_),
|
||||
MQDoorFlags(MQDoorFlags_) {
|
||||
}
|
||||
DungeonInfo::DungeonInfo()
|
||||
: hintKey(RHT_NONE), map(RG_NONE), compass(RG_NONE), smallKey(RG_NONE), keyRing(RG_NONE), bossKey(RG_NONE),
|
||||
@@ -92,6 +98,59 @@ RandomizerSettingKey DungeonInfo::GetMQSetting() const {
|
||||
return mqSetting;
|
||||
}
|
||||
|
||||
int8_t FindUsedSmallKeys(const SaveContext* saveContext, const SceneID scene, const std::vector<uint8_t>* DoorFlags) {
|
||||
// Get the swch value for the scene
|
||||
uint32_t swch;
|
||||
if (gPlayState != nullptr && gPlayState->sceneNum == scene) {
|
||||
swch = gPlayState->actorCtx.flags.swch;
|
||||
} else {
|
||||
swch = saveContext->sceneFlags[scene].swch;
|
||||
}
|
||||
|
||||
// Count the number of small keys doors unlocked
|
||||
int8_t unlockedSmallKeyDoors = 0;
|
||||
for (auto& smallKeyDoor : *DoorFlags) {
|
||||
unlockedSmallKeyDoors += swch >> smallKeyDoor & 1;
|
||||
}
|
||||
return unlockedSmallKeyDoors;
|
||||
}
|
||||
|
||||
int8_t FindCurrentSmallKeys(const SaveContext* saveContext, const SceneID scene) {
|
||||
int8_t dungeonKeys = saveContext->inventory.dungeonKeys[scene];
|
||||
if (dungeonKeys == -1) {
|
||||
// never got keys, so can't have used keys
|
||||
return 0;
|
||||
}
|
||||
return dungeonKeys;
|
||||
}
|
||||
|
||||
int8_t FindTotalSmallKeys(const SaveContext* saveContext, const SceneID scene, const std::vector<uint8_t>* DoorFlags) {
|
||||
return FindCurrentSmallKeys(saveContext, scene) + FindUsedSmallKeys(saveContext, scene, DoorFlags);
|
||||
}
|
||||
|
||||
int8_t DungeonInfo::GetUsedSmallKeys(SaveContext* saveContext) const {
|
||||
return FindUsedSmallKeys(saveContext, scene, GetDoorFlags());
|
||||
}
|
||||
|
||||
int8_t DungeonInfo::GetCurrentSmallKeys(SaveContext* saveContext) const {
|
||||
return FindCurrentSmallKeys(saveContext, scene);
|
||||
}
|
||||
|
||||
int8_t DungeonInfo::GetTotalSmallKeys(SaveContext* saveContext) const {
|
||||
return FindTotalSmallKeys(saveContext, scene, GetDoorFlags());
|
||||
}
|
||||
|
||||
const std::vector<uint8_t>* DungeonInfo::GetDoorFlags() const {
|
||||
if (IsMQ()) {
|
||||
return &MQDoorFlags;
|
||||
}
|
||||
if (IS_RANDO) {
|
||||
// Specifically non-MQ Rando, to handle an edge case in water temple
|
||||
return &randoDoorFlags;
|
||||
}
|
||||
return &vanillaDoorFlags;
|
||||
}
|
||||
|
||||
void DungeonInfo::SetDungeonKnown(bool known) {
|
||||
isDungeonModeKnown = known;
|
||||
}
|
||||
@@ -152,45 +211,53 @@ std::vector<RandomizerCheck> DungeonInfo::GetDungeonLocations() const {
|
||||
}
|
||||
|
||||
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, RG_KOKIRI_EMERALD, RA_DEKU_TREE, 0, 0, RSK_MQ_DEKU_TREE);
|
||||
dungeonList[DODONGOS_CAVERN] =
|
||||
DungeonInfo("Dodongo's Cavern", RHT_DODONGOS_CAVERN, RG_DODONGOS_CAVERN_MAP, RG_DODONGOS_CAVERN_COMPASS,
|
||||
RG_NONE, RG_NONE, RG_NONE, RG_GORON_RUBY, RA_DODONGOS_CAVERN, 0, 0, RSK_MQ_DODONGOS_CAVERN);
|
||||
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, RG_ZORA_SAPPHIRE, RA_JABU_JABUS_BELLY, 0, 0, RSK_MQ_JABU_JABU);
|
||||
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,
|
||||
RG_FOREST_MEDALLION, RA_FOREST_TEMPLE, 5, 6, RSK_MQ_FOREST_TEMPLE);
|
||||
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,
|
||||
RG_FIRE_MEDALLION, RA_FIRE_TEMPLE, 8, 5, RSK_MQ_FIRE_TEMPLE);
|
||||
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, RG_WATER_MEDALLION,
|
||||
RA_WATER_TEMPLE, 6, 2, RSK_MQ_WATER_TEMPLE);
|
||||
dungeonList[DEKU_TREE] =
|
||||
DungeonInfo("Deku Tree", RHT_DEKU_TREE, RG_DEKU_TREE_MAP, RG_DEKU_TREE_COMPASS, RG_NONE, RG_NONE, RG_NONE,
|
||||
RG_KOKIRI_EMERALD, RA_DEKU_TREE, 0, 0, RSK_MQ_DEKU_TREE, SCENE_DEKU_TREE, {}, {}, {});
|
||||
dungeonList[DODONGOS_CAVERN] = DungeonInfo(
|
||||
"Dodongo's Cavern", RHT_DODONGOS_CAVERN, RG_DODONGOS_CAVERN_MAP, RG_DODONGOS_CAVERN_COMPASS, RG_NONE, RG_NONE,
|
||||
RG_NONE, RG_GORON_RUBY, RA_DODONGOS_CAVERN, 0, 0, RSK_MQ_DODONGOS_CAVERN, SCENE_DODONGOS_CAVERN, {}, {}, {});
|
||||
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, RG_ZORA_SAPPHIRE, RA_JABU_JABUS_BELLY, 0, 0, RSK_MQ_JABU_JABU, SCENE_JABU_JABU, {}, {}, {});
|
||||
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, RG_FOREST_MEDALLION, RA_FOREST_TEMPLE, 5, 6,
|
||||
RSK_MQ_FOREST_TEMPLE, SCENE_FOREST_TEMPLE, { 0, 1, 2, 3, 4 }, { 0, 1, 2, 3, 4 }, { 0, 1, 2, 3, 4, 6 });
|
||||
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, RG_FIRE_MEDALLION,
|
||||
RA_FIRE_TEMPLE, 8, 5, RSK_MQ_FIRE_TEMPLE, SCENE_FIRE_TEMPLE, { 23, 24, 25, 26, 27, 29, 30, 31 },
|
||||
{ 23, 24, 25, 26, 27, 29, 30, 31 }, { 23, 24, 26, 27, 30 });
|
||||
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, RG_WATER_MEDALLION, RA_WATER_TEMPLE, 6, 2,
|
||||
RSK_MQ_WATER_TEMPLE, SCENE_WATER_TEMPLE, { 1, 2, 5, 6, 9, 21 }, { 1, 2, 5, 6, 9 }, { 4, 21 });
|
||||
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,
|
||||
RG_SPIRIT_MEDALLION, RA_SPIRIT_TEMPLE, 5, 7, RSK_MQ_SPIRIT_TEMPLE);
|
||||
RG_SPIRIT_MEDALLION, RA_SPIRIT_TEMPLE, 5, 7, RSK_MQ_SPIRIT_TEMPLE, SCENE_SPIRIT_TEMPLE,
|
||||
{ 13, 21, 27, 28, 30 }, { 13, 21, 27, 28, 30 }, { 1, 3, 18, 21, 27, 28, 30 });
|
||||
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,
|
||||
RG_SHADOW_MEDALLION, RA_SHADOW_TEMPLE, 5, 6, RSK_MQ_SHADOW_TEMPLE);
|
||||
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, RG_NONE, RA_BOTTOM_OF_THE_WELL, 3, 2, RSK_MQ_BOTTOM_OF_THE_WELL);
|
||||
dungeonList[ICE_CAVERN] = DungeonInfo("Ice Cavern", RHT_ICE_CAVERN, RG_ICE_CAVERN_MAP, RG_ICE_CAVERN_COMPASS,
|
||||
RG_NONE, RG_NONE, RG_NONE, RG_NONE, RA_ICE_CAVERN, 0, 0, RSK_MQ_ICE_CAVERN);
|
||||
RG_SHADOW_MEDALLION, RA_SHADOW_TEMPLE, 5, 6, RSK_MQ_SHADOW_TEMPLE, SCENE_SHADOW_TEMPLE,
|
||||
{ 21, 22, 23, 24, 25 }, { 21, 22, 23, 24, 25 }, { 21, 22, 23, 24, 25, 27 });
|
||||
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, RG_NONE, RA_BOTTOM_OF_THE_WELL, 3, 2,
|
||||
RSK_MQ_BOTTOM_OF_THE_WELL, SCENE_BOTTOM_OF_THE_WELL, { 27, 28, 29 }, { 27, 28, 29 }, { 20, 21 });
|
||||
dungeonList[ICE_CAVERN] =
|
||||
DungeonInfo("Ice Cavern", RHT_ICE_CAVERN, RG_ICE_CAVERN_MAP, RG_ICE_CAVERN_COMPASS, RG_NONE, RG_NONE, RG_NONE,
|
||||
RG_NONE, RA_ICE_CAVERN, 0, 0, RSK_MQ_ICE_CAVERN, SCENE_ICE_CAVERN, {}, {}, {});
|
||||
dungeonList[GERUDO_TRAINING_GROUND] = DungeonInfo(
|
||||
"Gerudo Training Ground", RHT_GERUDO_TRAINING_GROUND, RG_NONE, RG_NONE, RG_GERUDO_TRAINING_GROUND_SMALL_KEY,
|
||||
RG_GERUDO_TRAINING_GROUND_KEY_RING, RG_NONE, RG_NONE, RA_GERUDO_TRAINING_GROUND, 9, 3, RSK_MQ_GTG);
|
||||
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, RG_NONE, RA_GANONS_CASTLE, 2, 3, RSK_MQ_GANONS_CASTLE);
|
||||
RG_GERUDO_TRAINING_GROUND_KEY_RING, RG_NONE, RG_NONE, RA_GERUDO_TRAINING_GROUND, 9, 3, RSK_MQ_GTG,
|
||||
SCENE_GERUDO_TRAINING_GROUND, { 1, 3, 4, 5, 6, 7, 9, 10, 23 }, { 1, 3, 4, 5, 6, 7, 9, 10, 23 }, { 20, 23, 29 });
|
||||
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, RG_NONE, RA_GANONS_CASTLE, 2, 3,
|
||||
RSK_MQ_GANONS_CASTLE, SCENE_INSIDE_GANONS_CASTLE, { 29, 30 }, { 29, 30 }, { 20, 21, 22 });
|
||||
}
|
||||
|
||||
Dungeons::~Dungeons() = default;
|
||||
|
||||
@@ -6,13 +6,17 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "nlohmann/json.hpp"
|
||||
#include "z64save.h"
|
||||
#include "z64scene.h"
|
||||
|
||||
namespace Rando {
|
||||
class DungeonInfo {
|
||||
public:
|
||||
DungeonInfo(std::string name_, RandomizerHintTextKey hintKey_, RandomizerGet map_, RandomizerGet compass_,
|
||||
RandomizerGet smallKey_, RandomizerGet keyRing_, RandomizerGet bossKey_, RandomizerGet reward_,
|
||||
RandomizerArea area_, uint8_t vanillaKeyCount_, uint8_t mqKeyCount_, RandomizerSettingKey mqSetting_);
|
||||
RandomizerArea area_, uint8_t vanillaKeyCount_, uint8_t mqKeyCount_, RandomizerSettingKey mqSetting_,
|
||||
SceneID scene_, std::vector<uint8_t> vanillaDoorFlags_, std::vector<uint8_t> randoDoorFlags_,
|
||||
std::vector<uint8_t> MQDoorFlags_);
|
||||
DungeonInfo();
|
||||
~DungeonInfo();
|
||||
|
||||
@@ -33,7 +37,11 @@ class DungeonInfo {
|
||||
RandomizerGet GetCompass() const;
|
||||
RandomizerGet GetBossKey() const;
|
||||
RandomizerGet GetReward() const;
|
||||
int8_t GetUsedSmallKeys(SaveContext* saveContext) const;
|
||||
int8_t GetCurrentSmallKeys(SaveContext* saveContext) const;
|
||||
int8_t GetTotalSmallKeys(SaveContext* saveContext) const;
|
||||
RandomizerSettingKey GetMQSetting() const;
|
||||
const std::vector<uint8_t>* GetDoorFlags() const;
|
||||
void SetDungeonKnown(bool known);
|
||||
void PlaceVanillaMap() const;
|
||||
void PlaceVanillaCompass() const;
|
||||
@@ -45,21 +53,30 @@ class DungeonInfo {
|
||||
private:
|
||||
std::string name;
|
||||
RandomizerHintTextKey hintKey;
|
||||
RandomizerArea area;
|
||||
RandomizerGet map;
|
||||
RandomizerGet compass;
|
||||
RandomizerGet smallKey;
|
||||
RandomizerGet keyRing;
|
||||
RandomizerGet bossKey;
|
||||
RandomizerGet reward;
|
||||
RandomizerSettingKey mqSetting;
|
||||
bool isDungeonModeKnown = true;
|
||||
RandomizerArea area;
|
||||
uint8_t vanillaKeyCount{};
|
||||
uint8_t mqKeyCount{};
|
||||
RandomizerSettingKey mqSetting;
|
||||
bool isDungeonModeKnown = true;
|
||||
bool masterQuest = false;
|
||||
bool hasKeyRing = false;
|
||||
SceneID scene;
|
||||
std::vector<uint8_t> vanillaDoorFlags;
|
||||
// Specifically non-MQ Rando, to handle an edge case in water temple
|
||||
std::vector<uint8_t> randoDoorFlags;
|
||||
std::vector<uint8_t> MQDoorFlags;
|
||||
};
|
||||
|
||||
int8_t FindUsedSmallKeys(const SaveContext* saveContext, const SceneID scene, const std::vector<uint8_t>* DoorFlags);
|
||||
int8_t FindCurrentSmallKeys(const SaveContext* saveContext, const SceneID scene);
|
||||
int8_t FindTotalSmallKeys(const SaveContext* saveContext, const SceneID scene, const std::vector<uint8_t>* DoorFlags);
|
||||
|
||||
typedef enum {
|
||||
DEKU_TREE,
|
||||
DODONGOS_CAVERN,
|
||||
|
||||
@@ -873,7 +873,7 @@ bool BeanPlanted(const RandomizerGet bean) {
|
||||
}
|
||||
|
||||
// swchFlag found using the Actor Viewer to get the Obj_Bean parameters & 0x3F
|
||||
// not tested with multiple OTRs, but can be automated similarly to GetDungeonSmallKeyDoors
|
||||
// not tested with multiple OTRs, but can be automated similarly to GetUsedSmallKeys
|
||||
SceneID sceneID;
|
||||
uint8_t swchFlag;
|
||||
switch (bean) {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "SeedContext.h"
|
||||
#include "macros.h"
|
||||
#include "variables.h"
|
||||
#include "randomizer.h"
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <ship/utils/StringHelper.h>
|
||||
#include "soh/resource/type/Scene.h"
|
||||
@@ -80,8 +81,6 @@ bool Logic::HasItem(RandomizerGet itemName) {
|
||||
return CheckEquipment(RandoGetToEquipFlag.at(itemName)) || Get(LOGIC_MEDIGORON);
|
||||
case RG_BIGGORON_SWORD:
|
||||
return CheckEquipment(RandoGetToEquipFlag.at(itemName)) && mSaveContext->bgsFlag;
|
||||
case RG_POWER_BRACELET:
|
||||
return CheckRandoInf(RAND_INF_CAN_GRAB);
|
||||
case RG_GORONS_BRACELET:
|
||||
return CurrentUpgrade(UPG_STRENGTH);
|
||||
case RG_SILVER_GAUNTLETS:
|
||||
@@ -147,10 +146,27 @@ bool Logic::HasItem(RandomizerGet itemName) {
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
case RG_POWER_BRACELET:
|
||||
case RG_CHILD_WALLET:
|
||||
case RG_FISHING_POLE:
|
||||
case RG_BRONZE_SCALE:
|
||||
case RG_CLIMB:
|
||||
case RG_CRAWL:
|
||||
case RG_OPEN_CHEST:
|
||||
case RG_ZELDAS_LETTER:
|
||||
case RG_WEIRD_EGG:
|
||||
case RG_GREG_RUPEE:
|
||||
// Adult Trade
|
||||
case RG_COJIRO:
|
||||
case RG_ODD_MUSHROOM:
|
||||
case RG_ODD_POTION:
|
||||
case RG_POACHERS_SAW:
|
||||
case RG_BROKEN_SWORD:
|
||||
case RG_PRESCRIPTION:
|
||||
case RG_EYEBALL_FROG:
|
||||
case RG_EYEDROPS:
|
||||
case RG_CLAIM_CHECK:
|
||||
// Jabber Nuts
|
||||
case RG_SPEAK_DEKU:
|
||||
case RG_SPEAK_GERUDO:
|
||||
case RG_SPEAK_GORON:
|
||||
@@ -211,7 +227,7 @@ bool Logic::HasItem(RandomizerGet itemName) {
|
||||
case RG_HYLIA_LAB_KEY:
|
||||
case RG_FISHING_HOLE_KEY:
|
||||
case RG_RUTOS_LETTER:
|
||||
return CheckRandoInf(RandoGetToRandInf.at(itemName));
|
||||
return CheckRandoInf(StaticData::RandoGetToRandInf.at(itemName));
|
||||
// Boss Keys
|
||||
case RG_FOREST_TEMPLE_BOSS_KEY:
|
||||
case RG_FIRE_TEMPLE_BOSS_KEY:
|
||||
@@ -245,8 +261,6 @@ bool Logic::HasItem(RandomizerGet itemName) {
|
||||
case RG_ICE_CAVERN_COMPASS:
|
||||
return CheckDungeonItem(DUNGEON_COMPASS, RandoGetToDungeonScene.at(itemName));
|
||||
// Wallets
|
||||
case RG_CHILD_WALLET:
|
||||
return CheckRandoInf(RAND_INF_HAS_WALLET);
|
||||
case RG_ADULT_WALLET:
|
||||
return CurrentUpgrade(UPG_WALLET) >= 1;
|
||||
case RG_GIANT_WALLET:
|
||||
@@ -254,31 +268,13 @@ bool Logic::HasItem(RandomizerGet itemName) {
|
||||
case RG_TYCOON_WALLET:
|
||||
return CurrentUpgrade(UPG_WALLET) >= 3;
|
||||
// Scales
|
||||
case RG_BRONZE_SCALE:
|
||||
return CheckRandoInf(RAND_INF_CAN_SWIM);
|
||||
case RG_SILVER_SCALE:
|
||||
return CurrentUpgrade(UPG_SCALE) >= 1;
|
||||
case RG_GOLDEN_SCALE:
|
||||
return CurrentUpgrade(UPG_SCALE) >= 2;
|
||||
case RG_CLIMB:
|
||||
return CheckRandoInf(RAND_INF_CAN_CLIMB);
|
||||
case RG_CRAWL:
|
||||
return CheckRandoInf(RAND_INF_CAN_CRAWL);
|
||||
case RG_OPEN_CHEST:
|
||||
return CheckRandoInf(RAND_INF_CAN_OPEN_CHEST);
|
||||
case RG_POCKET_EGG:
|
||||
return CheckRandoInf(RAND_INF_ADULT_TRADES_HAS_POCKET_EGG) ||
|
||||
CheckRandoInf(RAND_INF_ADULT_TRADES_HAS_POCKET_CUCCO);
|
||||
case RG_COJIRO:
|
||||
case RG_ODD_MUSHROOM:
|
||||
case RG_ODD_POTION:
|
||||
case RG_POACHERS_SAW:
|
||||
case RG_BROKEN_SWORD:
|
||||
case RG_PRESCRIPTION:
|
||||
case RG_EYEBALL_FROG:
|
||||
case RG_EYEDROPS:
|
||||
case RG_CLAIM_CHECK:
|
||||
return CheckRandoInf(itemName - RG_COJIRO + RAND_INF_ADULT_TRADES_HAS_COJIRO);
|
||||
case RG_BOTTLE_WITH_BIG_POE:
|
||||
case RG_BOTTLE_WITH_BLUE_FIRE:
|
||||
case RG_BOTTLE_WITH_BLUE_POTION:
|
||||
@@ -1764,7 +1760,7 @@ bool Logic::CanTriggerLACS() {
|
||||
(ctx->LACSCondition() == RO_LACS_TOKENS && GetGSCount() >= ctx->GetOption(RSK_LACS_TOKEN_COUNT).Get());
|
||||
}
|
||||
|
||||
bool Logic::SmallKeys(s16 scene, uint8_t requiredAmount) {
|
||||
bool Logic::SmallKeys(SceneID scene, uint8_t requiredAmount) {
|
||||
if (HasItem(RG_SKELETON_KEY)) {
|
||||
return true;
|
||||
}
|
||||
@@ -1782,9 +1778,32 @@ std::map<RandomizerGet, uint32_t> Logic::RandoGetToEquipFlag = {
|
||||
{ RG_HOVER_BOOTS, EQUIP_FLAG_BOOTS_HOVER }
|
||||
};
|
||||
|
||||
std::map<RandomizerGet, uint32_t> Logic::RandoGetToRandInf = {
|
||||
std::map<RandomizerGet, uint32_t> StaticData::RandoGetToRandInf = {
|
||||
{ RG_BRONZE_SCALE, RAND_INF_CAN_SWIM },
|
||||
{ RG_POWER_BRACELET, RAND_INF_CAN_GRAB },
|
||||
{ RG_ZELDAS_LETTER, RAND_INF_ZELDAS_LETTER },
|
||||
{ RG_CLIMB, RAND_INF_CAN_CLIMB },
|
||||
{ RG_CRAWL, RAND_INF_CAN_CRAWL },
|
||||
{ RG_OPEN_CHEST, RAND_INF_CAN_OPEN_CHEST },
|
||||
{ RG_CHILD_WALLET, RAND_INF_HAS_WALLET },
|
||||
{ RG_QUIVER_INF, RAND_INF_HAS_INFINITE_QUIVER },
|
||||
{ RG_BOMB_BAG_INF, RAND_INF_HAS_INFINITE_BOMB_BAG },
|
||||
{ RG_BULLET_BAG_INF, RAND_INF_HAS_INFINITE_BULLET_BAG },
|
||||
{ RG_STICK_UPGRADE_INF, RAND_INF_HAS_INFINITE_STICK_UPGRADE },
|
||||
{ RG_NUT_UPGRADE_INF, RAND_INF_HAS_INFINITE_NUT_UPGRADE },
|
||||
{ RG_MAGIC_INF, RAND_INF_HAS_INFINITE_MAGIC_METER },
|
||||
{ RG_BOMBCHU_INF, RAND_INF_HAS_INFINITE_BOMBCHUS },
|
||||
{ RG_WALLET_INF, RAND_INF_HAS_INFINITE_MONEY },
|
||||
{ RG_WEIRD_EGG, RAND_INF_WEIRD_EGG },
|
||||
{ RG_COJIRO, RAND_INF_ADULT_TRADES_HAS_COJIRO },
|
||||
{ RG_ODD_MUSHROOM, RAND_INF_ADULT_TRADES_HAS_ODD_MUSHROOM },
|
||||
{ RG_ODD_POTION, RAND_INF_ADULT_TRADES_HAS_ODD_POTION },
|
||||
{ RG_POACHERS_SAW, RAND_INF_ADULT_TRADES_HAS_SAW },
|
||||
{ RG_BROKEN_SWORD, RAND_INF_ADULT_TRADES_HAS_SWORD_BROKEN },
|
||||
{ RG_PRESCRIPTION, RAND_INF_ADULT_TRADES_HAS_PRESCRIPTION },
|
||||
{ RG_EYEBALL_FROG, RAND_INF_ADULT_TRADES_HAS_FROG },
|
||||
{ RG_EYEDROPS, RAND_INF_ADULT_TRADES_HAS_EYEDROPS },
|
||||
{ RG_CLAIM_CHECK, RAND_INF_ADULT_TRADES_HAS_CLAIM_CHECK },
|
||||
{ RG_RUTOS_LETTER, RAND_INF_OBTAINED_RUTOS_LETTER },
|
||||
{ RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL, RAND_INF_DEATH_MOUNTAIN_CRATER_BEAN_SOUL },
|
||||
{ RG_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL, RAND_INF_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL },
|
||||
@@ -1853,7 +1872,7 @@ std::map<RandomizerGet, uint32_t> Logic::RandoGetToRandInf = {
|
||||
{ RG_FISHING_HOLE_KEY, RAND_INF_FISHING_HOLE_KEY_OBTAINED },
|
||||
};
|
||||
|
||||
std::map<uint32_t, uint32_t> Logic::RandoGetToDungeonScene = {
|
||||
std::map<uint32_t, SceneID> Logic::RandoGetToDungeonScene = {
|
||||
{ RG_FOREST_TEMPLE_SMALL_KEY, SCENE_FOREST_TEMPLE },
|
||||
{ RG_FIRE_TEMPLE_SMALL_KEY, SCENE_FIRE_TEMPLE },
|
||||
{ RG_WATER_TEMPLE_SMALL_KEY, SCENE_WATER_TEMPLE },
|
||||
@@ -2302,7 +2321,7 @@ void Logic::ApplyItemEffect(Item& item, bool state) {
|
||||
case RG_BACK_TOWER_KEY:
|
||||
case RG_HYLIA_LAB_KEY:
|
||||
case RG_FISHING_HOLE_KEY:
|
||||
SetRandoInf(RandoGetToRandInf.at(randoGet), state);
|
||||
SetRandoInf(StaticData::RandoGetToRandInf.at(randoGet), state);
|
||||
break;
|
||||
case RG_TRIFORCE_PIECE:
|
||||
mSaveContext->ship.quest.data.randomizer.triforcePiecesCollected += (!state ? -1 : 1);
|
||||
@@ -2630,83 +2649,13 @@ void Logic::SetQuestItem(uint32_t item, bool state) {
|
||||
}
|
||||
}
|
||||
|
||||
// Get the swch bit positions for the dungeon
|
||||
const std::vector<uint8_t>& GetDungeonSmallKeyDoors(const SceneID sceneId) {
|
||||
static const std::vector<uint8_t> emptyVector;
|
||||
|
||||
static const std::vector<uint8_t> normalSmallKeyDoors{ 1, 2, 3, 4 };
|
||||
static const std::vector<uint8_t> fastSmallKeyDoors{ 1 };
|
||||
static const std::vector<uint8_t> freeSmallKeyDoors{};
|
||||
|
||||
using SmallKeyDoorSets = std::pair<std::vector<uint8_t>, std::vector<uint8_t>>; // first = vanilla, second = MQ
|
||||
static const std::unordered_map<SceneID, SmallKeyDoorSets> dungeonSmallKeyDoors{
|
||||
{ SCENE_FOREST_TEMPLE, { { 0, 1, 2, 3, 4 }, { 0, 1, 2, 3, 4, 6 } } },
|
||||
{ SCENE_FIRE_TEMPLE, { { 23, 24, 25, 26, 27, 29, 30, 31 }, { 23, 24, 26, 27, 30 } } },
|
||||
{ SCENE_WATER_TEMPLE, { { 1, 2, 5, 6, 9 }, { 4, 21 } } },
|
||||
{ SCENE_SPIRIT_TEMPLE, { { 13, 21, 27, 28, 30 }, { 1, 3, 18, 21, 27, 28, 30 } } },
|
||||
{ SCENE_SHADOW_TEMPLE, { { 21, 22, 23, 24, 25 }, { 21, 22, 23, 24, 25, 27 } } },
|
||||
{ SCENE_BOTTOM_OF_THE_WELL, { { 27, 28, 29 }, { 20, 21 } } },
|
||||
{ SCENE_GERUDO_TRAINING_GROUND, { { 1, 3, 4, 5, 6, 7, 9, 10, 23 }, { 20, 23, 29 } } },
|
||||
{ SCENE_INSIDE_GANONS_CASTLE, { { 29, 30 }, { 20, 21, 22 } } },
|
||||
};
|
||||
static const std::vector<uint8_t> vanillaWaterTempleDoors{ 1, 2, 5, 6, 9, 21 };
|
||||
|
||||
int8_t Logic::GetSmallKeyCount(SceneID sceneId) {
|
||||
if (sceneId == SCENE_THIEVES_HIDEOUT) {
|
||||
if (RAND_GET_OPTION(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_NORMAL)) {
|
||||
return normalSmallKeyDoors;
|
||||
}
|
||||
if (RAND_GET_OPTION(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FAST)) {
|
||||
return fastSmallKeyDoors;
|
||||
}
|
||||
return freeSmallKeyDoors;
|
||||
std::vector<uint8_t> DoorFlags = THIEVES_HIDEOUT_DOOR_FLAGS;
|
||||
return FindTotalSmallKeys(mSaveContext, SCENE_THIEVES_HIDEOUT, &DoorFlags);
|
||||
}
|
||||
|
||||
if (sceneId == SCENE_WATER_TEMPLE && IS_VANILLA) {
|
||||
return vanillaWaterTempleDoors;
|
||||
}
|
||||
|
||||
auto dungeonInfo = Rando::Context::GetInstance()->GetDungeons()->GetDungeonFromScene(sceneId);
|
||||
if (dungeonInfo == nullptr) {
|
||||
return emptyVector;
|
||||
}
|
||||
|
||||
auto it = dungeonSmallKeyDoors.find(sceneId);
|
||||
if (it == dungeonSmallKeyDoors.end()) {
|
||||
return emptyVector;
|
||||
}
|
||||
|
||||
return dungeonInfo->IsMQ() ? it->second.second : it->second.first;
|
||||
}
|
||||
|
||||
int8_t Logic::GetUsedSmallKeyCount(SceneID sceneId) {
|
||||
const auto& smallKeyDoors = GetDungeonSmallKeyDoors(sceneId);
|
||||
|
||||
// Get the swch value for the scene
|
||||
uint32_t swch;
|
||||
if (gPlayState != nullptr && gPlayState->sceneNum == sceneId) {
|
||||
swch = gPlayState->actorCtx.flags.swch;
|
||||
} else {
|
||||
swch = mSaveContext->sceneFlags[sceneId].swch;
|
||||
}
|
||||
|
||||
// Count the number of small keys doors unlocked
|
||||
int8_t unlockedSmallKeyDoors = 0;
|
||||
for (auto& smallKeyDoor : smallKeyDoors) {
|
||||
unlockedSmallKeyDoors += swch >> smallKeyDoor & 1;
|
||||
}
|
||||
|
||||
// RANDOTODO: Account for MQ Water trick that causes the basement lock to unlock when the player clears the stalfos
|
||||
// pit.
|
||||
return unlockedSmallKeyDoors;
|
||||
}
|
||||
|
||||
uint8_t Logic::GetSmallKeyCount(uint32_t dungeonIndex) {
|
||||
int8_t dungeonKeys = mSaveContext->inventory.dungeonKeys[dungeonIndex];
|
||||
if (dungeonKeys == -1) {
|
||||
// never got keys, so can't have used keys
|
||||
return 0;
|
||||
}
|
||||
return dungeonKeys + GetUsedSmallKeyCount(SceneID(dungeonIndex));
|
||||
return Rando::Context::GetInstance()->GetDungeons()->GetDungeonFromScene(sceneId)->GetTotalSmallKeys(mSaveContext);
|
||||
}
|
||||
|
||||
void Logic::SetSmallKeyCount(uint32_t dungeonIndex, uint8_t count) {
|
||||
|
||||
@@ -18,8 +18,6 @@ enum class GlitchType {
|
||||
EquipSwap,
|
||||
};
|
||||
|
||||
const std::vector<uint8_t>& GetDungeonSmallKeyDoors(const SceneID sceneId);
|
||||
|
||||
class Logic {
|
||||
public:
|
||||
uint8_t Bottles = 0;
|
||||
@@ -47,7 +45,7 @@ class Logic {
|
||||
bool BAllowed();
|
||||
bool HasBossSoul(RandomizerGet itemName);
|
||||
bool CanOpenOverworldDoor(RandomizerGet itemName);
|
||||
bool SmallKeys(s16 scene, uint8_t requiredAmount);
|
||||
bool SmallKeys(SceneID scene, uint8_t requiredAmount);
|
||||
bool CanGroundJump(bool hasBombflower = false);
|
||||
bool CanGroundJumpslash(bool hasBombflower = false);
|
||||
bool CanMiddairGroundJump(bool hasBombflower = false);
|
||||
@@ -140,8 +138,7 @@ class Logic {
|
||||
bool CheckEquipment(uint32_t item);
|
||||
bool CheckQuestItem(uint32_t item);
|
||||
void SetQuestItem(uint32_t item, bool state);
|
||||
int8_t GetUsedSmallKeyCount(SceneID sceneId);
|
||||
uint8_t GetSmallKeyCount(uint32_t dungeonIndex);
|
||||
int8_t GetSmallKeyCount(SceneID sceneId);
|
||||
void SetSmallKeyCount(uint32_t dungeonIndex, uint8_t count);
|
||||
bool CheckDungeonItem(uint32_t item, uint32_t dungeonIndex);
|
||||
void SetDungeonItem(uint32_t item, uint32_t dungeonIndex, bool state);
|
||||
@@ -157,9 +154,8 @@ class Logic {
|
||||
void InitSaveContext();
|
||||
void NewSaveContext();
|
||||
static std::map<uint32_t, uint32_t> RandoGetToQuestItem;
|
||||
static std::map<uint32_t, uint32_t> RandoGetToDungeonScene;
|
||||
static std::map<uint32_t, SceneID> RandoGetToDungeonScene;
|
||||
static std::map<RandomizerGet, uint32_t> RandoGetToEquipFlag;
|
||||
static std::map<RandomizerGet, uint32_t> RandoGetToRandInf;
|
||||
bool IsReverseAccessPossible();
|
||||
bool DMCUpperToPots();
|
||||
bool DMCPotsToPad();
|
||||
|
||||
@@ -29,11 +29,14 @@
|
||||
#include "soh/Notification/Notification.h"
|
||||
#include "soh/ObjectExtension/ObjectExtension.h"
|
||||
#include "soh/Enhancements/randomizer/RCToRandInf.h"
|
||||
#include "static_data.h"
|
||||
#include "dungeon.h"
|
||||
|
||||
extern "C" {
|
||||
#include "src/overlays/actors/ovl_Obj_Bean/z_obj_bean.h"
|
||||
|
||||
extern void func_80B8FE00(ObjBean*); // trigger planting
|
||||
extern PlayState* gPlayState;
|
||||
}
|
||||
|
||||
static ObjectExtension::Register<CheckIdentity> RegisterIdentity;
|
||||
@@ -111,54 +114,6 @@ std::unordered_map<std::string, SceneID> spoilerFileDungeonToScene = {
|
||||
{ "Ganon's Castle", SCENE_INSIDE_GANONS_CASTLE }
|
||||
};
|
||||
|
||||
// used for items that only set a rand inf when obtained
|
||||
std::unordered_map<RandomizerGet, RandomizerInf> randomizerGetToRandInf = {
|
||||
{ RG_FISHING_POLE, RAND_INF_FISHING_POLE_FOUND },
|
||||
{ RG_BRONZE_SCALE, RAND_INF_CAN_SWIM },
|
||||
{ RG_POWER_BRACELET, RAND_INF_CAN_GRAB },
|
||||
{ RG_CLIMB, RAND_INF_CAN_CLIMB },
|
||||
{ RG_CRAWL, RAND_INF_CAN_CRAWL },
|
||||
{ RG_OPEN_CHEST, RAND_INF_CAN_OPEN_CHEST },
|
||||
{ RG_SPEAK_DEKU, RAND_INF_CAN_SPEAK_DEKU },
|
||||
{ RG_SPEAK_GERUDO, RAND_INF_CAN_SPEAK_GERUDO },
|
||||
{ RG_SPEAK_GORON, RAND_INF_CAN_SPEAK_GORON },
|
||||
{ RG_SPEAK_HYLIAN, RAND_INF_CAN_SPEAK_HYLIAN },
|
||||
{ RG_SPEAK_KOKIRI, RAND_INF_CAN_SPEAK_KOKIRI },
|
||||
{ RG_SPEAK_ZORA, RAND_INF_CAN_SPEAK_ZORA },
|
||||
{ RG_QUIVER_INF, RAND_INF_HAS_INFINITE_QUIVER },
|
||||
{ RG_BOMB_BAG_INF, RAND_INF_HAS_INFINITE_BOMB_BAG },
|
||||
{ RG_BULLET_BAG_INF, RAND_INF_HAS_INFINITE_BULLET_BAG },
|
||||
{ RG_STICK_UPGRADE_INF, RAND_INF_HAS_INFINITE_STICK_UPGRADE },
|
||||
{ RG_NUT_UPGRADE_INF, RAND_INF_HAS_INFINITE_NUT_UPGRADE },
|
||||
{ RG_MAGIC_INF, RAND_INF_HAS_INFINITE_MAGIC_METER },
|
||||
{ RG_BOMBCHU_INF, RAND_INF_HAS_INFINITE_BOMBCHUS },
|
||||
{ RG_WALLET_INF, RAND_INF_HAS_INFINITE_MONEY },
|
||||
{ RG_OCARINA_A_BUTTON, RAND_INF_HAS_OCARINA_A },
|
||||
{ RG_OCARINA_C_UP_BUTTON, RAND_INF_HAS_OCARINA_C_UP },
|
||||
{ RG_OCARINA_C_DOWN_BUTTON, RAND_INF_HAS_OCARINA_C_DOWN },
|
||||
{ RG_OCARINA_C_LEFT_BUTTON, RAND_INF_HAS_OCARINA_C_LEFT },
|
||||
{ RG_OCARINA_C_RIGHT_BUTTON, RAND_INF_HAS_OCARINA_C_RIGHT },
|
||||
{ RG_DEATH_MOUNTAIN_CRATER_BEAN_SOUL, RAND_INF_DEATH_MOUNTAIN_CRATER_BEAN_SOUL },
|
||||
{ RG_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL, RAND_INF_DEATH_MOUNTAIN_TRAIL_BEAN_SOUL },
|
||||
{ RG_DESERT_COLOSSUS_BEAN_SOUL, RAND_INF_DESERT_COLOSSUS_BEAN_SOUL },
|
||||
{ RG_GERUDO_VALLEY_BEAN_SOUL, RAND_INF_GERUDO_VALLEY_BEAN_SOUL },
|
||||
{ RG_GRAVEYARD_BEAN_SOUL, RAND_INF_GRAVEYARD_BEAN_SOUL },
|
||||
{ RG_KOKIRI_FOREST_BEAN_SOUL, RAND_INF_KOKIRI_FOREST_BEAN_SOUL },
|
||||
{ RG_LAKE_HYLIA_BEAN_SOUL, RAND_INF_LAKE_HYLIA_BEAN_SOUL },
|
||||
{ RG_LOST_WOODS_BRIDGE_BEAN_SOUL, RAND_INF_LOST_WOODS_BRIDGE_BEAN_SOUL },
|
||||
{ RG_LOST_WOODS_BEAN_SOUL, RAND_INF_LOST_WOODS_BEAN_SOUL },
|
||||
{ RG_ZORAS_RIVER_BEAN_SOUL, RAND_INF_ZORAS_RIVER_BEAN_SOUL },
|
||||
{ RG_GOHMA_SOUL, RAND_INF_GOHMA_SOUL },
|
||||
{ RG_KING_DODONGO_SOUL, RAND_INF_KING_DODONGO_SOUL },
|
||||
{ RG_BARINADE_SOUL, RAND_INF_BARINADE_SOUL },
|
||||
{ RG_PHANTOM_GANON_SOUL, RAND_INF_PHANTOM_GANON_SOUL },
|
||||
{ RG_VOLVAGIA_SOUL, RAND_INF_VOLVAGIA_SOUL },
|
||||
{ RG_MORPHA_SOUL, RAND_INF_MORPHA_SOUL },
|
||||
{ RG_BONGO_BONGO_SOUL, RAND_INF_BONGO_BONGO_SOUL },
|
||||
{ RG_TWINROVA_SOUL, RAND_INF_TWINROVA_SOUL },
|
||||
{ RG_GANON_SOUL, RAND_INF_GANON_SOUL },
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma optimize("", off)
|
||||
#else
|
||||
@@ -296,9 +251,10 @@ ItemObtainability Randomizer::GetItemObtainabilityFromRandomizerCheck(Randomizer
|
||||
}
|
||||
|
||||
ItemObtainability Randomizer::GetItemObtainabilityFromRandomizerGet(RandomizerGet randoGet) {
|
||||
if (randomizerGetToRandInf.find(randoGet) != randomizerGetToRandInf.end()) {
|
||||
return Flags_GetRandomizerInf(randomizerGetToRandInf.find(randoGet)->second) ? CANT_OBTAIN_ALREADY_HAVE
|
||||
: CAN_OBTAIN;
|
||||
if (Rando::StaticData::RandoGetToRandInf.find(randoGet) != Rando::StaticData::RandoGetToRandInf.end()) {
|
||||
return Flags_GetRandomizerInf((RandomizerInf)Rando::StaticData::RandoGetToRandInf.find(randoGet)->second)
|
||||
? CANT_OBTAIN_ALREADY_HAVE
|
||||
: CAN_OBTAIN;
|
||||
}
|
||||
|
||||
// This is needed since Plentiful item pool also adds a third progressive wallet
|
||||
@@ -311,6 +267,7 @@ ItemObtainability Randomizer::GetItemObtainabilityFromRandomizerGet(RandomizerGe
|
||||
u8 infiniteUpgrades = GetRandoSettingValue(RSK_INFINITE_UPGRADES);
|
||||
|
||||
u8 numWallets = 2 + (u8)tycoonWallet + (infiniteUpgrades != RO_INF_UPGRADES_OFF ? 1 : 0);
|
||||
|
||||
switch (randoGet) {
|
||||
case RG_NONE:
|
||||
case RG_TRIFORCE:
|
||||
@@ -520,23 +477,15 @@ ItemObtainability Randomizer::GetItemObtainabilityFromRandomizerGet(RandomizerGe
|
||||
return Inventory_HasEmptyBottle() ? CAN_OBTAIN : CANT_OBTAIN_NEED_EMPTY_BOTTLE;
|
||||
|
||||
// Trade Items
|
||||
// TODO: Do we want to be strict about any of this?
|
||||
// case RG_WEIRD_EGG:
|
||||
// case RG_ZELDAS_LETTER:
|
||||
// case RG_POCKET_EGG:
|
||||
// case RG_COJIRO:
|
||||
// case RG_ODD_MUSHROOM:
|
||||
// case RG_ODD_POTION:
|
||||
// case RG_POACHERS_SAW:
|
||||
// case RG_BROKEN_SWORD:
|
||||
// case RG_PRESCRIPTION:
|
||||
// case RG_EYEBALL_FROG:
|
||||
// case RG_EYEDROPS:
|
||||
// case RG_CLAIM_CHECK:
|
||||
// case RG_PROGRESSIVE_GORONSWORD:
|
||||
// case RG_GIANTS_KNIFE:
|
||||
|
||||
// Misc Items
|
||||
case RG_POCKET_EGG:
|
||||
return Flags_GetRandomizerInf(RAND_INF_ADULT_TRADES_HAS_POCKET_EGG) ||
|
||||
Flags_GetRandomizerInf(RAND_INF_ADULT_TRADES_HAS_POCKET_CUCCO)
|
||||
? CANT_OBTAIN_ALREADY_HAVE
|
||||
: CAN_OBTAIN;
|
||||
case RG_STONE_OF_AGONY:
|
||||
return !CHECK_QUEST_ITEM(QUEST_STONE_OF_AGONY) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE;
|
||||
case RG_GERUDO_MEMBERSHIP_CARD:
|
||||
@@ -642,43 +591,54 @@ ItemObtainability Randomizer::GetItemObtainabilityFromRandomizerGet(RandomizerGe
|
||||
case RG_GANONS_CASTLE_BOSS_KEY:
|
||||
return !CHECK_DUNGEON_ITEM(DUNGEON_KEY_BOSS, SCENE_GANONS_TOWER) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE;
|
||||
case RG_FOREST_TEMPLE_SMALL_KEY:
|
||||
return gSaveContext.inventory.dungeonKeys[SCENE_FOREST_TEMPLE] < FOREST_TEMPLE_SMALL_KEY_MAX
|
||||
return OTRGlobals::Instance->gRandoContext->GetDungeon(Rando::FOREST_TEMPLE)
|
||||
->GetTotalSmallKeys(&gSaveContext) < FOREST_TEMPLE_SMALL_KEY_MAX
|
||||
? CAN_OBTAIN
|
||||
: CANT_OBTAIN_ALREADY_HAVE;
|
||||
case RG_FIRE_TEMPLE_SMALL_KEY:
|
||||
return gSaveContext.inventory.dungeonKeys[SCENE_FIRE_TEMPLE] < FIRE_TEMPLE_SMALL_KEY_MAX
|
||||
return OTRGlobals::Instance->gRandoContext->GetDungeon(Rando::FIRE_TEMPLE)
|
||||
->GetTotalSmallKeys(&gSaveContext) < FIRE_TEMPLE_SMALL_KEY_MAX
|
||||
? CAN_OBTAIN
|
||||
: CANT_OBTAIN_ALREADY_HAVE;
|
||||
case RG_WATER_TEMPLE_SMALL_KEY:
|
||||
return gSaveContext.inventory.dungeonKeys[SCENE_WATER_TEMPLE] < WATER_TEMPLE_SMALL_KEY_MAX
|
||||
return OTRGlobals::Instance->gRandoContext->GetDungeon(Rando::WATER_TEMPLE)
|
||||
->GetTotalSmallKeys(&gSaveContext) < WATER_TEMPLE_SMALL_KEY_MAX
|
||||
? CAN_OBTAIN
|
||||
: CANT_OBTAIN_ALREADY_HAVE;
|
||||
case RG_SPIRIT_TEMPLE_SMALL_KEY:
|
||||
return gSaveContext.inventory.dungeonKeys[SCENE_SPIRIT_TEMPLE] < SPIRIT_TEMPLE_SMALL_KEY_MAX
|
||||
return OTRGlobals::Instance->gRandoContext->GetDungeon(Rando::SPIRIT_TEMPLE)
|
||||
->GetTotalSmallKeys(&gSaveContext) < SPIRIT_TEMPLE_SMALL_KEY_MAX
|
||||
? CAN_OBTAIN
|
||||
: CANT_OBTAIN_ALREADY_HAVE;
|
||||
case RG_SHADOW_TEMPLE_SMALL_KEY:
|
||||
return gSaveContext.inventory.dungeonKeys[SCENE_SHADOW_TEMPLE] < SHADOW_TEMPLE_SMALL_KEY_MAX
|
||||
return OTRGlobals::Instance->gRandoContext->GetDungeon(Rando::SHADOW_TEMPLE)
|
||||
->GetTotalSmallKeys(&gSaveContext) < SHADOW_TEMPLE_SMALL_KEY_MAX
|
||||
? CAN_OBTAIN
|
||||
: CANT_OBTAIN_ALREADY_HAVE;
|
||||
case RG_BOTTOM_OF_THE_WELL_SMALL_KEY:
|
||||
return gSaveContext.inventory.dungeonKeys[SCENE_BOTTOM_OF_THE_WELL] < BOTTOM_OF_THE_WELL_SMALL_KEY_MAX
|
||||
return OTRGlobals::Instance->gRandoContext->GetDungeon(Rando::BOTTOM_OF_THE_WELL)
|
||||
->GetTotalSmallKeys(&gSaveContext) < BOTTOM_OF_THE_WELL_SMALL_KEY_MAX
|
||||
? CAN_OBTAIN
|
||||
: CANT_OBTAIN_ALREADY_HAVE;
|
||||
case RG_GERUDO_TRAINING_GROUND_SMALL_KEY:
|
||||
return gSaveContext.inventory.dungeonKeys[SCENE_GERUDO_TRAINING_GROUND] <
|
||||
GERUDO_TRAINING_GROUND_SMALL_KEY_MAX
|
||||
return OTRGlobals::Instance->gRandoContext->GetDungeon(Rando::GERUDO_TRAINING_GROUND)
|
||||
->GetTotalSmallKeys(&gSaveContext) < GERUDO_TRAINING_GROUND_SMALL_KEY_MAX
|
||||
? CAN_OBTAIN
|
||||
: CANT_OBTAIN_ALREADY_HAVE;
|
||||
case RG_GERUDO_FORTRESS_SMALL_KEY:
|
||||
return gSaveContext.inventory.dungeonKeys[SCENE_THIEVES_HIDEOUT] < GERUDO_FORTRESS_SMALL_KEY_MAX
|
||||
case RG_GERUDO_FORTRESS_SMALL_KEY: {
|
||||
std::vector<uint8_t> DoorFlags = THIEVES_HIDEOUT_DOOR_FLAGS;
|
||||
return Rando::FindTotalSmallKeys(&gSaveContext, SCENE_THIEVES_HIDEOUT, &DoorFlags) <
|
||||
GERUDO_FORTRESS_SMALL_KEY_MAX
|
||||
? CAN_OBTAIN
|
||||
: CANT_OBTAIN_ALREADY_HAVE;
|
||||
}
|
||||
case RG_GANONS_CASTLE_SMALL_KEY:
|
||||
return gSaveContext.inventory.dungeonKeys[SCENE_INSIDE_GANONS_CASTLE] < GANONS_CASTLE_SMALL_KEY_MAX
|
||||
return OTRGlobals::Instance->gRandoContext->GetDungeon(Rando::GANONS_CASTLE)
|
||||
->GetTotalSmallKeys(&gSaveContext) < GANONS_CASTLE_SMALL_KEY_MAX
|
||||
? CAN_OBTAIN
|
||||
: CANT_OBTAIN_ALREADY_HAVE;
|
||||
case RG_TREASURE_GAME_SMALL_KEY:
|
||||
// I assume this cannot be easily manipulated?
|
||||
return gSaveContext.inventory.dungeonKeys[SCENE_TREASURE_BOX_SHOP] < TREASURE_GAME_SMALL_KEY_MAX
|
||||
? CAN_OBTAIN
|
||||
: CANT_OBTAIN_ALREADY_HAVE;
|
||||
@@ -1112,8 +1072,8 @@ extern "C" u16 Randomizer_Item_Give(PlayState* play, GetItemEntry giEntry) {
|
||||
Randomizer_GameplayStats_SetTimestamp(item);
|
||||
|
||||
// if it's an item that just sets a randomizerInf, set it
|
||||
if (randomizerGetToRandInf.find(item) != randomizerGetToRandInf.end()) {
|
||||
Flags_SetRandomizerInf(randomizerGetToRandInf.find(item)->second);
|
||||
if (Rando::StaticData::RandoGetToRandInf.find(item) != Rando::StaticData::RandoGetToRandInf.end()) {
|
||||
Flags_SetRandomizerInf((RandomizerInf)Rando::StaticData::RandoGetToRandInf.find(item)->second);
|
||||
return Return_Item_Entry(giEntry, RG_NONE);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,25 @@
|
||||
#include "../custom-message/CustomMessageTypes.h"
|
||||
|
||||
#define MAX_SEED_STRING_SIZE 1024
|
||||
#define FOREST_TEMPLE_SMALL_KEY_MAX (ResourceMgr_IsSceneMasterQuest(SCENE_FOREST_TEMPLE) ? 6 : 5)
|
||||
#define FIRE_TEMPLE_SMALL_KEY_MAX (ResourceMgr_IsSceneMasterQuest(SCENE_FIRE_TEMPLE) ? 5 : 8)
|
||||
#define WATER_TEMPLE_SMALL_KEY_MAX (ResourceMgr_IsSceneMasterQuest(SCENE_WATER_TEMPLE) ? 2 : 6)
|
||||
#define SPIRIT_TEMPLE_SMALL_KEY_MAX (ResourceMgr_IsSceneMasterQuest(SCENE_SPIRIT_TEMPLE) ? 7 : 5)
|
||||
#define SHADOW_TEMPLE_SMALL_KEY_MAX (ResourceMgr_IsSceneMasterQuest(SCENE_SHADOW_TEMPLE) ? 6 : 5)
|
||||
#define BOTTOM_OF_THE_WELL_SMALL_KEY_MAX (ResourceMgr_IsSceneMasterQuest(SCENE_BOTTOM_OF_THE_WELL) ? 2 : 3)
|
||||
#define GERUDO_TRAINING_GROUND_SMALL_KEY_MAX (ResourceMgr_IsSceneMasterQuest(SCENE_GERUDO_TRAINING_GROUND) ? 3 : 9)
|
||||
#define GERUDO_FORTRESS_SMALL_KEY_MAX \
|
||||
(OTRGlobals::Instance->gRandoContext->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FAST) ? 1 \
|
||||
: OTRGlobals::Instance->gRandoContext->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FREE) ? 0 \
|
||||
: 4)
|
||||
#define THIEVES_HIDEOUT_DOOR_FLAGS \
|
||||
(OTRGlobals::Instance->gRandoContext->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FAST) \
|
||||
? std::vector<uint8_t>{ 1 } \
|
||||
: OTRGlobals::Instance->gRandoContext->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FREE) \
|
||||
? std::vector<uint8_t>{} \
|
||||
: std::vector<uint8_t>{ 1, 2, 3, 4 })
|
||||
#define GANONS_CASTLE_SMALL_KEY_MAX (ResourceMgr_IsSceneMasterQuest(SCENE_INSIDE_GANONS_CASTLE) ? 3 : 2)
|
||||
#define TREASURE_GAME_SMALL_KEY_MAX 6
|
||||
|
||||
class Randomizer {
|
||||
private:
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "soh/SohGui/UIWidgets.hpp"
|
||||
#include "soh/util.h"
|
||||
#include "soh/Enhancements/randomizer/randomizer.h"
|
||||
#include "soh/Enhancements/randomizer/dungeon.h"
|
||||
|
||||
#include <fast/Fast3dGui.h>
|
||||
|
||||
@@ -579,56 +580,50 @@ ItemTrackerNumbers GetItemCurrentAndMax(ItemTrackerItem item) {
|
||||
// Though the ammo/capacity naming doesn't really make sense for keys, we are
|
||||
// hijacking the same system to display key counts as there are enough similarities
|
||||
result.currentAmmo = MAX(gSaveContext.inventory.dungeonKeys[item.data], 0);
|
||||
result.currentCapacity = gSaveContext.ship.stats.dungeonKeys[item.data];
|
||||
switch (item.data) {
|
||||
case SCENE_FOREST_TEMPLE:
|
||||
result.maxCapacity = FOREST_TEMPLE_SMALL_KEY_MAX;
|
||||
break;
|
||||
case SCENE_FIRE_TEMPLE:
|
||||
result.maxCapacity = FIRE_TEMPLE_SMALL_KEY_MAX;
|
||||
break;
|
||||
case SCENE_WATER_TEMPLE:
|
||||
result.maxCapacity = WATER_TEMPLE_SMALL_KEY_MAX;
|
||||
break;
|
||||
case SCENE_SPIRIT_TEMPLE:
|
||||
result.maxCapacity = SPIRIT_TEMPLE_SMALL_KEY_MAX;
|
||||
break;
|
||||
case SCENE_SHADOW_TEMPLE:
|
||||
result.maxCapacity = SHADOW_TEMPLE_SMALL_KEY_MAX;
|
||||
break;
|
||||
case SCENE_BOTTOM_OF_THE_WELL:
|
||||
result.maxCapacity = BOTTOM_OF_THE_WELL_SMALL_KEY_MAX;
|
||||
break;
|
||||
case SCENE_GERUDO_TRAINING_GROUND:
|
||||
result.maxCapacity = GERUDO_TRAINING_GROUND_SMALL_KEY_MAX;
|
||||
break;
|
||||
case SCENE_THIEVES_HIDEOUT:
|
||||
if (IS_RANDO) {
|
||||
switch (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GERUDO_FORTRESS)) {
|
||||
case RO_GF_CARPENTERS_NORMAL:
|
||||
result.maxCapacity = GERUDO_FORTRESS_SMALL_KEY_MAX;
|
||||
break;
|
||||
case RO_GF_CARPENTERS_FAST:
|
||||
result.maxCapacity = 1;
|
||||
break;
|
||||
case RO_GF_CARPENTERS_FREE:
|
||||
result.maxCapacity = 0;
|
||||
break;
|
||||
default:
|
||||
result.maxCapacity = 0;
|
||||
SPDLOG_ERROR(
|
||||
"Invalid value for RSK_GERUDO_FORTRESS: {}",
|
||||
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GERUDO_FORTRESS));
|
||||
assert(false);
|
||||
break;
|
||||
if (item.data == SCENE_THIEVES_HIDEOUT) {
|
||||
std::vector<uint8_t> DoorFlags = THIEVES_HIDEOUT_DOOR_FLAGS;
|
||||
result.currentCapacity = Rando::FindTotalSmallKeys(&gSaveContext, SCENE_THIEVES_HIDEOUT, &DoorFlags);
|
||||
result.maxCapacity = GERUDO_FORTRESS_SMALL_KEY_MAX;
|
||||
} else {
|
||||
result.currentCapacity = OTRGlobals::Instance->gRandoContext->GetDungeons()
|
||||
->GetDungeonFromScene(item.data)
|
||||
->GetTotalSmallKeys(&gSaveContext);
|
||||
switch (item.data) {
|
||||
case SCENE_FOREST_TEMPLE:
|
||||
result.maxCapacity = FOREST_TEMPLE_SMALL_KEY_MAX;
|
||||
break;
|
||||
case SCENE_FIRE_TEMPLE:
|
||||
result.maxCapacity = FIRE_TEMPLE_SMALL_KEY_MAX;
|
||||
if (IS_RANDO &&
|
||||
!(OTRGlobals::Instance->gRandoContext->GetOption(RSK_KEYSANITY)
|
||||
.Is(RO_DUNGEON_ITEM_LOC_ANYWHERE) ||
|
||||
OTRGlobals::Instance->gRandoContext->GetOption(RSK_KEYSANITY)
|
||||
.Is(RO_DUNGEON_ITEM_LOC_OVERWORLD) ||
|
||||
OTRGlobals::Instance->gRandoContext->GetOption(RSK_KEYSANITY)
|
||||
.Is(RO_DUNGEON_ITEM_LOC_ANY_DUNGEON)) &&
|
||||
OTRGlobals::Instance->gRandoContext->GetDungeon(Rando::FIRE_TEMPLE)->IsVanilla()) {
|
||||
result.currentCapacity = result.currentCapacity - 1;
|
||||
}
|
||||
} else {
|
||||
result.maxCapacity = GERUDO_FORTRESS_SMALL_KEY_MAX;
|
||||
}
|
||||
break;
|
||||
case SCENE_INSIDE_GANONS_CASTLE:
|
||||
result.maxCapacity = GANONS_CASTLE_SMALL_KEY_MAX;
|
||||
break;
|
||||
break;
|
||||
case SCENE_WATER_TEMPLE:
|
||||
result.maxCapacity = WATER_TEMPLE_SMALL_KEY_MAX;
|
||||
break;
|
||||
case SCENE_SPIRIT_TEMPLE:
|
||||
result.maxCapacity = SPIRIT_TEMPLE_SMALL_KEY_MAX;
|
||||
break;
|
||||
case SCENE_SHADOW_TEMPLE:
|
||||
result.maxCapacity = SHADOW_TEMPLE_SMALL_KEY_MAX;
|
||||
break;
|
||||
case SCENE_BOTTOM_OF_THE_WELL:
|
||||
result.maxCapacity = BOTTOM_OF_THE_WELL_SMALL_KEY_MAX;
|
||||
break;
|
||||
case SCENE_GERUDO_TRAINING_GROUND:
|
||||
result.maxCapacity = GERUDO_TRAINING_GROUND_SMALL_KEY_MAX;
|
||||
break;
|
||||
case SCENE_INSIDE_GANONS_CASTLE:
|
||||
result.maxCapacity = GANONS_CASTLE_SMALL_KEY_MAX;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -396,8 +396,10 @@ void SetStartingItems() {
|
||||
// We can resolve this by starting with some extra keys.
|
||||
if (ResourceMgr_IsSceneMasterQuest(SCENE_SPIRIT_TEMPLE)) {
|
||||
// MQ Spirit needs 3 keys.
|
||||
gSaveContext.inventory.dungeonKeys[SCENE_SPIRIT_TEMPLE] = 3;
|
||||
gSaveContext.ship.stats.dungeonKeys[SCENE_SPIRIT_TEMPLE] = 3;
|
||||
if (gSaveContext.inventory.dungeonKeys[SCENE_SPIRIT_TEMPLE] < 3) {
|
||||
gSaveContext.inventory.dungeonKeys[SCENE_SPIRIT_TEMPLE] = 3;
|
||||
gSaveContext.ship.stats.dungeonKeys[SCENE_SPIRIT_TEMPLE] = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -95,6 +95,7 @@ class StaticData {
|
||||
static std::vector<RandomizerGet> normalBottles;
|
||||
static std::vector<RandomizerGet> beanSouls;
|
||||
static std::vector<RandomizerGet> overworldKeys;
|
||||
static std::map<RandomizerGet, uint32_t> RandoGetToRandInf;
|
||||
static std::unordered_map<SceneID, std::set<RandomizerGet>> itemRestrictions;
|
||||
static std::set<RandomizerGet> restrictFW;
|
||||
static std::set<RandomizerGet> restrictSpells;
|
||||
|
||||
Reference in New Issue
Block a user