Advertisement
Guest User

Advize's Farm Expansion Mod 1.3 Source

a guest
Mar 25th, 2016
351
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 16.48 KB | None | 0 0
  1. using System;
  2. using System.IO;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5.  
  6. using StardewValley;
  7. using StardewValley.TerrainFeatures;
  8. using StardewModdingAPI;
  9. using StardewModdingAPI.Events;
  10.  
  11. using Microsoft.Xna.Framework;
  12. using Microsoft.Xna.Framework.Content;
  13. using xTile;
  14. using xTile.Dimensions;
  15.  
  16. /* Advize's Farm Expansion Mod v1.3 */
  17.  
  18. namespace FarmExpansionSMAPI
  19. {
  20.    
  21.     public class FarmExpansionSMAPI : Mod
  22.     {
  23.  
  24.         private static bool addCrows = false;
  25.         private static string modPath = "";
  26.  
  27.         //My quick and dirty config reader/writer. I don't recommend using it, SMAPI is now in the process of implementing one.
  28.         private static void LoadConfig()
  29.         {
  30.             string configLocation = Path.Combine(modPath, "FarmExpansionSMAPI.ini");
  31.  
  32.             if (!File.Exists(configLocation))
  33.             {
  34.                 try
  35.                 {
  36.                     File.Create(configLocation).Close();
  37.                     StreamWriter sw = new StreamWriter(configLocation);
  38.                     sw.WriteLine("addCrows=false");
  39.                     sw.Close();
  40.                 }
  41.                 catch (Exception e) { Log.Error(e, new object[0]); }
  42.             }
  43.             else
  44.             {
  45.                 try
  46.                 {
  47.                     StreamReader sr = new StreamReader(configLocation);
  48.                     if (sr.ReadLine().Contains("true")) addCrows = true;
  49.                 }
  50.                 catch (Exception e) { Log.Error(e, new object[0]); }
  51.             }
  52.         }
  53.  
  54.         //Executes when SMAPI loads the mod. I subscribe to the events I need and attempt to load a config file.
  55.         public override void Entry(params object[] objects)
  56.         {
  57.             modPath = this.PathOnDisk;
  58.             LoadConfig();
  59.             GameEvents.UpdateTick += Event_UpdateTick;
  60.             TimeEvents.DayOfMonthChanged += Event_DayOfMonthChanged;
  61.         }
  62.  
  63.         //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
  64.         static void Event_UpdateTick(object sender, EventArgs e)
  65.         {  
  66.             // Error prevention. Returns early if all 47 default locations have not yet loaded.
  67.             if (Game1.locations.Count < 47) return;
  68.             // More error prevention. Returns and unsubscribes from event if custom location has already been added to the game.
  69.             for (int i = 0; i <= Game1.locations.Count - 1; i++)
  70.             {
  71.                 GameLocation currentLocation = Game1.locations[i];
  72.                 if (currentLocation.Name == "FarmGreenhouseExtension")
  73.                 {
  74.                     GameEvents.UpdateTick -= Event_UpdateTick;
  75.                     return;
  76.                 }
  77.             }
  78.             //Load my custom map, add location properties as necessary, add the location to the game, and add warp points.
  79.             string relativeAssetPath = Path.Combine(modPath, "FarmExtension.xnb");
  80.             string mapName = "FarmGreenhouseExtension";
  81.  
  82.             GameLocation farmExtension = new GameLocation(LoadMap(relativeAssetPath), mapName);
  83.  
  84.             farmExtension.isFarm = true;
  85.             farmExtension.isOutdoors = true;
  86.             Game1.locations.Add(farmExtension);
  87.  
  88.             List<Warp> warps = new List<Warp>();
  89.            
  90.             Game1.locations[1].warps.Add(new Warp(-1, 44, mapName, 46, 4, false));
  91.             Game1.locations[1].warps.Add(new Warp(-1, 45, mapName, 46, 5, false));
  92.             Game1.locations[1].warps.Add(new Warp(-1, 46, mapName, 46, 6, false));
  93.             //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).
  94.             PatchMap(Game1.locations[1].Map);
  95.  
  96.             //Unsubscribe from the event as all mod initialization has been completed
  97.             GameEvents.UpdateTick -= Event_UpdateTick;
  98.         }
  99.  
  100.         static void Event_DayOfMonthChanged(object sender, EventArgs e)
  101.         {
  102.             GameLocation fe = Game1.getLocationFromName("FarmGreenhouseExtension");
  103.             //Water crops if raining
  104.             if (Game1.isRaining)
  105.             {
  106.                 foreach (KeyValuePair<Vector2, TerrainFeature> pair in fe.terrainFeatures)
  107.                 {
  108.                     if (pair.Value != null && pair.Value is HoeDirt)
  109.                     {
  110.                         ((HoeDirt)pair.Value).state = 1;
  111.                     }
  112.                 }
  113.             }
  114.             //Chance to remove old tilled dirt that doesn't contain crops
  115.             Dictionary<Vector2, TerrainFeature>.KeyCollection keys = fe.terrainFeatures.Keys;
  116.             for (int k = keys.Count - 1; k >= 0; k--)
  117.             {
  118.                 if (fe.terrainFeatures[keys.ElementAt(k)] is HoeDirt && (fe.terrainFeatures[keys.ElementAt(k)] as HoeDirt).crop == null && Game1.random.NextDouble() <= 0.1)
  119.                 {
  120.                     fe.terrainFeatures.Remove(keys.ElementAt(k));
  121.                 }
  122.             }
  123.             //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
  124.             if (fe.terrainFeatures.Count<KeyValuePair<Vector2, TerrainFeature>>() > 0 && Game1.currentSeason.Equals("fall") && Game1.dayOfMonth > 1 && Game1.random.NextDouble() < 0.05)
  125.             {
  126.                 for (int l = 0; l < 10; l++)
  127.                 {
  128.                     TerrainFeature value = fe.terrainFeatures.ElementAt(Game1.random.Next(fe.terrainFeatures.Count<KeyValuePair<Vector2, TerrainFeature>>())).Value;
  129.                     if (value is Tree && (value as Tree).growthStage >= 5 && !(value as Tree).tapped)
  130.                     {
  131.                         (value as Tree).treeType = 7;
  132.                         (value as Tree).loadSprite();
  133.                         break;
  134.                     }
  135.                 }
  136.             }
  137.             //Adds crows if enabled in config
  138.             if(addCrows)
  139.             {
  140.                 AddCrows(fe);
  141.             }
  142.             //The rest of this is for debris generation (stones, logs, trees, grass, etc.)
  143.             if (!Game1.currentSeason.Equals("winter"))
  144.             {
  145.                 fe.spawnWeedsAndStones(Game1.currentSeason.Equals("summer") ? 30 : 20, false, true);
  146.             }
  147.             fe.spawnWeeds(false);
  148.             if (Game1.dayOfMonth == 1)
  149.             {
  150.                 for (int m = fe.terrainFeatures.Count - 1; m >= 0; m--)
  151.                 {
  152.                     if (fe.terrainFeatures.ElementAt(m).Value is HoeDirt && (fe.terrainFeatures.ElementAt(m).Value as HoeDirt).crop == null && Game1.random.NextDouble() < 0.8)
  153.                     {
  154.                         fe.terrainFeatures.Remove(fe.terrainFeatures.ElementAt(m).Key);
  155.                     }
  156.                 }
  157.                 fe.spawnWeedsAndStones(20, false, false);
  158.                 if (Game1.currentSeason.Equals("spring") && Game1.stats.DaysPlayed > 1u)
  159.                 {
  160.                     fe.spawnWeedsAndStones(40, false, false);
  161.                     fe.spawnWeedsAndStones(40, true, false);
  162.                     for (int n = 0; n < 15; n++)
  163.                     {
  164.                         int num2 = Game1.random.Next(fe.map.DisplayWidth / Game1.tileSize);
  165.                         int num3 = Game1.random.Next(fe.map.DisplayHeight / Game1.tileSize);
  166.                         Vector2 vector = new Vector2((float)num2, (float)num3);
  167.                         StardewValley.Object @object;
  168.                         fe.objects.TryGetValue(vector, out @object);
  169.                         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)
  170.                         {
  171.                             fe.terrainFeatures.Add(vector, new Grass(1, 4));
  172.                         }
  173.                     }
  174.                     fe.growWeedGrass(40);
  175.                 }
  176.             }
  177.             fe.growWeedGrass(1);
  178.         }
  179.  
  180.         //Uses Xna Framework for loading maps outside of the game\content directory
  181.         static Map LoadMap(string filePath)
  182.         {
  183.             var ext = Path.GetExtension(filePath);
  184.             Map map = null;
  185.  
  186.             var path = Path.GetDirectoryName(filePath);
  187.             var fileName = Path.GetFileNameWithoutExtension(filePath);
  188.             var cm = new ContentManager(new GameServiceContainer(), path);
  189.             map = cm.Load<Map>(fileName);
  190.  
  191.             if (map == null) throw new FileLoadException();
  192.  
  193.             return map;
  194.         }
  195.  
  196.         //Meticulously planned tile edits for Farm.xnb
  197.         private static void PatchMap(Map map)
  198.         {
  199.             //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)
  200.             List<Tile> tileArray = new List<Tile>();
  201.             tileArray.Add(new Tile(0, 0, 38, 175)); tileArray.Add(new Tile(0, 1, 38, 175)); tileArray.Add(new Tile(0, 0, 43, 537));
  202.             tileArray.Add(new Tile(0, 1, 43, 537)); tileArray.Add(new Tile(0, 2, 43, 586)); tileArray.Add(new Tile(0, 0, 44, 566));
  203.             tileArray.Add(new Tile(0, 1, 44, 537)); tileArray.Add(new Tile(0, 2, 44, 618)); tileArray.Add(new Tile(0, 0, 45, 587));
  204.             tileArray.Add(new Tile(0, 1, 45, 473)); tileArray.Add(new Tile(0, 0, 46, 587)); tileArray.Add(new Tile(0, 1, 46, 587));
  205.             tileArray.Add(new Tile(0, 0, 48, 175)); tileArray.Add(new Tile(0, 1, 48, 175));
  206.  
  207.             tileArray.Add(new Tile(1, 0, 39, 175)); tileArray.Add(new Tile(1, 1, 39, 175)); tileArray.Add(new Tile(1, 2, 39, 444));
  208.             tileArray.Add(new Tile(1, 0, 40, 446)); tileArray.Add(new Tile(1, 1, 40, 468)); tileArray.Add(new Tile(1, 2, 40, 469));
  209.             tileArray.Add(new Tile(1, 0, 41, 492)); tileArray.Add(new Tile(1, 1, 41, 493)); tileArray.Add(new Tile(1, 2, 41, 494));
  210.             tileArray.Add(new Tile(1, 0, 42, 517)); tileArray.Add(new Tile(1, 1, 42, 518)); tileArray.Add(new Tile(1, 2, 42, 519));
  211.             tileArray.Add(new Tile(1, 0, 43, 542)); tileArray.Add(new Tile(1, 1, 43, 543)); tileArray.Add(new Tile(1, 2, 43, 544));
  212.             tileArray.Add(new Tile(1, 0, 44, -1)); tileArray.Add(new Tile(1, 1, 44, -1)); tileArray.Add(new Tile(1, 2, 44, -1));
  213.             tileArray.Add(new Tile(1, 0, 45, -1)); tileArray.Add(new Tile(1, 1, 45, -1)); tileArray.Add(new Tile(1, 2, 45, -1));
  214.             tileArray.Add(new Tile(1, 0, 46, -1)); tileArray.Add(new Tile(1, 1, 46, -1)); tileArray.Add(new Tile(1, 2, 46, -1));
  215.             tileArray.Add(new Tile(1, 0, 47, 175)); tileArray.Add(new Tile(1, 1, 47, 175)); tileArray.Add(new Tile(1, 0, 48, -1));
  216.  
  217.             tileArray.Add(new Tile(3, 0, 36, -1)); tileArray.Add(new Tile(3, 1, 36, -1)); tileArray.Add(new Tile(3, 0, 37, -1));
  218.             tileArray.Add(new Tile(3, 1, 37, -1)); tileArray.Add(new Tile(3, 0, 38, -1)); tileArray.Add(new Tile(3, 1, 38, -1));
  219.             tileArray.Add(new Tile(3, 0, 39, -1)); tileArray.Add(new Tile(3, 1, 39, -1)); tileArray.Add(new Tile(3, 0, 40, -1));
  220.             tileArray.Add(new Tile(3, 0, 41, -1)); tileArray.Add(new Tile(3, 0, 46, 414)); tileArray.Add(new Tile(3, 1, 46, 413));
  221.             tileArray.Add(new Tile(3, 2, 46, 438)); tileArray.Add(new Tile(3, 0, 47, 175)); tileArray.Add(new Tile(3, 1, 47, 175));
  222.             tileArray.Add(new Tile(3, 2, 47, 394));
  223.            
  224.             //Attempt to make the tile changes based on new tiles found in the array
  225.             foreach (Tile tile in tileArray)
  226.             {
  227.                 //Log.Success("Now trying coordinates " + tile.l + " " + tile.x + " " + tile.y);
  228.                 if (tile.tileIndex < 0)
  229.                 {
  230.                     map.Layers[tile.l].Tiles[tile.x, tile.y] = null;
  231.                     //Log.Success("Setting tile: " + tile.l + " " + tile.x + " " + tile.y + " to null");
  232.                     continue;
  233.                 }
  234.  
  235.                 if (map.Layers[tile.l].Tiles[tile.x, tile.y] != null)
  236.                 {
  237.                     map.Layers[tile.l].Tiles[tile.x, tile.y].TileIndex = tile.tileIndex;
  238.                     //Log.Success("Setting tile: " + tile.l + " " + tile.x + " " + tile.y + " " + tile.tileIndex);
  239.                 }
  240.                 else
  241.                 {
  242.                     int width = 0;
  243.                     bool done = false;
  244.  
  245.                     while (width <= map.Layers[tile.l].LayerWidth && !done)
  246.                     {
  247.                         int height = 0;
  248.                         while (height <= map.Layers[tile.l].LayerHeight)
  249.                         {
  250.                             if (map.Layers[tile.l].Tiles[width, height] != null)
  251.                             {
  252.                                 if (map.Layers[tile.l].Tiles[width, height].TileIndex != tile.tileIndex)
  253.                                 {
  254.                                     height++;
  255.                                     continue;
  256.                                 }
  257.                                 map.Layers[tile.l].Tiles[tile.x, tile.y] = map.Layers[tile.l].Tiles[width, height];
  258.                                 //Log.Success(tile.l + " " + tile.x + " " + tile.y + " was null. Copying from " + tile.l + " " + width + " " + height + " " + map.Layers[tile.l].Tiles[width, height].TileIndex);
  259.                                 done = true;
  260.                                 break;
  261.                             }
  262.                             height++;
  263.                         }
  264.                         width++;
  265.                     }
  266.                     //if (!done) Log.Success("Failed to find a clone");
  267.                 }
  268.             }
  269.         }
  270.  
  271.         //Adds chance for crows to consume crops in the new area. Added as a separate method as it's toggleable.
  272.         private static void AddCrows(GameLocation fe)
  273.         {
  274.             int num = 0;
  275.             foreach (KeyValuePair<Vector2, TerrainFeature> pair in fe.terrainFeatures)
  276.             {
  277.                 if (pair.Value is HoeDirt && (pair.Value as HoeDirt).crop != null)
  278.                 {
  279.                     num++;
  280.                 }
  281.             }
  282.             List<Vector2> list = new List<Vector2>();
  283.             foreach (KeyValuePair<Vector2, StardewValley.Object> pair in fe.objects)
  284.             {
  285.                 if (pair.Value.bigCraftable && pair.Value.Name.Contains("arecrow"))
  286.                 {
  287.                     list.Add(pair.Key);
  288.                 }
  289.             }
  290.             int num2 = Math.Min(4, num / 16);
  291.             for (int i = 0; i < num2; i++)
  292.             {
  293.                 if (Game1.random.NextDouble() < 0.3)
  294.                 {
  295.                     int j = 0;
  296.                     while (j < 10)
  297.                     {
  298.                         Vector2 key = fe.terrainFeatures.ElementAt(Game1.random.Next(fe.terrainFeatures.Count<KeyValuePair<Vector2, TerrainFeature>>())).Key;
  299.                         if (fe.terrainFeatures[key] is HoeDirt && (fe.terrainFeatures[key] as HoeDirt).crop != null && (fe.terrainFeatures[key] as HoeDirt).crop.currentPhase > 1)
  300.                         {
  301.                             bool flag = false;
  302.                             foreach (Vector2 current3 in list)
  303.                             {
  304.                                 if (Vector2.Distance(current3, key) < 9f)
  305.                                 {
  306.                                     flag = true;
  307.                                     fe.objects[current3].specialVariable++;
  308.                                     break;
  309.                                 }
  310.                             }
  311.                             if (!flag)
  312.                             {
  313.                                 (fe.terrainFeatures[key] as HoeDirt).crop = null;
  314.                                 fe.addCritter(new StardewValley.BellsAndWhistles.Crow((int)key.X, (int)key.Y));
  315.                                 break;
  316.                             }
  317.                             break;
  318.                         }
  319.                         else
  320.                         {
  321.                             j++;
  322.                         }
  323.                     }
  324.                 }
  325.             }
  326.         }
  327.     }
  328.  
  329.     public class Tile
  330.     {
  331.         public int l;
  332.         public int x;
  333.         public int y;
  334.         public int tileIndex;
  335.  
  336.         public Tile(int l, int x, int y, int tileIndex)
  337.         {
  338.             this.l = l; this.x = x; this.y = y; this.tileIndex = tileIndex;
  339.         }
  340.     }
  341. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement