protected override void AddContentToWindow(ConsoleWindow window) { var seg0 = window.Screen.CreateStandardSegment(); seg0.AddInterpretter(SubjectiveDisplay <bool> .Quick(false, M.m <bool>(x => { if (mods.All(y => y.processed)) { _focus.Do(); } return ("The following mods are required by this construct but are not installed on this instance of FtD.\n" + "This popup will automatically close when all mods are either installed or discarded.\n" + "You have to restart FtD in order to apply the newly installed mods."); }), "")); foreach (var mod in mods) { window.Screen.CreateHeader(mod.name, new ToolTip("Missing mod")) .SetConditionalDisplay(() => !mod.processed); var seg1 = window.Screen.CreateStandardSegment(); seg1.SetConditionalDisplay(() => !mod.processed); seg1.AddInterpretter(StringDisplay.Quick(mod.description, "Description of missing mod")); var seg2 = window.Screen.CreateStandardHorizontalSegment(); seg2.SetConditionalDisplay(() => !mod.processed); if (!string.IsNullOrWhiteSpace(mod.manifest) && Uri.TryCreate(mod.manifest, UriKind.Absolute, out var _)) { seg2.AddInterpretter(Button.Quick("Install mod with FtdModManager", new ToolTip(mod.manifest), () => { mod.processed = true; ModManagerPlugin.Instance.manager.Install(mod.manifest); })); } if (!string.IsNullOrWhiteSpace(mod.manifest) && Uri.TryCreate(mod.link, UriKind.Absolute, out var _)) { seg2.AddInterpretter(Button.Quick("Open mod page", new ToolTip(mod.link), () => { Application.OpenURL(mod.link); })); } seg2.AddInterpretter(Button.Quick("Discard", new ToolTip("Ignore this alert"), () => { mod.processed = true; })); } }
public static void Prefix(ApsTab __instance, AdvCannonFiringPiece ____focus) { var self = __instance; var focus = ____focus; var ShellRackModel = focus.ShellRackModel; var Node = focus.Node; var barrelSystem = focus.BarrelSystem as CannonMultiBarrelSystem; string GetLoaderROF() { float culmROF = 0; if (Node.ShellRacks.Racks.Count > 1) { foreach (var thisRack in Node.ShellRacks.Racks) { //Debug.Log("[Walrus Shells Ballistic Madness] Checking For Loaded Shell."); if (thisRack.LoadedShell != null) { //Debug.Log("[Walrus Shells Ballistic Madness] Calculating Load Time."); float loadtime = ShellConstants.LoadTimeForShellVolume(new ShellModel_Propellant(thisRack.LoadedShell).GetTotalVolume()); //Debug.Log("[Walrus Shells Ballistic Madness] Is it a beltfed rack?"); if (thisRack as BeltFeedShellRackModel != null) { BeltFeedShellRackModel belty = thisRack as BeltFeedShellRackModel; //Debug.Log("[Walrus Shells Ballistic Madness] Doing Beltfed Math?"); culmROF += 60 / loadtime / belty.LoadingTimeComplexityModifier / 0.2f; } else { //Debug.Log("[Walrus Shells Ballistic Madness] Is it a standard rack?"); if (thisRack as ShellRackModel != null) { ShellRackModel standardRack = thisRack as ShellRackModel; //Debug.Log("[Walrus Shells Ballistic Madness] Doing Normal Math?"); culmROF += 60 / loadtime / standardRack.MultipleDirectionsSpeedUpFactor() / standardRack.LoadingTimeComplexityModifier / Rounding.R2(Mathf.Min(1f / Mathf.Sqrt(standardRack.LengthCapacity), 1f)); } } } } } return($"Semi-Stable RoF Estimation: <b>{culmROF:0.##} rounds/min</b>"); } string GetBarrelROF() { var nextShell = Node.ShellRacks.GetNextShell(false); if (nextShell == null) { return("Burst RoF: No shell loaded"); } float baseCooldown = ShellConstants.CooldownTimeFromVolumeOfPropellant(nextShell.Propellant.GetNormalisedVolumeOfPropellant()); float cooldownFactor = Traverse.Create(barrelSystem).Method("CooldownFactor").GetValue <float>(); float rof = 60 / (baseCooldown * cooldownFactor) * barrelSystem.BarrelCount; return($"Burst RoF: <b>{rof:0.##} rounds/min</b>"); } string GetRecoilInfo() { float refresh = Node.HydraulicRefresh; float capacity = Node.HydraulicCapacity; float dt = 60 / focus.Data.MaxFireRatePerMinute; var shell = Node.ShellRacks.GetNextShell(false); if (shell == null) { return("No shell loaded, recoil information unavailable"); } float overclockFactor = Mathf.Max(focus.Data.CooldownOverClock + 1, 1); float railReloadTime = focus.RailReloadTime(); float railFraction = (railReloadTime < float.PositiveInfinity && railReloadTime > 0) ? Mathf.Clamp01(dt / railReloadTime) : 0; float total = overclockFactor * focus.GetRecoilForce( shell.Propellant.GetNormalisedVolumeOfPropellant(), focus.RailgunDraw() * railFraction); float reduction = Math.Min(refresh * dt, capacity); float actual = total - reduction; return ($"Recoil per shot at current RoF ({dt:0.####}s between shots): {total:0} - {reduction:0} = <b>{actual:0}</b>\n" + $"Maximum recoil reduction is {capacity:0} and recovers {refresh:0.#} per second"); } string GetAmmoInfo() { var shell = Node.ShellRacks.GetNextShell(false); if (shell == null) { return("Ammo Consumption: No shell loaded"); } float rof = focus.Data.MaxFireRatePerMinute / 60; float cost = shell.AmmoCost.GetAmmoCost(); return($"Ammo Consumption: <b>{cost * rof:0} ammo/s</b>"); } //Tuple<float, float> GetReductionForHydraulicLength(int len) //{ // return new Tuple<float, float>(1250f * len * len, Rounding.R0(10000f * Mathf.Pow(len, 2 / 3f))); //} //string recoilData = string.Join("\n", new[] { 1, 2, 4, 6, 8 }.Select(x => string.Join(", ", GetReductionForHydraulicLength(x)))); self.CreateHeader("Rate Of Fire Predictor", new ToolTip("")); var seg1 = self.CreateStandardSegment(); seg1.AddInterpretter(SubjectiveDisplay <AdvCannonFiringPiece> .Quick(focus, M.m <AdvCannonFiringPiece>(x => GetLoaderROF()), "Prediction of the cannon's actual rate of fire.")); seg1.AddInterpretter(SubjectiveDisplay <AdvCannonFiringPiece> .Quick(focus, M.m <AdvCannonFiringPiece>(x => GetBarrelROF()), "The maximum burst RoF of the cannon without overclocking. Based on cooldown time.")); seg1.AddInterpretter(SubjectiveDisplay <AdvCannonFiringPiece> .Quick(focus, M.m <AdvCannonFiringPiece>(x => GetRecoilInfo()), "Hydraulic Recoil Absorber data:\n\n" + "Length ║ Capacity │ Refresh Rate\n"+ "1m ║ 1250 │ 10000\n"+ "2m ║ 5000 │ 15874\n"+ "4m ║ 20000 │ 25198\n"+ "6m ║ 45000 │ 33019\n"+ "8m ║ 80000 │ 40000")); seg1.AddInterpretter(SubjectiveDisplay <AdvCannonFiringPiece> .Quick(focus, M.m <AdvCannonFiringPiece>(x => GetAmmoInfo()), "The ammunition requirement of the cannon at current RoF.")); }
protected override ConsoleWindow BuildInterface(string suggestedName = "") { var window1 = NewWindow("Mod List", WindowSizing.GetLhs()); window1.DisplayTextPrompt = false; var seg1 = window1.Screen.CreateStandardSegment(); foreach (var mod in _focus.mods) { var btn = seg1.AddInterpretter(SubjectiveButton <ModPreferences> .Quick(mod, mod.modName, new ToolTip(mod.basePath, 400), x => { selected = x; })); btn.Color = M.m <ModPreferences>(x => selected == x ? Color.green : Color.white); } var window2 = NewWindow("Mod Manager", WindowSizing.GetRhs()); window2.DisplayTextPrompt = false; window2.Screen.CreateHeader("Mod Options", new ToolTip("Options for the selected mod")); var seg2 = window2.Screen.CreateStandardSegment(); seg2.SetConditionalDisplay(() => selected != null); seg2.AddInterpretter(SubjectiveDisplay <Manager> .Quick(_focus, M.m <Manager>( x => { if (selected.Managed) { return("This mod is managed by FtdModManager"); } else { return("This mod is <b>not</b> managed by FtdModManager"); } } ), "Information about this mod")); var items = Enum.GetNames(typeof(UpdateType)).Select(x => new DropDownMenuAltItem <UpdateType> { Name = x, ToolTip = x }); var menu = new DropDownMenuAlt <UpdateType>(); menu.SetItems(items.ToArray()); seg2.AddInterpretter(new DropDown <Manager, UpdateType>(_focus, menu, (manager, x) => x == selected.updateType, (manager, x) => _focus.SetUpdateType(selected, x))); seg2.AddInterpretter(SubjectiveButton <Manager> .Quick(_focus, "Check update", new ToolTip("Check update"), x => { x.CheckUpdate(selected); })); seg2.AddInterpretter(SubjectiveButton <Manager> .Quick(_focus, "Uninstall", new ToolTip("Uninstall mod"), x => { _focus.DetectMods(); TriggerRebuild(); })); window2.Screen.CreateSpace(); window2.Screen.CreateHeader("Mod Installation", new ToolTip("Install mod, etc.")); var seg3 = window2.Screen.CreateStandardSegment(); seg3.AddInterpretter(SubjectiveButton <Manager> .Quick(_focus, "Install new mod", new ToolTip("Install new mod"), x => preparingInstall = true)) .SetConditionalDisplayFunction(() => !preparingInstall); seg3.AddInterpretter(TextInput <Manager> .Quick(_focus, M.m <Manager>(x => manifestUri), "Install URI", new ToolTip("Paste the URI of the modmanifest.json here"), (manager, x) => manifestUri = x)) .SetConditionalDisplayFunction(() => preparingInstall); seg3.AddInterpretter(TextInput <Manager> .Quick(_focus, M.m <Manager>(x => modDir), "Install path (Optional)", new ToolTip("The installation directory of the new mod. Leave empty to use default value"), (manager, x) => modDir = x)) .SetConditionalDisplayFunction(() => preparingInstall); var seg4 = window2.Screen.CreateStandardHorizontalSegment(); seg4.AddInterpretter(SubjectiveButton <Manager> .Quick(_focus, "Install", new ToolTip("Install new mod!"), x => { _focus.Install(manifestUri, modDir).ContinueWith(y => { isInstalling = false; preparingInstall = false; manifestUri = ""; modDir = ""; _focus.DetectMods(); TriggerRebuild(); }); })) .SetConditionalDisplayFunction(() => preparingInstall && !isInstalling); seg4.AddInterpretter(SubjectiveButton <Manager> .Quick(_focus, "Cancel", new ToolTip("Cancel mod installation"), x => preparingInstall = false)) .SetConditionalDisplayFunction(() => preparingInstall && !isInstalling); window2.Screen.CreateHeader("Miscellaneous", new ToolTip("Other useful operations")); var seg5 = window2.Screen.CreateStandardSegment(); (seg5.AddInterpretter(SubjectiveButton <Manager> .Quick(_focus, "Restart FtD", new ToolTip("Restart FtD in order to reload mods"), x => _focus.RestartGame())) .SetConditionalDisplayFunction(() => !isInstalling) as SubjectiveButton <Manager>) .Color = M.m <Manager>(new Color(255 / 255f, 179 / 255f, 179 / 255f)); //window.Screen.CreateSpace(); return(window1); }