public HijackCask(Cask b) : base(b.TileLocation) { heldObject.Value = b.heldObject.Value; agingRate.Value = b.agingRate.Value; daysToMature.Value = b.daysToMature.Value; MinutesUntilReady = b.MinutesUntilReady; }
public static bool GetAgingMultiplierForItem(ref Cask __instance, Item item, ref float __result) { __result = 0f; if (item != null && (Utility.IsNormalObjectAtParentSheetIndex(item, item.ParentSheetIndex) || IsColoredObjectAtParentSheetIndex(item, item.ParentSheetIndex))) { if (IsVanillaCask(__instance)) { if (DataLoader.CaskDataId.ContainsKey(item.ParentSheetIndex)) { __result = DataLoader.CaskDataId[item.ParentSheetIndex]; } else if (DataLoader.CaskDataId.ContainsKey(item.Category)) { __result = DataLoader.CaskDataId[item.Category]; } else { return(true); } } else { if (AgerController.GetAger(__instance.Name) is CustomAger ager) { var agingMultiplier = AgerController.GetAgingMultiplierForItem(ager, item); if (agingMultiplier.HasValue) { __result = agingMultiplier.Value; } } } } return(false); }
void OnEnable() { foreach (SceneComponent terrainComponent in targets) { terrainComponent.color = new Color(UnityEngine.Random.Range(0.5f, 1f), UnityEngine.Random.Range(0.5f, 1f), UnityEngine.Random.Range(0.5f, 1f)); //// 设置资源路径 add by TangJian 2018/03/13 15:37:42 //{ // if (PrefabUtility.GetPrefabType(terrainComponent.gameObject) == PrefabType.Prefab) // { // if (terrainComponent.filePath == null || terrainComponent.filePath == "") // terrainComponent.filePath = Tools.GetPrefabPath(terrainComponent.gameObject) ?? terrainComponent.filePath; // } // terrainComponent.prefab = AssetDatabase.LoadAssetAtPath<GameObject>(terrainComponent.filePath); //} if (terrainComponent.GetComponent <Cask>()) { Cask cask = terrainComponent.GetComponent <Cask>(); Bounds bounds = cask.gameObject.GetRendererBounds(2, 99); cask.data.width = bounds.size.x; cask.data.height = bounds.size.y; } } AssetDatabase.SaveAssets(); }
void Cask(RaycastHit _hit) { if (hasGlass && slot1 == 0) { Cask cask = _hit.transform.gameObject.GetComponent <Cask> (); slot1 = cask.beer; } }
public static bool IsValidCaskLocation(ref Cask __instance, ref bool __result) { if ((IsVanillaCask(__instance) && DataLoader.ModConfig.EnableCasksAnywhere) || (AgerController.GetAger(__instance.Name) is CustomAger ager && ager.EnableAgingAnywhere)) { __result = true; return(false); }
/********* ** Private methods *********/ /// <summary>Get whether an object is a machine with 'fast processing' enabled.</summary> /// <param name="context">The cheat context.</param> /// <param name="obj">The machine to check.</param> private bool IsFastMachine(CheatContext context, SObject obj) { // quick initial check bool mayBeMachine = obj != null && (obj.bigCraftable.Value || obj is CrabPot); if (!mayBeMachine) { return(false); } // specific check ModConfig config = context.Config; return(obj switch { Cask _ => config.FastCask, CrabPot _ => config.FastCrabPot, WoodChipper _ => config.FastWoodChipper, _ => obj.name switch { "Bee House" => config.FastBeeHouse, "Bone Mill" => config.FastBoneMill, "Charcoal Kiln" => config.FastCharcoalKiln, "Cheese Press" => config.FastCheesePress, "Coffee Maker" => config.FastCoffeeMaker, "Crystalarium" => config.FastCrystalarium, "Deconstructor" => config.FastDeconstructor, "Furnace" => config.FastFurnace, "Geode Crusher" => config.FastGeodeCrusher, "Heavy Tapper" => config.FastTapper, "Incubator" => config.FastIncubator, "Keg" => config.FastKeg, "Lightning Rod" => config.FastLightningRod, "Loom" => config.FastLoom, "Mayonnaise Machine" => config.FastMayonnaiseMachine, "Mushroom Box" => config.FastMushroomBox, "Oil Maker" => config.FastOilMaker, "Ostrich Incubator" => config.FastOstrichIncubator, "Preserves Jar" => config.FastPreservesJar, "Recycling Machine" => config.FastRecyclingMachine, "Seed Maker" => config.FastSeedMaker, "Slime Egg-Press" => config.FastSlimeEggPress, "Slime Incubator" => config.FastSlimeIncubator, "Soda Machine" => config.FastSodaMachine, "Solar Panel" => config.FastSolarPanel, "Statue Of Endless Fortune" => config.FastStatueOfEndlessFortune, "Statue Of Perfection" => config.FastStatueOfPerfection, "Statue Of True Perfection" => config.FastStatueOfTruePerfection, "Tapper" => config.FastTapper, "Worm Bin" => config.FastWormBin, _ => false } });
private Cask CaskBack(HijackCask j) { // get a cask back var cask = new Cask(j.TileLocation); // reset all the fields cask.heldObject.Value = j.heldObject.Value; cask.agingRate.Value = j.agingRate.Value; cask.daysToMature.Value = j.daysToMature.Value; cask.MinutesUntilReady = j.MinutesUntilReady; // return the cask return(cask); }
public static void Postfix(Cask __instance, SpriteBatch spriteBatch, int x, int y, float alpha) { if (__instance.heldObject.Value != null && (int)__instance.heldObject.Value.quality > 0) { if (__instance.heldObject.Value.Quality != 6 && __instance.heldObject.Value.Quality != -2) { return; } Vector2 scaleFactor = (((int)__instance.minutesUntilReady > 0) ? new Vector2(Math.Abs(__instance.scale.X - 5f), Math.Abs(__instance.scale.Y - 5f)) : Vector2.Zero); scaleFactor *= 4f; Vector2 position = Game1.GlobalToLocal(Game1.viewport, new Vector2(x * 64, y * 64 - 64)); Rectangle destination = new Rectangle((int)(position.X + 32f - 8f - scaleFactor.X / 2f) + ((__instance.shakeTimer > 0) ? Game1.random.Next(-1, 2) : 0), (int)(position.Y + 64f + 8f - scaleFactor.Y / 2f) + ((__instance.shakeTimer > 0) ? Game1.random.Next(-1, 2) : 0), (int)(16f + scaleFactor.X), (int)(16f + scaleFactor.Y / 2f)); Microsoft.Xna.Framework.Rectangle quality_rect = new(0, 0, 8, 8); Texture2D quality_sheet = __instance.Quality == 10 ? Mod.wonderfulTex : Mod.poorTex; spriteBatch.Draw(quality_sheet, destination, quality_rect, Color.White * 0.95f, 0f, Vector2.Zero, SpriteEffects.None, (float)((y + 1) * 64) / 10000f); } }
public static bool checkForMaturity(ref Cask __instance) { if (DataLoader.ModConfig.EnableMoreThanOneQualityIncrementPerDay) { if ((float)__instance.daysToMature.Value <= 0f) { __instance.MinutesUntilReady = 1; __instance.heldObject.Value.Quality = 4; } else if ((float)__instance.daysToMature.Value <= 28f) { __instance.heldObject.Value.Quality = 2; } else if ((float)__instance.daysToMature.Value <= 42f) { __instance.heldObject.Value.Quality = 1; } return(false); } return(true); }
private void Spawn(int itemId) { foreach (var loc in Game1.locations) { for (int xTile = 0; xTile < loc.Map.Layers[0].LayerWidth; ++xTile) { for (int yTile = 0; yTile < loc.Map.Layers[0].LayerHeight; ++yTile) { string prop = loc.doesTileHaveProperty((int)xTile, (int)yTile, "Diggable", "Back"); if (prop != null || prop == null) { if (loc.isTileLocationTotallyClearAndPlaceable(xTile, yTile)) { Cask c = new Cask(new Vector2(xTile, yTile)); loc.objects.Add(new Vector2(xTile, yTile), c); } } } } } }
private void Display_RenderedWorld(object sender, RenderedWorldEventArgs e) { if (Game1.activeClickableMenu == null) { GameLocation CurrentLocation = Game1.player.currentLocation; bool IsHoveringPlacedObject = CurrentLocation.Objects.TryGetValue(HoveredTile, out SObject HoveredObject); if (IsHoveringPlacedObject) { if (UserConfig.DrawToolTip) { // Draw a tooltip that shows how many of the machine were combined, and its total combined processing power // Such as: "Quantity: 5\nPower: 465%" if (HoveredObject.TryGetCombinedQuantity(out int CombinedQuantity)) { Cask Cask = HoveredObject as Cask; bool IsCask = Cask != null; CrabPot CrabPot = HoveredObject as CrabPot; bool IsCrabPot = CrabPot != null; bool IsScarecrow = HoveredObject.IsScarecrow(); bool HasHeldObject = HoveredObject.heldObject?.Value != null; float UIScaleFactor = Game1.options.zoomLevel / Game1.options.uiScale; SpriteFont DefaultFont = Game1.dialogueFont; int Padding = 25; int MarginBetweenColumns = 10; int MarginBetweenRows = 5; float LabelTextScale = 0.75f; float ValueTextScale = 1.0f; bool ShowDurationInfo = UserConfig.ToolTipShowDuration && UserConfig.ShouldModifyProcessingSpeed(HoveredObject); bool ShowQuantityInfo = UserConfig.ToolTipShowQuantity && UserConfig.ShouldModifyInputsAndOutputs(HoveredObject); // Compute row headers List <string> RowHeaders = new List <string>() { Helper.Translation.Get("ToolTipQuantityLabel"), Helper.Translation.Get("ToolTipPowerLabel") }; if (ShowDurationInfo) { if (IsCask) { //RowHeaders.Add(Helper.Translation.Get("ToolTipCaskAgingRateLabel")); if (HasHeldObject) { RowHeaders.Add(Helper.Translation.Get("ToolTipCaskDaysUntilIridiumLabel")); } } else if (IsCrabPot) { RowHeaders.Add(Helper.Translation.Get("ToolTipCrabPotProcessingIntervalLabel")); } else { if (HasHeldObject) { RowHeaders.Add(Helper.Translation.Get("ToolTipMinutesRemainingLabel")); } } } if (ShowQuantityInfo) { if (HasHeldObject && HoveredObject.HasModifiedOutput()) { RowHeaders.Add(Helper.Translation.Get("ToolTipProducedQuantityLabel")); } } if (IsScarecrow) { RowHeaders.Add(Helper.Translation.Get("ToolTipScarecrowRadiusLabel")); } List <Vector2> RowHeaderSizes = RowHeaders.Select(x => DefaultFont.MeasureString(x) * LabelTextScale).ToList(); double ProcessingPower = UserConfig.ComputeProcessingPower(CombinedQuantity) * 100.0; string FormattedProcessingPower = string.Format("{0}%", ProcessingPower.ToString("0.#")); // Compute row values List <string> RowValues = new List <string>() { CombinedQuantity.ToString(), FormattedProcessingPower }; if (ShowDurationInfo) { if (IsCask) { //RowValues.Add(Cask.agingRate.Value.ToString("0.##")); if (HasHeldObject) { RowValues.Add(Math.Ceiling(Cask.daysToMature.Value / Cask.agingRate.Value).ToString("0.##")); } } else if (IsCrabPot) { CrabPot.TryGetProcessingInterval(out double Power, out double IntervalHours, out int IntervalMinutes); RowValues.Add(IntervalMinutes.ToString()); } else { if (HasHeldObject) { RowValues.Add(HoveredObject.MinutesUntilReady.ToString("0.##")); } } } if (ShowQuantityInfo) { if (HasHeldObject && HoveredObject.HasModifiedOutput()) { RowValues.Add(HoveredObject.heldObject.Value.Stack.ToString()); } } if (IsScarecrow) { // Subtract 1 because the game internally counts the scarecrow's occupied tile as part of its radius, but users usually would be confused by that // So a typical user expects radius=8 for a regular scarecrow, even though the game does its calculations with radius=9 int OriginalRadius = HoveredObject.GetScarecrowBaseRadius() - 1; int AlteredRadius = HoveredObject.GetScarecrowRadius() - 1; //RowValues.Add(string.Format("{0}-->{1}", OriginalRadius, AlteredRadius)); RowValues.Add(AlteredRadius.ToString()); } List <Vector2> RowValueSizes = RowValues.Select(x => DrawHelpers.MeasureStringWithSpecialNumbers(x, ValueTextScale, 0.0f)).ToList(); // Measure the tooltip List <int> RowHeights = new List <int>(); for (int i = 0; i < RowHeaders.Count; i++) { RowHeights.Add((int)Math.Max(RowHeaderSizes[i].Y, RowValueSizes[i].Y)); } List <int> ColumnWidths = new List <int> { (int)RowHeaderSizes.Max(x => x.X), (int)RowValueSizes.Max(x => x.X) }; int ToolTipTopWidth = Padding + ColumnWidths.Sum() + (ColumnWidths.Count - 1) * MarginBetweenColumns + Padding; int ToolTipHeight = Padding + RowHeights.Sum() + (RowHeights.Count - 1) * MarginBetweenRows + Padding; Point ToolTipTopleft = DrawHelpers.GetTopleftPosition(new Point(ToolTipTopWidth, ToolTipHeight), new Point((int)((MouseScreenPosition.X + UserConfig.ToolTipOffset.X) / UIScaleFactor), (int)((MouseScreenPosition.Y + UserConfig.ToolTipOffset.Y) / UIScaleFactor)), 100); // Draw tooltip background DrawHelpers.DrawBox(e.SpriteBatch, new Rectangle(ToolTipTopleft.X, ToolTipTopleft.Y, ToolTipTopWidth, ToolTipHeight)); // Draw each row's header and value int CurrentY = ToolTipTopleft.Y + Padding; for (int i = 0; i < RowHeights.Count; i++) { int CurrentRowHeight = RowHeights[i]; // Draw the row header Vector2 RowHeaderPosition = new Vector2( ToolTipTopleft.X + Padding + ColumnWidths[0] - RowHeaderSizes[i].X, CurrentY + (RowHeights[i] - RowHeaderSizes[i].Y) / 2.0f ); e.SpriteBatch.DrawString(DefaultFont, RowHeaders[i], RowHeaderPosition, Color.Black, 0.0f, Vector2.Zero, LabelTextScale, SpriteEffects.None, 1.0f); // Draw the row value Vector2 RowValuePosition = new Vector2( ToolTipTopleft.X + Padding + ColumnWidths[0] + MarginBetweenColumns, CurrentY + (RowHeights[i] - RowValueSizes[i].Y) / 2.0f ); DrawHelpers.DrawStringWithSpecialNumbers(e.SpriteBatch, RowValuePosition, RowValues[i], ValueTextScale, Color.White); CurrentY += CurrentRowHeight + MarginBetweenRows; } } } } } }
public static void Cask_Postfix(Cask __instance, Item __result) { Postfix(__instance as SObject, __result); }
/// <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")); } }
public static bool PerformObjectDropInAction(Cask cask, Item dropIn, bool probe, Player who) { if (dropIn is SVObject o && o.bigCraftable.Value) { return(false); } if (cask.heldObject.Value != null) { return(false); } if (cask.Quality >= 4) { return(false); } bool goodItem = false; float multiplier = 1f; switch (dropIn.ParentSheetIndex) { case 426: goodItem = true; multiplier = 4f; break; case 424: goodItem = true; multiplier = 4f; break; case 348: goodItem = true; multiplier = 1f; break; case 459: goodItem = true; multiplier = 2f; break; case 303: goodItem = true; multiplier = 1.66f; break; case 346: goodItem = true; multiplier = 2f; break; } if (!goodItem) { return(false); } if (probe) { return(true); } cask.heldObject.Value = (SVObject)dropIn.getOne(); cask.agingRate.Value = multiplier; cask.MinutesUntilReady = 999999; switch (cask.heldObject.Value.Quality) { case 1: cask.daysToMature.Value = 42f; break; case 2: cask.daysToMature.Value = 28f; break; case 4: cask.daysToMature.Value = 0f; cask.MinutesUntilReady = 1; break; default: cask.daysToMature.Value = 56f; break; } who.currentLocation.playSound("Ship"); who.currentLocation.playSound("bubbles"); ModEntry.Multiplayer.broadcastSprites(who.currentLocation, new TemporaryAnimatedSprite("TileSheets\\animations", new Rectangle(256, 1856, 64, 128), 80f, 6, 999999, cask.TileLocation * 64f + new Vector2(0f, -128f), false, false, (cask.TileLocation.Y + 1f) * 64f / 10000f + 0.0001f, 0f, Color.Yellow * 0.75f, 1f, 0f, 0f, 0f) { alphaFade = 0.005f }); return(true); }
// ReSharper disable once UnusedMember.Global public static bool Prefix(Cask __instance, ref Item dropIn, ref bool probe, ref Player who, ref bool __result) { __result = PerformObjectDropInAction(__instance, dropIn, probe, who); return(false); }
public static bool PerformObjectDropInAction(ref Cask __instance, ref Item dropIn, ref bool probe, ref Farmer who, ref bool __result) { if (dropIn != null && dropIn is StardewValley.Object && (dropIn as StardewValley.Object).bigCraftable.Value || __instance.heldObject.Value != null) { __result = false; return(false); } if (!probe && (who == null || !(who.currentLocation is Cellar)) && !DataLoader.ModConfig.EnableCasksAnywhere) { Game1.showRedMessageUsingLoadString("Strings\\Objects:CaskNoCellar"); __result = false; return(false); } if (__instance.Quality >= 4) { __result = false; return(false); } bool flag = false; float num = 1f; if (DataLoader.CaskData.ContainsKey(dropIn.ParentSheetIndex)) { flag = true; num = DataLoader.CaskData[dropIn.ParentSheetIndex]; } else if (DataLoader.CaskData.ContainsKey(dropIn.Category)) { flag = true; num = DataLoader.CaskData[dropIn.Category]; } else { switch (dropIn.ParentSheetIndex) { case 303: flag = true; num = 1.66f; break; case 346: flag = true; num = 2f; break; case 348: flag = true; num = 1f; break; case 424: flag = true; num = 4f; break; case 426: flag = true; num = 4f; break; case 459: flag = true; num = 2f; break; } } if (!flag) { __result = false; return(false); } __instance.heldObject.Value = dropIn.getOne() as StardewValley.Object; if (!probe) { __instance.agingRate.Value = num; __instance.daysToMature.Value = 56f; __instance.MinutesUntilReady = 999999; if (__instance.heldObject.Value.Quality == 1) { __instance.daysToMature.Value = 42f; } else if (__instance.heldObject.Value.Quality == 2) { __instance.daysToMature.Value = 28f; } else if (__instance.heldObject.Value.Quality == 4) { __instance.daysToMature.Value = 0.0f; __instance.MinutesUntilReady = 1; } who.currentLocation.playSound("Ship"); who.currentLocation.playSound("bubbles"); Multiplayer multiplayer = DataLoader.Helper.Reflection.GetField <Multiplayer>(typeof(Game1), "multiplayer").GetValue(); multiplayer.broadcastSprites ( who.currentLocation , new TemporaryAnimatedSprite[1] { new TemporaryAnimatedSprite("TileSheets\\animations", new Rectangle(256, 1856, 64, 128), 80f, 6, 999999, __instance.TileLocation * 64f + new Vector2(0.0f, (float)sbyte.MinValue), false, false, (float)(((double)__instance.TileLocation.Y + 1.0) * 64.0 / 10000.0 + 9.99999974737875E-05), 0.0f, Color.Yellow * 0.75f, 1f, 0.0f, 0.0f, 0.0f, false) { alphaFade = 0.005f } } ); } __result = true; return(false); }
private void DrawHoverTooltip(object sender, EventArgs e) { //StardewValley.Object tile = Game1.currentLocation.Objects.SafeGet(Game1.currentCursorTile); //TerrainFeature feature = null; if (_currentTileBuilding != null) { if (_currentTileBuilding is Mill millBuilding) { if (!millBuilding.input.isEmpty()) { int wheatCount = 0; int beetCount = 0; foreach (var item in millBuilding.input.items) { switch (item.Name) { case "Wheat": wheatCount = item.Stack; break; case "Beet": beetCount = item.Stack; break; } } StringBuilder builder = new StringBuilder(); if (wheatCount > 0) { builder.Append(wheatCount + " wheat"); } if (beetCount > 0) { if (wheatCount > 0) { builder.Append(Environment.NewLine); } builder.Append(beetCount + " beets"); } if (builder.Length > 0) { IClickableMenu.drawHoverText( Game1.spriteBatch, builder.ToString(), Game1.smallFont); } } } } else if (_currentTile != null && (!_currentTile.bigCraftable || _currentTile.minutesUntilReady > 0)) { if (_currentTile.bigCraftable && _currentTile.minutesUntilReady > 0 && _currentTile.Name != "Heater") { StringBuilder hoverText = new StringBuilder(); if (_currentTile is Cask) { Cask currentCask = _currentTile as Cask; hoverText.Append((int)(currentCask.daysToMature / currentCask.agingRate)) .Append(" " + _helper.SafeGetString( LanguageKeys.DaysToMature)); } else if (_currentTile is StardewValley.Buildings.Mill) { } else { int hours = _currentTile.minutesUntilReady / 60; int minutes = _currentTile.minutesUntilReady % 60; if (hours > 0) { hoverText.Append(hours).Append(" ") .Append(_helper.SafeGetString( LanguageKeys.Hours)) .Append(", "); } hoverText.Append(minutes).Append(" ") .Append(_helper.SafeGetString( LanguageKeys.Minutes)); } IClickableMenu.drawHoverText( Game1.spriteBatch, hoverText.ToString(), Game1.smallFont); } } else if (_terrain != null) { if (_terrain is HoeDirt) { HoeDirt hoeDirt = _terrain as HoeDirt; if (hoeDirt.crop != null && !hoeDirt.crop.dead) { int num = 0; if (hoeDirt.crop.fullyGrown && hoeDirt.crop.dayOfCurrentPhase > 0) { num = hoeDirt.crop.dayOfCurrentPhase; } else { for (int i = 0; i < hoeDirt.crop.phaseDays.Count - 1; ++i) { if (hoeDirt.crop.currentPhase == i) { num -= hoeDirt.crop.dayOfCurrentPhase; } if (hoeDirt.crop.currentPhase <= i) { num += hoeDirt.crop.phaseDays[i]; } } } if (hoeDirt.crop.indexOfHarvest > 0) { String hoverText = _indexOfCropNames.SafeGet(hoeDirt.crop.indexOfHarvest); if (String.IsNullOrEmpty(hoverText)) { hoverText = new StardewValley.Object(new Debris(hoeDirt.crop.indexOfHarvest, Vector2.Zero, Vector2.Zero).chunkType, 1).DisplayName; _indexOfCropNames.Add(hoeDirt.crop.indexOfHarvest, hoverText); } StringBuilder finalHoverText = new StringBuilder(); finalHoverText.Append(hoverText).Append(": "); if (num > 0) { finalHoverText.Append(num).Append(" ") .Append(_helper.SafeGetString( LanguageKeys.Days)); } else { finalHoverText.Append(_helper.SafeGetString( LanguageKeys.ReadyToHarvest)); } IClickableMenu.drawHoverText( Game1.spriteBatch, finalHoverText.ToString(), Game1.smallFont); } } } else if (_terrain is FruitTree) { FruitTree tree = _terrain as FruitTree; if (tree.daysUntilMature > 0) { IClickableMenu.drawHoverText( Game1.spriteBatch, tree.daysUntilMature + " " + _helper.SafeGetString( LanguageKeys.DaysToMature), Game1.smallFont); } } } }
/// <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 isCrop = this.FromCrop != null; bool isSeed = this.SeedForCrop != null; bool isDeadCrop = this.FromCrop?.dead == true; // 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; Tuple <string, int> 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.GetDayOffset(daysToNextHarvest, metadata.Constants.DaysInSeason); } // generate field string summary; if (canHarvestNow) { summary = "now"; } else if (Game1.currentLocation.Name != Constant.LocationNames.Greenhouse && !crop.seasonsToGrowIn.Contains(dayOfNextHarvest.Item1)) { summary = $"too late in the season for the next harvest (would be on {dayOfNextHarvest.Item1} {dayOfNextHarvest.Item2})"; } else { summary = $"{dayOfNextHarvest.Item1} {dayOfNextHarvest.Item2} ({GameHelper.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} {GameHelper.Pluralise(daysToFirstHarvest, "day")}" + (crop.regrowAfterHarvest != -1 ? $", then every {GameHelper.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 {SaleValueField.GetSummary(this.GetSaleValue(drop, false), 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.GetDayOffset(daysLeft, metadata.Constants.DaysInSeason) } ) .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()} {GameHelper.Pluralise(entry.DaysLeft, "tomorrow", $"in {entry.DaysLeft} days")} ({entry.HarvestDate.Item1} {entry.HarvestDate.Item2})")); 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 " + GenericField.GetString(TimeSpan.FromMinutes(obj.minutesUntilReady)) : "ready"))); } } // item if (showInventoryFields) { var giftTastes = this.GetGiftTastes(item); if (!isCrop) { yield return(new SaleValueField("Sells for", this.GetSaleValue(item, this.KnownQuality), item.Stack)); } 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 (obj != null && obj.bigCraftable != true) { RecipeModel[] recipes = GameHelper.GetRecipesForIngredient(this.DisplayItem).ToArray(); if (recipes.Any()) { yield return(new RecipesForIngredientField("Recipes", item, recipes)); } } }
private void Input_ButtonPressed(object sender, StardewModdingAPI.Events.ButtonPressedEventArgs e) { if (e.Button.IsActionButton()) { Farmer player = Game1.player; Object activeObj = player.ActiveObject; if (activeObj != null) { int actualEdibility = activeObj.Edibility; if (actualEdibility == -300 && !activeObj.isPlaceable()) //isPlacable prevents machines turning into food (e.g. Chest -> Tuna) { //Create a dummy object and check if it normally has a different edibility Object objReference = new Object(activeObj.ParentSheetIndex, activeObj.Stack, activeObj.IsRecipe, activeObj.Price, activeObj.Quality); actualEdibility = objReference.Edibility; } //If it is actually edible, check if it can be used in the player's surroundings if (actualEdibility != -300) { int px = player.getTileX(); int py = player.getTileY(); bool preventEating = false; //Test for "action" blocks around the player for (int y = -1; y <= 1 && !preventEating; y++) { for (int x = -1; x <= 1 && !preventEating; x++) { if (x != 0 && y != 0) { Object tile = Game1.currentLocation.getObjectAtTile(px + x, py + y); if (tile != null) { Object tileCopy = null; //Make a copy to prevent modification of the real object if (tile is Cask) { //Casks have more properties, so copy it separately tileCopy = new Cask(); } else { tileCopy = new Object(tile.TileLocation, tile.ParentSheetIndex); tileCopy.Name = tile.Name; } //Just in case... (maybe due to an update in the future...?) if (tileCopy == null) { string log = "Copying tile failed. Please report to https://github.com/trienow/Stardew-CraftPriority/issues/new or https://www.nexusmods.com/stardewvalley/mods/4174?tab=bugs\r\n" + $"Tile to copy: '{tile.Name}'\r\nThanks! -TR"; Monitor.Log(log, LogLevel.Error); continue; } //To ignore filled machines: //tileCopy.heldObject.Set(tile.heldObject.Value); //If a action can be performed, prevent the player from eating the object preventEating = tileCopy.performObjectDropInAction(activeObj, true, player); } } } } //If the object can be used in the surrounding tiles: BAN IT! // otherwise unban the object and make it edible again activeObj.Edibility = preventEating ? -300 : actualEdibility; } } } }
/* * END ASSET EDITOR * */ /* * PATCH METHOD FOR HARMONY * Has instance of Cask and reference result manipulation. Always returns false to suppress original method. */ public static bool Patch_performObjectDropInAction(Cask __instance, ref bool __result, Item dropIn, bool probe, Farmer who) { if (dropIn != null && dropIn is SObject && (dropIn as SObject).bigCraftable.Value || __instance.heldObject.Value != null) { __result = false; //monitor.Log($"1, returning " + __result); return(false); } if (!probe && (who == null || !(who.currentLocation is Cellar || who.currentLocation.mapPath.Value == "Maps\\Winery"))) { Game1.showRedMessageUsingLoadString("Strings\\Objects:CaskNoCellar"); __result = false; //monitor.Log($"2, returning " + __result); return(false); } if (__instance.Quality >= 4) { __result = false; //monitor.Log($"3, returning " + __result); return(false); } bool flag = false; float num = 1f; switch (dropIn.ParentSheetIndex) { case 303: flag = true; //monitor.Log($"303, flag is " + flag); num = 1.66f; break; case 346: flag = true; //monitor.Log($"346, flag is " + flag); num = 2f; break; case 348: flag = true; //monitor.Log($"348, flag is " + flag); num = 1f; break; case 424: flag = true; //monitor.Log($"424, flag is " + flag); num = 4f; break; case 426: flag = true; //monitor.Log($"426, flag is " + flag); num = 4f; break; case 459: flag = true; //monitor.Log($"459, flag is "+flag); num = 2f; break; } if (!flag) { __result = false; //monitor.Log($"4, returning "+__result); return(false); } __instance.heldObject.Value = dropIn.getOne() as SObject; //monitor.Log($"Setting Cask's Held Object to "+__instance.heldObject.Value.DisplayName); if (!probe) { __instance.agingRate.Value = num; __instance.daysToMature.Value = 56f; __instance.MinutesUntilReady = 999999; if (__instance.heldObject.Value.Quality == 1) { __instance.daysToMature.Value = 42f; } else if (__instance.heldObject.Value.Quality == 2) { __instance.daysToMature.Value = 28f; } else if (__instance.heldObject.Value.Quality == 4) { __instance.daysToMature.Value = 0.0f; __instance.MinutesUntilReady = 1; } who.currentLocation.playSound("Ship"); who.currentLocation.playSound("bubbles"); who.currentLocation.temporarySprites.Add(new TemporaryAnimatedSprite("TileSheets\\animations", new Rectangle(256, 1856, 64, 128), 80f, 6, 999999, __instance.TileLocation * 64f + new Vector2(0.0f, (float)sbyte.MinValue), false, false, (float)(((double)__instance.TileLocation.Y + 1.0) * 64.0 / 10000.0 + 9.99999974737875E-05), 0.0f, Color.Yellow * 0.75f, 1f, 0.0f, 0.0f, 0.0f, false) { alphaFade = 0.005f }); } __result = true; //monitor.Log($"5, returning " + __result); return(false); }