From b9059c8bd9fdde686dd4f70832e763425bbab744 Mon Sep 17 00:00:00 2001 From: MattEqualsCoder Date: Thu, 11 Jun 2026 16:07:44 -0400 Subject: [PATCH] Fix invalid GT hints --- .../Generation/GameHintService.cs | 3 +- .../TrackerCouncil.Smz3.UI.csproj | 2 +- .../Text/GameHintTests.cs | 65 ++++++++++++++++++- 3 files changed, 66 insertions(+), 4 deletions(-) diff --git a/src/TrackerCouncil.Smz3.SeedGenerator/Generation/GameHintService.cs b/src/TrackerCouncil.Smz3.SeedGenerator/Generation/GameHintService.cs index 857a848f..5d33f0b8 100644 --- a/src/TrackerCouncil.Smz3.SeedGenerator/Generation/GameHintService.cs +++ b/src/TrackerCouncil.Smz3.SeedGenerator/Generation/GameHintService.cs @@ -10,6 +10,7 @@ using TrackerCouncil.Smz3.Data.Services; using TrackerCouncil.Smz3.Data.WorldData; using TrackerCouncil.Smz3.Data.WorldData.Regions; +using TrackerCouncil.Smz3.Data.WorldData.Regions.Zelda; using TrackerCouncil.Smz3.SeedGenerator.Contracts; using TrackerCouncil.Smz3.SeedGenerator.GameModes; using TrackerCouncil.Smz3.SeedGenerator.Infrastructure; @@ -394,7 +395,7 @@ private PlayerHintTile GetBasicLocationHint(Location location) private LocationUsefulness CheckIfLocationsAreImportant(List allWorlds, List locations, List? goalLocations, Reward? ignoredReward = null, List? defaultItems = null) { var worldLocations = allWorlds.SelectMany(x => x.Locations) - .Select(x => locations.Contains(x) ? new Location(x, ItemType.TwentyRupees) : x) + .Select(x => locations.Contains(x) && !(!x.World.Config.KeysanityForRegion(x.Region) && x.Region.IsRegionItem(x.Item) && x.Region is GanonsTower) ? new Location(x, ItemType.TwentyRupees) : x) .ToList(); try diff --git a/src/TrackerCouncil.Smz3.UI/TrackerCouncil.Smz3.UI.csproj b/src/TrackerCouncil.Smz3.UI/TrackerCouncil.Smz3.UI.csproj index 63814d97..6f760a13 100644 --- a/src/TrackerCouncil.Smz3.UI/TrackerCouncil.Smz3.UI.csproj +++ b/src/TrackerCouncil.Smz3.UI/TrackerCouncil.Smz3.UI.csproj @@ -6,7 +6,7 @@ true app.manifest true - 10.0.1 + 10.0.2 SMZ3CasRandomizer Assets\smz3.ico $(MSBuildProjectName.Replace(" ", "_")) diff --git a/tests/TrackerCouncil.Smz3.Tests/Text/GameHintTests.cs b/tests/TrackerCouncil.Smz3.Tests/Text/GameHintTests.cs index 76941b2b..f79a4761 100644 --- a/tests/TrackerCouncil.Smz3.Tests/Text/GameHintTests.cs +++ b/tests/TrackerCouncil.Smz3.Tests/Text/GameHintTests.cs @@ -184,7 +184,7 @@ void VanillaGoalSwordAndSilversHints() [Fact] void KeysanityHints() { - var world = GetVanillaWorld(new GameModeOptions() { KeysanityMode = KeysanityMode.Both } ); + var world = GetVanillaWorld(new GameModeOptions() { KeysanityMode = KeysanityMode.Both }); var hintService = GetGameHintService(); world.FindLocation(LocationId.KakarikoTavern).Item = new Item(ItemType.ProgressiveSword, world); @@ -295,7 +295,7 @@ void MultiworldHints() [Fact] void MetroidBossTokensHints() { - var world = GetVanillaWorld(new GameModeOptions { ShuffleMetroidBossTokens = true } ); + var world = GetVanillaWorld(new GameModeOptions { ShuffleMetroidBossTokens = true }); var hintService = GetGameHintService(); // Move the bow and boots out of eastern palace for testing @@ -376,6 +376,67 @@ void AllDungeonsHints() Assert.Equal(LocationUsefulness.Useless, hintService.GetUsefulness(world.Locations.Where(x => x.Region is EasternPalace).ToList(), [world], null)); } + + [Fact] + void GanonsTowerDefaultHints() + { + var world = GetVanillaWorld(); + var hintService = GetGameHintService(); + + // GT should be nice to have by default due to the tunic + var ganonsTower = world.Locations.Where(x => x.Region is GanonsTower).ToList(); + Assert.Equal(LocationUsefulness.NiceToHave, hintService.GetUsefulness(ganonsTower, [world], null)); + } + + [Fact] + void GanonsTowerSilverArrowsHints() + { + var world = GetVanillaWorld(); + var hintService = GetGameHintService(); + + // Move SilverArrows from the PyramidFairy into GT + SwapLocationItems(world.FindLocation(LocationId.PyramidFairyRight), world.FindLocation(LocationId.GanonsTowerBigChest)); + + // GT should be mandatory due to the silver arrows + var ganonsTower = world.Locations.Where(x => x.Region is GanonsTower).ToList(); + Assert.Equal(LocationUsefulness.Mandatory, hintService.GetUsefulness(ganonsTower, [world], null)); + } + + [Fact] + void GanonsTowerKeysanityHints() + { + var world = GetVanillaWorld(new GameModeOptions() { KeysanityMode = KeysanityMode.Both }); + var hintService = GetGameHintService(); + + // GT shows up as Key in keysanity as it is mandatory but a key (obviously) + var ganonsTower = world.Locations.Where(x => x.Region is GanonsTower).ToList(); + Assert.Equal(LocationUsefulness.Key, hintService.GetUsefulness(ganonsTower, [world], null)); + } + [Fact] + void CrateriaBossKeycardKeysanityHints() + { + var world = GetVanillaWorld(new GameModeOptions() { KeysanityMode = KeysanityMode.Both }); + var hintService = GetGameHintService(); + + var ganonsTower = world.Locations.Where(x => x.Region is GanonsTower).ToList(); + + // Move all keys out of GT + foreach (var location in ganonsTower.Where(x => x.ItemType is ItemType.KeyGT or ItemType.BigKeyGT)) + { + var otherLocation = world.Locations.First(x => x.ItemType is ItemType.HeartPiece && x.Region is not GanonsTower); + SwapLocationItems(location, otherLocation); + } + + // GT should be marked as nice to have due to the tunic and no keys + Assert.Equal(LocationUsefulness.NiceToHave, hintService.GetUsefulness(ganonsTower, [world], null)); + + // GT should show up as Key if the crateria boss keycard is in there + var crateriaBossKeycard = world.Locations.First(x => x.ItemType == ItemType.CardCrateriaBoss); + var gtBigChest = world.FindLocation(LocationId.GanonsTowerBigChest); + SwapLocationItems(crateriaBossKeycard, gtBigChest); + Assert.Equal(LocationUsefulness.Key, hintService.GetUsefulness(ganonsTower, [world], null)); + } + #region Private methods private void SwapLocationItems(Location one, Location two) {