private void GameLoop_DayStarted(object sender, DayStartedEventArgs e)
        {
            if (!Game1.player.IsMainPlayer)
            {
                if (!this.HasLoggedMultiplayerMessage)
                {
                    this.Monitor.Log("Not main player, so no color changes will be attempted", LogLevel.Debug);
                    this.HasLoggedMultiplayerMessage = true;
                }
                return;
            }

            // Because we need to account for the possibility of previously animated ponds being no longer animated due to population changes
            //  (or no longer existing) and we are rescanning all ponds anyway, I am just gonna clear the Active Animations list every morning.
            Instance.ActiveAnimations.Clear();

            IEnumerable <BuildableGameLocation> BuildableLocations =
                from loc in Game1.locations where loc is BuildableGameLocation select loc as BuildableGameLocation;

            foreach (BuildableGameLocation bloc in BuildableLocations)
            {
                IEnumerable <FishPond> FishPonds =
                    from b in bloc.buildings where b is FishPond select b as FishPond;
                foreach (FishPond pond in FishPonds)
                {
                    bool pondHasCustomColor = false;
                    this.Monitor.Log($"Checking pond at {pond.tileX}, {pond.tileY}.", LogLevel.Trace);
                    if (Config.Enable_Custom_Pond_Coloring)
                    {
                        if (pond.fishType == -1 && Data.EmptyPondColor != null)
                        {
                            pond.overrideWaterColor.Value = Data.EmptyPondColor;
                            this.Monitor.Log($"Pond is empty and was recolored", LogLevel.Trace);
                            break;
                        }
                        foreach (PondPainterDataEntry entry in Data.Entries)
                        {
                            bool match = true;
                            //this.Monitor.Log($"Comparing with entry {entry.LogName}", LogLevel.Trace);
                            foreach (string t in entry.Tags)
                            {
                                /* For now we are removing the capability to set a default color until I find a better
                                 * way to do it.
                                 * if (t.Equals("pp_default"))
                                 * {
                                 * // pp_default trumps all other tags and immediately sets the color
                                 *      // I need a better way to do this, possibly moving it to a config instead of per pack.
                                 * ChangePondColor(pond, entry);
                                 * match = false;
                                 * break;
                                 * }
                                 * //*/
                                SObject pondFish = new SObject(pond.fishType.Value, 1, false, -1, 0);
                                if (!pondFish.HasContextTag(t))
                                {
                                    match = false;
                                }
                            }
                            if (match)
                            {
                                pondHasCustomColor = true;
                                this.Monitor.Log($"Found a match on entry {entry.LogName} with tags {String.Join(", ", entry.Tags)}.", LogLevel.Trace);
                                ChangePondColor(pond, entry);
                                break;
                            }
                        }
                    }
                    if (Config.Auto_Color_Other_Ponds_by_Dye_Color_of_Inhabitants && !pondHasCustomColor)
                    {
                        if (pond.FishCount > 0 && pond.FishCount >= Config.Minimum_Population_For_Auto_Coloring)
                        {
                            // Copying similar logic to how the roe is colored, but convert
                            // White to nearest color Snow since White means no override to the game
                            Color?c     = TailoringMenu.GetDyeColor(pond.GetFishObject());
                            Color?white = new Color?(Color.White);
                            if (c.HasValue)
                            {
                                if (c.Equals(white))
                                {
                                    c = new Color?(Color.Snow);
                                }
                            }
                            else
                            {
                                c = white;
                            }
                            pond.overrideWaterColor.Value = c.Value;
                        }
                    }
                }
            }
            this.Monitor.Log($"Finished Day Update. There are {Instance.ActiveAnimations.Count} active animations.", LogLevel.Trace);
        }
        public IEnumerable <SearchableItem> GetAll()
        {
            //
            //
            // Be careful about closure variable capture here!
            //
            // SearchableItem stores the Func<Item> to create new instances later. Loop variables passed into the
            // function will be captured, so every func in the loop will use the value from the last iteration. Use the
            // TryCreate(type, id, entity => item) form to avoid the issue, or create a local variable to pass in.
            //
            //


            IEnumerable <SearchableItem> GetAllRaw()
            {
                // get tools
                for (int q = Tool.stone; q <= Tool.iridium; q++)
                {
                    int quality = q;

                    yield return(this.TryCreate(ItemType.Tool, ToolFactory.axe, _ => ToolFactory.getToolFromDescription(ToolFactory.axe, quality)));

                    yield return(this.TryCreate(ItemType.Tool, ToolFactory.hoe, _ => ToolFactory.getToolFromDescription(ToolFactory.hoe, quality)));

                    yield return(this.TryCreate(ItemType.Tool, ToolFactory.pickAxe, _ => ToolFactory.getToolFromDescription(ToolFactory.pickAxe, quality)));

                    yield return(this.TryCreate(ItemType.Tool, ToolFactory.wateringCan, _ => ToolFactory.getToolFromDescription(ToolFactory.wateringCan, quality)));

                    if (quality != Tool.iridium)
                    {
                        yield return(this.TryCreate(ItemType.Tool, ToolFactory.fishingRod, _ => ToolFactory.getToolFromDescription(ToolFactory.fishingRod, quality)));
                    }
                }
                yield return(this.TryCreate(ItemType.Tool, this.CustomIDOffset, _ => new MilkPail())); // these don't have any sort of ID, so we'll just assign some arbitrary ones

                yield return(this.TryCreate(ItemType.Tool, this.CustomIDOffset + 1, _ => new Shears()));

                yield return(this.TryCreate(ItemType.Tool, this.CustomIDOffset + 2, _ => new Pan()));

                yield return(this.TryCreate(ItemType.Tool, this.CustomIDOffset + 3, _ => new Wand()));

                // clothing
                {
                    // items
                    HashSet <int> clothingIds = new HashSet <int>();
                    foreach (int id in Game1.clothingInformation.Keys)
                    {
                        if (id < 0)
                        {
                            continue; // placeholder data for character customization clothing below
                        }
                        clothingIds.Add(id);
                        yield return(this.TryCreate(ItemType.Clothing, id, p => new Clothing(p.ID)));
                    }

                    // character customization shirts (some shirts in this range have no data, but game has special logic to handle them)
                    for (int id = 1000; id <= 1111; id++)
                    {
                        if (!clothingIds.Contains(id))
                        {
                            yield return(this.TryCreate(ItemType.Clothing, id, p => new Clothing(p.ID)));
                        }
                    }
                }

                // wallpapers
                for (int id = 0; id < 112; id++)
                {
                    yield return(this.TryCreate(ItemType.Wallpaper, id, p => new Wallpaper(p.ID)
                    {
                        Category = SObject.furnitureCategory
                    }));
                }

                // flooring
                for (int id = 0; id < 56; id++)
                {
                    yield return(this.TryCreate(ItemType.Flooring, id, p => new Wallpaper(p.ID, isFloor: true)
                    {
                        Category = SObject.furnitureCategory
                    }));
                }

                // equipment
                foreach (int id in this.TryLoad <int, string>("Data\\Boots").Keys)
                {
                    yield return(this.TryCreate(ItemType.Boots, id, p => new Boots(p.ID)));
                }
                foreach (int id in this.TryLoad <int, string>("Data\\hats").Keys)
                {
                    yield return(this.TryCreate(ItemType.Hat, id, p => new Hat(p.ID)));
                }

                // weapons
                foreach (int id in this.TryLoad <int, string>("Data\\weapons").Keys)
                {
                    yield return(this.TryCreate(ItemType.Weapon, id, p => (p.ID >= 32 && p.ID <= 34)
                        ? (Item) new Slingshot(p.ID)
                        : new MeleeWeapon(p.ID)
                                                ));
                }

                // furniture
                foreach (int id in this.TryLoad <int, string>("Data\\Furniture").Keys)
                {
                    yield return(this.TryCreate(ItemType.Furniture, id, p => Furniture.GetFurnitureInstance(p.ID)));
                }

                // craftables
                foreach (int id in Game1.bigCraftablesInformation.Keys)
                {
                    yield return(this.TryCreate(ItemType.BigCraftable, id, p => new SObject(Vector2.Zero, p.ID)));
                }

                // objects
                foreach (int id in Game1.objectInformation.Keys)
                {
                    string[] fields = Game1.objectInformation[id]?.Split('/');

                    // secret notes
                    if (id == 79)
                    {
                        foreach (int secretNoteId in this.TryLoad <int, string>("Data\\SecretNotes").Keys)
                        {
                            yield return(this.TryCreate(ItemType.Object, this.CustomIDOffset + secretNoteId, _ =>
                            {
                                SObject note = new SObject(79, 1);
                                note.name = $"{note.name} #{secretNoteId}";
                                return note;
                            }));
                        }
                    }

                    // ring
                    else if (id != 801 && fields?.Length >= 4 && fields[3] == "Ring") // 801 = wedding ring, which isn't an equippable ring
                    {
                        yield return(this.TryCreate(ItemType.Ring, id, p => new Ring(p.ID)));
                    }

                    // item
                    else
                    {
                        // spawn main item
                        SObject item = null;
                        yield return(this.TryCreate(ItemType.Object, id, p =>
                        {
                            return item = (p.ID == 812 // roe
                                ? new ColoredObject(p.ID, 1, Color.White)
                                : new SObject(p.ID, 1)
                                           );
                        }));

                        if (item == null)
                        {
                            continue;
                        }

                        // flavored items
                        switch (item.Category)
                        {
                        // fruit products
                        case SObject.FruitsCategory:
                            // wine
                            yield return(this.TryCreate(ItemType.Object, this.CustomIDOffset * 2 + item.ParentSheetIndex, _ => new SObject(348, 1)
                            {
                                Name = $"{item.Name} Wine",
                                Price = item.Price * 3,
                                preserve = { SObject.PreserveType.Wine },
                                preservedParentSheetIndex = { item.ParentSheetIndex }
                            }));

                            // jelly
                            yield return(this.TryCreate(ItemType.Object, this.CustomIDOffset * 3 + item.ParentSheetIndex, _ => new SObject(344, 1)
                            {
                                Name = $"{item.Name} Jelly",
                                Price = 50 + item.Price * 2,
                                preserve = { SObject.PreserveType.Jelly },
                                preservedParentSheetIndex = { item.ParentSheetIndex }
                            }));

                            break;

                        // vegetable products
                        case SObject.VegetableCategory:
                            // juice
                            yield return(this.TryCreate(ItemType.Object, this.CustomIDOffset * 4 + item.ParentSheetIndex, _ => new SObject(350, 1)
                            {
                                Name = $"{item.Name} Juice",
                                Price = (int)(item.Price * 2.25d),
                                preserve = { SObject.PreserveType.Juice },
                                preservedParentSheetIndex = { item.ParentSheetIndex }
                            }));

                            // pickled
                            yield return(this.TryCreate(ItemType.Object, this.CustomIDOffset * 5 + item.ParentSheetIndex, _ => new SObject(342, 1)
                            {
                                Name = $"Pickled {item.Name}",
                                Price = 50 + item.Price * 2,
                                preserve = { SObject.PreserveType.Pickle },
                                preservedParentSheetIndex = { item.ParentSheetIndex }
                            }));

                            break;

                        // flower honey
                        case SObject.flowersCategory:
                            yield return(this.TryCreate(ItemType.Object, this.CustomIDOffset * 5 + item.ParentSheetIndex, _ =>
                            {
                                SObject honey = new SObject(Vector2.Zero, 340, $"{item.Name} Honey", false, true, false, false)
                                {
                                    Name = $"{item.Name} Honey",
                                    preservedParentSheetIndex = { item.ParentSheetIndex }
                                };
                                honey.Price += item.Price * 2;
                                return honey;
                            }));

                            break;

                        // roe and aged roe (derived from FishPond.GetFishProduce)
                        case SObject.sellAtFishShopCategory when item.ParentSheetIndex == 812:
                        {
                            this.GetRoeContextTagLookups(out HashSet <string> simpleTags, out List <List <string> > complexTags);

                            foreach (var pair in Game1.objectInformation)
                            {
                                // get input
                                SObject input     = this.TryCreate(ItemType.Object, pair.Key, p => new SObject(p.ID, 1))?.Item as SObject;
                                var     inputTags = input?.GetContextTags();
                                if (inputTags?.Any() != true)
                                {
                                    continue;
                                }

                                // check if roe-producing fish
                                if (!inputTags.Any(tag => simpleTags.Contains(tag)) && !complexTags.Any(set => set.All(tag => input.HasContextTag(tag))))
                                {
                                    continue;
                                }

                                // yield roe
                                SObject roe   = null;
                                Color   color = this.GetRoeColor(input);
                                yield return(this.TryCreate(ItemType.Object, this.CustomIDOffset * 7 + item.ParentSheetIndex, _ =>
                                    {
                                        roe = new ColoredObject(812, 1, color)
                                        {
                                            name = $"{input.Name} Roe",
                                            preserve = { Value = SObject.PreserveType.Roe },
                                            preservedParentSheetIndex = { Value = input.ParentSheetIndex }
                                        };
                                        roe.Price += input.Price / 2;
                                        return roe;
                                    }));

                                // aged roe
                                if (roe != null && pair.Key != 698)         // aged sturgeon roe is caviar, which is a separate item
                                {
                                    yield return(this.TryCreate(ItemType.Object, this.CustomIDOffset * 7 + item.ParentSheetIndex, _ => new ColoredObject(447, 1, color)
                                        {
                                            name = $"Aged {input.Name} Roe",
                                            Category = -27,
                                            preserve = { Value = SObject.PreserveType.AgedRoe },
                                            preservedParentSheetIndex = { Value = input.ParentSheetIndex },
                                            Price = roe.Price * 2
                                        }));
                                }
                            }
                        }
                        break;
                        }
                    }
                }
            }

            return(GetAllRaw().Where(p => p != null));
        }
Beispiel #3
0
        /// <summary>Get flavored variants of a base item (like Blueberry Wine for Blueberry), if any.</summary>
        /// <param name="item">A sample of the base item.</param>
        private IEnumerable <SearchableItem> GetFlavoredObjectVariants(SObject item)
        {
            int id = item.ParentSheetIndex;

            switch (item.Category)
            {
            // fruit products
            case SObject.FruitsCategory:
                // wine
                yield return(this.TryCreate(ItemType.Object, this.CustomIDOffset * 2 + id, _ => new SObject(348, 1)
                {
                    Name = $"{item.Name} Wine",
                    Price = item.Price * 3,
                    preserve = { SObject.PreserveType.Wine },
                    preservedParentSheetIndex = { id }
                }));

                // jelly
                yield return(this.TryCreate(ItemType.Object, this.CustomIDOffset * 3 + id, _ => new SObject(344, 1)
                {
                    Name = $"{item.Name} Jelly",
                    Price = 50 + item.Price * 2,
                    preserve = { SObject.PreserveType.Jelly },
                    preservedParentSheetIndex = { id }
                }));

                break;

            // vegetable products
            case SObject.VegetableCategory:
                // juice
                yield return(this.TryCreate(ItemType.Object, this.CustomIDOffset * 4 + id, _ => new SObject(350, 1)
                {
                    Name = $"{item.Name} Juice",
                    Price = (int)(item.Price * 2.25d),
                    preserve = { SObject.PreserveType.Juice },
                    preservedParentSheetIndex = { id }
                }));

                // pickled
                yield return(this.TryCreate(ItemType.Object, this.CustomIDOffset * 5 + id, _ => new SObject(342, 1)
                {
                    Name = $"Pickled {item.Name}",
                    Price = 50 + item.Price * 2,
                    preserve = { SObject.PreserveType.Pickle },
                    preservedParentSheetIndex = { id }
                }));

                break;

            // flower honey
            case SObject.flowersCategory:
                yield return(this.TryCreate(ItemType.Object, this.CustomIDOffset * 5 + id, _ =>
                {
                    SObject honey = new SObject(Vector2.Zero, 340, $"{item.Name} Honey", false, true, false, false)
                    {
                        Name = $"{item.Name} Honey",
                        preservedParentSheetIndex = { id }
                    };
                    honey.Price += item.Price * 2;
                    return honey;
                }));

                break;

            // roe and aged roe (derived from FishPond.GetFishProduce)
            case SObject.sellAtFishShopCategory when id == 812:
            {
                this.GetRoeContextTagLookups(out HashSet <string> simpleTags, out List <List <string> > complexTags);

                foreach (var pair in Game1.objectInformation)
                {
                    // get input
                    SObject input     = this.TryCreate(ItemType.Object, pair.Key, p => new SObject(p.ID, 1))?.Item as SObject;
                    var     inputTags = input?.GetContextTags();
                    if (inputTags?.Any() != true)
                    {
                        continue;
                    }

                    // check if roe-producing fish
                    if (!inputTags.Any(tag => simpleTags.Contains(tag)) && !complexTags.Any(set => set.All(tag => input.HasContextTag(tag))))
                    {
                        continue;
                    }

                    // yield roe
                    SObject roe   = null;
                    Color   color = this.GetRoeColor(input);
                    yield return(this.TryCreate(ItemType.Object, this.CustomIDOffset * 7 + id, _ =>
                        {
                            roe = new ColoredObject(812, 1, color)
                            {
                                name = $"{input.Name} Roe",
                                preserve = { Value = SObject.PreserveType.Roe },
                                preservedParentSheetIndex = { Value = input.ParentSheetIndex }
                            };
                            roe.Price += input.Price / 2;
                            return roe;
                        }));

                    // aged roe
                    if (roe != null && pair.Key != 698)         // aged sturgeon roe is caviar, which is a separate item
                    {
                        yield return(this.TryCreate(ItemType.Object, this.CustomIDOffset * 7 + id, _ => new ColoredObject(447, 1, color)
                            {
                                name = $"Aged {input.Name} Roe",
                                Category = -27,
                                preserve = { Value = SObject.PreserveType.AgedRoe },
                                preservedParentSheetIndex = { Value = input.ParentSheetIndex },
                                Price = roe.Price * 2
                            }));
                    }
                }
            }
            break;
            }
        }