Skip to content

Commit 2c2395b

Browse files
authored
Merge pull request #140 from gymnast86/barren-hint-fixes
Fix barren hint edge cases in entrance rando
2 parents b0c9a4a + d1f4daf commit 2c2395b

12 files changed

Lines changed: 122 additions & 113 deletions

gui/desktop/tracker/tracker.cpp

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ bool MainWindow::autosave_current_tracker_preferences()
403403
pref["show_location_logic"] = trackerPreferences.showLocationLogic;
404404
pref["show_nonprogress_locations"] = trackerPreferences.showNonProgressLocations;
405405
pref["right_click_clear_all"] = trackerPreferences.rightClickClearAll;
406-
pref["clear_all_includes_dungeon_mail"] = trackerPreferences.clearAllIncludesDungeonMail;
406+
pref["clear_all_includes_dependent_locations"] = trackerPreferences.clearAllIncludesDependentLocations;
407407
pref["override_items_color"] = trackerPreferences.overrideItemsColor;
408408
pref["override_locations_color"] = trackerPreferences.overrideLocationsColor;
409409
pref["override_stats_color"] = trackerPreferences.overrideStatsColor;
@@ -490,9 +490,14 @@ void MainWindow::load_tracker_autosave()
490490
trackerPreferences.rightClickClearAll = pref["right_click_clear_all"].as<bool>();
491491
}
492492

493-
if (pref["clear_all_includes_dungeon_mail"])
493+
if (pref["clear_all_includes_dependent_locations"])
494494
{
495-
trackerPreferences.clearAllIncludesDungeonMail = pref["clear_all_includes_dungeon_mail"].as<bool>();
495+
trackerPreferences.clearAllIncludesDependentLocations = pref["clear_all_includes_dependent_locations"].as<bool>();
496+
}
497+
// Old name for above setting
498+
else if (pref["clear_all_includes_dungeon_mail"])
499+
{
500+
trackerPreferences.clearAllIncludesDependentLocations = pref["clear_all_includes_dungeon_mail"].as<bool>();
496501
}
497502

498503
if (!std::filesystem::exists(trackerPreferences.autosaveFilePath) || !std::filesystem::exists(Utility::get_app_save_path() / "tracker_preferences.yaml"))
@@ -1352,21 +1357,12 @@ void MainWindow::tracker_clear_specific_area(const std::string& areaPrefix)
13521357
for (auto loc : areaLocations[areaPrefix])
13531358
{
13541359
loc->marked = true;
1355-
// Clear certain mail locations associated with bosses
1356-
if (trackerPreferences.clearAllIncludesDungeonMail)
1360+
// Clear any outside dependent locations of this area
1361+
if (trackerPreferences.clearAllIncludesDependentLocations)
13571362
{
1358-
if (loc->getName() == "Forsaken Fortress - Helmaroc King Heart Container")
1359-
{
1360-
trackerWorld.locationTable["Mailbox - Letter from Aryll"]->marked = true;
1361-
trackerWorld.locationTable["Mailbox - Letter from Tingle"]->marked = true;
1362-
}
1363-
else if (loc->getName() == "Forbidden Woods - Kalle Demos Heart Container")
1364-
{
1365-
trackerWorld.locationTable["Mailbox - Letter from Orca"]->marked = true;
1366-
}
1367-
else if (loc->getName() == "Earth Temple - Jalhalla Heart Container")
1363+
for (auto outsideLoc : loc->outsideDependentLocations)
13681364
{
1369-
trackerWorld.locationTable["Mailbox - Letter from Baito"]->marked = true;
1365+
outsideLoc->marked = true;
13701366
}
13711367
}
13721368
}

gui/desktop/tracker/tracker_preferences.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ struct TrackerPreferences {
99
bool showLocationLogic = true;
1010
bool showNonProgressLocations = false;
1111
bool rightClickClearAll = true;
12-
bool clearAllIncludesDungeonMail = true;
12+
bool clearAllIncludesDependentLocations = true;
1313
bool overrideItemsColor = false;
1414
bool overrideLocationsColor = false;
1515
bool overrideStatsColor = false;

gui/desktop/tracker/tracker_preferences_dialog.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ TrackerPreferencesDialog::TrackerPreferencesDialog(MainWindow* main_) : main(mai
1111
ui.show_location_logic->setChecked(main->trackerPreferences.showLocationLogic);
1212
ui.show_nonprogress_locations->setChecked(main->trackerPreferences.showNonProgressLocations);
1313
ui.right_click_to_clear_all->setChecked(main->trackerPreferences.rightClickClearAll);
14-
ui.clear_all_includes_dungeon_mail->setChecked(main->trackerPreferences.clearAllIncludesDungeonMail);
14+
ui.clear_all_includes_dependent_locations->setChecked(main->trackerPreferences.clearAllIncludesDependentLocations);
1515
ui.override_items_background_color->setChecked(main->trackerPreferences.overrideItemsColor);
1616
ui.override_locations_background_color->setChecked(main->trackerPreferences.overrideLocationsColor);
1717
ui.override_statistics_background_color->setChecked(main->trackerPreferences.overrideStatsColor);
@@ -58,9 +58,9 @@ void TrackerPreferencesDialog::on_right_click_to_clear_all_stateChanged(int arg1
5858
}
5959

6060

61-
void TrackerPreferencesDialog::on_clear_all_includes_dungeon_mail_stateChanged(int arg1)
61+
void TrackerPreferencesDialog::on_clear_all_includes_dependent_locations_stateChanged(int arg1)
6262
{
63-
main->trackerPreferences.clearAllIncludesDungeonMail = arg1;
63+
main->trackerPreferences.clearAllIncludesDependentLocations = arg1;
6464
}
6565

6666

gui/desktop/tracker/tracker_preferences_dialog.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ private slots:
1616
void on_show_location_logic_stateChanged(int arg1);
1717
void on_show_nonprogress_locations_stateChanged(int arg1);
1818
void on_right_click_to_clear_all_stateChanged(int arg1);
19-
void on_clear_all_includes_dungeon_mail_stateChanged(int arg1);
19+
void on_clear_all_includes_dependent_locations_stateChanged(int arg1);
2020
void on_override_items_background_color_stateChanged(int arg1);
2121
void on_override_locations_background_color_stateChanged(int arg1);
2222
void on_override_statistics_background_color_stateChanged(int arg1);

gui/desktop/tracker/tracker_preferences_dialog.ui

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,9 @@
8282
</widget>
8383
</item>
8484
<item>
85-
<widget class="QCheckBox" name="clear_all_includes_dungeon_mail">
85+
<widget class="QCheckBox" name="clear_all_includes_dependent_locations">
8686
<property name="text">
87-
<string>Clear All Includes Dungeon Mail</string>
87+
<string>Clear All Includes Dependent Locations</string>
8888
</property>
8989
</widget>
9090
</item>

logic/Dungeon.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11

22
#include "Dungeon.hpp"
3+
#include "Location.hpp"
4+
35
#include <unordered_set>
46

57
// Helper function to make sure there are no dungeon name typos
@@ -19,3 +21,17 @@ bool isValidDungeon(const std::string& dungeonName)
1921

2022
return dungeonNames.contains(dungeonName);
2123
}
24+
25+
// Gather any outside dependent locations for any locations within the dungeon
26+
std::list<Location*> Dungeon::getOutsideDependentLocations() const
27+
{
28+
std::list<Location*> outsideLocs = {};
29+
for (auto loc : locations)
30+
{
31+
for (auto outsideLoc : loc->outsideDependentLocations)
32+
{
33+
outsideLocs.push_back(outsideLoc);
34+
}
35+
}
36+
return outsideLocs;
37+
}

logic/Dungeon.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ struct Dungeon {
1616
Item map = Item();
1717
Item compass = Item();
1818
std::list<Location*> locations = {};
19-
std::list<Location*> outsideDependentLocations = {}; // Locations which depend on beating the dungeon
2019
Location* raceModeLocation = nullptr;
2120
Area* startingArea = nullptr;
2221
Entrance* startingEntrance = nullptr;
@@ -30,6 +29,8 @@ struct Dungeon {
3029
std::string savewarpStage = "";
3130
uint8_t savewarpRoom = 0;
3231
uint8_t savewarpSpawn = 0;
32+
33+
std::list<Location*> getOutsideDependentLocations() const;
3334
};
3435

3536
bool isValidDungeon(const std::string& dungeonName);

logic/Fill.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,16 @@ static FillError randomizeOwnDungeon(WorldPool& worlds, ItemPool& itemPool)
437437
// Place small keys and big keys first since they're progression items
438438
FILL_ERROR_CHECK(assumedFill(worlds, dungeonPool, itemPool, dungeonLocations, worldId));
439439

440+
// Set any locations which got the keys as having expected items
441+
for (auto loc : dungeonLocations)
442+
{
443+
if ((dungeon.smallKey.isValidItem() && loc->currentItem == dungeon.smallKey && settings.dungeon_small_keys == PlacementOption::OwnDungeon) ||
444+
(dungeon.bigKey.isValidItem() && loc->currentItem == dungeon.bigKey && settings.dungeon_big_keys == PlacementOption::OwnDungeon))
445+
{
446+
loc->hasExpectedItem = true;
447+
}
448+
}
449+
440450
// Place maps and compasses after since they aren't progressive items
441451
dungeonPool.clear();
442452
if (settings.dungeon_maps_compasses == PlacementOption::OwnDungeon)
@@ -636,6 +646,13 @@ static FillError placeRaceModeItems(WorldPool& worlds, ItemPool& itemPool, Locat
636646
// Then place the items in the race mode locations
637647
FillError err;
638648
FILL_ERROR_CHECK(assumedFill(worlds, raceModeItems, itemPool, raceModeLocations));
649+
650+
// Set race mode locations which had items placed at them as having expected items
651+
for (auto raceModeLoc : raceModeLocations)
652+
{
653+
raceModeLoc->hasExpectedItem = true;
654+
}
655+
639656
// Recalculate major items since new items may now be required depending on
640657
// what items were placed at race mode locations
641658
determineMajorItems(worlds, itemPool, allLocations);
@@ -775,6 +792,7 @@ void clearWorlds(WorldPool& worlds)
775792
if (!location->plandomized && !location->hasKnownVanillaItem)
776793
{
777794
location->currentItem = {GameItem::INVALID, nullptr};
795+
location->hasExpectedItem = false;
778796
}
779797
}
780798
}

logic/Hints.cpp

Lines changed: 18 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -193,9 +193,8 @@ static HintError calculatePossibleBarrenRegions(WorldPool& worlds)
193193
// count as being part of the island.
194194
for (auto& [name, location] : world.locationTable)
195195
{
196-
// Locations which have known items should not block a region from being barren
197-
if (location->progression && !location->hasKnownVanillaItem &&
198-
!(location->isRaceModeLocation && world.getSettings().progression_dungeons != ProgressionDungeons::Disabled))
196+
// Locations which have known vanilla/expected items should not block a region from being barren
197+
if (location->progression && !location->hasKnownVanillaItem && !location->hasExpectedItem)
199198
{
200199
for (auto& locAccess : location->accessPoints)
201200
{
@@ -216,33 +215,20 @@ static HintError calculatePossibleBarrenRegions(WorldPool& worlds)
216215
{
217216
LOG_TO_DEBUG("Removed " + hintRegion + " from barren pool due to item " + location->currentItem.getName() + " at location " + location->getName());
218217
world.barrenRegions.erase(hintRegion);
218+
continue;
219219
}
220-
}
221-
}
222-
}
223-
}
224-
}
225-
}
226220

227-
// If a dungeon is barren, but has a non-junk item at any of it's
228-
// outside dependent locations, then it shouldn't be considered barren
229-
for (auto& [dungeonName, dungeon] : world.dungeons)
230-
{
231-
if (world.barrenRegions.contains(dungeonName))
232-
{
233-
for (auto loc : dungeon.outsideDependentLocations)
234-
{
235-
if (!loc->currentItem.canBeInBarrenRegion())
236-
{
237-
LOG_TO_DEBUG(dungeonName + " removed from barren pool due to " + loc->currentItem.getName() + " at outside location " + loc->getName());
238-
world.barrenRegions.erase(dungeonName);
239-
// Also remove any islands this dungeon is on from the barren pool
240-
for (const auto& island : dungeon.islands)
241-
{
242-
if (world.barrenRegions.contains(island))
243-
{
244-
LOG_TO_DEBUG(island + " removed from barren pool due to " + loc->currentItem.getName() + " at outside location " + loc->getName());
245-
world.barrenRegions.erase(island);
221+
// Also make sure the outside dependent locations are barren a well
222+
for (auto outsideLoc : location->outsideDependentLocations)
223+
{
224+
// If an outside dependent location is not barren, remove the region from being barren
225+
if (!outsideLoc->currentItemCanBeBarren())
226+
{
227+
LOG_TO_DEBUG("Removed " + hintRegion + " from barren pool due to item " + outsideLoc->currentItem.getName() + " at location " + outsideLoc->getName() + " which is dependent on " + location->getName());
228+
world.barrenRegions.erase(hintRegion);
229+
break;
230+
}
231+
}
246232
}
247233
}
248234
}
@@ -359,14 +345,10 @@ static HintError generatePathHintLocations(World& world, std::vector<Location*>&
359345

360346
auto possiblePathLocations = goalLocation->pathLocations;
361347

362-
// Filter out race mode locations, known vanilla items, and known
363-
// keys in dungeons from possible path locations
348+
// Filter out known vanilla items, and expected items
364349
filterAndEraseFromPool(possiblePathLocations, [settings = world.getSettings()](auto location){
365350
auto& item = location->currentItem;
366-
return (location->hasKnownVanillaItem ||
367-
(item.isSmallKey() && settings.dungeon_small_keys == PlacementOption::OwnDungeon) ||
368-
(item.isBigKey() && settings.dungeon_big_keys == PlacementOption::OwnDungeon) ||
369-
(location->isRaceModeLocation));
351+
return (location->hasKnownVanillaItem || location->hasExpectedItem);
370352
});
371353

372354
auto hintLocation = getHintableLocation(possiblePathLocations);
@@ -535,11 +517,9 @@ static HintError generateItemHintLocations(World& world, std::vector<Location*>&
535517
if (location->progression && // if the location is a progression location...
536518
!location->currentItem.isJunkItem() && // and does not have a junk item...
537519
!location->hasKnownVanillaItem && // and does not have a known vanilla item...
520+
!location->hasExpectedItem && // and does not have an expected item
538521
!location->hasBeenHinted && // and has not been hinted at yet...
539-
(!location->currentItem.isSmallKey() || settings.dungeon_small_keys != PlacementOption::OwnDungeon) && // and isn't a small key when small keys are in their own dungeon
540-
(!location->currentItem.isBigKey() || settings.dungeon_big_keys != PlacementOption::OwnDungeon) && // and isn't a big key when big keys are in their own dungeon
541-
(!location->isRaceModeLocation || settings.progression_dungeons == ProgressionDungeons::Disabled) && // and isn't a race mode location when race mode/require bosses is enabled...
542-
( location->hintPriority != "Always" || !world.getSettings().use_always_hints)) // and the hint priority is not "Always" when we're using always hints...
522+
(location->hintPriority != "Always" || !world.getSettings().use_always_hints)) // and the hint priority is not "Always" when we're using always hints...
543523
{
544524
// Then the item is a possible item hint location
545525
possibleItemHintLocations.push_back(location.get());

logic/Location.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ class Location
7575
bool plandomized;
7676
bool hasBeenHinted;
7777
bool hasKnownVanillaItem;
78+
bool hasExpectedItem;
7879
bool hasDungeonDependency;
7980
Item originalItem;
8081
Item currentItem;
@@ -88,6 +89,9 @@ class Location
8889
std::unordered_set<GameItem> itemsInComputedRequirement = {};
8990
std::vector<Location*> pathLocations = {};
9091

92+
// Locations which always require completing this one first regardless of what item it has
93+
std::list<Location*> outsideDependentLocations = {};
94+
9195
// Variables used for the searching algorithm
9296
bool hasBeenFound = false;
9397

@@ -113,6 +117,7 @@ class Location
113117
plandomized(false),
114118
hasBeenHinted(false),
115119
hasKnownVanillaItem(false),
120+
hasExpectedItem(false),
116121
hasDungeonDependency(false),
117122
originalItem(GameItem::INVALID, nullptr),
118123
currentItem(GameItem::INVALID, nullptr),

0 commit comments

Comments
 (0)