Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.IO;
- using System.Collections.Generic;
- using System.Linq;
- using StardewValley;
- using StardewValley.TerrainFeatures;
- using StardewModdingAPI;
- using StardewModdingAPI.Events;
- using Microsoft.Xna.Framework;
- using Microsoft.Xna.Framework.Content;
- using xTile;
- using xTile.Dimensions;
- /* Advize's Farm Expansion Mod v1.3 */
- namespace FarmExpansionSMAPI
- {
- public class FarmExpansionSMAPI : Mod
- {
- private static bool addCrows = false;
- private static string modPath = "";
- //My quick and dirty config reader/writer. I don't recommend using it, SMAPI is now in the process of implementing one.
- private static void LoadConfig()
- {
- string configLocation = Path.Combine(modPath, "FarmExpansionSMAPI.ini");
- if (!File.Exists(configLocation))
- {
- try
- {
- File.Create(configLocation).Close();
- StreamWriter sw = new StreamWriter(configLocation);
- sw.WriteLine("addCrows=false");
- sw.Close();
- }
- catch (Exception e) { Log.Error(e, new object[0]); }
- }
- else
- {
- try
- {
- StreamReader sr = new StreamReader(configLocation);
- if (sr.ReadLine().Contains("true")) addCrows = true;
- }
- catch (Exception e) { Log.Error(e, new object[0]); }
- }
- }
- //Executes when SMAPI loads the mod. I subscribe to the events I need and attempt to load a config file.
- public override void Entry(params object[] objects)
- {
- modPath = this.PathOnDisk;
- LoadConfig();
- GameEvents.UpdateTick += Event_UpdateTick;
- TimeEvents.DayOfMonthChanged += Event_DayOfMonthChanged;
- }
- //I use this event as a hack since there is no proper event that fires after a game save has been loaded, unsubscribe once done with it for performance boost
- static void Event_UpdateTick(object sender, EventArgs e)
- {
- // Error prevention. Returns early if all 47 default locations have not yet loaded.
- if (Game1.locations.Count < 47) return;
- // More error prevention. Returns and unsubscribes from event if custom location has already been added to the game.
- for (int i = 0; i <= Game1.locations.Count - 1; i++)
- {
- GameLocation currentLocation = Game1.locations[i];
- if (currentLocation.Name == "FarmGreenhouseExtension")
- {
- GameEvents.UpdateTick -= Event_UpdateTick;
- return;
- }
- }
- //Load my custom map, add location properties as necessary, add the location to the game, and add warp points.
- string relativeAssetPath = Path.Combine(modPath, "FarmExtension.xnb");
- string mapName = "FarmGreenhouseExtension";
- GameLocation farmExtension = new GameLocation(LoadMap(relativeAssetPath), mapName);
- farmExtension.isFarm = true;
- farmExtension.isOutdoors = true;
- Game1.locations.Add(farmExtension);
- List<Warp> warps = new List<Warp>();
- Game1.locations[1].warps.Add(new Warp(-1, 44, mapName, 46, 4, false));
- Game1.locations[1].warps.Add(new Warp(-1, 45, mapName, 46, 5, false));
- Game1.locations[1].warps.Add(new Warp(-1, 46, mapName, 46, 6, false));
- //Perform dynamic tile edits to the 1st index in the list of game locations (locations[1] is Farm. Array begins at 0 and ends at 46 by default).
- PatchMap(Game1.locations[1].Map);
- //Unsubscribe from the event as all mod initialization has been completed
- GameEvents.UpdateTick -= Event_UpdateTick;
- }
- static void Event_DayOfMonthChanged(object sender, EventArgs e)
- {
- GameLocation fe = Game1.getLocationFromName("FarmGreenhouseExtension");
- //Water crops if raining
- if (Game1.isRaining)
- {
- foreach (KeyValuePair<Vector2, TerrainFeature> pair in fe.terrainFeatures)
- {
- if (pair.Value != null && pair.Value is HoeDirt)
- {
- ((HoeDirt)pair.Value).state = 1;
- }
- }
- }
- //Chance to remove old tilled dirt that doesn't contain crops
- Dictionary<Vector2, TerrainFeature>.KeyCollection keys = fe.terrainFeatures.Keys;
- for (int k = keys.Count - 1; k >= 0; k--)
- {
- if (fe.terrainFeatures[keys.ElementAt(k)] is HoeDirt && (fe.terrainFeatures[keys.ElementAt(k)] as HoeDirt).crop == null && Game1.random.NextDouble() <= 0.1)
- {
- fe.terrainFeatures.Remove(keys.ElementAt(k));
- }
- }
- //Not sure what this does, but a quick glance suggests some kind of animation or alternate texture on full-grown non-tapped trees during fall
- if (fe.terrainFeatures.Count<KeyValuePair<Vector2, TerrainFeature>>() > 0 && Game1.currentSeason.Equals("fall") && Game1.dayOfMonth > 1 && Game1.random.NextDouble() < 0.05)
- {
- for (int l = 0; l < 10; l++)
- {
- TerrainFeature value = fe.terrainFeatures.ElementAt(Game1.random.Next(fe.terrainFeatures.Count<KeyValuePair<Vector2, TerrainFeature>>())).Value;
- if (value is Tree && (value as Tree).growthStage >= 5 && !(value as Tree).tapped)
- {
- (value as Tree).treeType = 7;
- (value as Tree).loadSprite();
- break;
- }
- }
- }
- //Adds crows if enabled in config
- if(addCrows)
- {
- AddCrows(fe);
- }
- //The rest of this is for debris generation (stones, logs, trees, grass, etc.)
- if (!Game1.currentSeason.Equals("winter"))
- {
- fe.spawnWeedsAndStones(Game1.currentSeason.Equals("summer") ? 30 : 20, false, true);
- }
- fe.spawnWeeds(false);
- if (Game1.dayOfMonth == 1)
- {
- for (int m = fe.terrainFeatures.Count - 1; m >= 0; m--)
- {
- if (fe.terrainFeatures.ElementAt(m).Value is HoeDirt && (fe.terrainFeatures.ElementAt(m).Value as HoeDirt).crop == null && Game1.random.NextDouble() < 0.8)
- {
- fe.terrainFeatures.Remove(fe.terrainFeatures.ElementAt(m).Key);
- }
- }
- fe.spawnWeedsAndStones(20, false, false);
- if (Game1.currentSeason.Equals("spring") && Game1.stats.DaysPlayed > 1u)
- {
- fe.spawnWeedsAndStones(40, false, false);
- fe.spawnWeedsAndStones(40, true, false);
- for (int n = 0; n < 15; n++)
- {
- int num2 = Game1.random.Next(fe.map.DisplayWidth / Game1.tileSize);
- int num3 = Game1.random.Next(fe.map.DisplayHeight / Game1.tileSize);
- Vector2 vector = new Vector2((float)num2, (float)num3);
- StardewValley.Object @object;
- fe.objects.TryGetValue(vector, out @object);
- if (@object == null && fe.doesTileHaveProperty(num2, num3, "Diggable", "Back") != null && fe.isTileLocationOpen(new Location(num2 * Game1.tileSize, num3 * Game1.tileSize)) && !fe.isTileOccupied(vector, "") && fe.doesTileHaveProperty(num2, num3, "Water", "Back") == null)
- {
- fe.terrainFeatures.Add(vector, new Grass(1, 4));
- }
- }
- fe.growWeedGrass(40);
- }
- }
- fe.growWeedGrass(1);
- }
- //Uses Xna Framework for loading maps outside of the game\content directory
- static Map LoadMap(string filePath)
- {
- var ext = Path.GetExtension(filePath);
- Map map = null;
- var path = Path.GetDirectoryName(filePath);
- var fileName = Path.GetFileNameWithoutExtension(filePath);
- var cm = new ContentManager(new GameServiceContainer(), path);
- map = cm.Load<Map>(fileName);
- if (map == null) throw new FileLoadException();
- return map;
- }
- //Meticulously planned tile edits for Farm.xnb
- private static void PatchMap(Map map)
- {
- //Create array of custom tile objects with layer, x & y location, and new texture information (-1 as a texture means set the tile to null)
- List<Tile> tileArray = new List<Tile>();
- tileArray.Add(new Tile(0, 0, 38, 175)); tileArray.Add(new Tile(0, 1, 38, 175)); tileArray.Add(new Tile(0, 0, 43, 537));
- tileArray.Add(new Tile(0, 1, 43, 537)); tileArray.Add(new Tile(0, 2, 43, 586)); tileArray.Add(new Tile(0, 0, 44, 566));
- tileArray.Add(new Tile(0, 1, 44, 537)); tileArray.Add(new Tile(0, 2, 44, 618)); tileArray.Add(new Tile(0, 0, 45, 587));
- tileArray.Add(new Tile(0, 1, 45, 473)); tileArray.Add(new Tile(0, 0, 46, 587)); tileArray.Add(new Tile(0, 1, 46, 587));
- tileArray.Add(new Tile(0, 0, 48, 175)); tileArray.Add(new Tile(0, 1, 48, 175));
- tileArray.Add(new Tile(1, 0, 39, 175)); tileArray.Add(new Tile(1, 1, 39, 175)); tileArray.Add(new Tile(1, 2, 39, 444));
- tileArray.Add(new Tile(1, 0, 40, 446)); tileArray.Add(new Tile(1, 1, 40, 468)); tileArray.Add(new Tile(1, 2, 40, 469));
- tileArray.Add(new Tile(1, 0, 41, 492)); tileArray.Add(new Tile(1, 1, 41, 493)); tileArray.Add(new Tile(1, 2, 41, 494));
- tileArray.Add(new Tile(1, 0, 42, 517)); tileArray.Add(new Tile(1, 1, 42, 518)); tileArray.Add(new Tile(1, 2, 42, 519));
- tileArray.Add(new Tile(1, 0, 43, 542)); tileArray.Add(new Tile(1, 1, 43, 543)); tileArray.Add(new Tile(1, 2, 43, 544));
- tileArray.Add(new Tile(1, 0, 44, -1)); tileArray.Add(new Tile(1, 1, 44, -1)); tileArray.Add(new Tile(1, 2, 44, -1));
- tileArray.Add(new Tile(1, 0, 45, -1)); tileArray.Add(new Tile(1, 1, 45, -1)); tileArray.Add(new Tile(1, 2, 45, -1));
- tileArray.Add(new Tile(1, 0, 46, -1)); tileArray.Add(new Tile(1, 1, 46, -1)); tileArray.Add(new Tile(1, 2, 46, -1));
- tileArray.Add(new Tile(1, 0, 47, 175)); tileArray.Add(new Tile(1, 1, 47, 175)); tileArray.Add(new Tile(1, 0, 48, -1));
- tileArray.Add(new Tile(3, 0, 36, -1)); tileArray.Add(new Tile(3, 1, 36, -1)); tileArray.Add(new Tile(3, 0, 37, -1));
- tileArray.Add(new Tile(3, 1, 37, -1)); tileArray.Add(new Tile(3, 0, 38, -1)); tileArray.Add(new Tile(3, 1, 38, -1));
- tileArray.Add(new Tile(3, 0, 39, -1)); tileArray.Add(new Tile(3, 1, 39, -1)); tileArray.Add(new Tile(3, 0, 40, -1));
- tileArray.Add(new Tile(3, 0, 41, -1)); tileArray.Add(new Tile(3, 0, 46, 414)); tileArray.Add(new Tile(3, 1, 46, 413));
- tileArray.Add(new Tile(3, 2, 46, 438)); tileArray.Add(new Tile(3, 0, 47, 175)); tileArray.Add(new Tile(3, 1, 47, 175));
- tileArray.Add(new Tile(3, 2, 47, 394));
- //Attempt to make the tile changes based on new tiles found in the array
- foreach (Tile tile in tileArray)
- {
- //Log.Success("Now trying coordinates " + tile.l + " " + tile.x + " " + tile.y);
- if (tile.tileIndex < 0)
- {
- map.Layers[tile.l].Tiles[tile.x, tile.y] = null;
- //Log.Success("Setting tile: " + tile.l + " " + tile.x + " " + tile.y + " to null");
- continue;
- }
- if (map.Layers[tile.l].Tiles[tile.x, tile.y] != null)
- {
- map.Layers[tile.l].Tiles[tile.x, tile.y].TileIndex = tile.tileIndex;
- //Log.Success("Setting tile: " + tile.l + " " + tile.x + " " + tile.y + " " + tile.tileIndex);
- }
- else
- {
- int width = 0;
- bool done = false;
- while (width <= map.Layers[tile.l].LayerWidth && !done)
- {
- int height = 0;
- while (height <= map.Layers[tile.l].LayerHeight)
- {
- if (map.Layers[tile.l].Tiles[width, height] != null)
- {
- if (map.Layers[tile.l].Tiles[width, height].TileIndex != tile.tileIndex)
- {
- height++;
- continue;
- }
- map.Layers[tile.l].Tiles[tile.x, tile.y] = map.Layers[tile.l].Tiles[width, height];
- //Log.Success(tile.l + " " + tile.x + " " + tile.y + " was null. Copying from " + tile.l + " " + width + " " + height + " " + map.Layers[tile.l].Tiles[width, height].TileIndex);
- done = true;
- break;
- }
- height++;
- }
- width++;
- }
- //if (!done) Log.Success("Failed to find a clone");
- }
- }
- }
- //Adds chance for crows to consume crops in the new area. Added as a separate method as it's toggleable.
- private static void AddCrows(GameLocation fe)
- {
- int num = 0;
- foreach (KeyValuePair<Vector2, TerrainFeature> pair in fe.terrainFeatures)
- {
- if (pair.Value is HoeDirt && (pair.Value as HoeDirt).crop != null)
- {
- num++;
- }
- }
- List<Vector2> list = new List<Vector2>();
- foreach (KeyValuePair<Vector2, StardewValley.Object> pair in fe.objects)
- {
- if (pair.Value.bigCraftable && pair.Value.Name.Contains("arecrow"))
- {
- list.Add(pair.Key);
- }
- }
- int num2 = Math.Min(4, num / 16);
- for (int i = 0; i < num2; i++)
- {
- if (Game1.random.NextDouble() < 0.3)
- {
- int j = 0;
- while (j < 10)
- {
- Vector2 key = fe.terrainFeatures.ElementAt(Game1.random.Next(fe.terrainFeatures.Count<KeyValuePair<Vector2, TerrainFeature>>())).Key;
- if (fe.terrainFeatures[key] is HoeDirt && (fe.terrainFeatures[key] as HoeDirt).crop != null && (fe.terrainFeatures[key] as HoeDirt).crop.currentPhase > 1)
- {
- bool flag = false;
- foreach (Vector2 current3 in list)
- {
- if (Vector2.Distance(current3, key) < 9f)
- {
- flag = true;
- fe.objects[current3].specialVariable++;
- break;
- }
- }
- if (!flag)
- {
- (fe.terrainFeatures[key] as HoeDirt).crop = null;
- fe.addCritter(new StardewValley.BellsAndWhistles.Crow((int)key.X, (int)key.Y));
- break;
- }
- break;
- }
- else
- {
- j++;
- }
- }
- }
- }
- }
- }
- public class Tile
- {
- public int l;
- public int x;
- public int y;
- public int tileIndex;
- public Tile(int l, int x, int y, int tileIndex)
- {
- this.l = l; this.x = x; this.y = y; this.tileIndex = tileIndex;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement