diff --git a/DensityMod.csproj b/DensityMod.csproj new file mode 100644 index 0000000..82eab11 --- /dev/null +++ b/DensityMod.csproj @@ -0,0 +1,34 @@ + + + + net6.0 + DensityMod + A mod by Nova to allow you to set the range of density allowed when generating a city + 1.4.0 + true + latest + + https://api.nuget.org/v3/index.json; + https://nuget.bepinex.dev/v3/index.json; + https://nuget.samboy.dev/v3/index.json + + DensityMod + + + + + + + + + + C:\Users\Nova\AppData\Roaming\Thunderstore Mod Manager\DataFolder\ShadowsofDoubt\profiles\Default\BepInEx + + + + + + + + + \ No newline at end of file diff --git a/Hook.cs b/Hook.cs new file mode 100644 index 0000000..7466946 --- /dev/null +++ b/Hook.cs @@ -0,0 +1,246 @@ +using HarmonyLib; +using System; +using Il2CppSystem.Collections.Generic; +using UnityEngine; +using Il2CppSystem; +using UnityEngine.Events; +using UnityEngine.UI; +using System.Globalization; +using System.Text.RegularExpressions; + +namespace DensityMod +{ + internal class DensityModHook{ + + static public GameObject dropdownDenLow; + static public GameObject dropdownDenHigh; + static public GameObject dropdownValueLow; + static public GameObject dropdownValueHigh; + static public GameObject densityMenu; + static public GameObject menuContainer; + static public GameObject GenerateCityMenu; + static public GameObject DensityModBtn; + + //This is to convert the Density enum to a clean looking string + static public string EnumToString(T e) where T : System.Enum{ + var s = e.ToString(); + s = Regex.Replace(s, "(\\B[A-Z])", " $1"); + s = new CultureInfo("en-US",false).TextInfo.ToTitleCase(s); + return s; + } + + //Converts string into the Density Enum + static public T StringToEnum(string s) where T : System.Enum{ + s = s.Substring(0,1).ToLower() + s.Substring(1).Replace(" ", ""); //Makes the first letter lowercase(Used in the case of veryHigh, as well as removing the space) + return (T)System.Enum.Parse(typeof(T), s); + } + + //Update the city generation with the desired density values + [HarmonyPatch(typeof(CityConstructor), "Update")] + public class Citydata_PopulationMultiplier{ + public static void Postfix(){ + CityTile[] cityTile = Resources.FindObjectsOfTypeAll(); + CityConstructor cityConstructor = Resources.FindObjectsOfTypeAll()[0]; + //Gets the values from the config file and stores them in a Vector 2, because two ints would be too easy... and messy + var DensityRange = new Vector2( + (int)System.Enum.Parse(typeof(BuildingPreset.Density), DensityMod.DensityMinConfig.Value), + (int)System.Enum.Parse(typeof(BuildingPreset.Density), DensityMod.DensityMaxConfig.Value)); + + var ValueRange = new Vector2( + (int)System.Enum.Parse(typeof(BuildingPreset.LandValue), DensityMod.LandValueMinConfig.Value), + (int)System.Enum.Parse(typeof(BuildingPreset.LandValue), DensityMod.LandValueMaxConfig.Value)); + + //Uses the valueRange and clamps the allowed density. This is done by treating the Enum as an int, since the values range from 0 - 3. + if (cityConstructor.generateNew){ + foreach(CityTile tile in cityTile){ + if (tile.name == "CityTile") return;//This was used, because there seems to be a CityTile manager or something, so I didn't want to edit it(Also caused issues before) + var d = (int)tile.density; + d = (int)System.Math.Clamp(d,DensityRange.x, DensityRange.y); + + var v = (int)tile.landValue; + v = (int)System.Math.Clamp(v,ValueRange.x, ValueRange.y); + + //Density Update + tile.density = (BuildingPreset.Density)d; + DensityMod.Logger.LogDebug($"{tile.name} density = {tile.density}"); + + //Land Value update + tile.landValue = (BuildingPreset.LandValue)v; + DensityMod.Logger.LogDebug($"{tile.name} landValue = {tile.landValue}"); + } + } + } + } + + //Simple function to close the Density menu + static void CloseDensityMenu(){ + densityMenu.SetActive(false); + GenerateCityMenu.SetActive(true); + } + + //Simple function to open the Density menu(duh) + static void OpenDensityMenu(){ + densityMenu.SetActive(true); + GenerateCityMenu.SetActive(false); + } + + //Creates the menu objects + [HarmonyPatch(typeof(MainMenuController), "Start")] + public class MainMenuController_Start{ + + public static void Postfix(){ + var inputTemplate = GameObject.Find("MenuCanvas").transform.Find("MainMenu/GenerateCityPanel/GenerateNewCityComponents/SizeDropdown").gameObject; + GenerateCityMenu = GameObject.Find("MenuCanvas").transform.Find("MainMenu/GenerateCityPanel/").gameObject; + + //Dropdown list of options. + List DensityOptions = new List(); + DensityOptions.Add("Low"); + DensityOptions.Add("Medium"); + DensityOptions.Add("High"); + DensityOptions.Add("Very High"); + + List ValueOptions = new List(); + ValueOptions.Add("Very Low"); + ValueOptions.Add("Low"); + ValueOptions.Add("Medium"); + ValueOptions.Add("High"); + ValueOptions.Add("Very High"); + + if (GenerateCityMenu != null){ + //Generate a density menu, based on the Generate City menu already present + densityMenu = GameObject.Instantiate(GenerateCityMenu.gameObject); + densityMenu.name = "Density Menu"; + densityMenu.transform.parent = GenerateCityMenu.transform.parent; + densityMenu.transform.localPosition = new Vector3(0, -42, 0);//Set the localPosition to this, because when cloned it starts in an odd position. + + //Finds the gameobject that holds the dropdowns + menuContainer = densityMenu.transform.FindChild("GenerateNewCityComponents").gameObject; + menuContainer.name = "DensitySettingsComponents"; + + //Removes all elements currently present + //Note: it was done in this way, because a while and foreach loop would fail. It seems when this is created, the data is static, + // so when you remove Child(0), Child(1) does not become the new Child(0) as you would expect in Unity. + for(int i = 0; i < menuContainer.transform.GetChildCount(); i++){ + GameObject.Destroy(menuContainer.transform.GetChild(i).gameObject); + } + + //Removes one of the buttons from the menu, then changes the remaining one to be the done button + GameObject.Destroy(densityMenu.transform.FindChild("ButtonArea").GetChild(0).gameObject); + var doneButton = densityMenu.transform.FindChild("ButtonArea").GetChild(1).gameObject; + doneButton.transform.parent = densityMenu.transform.FindChild("ButtonArea").transform; + doneButton.GetComponent