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;