Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/TrackerCouncil.Smz3.Data/Options/GameModeOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ public class GameModeOptions
public int MinGanonsTowerCrystalCount { get; set; } = 7;
public int MaxGanonsTowerCrystalCount { get; set; } = 7;
public KeysanityMode KeysanityMode { get; set; }
public bool SkipTourianBossDoor { get; set; }
public bool PlaceGTBigKeyInGT { get; set; }
public TourianBossDoor TourianBossDoor { get; set; }
public KeysanityGanonsTowerBigKeyLocation KeysanityGanonsTowerBigKeyLocation { get; set; }
public bool ShuffleMetroidBossTokens { get; set; }
public bool OpenPyramid { get; set; }
public PyramidHole PyramidHole { get; set; }

public GameModeOptions Clone()
{
Expand Down
4 changes: 2 additions & 2 deletions src/TrackerCouncil.Smz3.Data/Options/PlandoConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ public PlandoConfig(World world)
LiftOffOnGoalCompletion = world.Config.GameModeOptions.LiftOffOnGoalCompletion;

KeysanityMode = world.Config.GameModeOptions.KeysanityMode;
SkipTourianBossDoor = world.Config.GameModeOptions.SkipTourianBossDoor;
OpenPyramid = world.Config.GameModeOptions.OpenPyramid;
SkipTourianBossDoor = world.Config.GameModeOptions.TourianBossDoor == TourianBossDoor.Open;
OpenPyramid = world.Config.GameModeOptions.PyramidHole == PyramidHole.Open;

Items = world.Locations
.ToDictionary(x => x.ToString(), x => x.Item.Type);
Expand Down
12 changes: 9 additions & 3 deletions src/TrackerCouncil.Smz3.Data/Options/RandomizerOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,16 @@ public static RandomizerOptions Load(string loadPath, string savePath, bool isYa
options.SeedOptions.GameModeOptions.GanonCrystalCount = options.SeedOptions.GanonCrystalCount.Value;
options.SeedOptions.GameModeOptions.GanonsTowerCrystalCount = options.SeedOptions.GanonsTowerCrystalCount!.Value;
options.SeedOptions.GameModeOptions.TourianBossCount = options.SeedOptions.TourianBossCount!.Value;
options.SeedOptions.GameModeOptions.SkipTourianBossDoor = options.SeedOptions.SkipTourianBossDoor!.Value;
options.SeedOptions.GameModeOptions.TourianBossDoor = options.SeedOptions.SkipTourianBossDoor!.Value
? TourianBossDoor.Open
: TourianBossDoor.Closed;
options.SeedOptions.GameModeOptions.KeysanityMode = options.SeedOptions.KeysanityMode!.Value;
options.SeedOptions.GameModeOptions.PlaceGTBigKeyInGT = options.SeedOptions.PlaceGTBigKeyInGT!.Value;
options.SeedOptions.GameModeOptions.OpenPyramid = options.SeedOptions.OpenPyramid!.Value;
options.SeedOptions.GameModeOptions.KeysanityGanonsTowerBigKeyLocation =
options.SeedOptions.PlaceGTBigKeyInGT!.Value
? KeysanityGanonsTowerBigKeyLocation.GanonsTower
: KeysanityGanonsTowerBigKeyLocation.Anywhere;
options.SeedOptions.GameModeOptions.PyramidHole =
options.SeedOptions.OpenPyramid!.Value ? PyramidHole.Open : PyramidHole.Closed;
options.SeedOptions.GanonCrystalCount = null;
options.SeedOptions.GanonsTowerCrystalCount = null;
options.SeedOptions.TourianBossCount = null;
Expand Down
2 changes: 1 addition & 1 deletion src/TrackerCouncil.Smz3.Data/Options/RandomizerPreset.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public static List<RandomizerPreset> GetDefaultPresets()
GanonCrystalCount = 0,
GanonsTowerCrystalCount = 0,
TourianBossCount = 0,
OpenPyramid = true
PyramidHole = PyramidHole.Open
},
}
},
Expand Down
2 changes: 1 addition & 1 deletion src/TrackerCouncil.Smz3.Data/ParsedRom/ParsedRomDetails.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public class ParsedRomDetails
public required int GanonsTowerCrystalCount { get; set; }
public required int GanonCrystalCount { get; set; }
public required int TourianBossCount { get; set; }
public required bool OpenPyarmid { get; set; }
public required bool OpenPyramid { get; set; }
public required bool SkipTourianBossDoor { get; set; }
public required bool SpinJumpAnimations { get; set; }
public required GameModeType GameModeType { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,8 @@ public void LoadPlando(PlandoConfig config)

_model.GameSettings.AdditionalSettings.GanonsTowerCrystalCount = _model.PlandoConfig.GanonsTowerCrystalCount;
_model.GameSettings.AdditionalSettings.KeysanityMode = _model.PlandoConfig.KeysanityMode;
_model.GameSettings.AdditionalSettings.SkipTourianBossDoor = _model.PlandoConfig.SkipTourianBossDoor;
_model.GameSettings.AdditionalSettings.OpenPyramid = _model.PlandoConfig.OpenPyramid;
_model.GameSettings.AdditionalSettings.TourianBossDoor = _model.PlandoConfig.SkipTourianBossDoor ? TourianBossDoor.Open : TourianBossDoor.Closed;
_model.GameSettings.AdditionalSettings.PyramidHole = _model.PlandoConfig.OpenPyramid ? PyramidHole.Open : PyramidHole.Closed;

var hasShuffleMetroidBossTokens = false;
foreach (var reward in _model.PlandoConfig.Rewards)
Expand Down Expand Up @@ -532,7 +532,7 @@ public void UpdateSummaryText()
sb.AppendLine($" - GT Crystal Count: {details.GanonsTowerCrystalCount}");
sb.AppendLine($" - Ganon Crystal Count: {details.GanonCrystalCount}");
sb.AppendLine($" - Tourian Boss Count: {details.TourianBossCount}");
sb.AppendLine($" - Open Pyramid: {details.OpenPyarmid}");
sb.AppendLine($" - Open Pyramid: {details.OpenPyramid}");
}

sb.AppendLine($" - IsMultiworld: {ynResponses[details.IsMultiworld]}");
Expand All @@ -552,7 +552,7 @@ public void UpdateSummaryText()
if (_model.IsPlando)
{
_model.GameSettings.GoalSettings.HideCrystalBossCount = _model.PlandoConfig?.HideGoalCount == true;
hiddenProperties.Add("PlaceGTBigKeyInGT");;
hiddenProperties.Add("KeysanityGanonsTowerBigKeyLocation");;
hiddenProperties.Add("MinGanonsTowerCrystalCount");
hiddenProperties.Add("MaxGanonsTowerCrystalCount");
hiddenProperties.Add("MinGanonCrystalCount");
Expand Down Expand Up @@ -647,7 +647,7 @@ public void UpdateSummaryText()
if (_model.GameSettings.AdditionalSettings.KeysanityMode is KeysanityMode.None
or KeysanityMode.SuperMetroid)
{
hiddenProperties.Add("PlaceGTBigKeyInGT");
hiddenProperties.Add("KeysanityGanonsTowerBigKeyLocation");
}

sb.AppendLine("Game Mode");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ public int MaxGanonsTowerCrystalCount
}
}

[DynamicFormFieldBoolComboBox("Pyramid access:", falseText: "Opens after Ganon's Tower is completed", trueText: "Open by default", trueFirst: false)]
public bool OpenPyramid { get; set; }
[DynamicFormFieldComboBox(label: "Pyramid access:")]
public PyramidHole PyramidHole { get; set; }

[DynamicFormFieldBoolComboBox("Metroid boss tokens:", falseText: "Disabled", trueText: "Shuffled with dungeon rewards", trueFirst: false)]
public bool ShuffleMetroidBossTokens { get; set; }
Expand All @@ -59,15 +59,15 @@ public KeysanityMode KeysanityMode
}
}

[DynamicFormFieldBoolComboBox("Metroid statue room access:", falseText: "Require Crateria boss keycard", trueText: "Open by default", visibleWhenTrue: nameof(IsMetroidKeysanity))]
public bool SkipTourianBossDoor { get; set; }
[DynamicFormFieldComboBox(label: "Metroid statue room access:")]
public TourianBossDoor TourianBossDoor { get; set; }

[DynamicFormFieldBoolComboBox("Ganon's Tower big key location:", falseText: "Fully randomized", trueText: "In Ganon's Tower", trueFirst: false, visibleWhenTrue: nameof(IsZeldaKeysanity))]
public bool PlaceGTBigKeyInGT { get; set; }
[DynamicFormFieldComboBox(label: "Ganon's Tower big key location:", visibleWhenTrue: nameof(IsZeldaKeysanity))]
public KeysanityGanonsTowerBigKeyLocation KeysanityGanonsTowerBigKeyLocation { get; set; }

public bool IsMetroidKeysanity => KeysanityMode is KeysanityMode.Both or KeysanityMode.SuperMetroid;
public bool IsMetroidKeysanity => KeysanityMode is KeysanityMode.Both or KeysanityMode.SuperMetroid or KeysanityMode.Random;

public bool IsZeldaKeysanity => KeysanityMode is KeysanityMode.Both or KeysanityMode.Zelda;
public bool IsZeldaKeysanity => KeysanityMode is KeysanityMode.Both or KeysanityMode.Zelda or KeysanityMode.Random;

public bool AlwaysHidden => false;
public bool RandomizeGoalCounts
Expand Down
2 changes: 1 addition & 1 deletion src/TrackerCouncil.Smz3.Data/WorldData/Location.cs
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ public bool CanFill(Item item, Progression items)
if (World.Config.MultiWorld && item.Type == ItemType.ProgressiveShield && item.World != World)
fillable = false;
// If the user wants the GT key in GT for the guessing game while playing Keysanity
else if (item is { Type: ItemType.BigKeyGT, World.Config.ZeldaKeysanity: true, World.Config.GameModeOptions.PlaceGTBigKeyInGT: true })
else if (item is { Type: ItemType.BigKeyGT, World.Config.ZeldaKeysanity: true, World.Config.GameModeOptions.KeysanityGanonsTowerBigKeyLocation: KeysanityGanonsTowerBigKeyLocation.GanonsTower })
fillable = fillable && Region is GanonsTower;

Item = oldItem;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public void UpdateMotherBrainAccessibility(Progression progression, bool hasAltG
else if (World.LegacyWorld == null)
{
var canAccessStatueRoom = Terminator.Locations.First().IsAvailable(progression) &&
(!World.Config.MetroidKeysanity || World.Config.GameModeOptions.SkipTourianBossDoor ||
(!World.Config.MetroidKeysanity || World.Config.GameModeOptions.TourianBossDoor == TourianBossDoor.Open ||
progression.CardCrateriaBoss);

var rewardCount = World.Config.GameModeOptions.ShuffleMetroidBossTokens
Expand All @@ -147,7 +147,7 @@ public void UpdateMotherBrainAccessibility(Progression progression, bool hasAltG
else
{
var canAccessStatueRoom = World.LegacyWorld.IsLocationAccessible((int)LocationId.CrateriaTerminator, progression.LegacyProgression) &&
(!World.Config.MetroidKeysanity || World.Config.GameModeOptions.SkipTourianBossDoor ||
(!World.Config.MetroidKeysanity || World.Config.GameModeOptions.TourianBossDoor == TourianBossDoor.Open ||
progression.CardCrateriaBoss);

var canEnterTourian = World.Rewards.Count(x => x.MarkedReward?.IsInCategory(RewardCategory.Metroid) == true && x.HasReceivedReward) >= tourianBossRequirement;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public void UpdateGanonAccessibility(Progression progression, Progression assume
World.GanonsTower.Locations.All(x => x.IsAvailable(assumedKeyProgression)) &&
World.GanonsTower.CanBeatBoss(assumedKeyProgression, true));

var isPyramidOpen = World.Config.GameModeOptions.OpenPyramid || canClimbGt;
var isPyramidOpen = World.Config.GameModeOptions.PyramidHole == PyramidHole.Open || canClimbGt;
var hasMetGoal = hasAltGameMode
? isAltGameModeComplete
: World.Config.GameModeOptions.SelectedGameModeType == GameModeType.Vanilla
Expand All @@ -114,7 +114,7 @@ public void UpdateGanonAccessibility(Progression progression, Progression assume
World.LegacyWorld.IsLocationAccessible((int)x.Id,
assumedKeyProgression.LegacyProgression)));

var isPyramidOpen = World.Config.GameModeOptions.OpenPyramid || canClimbGt;
var isPyramidOpen = World.Config.GameModeOptions.PyramidHole == PyramidHole.Open || canClimbGt;
var hasMetGoal = World.Config.GameModeOptions.SelectedGameModeType == GameModeType.Vanilla
? numAcquiredCrystals >= ganonCrystalRequirement
: progression is { AllCrystals: true, AllPendants: true, MetroidBossCount: >= 4, Agahnim: true };
Expand Down
20 changes: 20 additions & 0 deletions src/TrackerCouncil.Smz3.Data/WorldData/World.cs
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,26 @@ public Boss GetBossOfType(BossType type)

public void Setup(Random rnd)
{
if (Config.GameModeOptions.KeysanityMode == KeysanityMode.Random)
{
Config.GameModeOptions.KeysanityMode = rnd.NextExcludingLast<KeysanityMode>();
}

if (Config.GameModeOptions.KeysanityGanonsTowerBigKeyLocation == KeysanityGanonsTowerBigKeyLocation.Random)
{
Config.GameModeOptions.KeysanityGanonsTowerBigKeyLocation = rnd.NextExcludingLast<KeysanityGanonsTowerBigKeyLocation>();
}

if (Config.GameModeOptions.PyramidHole == PyramidHole.Random)
{
Config.GameModeOptions.PyramidHole = rnd.NextExcludingLast<PyramidHole>();
}

if (Config.GameModeOptions.TourianBossDoor == TourianBossDoor.Random)
{
Config.GameModeOptions.TourianBossDoor = rnd.NextExcludingLast<TourianBossDoor>();
}

SetMedallions(rnd);
SetRewards(rnd);
SetBottles(rnd);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public override IEnumerable<GeneratedPatch> GetChanges(GetPatchesRequest data)
}

// Open pyramid
if (data.Config.GameModeOptions.OpenPyramid)
if (data.Config.GameModeOptions.PyramidHole == PyramidHole.Open)
{
yield return new GeneratedPatch(0x40008B, [0x01]);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public override IEnumerable<GeneratedPatch> GetChanges(GetPatchesRequest data)

foreach (var door in s_doorList)
{
if (door[0] == 0x99BD && data.World.Config.GameModeOptions.SkipTourianBossDoor)
if (door[0] == 0x99BD && data.World.Config.GameModeOptions.TourianBossDoor == TourianBossDoor.Open)
{
continue;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,15 @@ private IEnumerable<GeneratedPatch> GetFullTextPatchList(GetPatchesRequest data)
GameLines.TriforceRoom, _plandoText.TriforceRoom, true);

var gtCrystalCount = data.World.Config.GameModeOptions.GanonsTowerCrystalCount;
SetText(StringTable.GanonsTowerGoalSign,
GameLines.GanonsTowerGoalSign, _plandoText.GanonsTowerGoalSign, false, gtCrystalCount == 1 ? "1 crystal" : $"{gtCrystalCount} crystals");
var gtCrystalCountText = gtCrystalCount == 1 ? "1 crystal" : $"{gtCrystalCount} crystals";
var gtKeyLocation = data.Worlds.SelectMany(world => world.Locations)
.FirstOrDefault(l => l.ItemIs(ItemType.BigKeyGT, data.World));
var gtKeyLocationPlayer = data.Config.MultiWorld && gtKeyLocation?.World != data.World
? gtKeyLocation?.World.Player ?? "another player"
: "You";

SetText(StringTable.GanonsTowerGoalSign, GameLines.GanonsTowerGoalSign, _plandoText.GanonsTowerGoalSign, false,
gtCrystalCountText, gtKeyLocationPlayer, gtKeyLocation?.Region.Area ?? "unknown location");

SetText(StringTable.GanonGoalSign, null, _plandoText.GanonGoalSign ?? gameModeText?.GanonGoalSign);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,14 @@ public override bool IsComplete(World world)
return progression is { AllPendants: true, AllCrystals: true } &&
progression.MetroidBossCount >= 4 &&
world.AllBosses.First(x => x.Type == BossType.Agahnim).Defeated &&
(_tracker.AutoTracker?.OpenPyramid == true || world.AllBosses.First(x => x.Type == BossType.Ganon).Defeated || world.Config.GameModeOptions.OpenPyramid);
(_tracker.AutoTracker?.OpenPyramid == true || world.AllBosses.First(x => x.Type == BossType.Ganon).Defeated || world.Config.GameModeOptions.PyramidHole == PyramidHole.Open);
}

public override void UpdateWorld(World world, Random rng, GameModeOptions gameModeOptions)
{
gameModeOptions.GanonCrystalCount = 7;
gameModeOptions.TourianBossCount = 4;
gameModeOptions.OpenPyramid = false;
gameModeOptions.PyramidHole = PyramidHole.Closed;
}

public override void UpdateInitialTrackerState(GameModeOptions gameModeOptions, TrackerState trackerState,
Expand Down Expand Up @@ -108,7 +108,7 @@ public override List<GoalUiDetails> GetGoalUiDetails(World world, Progression pr
dungeons++;
}

if (_tracker.AutoTracker?.OpenPyramid == true || world.AllBosses.First(x => x.Type == BossType.Ganon).Defeated || world.Config.GameModeOptions.OpenPyramid)
if (_tracker.AutoTracker?.OpenPyramid == true || world.AllBosses.First(x => x.Type == BossType.Ganon).Defeated || world.Config.GameModeOptions.PyramidHole == PyramidHole.Open)
{
dungeons++;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -439,14 +439,14 @@ private LocationUsefulness VerifyWorld(Playthrough.Sphere sphere, World world, L
}

// Make sure the player can access tourian
if (world.Config is { MetroidKeysanity: true, GameModeOptions.SkipTourianBossDoor: false } &&
if (world.Config is { MetroidKeysanity: true, GameModeOptions.TourianBossDoor: TourianBossDoor.Closed } &&
!progression.Contains(ItemType.CardCrateriaBoss))
{
return LocationUsefulness.Mandatory;
}

// Make sure the player can access Ganon
if (!world.Config.GameModeOptions.OpenPyramid && !worldLocations.ContainsKey(LocationId.GanonsTowerMoldormChest))
if (world.Config.GameModeOptions.PyramidHole == PyramidHole.Closed && !worldLocations.ContainsKey(LocationId.GanonsTowerMoldormChest))
{
return LocationUsefulness.Mandatory;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ public SeedData GeneratePlandoSeed(RandomizerOptions options, PlandoConfig pland
config.GameModeOptions.LiftOffOnGoalCompletion = plandoConfig.LiftOffOnGoalCompletion;

config.GameModeOptions.KeysanityMode = plandoConfig.KeysanityMode;
config.GameModeOptions.SkipTourianBossDoor = plandoConfig.SkipTourianBossDoor;
config.GameModeOptions.OpenPyramid = plandoConfig.OpenPyramid;
config.GameModeOptions.TourianBossDoor = plandoConfig.SkipTourianBossDoor ? TourianBossDoor.Open : TourianBossDoor.Closed;
config.GameModeOptions.PyramidHole = plandoConfig.OpenPyramid ? PyramidHole.Open : PyramidHole.Closed;

config.LogicConfig = plandoConfig.Logic.Clone();
return plandomizer.GenerateSeed(config, CancellationToken.None);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,12 +207,12 @@ private string GetSpoilerLog(RandomizerOptions options, SeedData seed, bool conf

if (world.Config.MetroidKeysanity)
{
keysanityOptions += $", SkipTourianBossDoor = {gameModeOptions.SkipTourianBossDoor}";
keysanityOptions += $", TourianBossDoor = {gameModeOptions.TourianBossDoor}";
}

if (world.Config.ZeldaKeysanity)
{
keysanityOptions += $", PlaceGTBigKeyInGT = {gameModeOptions.PlaceGTBigKeyInGT}";
keysanityOptions += $", KeysanityGanonsTowerBigKeyLocation = {gameModeOptions.KeysanityGanonsTowerBigKeyLocation}";
}
}
else
Expand All @@ -221,7 +221,7 @@ private string GetSpoilerLog(RandomizerOptions options, SeedData seed, bool conf
}

log.AppendLine(
$"Additional Settings: GanonsTowerCrystalCount = {gameModeOptions.GanonsTowerCrystalCount}, OpenPyramid = {gameModeOptions.OpenPyramid}, ShuffleMetroidBossTokens = {gameModeOptions.ShuffleMetroidBossTokens}, {keysanityOptions}");
$"Additional Settings: GanonsTowerCrystalCount = {gameModeOptions.GanonsTowerCrystalCount}, PyramidHole = {gameModeOptions.PyramidHole}, ShuffleMetroidBossTokens = {gameModeOptions.ShuffleMetroidBossTokens}, {keysanityOptions}");

log.AppendLine();
}
Expand Down
Loading
Loading