Merge branch 'develop' into ItemName

This commit is contained in:
Pepper0ni 2025-04-02 12:40:13 +01:00
commit f7c358dff8
25 changed files with 453 additions and 68 deletions

View file

@ -10,6 +10,8 @@ set(CVAR_PREFIX_TRACKER "gTrackers")
set(CVAR_PREFIX_DEVELOPER_TOOLS "gDeveloperTools") set(CVAR_PREFIX_DEVELOPER_TOOLS "gDeveloperTools")
set(CVAR_PREFIX_GENERAL "gGeneral") set(CVAR_PREFIX_GENERAL "gGeneral")
set(CVAR_PREFIX_REMOTE "gRemote") set(CVAR_PREFIX_REMOTE "gRemote")
set(CVAR_PREFIX_GAMEPLAY_STATS "gGameplayStats")
set(CVAR_PREFIX_TIME_DISPLAY "gTimeDisplay")
add_compile_definitions( add_compile_definitions(
CVAR_PREFIX_RANDOMIZER_ENHANCEMENT="${CVAR_PREFIX_RANDOMIZER_ENHANCEMENT}" CVAR_PREFIX_RANDOMIZER_ENHANCEMENT="${CVAR_PREFIX_RANDOMIZER_ENHANCEMENT}"
CVAR_PREFIX_RANDOMIZER_SETTING="${CVAR_PREFIX_RANDOMIZER_SETTING}" CVAR_PREFIX_RANDOMIZER_SETTING="${CVAR_PREFIX_RANDOMIZER_SETTING}"
@ -23,4 +25,6 @@ add_compile_definitions(
CVAR_PREFIX_DEVELOPER_TOOLS="${CVAR_PREFIX_DEVELOPER_TOOLS}" CVAR_PREFIX_DEVELOPER_TOOLS="${CVAR_PREFIX_DEVELOPER_TOOLS}"
CVAR_PREFIX_GENERAL="${CVAR_PREFIX_GENERAL}" CVAR_PREFIX_GENERAL="${CVAR_PREFIX_GENERAL}"
CVAR_PREFIX_REMOTE="${CVAR_PREFIX_REMOTE}" CVAR_PREFIX_REMOTE="${CVAR_PREFIX_REMOTE}"
CVAR_PREFIX_GAMEPLAY_STATS="${CVAR_PREFIX_GAMEPLAY_STATS}"
CVAR_PREFIX_TIME_DISPLAY="${CVAR_PREFIX_TIME_DISPLAY}"
) )

View file

@ -37,10 +37,10 @@ const static std::vector<std::pair<std::string, const char*>> digitList = {
}; };
const std::vector<TimeObject> timeDisplayList = { const std::vector<TimeObject> timeDisplayList = {
{ DISPLAY_IN_GAME_TIMER, "Display Gameplay Timer", CVAR_ENHANCEMENT("TimeDisplay.Timers.InGameTimer") }, { DISPLAY_IN_GAME_TIMER, "Display Gameplay Timer", CVAR_TIME_DISPLAY("Timers.InGameTimer") },
{ DISPLAY_TIME_OF_DAY, "Display Time of Day", CVAR_ENHANCEMENT("TimeDisplay.Timers.TimeofDay") }, { DISPLAY_TIME_OF_DAY, "Display Time of Day", CVAR_TIME_DISPLAY("Timers.TimeofDay") },
{ DISPLAY_CONDITIONAL_TIMER, "Display Conditional Timer", CVAR_ENHANCEMENT("TimeDisplay.Timers.HotWater") }, { DISPLAY_CONDITIONAL_TIMER, "Display Conditional Timer", CVAR_TIME_DISPLAY("Timers.HotWater") },
{ DISPLAY_NAVI_TIMER, "Display Navi Timer", CVAR_ENHANCEMENT("TimeDisplay.Timers.NaviTimer") } { DISPLAY_NAVI_TIMER, "Display Navi Timer", CVAR_TIME_DISPLAY("Timers.NaviTimer") }
}; };
static std::vector<TimeObject> activeTimers; static std::vector<TimeObject> activeTimers;
@ -227,11 +227,11 @@ void TimeDisplayWindow::Draw() {
} }
void TimeDisplayInitSettings() { void TimeDisplayInitSettings() {
fontScale = CVarGetFloat(CVAR_ENHANCEMENT("TimeDisplay.FontScale"), 1.0f); fontScale = CVarGetFloat(CVAR_TIME_DISPLAY("FontScale"), 1.0f);
if (fontScale < 1.0f) { if (fontScale < 1.0f) {
fontScale = 1.0f; fontScale = 1.0f;
} }
if (CVarGetInteger(CVAR_ENHANCEMENT("TimeDisplay.ShowWindowBG"), 0)) { if (CVarGetInteger(CVAR_TIME_DISPLAY("ShowWindowBG"), 0)) {
windowBG = ImVec4(0, 0, 0, 0); windowBG = ImVec4(0, 0, 0, 0);
} else { } else {
windowBG = ImVec4(0, 0, 0, 0.5f); windowBG = ImVec4(0, 0, 0, 0.5f);

View file

@ -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" },

View file

@ -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 = {};
} }

View file

@ -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 = {};

View file

@ -391,7 +391,7 @@ void GameplayStatsRow(const char* label, const std::string& value, ImVec4 color
} }
bool compareTimestampInfoByTime(const TimestampInfo& a, const TimestampInfo& b) { bool compareTimestampInfoByTime(const TimestampInfo& a, const TimestampInfo& b) {
return CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.ReverseTimestamps"), 0) ? a.time > b.time : a.time < b.time; return CVarGetInteger(CVAR_GAMEPLAY_STATS("ReverseTimestamps"), 0) ? a.time > b.time : a.time < b.time;
} }
const char* ResolveSceneID(int sceneID, int roomID){ const char* ResolveSceneID(int sceneID, int roomID){
@ -452,13 +452,13 @@ void DrawGameplayStatsHeader() {
} else { } else {
GameplayStatsRow("Total Game Time:", formatTimestampGameplayStat(GAMEPLAYSTAT_TOTAL_TIME), gSaveContext.ship.stats.gameComplete ? COLOR_GREEN : COLOR_WHITE); GameplayStatsRow("Total Game Time:", formatTimestampGameplayStat(GAMEPLAYSTAT_TOTAL_TIME), gSaveContext.ship.stats.gameComplete ? COLOR_GREEN : COLOR_WHITE);
} }
if (CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.ShowAdditionalTimers"), 0)) { // !Only display total game time if (CVarGetInteger(CVAR_GAMEPLAY_STATS("ShowAdditionalTimers"), 0)) { // !Only display total game time
GameplayStatsRow("Gameplay Time:", formatTimestampGameplayStat(gSaveContext.ship.stats.playTimer / 2), COLOR_GREY); GameplayStatsRow("Gameplay Time:", formatTimestampGameplayStat(gSaveContext.ship.stats.playTimer / 2), COLOR_GREY);
GameplayStatsRow("Pause Menu Time:", formatTimestampGameplayStat(gSaveContext.ship.stats.pauseTimer / 3), COLOR_GREY); GameplayStatsRow("Pause Menu Time:", formatTimestampGameplayStat(gSaveContext.ship.stats.pauseTimer / 3), COLOR_GREY);
GameplayStatsRow("Time in scene:", formatTimestampGameplayStat(gSaveContext.ship.stats.sceneTimer / 2), COLOR_LIGHT_BLUE); GameplayStatsRow("Time in scene:", formatTimestampGameplayStat(gSaveContext.ship.stats.sceneTimer / 2), COLOR_LIGHT_BLUE);
GameplayStatsRow("Time in room:", formatTimestampGameplayStat(gSaveContext.ship.stats.roomTimer / 2), COLOR_LIGHT_BLUE); GameplayStatsRow("Time in room:", formatTimestampGameplayStat(gSaveContext.ship.stats.roomTimer / 2), COLOR_LIGHT_BLUE);
} }
if (gPlayState != NULL && CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.ShowDebugInfo"), 0)) { // && display debug info if (gPlayState != NULL && CVarGetInteger(CVAR_GAMEPLAY_STATS("ShowDebugInfo"), 0)) { // && display debug info
GameplayStatsRow("play->sceneNum:", formatHexGameplayStat(gPlayState->sceneNum), COLOR_YELLOW); GameplayStatsRow("play->sceneNum:", formatHexGameplayStat(gPlayState->sceneNum), COLOR_YELLOW);
GameplayStatsRow("gSaveContext.entranceIndex:", formatHexGameplayStat(gSaveContext.entranceIndex), COLOR_YELLOW); GameplayStatsRow("gSaveContext.entranceIndex:", formatHexGameplayStat(gSaveContext.entranceIndex), COLOR_YELLOW);
GameplayStatsRow("gSaveContext.cutsceneIndex:", formatHexOnlyGameplayStat(gSaveContext.cutsceneIndex), COLOR_YELLOW); GameplayStatsRow("gSaveContext.cutsceneIndex:", formatHexOnlyGameplayStat(gSaveContext.cutsceneIndex), COLOR_YELLOW);
@ -576,13 +576,13 @@ void DrawGameplayStatsBreakdownTab() {
for (int i = 0; i < gSaveContext.ship.stats.tsIdx; i++) { for (int i = 0; i < gSaveContext.ship.stats.tsIdx; i++) {
std::string sceneName = ResolveSceneID(gSaveContext.ship.stats.sceneTimestamps[i].scene, gSaveContext.ship.stats.sceneTimestamps[i].room); std::string sceneName = ResolveSceneID(gSaveContext.ship.stats.sceneTimestamps[i].scene, gSaveContext.ship.stats.sceneTimestamps[i].room);
std::string name; std::string name;
if (CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.RoomBreakdown"), 0) && gSaveContext.ship.stats.sceneTimestamps[i].scene != SCENE_GROTTOS) { if (CVarGetInteger(CVAR_GAMEPLAY_STATS("RoomBreakdown"), 0) && gSaveContext.ship.stats.sceneTimestamps[i].scene != SCENE_GROTTOS) {
name = fmt::format("{:s} Room {:d}", sceneName, gSaveContext.ship.stats.sceneTimestamps[i].room); name = fmt::format("{:s} Room {:d}", sceneName, gSaveContext.ship.stats.sceneTimestamps[i].room);
} else { } else {
name = sceneName; name = sceneName;
} }
strcpy(sceneTimestampDisplay[i].name, name.c_str()); strcpy(sceneTimestampDisplay[i].name, name.c_str());
sceneTimestampDisplay[i].time = CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.RoomBreakdown"), 0) ? sceneTimestampDisplay[i].time = CVarGetInteger(CVAR_GAMEPLAY_STATS("RoomBreakdown"), 0) ?
gSaveContext.ship.stats.sceneTimestamps[i].roomTime : gSaveContext.ship.stats.sceneTimestamps[i].sceneTime; gSaveContext.ship.stats.sceneTimestamps[i].roomTime : gSaveContext.ship.stats.sceneTimestamps[i].sceneTime;
sceneTimestampDisplay[i].color = COLOR_GREY; sceneTimestampDisplay[i].color = COLOR_GREY;
sceneTimestampDisplay[i].isRoom = gSaveContext.ship.stats.sceneTimestamps[i].isRoom; sceneTimestampDisplay[i].isRoom = gSaveContext.ship.stats.sceneTimestamps[i].isRoom;
@ -593,13 +593,13 @@ void DrawGameplayStatsBreakdownTab() {
ImGui::TableSetupColumn("stat", ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn("stat", ImGuiTableColumnFlags_WidthStretch);
for (int i = 0; i < gSaveContext.ship.stats.tsIdx; i++) { for (int i = 0; i < gSaveContext.ship.stats.tsIdx; i++) {
TimestampInfo tsInfo = sceneTimestampDisplay[i]; TimestampInfo tsInfo = sceneTimestampDisplay[i];
bool canShow = !tsInfo.isRoom || CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.RoomBreakdown"), 0); bool canShow = !tsInfo.isRoom || CVarGetInteger(CVAR_GAMEPLAY_STATS("RoomBreakdown"), 0);
if (tsInfo.time > 0 && strnlen(tsInfo.name, 40) > 1 && canShow) { if (tsInfo.time > 0 && strnlen(tsInfo.name, 40) > 1 && canShow) {
GameplayStatsRow(tsInfo.name, formatTimestampGameplayStat(tsInfo.time), tsInfo.color); GameplayStatsRow(tsInfo.name, formatTimestampGameplayStat(tsInfo.time), tsInfo.color);
} }
} }
std::string toPass; std::string toPass;
if (CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.RoomBreakdown"), 0) && gSaveContext.ship.stats.sceneNum != SCENE_GROTTOS) { if (CVarGetInteger(CVAR_GAMEPLAY_STATS("RoomBreakdown"), 0) && gSaveContext.ship.stats.sceneNum != SCENE_GROTTOS) {
toPass = fmt::format("{:s} Room {:d}", ResolveSceneID(gSaveContext.ship.stats.sceneNum, gSaveContext.ship.stats.roomNum), gSaveContext.ship.stats.roomNum); toPass = fmt::format("{:s} Room {:d}", ResolveSceneID(gSaveContext.ship.stats.sceneNum, gSaveContext.ship.stats.roomNum), gSaveContext.ship.stats.roomNum);
} else { } else {
toPass = ResolveSceneID(gSaveContext.ship.stats.sceneNum, gSaveContext.ship.stats.roomNum); toPass = ResolveSceneID(gSaveContext.ship.stats.sceneNum, gSaveContext.ship.stats.roomNum);
@ -610,27 +610,27 @@ void DrawGameplayStatsBreakdownTab() {
} }
void DrawGameplayStatsOptionsTab() { void DrawGameplayStatsOptionsTab() {
UIWidgets::CVarCheckbox("Show in-game total timer", CVAR_ENHANCEMENT("GameplayStats.ShowIngameTimer"), UIWidgets::CVarCheckbox("Show in-game total timer", CVAR_GAMEPLAY_STATS("ShowIngameTimer"),
UIWidgets::CheckboxOptions() UIWidgets::CheckboxOptions()
.Tooltip("Keep track of the timer as an in-game HUD element. The position of the " .Tooltip("Keep track of the timer as an in-game HUD element. The position of the "
"timer can be changed in the Cosmetics Editor.") "timer can be changed in the Cosmetics Editor.")
.Color(THEME_COLOR)); .Color(THEME_COLOR));
UIWidgets::CVarCheckbox("Show latest timestamps on top", CVAR_ENHANCEMENT("GameplayStats.ReverseTimestamps"), UIWidgets::CVarCheckbox("Show latest timestamps on top", CVAR_GAMEPLAY_STATS("ReverseTimestamps"),
UIWidgets::CheckboxOptions().Color(THEME_COLOR)); UIWidgets::CheckboxOptions().Color(THEME_COLOR));
UIWidgets::CVarCheckbox("Room Breakdown", CVAR_ENHANCEMENT("GameplayStats.RoomBreakdown"), UIWidgets::CVarCheckbox("Room Breakdown", CVAR_GAMEPLAY_STATS("RoomBreakdown"),
UIWidgets::CheckboxOptions() UIWidgets::CheckboxOptions()
.Tooltip("Allows a more in-depth perspective of time spent in a certain map.") .Tooltip("Allows a more in-depth perspective of time spent in a certain map.")
.Color(THEME_COLOR)); .Color(THEME_COLOR));
UIWidgets::CVarCheckbox("RTA Timing on new files", CVAR_ENHANCEMENT("GameplayStats.RTATiming"), UIWidgets::CVarCheckbox("RTA Timing on new files", CVAR_GAMEPLAY_STATS("RTATiming"),
UIWidgets::CheckboxOptions() UIWidgets::CheckboxOptions()
.Tooltip("Timestamps are relative to starting timestamp rather than in game time, " .Tooltip("Timestamps are relative to starting timestamp rather than in game time, "
"usually necessary for races/speedruns.\n\n" "usually necessary for races/speedruns.\n\n"
"Starting timestamp is on first non-C-up input after intro cutscene.\n\n" "Starting timestamp is on first non-C-up input after intro cutscene.\n\n"
"NOTE: THIS NEEDS TO BE SET BEFORE CREATING A FILE TO TAKE EFFECT") "NOTE: THIS NEEDS TO BE SET BEFORE CREATING A FILE TO TAKE EFFECT")
.Color(THEME_COLOR)); .Color(THEME_COLOR));
UIWidgets::CVarCheckbox("Show additional detail timers", CVAR_ENHANCEMENT("GameplayStats.ShowAdditionalTimers"), UIWidgets::CVarCheckbox("Show additional detail timers", CVAR_GAMEPLAY_STATS("ShowAdditionalTimers"),
UIWidgets::CheckboxOptions().Color(THEME_COLOR)); UIWidgets::CheckboxOptions().Color(THEME_COLOR));
UIWidgets::CVarCheckbox("Show Debug Info", CVAR_ENHANCEMENT("GameplayStats.ShowDebugInfo"), UIWidgets::CVarCheckbox("Show Debug Info", CVAR_GAMEPLAY_STATS("ShowDebugInfo"),
UIWidgets::CheckboxOptions().Color(THEME_COLOR)); UIWidgets::CheckboxOptions().Color(THEME_COLOR));
} }
@ -671,7 +671,7 @@ void InitStats(bool isDebug) {
for (int dungeon = 0; dungeon < ARRAY_COUNT(gSaveContext.ship.stats.dungeonKeys); dungeon++) { for (int dungeon = 0; dungeon < ARRAY_COUNT(gSaveContext.ship.stats.dungeonKeys); dungeon++) {
gSaveContext.ship.stats.dungeonKeys[dungeon] = isDebug ? 8 : 0; gSaveContext.ship.stats.dungeonKeys[dungeon] = isDebug ? 8 : 0;
} }
gSaveContext.ship.stats.rtaTiming = CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.RTATiming"), 0); gSaveContext.ship.stats.rtaTiming = CVarGetInteger(CVAR_GAMEPLAY_STATS("RTATiming"), 0);
gSaveContext.ship.stats.fileCreatedAt = 0; gSaveContext.ship.stats.fileCreatedAt = 0;
gSaveContext.ship.stats.playTimer = 0; gSaveContext.ship.stats.playTimer = 0;
gSaveContext.ship.stats.pauseTimer = 0; gSaveContext.ship.stats.pauseTimer = 0;

View file

@ -27,7 +27,7 @@ extern "C" {
: gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_TRIFORCE_COMPLETED])) \ : gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_TRIFORCE_COMPLETED])) \
:\ :\
(gSaveContext.ship.stats.playTimer / 2 + gSaveContext.ship.stats.pauseTimer / 3)) (gSaveContext.ship.stats.playTimer / 2 + gSaveContext.ship.stats.pauseTimer / 3))
#define CURRENT_MODE_TIMER (CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.RoomBreakdown"), 0) ?\ #define CURRENT_MODE_TIMER (CVarGetInteger(CVAR_GAMEPLAY_STATS("RoomBreakdown"), 0) ?\
gSaveContext.ship.stats.roomTimer :\ gSaveContext.ship.stats.roomTimer :\
gSaveContext.ship.stats.sceneTimer) gSaveContext.ship.stats.sceneTimer)

View file

@ -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;
} }
} }

View file

@ -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();

View file

@ -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;

View file

@ -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_;
} }
} }

View file

@ -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

View file

@ -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) {

View file

@ -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;

View file

@ -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,97 @@ namespace Rando {
} }
} }
// Get the swch bit positions for the dungeon
const std::vector<uint8_t>& GetDungeonSmallKeyDoors(SceneID sceneId) {
static const std::vector<uint8_t> emptyVector;
auto dungeonInfo = Rando::Context::GetInstance()->GetDungeons()->GetDungeonFromScene(sceneId);
if (dungeonInfo == nullptr) {
return emptyVector;
}
bool masterQuest = dungeonInfo->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 +2269,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;

View file

@ -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;

View file

@ -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();
@ -1718,7 +1824,7 @@ void DrawLocation(RandomizerCheck rc) {
if (conditionStr != "true") { if (conditionStr != "true") {
UIWidgets::Tooltip(conditionStr.c_str()); UIWidgets::Tooltip(conditionStr.c_str());
} }
return; break;
} }
} }
} }
@ -1796,6 +1902,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;
@ -1850,7 +2005,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"),
@ -1860,6 +2015,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();

View file

@ -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

View file

@ -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) {

View file

@ -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

View file

@ -1775,7 +1775,7 @@ void SohMenu::AddMenuEnhancements() {
.WindowName("Additional Timers") .WindowName("Additional Timers")
.Options(WindowButtonOptions().Tooltip("Enables the separate Additional Timers Window.")); .Options(WindowButtonOptions().Tooltip("Enables the separate Additional Timers Window."));
AddWidget(path, "Font Scale: %.2fx", WIDGET_CVAR_SLIDER_FLOAT) AddWidget(path, "Font Scale: %.2fx", WIDGET_CVAR_SLIDER_FLOAT)
.CVar(CVAR_ENHANCEMENT("TimeDisplay.FontScale")) .CVar(CVAR_TIME_DISPLAY("FontScale"))
.Callback([](WidgetInfo& info) { .Callback([](WidgetInfo& info) {
TimeDisplayInitSettings(); TimeDisplayInitSettings();
}) })
@ -1786,7 +1786,7 @@ void SohMenu::AddMenuEnhancements() {
.Format("%.2fx") .Format("%.2fx")
); );
AddWidget(path, "Hide Background", WIDGET_CVAR_CHECKBOX) AddWidget(path, "Hide Background", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENHANCEMENT("TimeDisplay.ShowWindowBG")) .CVar(CVAR_TIME_DISPLAY("ShowWindowBG"))
.Callback([](WidgetInfo& info) { .Callback([](WidgetInfo& info) {
TimeDisplayInitSettings(); TimeDisplayInitSettings();
}); });

View file

@ -299,12 +299,8 @@ namespace SOH {
{ MigrationAction::Rename, "gUniformLR", "gEnhancements.FixMenuLR" }, { MigrationAction::Rename, "gUniformLR", "gEnhancements.FixMenuLR" },
{ MigrationAction::Rename, "gVisualAgony", "gEnhancements.VisualAgony" }, { MigrationAction::Rename, "gVisualAgony", "gEnhancements.VisualAgony" },
{ MigrationAction::Rename, "gVoidDamageMul", "gEnhancements.VoidDamageMult" }, { MigrationAction::Rename, "gVoidDamageMul", "gEnhancements.VoidDamageMult" },
{ MigrationAction::Rename, "gGameplayStats.ShowAdditionalTimers", "gEnhancements.GameplayStats.ShowAdditionalTimers" }, { MigrationAction::Rename, "gGameplayStats.ShowIngameTimer", "gGameplayStats.ShowInGameTimer" },
{ MigrationAction::Rename, "gGameplayStats.ShowDebugInfo", "gEnhancements.GameplayStats.ShowDebugInfo" }, { MigrationAction::Rename, "gGameplayStats.TimestampsReverse", "gGameplayStats.ReverseTimestamps" },
{ MigrationAction::Rename, "gGameplayStats.RoomBreakdown", "gEnhancements.GameplayStats.RoomBreakdown" },
{ MigrationAction::Rename, "gGameplayStats.ShowIngameTimer", "gEnhancements.GameplayStats.ShowInGameTimer" },
{ MigrationAction::Rename, "gGameplayStats.TimestampsReverse", "gEnhancements.GameplayStats.ReverseTimestamps" },
{ MigrationAction::Rename, "gGameplayStats.RTATiming", "gEnhancements.GameplayStats.RTATiming" },
{ MigrationAction::Rename, "gMirroredWorld", "gEnhancements.MirroredWorld" }, { MigrationAction::Rename, "gMirroredWorld", "gEnhancements.MirroredWorld" },
{ MigrationAction::Rename, "gBetaQuestWorld", "gCheats.BetaQuestWorld" }, { MigrationAction::Rename, "gBetaQuestWorld", "gCheats.BetaQuestWorld" },
{ MigrationAction::Rename, "gBombTimerMultiplier", "gCheats.BombTimerMultiplier" }, { MigrationAction::Rename, "gBombTimerMultiplier", "gCheats.BombTimerMultiplier" },

View file

@ -14,4 +14,6 @@
#define CVAR_GENERAL(var) CVAR_PREFIX_GENERAL "." var #define CVAR_GENERAL(var) CVAR_PREFIX_GENERAL "." var
#define CVAR_REMOTE(var) CVAR_PREFIX_REMOTE "." var #define CVAR_REMOTE(var) CVAR_PREFIX_REMOTE "." var
#define CVAR_REMOTE_CROWD_CONTROL(var) CVAR_REMOTE("CrowdControl." var) #define CVAR_REMOTE_CROWD_CONTROL(var) CVAR_REMOTE("CrowdControl." var)
#define CVAR_REMOTE_SAIL(var) CVAR_REMOTE("Sail." var) #define CVAR_REMOTE_SAIL(var) CVAR_REMOTE("Sail." var)
#define CVAR_GAMEPLAY_STATS(var) CVAR_PREFIX_GAMEPLAY_STATS "." var
#define CVAR_TIME_DISPLAY(var) CVAR_PREFIX_TIME_DISPLAY "." var

View file

@ -6123,7 +6123,7 @@ void Interface_DrawTotalGameplayTimer(PlayState* play) {
// Draw timer based on the Gameplay Stats total time. // Draw timer based on the Gameplay Stats total time.
if ((IS_BOSS_RUSH && gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_TIMER] == BR_CHOICE_TIMER_YES) || if ((IS_BOSS_RUSH && gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_TIMER] == BR_CHOICE_TIMER_YES) ||
(CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.ShowIngameTimer"), 0) && gSaveContext.fileNum >= 0 && gSaveContext.fileNum <= 2)) { (CVarGetInteger(CVAR_GAMEPLAY_STATS("ShowIngameTimer"), 0) && gSaveContext.fileNum >= 0 && gSaveContext.fileNum <= 2)) {
s32 X_Margins_Timer = 0; s32 X_Margins_Timer = 0;
if (CVarGetInteger(CVAR_COSMETIC("HUD.IGT.UseMargins"), 0) != 0) { if (CVarGetInteger(CVAR_COSMETIC("HUD.IGT.UseMargins"), 0) != 0) {

View file

@ -317,7 +317,8 @@ void KaleidoScope_HandleItemCycleExtras(PlayState* play, u8 slot, bool canCycle,
bool CanMaskSelect() { bool CanMaskSelect() {
if (IS_RANDO) { if (IS_RANDO) {
return CVarGetInteger(CVAR_ENHANCEMENT("MaskSelect"), 0) /* || Randomizer_GetSettingValue(RSK_SHUFFLE_CHILD_TRADE) */; return CVarGetInteger(CVAR_ENHANCEMENT("MaskSelect"), 0)
&& Flags_GetRandomizerInf(RAND_INF_ZELDAS_LETTER);/* || Randomizer_GetSettingValue(RSK_SHUFFLE_CHILD_TRADE) */
} }
// only allow mask select when: // only allow mask select when: