├── Dependencies ├── UITools.dll └── UITools.xml ├── src ├── World │ ├── Patches │ │ ├── Graphics.cs │ │ ├── ToggleTorque.cs │ │ ├── HoverMode.cs │ │ ├── TimewarpBehavior.cs │ │ ├── ReplaceClearDebrisMenu.cs │ │ ├── ChangeDebrisColor.cs │ │ └── StopTimewarpOnEncounter.cs │ ├── MiscWorldFunctionality.cs │ ├── WorldManager.cs │ ├── TimeManipulation.cs │ ├── HoverHandler.cs │ ├── AutosaveHandler.cs │ ├── MissionLogButton.cs │ ├── WorldClockDisplay.cs │ ├── AdvancedInfoUI.cs │ └── AdvancedInfo.cs ├── Build │ ├── Patches │ │ ├── SkipBuildNewPrompt.cs │ │ ├── DisableAdaptation.cs │ │ └── ReplacePickCategories.cs │ ├── KeyMethods.cs │ └── BuildSettings.cs ├── ErrorNotification.cs ├── Utility │ ├── Extensions.cs │ └── UIExtensions.cs ├── Patches │ ├── LoosenCameraRestrictions.cs │ ├── BugFixes.cs │ ├── DisplayAccurateTWR.cs │ ├── MenuPatches.cs │ └── UnitsPatches.cs ├── Config │ ├── Config.cs │ ├── CustomKeys.cs │ └── ConfigUI.cs └── Main.cs ├── VanillaUpgrades.sln ├── Properties └── AssemblyInfo.cs ├── README.md ├── .gitattributes ├── .gitignore └── VanillaUpgrades.csproj /Dependencies/UITools.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Neptune-Sky/SFSVanillaUpgrades/HEAD/Dependencies/UITools.dll -------------------------------------------------------------------------------- /src/World/Patches/Graphics.cs: -------------------------------------------------------------------------------- 1 | using HarmonyLib; 2 | using SFS.World; 3 | 4 | namespace VanillaUpgrades.World.Patches 5 | { 6 | [HarmonyPatch(typeof(EffectManager))] 7 | public class StopExplosions 8 | { 9 | [HarmonyPatch("CreateExplosion")] 10 | [HarmonyPatch("CreatePartOverheatEffect")] 11 | [HarmonyPrefix] 12 | private static bool Prefix() 13 | { 14 | return Config.settings.explosions; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/Build/Patches/SkipBuildNewPrompt.cs: -------------------------------------------------------------------------------- 1 | using HarmonyLib; 2 | using JetBrains.Annotations; 3 | using SFS; 4 | using SFS.Builds; 5 | 6 | namespace VanillaUpgrades.Build 7 | { 8 | [HarmonyPatch(typeof(BuildManager), "Start")] 9 | internal class SkipBuildNewPrompt 10 | { 11 | [UsedImplicitly] 12 | private static void Prefix() 13 | { 14 | if (Config.settings.skipBuildNewPrompt) Base.sceneLoader.sceneSettings.askBuildNew = false; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/Build/KeyMethods.cs: -------------------------------------------------------------------------------- 1 | using HarmonyLib; 2 | using SFS; 3 | using SFS.Builds; 4 | 5 | namespace VanillaUpgrades.Build 6 | { 7 | [HarmonyPatch(typeof(PickCategoriesMenu), "Start")] 8 | public static class KeyMethods 9 | { 10 | public static PickCategoriesMenu pickCategoriesMenu; 11 | 12 | private static void Prefix(PickCategoriesMenu __instance) 13 | { 14 | pickCategoriesMenu = __instance; 15 | } 16 | 17 | public static void Launch() 18 | { 19 | BuildState.main.UpdatePersistent(); 20 | Base.sceneLoader.LoadWorldScene(true); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /src/ErrorNotification.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using SFS.UI; 4 | using UnityEngine; 5 | 6 | namespace VanillaUpgrades 7 | { 8 | public class ErrorNotification : MonoBehaviour 9 | { 10 | private static readonly StringBuilder Errors = new(); 11 | 12 | private void Start() 13 | { 14 | if (Errors.Length == 0) return; 15 | Errors.Insert(0, 16 | "An error occured while loading VanillaUpgrades." + Environment.NewLine + Environment.NewLine); 17 | Menu.read.ShowReport(Errors, () => Errors.Clear()); 18 | } 19 | 20 | public static void Error(string error) 21 | { 22 | Errors.AppendLine($"- {error}"); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/Utility/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using SFS.UI; 3 | using Button = SFS.UI.ModGUI.Button; 4 | 5 | // ReSharper disable once CheckNamespace 6 | namespace VanillaUpgrades 7 | { 8 | public static class Extensions 9 | { 10 | public static TValue GetValueOrDefault(this Dictionary dictionary, TKey key, 11 | TValue defaultValue) 12 | { 13 | return CollectionExtensions.GetValueOrDefault(dictionary, key, defaultValue); 14 | } 15 | 16 | public static void SetSelected(this Button button, bool selected = true) 17 | { 18 | button.gameObject.GetComponentInChildren().SetSelected(selected); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /src/World/Patches/ToggleTorque.cs: -------------------------------------------------------------------------------- 1 | using HarmonyLib; 2 | using SFS.UI; 3 | using SFS.World; 4 | 5 | // ReSharper disable InconsistentNaming 6 | // ReSharper disable UnusedMember.Local 7 | 8 | namespace VanillaUpgrades.World.Patches 9 | { 10 | [HarmonyPatch(typeof(Rocket), "GetTorque")] 11 | public static class ToggleTorque 12 | { 13 | private static bool disableTorque; 14 | 15 | public static void Set(bool setting = true) 16 | { 17 | disableTorque = setting; 18 | } 19 | 20 | public static void Toggle() 21 | { 22 | if (!PlayerController.main.HasControl(MsgDrawer.main)) return; 23 | Set(!disableTorque); 24 | MsgDrawer.main.Log("Torque " + (disableTorque ? "Disabled" : "Enabled")); 25 | } 26 | 27 | private static bool Prefix(ref float __result) 28 | { 29 | if (!disableTorque) return true; 30 | __result = 0f; 31 | return false; 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/World/Patches/HoverMode.cs: -------------------------------------------------------------------------------- 1 | using HarmonyLib; 2 | using SFS.World; 3 | 4 | namespace VanillaUpgrades.World.Patches 5 | { 6 | [HarmonyPatch(typeof(ThrottleDrawer))] 7 | public class ManageHoverMode 8 | { 9 | [HarmonyPatch("ToggleThrottle")] 10 | [HarmonyPostfix] 11 | public static void ToggleThrottle_Postfix(ref Throttle_Local ___throttle) 12 | { 13 | if (!___throttle.Value.throttleOn) 14 | // Do this only if throttle has been turned off (keep hover mode on if this was set before throttle is turned on) 15 | HoverHandler.EnableHoverMode(false, false); 16 | } 17 | 18 | [HarmonyPatch("AdjustThrottleRaw")] 19 | [HarmonyPostfix] 20 | public static void AdjustThrottleRaw_Postfix() 21 | { 22 | HoverHandler.EnableHoverMode(false); 23 | } 24 | 25 | [HarmonyPatch("SetThrottleRaw")] 26 | [HarmonyPostfix] 27 | public static void SetThrottleRaw_Postfix() 28 | { 29 | HoverHandler.EnableHoverMode(false); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/World/MiscWorldFunctionality.cs: -------------------------------------------------------------------------------- 1 | using SFS.UI; 2 | using SFS.World; 3 | using UnityEngine; 4 | using static VanillaUpgrades.World.HoverHandler; 5 | 6 | namespace VanillaUpgrades.World 7 | { 8 | internal static partial class WorldManager 9 | { 10 | public static void Throttle01() 11 | { 12 | if (currentRocket == null || !PlayerController.main.HasControl(MsgDrawer.main)) return; 13 | if (!WorldTime.main.realtimePhysics.Value) 14 | { 15 | MsgDrawer.main.Log("Cannot throttle while timewarping"); 16 | return; 17 | } 18 | 19 | EnableHoverMode(false); 20 | currentRocket.throttle.throttlePercent.Value = 0.0005f; 21 | } 22 | 23 | private static void HideTopLeftButtonText() 24 | { 25 | GameObject topLeftPanel = GameObject.Find("Top Left Panel"); 26 | foreach (TextAdapter textAdapter in topLeftPanel.gameObject.GetComponentsInChildren(true)) 27 | textAdapter.gameObject.SetActive(!Config.settings.hideTopLeftButtonText); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /VanillaUpgrades.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.1.32210.238 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VanillaUpgrades", "VanillaUpgrades.csproj", "{A4D8A250-72A2-4002-9B2E-EF52639E8925}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {A4D8A250-72A2-4002-9B2E-EF52639E8925}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {A4D8A250-72A2-4002-9B2E-EF52639E8925}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {A4D8A250-72A2-4002-9B2E-EF52639E8925}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {A4D8A250-72A2-4002-9B2E-EF52639E8925}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {21A263DE-4A68-4DC8-B9FD-6CBE4D5B1B15} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /src/Patches/LoosenCameraRestrictions.cs: -------------------------------------------------------------------------------- 1 | using HarmonyLib; 2 | using SFS.World; 3 | using UnityEngine; 4 | 5 | // ReSharper disable InconsistentNaming 6 | // ReSharper disable UnusedMember.Local 7 | 8 | namespace VanillaUpgrades.Patches 9 | { 10 | [HarmonyPatch(typeof(PlayerController))] 11 | internal class LoosenCameraRestrictions 12 | { 13 | [HarmonyPatch(typeof(PlayerController), "ClampTrackingOffset")] 14 | [HarmonyPrefix] 15 | private static bool MoreCameraMove(ref Vector2 __result, Vector2 newValue) 16 | { 17 | if (!Config.settings.moreCameraMove) return true; 18 | if (PlayerController.main.player.Value == null) return true; 19 | PlayerController.main.player.Value.ClampTrackingOffset(ref newValue, -30); 20 | __result = newValue; 21 | return false; 22 | } 23 | 24 | [HarmonyPatch("ClampCameraDistance")] 25 | [HarmonyPrefix] 26 | private static bool MoreCameraZoom(ref float __result, float newValue) 27 | { 28 | if (!Config.settings.moreCameraZoom) return true; 29 | if (PlayerController.main.player.Value == null) return true; 30 | __result = Mathf.Clamp(newValue, 0.05f, 2.5E+10f); 31 | return false; 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("ASoD's VanillaUpgrades")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("ASoD's VanillaUpgrades")] 12 | [assembly: AssemblyCopyright("Copyright © 2022")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("a4d8a250-72a2-4002-9b2e-ef52639e8925")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] -------------------------------------------------------------------------------- /src/Build/Patches/DisableAdaptation.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using HarmonyLib; 3 | using SFS.Builds; 4 | using SFS.Parts.Modules; 5 | using UnityEngine; 6 | 7 | namespace VanillaUpgrades.Build 8 | { 9 | [HarmonyPatch(typeof(PartGrid), "UpdateAdaptation")] 10 | internal class StopAdaptation 11 | { 12 | private static bool Prefix() 13 | { 14 | return !BuildSettings.noAdaptation || BuildSettings.noAdaptOverride; 15 | } 16 | } 17 | 18 | [HarmonyPatch(typeof(HoldGrid), "TakePart_PickGrid")] 19 | internal class AdaptPartPicker 20 | { 21 | private static void Prefix() 22 | { 23 | BuildSettings.noAdaptOverride = true; 24 | } 25 | 26 | private static void Postfix() 27 | { 28 | BuildSettings.noAdaptOverride = false; 29 | } 30 | } 31 | 32 | 33 | [HarmonyPatch(typeof(AdaptModule), "UpdateAdaptation")] 34 | internal class FixCucumber 35 | { 36 | private static bool Prefix() 37 | { 38 | return !BuildSettings.noAdaptation || BuildSettings.noAdaptOverride; 39 | } 40 | } 41 | 42 | [HarmonyPatch(typeof(MagnetModule), nameof(MagnetModule.GetAllSnapOffsets))] 43 | internal class KillMagnet 44 | { 45 | private static bool Prefix(MagnetModule A, MagnetModule B, float snapDistance, ref List __result) 46 | { 47 | if (!BuildSettings.noSnapping) 48 | return true; 49 | __result = new List(); 50 | return false; 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /src/Patches/BugFixes.cs: -------------------------------------------------------------------------------- 1 | using HarmonyLib; 2 | using SFS.Builds; 3 | using SFS.UI; 4 | using SFS.World; 5 | using SFS.World.Maps; 6 | using UnityEngine; 7 | 8 | // ReSharper disable InconsistentNaming 9 | // ReSharper disable UnusedMember.Local 10 | 11 | namespace VanillaUpgrades.Patches 12 | { 13 | // Stops the camera from zooming while the cursor isn't in the game window. 14 | [HarmonyPatch] 15 | internal class ZoomFix 16 | { 17 | private static bool CheckMouseBounds() 18 | { 19 | Rect screenRect = new(0, 0, Screen.width, Screen.height); 20 | return screenRect.Contains(Input.mousePosition); 21 | } 22 | 23 | [HarmonyPatch(typeof(BuildManager), "OnZoom")] 24 | [HarmonyPatch(typeof(PlayerController), "OnZoom")] 25 | [HarmonyPatch(typeof(MapView), "OnZoom")] 26 | [HarmonyPrefix] 27 | private static bool WorldMap() 28 | { 29 | return CheckMouseBounds(); 30 | } 31 | } 32 | 33 | // Fixes throttle fill bar being offset from actual value 34 | [HarmonyPatch(typeof(ThrottleDrawer), "UpdatePercentUI")] 35 | internal class ThrottleFillBarAccuracyFix 36 | { 37 | private static bool Prefix(Throttle_Local ___throttle, FillSlider ___throttleSlider, 38 | TextAdapter ___throttlePercentText) 39 | { 40 | var value = ___throttle.Value.throttlePercent.Value; 41 | ___throttlePercentText.Text = value.ToPercentString(); 42 | ___throttleSlider.SetFillAmount(0.16f + value * 0.68f, false); 43 | return false; 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /src/World/WorldManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using HarmonyLib; 3 | using SFS.World; 4 | using VanillaUpgrades.World.Patches; 5 | using static VanillaUpgrades.World.HoverHandler; 6 | 7 | namespace VanillaUpgrades.World 8 | { 9 | // Hook for things that need to run every frame in-game. 10 | [HarmonyPatch(typeof(GameManager))] 11 | public class UpdateInGame 12 | { 13 | public static Action execute = () => { }; 14 | 15 | [HarmonyPatch("Update")] 16 | public static void Postfix() 17 | { 18 | execute.Invoke(); 19 | } 20 | } 21 | 22 | internal static partial class WorldManager 23 | { 24 | public static Rocket currentRocket; 25 | 26 | private static void UpdatePlayer() 27 | { 28 | currentRocket = PlayerController.main.player.Value != null 29 | ? PlayerController.main.player.Value as Rocket 30 | : null; 31 | ToggleTorque.Set(false); 32 | EnableHoverMode(false, false); 33 | } 34 | 35 | public static void Setup() 36 | { 37 | UpdatePlayer(); 38 | HideTopLeftButtonText(); 39 | 40 | PlayerController.main.player.OnChange += UpdatePlayer; 41 | Config.settings.allowTimeSlowdown.OnChange += TimeManipulation.ToggleChange; 42 | Config.settings.hideTopLeftButtonText.OnChange += HideTopLeftButtonText; 43 | 44 | AdvancedInfo.Setup(); 45 | WorldClockDisplay.Setup(); 46 | 47 | UpdateInGame.execute += () => 48 | { 49 | if (hoverMode) TwrTo1(); 50 | }; 51 | 52 | MissionLogButton.Create(); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /src/World/Patches/TimewarpBehavior.cs: -------------------------------------------------------------------------------- 1 | using HarmonyLib; 2 | using SFS.Translations; 3 | using SFS.UI; 4 | using SFS.World; 5 | 6 | namespace VanillaUpgrades.World.Patches 7 | { 8 | [HarmonyPatch(typeof(Rocket), "CanTimewarp")] 9 | internal class PhysicsTimewarpIfTurning 10 | { 11 | private static void Postfix(ref bool __result) 12 | { 13 | if (WorldManager.currentRocket.arrowkeys.turnAxis == 0) return; 14 | WorldTime.ShowCannotTimewarpMsg(Field.Text("Cannot timewarp faster than %speed%x while turning"), 15 | MsgDrawer.main); 16 | __result = false; 17 | } 18 | } 19 | 20 | [HarmonyPatch(typeof(WorldTime))] 21 | public class RaiseMaxPhysicsTimewarp 22 | { 23 | [HarmonyPatch("GetTimewarpSpeed_Physics")] 24 | [HarmonyPrefix] 25 | public static bool AddMoreIndexes(ref double __result, int timewarpIndex_Physics) 26 | { 27 | if (!Config.settings.higherPhysicsWarp) return true; 28 | __result = new[] { 1, 2, 3, 5, 10, 25 }[timewarpIndex_Physics]; 29 | return false; 30 | } 31 | 32 | [HarmonyPatch("MaxPhysicsIndex", MethodType.Getter)] 33 | [HarmonyPrefix] 34 | public static bool AllowUsingIndexes(ref int __result) 35 | { 36 | if (!Config.settings.higherPhysicsWarp) return true; 37 | __result = 5; 38 | return false; 39 | } 40 | } 41 | 42 | [HarmonyPatch(typeof(FlightInfoDrawer), "Update")] 43 | internal class LimitDecimalsOfTimewarpText 44 | { 45 | private static void Postfix(TextAdapter ___timewarpText) 46 | { 47 | ___timewarpText.Text = WorldTime.main.timewarpSpeed.Round(2) + "x"; 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VanillaUpgrades 2 | 3 | Source code for the Vanilla Upgrades mod. 4 | 5 | If you use any of my code for your mods, all I ask is that you give credit for the portion you took. 6 | 7 | # What does this mod do? 8 | 9 | The purpose of this mod is to add tons of quality of life features the vanilla game ought to have, or even re-implement features the game used to have that were removed. 10 | 11 | 12 | Some notable features include: 13 | 14 | - Greatly increased zoom-in/movement limits of the camera in world/build views. 15 | - New cheats for time slowdown/freezing and physics timewarp up to 25x. 16 | - Scrolling for part picker categories. 17 | - Advanced info display, real time world clock/timewarp length. 18 | ![image](https://github.com/Neptune-Sky/VanillaUpgrades/assets/68938422/59b0514f-1485-49c7-a46a-4011c194a582) 19 | ![image](https://github.com/Neptune-Sky/VanillaUpgrades/assets/68938422/c10e96c6-f412-4389-95b9-887e8e9b0ba8) 20 | - Reimplementation of "Exit to Main Menu" button, because having to press "Exit" twice to get back there is annoying. 21 | - Tons of new keybinds, including hiding UI, toggling windowed mode, toggling torque for your rockets, and lots of minor QoL stuff. 22 | - More units to condense the huge numbers certain readouts can have. 23 | - And lots more! A complete list of features can be found [in the wiki.](https://github.com/Neptune-Sky/VanillaUpgrades/wiki) 24 | 25 | 26 | This mod is made to be extensively customizable, the majority of features can be disabled or tweaked. The only ones that aren't are mainly common sense items that nobody would realistically want to disable, such as scrollable pick categories. 27 | 28 | # Installation 29 | 30 | 1. Download the latest DLL. 31 | 2. Use the "Open Mods Folder" button in-game. 32 | 3. Drag and drop the dll from your downloads into the mods folder, then restart the game. 33 | 34 | 35 | **This mod is untested on Mac.** Use at your own risk. 36 | -------------------------------------------------------------------------------- /src/World/Patches/ReplaceClearDebrisMenu.cs: -------------------------------------------------------------------------------- 1 | using HarmonyLib; 2 | using SFS.Input; 3 | using SFS.UI; 4 | using SFS.World; 5 | 6 | namespace VanillaUpgrades.World.Patches 7 | { 8 | [HarmonyPatch(typeof(GameManager), "OpenClearDebrisMenu")] 9 | internal static class ReplaceClearDebrisMenu 10 | { 11 | // ReSharper disable once UnusedMember.Local 12 | private static bool Prefix() 13 | { 14 | MenuGenerator.ShowChoices(() => "What objects would you like to clear?", 15 | ButtonBuilder.CreateButton(null, 16 | () => "All Unnamed Debris", () => { ClearDebris(); }, CloseMode.Stack), 17 | ButtonBuilder.CreateButton(null, 18 | () => "All Debris", () => { ClearDebris(false); }, CloseMode.Stack), 19 | ButtonBuilder.CreateButton(null, 20 | () => "All Unnamed Rockets", () => { ClearDebris(true, true); }, CloseMode.Stack), 21 | ButtonBuilder.CreateButton(null, 22 | () => "Everything", () => 23 | { 24 | MenuGenerator.OpenConfirmation(CloseMode.None, () => 25 | "Are you sure you want to delete EVERYTHING in your world? This includes all named rockets and debris.", 26 | () => "Yes", () => 27 | { 28 | ClearDebris(false, true); 29 | ScreenManager.main.CloseStack(); 30 | }, 31 | () => "No", ScreenManager.main.CloseCurrent); 32 | }, CloseMode.None), 33 | ButtonBuilder.CreateButton(null, 34 | () => "Cancel", null, CloseMode.Current) 35 | ); 36 | return false; 37 | } 38 | 39 | private static void ClearDebris(bool onlyUnnamed = true, bool destroyControllable = false) 40 | { 41 | var rockets = GameManager.main.rockets; 42 | for (var num = rockets.Count - 1; num >= 0; num--) 43 | { 44 | if (onlyUnnamed && rockets[num].rocketName != "") continue; 45 | if (!destroyControllable && rockets[num].hasControl.Value) continue; 46 | 47 | RocketManager.DestroyRocket(rockets[num], DestructionReason.Intentional); 48 | } 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /src/Build/BuildSettings.cs: -------------------------------------------------------------------------------- 1 | using SFS.Builds; 2 | using SFS.UI; 3 | using UnityEngine; 4 | using Button = SFS.UI.ModGUI.Button; 5 | using UIExtensions = VanillaUpgrades.Utility.UIExtensions; 6 | 7 | namespace VanillaUpgrades.Build 8 | { 9 | public static class BuildSettings 10 | { 11 | private static GameObject[] buttons; 12 | 13 | public static bool noSnapping; 14 | public static bool noAdaptation; 15 | public static bool noAdaptOverride; 16 | 17 | public static void Setup() 18 | { 19 | noSnapping = false; 20 | noAdaptation = false; 21 | CreateGUI(); 22 | Config.settings.showBuildGui.OnChange += OnToggle; 23 | Config.settings.showBuildGui.Value &= !Main.buildSettingsPresent; 24 | 25 | if (!Config.settings.moreCameraZoom) return; 26 | BuildManager.main.buildCamera.maxCameraDistance = 300; 27 | BuildManager.main.buildCamera.minCameraDistance = 0.1f; 28 | } 29 | 30 | private static void OnToggle() 31 | { 32 | buttons.ForEach(e => e.SetActive(Config.settings.showBuildGui.Value)); 33 | } 34 | 35 | private static void CreateGUI() 36 | { 37 | Transform topRight = GameObject.Find("Top Right").transform; 38 | 39 | Button adaptModButton = UIExtensions.ButtonForVanillaUI(out GameObject adaptingButton, topRight, 130, 50, 40 | 25, null, "Adapting"); 41 | adaptingButton.transform.SetAsFirstSibling(); 42 | adaptModButton.OnClick = () => 43 | { 44 | noAdaptation ^= true; 45 | MsgDrawer.main.Log("Part Adaptation " + (noAdaptation ? "Disabled" : "Enabled")); 46 | adaptModButton.SetSelected(!noAdaptation); 47 | }; 48 | adaptModButton.SetSelected(); 49 | 50 | Button snapModButton = UIExtensions.ButtonForVanillaUI(out GameObject snappingButton, topRight, 130, 50, 25, 51 | null, "Snapping"); 52 | snappingButton.transform.SetAsFirstSibling(); 53 | snapModButton.OnClick = () => 54 | { 55 | noSnapping ^= true; 56 | MsgDrawer.main.Log("Part Snapping " + (noSnapping ? "Disabled" : "Enabled")); 57 | snapModButton.SetSelected(!noSnapping); 58 | }; 59 | snapModButton.SetSelected(); 60 | 61 | buttons = new[] { adaptingButton, snappingButton }; 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /src/World/Patches/ChangeDebrisColor.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Reflection; 4 | using System.Reflection.Emit; 5 | using HarmonyLib; 6 | using SFS.World; 7 | using SFS.World.Maps; 8 | 9 | // ReSharper disable InconsistentNaming 10 | // ReSharper disable UnusedMember.Local 11 | // ReSharper disable UnusedMember.Global 12 | 13 | namespace VanillaUpgrades.World.Patches 14 | { 15 | [HarmonyPatch(typeof(MapIcon), "UpdateAlpha")] 16 | internal static class Alpha 17 | { 18 | private static MapIcon _obj; 19 | 20 | private static void Prefix(MapIcon __instance) 21 | { 22 | _obj = __instance; 23 | } 24 | 25 | private static IEnumerable Transpiler(IEnumerable instructions) 26 | { 27 | var codes = new List(instructions); 28 | 29 | for (var i = 0; i < codes.Count; i++) 30 | if (codes[i].opcode == OpCodes.Ldc_R4 && codes[i].OperandIs(1f)) 31 | codes[i] = new CodeInstruction(OpCodes.Call, typeof(Alpha).GetMethod("CheckForControl", 32 | BindingFlags.Static | BindingFlags.Public)); 33 | 34 | return codes.AsEnumerable(); 35 | } 36 | 37 | public static float CheckForControl() 38 | { 39 | var rocket = _obj.gameObject.GetComponent(); 40 | if (rocket == null || !Config.settings.darkenDebris) return 1f; 41 | return rocket.hasControl ? 1f : 0.5f; 42 | } 43 | } 44 | 45 | [HarmonyPatch(typeof(RocketManager), "CreateRocket")] 46 | internal static class ChildRocketsGetColored 47 | { 48 | private static void Postfix(Rocket __result) 49 | { 50 | Traverse.Create(__result.mapIcon).Method("UpdateAlpha").GetValue(); 51 | } 52 | } 53 | 54 | [HarmonyPatch(typeof(Staging), "OnSplit")] 55 | internal static class NewRocketsGetColored 56 | { 57 | private static void Postfix(Rocket parentRocket, Rocket childRocket) 58 | { 59 | Traverse.Create(parentRocket.mapIcon).Method("UpdateAlpha").GetValue(); 60 | Traverse.Create(childRocket.mapIcon).Method("UpdateAlpha").GetValue(); 61 | } 62 | } 63 | 64 | [HarmonyPatch(typeof(RocketManager), "MergeRockets")] 65 | internal static class DockedRocketsGetColored 66 | { 67 | private static void Postfix(Rocket rocket_A) 68 | { 69 | Traverse.Create(rocket_A.mapIcon).Method("UpdateAlpha").GetValue(); 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /src/Config/Config.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SFS.IO; 3 | using SFS.Variables; 4 | using UITools; 5 | using UnityEngine; 6 | 7 | namespace VanillaUpgrades 8 | { 9 | [Serializable] 10 | public class PersistentVars 11 | { 12 | public Float_Local windowScale = new() { Value = 1 }; 13 | public float minutesUntilAutosave = 10f; 14 | public int allowedAutosaveSlots = 5; 15 | } 16 | 17 | [Serializable] 18 | public class SettingsData 19 | { 20 | // random vars 21 | public PersistentVars persistentVars = new(); 22 | 23 | // Display 24 | public Bool_Local showBuildGui = new() { Value = true }; 25 | public Bool_Local showAdvanced = new() { Value = true }; 26 | public Bool_Local showAdvancedInSeparateWindow = new(); 27 | public Bool_Local horizontalMode = new(); 28 | public Bool_Local showTime = new() { Value = true }; 29 | public Bool_Local showWorldTime = new() { Value = true }; 30 | public Bool_Local alwaysShowTime = new(); 31 | public bool explosions = true; 32 | public bool morePrecisePercentages = true; 33 | public Bool_Local hideTopLeftButtonText = new() { Value = true }; 34 | public bool darkenDebris = true; 35 | 36 | // Units 37 | public bool lyUnits = true; 38 | public bool gmUnits = true; 39 | public bool mmUnits = true; 40 | public bool kmsUnits = true; 41 | public bool cUnits = true; 42 | public bool ktUnits = true; 43 | 44 | // Misc 45 | public bool skipBuildNewPrompt = true; 46 | public bool stopTimewarpOnEncounter = true; 47 | public bool moreCameraZoom = true; 48 | public bool moreCameraMove = true; 49 | public Bool_Local allowBackgroundProcess = new(); 50 | public Bool_Local allowTimeSlowdown = new(); 51 | public bool higherPhysicsWarp; 52 | } 53 | 54 | public class Config : ModSettings 55 | { 56 | private static Config main; 57 | 58 | private Action saveAction; 59 | 60 | protected override FilePath SettingsFile { get; } = Main.modFolder.ExtendToFile("Config.txt"); 61 | 62 | public static void Load() 63 | { 64 | main = new Config(); 65 | main.Initialize(); 66 | } 67 | 68 | public static void Save() 69 | { 70 | main.saveAction?.Invoke(); 71 | } 72 | 73 | protected override void RegisterOnVariableChange(Action onChange) 74 | { 75 | saveAction = onChange; 76 | Application.quitting += onChange; 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /src/World/TimeManipulation.cs: -------------------------------------------------------------------------------- 1 | using HarmonyLib; 2 | using JetBrains.Annotations; 3 | using SFS.UI; 4 | using SFS.World; 5 | 6 | namespace VanillaUpgrades.World 7 | { 8 | [HarmonyPatch] 9 | internal static class TimeDecelerationPatch 10 | { 11 | [HarmonyPatch(typeof(WorldTime), nameof(WorldTime.DecelerateTime))] 12 | [HarmonyPrefix] 13 | [UsedImplicitly] 14 | public static bool TimeSlowdown() 15 | { 16 | if (WorldTime.main.timewarpIndex != 0) return true; 17 | TimeManipulation.SlowTime(); 18 | return false; 19 | } 20 | 21 | [HarmonyPatch(typeof(WorldTime), nameof(WorldTime.AccelerateTime))] 22 | [HarmonyPrefix] 23 | [UsedImplicitly] 24 | public static bool EndDeceleration() 25 | { 26 | if (TimeManipulation.timeDecelIndex <= 0) return true; 27 | 28 | WorldTime.main.SetState(1, true, false); 29 | MsgDrawer.main.Log("Time restored to normal"); 30 | TimeManipulation.timeDecelIndex = 0; 31 | return false; 32 | } 33 | } 34 | 35 | public static class TimeManipulation 36 | { 37 | public static int timeDecelIndex; 38 | private static readonly double[] decelSpeeds = { 0.75, 0.5, 0.25, 0.1, 0 }; 39 | 40 | public static void SlowTime() 41 | { 42 | if (!Config.settings.allowTimeSlowdown) return; 43 | if (timeDecelIndex >= decelSpeeds.Length) return; 44 | timeDecelIndex++; 45 | var defaultMessage = true; 46 | var speed = decelSpeeds[timeDecelIndex - 1]; 47 | if (speed == 0) 48 | { 49 | defaultMessage = false; 50 | MsgDrawer.main.Log("Time frozen"); 51 | } 52 | 53 | WorldTime.main.SetState(speed, true, defaultMessage); 54 | } 55 | 56 | public static void ToggleChange() 57 | { 58 | if (!Config.settings.allowTimeSlowdown && timeDecelIndex != 0) 59 | { 60 | WorldTime.main.SetState(1, true, false); 61 | timeDecelIndex = 0; 62 | } 63 | 64 | if (timeDecelIndex != 0 && WorldTime.main.timewarpIndex != 0) timeDecelIndex = 0; 65 | } 66 | 67 | public static void StopTimewarp(bool showmsg) 68 | { 69 | if (WorldTime.main.timewarpIndex == 0 && timeDecelIndex == 0) return; 70 | WorldTime.main.timewarpIndex = 0; 71 | WorldTime.main.SetState(1, true, false); 72 | timeDecelIndex = 0; 73 | if (showmsg) MsgDrawer.main.Log("Time acceleration stopped"); 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /src/World/HoverHandler.cs: -------------------------------------------------------------------------------- 1 | using SFS; 2 | using SFS.Parts.Modules; 3 | using SFS.UI; 4 | using SFS.World; 5 | using UnityEngine; 6 | 7 | namespace VanillaUpgrades.World 8 | { 9 | internal static class HoverHandler 10 | { 11 | public static bool hoverMode; 12 | 13 | public static void ToggleHoverMode() 14 | { 15 | EnableHoverMode(!hoverMode); 16 | } 17 | 18 | public static void EnableHoverMode(bool enable = true, bool showMsg = true) 19 | { 20 | if (WorldTime.main.realtimePhysics.Value) 21 | { 22 | if (hoverMode == enable) return; 23 | hoverMode = enable; 24 | if (hoverMode) TwrTo1(); 25 | if (showMsg) MsgDrawer.main.Log(hoverMode ? "Hovering..." : "Exit hover mode"); 26 | return; 27 | } 28 | 29 | if (enable) MsgDrawer.main.Log("Cannot hover while timewarping"); 30 | } 31 | 32 | public static void TwrTo1() 33 | { 34 | if (WorldManager.currentRocket == null || !PlayerController.main.HasControl(MsgDrawer.main)) 35 | { 36 | EnableHoverMode(false, false); 37 | return; 38 | } 39 | 40 | var mass = WorldManager.currentRocket.rb2d.mass; 41 | var localGravity = 42 | (float)WorldManager.currentRocket.location.planet.Value.GetGravity(WorldManager.currentRocket.location 43 | .position.Value.magnitude); 44 | 45 | // Calculate thrust at 100% throttle (this method takes into account each engine's direction) 46 | // Note: Boosters are ignored. But honestly you wouldn't use that functionality with boosters... 47 | var thrustAt100PerCent = new Vector2(0.0f, 0.0f); 48 | 49 | foreach (EngineModule engineModule in WorldManager.currentRocket.partHolder.GetModules()) 50 | { 51 | if (!engineModule.engineOn.Value) continue; // engine has to be on 52 | Vector2 direction = engineModule.transform.TransformVector(engineModule.thrustNormal.Value); 53 | 54 | // For cheaters... 55 | var stretchFactor = 1.0f; 56 | if (Base.worldBase.AllowsCheats) stretchFactor = direction.magnitude; 57 | 58 | Vector2 engineThrust = engineModule.thrust.Value * direction.normalized * stretchFactor; 59 | thrustAt100PerCent += engineThrust; 60 | } 61 | 62 | var twrAt100PerCent = thrustAt100PerCent.magnitude / mass * 9.8f / localGravity; 63 | 64 | if (twrAt100PerCent < 1.0) 65 | // Throttle at 100% is not enough to reach TWR of 1 -> set it at 100% (Note: also works if thrust is 0) 66 | WorldManager.currentRocket.throttle.throttlePercent.Value = 1.0f; 67 | else 68 | // Adjust the throttle at the suited value 69 | WorldManager.currentRocket.throttle.throttlePercent.Value = 1.0f / twrAt100PerCent; 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /src/Build/Patches/ReplacePickCategories.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using HarmonyLib; 4 | using SFS.Builds; 5 | using SFS.UI; 6 | using SFS.UI.ModGUI; 7 | using UnityEngine; 8 | using UnityEngine.UI; 9 | using static SFS.UI.ModGUI.Builder; 10 | using Button = SFS.UI.ModGUI.Button; 11 | using Type = SFS.UI.ModGUI.Type; 12 | 13 | namespace VanillaUpgrades.Build 14 | { 15 | [HarmonyPatch(typeof(PickCategoriesMenu))] 16 | internal static class ReplacePickCategories 17 | { 18 | private static Window window; 19 | private static PickCategoriesMenu inst; 20 | 21 | private static int categories; 22 | 23 | [HarmonyPrefix] 24 | [HarmonyPatch("Start")] 25 | private static void Start(PickCategoriesMenu __instance) 26 | { 27 | inst = __instance; 28 | } 29 | 30 | [HarmonyPrefix] 31 | [HarmonyPatch("SetupElements")] 32 | private static bool SetupElements(IReadOnlyCollection picklists) 33 | { 34 | categories = picklists.Count; 35 | if (categories <= 24) return true; 36 | List