From 3b1eaae87f93fa89bcfecd3fdc6363a125e3dc40 Mon Sep 17 00:00:00 2001 From: Caladius Date: Sun, 1 Feb 2026 19:39:25 -0500 Subject: [PATCH 1/2] Split up Bowser final stage --- include/macro_presets.h | 2 +- src/port/Rando/GhostshipMenuRando.cpp | 6 ++- src/port/Rando/Logic/GeneratePools.cpp | 5 +++ src/port/Rando/StaticData/Entrances.cpp | 50 ++++++++++++------------- src/port/Rando/StaticData/Options.cpp | 19 +++++----- src/port/Rando/Types.h | 2 + 6 files changed, 48 insertions(+), 36 deletions(-) diff --git a/include/macro_presets.h b/include/macro_presets.h index 9d390b5e4..38b1eb69b 100644 --- a/include/macro_presets.h +++ b/include/macro_presets.h @@ -11,7 +11,7 @@ struct MacroPreset { /*0x06*/ s16 param; }; -extern struct MacroPreset MacroObjectPresets[] = { +struct MacroPreset MacroObjectPresets[] = { {bhvYellowCoin, MODEL_YELLOW_COIN, 0}, {bhvOneCoin, MODEL_YELLOW_COIN, 0}, {bhvMovingBlueCoin, MODEL_BLUE_COIN, 0}, diff --git a/src/port/Rando/GhostshipMenuRando.cpp b/src/port/Rando/GhostshipMenuRando.cpp index 5e29456f8..11484910f 100644 --- a/src/port/Rando/GhostshipMenuRando.cpp +++ b/src/port/Rando/GhostshipMenuRando.cpp @@ -128,7 +128,11 @@ void GhostshipMenu::AddMenuRando() { AddWidget(path, "Shuffle Bowser Levels", WIDGET_CVAR_CHECKBOX) .CVar(Rando::StaticData::Options[RO_SHUFFLE_ENTRANCES_BOWSER].cvar) .RaceDisable(false) - .Options(CheckboxOptions().Tooltip("Shuffles Bowser Entrances.")); + .Options(CheckboxOptions().Tooltip("Shuffles Bowser in the Dark World and Fire Sea Entrances.")); + AddWidget(path, "Shuffle Bowser in the Sky Level", WIDGET_CVAR_CHECKBOX) + .CVar(Rando::StaticData::Options[RO_SHUFFLE_ENTRANCES_BOWSER_FINAL].cvar) + .RaceDisable(false) + .Options(CheckboxOptions().Tooltip("Shuffles Bowser in the Sky Entrance.")); AddWidget(path, "Shuffle Cap Unlock Levels", WIDGET_CVAR_CHECKBOX) .CVar(Rando::StaticData::Options[RO_SHUFFLE_ENTRANCES_CAP].cvar) .RaceDisable(false) diff --git a/src/port/Rando/Logic/GeneratePools.cpp b/src/port/Rando/Logic/GeneratePools.cpp index 9c2885bf8..b7f8cc113 100644 --- a/src/port/Rando/Logic/GeneratePools.cpp +++ b/src/port/Rando/Logic/GeneratePools.cpp @@ -146,6 +146,11 @@ void GenerateShuffleList() { continue; } + if (randoStaticEntrance.randoEntranceType == RETYPE_BOWSER_FINAL && + CVarGetInteger(Rando::StaticData::Options[RO_SHUFFLE_ENTRANCES_BOWSER_FINAL].cvar, 0) == RO_GENERIC_OFF) { + continue; + } + if (randoStaticEntrance.randoEntranceType == RETYPE_CAP && CVarGetInteger(Rando::StaticData::Options[RO_SHUFFLE_ENTRANCES_CAP].cvar, 0) == RO_GENERIC_OFF) { continue; diff --git a/src/port/Rando/StaticData/Entrances.cpp b/src/port/Rando/StaticData/Entrances.cpp index 06d6208bd..dd4877be5 100644 --- a/src/port/Rando/StaticData/Entrances.cpp +++ b/src/port/Rando/StaticData/Entrances.cpp @@ -22,31 +22,31 @@ namespace StaticData { // clang-format off std::map Entrances = { - RE(RE_UNKNOWN, LEVEL_UNKNOWN_1, RETYPE_NONE, WARP_NODE_00, REAREA_NONE), - RE(RE_BBH, LEVEL_BBH, RETYPE_PAINTING, WARP_NODE_0B, REAREA_01), - RE(RE_BITDW, LEVEL_BITDW, RETYPE_BOWSER, WARP_NODE_25, REAREA_01), - RE(RE_BITFS, LEVEL_BITFS, RETYPE_BOWSER, WARP_NODE_68, REAREA_03), - RE(RE_BITS, LEVEL_BITS, RETYPE_BOWSER, WARP_NODE_6B, REAREA_02), - RE(RE_BOB, LEVEL_BOB, RETYPE_PAINTING, WARP_NODE_64, REAREA_01), - RE(RE_CCM, LEVEL_CCM, RETYPE_PAINTING, WARP_NODE_65, REAREA_01), - RE(RE_COTMC, LEVEL_COTMC, RETYPE_CAP, WARP_NODE_66, REAREA_03), - RE(RE_DDD, LEVEL_DDD, RETYPE_PAINTING, WARP_NODE_67, REAREA_03), - RE(RE_HMC, LEVEL_HMC, RETYPE_PAINTING, WARP_NODE_66, REAREA_03), - RE(RE_JRB, LEVEL_JRB, RETYPE_PAINTING, WARP_NODE_67, REAREA_01), - RE(RE_LLL, LEVEL_LLL, RETYPE_PAINTING, WARP_NODE_64, REAREA_03), - RE(RE_PSS, LEVEL_PSS, RETYPE_SECRET, WARP_NODE_23, REAREA_01), - RE(RE_RR, LEVEL_RR, RETYPE_PAINTING, WARP_NODE_6C, REAREA_02), - RE(RE_SA, LEVEL_SA, RETYPE_SECRET, WARP_NODE_28, REAREA_01), - RE(RE_SL, LEVEL_SL, RETYPE_PAINTING, WARP_NODE_68, REAREA_02), - RE(RE_SSL, LEVEL_SSL, RETYPE_PAINTING, WARP_NODE_65, REAREA_03), - RE(RE_THI, LEVEL_THI, RETYPE_PAINTING, WARP_NODE_69, REAREA_02), - RE(RE_TOTWC, LEVEL_TOTWC, RETYPE_CAP, WARP_NODE_23, REAREA_01), - RE(RE_TTC, LEVEL_TTC, RETYPE_PAINTING, WARP_NODE_67, REAREA_02), - RE(RE_TTM, LEVEL_TTM, RETYPE_PAINTING, WARP_NODE_66, REAREA_02), - RE(RE_VCUTM, LEVEL_VCUTM, RETYPE_CAP, WARP_NODE_06, REAREA_01), - RE(RE_WDW, LEVEL_WDW, RETYPE_PAINTING, WARP_NODE_64, REAREA_02), - RE(RE_WF, LEVEL_WF, RETYPE_PAINTING, WARP_NODE_66, REAREA_01), - RE(RE_WMOTR, LEVEL_WMOTR, RETYPE_SECRET, WARP_NODE_0A, REAREA_02), + RE(RE_UNKNOWN, LEVEL_UNKNOWN_1, RETYPE_NONE, WARP_NODE_00, REAREA_NONE), + RE(RE_BBH, LEVEL_BBH, RETYPE_PAINTING, WARP_NODE_0B, REAREA_01), + RE(RE_BITDW, LEVEL_BITDW, RETYPE_BOWSER, WARP_NODE_25, REAREA_01), + RE(RE_BITFS, LEVEL_BITFS, RETYPE_BOWSER, WARP_NODE_68, REAREA_03), + RE(RE_BITS, LEVEL_BITS, RETYPE_BOWSER_FINAL, WARP_NODE_6B, REAREA_02), + RE(RE_BOB, LEVEL_BOB, RETYPE_PAINTING, WARP_NODE_64, REAREA_01), + RE(RE_CCM, LEVEL_CCM, RETYPE_PAINTING, WARP_NODE_65, REAREA_01), + RE(RE_COTMC, LEVEL_COTMC, RETYPE_CAP, WARP_NODE_66, REAREA_03), + RE(RE_DDD, LEVEL_DDD, RETYPE_PAINTING, WARP_NODE_67, REAREA_03), + RE(RE_HMC, LEVEL_HMC, RETYPE_PAINTING, WARP_NODE_66, REAREA_03), + RE(RE_JRB, LEVEL_JRB, RETYPE_PAINTING, WARP_NODE_67, REAREA_01), + RE(RE_LLL, LEVEL_LLL, RETYPE_PAINTING, WARP_NODE_64, REAREA_03), + RE(RE_PSS, LEVEL_PSS, RETYPE_SECRET, WARP_NODE_23, REAREA_01), + RE(RE_RR, LEVEL_RR, RETYPE_PAINTING, WARP_NODE_6C, REAREA_02), + RE(RE_SA, LEVEL_SA, RETYPE_SECRET, WARP_NODE_28, REAREA_01), + RE(RE_SL, LEVEL_SL, RETYPE_PAINTING, WARP_NODE_68, REAREA_02), + RE(RE_SSL, LEVEL_SSL, RETYPE_PAINTING, WARP_NODE_65, REAREA_03), + RE(RE_THI, LEVEL_THI, RETYPE_PAINTING, WARP_NODE_69, REAREA_02), + RE(RE_TOTWC, LEVEL_TOTWC, RETYPE_CAP, WARP_NODE_23, REAREA_01), + RE(RE_TTC, LEVEL_TTC, RETYPE_PAINTING, WARP_NODE_67, REAREA_02), + RE(RE_TTM, LEVEL_TTM, RETYPE_PAINTING, WARP_NODE_66, REAREA_02), + RE(RE_VCUTM, LEVEL_VCUTM, RETYPE_CAP, WARP_NODE_06, REAREA_01), + RE(RE_WDW, LEVEL_WDW, RETYPE_PAINTING, WARP_NODE_64, REAREA_02), + RE(RE_WF, LEVEL_WF, RETYPE_PAINTING, WARP_NODE_66, REAREA_01), + RE(RE_WMOTR, LEVEL_WMOTR, RETYPE_SECRET, WARP_NODE_0A, REAREA_02), }; // clang-format on diff --git a/src/port/Rando/StaticData/Options.cpp b/src/port/Rando/StaticData/Options.cpp index 0fda09d4b..514dbb5e7 100644 --- a/src/port/Rando/StaticData/Options.cpp +++ b/src/port/Rando/StaticData/Options.cpp @@ -13,15 +13,16 @@ namespace StaticData { // clang-format off std::map Options = { - RO(RO_LOGIC, RO_LOGIC_NO_LOGIC), - RO(RO_SHUFFLE_COINS_BLUE, RO_GENERIC_OFF), - RO(RO_SHUFFLE_COINS_RED, RO_GENERIC_OFF), - RO(RO_SHUFFLE_ENTRANCES_BOWSER, RO_GENERIC_OFF), - RO(RO_SHUFFLE_ENTRANCES_CAP, RO_GENERIC_OFF), - RO(RO_SHUFFLE_ENTRANCES_PAINTING, RO_GENERIC_OFF), - RO(RO_SHUFFLE_ENTRANCES_SECRET, RO_GENERIC_OFF), - RO(RO_SHUFFLE_RED_COIN_STARS, RO_GENERIC_OFF), - RO(RO_SHUFFLE_STARS, RO_GENERIC_OFF), + RO(RO_LOGIC, RO_LOGIC_NO_LOGIC), + RO(RO_SHUFFLE_COINS_BLUE, RO_GENERIC_OFF), + RO(RO_SHUFFLE_COINS_RED, RO_GENERIC_OFF), + RO(RO_SHUFFLE_ENTRANCES_BOWSER, RO_GENERIC_OFF), + RO(RO_SHUFFLE_ENTRANCES_BOWSER_FINAL, RO_GENERIC_OFF), + RO(RO_SHUFFLE_ENTRANCES_CAP, RO_GENERIC_OFF), + RO(RO_SHUFFLE_ENTRANCES_PAINTING, RO_GENERIC_OFF), + RO(RO_SHUFFLE_ENTRANCES_SECRET, RO_GENERIC_OFF), + RO(RO_SHUFFLE_RED_COIN_STARS, RO_GENERIC_OFF), + RO(RO_SHUFFLE_STARS, RO_GENERIC_OFF), }; std::unordered_map logicOptions = { diff --git a/src/port/Rando/Types.h b/src/port/Rando/Types.h index 0cdb3a460..afb0fe7b5 100644 --- a/src/port/Rando/Types.h +++ b/src/port/Rando/Types.h @@ -381,6 +381,7 @@ typedef enum { typedef enum { RETYPE_NONE, RETYPE_BOWSER, + RETYPE_BOWSER_FINAL, RETYPE_CAP, RETYPE_PAINTING, RETYPE_SECRET, @@ -447,6 +448,7 @@ typedef enum { RO_SHUFFLE_COINS_BLUE, RO_SHUFFLE_COINS_RED, RO_SHUFFLE_ENTRANCES_BOWSER, + RO_SHUFFLE_ENTRANCES_BOWSER_FINAL, RO_SHUFFLE_ENTRANCES_CAP, RO_SHUFFLE_ENTRANCES_PAINTING, RO_SHUFFLE_ENTRANCES_SECRET, From ee86ad3602be6402f3717416bee1ba8949584ce1 Mon Sep 17 00:00:00 2001 From: Caladius Date: Mon, 2 Feb 2026 13:59:25 -0500 Subject: [PATCH 2/2] Cleanup and Allowing Spoiler Selection --- src/game/save_file.h | 10 +-- src/port/Rando/GhostshipMenuRando.cpp | 17 ++++- src/port/Rando/Logic/GeneratePools.cpp | 13 ++-- src/port/Rando/Logic/Logic.h | 1 + src/port/Rando/Logic/NoLogic.cpp | 3 - src/port/Rando/MiscBehavior/OnFileLoad.cpp | 23 +++++-- src/port/Rando/Rando.cpp | 3 +- src/port/Rando/Spoiler/File.cpp | 2 - src/port/Rando/Spoiler/Generate.cpp | 74 ++++++++++++++++------ src/port/Rando/Spoiler/RefreshOptions.cpp | 40 ++++++++++++ src/port/Rando/Spoiler/Spoiler.h | 11 +++- src/port/Rando/StaticData/Entrances.cpp | 10 ++- src/port/Rando/StaticData/StaticData.h | 1 + src/port/data/SaveConversion.h | 4 +- src/port/ui/UIWidgets.hpp | 14 ++++ 15 files changed, 178 insertions(+), 48 deletions(-) create mode 100644 src/port/Rando/Spoiler/RefreshOptions.cpp diff --git a/src/game/save_file.h b/src/game/save_file.h index 4c86d6efa..c0d5a1aaa 100644 --- a/src/game/save_file.h +++ b/src/game/save_file.h @@ -29,9 +29,11 @@ struct RandoSaveCheck { struct RandoSaveEntrance { RandoEntranceId randoEntranceId; int16_t destinationId; - RandoEntranceType randoEntranceType; - WarpNodes deathWarpId; - int16_t deathArea; +}; + +struct RandoSaveOption { + const char* randoOptionName; + int32_t randoOptionValue; }; typedef enum { @@ -42,8 +44,8 @@ typedef enum { struct RandoSaveData { struct RandoSaveCheck randoSaveChecks[RC_MAX]; struct RandoSaveEntrance randoSaveEntrances[RE_MAX]; + u32 randoSaveOptions[RO_MAX]; u32 finalSeed; - // u32 randoSaveOptions[RO_MAX]; }; struct ShipSaveData { diff --git a/src/port/Rando/GhostshipMenuRando.cpp b/src/port/Rando/GhostshipMenuRando.cpp index 11484910f..2c6b1ae90 100644 --- a/src/port/Rando/GhostshipMenuRando.cpp +++ b/src/port/Rando/GhostshipMenuRando.cpp @@ -49,6 +49,20 @@ void GhostshipMenu::AddMenuRando() { .PreFunc([](WidgetInfo& info) { info.options->Disabled(CVarGetInteger(CVAR_RANDOMIZER_SETTING("ManualSeedEntry"), 0)); }); + AddWidget(path, "Available Spoiler Logs", WIDGET_CUSTOM).CustomFunction([](WidgetInfo& info) { + ImGui::BeginDisabled(!CVarGetInteger(CVAR_RANDOMIZER_SETTING("UseExistingLog"), 0)); + if (UIWidgets::CVarCombobox("Seed", CVAR_RANDOMIZER_SETTING("SpoilerFileIndex"), Rando::Spoiler::spoilerLogs)) { + if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("SpoilerFileIndex"), 0) == 0) { + CVarSetString(CVAR_RANDOMIZER_SETTING("SpoilerFile"), ""); + } else { + CVarSetString( + "gRandoSettings.SpoilerFile", + Rando::Spoiler::spoilerLogs[CVarGetInteger(CVAR_RANDOMIZER_SETTING("SpoilerFileIndex"), 0)] + .c_str()); + } + } + ImGui::EndDisabled(); + }); AddWidget(path, "Manual Seed Entry", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_RANDOMIZER_SETTING("ManualSeedEntry")) .RaceDisable(false) @@ -76,7 +90,8 @@ void GhostshipMenu::AddMenuRando() { }); AddWidget(path, "Create Spoiler Log", WIDGET_BUTTON) .Callback([](WidgetInfo& info) { - nlohmann::json spoiler = Rando::Spoiler::GenerateFromPoolGeneration(Rando::Logic::shuffledPool); + nlohmann::json spoiler = + Rando::Spoiler::GenerateFromPoolGeneration(Rando::Logic::shuffledPool, Rando::Logic::shuffledEntrances); std::string fileName = std::to_string(spoiler["finalSeed"].get()).c_str(); fileName += ".json"; Rando::Spoiler::SaveToFile(fileName, spoiler); diff --git a/src/port/Rando/Logic/GeneratePools.cpp b/src/port/Rando/Logic/GeneratePools.cpp index b7f8cc113..2c44ce673 100644 --- a/src/port/Rando/Logic/GeneratePools.cpp +++ b/src/port/Rando/Logic/GeneratePools.cpp @@ -75,14 +75,17 @@ void InitializeSaveChecks() { void InitializeSaveEntrances() { for (auto& [randoEntranceId, randoStaticEntrance] : Rando::StaticData::Entrances) { RandoSaveEntrance randoSaveEntrance = { .randoEntranceId = randoEntranceId, - .destinationId = randoStaticEntrance.destinationId, - .randoEntranceType = randoStaticEntrance.randoEntranceType, - .deathWarpId = randoStaticEntrance.deathWarpId, - .deathArea = randoStaticEntrance.deathArea }; + .destinationId = randoStaticEntrance.destinationId }; RANDO_SAVE_ENTRANCES(selectedFileNum)[randoEntranceId] = randoSaveEntrance; } } +void InitializeSaveOptions() { + for (auto& [randoOptionId, optionData] : Rando::StaticData::Options) { + RANDO_SAVE_OPTIONS(selectedFileNum)[randoOptionId] = optionData.defaultValue; + } +} + void GenerateShuffleList() { shuffledPool.clear(); shuffledEntrances.clear(); @@ -181,7 +184,7 @@ void GenerateShuffleList() { gSaveBuffer.files[selectedFileNum][0].shipSaveData.randoSaveData.finalSeed = finalSeed; if (CVarGetInteger("gRandoSettings.GenerateLog", 0)) { - nlohmann::json spoilerLog = Rando::Spoiler::GenerateFromPoolGeneration(shuffledPool); + nlohmann::json spoilerLog = Rando::Spoiler::GenerateFromPoolGeneration(shuffledPool, shuffledEntrances); if (spoilerLog.empty()) { Notification::Emit( { .message = "Error: No Spoiler Log was created.", .messageColor = ImVec4(0.85f, 0.3f, 0, 1) }); diff --git a/src/port/Rando/Logic/Logic.h b/src/port/Rando/Logic/Logic.h index 3503ec10d..e17ee4592 100644 --- a/src/port/Rando/Logic/Logic.h +++ b/src/port/Rando/Logic/Logic.h @@ -34,6 +34,7 @@ void ShuffleRandoItems(std::vector>& shuffledIt void ShuffleRandoEntrances(std::vector& shuffledLevels, const std::string& input); void InitializeSaveChecks(); void InitializeSaveEntrances(); +void InitializeSaveOptions(); void GenerateShuffleList(); void ApplyNoLogicToSaveContext(std::vector>& initialPool, diff --git a/src/port/Rando/Logic/NoLogic.cpp b/src/port/Rando/Logic/NoLogic.cpp index b32e89023..e6cb935ce 100644 --- a/src/port/Rando/Logic/NoLogic.cpp +++ b/src/port/Rando/Logic/NoLogic.cpp @@ -41,9 +41,6 @@ void ApplyNoLogicToSaveContext(std::vector>& init RandoSaveEntrance randoSaveEntrance; randoSaveEntrance.randoEntranceId = entranceIds[e]; randoSaveEntrance.destinationId = initialLevelPool[e]; - randoSaveEntrance.randoEntranceType = - Rando::StaticData::Entrances[randoSaveEntrance.randoEntranceId].randoEntranceType; - randoSaveEntrance.deathWarpId = Rando::StaticData::Entrances[randoSaveEntrance.randoEntranceId].deathWarpId; entrancePool.push_back(randoSaveEntrance); } } diff --git a/src/port/Rando/MiscBehavior/OnFileLoad.cpp b/src/port/Rando/MiscBehavior/OnFileLoad.cpp index 14d49356c..db459a26b 100644 --- a/src/port/Rando/MiscBehavior/OnFileLoad.cpp +++ b/src/port/Rando/MiscBehavior/OnFileLoad.cpp @@ -7,7 +7,7 @@ extern "C" { extern struct SaveBuffer gSaveBuffer; } -bool SpoilerExistsForFileNum(std::string fileName) { +bool SpoilerExistsForFileName(std::string fileName) { nlohmann::json spoilerCheck = Rando::Spoiler::LoadFromFile(fileName); if (spoilerCheck.empty()) { Notification::Emit({ .message = "Error: No Spoiler Log found.", .messageColor = ImVec4(0.85f, 0.3f, 0, 1) }); @@ -22,6 +22,8 @@ void Rando::MiscBehavior::OnFileLoad() { OnGameFileLoad* ev = (OnGameFileLoad*)event; selectedFileNum = ev->fileNum - 1; + bool loadedFromSpoiler = false; + if (!CVarGetInteger("gRandoSettings.Enabled", 0)) { gSaveBuffer.files[selectedFileNum]->shipSaveData.saveType = SAVETYPE_VANILLA; Rando::Logic::shuffledPool.clear(); @@ -32,17 +34,20 @@ void Rando::MiscBehavior::OnFileLoad() { gSaveBuffer.files[selectedFileNum]->shipSaveData.saveType = SAVETYPE_RANDO; Rando::Logic::InitializeSaveChecks(); Rando::Logic::InitializeSaveEntrances(); + Rando::Logic::InitializeSaveOptions(); if (CVarGetInteger("gRandoSettings.ManualSeedEntry", 0)) { Rando::Logic::GenerateShuffleList(); } else if (CVarGetInteger("gRandoSettings.UseExistingLog", 0)) { - std::string fileName = std::to_string(selectedFileNum) + ".json"; - bool logExists = SpoilerExistsForFileNum(fileName); + std::string fileName = + Rando::Spoiler::spoilerLogs.at(CVarGetInteger("gRandoSettings.SpoilerFileIndex", 0)); + bool logExists = SpoilerExistsForFileName(fileName); if (!logExists) { Rando::Logic::GenerateShuffleList(); } else { nlohmann::json loadedSpoiler = Rando::Spoiler::LoadFromFile(fileName); - Rando::Logic::shuffledPool = Rando::Spoiler::GenerateFromSpoilerLog(loadedSpoiler); + Rando::Spoiler::GenerateFromSpoiler(loadedSpoiler); + loadedFromSpoiler = true; } } else { Rando::Logic::GenerateShuffleList(); @@ -63,14 +68,18 @@ void Rando::MiscBehavior::OnFileLoad() { RandoSaveEntrance randoSaveEntrance; randoSaveEntrance.randoEntranceId = entrance.randoEntranceId; randoSaveEntrance.destinationId = entrance.destinationId; - randoSaveEntrance.randoEntranceType = entrance.randoEntranceType; - randoSaveEntrance.deathWarpId = entrance.deathWarpId; - randoSaveEntrance.deathArea = entrance.deathArea; RANDO_SAVE_ENTRANCES(selectedFileNum)[entrance.randoEntranceId] = randoSaveEntrance; } } + if (!loadedFromSpoiler) { + for (auto& [randoOptionId, optionData] : Rando::StaticData::Options) { + RANDO_SAVE_OPTIONS(selectedFileNum) + [randoOptionId] = CVarGetInteger(optionData.cvar, optionData.defaultValue); + } + } + Notification::Emit( { .message = "Spoiler written to Save File.", .messageColor = ImVec4(0, 0.85f, 0.3f, 1) }); save_file_do_save(selectedFileNum); diff --git a/src/port/Rando/Rando.cpp b/src/port/Rando/Rando.cpp index 1a24c4cd8..c8e5a4677 100644 --- a/src/port/Rando/Rando.cpp +++ b/src/port/Rando/Rando.cpp @@ -3,6 +3,7 @@ #include "ObjectBehavior/ObjectBehavior.h" #include "MiscBehavior/MiscBehavior.h" #include "port/Rando/CheckTracker/CheckTracker.h" +#include "port/Rando/Spoiler/Spoiler.h" #include "port/ShipInit.hpp" #include @@ -18,7 +19,7 @@ void Rando::Init() { fs::create_directory(dir); } - // Rando::Spoiler::RefreshOptions(); + Rando::Spoiler::RefreshSpoilerLogs(); Rando::MiscBehavior::Init(); Rando::ObjectBehavior::Init(); Rando::CheckTracker::Init(); diff --git a/src/port/Rando/Spoiler/File.cpp b/src/port/Rando/Spoiler/File.cpp index 293c4b57e..ad2f99ae1 100644 --- a/src/port/Rando/Spoiler/File.cpp +++ b/src/port/Rando/Spoiler/File.cpp @@ -1,9 +1,7 @@ #include "Spoiler.h" #include "port/ui/Notification.h" #include -#include -const std::string appShortName = "sm64"; namespace fs = std::filesystem; namespace Rando { diff --git a/src/port/Rando/Spoiler/Generate.cpp b/src/port/Rando/Spoiler/Generate.cpp index 2401f11f2..f04a5d275 100644 --- a/src/port/Rando/Spoiler/Generate.cpp +++ b/src/port/Rando/Spoiler/Generate.cpp @@ -1,16 +1,14 @@ #include "Spoiler.h" #include "port/Rando/Logic/Logic.h" -#include "port/Rando/Rando.h" #include "port/ui/Notification.h" namespace Rando { namespace Spoiler { - -nlohmann::json GenerateFromPoolGeneration(std::vector& shuffledPool) { +nlohmann::json GenerateFromPoolGeneration(std::vector& shuffledPool, + std::vector& shuffledEntrances) { nlohmann::json spoiler; spoiler["type"] = "GHOSTSHIP_RANDO_SPOILER"; - spoiler["fileNum"] = std::to_string(selectedFileNum); if (CVarGetInteger("gRandoSettings.ManualSeedEntry", 0)) { spoiler["seed"] = seedString; } else { @@ -18,11 +16,10 @@ nlohmann::json GenerateFromPoolGeneration(std::vector& shuffl } spoiler["finalSeed"] = gSaveBuffer.files[selectedFileNum][0].shipSaveData.randoSaveData.finalSeed; - // TODO: Add once JSON Saves are in. - // spoiler["options"] = nlohmann::json::object(); - // for (auto& [randoOptionId, randoStaticOption] : Rando::StaticData::Options) { - // spoiler["options"][randoStaticOption.name] = RANDO_SAVE_OPTIONS[randoOptionId]; - // } + spoiler["options"] = nlohmann::json::object(); + for (auto& [randoOptionId, randoStaticOption] : Rando::StaticData::Options) { + spoiler["options"][randoStaticOption.name] = RANDO_SAVE_OPTIONS(selectedFileNum)[randoOptionId]; + } spoiler["checks"] = nlohmann::json::object(); for (auto& entry : shuffledPool) { @@ -37,46 +34,83 @@ nlohmann::json GenerateFromPoolGeneration(std::vector& shuffl } } + if (!shuffledEntrances.empty()) { + spoiler["entrances"] = nlohmann::json::object(); + for (auto& entrance : shuffledEntrances) { + spoiler["entrances"][Rando::StaticData::Entrances[entrance.randoEntranceId].name] = + Rando::StaticData::Entrances[Rando::StaticData::GetEntranceIdFromDestination(entrance.destinationId)] + .name; + } + } + return spoiler; } -std::vector GenerateFromSpoilerLog(nlohmann::json spoiler) { - std::vector spoilerChecks; + +void GenerateFromSpoiler(nlohmann::json spoiler) { + Rando::Logic::shuffledPool.clear(); + Rando::Logic::shuffledEntrances.clear(); if (!spoiler.contains("type") || spoiler["type"] != "GHOSTSHIP_RANDO_SPOILER") { Notification::Emit({ .message = "Error: Invalid Spoiler Log.", .messageColor = ImVec4(0.85f, 0.3f, 0, 1) }); - return spoilerChecks; } if (spoiler.contains("checks") && !spoiler["checks"].empty()) { for (auto& data : spoiler["checks"].items()) { - struct LevelShuffleEntry levelEntry; + struct LevelShuffleEntry checkEntry; for (auto& [checkId, staticCheck] : Rando::StaticData::Checks) { if (staticCheck.name == data.key()) { - levelEntry.randoCheckId = checkId; + checkEntry.randoCheckId = checkId; break; } } std::string randoItemStr = ""; if (data.value().contains("randoAct")) { - levelEntry.randoAct = data.value()["randoAct"]; + checkEntry.randoAct = data.value()["randoAct"]; randoItemStr = data.value()["randoItemId"]; } else { - levelEntry.randoAct = RA_ACT_NONE; + checkEntry.randoAct = RA_ACT_NONE; randoItemStr = data.value(); } for (auto& [itemId, staticItem] : Rando::StaticData::Items) { if (staticItem.spoilerName == randoItemStr) { - levelEntry.randoItemId = itemId; + checkEntry.randoItemId = itemId; + } + } + checkEntry.obtained = false; + checkEntry.skipped = false; + Rando::Logic::shuffledPool.push_back(checkEntry); + } + } + + if (spoiler.contains("entrances") && !spoiler["entrances"].empty()) { + for (auto& data : spoiler["entrances"].items()) { + RandoSaveEntrance randoSaveEntrance; + for (auto& [entranceId, staticEntrance] : Rando::StaticData::Entrances) { + if (staticEntrance.name == data.key()) { + randoSaveEntrance.randoEntranceId = entranceId; + } + if (staticEntrance.name == data.value()) { + randoSaveEntrance.destinationId = staticEntrance.destinationId; } } - levelEntry.obtained = false; - spoilerChecks.push_back(levelEntry); + + Rando::Logic::shuffledEntrances.push_back(randoSaveEntrance); } } - return spoilerChecks; + if (spoiler.contains("options") && !spoiler["options"].empty()) { + for (auto& data : spoiler["options"].items()) { + for (auto& [optionId, staticOption] : Rando::StaticData::Options) { + RandoSaveOption randoSaveOption; + if (staticOption.name == data.key()) { + RANDO_SAVE_OPTIONS(selectedFileNum)[optionId] = data.value().get(); + break; + } + } + } + } } } // namespace Spoiler diff --git a/src/port/Rando/Spoiler/RefreshOptions.cpp b/src/port/Rando/Spoiler/RefreshOptions.cpp new file mode 100644 index 000000000..31cdcd6a6 --- /dev/null +++ b/src/port/Rando/Spoiler/RefreshOptions.cpp @@ -0,0 +1,40 @@ +#include "Spoiler.h" +#include +#include + +#include + +std::vector Rando::Spoiler::spoilerLogs; +const std::filesystem::path randomizerFolderPath(Ship::Context::GetPathRelativeToAppDirectory("randomizer", + appShortName)); + +void Rando::Spoiler::RefreshSpoilerLogs() { + Rando::Spoiler::spoilerLogs.clear(); + + Rando::Spoiler::spoilerLogs.push_back("Generate New Seed"); + s32 spoilerFileIndex = -1; + + if (!std::filesystem::exists(randomizerFolderPath)) { + std::filesystem::create_directory(randomizerFolderPath); + } + + for (const auto& entry : std::filesystem::directory_iterator(randomizerFolderPath)) { + if (entry.is_regular_file()) { + std::string fileName = entry.path().filename().string(); + + Rando::Spoiler::spoilerLogs.push_back(fileName); + + // Check if the current file is the one set in the cvar + if (fileName == CVarGetString("gRandoSettings.SpoilerFile", "")) { + spoilerFileIndex = Rando::Spoiler::spoilerLogs.size() - 1; + } + } + } + + if (spoilerFileIndex == -1) { + CVarSetInteger("gRandoSettings.SpoilerFileIndex", 0); + CVarSetString("gRandoSettings.SpoilerFile", ""); + } else { + CVarSetInteger("gRandoSettings.SpoilerFileIndex", spoilerFileIndex); + } +} \ No newline at end of file diff --git a/src/port/Rando/Spoiler/Spoiler.h b/src/port/Rando/Spoiler/Spoiler.h index 53e1378fa..e83decb52 100644 --- a/src/port/Rando/Spoiler/Spoiler.h +++ b/src/port/Rando/Spoiler/Spoiler.h @@ -5,13 +5,20 @@ #include #include "nlohmann/json.hpp" #include "port/Rando/Logic/Logic.h" +#include + +const std::string appShortName = "sm64"; namespace Rando { namespace Spoiler { +extern std::vector spoilerLogs; + +nlohmann::json GenerateFromPoolGeneration(std::vector& shuffledPool, + std::vector& shuffledEntrances); -nlohmann::json GenerateFromPoolGeneration(std::vector& shuffledPool); -std::vector GenerateFromSpoilerLog(nlohmann::json spoiler); +void GenerateFromSpoiler(nlohmann::json spoiler); +void RefreshSpoilerLogs(); void SaveToFile(const std::string& fileName, nlohmann::json spoiler); nlohmann::json LoadFromFile(const std::string& filePath); // void ApplyToSaveContext(nlohmann::json spoiler); diff --git a/src/port/Rando/StaticData/Entrances.cpp b/src/port/Rando/StaticData/Entrances.cpp index dd4877be5..b933b5bd2 100644 --- a/src/port/Rando/StaticData/Entrances.cpp +++ b/src/port/Rando/StaticData/Entrances.cpp @@ -48,8 +48,16 @@ std::map Entrances = { RE(RE_WF, LEVEL_WF, RETYPE_PAINTING, WARP_NODE_66, REAREA_01), RE(RE_WMOTR, LEVEL_WMOTR, RETYPE_SECRET, WARP_NODE_0A, REAREA_02), }; - // clang-format on +RandoEntranceId GetEntranceIdFromDestination(int16_t destinationId) { + for (auto& [randoEntranceId, randoStaticEntrance] : Entrances) { + if (randoStaticEntrance.destinationId == destinationId) { + return randoEntranceId; + } + } + return RE_MAX; +} + } // namespace StaticData } // namespace Rando \ No newline at end of file diff --git a/src/port/Rando/StaticData/StaticData.h b/src/port/Rando/StaticData/StaticData.h index b4f94d7fb..c1ffd3a43 100644 --- a/src/port/Rando/StaticData/StaticData.h +++ b/src/port/Rando/StaticData/StaticData.h @@ -66,6 +66,7 @@ struct RandoStaticEntrance { extern std::map Entrances; +RandoEntranceId GetEntranceIdFromDestination(int16_t destinationId); struct RandoStaticOption { RandoOptionId randoOptionId; diff --git a/src/port/data/SaveConversion.h b/src/port/data/SaveConversion.h index b50d188a1..5d95216e1 100644 --- a/src/port/data/SaveConversion.h +++ b/src/port/data/SaveConversion.h @@ -6,8 +6,8 @@ #include NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(RandoSaveCheck, randoItemId, randoAct, obtained, skipped) -NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(RandoSaveEntrance, randoEntranceId, destinationId, randoEntranceType, deathWarpId, deathArea) -NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(RandoSaveData, randoSaveChecks, randoSaveEntrances, finalSeed) +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(RandoSaveEntrance, randoEntranceId, destinationId) +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(RandoSaveData, randoSaveChecks, randoSaveEntrances, randoSaveOptions, finalSeed) using json = nlohmann::json; diff --git a/src/port/ui/UIWidgets.hpp b/src/port/ui/UIWidgets.hpp index da57ccb7a..2de755da3 100644 --- a/src/port/ui/UIWidgets.hpp +++ b/src/port/ui/UIWidgets.hpp @@ -1009,6 +1009,20 @@ bool CVarCombobox(const char* label, const char* cvarName, const std::vector +bool CVarCombobox(const char* label, const char* cvarName, const std::vector& comboVector, + const ComboboxOptions& options = {}) { + bool dirty = false; + int32_t value = CVarGetInteger(cvarName, options.defaultIndex); + if (Combobox(label, &value, comboVector, options)) { + CVarSetInteger(cvarName, value); + Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame(); + ShipInit::Init(cvarName); + dirty = true; + } + return dirty; +} + template bool CVarCombobox(const char* label, const char* cvarName, const char* (&comboArray)[N], const ComboboxOptions& options = {}) {