Guest User

Advize's Farm Expansion Mod 1.3 Source

a guest
Mar 25th, 2016
310
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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. }
RAW Paste Data

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×