summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--soh/soh/Enhancements/randomizer/3drando/fill.cpp39
-rw-r--r--soh/soh/Enhancements/randomizer/3drando/fill.hpp3
-rw-r--r--soh/soh/Enhancements/randomizer/item_location.cpp5
-rw-r--r--soh/soh/Enhancements/randomizer/item_location.h2
4 files changed, 32 insertions, 17 deletions
diff --git a/soh/soh/Enhancements/randomizer/3drando/fill.cpp b/soh/soh/Enhancements/randomizer/3drando/fill.cpp
index 0f8f0ccbf..afa2efb03 100644
--- a/soh/soh/Enhancements/randomizer/3drando/fill.cpp
+++ b/soh/soh/Enhancements/randomizer/3drando/fill.cpp
@@ -304,13 +304,12 @@ bool IsBombchus(RandomizerGet item, bool includeShops = false) {
bool IsBeatableWithout(RandomizerCheck excludedCheck, bool replaceItem,
RandomizerGet ignore = RG_NONE) { // RANDOTODO make excludedCheck an ItemLocation
- auto ctx = Rando::Context::GetInstance();
- RandomizerGet copy = ctx->GetItemLocation(excludedCheck)->GetPlacedRandomizerGet(); // Copy out item
- ctx->GetItemLocation(excludedCheck)->SetPlacedItem(RG_NONE); // Write in empty item
+ Rando::ItemLocation* location = Rando::Context::GetInstance()->GetItemLocation(excludedCheck);
+ location->DelayItem();
logic->Reset();
bool result = CheckBeatable(ignore);
if (replaceItem) {
- ctx->GetItemLocation(excludedCheck)->SetPlacedItem(copy); // Immediately put item back
+ location->SaveDelayedItem(); // Immediately put item back
}
return result;
}
@@ -338,6 +337,10 @@ void AddToPlaythrough(LocationAccess& locPair, GetAccessibleLocationsStruct& gal
RandomizerCheck loc = locPair.GetLocation();
Rando::ItemLocation* location = ctx->GetItemLocation(loc);
RandomizerGet locItem = location->GetPlacedRandomizerGet();
+ // Reached after wincon, so never part of playthrough. Pare first
+ if (ctx->playthroughBeatable && location->GetPlacedItem().IsAdvancement()) {
+ gals.lateLocations.push_back(loc);
+ }
// Item is an advancement item, figure out if it should be added to this sphere
if (!ctx->playthroughBeatable && location->GetPlacedItem().IsAdvancement()) {
ItemType type = location->GetPlacedItem().GetItemType();
@@ -378,6 +381,12 @@ void AddToPlaythrough(LocationAccess& locPair, GetAccessibleLocationsStruct& gal
gals.itemSphere.clear();
gals.itemSphere.push_back(loc);
ctx->playthroughBeatable = true;
+ // Items found in this sphere aren't collected before wincon
+ for (Rando::ItemLocation* pending : gals.newItemLocations) {
+ if (pending != location && pending->GetPlacedItem().IsAdvancement()) {
+ gals.lateLocations.push_back(pending->GetRandomizerCheck());
+ }
+ }
}
}
}
@@ -565,7 +574,7 @@ std::vector<RandomizerCheck> ReachabilitySearch(const std::vector<RandomizerChec
}
// Create the playthrough for the seed
-void GeneratePlaythrough() {
+std::vector<RandomizerCheck> GeneratePlaythrough() {
auto ctx = Rando::Context::GetInstance();
ctx->playthroughBeatable = false;
logic->Reset();
@@ -589,6 +598,7 @@ void GeneratePlaythrough() {
ctx->GetEntranceShuffler()->playthroughEntrances.push_back(gals.entranceSphere);
}
} while (gals.logicUpdated);
+ return gals.lateLocations;
}
// return if the seed is currently beatable or not
@@ -710,17 +720,21 @@ void SetAreas() {
// Remove unnecessary items from playthrough by removing their location, and checking if game is still beatable
// To reduce searches, some preprocessing is done in playthrough generation to avoid adding obviously unnecessary items
-static void PareDownPlaythrough() {
+static void PareDownPlaythrough(const std::vector<RandomizerCheck>& lateLocations) {
auto ctx = Rando::Context::GetInstance();
std::vector<RandomizerCheck> toAddBackItem;
+ // Hide items only reachable after wincon. Otherwise they can stand in for a removed playthrough item
+ for (RandomizerCheck loc : lateLocations) {
+ ctx->GetItemLocation(loc)->DelayItem();
+ toAddBackItem.push_back(loc);
+ }
// Start at sphere before Ganon's and count down
for (int32_t i = static_cast<int32_t>(ctx->playthroughLocations.size()) - 2; i >= 0; i--) {
// Check each item location in sphere
- std::vector<int> erasableIndices;
std::vector<RandomizerCheck> sphere = ctx->playthroughLocations.at(i);
for (int32_t j = static_cast<int32_t>(sphere.size()) - 1; j >= 0; j--) {
RandomizerCheck loc = sphere.at(j);
- RandomizerGet locGet = ctx->GetItemLocation(loc)->GetPlacedRandomizerGet(); // Copy out item
+ RandomizerGet locGet = ctx->GetItemLocation(loc)->GetPlacedRandomizerGet();
RandomizerGet ignore = RG_NONE;
if (locGet == RG_GOLD_SKULLTULA_TOKEN || IsBombchus(locGet, true) ||
@@ -731,10 +745,9 @@ static void PareDownPlaythrough() {
// Playthrough is still beatable without this item, therefore it can be removed from playthrough section.
if (IsBeatableWithout(loc, false, ignore)) {
ctx->playthroughLocations[i].erase(ctx->playthroughLocations[i].begin() + j);
- ctx->GetItemLocation(loc)->SetDelayedItem(locGet); // Game is still beatable, don't add back until later
- toAddBackItem.push_back(loc);
+ toAddBackItem.push_back(loc); // Game is still beatable, don't add back until later
} else {
- ctx->GetItemLocation(loc)->SetPlacedItem(locGet); // Immediately put item back so game is beatable again
+ ctx->GetItemLocation(loc)->SaveDelayedItem(); // Immediately put item back so game is beatable again
}
}
}
@@ -1459,13 +1472,13 @@ int Fill() {
StopPerformanceTimer(PT_REMAINING_ITEMS);
StartPerformanceTimer(PT_PLAYTHROUGH_GENERATION);
- GeneratePlaythrough();
+ std::vector<RandomizerCheck> lateLocations = GeneratePlaythrough();
StopPerformanceTimer(PT_PLAYTHROUGH_GENERATION);
// Successful placement, produced beatable result
if (ctx->playthroughBeatable && !placementFailure) {
SPDLOG_INFO("Calculating Playthrough...");
StartPerformanceTimer(PT_PARE_DOWN_PLAYTHROUGH);
- PareDownPlaythrough();
+ PareDownPlaythrough(lateLocations);
StopPerformanceTimer(PT_PARE_DOWN_PLAYTHROUGH);
StartPerformanceTimer(PT_WOTH);
diff --git a/soh/soh/Enhancements/randomizer/3drando/fill.hpp b/soh/soh/Enhancements/randomizer/3drando/fill.hpp
index 0c972bb42..055f909e2 100644
--- a/soh/soh/Enhancements/randomizer/3drando/fill.hpp
+++ b/soh/soh/Enhancements/randomizer/3drando/fill.hpp
@@ -13,6 +13,7 @@ struct GetAccessibleLocationsStruct {
int gsCount;
int maxGsCount;
std::vector<LogicVal> buyIgnores;
+ std::vector<RandomizerCheck> lateLocations;
// Variables for search
std::vector<Rando::ItemLocation*> newItemLocations;
@@ -68,7 +69,7 @@ std::vector<RandomizerCheck> ReachabilitySearch(const std::vector<RandomizerChec
RandomizerRegion startingRegion = RR_ROOT,
RandoAgeTime startingAgeTime = RAT_NONE);
-void GeneratePlaythrough();
+std::vector<RandomizerCheck> GeneratePlaythrough();
bool CheckBeatable(RandomizerGet ignore = RG_NONE);
diff --git a/soh/soh/Enhancements/randomizer/item_location.cpp b/soh/soh/Enhancements/randomizer/item_location.cpp
index 1bfe380d0..cfdf535c3 100644
--- a/soh/soh/Enhancements/randomizer/item_location.cpp
+++ b/soh/soh/Enhancements/randomizer/item_location.cpp
@@ -48,8 +48,9 @@ void ItemLocation::SetPlacedItem(const RandomizerGet item) {
SetPrice(StaticData::RetrieveItem(placedItem).GetPrice());
}
-void ItemLocation::SetDelayedItem(const RandomizerGet item) {
- delayedItem = item;
+void ItemLocation::DelayItem() {
+ delayedItem = placedItem;
+ placedItem = RG_NONE;
}
void ItemLocation::SaveDelayedItem() {
diff --git a/soh/soh/Enhancements/randomizer/item_location.h b/soh/soh/Enhancements/randomizer/item_location.h
index d96ab16ad..8064462ba 100644
--- a/soh/soh/Enhancements/randomizer/item_location.h
+++ b/soh/soh/Enhancements/randomizer/item_location.h
@@ -18,7 +18,7 @@ class ItemLocation {
RandomizerGet GetPlacedRandomizerGet() const;
void SetPlacedItem(RandomizerGet item);
RandomizerGet& RefPlacedItem();
- void SetDelayedItem(RandomizerGet item);
+ void DelayItem();
RandomizerRegion GetParentRegionKey() const;
void SetParentRegion(RandomizerRegion region);
std::set<RandomizerArea> GetAreas() const;