Zariteis vor 4 Jahren
Commit
ed6084bb1b

+ 512 - 0
.gitignore

@@ -0,0 +1,512 @@
+### Csharp ###
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
+
+# User-specific files
+*.rsuser
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Mono auto generated files
+mono_crash.*
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+[Ll]ogs/
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUnit
+*.VisualState.xml
+TestResult.xml
+nunit-*.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_h.h
+*.ilk
+*.meta
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*_wpftmp.csproj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# Visual Studio Trace Files
+*.e2e
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Coverlet is a free, cross platform Code Coverage Tool
+coverage*[.json, .xml, .info]
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# NuGet Symbol Packages
+*.snupkg
+# The packages folder can be ignored because of Package Restore
+**/[Pp]ackages/*
+# except build/, which is used as an MSBuild target.
+!**/[Pp]ackages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+*.appxbundle
+*.appxupload
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!?*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+*.rptproj.rsuser
+*- [Bb]ackup.rdl
+*- [Bb]ackup ([0-9]).rdl
+*- [Bb]ackup ([0-9][0-9]).rdl
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# CodeRush personal settings
+.cr/personal
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+# Local History for Visual Studio
+.localhistory/
+
+# BeatPulse healthcheck temp database
+healthchecksdb
+
+# Backup folder for Package Reference Convert tool in Visual Studio 2017
+MigrationBackup/
+
+# Ionide (cross platform F# VS Code tools) working folder
+.ionide/
+
+### vs ###
+
+# User-specific files
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+
+# Mono auto generated files
+
+# Build results
+
+# Visual Studio 2015/2017 cache/options directory
+# Uncomment if you have tasks that create the project's static files in wwwroot
+
+# Visual Studio 2017 auto generated files
+
+# MSTest test Results
+
+# NUnit
+
+# Build Results of an ATL Project
+
+# Benchmark Results
+
+# .NET Core
+
+# StyleCop
+
+# Files built by Visual Studio
+
+# Chutzpah Test files
+
+# Visual C++ cache files
+
+# Visual Studio profiler
+
+# Visual Studio Trace Files
+
+# TFS 2012 Local Workspace
+
+# Guidance Automation Toolkit
+
+# ReSharper is a .NET coding add-in
+
+# TeamCity is a build add-in
+
+# DotCover is a Code Coverage Tool
+
+# AxoCover is a Code Coverage Tool
+
+# Coverlet is a free, cross platform Code Coverage Tool
+
+# Visual Studio code coverage results
+
+# NCrunch
+
+# MightyMoose
+
+# Web workbench (sass)
+
+# Installshield output folder
+
+# DocProject is a documentation generator add-in
+
+# Click-Once directory
+
+# Publish Web Output
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+
+# NuGet Packages
+# NuGet Symbol Packages
+# The packages folder can be ignored because of Package Restore
+# except build/, which is used as an MSBuild target.
+# Uncomment if necessary however generally it will be regenerated when needed
+# NuGet v3's project.json files produces more ignorable files
+
+# Microsoft Azure Build Output
+
+# Microsoft Azure Emulator
+
+# Windows Store app package directories and files
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+# but keep track of directories ending in .cache
+
+# Others
+
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+
+# RIA/Silverlight projects
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+
+# SQL Server files
+
+# Business Intelligence projects
+
+# Microsoft Fakes
+
+# GhostDoc plugin setting file
+
+# Node.js Tools for Visual Studio
+
+# Visual Studio 6 build log
+
+# Visual Studio 6 workspace options file
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+
+# Visual Studio LightSwitch build output
+
+# Paket dependency manager
+
+# FAKE - F# Make
+
+# CodeRush personal settings
+
+# Python Tools for Visual Studio (PTVS)
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+
+# Telerik's JustMock configuration file
+
+# BizTalk build output
+
+# OpenCover UI analysis results
+
+# Azure Stream Analytics local run output
+
+# MSBuild Binary and Structured Log
+
+# NVidia Nsight GPU debugger configuration file
+
+# MFractors (Xamarin productivity tool) working folder
+
+# Local History for Visual Studio
+
+# BeatPulse healthcheck temp database
+
+# Backup folder for Package Reference Convert tool in Visual Studio 2017
+
+# Ionide (cross platform F# VS Code tools) working folder

+ 163 - 0
API/RecipePage.cs

@@ -0,0 +1,163 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace RecipeMenuCore.API
+{
+  /// <summary>
+  /// Defines a custom RecipePage. Make sure to call Register on it to enable your RecipePage and to add at least one RecipePageEntry using AddRecipePageEntry.
+  /// </summary>
+  public class RecipePage
+  {
+    /// <summary>
+    /// The RecipePageType of this RecipePage
+    /// </summary>
+    public readonly RecipePageType Type;
+
+    /// <summary>
+    /// The Title displayed on top of this RecipePage.
+    /// </summary>
+    public readonly string Title;
+
+    /// <summary>
+    /// The Texture associated with this RecipePage. May be null.
+    /// </summary>
+    public Texture Tex { get; protected set; }
+
+    /// <summary>
+    /// The Material associated with this RecipePage. May be null.
+    /// </summary>
+    public Material Mat { get; protected set; }
+
+    internal List<RecipePageEntry> Rows = new List<RecipePageEntry>();
+
+    /// <summary>
+    /// Use to create a new RecipePage. Make sure to call Register on it to enable your RecipePage.
+    /// </summary>
+    public RecipePage(RecipePageType Type, string Title, Texture Tex)
+    {
+      this.Type = Type;
+      this.Title = Title;
+      this.Tex = Tex;
+    }
+
+    /// <summary>
+    /// Use to create a new RecipePage. Make sure to call Register on it to enable your RecipePage.
+    /// </summary>
+    public RecipePage(RecipePageType Type, string Title, Material Mat)
+    {
+      this.Type = Type;
+      this.Title = Title;
+      this.Mat = Mat;
+    }
+
+    /// <summary>
+    /// Used to register the page and make it show.
+    /// </summary>
+    public virtual RecipePage Register()
+    {
+      PostRegister();
+      switch (Type)
+      {
+        case RecipePageType.GearForge:
+          Core.pageGearForgeInfoList.Add(this);
+          break;
+        case RecipePageType.AlchemyStation:
+          Core.pageAlchemyStationInfoList.Add(this);
+          break;
+        case RecipePageType.UltimateForge:
+          Core.pageUltimateForgeInfoList.Add(this);
+          break;
+        case RecipePageType.UniversalCrafter:
+          Core.pageUniversalCrafterInfoList.Add(this);
+          break;
+      }
+      return this;
+    }
+
+    /// <summary>
+    /// Used to register the page to repalce a vanilla one and make it show.
+    /// </summary>
+    public virtual RecipePage RegisterAsVanilla(int i)
+    {
+      PostRegister();
+      switch (Type)
+      {
+        case RecipePageType.GearForge:
+          Core.pageGearForgeInfoListVanilla[i] = this;
+          break;
+        case RecipePageType.AlchemyStation:
+          Core.pageAlchemyStationInfoListVanilla[i] = this;
+          break;
+        case RecipePageType.UltimateForge:
+          Core.pageUltimateForgeInfoListVanilla[i] = this;
+          break;
+      }
+      return this;
+    }
+
+    protected void PostRegister()
+    {
+      if (Mat == null)
+      {
+        Mat = new Material(Shader.Find("Unlit/Transparent"))
+        {
+          mainTexture = Tex
+        };
+      }
+      else
+      {
+        Tex = Mat.mainTexture;
+      }
+    }
+
+    /// <summary>
+    /// Used to register the RecipePage to make it show up.
+    /// </summary>
+    public RecipePageType GetEntryType()
+    {
+      return Type;
+    }
+
+    /// <summary>
+    /// Adds a new RecipePageEntry to the RecipePage.
+    /// </summary>
+    public void AddRecipePageEntry(RecipePageEntry row)
+    {
+      Rows.Add(row);
+    }
+
+    /// <summary>
+    /// Returns the list of avalible RecipePageEntry on this RecipePage.
+    /// </summary>
+    public RecipePageEntry[] GetRecipePageEntries()
+    {
+      return Rows.ToArray();
+    }
+  }
+
+  /// <summary>
+  /// This indicates what types of recipes are avalible.
+  /// </summary>
+  public enum RecipePageType
+  {
+    /// <summary>
+    /// This recipe is for the Gear Forge.
+    /// </summary>
+    GearForge,
+
+    /// <summary>
+    /// This recipe is for the Alchemy Station.
+    /// </summary>
+    AlchemyStation,
+
+    /// <summary>
+    /// This recipe is for the Ultimate Forge.
+    /// </summary>
+    UltimateForge,
+
+    /// <summary>
+    /// This recipe is for the Gadget Core Universal Crafter.
+    /// </summary>
+    UniversalCrafter
+  }
+}

+ 65 - 0
API/RecipePageEntry.cs

@@ -0,0 +1,65 @@
+namespace RecipeMenuCore.API
+{
+  public class RecipePageEntry
+  {
+    /// <summary>
+    /// The ultimate items in UltimateFore recipes or the inputs in other recipes.
+    /// </summary>
+    public int[] ItemIdExtension { get; protected set; }
+
+    /// <summary>
+    /// The normal item in UltimateFore recipes or the output in other recipes.
+    /// </summary>
+    public int ItemIdBase { get; protected set; }
+
+    /// <summary>
+    /// The MinAmount of items created from a recipe.
+    /// </summary>
+    public int MinAmount { get; protected set; }
+
+    /// <summary>
+    /// The MaxBonusAmount to be added to the base value.
+    /// </summary>
+    public int MaxBonusAmount { get; protected set; }
+
+    /// <summary>
+    /// Should the input be visible, if the craft has never been done before.
+    /// </summary>
+    public bool AllwaysShowInput { get; protected set; }
+
+    /// <summary>
+    /// Use to create a new RecipePageEntry.
+    /// </summary>
+    /// <param name="id1">The first ultimate item in UltimateFore recipes or the first input in other recipes.</param>
+    /// <param name="id2">The second ultimate item in UltimateFore recipes or the second input in other recipes.</param>
+    /// <param name="id3">The third ultimate item in UltimateFore recipes or the third input in other recipes.</param>
+    /// <param name="idBase">The normal item in UltimateFore recipes or the output in other recipes.</param>
+    /// <param name="min">The minimum amount of items created from a recipe.</param>
+    /// <param name="maxBonus">The maximum bonus amount of items created from a recipe.</param>
+    public RecipePageEntry(int id1, int id2, int id3, int idBase, int min = 1, int maxBonus = 0)
+    {
+      ItemIdExtension = new int[] { id1, id2, id3 };
+      ItemIdBase = idBase;
+      MinAmount = min;
+      MaxBonusAmount = maxBonus;
+    }
+
+    /// <summary>
+    /// Use to create a new RecipePageEntry.
+    /// </summary>
+    /// <param name="id1">The first ultimate item in UltimateFore recipes or the first input in other recipes.</param>
+    /// <param name="id2">The second ultimate item in UltimateFore recipes or the second input in other recipes.</param>
+    /// <param name="id3">The third ultimate item in UltimateFore recipes or the third input in other recipes.</param>
+    /// <param name="idBase">The normal item in UltimateFore recipes or the output in other recipes.</param>
+    /// <param name="min">The minimum amount of items created from a recipe.</param>
+    /// <param name="maxBonus">The maximum bonus amount of items created from a recipe.</param>
+    public RecipePageEntry(int id1, int id2, int id3, int idBase, int min = 1, int maxBonus = 0, bool allwaysShowInput = false)
+    {
+      ItemIdExtension = new int[] { id1, id2, id3 };
+      ItemIdBase = idBase;
+      MinAmount = min;
+      MaxBonusAmount = maxBonus;
+      AllwaysShowInput = allwaysShowInput;
+    }
+  }
+}

BIN
Assets/hoverItem.png


BIN
Assets/recipeLock.png


BIN
Assets/recipeLockSmall.png


+ 23 - 0
Core.cs

@@ -0,0 +1,23 @@
+using GadgetCore;
+using GadgetCore.API;
+using RecipeMenuCore.API;
+using System.Collections.Generic;
+
+namespace RecipeMenuCore
+{
+  internal static class Core
+  {
+    internal static List<RecipePage> pageGearForgeInfoList = new List<RecipePage>();
+    internal static List<RecipePage> pageAlchemyStationInfoList = new List<RecipePage>();
+    internal static List<RecipePage> pageUltimateForgeInfoList = new List<RecipePage>();
+    internal static List<RecipePage> pageUniversalCrafterInfoList = new List<RecipePage>();
+
+    internal static RecipePage[] pageGearForgeInfoListVanilla = new RecipePage[6];
+    internal static RecipePage[] pageAlchemyStationInfoListVanilla = new RecipePage[2];
+    internal static RecipePage[] pageUltimateForgeInfoListVanilla = new RecipePage[6];
+
+    internal static bool settingUseDialog;
+
+    internal static GadgetLogger logger;
+  }
+}

+ 3 - 0
Manifest.ini

@@ -0,0 +1,3 @@
+[Metadata]
+Name=Recipe Menu Core
+Assembly=RecipeMenuCore.dll

+ 1 - 0
ModInfo.txt

@@ -0,0 +1 @@
+A utility mod providing a recipe menu API.

+ 26 - 0
Patches/Patch_CraftMenuInfo_AllowQuickCrafting.cs

@@ -0,0 +1,26 @@
+using HarmonyLib;
+using GadgetCore.API;
+using UnityEngine;
+using System.Collections;
+using System.Reflection;
+using System.Collections.Generic;
+
+namespace RecipeMenuCore.Patches
+{
+  [HarmonyPatch(typeof(CraftMenuInfo))]
+  [HarmonyPatch("AllowQuickCrafting")]
+  [HarmonyGadget("RecipeMenuCore")]
+  public static class Patch_CraftMenuInfo_AllowQuickCrafting
+  {
+    [HarmonyPrefix]
+    public static bool Prefix(CraftMenuInfo __instance, ref bool __result)
+    {
+      if(__instance.GetRegistryName() == "Gadget Core:Crafter Menu")
+      {
+        __result = Core.pageUniversalCrafterInfoList.Count > 0;
+        return false;
+      }
+      return true;
+    }
+  }
+}

+ 173 - 0
Patches/Patch_GameScript_HoverRecipeSelect.cs

@@ -0,0 +1,173 @@
+using HarmonyLib;
+using GadgetCore.API;
+using UnityEngine;
+using System.Collections;
+using System.Reflection;
+using System.Collections.Generic;
+using System.Globalization;
+
+namespace RecipeMenuCore.Patches
+{
+  [HarmonyPatch(typeof(GameScript))]
+  [HarmonyPatch("HoverRecipeSelect")]
+  [HarmonyGadget("RecipeMenuCore")]
+  public static class Patch_GameScript_HoverRecipeSelect
+  {
+    [HarmonyPrefix]
+    public static bool Prefix(GameScript __instance, int id, int ___craftType, ref int ___curRecipePage, GameObject ___itemexpbar, GameObject[] ___aspectObj, TextMesh ___itemName,
+      GameObject ___hoverItem, TextMesh[] ___itemStat, GameObject ___txtStats, TextMesh ___itemDesc, Material ___hoverItemMat2, Material ___hoverItemMat1, GameObject ___hoverDroid,
+      TextMesh[] ___txtHoverStat, TextMesh ___txtHoverStatInfo, TextMesh[] ___itemAspect, TextMesh ___itemLevel, GameObject[] ___recipeLock)
+    {
+      if (!Core.settingUseDialog)
+        return true;
+
+      if (___craftType == 0 || ___craftType == 1 || ___craftType == MenuRegistry.Singleton["Gadget Core:Crafter Menu"].GetID())
+      {
+        if (id >= 12 || ___recipeLock[id].active)
+        {
+          ___hoverItem.SetActive(false);
+          return false;
+        }
+      }
+      var item = new Item(GetItemId(__instance, id, ___craftType, ___curRecipePage), 1, 0, 0, 0, new int[3], new int[3]);
+      var itemInfo = ItemRegistry.GetItem(item.id);
+
+      ___txtHoverStat[0].text = string.Empty;
+      ___txtHoverStat[1].text = ___txtHoverStat[0].text;
+      ___txtHoverStatInfo.text = string.Empty;
+      ___aspectObj[0].SetActive(false);
+      ___aspectObj[1].SetActive(false);
+      ___aspectObj[2].SetActive(false);
+      ___itemAspect[0].text = string.Empty;
+      ___itemAspect[1].text = string.Empty;
+      ___itemAspect[2].text = string.Empty;
+      ___itemLevel.text = string.Empty;
+
+      if (Camera.main.ScreenToWorldPoint(Input.mousePosition).y < MenuScript.player.transform.position.y - 4.5f)
+        ___hoverItem.transform.localPosition = new Vector3(5f, 0f, -4.55f);
+      else
+        ___hoverItem.transform.localPosition = new Vector3(5f, -4f, -4.55f);
+
+      ___hoverDroid.SetActive(false);
+      ___itemexpbar.SetActive(false);
+
+      if (item.id > 0)
+      {
+        ___itemName.text = itemInfo.Name;
+        ___itemName.color = Color.white;
+        ___itemDesc.text = GenerateDescription(itemInfo);
+
+        bool hasStats = false;
+        int[] gearBaseStats = ItemRegistry.GetItem(item.id).Stats.GetStatArray();
+        for (int i = 0; i < 6; i++)
+        {
+          if (gearBaseStats[i] > 0)
+          {
+            ___itemStat[i].text = "+" + gearBaseStats[i];
+            hasStats = true;
+          }
+          else
+            ___itemStat[i].text = string.Empty;
+        }
+        ___txtStats.SetActive(hasStats);
+        ___hoverItem.SetActive(true);
+        if (hasStats)
+          ___hoverItem.GetComponent<Renderer>().material = hoverItem;
+        else
+          ___hoverItem.GetComponent<Renderer>().material = ___hoverItemMat1;
+      }
+      else
+      {
+        ___hoverItem.SetActive(false);
+      }
+      return false;
+    }
+
+    private static Material hoverItem = new Material(Shader.Find("Unlit/Transparent"))
+    {
+      mainTexture = GadgetCoreAPI.LoadTexture2D("hoverItem.png")
+    };
+
+    private static string GenerateDescription(ItemInfo item)
+    {
+      if ((item.GetID() >= 1000 && item.GetID() < 1000 + 6)
+        || (item.GetID() >= 1012 && item.GetID() < 1012 + 3 * 6))
+        return "";
+      var desc = item.Desc;
+      if (desc == null || desc.Length <= 0)
+      {
+        float[] ws = item.WeaponScaling;
+        if (ws != null)
+        {
+          string o = "";
+          for (int i = 0; i < ws.Length; i++)
+          {
+            if (ws[i] > 0)
+            {
+              string type = i == 0 ? "VIT" : i == 1 ? "STR" : i == 2 ? "DEX" : i == 3 ? "TEC" : i == 4 ? "MAG" : "FTH";
+              o += "DMG x" + (ws[i] >= 1 ? ws[i].ToString(CultureInfo.InvariantCulture) : "1/" + (1 / ws[i])).ToString(CultureInfo.InvariantCulture) + " " + type + "\n";
+            }
+          }
+          return o;
+        }
+      }
+      return desc;
+    }
+
+    private static int GetItemId(GameScript __instance, int index, int craftType, int curRecipePage)
+    {
+      if (index >= 12)
+      {
+        if (craftType == 2 && curRecipePage >= 6)
+          return Core.pageUltimateForgeInfoList[curRecipePage - 6].GetRecipePageEntries()[(index - 12) / 3].ItemIdExtension[(index - 12) % 3];
+        return CalculateUltimaleWeapon((index - 12) % (3 * 6), (index - 12) / (3 * 6) + curRecipePage * 2);
+      }
+
+      if (craftType == 0 && curRecipePage >= 6)
+        return Core.pageGearForgeInfoList[curRecipePage - 6].GetRecipePageEntries()[index].ItemIdBase;
+      else if (craftType == 1 && curRecipePage >= 2)
+        return Core.pageAlchemyStationInfoList[curRecipePage - 2].GetRecipePageEntries()[index].ItemIdBase;
+      else if (craftType == 2 && curRecipePage >= 6)
+        return Core.pageUltimateForgeInfoList[curRecipePage - 6].GetRecipePageEntries()[index].ItemIdBase;
+      else if (craftType == MenuRegistry.Singleton["Gadget Core:Crafter Menu"].GetID())
+        return Core.pageUniversalCrafterInfoList[curRecipePage].GetRecipePageEntries()[index].ItemIdBase;
+
+      else if (craftType == 0 && curRecipePage < 6 && Core.pageGearForgeInfoListVanilla[curRecipePage] != null)
+        return Core.pageGearForgeInfoListVanilla[curRecipePage].GetRecipePageEntries()[index].ItemIdBase;
+      else if (craftType == 1 && curRecipePage < 2 && Core.pageAlchemyStationInfoListVanilla[curRecipePage] != null)
+        return Core.pageAlchemyStationInfoListVanilla[curRecipePage].GetRecipePageEntries()[index].ItemIdBase;
+      else if (craftType == 2 && curRecipePage < 6 && Core.pageUltimateForgeInfoListVanilla[curRecipePage] != null)
+        return Core.pageUltimateForgeInfoListVanilla[curRecipePage].GetRecipePageEntries()[index].ItemIdBase;
+
+      return __instance.GetRecipeItem(curRecipePage, index).id;
+    }
+    private static int CalculateUltimaleWeapon(int index, int page)
+    {
+      if (page == 0)
+        return 312 + index;
+      if (page == 1)
+        return 362 + index;
+      if (page == 2)
+        return 412 + index;
+      if (page == 3)
+        return 462 + index;
+      if (page == 4)
+        return 512 + index;
+      if (page == 5)
+        return 562 + index;
+      if (page == 6) //shield
+        return 612 + index;
+      if (page == 7) //droid
+        return 1012 + index;
+      if (page == 8) //helmet 1
+        return 750 + index;
+      if (page == 9) //helmet 2
+        return 768 + index;
+      if (page == 10) //armor 1
+        return 850 + index;
+      if (page == 11) //armor 2
+        return 868 + index;
+      return 0;
+    }
+  }
+}

+ 31 - 0
Patches/Patch_GameScript_RecipeDown.cs

@@ -0,0 +1,31 @@
+using HarmonyLib;
+using GadgetCore.API;
+using UnityEngine;
+using System.Collections;
+
+namespace RecipeMenuCore.Patches
+{
+  [HarmonyPatch(typeof(GameScript))]
+  [HarmonyPatch("RecipeDown")]
+  [HarmonyGadget("RecipeMenuCore")]
+  public static class Patch_GameScript_RecipeDown
+  {
+    [HarmonyPrefix]
+    public static bool Prefix(GameScript __instance, int ___craftType, ref int ___curRecipePage)
+    {
+      int pages = 1;
+      if (___craftType == 0)
+        pages = 6 + Core.pageGearForgeInfoList.Count;
+      else if (___craftType == 1)
+        pages = 2 + Core.pageAlchemyStationInfoList.Count;
+      else if (___craftType == 2)
+        pages = 6 + Core.pageUltimateForgeInfoList.Count;
+      else if (___craftType == MenuRegistry.Singleton["Gadget Core:Crafter Menu"].GetID())
+        pages = Core.pageUniversalCrafterInfoList.Count;
+
+      ___curRecipePage = (___curRecipePage + pages - 1) % pages;
+      __instance.RefreshRecipe();
+      return false;
+    }
+  }
+}

+ 31 - 0
Patches/Patch_GameScript_RecipeUp.cs

@@ -0,0 +1,31 @@
+using HarmonyLib;
+using GadgetCore.API;
+using UnityEngine;
+using System.Collections;
+
+namespace RecipeMenuCore.Patches
+{
+  [HarmonyPatch(typeof(GameScript))]
+  [HarmonyPatch("RecipeUp")]
+  [HarmonyGadget("RecipeMenuCore")]
+  public static class Patch_GameScript_RecipeUp
+  {
+    [HarmonyPrefix]
+    public static bool Prefix(GameScript __instance, int ___craftType, ref int ___curRecipePage)
+    {
+      int pages = 1;
+      if (___craftType == 0)
+        pages = 6 + Core.pageGearForgeInfoList.Count;
+      else if (___craftType == 1)
+        pages = 2 + Core.pageAlchemyStationInfoList.Count;
+      else if (___craftType == 2)
+        pages = 6 + Core.pageUltimateForgeInfoList.Count;
+      else if (___craftType == MenuRegistry.Singleton["Gadget Core:Crafter Menu"].GetID())
+        pages = Core.pageUniversalCrafterInfoList.Count;
+
+      ___curRecipePage = (___curRecipePage + 1) % pages;
+      __instance.RefreshRecipe();
+      return false;
+    }
+  }
+}

+ 94 - 0
Patches/Patch_GameScript_RefreshRecipe.cs

@@ -0,0 +1,94 @@
+using HarmonyLib;
+using GadgetCore.API;
+using UnityEngine;
+using System.Collections;
+
+namespace RecipeMenuCore.Patches
+{
+  [HarmonyPatch(typeof(GameScript))]
+  [HarmonyPatch("RefreshRecipe")]
+  [HarmonyGadget("RecipeMenuCore")]
+  public static class Patch_GameScript_RefreshRecipe
+  {
+    [HarmonyPrefix]
+    public static bool Prefix(GameScript __instance, int ___craftType, int ___curRecipePage)
+    {
+      if (___craftType == 0)
+      {
+        __instance.txtRecipeName[0].text = string.Empty + __instance.GetRecipeName0(___curRecipePage);
+        __instance.txtRecipeUnlocked[0].text = "Page " + (___curRecipePage + 1) + "/" + (6 + Core.pageGearForgeInfoList.Count);
+      }
+      else if (___craftType == 1)
+      {
+        __instance.txtRecipeName[0].text = string.Empty + __instance.GetRecipeName1(___curRecipePage);
+        __instance.txtRecipeUnlocked[0].text = "Page " + (___curRecipePage + 1) + "/" + (2 + Core.pageAlchemyStationInfoList.Count);
+      }
+      else if (___craftType == 2)
+      {
+        __instance.txtRecipeName[0].text = string.Empty + __instance.GetRecipeName2(___curRecipePage);
+        __instance.txtRecipeUnlocked[0].text = "Page " + (___curRecipePage + 1) + "/" + (6 + Core.pageUltimateForgeInfoList.Count);
+      }
+      else if (___craftType == MenuRegistry.Singleton["Gadget Core:Crafter Menu"].GetID())
+      {
+        __instance.txtRecipeName[0].text = string.Empty + __instance.GetRecipeName2(___curRecipePage);
+        __instance.txtRecipeUnlocked[0].text = "Page " + (___curRecipePage + 1) + "/" + (Core.pageUniversalCrafterInfoList.Count);
+      }
+      __instance.txtRecipeUnlocked[0].gameObject.GetComponent<Animation>().Play();
+      __instance.txtRecipeName[0].gameObject.GetComponent<Animation>().Play();
+      __instance.txtRecipeName[1].text = __instance.txtRecipeName[0].text;
+      __instance.txtRecipeUnlocked[1].text = __instance.txtRecipeUnlocked[0].text;
+      if ((___craftType != 0 || (___curRecipePage <= 5 && Core.pageGearForgeInfoListVanilla[___curRecipePage] == null))
+        && (___craftType != 1 || (___curRecipePage <= 1 && Core.pageAlchemyStationInfoListVanilla[___curRecipePage] == null))
+        && (___craftType != 2 || (___curRecipePage <= 5 && Core.pageUltimateForgeInfoListVanilla[___curRecipePage] == null))
+        && (___craftType != MenuRegistry.Singleton["Gadget Core:Crafter Menu"].GetID()))
+      {
+        __instance.menuRecipe.GetComponent<Renderer>().material = (Material)Resources.Load(string.Concat(new object[] { "mat/r", ___curRecipePage, "t", ___craftType }));
+      }
+      else
+      {
+        if (___craftType == 0)
+        {
+          var page = ___curRecipePage >= 6 ? Core.pageGearForgeInfoList[___curRecipePage - 6] : Core.pageGearForgeInfoListVanilla[___curRecipePage];
+          __instance.txtRecipeName[0].text = page.Title;
+          __instance.txtRecipeName[1].text = __instance.txtRecipeName[0].text;
+          __instance.menuRecipe.GetComponent<Renderer>().material = page.Mat;
+        }
+        else if (___craftType == 1)
+        {
+          var page = ___curRecipePage >= 2 ? Core.pageAlchemyStationInfoList[___curRecipePage - 2] : Core.pageAlchemyStationInfoListVanilla[___curRecipePage];
+          __instance.txtRecipeName[0].text = page.Title;
+          __instance.txtRecipeName[1].text = __instance.txtRecipeName[0].text;
+          __instance.menuRecipe.GetComponent<Renderer>().material = page.Mat;
+        }
+        else if (___craftType == 2)
+        {
+          var page = ___curRecipePage >= 6 ? Core.pageUltimateForgeInfoList[___curRecipePage - 6] : Core.pageUltimateForgeInfoListVanilla[___curRecipePage];
+          __instance.txtRecipeName[0].text = page.Title;
+          __instance.txtRecipeName[1].text = __instance.txtRecipeName[0].text;
+          __instance.menuRecipe.GetComponent<Renderer>().material = page.Mat;
+        }
+        else if (___craftType == MenuRegistry.Singleton["Gadget Core:Crafter Menu"].GetID())
+        {
+          var page = Core.pageUniversalCrafterInfoList[___curRecipePage];
+          __instance.txtRecipeName[0].text = page.Title;
+          __instance.txtRecipeName[1].text = __instance.txtRecipeName[0].text;
+          __instance.menuRecipe.GetComponent<Renderer>().material = page.Mat;
+        }
+      }
+      __instance.RefreshRecipeUnlock();
+      return false;
+    }
+
+
+    [HarmonyPostfix]
+    [HarmonyAfter("URP.URP.gadget")]
+    public static void Postfix(GameScript __instance, int ___curRecipePage, int ___craftType)
+    {
+      if (___curRecipePage == 1 && ___craftType == 1 && Core.pageAlchemyStationInfoListVanilla[1] != null)
+      {
+        var page = Core.pageAlchemyStationInfoListVanilla[1];
+        __instance.menuRecipe.GetComponent<Renderer>().material = page.Mat;
+      }
+    }
+  }
+}

+ 174 - 0
Patches/Patch_GameScript_RefreshRecipeUnlock.cs

@@ -0,0 +1,174 @@
+using HarmonyLib;
+using GadgetCore.API;
+using UnityEngine;
+using System.Collections;
+using System.Reflection;
+using System.Collections.Generic;
+
+namespace RecipeMenuCore.Patches
+{
+  [HarmonyPatch(typeof(GameScript))]
+  [HarmonyPatch("RefreshRecipeUnlock")]
+  [HarmonyGadget("RecipeMenuCore")]
+  public static class Patch_GameScript_RefreshRecipeUnlock
+  {
+    private static Material recipeLockSmall = new Material(Shader.Find("Unlit/Transparent"))
+    {
+      mainTexture = GadgetCoreAPI.LoadTexture2D("recipeLockSmall.png")
+    };
+    private static Material recipeLock = new Material(Shader.Find("Unlit/Transparent"))
+    {
+      mainTexture = GadgetCoreAPI.LoadTexture2D("recipeLock.png")
+    };
+
+    [HarmonyPrefix]
+    public static bool Prefix(GameScript __instance, int ___craftType, int ___curRecipePage, GameObject ___ultLocksObj, GameObject ___recipeButtons,
+      GameObject[] ___recipeLock, GameObject[] ___ultLocks, int[,] ___ultLocksUnlocked)
+    {
+      if (___craftType == 0 || ___craftType == 1 || ___craftType == MenuRegistry.Singleton["Gadget Core:Crafter Menu"].GetID())
+      {
+        for (int i = 0; i < 12; i++)
+        {
+          ___recipeButtons.transform.GetChild(i).gameObject.SetActive(true);
+          ___recipeLock[i].GetComponent<Renderer>().material = recipeLock;
+        }
+      }
+
+      var hoverElements = ___ultLocksObj.transform.parent.Find("hoverElements").gameObject;
+      hoverElements.SetActive(false);
+
+      if (___craftType == 2 && ___curRecipePage < 6 && Core.pageUltimateForgeInfoListVanilla[___curRecipePage] == null)
+      {
+        hoverElements.SetActive(true);
+        for (int i = 0; i < 36; i++)
+        {
+          if (___ultLocksUnlocked[___curRecipePage, i] == 0)
+          {
+            hoverElements.transform.GetChild(i).gameObject.SetActive(false);
+          }
+          else
+          {
+            hoverElements.transform.GetChild(i).gameObject.SetActive(true);
+          }
+        }
+      }
+
+      if (___craftType == 0 && (___curRecipePage >= 6 || Core.pageGearForgeInfoListVanilla[___curRecipePage] != null))
+      {
+        ___ultLocksObj.SetActive(false);
+        ___recipeButtons.SetActive(true);
+        var page = ___curRecipePage >= 6 ? Core.pageGearForgeInfoList[___curRecipePage - 6] : Core.pageGearForgeInfoListVanilla[___curRecipePage];
+        for (int i = 0; i < 12; i++)
+        {
+          if (page.GetRecipePageEntries().Length > i)
+          {
+            int itemID = page.GetRecipePageEntries()[i].ItemIdBase;
+            if (__instance.RecipeCraftedAlready(itemID, page.GetRecipePageEntries()[i].MinAmount))
+              ___recipeLock[i].SetActive(false);
+            else
+            {
+              if (page.GetRecipePageEntries()[i].AllwaysShowInput)
+                ___recipeLock[i].GetComponent<Renderer>().material = recipeLockSmall;
+              ___recipeLock[i].SetActive(true);
+            }
+          }
+          else
+          {
+            ___recipeLock[i].SetActive(false);
+            ___recipeButtons.transform.GetChild(i).gameObject.SetActive(false);
+          }
+        }
+        return false;
+      }
+      else if (___craftType == 1 && (___curRecipePage >=2  || Core.pageAlchemyStationInfoListVanilla[___curRecipePage] != null))
+      {
+        ___ultLocksObj.SetActive(false);
+        ___recipeButtons.SetActive(true);
+        var page = ___curRecipePage >= 6 ? Core.pageAlchemyStationInfoList[___curRecipePage - 2] : Core.pageAlchemyStationInfoListVanilla[___curRecipePage];
+        for (int i = 0; i < 12; i++)
+        {
+          if (page.GetRecipePageEntries().Length > i)
+          {
+            int itemID = page.GetRecipePageEntries()[i].ItemIdBase;
+            if (__instance.RecipeCraftedAlready(itemID, page.GetRecipePageEntries()[i].MinAmount))
+              ___recipeLock[i].SetActive(false);
+            else
+            {
+              if (page.GetRecipePageEntries()[i].AllwaysShowInput)
+                ___recipeLock[i].GetComponent<Renderer>().material = recipeLockSmall;
+              ___recipeLock[i].SetActive(true);
+            }
+          }
+          else
+          {
+            ___recipeLock[i].SetActive(false);
+            ___recipeButtons.transform.GetChild(i).gameObject.SetActive(false);
+          }
+        }
+        return false;
+      }
+      else if (___craftType == 2 && (___curRecipePage >= 6 || Core.pageUltimateForgeInfoListVanilla[___curRecipePage] != null))
+      {
+        hoverElements.SetActive(true);
+        ___ultLocksObj.SetActive(true);
+        ___recipeButtons.SetActive(false);
+        var page = ___curRecipePage >= 6 ? Core.pageUltimateForgeInfoList[___curRecipePage - 6] : Core.pageUltimateForgeInfoListVanilla[___curRecipePage];
+        for (int i = 0; i < 36; i++)
+        {
+          if (i < 12)
+          {
+            ___recipeLock[i].SetActive(false);
+          }
+          if (page.GetRecipePageEntries().Length > i / 3)
+          {
+            int itemID = page.GetRecipePageEntries()[i / 3].ItemIdExtension[i % 3];
+            if (__instance.RecipeCraftedAlready(itemID, 1))
+            {
+              ___ultLocks[i].SetActive(false);
+              hoverElements.transform.GetChild(i).gameObject.SetActive(true);
+            }
+            else
+            {
+              ___ultLocks[i].SetActive(true);
+              hoverElements.transform.GetChild(i).gameObject.SetActive(false);
+            }
+          }
+          else
+          {
+            ___ultLocks[i].SetActive(false);
+            hoverElements.transform.GetChild(i).gameObject.SetActive(false);
+          }
+        }
+        return false;
+      }
+      else if (___craftType == MenuRegistry.Singleton["Gadget Core:Crafter Menu"].GetID())
+      {
+        ___ultLocksObj.SetActive(false);
+        ___recipeButtons.SetActive(true);
+        var page = Core.pageUniversalCrafterInfoList[___curRecipePage];
+        for (int i = 0; i < 12; i++)
+        {
+          if (page.GetRecipePageEntries().Length > i)
+          {
+            int itemID = page.GetRecipePageEntries()[i].ItemIdBase;
+            if (((CraftMenuInfo)MenuRegistry.Singleton["Gadget Core:Crafter Menu"]).IsRecipeUnlocked(itemID))
+              ___recipeLock[i].SetActive(false);
+            else
+            {
+              if (page.GetRecipePageEntries()[i].AllwaysShowInput)
+                ___recipeLock[i].GetComponent<Renderer>().material = recipeLockSmall;
+              ___recipeLock[i].SetActive(true);
+            }
+          }
+          else
+          {
+            ___recipeLock[i].SetActive(false);
+            ___recipeButtons.transform.GetChild(i).gameObject.SetActive(false);
+          }
+        }
+        return false;
+      }
+      return true;
+    }
+  }
+}

+ 200 - 0
Patches/Patch_GameScript_Update.cs

@@ -0,0 +1,200 @@
+using HarmonyLib;
+using GadgetCore.API;
+using UnityEngine;
+using System.Collections;
+using System.Reflection;
+using System.Collections.Generic;
+
+namespace RecipeMenuCore.Patches
+{
+  [HarmonyPatch(typeof(GameScript))]
+  [HarmonyPatch("Update")]
+  [HarmonyGadget("RecipeMenuCore")]
+  public static class Patch_GameScript_Update
+  {
+    [HarmonyPrefix]
+    public static bool Prefix(GameScript __instance, int ___craftType, int ___curRecipePage, Item[] ___inventory, Item[] ___craft)
+    {
+      bool acted = false;
+      if (MenuScript.player)
+      {
+        if (!GameScript.pausing)
+        {
+          if (Input.GetMouseButtonDown(0) && GameScript.inventoryOpen)
+          {
+            var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
+            RaycastHit hit;
+            if (Physics.Raycast(ray, out hit, 7f))
+            {
+              if (hit.transform.gameObject.layer == 16)
+              {
+                if (hit.transform.gameObject.tag == "recipe")
+                {
+                  var slotID = int.Parse(hit.transform.gameObject.name);
+                  MonoBehaviour.print("hit recipe");
+                  if (___craftType == 0 && (___curRecipePage >= 6 || Core.pageGearForgeInfoListVanilla[___curRecipePage] != null))
+                  {
+                    __instance.StartCoroutine(QuickCraft(__instance, ___curRecipePage, slotID, ___craftType, ___inventory, ___craft));
+                    acted = true;
+                  }
+                  else if (___craftType == 1 && (___curRecipePage >= 2 || Core.pageAlchemyStationInfoListVanilla[___curRecipePage] != null))
+                  {
+                    __instance.StartCoroutine(QuickCraft(__instance, ___curRecipePage, slotID, ___craftType, ___inventory, ___craft));
+                    acted = true;
+                  }
+                  else if (___craftType == 2 && (___curRecipePage >= 6 || Core.pageUltimateForgeInfoListVanilla[___curRecipePage] != null))
+                  {
+                    acted = true;
+                  }
+                  else if (___craftType == MenuRegistry.Singleton["Gadget Core:Crafter Menu"].GetID())
+                  {
+                    __instance.StartCoroutine(QuickCraft(__instance, ___curRecipePage, slotID, ___craftType, ___inventory, ___craft));
+                    acted = true;
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+      if (acted)
+        return false;
+      return true;
+    }
+
+    private static IEnumerator QuickCraft(GameScript __instance, int ___curRecipePage, int slot, int ___craftType, Item[] ___inventory, Item[] ___craft)
+    {
+      FieldInfo quickCraftingField = typeof(GameScript).GetField("quickCrafting", BindingFlags.NonPublic | BindingFlags.Instance);
+      FieldInfo holdingItemField = typeof(GameScript).GetField("holdingItem", BindingFlags.NonPublic | BindingFlags.Instance);
+
+      if (!(bool)quickCraftingField.GetValue(__instance))
+      {
+        quickCraftingField.SetValue(__instance, true);
+        try
+        {
+          int craftingItemID = 0;
+          int craftingItemAmount = 1;
+          List<int> price = new List<int>();
+          List<int> takePlayerInventory = new List<int>();
+          List<int> takeCraftingInventory = new List<int>();
+          bool hasAllItems = true;
+          if (___craftType == 0)
+          {
+            var recipePageEntry = ___curRecipePage >= 6 ? Core.pageGearForgeInfoList[___curRecipePage - 6].GetRecipePageEntries()[slot] : Core.pageGearForgeInfoListVanilla[___curRecipePage].GetRecipePageEntries()[slot];
+            craftingItemID = recipePageEntry.ItemIdBase;
+            craftingItemAmount = recipePageEntry.MinAmount + Random.Range(0, 1 + recipePageEntry.MaxBonusAmount);
+            for (int i = 0; i < recipePageEntry.ItemIdExtension.Length; i++)
+            {
+              var itemID = recipePageEntry.ItemIdExtension[i];
+              if (itemID > 0)
+                price.Add(itemID);
+            }
+          }
+          else if (___craftType == 1)
+          {
+            var recipePageEntry = ___curRecipePage >= 2 ? Core.pageAlchemyStationInfoList[___curRecipePage - 2].GetRecipePageEntries()[slot] : Core.pageAlchemyStationInfoListVanilla[___curRecipePage].GetRecipePageEntries()[slot];
+            craftingItemID = recipePageEntry.ItemIdBase;
+            craftingItemAmount = recipePageEntry.MinAmount + Random.Range(0, 1 + recipePageEntry.MaxBonusAmount);
+            for (int i = 0; i < recipePageEntry.ItemIdExtension.Length; i++)
+            {
+              var itemID = recipePageEntry.ItemIdExtension[i];
+              if (itemID > 0)
+                price.Add(itemID);
+            }
+          }
+          else if (___craftType == MenuRegistry.Singleton["Gadget Core:Crafter Menu"].GetID())
+          {
+            var recipePageEntry = Core.pageUniversalCrafterInfoList[___curRecipePage].GetRecipePageEntries()[slot];
+            craftingItemID = recipePageEntry.ItemIdBase;
+            craftingItemAmount = recipePageEntry.MinAmount + Random.Range(0, 1 + recipePageEntry.MaxBonusAmount);
+            for (int i = 0; i < recipePageEntry.ItemIdExtension.Length; i++)
+            {
+              var itemID = recipePageEntry.ItemIdExtension[i];
+              if (itemID > 0)
+                price.Add(itemID);
+            }
+          }
+          if (craftingItemID == 0 
+            || !(___craftType == MenuRegistry.Singleton["Gadget Core:Crafter Menu"].GetID()
+            ? ((CraftMenuInfo)MenuRegistry.Singleton["Gadget Core:Crafter Menu"]).IsRecipeUnlocked(craftingItemID)
+            : __instance.RecipeCraftedAlready(craftingItemID, 0) ))
+          {
+            yield break;
+          }
+          for (int i = 0; i < price.Count; i++)
+          {
+            int itemSlotPlayerInventory = __instance.ItemExistsSlot(price[i]);
+            int itemSlotCraftingInventory = __instance.ItemExistsCraft(price[i]);
+            if (itemSlotPlayerInventory == -1 && itemSlotCraftingInventory == -1)
+            {
+              hasAllItems = false;
+              break;
+            }
+            else if (itemSlotPlayerInventory != -1)
+              takePlayerInventory.Add(itemSlotPlayerInventory);
+            else if (itemSlotCraftingInventory != -1)
+              takeCraftingInventory.Add(itemSlotCraftingInventory);
+          }
+          if (hasAllItems)
+          {
+            bool hasCrafted = false;
+            Item tempItem = (Item)holdingItemField.GetValue(__instance);
+            if (tempItem == null || tempItem.id == 0 || tempItem.id == craftingItemID)
+            {
+              ItemInfo itemInfo = ItemRegistry.GetItem(craftingItemID);
+              ItemType slotItemType = itemInfo != null ? (itemInfo.Type & (ItemType.EQUIP_MASK | ItemType.TYPE_MASK)) : ItemRegistry.GetDefaultTypeByID(craftingItemID);
+              if ((slotItemType & ItemType.NONSTACKING) == ItemType.STACKING)
+              {
+                if (tempItem == null || tempItem.id == 0)
+                {
+                  holdingItemField.SetValue(__instance, new Item(craftingItemID, craftingItemAmount, 0, 0, 0, new int[3], new int[3]));
+                  hasCrafted = true;
+                }
+                else if (tempItem.q < 9999)
+                {
+                  tempItem.q += craftingItemAmount;
+                  if (tempItem.q > 9999)
+                    tempItem.q = 9999;
+                  hasCrafted = true;
+                }
+              }
+              else
+              {
+                if (tempItem == null || tempItem.id == 0)
+                {
+                  holdingItemField.SetValue(__instance, new Item(craftingItemID, 1, 0, __instance.GetRandomTier(), 0, new int[3], new int[3]));
+                  hasCrafted = true;
+                }
+              }
+            }
+            if (hasCrafted)
+            {
+              Object.Instantiate(Resources.Load("clickBurst"), new Vector3(Camera.main.ScreenToWorldPoint(Input.mousePosition).x, Camera.main.ScreenToWorldPoint(Input.mousePosition).y, 0f), Quaternion.identity);
+              __instance.GetComponent<AudioSource>().PlayOneShot((AudioClip)Resources.Load("Au/create"), Menuu.soundLevel / 10f);
+
+              for (int i = 0; i < takePlayerInventory.Count; i++)
+              {
+                ___inventory[takePlayerInventory[i]].q--;
+                __instance.RefreshSlot(takePlayerInventory[i]);
+              }
+              for (int i = 0; i < takeCraftingInventory.Count; i++)
+              {
+                ___craft[takeCraftingInventory[i]].q--;
+                __instance.RefreshSlotCraft(takeCraftingInventory[i]);
+              }
+            }
+            __instance.RefreshHoldingSlot();
+          }
+          else
+            __instance.Error(6);
+        }
+        catch (System.Exception e) { Core.logger.Log(e); }
+        finally
+        {
+          quickCraftingField.SetValue(__instance, false);
+        }
+      }
+      yield break;
+    }
+  }
+}

+ 10 - 0
Properties/AssemblyInfo.cs

@@ -0,0 +1,10 @@
+using System.Reflection;
+using static RecipeMenuCore.RecipeMenuCore;
+
+[assembly: AssemblyProduct("RecipeMenuCore")] //Set this to the full name of the mod including spaces.
+[assembly: AssemblyTitle("ScrapYard")] //This is only used when mousing over a dll file in Windows explorer.
+[assembly: AssemblyDescription("A utility mod providing a recipe menu API.")] //This is a short description for your mod's assembly.
+[assembly: AssemblyCompany("")] //Set this to your name/nickname and/or website
+[assembly: AssemblyCopyright("© 2021 Zariteis. All rights reserved.")] //Set this to your copyright name.
+[assembly: AssemblyVersion(MOD_VERSION)]
+[assembly: AssemblyFileVersion(MOD_VERSION)]

+ 8 - 0
Properties/launchSettings.json

@@ -0,0 +1,8 @@
+{
+  "profiles": {
+    "RecipeMenuCore": {
+      "commandName": "Executable",
+      "executablePath": "C:\\Program Files (x86)\\Steam\\steamapps\\common\\Roguelands\\Roguelands.exe"
+    }
+  }
+}

+ 77 - 0
RecipeMenuCore.cs

@@ -0,0 +1,77 @@
+using GadgetCore.API;
+using GadgetCore.API.ConfigMenu;
+using RecipeMenuCore.API;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.SceneManagement;
+
+namespace RecipeMenuCore
+{
+
+  [Gadget("RecipeMenuCore", RequiredOnClients: false)]
+  public class RecipeMenuCore : Gadget<RecipeMenuCore>
+  {
+    public const string MOD_VERSION = "1.6"; // Set this to the version of your mod.
+    public const string CONFIG_VERSION = "1.0"; // Increment this whenever you change your mod's config file.
+
+    protected override void LoadConfig()
+    {
+      Config.Load();
+      string fileVersion = Config.ReadString("ConfigVersion", CONFIG_VERSION, comments: "The Config Version (not to be confused with mod version)");
+      if (fileVersion != CONFIG_VERSION)
+      {
+        Config.Reset();
+        Config.WriteString("ConfigVersion", CONFIG_VERSION, comments: "The Config Version (not to be confused with mod version)");
+      }
+
+      Core.settingUseDialog = Config.ReadBool("UseDialog", true, comments: new string[] { "Should an item dialog be shown in recipe menus?" });
+
+      Config.Save();
+    }
+
+    public override string GetModDescription()
+    {
+      return "A utility mod providing a recipe menu API.";
+    }
+
+    protected override void Initialize()
+    {
+      Logger.Log("Recipe Menu Core v" + Info.Mod.Version);
+      Core.logger = Logger;
+
+      Core.pageGearForgeInfoList = new List<RecipePage>();
+      Core.pageAlchemyStationInfoList = new List<RecipePage>();
+      Core.pageUltimateForgeInfoList = new List<RecipePage>();
+      SceneManager.sceneLoaded += OnSceneLoaded;
+    }
+
+    internal static void OnSceneLoaded(Scene scene, LoadSceneMode mode)
+    {
+      if (scene.buildIndex == 1)
+      {
+        var menuRecipeElement = GameObject.Find("Main Camera").transform.Find("menuRecipe");
+        var locksElement = menuRecipeElement.Find("ultLocks").gameObject;
+        var hoverElements = Object.Instantiate(locksElement, menuRecipeElement.transform);
+        hoverElements.name = "hoverElements";
+        for (int i = 0; i < 12 * 3; i++)
+        {
+          var element = hoverElements.transform.GetChild(i).gameObject;
+          Component.DestroyImmediate(element.GetComponent<Renderer>());
+          var collider = element.AddComponent<BoxCollider>();
+          collider.size = new Vector3(14f / 32f * 2, (18f + 1) / 32f * 2, 1);
+          collider.isTrigger = true;
+          element.tag = "recipe";
+          element.layer = 16;
+          element.name = "" + (i + 12);
+        }
+        var buttonsElement = menuRecipeElement.Find("buttons").gameObject;
+        for (int i = 0; i < 12; i++)
+        {
+          var element = buttonsElement.transform.GetChild(i).gameObject;
+          var collider = element.GetComponent<BoxCollider>();
+          collider.size = new Vector3(collider.size.x, 0.6f, collider.size.z);
+        }
+      }
+    }
+  }
+}

+ 359 - 0
RecipeMenuCore.csproj

@@ -0,0 +1,359 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project Sdk="Microsoft.NET.Sdk">
+  <ImportGroup>
+    <Import Project="../GamePaths.xml" />
+  </ImportGroup>
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <ProjectGuid>{91AB81DE-EAEE-47D1-93DD-541179208219}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>RecipeMenuCore</RootNamespace>
+    <AssemblyName>RecipeMenuCore</AssemblyName>
+    <TargetFrameworks>net35</TargetFrameworks>
+    <FileAlignment>512</FileAlignment>
+    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
+    <Configurations>Release</Configurations>
+    <Authors>Zariteis</Authors>
+    <ApplicationIcon />
+    <StartupObject />
+    <Platforms>x86</Platforms>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <PlatformTarget>x86</PlatformTarget>
+    <DebugType>none</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net35|x86'">
+    <NoWarn>1701;1702</NoWarn>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="0Harmony">
+      <HintPath>$(GamePath)$(ManagedFolder)0Harmony.dll</HintPath>
+      <Private>false</Private>
+    </Reference>
+    <Reference Include="Assembly-CSharp">
+      <HintPath>$(GamePath)$(ManagedFolder)Assembly-CSharp.dll</HintPath>
+      <Private>false</Private>
+    </Reference>
+    <Reference Include="GadgetCore">
+      <HintPath>$(GamePath)$(ManagedFolder)GadgetCore.dll</HintPath>
+      <Private>false</Private>
+    </Reference>
+    <Reference Include="UnityEngine">
+      <HintPath>$(GamePath)$(ManagedFolder)UnityEngine.dll</HintPath>
+      <Private>false</Private>
+    </Reference>
+    <Reference Include="WindowsBase" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="ModInfo.txt">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+  <UsingTask TaskName="GetFileVersion" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
+    <ParameterGroup>
+      <AssemblyPath ParameterType="System.String" Required="true" />
+      <Version ParameterType="System.String" Output="true" />
+      <TrimmedVersion ParameterType="System.String" Output="true" />
+    </ParameterGroup>
+    <Task>
+      <Using Namespace="System.Diagnostics" />
+      <Using Namespace="System.Text" />
+      <Using Namespace="System.Linq" />
+      <Code Type="Fragment" Language="cs">
+        <![CDATA[
+      this.Version = FileVersionInfo.GetVersionInfo(this.AssemblyPath).FileVersion;  
+      this.TrimmedVersion = this.Version.Split('.').TakeWhile(x => !x.Equals("0")).Aggregate(new StringBuilder(), (a, b) => { if (a.Length > 0) a.Append("."); a.Append(b); return a; }).ToString();
+      if (this.TrimmedVersion.IndexOf('.') == -1) this.TrimmedVersion += ".0";
+    ]]>
+      </Code>
+    </Task>
+  </UsingTask>
+  <Target Name="PostBuild" AfterTargets="PostBuildEvent">
+    <GetFileVersion AssemblyPath="$(TargetPath)">
+      <Output TaskParameter="Version" PropertyName="ModFullVersion" />
+      <Output TaskParameter="TrimmedVersion" PropertyName="AssemblyFileVersion" />
+    </GetFileVersion>
+    <ItemGroup>
+      <OldZip Include="$(TargetDir)$(AssemblyName)_v*.zip" />
+      <OldZip Include="$(GamePath)GadgetCore\Mods\$(AssemblyName)_v*.zip" />
+    </ItemGroup>
+    <Delete Files="@(OldZip)" />
+    <MakeDir Directories="$(TargetDir)..\BuildCache\" />
+    <ZipDirectory SourceDirectory="$(TargetDir)" DestinationFile="$(TargetDir)..\BuildCache\$(AssemblyName)_v$(AssemblyFileVersion).zip" />
+    <Copy SourceFiles="$(TargetDir)..\BuildCache\$(AssemblyName)_v$(AssemblyFileVersion).zip" DestinationFiles="$(TargetDir)$(AssemblyName)_v$(AssemblyFileVersion).zip" />
+    <RemoveDir Directories="$(TargetDir)..\BuildCache\" />
+    <MakeDir Directories="$(GamePath)GadgetCore\Mods\" />
+    <Copy SourceFiles="$(TargetDir)$(AssemblyName)_v$(AssemblyFileVersion).zip" DestinationFiles="$(GamePath)GadgetCore\Mods\$(AssemblyName)_v$(AssemblyFileVersion).zip" />
+    <Message Importance="High" Text="Mod Exported to $(GamePath)GadgetCore\Mods\$(AssemblyName)_v$(AssemblyFileVersion).zip" />
+  </Target>
+  <ItemGroup>
+    <None Update="Assets\ancientCrystal.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\ancientCrystalCM.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\bgScrapYard.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\bgSpace.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\bScrapYardbg0.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\bScrapYardbg1.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\bScrapYardbg2.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\bScrapYardbg3.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\bSpacebg0.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\bSpacebg1.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\bSpacebg2.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\bSpacebg3.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\bugspotBig.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\cGreenLamp.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\charBG.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\cOrangeLamp.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\cPlatform.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\cPurpleLamp.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\cWhiteLamp.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\cYellowLamp.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\entranceScrapYard.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\entranceSpace.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\First\one">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\frozenWisp.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\goldenShroom.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\hoverItem.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\iAirCore.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\iCore.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\iEarthCore.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\iFireCore.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\iGreenLamp.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\iOrangeLamp.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\iPlatform.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\iPurpleLamp.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\iWaterCore.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\iWhiteLamp.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\iYellowLamp.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\meteor1.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\meteor2.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\meteor3.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\meteor4.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\midCoverChunk0.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\midHiddenChunk0.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\midScrapYardChunk0.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\midScrapYardChunk1.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\midSpaceChunk0.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\midSpaceChunk1.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\one">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\plagueBall.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\plagueNest.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\planetScrapYard.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\planetSpace.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\planetSpacePrev.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\recipeLock.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\recipeLockSmall.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\sideBigScrapYard.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\sideBigSpace.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\sidesmallScrapYard.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\sideSmallSpace.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\signScrapYard - Kopie.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\signScrapYard.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\signSpace.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\spaceOre.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\spaceOreBig.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\spiderEgg.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\spiderEggCM.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\spiderEggCM2.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\spikePlant.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\spikePlantCM.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\stars.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\tx1.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Assets\tx2.png">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Manifest.ini">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+  </ItemGroup>
+  <ItemGroup>
+    <Reference Update="System">
+      <Private>false</Private>
+      <SpecificVersion>true</SpecificVersion>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Reference Update="System.Data">
+      <EmbedInteropTypes>false</EmbedInteropTypes>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Reference Update="System.Drawing">
+      <EmbedInteropTypes>false</EmbedInteropTypes>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Reference Update="System.IO.Compression.FileSystem">
+      <EmbedInteropTypes>false</EmbedInteropTypes>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Reference Update="System.Numerics">
+      <EmbedInteropTypes>false</EmbedInteropTypes>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Reference Update="System.Runtime.Serialization">
+      <EmbedInteropTypes>false</EmbedInteropTypes>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Reference Update="System.Xml">
+      <EmbedInteropTypes>false</EmbedInteropTypes>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Reference Update="System.Xml.Linq">
+      <EmbedInteropTypes>false</EmbedInteropTypes>
+    </Reference>
+  </ItemGroup>
+</Project>

+ 22 - 0
RecipeMenuCore.sln

@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31205.134
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RecipeMenuCore", "RecipeMenuCore.csproj", "{91AB81DE-EAEE-47D1-93DD-541179208219}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{91AB81DE-EAEE-47D1-93DD-541179208219}.Release|x86.ActiveCfg = Release|x86
+		{91AB81DE-EAEE-47D1-93DD-541179208219}.Release|x86.Build.0 = Release|x86
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {C408A6B0-1D86-4E96-851D-E7F196805F31}
+	EndGlobalSection
+EndGlobal