diff --git a/GameData/RP-1/CustomBarnKit.cfg b/GameData/RP-1/CustomBarnKit.cfg index 810d7c01fba..1ca6c5600c3 100644 --- a/GameData/RP-1/CustomBarnKit.cfg +++ b/GameData/RP-1/CustomBarnKit.cfg @@ -90,11 +90,11 @@ } @ADMINISTRATION { - @levels = 3 - @upgradesVisual = 1, 2, 3 - @upgrades = 25000, 250000, 750000 - @activeStrategyLimit = 2, 3, 4 - @strategyCommitRange = 0, 0, 0 + @levels = 9 + @upgradesVisual = 1, 1, 2, 2, 2, 3, 3, 3, 3 + @upgrades = 25000, 40000, 140000, 250000, 400000, 500000, 500000, 500000, 500000 + @activeStrategyLimit = 5, 6, 7, 8, 9, 10, 11, 12, 13 + @strategyCommitRange = 0, 0, 0, 0, 0, 0, 0, 0, 0 } @RESEARCH { diff --git a/GameData/RP-1/Localization/en-us.cfg b/GameData/RP-1/Localization/en-us.cfg index bbfa53e1530..52cc451307e 100644 --- a/GameData/RP-1/Localization/en-us.cfg +++ b/GameData/RP-1/Localization/en-us.cfg @@ -3,11 +3,11 @@ RP0conf = True en-us { - #autoLOC_439627 = Active Programs: <<1>> [Max: <<2>>] - #autoLOC_900144 = Max Active Programs: [StrategyCount] + #autoLOC_439627 = Program Slots: <<1>> [Max: <<2>>] + #autoLOC_900144 = Max Program Slots: [StrategyCount] #autoLOC_900268 = Active Programs #autoLOC_6001741 = Programs - #autoLOC_6002231 = Max Active Programs: + #autoLOC_6002231 = Max Program Slots: #autoLOC_304887 = Leader can be removed #autoLOC_304890 = Leader: Cannot be removed as they have not yet served the minimum time. diff --git a/GameData/RP-1/Programs/Programs.cfg b/GameData/RP-1/Programs/Programs.cfg index 92d78e4494e..e274ef8d2b9 100644 --- a/GameData/RP-1/Programs/Programs.cfg +++ b/GameData/RP-1/Programs/Programs.cfg @@ -9,6 +9,7 @@ RP0_PROGRAM fundingCurve = BackloadedFundingCurve repDeltaOnCompletePerYearEarly = 30 repPenaltyPerYearLate = 30 + slots = 2 OBJECTIVES { @@ -66,6 +67,7 @@ RP0_PROGRAM baseFunding = 210000 repDeltaOnCompletePerYearEarly = 20 repPenaltyPerYearLate = 20 + slots = 2 OBJECTIVES { @@ -98,6 +100,7 @@ RP0_PROGRAM baseFunding = 210000 repDeltaOnCompletePerYearEarly = 20 repPenaltyPerYearLate = 20 + slots = 2 OBJECTIVES { @@ -150,6 +153,7 @@ RP0_PROGRAM fundingCurve = MildBackloadedFundingCurve repDeltaOnCompletePerYearEarly = 50 repPenaltyPerYearLate = 50 + slots = 2 REQUIREMENTS { @@ -199,6 +203,7 @@ RP0_PROGRAM baseFunding = 875000 repDeltaOnCompletePerYearEarly = 75 repPenaltyPerYearLate = 75 + slots = 3 REQUIREMENTS { @@ -245,6 +250,7 @@ RP0_PROGRAM baseFunding = 360000 repDeltaOnCompletePerYearEarly = 100 repPenaltyPerYearLate = 100 + slots = 1 REQUIREMENTS { @@ -289,6 +295,7 @@ RP0_PROGRAM baseFunding = 400000 repDeltaOnCompletePerYearEarly = 100 repPenaltyPerYearLate = 100 + slots = 1 REQUIREMENTS { @@ -327,6 +334,7 @@ RP0_PROGRAM fundingCurve = MildBackloadedFundingCurve repDeltaOnCompletePerYearEarly = 400 repPenaltyPerYearLate = 400 + slots = 2 REQUIREMENTS { @@ -361,6 +369,7 @@ RP0_PROGRAM baseFunding = 800000 repDeltaOnCompletePerYearEarly = 200 repPenaltyPerYearLate = 200 + slots = 2 REQUIREMENTS { @@ -403,6 +412,7 @@ RP0_PROGRAM fundingCurve = MildBackloadedFundingCurve repDeltaOnCompletePerYearEarly = 400 repPenaltyPerYearLate = 400 + slots = 2 REQUIREMENTS { @@ -445,6 +455,7 @@ RP0_PROGRAM repDeltaOnCompletePerYearEarly = 400 repPenaltyPerYearLate = 400 repToConfidence = 3 + slots = 3 REQUIREMENTS { @@ -495,6 +506,7 @@ RP0_PROGRAM fundingCurve = BackloadedFundingCurve repDeltaOnCompletePerYearEarly = 400 repPenaltyPerYearLate = 400 + slots = 3 REQUIREMENTS { @@ -539,6 +551,7 @@ RP0_PROGRAM repDeltaOnCompletePerYearEarly = 300 repPenaltyPerYearLate = 300 repToConfidence = 2 + slots = 2 REQUIREMENTS { @@ -577,6 +590,7 @@ RP0_PROGRAM repDeltaOnCompletePerYearEarly = 800 repPenaltyPerYearLate = 800 repToConfidence = 2 + slots = 4 REQUIREMENTS { @@ -630,6 +644,7 @@ disabled_RP0_PROGRAM baseFunding = 15000000 repDeltaOnCompletePerYearEarly = 750 repPenaltyPerYearLate = 750 + slots = 3 REQUIREMENTS { @@ -663,6 +678,7 @@ RP0_PROGRAM repDeltaOnCompletePerYearEarly = 800 repPenaltyPerYearLate = 800 repToConfidence = 2 + slots = 3 REQUIREMENTS { @@ -705,6 +721,7 @@ RP0_PROGRAM repDeltaOnCompletePerYearEarly = 800 repPenaltyPerYearLate = 800 repToConfidence = 2 + slots = 3 REQUIREMENTS { @@ -741,6 +758,7 @@ RP0_PROGRAM baseFunding = 4000000 repDeltaOnCompletePerYearEarly = 600 repPenaltyPerYearLate = 600 + slots = 2 REQUIREMENTS { @@ -777,6 +795,7 @@ RP0_PROGRAM repDeltaOnCompletePerYearEarly = 600 repPenaltyPerYearLate = 600 repToConfidence = 3 + slots = 3 REQUIREMENTS { @@ -813,6 +832,7 @@ RP0_PROGRAM repDeltaOnCompletePerYearEarly = 600 repPenaltyPerYearLate = 600 repToConfidence = 3 + slots = 2 REQUIREMENTS { @@ -850,6 +870,7 @@ RP0_PROGRAM repDeltaOnCompletePerYearEarly = 600 repPenaltyPerYearLate = 600 repToConfidence = 3 + slots = 3 REQUIREMENTS { @@ -896,6 +917,7 @@ disabled_RP0_PROGRAM baseFunding = 14400000 repDeltaOnCompletePerYearEarly = 800 repPenaltyPerYearLate = 800 + slots = 4 REQUIREMENTS { @@ -926,6 +948,7 @@ RP0_PROGRAM repDeltaOnCompletePerYearEarly = 600 repPenaltyPerYearLate = 600 repToConfidence = 3 + slots = 3 REQUIREMENTS { @@ -979,6 +1002,7 @@ disabled_RP0_PROGRAM baseFunding = 21600000 repDeltaOnCompletePerYearEarly = 800 repPenaltyPerYearLate = 800 + slots = 4 REQUIREMENTS { @@ -1009,6 +1033,7 @@ RP0_PROGRAM repDeltaOnCompletePerYearEarly = 600 repPenaltyPerYearLate = 600 repToConfidence = 2 + slots = 3 REQUIREMENTS { @@ -1052,6 +1077,7 @@ RP0_PROGRAM repDeltaOnCompletePerYearEarly = 1000 repPenaltyPerYearLate = 1000 repToConfidence = 3 + slots = 4 REQUIREMENTS { @@ -1106,6 +1132,7 @@ RP0_PROGRAM baseFunding = 25200000 repDeltaOnCompletePerYearEarly = 1200 repPenaltyPerYearLate = 1200 + slots = 4 REQUIREMENTS { @@ -1142,6 +1169,7 @@ disabled_RP0_PROGRAM baseFunding = 20000000 repDeltaOnCompletePerYearEarly = 1500 repPenaltyPerYearLate = 1500 + slots = 5 REQUIREMENTS { @@ -1175,6 +1203,7 @@ disabled_RP0_PROGRAM baseFunding = 42000000 repDeltaOnCompletePerYearEarly = 2000 repPenaltyPerYearLate = 2000 + slots = 5 REQUIREMENTS { @@ -1204,6 +1233,7 @@ disabled_RP0_PROGRAM baseFunding = 15000000 repDeltaOnCompletePerYearEarly = 2000 repPenaltyPerYearLate = 2000 + slots = 4 REQUIREMENTS { @@ -1233,6 +1263,7 @@ disabled_RP0_PROGRAM baseFunding = 60000000 repDeltaOnCompletePerYearEarly = 2500 repPenaltyPerYearLate = 2500 + slots = 6 REQUIREMENTS { diff --git a/Source/Harmony/Administration.cs b/Source/Harmony/Administration.cs index a8acb92a60d..c3e2011d8a3 100644 --- a/Source/Harmony/Administration.cs +++ b/Source/Harmony/Administration.cs @@ -19,8 +19,8 @@ internal class PatchAdministration internal static void FixProgramCounts(Administration __instance) { // We need to reset the strategy count because we only want to track programs, not leaders too. - __instance.activeStrategyCount = ProgramHandler.Instance.ActivePrograms.Count; - __instance.maxActiveStrategies = ProgramHandler.Instance.ActiveProgramLimit; + __instance.activeStrategyCount = ProgramHandler.Instance.ActiveProgramSlots; + __instance.maxActiveStrategies = ProgramHandler.Instance.MaxProgramSlots; } [HarmonyPrefix] @@ -252,7 +252,7 @@ internal static bool Prefix_CreateActiveStratList(Administration __instance) _strategies.Clear(); FixProgramCounts(__instance); - __instance.activeStratCount.text = Localizer.Format("#autoLOC_439627", ProgramHandler.Instance.ActivePrograms.Count, ProgramHandler.Instance.ActiveProgramLimit); + __instance.UpdateStrategyCount(); return false; } @@ -386,8 +386,10 @@ internal static void OnActivateProgramConfirm() { var newActiveStrat = Administration.Instance.SelectedWrapper.strategy; AdminExtender.Instance.SetTabView(AdministrationActiveTabView.Active); - Administration.StrategyWrapper selectedStrategy = Administration.Instance.AddActiveStratItem(Administration.Instance.SelectedWrapper.strategy); - Administration.Instance.SetSelectedStrategy(selectedStrategy); + Administration.Instance.scrollListActive.AddItem(Administration.Instance.CreateActiveStratItem(Administration.Instance.SelectedWrapper.strategy, out var wrapper)); + Administration.Instance.SetSelectedStrategy(wrapper); + FixProgramCounts(Administration.Instance); + Administration.Instance.UpdateStrategyCount(); // Reset program speeds - safe because we early-out if a program is active or complete. foreach (var strat in StrategySystem.Instance.Strategies) { @@ -531,7 +533,7 @@ internal static void Prefix_OnAcceptConfirm(Administration __instance) [HarmonyPatch("UpdateStrategyCount")] internal static bool Prefix_UpdateStrategyCount(Administration __instance) { - __instance.activeStratCount.text = Localizer.Format("#autoLOC_439627", ProgramHandler.Instance.ActivePrograms.Count, ProgramHandler.Instance.ActiveProgramLimit); + __instance.activeStratCount.text = Localizer.Format("#autoLOC_439627", ProgramHandler.Instance.ActiveProgramSlots, ProgramHandler.Instance.MaxProgramSlots); return false; } } diff --git a/Source/Harmony/Strategy.cs b/Source/Harmony/Strategy.cs index 246a7b0e2f5..db928a53f4f 100644 --- a/Source/Harmony/Strategy.cs +++ b/Source/Harmony/Strategy.cs @@ -82,7 +82,7 @@ internal static void Prefix_CanBeActivated(Strategies.Strategy __instance) [HarmonyPatch("CanBeActivated")] internal static void Postfix_CanBeActivated() { - KSP.UI.Screens.Administration.Instance.activeStrategyCount = ProgramHandler.Instance.ActivePrograms.Count; + KSP.UI.Screens.Administration.Instance.activeStrategyCount = ProgramHandler.Instance.ActiveProgramSlots; } // For our Strategy class, replace the basic Activate with a virtual one. diff --git a/Source/Programs/Program.cs b/Source/Programs/Program.cs index 60b51729a3b..e62ec95527f 100644 --- a/Source/Programs/Program.cs +++ b/Source/Programs/Program.cs @@ -126,9 +126,12 @@ public static double RepPenaltyPerYearLateCalc(Speed spd, double pen) } [Persistent(isPersistant = false)] - public float repToConfidence = -1f; + private float repToConfidence = -1f; public float RepToConfidence => repToConfidence >= 0f ? repToConfidence : ProgramHandler.Settings.repToConfidence; + [Persistent(isPersistant = false)] + public int slots = 2; + public List programsToDisableOnAccept = new List(); public List optionalContracts = new List(); @@ -191,6 +194,7 @@ public Program(Program toCopy) : this() speed = toCopy.speed; confidenceCosts = toCopy.confidenceCosts; repToConfidence = toCopy.repToConfidence; + slots = toCopy.slots; } public override string ToString() => $"{name} ({(IsComplete ? "Complete" : IsActive ? "Active" : "Inactive")})"; @@ -464,6 +468,8 @@ public string GetDescription(bool extendedInfo) text += $"\n\n{Localizer.Format("#rp0_Admin_Program_ConfidenceRequired", DisplayConfidenceCost.ToString("N0"))}"; } + text = $"Slots Taken: {slots}\n\n{text}"; + var leadersUnlockedByThis = StrategySystem.Instance.SystemConfig.Strategies .OfType() .Where(s => s.DepartmentName != "Programs" && diff --git a/Source/Programs/ProgramHandler.cs b/Source/Programs/ProgramHandler.cs index b48040eba12..b1a7efcec98 100644 --- a/Source/Programs/ProgramHandler.cs +++ b/Source/Programs/ProgramHandler.cs @@ -40,7 +40,19 @@ public class ProgramHandler : ScenarioModule public HashSet DisabledPrograms { get; private set; } = new HashSet(); - public int ActiveProgramLimit => GameVariables.Instance.GetActiveStrategyLimit(ScenarioUpgradeableFacilities.GetFacilityLevel(SpaceCenterFacility.Administration)); + public int MaxProgramSlots => GameVariables.Instance.GetActiveStrategyLimit(ScenarioUpgradeableFacilities.GetFacilityLevel(SpaceCenterFacility.Administration)); + + public int ActiveProgramSlots + { + get + { + int pts = 0; + foreach (var p in ActivePrograms) + pts += p.slots; + + return pts; + } + } public static void EnsurePrograms() { @@ -280,7 +292,7 @@ private void WindowFunction(int windowID) _scrollPos = scrollScope.scrollPosition; GUILayout.BeginHorizontal(); - GUILayout.Label($"Active programs: {ActivePrograms.Count}/{ActiveProgramLimit}", HighLogic.Skin.label); + GUILayout.Label($"Program Points: {ActiveProgramSlots}/{MaxProgramSlots}", HighLogic.Skin.label); GUILayout.EndHorizontal(); foreach (Program p in ActivePrograms) @@ -330,7 +342,7 @@ private void DrawProgramSection(Program p) } else if (!isActive) { - GUI.enabled = ActivePrograms.Count < ActiveProgramLimit; + GUI.enabled = ActiveProgramSlots < MaxProgramSlots; if (GUILayout.Button(canAccept ? "Accept" : "CHTAccept", HighLogic.Skin.button)) { ActivateProgram(p); diff --git a/Source/Programs/ProgramStrategy.cs b/Source/Programs/ProgramStrategy.cs index 1466f19efb8..8ddde041881 100644 --- a/Source/Programs/ProgramStrategy.cs +++ b/Source/Programs/ProgramStrategy.cs @@ -114,7 +114,7 @@ public override bool CanActivate(ref string reason) } // Handled by base in the Admin screen. - //if (ProgramHandler.Instance.ActivePrograms.Count >= ProgramHandler.Instance.ActiveProgramLimit) + //if (ProgramHandler.Instance.ProgramPoints >= ProgramHandler.Instance.ActiveProgramLimit) // return false; return true; diff --git a/Source/Properties/AssemblyInfo.cs b/Source/Properties/AssemblyInfo.cs index ef3001e7cc0..20c3d318d70 100644 --- a/Source/Properties/AssemblyInfo.cs +++ b/Source/Properties/AssemblyInfo.cs @@ -38,9 +38,9 @@ [assembly: AssemblyInformationalVersion("@ASSEMBLYINFORMATIONALVERSION@")] [assembly: KSPAssembly("RP-0", @MAJOR@, @MINOR@)] #else -[assembly: AssemblyFileVersion("2.3.0.0")] -[assembly: AssemblyInformationalVersion("2.3.0.0")] -[assembly: KSPAssembly("RP-0", 2, 3)] +[assembly: AssemblyFileVersion("2.4.0.0")] +[assembly: AssemblyInformationalVersion("2.4.0.0")] +[assembly: KSPAssembly("RP-0", 2, 4)] #endif [assembly: KSPAssemblyDependency("ModularFlightIntegrator", 1, 0)] diff --git a/Source/RP0.csproj b/Source/RP0.csproj index 290f3e76801..376860ed3b2 100644 --- a/Source/RP0.csproj +++ b/Source/RP0.csproj @@ -191,6 +191,7 @@ + diff --git a/Source/UpgradeScripts/v2_4_AdminLevels.cs b/Source/UpgradeScripts/v2_4_AdminLevels.cs new file mode 100644 index 00000000000..a2a69f55e58 --- /dev/null +++ b/Source/UpgradeScripts/v2_4_AdminLevels.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.Generic; +using SaveUpgradePipeline; +using UnityEngine; + +namespace RP0.UpgradeScripts +{ + [UpgradeModule(LoadContext.SFS, sfsNodeUrl = "GAME/SCENARIO")] + public class v2_4_AdminLevels : UpgradeScript + { + public override string Name { get => "RP-1 Admin Building Levels Upgrader"; } + public override string Description { get => "Updates admin building level"; } + public override Version EarliestCompatibleVersion { get => new Version(2, 0, 0); } + protected static Version _targetVersion = new Version(2, 4, 0); + public override Version TargetVersion => _targetVersion; + + public override TestResult OnTest(ConfigNode node, LoadContext loadContext, ref string nodeName) + { + nodeName = node.GetValue("name"); + return nodeName == "ScenarioUpgradeableFacilities" ? TestResult.Upgradeable : TestResult.Pass; + } + + public override void OnUpgrade(ConfigNode node, LoadContext loadContext, ConfigNode parentNode) + { + string name = node.GetValue("name"); + if (name != "ScenarioUpgradeableFacilities") + return; + + foreach (ConfigNode n in node.nodes) + { + if (n.name != "SpaceCenter/Administration") + continue; + + string lvl = n.GetValue("lvl"); + switch (lvl) + { + case "0.5": lvl = "0.375"; break; + case "1": lvl = "0.625"; break; + default: return; + } + + n.SetValue("lvl", lvl); + Debug.Log($"[RP-0] UpgradePipeline context {loadContext} updated Admin level to {lvl}"); + return; + } + } + } + + [UpgradeModule(LoadContext.SFS, sfsNodeUrl = "GAME/SCENARIO/KSCs/KSCItem/FacilityUpgrades/FacilityUpgrade")] + public class v2_4_AdminLevelsKCT : UpgradeScript + { + public override string Name { get => "RP-1 Admin Building Levels Upgrader"; } + public override string Description { get => "Updates admin building level"; } + public override Version EarliestCompatibleVersion { get => new Version(2, 0, 0); } + protected static Version _targetVersion = new Version(2, 4, 0); + public override Version TargetVersion => _targetVersion; + + public override TestResult OnTest(ConfigNode node, LoadContext loadContext, ref string nodeName) + { + nodeName = node.GetValue("id"); + return nodeName == "SpaceCenter/Administration" ? TestResult.Upgradeable : TestResult.Pass; + } + + public override void OnUpgrade(ConfigNode node, LoadContext loadContext, ConfigNode parentNode) + { + string name = node.GetValue("id"); + if (name != "SpaceCenter/Administration") + return; + + int oldCur = 0; + int oldUp = 0; + double oldCost = 0d; + node.TryGetValue("currentLevel", ref oldCur); + node.TryGetValue("upgradeLevel", ref oldUp); + node.TryGetValue("spentCost", ref oldCost); + + int newCur = 0; + int newUp = 0; + switch (oldUp) + { + case 1: + if (oldCost < 40000d) + { + newCur = 0; + newUp = 1; + } + else if (oldCost < 140000d) + { + newCur = 1; + newUp = 2; + } + else + { + newCur = 2; + newUp = 3; + } + break; + + case 2: + if (oldCost < 400000d) + { + newCur = 3; + newUp = 4; + } + else + { + newCur = 4; + newUp = 5; + } + break; + } + if (newUp != 5) + { + // Except in the case of going to lvl5, we rejigger BP and total cost + double cost = 0; + switch (newUp) + { + case 1: cost = 40000d; break; + case 2: cost = 140000d; break; + case 3: cost = 250000d; break; + case 4: cost = 400000d; break; + } + node.SetValue("BP", KerbalConstructionTime.Formula.GetConstructionBP(cost, SpaceCenterFacility.Administration)); + node.SetValue("cost", cost.ToString("N0")); + } + node.SetValue("currentLevel", newCur); + node.SetValue("upgradeLevel", newUp); + + Debug.Log($"[RP-0] UpgradePipeline context {loadContext} updated KCT Admin Building upgrade to target level {newUp} (was {oldUp})"); + } + } +}