private void beforeSave(object sender, EventArgs args) { Log.info("Before save, use vanilla farms..."); foreach (var entry in Data.FarmTypes) { GameLocation loc = Game1.getLocationFromName(entry.Key); if (loc.GetType() == typeof(CustomFarm)) { Log.debug("Putting vanilla farm over " + entry.Key + "=" + entry.Value); var farm = loc as CustomFarm; Farm newFarm = new Farm(Helper.Content.Load <xTile.Map>("Maps\\Farm", ContentSource.GameContent), loc.name); CustomFarm.swapFarms(farm, newFarm); Game1.locations.Remove(farm); Game1.locations.Add(newFarm); } } }
public static object SafeDeSerialize(XmlReader reader, GameLocation location) { Type baseType = typeof(GameLocation); Type customType = location.GetType(); bool IsUnsafe = location is BuildableGameLocation || location is IAnimalLocation || location is DecoratableLocation; // No need to fix types from the base game. if (!IsUnsafe || object.ReferenceEquals(customType.Assembly, baseType.Assembly)) { return(SaveGame.locationSerializer.Deserialize(reader)); } var xmlOverrides = new XmlAttributeOverrides(); XmlSerializer serializer = new XmlSerializer(customType, xmlOverrides, ExtraTypes, null, null); return(serializer.Deserialize(reader)); }
/// <summary>Raised before the game creates a new save file or saves.</summary> /// <param name="sender">The event sender.</param> /// <param name="e">The event arguments.</param> private void OnSaving(object sender, EventArgs e) { Log.info("Before save, use vanilla farms..."); foreach (var entry in Data.FarmTypes) { GameLocation loc = Game1.getLocationFromName(entry.Key); if (loc.GetType() == typeof(CustomFarm)) { Log.debug($"Putting vanilla farm over {entry.Key}={entry.Value}"); var farm = loc as CustomFarm; Farm newFarm = new Farm("Maps\\Farm", loc.Name); CustomFarm.swapFarms(farm, newFarm); Game1.locations.Remove(farm); Game1.locations.Add(newFarm); } } Helper.Data.WriteSaveData("custom-farm-types", Data); }
public override IActiveEffect onCast(Farmer player, int level, int targetX, int targetY) { level += 1; targetX /= Game1.tileSize; targetY /= Game1.tileSize; Vector2 target = new Vector2(targetX, targetY); Tool dummyAxe = new Axe(); dummyAxe.UpgradeLevel = level; Tool dummyPick = new Pickaxe(); dummyPick.UpgradeLevel = level; Mod.instance.Helper.Reflection.GetField <Farmer>(dummyAxe, "lastUser").SetValue(player); Mod.instance.Helper.Reflection.GetField <Farmer>(dummyPick, "lastUser").SetValue(player); GameLocation loc = player.currentLocation; for (int ix = targetX - level; ix <= targetX + level; ++ix) { for (int iy = targetY - level; iy <= targetY + level; ++iy) { if (player.getCurrentMana() <= 0) { return(null); } Vector2 pos = new Vector2(ix, iy); if (loc.objects.ContainsKey(pos)) { var obj = loc.objects[pos]; if (obj.performToolAction(dummyAxe, loc)) { if (obj.Type == "Crafting" && obj.Fragility != 2) { loc.debris.Add(new Debris(obj.bigCraftable.Value ? -obj.ParentSheetIndex : obj.ParentSheetIndex, pos, pos)); } obj.performRemoveAction(pos, loc); loc.objects.Remove(pos); player.addMana(-3); player.AddCustomSkillExperience(Magic.Skill, 1); } else { var oldStam = player.stamina; dummyPick.DoFunction(loc, ix * Game1.tileSize, iy * Game1.tileSize, 0, player); player.stamina = oldStam; player.addMana(-3); player.AddCustomSkillExperience(Magic.Skill, 1); } } // Trees if (level >= 2) { if (loc.terrainFeatures.ContainsKey(pos) && !(loc.terrainFeatures[pos] is HoeDirt)) { TerrainFeature tf = loc.terrainFeatures[pos]; if (tf is Tree) { player.addMana(-3); } if (tf.performToolAction(dummyAxe, 0, pos, loc) || tf is Grass || (tf is Tree && tf.performToolAction(dummyAxe, 0, pos, loc))) { if (tf is Tree) { player.AddCustomSkillExperience(Magic.Skill, 5); } loc.terrainFeatures.Remove(pos); } if (tf is Grass && loc is Farm) { (loc as Farm).tryToAddHay(1); Game1.playSound("swordswipe"); loc.temporarySprites.Add(new TemporaryAnimatedSprite(28, pos * (float)Game1.tileSize + new Vector2((float)Game1.random.Next(-Game1.pixelZoom * 4, Game1.pixelZoom * 4), (float)Game1.random.Next(-Game1.pixelZoom * 4, Game1.pixelZoom * 4)), Color.Green, 8, Game1.random.NextDouble() < 0.5, (float)Game1.random.Next(60, 100), 0, -1, -1f, -1, 0)); loc.temporarySprites.Add(new TemporaryAnimatedSprite(Game1.objectSpriteSheetName, Game1.getSourceRectForStandardTileSheet(Game1.objectSpriteSheet, 178, 16, 16), 750f, 1, 0, player.position - new Vector2(0.0f, (float)(Game1.tileSize * 2)), false, false, player.position.Y / 10000f, 0.005f, Color.White, (float)Game1.pixelZoom, -0.005f, 0.0f, 0.0f, false) { motion = { Y = -1f }, layerDepth = (float)(1.0 - (double)Game1.random.Next(100) / 10000.0), delayBeforeAnimationStart = Game1.random.Next(350) }); } } } if (level >= 3) { ICollection <ResourceClump> clumps = (NetCollection <ResourceClump>)loc.GetType().GetField("resourceClumps", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).GetValue(loc); if (loc is Woods) { clumps = (loc as Woods).stumps; } if (clumps != null) { foreach (var rc in clumps) { if (new Rectangle((int)rc.tile.X, (int)rc.tile.Y, rc.width.Value, rc.height.Value).Contains(ix, iy)) { player.addMana(-3); if (rc.performToolAction(dummyAxe, 1, pos, loc) || rc.performToolAction(dummyPick, 1, pos, loc)) { clumps.Remove(rc); player.AddCustomSkillExperience(Magic.Skill, 10); } break; } } } } } } return(null); }
public static void TrySpousesKiss() { GameLocation location = Game1.currentLocation; if (location == null || !ReferenceEquals(location.GetType(), typeof(FarmHouse))) { return; } Farmer owner = (location as FarmHouse).owner; lastKissTime++; if (location == null || location.characters == null) { return; } List <NPC> list = location.characters.ToList(); Misc.ShuffleList(ref list); foreach (NPC npc1 in list) { if (!owner.friendshipData.ContainsKey(npc1.Name)) { continue; } if (!ModEntry.config.RoommateRomance && owner.friendshipData[npc1.Name].RoommateMarriage) { continue; } foreach (NPC npc2 in list) { if (!owner.friendshipData.ContainsKey(npc2.Name)) { continue; } if (npc1.Name == npc2.Name || (!ModEntry.config.RoommateRomance && owner.friendshipData[npc2.Name].RoommateMarriage)) { continue; } if (lastKissTime >= ModEntry.config.MinSpouseKissInterval) { kissingSpouses.Clear(); } float distance = Vector2.Distance(npc1.position, npc2.position); if ( npc1.getSpouse() != null && npc2.getSpouse() != null && npc1.getSpouse().Name == npc2.getSpouse().Name && distance < ModEntry.config.MaxDistanceToKiss && !kissingSpouses.Contains(npc1.Name) && !kissingSpouses.Contains(npc2.Name) && owner.getFriendshipHeartLevelForNPC(npc1.Name) >= ModEntry.config.MinHeartsForKiss && owner.getFriendshipHeartLevelForNPC(npc2.Name) >= ModEntry.config.MinHeartsForKiss && lastKissTime > ModEntry.config.MinSpouseKissInterval && ModEntry.myRand.NextDouble() < ModEntry.config.SpouseKissChance && (!ModEntry.config.PreventRelativesFromKissing || !Misc.AreSpousesRelated(npc1.Name, npc2.Name)) ) { kissingSpouses.Add(npc1.Name); kissingSpouses.Add(npc2.Name); ModEntry.PMonitor.Log("spouses kissing"); lastKissTime = 0; Vector2 npc1pos = npc1.position; Vector2 npc2pos = npc2.position; int npc1face = npc1.facingDirection; int npc2face = npc1.facingDirection; Vector2 midpoint = new Vector2((npc1.position.X + npc2.position.X) / 2, (npc1.position.Y + npc2.position.Y) / 2); PerformKiss(npc1, midpoint, npc2.Name); PerformKiss(npc2, midpoint, npc1.Name); DelayedAction action = new DelayedAction(1000); var t = Task.Run(async delegate { await Task.Delay(TimeSpan.FromSeconds(1)); npc1.position.Value = npc1pos; npc2.position.Value = npc2pos; npc1.FacingDirection = npc1face; npc2.FacingDirection = npc2face; return; }); } } } }
//this was almost entirely stolen from spacechase0 with very little contribution on my part. internal static void HandleToolTransmute(Tool tool) { int alchemyLevel = (EquivalentExchange.IsShiftKeyPressed() ? 0 : Alchemy.GetToolTransmuteRadius()); int toolLevel = tool.UpgradeLevel; //set last user to dodge a null pointer var toolPlayerFieldReflector = tool.GetType().GetField("lastUser", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); toolPlayerFieldReflector.SetValue(tool, Game1.player); Point hitLocation = GetMouseHitLocation(); GameLocation location = Game1.player.currentLocation; bool performedAction = false; //getting this out of the way, helps with easily determining tool types bool isScythe = tool is MeleeWeapon && tool.Name.ToLower().Contains("scythe"); bool isAxe = tool is StardewValley.Tools.Axe; bool isPickaxe = tool is StardewValley.Tools.Pickaxe; bool isHoe = tool is StardewValley.Tools.Hoe; bool isWateringCan = tool is StardewValley.Tools.WateringCan; for (int xOffset = -alchemyLevel; xOffset <= alchemyLevel; xOffset++) { for (int yOffset = -alchemyLevel; yOffset <= alchemyLevel; yOffset++) { if (!isScythe) { if (!IsCapableOfWithstandingToolTransmuteCost(Game1.player, 2F)) { return; } } Vector2 offsetPosition = new Vector2(xOffset + hitLocation.X, yOffset + hitLocation.Y); if (location.objects.ContainsKey(offsetPosition)) { if (isAxe || isScythe || isPickaxe || isHoe) { var snapshotPlayerExperience = Game1.player.experiencePoints; performedAction = DoToolFunction(location, Game1.player, tool, (int)offsetPosition.X, (int)offsetPosition.Y); RestorePlayerExperience(snapshotPlayerExperience); if (performedAction && !isScythe) { HandleToolTransmuteConsequence(2F); } } } else if (location.terrainFeatures.ContainsKey(offsetPosition)) { //a terrain feature, rather than a tool check, might respond to the tool TerrainFeature terrainFeature = location.terrainFeatures[offsetPosition]; //don't break stumps unless the player is in precision mode. if (terrainFeature is Tree && isAxe && (!(terrainFeature as Tree).stump || EquivalentExchange.IsShiftKeyPressed())) { Netcode.NetArray <int, Netcode.NetInt> snapshotPlayerExperience = Game1.player.experiencePoints; //trees get removed automatically performedAction = DoToolFunction(location, Game1.player, tool, (int)offsetPosition.X, (int)offsetPosition.Y); RestorePlayerExperience(snapshotPlayerExperience); if (performedAction) { HandleToolTransmuteConsequence(2F); } } else if (terrainFeature is Grass && location is Farm && isScythe) { int oldHay = (location as Farm).piecesOfHay; var snapshotPlayerExperience = Game1.player.experiencePoints; if (terrainFeature.performToolAction(tool, 0, offsetPosition, location)) { location.terrainFeatures.Remove(offsetPosition); //HandleToolTransmuteConsequence(); Scythe transmute is special and doesn't cost anything, but you don't get experience. performedAction = true; } RestorePlayerExperience(snapshotPlayerExperience); //hay get! spawn the sprite animation for acquisition of hay if (oldHay < (location as Farm).piecesOfHay) { SpawnHayAnimationSprite(location, offsetPosition, Game1.player); } } else if (terrainFeature is HoeDirt && isWateringCan && (tool as WateringCan).WaterLeft > 0) { //state of 0 is unwatered. if ((terrainFeature as HoeDirt).state != 1) { var snapshotPlayerExperience = Game1.player.experiencePoints; terrainFeature.performToolAction(tool, 0, offsetPosition, location); RestorePlayerExperience(snapshotPlayerExperience); (tool as WateringCan).WaterLeft = (tool as WateringCan).WaterLeft - 1; SpawnWateringCanAnimationSprite(location, offsetPosition); HandleToolTransmuteConsequence(2F); performedAction = true; } } else if (isPickaxe && terrainFeature is HoeDirt) { var snapshotPlayerExperience = Game1.player.experiencePoints; performedAction = DoToolFunction(location, Game1.player, tool, (int)offsetPosition.X, (int)offsetPosition.Y); RestorePlayerExperience(snapshotPlayerExperience); if (performedAction) { HandleToolTransmuteConsequence(2F); } } } else if ((isPickaxe || isAxe)) { ICollection <ResourceClump> largeResourceClusters = null; if (location is Farm) { largeResourceClusters = (NetCollection <ResourceClump>)location.GetType().GetField("resourceClumps", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).GetValue(location); } else if (location is MineShaft) { largeResourceClusters = (NetObjectList <ResourceClump>)location.GetType().GetField("resourceClumps", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).GetValue(location); } else if (location is Woods) { largeResourceClusters = (location as Woods).stumps; } DoLargeResourceClusterAction(largeResourceClusters, tool, offsetPosition, performedAction); } else if (isHoe) { var snapshotPlayerExperience = Game1.player.experiencePoints; performedAction = DoToolFunction(location, Game1.player, tool, (int)offsetPosition.X, (int)offsetPosition.Y); RestorePlayerExperience(snapshotPlayerExperience); if (performedAction) { HandleToolTransmuteConsequence(2F); } } } } if (performedAction) { SoundUtil.PlayMagickySound(); } }
private GameLocation Serialize(Dictionary <string, Tuple <bool, InstanceState> > data, GameLocation location, bool building = false) { string guid = Guid.NewGuid().ToString(); var output = new GameLocation(); #pragma warning disable AvoidNetField // Avoid Netcode types when possible output.name.Value = guid; #pragma warning restore AvoidNetField // Avoid Netcode types when possible data.Add(building ? guid : location.Name, new Tuple <bool, InstanceState>(building, new InstanceState(location.GetType().AssemblyQualifiedName, JToken.FromObject(location, Serializer)))); return(output); }
public static bool Prefix(GameLocation location, Item item, int x, int y, Farmer f, ref bool __result) { if (!Config.EnableMod || item is not Object || !(item as Object).bigCraftable.Value || item.ParentSheetIndex != 62 || !typeof(DecoratableLocation).IsAssignableFrom(location.GetType()) || !(location as DecoratableLocation).isTileOnWall(x / 64, y / 64) || !Utility.isWithinTileWithLeeway(x, y, item, f)) { return(true); } SMonitor.Log($"Placing planter on wall"); __result = true; return(false); }
public static GameLocation GetOriginLocation(GameLocation location) { return(!(location is IHookedLocation) ? location : CopyData(location, location.GetType().BaseType)); }
public static bool Prefix(GameLocation location, Item item, int x, int y, Farmer f, ref bool __result) { if (!Config.EnableMod || item is not TV || item.Name.Contains("Budget") || item.Name.Contains("Floor") || !typeof(DecoratableLocation).IsAssignableFrom(location.GetType()) || !(location as DecoratableLocation).isTileOnWall(x / 64, y / 64) || (location as DecoratableLocation).isTileOnWall(x / 64, y / 64 + 1) || !Utility.isWithinTileWithLeeway(x, y, item, f)) { return(true); } __result = true; return(false); }
public static bool Prefix(Furniture __instance, GameLocation location, int x, int y, ref int __result) { if (!Config.EnableMod || __instance is not TV || __instance.Name.Contains("Budget") || __instance.Name.Contains("Floor") || !typeof(DecoratableLocation).IsAssignableFrom(location.GetType()) || !(location as DecoratableLocation).isTileOnWall((int)x / 64, (int)y / 64) || (location as DecoratableLocation).isTileOnWall(x / 64, y / 64 + 1)) { return(true); } __instance.TileLocation = new Vector2(x / 64, y / 64); __result = 0; return(false); }
public static bool Prefix(Furniture __instance, GameLocation l, Vector2 tile, ref bool __result) { if (!Config.EnableMod || __instance is not TV || __instance.Name.Contains("Budget") || __instance.Name.Contains("Floor") || !typeof(DecoratableLocation).IsAssignableFrom(l.GetType()) || !(l as DecoratableLocation).isTileOnWall((int)tile.X, (int)tile.Y) || (l as DecoratableLocation).isTileOnWall((int)tile.X, (int)tile.Y + 1)) { return(true); } __result = true; return(false); }