private static HashSet <string> GetRandomizedItems() // not suitable outside randomizer, because it can't compute duplicate items { HashSet <string> items = new HashSet <string>(); if (RandomizerMod.Instance.Settings.RandomizeDreamers) { items.UnionWith(LogicManager.GetItemsByPool("Dreamer")); } if (RandomizerMod.Instance.Settings.RandomizeSkills) { items.UnionWith(LogicManager.GetItemsByPool("Skill")); } if (RandomizerMod.Instance.Settings.RandomizeCharms) { items.UnionWith(LogicManager.GetItemsByPool("Charm")); } if (RandomizerMod.Instance.Settings.RandomizeKeys) { items.UnionWith(LogicManager.GetItemsByPool("Key")); } if (RandomizerMod.Instance.Settings.RandomizeMaskShards) { items.UnionWith(LogicManager.GetItemsByPool("Mask")); } if (RandomizerMod.Instance.Settings.RandomizeVesselFragments) { items.UnionWith(LogicManager.GetItemsByPool("Vessel")); } if (RandomizerMod.Instance.Settings.RandomizePaleOre) { items.UnionWith(LogicManager.GetItemsByPool("Ore")); } if (RandomizerMod.Instance.Settings.RandomizeCharmNotches) { items.UnionWith(LogicManager.GetItemsByPool("Notch")); } if (RandomizerMod.Instance.Settings.RandomizeGeoChests) { items.UnionWith(LogicManager.GetItemsByPool("Geo")); } if (RandomizerMod.Instance.Settings.RandomizeRancidEggs) { items.UnionWith(LogicManager.GetItemsByPool("Egg")); } if (RandomizerMod.Instance.Settings.RandomizeRelics) { items.UnionWith(LogicManager.GetItemsByPool("Relic")); } if (RandomizerMod.Instance.Settings.RandomizeMaps) { items.UnionWith(LogicManager.GetItemsByPool("Map")); } if (RandomizerMod.Instance.Settings.RandomizeStags) { items.UnionWith(LogicManager.GetItemsByPool("Stag")); } if (RandomizerMod.Instance.Settings.RandomizeGrubs) { items.UnionWith(LogicManager.GetItemsByPool("Grub")); } if (RandomizerMod.Instance.Settings.RandomizeWhisperingRoots) { items.UnionWith(LogicManager.GetItemsByPool("Root")); } if (RandomizerMod.Instance.Settings.RandomizeRocks) { items.UnionWith(LogicManager.GetItemsByPool("Rock")); } if (RandomizerMod.Instance.Settings.RandomizeSoulTotems) { items.UnionWith(LogicManager.GetItemsByPool("Soul")); } if (RandomizerMod.Instance.Settings.RandomizePalaceTotems) { items.UnionWith(LogicManager.GetItemsByPool("PalaceSoul")); } if (RandomizerMod.Instance.Settings.RandomizeLoreTablets) { items.UnionWith(LogicManager.GetItemsByPool("Lore")); } if (RandomizerMod.Instance.Settings.RandomizeLifebloodCocoons) { items.UnionWith(LogicManager.GetItemsByPool("Cocoon")); } if (RandomizerMod.Instance.Settings.RandomizeGrimmkinFlames) { items.UnionWith(LogicManager.GetItemsByPool("Flame")); } if (RandomizerMod.Instance.Settings.Cursed) { items.Remove("Shade_Soul"); items.Remove("Descending_Dark"); items.Remove("Abyss_Shriek"); int i = 0; List <string> iterate = items.ToList(); foreach (string item in iterate) { switch (LogicManager.GetItemDef(item).pool) { case "Mask": case "Vessel": case "Ore": case "Notch": case "Geo": case "Egg": case "Relic": case "Rock": case "Soul": case "PalaceSoul": case "Lore": items.Remove(item); items.Add("1_Geo_(" + i + ")"); i++; break; } } items.UnionWith(LogicManager.GetItemsByPool("Cursed")); } if (RandomizerMod.Instance.Settings.DuplicateMajorItems) { duplicatedItems = new List <string>(); foreach (string majorItem in LogicManager.ItemNames.Where(_item => LogicManager.GetItemDef(_item).majorItem).ToList()) { if (Randomizer.startItems.Contains(majorItem)) { continue; } if (RandomizerMod.Instance.Settings.Cursed && (majorItem == "Vengeful_Spirit" || majorItem == "Desolate_Dive" || majorItem == "Howling_Wraiths")) { continue; } duplicatedItems.Add(majorItem); } } return(items); }
private static void SecondPass() { Log("Beginning second pass of item placement..."); im.TransferStandby(); // We fill the remaining locations and shops with the leftover junk while (im.anyItems) { string placeItem = im.NextItem(checkFlag: false); string placeLocation; if (im.anyLocations) { placeLocation = im.NextLocation(checkLogic: false); } else { placeLocation = LogicManager.ShopNames[rand.Next(5)]; } im.PlaceItemFromStandby(placeItem, placeLocation); } // try to guarantee no empty shops if (im.normalFillShops && ItemManager.shopItems.Any(kvp => !kvp.Value.Any())) { Log("Exited randomizer with empty shop. Attempting repair..."); Dictionary <string, List <string> > nonprogressionShopItems = ItemManager.shopItems.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Where(i => !LogicManager.GetItemDef(i).progression).ToList()); if (nonprogressionShopItems.Select(kvp => kvp.Value.Count).Aggregate(0, (total, next) => total + next) >= 5) { int i = 0; while (ItemManager.shopItems.FirstOrDefault(kvp => !kvp.Value.Any()).Key is string emptyShop && nonprogressionShopItems.FirstOrDefault(kvp => kvp.Value.Count > 1).Key is string fullShop) { string item = ItemManager.shopItems[fullShop].First(); ItemManager.shopItems[emptyShop].Add(item); ItemManager.shopItems[fullShop].Remove(item); nonprogressionShopItems[emptyShop].Add(item); nonprogressionShopItems[fullShop].Remove(item); i++; if (i > 5) { LogError("Emergency exit from shop repair."); break; } } } Log("Successfully repaired shops."); } if (im.anyLocations) { LogError("Exited item randomizer with unfilled locations."); } }
private static bool ValidateItemRandomization() { RandomizerMod.Instance.Log("Beginning item placement validation..."); List <string> unfilledLocations; if (im.normalFillShops) { unfilledLocations = im.randomizedLocations.Except(ItemManager.nonShopItems.Keys).Except(ItemManager.shopItems.Keys).ToList(); } else { unfilledLocations = im.randomizedLocations.Except(ItemManager.nonShopItems.Keys).Except(LogicManager.ShopNames).ToList(); } if (unfilledLocations.Any()) { Log("Unable to validate!"); string m = "The following locations were not filled: "; foreach (string l in unfilledLocations) { m += l + ", "; } Log(m); return(false); } HashSet <(string, string)> LIpairs = new HashSet <(string, string)>(ItemManager.nonShopItems.Select(kvp => (kvp.Key, kvp.Value))); foreach (var kvp in ItemManager.shopItems) { LIpairs.UnionWith(kvp.Value.Select(i => (kvp.Key, i))); } var lookup = LIpairs.ToLookup(pair => pair.Item2, pair => pair.Item1).Where(x => x.Count() > 1); if (lookup.Any()) { Log("Unable to validate!"); string m = "The following items were placed multiple times: "; foreach (var x in lookup) { m += x.Key + ", "; } Log(m); string l = "The following locations were filled by these items: "; foreach (var x in lookup) { foreach (string k in x) { l += k + ", "; } } Log(l); return(false); } /* * // Potentially useful debug logs * foreach (string item in ItemManager.GetRandomizedItems()) * { * if (ItemManager.nonShopItems.Any(kvp => kvp.Value == item)) * { * Log($"Placed {item} at {ItemManager.nonShopItems.First(kvp => kvp.Value == item).Key}"); * } * else if (ItemManager.shopItems.Any(kvp => kvp.Value.Contains(item))) * { * Log($"Placed {item} at {ItemManager.shopItems.First(kvp => kvp.Value.Contains(item)).Key}"); * } * else LogError($"Unable to find where {item} was placed."); * } * foreach (string location in ItemManager.GetRandomizedLocations()) * { * if (ItemManager.nonShopItems.TryGetValue(location, out string item)) * { * Log($"Filled {location} with {item}"); * } * else if (ItemManager.shopItems.ContainsKey(location)) * { * Log($"Filled {location}"); * } * else LogError($"{location} was not filled."); * } */ ProgressionManager pm = new ProgressionManager( RandomizerState.Validating ); pm.Add(startProgression); HashSet <string> locations = new HashSet <string>(im.randomizedLocations.Union(vm.progressionLocations)); HashSet <string> transitions = new HashSet <string>(); HashSet <string> items = im.randomizedItems; items.ExceptWith(startItems); if (RandomizerMod.Instance.Settings.RandomizeTransitions) { transitions.UnionWith(LogicManager.TransitionNames()); tm.ResetReachableTransitions(); tm.UpdateReachableTransitions(_pm: pm); } vm.ResetReachableLocations(false, pm); int passes = 0; while (locations.Any() || items.Any() || transitions.Any()) { if (RandomizerMod.Instance.Settings.RandomizeTransitions) { transitions.ExceptWith(tm.reachableTransitions); } foreach (string location in locations.Where(loc => pm.CanGet(loc)).ToList()) { locations.Remove(location); if (vm.progressionLocations.Contains(location)) { vm.UpdateVanillaLocations(location, false, pm); if (RandomizerMod.Instance.Settings.RandomizeTransitions && !LogicManager.ShopNames.Contains(location)) { tm.UpdateReachableTransitions(location, true, pm); } else if (RandomizerMod.Instance.Settings.RandomizeTransitions) { foreach (string i in vm.progressionShopItems[location]) { tm.UpdateReachableTransitions(i, true, pm); } } } else if (ItemManager.nonShopItems.TryGetValue(location, out string item)) { items.Remove(item); if (LogicManager.GetItemDef(item).progression) { pm.Add(item); if (RandomizerMod.Instance.Settings.RandomizeTransitions) { tm.UpdateReachableTransitions(item, true, pm); } } } else if (ItemManager.shopItems.TryGetValue(location, out List <string> shopItems)) { foreach (string newItem in shopItems) { items.Remove(newItem); if (LogicManager.GetItemDef(newItem).progression) { pm.Add(newItem); if (RandomizerMod.Instance.Settings.RandomizeTransitions) { tm.UpdateReachableTransitions(newItem, true, pm); } } } } else { Log("Unable to validate!"); Log($"Location {location} did not correspond to any known placement."); return(false); } } passes++; if (passes > 400) { Log("Unable to validate!"); Log("Progression: " + pm.ListObtainedProgression() + Environment.NewLine + "Grubs: " + pm.obtained[LogicManager.grubIndex] + Environment.NewLine + "Essence: " + pm.obtained[LogicManager.essenceIndex] + Environment.NewLine + "Flames: " + pm.obtained[LogicManager.flameIndex]); string m = string.Empty; foreach (string s in items) { m += s + ", "; } Log("Unable to get items: " + m); m = string.Empty; foreach (string s in locations) { m += s + ", "; } Log("Unable to get locations: " + m); m = string.Empty; foreach (string s in transitions) { m += s + ","; } Log("Unable to get transitions: " + m); LogItemPlacements(pm); return(false); } } //LogItemPlacements(pm); Log("Validation successful."); return(true); }
private static void FirstPass() { Log("Beginning first pass of item placement..."); { im.ResetReachableLocations(); vm.ResetReachableLocations(); foreach (string item in startProgression) { im.UpdateReachableLocations(item); } Log("Finished first update"); } while (true) { string placeItem; string placeLocation; switch (im.availableCount) { case 0: if (im.anyLocations) { if (im.canGuess) { if (!overflow) { Log("Entered overflow state with 0 reachable locations after placing " + ItemManager.nonShopItems.Count + " locations"); } overflow = true; placeItem = im.GuessItem(); im.PlaceProgressionToStandby(placeItem); continue; } } return; case 1: placeItem = im.ForceItem(); if (placeItem is null) { if (im.canGuess) { if (!overflow) { Log("Entered overflow state with 1 reachable location after placing " + ItemManager.nonShopItems.Count + " locations"); } overflow = true; placeItem = im.GuessItem(); im.PlaceProgressionToStandby(placeItem); continue; } else { placeItem = im.NextItem(); } } else { im.Delinearize(rand); } placeLocation = im.NextLocation(); break; default: placeItem = im.NextItem(); placeLocation = im.NextLocation(); break; } //Log($"i: {placeItem}, l: {placeLocation}, o: {overflow}, p: {LogicManager.GetItemDef(placeItem).progression}"); if (!overflow && !LogicManager.GetItemDef(placeItem).progression) { im.PlaceJunkItemToStandby(placeItem, placeLocation); } else { im.PlaceItem(placeItem, placeLocation); } } }