Beispiel #1
0
        /// <summary>Get the data to display for this subject.</summary>
        /// <param name="metadata">Provides metadata that's not available from the game data directly.</param>
        public override IEnumerable <ICustomField> GetData(Metadata metadata)
        {
            // get data
            Item    item       = this.Target;
            SObject obj        = item as SObject;
            bool    isObject   = obj != null;
            bool    isCrop     = this.FromCrop != null;
            bool    isSeed     = this.SeedForCrop != null;
            bool    isDeadCrop = this.FromCrop?.dead.Value == true;
            bool    canSell    = obj?.canBeShipped() == true || metadata.Shops.Any(shop => shop.BuysCategories.Contains(item.Category));

            // get overrides
            bool showInventoryFields = true;

            {
                ObjectData objData = metadata.GetObject(item, this.Context);
                if (objData != null)
                {
                    this.Name = objData.NameKey != null?this.Translate(objData.NameKey) : this.Name;

                    this.Description = objData.DescriptionKey != null?this.Translate(objData.DescriptionKey) : this.Description;

                    this.Type = objData.TypeKey != null?this.Translate(objData.TypeKey) : this.Type;

                    showInventoryFields = objData.ShowInventoryFields ?? true;
                }
            }

            // don't show data for dead crop
            if (isDeadCrop)
            {
                yield return(new GenericField(this.Translate(L10n.Crop.Summary), this.Translate(L10n.Crop.SummaryDead)));

                yield break;
            }

            // crop fields
            if (isCrop || isSeed)
            {
                // get crop
                Crop crop = this.FromCrop ?? this.SeedForCrop;

                // get harvest schedule
                int  harvestablePhase   = crop.phaseDays.Count - 1;
                bool canHarvestNow      = (crop.currentPhase.Value >= harvestablePhase) && (!crop.fullyGrown.Value || crop.dayOfCurrentPhase.Value <= 0);
                int  daysToFirstHarvest = crop.phaseDays.Take(crop.phaseDays.Count - 1).Sum(); // ignore harvestable phase

                // add next-harvest field
                if (isCrop)
                {
                    // calculate next harvest
                    int   daysToNextHarvest = 0;
                    SDate dayOfNextHarvest  = null;
                    if (!canHarvestNow)
                    {
                        // calculate days until next harvest
                        int daysUntilLastPhase = daysToFirstHarvest - crop.dayOfCurrentPhase.Value - crop.phaseDays.Take(crop.currentPhase.Value).Sum();
                        {
                            // growing: days until next harvest
                            if (!crop.fullyGrown.Value)
                            {
                                daysToNextHarvest = daysUntilLastPhase;
                            }

                            // regrowable crop harvested today
                            else if (crop.dayOfCurrentPhase.Value >= crop.regrowAfterHarvest.Value)
                            {
                                daysToNextHarvest = crop.regrowAfterHarvest.Value;
                            }

                            // regrowable crop
                            else
                            {
                                daysToNextHarvest = crop.dayOfCurrentPhase.Value; // dayOfCurrentPhase decreases to 0 when fully grown, where <=0 is harvestable
                            }
                        }
                        dayOfNextHarvest = SDate.Now().AddDays(daysToNextHarvest);
                    }

                    // generate field
                    string summary;
                    if (canHarvestNow)
                    {
                        summary = this.Translate(L10n.Crop.HarvestNow);
                    }
                    else if (Game1.currentLocation.Name != Constant.LocationNames.Greenhouse && !crop.seasonsToGrowIn.Contains(dayOfNextHarvest.Season))
                    {
                        summary = this.Translate(L10n.Crop.HarvestTooLate, new { date = this.Stringify(dayOfNextHarvest) });
                    }
                    else
                    {
                        summary = $"{this.Stringify(dayOfNextHarvest)} ({this.Text.GetPlural(daysToNextHarvest, L10n.Generic.Tomorrow, L10n.Generic.InXDays).Tokens(new { count = daysToNextHarvest })})";
                    }

                    yield return(new GenericField(this.Translate(L10n.Crop.Harvest), summary));
                }

                // crop summary
                {
                    List <string> summary = new List <string>();

                    // harvest
                    summary.Add(crop.regrowAfterHarvest.Value == -1
                        ? this.Translate(L10n.Crop.SummaryHarvestOnce, new { daysToFirstHarvest = daysToFirstHarvest })
                        : this.Translate(L10n.Crop.SummaryHarvestMulti, new { daysToFirstHarvest = daysToFirstHarvest, daysToNextHarvests = crop.regrowAfterHarvest })
                                );

                    // seasons
                    summary.Add(this.Translate(L10n.Crop.SummarySeasons, new { seasons = string.Join(", ", this.Text.GetSeasonNames(crop.seasonsToGrowIn)) }));

                    // drops
                    if (crop.minHarvest != crop.maxHarvest && crop.chanceForExtraCrops.Value > 0)
                    {
                        summary.Add(this.Translate(L10n.Crop.SummaryDropsXToY, new { min = crop.minHarvest, max = crop.maxHarvest, percent = Math.Round(crop.chanceForExtraCrops.Value * 100, 2) }));
                    }
                    else if (crop.minHarvest.Value > 1)
                    {
                        summary.Add(this.Translate(L10n.Crop.SummaryDropsX, new { count = crop.minHarvest }));
                    }

                    // crop sale price
                    Item drop = GameHelper.GetObjectBySpriteIndex(crop.indexOfHarvest.Value);
                    summary.Add(this.Translate(L10n.Crop.SummarySellsFor, new { price = GenericField.GetSaleValueString(this.GetSaleValue(drop, false, metadata), 1, this.Text) }));

                    // generate field
                    yield return(new GenericField(this.Translate(L10n.Crop.Summary), "-" + string.Join($"{Environment.NewLine}-", summary)));
                }
            }

            // crafting
            if (obj?.heldObject?.Value != null)
            {
                if (obj is Cask cask)
                {
                    // get cask data
                    SObject     agingObj       = cask.heldObject.Value;
                    ItemQuality curQuality     = (ItemQuality)agingObj.Quality;
                    string      curQualityName = this.Translate(L10n.For(curQuality));

                    // calculate aging schedule
                    float effectiveAge = metadata.Constants.CaskAgeSchedule.Values.Max() - cask.daysToMature.Value;
                    var   schedule     =
                        (
                            from entry in metadata.Constants.CaskAgeSchedule
                            let quality = entry.Key
                                          let baseDays = entry.Value
                                                         where baseDays > effectiveAge
                                                         orderby baseDays ascending
                                                         let daysLeft = (int)Math.Ceiling((baseDays - effectiveAge) / cask.agingRate.Value)
                                                                        select new
                    {
                        Quality = quality,
                        DaysLeft = daysLeft,
                        HarvestDate = SDate.Now().AddDays(daysLeft)
                    }
                        )
                        .ToArray();

                    // display fields
                    yield return(new ItemIconField(this.Translate(L10n.Item.Contents), obj.heldObject.Value));

                    if (cask.MinutesUntilReady <= 0 || !schedule.Any())
                    {
                        yield return(new GenericField(this.Translate(L10n.Item.CaskSchedule), this.Translate(L10n.Item.CaskScheduleNow, new { quality = curQualityName })));
                    }
                    else
                    {
                        string scheduleStr = string.Join(Environment.NewLine, (
                                                             from entry in schedule
                                                             let tokens = new { quality = this.Translate(L10n.For(entry.Quality)), count = entry.DaysLeft, date = entry.HarvestDate }
                                                             let str = this.Text.GetPlural(entry.DaysLeft, L10n.Item.CaskScheduleTomorrow, L10n.Item.CaskScheduleInXDays).Tokens(tokens)
                                                                       select $"-{str}"
                                                             ));
                        yield return(new GenericField(this.Translate(L10n.Item.CaskSchedule), this.Translate(L10n.Item.CaskSchedulePartial, new { quality = curQualityName }) + Environment.NewLine + scheduleStr));
                    }
                }
                else if (obj is Furniture)
                {
                    string summary = this.Translate(L10n.Item.ContentsPlaced, new { name = obj.heldObject.Value.DisplayName });
                    yield return(new ItemIconField(this.Translate(L10n.Item.Contents), obj.heldObject.Value, summary));
                }
                else
                {
                    string summary = obj.MinutesUntilReady <= 0
                        ? this.Translate(L10n.Item.ContentsReady, new { name = obj.heldObject.Value.DisplayName })
                        : this.Translate(L10n.Item.ContentsPartial, new { name = obj.heldObject.Value.DisplayName, time = this.Stringify(TimeSpan.FromMinutes(obj.MinutesUntilReady)) });
                    yield return(new ItemIconField(this.Translate(L10n.Item.Contents), obj.heldObject.Value, summary));
                }
            }

            // item
            if (showInventoryFields)
            {
                // needed for
                {
                    List <string> neededFor = new List <string>();

                    // bundles
                    if (isObject)
                    {
                        string[] bundles = (from bundle in this.GetUnfinishedBundles(obj) orderby bundle.Area, bundle.DisplayName select $"{this.GetTranslatedBundleArea(bundle)}: {bundle.DisplayName}").ToArray();
                        if (bundles.Any())
                        {
                            neededFor.Add(this.Translate(L10n.Item.NeededForCommunityCenter, new { bundles = string.Join(", ", bundles) }));
                        }
                    }

                    // polyculture achievement
                    if (isObject && metadata.Constants.PolycultureCrops.Contains(obj.ParentSheetIndex))
                    {
                        int needed = metadata.Constants.PolycultureCount - GameHelper.GetShipped(obj.ParentSheetIndex);
                        if (needed > 0)
                        {
                            neededFor.Add(this.Translate(L10n.Item.NeededForPolyculture, new { count = needed }));
                        }
                    }

                    // full shipment achievement
                    if (isObject && GameHelper.GetFullShipmentAchievementItems().Any(p => p.Key == obj.ParentSheetIndex && !p.Value))
                    {
                        neededFor.Add(this.Translate(L10n.Item.NeededForFullShipment));
                    }

                    // a full collection achievement
                    LibraryMuseum museum = Game1.locations.OfType <LibraryMuseum>().FirstOrDefault();
                    if (museum != null && museum.isItemSuitableForDonation(obj))
                    {
                        neededFor.Add(this.Translate(L10n.Item.NeededForFullCollection));
                    }

                    // yield
                    if (neededFor.Any())
                    {
                        yield return(new GenericField(this.Translate(L10n.Item.NeededFor), string.Join(", ", neededFor)));
                    }
                }

                // sale data
                if (canSell && !isCrop)
                {
                    // sale price
                    string saleValueSummary = GenericField.GetSaleValueString(this.GetSaleValue(item, this.KnownQuality, metadata), item.Stack, this.Text);
                    yield return(new GenericField(this.Translate(L10n.Item.SellsFor), saleValueSummary));

                    // sell to
                    List <string> buyers = new List <string>();
                    if (obj?.canBeShipped() == true)
                    {
                        buyers.Add(this.Translate(L10n.Item.SellsToShippingBox));
                    }
                    buyers.AddRange(
                        from shop in metadata.Shops
                        where shop.BuysCategories.Contains(item.Category)
                        let name = this.Translate(shop.DisplayKey).ToString()
                                   orderby name
                                   select name
                        );
                    yield return(new GenericField(this.Translate(L10n.Item.SellsTo), string.Join(", ", buyers)));
                }

                // gift tastes
                var giftTastes = this.GetGiftTastes(item, metadata);
                yield return(new ItemGiftTastesField(this.Translate(L10n.Item.LovesThis), giftTastes, GiftTaste.Love));

                yield return(new ItemGiftTastesField(this.Translate(L10n.Item.LikesThis), giftTastes, GiftTaste.Like));
            }

            // fence
            if (item is Fence fence)
            {
                string healthLabel = this.Translate(L10n.Item.FenceHealth);

                // health
                if (Game1.getFarm().isBuildingConstructed(Constant.BuildingNames.GoldClock))
                {
                    yield return(new GenericField(healthLabel, this.Translate(L10n.Item.FenceHealthGoldClock)));
                }
                else
                {
                    float  maxHealth = fence.isGate.Value ? fence.maxHealth.Value * 2 : fence.maxHealth.Value;
                    float  health    = fence.health.Value / maxHealth;
                    double daysLeft  = Math.Round(fence.health.Value * metadata.Constants.FenceDecayRate / 60 / 24);
                    double percent   = Math.Round(health * 100);
                    yield return(new PercentageBarField(healthLabel, (int)fence.health, (int)maxHealth, Color.Green, Color.Red, this.Translate(L10n.Item.FenceHealthSummary, new { percent = percent, count = daysLeft })));
                }
            }

            // recipes
            if (item.GetSpriteType() == ItemSpriteType.Object)
            {
                RecipeModel[] recipes = GameHelper.GetRecipesForIngredient(this.DisplayItem).ToArray();
                if (recipes.Any())
                {
                    yield return(new RecipesForIngredientField(this.Translate(L10n.Item.Recipes), item, recipes, this.Text));
                }
            }

            // owned
            if (showInventoryFields && !isCrop && !(item is Tool))
            {
                yield return(new GenericField(this.Translate(L10n.Item.Owned), this.Translate(L10n.Item.OwnedSummary, new { count = GameHelper.CountOwnedItems(item) })));
            }

            // see also crop
            bool seeAlsoCrop =
                isSeed &&
                item.ParentSheetIndex != this.SeedForCrop.indexOfHarvest.Value && // skip seeds which produce themselves (e.g. coffee beans)
                !(item.ParentSheetIndex >= 495 && item.ParentSheetIndex <= 497) && // skip random seasonal seeds
                item.ParentSheetIndex != 770;    // skip mixed seeds

            if (seeAlsoCrop)
            {
                Item drop = GameHelper.GetObjectBySpriteIndex(this.SeedForCrop.indexOfHarvest.Value);
                yield return(new LinkField(this.Translate(L10n.Item.SeeAlso), drop.DisplayName, () => new ItemSubject(this.Text, drop, ObjectContext.Inventory, false, this.SeedForCrop)));
            }
        }
Beispiel #2
0
        /// <summary>Get the data to display for this subject.</summary>
        /// <param name="metadata">Provides metadata that's not available from the game data directly.</param>
        public override IEnumerable <ICustomField> GetData(Metadata metadata)
        {
            // get data
            Item    item       = this.Target;
            SObject obj        = item as SObject;
            bool    isCrop     = this.FromCrop != null;
            bool    isSeed     = this.SeedForCrop != null;
            bool    isDeadCrop = this.FromCrop?.dead.Value == true;
            bool    canSell    = obj?.canBeShipped() == true || metadata.Shops.Any(shop => shop.BuysCategories.Contains(item.Category));

            // get overrides
            bool showInventoryFields = true;

            {
                ObjectData objData = metadata.GetObject(item, this.Context);
                if (objData != null)
                {
                    this.Name = objData.NameKey != null?this.Translate(objData.NameKey) : this.Name;

                    this.Description = objData.DescriptionKey != null?this.Translate(objData.DescriptionKey) : this.Description;

                    this.Type = objData.TypeKey != null?this.Translate(objData.TypeKey) : this.Type;

                    showInventoryFields = objData.ShowInventoryFields ?? true;
                }
            }

            // don't show data for dead crop
            if (isDeadCrop)
            {
                yield return(new GenericField(this.GameHelper, this.Translate(L10n.Crop.Summary), this.Translate(L10n.Crop.SummaryDead)));

                yield break;
            }

            // crop fields
            foreach (ICustomField field in this.GetCropFields(this.FromCrop ?? this.SeedForCrop, isSeed, metadata))
            {
                yield return(field);
            }

            // indoor pot crop
            if (obj is IndoorPot pot)
            {
                Crop potCrop = pot.hoeDirt.Value.crop;
                if (potCrop != null)
                {
                    Item drop = this.GameHelper.GetObjectBySpriteIndex(potCrop.indexOfHarvest.Value);
                    yield return(new LinkField(this.GameHelper, this.Translate(L10n.Item.Contents), drop.DisplayName, () => new ItemSubject(this.GameHelper, this.Text, this.GameHelper.GetObjectBySpriteIndex(potCrop.indexOfHarvest.Value), ObjectContext.World, knownQuality: false, fromCrop: potCrop)));
                }
            }

            // machine output
            foreach (ICustomField field in this.GetMachineOutputFields(obj, metadata))
            {
                yield return(field);
            }

            // item
            if (showInventoryFields)
            {
                // needed for
                foreach (ICustomField field in this.GetNeededForFields(obj, metadata))
                {
                    yield return(field);
                }

                // sale data
                if (canSell && !isCrop)
                {
                    // sale price
                    string saleValueSummary = GenericField.GetSaleValueString(this.GetSaleValue(item, this.KnownQuality, metadata), item.Stack, this.Text);
                    yield return(new GenericField(this.GameHelper, this.Translate(L10n.Item.SellsFor), saleValueSummary));

                    // sell to
                    List <string> buyers = new List <string>();
                    if (obj?.canBeShipped() == true)
                    {
                        buyers.Add(this.Translate(L10n.Item.SellsToShippingBox));
                    }
                    buyers.AddRange(
                        from shop in metadata.Shops
                        where shop.BuysCategories.Contains(item.Category)
                        let name = this.Translate(shop.DisplayKey).ToString()
                                   orderby name
                                   select name
                        );
                    yield return(new GenericField(this.GameHelper, this.Translate(L10n.Item.SellsTo), string.Join(", ", buyers)));
                }

                // gift tastes
                var giftTastes = this.GetGiftTastes(item, metadata);
                yield return(new ItemGiftTastesField(this.GameHelper, this.Translate(L10n.Item.LovesThis), giftTastes, GiftTaste.Love));

                yield return(new ItemGiftTastesField(this.GameHelper, this.Translate(L10n.Item.LikesThis), giftTastes, GiftTaste.Like));
            }

            // fence
            if (item is Fence fence)
            {
                string healthLabel = this.Translate(L10n.Item.FenceHealth);

                // health
                if (Game1.getFarm().isBuildingConstructed(Constant.BuildingNames.GoldClock))
                {
                    yield return(new GenericField(this.GameHelper, healthLabel, this.Translate(L10n.Item.FenceHealthGoldClock)));
                }
                else
                {
                    float  maxHealth = fence.isGate.Value ? fence.maxHealth.Value * 2 : fence.maxHealth.Value;
                    float  health    = fence.health.Value / maxHealth;
                    double daysLeft  = Math.Round(fence.health.Value * metadata.Constants.FenceDecayRate / 60 / 24);
                    double percent   = Math.Round(health * 100);
                    yield return(new PercentageBarField(this.GameHelper, healthLabel, (int)fence.health.Value, (int)maxHealth, Color.Green, Color.Red, this.Translate(L10n.Item.FenceHealthSummary, new { percent = percent, count = daysLeft })));
                }
            }

            // recipes
            if (item.GetSpriteType() == ItemSpriteType.Object)
            {
                RecipeModel[] recipes = this.GameHelper.GetRecipesForIngredient(this.DisplayItem).ToArray();
                if (recipes.Any())
                {
                    yield return(new RecipesForIngredientField(this.GameHelper, this.Translate(L10n.Item.Recipes), item, recipes, this.Text));
                }
            }

            // owned
            if (showInventoryFields && !isCrop && !(item is Tool))
            {
                yield return(new GenericField(this.GameHelper, this.Translate(L10n.Item.Owned), this.Translate(L10n.Item.OwnedSummary, new { count = this.GameHelper.CountOwnedItems(item) })));
            }

            // see also crop
            bool seeAlsoCrop =
                isSeed &&
                item.ParentSheetIndex != this.SeedForCrop.indexOfHarvest.Value && // skip seeds which produce themselves (e.g. coffee beans)
                !(item.ParentSheetIndex >= 495 && item.ParentSheetIndex <= 497) && // skip random seasonal seeds
                item.ParentSheetIndex != 770;    // skip mixed seeds

            if (seeAlsoCrop)
            {
                Item drop = this.GameHelper.GetObjectBySpriteIndex(this.SeedForCrop.indexOfHarvest.Value);
                yield return(new LinkField(this.GameHelper, this.Translate(L10n.Item.SeeAlso), drop.DisplayName, () => new ItemSubject(this.GameHelper, this.Text, drop, ObjectContext.Inventory, false, this.SeedForCrop)));
            }
        }
Beispiel #3
0
        /// <summary>Get the data to display for this subject.</summary>
        public override IEnumerable <ICustomField> GetData()
        {
            // get data
            Item     item       = this.Target;
            ItemType itemType   = item.GetItemType();
            SObject  obj        = item as SObject;
            bool     isCrop     = this.FromCrop != null;
            bool     isSeed     = this.SeedForCrop != null;
            bool     isDeadCrop = this.FromCrop?.dead.Value == true;
            bool     canSell    = obj?.canBeShipped() == true || this.Metadata.Shops.Any(shop => shop.BuysCategories.Contains(item.Category));

            // get overrides
            bool showInventoryFields = !this.IsSpawnedStoneNode();

            {
                ObjectData objData = this.Metadata.GetObject(item, this.Context);
                if (objData != null)
                {
                    this.Name = objData.NameKey != null?I18n.GetByKey(objData.NameKey) : this.Name;

                    this.Description = objData.DescriptionKey != null?I18n.GetByKey(objData.DescriptionKey) : this.Description;

                    this.Type = objData.TypeKey != null?I18n.GetByKey(objData.TypeKey) : this.Type;

                    showInventoryFields = objData.ShowInventoryFields ?? showInventoryFields;
                }
            }

            // don't show data for dead crop
            if (isDeadCrop)
            {
                yield return(new GenericField(I18n.Crop_Summary(), I18n.Crop_Summary_Dead()));

                yield break;
            }

            // crop fields
            foreach (ICustomField field in this.GetCropFields(this.FromDirt, this.FromCrop ?? this.SeedForCrop, isSeed))
            {
                yield return(field);
            }

            // indoor pot crop
            if (obj is IndoorPot pot)
            {
                Crop potCrop = pot.hoeDirt.Value.crop;
                if (potCrop != null)
                {
                    Item drop = this.GameHelper.GetObjectBySpriteIndex(potCrop.indexOfHarvest.Value);
                    yield return(new LinkField(I18n.Item_Contents(), drop.DisplayName, () => this.GetCropSubject(potCrop, ObjectContext.World, pot.hoeDirt.Value)));
                }
            }

            // machine output
            foreach (ICustomField field in this.GetMachineOutputFields(obj))
            {
                yield return(field);
            }

            // music blocks
            if (obj?.Name == "Flute Block")
            {
                yield return(new GenericField(I18n.Item_MusicBlock_Pitch(), I18n.Generic_Ratio(value: obj.preservedParentSheetIndex.Value, max: 2300)));
            }
            else if (obj?.Name == "Drum Block")
            {
                yield return(new GenericField(I18n.Item_MusicBlock_DrumType(), I18n.Generic_Ratio(value: obj.preservedParentSheetIndex.Value, max: 6)));
            }

            // item
            if (showInventoryFields)
            {
                // needed for
                foreach (ICustomField field in this.GetNeededForFields(obj))
                {
                    yield return(field);
                }

                // sale data
                if (canSell && !isCrop)
                {
                    // sale price
                    string saleValueSummary = GenericField.GetSaleValueString(this.GetSaleValue(item, this.KnownQuality), item.Stack);
                    yield return(new GenericField(I18n.Item_SellsFor(), saleValueSummary));

                    // sell to
                    List <string> buyers = new List <string>();
                    if (obj?.canBeShipped() == true)
                    {
                        buyers.Add(I18n.Item_SellsTo_ShippingBox());
                    }
                    buyers.AddRange(
                        from shop in this.Metadata.Shops
                        where shop.BuysCategories.Contains(item.Category)
                        let name = I18n.GetByKey(shop.DisplayKey).ToString()
                                   orderby name
                                   select name
                        );
                    yield return(new GenericField(I18n.Item_SellsTo(), string.Join(", ", buyers)));
                }

                // clothing
                if (item is Clothing clothing)
                {
                    yield return(new GenericField(I18n.Item_CanBeDyed(), this.Stringify(clothing.dyeable.Value)));
                }

                // gift tastes
                IDictionary <GiftTaste, GiftTasteModel[]> giftTastes = this.GetGiftTastes(item);
                yield return(new ItemGiftTastesField(I18n.Item_LovesThis(), giftTastes, GiftTaste.Love, onlyRevealed: this.ProgressionMode, highlightUnrevealed: this.HighlightUnrevealedGiftTastes));

                yield return(new ItemGiftTastesField(I18n.Item_LikesThis(), giftTastes, GiftTaste.Like, onlyRevealed: this.ProgressionMode, highlightUnrevealed: this.HighlightUnrevealedGiftTastes));

                if (this.ProgressionMode || this.HighlightUnrevealedGiftTastes)
                {
                    yield return(new ItemGiftTastesField(I18n.Item_NeutralAboutThis(), giftTastes, GiftTaste.Neutral, onlyRevealed: this.ProgressionMode, highlightUnrevealed: this.HighlightUnrevealedGiftTastes));

                    yield return(new ItemGiftTastesField(I18n.Item_DislikesThis(), giftTastes, GiftTaste.Dislike, onlyRevealed: this.ProgressionMode, highlightUnrevealed: this.HighlightUnrevealedGiftTastes));

                    yield return(new ItemGiftTastesField(I18n.Item_HatesThis(), giftTastes, GiftTaste.Hate, onlyRevealed: this.ProgressionMode, highlightUnrevealed: this.HighlightUnrevealedGiftTastes));
                }
            }

            // recipes
            if (showInventoryFields)
            {
                switch (itemType)
                {
                // for ingredient
                case ItemType.Object:
                {
                    RecipeModel[] recipes = this.GameHelper.GetRecipesForIngredient(this.DisplayItem).ToArray();
                    if (recipes.Any())
                    {
                        yield return(new RecipesForIngredientField(this.GameHelper, I18n.Item_Recipes(), item, recipes));
                    }
                }
                break;

                // for machine
                case ItemType.BigCraftable:
                {
                    RecipeModel[] recipes = this.GameHelper.GetRecipesForMachine(this.DisplayItem as SObject).ToArray();
                    if (recipes.Any())
                    {
                        yield return(new RecipesForMachineField(this.GameHelper, I18n.Item_Recipes(), recipes));
                    }
                }
                break;
                }
            }

            // fish
            if (item.Category == SObject.FishCategory)
            {
                // spawn rules
                yield return(new FishSpawnRulesField(this.GameHelper, I18n.Item_FishSpawnRules(), item.ParentSheetIndex));

                // fish pond data
                foreach (FishPondData fishPondData in Game1.content.Load <List <FishPondData> >("Data\\FishPondData"))
                {
                    if (!fishPondData.RequiredTags.All(item.HasContextTag))
                    {
                        continue;
                    }

                    int    minChanceOfAnyDrop = (int)Math.Round(Utility.Lerp(0.15f, 0.95f, 1 / 10f) * 100);
                    int    maxChanceOfAnyDrop = (int)Math.Round(Utility.Lerp(0.15f, 0.95f, FishPond.MAXIMUM_OCCUPANCY / 10f) * 100);
                    string preface            = I18n.Building_FishPond_Drops_Preface(chance: I18n.Generic_Range(min: minChanceOfAnyDrop, max: maxChanceOfAnyDrop));
                    yield return(new FishPondDropsField(this.GameHelper, I18n.Item_FishPondDrops(), -1, fishPondData, preface));

                    break;
                }
            }

            // fence
            if (item is Fence fence)
            {
                string healthLabel = I18n.Item_FenceHealth();

                // health
                if (Game1.getFarm().isBuildingConstructed(Constant.BuildingNames.GoldClock))
                {
                    yield return(new GenericField(healthLabel, I18n.Item_FenceHealth_GoldClock()));
                }
                else
                {
                    float  maxHealth = fence.isGate.Value ? fence.maxHealth.Value * 2 : fence.maxHealth.Value;
                    float  health    = fence.health.Value / maxHealth;
                    double daysLeft  = Math.Round(fence.health.Value * this.Constants.FenceDecayRate / 60 / 24);
                    double percent   = Math.Round(health * 100);
                    yield return(new PercentageBarField(healthLabel, (int)fence.health.Value, (int)maxHealth, Color.Green, Color.Red, I18n.Item_FenceHealth_Summary(percent: (int)percent, count: (int)daysLeft)));
                }
            }

            // movie ticket
            if (obj?.ParentSheetIndex == 809 && !obj.bigCraftable.Value)
            {
                MovieData movie = MovieTheater.GetMovieForDate(Game1.Date);
                if (movie == null)
                {
                    yield return(new GenericField(I18n.Item_MovieTicket_MovieThisWeek(), I18n.Item_MovieTicket_MovieThisWeek_None()));
                }
                else
                {
                    // movie this week
                    yield return(new GenericField(I18n.Item_MovieTicket_MovieThisWeek(), new IFormattedText[]
                    {
                        new FormattedText(movie.Title, bold: true),
                        new FormattedText(Environment.NewLine),
                        new FormattedText(movie.Description)
                    }));

                    // movie tastes
                    IDictionary <GiftTaste, string[]> tastes = this.GameHelper.GetMovieTastes()
                                                               .GroupBy(entry => entry.Value)
                                                               .ToDictionary(group => group.Key, group => group.Select(p => p.Key.Name).OrderBy(p => p).ToArray());

                    yield return(new MovieTastesField(I18n.Item_MovieTicket_LovesMovie(), tastes, GiftTaste.Love));

                    yield return(new MovieTastesField(I18n.Item_MovieTicket_LikesMovie(), tastes, GiftTaste.Like));

                    yield return(new MovieTastesField(I18n.Item_MovieTicket_DislikesMovie(), tastes, GiftTaste.Dislike));
                }
            }

            // dyes
            if (showInventoryFields)
            {
                yield return(new ColorField(I18n.Item_ProducesDye(), item));
            }

            // owned and times cooked/crafted
            if (showInventoryFields && !isCrop)
            {
                // owned
                yield return(new GenericField(I18n.Item_NumberOwned(), I18n.Item_NumberOwned_Summary(count: this.GameHelper.CountOwnedItems(item))));

                // times crafted
                RecipeModel[] recipes = this.GameHelper
                                        .GetRecipes()
                                        .Where(recipe => recipe.OutputItemIndex == this.Target.ParentSheetIndex && recipe.OutputItemType == this.Target.GetItemType())
                                        .ToArray();
                if (recipes.Any())
                {
                    string label        = recipes.First().Type == RecipeType.Cooking ? I18n.Item_NumberCooked() : I18n.Item_NumberCrafted();
                    int    timesCrafted = recipes.Sum(recipe => recipe.GetTimesCrafted(Game1.player));
                    if (timesCrafted >= 0) // negative value means not available for this recipe type
                    {
                        yield return(new GenericField(label, I18n.Item_NumberCrafted_Summary(count: timesCrafted)));
                    }
                }
            }

            // see also crop
            bool seeAlsoCrop =
                isSeed &&
                item.ParentSheetIndex != this.SeedForCrop.indexOfHarvest.Value && // skip seeds which produce themselves (e.g. coffee beans)
                !(item.ParentSheetIndex >= 495 && item.ParentSheetIndex <= 497) && // skip random seasonal seeds
                item.ParentSheetIndex != 770;    // skip mixed seeds

            if (seeAlsoCrop)
            {
                Item drop = this.GameHelper.GetObjectBySpriteIndex(this.SeedForCrop.indexOfHarvest.Value);
                yield return(new LinkField(I18n.Item_SeeAlso(), drop.DisplayName, () => this.GetCropSubject(this.SeedForCrop, ObjectContext.Inventory, null)));
            }
        }
Beispiel #4
0
        /// <summary>Get the data to display for this subject.</summary>
        /// <param name="metadata">Provides metadata that's not available from the game data directly.</param>
        public override IEnumerable <ICustomField> GetData(Metadata metadata)
        {
            // get data
            Item    item       = this.Target;
            SObject obj        = item as SObject;
            bool    isCrop     = this.FromCrop != null;
            bool    isSeed     = this.SeedForCrop != null;
            bool    isDeadCrop = this.FromCrop?.dead.Value == true;
            bool    canSell    = obj?.canBeShipped() == true || metadata.Shops.Any(shop => shop.BuysCategories.Contains(item.Category));

            // get overrides
            bool showInventoryFields = true;

            {
                ObjectData objData = metadata.GetObject(item, this.Context);
                if (objData != null)
                {
                    this.Name = objData.NameKey != null?L10n.GetRaw(objData.NameKey) : this.Name;

                    this.Description = objData.DescriptionKey != null?L10n.GetRaw(objData.DescriptionKey) : this.Description;

                    this.Type = objData.TypeKey != null?L10n.GetRaw(objData.TypeKey) : this.Type;

                    showInventoryFields = objData.ShowInventoryFields ?? true;
                }
            }

            // don't show data for dead crop
            if (isDeadCrop)
            {
                yield return(new GenericField(this.GameHelper, L10n.Crop.Summary(), L10n.Crop.SummaryDead()));

                yield break;
            }

            // crop fields
            foreach (ICustomField field in this.GetCropFields(this.FromCrop ?? this.SeedForCrop, isSeed, metadata))
            {
                yield return(field);
            }

            // indoor pot crop
            if (obj is IndoorPot pot)
            {
                Crop potCrop = pot.hoeDirt.Value.crop;
                if (potCrop != null)
                {
                    Item drop = this.GameHelper.GetObjectBySpriteIndex(potCrop.indexOfHarvest.Value);
                    yield return(new LinkField(this.GameHelper, L10n.Item.Contents(), drop.DisplayName, () => new ItemSubject(this.GameHelper, this.Text, this.ProgressionMode, this.GameHelper.GetObjectBySpriteIndex(potCrop.indexOfHarvest.Value), ObjectContext.World, knownQuality: false, fromCrop: potCrop)));
                }
            }

            // machine output
            foreach (ICustomField field in this.GetMachineOutputFields(obj, metadata))
            {
                yield return(field);
            }

            // item
            if (showInventoryFields)
            {
                // needed for
                foreach (ICustomField field in this.GetNeededForFields(obj, metadata))
                {
                    yield return(field);
                }

                // sale data
                if (canSell && !isCrop)
                {
                    // sale price
                    string saleValueSummary = GenericField.GetSaleValueString(this.GetSaleValue(item, this.KnownQuality, metadata), item.Stack, this.Text);
                    yield return(new GenericField(this.GameHelper, L10n.Item.SellsFor(), saleValueSummary));

                    // sell to
                    List <string> buyers = new List <string>();
                    if (obj?.canBeShipped() == true)
                    {
                        buyers.Add(L10n.Item.SellsToShippingBox());
                    }
                    buyers.AddRange(
                        from shop in metadata.Shops
                        where shop.BuysCategories.Contains(item.Category)
                        let name = L10n.GetRaw(shop.DisplayKey).ToString()
                                   orderby name
                                   select name
                        );
                    yield return(new GenericField(this.GameHelper, L10n.Item.SellsTo(), string.Join(", ", buyers)));
                }

                // clothing
                if (item is Clothing clothing)
                {
                    yield return(new GenericField(this.GameHelper, L10n.Item.CanBeDyed(), this.Stringify(clothing.dyeable.Value)));
                }

                // gift tastes
                IDictionary <GiftTaste, GiftTasteModel[]> giftTastes = this.GetGiftTastes(item, metadata);
                yield return(new ItemGiftTastesField(this.GameHelper, L10n.Item.LovesThis(), item.ParentSheetIndex, giftTastes, GiftTaste.Love, onlyRevealed: this.ProgressionMode));

                yield return(new ItemGiftTastesField(this.GameHelper, L10n.Item.LikesThis(), item.ParentSheetIndex, giftTastes, GiftTaste.Like, onlyRevealed: this.ProgressionMode));

                if (this.ProgressionMode)
                {
                    yield return(new ItemGiftTastesField(this.GameHelper, L10n.Item.NeutralAboutThis(), item.ParentSheetIndex, giftTastes, GiftTaste.Neutral, onlyRevealed: this.ProgressionMode));

                    yield return(new ItemGiftTastesField(this.GameHelper, L10n.Item.DislikesThis(), item.ParentSheetIndex, giftTastes, GiftTaste.Dislike, onlyRevealed: this.ProgressionMode));

                    yield return(new ItemGiftTastesField(this.GameHelper, L10n.Item.HatesThis(), item.ParentSheetIndex, giftTastes, GiftTaste.Hate, onlyRevealed: this.ProgressionMode));
                }
            }

            // fence
            if (item is Fence fence)
            {
                string healthLabel = L10n.Item.FenceHealth();

                // health
                if (Game1.getFarm().isBuildingConstructed(Constant.BuildingNames.GoldClock))
                {
                    yield return(new GenericField(this.GameHelper, healthLabel, L10n.Item.FenceHealthGoldClock()));
                }
                else
                {
                    float  maxHealth = fence.isGate.Value ? fence.maxHealth.Value * 2 : fence.maxHealth.Value;
                    float  health    = fence.health.Value / maxHealth;
                    double daysLeft  = Math.Round(fence.health.Value * metadata.Constants.FenceDecayRate / 60 / 24);
                    double percent   = Math.Round(health * 100);
                    yield return(new PercentageBarField(this.GameHelper, healthLabel, (int)fence.health.Value, (int)maxHealth, Color.Green, Color.Red, L10n.Item.FenceHealthSummary(percent: (int)percent, count: (int)daysLeft)));
                }
            }

            // movie ticket
            if (obj?.ParentSheetIndex == 809 && !obj.bigCraftable.Value)
            {
                MovieData movie = MovieTheater.GetMovieForDate(Game1.Date);
                if (movie == null)
                {
                    yield return(new GenericField(this.GameHelper, L10n.MovieTicket.MovieThisWeek(), L10n.MovieTicket.NoMovieThisWeek()));
                }
                else
                {
                    // movie this week
                    yield return(new GenericField(this.GameHelper, L10n.MovieTicket.MovieThisWeek(), new IFormattedText[]
                    {
                        new FormattedText(movie.Title, bold: true),
                        new FormattedText(Environment.NewLine),
                        new FormattedText(movie.Description)
                    }));

                    // movie tastes
                    IDictionary <GiftTaste, string[]> tastes = this.GameHelper.GetMovieTastes(metadata)
                                                               .GroupBy(entry => entry.Value)
                                                               .ToDictionary(group => group.Key, group => group.Select(p => p.Key.Name).OrderBy(p => p).ToArray());

                    yield return(new MovieTastesField(this.GameHelper, L10n.MovieTicket.LovesMovie(), tastes, GiftTaste.Love));

                    yield return(new MovieTastesField(this.GameHelper, L10n.MovieTicket.LikesMovie(), tastes, GiftTaste.Like));

                    yield return(new MovieTastesField(this.GameHelper, L10n.MovieTicket.DislikesMovie(), tastes, GiftTaste.Dislike));
                }
            }

            // recipes
            switch (item.GetSpriteType())
            {
            // for ingredient
            case ItemSpriteType.Object:
            {
                RecipeModel[] recipes = this.GameHelper.GetRecipesForIngredient(this.DisplayItem).ToArray();
                if (recipes.Any())
                {
                    yield return(new RecipesForIngredientField(this.GameHelper, L10n.Item.Recipes(), item, recipes));
                }
            }
            break;

            // for machine
            case ItemSpriteType.BigCraftable:
            {
                RecipeModel[] recipes = this.GameHelper.GetRecipesForMachine(this.DisplayItem as SObject).ToArray();
                if (recipes.Any())
                {
                    yield return(new RecipesForMachineField(this.GameHelper, L10n.Item.Recipes(), recipes));
                }
            }
            break;
            }

            // dyes
            yield return(new ColorField(this.GameHelper, L10n.Item.ProducesDye(), item));

            // owned and times cooked/crafted
            if (showInventoryFields && !isCrop && !(item is Tool))
            {
                // owned
                yield return(new GenericField(this.GameHelper, L10n.Item.Owned(), L10n.Item.OwnedSummary(count: this.GameHelper.CountOwnedItems(item))));

                // times crafted
                RecipeModel[] recipes = this.GameHelper
                                        .GetRecipes()
                                        .Where(recipe => recipe.OutputItemIndex == this.Target.ParentSheetIndex)
                                        .ToArray();
                if (recipes.Any())
                {
                    string label        = recipes.First().Type == RecipeType.Cooking ? L10n.Item.Cooked() : L10n.Item.Crafted();
                    int    timesCrafted = recipes.Sum(recipe => recipe.GetTimesCrafted(Game1.player));
                    if (timesCrafted >= 0) // negative value means not available for this recipe type
                    {
                        yield return(new GenericField(this.GameHelper, label, L10n.Item.CraftedSummary(count: timesCrafted)));
                    }
                }
            }

            // see also crop
            bool seeAlsoCrop =
                isSeed &&
                item.ParentSheetIndex != this.SeedForCrop.indexOfHarvest.Value && // skip seeds which produce themselves (e.g. coffee beans)
                !(item.ParentSheetIndex >= 495 && item.ParentSheetIndex <= 497) && // skip random seasonal seeds
                item.ParentSheetIndex != 770;    // skip mixed seeds

            if (seeAlsoCrop)
            {
                Item drop = this.GameHelper.GetObjectBySpriteIndex(this.SeedForCrop.indexOfHarvest.Value);
                yield return(new LinkField(this.GameHelper, L10n.Item.SeeAlso(), drop.DisplayName, () => new ItemSubject(this.GameHelper, this.Text, this.ProgressionMode, drop, ObjectContext.Inventory, false, this.SeedForCrop)));
            }
        }
Beispiel #5
0
        /// <summary>Get the data to display for this subject.</summary>
        /// <param name="metadata">Provides metadata that's not available from the game data directly.</param>
        public override IEnumerable <ICustomField> GetData(Metadata metadata)
        {
            // get data
            Item   item       = this.Target;
            Object obj        = item as Object;
            bool   isObject   = obj != null;
            bool   isCrop     = this.FromCrop != null;
            bool   isSeed     = this.SeedForCrop != null;
            bool   isDeadCrop = this.FromCrop?.dead == true;
            bool   canSell    = obj?.canBeShipped() == true || metadata.Shops.Any(shop => shop.BuysCategories.Contains(item.category));

            // get overrides
            bool showInventoryFields = true;

            {
                ObjectData objData = metadata.GetObject(item, this.Context);
                if (objData != null)
                {
                    this.Name           = objData.Name ?? this.Name;
                    this.Description    = objData.Description ?? this.Description;
                    this.Type           = objData.Type ?? this.Type;
                    showInventoryFields = objData.ShowInventoryFields ?? true;
                }
            }

            // don't show data for dead crop
            if (isDeadCrop)
            {
                yield return(new GenericField("Crop", "This crop is dead."));

                yield break;
            }

            // crop fields
            if (isCrop || isSeed)
            {
                // get crop
                Crop crop = this.FromCrop ?? this.SeedForCrop;

                // get harvest schedule
                int  harvestablePhase   = crop.phaseDays.Count - 1;
                bool canHarvestNow      = (crop.currentPhase >= harvestablePhase) && (!crop.fullyGrown || crop.dayOfCurrentPhase <= 0);
                int  daysToFirstHarvest = crop.phaseDays.Take(crop.phaseDays.Count - 1).Sum(); // ignore harvestable phase

                // add next-harvest field
                if (isCrop)
                {
                    // calculate next harvest
                    int      daysToNextHarvest = 0;
                    GameDate dayOfNextHarvest  = null;
                    if (!canHarvestNow)
                    {
                        // calculate days until next harvest
                        int daysUntilLastPhase = daysToFirstHarvest - crop.dayOfCurrentPhase - crop.phaseDays.Take(crop.currentPhase).Sum();
                        {
                            // growing: days until next harvest
                            if (!crop.fullyGrown)
                            {
                                daysToNextHarvest = daysUntilLastPhase;
                            }

                            // regrowable crop harvested today
                            else if (crop.dayOfCurrentPhase >= crop.regrowAfterHarvest)
                            {
                                daysToNextHarvest = crop.regrowAfterHarvest;
                            }

                            // regrowable crop
                            else
                            {
                                daysToNextHarvest = crop.dayOfCurrentPhase; // dayOfCurrentPhase decreases to 0 when fully grown, where <=0 is harvestable
                            }
                        }
                        dayOfNextHarvest = GameHelper.GetDate(metadata.Constants.DaysInSeason).GetDayOffset(daysToNextHarvest);
                    }

                    // generate field
                    string summary;
                    if (canHarvestNow)
                    {
                        summary = "now";
                    }
                    else if (Game1.currentLocation.Name != Constant.LocationNames.Greenhouse && !crop.seasonsToGrowIn.Contains(dayOfNextHarvest.Season))
                    {
                        summary = $"too late in the season for the next harvest (would be on {dayOfNextHarvest})";
                    }
                    else
                    {
                        summary = $"{dayOfNextHarvest} ({TextHelper.Pluralise(daysToNextHarvest, "tomorrow", $"in {daysToNextHarvest} days")})";
                    }

                    yield return(new GenericField("Harvest", summary));
                }

                // crop summary
                {
                    List <string> summary = new List <string>();

                    // harvest
                    summary.Add($"-harvest after {daysToFirstHarvest} {TextHelper.Pluralise(daysToFirstHarvest, "day")}" + (crop.regrowAfterHarvest != -1 ? $", then every {TextHelper.Pluralise(crop.regrowAfterHarvest, "day", $"{crop.regrowAfterHarvest} days")}" : ""));

                    // seasons
                    summary.Add($"-grows in {string.Join(", ", crop.seasonsToGrowIn)}");

                    // drops
                    if (crop.minHarvest != crop.maxHarvest && crop.chanceForExtraCrops > 0)
                    {
                        summary.Add($"-drops {crop.minHarvest} to {crop.maxHarvest} ({Math.Round(crop.chanceForExtraCrops * 100, 2)}% chance of extra crops)");
                    }
                    else if (crop.minHarvest > 1)
                    {
                        summary.Add($"-drops {crop.minHarvest}");
                    }

                    // crop sale price
                    Item drop = GameHelper.GetObjectBySpriteIndex(crop.indexOfHarvest);
                    summary.Add($"-sells for {GenericField.GetSaleValueString(this.GetSaleValue(drop, false, metadata), 1)}");

                    // generate field
                    yield return(new GenericField("Crop", string.Join(Environment.NewLine, summary)));
                }
            }

            // crafting
            if (obj?.heldObject != null)
            {
                if (obj is Cask)
                {
                    // get cask data
                    Cask        cask           = (Cask)obj;
                    Object      agingObj       = cask.heldObject;
                    ItemQuality currentQuality = (ItemQuality)agingObj.quality;

                    // calculate aging schedule
                    float effectiveAge = metadata.Constants.CaskAgeSchedule.Values.Max() - cask.daysToMature;
                    var   schedule     =
                        (
                            from entry in metadata.Constants.CaskAgeSchedule
                            let quality = entry.Key
                                          let baseDays = entry.Value
                                                         where baseDays > effectiveAge
                                                         orderby baseDays ascending
                                                         let daysLeft = (int)Math.Ceiling((baseDays - effectiveAge) / cask.agingRate)
                                                                        select new
                    {
                        Quality = quality,
                        DaysLeft = daysLeft,
                        HarvestDate = GameHelper.GetDate(metadata.Constants.DaysInSeason).GetDayOffset(daysLeft)
                    }
                        )
                        .ToArray();

                    // display fields
                    yield return(new ItemIconField("Contents", obj.heldObject));

                    if (cask.minutesUntilReady <= 0 || !schedule.Any())
                    {
                        yield return(new GenericField("Aging", $"{currentQuality.GetName()} quality ready"));
                    }
                    else
                    {
                        string scheduleStr = string.Join(Environment.NewLine, (from entry in schedule select $"-{entry.Quality.GetName()} {TextHelper.Pluralise(entry.DaysLeft, "tomorrow", $"in {entry.DaysLeft} days")} ({entry.HarvestDate})"));
                        yield return(new GenericField("Aging", $"-{currentQuality.GetName()} now (use pickaxe to stop aging){Environment.NewLine}" + scheduleStr));
                    }
                }
                else
                {
                    yield return(new ItemIconField("Contents", obj.heldObject, $"{obj.heldObject.Name} " + (obj.minutesUntilReady > 0 ? "in " + TextHelper.Stringify(TimeSpan.FromMinutes(obj.minutesUntilReady)) : "ready")));
                }
            }

            // item
            if (showInventoryFields)
            {
                // needed for
                {
                    List <string> neededFor = new List <string>();

                    // bundles
                    if (isObject)
                    {
                        string[] bundles = (from bundle in this.GetUnfinishedBundles(obj) orderby bundle.Area, bundle.Name select $"{bundle.Area}: {bundle.Name}").ToArray();
                        if (bundles.Any())
                        {
                            neededFor.Add($"community center ({string.Join(", ", bundles)})");
                        }
                    }

                    // polyculture achievement
                    if (isObject && metadata.Constants.PolycultureCrops.Contains(obj.ParentSheetIndex))
                    {
                        int needed = metadata.Constants.PolycultureCount - GameHelper.GetShipped(obj.ParentSheetIndex);
                        if (needed > 0)
                        {
                            neededFor.Add($"polyculture achievement (ship {needed} more)");
                        }
                    }

                    // full shipment achievement
                    if (isObject && GameHelper.GetFullShipmentAchievementItems().Any(p => p.Key == obj.ParentSheetIndex && !p.Value))
                    {
                        neededFor.Add("full shipment achievement (ship one)");
                    }

                    // a full collection achievement
                    LibraryMuseum museum = Game1.locations.OfType <LibraryMuseum>().FirstOrDefault();
                    if (museum != null && museum.isItemSuitableForDonation(obj))
                    {
                        neededFor.Add("full collection achievement (donate one to museum)");
                    }

                    // yield
                    if (neededFor.Any())
                    {
                        yield return(new GenericField("Needed for", string.Join(", ", neededFor)));
                    }
                }

                // sale data
                if (canSell && !isCrop)
                {
                    // sale price
                    string saleValueSummary = GenericField.GetSaleValueString(this.GetSaleValue(item, this.KnownQuality, metadata), item.Stack);
                    yield return(new GenericField("Sells for", saleValueSummary));

                    // sell to
                    List <string> buyers = new List <string>();
                    if (obj?.canBeShipped() == true)
                    {
                        buyers.Add("shipping box");
                    }
                    buyers.AddRange(from shop in metadata.Shops where shop.BuysCategories.Contains(item.category) orderby shop.DisplayName select shop.DisplayName);
                    yield return(new GenericField("Sells to", TextHelper.OrList(buyers.ToArray())));
                }

                // gift tastes
                var giftTastes = this.GetGiftTastes(item, metadata);
                yield return(new ItemGiftTastesField("Loves this", giftTastes, GiftTaste.Love));

                yield return(new ItemGiftTastesField("Likes this", giftTastes, GiftTaste.Like));
            }

            // fence
            if (item is Fence)
            {
                Fence fence = (Fence)item;

                // health
                if (Game1.getFarm().isBuildingConstructed(Constant.BuildingNames.GoldClock))
                {
                    yield return(new GenericField("Health", "no decay with Gold Clock"));
                }
                else
                {
                    float maxHealth = fence.isGate ? fence.maxHealth * 2 : fence.maxHealth;
                    float health    = fence.health / maxHealth;
                    float daysLeft  = fence.health * metadata.Constants.FenceDecayRate / 60 / 24;
                    yield return(new PercentageBarField("Health", (int)fence.health, (int)maxHealth, Color.Green, Color.Red, $"{Math.Round(health * 100)}% (roughly {Math.Round(daysLeft)} days left)"));
                }
            }

            // recipes
            if (item.GetSpriteType() == ItemSpriteType.Object)
            {
                RecipeModel[] recipes = GameHelper.GetRecipesForIngredient(this.DisplayItem).ToArray();
                if (recipes.Any())
                {
                    yield return(new RecipesForIngredientField("Recipes", item, recipes));
                }
            }

            // owned
            if (showInventoryFields && !isCrop && !(item is Tool))
            {
                yield return(new GenericField("Owned", $"you own {GameHelper.CountOwnedItems(item)} of these"));
            }
        }
Beispiel #6
0
        public bool HighlightItemToShip(Item i)
        {
            SObject @object = i as SObject;

            return(@object != null && @object.canBeShipped());
        }