Modding Help How to add new farm maps without replacing old ones?

Discussion in 'Mods' started by Arkanzier, Mar 16, 2017.

  1. Arkanzier

    Arkanzier Void-Bound Voyager

    I'm working on a new farm map and I'd like to add it as an additional option, rather than just replacing one of the existing map options. It looks like the game would do the work for me if I can get an extra entry into the farmTypeButtons variable under CharacterCustomization.cs but, problem is, it's private and I don't know of a way to gain access to it.

    Is there some way that anyone knows to do that without recompiling any of the game itself?

    If not, is there a way to get SMAPI 1.8 to tell me when the user is on the new game screen so I can have it listen for a particular key press or something?
     
    • Hammurabi

      Hammurabi Big Damn Hero

      Possibly, but it will definitely require reflection to do so. I'll look into it and get back to you.
       
      • Hammurabi

        Hammurabi Big Damn Hero

        Well... it seems that this is a bit buggy as well as being totally non-functional without a lot of extra work. If you just add a new button to the list, it'll show a new button on the screen... very far to the left of where it should be. The button will also be unselectable, and looking a little closer at the code, it would actually require you to intercept or overwrite the CharacterCustomization.optionButtonClick(string name) method to make it work (since that is where the game actually sets the effects of your farm selection), which is a bit beyond my skill level.

        Here's what I came up with, which does at least add the button:

        Code:
        using System;
        using System.Collections.Generic;
        using System.Reflection;
        using Microsoft.Xna.Framework;
        using StardewModdingAPI;
        using StardewModdingAPI.Events;
        using StardewValley;
        using StardewValley.Menus;
        
        namespace NewMapOptionTest {
           public class Class1 : Mod
          {
             public override void Entry(IModHelper helper) {
               MenuEvents.MenuChanged += MenuEvents_MenuChanged;
             }
        
             public void MenuEvents_MenuChanged(object sender, EventArgsClickableMenuChanged e) {
               if (Game1.activeClickableMenu is TitleMenu) {
                 GameEvents.UpdateTick += AddFarmOption;
               }
             }
        
             public void AddFarmOption(object sender, EventArgs e) {
               if (Game1.activeClickableMenu is TitleMenu) {
                 IClickableMenu subMenu = (IClickableMenu) typeof(TitleMenu).GetField("subMenu", BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance).GetValue(Game1.activeClickableMenu);
                 if (subMenu is CharacterCustomization) {
                   List<ClickableTextureComponent> farmList = (List<ClickableTextureComponent>) typeof(CharacterCustomization).GetField("farmTypeButtons", BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance).GetValue((CharacterCustomization) subMenu);
                   ClickableTextureComponent lastEntry = farmList[farmList.Count - 1];
                   Point point = new Point(lastEntry.sourceRect.X, lastEntry.sourceRect.Y);
                   farmList.Add(new ClickableTextureComponent("Test", new Rectangle(point.X, point.Y + 22 * Game1.pixelZoom, 22 * Game1.pixelZoom, 20 * Game1.pixelZoom), (string) null, Game1.content.LoadString("Strings\\UI:Character_FarmStandard"), Game1.mouseCursors, new Rectangle(0, 324, 22, 20), (float) Game1.pixelZoom, false));
        
                   GameEvents.UpdateTick -= AddFarmOption;
                   GameEvents.UpdateTick += WatchForBackButton;
                 }
               }
             }
        
             public void WatchForBackButton(object sender, EventArgs e) {
               if (Game1.activeClickableMenu is TitleMenu) {
                 IClickableMenu subMenu = (IClickableMenu) typeof(TitleMenu).GetField("subMenu", BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance).GetValue(Game1.activeClickableMenu);
                 if (!(subMenu is CharacterCustomization)) {
                   GameEvents.UpdateTick -= WatchForBackButton;
                   GameEvents.UpdateTick += AddFarmOption;
                 }
               }
             }
           }
        }
        
         
        • Arkanzier

          Arkanzier Void-Bound Voyager

          Thanks for taking a look for me. You managed to get it halfway there, which is much further than me.

          I'll mess around with it a bit later tonight, maybe I'll come up with something to bring it the rest of the way.
           
          • Entoarox

            Entoarox Oxygen Tank

            With the current limits it is not possible, CA hardcoded a lot of the mechanics behind the extra farm types, including what type is linked to what file, so until Farmhand (eventually) releases, this is simply outside of our capability to even try.
             

            Share This Page