Esempio n. 1
0
        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);
                }
            }
        }