// ReSharper disable once InconsistentNaming private static void HandleItemDrop(int itemToDrop, ref FarmAnimal __instance) { var flag3 = true; var quality = ChooseQuality(ref __instance); foreach (var @object in __instance.home.indoors.Value.objects.Values .Where(@object => @object.bigCraftable.Value && @object.ParentSheetIndex == 165 && @object.heldObject.Value != null) .Where(@object => (@object.heldObject.Value as Chest)? .addItem(new Object(Vector2.Zero, itemToDrop, null, false, true, false, false) { Quality = quality }) == null)) { @object.showNextIndex.Value = true; flag3 = false; break; } if (flag3 && !__instance.home.indoors.Value.Objects.ContainsKey(__instance.getTileLocation())) { StardewValley.Utility.spawnObjectAround(__instance.getTileLocation(), new Object(Vector2.Zero, itemToDrop, null, false, true, false, true) { Quality = quality }, __instance.home.indoors.Value); } }
public static void dayUpdate(FarmAnimal __instance) { if (__instance.harvestType.Value == FarmAnimal.layHarvestType && __instance.daysSinceLastLay.Value == 0 && AnimalContestController.HasFertilityBonus(__instance) && !DataLoader.ModConfig.DisableContestBonus) { GameLocation homeIndoors = __instance.home.indoors.Value; if (homeIndoors.Objects.ContainsKey(__instance.getTileLocation())) { StardewValley.Object originalLayedObject = homeIndoors.Objects[__instance.getTileLocation()]; if (originalLayedObject.Category == StardewValley.Object.EggCategory) { __instance.setRandomPosition(homeIndoors); if (!homeIndoors.Objects.ContainsKey(__instance.getTileLocation())) { homeIndoors.Objects.Add(__instance.getTileLocation(), new StardewValley.Object(Vector2.Zero, originalLayedObject.ParentSheetIndex, (string)null, false, true, false, true) { Quality = originalLayedObject.Quality }); } } } } }
public static bool FarmAnimalDayUpdate(ref FarmAnimal __instance, GameLocation environtment) { __instance.controller = null; __instance.health.Value = 3; bool flag1 = false; if (__instance.home != null && !(__instance.home.indoors.Value as AnimalHouse).animals.ContainsKey(__instance.myID) && environtment is Farm) { if (!__instance.home.animalDoorOpen.Value) { __instance.moodMessage.Value = 6; flag1 = true; __instance.happiness.Value /= 2; } else { (environtment as Farm).animals.Remove(__instance.myID.Value); (__instance.home.indoors.Value as AnimalHouse).animals.Add(__instance.myID.Value, __instance); if (Game1.timeOfDay > 1800 && __instance.controller == null) { __instance.happiness.Value /= 2; } environtment = __instance.home.indoors.Value; __instance.setRandomPosition(environtment); return(false); } } ++__instance.daysSinceLastLay.Value; if (!__instance.wasPet.Value) { __instance.friendshipTowardFarmer.Value = Math.Max(0, __instance.friendshipTowardFarmer.Value - (10 - __instance.friendshipTowardFarmer / 200)); __instance.happiness.Value = (byte)Math.Max(0, __instance.happiness.Value - __instance.happinessDrain.Value * 5); } __instance.wasPet.Value = false; if ((__instance.fullness.Value < 200 || Game1.timeOfDay < 1700) && environtment is AnimalHouse) { for (int index = environtment.objects.Count() - 1; index >= 0; --index) { KeyValuePair <Vector2, SObject> keyValuePair = environtment.objects.Pairs.ElementAt(index); if (keyValuePair.Value.Name.Equals("Hay")) { OverlaidDictionary objects = environtment.objects; keyValuePair = environtment.objects.Pairs.ElementAt(index); Vector2 key = keyValuePair.Key; objects.Remove(key); __instance.fullness.Value = Byte.MaxValue; break; } } } var random = new Random((int)(long)__instance.myID / 2 + (int)Game1.stats.DaysPlayed); if (__instance.fullness > 200 || random.NextDouble() < (__instance.fullness.Value - 30) / 170.0) { ++__instance.age.Value; if (__instance.age.Value == __instance.ageWhenMature.Value) { __instance.Sprite.LoadTexture("Animals\\" + __instance.type.Value); if (__instance.type.Value.Contains("Sheep")) { __instance.currentProduce.Value = __instance.defaultProduceIndex; } __instance.daysSinceLastLay.Value = 99; } __instance.happiness.Value = (byte)Math.Min(Byte.MaxValue, __instance.happiness.Value + __instance.happinessDrain.Value * 2); } if (__instance.fullness.Value < 200) { __instance.happiness.Value = (byte)Math.Max(0, __instance.happiness.Value - 100); __instance.friendshipTowardFarmer.Value = Math.Max(0, __instance.friendshipTowardFarmer.Value - 20); } bool flag2 = __instance.daysSinceLastLay.Value >= __instance.daysToLay.Value - (!__instance.type.Value.Equals("Sheep") || !Game1.getFarmer(__instance.ownerID.Value).professions.Contains(3) ? 0 : 1) && random.NextDouble() < __instance.fullness.Value / 200.0 && random.NextDouble() < __instance.happiness.Value / 70.0; int parentSheetIndex; if (!flag2 || __instance.age.Value < __instance.ageWhenMature.Value) { parentSheetIndex = -1; } else { __instance.daysSinceLastLay.Value = 0; parentSheetIndex = __instance.defaultProduceIndex.Value; if (parentSheetIndex == 107 && Loader.CONFIG.InfertileEggs) { parentSheetIndex = Loader.DATA["Dino Egg"]; } if (random.NextDouble() < __instance.happiness.Value / 150.0) { float num1 = __instance.happiness.Value > 200 ? __instance.happiness.Value * 1.5f : (__instance.happiness.Value <= 100 ? __instance.happiness.Value - 100 : 0.0f); if (__instance.type.Value.Equals("Duck") && random.NextDouble() < (__instance.friendshipTowardFarmer.Value + (double)num1) / 5000.0 + Game1.player.team.AverageDailyLuck(null) + Game1.player.team.AverageLuckLevel(null) * 0.01) { parentSheetIndex = __instance.deluxeProduceIndex.Value; } else if (__instance.type.Value.Equals("Rabbit") && random.NextDouble() < (__instance.friendshipTowardFarmer.Value + (double)num1) / 5000.0 + Game1.player.team.AverageDailyLuck(null) + Game1.player.team.AverageLuckLevel(null) * 0.02) { parentSheetIndex = __instance.deluxeProduceIndex.Value; } else if (__instance.type.Value.Equals("Blue Chicken") && random.NextDouble() < (__instance.friendshipTowardFarmer.Value + (double)num1) / 5000.0 + Game1.player.team.AverageDailyLuck() + Game1.player.team.AverageLuckLevel() * 0.01) { parentSheetIndex = Loader.DATA["Blue Chicken Egg"]; } switch (parentSheetIndex) { case 176: ++Game1.stats.ChickenEggsLayed; break; case 180: ++Game1.stats.ChickenEggsLayed; break; case 440: ++Game1.stats.RabbitWoolProduced; break; case 442: ++Game1.stats.DuckEggsLayed; break; } if (random.NextDouble() < (__instance.friendshipTowardFarmer.Value + num1) / 1200.0 && !__instance.type.Value.Equals("Duck") && (!__instance.type.Value.Equals("Rabbit") && !__instance.type.Value.Equals("Blue Chicken") && __instance.deluxeProduceIndex.Value != -1) && __instance.friendshipTowardFarmer.Value >= 200) { parentSheetIndex = __instance.deluxeProduceIndex.Value; } double num2 = __instance.friendshipTowardFarmer.Value / 1000.0 - (1.0 - __instance.happiness.Value / 225.0); if (!__instance.isCoopDweller() && Game1.getFarmer(__instance.ownerID.Value).professions.Contains(3) || __instance.isCoopDweller() && Game1.getFarmer(__instance.ownerID.Value).professions.Contains(2)) { num2 += 0.33; } if (num2 >= 0.95 && random.NextDouble() < num2 / 2.0) { __instance.produceQuality.Value = 4; } else if (random.NextDouble() < num2 / 2.0) { __instance.produceQuality.Value = 2; } else if (random.NextDouble() < num2) { __instance.produceQuality.Value = 1; } else { __instance.produceQuality.Value = 0; } } } if (__instance.harvestType == 1 & flag2) { __instance.currentProduce.Value = parentSheetIndex; parentSheetIndex = -1; } if (parentSheetIndex != -1 && __instance.home != null) { bool flag3 = true; foreach (SObject @object in __instance.home.indoors.Value.objects.Values) { if (@object.bigCraftable.Value && @object.parentSheetIndex.Value == 165 && @object.heldObject.Value != null) { if ((@object.heldObject.Value as Chest).addItem(new SObject(Vector2.Zero, parentSheetIndex, null, false, true, false, false) { Quality = __instance.produceQuality.Value }) == null) { @object.showNextIndex.Value = true; flag3 = false; break; } } } if (flag3 && !__instance.home.indoors.Value.Objects.ContainsKey(__instance.getTileLocation())) { __instance.home.indoors.Value.Objects.Add(__instance.getTileLocation(), new SObject(Vector2.Zero, parentSheetIndex, null, false, true, false, true) { Quality = __instance.produceQuality.Value }); } } if (!flag1) { if (__instance.fullness.Value < 30) { __instance.moodMessage.Value = 4; } else if (__instance.happiness.Value < 30) { __instance.moodMessage.Value = 3; } else if (__instance.happiness.Value < 200) { __instance.moodMessage.Value = 2; } else { __instance.moodMessage.Value = 1; } } if (Game1.timeOfDay < 1700) { __instance.fullness.Value = (byte)Math.Max(0, __instance.fullness.Value - __instance.fullnessDrain.Value * (1700 - Game1.timeOfDay) / 100); } __instance.fullness.Value = 0; if (Utility.isFestivalDay(Game1.dayOfMonth, Game1.currentSeason)) { __instance.fullness.Value = 250; } __instance.reload(__instance.home); return(false); }
/********* ** Private methods *********/ /// <summary>The method to call before <see cref="FarmAnimal.updateWhenNotCurrentLocation"/>.</summary> private static bool Before_UpdateWhenNotCurrentLocation(FarmAnimal __instance, Building currentBuilding, GameTime time, GameLocation environment) { Mod.Instance.Helper.Reflection.GetField <NetEvent1Field <int, NetInt> >(__instance, "doFarmerPushEvent").GetValue().Poll(); Mod.Instance.Helper.Reflection.GetField <NetEvent0>(__instance, "doBuildingPokeEvent").GetValue().Poll(); if (!Game1.shouldTimePass()) { return(false); } __instance.update(time, environment, __instance.myID.Value, false); if (!Game1.IsMasterGame) { return(false); } if (currentBuilding != null && Game1.random.NextDouble() < 0.002 && (currentBuilding.animalDoorOpen.Value && Game1.timeOfDay < 1630) && (!Game1.isRaining && !Game1.currentSeason.Equals("winter") && environment.farmers.Count == 0)) { GameLocation locationFromName = Mod.FindOutdoorsOf(currentBuilding); IAnimalLocation locationFromName_animals = (IAnimalLocation)locationFromName; if (locationFromName.isCollidingPosition(new Rectangle((currentBuilding.tileX.Value + currentBuilding.animalDoor.X) * 64 + 2, (currentBuilding.tileY.Value + currentBuilding.animalDoor.Y) * 64 + 2, (__instance.isCoopDweller() ? 64 : 128) - 4, 60), Game1.viewport, false, 0, false, __instance, false) || locationFromName.isCollidingPosition(new Rectangle((currentBuilding.tileX.Value + currentBuilding.animalDoor.X) * 64 + 2, (currentBuilding.tileY.Value + currentBuilding.animalDoor.Y + 1) * 64 + 2, (__instance.isCoopDweller() ? 64 : 128) - 4, 60), Game1.viewport, false, 0, false, __instance, false)) { return(false); } if (locationFromName_animals.Animals.ContainsKey(__instance.myID.Value)) { for (int index = locationFromName_animals.Animals.Count() - 1; index >= 0; --index) { if (locationFromName_animals.Animals.Pairs.ElementAt(index).Key.Equals(__instance.myID.Value)) { locationFromName_animals.Animals.Remove(__instance.myID.Value); break; } } } (currentBuilding.indoors.Value as AnimalHouse).animals.Remove(__instance.myID.Value); locationFromName_animals.Animals.Add(__instance.myID.Value, __instance); __instance.faceDirection(2); __instance.SetMovingDown(true); __instance.Position = new Vector2(currentBuilding.getRectForAnimalDoor().X, (currentBuilding.tileY.Value + currentBuilding.animalDoor.Y) * 64 - (__instance.Sprite.getHeight() * 4 - __instance.GetBoundingBox().Height) + 32); if (FarmAnimal.NumPathfindingThisTick < FarmAnimal.MaxPathfindingPerTick) { ++FarmAnimal.NumPathfindingThisTick; __instance.controller = new PathFindController(__instance, locationFromName, FarmAnimal.grassEndPointFunction, Game1.random.Next(4), false, FarmAnimal.behaviorAfterFindingGrassPatch, 200, Point.Zero); } if (__instance.controller?.pathToEndPoint == null || __instance.controller.pathToEndPoint.Count < 3) { __instance.SetMovingDown(true); __instance.controller = null; } else { __instance.faceDirection(2); __instance.Position = new Vector2(__instance.controller.pathToEndPoint.Peek().X * 64, __instance.controller.pathToEndPoint.Peek().Y * 64 - (__instance.Sprite.getHeight() * 4 - __instance.GetBoundingBox().Height) + 16); if (!__instance.isCoopDweller()) { __instance.position.X -= 32f; } } __instance.noWarpTimer = 3000; --currentBuilding.currentOccupants.Value; if (Utility.isOnScreen(__instance.getTileLocationPoint(), 192, locationFromName)) { locationFromName.localSound("sandyStep"); } if (environment.isTileOccupiedByFarmer(__instance.getTileLocation()) != null) { environment.isTileOccupiedByFarmer(__instance.getTileLocation()).TemporaryPassableTiles.Add(__instance.GetBoundingBox()); } } Mod.Instance.Helper.Reflection.GetMethod(__instance, "behaviors").Invoke(time, environment); return(false); }
/********* ** Public methods *********/ /// <summary>Construct an instance.</summary> /// <param name="gameHelper">Provides utility methods for interacting with the game code.</param> /// <param name="obj">The underlying in-game object.</param> public FarmAnimalTarget(GameHelper gameHelper, FarmAnimal obj) : base(gameHelper, TargetType.FarmAnimal, obj, obj.getTileLocation(), obj.Position) { }
/// <summary>The prefix for the DayUpdate method.</summary> /// <param name="environtment">The current location of the animal.</param> /// <param name="__instance">The <see cref="FarmAnimal"/> instance being patched.</param> /// <returns>False meaning the original method won't get ran.</returns> internal static bool DayUpdatePrefix(GameLocation environtment, FarmAnimal __instance) // TODO: check if I can correct the mispelling from the game code with Harmony still working { var random = new Random((int)(__instance.myID / 2 + Game1.stats.DaysPlayed)); __instance.controller = null; __instance.health.Value = 3; var hasBeenLockedOutside = false; // check if the animal is currently outside if (__instance.home != null && !(__instance.home.indoors.Value as AnimalHouse).animals.ContainsKey(__instance.myID) && environtment is Farm) { // check if they were locked outside if (!__instance.home.animalDoorOpen) { __instance.moodMessage.Value = 6; // locked outside mood message __instance.happiness.Value /= (byte)2; hasBeenLockedOutside = true; } else // animal is outside but door is open, move the animal inside { (environtment as Farm).animals.Remove(__instance.myID); (__instance.home.indoors.Value as AnimalHouse).animals.Add(__instance.myID, __instance); if (Game1.timeOfDay > 1800) { __instance.happiness.Value /= 2; } environtment = __instance.home.indoors; __instance.setRandomPosition(environtment); return(false); } } __instance.daysSinceLastLay.Value++; if (!__instance.wasPet) // check if the animal wasn't pet, if it wasn't then reduce happiness and friendship { __instance.friendshipTowardFarmer.Value = Math.Max(0, __instance.friendshipTowardFarmer - (10 - __instance.friendshipTowardFarmer / 200)); __instance.happiness.Value = (byte)Math.Max(0, __instance.happiness - __instance.happinessDrain * 5); } __instance.wasPet.Value = false; // check if there is hay to eat if ((__instance.fullness < 200 || Game1.timeOfDay < 1700) && environtment is AnimalHouse) { for (int index = environtment.objects.Count() - 1; index >= 0; --index) { var environmentObjects = environtment.objects.Pairs.ElementAt(index); // Key: location - Value: object if (environmentObjects.Value.Name == "Hay") { // remove object and restore fullness var objects = environtment.objects; environmentObjects = environtment.objects.Pairs.ElementAt(index); var location = environmentObjects.Key; objects.Remove(location); __instance.fullness.Value = byte.MaxValue; break; } } } // increase age of animal if (__instance.fullness > 200 || random.NextDouble() < (__instance.fullness - 30) / 170.0) { __instance.age.Value++; if (__instance.age == __instance.ageWhenMature) { // change sprite sheet to be adult __instance.Sprite.LoadTexture(Path.Combine("Animals", __instance.type.Value)); // make sheep harvestable if (__instance.type.Value.Contains("Sheep")) { __instance.currentProduce.Value = __instance.defaultProduceIndex; } // ensure all animals are redy to produce - this is so the player doesn't need to wait a couple of days for them to produce __instance.daysSinceLastLay.Value = 99; } // increase animal happiness - they increase happiness when full, even if not pet __instance.happiness.Value = (byte)Math.Min(byte.MaxValue, __instance.happiness + __instance.happinessDrain * 2); } // decrease animal happiness and friendship if they are hungry if (__instance.fullness.Value < 200) { __instance.happiness.Value = (byte)Math.Max(0, __instance.happiness - 100); __instance.friendshipTowardFarmer.Value = Math.Max(0, __instance.friendshipTowardFarmer - 20); } // determine whether the animal can produce an item today bool canProduceItem = __instance.daysSinceLastLay >= __instance.daysToLay - (!__instance.type.Value.Equals("Sheep") || !Game1.getFarmer((long)__instance.ownerID).professions.Contains(3) ? 0 : 1) && random.NextDouble() < __instance.fullness / 200.0 && random.NextDouble() < __instance.happiness / 70.0; var producedItemId = -1; if (canProduceItem && !__instance.isBaby()) // check whether the animal can produce an item and which one { var subType = ModEntry.Instance.Api.GetAnimalSubTypeByName(__instance.type.Value); if (subType != null) { var numberOfHearts = (int)(__instance.friendshipTowardFarmer / 195f); producedItemId = subType.Produce.GetRandomDefault(numberOfHearts, out var harvestType); __instance.harvestType.Value = (byte)harvestType; } if (random.NextDouble() < __instance.happiness / 150.0) { // create a frienship modifier based off of animal happiness - this is so deluxe item drops are also determine from animal happiness, not just friendship float frienshipModifier = __instance.happiness > 200 ? __instance.happiness * 1.5f : __instance.happiness <= 100 ? __instance.happiness - 100 : 0.0f; // determine deluxe products for Ducks and Rabbits separately as their deluxe products are rare drops, unlike other animals if (__instance.type.Value.Equals("Duck") && random.NextDouble() < (__instance.friendshipTowardFarmer + frienshipModifier) / 5000.0 + Game1.player.team.AverageDailyLuck() + Game1.player.team.AverageLuckLevel() * 0.01) { producedItemId = __instance.deluxeProduceIndex; } else if (__instance.type.Value.Equals("Rabbit") && random.NextDouble() < (__instance.friendshipTowardFarmer + frienshipModifier) / 5000.0 + Game1.player.team.AverageDailyLuck() + Game1.player.team.AverageLuckLevel() * 0.02) { producedItemId = __instance.deluxeProduceIndex; } __instance.daysSinceLastLay.Value = 0; // increase game stats for items produced - this only applies to items layable by default animals switch (producedItemId) { case 176: Game1.stats.ChickenEggsLayed++; break; case 180: Game1.stats.ChickenEggsLayed++; break; case 440: Game1.stats.RabbitWoolProduced++; break; case 442: Game1.stats.DuckEggsLayed++; break; } // determine whether deluxe product should be produced, exclude Ducks and Rabbits as they've been handled above if (!__instance.type.Value.Equals("Duck") && !__instance.type.Value.Equals("Rabbit")) { if (random.NextDouble() < (__instance.friendshipTowardFarmer + frienshipModifier) / 1200.0 && __instance.friendshipTowardFarmer >= 200) { var numberOfHearts = (int)(__instance.friendshipTowardFarmer / 195f); var customSubType = ModEntry.Instance.Api.GetAnimalSubTypeByName(__instance.type.Value); var deluxeId = customSubType.Produce.GetRandomDeluxe(numberOfHearts, out var harvestType); if (deluxeId != -1) // only change to a deluxe product if one could be found (not all animals have deluxe produce) { producedItemId = deluxeId; __instance.harvestType.Value = (byte)harvestType; } } } double productQualityChance = __instance.friendshipTowardFarmer / 1000.0 - (1.0 - __instance.happiness / 225.0); // if the farmer has a related profession, increase the chance of getting a high quality drop if (!__instance.isCoopDweller() && Game1.getFarmer(__instance.ownerID).professions.Contains(3) || __instance.isCoopDweller() && Game1.getFarmer(__instance.ownerID).professions.Contains(2)) { productQualityChance += 0.33; } // determine quality of produced item if (productQualityChance >= 0.95 && random.NextDouble() < productQualityChance / 2.0) { __instance.produceQuality.Value = 4; } else if (random.NextDouble() < productQualityChance / 2.0) { __instance.produceQuality.Value = 2; } else if (random.NextDouble() < productQualityChance) { __instance.produceQuality.Value = 1; } else { __instance.produceQuality.Value = 0; } } } // setup harvest type with a tool - this is so it's produce doesn't spawn in the animal house, instead must be manually harvested if (__instance.harvestType == 1 && canProduceItem) { __instance.currentProduce.Value = producedItemId; producedItemId = -1; } // ensure animal has an item ready to spawn and a valid home to spawn it in if (producedItemId != -1 && __instance.home != null) { var needsToPlaceProduce = true; // whether the animal needs to place there object - used for determining the the produce has been placed in an autograbber // check if the animal house has an auto grabber, if so spawn the item in there foreach (SObject environmentObject in __instance.home.indoors.Value.objects.Values) { if (environmentObject.bigCraftable && environmentObject.parentSheetIndex == 165 && environmentObject.heldObject.Value != null) { var producedItem = new SObject(Vector2.Zero, producedItemId, null, false, true, false, false) { Quality = __instance.produceQuality }; if ((environmentObject.heldObject.Value as Chest).addItem(producedItem) == null) // if addItem returns null it mean's all the items could be placed in the autograbber { environmentObject.showNextIndex.Value = true; needsToPlaceProduce = false; break; } } } // spawn the object if there was no valid auto grabber and there is a valid space under the animal if (needsToPlaceProduce && !__instance.home.indoors.Value.Objects.ContainsKey(__instance.getTileLocation())) { var producedItem = new SObject(Vector2.Zero, producedItemId, null, false, true, false, true) { Quality = __instance.produceQuality }; __instance.home.indoors.Value.Objects.Add(__instance.getTileLocation(), producedItem); } } // calculate the mood message for the animal if (!hasBeenLockedOutside) // ensure they haven't been locked outside, this is because a mood message would have been set already { if (__instance.fullness < 30) { __instance.moodMessage.Value = 4; } else if (__instance.happiness < 30) { __instance.moodMessage.Value = 3; } else if (__instance.happiness < 200) { __instance.moodMessage.Value = 2; } else { __instance.moodMessage.Value = 1; } } // make animal hungry __instance.fullness.Value = 0; // if it's a festival today, don't make animal hungry - festivals go on for most of the day so making them hungry would be unfair to the player if (Utility.isFestivalDay(Game1.dayOfMonth, Game1.currentSeason)) { __instance.fullness.Value = 250; } // reload animal data __instance.reload(__instance.home); return(false); }
/// <summary>The prefix for the UpdateWhenNotCurrentLocation method.</summary> /// <param name="currentBuilding">The current building the animal is in.</param> /// <param name="time">The GameTime object that contains time data about the game's frame time.</param> /// <param name="environment">The <see cref="GameLocation"/> of the animal.</param> /// <returns>False meaning the original method won't get ran.</returns> internal static bool UpdateWhenNotCurrentLocationPrefix(Building currentBuilding, GameTime time, GameLocation environment, FarmAnimal __instance) { var behaviors = typeof(FarmAnimal).GetMethod("behaviors", BindingFlags.NonPublic | BindingFlags.Instance); var doFarmerPushEvent = (NetEvent1Field <int, NetInt>) typeof(FarmAnimal).GetField("doFarmerPushEvent", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(__instance); var doBuildingPokeEvent = (NetEvent0)typeof(FarmAnimal).GetField("doBuildingPokeEvent", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(__instance); doFarmerPushEvent.Poll(); doBuildingPokeEvent.Poll(); // skip if time is paused if (!Game1.shouldTimePass()) { return(false); } __instance.update(time, environment, __instance.myID, false); // ensure this is the game host (not the farmhands) if (!Game1.IsMasterGame) { return(false); } // check if the animal is able to go outside if (currentBuilding == null || Game1.random.NextDouble() > .002 || !currentBuilding.animalDoorOpen || Game1.timeOfDay >= 1630 || Game1.isRaining || environment.farmers.Count > 0) { behaviors.Invoke(__instance, new object[] { time, environment }); return(false); } // check for special season conditions on the animal var animal = ModEntry.Instance.Api.GetAnimalBySubTypeName(__instance.type); if (animal != null) { // convert season string value into enum Season season = Season.Spring; switch (Game1.currentSeason) { case "summer": season = Season.Summer; break; case "fall": season = Season.Fall; break; case "winter": season = Season.Winter; break; } if (!animal.Data.SeasonsAllowedOutdoors.Contains(season)) { behaviors.Invoke(__instance, new object[] { time, environment }); return(false); } } // get the farm location to spawn the animal in Farm farm = (Farm)Game1.getLocationFromName("Farm"); // ensure the animal won't be colliding with anything when they leave the house var exitCollisionBox = new Rectangle( x: (currentBuilding.tileX + currentBuilding.animalDoor.X) * 64 + 2, y: (currentBuilding.tileY + currentBuilding.animalDoor.Y) * 64 + 2, width: __instance.isCoopDweller() ? 60 : 124, height: 60 ); if (farm.isCollidingPosition(exitCollisionBox, Game1.viewport, false, 0, false, __instance, false, false, false)) { return(false); } // remove animal from farm if (farm.animals.ContainsKey(__instance.myID)) { for (int index = farm.animals.Count() - 1; index >= 0; --index) { if (farm.animals.Pairs.ElementAt(index).Key.Equals(__instance.myID)) { farm.animals.Remove(__instance.myID); break; } } } // remove animal from building (currentBuilding.indoors.Value as AnimalHouse).animals.Remove(__instance.myID); // add animal to farm, initial values farm.animals.Add(__instance.myID, __instance); __instance.faceDirection(2); __instance.SetMovingDown(true); __instance.Position = new Vector2((float)currentBuilding.getRectForAnimalDoor().X, (float)((currentBuilding.tileY + currentBuilding.animalDoor.Y) * 64 - (__instance.Sprite.getHeight() * 4 - __instance.GetBoundingBox().Height) + 32)); // sort out path finding if (FarmAnimal.NumPathfindingThisTick < FarmAnimal.MaxPathfindingPerTick) { ++FarmAnimal.NumPathfindingThisTick; __instance.controller = new PathFindController( c: __instance, location: farm, endFunction: new PathFindController.isAtEnd(FarmAnimal.grassEndPointFunction), finalFacingDirection: Game1.random.Next(4), eraseOldPathController: false, endBehaviorFunction: new PathFindController.endBehavior(FarmAnimal.behaviorAfterFindingGrassPatch), limit: 200, endPoint: Point.Zero ); } if (__instance.controller == null || __instance.controller.pathToEndPoint == null || __instance.controller.pathToEndPoint.Count < 3) { __instance.SetMovingDown(true); __instance.controller = null; } else { __instance.faceDirection(2); __instance.Position = new Vector2( x: __instance.controller.pathToEndPoint.Peek().X * 64, y: (__instance.controller.pathToEndPoint.Peek().Y * 64 - (__instance.Sprite.getHeight() * 4 - __instance.GetBoundingBox().Height) + 16) ); if (!__instance.isCoopDweller()) { __instance.position.X -= 32f; } } __instance.noWarpTimer = 3000; currentBuilding.currentOccupants.Value--; if (Utility.isOnScreen(__instance.getTileLocationPoint(), 192, farm)) { farm.localSound("sandyStep"); } if (environment.isTileOccupiedByFarmer(__instance.getTileLocation()) != null) { environment.isTileOccupiedByFarmer(__instance.getTileLocation()).TemporaryPassableTiles.Add(__instance.GetBoundingBox()); } behaviors.Invoke(__instance, new object[] { time, environment }); return(false); }
/// <summary>The prefix for the FindTruffle method.</summary> /// <remarks>Although the method is called 'FindTruffle' it's responsible for all produce that is foraged.</remarks> /// <param name="__instance">The current <see cref="FarmAnimal"/> instance being patched.</param> /// <returns>False meaning the original method won't get ran.</returns> public static bool FindTrufflePrefix(FarmAnimal __instance) { // detemine the item to drop var productId = -1; var subType = ModEntry.Instance.Api.GetAnimalSubTypeByName(__instance.type); if (subType != null) { // get all the foragable items var foragableItems = subType.Produce?.AllSeasons?.Products?.Where(product => product.HarvestType == HarvestType.Forage).Select(product => product.Id).ToList(); switch (Game1.currentSeason) { case "spring": { var products = subType.Produce?.Spring?.Products?.Where(produce => produce.HarvestType == HarvestType.Forage).Select(produce => produce.Id).ToList(); if (products != null) { foragableItems.AddRange(products); } break; } case "summer": { var products = subType.Produce?.Summer?.Products?.Where(produce => produce.HarvestType == HarvestType.Forage).Select(produce => produce.Id).ToList(); if (products != null) { foragableItems.AddRange(products); } break; } case "fall": { var products = subType.Produce?.Fall?.Products?.Where(produce => produce.HarvestType == HarvestType.Forage).Select(produce => produce.Id).ToList(); if (products != null) { foragableItems.AddRange(products); } break; } case "winter": { var products = subType.Produce?.Winter?.Products?.Where(produce => produce.HarvestType == HarvestType.Forage).Select(produce => produce.Id).ToList(); if (products != null) { foragableItems.AddRange(products); } break; } } if (foragableItems.Count == 0) { return(false); } var productStringId = foragableItems[Game1.random.Next(foragableItems.Count)]; if (!int.TryParse(productStringId, out productId)) { return(false); } } // try to spawn the product around the animal if (Utility.spawnObjectAround(Utility.getTranslatedVector2(__instance.getTileLocation(), __instance.FacingDirection, 1f), new SObject(__instance.getTileLocation(), productId, 1), Game1.getFarm(), true)) { if (productId == 430) { ++Game1.stats.TrufflesFound; } } // if the player is a high friendship, increase the possiblility of skipping resetting the currentProduce - this means high friendshipped animals produce more if (Game1.random.NextDouble() <= __instance.friendshipTowardFarmer / 1500.0) { return(false); } __instance.currentProduce.Value = -1; return(false); }