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)); }
/// <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; } }