// is this tile and every tile around it plantable? private bool BorderClear(Farm farm, Vector2 pos) { // is this tile in the planting pattern? if (!IsTileInPattern(pos)) { return(false); } if (FruitTree.IsGrowthBlocked(pos, farm)) { //Monitor.Log($"BorderClear [{pos.X}, {pos.Y}]: growth blocked", LogLevel.Warn); return(false); } if (!Plantable(farm, pos)) { //Monitor.Log($"BorderClear [{pos.X}, {pos.Y}]: growth possible but tile not plantable", LogLevel.Warn); return(false); } for (int x = -1; x < 2; x++) { for (int y = -1; y < 2; y++) { Vector2 v = new Vector2(pos.X + x, pos.Y + y); if (!Plantable(farm, v)) { //Monitor.Log($"BorderClear [{pos.X}, {pos.Y}]: neighbour tile [{v.X}, {v.Y}] not plantable", LogLevel.Warn); return(false); } } } return(true); }
/// <summary>Before a save, check every fruit tree to see if it can grow. If not, make it grow.</summary> private void OnSaving(object sender, SavingEventArgs e) { foreach (GameLocation l in Game1.locations) { foreach (KeyValuePair <Vector2, TerrainFeature> fruitTree in l.terrainFeatures.Pairs.Where( item => item.Value is FruitTree)) { if (FruitTree.IsGrowthBlocked(fruitTree.Key, l)) { this.SimulateFruitTreeDayUpdate(l, fruitTree.Value as FruitTree); } } } }
private static bool CanPlantFruitTreeOnTile(GameLocation farm, Vector2 pos) { if (FruitTree.IsGrowthBlocked(pos, farm)) { return(false); } if (Util.IsOccupied(farm, pos)) { return(false); } if (Util.IsHoed(farm, pos)) { return(false); } return(true); }
/// <summary> /// Grows the fruit tree using the vanilla constraints taken from StardewValley.TerrainFeatures.FruitTree.dayUpdate. /// </summary> /// <param name="fruittree">current fruit tree</param> /// <param name="location">ingame location (e.g. farm)</param> /// <param name="tileLocation">position in said location</param> /// <param name="increaseGrowthElseRevertGrowth">if true reduce days until mature (grow), otherwise increase days (revert growth)</param> private void GrowFruitTree(FruitTree fruittree, GameLocation location, Vector2 tileLocation, bool increaseGrowthElseRevertGrowth) { bool foundSomething = FruitTree.IsGrowthBlocked(tileLocation, location); // check if the tree can grow and if it's not fully matured. the base game reduces daysUntilMatured for fully grown trees to determine the tree age. if (!foundSomething && fruittree.growthStage != 4) { if (increaseGrowthElseRevertGrowth) { // grow tree (reduce days until mature) fruittree.daysUntilMature.Set(fruittree.daysUntilMature.Value - 1); } else { // revert tree growth (increase days until mature) fruittree.daysUntilMature.Set(fruittree.daysUntilMature.Value + 1); } UpdateGrowthStage(fruittree); } }
/// <summary>Get the data to display for this subject.</summary> /// <remarks>Tree growth algorithm reverse engineered from <see cref="FruitTree.dayUpdate"/>.</remarks> public override IEnumerable <ICustomField> GetData() { FruitTree tree = this.Target; // get basic info bool isMature = tree.daysUntilMature.Value <= 0; bool isDead = tree.stump.Value; bool isStruckByLightning = tree.struckByLightningCountdown.Value > 0; // show next fruit if (isMature && !isDead) { SDate nextFruit = SDate.Now().AddDays(1); string label = I18n.FruitTree_NextFruit(); if (isStruckByLightning) { yield return(new GenericField(label, I18n.FruitTree_NextFruit_StruckByLightning(count: tree.struckByLightningCountdown.Value))); } else if (!this.IsInSeason(tree, nextFruit.Season)) { yield return(new GenericField(label, I18n.FruitTree_NextFruit_OutOfSeason())); } else if (tree.fruitsOnTree.Value == FruitTree.maxFruitsOnTrees) { yield return(new GenericField(label, I18n.FruitTree_NextFruit_MaxFruit())); } else { yield return(new GenericField(label, I18n.Generic_Tomorrow())); } } // show growth data if (!isMature) { SDate dayOfMaturity = SDate.Now().AddDays(tree.daysUntilMature.Value); string grownOnDateText = I18n.FruitTree_Growth_Summary(date: this.Stringify(dayOfMaturity)); yield return(new GenericField(I18n.FruitTree_NextFruit(), I18n.FruitTree_NextFruit_TooYoung())); yield return(new GenericField(I18n.FruitTree_Growth(), $"{grownOnDateText} ({this.GetRelativeDateStr(dayOfMaturity)})")); if (FruitTree.IsGrowthBlocked(this.Tile, tree.currentLocation)) { yield return(new GenericField(I18n.FruitTree_Complaints(), I18n.FruitTree_Complaints_AdjacentObjects())); } } else { // get quality schedule ItemQuality currentQuality = this.GetCurrentQuality(tree, this.Constants.FruitTreeQualityGrowthTime); if (currentQuality == ItemQuality.Iridium) { yield return(new GenericField(I18n.FruitTree_Quality(), I18n.FruitTree_Quality_Now(quality: I18n.For(currentQuality)))); } else { string[] summary = this .GetQualitySchedule(tree, currentQuality, this.Constants.FruitTreeQualityGrowthTime) .Select(entry => { // read schedule ItemQuality quality = entry.Key; int daysLeft = entry.Value; SDate date = SDate.Now().AddDays(daysLeft); int yearOffset = date.Year - Game1.year; // generate summary line if (daysLeft <= 0) { return($"-{I18n.FruitTree_Quality_Now(quality: I18n.For(quality))}"); } string line = yearOffset == 1 ? $"-{I18n.FruitTree_Quality_OnDateNextYear(quality: I18n.For(quality), date: this.Stringify(date))}" : $"-{I18n.FruitTree_Quality_OnDate(quality: I18n.For(quality), date: this.Stringify(date))}"; line += $" ({this.GetRelativeDateStr(daysLeft)})"; return(line); }) .ToArray(); yield return(new GenericField(I18n.FruitTree_Quality(), string.Join(Environment.NewLine, summary))); } } // show season yield return(new GenericField( I18n.FruitTree_Season(), I18n.FruitTree_Season_Summary(I18n.GetSeasonName(tree.fruitSeason.Value == "island" ? "summer" : tree.fruitSeason.Value)) )); }