Ejemplo n.º 1
0
        /// <summary>Get the data to display for this subject.</summary>
        public override IEnumerable <ICustomField> GetData()
        {
            // 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 || this.Metadata.Shops.Any(shop => shop.BuysCategories.Contains(item.Category));
            bool    isMovieTicket = obj?.ParentSheetIndex == 809 && !obj.bigCraftable.Value;

            // 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;
                Bush?potBush = pot.bush.Value;

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

                if (potBush != null)
                {
                    ISubject?subject = this.Codex.GetByEntity(potBush, this.Location ?? potBush.currentLocation);
                    if (subject != null)
                    {
                        yield return(new LinkField(I18n.Item_Contents(), subject.Name, () => subject));
                    }
                }
            }

            // 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();
                    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
                if (!isMovieTicket)
                {
                    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 || this.ShowAllGiftTastes)
                    {
                        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)
            {
                RecipeModel[] recipes =
                    // recipes that take this item as ingredient
                    this.GameHelper.GetRecipesForIngredient(this.DisplayItem)
                    .Concat(this.GameHelper.GetRecipesForIngredient(item))

                    // recipes which produce this item
                    .Concat(this.GameHelper.GetRecipesForOutput(this.DisplayItem))
                    .Concat(this.GameHelper.GetRecipesForOutput(item))

                    // recipes for a machine
                    .Concat(this.GameHelper.GetRecipesForMachine(this.DisplayItem as SObject))
                    .Concat(this.GameHelper.GetRecipesForMachine(item as SObject))
                    .ToArray();

                if (recipes.Any())
                {
                    yield return(new ItemRecipesField(this.GameHelper, I18n.Item_Recipes(), item, recipes.ToArray()));
                }
            }

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

            // fish pond data
            // derived from FishPond::doAction and FishPond::isLegalFishForPonds
            if (!item.HasContextTag("fish_legendary") && (item.Category == SObject.FishCategory || Utility.IsNormalObjectAtParentSheetIndex(item, 393 /*coral*/) || Utility.IsNormalObjectAtParentSheetIndex(item, 397 /*sea urchin*/)))
            {
                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 (isMovieTicket)
            {
                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
                    const GiftTaste rejectKey = (GiftTaste)(-1);
                    IDictionary <GiftTaste, string[]> tastes = this.GameHelper.GetMovieTastes()
                                                               .GroupBy(entry => entry.Value ?? rejectKey)
                                                               .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));

                    yield return(new MovieTastesField(I18n.Item_MovieTicket_RejectsMovie(), tastes, rejectKey));
                }
            }

            // 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 is not(495 or 496 or 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)));
            }
        }
Ejemplo n.º 2
0
        /// <summary>Get the data to display for this subject.</summary>
        public override IEnumerable <ICustomField> GetData()
        {
            // get info
            Building building     = this.Target;
            bool     built        = !building.isUnderConstruction();
            int?     upgradeLevel = this.GetUpgradeLevel(building);

            // construction / upgrade
            if (!built || building.daysUntilUpgrade.Value > 0)
            {
                int   daysLeft  = building.isUnderConstruction() ? building.daysOfConstructionLeft.Value : building.daysUntilUpgrade.Value;
                SDate readyDate = SDate.Now().AddDays(daysLeft);
                yield return(new GenericField(I18n.Building_Construction(), I18n.Building_Construction_Summary(date: this.Stringify(readyDate))));
            }

            // owner
            Farmer owner = this.GetOwner();

            if (owner != null)
            {
                yield return(new LinkField(I18n.Building_Owner(), owner.Name, () => this.Codex.GetByEntity(owner)));
            }
            else if (building.indoors.Value is Cabin)
            {
                yield return(new GenericField(I18n.Building_Owner(), I18n.Building_Owner_None()));
            }

            // stable horse
            if (built && building is Stable stable)
            {
                Horse horse = Utility.findHorse(stable.HorseId);
                if (horse != null)
                {
                    yield return(new LinkField(I18n.Building_Horse(), horse.Name, () => this.Codex.GetByEntity(horse)));

                    yield return(new GenericField(I18n.Building_HorseLocation(), I18n.Building_HorseLocation_Summary(location: horse.currentLocation.Name, x: horse.getTileX(), y: horse.getTileY())));
                }
            }

            // animals
            if (built && building.indoors.Value is AnimalHouse animalHouse)
            {
                // animal counts
                yield return(new GenericField(I18n.Building_Animals(), I18n.Building_Animals_Summary(count: animalHouse.animalsThatLiveHere.Count, max: animalHouse.animalLimit.Value)));

                // feed trough
                if ((building is Barn || building is Coop) && upgradeLevel >= 2)
                {
                    yield return(new GenericField(I18n.Building_FeedTrough(), I18n.Building_FeedTrough_Automated()));
                }
                else
                {
                    this.GetFeedMetrics(animalHouse, out int totalFeedSpaces, out int filledFeedSpaces);
                    yield return(new GenericField(I18n.Building_FeedTrough(), I18n.Building_FeedTrough_Summary(filled: filledFeedSpaces, max: totalFeedSpaces)));
                }
            }

            // slimes
            if (built && building.indoors.Value is SlimeHutch slimeHutch)
            {
                // slime count
                int slimeCount = slimeHutch.characters.OfType <GreenSlime>().Count();
                yield return(new GenericField(I18n.Building_Slimes(), I18n.Building_Slimes_Summary(count: slimeCount, max: 20)));

                // water trough
                yield return(new GenericField(I18n.Building_WaterTrough(), I18n.Building_WaterTrough_Summary(filled: slimeHutch.waterSpots.Count(p => p), max: slimeHutch.waterSpots.Count)));
            }

            // upgrade level
            if (built)
            {
                var upgradeLevelSummary = this.GetUpgradeLevelSummary(building, upgradeLevel).ToArray();
                if (upgradeLevelSummary.Any())
                {
                    yield return(new CheckboxListField(I18n.Building_Upgrades(), upgradeLevelSummary));
                }
            }

            // specific buildings
            if (built)
            {
                switch (building)
                {
                // fish pond
                case FishPond pond:
                    if (pond.fishType.Value <= -1)
                    {
                        yield return(new GenericField(I18n.Building_FishPond_Population(), I18n.Building_FishPond_Population_Empty()));
                    }
                    else
                    {
                        // get fish population
                        SObject fish = pond.GetFishObject();
                        fish.Stack = pond.FishCount;
                        var pondData = pond.GetFishPondData();

                        // population field
                        {
                            string populationStr = $"{fish.DisplayName} ({I18n.Generic_Ratio(pond.FishCount, pond.maxOccupants.Value)})";
                            if (pond.FishCount < pond.maxOccupants.Value)
                            {
                                SDate nextSpawn = SDate.Now().AddDays(pondData.SpawnTime - pond.daysSinceSpawn.Value);
                                populationStr += Environment.NewLine + I18n.Building_FishPond_Population_NextSpawn(relativeDate: this.GetRelativeDateStr(nextSpawn));
                            }

                            yield return(new ItemIconField(this.GameHelper, I18n.Building_FishPond_Population(), fish, text: populationStr));
                        }

                        // output
                        yield return(new ItemIconField(this.GameHelper, I18n.Building_OutputReady(), pond.output.Value));

                        // drops
                        int chanceOfAnyDrop = (int)Math.Round(Utility.Lerp(0.15f, 0.95f, pond.currentOccupants.Value / 10f) * 100);
                        yield return(new FishPondDropsField(this.GameHelper, I18n.Building_FishPond_Drops(), pond.currentOccupants.Value, pondData, preface: I18n.Building_FishPond_Drops_Preface(chance: chanceOfAnyDrop.ToString())));

                        // quests
                        if (pondData.PopulationGates?.Any(gate => gate.Key > pond.lastUnlockedPopulationGate.Value) == true)
                        {
                            yield return(new CheckboxListField(I18n.Building_FishPond_Quests(), this.GetPopulationGates(pond, pondData)));
                        }
                    }
                    break;

                // Junimo hut
                case JunimoHut hut:
                    yield return(new GenericField(I18n.Building_JunimoHarvestingEnabled(), I18n.Stringify(!hut.noHarvest.Value)));

                    yield return(new ItemIconListField(this.GameHelper, I18n.Building_OutputReady(), hut.output.Value?.items, showStackSize: true));

                    break;

                // mill
                case Mill mill:
                    yield return(new ItemIconListField(this.GameHelper, I18n.Building_OutputProcessing(), mill.input.Value?.items, showStackSize: true));

                    yield return(new ItemIconListField(this.GameHelper, I18n.Building_OutputReady(), mill.output.Value?.items, showStackSize: true));

                    break;

                // silo
                case Building _ when building.buildingType.Value == "Silo":
                {
                    // hay summary
                    Farm farm      = Game1.getFarm();
                    int  siloCount = Utility.numSilos();
                    int  hayCount  = farm.piecesOfHay.Value;
                    int  maxHay    = Math.Max(farm.piecesOfHay.Value, siloCount * 240);
                    yield return(new GenericField(
                                     I18n.Building_StoredHay(),
                                     siloCount == 1
                                    ? I18n.Building_StoredHay_SummaryOneSilo(hayCount: hayCount, maxHay: maxHay)
                                    : I18n.Building_StoredHay_SummaryMultipleSilos(hayCount: hayCount, maxHay: maxHay, siloCount: siloCount)
                                     ));
                }
                break;
                }
            }
        }