mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2025-04-28 21:27:58 +03:00
Available Randomizer Checks (#5091)
* Calculate accessible checks and show them in the check tracker. * Added added DoorUnlocked checks to the Fire Temple doors. This is needed when calculating Accessible checks while playing and using small keys. Otherwise checks will appear unaccessible because Keys have been used. * Changed RecalculateAccessibleChecks to use the logic ReachabilitySearch. * Reverted DoorUnlocked changes. * Added recalculate_accessible_checks debug console command. * Skip CanBuy check when calculating accessible checks, it spoils that some items can't be bought with the current wallet. * Set RAND_INF_ZELDAS_LETTER. * Don't add locations to the pool when calculating accessible checks. * Save and Load randomizer trick options. * Get the number of used small keys. * Added check if bean was planted. * Show number of Accessible checks in each Area. * Accounted for missing RG_POCKET_CUCCO in logic HasItem and ApplyItemEffect. * Show accessible checks via an icon. * Check shop price against current wallet. * Recalculate Accessible Checks in CheckTrackerLoadGame instead of LoadFile. * RecalculateAccessibleChecks on save. * Don't unset Zelda's Letter. * Added Only Show Available Checks checkbox. * Rename Accessible Checks to Available Checks. * Added option to Enable Available Checks. * Remove debug console to recalculate available checks, this can now be done by toggling Enable Available Checks in the settings. * Remove extra requiredTrial. * Default "Hide unshuffled shop item checks" unchecked. * Updated GetSmallKeyCount to return int8_t. * Default AmmoDrop to true until the setting is implemented. * Fixed Sleeping Waterfall timesaver. * Updated Only Show Available Checks to let Show Hidden Items reveal hidden available checks. * Revert "Don't unset Zelda's Letter." This reverts commit4b5903940f
. * Set RAND_INF_ZELDAS_LETTER. * Revert "Fixed Sleeping Waterfall timesaver." This reverts commit9b62fd5297
. * Added isMagicAcquired to Logic::HasItem. * GetDungeonSmallKeyDoors return static emptyVector. * Comment out AmmoCanDrop in ResetLogic. * Added location_access CanBuy todo. * Reverted Get and Set SmallKeyCount to use uint8_t and handled -1 keys. * Added todo for MQ Water GetUsedSmallKeyCount.
This commit is contained in:
parent
ae209709ea
commit
35d17b8b0b
16 changed files with 432 additions and 36 deletions
|
@ -1164,6 +1164,9 @@ const std::vector<FlagTable> flagTables = {
|
||||||
{ RAND_INF_COLOSSUS_GREAT_FAIRY_REWARD, "RAND_INF_COLOSSUS_GREAT_FAIRY_REWARD" },
|
{ RAND_INF_COLOSSUS_GREAT_FAIRY_REWARD, "RAND_INF_COLOSSUS_GREAT_FAIRY_REWARD" },
|
||||||
{ RAND_INF_OGC_GREAT_FAIRY_REWARD, "RAND_INF_OGC_GREAT_FAIRY_REWARD" },
|
{ RAND_INF_OGC_GREAT_FAIRY_REWARD, "RAND_INF_OGC_GREAT_FAIRY_REWARD" },
|
||||||
|
|
||||||
|
{ RAND_INF_ZELDAS_LETTER, "RAND_INF_ZELDAS_LETTER" },
|
||||||
|
{ RAND_INF_WEIRD_EGG, "RAND_INF_WEIRD_EGG" },
|
||||||
|
|
||||||
{ RAND_INF_KF_SOUTH_GRASS_WEST_RUPEE, "RAND_INF_KF_SOUTH_GRASS_WEST_RUPEE" },
|
{ RAND_INF_KF_SOUTH_GRASS_WEST_RUPEE, "RAND_INF_KF_SOUTH_GRASS_WEST_RUPEE" },
|
||||||
{ RAND_INF_KF_NORTH_GRASS_WEST_RUPEE, "RAND_INF_KF_NORTH_GRASS_WEST_RUPEE" },
|
{ RAND_INF_KF_NORTH_GRASS_WEST_RUPEE, "RAND_INF_KF_NORTH_GRASS_WEST_RUPEE" },
|
||||||
{ RAND_INF_KF_NORTH_GRASS_EAST_RUPEE, "RAND_INF_KF_NORTH_GRASS_EAST_RUPEE" },
|
{ RAND_INF_KF_NORTH_GRASS_EAST_RUPEE, "RAND_INF_KF_NORTH_GRASS_EAST_RUPEE" },
|
||||||
|
|
|
@ -12,6 +12,10 @@ std::chrono::duration<double, std::milli> GetPerformanceTimer(TimerID timer){
|
||||||
return totalTimes[timer];
|
return totalTimes[timer];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ResetPerformanceTimer(TimerID timer) {
|
||||||
|
totalTimes[timer] = {};
|
||||||
|
}
|
||||||
|
|
||||||
void ResetPerformanceTimers(){
|
void ResetPerformanceTimers(){
|
||||||
totalTimes = {};
|
totalTimes = {};
|
||||||
}
|
}
|
|
@ -25,12 +25,14 @@ typedef enum {
|
||||||
PT_TOD_ACCESS,
|
PT_TOD_ACCESS,
|
||||||
PT_ENTRANCE_LOGIC,
|
PT_ENTRANCE_LOGIC,
|
||||||
PT_LOCATION_LOGIC,
|
PT_LOCATION_LOGIC,
|
||||||
|
PT_RECALCULATE_AVAILABLE_CHECKS,
|
||||||
PT_MAX
|
PT_MAX
|
||||||
} TimerID;
|
} TimerID;
|
||||||
|
|
||||||
void StartPerformanceTimer(TimerID timer);
|
void StartPerformanceTimer(TimerID timer);
|
||||||
void StopPerformanceTimer(TimerID timer);
|
void StopPerformanceTimer(TimerID timer);
|
||||||
std::chrono::duration<double, std::milli> GetPerformanceTimer(TimerID timer);
|
std::chrono::duration<double, std::milli> GetPerformanceTimer(TimerID timer);
|
||||||
|
void ResetPerformanceTimer(TimerID timer);
|
||||||
void ResetPerformanceTimers();
|
void ResetPerformanceTimers();
|
||||||
static std::array<std::chrono::duration<double, std::milli>, PT_MAX> totalTimes = {};
|
static std::array<std::chrono::duration<double, std::milli>, PT_MAX> totalTimes = {};
|
||||||
static std::array<std::chrono::high_resolution_clock::time_point, PT_MAX> timeStarted = {};
|
static std::array<std::chrono::high_resolution_clock::time_point, PT_MAX> timeStarted = {};
|
||||||
|
|
|
@ -402,7 +402,13 @@ bool AddCheckToLogic(LocationAccess& locPair, GetAccessibleLocationsStruct& gals
|
||||||
Rando::ItemLocation* location = ctx->GetItemLocation(loc);
|
Rando::ItemLocation* location = ctx->GetItemLocation(loc);
|
||||||
RandomizerGet locItem = location->GetPlacedRandomizerGet();
|
RandomizerGet locItem = location->GetPlacedRandomizerGet();
|
||||||
|
|
||||||
if (!location->IsAddedToPool() && locPair.ConditionsMet(parentRegion)) {
|
if (!location->IsAddedToPool() && locPair.ConditionsMet(parentRegion, gals.calculatingAvailableChecks)) {
|
||||||
|
if (gals.calculatingAvailableChecks) {
|
||||||
|
gals.accessibleLocations.push_back(loc);
|
||||||
|
StopPerformanceTimer(PT_LOCATION_LOGIC);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
location->AddToPool();
|
location->AddToPool();
|
||||||
|
|
||||||
if (locItem == RG_NONE) {
|
if (locItem == RG_NONE) {
|
||||||
|
@ -498,19 +504,23 @@ void ProcessRegion(Region* region, GetAccessibleLocationsStruct& gals, Randomize
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return any of the targetLocations that are accessible in logic
|
// Return any of the targetLocations that are accessible in logic
|
||||||
std::vector<RandomizerCheck> ReachabilitySearch(const std::vector<RandomizerCheck>& targetLocations, RandomizerGet ignore /* = RG_NONE*/) {
|
std::vector<RandomizerCheck> ReachabilitySearch(const std::vector<RandomizerCheck>& targetLocations, RandomizerGet ignore /* = RG_NONE*/, bool calculatingAvailableChecks /* = false */) {
|
||||||
auto ctx = Rando::Context::GetInstance();
|
auto ctx = Rando::Context::GetInstance();
|
||||||
GetAccessibleLocationsStruct gals(0);
|
GetAccessibleLocationsStruct gals(0);
|
||||||
ResetLogic(ctx, gals, true);
|
gals.calculatingAvailableChecks = calculatingAvailableChecks;
|
||||||
|
ResetLogic(ctx, gals, !calculatingAvailableChecks);
|
||||||
do {
|
do {
|
||||||
gals.InitLoop();
|
gals.InitLoop();
|
||||||
for (size_t i = 0; i < gals.regionPool.size(); i++) {
|
for (size_t i = 0; i < gals.regionPool.size(); i++) {
|
||||||
ProcessRegion(RegionTable(gals.regionPool[i]), gals, ignore);
|
ProcessRegion(RegionTable(gals.regionPool[i]), gals, ignore);
|
||||||
}
|
}
|
||||||
} while (gals.logicUpdated);
|
} while (gals.logicUpdated);
|
||||||
erase_if(gals.accessibleLocations, [&targetLocations, ctx](RandomizerCheck loc){
|
erase_if(gals.accessibleLocations, [&targetLocations, ctx, calculatingAvailableChecks](RandomizerCheck loc) {
|
||||||
|
if (ctx->GetItemLocation(loc)->GetPlacedRandomizerGet() != RG_NONE && !calculatingAvailableChecks) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
for (RandomizerCheck allowedLocation : targetLocations) {
|
for (RandomizerCheck allowedLocation : targetLocations) {
|
||||||
if (loc == allowedLocation || ctx->GetItemLocation(loc)->GetPlacedRandomizerGet() != RG_NONE) {
|
if (loc == allowedLocation) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,8 @@ struct GetAccessibleLocationsStruct {
|
||||||
std::vector<RandomizerCheck> itemSphere;
|
std::vector<RandomizerCheck> itemSphere;
|
||||||
std::list<Rando::Entrance*> entranceSphere;
|
std::list<Rando::Entrance*> entranceSphere;
|
||||||
|
|
||||||
|
bool calculatingAvailableChecks = false;
|
||||||
|
|
||||||
GetAccessibleLocationsStruct(int _maxGsCount){
|
GetAccessibleLocationsStruct(int _maxGsCount){
|
||||||
regionPool = {RR_ROOT};
|
regionPool = {RR_ROOT};
|
||||||
gsCount = 0;
|
gsCount = 0;
|
||||||
|
@ -62,7 +64,7 @@ std::vector<RandomizerCheck> GetEmptyLocations(std::vector<RandomizerCheck> allo
|
||||||
void ProcessRegion(Region* region, GetAccessibleLocationsStruct& gals, RandomizerGet ignore = RG_NONE,
|
void ProcessRegion(Region* region, GetAccessibleLocationsStruct& gals, RandomizerGet ignore = RG_NONE,
|
||||||
bool stopOnBeatable = false, bool addToPlaythrough = false);
|
bool stopOnBeatable = false, bool addToPlaythrough = false);
|
||||||
|
|
||||||
std::vector<RandomizerCheck> ReachabilitySearch(const std::vector<RandomizerCheck>& allowedLocations, RandomizerGet ignore=RG_NONE);
|
std::vector<RandomizerCheck> ReachabilitySearch(const std::vector<RandomizerCheck>& allowedLocations, RandomizerGet ignore=RG_NONE, bool calculatingAvailableChecks=false);
|
||||||
|
|
||||||
void GeneratePlaythrough();
|
void GeneratePlaythrough();
|
||||||
|
|
||||||
|
|
|
@ -236,6 +236,14 @@ void RandomizerOnFlagSetHandler(int16_t flagType, int16_t flag) {
|
||||||
Flags_UnsetRandomizerInf(RAND_INF_CHILD_TRADES_HAS_CHICKEN);
|
Flags_UnsetRandomizerInf(RAND_INF_CHILD_TRADES_HAS_CHICKEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flagType == FLAG_EVENT_CHECK_INF && flag == EVENTCHKINF_OBTAINED_ZELDAS_LETTER) {
|
||||||
|
Flags_SetRandomizerInf(RAND_INF_ZELDAS_LETTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flagType == FLAG_EVENT_CHECK_INF && flag == EVENTCHKINF_OBTAINED_POCKET_EGG) {
|
||||||
|
Flags_SetRandomizerInf(RAND_INF_WEIRD_EGG);
|
||||||
|
}
|
||||||
|
|
||||||
RandomizerCheck rc = GetRandomizerCheckFromFlag(flagType, flag);
|
RandomizerCheck rc = GetRandomizerCheckFromFlag(flagType, flag);
|
||||||
if (rc == RC_UNKNOWN_CHECK) return;
|
if (rc == RC_UNKNOWN_CHECK) return;
|
||||||
|
|
||||||
|
@ -351,6 +359,7 @@ void RandomizerOnItemReceiveHandler(GetItemEntry receivedItemEntry) {
|
||||||
loc->SetCheckStatus(RCSHOW_COLLECTED);
|
loc->SetCheckStatus(RCSHOW_COLLECTED);
|
||||||
CheckTracker::SpoilAreaFromCheck(randomizerQueuedCheck);
|
CheckTracker::SpoilAreaFromCheck(randomizerQueuedCheck);
|
||||||
CheckTracker::RecalculateAllAreaTotals();
|
CheckTracker::RecalculateAllAreaTotals();
|
||||||
|
CheckTracker::RecalculateAvailableChecks();
|
||||||
SaveManager::Instance->SaveSection(gSaveContext.fileNum, SECTION_ID_TRACKER_DATA, true);
|
SaveManager::Instance->SaveSection(gSaveContext.fileNum, SECTION_ID_TRACKER_DATA, true);
|
||||||
randomizerQueuedCheck = RC_UNKNOWN_CHECK;
|
randomizerQueuedCheck = RC_UNKNOWN_CHECK;
|
||||||
randomizerQueuedItemEntry = GET_ITEM_NONE;
|
randomizerQueuedItemEntry = GET_ITEM_NONE;
|
||||||
|
|
|
@ -228,5 +228,14 @@ void ItemLocation::ResetVariables() {
|
||||||
areas = {};
|
areas = {};
|
||||||
status = RCSHOW_UNCHECKED;
|
status = RCSHOW_UNCHECKED;
|
||||||
isSkipped = false;
|
isSkipped = false;
|
||||||
|
isAvailable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ItemLocation::IsAvailable() const {
|
||||||
|
return isAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemLocation::SetAvailable(bool isAvailable_) {
|
||||||
|
isAvailable = isAvailable_;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -56,6 +56,8 @@ class ItemLocation {
|
||||||
bool IsFoolishCandidate() const;
|
bool IsFoolishCandidate() const;
|
||||||
void SetBarrenCandidate();
|
void SetBarrenCandidate();
|
||||||
void ResetVariables();
|
void ResetVariables();
|
||||||
|
bool IsAvailable() const;
|
||||||
|
void SetAvailable(bool isAvailable_);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RandomizerCheck rc;
|
RandomizerCheck rc;
|
||||||
|
@ -76,5 +78,6 @@ class ItemLocation {
|
||||||
bool barrenCandidate = false;
|
bool barrenCandidate = false;
|
||||||
RandomizerCheckStatus status = RCSHOW_UNCHECKED;
|
RandomizerCheckStatus status = RCSHOW_UNCHECKED;
|
||||||
bool isSkipped = false;
|
bool isSkipped = false;
|
||||||
|
bool isAvailable = false;
|
||||||
};
|
};
|
||||||
} // namespace Rando
|
} // namespace Rando
|
|
@ -11,6 +11,11 @@
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
extern SaveContext gSaveContext;
|
||||||
|
extern PlayState* gPlayState;
|
||||||
|
}
|
||||||
|
|
||||||
//generic grotto event list
|
//generic grotto event list
|
||||||
std::vector<EventAccess> grottoEvents;
|
std::vector<EventAccess> grottoEvents;
|
||||||
|
|
||||||
|
@ -27,7 +32,7 @@ bool LocationAccess::CheckConditionAtAgeTime(bool& age, bool& time) const {
|
||||||
return GetConditionsMet();
|
return GetConditionsMet();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LocationAccess::ConditionsMet(Region* parentRegion) const {
|
bool LocationAccess::ConditionsMet(Region* parentRegion, bool calculatingAvailableChecks) const {
|
||||||
//WARNING enterance validation can run this after resetting the access for sphere 0 validation
|
//WARNING enterance validation can run this after resetting the access for sphere 0 validation
|
||||||
//When refactoring ToD access, either fix the above or do not assume that we
|
//When refactoring ToD access, either fix the above or do not assume that we
|
||||||
//have any access at all just because this is being run
|
//have any access at all just because this is being run
|
||||||
|
@ -41,8 +46,8 @@ bool LocationAccess::ConditionsMet(Region* parentRegion) const {
|
||||||
) {
|
) {
|
||||||
conditionsMet = true;
|
conditionsMet = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return conditionsMet && CanBuy();
|
return conditionsMet && (calculatingAvailableChecks || CanBuy()); // TODO: run CanBuy when price is known due to settings
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LocationAccess::CanBuy() const {
|
bool LocationAccess::CanBuy() const {
|
||||||
|
@ -224,8 +229,73 @@ bool MQSpiritSharedBrokenWallRoom(const RandomizerRegion region, ConditionFn con
|
||||||
return areaTable[region].MQSpiritShared(condition, true, anyAge);
|
return areaTable[region].MQSpiritShared(condition, true, anyAge);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BeanPlanted(const RandomizerRegion region) {
|
||||||
|
// 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
|
||||||
|
SceneID sceneID;
|
||||||
|
uint8_t swchFlag;
|
||||||
|
switch (region) {
|
||||||
|
case RR_ZORAS_RIVER:
|
||||||
|
sceneID = SceneID::SCENE_ZORAS_RIVER;
|
||||||
|
swchFlag = 3;
|
||||||
|
break;
|
||||||
|
case RR_THE_GRAVEYARD:
|
||||||
|
sceneID = SceneID::SCENE_GRAVEYARD;
|
||||||
|
swchFlag = 3;
|
||||||
|
break;
|
||||||
|
case RR_KOKIRI_FOREST:
|
||||||
|
sceneID = SceneID::SCENE_KOKIRI_FOREST;
|
||||||
|
swchFlag = 9;
|
||||||
|
break;
|
||||||
|
case RR_THE_LOST_WOODS:
|
||||||
|
sceneID = SceneID::SCENE_LOST_WOODS;
|
||||||
|
swchFlag = 4;
|
||||||
|
break;
|
||||||
|
case RR_LW_BEYOND_MIDO:
|
||||||
|
sceneID = SceneID::SCENE_LOST_WOODS;
|
||||||
|
swchFlag = 18;
|
||||||
|
break;
|
||||||
|
case RR_DEATH_MOUNTAIN_TRAIL:
|
||||||
|
sceneID = SceneID::SCENE_DEATH_MOUNTAIN_TRAIL;
|
||||||
|
swchFlag = 6;
|
||||||
|
break;
|
||||||
|
case RR_LAKE_HYLIA:
|
||||||
|
sceneID = SceneID::SCENE_LAKE_HYLIA;
|
||||||
|
swchFlag = 1;
|
||||||
|
break;
|
||||||
|
case RR_GERUDO_VALLEY:
|
||||||
|
sceneID = SceneID::SCENE_GERUDO_VALLEY;
|
||||||
|
swchFlag = 3;
|
||||||
|
break;
|
||||||
|
case RR_DMC_CENTRAL_LOCAL:
|
||||||
|
sceneID = SceneID::SCENE_DEATH_MOUNTAIN_CRATER;
|
||||||
|
swchFlag = 3;
|
||||||
|
break;
|
||||||
|
case RR_DESERT_COLOSSUS:
|
||||||
|
sceneID = SceneID::SCENE_DESERT_COLOSSUS;
|
||||||
|
swchFlag = 24;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sceneID = SCENE_ID_MAX;
|
||||||
|
swchFlag = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the swch value for the scene
|
||||||
|
uint32_t swch;
|
||||||
|
if (gPlayState != nullptr && gPlayState->sceneNum == sceneID) {
|
||||||
|
swch = gPlayState->actorCtx.flags.swch;
|
||||||
|
} else if (sceneID != SCENE_ID_MAX) {
|
||||||
|
swch = gSaveContext.sceneFlags[sceneID].swch;
|
||||||
|
} else {
|
||||||
|
swch = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return swch >> swchFlag & 1;
|
||||||
|
}
|
||||||
|
|
||||||
bool CanPlantBean(const RandomizerRegion region) {
|
bool CanPlantBean(const RandomizerRegion region) {
|
||||||
return areaTable[region].CanPlantBeanCheck();
|
return areaTable[region].CanPlantBeanCheck() || BeanPlanted(region);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BothAges(const RandomizerRegion region) {
|
bool BothAges(const RandomizerRegion region) {
|
||||||
|
|
|
@ -75,7 +75,7 @@ class LocationAccess {
|
||||||
|
|
||||||
bool CheckConditionAtAgeTime(bool& age, bool& time) const;
|
bool CheckConditionAtAgeTime(bool& age, bool& time) const;
|
||||||
|
|
||||||
bool ConditionsMet(Region* parentRegion) const;
|
bool ConditionsMet(Region* parentRegion, bool calculatingAvailableChecks) const;
|
||||||
|
|
||||||
RandomizerCheck GetLocation() const {
|
RandomizerCheck GetLocation() const {
|
||||||
return location;
|
return location;
|
||||||
|
|
|
@ -13,6 +13,11 @@
|
||||||
#include "macros.h"
|
#include "macros.h"
|
||||||
#include "variables.h"
|
#include "variables.h"
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
|
#include "StringHelper.h"
|
||||||
|
#include "soh/resource/type/Scene.h"
|
||||||
|
#include "soh/resource/type/scenecommand/SetTransitionActorList.h"
|
||||||
|
#include "src/overlays/actors/ovl_En_Door/z_en_door.h"
|
||||||
|
#include "src/overlays/actors/ovl_Door_Shutter/z_door_shutter.h"
|
||||||
|
|
||||||
namespace Rando {
|
namespace Rando {
|
||||||
|
|
||||||
|
@ -87,7 +92,7 @@ namespace Rando {
|
||||||
case RG_BOMB_BAG:
|
case RG_BOMB_BAG:
|
||||||
return CurrentUpgrade(UPG_BOMB_BAG);
|
return CurrentUpgrade(UPG_BOMB_BAG);
|
||||||
case RG_MAGIC_SINGLE:
|
case RG_MAGIC_SINGLE:
|
||||||
return GetSaveContext()->magicLevel >= 1;
|
return GetSaveContext()->magicLevel >= 1 || GetSaveContext()->isMagicAcquired;
|
||||||
// Songs
|
// Songs
|
||||||
case RG_ZELDAS_LULLABY:
|
case RG_ZELDAS_LULLABY:
|
||||||
case RG_EPONAS_SONG:
|
case RG_EPONAS_SONG:
|
||||||
|
@ -217,6 +222,7 @@ namespace Rando {
|
||||||
case RG_GOLDEN_SCALE:
|
case RG_GOLDEN_SCALE:
|
||||||
return CurrentUpgrade(UPG_SCALE) >= 2;
|
return CurrentUpgrade(UPG_SCALE) >= 2;
|
||||||
case RG_POCKET_EGG:
|
case RG_POCKET_EGG:
|
||||||
|
return CheckRandoInf(RAND_INF_ADULT_TRADES_HAS_POCKET_EGG);
|
||||||
case RG_COJIRO:
|
case RG_COJIRO:
|
||||||
case RG_ODD_MUSHROOM:
|
case RG_ODD_MUSHROOM:
|
||||||
case RG_ODD_POTION:
|
case RG_ODD_POTION:
|
||||||
|
@ -226,7 +232,7 @@ namespace Rando {
|
||||||
case RG_EYEBALL_FROG:
|
case RG_EYEBALL_FROG:
|
||||||
case RG_EYEDROPS:
|
case RG_EYEDROPS:
|
||||||
case RG_CLAIM_CHECK:
|
case RG_CLAIM_CHECK:
|
||||||
return CheckRandoInf(itemName - RG_POCKET_EGG + RAND_INF_ADULT_TRADES_HAS_POCKET_EGG);
|
return CheckRandoInf(itemName - RG_COJIRO + RAND_INF_ADULT_TRADES_HAS_COJIRO);
|
||||||
case RG_BOTTLE_WITH_BIG_POE:
|
case RG_BOTTLE_WITH_BIG_POE:
|
||||||
case RG_BOTTLE_WITH_BLUE_FIRE:
|
case RG_BOTTLE_WITH_BLUE_FIRE:
|
||||||
case RG_BOTTLE_WITH_BLUE_POTION:
|
case RG_BOTTLE_WITH_BLUE_POTION:
|
||||||
|
@ -1509,6 +1515,8 @@ namespace Rando {
|
||||||
mSaveContext->isDoubleDefenseAcquired = state;
|
mSaveContext->isDoubleDefenseAcquired = state;
|
||||||
break;
|
break;
|
||||||
case RG_POCKET_EGG:
|
case RG_POCKET_EGG:
|
||||||
|
SetRandoInf(RAND_INF_ADULT_TRADES_HAS_POCKET_EGG, state);
|
||||||
|
break;
|
||||||
case RG_COJIRO:
|
case RG_COJIRO:
|
||||||
case RG_ODD_MUSHROOM:
|
case RG_ODD_MUSHROOM:
|
||||||
case RG_ODD_POTION:
|
case RG_ODD_POTION:
|
||||||
|
@ -1518,7 +1526,7 @@ namespace Rando {
|
||||||
case RG_EYEBALL_FROG:
|
case RG_EYEBALL_FROG:
|
||||||
case RG_EYEDROPS:
|
case RG_EYEDROPS:
|
||||||
case RG_CLAIM_CHECK:
|
case RG_CLAIM_CHECK:
|
||||||
SetRandoInf(randoGet - RG_POCKET_EGG + RAND_INF_ADULT_TRADES_HAS_POCKET_EGG, state);
|
SetRandoInf(randoGet - RG_COJIRO + RAND_INF_ADULT_TRADES_HAS_COJIRO, state);
|
||||||
break;
|
break;
|
||||||
case RG_PROGRESSIVE_HOOKSHOT:
|
case RG_PROGRESSIVE_HOOKSHOT:
|
||||||
{
|
{
|
||||||
|
@ -2096,8 +2104,111 @@ namespace Rando {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unordered_map<SceneID, DungeonKey> SceneToDungeon = {
|
||||||
|
{ SceneID::SCENE_DEKU_TREE, DungeonKey::DEKU_TREE },
|
||||||
|
{ SceneID::SCENE_DODONGOS_CAVERN, DungeonKey::DODONGOS_CAVERN },
|
||||||
|
{ SceneID::SCENE_JABU_JABU, DungeonKey::JABU_JABUS_BELLY },
|
||||||
|
{ SceneID::SCENE_FOREST_TEMPLE, DungeonKey::FOREST_TEMPLE },
|
||||||
|
{ SceneID::SCENE_FIRE_TEMPLE, DungeonKey::FIRE_TEMPLE },
|
||||||
|
{ SceneID::SCENE_WATER_TEMPLE, DungeonKey::WATER_TEMPLE },
|
||||||
|
{ SceneID::SCENE_SPIRIT_TEMPLE, DungeonKey::SPIRIT_TEMPLE },
|
||||||
|
{ SceneID::SCENE_SHADOW_TEMPLE, DungeonKey::SHADOW_TEMPLE },
|
||||||
|
{ SceneID::SCENE_BOTTOM_OF_THE_WELL, DungeonKey::BOTTOM_OF_THE_WELL },
|
||||||
|
{ SceneID::SCENE_ICE_CAVERN, DungeonKey::ICE_CAVERN },
|
||||||
|
{ SceneID::SCENE_GERUDO_TRAINING_GROUND, DungeonKey::GERUDO_TRAINING_GROUND },
|
||||||
|
{ SceneID::SCENE_INSIDE_GANONS_CASTLE, DungeonKey::GANONS_CASTLE },
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get the swch bit positions for the dungeon
|
||||||
|
const std::vector<uint8_t>& GetDungeonSmallKeyDoors(SceneID sceneId) {
|
||||||
|
static const std::vector<uint8_t> emptyVector;
|
||||||
|
auto foundDungeon = SceneToDungeon.find(static_cast<SceneID>(sceneId));
|
||||||
|
if (foundDungeon == SceneToDungeon.end()) {
|
||||||
|
return emptyVector;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool masterQuest = Rando::Context::GetInstance()->GetDungeon(foundDungeon->second)->IsMQ();
|
||||||
|
|
||||||
|
// Create a unique key for the dungeon and master quest
|
||||||
|
uint8_t key = sceneId | (masterQuest << 7);
|
||||||
|
|
||||||
|
static std::unordered_map<uint8_t, std::vector<uint8_t>> dungeonSmallKeyDoors;
|
||||||
|
auto foundEntry = dungeonSmallKeyDoors.find(key);
|
||||||
|
if (foundEntry != dungeonSmallKeyDoors.end()) {
|
||||||
|
return foundEntry->second;
|
||||||
|
}
|
||||||
|
dungeonSmallKeyDoors[key] = {};
|
||||||
|
|
||||||
|
// Get the scene path
|
||||||
|
SceneTableEntry* sceneTableEntry = &gSceneTable[sceneId];
|
||||||
|
std::string scenePath = StringHelper::Sprintf("scenes/%s/%s/%s", masterQuest ? "mq" : "nonmq",
|
||||||
|
sceneTableEntry->sceneFile.fileName, sceneTableEntry->sceneFile.fileName);
|
||||||
|
|
||||||
|
// Load the scene
|
||||||
|
std::shared_ptr<SOH::Scene> scene = std::dynamic_pointer_cast<SOH::Scene>(
|
||||||
|
Ship::Context::GetInstance()->GetResourceManager()->LoadResource(scenePath));
|
||||||
|
if (scene == nullptr) {
|
||||||
|
return emptyVector;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the SetTransitionActorList command
|
||||||
|
std::shared_ptr<SOH::SetTransitionActorList> transitionActorListCommand = nullptr;
|
||||||
|
for (auto& command : scene->commands) {
|
||||||
|
if (command->cmdId == SOH::SceneCommandID::SetTransitionActorList) {
|
||||||
|
transitionActorListCommand = std::dynamic_pointer_cast<SOH::SetTransitionActorList>(command);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (transitionActorListCommand == nullptr) {
|
||||||
|
return emptyVector;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the bit position for the small key doors
|
||||||
|
for (auto& transitionActor : transitionActorListCommand->transitionActorList) {
|
||||||
|
if (transitionActor.id == ACTOR_EN_DOOR) {
|
||||||
|
uint8_t doorType = (transitionActor.params >> 7) & 7;
|
||||||
|
if (doorType == DOOR_LOCKED) {
|
||||||
|
dungeonSmallKeyDoors[key].emplace_back(transitionActor.params & 0x3F);
|
||||||
|
}
|
||||||
|
} else if (transitionActor.id == ACTOR_DOOR_SHUTTER) {
|
||||||
|
uint8_t doorType = (transitionActor.params >> 7) & 15;
|
||||||
|
if (doorType == SHUTTER_BACK_LOCKED || doorType == SHUTTER_BOSS || doorType == SHUTTER_KEY_LOCKED) {
|
||||||
|
dungeonSmallKeyDoors[key].emplace_back(transitionActor.params & 0x3F);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dungeonSmallKeyDoors[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t 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 = gSaveContext.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) {
|
uint8_t Logic::GetSmallKeyCount(uint32_t dungeonIndex) {
|
||||||
return mSaveContext->inventory.dungeonKeys[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));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logic::SetSmallKeyCount(uint32_t dungeonIndex, uint8_t count) {
|
void Logic::SetSmallKeyCount(uint32_t dungeonIndex, uint8_t count) {
|
||||||
|
@ -2172,7 +2283,8 @@ namespace Rando {
|
||||||
IsKeysanity = ctx->GetOption(RSK_KEYSANITY).Is(RO_DUNGEON_ITEM_LOC_ANYWHERE) ||
|
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) ||
|
||||||
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;
|
|
||||||
|
//AmmoCanDrop = /*AmmoDrops.IsNot(AMMODROPS_NONE)*/ false; TODO: AmmoDrop setting
|
||||||
|
|
||||||
//Child item logic
|
//Child item logic
|
||||||
SkullMask = false;
|
SkullMask = false;
|
||||||
|
|
|
@ -90,7 +90,7 @@ class Logic {
|
||||||
bool FairyPot = false;
|
bool FairyPot = false;
|
||||||
bool FreeFairies = false;
|
bool FreeFairies = false;
|
||||||
bool FairyPond = false;
|
bool FairyPond = false;
|
||||||
bool AmmoCanDrop = false;
|
bool AmmoCanDrop = true;
|
||||||
|
|
||||||
uint8_t PieceOfHeart = 0;
|
uint8_t PieceOfHeart = 0;
|
||||||
uint8_t HeartContainer = 0;
|
uint8_t HeartContainer = 0;
|
||||||
|
|
|
@ -9,7 +9,10 @@
|
||||||
#include "soh/SohGui/UIWidgets.hpp"
|
#include "soh/SohGui/UIWidgets.hpp"
|
||||||
#include "soh/SohGui/SohGui.hpp"
|
#include "soh/SohGui/SohGui.hpp"
|
||||||
#include "dungeon.h"
|
#include "dungeon.h"
|
||||||
|
#include "entrance.h"
|
||||||
#include "location_access.h"
|
#include "location_access.h"
|
||||||
|
#include "3drando/fill.hpp"
|
||||||
|
#include "soh/Enhancements/debugger/performanceTimer.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -84,7 +87,7 @@ bool fishsanityAgeSplit;
|
||||||
bool initialized;
|
bool initialized;
|
||||||
bool doAreaScroll;
|
bool doAreaScroll;
|
||||||
bool previousShowHidden = false;
|
bool previousShowHidden = false;
|
||||||
bool hideShopUnshuffledChecks = true;
|
bool hideShopUnshuffledChecks = false;
|
||||||
bool alwaysShowGS = false;
|
bool alwaysShowGS = false;
|
||||||
|
|
||||||
std::map<uint32_t, RandomizerCheck> startingShopItem = { { SCENE_KOKIRI_SHOP, RC_KF_SHOP_ITEM_1 },
|
std::map<uint32_t, RandomizerCheck> startingShopItem = { { SCENE_KOKIRI_SHOP, RC_KF_SHOP_ITEM_1 },
|
||||||
|
@ -132,8 +135,10 @@ bool areasFullyChecked[RCAREA_INVALID];
|
||||||
u32 areasSpoiled = 0;
|
u32 areasSpoiled = 0;
|
||||||
bool showVOrMQ;
|
bool showVOrMQ;
|
||||||
s8 areaChecksGotten[RCAREA_INVALID]; //| "Kokiri Forest (4/9)"
|
s8 areaChecksGotten[RCAREA_INVALID]; //| "Kokiri Forest (4/9)"
|
||||||
|
s8 areaChecksAvailable[RCAREA_INVALID];
|
||||||
s8 areaCheckTotals[RCAREA_INVALID];
|
s8 areaCheckTotals[RCAREA_INVALID];
|
||||||
uint16_t totalChecks = 0;
|
uint16_t totalChecks = 0;
|
||||||
|
uint16_t totalChecksAvailable = 0;
|
||||||
uint16_t totalChecksGotten = 0;
|
uint16_t totalChecksGotten = 0;
|
||||||
bool optCollapseAll; // A bool that will collapse all checks once
|
bool optCollapseAll; // A bool that will collapse all checks once
|
||||||
bool optExpandAll; // A bool that will expand all checks once
|
bool optExpandAll; // A bool that will expand all checks once
|
||||||
|
@ -166,6 +171,8 @@ bool hideCollected = false;
|
||||||
bool showHidden = true;
|
bool showHidden = true;
|
||||||
bool mystery = false;
|
bool mystery = false;
|
||||||
bool showLogicTooltip = false;
|
bool showLogicTooltip = false;
|
||||||
|
bool enableAvailableChecks = false;
|
||||||
|
bool onlyShowAvailable = false;
|
||||||
|
|
||||||
SceneID DungeonSceneLookupByArea(RandomizerCheckArea area) {
|
SceneID DungeonSceneLookupByArea(RandomizerCheckArea area) {
|
||||||
switch (area) {
|
switch (area) {
|
||||||
|
@ -235,10 +242,12 @@ void TrySetAreas() {
|
||||||
|
|
||||||
void CalculateTotals() {
|
void CalculateTotals() {
|
||||||
totalChecks = 0;
|
totalChecks = 0;
|
||||||
|
totalChecksAvailable = 0;
|
||||||
totalChecksGotten = 0;
|
totalChecksGotten = 0;
|
||||||
|
|
||||||
for (uint8_t i = 0; i < RCAREA_INVALID; i++) {
|
for (uint8_t i = 0; i < RCAREA_INVALID; i++) {
|
||||||
totalChecks += areaCheckTotals[i];
|
totalChecks += areaCheckTotals[i];
|
||||||
|
totalChecksAvailable += areaChecksAvailable[i];
|
||||||
totalChecksGotten += areaChecksGotten[i];
|
totalChecksGotten += areaChecksGotten[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -251,17 +260,43 @@ uint16_t GetTotalChecksGotten() {
|
||||||
return totalChecksGotten;
|
return totalChecksGotten;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsCheckHidden(RandomizerCheck rc) {
|
||||||
|
Rando::ItemLocation* itemLocation = OTRGlobals::Instance->gRandoContext->GetItemLocation(rc);
|
||||||
|
RandomizerCheckStatus status = itemLocation->GetCheckStatus();
|
||||||
|
bool available = itemLocation->IsAvailable();
|
||||||
|
bool skipped = itemLocation->GetIsSkipped();
|
||||||
|
bool obtained = itemLocation->HasObtained();
|
||||||
|
bool seen = status == RCSHOW_SEEN || status == RCSHOW_IDENTIFIED;
|
||||||
|
bool scummed = status == RCSHOW_SCUMMED;
|
||||||
|
bool unchecked = status == RCSHOW_UNCHECKED;
|
||||||
|
|
||||||
|
return !showHidden && (
|
||||||
|
(skipped && hideSkipped) ||
|
||||||
|
(seen && hideSeen) ||
|
||||||
|
(scummed && hideScummed) ||
|
||||||
|
(unchecked && hideUnchecked)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void RecalculateAreaTotals(RandomizerCheckArea rcArea) {
|
void RecalculateAreaTotals(RandomizerCheckArea rcArea) {
|
||||||
areaChecksGotten[rcArea] = 0;
|
areaChecksGotten[rcArea] = 0;
|
||||||
|
areaChecksAvailable[rcArea] = 0;
|
||||||
areaCheckTotals[rcArea] = 0;
|
areaCheckTotals[rcArea] = 0;
|
||||||
for (auto rc : checksByArea.at(rcArea)) {
|
for (auto rc : checksByArea.at(rcArea)) {
|
||||||
if (!IsVisibleInCheckTracker(rc)) {
|
if (!IsVisibleInCheckTracker(rc)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
areaCheckTotals[rcArea]++;
|
areaCheckTotals[rcArea]++;
|
||||||
if (OTRGlobals::Instance->gRandoContext->GetItemLocation(rc)->GetIsSkipped() || OTRGlobals::Instance->gRandoContext->GetItemLocation(rc)->HasObtained()) {
|
|
||||||
|
Rando::ItemLocation* itemLoc = OTRGlobals::Instance->gRandoContext->GetItemLocation(rc);
|
||||||
|
|
||||||
|
if (itemLoc->GetIsSkipped() || itemLoc->HasObtained()) {
|
||||||
areaChecksGotten[rcArea]++;
|
areaChecksGotten[rcArea]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (itemLoc->IsAvailable() && !IsCheckHidden(rc)) {
|
||||||
|
areaChecksAvailable[rcArea]++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
CalculateTotals();
|
CalculateTotals();
|
||||||
}
|
}
|
||||||
|
@ -308,6 +343,7 @@ void SetCheckCollected(RandomizerCheck rc) {
|
||||||
if (IsVisibleInCheckTracker(rc)) {
|
if (IsVisibleInCheckTracker(rc)) {
|
||||||
if (!OTRGlobals::Instance->gRandoContext->GetItemLocation(rc)->GetIsSkipped()) {
|
if (!OTRGlobals::Instance->gRandoContext->GetItemLocation(rc)->GetIsSkipped()) {
|
||||||
areaChecksGotten[loc->GetArea()]++;
|
areaChecksGotten[loc->GetArea()]++;
|
||||||
|
areaChecksAvailable[loc->GetArea()]--;
|
||||||
} else {
|
} else {
|
||||||
OTRGlobals::Instance->gRandoContext->GetItemLocation(rc)->SetIsSkipped(false);
|
OTRGlobals::Instance->gRandoContext->GetItemLocation(rc)->SetIsSkipped(false);
|
||||||
}
|
}
|
||||||
|
@ -424,10 +460,12 @@ void ClearAreaChecksAndTotals() {
|
||||||
for (auto& [rcArea, vec] : checksByArea) {
|
for (auto& [rcArea, vec] : checksByArea) {
|
||||||
vec.clear();
|
vec.clear();
|
||||||
areaChecksGotten[rcArea] = 0;
|
areaChecksGotten[rcArea] = 0;
|
||||||
|
areaChecksAvailable[rcArea] = 0;
|
||||||
areaCheckTotals[rcArea] = 0;
|
areaCheckTotals[rcArea] = 0;
|
||||||
}
|
}
|
||||||
totalChecks = 0;
|
totalChecks = 0;
|
||||||
totalChecksGotten = 0;
|
totalChecksGotten = 0;
|
||||||
|
totalChecksAvailable = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetShopSeen(uint32_t sceneNum, bool prices) {
|
void SetShopSeen(uint32_t sceneNum, bool prices) {
|
||||||
|
@ -469,6 +507,9 @@ void CheckTrackerLoadGame(int32_t fileNum) {
|
||||||
if (loc->GetCheckStatus() == RCSHOW_SAVED || loc->GetIsSkipped()) {
|
if (loc->GetCheckStatus() == RCSHOW_SAVED || loc->GetIsSkipped()) {
|
||||||
areaChecksGotten[entry2->GetArea()]++;
|
areaChecksGotten[entry2->GetArea()]++;
|
||||||
}
|
}
|
||||||
|
if (loc->IsAvailable()) {
|
||||||
|
areaChecksAvailable[entry2->GetArea()]++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (areaChecksGotten[entry2->GetArea()] != 0 || RandomizerCheckObjects::AreaIsOverworld(entry2->GetArea()) ||
|
if (areaChecksGotten[entry2->GetArea()] != 0 || RandomizerCheckObjects::AreaIsOverworld(entry2->GetArea()) ||
|
||||||
|
@ -524,6 +565,7 @@ void CheckTrackerLoadGame(int32_t fileNum) {
|
||||||
UpdateAllOrdering();
|
UpdateAllOrdering();
|
||||||
UpdateInventoryChecks();
|
UpdateInventoryChecks();
|
||||||
UpdateFilters();
|
UpdateFilters();
|
||||||
|
RecalculateAvailableChecks();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckTrackerShopSlotChange(uint8_t cursorSlot, int16_t basePrice) {
|
void CheckTrackerShopSlotChange(uint8_t cursorSlot, int16_t basePrice) {
|
||||||
|
@ -539,6 +581,7 @@ void CheckTrackerShopSlotChange(uint8_t cursorSlot, int16_t basePrice) {
|
||||||
if (status == RCSHOW_SEEN) {
|
if (status == RCSHOW_SEEN) {
|
||||||
OTRGlobals::Instance->gRandoContext->GetItemLocation(slot)->SetCheckStatus(RCSHOW_IDENTIFIED);
|
OTRGlobals::Instance->gRandoContext->GetItemLocation(slot)->SetCheckStatus(RCSHOW_IDENTIFIED);
|
||||||
SaveManager::Instance->SaveSection(gSaveContext.fileNum, sectionId, true);
|
SaveManager::Instance->SaveSection(gSaveContext.fileNum, sectionId, true);
|
||||||
|
RecalculateAvailableChecks();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -812,6 +855,9 @@ void SaveTrackerData(SaveContext* saveContext, int sectionID, bool fullSave) {
|
||||||
|
|
||||||
void SaveFile(SaveContext* saveContext, int sectionID, bool fullSave) {
|
void SaveFile(SaveContext* saveContext, int sectionID, bool fullSave) {
|
||||||
SaveTrackerData(saveContext, sectionID, fullSave);
|
SaveTrackerData(saveContext, sectionID, fullSave);
|
||||||
|
if (fullSave) {
|
||||||
|
RecalculateAvailableChecks();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadFile() {
|
void LoadFile() {
|
||||||
|
@ -882,6 +928,8 @@ void CheckTrackerWindow::DrawElement() {
|
||||||
showHidden = CVarGetInteger(CVAR_TRACKER_CHECK("ShowHidden"), 0);
|
showHidden = CVarGetInteger(CVAR_TRACKER_CHECK("ShowHidden"), 0);
|
||||||
mystery = CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("MysteriousShuffle"), 0);
|
mystery = CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("MysteriousShuffle"), 0);
|
||||||
showLogicTooltip = CVarGetInteger(CVAR_TRACKER_CHECK("ShowLogic"), 0);
|
showLogicTooltip = CVarGetInteger(CVAR_TRACKER_CHECK("ShowLogic"), 0);
|
||||||
|
enableAvailableChecks = CVarGetInteger(CVAR_TRACKER_CHECK("EnableAvailableChecks"), 0);
|
||||||
|
onlyShowAvailable = CVarGetInteger(CVAR_TRACKER_CHECK("OnlyShowAvailable"), 0);
|
||||||
|
|
||||||
hideShopUnshuffledChecks = CVarGetInteger(CVAR_TRACKER_CHECK("HideUnshuffledShopChecks"), 0);
|
hideShopUnshuffledChecks = CVarGetInteger(CVAR_TRACKER_CHECK("HideUnshuffledShopChecks"), 0);
|
||||||
alwaysShowGS = CVarGetInteger(CVAR_TRACKER_CHECK("AlwaysShowGSLocs"), 0);
|
alwaysShowGS = CVarGetInteger(CVAR_TRACKER_CHECK("AlwaysShowGSLocs"), 0);
|
||||||
|
@ -932,9 +980,21 @@ void CheckTrackerWindow::DrawElement() {
|
||||||
|
|
||||||
ImGui::TableNextRow(0, headerHeight);
|
ImGui::TableNextRow(0, headerHeight);
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
UIWidgets::CVarCheckbox(
|
if (UIWidgets::CVarCheckbox(
|
||||||
"Show Hidden Items", CVAR_TRACKER_CHECK("ShowHidden"), UIWidgets::CheckboxOptions({{ .tooltip = "When active, items will show hidden checks by default when updated to this state." }})
|
"Show Hidden Items", CVAR_TRACKER_CHECK("ShowHidden"), UIWidgets::CheckboxOptions({{.tooltip = "When active, items will show hidden checks by default when updated to this state." }})
|
||||||
.Color(THEME_COLOR));
|
.Color(THEME_COLOR))) {
|
||||||
|
doAreaScroll = true;
|
||||||
|
showHidden = CVarGetInteger(CVAR_TRACKER_CHECK("ShowHidden"), 0);
|
||||||
|
RecalculateAllAreaTotals();
|
||||||
|
}
|
||||||
|
if (enableAvailableChecks) {
|
||||||
|
if (UIWidgets::CVarCheckbox(
|
||||||
|
"Only Show Available Checks", CVAR_TRACKER_CHECK("OnlyShowAvailable"), UIWidgets::CheckboxOptions({{ .tooltip = "When active, unavailable checks will be hidden." }})
|
||||||
|
.Color(THEME_COLOR))) {
|
||||||
|
doAreaScroll = true;
|
||||||
|
RecalculateAllAreaTotals();
|
||||||
|
}
|
||||||
|
}
|
||||||
UIWidgets::PaddedSeparator();
|
UIWidgets::PaddedSeparator();
|
||||||
if (UIWidgets::Button("Expand All", UIWidgets::ButtonOptions().Color(THEME_COLOR).Size(UIWidgets::Sizes::Inline))) {
|
if (UIWidgets::Button("Expand All", UIWidgets::ButtonOptions().Color(THEME_COLOR).Size(UIWidgets::Sizes::Inline))) {
|
||||||
optCollapseAll = false;
|
optCollapseAll = false;
|
||||||
|
@ -960,7 +1020,13 @@ void CheckTrackerWindow::DrawElement() {
|
||||||
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
ImGui::Text("Total Checks: %d / %d", totalChecksGotten, totalChecks);
|
std::ostringstream totalChecksSS;
|
||||||
|
totalChecksSS << "Total Checks: ";
|
||||||
|
if (enableAvailableChecks) {
|
||||||
|
totalChecksSS << totalChecksAvailable << " Available / ";
|
||||||
|
}
|
||||||
|
totalChecksSS << totalChecksGotten << " Checked / " << totalChecks << " Total";
|
||||||
|
ImGui::Text(totalChecksSS.str().c_str());
|
||||||
|
|
||||||
UIWidgets::PaddedSeparator();
|
UIWidgets::PaddedSeparator();
|
||||||
|
|
||||||
|
@ -1012,7 +1078,8 @@ void CheckTrackerWindow::DrawElement() {
|
||||||
doAreaScroll = true;
|
doAreaScroll = true;
|
||||||
}
|
}
|
||||||
if ((shouldHideFilteredAreas && filterAreasHidden[rcArea]) ||
|
if ((shouldHideFilteredAreas && filterAreasHidden[rcArea]) ||
|
||||||
(!showHidden && ((hideComplete && thisAreaFullyChecked) || (hideIncomplete && !thisAreaFullyChecked)))
|
(!showHidden && ((hideComplete && thisAreaFullyChecked) || (hideIncomplete && !thisAreaFullyChecked))) ||
|
||||||
|
(enableAvailableChecks && onlyShowAvailable && areaChecksAvailable[rcArea] == 0)
|
||||||
) {
|
) {
|
||||||
doDraw = false;
|
doDraw = false;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1051,14 +1118,27 @@ void CheckTrackerWindow::DrawElement() {
|
||||||
isThisAreaSpoiled = IsAreaSpoiled(rcArea) || mqSpoilers;
|
isThisAreaSpoiled = IsAreaSpoiled(rcArea) || mqSpoilers;
|
||||||
|
|
||||||
if (isThisAreaSpoiled) {
|
if (isThisAreaSpoiled) {
|
||||||
if (showVOrMQ && RandomizerCheckObjects::AreaIsDungeon(rcArea)) {
|
std::ostringstream areaTotalsSS;
|
||||||
if (OTRGlobals::Instance->gRandoContext->GetDungeons()->GetDungeonFromScene(DungeonSceneLookupByArea(rcArea))->IsMQ())
|
std::ostringstream areaTotalsTooltipSS;
|
||||||
ImGui::Text("(%d/%d) - MQ", areaChecksGotten[rcArea], areaCheckTotals[rcArea]);
|
|
||||||
else
|
areaTotalsSS << "(";
|
||||||
ImGui::Text("(%d/%d) - Vanilla", areaChecksGotten[rcArea], areaCheckTotals[rcArea]);
|
if (enableAvailableChecks) {
|
||||||
} else {
|
areaTotalsSS << static_cast<uint16_t>(areaChecksAvailable[rcArea]) << " / ";
|
||||||
ImGui::Text("(%d/%d)", areaChecksGotten[rcArea], areaCheckTotals[rcArea]);
|
areaTotalsTooltipSS << "Available / ";
|
||||||
}
|
}
|
||||||
|
areaTotalsSS << static_cast<uint16_t>(areaChecksGotten[rcArea]) << " / " << static_cast<uint16_t>(areaCheckTotals[rcArea]) << ")";
|
||||||
|
areaTotalsTooltipSS << "Checked / Total";
|
||||||
|
|
||||||
|
if (showVOrMQ && RandomizerCheckObjects::AreaIsDungeon(rcArea)) {
|
||||||
|
if (OTRGlobals::Instance->gRandoContext->GetDungeons()->GetDungeonFromScene(DungeonSceneLookupByArea(rcArea))->IsMQ()) {
|
||||||
|
areaTotalsSS << " - MQ";
|
||||||
|
} else {
|
||||||
|
areaTotalsSS << " - Vanilla";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Text(areaTotalsSS.str().c_str());
|
||||||
|
UIWidgets::Tooltip(areaTotalsTooltipSS.str().c_str());
|
||||||
} else {
|
} else {
|
||||||
ImGui::Text("???");
|
ImGui::Text("???");
|
||||||
}
|
}
|
||||||
|
@ -1561,6 +1641,12 @@ void DrawLocation(RandomizerCheck rc) {
|
||||||
Rando::ItemLocation* itemLoc = OTRGlobals::Instance->gRandoContext->GetItemLocation(rc);
|
Rando::ItemLocation* itemLoc = OTRGlobals::Instance->gRandoContext->GetItemLocation(rc);
|
||||||
RandomizerCheckStatus status = itemLoc->GetCheckStatus();
|
RandomizerCheckStatus status = itemLoc->GetCheckStatus();
|
||||||
bool skipped = itemLoc->GetIsSkipped();
|
bool skipped = itemLoc->GetIsSkipped();
|
||||||
|
bool available = itemLoc->IsAvailable();
|
||||||
|
|
||||||
|
if (enableAvailableChecks && onlyShowAvailable && !available) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (status == RCSHOW_COLLECTED) {
|
if (status == RCSHOW_COLLECTED) {
|
||||||
if (!showHidden && hideCollected) {
|
if (!showHidden && hideCollected) {
|
||||||
return;
|
return;
|
||||||
|
@ -1637,10 +1723,18 @@ void DrawLocation(RandomizerCheck rc) {
|
||||||
OTRGlobals::Instance->gRandoContext->GetItemLocation(rc)->SetIsSkipped(false);
|
OTRGlobals::Instance->gRandoContext->GetItemLocation(rc)->SetIsSkipped(false);
|
||||||
areaChecksGotten[loc->GetArea()]--;
|
areaChecksGotten[loc->GetArea()]--;
|
||||||
totalChecksGotten--;
|
totalChecksGotten--;
|
||||||
|
if (available) {
|
||||||
|
areaChecksAvailable[loc->GetArea()]++;
|
||||||
|
totalChecksAvailable++;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
OTRGlobals::Instance->gRandoContext->GetItemLocation(rc)->SetIsSkipped(true);
|
OTRGlobals::Instance->gRandoContext->GetItemLocation(rc)->SetIsSkipped(true);
|
||||||
areaChecksGotten[loc->GetArea()]++;
|
areaChecksGotten[loc->GetArea()]++;
|
||||||
totalChecksGotten++;
|
totalChecksGotten++;
|
||||||
|
if (available) {
|
||||||
|
areaChecksAvailable[loc->GetArea()]--;
|
||||||
|
totalChecksAvailable--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
UpdateOrdering(loc->GetArea());
|
UpdateOrdering(loc->GetArea());
|
||||||
UpdateInventoryChecks();
|
UpdateInventoryChecks();
|
||||||
|
@ -1654,7 +1748,19 @@ void DrawLocation(RandomizerCheck rc) {
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
//Draw
|
//Draw
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(mainColor.r / 255.0f, mainColor.g / 255.0f, mainColor.b / 255.0f, mainColor.a / 255.0f));
|
ImVec4 styleColor(mainColor.r / 255.0f, mainColor.g / 255.0f, mainColor.b / 255.0f, mainColor.a / 255.0f);
|
||||||
|
if (enableAvailableChecks) {
|
||||||
|
if (itemLoc->HasObtained()) {
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0, 0, 0, 0));
|
||||||
|
} else {
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, styleColor);
|
||||||
|
}
|
||||||
|
ImGui::Text("%s", available ? ICON_FA_UNLOCK : ICON_FA_LOCK);
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
ImGui::SameLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, styleColor);
|
||||||
ImGui::Text("%s", txt.c_str());
|
ImGui::Text("%s", txt.c_str());
|
||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
|
|
||||||
|
@ -1726,7 +1832,7 @@ void DrawLocation(RandomizerCheck rc) {
|
||||||
if (conditionStr != "true") {
|
if (conditionStr != "true") {
|
||||||
UIWidgets::Tooltip(conditionStr.c_str());
|
UIWidgets::Tooltip(conditionStr.c_str());
|
||||||
}
|
}
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1804,6 +1910,55 @@ void ImGuiDrawTwoColorPickerSection(const char* text, const char* cvarMainName,
|
||||||
UIWidgets::PopStyleCombobox();
|
UIWidgets::PopStyleCombobox();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RecalculateAvailableChecks() {
|
||||||
|
if (!enableAvailableChecks) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResetPerformanceTimer(PT_RECALCULATE_AVAILABLE_CHECKS);
|
||||||
|
StartPerformanceTimer(PT_RECALCULATE_AVAILABLE_CHECKS);
|
||||||
|
|
||||||
|
std::vector<RandomizerCheck> targetLocations;
|
||||||
|
targetLocations.reserve(RR_MAX);
|
||||||
|
for (auto& location : Rando::StaticData::GetLocationTable()) {
|
||||||
|
RandomizerCheck rc = location.GetRandomizerCheck();
|
||||||
|
Rando::ItemLocation* itemLocation = OTRGlobals::Instance->gRandoContext->GetItemLocation(rc);
|
||||||
|
itemLocation->SetAvailable(false);
|
||||||
|
if (!itemLocation->HasObtained()) {
|
||||||
|
targetLocations.emplace_back(rc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<RandomizerCheck> availableChecks = ReachabilitySearch(targetLocations, RG_NONE, true);
|
||||||
|
for (auto& rc : availableChecks) {
|
||||||
|
const auto& location = Rando::StaticData::GetLocation(rc);
|
||||||
|
const auto& itemLocation = OTRGlobals::Instance->gRandoContext->GetItemLocation(rc);
|
||||||
|
if (location->GetRCType() == RCTYPE_SHOP && itemLocation->GetCheckStatus() == RCSHOW_IDENTIFIED) {
|
||||||
|
if (CanBuyAnother(rc)) {
|
||||||
|
itemLocation->SetAvailable(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
itemLocation->SetAvailable(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
totalChecksAvailable = 0;
|
||||||
|
for (auto& [rcArea, vec] : checksByArea) {
|
||||||
|
areaChecksAvailable[rcArea] = 0;
|
||||||
|
for (auto& rc : vec) {
|
||||||
|
Rando::ItemLocation* itemLocation = OTRGlobals::Instance->gRandoContext->GetItemLocation(rc);
|
||||||
|
if (itemLocation->IsAvailable() && IsVisibleInCheckTracker(rc) && !IsCheckHidden(rc)) {
|
||||||
|
areaChecksAvailable[rcArea]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
totalChecksAvailable += areaChecksAvailable[rcArea];
|
||||||
|
}
|
||||||
|
|
||||||
|
StopPerformanceTimer(PT_RECALCULATE_AVAILABLE_CHECKS);
|
||||||
|
SPDLOG_INFO("Recalculate Available Checks Time: {}ms", GetPerformanceTimer(PT_RECALCULATE_AVAILABLE_CHECKS).count());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void CheckTrackerWindow::Draw() {
|
void CheckTrackerWindow::Draw() {
|
||||||
if (!IsVisible()) {
|
if (!IsVisible()) {
|
||||||
return;
|
return;
|
||||||
|
@ -1858,7 +2013,7 @@ void CheckTrackerSettingsWindow::DrawElement() {
|
||||||
.Tooltip("If enabled, Vanilla/MQ dungeons will show on the tracker immediately. Otherwise, Vanilla/MQ dungeon locations must be unlocked.").Color(THEME_COLOR));
|
.Tooltip("If enabled, Vanilla/MQ dungeons will show on the tracker immediately. Otherwise, Vanilla/MQ dungeon locations must be unlocked.").Color(THEME_COLOR));
|
||||||
if (UIWidgets::CVarCheckbox("Hide unshuffled shop item checks", CVAR_TRACKER_CHECK("HideUnshuffledShopChecks"),
|
if (UIWidgets::CVarCheckbox("Hide unshuffled shop item checks", CVAR_TRACKER_CHECK("HideUnshuffledShopChecks"),
|
||||||
UIWidgets::CheckboxOptions().Tooltip("If enabled, will prevent the tracker from displaying slots with non-shop-item shuffles.").Color(THEME_COLOR))) {
|
UIWidgets::CheckboxOptions().Tooltip("If enabled, will prevent the tracker from displaying slots with non-shop-item shuffles.").Color(THEME_COLOR))) {
|
||||||
hideShopUnshuffledChecks = !hideShopUnshuffledChecks;
|
hideShopUnshuffledChecks = CVarGetInteger(CVAR_TRACKER_CHECK("HideUnshuffledShopChecks"), 0);
|
||||||
UpdateFilters();
|
UpdateFilters();
|
||||||
}
|
}
|
||||||
if (UIWidgets::CVarCheckbox("Always show gold skulltulas", CVAR_TRACKER_CHECK("AlwaysShowGSLocs"),
|
if (UIWidgets::CVarCheckbox("Always show gold skulltulas", CVAR_TRACKER_CHECK("AlwaysShowGSLocs"),
|
||||||
|
@ -1868,6 +2023,11 @@ void CheckTrackerSettingsWindow::DrawElement() {
|
||||||
}
|
}
|
||||||
UIWidgets::CVarCheckbox("Show Logic", CVAR_TRACKER_CHECK("ShowLogic"),
|
UIWidgets::CVarCheckbox("Show Logic", CVAR_TRACKER_CHECK("ShowLogic"),
|
||||||
UIWidgets::CheckboxOptions().Tooltip("If enabled, will show a check's logic when hovering over it.").Color(THEME_COLOR));
|
UIWidgets::CheckboxOptions().Tooltip("If enabled, will show a check's logic when hovering over it.").Color(THEME_COLOR));
|
||||||
|
if (UIWidgets::CVarCheckbox("Enable Available Checks", CVAR_TRACKER_CHECK("EnableAvailableChecks"),
|
||||||
|
UIWidgets::CheckboxOptions().Tooltip("If enabled, will show the checks that are available to be collected with your current progress.").Color(THEME_COLOR))) {
|
||||||
|
enableAvailableChecks = CVarGetInteger(CVAR_TRACKER_CHECK("EnableAvailableChecks"), 0);
|
||||||
|
RecalculateAvailableChecks();
|
||||||
|
}
|
||||||
|
|
||||||
// Filtering settings
|
// Filtering settings
|
||||||
UIWidgets::PaddedSeparator();
|
UIWidgets::PaddedSeparator();
|
||||||
|
|
|
@ -61,4 +61,5 @@ void UpdateAllOrdering();
|
||||||
void UpdateAllAreas();
|
void UpdateAllAreas();
|
||||||
void RecalculateAllAreaTotals();
|
void RecalculateAllAreaTotals();
|
||||||
void SpoilAreaFromCheck(RandomizerCheck rc);
|
void SpoilAreaFromCheck(RandomizerCheck rc);
|
||||||
|
void RecalculateAvailableChecks();
|
||||||
} // namespace CheckTracker
|
} // namespace CheckTracker
|
||||||
|
|
|
@ -306,11 +306,13 @@ extern "C" void Randomizer_InitSaveFile() {
|
||||||
|
|
||||||
// Malon/Talon back at ranch.
|
// Malon/Talon back at ranch.
|
||||||
Flags_SetEventChkInf(EVENTCHKINF_OBTAINED_POCKET_EGG);
|
Flags_SetEventChkInf(EVENTCHKINF_OBTAINED_POCKET_EGG);
|
||||||
|
Flags_SetRandomizerInf(RAND_INF_WEIRD_EGG);
|
||||||
Flags_SetEventChkInf(EVENTCHKINF_TALON_WOKEN_IN_CASTLE);
|
Flags_SetEventChkInf(EVENTCHKINF_TALON_WOKEN_IN_CASTLE);
|
||||||
Flags_SetEventChkInf(EVENTCHKINF_TALON_RETURNED_FROM_CASTLE);
|
Flags_SetEventChkInf(EVENTCHKINF_TALON_RETURNED_FROM_CASTLE);
|
||||||
|
|
||||||
// Set "Got Zelda's Letter" flag. Also ensures Saria is back at SFM.
|
// Set "Got Zelda's Letter" flag. Also ensures Saria is back at SFM.
|
||||||
Flags_SetEventChkInf(EVENTCHKINF_OBTAINED_ZELDAS_LETTER);
|
Flags_SetEventChkInf(EVENTCHKINF_OBTAINED_ZELDAS_LETTER);
|
||||||
|
Flags_SetRandomizerInf(RAND_INF_ZELDAS_LETTER);
|
||||||
Flags_SetRandomizerInf(RAND_INF_CHILD_TRADES_HAS_LETTER_ZELDA);
|
Flags_SetRandomizerInf(RAND_INF_CHILD_TRADES_HAS_LETTER_ZELDA);
|
||||||
|
|
||||||
// Got item from Impa.
|
// Got item from Impa.
|
||||||
|
@ -321,7 +323,6 @@ extern "C" void Randomizer_InitSaveFile() {
|
||||||
// Set this at the end to ensure we always start with the letter.
|
// Set this at the end to ensure we always start with the letter.
|
||||||
// This is for the off chance, we got the Weird Egg from Impa (which should never happen).
|
// This is for the off chance, we got the Weird Egg from Impa (which should never happen).
|
||||||
INV_CONTENT(ITEM_LETTER_ZELDA) = ITEM_LETTER_ZELDA;
|
INV_CONTENT(ITEM_LETTER_ZELDA) = ITEM_LETTER_ZELDA;
|
||||||
Flags_SetRandomizerInf(RAND_INF_CHILD_TRADES_HAS_LETTER_ZELDA);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) && startingAge == RO_AGE_ADULT) {
|
if (Randomizer_GetSettingValue(RSK_SHUFFLE_MASTER_SWORD) && startingAge == RO_AGE_ADULT) {
|
||||||
|
|
|
@ -459,10 +459,16 @@ void SaveManager::LoadRandomizerVersion3() {
|
||||||
});
|
});
|
||||||
|
|
||||||
randoContext->GetTrials()->SkipAll();
|
randoContext->GetTrials()->SkipAll();
|
||||||
SaveManager::Instance->LoadArray("requiredTrials", randoContext->GetOption(RSK_TRIAL_COUNT).Get() + 1, [&](size_t i) {
|
SaveManager::Instance->LoadArray("requiredTrials", randoContext->GetOption(RSK_TRIAL_COUNT).Get(), [&](size_t i) {
|
||||||
size_t trialId;
|
size_t trialId;
|
||||||
SaveManager::Instance->LoadData("", trialId);
|
SaveManager::Instance->LoadData("", trialId);
|
||||||
randoContext->GetTrial(trialId)->SetAsRequired();
|
randoContext->GetTrial(trialId)->SetAsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
SaveManager::Instance->LoadArray("trickOptions", RT_MAX, [&](size_t i) {
|
||||||
|
uint8_t value = 0;
|
||||||
|
SaveManager::Instance->LoadData("", value);
|
||||||
|
randoContext->GetTrickOption(RandomizerTrick(i)).Set(value);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -596,6 +602,10 @@ void SaveManager::SaveRandomizer(SaveContext* saveContext, int sectionID, bool f
|
||||||
SaveManager::Instance->SaveData("", i);
|
SaveManager::Instance->SaveData("", i);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
SaveManager::Instance->SaveArray("trickOptions", RT_MAX, [&](size_t i) {
|
||||||
|
SaveManager::Instance->SaveData("", randoContext->GetTrickOption(RandomizerTrick(i)).Get());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init() here is an extension of InitSram, and thus not truly an initializer for SaveManager itself. don't put any class initialization stuff here
|
// Init() here is an extension of InitSram, and thus not truly an initializer for SaveManager itself. don't put any class initialization stuff here
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue