diff --git a/FarmExpansion/FarmExpansion.cs b/FarmExpansion/FarmExpansion.cs index bdc90e7..8465a9f 100644 --- a/FarmExpansion/FarmExpansion.cs +++ b/FarmExpansion/FarmExpansion.cs @@ -14,6 +14,9 @@ using Object = StardewValley.Object; using Rectangle = Microsoft.Xna.Framework.Rectangle; using FarmExpansion.Framework; +using StardewValley.Locations; +using Netcode; +using StardewValley.Network; namespace FarmExpansion { @@ -28,114 +31,73 @@ public FarmExpansion() { } - public FarmExpansion(Map m, string name, FEFramework framework) : base(m, name) + public FarmExpansion(Map m, string name, FEFramework framework) : base(/*"FarmExpansion", name*/) { this.framework = framework; + this.Map = m; + this.name.Value = name; } public override void DayUpdate(int dayOfMonth) { - new Random((int)Game1.uniqueIDForThisGame + (int)Game1.stats.DaysPlayed); - this.temporarySprites.Clear(); - for (int i = this.terrainFeatures.Count - 1; i >= 0; i--) { - if (!this.isTileOnMap(this.terrainFeatures.ElementAt(i).Key)) - { - this.terrainFeatures.Remove(this.terrainFeatures.ElementAt(i).Key); - } - else - { - this.terrainFeatures.ElementAt(i).Value.dayUpdate(this, this.terrainFeatures.ElementAt(i).Key); - } + // skip Farm.dayUpdate, call BuildableGameLocation.dayUpdate and anything further + // up the chain of inheritance. + // Don't try this at home, kids, this is ultimate example of how NOT to do things. + // thanks to https://stackoverflow.com/a/32562464 for this ugly workaround. + var ptr = typeof(BuildableGameLocation).GetMethod("DayUpdate").MethodHandle.GetFunctionPointer(); + var grandparentDayUpdate = (Action)Activator.CreateInstance(typeof(Action), this, ptr); + grandparentDayUpdate(dayOfMonth); } - if (this.largeTerrainFeatures != null) - { - foreach (LargeTerrainFeature current in this.largeTerrainFeatures) - { - current.dayUpdate(this); - } - } - foreach (Object current in this.objects.Values) - { - current.DayUpdate(this); - } - this.debris.Clear(); - this.spawnObjects(); - if (Game1.dayOfMonth == 1) - { - this.spawnObjects(); - } - if (Game1.stats.DaysPlayed < 4u) - { - this.spawnObjects(); - } - this.lightLevel = 0f; - this.addLightGlows(); // gamelocation dayupdate - foreach(Building current in this.buildings) - { - current.dayUpdate(dayOfMonth); - }// buildablelocation dayupdate + for (int index = this.animals.Count() - 1; index >= 0; --index) + this.animals.Pairs.ElementAt>(index).Value.dayUpdate((GameLocation)this); /*if (Game1.whichFarm == 4 && !Game1.player.mailReceived.Contains("henchmanGone")) { Game1.spawnMonstersAtNight = true; }*/ this.lastItemShipped = null; - for (int i = this.animals.Count - 1; i >= 0; i--) - { - this.animals.ElementAt(i).Value.dayUpdate(this); - } - for (int j = this.characters.Count - 1; j >= 0; j--) + for (int index = this.characters.Count - 1; index >= 0; --index) { - if (this.characters[j] is JunimoHarvester) - { - this.characters.RemoveAt(j); - } + if (this.characters[index] is JunimoHarvester) + this.characters.RemoveAt(index); } - for (int k = this.characters.Count - 1; k >= 0; k--) + for (int index = this.characters.Count - 1; index >= 0; --index) { - if (this.characters[k] is Monster && (this.characters[k] as Monster).wildernessFarmMonster) - { - this.characters.RemoveAt(k); - } + if (this.characters[index] is Monster && (this.characters[index] as Monster).wildernessFarmMonster) + this.characters.RemoveAt(index); } if (this.characters.Count > 5) { int num = 0; - for (int l = this.characters.Count - 1; l >= 0; l--) + for (int index = this.characters.Count - 1; index >= 0; --index) { - if (this.characters[l] is GreenSlime && Game1.random.NextDouble() < 0.035) + if (this.characters[index] is GreenSlime && Game1.random.NextDouble() < 0.035) { - this.characters.RemoveAt(l); - num++; + this.characters.RemoveAt(index); + ++num; } } if (num > 0) - { - Game1.showGlobalMessage(Game1.content.LoadString((num == 1) ? "Strings\\Locations:Farm_1SlimeEscaped" : "Strings\\Locations:Farm_NSlimesEscaped", new object[] - { - num - })); - } + Game1.showGlobalMessage(Game1.content.LoadString(num == 1 ? "Strings\\Locations:Farm_1SlimeEscaped" : "Strings\\Locations:Farm_NSlimesEscaped", (object)num)); } - - Dictionary.KeyCollection keys = this.terrainFeatures.Keys; - for (int num3 = keys.Count - 1; num3 >= 0; num3--) + // stuff for handling specific Game1.whichFarm (hardwood stump/geode spawning) - ommited, doesn't concern expansion + + ICollection source = (ICollection)new List(this.terrainFeatures.Keys); + for (int index = source.Count - 1; index >= 0; --index) { - if (this.terrainFeatures[keys.ElementAt(num3)] is HoeDirt && (this.terrainFeatures[keys.ElementAt(num3)] as HoeDirt).crop == null && Game1.random.NextDouble() <= 0.1) - { - this.terrainFeatures.Remove(keys.ElementAt(num3)); - } + if (this.terrainFeatures[source.ElementAt(index)] is HoeDirt && (this.terrainFeatures[source.ElementAt(index)] as HoeDirt).crop == null && Game1.random.NextDouble() <= 0.1) + this.terrainFeatures.Remove(source.ElementAt(index)); } - if (this.terrainFeatures.Count > 0 && Game1.currentSeason.Equals("fall") && Game1.dayOfMonth > 1 && Game1.random.NextDouble() < 0.05) + if (this.terrainFeatures.Count() > 0 && Game1.currentSeason.Equals("fall") && (Game1.dayOfMonth > 1 && Game1.random.NextDouble() < 0.05)) { - for (int num4 = 0; num4 < 10; num4++) + for (int index = 0; index < 10; ++index) { - TerrainFeature value2 = this.terrainFeatures.ElementAt(Game1.random.Next(this.terrainFeatures.Count)).Value; - if (value2 is Tree && (value2 as Tree).growthStage >= 5 && !(value2 as Tree).tapped) + TerrainFeature terrainFeature = this.terrainFeatures.Pairs.ElementAt>(Game1.random.Next(this.terrainFeatures.Count())).Value; + if (terrainFeature is Tree && (int)((NetFieldBase)(terrainFeature as Tree).growthStage) >= 5 && !(bool)((NetFieldBase)(terrainFeature as Tree).tapped)) { - (value2 as Tree).treeType = 7; - (value2 as Tree).loadSprite(); + (terrainFeature as Tree).treeType.Value = 7; + (terrainFeature as Tree).loadSprite(); break; } } @@ -151,256 +113,212 @@ public override void DayUpdate(int dayOfMonth) spawnWeeds(false); if (dayOfMonth == 1) { - for (int num5 = this.terrainFeatures.Count - 1; num5 >= 0; num5--) + for (int index = this.terrainFeatures.Count() - 1; index >= 0; --index) { - if (this.terrainFeatures.ElementAt(num5).Value is HoeDirt && (this.terrainFeatures.ElementAt(num5).Value as HoeDirt).crop == null && Game1.random.NextDouble() < 0.8) + KeyValuePair keyValuePair = this.terrainFeatures.Pairs.ElementAt>(index); + if (keyValuePair.Value is HoeDirt) { - this.terrainFeatures.Remove(this.terrainFeatures.ElementAt(num5).Key); + keyValuePair = this.terrainFeatures.Pairs.ElementAt>(index); + if ((keyValuePair.Value as HoeDirt).crop == null && Game1.random.NextDouble() < 0.8) + { + NetVector2Dictionary> terrainFeatures = this.terrainFeatures; + keyValuePair = this.terrainFeatures.Pairs.ElementAt>(index); + Vector2 key = keyValuePair.Key; + terrainFeatures.Remove(key); + } } } spawnWeedsAndStones(20, false, false); - if (Game1.currentSeason.Equals("spring") && Game1.stats.DaysPlayed > 1u) + if (Game1.currentSeason.Equals("spring") && Game1.stats.DaysPlayed > 1U) { spawnWeedsAndStones(40, false, false); spawnWeedsAndStones(40, true, false); - for (int num6 = 0; num6 < 15; num6++) + for (int index = 0; index < 15; ++index) { - int num7 = Game1.random.Next(this.map.DisplayWidth / Game1.tileSize); - int num8 = Game1.random.Next(this.map.DisplayHeight / Game1.tileSize); - Vector2 vector = new Vector2((float)num7, (float)num8); + int xTile = Game1.random.Next(this.map.DisplayWidth / 64); + int yTile = Game1.random.Next(this.map.DisplayHeight / 64); + Vector2 vector2 = new Vector2((float)xTile, (float)yTile); Object @object; - this.objects.TryGetValue(vector, out @object); - if (@object == null && base.doesTileHaveProperty(num7, num8, "Diggable", "Back") != null && base.isTileLocationOpen(new Location(num7 * Game1.tileSize, num8 * Game1.tileSize)) && !this.isTileOccupied(vector, "") && base.doesTileHaveProperty(num7, num8, "Water", "Back") == null) - { - this.terrainFeatures.Add(vector, new Grass(1, 4)); - } + this.objects.TryGetValue(vector2, out @object); + if (@object == null && this.doesTileHaveProperty(xTile, yTile, "Diggable", "Back") != null && (this.isTileLocationOpen(new Location(xTile * 64, yTile * 64)) && !this.isTileOccupied(vector2, "")) && this.doesTileHaveProperty(xTile, yTile, "Water", "Back") == null) + this.terrainFeatures.Add(vector2, (TerrainFeature)new Grass(1, 4)); } - base.growWeedGrass(40); + this.growWeedGrass(40); } } base.growWeedGrass(1); } - new public void spawnWeedsAndStones(int numDebris = -1, bool weedsOnly = false, bool spawnFromOldWeeds = true) - { - if ((this as Farm).isBuildingConstructed("Gold Clock")) - { - return; - } - if (!Game1.currentSeason.Equals("winter")) - { - int num = (numDebris != -1) ? numDebris : ((Game1.random.NextDouble() < 0.95) ? ((Game1.random.NextDouble() < 0.25) ? Game1.random.Next(10, 21) : Game1.random.Next(5, 11)) : 0); - if (Game1.isRaining) - { - num *= 2; - } - if (Game1.dayOfMonth == 1) - { - num *= 5; - } - if (this.objects.Count <= 0 & spawnFromOldWeeds) - { - return; - } - for (int i = 0; i < num; i++) - { - Vector2 vector = spawnFromOldWeeds ? new Vector2((float)Game1.random.Next(-1, 2), (float)Game1.random.Next(-1, 2)) : new Vector2((float)Game1.random.Next(this.map.Layers[0].LayerWidth), (float)Game1.random.Next(this.map.Layers[0].LayerHeight)); - while (spawnFromOldWeeds && vector.Equals(Vector2.Zero)) - { - vector = new Vector2((float)Game1.random.Next(-1, 2), (float)Game1.random.Next(-1, 2)); - } - KeyValuePair keyValuePair = new KeyValuePair(Vector2.Zero, null); - if (spawnFromOldWeeds) - { - keyValuePair = this.objects.ElementAt(Game1.random.Next(this.objects.Count)); - } - Vector2 vector2 = spawnFromOldWeeds ? keyValuePair.Key : Vector2.Zero; - if (((this.doesTileHaveProperty((int)(vector.X + vector2.X), (int)(vector.Y + vector2.Y), "Diggable", "Back") != null) || (this.doesTileHaveProperty((int)(vector.X + vector2.X), (int)(vector.Y + vector2.Y), "Diggable", "Back") == null)) && (this.doesTileHaveProperty((int)(vector.X + vector2.X), (int)(vector.Y + vector2.Y), "Type", "Back") == null || !this.doesTileHaveProperty((int)(vector.X + vector2.X), (int)(vector.Y + vector2.Y), "Type", "Back").Equals("Wood")) && (this.isTileLocationTotallyClearAndPlaceable(vector + vector2) || (spawnFromOldWeeds && ((this.objects.ContainsKey(vector + vector2) && this.objects[vector + vector2].parentSheetIndex != 105) || (this.terrainFeatures.ContainsKey(vector + vector2) && (this.terrainFeatures[vector + vector2] is HoeDirt || this.terrainFeatures[vector + vector2] is Flooring))))) && this.doesTileHaveProperty((int)(vector.X + vector2.X), (int)(vector.Y + vector2.Y), "NoSpawn", "Back") == null && (spawnFromOldWeeds || !this.objects.ContainsKey(vector + vector2))) - { - int num2 = -1; + // not needed, does exactly the same as GameLocation.spawnWeedsAndStones + //new public void spawnWeedsAndStones(int numDebris = -1, bool weedsOnly = false, bool spawnFromOldWeeds = true) + //{ + // if ((this as Farm).isBuildingConstructed("Gold Clock")) + // { + // return; + // } + // if (!Game1.currentSeason.Equals("winter")) + // { + // int num = (numDebris != -1) ? numDebris : ((Game1.random.NextDouble() < 0.95) ? ((Game1.random.NextDouble() < 0.25) ? Game1.random.Next(10, 21) : Game1.random.Next(5, 11)) : 0); + // if (Game1.isRaining) + // { + // num *= 2; + // } + // if (Game1.dayOfMonth == 1) + // { + // num *= 5; + // } + // if (this.objects.Count() <= 0 & spawnFromOldWeeds) + // { + // return; + // } + // for (int i = 0; i < num; i++) + // { + // Vector2 vector = spawnFromOldWeeds ? new Vector2((float)Game1.random.Next(-1, 2), (float)Game1.random.Next(-1, 2)) : new Vector2((float)Game1.random.Next(this.map.Layers[0].LayerWidth), (float)Game1.random.Next(this.map.Layers[0].LayerHeight)); + // while (spawnFromOldWeeds && vector.Equals(Vector2.Zero)) + // { + // vector = new Vector2((float)Game1.random.Next(-1, 2), (float)Game1.random.Next(-1, 2)); + // } + // KeyValuePair keyValuePair = new KeyValuePair(Vector2.Zero, null); + // if (spawnFromOldWeeds) + // { + // keyValuePair = this.objects.Pairs.ElementAt(Game1.random.Next(this.objects.Count())); + // } + // Vector2 vector2 = spawnFromOldWeeds ? keyValuePair.Key : Vector2.Zero; + // if (((this.doesTileHaveProperty((int)(vector.X + vector2.X), (int)(vector.Y + vector2.Y), "Diggable", "Back") != null) || (this.doesTileHaveProperty((int)(vector.X + vector2.X), (int)(vector.Y + vector2.Y), "Diggable", "Back") == null)) && (this.doesTileHaveProperty((int)(vector.X + vector2.X), (int)(vector.Y + vector2.Y), "Type", "Back") == null || !this.doesTileHaveProperty((int)(vector.X + vector2.X), (int)(vector.Y + vector2.Y), "Type", "Back").Equals("Wood")) && (this.isTileLocationTotallyClearAndPlaceable(vector + vector2) || (spawnFromOldWeeds && ((this.objects.ContainsKey(vector + vector2) && this.objects[vector + vector2].ParentSheetIndex != 105) || (this.terrainFeatures.ContainsKey(vector + vector2) && (this.terrainFeatures[vector + vector2] is HoeDirt || this.terrainFeatures[vector + vector2] is Flooring))))) && this.doesTileHaveProperty((int)(vector.X + vector2.X), (int)(vector.Y + vector2.Y), "NoSpawn", "Back") == null && (spawnFromOldWeeds || !this.objects.ContainsKey(vector + vector2))) + // { + // int parentSheetIndex = -1; - if (Game1.random.NextDouble() < 0.5 && !weedsOnly && (!spawnFromOldWeeds || keyValuePair.Value.Name.Equals("Stone") || keyValuePair.Value.Name.Contains("Twig"))) - { - if (Game1.random.NextDouble() < 0.5) - { - num2 = ((Game1.random.NextDouble() < 0.5) ? 294 : 295); - } - else - { - num2 = ((Game1.random.NextDouble() < 0.5) ? 343 : 450); - } - } - else if (!spawnFromOldWeeds || keyValuePair.Value.Name.Contains("Weed")) - { - num2 = GameLocation.getWeedForSeason(Game1.random, Game1.currentSeason); - } - if (!spawnFromOldWeeds && Game1.random.NextDouble() < 0.05) - { - this.terrainFeatures.Add(vector + vector2, new Tree(Game1.random.Next(3) + 1, Game1.random.Next(3))); - continue; - } - if (num2 != -1) - { - bool flag2 = false; - if (this.objects.ContainsKey(vector + vector2)) - { - Object @object = this.objects[vector + vector2]; - if (@object is Fence || @object is Chest) - { - continue; - } - if (@object.name != null && !@object.Name.Contains("Weed") && !@object.Name.Equals("Stone") && !@object.name.Contains("Twig") && @object.name.Length > 0) - { - flag2 = true; - Game1.debugOutput = @object.Name + " was destroyed"; - } - this.objects.Remove(vector + vector2); - } - else if (this.terrainFeatures.ContainsKey(vector + vector2)) - { - try - { - flag2 = (this.terrainFeatures[vector + vector2] is HoeDirt || this.terrainFeatures[vector + vector2] is Flooring); - } - catch (Exception) - { - } - if (!flag2) - { - return; - } - this.terrainFeatures.Remove(vector + vector2); - } - if (flag2) - { - Game1.showGlobalMessage(Game1.content.LoadString("Strings\\Locations:Farm_WeedsDestruction", new object[0])); - } - this.objects.Add(vector + vector2, new Object(vector + vector2, num2, 1)); - } - } - } - } - } + // if (Game1.random.NextDouble() < 0.5 && !weedsOnly && (!spawnFromOldWeeds || keyValuePair.Value.Name.Equals("Stone") || keyValuePair.Value.Name.Contains("Twig"))) + // { + // if (Game1.random.NextDouble() < 0.5) + // { + // parentSheetIndex = ((Game1.random.NextDouble() < 0.5) ? 294 : 295); + // } + // else + // { + // parentSheetIndex = ((Game1.random.NextDouble() < 0.5) ? 343 : 450); + // } + // } + // else if (!spawnFromOldWeeds || keyValuePair.Value.Name.Contains("Weed")) + // { + // parentSheetIndex = GameLocation.getWeedForSeason(Game1.random, Game1.currentSeason); + // } + // if (!spawnFromOldWeeds && Game1.random.NextDouble() < 0.05) + // { + // this.terrainFeatures.Add(vector + vector2, new Tree(Game1.random.Next(3) + 1, Game1.random.Next(3))); + // continue; + // } + // if (parentSheetIndex != -1) + // { + // bool flag2 = false; + // if (this.objects.ContainsKey(vector + vector2)) + // { + // Object @object = this.objects[vector + vector2]; + // if (@object is Fence || @object is Chest) + // { + // continue; + // } + // if (@object.name != null && !@object.Name.Contains("Weed") && !@object.Name.Equals("Stone") && !@object.name.Contains("Twig") && @object.name.Length > 0) + // { + // flag2 = true; + // Game1.debugOutput = @object.Name + " was destroyed"; + // } + // this.objects.Remove(vector + vector2); + // } + // else if (this.terrainFeatures.ContainsKey(vector + vector2)) + // { + // try + // { + // flag2 = (this.terrainFeatures[vector + vector2] is HoeDirt || this.terrainFeatures[vector + vector2] is Flooring); + // } + // catch (Exception) + // { + // } + // if (!flag2) + // { + // return; + // } + // this.terrainFeatures.Remove(vector + vector2); + // } + // if (flag2) + // { + // Game1.showGlobalMessage(Game1.content.LoadString("Strings\\Locations:Farm_WeedsDestruction", new object[0])); + // } + // this.objects.Add(vector + vector2, new Object(vector + vector2, parentSheetIndex, 1)); + // } + // } + // } + // } + //} - new public void spawnWeeds(bool weedsOnly) - { - int num = Game1.random.Next(5, 12); - if (Game1.dayOfMonth == 1 && Game1.currentSeason.Equals("spring")) - { - num *= 15; - } - for (int i = 0; i < num; i++) - { - for (int j = 0; j < 3; j++) - { - int num2 = Game1.random.Next(this.map.DisplayWidth / Game1.tileSize); - int num3 = Game1.random.Next(this.map.DisplayHeight / Game1.tileSize); - Vector2 vector = new Vector2((float)num2, (float)num3); - Object @object; - this.objects.TryGetValue(vector, out @object); - int num4 = -1; - int num5 = -1; - if (Game1.random.NextDouble() < 0.15 + (weedsOnly ? 0.05 : 0.0)) - { - num4 = 1; - } - else if (!weedsOnly && Game1.random.NextDouble() < 0.35) - { - num5 = 1; - } - if (num5 != -1) - { - if (Game1.random.NextDouble() < 0.25) - { - return; - } - } - else if (@object == null && this.doesTileHaveProperty(num2, num3, "Diggable", "Back") != null && this.isTileLocationOpen(new Location(num2 * Game1.tileSize, num3 * Game1.tileSize)) && !this.isTileOccupied(vector, "") && this.doesTileHaveProperty(num2, num3, "Water", "Back") == null) - { - string text = this.doesTileHaveProperty(num2, num3, "NoSpawn", "Back"); - if (text != null && (text.Equals("Grass") || text.Equals("All") || text.Equals("True"))) - { - continue; - } - if (num4 != -1 && !Game1.currentSeason.Equals("winter")) - { - int numberOfWeeds = Game1.random.Next(1, 3); - this.terrainFeatures.Add(vector, new Grass(num4, numberOfWeeds)); - } - } - } - } - } + //new public void spawnWeeds(bool weedsOnly) + // shouldn't be needed (didn't check too thoroughly though) + //{ + // int num = Game1.random.Next(5, 12); + // if (Game1.dayOfMonth == 1 && Game1.currentSeason.Equals("spring")) + // { + // num *= 15; + // } + // for (int i = 0; i < num; i++) + // { + // for (int j = 0; j < 3; j++) + // { + // int num2 = Game1.random.Next(this.map.DisplayWidth / Game1.tileSize); + // int num3 = Game1.random.Next(this.map.DisplayHeight / Game1.tileSize); + // Vector2 vector = new Vector2((float)num2, (float)num3); + // Object @object; + // this.objects.TryGetValue(vector, out @object); + // int num4 = -1; + // int num5 = -1; + // if (Game1.random.NextDouble() < 0.15 + (weedsOnly ? 0.05 : 0.0)) + // { + // num4 = 1; + // } + // else if (!weedsOnly && Game1.random.NextDouble() < 0.35) + // { + // num5 = 1; + // } + // if (num5 != -1) + // { + // if (Game1.random.NextDouble() < 0.25) + // { + // return; + // } + // } + // else if (@object == null && this.doesTileHaveProperty(num2, num3, "Diggable", "Back") != null && this.isTileLocationOpen(new Location(num2 * Game1.tileSize, num3 * Game1.tileSize)) && !this.isTileOccupied(vector, "") && this.doesTileHaveProperty(num2, num3, "Water", "Back") == null) + // { + // string text = this.doesTileHaveProperty(num2, num3, "NoSpawn", "Back"); + // if (text != null && (text.Equals("Grass") || text.Equals("All") || text.Equals("True"))) + // { + // continue; + // } + // if (num4 != -1 && !Game1.currentSeason.Equals("winter")) + // { + // int numberOfWeeds = Game1.random.Next(1, 3); + // this.terrainFeatures.Add(vector, new Grass(num4, numberOfWeeds)); + // } + // } + // } + // } + //} public override void draw(SpriteBatch b) { - if (!Game1.eventUp) - { - for (int i = 0; i < this.characters.Count; i++) - { - if (this.characters[i] != null) - { - this.characters[i].draw(b); - } - } - } - for (int j = 0; j < this.projectiles.Count; j++) - { - this.projectiles[j].draw(b); - } - for (int k = 0; k < this.farmers.Count; k++) - { - if (!this.farmers[k].uniqueMultiplayerID.Equals(Game1.player.uniqueMultiplayerID)) - { - this.farmers[k].draw(b); - } - } - if (this.critters != null) - { - for (int l = 0; l < this.critters.Count; l++) - { - this.critters[l].draw(b); - } - } - this.drawDebris(b); - if (!Game1.eventUp || (this.currentEvent != null && this.currentEvent.showGroundObjects)) { - foreach (KeyValuePair current in this.objects) - { - current.Value.draw(b, (int)current.Key.X, (int)current.Key.Y, 1f); - } - } - if (this.doorSprites != null) - { - foreach (TemporaryAnimatedSprite current in this.doorSprites.Values) - { - current.draw(b, false, 0, 0); - } - } - if (this.largeTerrainFeatures != null) - { - foreach (LargeTerrainFeature current in largeTerrainFeatures) - { - current.draw(b); - } - } - if (this.fishSplashAnimation != null) - { - this.fishSplashAnimation.draw(b, false, 0, 0); - } - if (this.orePanAnimation != null) - { - this.orePanAnimation.draw(b, false, 0, 0); - } - foreach (Building current in this.buildings) - { - current.draw(b); + // skip Farm.draw, call BuildableGameLocation.draw and anything further + // up the chain of inheritance. + // Don't try this at home, kids, this is ultimate example of how NOT to do things. + // thanks to https://stackoverflow.com/a/32562464 for this ugly workaround. + var ptr = typeof(BuildableGameLocation).GetMethod("draw").MethodHandle.GetFunctionPointer(); + var grandparentDraw = (Action)Activator.CreateInstance(typeof(Action), this, ptr); + grandparentDraw(b); } + foreach (ResourceClump current in this.resourceClumps) { - current.draw(b, current.tile); + current.draw(b, current.tile.Value); } - foreach (KeyValuePair current in this.animals) + foreach (KeyValuePair current in this.animals.Pairs) { current.Value.draw(b); } @@ -464,75 +382,75 @@ public override bool checkAction(Location tileLocation, xTile.Dimensions.Rectang if ((this.objects[vector].Type.Equals("Crafting") || this.objects[vector].Type.Equals("interactive")) && this.objects[vector].name.Equals("Bee House")) { Object beeHive = this.objects[vector]; - if (!beeHive.readyForHarvest) + if (!beeHive.readyForHarvest.Value) { return false; } - beeHive.honeyType = new Object.HoneyType?(Object.HoneyType.Wild); + beeHive.honeyType.Value = new Object.HoneyType?(Object.HoneyType.Wild); string str = "Wild"; int num6 = 0; - Crop crop = this.findCloseFlower(beeHive.tileLocation); + Crop crop = this.findCloseFlower(beeHive.TileLocation); if (crop != null) { - str = Game1.objectInformation[crop.indexOfHarvest].Split(new char[] + str = Game1.objectInformation[crop.indexOfHarvest.Value].Split(new char[] { '/' })[0]; - int indexOfHarvest = crop.indexOfHarvest; + int indexOfHarvest = crop.indexOfHarvest.Value; if (indexOfHarvest != 376) { switch (indexOfHarvest) { case 591: - beeHive.honeyType = new Object.HoneyType?(Object.HoneyType.Tulip); + beeHive.honeyType.Value = new Object.HoneyType?(Object.HoneyType.Tulip); break; case 593: - beeHive.honeyType = new Object.HoneyType?(Object.HoneyType.SummerSpangle); + beeHive.honeyType.Value = new Object.HoneyType?(Object.HoneyType.SummerSpangle); break; case 595: - beeHive.honeyType = new Object.HoneyType?(Object.HoneyType.FairyRose); + beeHive.honeyType.Value = new Object.HoneyType?(Object.HoneyType.FairyRose); break; case 597: - beeHive.honeyType = new Object.HoneyType?(Object.HoneyType.BlueJazz); + beeHive.honeyType.Value = new Object.HoneyType?(Object.HoneyType.BlueJazz); break; } } else { - beeHive.honeyType = new Object.HoneyType?(Object.HoneyType.Poppy); + beeHive.honeyType.Value = new Object.HoneyType?(Object.HoneyType.Poppy); } - num6 = Convert.ToInt32(Game1.objectInformation[crop.indexOfHarvest].Split(new char[] + num6 = Convert.ToInt32(Game1.objectInformation[crop.indexOfHarvest.Value].Split(new char[] { '/' })[1]) * 2; } - if (beeHive.heldObject != null) + if (beeHive.heldObject.Value != null) { - beeHive.heldObject.name = str + " Honey"; + beeHive.heldObject.Value.name = str + " Honey"; string displayName = framework.helper.Reflection.GetMethod(beeHive, "loadDisplayName").Invoke(); - beeHive.heldObject.displayName = displayName; - beeHive.heldObject.price += num6; + beeHive.heldObject.Value.displayName = displayName; + beeHive.heldObject.Value.Price += num6; if (Game1.currentSeason.Equals("winter")) { - beeHive.heldObject = null; - beeHive.readyForHarvest = false; - beeHive.showNextIndex = false; + beeHive.heldObject.Value = null; + beeHive.readyForHarvest.Value = false; + beeHive.showNextIndex.Value = false; return false; } - if (who.IsMainPlayer && !who.addItemToInventoryBool(beeHive.heldObject, false)) + if (who.IsMainPlayer && !who.addItemToInventoryBool(beeHive.heldObject.Value, false)) { Game1.showRedMessage(Game1.content.LoadString("Strings\\StringsFromCSFiles:Crop.cs.588", new object[0])); return false; } Game1.playSound("coin"); } - beeHive.readyForHarvest = false; - beeHive.showNextIndex = false; + beeHive.readyForHarvest.Value = false; + beeHive.showNextIndex.Value = false; if (!Game1.currentSeason.Equals("winter")) { - beeHive.heldObject = new Object(Vector2.Zero, 340, null, false, true, false, false); - beeHive.minutesUntilReady = 2400 - Game1.timeOfDay + 4320; + beeHive.heldObject.Value = new Object(Vector2.Zero, 340, null, false, true, false, false); + beeHive.MinutesUntilReady = 2400 - Game1.timeOfDay + 4320; } return true; } @@ -547,25 +465,45 @@ private void fixAnimalLocation() { if (buildings.Contains(animal.home)) { - Game1.getFarm().animals.Remove(animal.myID); - animals.Add(animal.myID, animal); + Game1.getFarm().animals.Remove(animal.myID.Value); + animals.Add(animal.myID.Value, animal); } } foreach (Building building in buildings) { - if (building.indoors == null) + if (building.indoors.Value == null) continue; - if (building.indoors is AnimalHouse) + if (building.indoors.Value is AnimalHouse) { List stuckAnimals = new List(); - foreach (FarmAnimal animal in ((AnimalHouse)building.indoors).animals.Values) + foreach (FarmAnimal animal in ((AnimalHouse)building.indoors.Value).animals.Values) { - if (Game1.getFarm().isCollidingPosition(new Rectangle((building.tileX + building.animalDoor.X) * Game1.tileSize + 2, (building.tileY + building.animalDoor.Y) * Game1.tileSize + 2, (animal.isCoopDweller() ? Game1.tileSize : (Game1.tileSize * 2)) - 4, Game1.tileSize - 4), Game1.viewport, false, 0, false, animal, false, false, false) || Game1.getFarm().isCollidingPosition(new Rectangle((building.tileX + building.animalDoor.X) * Game1.tileSize + 2, (building.tileY + building.animalDoor.Y + 1) * Game1.tileSize + 2, (animal.isCoopDweller() ? Game1.tileSize : (Game1.tileSize * 2)) - 4, Game1.tileSize - 4), Game1.viewport, false, 0, false, animal, false, false, false)) + if (Game1.getFarm().isCollidingPosition( + new Rectangle( + (building.tileX.Value + building.animalDoor.X) * Game1.tileSize + 2, + (building.tileY.Value + building.animalDoor.Y) * Game1.tileSize + 2, + (animal.isCoopDweller() ? Game1.tileSize : (Game1.tileSize * 2)) - 4, + Game1.tileSize - 4), + Game1.viewport, false, 0, false, animal, false, false, false + ) + || Game1.getFarm().isCollidingPosition( + new Rectangle( + (building.tileX.Value + building.animalDoor.X) * Game1.tileSize + 2, + (building.tileY.Value + building.animalDoor.Y + 1) * Game1.tileSize + 2, + (animal.isCoopDweller() ? Game1.tileSize : (Game1.tileSize * 2)) - 4, + Game1.tileSize - 4), + Game1.viewport, false, 0, false, animal, false, false, false)) { - if (Game1.random.NextDouble() < 0.002 && building.animalDoorOpen && Game1.timeOfDay < 1630 && !Game1.isRaining && !Game1.currentSeason.Equals("winter") && building.indoors.getFarmers().Count() == 0 && !building.indoors.Equals(Game1.currentLocation)) + if (Game1.random.NextDouble() < 0.002 + && building.animalDoorOpen.Value + && Game1.timeOfDay < 1630 + && !Game1.isRaining + && !Game1.currentSeason.Equals("winter") + && building.indoors.Value.farmers.Count() == 0 + && !building.indoors.Equals(Game1.currentLocation)) { - if (isCollidingPosition(new Rectangle((building.tileX + building.animalDoor.X) * Game1.tileSize + 2, (building.tileY + building.animalDoor.Y) * Game1.tileSize + 2, (animal.isCoopDweller() ? Game1.tileSize : (Game1.tileSize * 2)) - 4, Game1.tileSize - 4), Game1.viewport, false, 0, false, animal, false, false, false) || isCollidingPosition(new Rectangle((building.tileX + building.animalDoor.X) * Game1.tileSize + 2, (building.tileY + building.animalDoor.Y + 1) * Game1.tileSize + 2, (animal.isCoopDweller() ? Game1.tileSize : (Game1.tileSize * 2)) - 4, Game1.tileSize - 4), Game1.viewport, false, 0, false, animal, false, false, false)) + if (isCollidingPosition(new Rectangle((building.tileX.Value + building.animalDoor.X) * Game1.tileSize + 2, (building.tileY.Value + building.animalDoor.Y) * Game1.tileSize + 2, (animal.isCoopDweller() ? Game1.tileSize : (Game1.tileSize * 2)) - 4, Game1.tileSize - 4), Game1.viewport, false, 0, false, animal, false, false, false) || isCollidingPosition(new Rectangle((building.tileX.Value + building.animalDoor.X) * Game1.tileSize + 2, (building.tileY.Value + building.animalDoor.Y + 1) * Game1.tileSize + 2, (animal.isCoopDweller() ? Game1.tileSize : (Game1.tileSize * 2)) - 4, Game1.tileSize - 4), Game1.viewport, false, 0, false, animal, false, false, false)) { break; } @@ -581,12 +519,12 @@ private void fixAnimalLocation() if (localBuildingAnimal.noWarpTimer <= 0) { localBuildingAnimal.noWarpTimer = 9000; - ((AnimalHouse)building.indoors).animals.Remove(localBuildingAnimal.myID); - building.currentOccupants--; - animals.Add(localBuildingAnimal.myID, localBuildingAnimal); + ((AnimalHouse)building.indoors.Value).animals.Remove(localBuildingAnimal.myID.Value); + building.currentOccupants.Value--; + animals.Add(localBuildingAnimal.myID.Value, localBuildingAnimal); localBuildingAnimal.faceDirection(2); localBuildingAnimal.SetMovingDown(true); - localBuildingAnimal.position = new Vector2(building.getRectForAnimalDoor().X, (building.tileY + building.animalDoor.Y) * Game1.tileSize - (localBuildingAnimal.sprite.getHeight() * Game1.pixelZoom - localBuildingAnimal.GetBoundingBox().Height) + Game1.tileSize / 2); + localBuildingAnimal.position.Value = new Vector2(building.getRectForAnimalDoor().X, (building.tileY.Value + building.animalDoor.Y) * Game1.tileSize - (localBuildingAnimal.Sprite.getHeight() * Game1.pixelZoom - localBuildingAnimal.GetBoundingBox().Height) + Game1.tileSize / 2); } } } @@ -601,11 +539,11 @@ private void fixAnimalLocation() Game1.playSound("dwoop"); } localAnimal.noWarpTimer = 3000; - localAnimal.home.currentOccupants++; - animals.Remove(localAnimal.myID); - ((AnimalHouse)localAnimal.home.indoors).animals.Add(localAnimal.myID, localAnimal); + localAnimal.home.currentOccupants.Value++; + animals.Remove(localAnimal.myID.Value); + ((AnimalHouse)localAnimal.home.indoors.Value).animals.Add(localAnimal.myID.Value, localAnimal); - localAnimal.setRandomPosition(localAnimal.home.indoors); + localAnimal.setRandomPosition(localAnimal.home.indoors.Value); localAnimal.faceDirection(Game1.random.Next(4)); localAnimal.controller = null; } @@ -620,18 +558,18 @@ internal void removeCarpenter() foreach (Building building in buildings) { npcsToRemove.Clear(); - if (building.indoors != null) + if (building.indoors.Value != null) { - foreach (NPC npc in building.indoors.characters) + foreach (NPC npc in building.indoors.Value.characters) { - if (npc.name.Equals("Robin")) + if (npc.Name.Equals("Robin")) { npcsToRemove.Add(npc); } } foreach (NPC carpenter in npcsToRemove) { - building.indoors.characters.Remove(carpenter); + building.indoors.Value.characters.Remove(carpenter); } } } @@ -647,7 +585,7 @@ private Crop findCloseFlower(Vector2 startTileLocation) while (num <= 150 && queue.Count > 0) { Vector2 vector = queue.Dequeue(); - if (this.terrainFeatures.ContainsKey(vector) && this.terrainFeatures[vector] is HoeDirt && (this.terrainFeatures[vector] as HoeDirt).crop != null && (this.terrainFeatures[vector] as HoeDirt).crop.programColored && (this.terrainFeatures[vector] as HoeDirt).crop.currentPhase >= (this.terrainFeatures[vector] as HoeDirt).crop.phaseDays.Count - 1 && !(this.terrainFeatures[vector] as HoeDirt).crop.dead) + if (this.terrainFeatures.ContainsKey(vector) && this.terrainFeatures[vector] is HoeDirt && (this.terrainFeatures[vector] as HoeDirt).crop != null && (this.terrainFeatures[vector] as HoeDirt).crop.programColored.Value && (this.terrainFeatures[vector] as HoeDirt).crop.currentPhase.Value >= (this.terrainFeatures[vector] as HoeDirt).crop.phaseDays.Count - 1 && !(this.terrainFeatures[vector] as HoeDirt).crop.dead.Value) { return (this.terrainFeatures[vector] as HoeDirt).crop; } diff --git a/FarmExpansion/FarmExpansion.csproj b/FarmExpansion/FarmExpansion.csproj index 7708737..b34873f 100644 --- a/FarmExpansion/FarmExpansion.csproj +++ b/FarmExpansion/FarmExpansion.csproj @@ -20,6 +20,7 @@ DEBUG;TRACE prompt 4 + x86 pdbonly @@ -28,7 +29,11 @@ TRACE prompt 4 + x86 + + + @@ -37,10 +42,12 @@ + + @@ -52,7 +59,6 @@ PreserveNewest - @@ -63,11 +69,4 @@ - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - \ No newline at end of file diff --git a/FarmExpansion/Framework/FEFramework.cs b/FarmExpansion/Framework/FEFramework.cs index 945da02..b2109c1 100644 --- a/FarmExpansion/Framework/FEFramework.cs +++ b/FarmExpansion/Framework/FEFramework.cs @@ -14,16 +14,19 @@ using StardewValley.Buildings; using StardewValley.Menus; using StardewValley.TerrainFeatures; -using Object = StardewValley.Object; using xTile; using xTile.Layers; using xTile.Tiles; +using Object = StardewValley.Object; using Rectangle = Microsoft.Xna.Framework.Rectangle; namespace FarmExpansion.Framework { public class FEFramework { + public event EventHandler BeforeRemoveEvent; + public event EventHandler AfterAppendEvent; + internal IModHelper helper; internal IMonitor monitor; @@ -94,120 +97,152 @@ internal void AddExpansionBluePrint(BluePrint blueprint) } }*/ - internal void ControlEvents_MouseChanged(object sender, EventArgsMouseStateChanged e) + internal void OnButtonPressed(object sender, ButtonPressedEventArgs e) { if (!overridableMenuActive) return; - menuOverride.performHoverAction(Game1.getMouseX(), Game1.getMouseY()); - - if (e.NewState.LeftButton == ButtonState.Pressed && e.PriorState.LeftButton != ButtonState.Pressed) + if (e.Button == SButton.MouseLeft) menuOverride.receiveLeftClick(Game1.getMouseX(), Game1.getMouseY(), false); } - internal void GraphicsEvents_OnPreRenderGuiEvent(object sender, EventArgs e) + internal void OnCursorMoved(object sender, CursorMovedEventArgs e) + { + if (!overridableMenuActive) + return; + + menuOverride.performHoverAction(Game1.getMouseX(), Game1.getMouseY()); + } + + /// When a menu is open ( isn't null), raised before that menu is drawn to the screen. + /// The event sender. + /// The event data. + internal void RenderingActiveMenu(object sender, EventArgs e) { menuOverride.draw(Game1.spriteBatch); } - internal void MenuEvents_MenuChanged(object sender, EventArgsClickableMenuChanged e) + /// Raised after a game menu is opened, closed, or replaced. + /// The event sender. + /// The event data. + internal void OnMenuChanged(object sender, MenuChangedEventArgs e) { - // Add farm expansion point to world map - if (e.NewMenu is GameMenu) + switch (e.NewMenu) { - MapPage mp = null; + // menu closed + case null: + if (e.OldMenu is NamingMenu) + { + foreach (Building building in farmExpansion.buildings) + Game1.getFarm().buildings.Remove(building); + } - foreach (IClickableMenu page in this.helper.Reflection.GetField>(Game1.activeClickableMenu, "pages").GetValue()) - { - if (!(page is MapPage)) - continue; - mp = page as MapPage; + if (IsTreeTransplantLoaded) + { + if (e.OldMenu.GetType().FullName.Equals("TreeTransplant.TreeTransplantMenu")) + { + helper.Events.Input.ButtonPressed -= this.OnButtonPressed; + helper.Events.Input.CursorMoved -= this.OnCursorMoved; + helper.Events.Display.RenderingActiveMenu -= this.RenderingActiveMenu; + overridableMenuActive = false; + menuOverride = null; + } + } break; - } - if (mp == null) - return; - int mapX = this.helper.Reflection.GetField(mp, "mapX").GetValue(); - int mapY = this.helper.Reflection.GetField(mp, "mapY").GetValue(); - Rectangle locationOnMap = new Rectangle(mapX + 156, mapY + 272, 100, 80); + // Add farm expansion point to world map + case GameMenu _: + { + MapPage mp = null; - mp.points.Add(new ClickableComponent(locationOnMap, "Farm Expansion")); + foreach (IClickableMenu page in this.helper.Reflection.GetField>(Game1.activeClickableMenu, "pages").GetValue()) + { + if (!(page is MapPage)) + continue; + mp = page as MapPage; + break; + } + if (mp == null) + return; - foreach (ClickableComponent cc in mp.points) - { - if (cc.myID != 1030) - continue; + int mapX = this.helper.Reflection.GetField(mp, "mapX").GetValue(); + int mapY = this.helper.Reflection.GetField(mp, "mapY").GetValue(); + Rectangle locationOnMap = new Rectangle(mapX + 156, mapY + 272, 100, 80); - cc.bounds.Width -= 64; - break; - } + mp.points.Add(new ClickableComponent(locationOnMap, "Farm Expansion")); - if (Game1.currentLocation == farmExpansion) - { - this.helper.Reflection.GetField(mp, "playerMapPosition").SetValue(new Vector2(mapX + 50 * Game1.pixelZoom, mapY + 75 * Game1.pixelZoom)); - this.helper.Reflection.GetField(mp, "playerLocationName").SetValue("Farm Expansion"); - } - return; - } - // Intercept carpenter menu - if (e.NewMenu is CarpenterMenu) - { - if (!this.helper.Reflection.GetField(e.NewMenu, "magicalConstruction").GetValue()) - Game1.activeClickableMenu = new FECarpenterMenu(this, this.FarmBlueprints.ToArray(), this.ExpansionBlueprints.ToArray()); // copy blueprint lists to avoid saving temporary blueprints - return; - } - // Intercept purchase animals menu - if (e.NewMenu is PurchaseAnimalsMenu) - { - Game1.activeClickableMenu = new FEPurchaseAnimalsMenu(this); - return; - } - // Fixes infinite loop when animals hatch on farm expansion - if (e.NewMenu is NamingMenu) - { - foreach (Building building in farmExpansion.buildings) - if (building.indoors != null && building.indoors == Game1.currentLocation) - Game1.getFarm().buildings.AddRange(farmExpansion.buildings); - return; - } - if (IsTreeTransplantLoaded) - if (e.NewMenu.GetType().FullName.Equals("TreeTransplant.TreeTransplantMenu")) - { - if (TreeTransplantFarmIcon == null) + foreach (ClickableComponent cc in mp.points) + { + if (cc.myID != 1030) + continue; + + cc.bounds.Width -= 64; + break; + } + + if (Game1.currentLocation == farmExpansion) + { + // may result in wrong map position, getPlayerMapPosition is complex 600-line method in SDV1.3 instead of just a + // simple Vector2 field to be assigned. But at glance everything seems to work allright even without this hack. + //this.helper.Reflection.GetField(mp, "playerMapPosition").SetValue(new Vector2(mapX + 50 * Game1.pixelZoom, mapY + 75 * Game1.pixelZoom)); + this.helper.Reflection.GetField(mp, "playerLocationName").SetValue("Farm Expansion"); + } + return; + } + + // Intercept carpenter menu + case CarpenterMenu _: + if (!this.helper.Reflection.GetField(e.NewMenu, "magicalConstruction").GetValue()) + Game1.activeClickableMenu = new FECarpenterMenu(this, this.FarmBlueprints.ToArray(), this.ExpansionBlueprints.ToArray()); // copy blueprint lists to avoid saving temporary blueprints + return; + + // Intercept purchase animals menu + case PurchaseAnimalsMenu _: + Game1.activeClickableMenu = new FEPurchaseAnimalsMenu(this); + return; + + // Fixes infinite loop when animals hatch on farm expansion + case NamingMenu _: + foreach (Building building in farmExpansion.buildings) { - try + if (building.indoors.Value != null && building.indoors.Value == Game1.currentLocation) { - this.TreeTransplantFarmIcon = this.helper.Content.Load(@"assets\TreeTransplantFarmIcon.png"); + foreach (var b in farmExpansion.buildings) + Game1.getFarm().buildings.Add(b); } - catch(Exception ex) + } + return; + + default: + if (IsTreeTransplantLoaded && e.NewMenu.GetType().FullName.Equals("TreeTransplant.TreeTransplantMenu")) + { + if (TreeTransplantFarmIcon == null) { - this.monitor.Log($"Could not load the menu icon for TreeTransplant compatibility.\n{ex}"); - return; + try + { + this.TreeTransplantFarmIcon = this.helper.Content.Load(@"assets\TreeTransplantFarmIcon.png"); + } + catch (Exception ex) + { + this.monitor.Log($"Could not load the menu icon for TreeTransplant compatibility.\n{ex}"); + return; + } } + menuOverride = new FETreeTransplantMenu(this, e.NewMenu); + overridableMenuActive = true; + helper.Events.Display.RenderingActiveMenu += this.RenderingActiveMenu; + helper.Events.Input.ButtonPressed += this.OnButtonPressed; + helper.Events.Input.CursorMoved += this.OnCursorMoved; } - menuOverride = new FETreeTransplantMenu(this, e.NewMenu); - overridableMenuActive = true; - GraphicsEvents.OnPreRenderGuiEvent += this.GraphicsEvents_OnPreRenderGuiEvent; - ControlEvents.MouseChanged += this.ControlEvents_MouseChanged; - } - } - internal void MenuEvents_MenuClosed(object sender, EventArgsClickableMenuClosed e) - { - if (e.PriorMenu is NamingMenu) - foreach (Building building in farmExpansion.buildings) - Game1.getFarm().buildings.Remove(building); - if (IsTreeTransplantLoaded) - if (e.PriorMenu.GetType().FullName.Equals("TreeTransplant.TreeTransplantMenu")) - { - ControlEvents.MouseChanged -= this.ControlEvents_MouseChanged; - GraphicsEvents.OnPreRenderGuiEvent -= this.GraphicsEvents_OnPreRenderGuiEvent; - overridableMenuActive = false; - menuOverride = null; - } + break; + } } - internal void SaveEvents_AfterLoad(object sender, EventArgs e) + /// Raised after the player loads a save slot and the world is initialised. + /// The event sender. + /// The event data. + internal void OnSaveLoaded(object sender, SaveLoadedEventArgs e) { try { @@ -217,13 +252,12 @@ internal void SaveEvents_AfterLoad(object sender, EventArgs e) catch (Exception ex) { //ControlEvents.KeyPressed -= this.ControlEvents_KeyPress; - MenuEvents.MenuChanged -= this.MenuEvents_MenuChanged; - MenuEvents.MenuClosed -= this.MenuEvents_MenuClosed; - SaveEvents.AfterLoad -= this.SaveEvents_AfterLoad; - SaveEvents.BeforeSave -= this.SaveEvents_BeforeSave; - SaveEvents.AfterSave -= this.SaveEvents_AfterSave; - SaveEvents.AfterReturnToTitle -= this.SaveEvents_AfterReturnToTitle; - TimeEvents.AfterDayStarted -= this.TimeEvents_AfterDayStarted; + helper.Events.Display.MenuChanged -= this.OnMenuChanged; + helper.Events.GameLoop.SaveLoaded -= this.OnSaveLoaded; + helper.Events.GameLoop.Saving -= this.OnSaving; + helper.Events.GameLoop.Saved -= this.OnSaved; + helper.Events.GameLoop.ReturnedToTitle -= this.OnReturnedToTitle; + helper.Events.GameLoop.DayStarted -= this.OnDayStarted; monitor.Log(ex.Message, LogLevel.Error); monitor.Log($"Unable to load map file 'FarmExpansion.tbin', unloading mod. Please try re-installing the mod.", LogLevel.Alert); @@ -234,8 +268,8 @@ internal void SaveEvents_AfterLoad(object sender, EventArgs e) { farmExpansion = new FarmExpansion(map, "FarmExpansion", this) { - isFarm = true, - isOutdoors = true + IsFarm = true, + IsOutdoors = true }; /*if (Game1.currentSeason.Equals("winter")) { @@ -261,39 +295,58 @@ internal void SaveEvents_AfterLoad(object sender, EventArgs e) } Game1.locations.Add(farmExpansion); + AfterAppendEvent?.Invoke(farmExpansion, EventArgs.Empty); PatchMap(); RepairBuildingWarps(); } - internal void SaveEvents_BeforeSave(object sender, EventArgs e) + /// Raised before the game begins writes data to the save file (except the initial save creation). + /// The event sender. + /// The event data. + internal void OnSaving(object sender, SavingEventArgs e) { Save(); + BeforeRemoveEvent?.Invoke(farmExpansion, EventArgs.Empty); Game1.locations.Remove(farmExpansion); } - internal void SaveEvents_AfterSave(object sender, EventArgs e) + /// Raised after the game finishes writing data to the save file (except the initial save creation). + /// The event sender. + /// The event data. + internal void OnSaved(object sender, SavedEventArgs e) { Game1.locations.Add(farmExpansion); + AfterAppendEvent?.Invoke(farmExpansion, EventArgs.Empty); } - internal void SaveEvents_AfterReturnToTitle(object sender, EventArgs e) + /// Raised after the game returns to the title screen. + /// The event sender. + /// The event data. + internal void OnReturnedToTitle(object sender, ReturnedToTitleEventArgs e) { farmExpansion = null; map = null; } - internal void TimeEvents_AfterDayStarted(object sender, EventArgs e) + /// Raised after the game begins a new day (including when the player loads a save). + /// The event sender. + /// The event data. + internal void OnDayStarted(object sender, DayStartedEventArgs e) { if (Game1.isRaining) - foreach (KeyValuePair pair in farmExpansion.terrainFeatures) - if (pair.Value != null && pair.Value is HoeDirt) - ((HoeDirt)pair.Value).state = 1; + { + foreach (var feature in farmExpansion.terrainFeatures.Values) + { + if (feature is HoeDirt dirt) + dirt.state.Value = 1; + } + } foreach (Building current in farmExpansion.buildings) - if (current.indoors != null) - for (int k = current.indoors.objects.Count - 1; k >= 0; k--) - if (current.indoors.objects[current.indoors.objects.Keys.ElementAt(k)].minutesElapsed(3000 - Game1.timeOfDay, current.indoors)) - current.indoors.objects.Remove(current.indoors.objects.Keys.ElementAt(k)); + if (current.indoors.Value != null) + for (int k = current.indoors.Value.objects.Count() - 1; k >= 0; k--) + if (current.indoors.Value.objects[current.indoors.Value.objects.Keys.ElementAt(k)].minutesElapsed(3000 - Game1.timeOfDay, current.indoors.Value)) + current.indoors.Value.objects.Remove(current.indoors.Value.objects.Keys.ElementAt(k)); if (Game1.player.currentUpgrade != null) if (farmExpansion.objects.ContainsKey(new Vector2(Game1.player.currentUpgrade.positionOfCarpenter.X / Game1.tileSize, Game1.player.currentUpgrade.positionOfCarpenter.Y / Game1.tileSize))) @@ -311,12 +364,11 @@ internal void TimeEvents_AfterDayStarted(object sender, EventArgs e) foreach (NPC npc in location.characters) { - if (!npc.name.Equals("Robin")) + if (!npc.Name.Equals("Robin")) continue; robin = npc; - npc.ignoreMultiplayerUpdates = true; - npc.sprite.setCurrentAnimation(new List + npc.Sprite.setCurrentAnimation(new List { new FarmerSprite.AnimationFrame(24, 75), new FarmerSprite.AnimationFrame(25, 75), @@ -325,20 +377,26 @@ internal void TimeEvents_AfterDayStarted(object sender, EventArgs e) }); npc.ignoreScheduleToday = true; Building buildingUnderConstruction = farmExpansion.getBuildingUnderConstruction(); - if (buildingUnderConstruction.daysUntilUpgrade > 0) + if (buildingUnderConstruction.daysUntilUpgrade.Value > 0) { - if (!buildingUnderConstruction.indoors.characters.Contains(npc)) - buildingUnderConstruction.indoors.addCharacter(npc); + if (!buildingUnderConstruction.indoors.Value.characters.Contains(npc)) + buildingUnderConstruction.indoors.Value.addCharacter(npc); if (npc.currentLocation != null) npc.currentLocation.characters.Remove(npc); - npc.currentLocation = buildingUnderConstruction.indoors; + npc.currentLocation = buildingUnderConstruction.indoors.Value; npc.setTilePosition(1, 5); } else { - Game1.warpCharacter(npc, "FarmExpansion", new Vector2(buildingUnderConstruction.tileX + buildingUnderConstruction.tilesWide / 2, buildingUnderConstruction.tileY + buildingUnderConstruction.tilesHigh / 2), false, false); + Game1.warpCharacter( + npc, + "FarmExpansion", + new Vector2( + buildingUnderConstruction.tileX.Value + buildingUnderConstruction.tilesWide.Value / 2, + buildingUnderConstruction.tileY.Value + buildingUnderConstruction.tilesHigh.Value / 2 + )); npc.position.X = npc.position.X + Game1.tileSize / 4; npc.position.Y = npc.position.Y - Game1.tileSize / 2; } @@ -374,8 +432,8 @@ private void Load() { farmExpansion = new FarmExpansion(map, "FarmExpansion", this) { - isFarm = true, - isOutdoors = true + IsFarm = true, + IsOutdoors = true }; string path = Path.Combine(helper.DirectoryPath, "pslocationdata", $"{Constants.SaveFolderName}.xml"); @@ -387,33 +445,32 @@ private void Load() } //monitor.Log($"Object deserialized from {path}"); - farmExpansion.animals = loaded.animals; - farmExpansion.buildings = loaded.buildings; - farmExpansion.characters = loaded.characters; - farmExpansion.terrainFeatures = loaded.terrainFeatures; - farmExpansion.largeTerrainFeatures = loaded.largeTerrainFeatures; - farmExpansion.resourceClumps = loaded.resourceClumps; - farmExpansion.objects = loaded.objects; + farmExpansion.animals.CopyFrom(loaded.animals.Pairs); + farmExpansion.characters.ReplaceWith(loaded.characters); + farmExpansion.terrainFeatures.ReplaceWith(loaded.terrainFeatures); + farmExpansion.largeTerrainFeatures.ReplaceWith(loaded.largeTerrainFeatures); + farmExpansion.resourceClumps.ReplaceWith(loaded.resourceClumps); + farmExpansion.objects.ReplaceWith(loaded.objects); farmExpansion.numberOfSpawnedObjectsOnMap = loaded.numberOfSpawnedObjectsOnMap; - farmExpansion.piecesOfHay = loaded.piecesOfHay; + farmExpansion.piecesOfHay.Value = loaded.piecesOfHay.Value; //farmExpansion.hasSeenGrandpaNote = loaded.hasSeenGrandpaNote; //farmExpansion.grandpaScore = loaded.grandpaScore; - foreach (KeyValuePair animal in farmExpansion.animals) - animal.Value.reload(); + foreach (KeyValuePair animal in farmExpansion.animals.Pairs) + animal.Value.reload(null); foreach (Building building in farmExpansion.buildings) { building.load(); - if (building.indoors != null && building.indoors is AnimalHouse) + if (building.indoors.Value != null && building.indoors.Value is AnimalHouse) { - foreach (KeyValuePair animalsInBuilding in ((AnimalHouse)building.indoors).animals) + foreach (KeyValuePair animalsInBuilding in ((AnimalHouse)building.indoors.Value).animals.Pairs) { FarmAnimal animal = animalsInBuilding.Value; foreach (Building current in farmExpansion.buildings) { - if (current.tileX == (int)animal.homeLocation.X && current.tileY == (int)animal.homeLocation.Y) + if (current.tileX.Value == (int)animal.homeLocation.X && current.tileY.Value == (int)animal.homeLocation.Y) { animal.home = current; break; @@ -425,7 +482,7 @@ private void Load() for (int i = farmExpansion.characters.Count - 1; i >= 0; i--) { if (!farmExpansion.characters[i].DefaultPosition.Equals(Vector2.Zero)) - farmExpansion.characters[i].position = farmExpansion.characters[i].DefaultPosition; + farmExpansion.characters[i].position.Value = farmExpansion.characters[i].DefaultPosition; farmExpansion.characters[i].currentLocation = farmExpansion; @@ -433,23 +490,23 @@ private void Load() farmExpansion.characters[i].reloadSprite(); } - foreach (KeyValuePair terrainFeature in farmExpansion.terrainFeatures) + foreach (KeyValuePair terrainFeature in farmExpansion.terrainFeatures.Pairs) terrainFeature.Value.loadSprite(); - foreach (KeyValuePair current in farmExpansion.objects) + foreach (KeyValuePair current in farmExpansion.objects.Pairs) { current.Value.initializeLightSource(current.Key); current.Value.reloadSprite(); } foreach (Building building in farmExpansion.buildings) { - Vector2 tile = new Vector2((float)building.tileX, (float)building.tileY); + Vector2 tile = new Vector2((float)building.tileX.Value, (float)building.tileY.Value); - if (building.indoors is Shed) + if (building.indoors.Value is Shed) { - (building.indoors as Shed).furniture = (loaded.getBuildingAt(tile).indoors as Shed).furniture; - (building.indoors as Shed).wallPaper = (loaded.getBuildingAt(tile).indoors as Shed).wallPaper; - (building.indoors as Shed).floor = (loaded.getBuildingAt(tile).indoors as Shed).floor; + (building.indoors.Value as Shed).furniture.ReplaceWith((loaded.getBuildingAt(tile).indoors.Value as Shed).furniture); + (building.indoors.Value as Shed).wallPaper.Set((loaded.getBuildingAt(tile).indoors.Value as Shed).wallPaper); + (building.indoors.Value as Shed).floor.Set((loaded.getBuildingAt(tile).indoors.Value as Shed).floor); } } } @@ -458,15 +515,15 @@ private void RepairBuildingWarps() { foreach (Building building in farmExpansion.buildings) { - if (building.indoors != null) + if (building.indoors.Value != null) { List warps = new List(); - foreach (Warp warp in building.indoors.warps) + foreach (Warp warp in building.indoors.Value.warps) { - warps.Add(new Warp(warp.X, warp.Y, "FarmExpansion", building.humanDoor.X + building.tileX, building.humanDoor.Y + building.tileY + 1, false)); + warps.Add(new Warp(warp.X, warp.Y, "FarmExpansion", building.humanDoor.X + building.tileX.Value, building.humanDoor.Y + building.tileY.Value + 1, false)); } - building.indoors.warps.Clear(); - building.indoors.warps.AddRange(warps); + building.indoors.Value.warps.Clear(); + building.indoors.Value.warps.AddRange(warps); } } } @@ -743,15 +800,15 @@ private void robinVariablePause(StardewValley.Farmer who) { if (Game1.random.NextDouble() < 0.4) { - robin.sprite.currentAnimation[robin.sprite.currentAnimationIndex] = new FarmerSprite.AnimationFrame(27, 300, false, false, new AnimatedSprite.endOfAnimationBehavior(robinVariablePause), false); + robin.Sprite.currentAnimation[robin.Sprite.currentAnimationIndex] = new FarmerSprite.AnimationFrame(27, 300, false, false, new AnimatedSprite.endOfAnimationBehavior(robinVariablePause), false); return; } if (Game1.random.NextDouble() < 0.25) { - robin.sprite.currentAnimation[robin.sprite.currentAnimationIndex] = new FarmerSprite.AnimationFrame(23, Game1.random.Next(500, 4000), false, false, new AnimatedSprite.endOfAnimationBehavior(robinVariablePause), false); + robin.Sprite.currentAnimation[robin.Sprite.currentAnimationIndex] = new FarmerSprite.AnimationFrame(23, Game1.random.Next(500, 4000), false, false, new AnimatedSprite.endOfAnimationBehavior(robinVariablePause), false); return; } - robin.sprite.currentAnimation[robin.sprite.currentAnimationIndex] = new FarmerSprite.AnimationFrame(27, Game1.random.Next(1000, 4000), false, false, new AnimatedSprite.endOfAnimationBehavior(robinVariablePause), false); + robin.Sprite.currentAnimation[robin.Sprite.currentAnimationIndex] = new FarmerSprite.AnimationFrame(27, Game1.random.Next(1000, 4000), false, false, new AnimatedSprite.endOfAnimationBehavior(robinVariablePause), false); } internal Farm swapFarm(Farm currentFarm) @@ -764,4 +821,4 @@ internal bool expansionSelected(string currentFarmName) return currentFarmName.Equals("FarmExpansion"); } } -} \ No newline at end of file +} diff --git a/FarmExpansion/Framework/IBetterFarmAnimalVarietyApi.cs b/FarmExpansion/Framework/IBetterFarmAnimalVarietyApi.cs new file mode 100644 index 0000000..82560c9 --- /dev/null +++ b/FarmExpansion/Framework/IBetterFarmAnimalVarietyApi.cs @@ -0,0 +1,20 @@ +using Microsoft.Xna.Framework.Graphics; +using System.Collections.Generic; + +namespace FarmExpansion.Framework +{ + public interface IBetterFarmAnimalVarietyApi + { + /// StardewValley.Farm + /// Returns List + List GetAnimalShopStock(StardewValley.Farm farm); + + /// Determine if the mod is enabled. + Dictionary GetAnimalShopIcons(); + + /// string + /// StardewValley.Farmer + /// Returns string + string GetRandomAnimalShopType(string category, StardewValley.Farmer farmer); + } +} diff --git a/FarmExpansion/Framework/IModApi.cs b/FarmExpansion/Framework/IModApi.cs index 1b0aabd..d96a98f 100644 --- a/FarmExpansion/Framework/IModApi.cs +++ b/FarmExpansion/Framework/IModApi.cs @@ -1,4 +1,5 @@ -using StardewValley; +using System; +using StardewValley; namespace FarmExpansion.Framework { @@ -12,5 +13,17 @@ public interface IModApi /// Add a blueprint to all future carpenter menus for the expansion area. /// The blueprint to add. void AddExpansionBluePrint(BluePrint blueprint); + + /// + /// Mod removes itself from game world in BeforeSave and handles saving separately. + /// Hook this if you need to do some fixup to contained stuff (FurnitureAnywhere, Tractor etc). + /// + /// + void AddRemoveListener(EventHandler handler); + + /// + /// Second half for AddRemoveListener + /// + void AddAppendListener(EventHandler handler); } } \ No newline at end of file diff --git a/FarmExpansion/Framework/ModApi.cs b/FarmExpansion/Framework/ModApi.cs index 3a06d9a..29f52f1 100644 --- a/FarmExpansion/Framework/ModApi.cs +++ b/FarmExpansion/Framework/ModApi.cs @@ -1,4 +1,5 @@ -using StardewValley; +using System; +using StardewValley; namespace FarmExpansion.Framework { @@ -35,5 +36,15 @@ public void AddExpansionBluePrint(BluePrint blueprint) { this.Framework.ExpansionBlueprints.Add(blueprint); } + + public void AddRemoveListener(EventHandler handler) + { + Framework.BeforeRemoveEvent += handler; + } + + public void AddAppendListener(EventHandler handler) + { + Framework.AfterAppendEvent += handler; + } } } diff --git a/FarmExpansion/Helpers.cs b/FarmExpansion/Helpers.cs new file mode 100644 index 0000000..12a56a4 --- /dev/null +++ b/FarmExpansion/Helpers.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Netcode; +using StardewValley; +using StardewValley.Network; + +namespace FarmExpansion +{ + static class Helpers + { + public static void ReplaceWith(this NetVector2Dictionary collection, NetVector2Dictionary source) + where TField : NetField, new() + { + collection.Clear(); + foreach (var kvp in source.Pairs) + { + collection.Add(kvp.Key, kvp.Value); + } + } + + public static void ReplaceWith(this OverlaidDictionary collection, OverlaidDictionary source) + { + collection.Clear(); + foreach (var kvp in source.Pairs) + { + collection.Add(kvp.Key, kvp.Value); + } + } + + public static void ReplaceWith(this Netcode.NetCollection collection, Netcode.NetCollection source) + where T : class, Netcode.INetObject + { + collection.Clear(); + foreach (var item in source) + { + collection.Add(item); + } + } + } +} diff --git a/FarmExpansion/Menus/FECarpenterMenu.cs b/FarmExpansion/Menus/FECarpenterMenu.cs index 89f7f21..22f8cee 100644 --- a/FarmExpansion/Menus/FECarpenterMenu.cs +++ b/FarmExpansion/Menus/FECarpenterMenu.cs @@ -314,7 +314,7 @@ public override void performHoverAction(int x, int y) { foreach (Building current in currentFarm.buildings) { - current.color = Color.White; + current.color.Value = Color.White; } Building buildingAt = currentFarm.getBuildingAt(new Vector2((float)((Game1.viewport.X + Game1.getOldMouseX()) / Game1.tileSize), (float)((Game1.viewport.Y + Game1.getOldMouseY()) / Game1.tileSize))); if (buildingAt == null) @@ -327,14 +327,14 @@ public override void performHoverAction(int x, int y) } if (this.upgrading) { - if (buildingAt != null && this.CurrentBlueprint.nameOfBuildingToUpgrade != null && this.CurrentBlueprint.nameOfBuildingToUpgrade.Equals(buildingAt.buildingType)) + if (buildingAt != null && this.CurrentBlueprint.nameOfBuildingToUpgrade != null && this.CurrentBlueprint.nameOfBuildingToUpgrade.Equals(buildingAt.buildingType.Value)) { - buildingAt.color = Color.Lime * 0.8f; + buildingAt.color.Value = Color.Lime * 0.8f; return; } if (buildingAt != null) { - buildingAt.color = Color.Red * 0.8f; + buildingAt.color.Value = Color.Red * 0.8f; return; } } @@ -342,13 +342,13 @@ public override void performHoverAction(int x, int y) { if (buildingAt != null) { - buildingAt.color = Color.Red * 0.8f; + buildingAt.color.Value = Color.Red * 0.8f; return; } } else if (this.moving && buildingAt != null) { - buildingAt.color = Color.Lime * 0.8f; + buildingAt.color.Value = Color.Lime * 0.8f; } } return; @@ -595,20 +595,20 @@ public override void receiveLeftClick(int x, int y, bool playSound = true) if (this.demolishing) { Building buildingAt = currentFarm.getBuildingAt(new Vector2((float)((Game1.viewport.X + Game1.getOldMouseX()) / Game1.tileSize), (float)((Game1.viewport.Y + Game1.getOldMouseY()) / Game1.tileSize))); - if (buildingAt != null && (buildingAt.daysOfConstructionLeft > 0 || buildingAt.daysUntilUpgrade > 0)) + if (buildingAt != null && (buildingAt.daysOfConstructionLeft.Value > 0 || buildingAt.daysUntilUpgrade.Value > 0)) { Game1.addHUDMessage(new HUDMessage(Game1.content.LoadString("Strings\\UI:Carpenter_CantDemolish_DuringConstruction", new object[0]), Color.Red, 3500f)); return; } - if (buildingAt != null && buildingAt.indoors != null && buildingAt.indoors is AnimalHouse && (buildingAt.indoors as AnimalHouse).animalsThatLiveHere.Count > 0) + if (buildingAt != null && buildingAt.indoors.Value != null && buildingAt.indoors.Value is AnimalHouse && (buildingAt.indoors.Value as AnimalHouse).animalsThatLiveHere.Count > 0) { Game1.addHUDMessage(new HUDMessage(Game1.content.LoadString("Strings\\UI:Carpenter_CantDemolish_AnimalsHere", new object[0]), Color.Red, 3500f)); return; } if (buildingAt != null && currentFarm.destroyStructure(buildingAt)) { - int arg_366_0 = buildingAt.tileY; - int arg_36D_0 = buildingAt.tilesHigh; + int arg_366_0 = buildingAt.tileY.Value; + int arg_36D_0 = buildingAt.tilesHigh.Value; Game1.flashAlpha = 1f; buildingAt.showDestroyedAnimation(currentFarm); Game1.playSound("explosion"); @@ -624,7 +624,7 @@ public override void receiveLeftClick(int x, int y, bool playSound = true) if (buildingAt2 != null && this.CurrentBlueprint.name != null && buildingAt2.buildingType.Equals(this.CurrentBlueprint.nameOfBuildingToUpgrade)) { this.CurrentBlueprint.consumeResources(); - buildingAt2.daysUntilUpgrade = 2; + buildingAt2.daysUntilUpgrade.Value = 2; buildingAt2.showUpgradeAnimation(currentFarm); Game1.playSound("axe"); DelayedAction.fadeAfterDelay(new Game1.afterFadeFunction(this.returnToCarpentryMenuAfterSuccessfulBuild), 1500); @@ -644,7 +644,7 @@ public override void receiveLeftClick(int x, int y, bool playSound = true) this.buildingToMove = currentFarm.getBuildingAt(new Vector2((float)((Game1.viewport.X + Game1.getMouseX()) / Game1.tileSize), (float)((Game1.viewport.Y + Game1.getMouseY()) / Game1.tileSize))); if (this.buildingToMove != null) { - if (this.buildingToMove.daysOfConstructionLeft > 0) + if (this.buildingToMove.daysOfConstructionLeft.Value > 0) { this.buildingToMove = null; return; @@ -654,7 +654,10 @@ public override void receiveLeftClick(int x, int y, bool playSound = true) } return; } - if (currentFarm.buildStructure(this.buildingToMove, new Vector2((float)((Game1.viewport.X + Game1.getMouseX()) / Game1.tileSize), (float)((Game1.viewport.Y + Game1.getMouseY()) / Game1.tileSize)), false, Game1.player)) + if (currentFarm.buildStructure( + this.buildingToMove, + new Vector2((float)((Game1.viewport.X + Game1.getMouseX()) / Game1.tileSize), (float)((Game1.viewport.Y + Game1.getMouseY()) / Game1.tileSize)), + Game1.player, false)) { this.buildingToMove = null; Game1.playSound("axchop"); @@ -681,7 +684,10 @@ public override void receiveLeftClick(int x, int y, bool playSound = true) public bool tryToBuild() { - return currentFarm.buildStructure(this.CurrentBlueprint, new Vector2((float)((Game1.viewport.X + Game1.getOldMouseX()) / Game1.tileSize), (float)((Game1.viewport.Y + Game1.getOldMouseY()) / Game1.tileSize)), false, Game1.player, /*this.magicalConstruction*/false); + return currentFarm.buildStructure( + this.CurrentBlueprint, + new Vector2((float)((Game1.viewport.X + Game1.getOldMouseX()) / Game1.tileSize), (float)((Game1.viewport.Y + Game1.getOldMouseY()) / Game1.tileSize)), + Game1.player, magicalConstruction: false, skipSafetyChecks: false); } public void returnToCarpentryMenu() @@ -794,7 +800,7 @@ public override void draw(SpriteBatch b) { base.draw(b); IClickableMenu.drawTextureBox(b, this.xPositionOnScreen - Game1.tileSize * 3 / 2, this.yPositionOnScreen - Game1.tileSize / 4, this.maxWidthOfBuildingViewer + Game1.tileSize, this.maxHeightOfBuildingViewer + Game1.tileSize, /*this.magicalConstruction ? Color.RoyalBlue : */Color.White); - this.currentBuilding.drawInMenu(b, this.xPositionOnScreen + this.maxWidthOfBuildingViewer / 2 - this.currentBuilding.tilesWide * Game1.tileSize / 2 - Game1.tileSize, this.yPositionOnScreen + this.maxHeightOfBuildingViewer / 2 - this.currentBuilding.getSourceRectForMenu().Height * Game1.pixelZoom / 2); + this.currentBuilding.drawInMenu(b, this.xPositionOnScreen + this.maxWidthOfBuildingViewer / 2 - this.currentBuilding.tilesWide.Value * Game1.tileSize / 2 - Game1.tileSize, this.yPositionOnScreen + this.maxHeightOfBuildingViewer / 2 - this.currentBuilding.getSourceRectForMenu().Height * Game1.pixelZoom / 2); if (this.CurrentBlueprint.isUpgrade()) { this.upgradeIcon.draw(b); @@ -832,7 +838,7 @@ public override void draw(SpriteBatch b) { vector.Y += (float)(Game1.tileSize + Game1.pixelZoom); current.drawInMenu(b, vector, 1f); - bool flag = !(current is Object) || Game1.player.hasItemInInventory((current as Object).parentSheetIndex, current.Stack, 0); + bool flag = !(current is Object) || Game1.player.hasItemInInventory((current as Object).ParentSheetIndex, current.Stack, 0); /*if (this.magicalConstruction) { Utility.drawTextWithShadow(b, current.DisplayName, Game1.dialogueFont, new Vector2(vector.X + (float)Game1.tileSize + (float)(Game1.pixelZoom * 3), vector.Y + (float)(Game1.pixelZoom * 6)), Game1.textColor * 0.25f, 1f, -1f, -1, -1, this.magicalConstruction ? 0f : 0.25f, 3); @@ -875,9 +881,9 @@ public override void draw(SpriteBatch b) else if (this.moving && this.buildingToMove != null) { Vector2 vector4 = new Vector2((float)((Game1.viewport.X + Game1.getOldMouseX()) / Game1.tileSize), (float)((Game1.viewport.Y + Game1.getOldMouseY()) / Game1.tileSize)); - for (int k = 0; k < this.buildingToMove.tilesHigh; k++) + for (int k = 0; k < this.buildingToMove.tilesHigh.Value; k++) { - for (int l = 0; l < this.buildingToMove.tilesWide; l++) + for (int l = 0; l < this.buildingToMove.tilesWide.Value; l++) { int num2 = this.buildingToMove.getTileSheetIndexForStructurePlacementTile(l, k); Vector2 vector5 = new Vector2(vector4.X + (float)l, vector4.Y + (float)k); diff --git a/FarmExpansion/Menus/FEPurchaseAnimalsMenu.cs b/FarmExpansion/Menus/FEPurchaseAnimalsMenu.cs index 765b21c..4d68834 100644 --- a/FarmExpansion/Menus/FEPurchaseAnimalsMenu.cs +++ b/FarmExpansion/Menus/FEPurchaseAnimalsMenu.cs @@ -131,70 +131,115 @@ private void resetBounds() private void populateAnimalStock() { this.animalsToPurchase.Clear(); + List stock = this.getPurchaseAnimalStock(); + + // Integrate with Better Farm Animal Variety (BFAV) >= 3.x + IBetterFarmAnimalVarietyApi api = framework.helper.ModRegistry.GetApi("Paritee.BetterFarmAnimalVariety"); + Dictionary icons = api?.GetAnimalShopIcons(); + int iconHeight = 0; + for (int i = 0; i < stock.Count; i++) { - this.animalsToPurchase.Add(new ClickableTextureComponent(string.Concat(stock[i].salePrice()), new Microsoft.Xna.Framework.Rectangle(this.xPositionOnScreen + IClickableMenu.borderWidth + i % 3 * Game1.tileSize * 2, this.yPositionOnScreen + IClickableMenu.spaceToClearTopBorder + IClickableMenu.borderWidth / 2 + i / 3 * (Game1.tileSize + Game1.tileSize / 3), Game1.tileSize * 2, Game1.tileSize), null, stock[i].Name, Game1.mouseCursors, new Microsoft.Xna.Framework.Rectangle(i % 3 * 16 * 2, 448 + i / 3 * 16, 32, 16), 4f, stock[i].type == null) + Texture2D texture; + Microsoft.Xna.Framework.Rectangle sourceRect; + Object obj = stock[i]; + + if (icons != null) + { + texture = icons[obj.Name]; + sourceRect = new Microsoft.Xna.Framework.Rectangle(0, 0, texture.Width, texture.Height); + iconHeight = textBox.Height > iconHeight ? textBox.Height : iconHeight; + } + else + { + texture = Game1.mouseCursors; + sourceRect = new Microsoft.Xna.Framework.Rectangle(i % 3 * 16 * 2, 448 + i / 3 * 16, 32, 16); + } + + string name = obj.salePrice().ToString(); + string label = null; + string hoverText = obj.Name; + Microsoft.Xna.Framework.Rectangle bounds = new Microsoft.Xna.Framework.Rectangle(this.xPositionOnScreen + IClickableMenu.borderWidth + i % 3 * 64 * 2, this.yPositionOnScreen + IClickableMenu.spaceToClearTopBorder + IClickableMenu.borderWidth / 2 + i / 3 * 85, 128, 64); + float scale = 4f; + bool drawShadow = obj.Type == null; + + this.animalsToPurchase.Add(new ClickableTextureComponent(name, bounds, label, hoverText, texture, sourceRect, scale, drawShadow) { - item = stock[i], + item = obj, myID = i, - rightNeighborID = ((i % 3 == 2) ? -1 : (i + 1)), - leftNeighborID = ((i % 3 == 0) ? -1 : (i - 1)), + rightNeighborID = i % 3 == 2 ? -1 : i + 1, + leftNeighborID = i % 3 == 0 ? -1 : i - 1, downNeighborID = i + 3, upNeighborID = i - 3 }); } + + // Adjust the size of the menu if there are more or less rows than it normally handles + if (iconHeight > 0) + { + int rows = (int)Math.Ceiling((float)this.animalsToPurchase.Count / 3); // Always at least one row + this.height = (int)(iconHeight * 2f) + IClickableMenu.spaceToClearTopBorder + IClickableMenu.borderWidth / 2 + rows * 85; + } } private List getPurchaseAnimalStock() { + // Integrate with Better Farm Animal Variety (BFAV) >= 3.x + IBetterFarmAnimalVarietyApi api = framework.helper.ModRegistry.GetApi("Paritee.BetterFarmAnimalVariety"); + + if (api != null) + { + return api.GetAnimalShopStock(currentFarm); + } + List list = new List(); Object item = new Object(100, 1, false, 400, 0) { name = "Chicken", - type = ((currentFarm.isBuildingConstructed("Coop") || currentFarm.isBuildingConstructed("Deluxe Coop") || currentFarm.isBuildingConstructed("Big Coop")) ? null : Game1.content.LoadString("Strings\\StringsFromCSFiles:Utility.cs.5926", new object[0])), + Type = ((currentFarm.isBuildingConstructed("Coop") || currentFarm.isBuildingConstructed("Deluxe Coop") || currentFarm.isBuildingConstructed("Big Coop")) ? null : Game1.content.LoadString("Strings\\StringsFromCSFiles:Utility.cs.5926", new object[0])), displayName = Game1.content.LoadString("Strings\\StringsFromCSFiles:Utility.cs.5922", new object[0]) }; list.Add(item); item = new Object(100, 1, false, 750, 0) { name = "Dairy Cow", - type = ((currentFarm.isBuildingConstructed("Barn") || currentFarm.isBuildingConstructed("Deluxe Barn") || currentFarm.isBuildingConstructed("Big Barn")) ? null : Game1.content.LoadString("Strings\\StringsFromCSFiles:Utility.cs.5931", new object[0])), + Type = ((currentFarm.isBuildingConstructed("Barn") || currentFarm.isBuildingConstructed("Deluxe Barn") || currentFarm.isBuildingConstructed("Big Barn")) ? null : Game1.content.LoadString("Strings\\StringsFromCSFiles:Utility.cs.5931", new object[0])), displayName = Game1.content.LoadString("Strings\\StringsFromCSFiles:Utility.cs.5927", new object[0]) }; list.Add(item); item = new Object(100, 1, false, 2000, 0) { name = "Goat", - type = ((currentFarm.isBuildingConstructed("Big Barn") || currentFarm.isBuildingConstructed("Deluxe Barn")) ? null : Game1.content.LoadString("Strings\\StringsFromCSFiles:Utility.cs.5936", new object[0])), + Type = ((currentFarm.isBuildingConstructed("Big Barn") || currentFarm.isBuildingConstructed("Deluxe Barn")) ? null : Game1.content.LoadString("Strings\\StringsFromCSFiles:Utility.cs.5936", new object[0])), displayName = Game1.content.LoadString("Strings\\StringsFromCSFiles:Utility.cs.5933", new object[0]) }; list.Add(item); item = new Object(100, 1, false, 2000, 0) { name = "Duck", - type = ((currentFarm.isBuildingConstructed("Big Coop") || currentFarm.isBuildingConstructed("Deluxe Coop")) ? null : Game1.content.LoadString("Strings\\StringsFromCSFiles:Utility.cs.5940", new object[0])), + Type = ((currentFarm.isBuildingConstructed("Big Coop") || currentFarm.isBuildingConstructed("Deluxe Coop")) ? null : Game1.content.LoadString("Strings\\StringsFromCSFiles:Utility.cs.5940", new object[0])), displayName = Game1.content.LoadString("Strings\\StringsFromCSFiles:Utility.cs.5937", new object[0]) }; list.Add(item); item = new Object(100, 1, false, 4000, 0) { name = "Sheep", - type = (currentFarm.isBuildingConstructed("Deluxe Barn") ? null : Game1.content.LoadString("Strings\\StringsFromCSFiles:Utility.cs.5944", new object[0])), + Type = (currentFarm.isBuildingConstructed("Deluxe Barn") ? null : Game1.content.LoadString("Strings\\StringsFromCSFiles:Utility.cs.5944", new object[0])), displayName = Game1.content.LoadString("Strings\\StringsFromCSFiles:Utility.cs.5942", new object[0]) }; list.Add(item); item = new Object(100, 1, false, 4000, 0) { name = "Rabbit", - type = (currentFarm.isBuildingConstructed("Deluxe Coop") ? null : Game1.content.LoadString("Strings\\StringsFromCSFiles:Utility.cs.5947", new object[0])), + Type = (currentFarm.isBuildingConstructed("Deluxe Coop") ? null : Game1.content.LoadString("Strings\\StringsFromCSFiles:Utility.cs.5947", new object[0])), displayName = Game1.content.LoadString("Strings\\StringsFromCSFiles:Utility.cs.5945", new object[0]) }; list.Add(item); item = new Object(100, 1, false, 8000, 0) { name = "Pig", - type = (currentFarm.isBuildingConstructed("Deluxe Barn") ? null : Game1.content.LoadString("Strings\\StringsFromCSFiles:Utility.cs.5950", new object[0])), + Type = (currentFarm.isBuildingConstructed("Deluxe Barn") ? null : Game1.content.LoadString("Strings\\StringsFromCSFiles:Utility.cs.5950", new object[0])), displayName = Game1.content.LoadString("Strings\\StringsFromCSFiles:Utility.cs.5948", new object[0]) }; list.Add(item); @@ -226,13 +271,13 @@ public void textBoxEnter(TextBox sender) return; } this.textBox.OnEnterPressed -= this.e; - this.animalBeingPurchased.name = sender.Text; + this.animalBeingPurchased.Name = sender.Text; this.animalBeingPurchased.displayName = sender.Text; this.animalBeingPurchased.home = this.newAnimalHome; - this.animalBeingPurchased.homeLocation = new Vector2((float)this.newAnimalHome.tileX, (float)this.newAnimalHome.tileY); - this.animalBeingPurchased.setRandomPosition(this.animalBeingPurchased.home.indoors); - (this.newAnimalHome.indoors as AnimalHouse).animals.Add(this.animalBeingPurchased.myID, this.animalBeingPurchased); - (this.newAnimalHome.indoors as AnimalHouse).animalsThatLiveHere.Add(this.animalBeingPurchased.myID); + this.animalBeingPurchased.homeLocation.Value = new Vector2((float)this.newAnimalHome.tileX.Value, (float)this.newAnimalHome.tileY.Value); + this.animalBeingPurchased.setRandomPosition(this.animalBeingPurchased.home.indoors.Value); + (this.newAnimalHome.indoors.Value as AnimalHouse).animals.Add(this.animalBeingPurchased.myID.Value, this.animalBeingPurchased); + (this.newAnimalHome.indoors.Value as AnimalHouse).animalsThatLiveHere.Add(this.animalBeingPurchased.myID.Value); this.newAnimalHome = null; this.namingAnimal = false; Game1.player.money -= this.priceOfAnimal; @@ -335,19 +380,19 @@ public override void receiveLeftClick(int x, int y, bool playSound = true) Building buildingAt = currentFarm.getBuildingAt(tile); if (buildingAt != null && !this.namingAnimal) { - if (buildingAt.buildingType.Contains(this.animalBeingPurchased.buildingTypeILiveIn)) + if (buildingAt.buildingType.Contains(this.animalBeingPurchased.buildingTypeILiveIn.Value)) { - if ((buildingAt.indoors as AnimalHouse).isFull()) + if ((buildingAt.indoors.Value as AnimalHouse).isFull()) { Game1.showRedMessage(Game1.content.LoadString("Strings\\StringsFromCSFiles:PurchaseAnimalsMenu.cs.11321", new object[0])); } - else if (this.animalBeingPurchased.harvestType != 2) + else if (this.animalBeingPurchased.harvestType.Value != 2) { this.namingAnimal = true; this.newAnimalHome = buildingAt; - if (this.animalBeingPurchased.sound != null && Game1.soundBank != null) + if (this.animalBeingPurchased.sound.Value != null && Game1.soundBank != null) { - Cue expr_15B = Game1.soundBank.GetCue(this.animalBeingPurchased.sound); + Cue expr_15B = Game1.soundBank.GetCue(this.animalBeingPurchased.sound.Value); expr_15B.SetVariable("Pitch", (float)(1200 + Game1.random.Next(-200, 201))); expr_15B.Play(); } @@ -364,15 +409,15 @@ public override void receiveLeftClick(int x, int y, bool playSound = true) { this.newAnimalHome = buildingAt; this.animalBeingPurchased.home = this.newAnimalHome; - this.animalBeingPurchased.homeLocation = new Vector2((float)this.newAnimalHome.tileX, (float)this.newAnimalHome.tileY); - this.animalBeingPurchased.setRandomPosition(this.animalBeingPurchased.home.indoors); - (this.newAnimalHome.indoors as AnimalHouse).animals.Add(this.animalBeingPurchased.myID, this.animalBeingPurchased); - (this.newAnimalHome.indoors as AnimalHouse).animalsThatLiveHere.Add(this.animalBeingPurchased.myID); + this.animalBeingPurchased.homeLocation.Value = new Vector2((float)this.newAnimalHome.tileX.Value, (float)this.newAnimalHome.tileY.Value); + this.animalBeingPurchased.setRandomPosition(this.animalBeingPurchased.home.indoors.Value); + (this.newAnimalHome.indoors.Value as AnimalHouse).animals.Add(this.animalBeingPurchased.myID.Value, this.animalBeingPurchased); + (this.newAnimalHome.indoors.Value as AnimalHouse).animalsThatLiveHere.Add(this.animalBeingPurchased.myID.Value); this.newAnimalHome = null; this.namingAnimal = false; - if (this.animalBeingPurchased.sound != null && Game1.soundBank != null) + if (this.animalBeingPurchased.sound.Value != null && Game1.soundBank != null) { - Cue expr_2DC = Game1.soundBank.GetCue(this.animalBeingPurchased.sound); + Cue expr_2DC = Game1.soundBank.GetCue(this.animalBeingPurchased.sound.Value); expr_2DC.SetVariable("Pitch", (float)(1200 + Game1.random.Next(-200, 201))); expr_2DC.Play(); } @@ -381,7 +426,7 @@ public override void receiveLeftClick(int x, int y, bool playSound = true) { this.animalBeingPurchased.displayType }), Color.LimeGreen, 3500f)); - this.animalBeingPurchased = new FarmAnimal(this.animalBeingPurchased.type, MultiplayerUtility.getNewID(), Game1.player.uniqueMultiplayerID); + this.animalBeingPurchased = new FarmAnimal(this.animalBeingPurchased.type.Value, ModEntry.ModHelper.Multiplayer.GetNewID(), Game1.player.UniqueMultiplayerID); } else if (Game1.player.money < this.priceOfAnimal) { @@ -405,8 +450,8 @@ public override void receiveLeftClick(int x, int y, bool playSound = true) } else if (this.namingAnimal && this.randomButton.containsPoint(x, y)) { - this.animalBeingPurchased.name = Dialogue.randomName(); - this.animalBeingPurchased.displayName = this.animalBeingPurchased.name; + this.animalBeingPurchased.Name = Dialogue.randomName(); + this.animalBeingPurchased.displayName = this.animalBeingPurchased.Name; this.textBox.Text = this.animalBeingPurchased.displayName; this.randomButton.scale = this.randomButton.baseScale; Game1.playSound("drumkit6"); @@ -431,7 +476,7 @@ public override void receiveLeftClick(int x, int y, bool playSound = true) } foreach (ClickableTextureComponent current in this.animalsToPurchase) { - if (current.containsPoint(x, y) && (current.item as Object).type == null) + if (current.containsPoint(x, y) && (current.item as Object).Type == null) { int num = current.item.salePrice(); if (Game1.player.money >= num) @@ -439,7 +484,11 @@ public override void receiveLeftClick(int x, int y, bool playSound = true) Game1.globalFadeToBlack(new Game1.afterFadeFunction(this.setUpForAnimalPlacement), 0.02f); Game1.playSound("smallSelect"); this.onFarm = true; - this.animalBeingPurchased = new FarmAnimal(current.hoverText, MultiplayerUtility.getNewID(), Game1.player.uniqueMultiplayerID); + + // Integrate with Better Farm Animal Variety (BFAV) >= 3.x + IBetterFarmAnimalVarietyApi api = framework.helper.ModRegistry.GetApi("Paritee.BetterFarmAnimalVariety"); + string type = api == null ? current.hoverText : api.GetRandomAnimalShopType(current.hoverText, Game1.player); + this.animalBeingPurchased = new FarmAnimal(type, ModEntry.ModHelper.Multiplayer.GetNewID(), Game1.player.UniqueMultiplayerID); this.priceOfAnimal = num; } else @@ -609,18 +658,18 @@ public override void performHoverAction(int x, int y) Vector2 tile = new Vector2((float)((x + Game1.viewport.X) / Game1.tileSize), (float)((y + Game1.viewport.Y) / Game1.tileSize)); foreach (Building current in currentFarm.buildings) { - current.color = Color.White; + current.color.Value = Color.White; } Building buildingAt = currentFarm.getBuildingAt(tile); if (buildingAt != null) { - if (buildingAt.buildingType.Contains(this.animalBeingPurchased.buildingTypeILiveIn) && !(buildingAt.indoors as AnimalHouse).isFull()) + if (buildingAt.buildingType.Contains(this.animalBeingPurchased.buildingTypeILiveIn.Value) && !(buildingAt.indoors.Value as AnimalHouse).isFull()) { - buildingAt.color = Color.LightGreen * 0.8f; + buildingAt.color.Value = Color.LightGreen * 0.8f; } else { - buildingAt.color = Color.Red * 0.8f; + buildingAt.color.Value = Color.Red * 0.8f; } } } @@ -673,7 +722,7 @@ public override void draw(SpriteBatch b) while (enumerator.MoveNext()) { ClickableTextureComponent current = enumerator.Current; - current.draw(b, ((current.item as Object).type != null) ? (Color.Black * 0.4f) : Color.White, 0.87f); + current.draw(b, ((current.item as Object).Type != null) ? (Color.Black * 0.4f) : Color.White, 0.87f); } goto IL_2AE; } @@ -703,9 +752,9 @@ public override void draw(SpriteBatch b) } if (this.hovered != null) { - if ((this.hovered.item as Object).type != null) + if ((this.hovered.item as Object).Type != null) { - IClickableMenu.drawHoverText(b, Game1.parseText((this.hovered.item as Object).type, Game1.dialogueFont, Game1.tileSize * 5), Game1.dialogueFont, 0, 0, -1, null, -1, null, null, 0, -1, -1, -1, -1, 1f, null); + IClickableMenu.drawHoverText(b, Game1.parseText((this.hovered.item as Object).Type, Game1.dialogueFont, Game1.tileSize * 5), Game1.dialogueFont, 0, 0, -1, null, -1, null, null, 0, -1, -1, -1, -1, 1f, null); } else { diff --git a/FarmExpansion/ModEntry.cs b/FarmExpansion/ModEntry.cs index 7418dcb..dbed46f 100644 --- a/FarmExpansion/ModEntry.cs +++ b/FarmExpansion/ModEntry.cs @@ -12,6 +12,7 @@ namespace FarmExpansion public class ModEntry : Mod, IAssetEditor { private FEFramework framework; + public static IModHelper ModHelper; public bool CanEdit(IAssetInfo asset) { @@ -58,16 +59,15 @@ public void Edit(IAssetData asset) /// Provides simplified APIs for writing mods. public override void Entry(IModHelper helper) { + ModHelper = helper; framework = new FEFramework(helper, Monitor); framework.IsTreeTransplantLoaded = helper.ModRegistry.IsLoaded("TreeTransplant");// && helper.ModRegistry.Get("TreeTransplant").Version.IsNewerThan("1.0.0"); - //ControlEvents.KeyPressed += framework.ControlEvents_KeyPress; - MenuEvents.MenuChanged += framework.MenuEvents_MenuChanged; - MenuEvents.MenuClosed += framework.MenuEvents_MenuClosed; - SaveEvents.AfterLoad += framework.SaveEvents_AfterLoad; - SaveEvents.BeforeSave += framework.SaveEvents_BeforeSave; - SaveEvents.AfterSave += framework.SaveEvents_AfterSave; - SaveEvents.AfterReturnToTitle += framework.SaveEvents_AfterReturnToTitle; - TimeEvents.AfterDayStarted += framework.TimeEvents_AfterDayStarted; + helper.Events.Display.MenuChanged += framework.OnMenuChanged; + helper.Events.GameLoop.SaveLoaded += framework.OnSaveLoaded; + helper.Events.GameLoop.Saving += framework.OnSaving; + helper.Events.GameLoop.Saved += framework.OnSaved; + helper.Events.GameLoop.ReturnedToTitle += framework.OnReturnedToTitle; + helper.Events.GameLoop.DayStarted += framework.OnDayStarted; } /// Get an API that other mods can access. This is always called after . diff --git a/FarmExpansion/manifest.json b/FarmExpansion/manifest.json index 5be9532..4c15fbd 100644 --- a/FarmExpansion/manifest.json +++ b/FarmExpansion/manifest.json @@ -1,10 +1,10 @@ { "Name": "Farm Expansion", "Author": "Advize", - "Version": "3.3.0", - "MinimumApiVersion": "2.5", + "Version": "3.3.1-unofficial.1", "Description": "Adds an additional plot of land for crops and animals.", "UniqueID": "Advize.FarmExpansion", "EntryDll": "FarmExpansion.dll", + "MinimumApiVersion": "2.10.1", "UpdateKeys": [ "Nexus:130" ] -} \ No newline at end of file +} diff --git a/FarmExpansion/packages.config b/FarmExpansion/packages.config deleted file mode 100644 index 028670c..0000000 --- a/FarmExpansion/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file