/// <summary>The method to call before <see cref="FarmAnimal.updateWhenCurrentLocation"/>.</summary> private static bool Before_UpdateWhenCurrentLocation(FarmAnimal __instance, GameTime time, GameLocation location, ref bool __result) { if (!Game1.shouldTimePass()) { return(false); } if (__instance.health.Value <= 0) { return(true); } Mod.Instance.Helper.Reflection.GetField <NetEvent0>(__instance, "doBuildingPokeEvent").GetValue().Poll(); if (__instance.hitGlowTimer > 0) { __instance.hitGlowTimer -= time.ElapsedGameTime.Milliseconds; } if (__instance.Sprite.CurrentAnimation != null) { if (__instance.Sprite.animateOnce(time)) { __instance.Sprite.CurrentAnimation = null; } return(false); } __instance.update(time, location, __instance.myID.Value, false); if (Game1.IsMasterGame && Mod.Instance.Helper.Reflection.GetMethod(__instance, "behaviors").Invoke <bool>(time, location) || __instance.Sprite.CurrentAnimation != null) { return(false); } if (__instance.controller != null && __instance.controller.timerSinceLastCheckPoint > 10000) { __instance.controller = null; __instance.Halt(); } if (location is BuildableGameLocation && location is IAnimalLocation animalLocation && __instance.noWarpTimer <= 0) { Building building = __instance.home; if (building != null && Game1.IsMasterGame && building.getRectForAnimalDoor().Contains(__instance.GetBoundingBox().Center.X, __instance.GetBoundingBox().Top)) { if (Utility.isOnScreen(__instance.getTileLocationPoint(), 192, location)) { location.localSound("dwoop"); } animalLocation.Animals.Remove(__instance.myID.Value); (building.indoors.Value as AnimalHouse).animals[__instance.myID.Value] = __instance; __instance.setRandomPosition(building.indoors.Value); __instance.faceDirection(Game1.random.Next(4)); __instance.controller = null; return(true); } } __instance.noWarpTimer = Math.Max(0, __instance.noWarpTimer - time.ElapsedGameTime.Milliseconds); if (__instance.pauseTimer > 0) { __instance.pauseTimer -= time.ElapsedGameTime.Milliseconds; } if (Game1.timeOfDay >= 2000) { __instance.Sprite.currentFrame = __instance.buildingTypeILiveIn.Contains("Coop") ? 16 : 12; __instance.Sprite.UpdateSourceRect(); __instance.FacingDirection = 2; if (!__instance.isEmoting && Game1.random.NextDouble() < 0.002) { __instance.doEmote(24); } } else if (__instance.pauseTimer <= 0) { if (Game1.random.NextDouble() < 0.001 && __instance.age.Value >= __instance.ageWhenMature.Value && (Game1.gameMode == 3 && __instance.sound.Value != null) && Utility.isOnScreen(__instance.Position, 192)) { __instance.makeSound(); } if (!Game1.IsClient && Game1.random.NextDouble() < 0.007 && __instance.uniqueFrameAccumulator == -1) { int direction = Game1.random.Next(5); if (direction != (__instance.FacingDirection + 2) % 4) { if (direction < 4) { int facingDirection = __instance.FacingDirection; __instance.faceDirection(direction); if (!location.IsOutdoors && location.isCollidingPosition(__instance.nextPosition(direction), Game1.viewport, __instance)) { __instance.faceDirection(facingDirection); return(false); } } switch (direction) { case 0: __instance.SetMovingUp(true); break; case 1: __instance.SetMovingRight(true); break; case 2: __instance.SetMovingDown(true); break; case 3: __instance.SetMovingLeft(true); break; default: __instance.Halt(); __instance.Sprite.StopAnimation(); break; } } else if (__instance.noWarpTimer <= 0) { __instance.Halt(); __instance.Sprite.StopAnimation(); } } if (!Game1.IsClient && __instance.isMoving() && (Game1.random.NextDouble() < 0.014 && __instance.uniqueFrameAccumulator == -1)) { __instance.Halt(); __instance.Sprite.StopAnimation(); if (Game1.random.NextDouble() < 0.75) { __instance.uniqueFrameAccumulator = 0; if (__instance.buildingTypeILiveIn.Contains("Coop")) { switch (__instance.FacingDirection) { case 0: __instance.Sprite.currentFrame = 20; break; case 1: __instance.Sprite.currentFrame = 18; break; case 2: __instance.Sprite.currentFrame = 16; break; case 3: __instance.Sprite.currentFrame = 22; break; } } else if (__instance.buildingTypeILiveIn.Contains("Barn")) { switch (__instance.FacingDirection) { case 0: __instance.Sprite.currentFrame = 15; break; case 1: __instance.Sprite.currentFrame = 14; break; case 2: __instance.Sprite.currentFrame = 13; break; case 3: __instance.Sprite.currentFrame = 14; break; } } } __instance.Sprite.UpdateSourceRect(); } if (__instance.uniqueFrameAccumulator != -1 && !Game1.IsClient) { __instance.uniqueFrameAccumulator += time.ElapsedGameTime.Milliseconds; if (__instance.uniqueFrameAccumulator > 500) { if (__instance.buildingTypeILiveIn.Contains("Coop")) { __instance.Sprite.currentFrame = __instance.Sprite.currentFrame + 1 - __instance.Sprite.currentFrame % 2 * 2; } else if (__instance.Sprite.currentFrame > 12) { __instance.Sprite.currentFrame = (__instance.Sprite.currentFrame - 13) * 4; } else { switch (__instance.FacingDirection) { case 0: __instance.Sprite.currentFrame = 15; break; case 1: __instance.Sprite.currentFrame = 14; break; case 2: __instance.Sprite.currentFrame = 13; break; case 3: __instance.Sprite.currentFrame = 14; break; } } __instance.uniqueFrameAccumulator = 0; if (Game1.random.NextDouble() < 0.4) { __instance.uniqueFrameAccumulator = -1; } } } else if (!Game1.IsClient) { __instance.MovePosition(time, Game1.viewport, location); } } 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); }
/// <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); }