From dadc6baff7fe245718e716bb70232a391a2a27b0 Mon Sep 17 00:00:00 2001 From: siimav <1120038+siimav@users.noreply.github.com> Date: Sun, 12 May 2024 00:18:13 +0300 Subject: [PATCH] Add automated staff hiring (#2352) --- Source/RP0/RP0.csproj | 1 + Source/RP0/Settings/SpaceCenterSettings.cs | 9 -- .../LaunchComplex/LaunchComplex.cs | 2 + .../SpaceCenter/Projects/FundTargetProject.cs | 7 +- .../SpaceCenter/Projects/HireStaffProject.cs | 133 ++++++++++++++++++ .../RP0/SpaceCenter/SpaceCenterManagement.cs | 11 ++ Source/RP0/UI/KCT/GUI_BuildList.cs | 15 +- Source/RP0/UI/KCT/GUI_NewLC.cs | 2 + Source/RP0/UI/KCT/GUI_Personnel.cs | 130 ++++++++++++----- Source/RP0/UI/MaintenanceGUI.cs | 50 +++++-- Source/RP0/Utilities/KCTUtilities.cs | 27 ++++ 11 files changed, 323 insertions(+), 64 deletions(-) create mode 100644 Source/RP0/SpaceCenter/Projects/HireStaffProject.cs diff --git a/Source/RP0/RP0.csproj b/Source/RP0/RP0.csproj index a5ff208e25c..dd061e7294a 100644 --- a/Source/RP0/RP0.csproj +++ b/Source/RP0/RP0.csproj @@ -47,6 +47,7 @@ + diff --git a/Source/RP0/Settings/SpaceCenterSettings.cs b/Source/RP0/Settings/SpaceCenterSettings.cs index e7c45126ef7..ad4767623ac 100644 --- a/Source/RP0/Settings/SpaceCenterSettings.cs +++ b/Source/RP0/Settings/SpaceCenterSettings.cs @@ -117,15 +117,6 @@ public void ResetBools() nautUpkeepTrainingBools[i] = false; } - public int GetResearcherCap(int lvl = -1) - { - return -1; - - /*if (lvl == -1) - lvl = Utilities.GetBuildingUpgradeLevel(SpaceCenterFacility.ResearchAndDevelopment); - return GeneralSettings.ResearcherCaps[lvl];*/ - } - public int GetStartingPersonnel(Game.Modes mode) { if (mode == Game.Modes.CAREER) diff --git a/Source/RP0/SpaceCenter/LaunchComplex/LaunchComplex.cs b/Source/RP0/SpaceCenter/LaunchComplex/LaunchComplex.cs index 2329b09ae9c..3d212495a42 100644 --- a/Source/RP0/SpaceCenter/LaunchComplex/LaunchComplex.cs +++ b/Source/RP0/SpaceCenter/LaunchComplex/LaunchComplex.cs @@ -377,6 +377,8 @@ public void Delete() SpaceCenterManagement.Instance.UnregsiterLP(lp); SpaceCenterManagement.Instance.UnregisterLC(this); + if (SpaceCenterManagement.Instance.staffTarget.LCID == ID) + SpaceCenterManagement.Instance.staffTarget.Clear(); int index = KSC.LaunchComplexes.IndexOf(this); KSC.LaunchComplexes.RemoveAt(index); diff --git a/Source/RP0/SpaceCenter/Projects/FundTargetProject.cs b/Source/RP0/SpaceCenter/Projects/FundTargetProject.cs index 3df8ecce7cd..69e5d04c4dd 100644 --- a/Source/RP0/SpaceCenter/Projects/FundTargetProject.cs +++ b/Source/RP0/SpaceCenter/Projects/FundTargetProject.cs @@ -66,14 +66,17 @@ public ProjectType GetProjectType() public double GetTimeLeft() { - double baseFunds = Funding.Instance.Funds; + return EstimateTimeToFunds(Funding.Instance.Funds, targetFunds, epsilonTime); + } + public static double EstimateTimeToFunds(double baseFunds, double targetFunds, double epsilonTime) + { if (targetFunds - baseFunds <= 0.001d) return 0d; double timeLower = MinTime; double timeUpper = MaxTime; - + double bestTime = -1d; double lastFunds = 0d; bool lastDir = false; diff --git a/Source/RP0/SpaceCenter/Projects/HireStaffProject.cs b/Source/RP0/SpaceCenter/Projects/HireStaffProject.cs new file mode 100644 index 00000000000..9c5f1a8c979 --- /dev/null +++ b/Source/RP0/SpaceCenter/Projects/HireStaffProject.cs @@ -0,0 +1,133 @@ +using ROUtils.DataTypes; +using System; + +namespace RP0 +{ + public class HireStaffProject : ConfigNodePersistenceBase, ISpaceCenterProject, IConfigNode + { + [Persistent] + private double reserveFunds = 0d; + + [Persistent] + private int startCrewCount = 0; + + [Persistent] + private int targetCrewCount = 0; + + [Persistent] + private Guid _lcID = Guid.Empty; + public Guid LCID + { + get + { + return _lcID; + } + set + { + _lcID = value; + if (_lcID == Guid.Empty) + _lc = null; + else + _lc = SpaceCenterManagement.Instance.LC(_lcID); + } + } + + private LaunchComplex _lc = null; + public LaunchComplex LC + { + get + { + if (_lc == null && LCID != Guid.Empty) + { + _lc = SpaceCenterManagement.Instance.LC(_lcID); + } + return _lc; + } + set + { + _lc = value; + if (_lc == null) + _lcID = Guid.Empty; + else + _lcID = _lc.ID; + } + } + + public bool IsValid => targetCrewCount > 0; + + public HireStaffProject() { } + + public HireStaffProject(int startCrewCount, int targetCrewCount, double reserveFunds, LaunchComplex lc = null) + { + LC = lc; + this.startCrewCount = startCrewCount; + this.targetCrewCount = targetCrewCount; + this.reserveFunds = reserveFunds; + } + + public void Clear() + { + reserveFunds = 0d; + startCrewCount = targetCrewCount = 0; + LCID = Guid.Empty; + } + + public double GetBuildRate() + { + return 1d; + } + + public double GetFractionComplete() + { + int total = targetCrewCount - startCrewCount; + if (total <= 0) return 0d; + + return (CurrentAmount - startCrewCount) / total; + } + + public string GetItemName() + { + return $"Reach {targetCrewCount} {(IsResearch ? "researchers" : "engineers")}"; + } + + public ProjectType GetProjectType() + { + return ProjectType.None; + } + + public double GetTimeLeft() + { + double modifiedHireCost = -CurrencyUtils.Funds(IsResearch ? TransactionReasonsRP0.HiringResearchers : TransactionReasonsRP0.HiringEngineers, -Database.SettingsSC.HireCost); + double curFunds = Funding.Instance.Funds; + double fundsNeeded = reserveFunds + NumLeftToHire * modifiedHireCost; + return FundTargetProject.EstimateTimeToFunds(curFunds, fundsNeeded, 60); + } + + public double GetTimeLeftEst(double offset) + { + return GetTimeLeft(); + } + + public double IncrementProgress(double UTDiff) + { + double modifiedHireCost = -CurrencyUtils.Funds(IsResearch ? TransactionReasonsRP0.HiringResearchers : TransactionReasonsRP0.HiringEngineers, -Database.SettingsSC.HireCost); + double nextHireAt = reserveFunds + modifiedHireCost; + if (SpaceCenterManagement.Instance.Applicants > 0 || Funding.Instance.Funds > nextHireAt) + { + int numCanHire = (int)((Funding.Instance.Funds - reserveFunds) / modifiedHireCost); + numCanHire = SpaceCenterManagement.Instance.Applicants + numCanHire; + KCTUtilities.HireStaff(IsResearch, Math.Min(numCanHire, NumLeftToHire), LC); + } + + return 0d; + } + + public bool IsResearch => LCID == Guid.Empty; + + public bool IsComplete() => NumLeftToHire <= 0; + + public int NumLeftToHire => targetCrewCount - CurrentAmount; + + public int CurrentAmount => IsResearch ? SpaceCenterManagement.Instance.Researchers : LC.Engineers; + } +} diff --git a/Source/RP0/SpaceCenter/SpaceCenterManagement.cs b/Source/RP0/SpaceCenter/SpaceCenterManagement.cs index b07f6531335..3cad8836a3a 100644 --- a/Source/RP0/SpaceCenter/SpaceCenterManagement.cs +++ b/Source/RP0/SpaceCenter/SpaceCenterManagement.cs @@ -140,6 +140,9 @@ public static void ClearVesselEditMode() [KSPField(isPersistant = true)] public FundTargetProject fundTarget = new FundTargetProject(); + [KSPField(isPersistant = true)] + public HireStaffProject staffTarget = new HireStaffProject(); + #endregion #region Fields @@ -1691,6 +1694,14 @@ public void ProgressBuildTime(double UTDiff) if (fundTarget.IsValid && fundTarget.GetTimeLeft() < 0.5d) fundTarget.Clear(); } + + if (staffTarget.IsValid) + { + staffTarget.IncrementProgress(UTDiff); + if (staffTarget.IsComplete()) + staffTarget.Clear(); + } + Profiler.EndSample(); } diff --git a/Source/RP0/UI/KCT/GUI_BuildList.cs b/Source/RP0/UI/KCT/GUI_BuildList.cs index 98d8e53dedc..2e63e14daa5 100644 --- a/Source/RP0/UI/KCT/GUI_BuildList.cs +++ b/Source/RP0/UI/KCT/GUI_BuildList.cs @@ -26,7 +26,7 @@ public enum RenameType { None, Vessel, Pad, LaunchComplex }; private static double _accumulatedTimeBefore; private static GUIStyle _redText, _yellowText, _greenText, _blobText, _yellowButton, _redButton, _greenButton; - private static GUIContent _settingsTexture, _planeTexture, _rocketTexture, _techTexture, _constructTexture, + private static GUIContent _emptyTexture, _settingsTexture, _planeTexture, _rocketTexture, _techTexture, _constructTexture, _reconTexture, _rolloutTexture, _rollbackTexture, _airlaunchTexture, _recoveryTexture, _hangarTexture, _repairTexture; private const int _width1 = 120; private const int _width2 = 100; @@ -115,6 +115,7 @@ public static void InitBuildListVars() _settingsTexture = new GUIContent(GameDatabase.Instance.GetTexture("RP-1/Resources/KCT_settings16", false)); _techTexture = new GUIContent(GameDatabase.Instance.GetTexture("RP-1/Resources/KCT_tech16", false)); _repairTexture = new GUIContent(GameDatabase.Instance.GetTexture("RP-1/Resources/KCT_repair", false)); + _emptyTexture = new GUIContent(""); } public static void DrawBuildListWindow(int windowID) @@ -653,6 +654,9 @@ private static void RenderCombinedList() if (SpaceCenterManagement.Instance.fundTarget.IsValid) _allItems.Add(SpaceCenterManagement.Instance.fundTarget); + if (SpaceCenterManagement.Instance.staffTarget.IsValid) + _allItems.Add(SpaceCenterManagement.Instance.staffTarget); + // Precalc times and then sort foreach (var b in _allItems) _estTimeForItem[b] = b.GetTimeLeftEst(_timeBeforeItem.ValueOrDefault(b)); @@ -673,6 +677,13 @@ private static void RenderCombinedList() continue; GUILayout.BeginHorizontal(); + if ((t is HireStaffProject || t is FundTargetProject) && + GUILayout.Button("X", GUILayout.Width(_butW))) + { + (t as HireStaffProject)?.Clear(); + (t as FundTargetProject)?.Clear(); + } + DrawTypeIcon(t); VesselProject vp; if (t is ReconRolloutProject r) @@ -833,7 +844,7 @@ private static GUIContent GetTypeIcon(ISpaceCenterProject b) return _repairTexture; } - return _constructTexture; + return _emptyTexture; } private static void DrawTypeIcon(ISpaceCenterProject b) diff --git a/Source/RP0/UI/KCT/GUI_NewLC.cs b/Source/RP0/UI/KCT/GUI_NewLC.cs index 47059a05a42..2058f0a4fee 100644 --- a/Source/RP0/UI/KCT/GUI_NewLC.cs +++ b/Source/RP0/UI/KCT/GUI_NewLC.cs @@ -590,6 +590,8 @@ private static void ProcessNewLC(bool isModify, double curPadCost, double totalC if (isModify) { lc = activeLC; + if (SpaceCenterManagement.Instance.staffTarget.LCID == lc.ID) + SpaceCenterManagement.Instance.staffTarget.Clear(); KCTUtilities.ChangeEngineers(lc, -engineers); SpaceCenterManagement.Instance.ActiveSC.SwitchToPrevLaunchComplex(); diff --git a/Source/RP0/UI/KCT/GUI_Personnel.cs b/Source/RP0/UI/KCT/GUI_Personnel.cs index fb9ba7c518f..108c9bb14b3 100644 --- a/Source/RP0/UI/KCT/GUI_Personnel.cs +++ b/Source/RP0/UI/KCT/GUI_Personnel.cs @@ -246,13 +246,6 @@ private static void RenderResearchersSection(bool isCostCacheInvalid) GUILayout.Label(SpaceCenterManagement.Instance.Researchers.ToString("N0"), GetLabelRightAlignStyle()); GUILayout.EndHorizontal(); - GUILayout.BeginHorizontal(); - GUILayout.Label("Max:", GUILayout.Width(90)); - int resLimit = Database.SettingsSC.GetResearcherCap(); - string resLimitStr = resLimit >= 0 ? resLimit.ToString("N0") : "Unlimited"; - GUILayout.Label(resLimitStr, GetLabelRightAlignStyle()); - GUILayout.EndHorizontal(); - RenderHireFire(true, out int fireAmount, out int hireAmount); int delta = 0; @@ -307,16 +300,16 @@ private static void RenderResearchersSection(bool isCostCacheInvalid) GUILayout.EndHorizontal(); } - private static void RenderHireFire(bool research, out int fireAmount, out int hireAmount) + private static void RenderHireFire(bool isResearch, out int fireAmount, out int hireAmount) { if (KSPUtils.CurrentGameIsCareer()) { GUILayout.BeginHorizontal(); - string title = research ? "Researchers" : "Engineers"; + string title = isResearch ? "Researchers" : "Engineers"; GUILayout.Label($"Hire/Fire {title}:"); - fireAmount = research ? SpaceCenterManagement.Instance.Researchers : SpaceCenterManagement.Instance.ActiveSC.UnassignedEngineers; + fireAmount = isResearch ? SpaceCenterManagement.Instance.Researchers : SpaceCenterManagement.Instance.ActiveSC.UnassignedEngineers; int workers = _buyModifier; if (workers == int.MaxValue) workers = fireAmount; @@ -325,7 +318,7 @@ private static void RenderHireFire(bool research, out int fireAmount, out int hi GUIStyle style = canAfford ? GUI.skin.button : GetCannotAffordStyle(); if (GUILayout.Button($"Fire {workers:N0}", style, GUILayout.ExpandWidth(false)) && canAfford) { - if (research) + if (isResearch) { KCTUtilities.ChangeResearchers(-workers); SpaceCenterManagement.Instance.UpdateTechTimes(); @@ -337,6 +330,7 @@ private static void RenderHireFire(bool research, out int fireAmount, out int hi ksc.RecalculateBuildRates(false); } } + if (Event.current.type == EventType.Repaint) { if (GUILayoutUtility.GetLastRect().Contains(Event.current.mousePosition)) @@ -346,48 +340,29 @@ private static void RenderHireFire(bool research, out int fireAmount, out int hi } fireAmount = Math.Min(workers, fireAmount); - double modifiedHireCost = -CurrencyUtils.Funds(research ? TransactionReasonsRP0.HiringResearchers : TransactionReasonsRP0.HiringEngineers, -Database.SettingsSC.HireCost); + double modifiedHireCost = -CurrencyUtils.Funds(isResearch ? TransactionReasonsRP0.HiringResearchers : TransactionReasonsRP0.HiringEngineers, -Database.SettingsSC.HireCost); workers = _buyModifier; if (workers == int.MaxValue) workers = Math.Max(_buyModifierMultsPersonnel[0], SpaceCenterManagement.Instance.Applicants + (int)(Funding.Instance.Funds / modifiedHireCost)); - if (research) + if (isResearch) { - int maxRes = Database.SettingsSC.GetResearcherCap(); - if (maxRes < 0) - maxRes = int.MaxValue; - - workers = Math.Max(0, Math.Min(workers, maxRes - SpaceCenterManagement.Instance.Researchers)); + workers = Math.Max(0, workers); } - double workersToHire = Math.Max(0, workers - SpaceCenterManagement.Instance.Applicants); + int workersToHire = Math.Max(0, workers - SpaceCenterManagement.Instance.Applicants); _fundsCost = modifiedHireCost * workersToHire; // Show the result for whatever you're asking for, even if you can't afford it. - hireAmount = workers; // Math.Min(workers, (int)(Funding.Instance.Funds / Database.SettingsSC.HireCost) + KerbalConstructionTimeData.Instance.UnassignedPersonnel); + hireAmount = workers; canAfford = Funding.Instance.Funds >= _fundsCost; style = canAfford ? GUI.skin.button : GetCannotAffordStyle(); if (GUILayout.Button($"Hire {workers:N0}: √{_fundsCost:N0}", style, GUILayout.ExpandWidth(false)) && canAfford) { - // Note: have to pass base, not modified, cost here, since the CMQ reruns - KCTUtilities.SpendFunds(workersToHire * Database.SettingsSC.HireCost, research ? TransactionReasonsRP0.HiringResearchers : TransactionReasonsRP0.HiringEngineers); - if (research) - { - KCTUtilities.ChangeResearchers(workers); - SpaceCenterManagement.Instance.UpdateTechTimes(); - } - else - { - LCSpaceCenter ksc = SpaceCenterManagement.Instance.ActiveSC; - KCTUtilities.ChangeEngineers(ksc, workers); - ksc.RecalculateBuildRates(false); - } - SpaceCenterManagement.Instance.Applicants = Math.Max(0, SpaceCenterManagement.Instance.Applicants - workers); - if (SpaceCenterManagement.Instance.Applicants == 0) - SpaceCenterManagement.Instance.HiredStarterApplicants = true; - + KCTUtilities.HireStaff(isResearch, workers); _fundsCost = int.MinValue; } + if (Event.current.type == EventType.Repaint) { if (GUILayoutUtility.GetLastRect().Contains(Event.current.mousePosition)) @@ -396,6 +371,8 @@ private static void RenderHireFire(bool research, out int fireAmount, out int hi _currentPersonnelHover = PersonnelButtonHover.None; } + RenderHireNButton(isResearch); + GUILayout.EndHorizontal(); } else @@ -405,6 +382,85 @@ private static void RenderHireFire(bool research, out int fireAmount, out int hi } } + private static void RenderHireNButton(bool isResearch) + { + if (!isResearch && SpaceCenterManagement.Instance.ActiveSC.ActiveLC == null) + return; + + if (GUILayout.Button(new GUIContent("Auto hire", "Schedules staff to be hired over time"), GUILayout.ExpandWidth(false))) + { + string dialogName = "warpToStaff"; + string dialogTitle = $"Auto hire {(isResearch ? "researchers" : "engineers")}"; + + if (SpaceCenterManagement.Instance.fundTarget.IsValid) + { + string msg = "This functionality cannot be used while there's Warp To Fund Target in progress."; + PopupDialog.SpawnPopupDialog(new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), + new MultiOptionDialog(dialogName, msg, dialogTitle, HighLogic.UISkin, + new DialogGUIButton("Understood", () => { }) + ), false, HighLogic.UISkin).HideGUIsWhilePopup(); + } + else + { + int curCount = isResearch ? SpaceCenterManagement.Instance.Researchers : SpaceCenterManagement.Instance.ActiveSC.ActiveLC.Engineers; + string sNumCrew = curCount.ToString("N0"); + string sReserveFunds = Funding.Instance.Funds.ToString("N0"); + PopupDialog.SpawnPopupDialog(new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), + new MultiOptionDialog(dialogName, "", dialogTitle, HighLogic.UISkin, + isResearch ? new DialogGUISpace(0f) : new DialogGUILabel($"LC: {SpaceCenterManagement.Instance.ActiveSC.ActiveLC.Name}"), + new DialogGUILabel($"Final count {(isResearch ? "" : $"(max: {SpaceCenterManagement.Instance.ActiveSC.ActiveLC.MaxEngineers:N0})")}"), + new DialogGUITextInput(sNumCrew, false, 7, (string n) => + { + sNumCrew = n; + return sNumCrew; + }, 24f), + new DialogGUILabel("Reserve funds"), + new DialogGUITextInput(sReserveFunds, false, 12, (string n) => + { + sReserveFunds = n; + return sReserveFunds; + }, 24f), + new DialogGUIButton("Add", () => { ConfirmTargetDialog(sNumCrew, sReserveFunds, isResearch); }), + new DialogGUIButton("Cancel", () => { }) + ), false, HighLogic.UISkin).HideGUIsWhilePopup(); + } + } + } + + private static void ConfirmTargetDialog(string sNumCrew, string sReserveFunds, bool isResearch) + { + bool b1 = int.TryParse(sNumCrew, out int numCrew); + bool b2 = double.TryParse(sReserveFunds, out double reserveFunds); + if (!b1 || !b2) + { + PopupDialog.SpawnPopupDialog(new MultiOptionDialog("warpToStaffConfirmFail", + $"Failed to parse {(b1 ? "crew count" : "reserve funds")}!", + "Error", + HighLogic.UISkin, + 300, + new DialogGUIButton("Understood", () => { }) + ), false, HighLogic.UISkin).HideGUIsWhilePopup(); + } + else + { + int startCount, endCount; + LaunchComplex lc = null; + if (isResearch) + { + startCount = SpaceCenterManagement.Instance.Researchers; + endCount = numCrew; + } + else + { + lc = SpaceCenterManagement.Instance.ActiveSC.ActiveLC; + startCount = Math.Min(lc.Engineers, lc.MaxEngineers); + } + + var target = new HireStaffProject(startCount, numCrew, reserveFunds, lc); + SpaceCenterManagement.Instance.staffTarget = target; + } + } + private static string GetAssignText(bool add, LaunchComplex currentLC, out int mod) { string signChar; diff --git a/Source/RP0/UI/MaintenanceGUI.cs b/Source/RP0/UI/MaintenanceGUI.cs index 6c50b7ac582..32b8aac6c23 100644 --- a/Source/RP0/UI/MaintenanceGUI.cs +++ b/Source/RP0/UI/MaintenanceGUI.cs @@ -241,27 +241,49 @@ public void RenderSummaryTab() GUILayout.Label(FormatCost(CurrencyUtils.Rate(TransactionReasonsRP0.RateUnlockCreditIncrease) * unlockCredit), RightLabel, GUILayout.Width(160)); GUILayout.EndHorizontal(); - if (HighLogic.LoadedScene == GameScenes.SPACECENTER && GUILayout.Button(new GUIContent("Warp to Fund Target", "Warps to the fund target you specify in the resulting dialog"), HighLogic.Skin.button)) + if (HighLogic.LoadedScene == GameScenes.SPACECENTER && + GUILayout.Button(new GUIContent("Warp to Fund Target", "Warps to the fund target you specify in the resulting dialog"), HighLogic.Skin.button)) + { + ShowWarpToFundsDlg(); + } + } + + private void ShowWarpToFundsDlg() + { + InputLockManager.SetControlLock(ControlTypes.KSC_ALL, "warptofunds"); + UIHolder.Instance.HideWindow(); + if (SpaceCenterManagement.Instance.staffTarget.IsValid) + { + string msg = "This functionality cannot be used while there's automatic staff hiring in progress."; + PopupDialog.SpawnPopupDialog(new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), + new MultiOptionDialog("warpToFunds", msg, "Warp To Funds", HighLogic.UISkin, + new DialogGUIButton("Understood", () => + { + UIHolder.Instance.ShowWindow(); + InputLockManager.RemoveControlLock("warptofunds"); + }) + ), false, HighLogic.UISkin); + } + else { - InputLockManager.SetControlLock(ControlTypes.KSC_ALL, "warptofunds"); - UIHolder.Instance.HideWindow(); PopupDialog.SpawnPopupDialog(new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new MultiOptionDialog("warpToFunds", "Fund Target", "Warp To Funds", HighLogic.UISkin, - new DialogGUITextInput(warpToFundsString, false, 64, (string n) => - { - warpToFundsString = n; - return warpToFundsString; - }, 24f), - new DialogGUIButton("Estimate Time", () => { ConfirmWarpDialog(); }), - new DialogGUIButton("Cancel", () => { - UIHolder.Instance.ShowWindow(); - InputLockManager.RemoveControlLock("warptofunds"); - }) + new DialogGUITextInput(warpToFundsString, false, 64, (string n) => + { + warpToFundsString = n; + return warpToFundsString; + }, 24f), + new DialogGUIButton("Estimate Time", () => { ShowConfirmWarpDialog(); }), + new DialogGUIButton("Cancel", () => + { + UIHolder.Instance.ShowWindow(); + InputLockManager.RemoveControlLock("warptofunds"); + }) ), false, HighLogic.UISkin); } } - private void ConfirmWarpDialog() + private void ShowConfirmWarpDialog() { if (!double.TryParse(warpToFundsString, out double fundTarget)) { diff --git a/Source/RP0/Utilities/KCTUtilities.cs b/Source/RP0/Utilities/KCTUtilities.cs index 586ef3c9f18..619ecad5628 100644 --- a/Source/RP0/Utilities/KCTUtilities.cs +++ b/Source/RP0/Utilities/KCTUtilities.cs @@ -684,6 +684,8 @@ public static ISpaceCenterProject GetNextThingToFinish() _checkTime(course, ref shortestTime, ref thing); if (SpaceCenterManagement.Instance.fundTarget.IsValid) _checkTime(SpaceCenterManagement.Instance.fundTarget, ref shortestTime, ref thing); + if (SpaceCenterManagement.Instance.staffTarget.IsValid) + _checkTime(SpaceCenterManagement.Instance.staffTarget, ref shortestTime, ref thing); return thing; } @@ -1324,6 +1326,31 @@ public static void ScrapVessel(VesselProject b) AddFunds(b.GetTotalCost(), TransactionReasonsRP0.VesselPurchase); } + public static void HireStaff(bool isResearch, int workerAmount, LaunchComplex lc = null) + { + // Use up applicants first + int workersToHire = Math.Max(0, workerAmount - SpaceCenterManagement.Instance.Applicants); + + // Note: have to pass base, not modified, cost here, since the CMQ reruns + SpendFunds(workersToHire * Database.SettingsSC.HireCost, isResearch ? TransactionReasonsRP0.HiringResearchers : TransactionReasonsRP0.HiringEngineers); + if (isResearch) + { + ChangeResearchers(workerAmount); + SpaceCenterManagement.Instance.UpdateTechTimes(); + } + else + { + LCSpaceCenter ksc = lc?.KSC ?? SpaceCenterManagement.Instance.ActiveSC; + ChangeEngineers(ksc, workerAmount); + if (lc != null) + ChangeEngineers(lc, workerAmount); + ksc.RecalculateBuildRates(false); + } + SpaceCenterManagement.Instance.Applicants = Math.Max(0, SpaceCenterManagement.Instance.Applicants - workerAmount); + if (SpaceCenterManagement.Instance.Applicants == 0) + SpaceCenterManagement.Instance.HiredStarterApplicants = true; + } + public static void ChangeEngineers(LaunchComplex currentLC, int delta) { currentLC.Engineers += delta;