public static void Postfix(IndoorPot __instance, SpriteBatch spriteBatch, int x, int y, float alpha) { if (drawingConnectedPot && gardenPotspriteSheet is not null) { Vector2 scaleFactor = __instance.getScale(); scaleFactor *= 4f; Vector2 position = Game1.GlobalToLocal(Game1.viewport, new Vector2(x * 64, y * 64 - 64)); Rectangle destination = new Rectangle((int)(position.X - scaleFactor.X / 2f) + ((__instance.shakeTimer > 0) ? Game1.random.Next(-1, 2) : 0), (int)(position.Y - scaleFactor.Y / 2f) + ((__instance.shakeTimer > 0) ? Game1.random.Next(-1, 2) : 0), (int)(64f + scaleFactor.X), (int)(128f + scaleFactor.Y / 2f)); Rectangle destination1 = new Rectangle((int)(position.X - scaleFactor.X / 2f) + ((__instance.shakeTimer > 0) ? Game1.random.Next(-1, 2) : 0), (int)(position.Y - scaleFactor.Y / 2f) + ((__instance.shakeTimer > 0) ? Game1.random.Next(-1, 2) : 0), (int)(64f + scaleFactor.X), (int)(128f + scaleFactor.Y / 2f) / 2); Rectangle destination2 = new Rectangle((int)(position.X - scaleFactor.X / 2f) + ((__instance.shakeTimer > 0) ? Game1.random.Next(-1, 2) : 0), (int)(position.Y - scaleFactor.Y / 2f) + ((__instance.shakeTimer > 0) ? Game1.random.Next(-1, 2) : 0) + 64, (int)(64f + scaleFactor.X), (int)(128f + scaleFactor.Y / 2f) / 2); if (topIndex >= 0) { spriteBatch.Draw(gardenPotspriteSheet, destination1, new Rectangle(topIndex * 16, 32, 16, 16), Color.White * alpha, 0f, Vector2.Zero, SpriteEffects.None, Math.Max(0f, ((y + 1) * 64 - 24) / 10000f) + x * 1E-05f); } if (leftIndex >= 0) { spriteBatch.Draw(gardenPotspriteSheet, destination2, new Rectangle(leftIndex * 16, 48, 16, 16), Color.White * alpha, 0f, Vector2.Zero, SpriteEffects.None, Math.Max(0f, ((y + 1) * 64 - 24) / 10000f) + x * 1E-05f + 1 / 10000f); } if (rightIndex >= 0) { spriteBatch.Draw(gardenPotspriteSheet, destination2, new Rectangle(rightIndex * 16, 64, 16, 16), Color.White * alpha, 0f, Vector2.Zero, SpriteEffects.None, Math.Max(0f, ((y + 1) * 64 - 24) / 10000f) + x * 1E-05f + 1 / 10000f); } drawingConnectedPot = false; } }
private void SetupHoeDirtListeners(HoeDirt hoeDirt, IndoorPot pot = null) { try { var netCrop = Helper.Reflection.GetField <NetRef <Crop> >(hoeDirt, "netCrop", true).GetValue(); if (netCrop.Value != null) { TrackAndWater(hoeDirt, pot); } netCrop.fieldChangeVisibleEvent += (_, __, crop) => { if (crop != null) { TrackAndWater(hoeDirt, pot); } else { RemoveTrack(hoeDirt, pot); } }; } catch (Exception ex) { Monitor.Log($"Could not read crop data on dirt; possible new game version?\n{ex}", LogLevel.Error); } }
private static Texture2D GetSpriteSheet(IndoorPot __instance) { if (!Config.EnableMod || __instance.modData.ContainsKey("aedenthorn.WallPlanter/offset") || !IsConnectedPot(__instance)) { return(Game1.bigCraftableSpriteSheet); } return(gardenPotspriteSheet); }
/********* ** Private methods *********/ /// <summary>The method to call before <see cref="IndoorPot.performObjectDropInAction"/>.</summary> /// <returns>Returns whether to run the original method.</returns> private static bool Before_PerformObjectDropInAction(IndoorPot __instance, Item dropInItem, bool probe, Farmer who, ref bool __result) { if (dropInItem is CustomObject obj && !string.IsNullOrEmpty(obj.Data.Plants)) { __result = IndoorPotPatcher.Impl(__instance, obj, probe, who); return(false); } return(true); }
/// <summary>Update the indoor pot state on load for automation.</summary> /// <param name="indoorPot">The indoor pot to update.</param> /// <param name="reflection">Simplifies access to private code.</param> /// <remarks>Derived from <see cref="IndoorPot.updateWhenCurrentLocation"/>. When an indoor pot is loaded from the save file, the bush it contains isn't updated immediately. Instead it's marked dirty and will call <see cref="Bush.loadSprite"/> when the player first enters the location. For Automate, that means a bush that's already harvested may reset and produce a new harvest for the day.</remarks> private void UpdateIndoorPotOnLoad(IndoorPot indoorPot, IReflectionHelper reflection) { NetBool bushLoadDirty = reflection.GetField <NetBool>(indoorPot, "bushLoadDirty").GetValue(); if (bushLoadDirty.Value) { indoorPot.bush.Value.loadSprite(); bushLoadDirty.Value = false; } }
private static bool Impl(IndoorPot this_, CustomObject dropInItem, bool probe, Farmer who) { if (who != null && dropInItem != null && this_.bush.Value == null && dropInItem.CanPlantThisSeedHere(this_.hoeDirt.Value, (int)this_.tileLocation.X, (int)this_.tileLocation.Y, dropInItem.Category == -19)) { //if ((int)dropInItem.parentSheetIndex == 805) //{ // if (!probe) // { // Game1.showRedMessage(Game1.content.LoadString("Strings\\StringsFromCSFiles:Object.cs.13053")); // } // return false; //} //if ((int)dropInItem.parentSheetIndex == 499) //{ // if (!probe) // { // Game1.playSound("cancel"); // Game1.showGlobalMessage(Game1.content.LoadString("Strings\\Objects:AncientFruitPot")); // } // return false; //} if (!probe) { if (!dropInItem.Plant(this_.hoeDirt.Value, (int)this_.tileLocation.X, (int)this_.tileLocation.Y, who, dropInItem.Category == -19, who.currentLocation)) { return(false); } } else { this_.heldObject.Value = new StardewValley.Object(); } return(true); } //if (who != null && dropInItem != null && this_.hoeDirt.Value.crop == null && this_.bush.Value == null && dropInItem is StardewValley.Object && !(dropInItem as StardewValley.Object).bigCraftable && (int)dropInItem.parentSheetIndex == 251) //{ // if (probe) // { // this_.heldObject.Value = new StardewValley.Object(); // } // else // { // this_.bush.Value = new Bush(this_.tileLocation, 3, who.currentLocation); // if (!who.currentLocation.IsOutdoors) // { // this_.bush.Value.greenhouseBush.Value = true; // this_.bush.Value.loadSprite(); // Game1.playSound("coin"); // } // } // return true; //} return(false); }
/// <summary> /// Removes a waterable target from the corresponding collection /// </summary> /// <param name="tilledDirt">Tilled dirt plot to untrack</param> /// <param name="indoorPot">Garden pot to untrack</param> private void RemoveTrack(HoeDirt tilledDirt, IndoorPot indoorPot = null) { if (indoorPot != null) { _indoorPots.Remove(indoorPot); } else { _tilledDirtPlots.Remove(tilledDirt); } }
private void RemoveTrack(HoeDirt hoeDirt, IndoorPot indoorPot = null) { if (indoorPot != null) { _indoorPots.Remove(indoorPot); } else { _hoeDirts.Remove(hoeDirt); } }
private void TrackAndWater(HoeDirt hoeDirt, IndoorPot indoorPot = null) { if (indoorPot != null) { _indoorPots.Add(indoorPot); } else { _hoeDirts.Add(hoeDirt); } Water(hoeDirt, indoorPot); }
/// <summary> /// Adds a waterable target to the corresponding collection, and then waters that target /// </summary> /// <param name="tilledDirt">Tilled dirt plot to track and water</param> /// <param name="indoorPot">Garden pot to track and water</param> private void TrackAndWater(HoeDirt tilledDirt, IndoorPot indoorPot = null) { if (indoorPot != null) { _indoorPots.Add(indoorPot); } else { _tilledDirtPlots.Add(tilledDirt); } Water(tilledDirt, indoorPot); }
private static void Postfix(IndoorPot __instance, Item?dropInItem, bool probe) { if (probe) { return; } if (dropInItem?.modData?.GetBool(CanPlaceHandler.Organic) == true && __instance.hoeDirt?.Value?.fertilizer?.Value is HoeDirt.noFertilizer && ModEntry.OrganicFertilizerID != -1) { __instance.hoeDirt.Value.fertilizer.Value = ModEntry.OrganicFertilizerID; } }
private static bool DrawPrefix(IndoorPot __instance, SpriteBatch spriteBatch, int x, int y, float alpha = 1f) { if (__instance.modData.ContainsKey("AlternativeTextureName")) { var textureModel = AlternativeTextures.textureManager.GetSpecificTextureModel(__instance.modData["AlternativeTextureName"]); if (textureModel is null) { return(true); } var textureVariation = Int32.Parse(__instance.modData["AlternativeTextureVariation"]); if (textureVariation == -1 || AlternativeTextures.modConfig.IsTextureVariationDisabled(textureModel.GetId(), textureVariation)) { return(true); } var textureOffset = textureModel.GetTextureOffset(textureVariation); Vector2 scaleFactor = __instance.getScale(); scaleFactor *= 4f; Vector2 position = Game1.GlobalToLocal(Game1.viewport, new Vector2(x * 64, y * 64 - 64)); Rectangle destination = new Rectangle((int)(position.X - scaleFactor.X / 2f) + ((__instance.shakeTimer > 0) ? Game1.random.Next(-1, 2) : 0), (int)(position.Y - scaleFactor.Y / 2f) + ((__instance.shakeTimer > 0) ? Game1.random.Next(-1, 2) : 0), (int)(64f + scaleFactor.X), (int)(128f + scaleFactor.Y / 2f)); spriteBatch.Draw(textureModel.GetTexture(textureVariation), destination, new Rectangle((__instance.showNextIndex ? 1 : 0) * textureModel.TextureWidth, textureOffset, 16, 32), Color.White * alpha, 0f, Vector2.Zero, SpriteEffects.None, Math.Max(0f, (float)((y + 1) * 64 - 24) / 10000f) + (((int)__instance.parentSheetIndex == 105) ? 0.0035f : 0f) + (float)x * 1E-05f); if ((int)__instance.hoeDirt.Value.fertilizer != 0) { Rectangle fertilizer_rect = __instance.hoeDirt.Value.GetFertilizerSourceRect(__instance.hoeDirt.Value.fertilizer); fertilizer_rect.Width = 13; fertilizer_rect.Height = 13; spriteBatch.Draw(Game1.mouseCursors, Game1.GlobalToLocal(Game1.viewport, new Vector2(__instance.tileLocation.X * 64f + 4f, __instance.tileLocation.Y * 64f - 12f)), fertilizer_rect, Color.White, 0f, Vector2.Zero, 4f, SpriteEffects.None, (__instance.tileLocation.Y + 0.65f) * 64f / 10000f + (float)x * 1E-05f); } if (__instance.hoeDirt.Value.crop != null) { __instance.hoeDirt.Value.crop.drawWithOffset(spriteBatch, __instance.tileLocation, ((int)__instance.hoeDirt.Value.state == 1 && (int)__instance.hoeDirt.Value.crop.currentPhase == 0 && !__instance.hoeDirt.Value.crop.raisedSeeds) ? (new Color(180, 100, 200) * 1f) : Color.White, __instance.hoeDirt.Value.getShakeRotation(), new Vector2(32f, 8f)); } if (__instance.heldObject.Value != null) { __instance.heldObject.Value.draw(spriteBatch, x * 64, y * 64 - 48, (__instance.tileLocation.Y + 0.66f) * 64f / 10000f + (float)x * 1E-05f, 1f); } if (__instance.bush.Value != null) { __instance.bush.Value.draw(spriteBatch, new Vector2(x, y), -24f); } return(false); } return(true); }
private void Water(HoeDirt hoeDirt, IndoorPot pot = null) { if (!_config.Enabled || !_shouldWaterToday) { return; } hoeDirt.state.Value = HoeDirt.watered; if (_config.Fertilizer.HasValue) { hoeDirt.fertilizer.Value = _config.Fertilizer.Value; } if (pot != null) { pot.showNextIndex.Value = true; } }
/// <summary> /// Waters either a plot of tilled dirt or a garden pot /// </summary> /// <param name="tilledDirt">Tilled dirt plot to water</param> /// <param name="indoorPot">Garden pot to water</param> private void Water(HoeDirt tilledDirt, IndoorPot indoorPot = null) { if (!_shouldWaterToday) { return; } tilledDirt.state.Value = HoeDirt.watered; if (_config.Fertilizer.HasValue) { tilledDirt.fertilizer.Value = _config.Fertilizer.Value; } if (indoorPot != null) { indoorPot.showNextIndex.Value = true; } }
public static void Prefix(IndoorPot __instance, int x, int y) { if (!Config.EnableMod || !typeof(DecoratableLocation).IsAssignableFrom(Game1.currentLocation.GetType()) || !(Game1.currentLocation as DecoratableLocation).isTileOnWall(x, y)) { return; } if (!__instance.modData.TryGetValue("aedenthorn.WallPlanter/offset", out string offsetString)) { __instance.modData["aedenthorn.WallPlanter/offset"] = Config.OffsetY + ""; } if (!__instance.modData.TryGetValue("aedenthorn.WallPlanter/innerOffset", out string innerOffsetString)) { __instance.modData["aedenthorn.WallPlanter/innerOffset"] = Config.InnerOffsetY + ""; } drawingWallPotOffset = int.Parse(__instance.modData["aedenthorn.WallPlanter/offset"]); drawingWallPotInnerOffset = int.Parse(__instance.modData["aedenthorn.WallPlanter/innerOffset"]); drawingWallPot = true; }
private static bool IsConnectedPot(IndoorPot instance) { Vector2 tile = instance.TileLocation; for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { if (Game1.currentLocation.objects.TryGetValue(tile + new Vector2(x - 1, y - 1), out Object obj) && obj is IndoorPot && !obj.modData.ContainsKey("aedenthorn.WallPlanter/offset")) { int i = 3 * y + x; if (i % 2 == 1) { return(true); } } } } return(false); }
private static Rectangle GetSourceRect(int index, IndoorPot __instance) { if (!Config.EnableMod || __instance.modData.ContainsKey("aedenthorn.WallPlanter/offset") || !IsConnectedPot(__instance)) { return(Object.getSourceRectForBigCraftable(index)); } drawingConnectedPot = false; bool[] potTiles = new bool[9]; Vector2 tile = __instance.TileLocation; for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { int i = 3 * y + x; potTiles[i] = Game1.currentLocation.objects.TryGetValue(tile + new Vector2(x - 1, y - 1), out Object obj) && obj is IndoorPot && !obj.modData.ContainsKey("aedenthorn.WallPlanter/offset"); } } topIndex = -2; leftIndex = -2; rightIndex = -2; drawingConnectedPot = true; if (!potTiles[1]) // none top { if (!potTiles[3]) // none left { if (!potTiles[5]) // pot below { topIndex = 6; potIndex = 0; } else if (!potTiles[7]) // pot right { topIndex = 0; potIndex = 2; } else // pot right pot below { topIndex = 0; potIndex = 0; } } else if (!potTiles[5]) // pot left none right { if (!potTiles[7]) // pot left { topIndex = 4; potIndex = 6; } else // pot left pot below { topIndex = 4; potIndex = 0; } } else if (!potTiles[7]) // pot left pot right { topIndex = 2; potIndex = 4; } else // pot left pot right pot below { topIndex = 2; potIndex = 0; } } else // pot top { if (!potTiles[3]) // none left { if (!potTiles[5]) // none right { if (!potTiles[7]) // pot top { potIndex = 8; } else // pot top pot bottom { potIndex = 0; } } else // pot right { if (!potTiles[7]) // pot top pot right { potIndex = 2; } else // pot top pot right pot bottom { potIndex = 0; } } } else if (!potTiles[5]) // pot left none right { if (!potTiles[7]) // pot top pot left { potIndex = 6; } else // pot top pot left pot below { potIndex = 0; } } else if (!potTiles[7]) // pot top pot left pot right { potIndex = 4; } else // pot top pot left pot right pot below { potIndex = 0; } } if (potIndex == 0) { if (!potTiles[3]) { leftIndex = potTiles[6] ? 2 : 0; } else if (!potTiles[6]) { leftIndex = 4; } if (!potTiles[5]) { rightIndex = potTiles[8] ? 2 : 0; } else if (!potTiles[8]) { rightIndex = 4; } } if (__instance.showNextIndex.Value) { potIndex++; topIndex++; leftIndex++; rightIndex++; } return(new Rectangle(potIndex * 16, 0, 16, 32)); }
private void SetupIndoorPotListeners(IndoorPot indoorPot) { SetupHoeDirtListeners(indoorPot.hoeDirt.Value, indoorPot); }
/// <summary>Get the tilled dirt for a tile, if any.</summary> /// <param name="tileFeature">The feature on the tile.</param> /// <param name="tileObj">The object on the tile.</param> /// <param name="dirt">The tilled dirt found, if any.</param> /// <param name="isCoveredByObj">Whether there's an object placed over the tilled dirt.</param> /// <param name="pot">The indoor pot containing the dirt, if applicable.</param> /// <returns>Returns whether tilled dirt was found.</returns> protected bool TryGetHoeDirt(TerrainFeature tileFeature, SObject tileObj, out HoeDirt dirt, out bool isCoveredByObj, out IndoorPot pot) { // garden pot if (tileObj is IndoorPot _pot) { pot = _pot; dirt = pot.hoeDirt.Value; isCoveredByObj = false; return(true); } // regular dirt if ((dirt = tileFeature as HoeDirt) != null) { pot = null; isCoveredByObj = tileObj != null; return(true); } // none found pot = null; dirt = null; isCoveredByObj = false; return(false); }
/// <summary>Construct an instance.</summary> /// <param name="indoorPot">The indoor pot containing the bush.</param> /// <param name="indoorPotTile">The tile coordinate of the indoor pot containing this bush.</param> /// <param name="location">The machine's in-game location.</param> /// <param name="reflection">Simplifies access to private code.</param> public BushMachine(IndoorPot indoorPot, Vector2 indoorPotTile, GameLocation location, IReflectionHelper reflection) : this(indoorPot.bush.Value, location, GetTileAreaFor(indoorPotTile)) { this.UpdateIndoorPotOnLoad(indoorPot, reflection); }
private static void DrawIndoorPot(SpriteBatch spriteBatch, Texture2D texture, Rectangle destinationRectangle, Rectangle?sourceRectangle, Color color, float rotation, Vector2 origin, SpriteEffects effects, float layerDepth, IndoorPot pot) { if (texture is null || pot is null) { return; } int x = (destinationRectangle.X + Game1.viewport.X) / 64; int y = (destinationRectangle.Y + Game1.viewport.Y) / 64 + 1; if (!Config.EnableMod || !drawingWallPot) { spriteBatch.Draw(texture, destinationRectangle, sourceRectangle, color, rotation, origin, effects, layerDepth); } else { texture = pot.showNextIndex.Value ? wallPotTextureWet : (pot.bush.Value != null && pot.hoeDirt.Value.state.Value == 1 ? wallPotTextureWet : wallPotTexture); if (texture is null) { return; } destinationRectangle = new Rectangle(destinationRectangle.Location - new Point(0, drawingWallPotOffset), destinationRectangle.Size); spriteBatch.Draw(texture, destinationRectangle, null, color, rotation, origin, effects, layerDepth); } }
private void SearchForIndoorPots(GameLocation location) { // Search for IndoorPots with crops foreach (KeyValuePair <Vector2, Object> tileToIndoorPot in location.objects.Pairs.Where(p => p.Value is IndoorPot)) { if (!HasRoomForHarvest()) { isFull = true; return; } Vector2 tile = tileToIndoorPot.Key; IndoorPot pot = tileToIndoorPot.Value as IndoorPot; HoeDirt hoeDirt = pot.hoeDirt.Value; // HoeDirt seems to be missing its currentLocation when coming from IndoorPots, which is problematic for Crop.harvest() if (hoeDirt.currentLocation is null) { hoeDirt.currentLocation = location; } if (hoeDirt.readyForHarvest()) { if (!doJunimosHarvestFromFlowers && new Object(tile, hoeDirt.crop.indexOfHarvest, 0).Category == -80) { // Crop is flower and config has been set to skip them continue; } hoeDirt.crop.harvest((int)tile.X, (int)tile.Y, hoeDirt, null); harvestedToday = true; // Clear any non-renewing crop if (hoeDirt.crop.regrowAfterHarvest == -1) { int seedIndex = hoeDirt.crop.netSeedIndex; hoeDirt.crop = null; // Attempt to replant, if it is enabled and has valid seed if (doJunimosSowSeedsAfterHarvest) { AttemptSowSeed(seedIndex, hoeDirt, tile); } } } } // Search for IndoorPots with forage items foreach (KeyValuePair <Vector2, Object> tileToIndoorPot in location.objects.Pairs.Where(p => p.Value is IndoorPot)) { if (!HasRoomForHarvest()) { isFull = true; return; } Vector2 tile = tileToIndoorPot.Key; IndoorPot pot = tileToIndoorPot.Value as IndoorPot; if (pot.heldObject.Value != null && pot.heldObject.Value.isForage(location)) { if (chest.addItem(pot.heldObject.Value.getOne()) != null) { chest.modData[ModEntry.ateCropsFlag] = true.ToString(); } pot.heldObject.Value = null; harvestedToday = true; } } }