summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEblo <7004497+Eblo@users.noreply.github.com>2025-10-29 17:24:39 -0400
committerGitHub <noreply@github.com>2025-10-29 17:24:39 -0400
commit84f3aedf609b2795f3ba39612312a948be97fb8b (patch)
tree97aeaf987a150f2af6d222bc91e9924a4587cad3
parent78059b1ba9af17e99908201797e0358339c30a3d (diff)
Retire French Vanilla logic setting (#1311)
-rw-r--r--mm/2s2h/Rando/Logic/FrenchVanilla.cpp226
-rw-r--r--mm/2s2h/Rando/Logic/Logic.h1
-rw-r--r--mm/2s2h/Rando/Menu.cpp29
-rw-r--r--mm/2s2h/Rando/MiscBehavior/OnFileCreate.cpp4
-rw-r--r--mm/2s2h/Rando/Types.h1
5 files changed, 4 insertions, 257 deletions
diff --git a/mm/2s2h/Rando/Logic/FrenchVanilla.cpp b/mm/2s2h/Rando/Logic/FrenchVanilla.cpp
deleted file mode 100644
index 621e8dee3..000000000
--- a/mm/2s2h/Rando/Logic/FrenchVanilla.cpp
+++ /dev/null
@@ -1,226 +0,0 @@
-#include "Logic.h"
-#include "2s2h/Rando/Types.h"
-
-#include <stdexcept>
-#include <spdlog/spdlog.h>
-
-extern "C" {
-#include "variables.h"
-#include "ShipUtils.h"
-uint64_t GetUnixTimestamp();
-}
-
-namespace Rando {
-
-namespace Logic {
-
-struct RandoPoolEntry {
- bool shuffled;
- RandoItemId vanillaItemId;
- RandoItemId placedItemId;
- bool itemPlaced;
- bool checkFilled;
- bool inPool;
-};
-
-struct RandoPoolPlacement {
- RandoCheckId randoCheckId;
- RandoCheckId randoCheckIdFromItem;
- RandoItemId placedItemId;
-};
-
-void ApplyFrenchVanillaLogicToSaveContext(std::vector<RandoCheckId>& checkPool, std::vector<RandoItemId>& itemPool) {
- uint64_t tick = GetUnixTimestamp();
- std::set<RandoCheckId> allChecksThatAreInLogic;
- std::set<RandoCheckId> allChecksThatHaveBeenReachedAtLeastOnce;
-
- // Used across all iterations
- std::map<RandoCheckId, RandoPoolEntry> currentCheckPool;
- std::set<RandoRegionId> currentReachableRegions = { RR_MAX };
- std::set<std::pair<RandoEvent, std::function<bool()>>*> currentEventsTriggered;
-
- // Used for backtracking
- std::vector<RandoPoolPlacement> placements;
- std::vector<RandoRegionId> newlyAccessibleRegions;
- std::vector<int> amountOfNewlyAccessibleRegions;
- std::vector<RandoCheckId> newlyAccessibleChecks;
- std::vector<int> amountOfNewlyAccessibleChecks;
- std::vector<std::pair<RandoEvent, std::function<bool()>>*> newlyTriggeredEvents;
- std::vector<int> amountOfNewlyTriggeredEvents;
-
- SaveContext copiedSaveContext;
- memcpy(&copiedSaveContext, &gSaveContext, sizeof(SaveContext));
-
- // First loop through all regions and add checks/items to the pool
- for (auto& [randoRegionId, randoRegion] : Rando::Logic::Regions) {
- for (auto& [randoCheckId, _] : randoRegion.checks) {
- auto& randoStaticCheck = Rando::StaticData::Checks[randoCheckId];
- bool isShuffled = std::find(checkPool.begin(), checkPool.end(), randoCheckId) != checkPool.end();
-
- allChecksThatAreInLogic.insert(randoCheckId);
- currentCheckPool[randoCheckId] = {
- isShuffled, randoStaticCheck.randoItemId, RI_UNKNOWN, false, false, false
- };
- }
- }
-
- while (true) {
- // Break if we've been running for too long
- if (GetUnixTimestamp() - tick > 5000) {
- tick = GetUnixTimestamp();
-
- // Log checks that have never been reached
- std::vector<RandoCheckId> checksThatHaveNeverBeenReached;
-
- std::set_difference(allChecksThatAreInLogic.begin(), allChecksThatAreInLogic.end(),
- allChecksThatHaveBeenReachedAtLeastOnce.begin(),
- allChecksThatHaveBeenReachedAtLeastOnce.end(),
- std::inserter(checksThatHaveNeverBeenReached, checksThatHaveNeverBeenReached.begin()));
-
- SPDLOG_ERROR("Checks that have never been reached:");
- for (RandoCheckId randoCheckId : checksThatHaveNeverBeenReached) {
- SPDLOG_ERROR("{}", Rando::StaticData::Checks[randoCheckId].name);
- }
-
- throw std::runtime_error("Logic Generation Timeout");
- }
-
- // Crawl through all reachable regions and add any new reachable regions
- int currentAmountOfNewlyAccessibleRegions = newlyAccessibleRegions.size();
- std::set<RandoRegionId> currentReachableRegionsCopy = currentReachableRegions;
- for (RandoRegionId regionId : currentReachableRegions) {
- FindReachableRegions(regionId, currentReachableRegions);
- }
- // Difference between the new and old reachable regions
- std::set_difference(currentReachableRegions.begin(), currentReachableRegions.end(),
- currentReachableRegionsCopy.begin(), currentReachableRegionsCopy.end(),
- std::inserter(newlyAccessibleRegions,
- newlyAccessibleRegions.begin() + currentAmountOfNewlyAccessibleRegions));
- amountOfNewlyAccessibleRegions.push_back(newlyAccessibleRegions.size() - currentAmountOfNewlyAccessibleRegions);
-
- // Track newly accessible checks
- int currentAmountOfNewlyAccessibleChecks = newlyAccessibleChecks.size();
- for (RandoRegionId regionId : currentReachableRegions) {
- auto& randoRegion = Rando::Logic::Regions[regionId];
- for (auto& [randoCheckId, accessLogicFunc] : randoRegion.checks) {
- if (
- // Check is not already in the pool
- currentCheckPool[randoCheckId].inPool == false &&
- // Check is accessible
- accessLogicFunc.first()) {
- allChecksThatHaveBeenReachedAtLeastOnce.insert(randoCheckId);
- currentCheckPool[randoCheckId].inPool = true;
- newlyAccessibleChecks.push_back(randoCheckId);
- }
- }
- }
- amountOfNewlyAccessibleChecks.push_back(newlyAccessibleChecks.size() - currentAmountOfNewlyAccessibleChecks);
-
- // Track newly triggered events
- int currentAmountOfNewlyTriggeredEvents = newlyTriggeredEvents.size();
- for (RandoRegionId regionId : currentReachableRegions) {
- auto& randoRegion = Rando::Logic::Regions[regionId];
- for (auto& randoEvent : randoRegion.events) {
- if (
- // Event is not already triggered
- !currentEventsTriggered.contains(&randoEvent) &&
- // Event condition is met
- randoEvent.second()) {
- currentEventsTriggered.insert(&randoEvent);
- newlyTriggeredEvents.push_back(&randoEvent);
- RANDO_EVENTS[randoEvent.first]++;
- }
- }
- }
- amountOfNewlyTriggeredEvents.push_back(newlyTriggeredEvents.size() - currentAmountOfNewlyTriggeredEvents);
-
- // Determine if we have placed all items
- int checksLeft = 0;
- std::vector<RandoCheckId> currentCheckList;
- std::vector<std::pair<RandoItemId, RandoCheckId>> currentItemList;
- for (auto& [randoCheckId, randoPoolEntry] : currentCheckPool) {
- if (randoPoolEntry.inPool) {
- if (!randoPoolEntry.itemPlaced && randoPoolEntry.shuffled) {
- currentItemList.push_back({ randoPoolEntry.vanillaItemId, randoCheckId });
- }
- if (!randoPoolEntry.checkFilled) {
- currentCheckList.push_back(randoCheckId);
- }
- }
- if (!randoPoolEntry.checkFilled) {
- checksLeft++;
- }
- }
- if (checksLeft == 0) {
- break; // All items placed
- }
-
- // If there are no items to place, backtrack
- if (currentCheckList.size() == 0) {
- for (int i = 0; i < amountOfNewlyAccessibleRegions.back(); i++) {
- currentReachableRegions.erase(newlyAccessibleRegions.back());
- newlyAccessibleRegions.pop_back();
- }
- amountOfNewlyAccessibleRegions.pop_back();
- for (int i = 0; i < amountOfNewlyAccessibleChecks.back(); i++) {
- currentCheckPool[newlyAccessibleChecks.back()].inPool = false;
- newlyAccessibleChecks.pop_back();
- }
- amountOfNewlyAccessibleChecks.pop_back();
- for (int i = 0; i < amountOfNewlyTriggeredEvents.back(); i++) {
- RANDO_EVENTS[newlyTriggeredEvents.back()->first]--;
- currentEventsTriggered.erase(newlyTriggeredEvents.back());
- newlyTriggeredEvents.pop_back();
- }
- amountOfNewlyTriggeredEvents.pop_back();
- auto [randoCheckId, randoCheckIdFromItem, convertedItemId] = placements.back();
- currentCheckPool[randoCheckId].checkFilled = false;
- currentCheckPool[randoCheckId].placedItemId = RI_UNKNOWN;
- currentCheckPool[randoCheckIdFromItem].itemPlaced = false;
- RemoveItem(convertedItemId);
- placements.pop_back();
- continue;
- }
-
- // Select a random check
- size_t checkIndex = currentCheckList.size() > 1 ? Ship_Random(0, currentCheckList.size() - 1) : 0;
- RandoCheckId randoCheckId = currentCheckList[checkIndex];
- if (currentCheckPool[randoCheckId].shuffled) {
- // Select a random item
- size_t itemIndex = currentItemList.size() > 1 ? Ship_Random(0, currentItemList.size() - 1) : 0;
- auto [randoItemId, randoCheckIdFromItem] = currentItemList[itemIndex];
- SPDLOG_TRACE("Placing item {} in check {}", Rando::StaticData::Items[randoItemId].spoilerName,
- Rando::StaticData::Checks[randoCheckId].name);
- // Place the item in the check
- currentCheckPool[randoCheckId].checkFilled = true;
- currentCheckPool[randoCheckId].placedItemId = randoItemId;
- currentCheckPool[randoCheckIdFromItem].itemPlaced = true;
- RandoItemId convertedItemId = ConvertItem(randoItemId);
- GiveItem(convertedItemId);
- placements.push_back({ randoCheckId, randoCheckIdFromItem, convertedItemId });
- } else {
- // Place vanilla item in the check
- currentCheckPool[randoCheckId].checkFilled = true;
- currentCheckPool[randoCheckId].placedItemId = currentCheckPool[randoCheckId].vanillaItemId;
- currentCheckPool[randoCheckId].itemPlaced = true;
- RandoItemId convertedItemId = ConvertItem(currentCheckPool[randoCheckId].vanillaItemId);
- GiveItem(convertedItemId);
- placements.push_back({ randoCheckId, randoCheckId, convertedItemId });
- }
- }
-
- memcpy(&gSaveContext, &copiedSaveContext, sizeof(SaveContext));
-
- for (auto& [randoCheckId, randoPoolEntry] : currentCheckPool) {
- if (randoPoolEntry.shuffled) {
- RANDO_SAVE_CHECKS[randoCheckId].randoItemId = randoPoolEntry.placedItemId;
- RANDO_SAVE_CHECKS[randoCheckId].shuffled = true;
- }
- }
-
- SPDLOG_INFO("Successfully placed all items with French Vanilla logic");
-}
-
-} // namespace Logic
-
-} // namespace Rando
diff --git a/mm/2s2h/Rando/Logic/Logic.h b/mm/2s2h/Rando/Logic/Logic.h
index 2c0ed8db3..31912efb2 100644
--- a/mm/2s2h/Rando/Logic/Logic.h
+++ b/mm/2s2h/Rando/Logic/Logic.h
@@ -19,7 +19,6 @@ namespace Logic {
void FindReachableRegions(RandoRegionId currentRegion, std::set<RandoRegionId>& reachableRegions);
RandoRegionId GetRegionIdFromEntrance(s32 entrance);
-void ApplyFrenchVanillaLogicToSaveContext(std::vector<RandoCheckId>& checkPool, std::vector<RandoItemId>& itemPool);
void ApplyGlitchlessLogicToSaveContext(std::vector<RandoCheckId>& checkPool, std::vector<RandoItemId>& itemPool);
void ApplyNearlyNoLogicToSaveContext(std::vector<RandoCheckId>& checkPool, std::vector<RandoItemId>& itemPool);
void ApplyNoLogicToSaveContext(std::vector<RandoCheckId>& checkPool, std::vector<RandoItemId>& itemPool);
diff --git a/mm/2s2h/Rando/Menu.cpp b/mm/2s2h/Rando/Menu.cpp
index 1ec1d840a..b5fc784c2 100644
--- a/mm/2s2h/Rando/Menu.cpp
+++ b/mm/2s2h/Rando/Menu.cpp
@@ -10,7 +10,6 @@ std::unordered_map<int32_t, const char*> logicOptions = {
{ RO_LOGIC_GLITCHLESS, "Glitchless" },
{ RO_LOGIC_NO_LOGIC, "No Logic" },
{ RO_LOGIC_NEARLY_NO_LOGIC, "Nearly No Logic" },
- { RO_LOGIC_FRENCH_VANILLA, "French Vanilla" },
{ RO_LOGIC_VANILLA, "Vanilla" },
};
@@ -29,12 +28,6 @@ std::unordered_map<int32_t, const char*> accessTrialsOptions = {
{ RO_ACCESS_TRIALS_OPEN, "Open" },
};
-std::vector<int32_t> incompatibleWithFrenchVanilla = {
- RO_SHUFFLE_BOSS_SOULS,
- RO_SHUFFLE_SWIM,
- RO_PLENTIFUL_ITEMS,
-};
-
std::vector<int32_t> incompatibleWithVanilla = {
RO_SHUFFLE_BOSS_SOULS,
RO_SHUFFLE_SWIM,
@@ -61,14 +54,7 @@ void ClearIncompatibleSetting() {
int32_t currentLogicSetting =
CVarGetInteger(Rando::StaticData::Options[RO_LOGIC].cvar, Rando::StaticData::Options[RO_LOGIC].defaultValue);
switch (currentLogicSetting) {
- // French Vanilla can't have any options that add items without a corresponding check
- case RO_LOGIC_FRENCH_VANILLA:
- CVarClear(Rando::StaticData::Options[RO_PLENTIFUL_ITEMS].cvar);
- CVarClear(Rando::StaticData::Options[RO_SHUFFLE_BOSS_SOULS].cvar);
- CVarClear(Rando::StaticData::Options[RO_SHUFFLE_SWIM].cvar);
- // TODO: Handle Starting Items to ensure starting sword/shield
- break;
- // Similar to French Vanilla, Vanilla can't add items without corresponding checks
+ // Vanilla can't add items without corresponding checks
case RO_LOGIC_VANILLA:
CVarClear(Rando::StaticData::Options[RO_PLENTIFUL_ITEMS].cvar);
CVarClear(Rando::StaticData::Options[RO_SHUFFLE_BOSS_SOULS].cvar);
@@ -83,12 +69,6 @@ bool IncompatibleWithLogicSetting(int32_t option) {
int32_t currentLogicSetting =
CVarGetInteger(Rando::StaticData::Options[RO_LOGIC].cvar, Rando::StaticData::Options[RO_LOGIC].defaultValue);
switch (currentLogicSetting) {
- case RO_LOGIC_FRENCH_VANILLA:
- if (std::find(incompatibleWithFrenchVanilla.begin(), incompatibleWithFrenchVanilla.end(), option) !=
- incompatibleWithFrenchVanilla.end()) {
- return true;
- }
- break;
case RO_LOGIC_VANILLA:
if (std::find(incompatibleWithVanilla.begin(), incompatibleWithVanilla.end(), option) !=
incompatibleWithVanilla.end()) {
@@ -197,9 +177,6 @@ static void DrawLogicConditionsTab() {
"- Oath to Order and Remains cannot be placed on the Moon.\n"
"- Deku Mask, Zora Mask, Sonata, and Bossa Nova cannot be placed in their respective Temples or on "
"the Moon.\n\n"
- "French Vanilla - This is an alternative variant to Glitchless, but the items are biased to be "
- "closer to their vanilla locations. Tends to be an more beginner friendly experience.\n"
- "Not compatible with settings that add items to the pool, like Boss Souls or Plentiful Items.\n\n"
"Vanilla - The items are not shuffled.\n"
"Not compatible with settings that add items to the pool, like Boss Souls or Plentiful Items.");
ImGui::EndChild();
@@ -502,9 +479,9 @@ static void DrawStartingItemsTab() {
}
static void DrawLocationsTab() {
- if (CVarGetInteger(Rando::StaticData::Options[RO_LOGIC].cvar, RO_LOGIC_GLITCHLESS) >= RO_LOGIC_FRENCH_VANILLA) {
+ if (CVarGetInteger(Rando::StaticData::Options[RO_LOGIC].cvar, RO_LOGIC_GLITCHLESS) >= RO_LOGIC_VANILLA) {
ImGui::TextColored(UIWidgets::ColorValues.at(UIWidgets::Colors::Red),
- "This setting is not compatible with French Vanilla or Vanilla Logic.");
+ "This setting is not compatible with Vanilla Logic.");
return;
}
diff --git a/mm/2s2h/Rando/MiscBehavior/OnFileCreate.cpp b/mm/2s2h/Rando/MiscBehavior/OnFileCreate.cpp
index 42e712ac5..f41e47afc 100644
--- a/mm/2s2h/Rando/MiscBehavior/OnFileCreate.cpp
+++ b/mm/2s2h/Rando/MiscBehavior/OnFileCreate.cpp
@@ -212,7 +212,7 @@ void Rando::MiscBehavior::OnFileCreate(s16 fileNum) {
}
// Skip checks that have been excluded in the Locations menu and add their vanilla item to the
- // pool except if Logic is set to Vanilla or French Vanilla.
+ // pool except if Logic is set to Vanilla.
if (RANDO_SAVE_OPTIONS[RO_LOGIC] <= RO_LOGIC_NEARLY_NO_LOGIC) {
auto it = std::find(excludedChecks.begin(), excludedChecks.end(), randoCheckId);
if (it != excludedChecks.end()) {
@@ -424,8 +424,6 @@ void Rando::MiscBehavior::OnFileCreate(s16 fileNum) {
Rando::Logic::ApplyNearlyNoLogicToSaveContext(checkPool, itemPool);
} else if (RANDO_SAVE_OPTIONS[RO_LOGIC] == RO_LOGIC_GLITCHLESS) {
Rando::Logic::ApplyGlitchlessLogicToSaveContext(checkPool, itemPool);
- } else if (RANDO_SAVE_OPTIONS[RO_LOGIC] == RO_LOGIC_FRENCH_VANILLA) {
- Rando::Logic::ApplyFrenchVanillaLogicToSaveContext(checkPool, itemPool);
} else {
throw std::runtime_error("Logic option not implemented: " +
std::to_string(RANDO_SAVE_OPTIONS[RO_LOGIC]));
diff --git a/mm/2s2h/Rando/Types.h b/mm/2s2h/Rando/Types.h
index 8841137d7..55f72831d 100644
--- a/mm/2s2h/Rando/Types.h
+++ b/mm/2s2h/Rando/Types.h
@@ -2828,7 +2828,6 @@ typedef enum {
RO_LOGIC_GLITCHLESS,
RO_LOGIC_NO_LOGIC,
RO_LOGIC_NEARLY_NO_LOGIC,
- RO_LOGIC_FRENCH_VANILLA,
RO_LOGIC_VANILLA,
} RandoOptionLogic;