From fe4936c5268b21a32cd85559fdfd98a1b6d5ebd9 Mon Sep 17 00:00:00 2001 From: siimav Date: Tue, 19 Sep 2023 00:31:53 +0300 Subject: [PATCH] Allow only EC to be added inside procedural avionics. This allows the removal of spherical tank shenanigans and the need to tool separate SM tanks along with the avioncs unit. --- GameData/RP-1/Tree/ProceduralAvionics.cfg | 2 +- GameData/RP-1/Tree/ResourceTechs.cfg | 21 +++++ Source/Avionics/ModuleProceduralAvionics.cs | 12 +-- Source/Avionics/ProceduralAvionicsWindow.cs | 64 ++++------------ Source/RP0.csproj | 1 - Source/Tooling/ModuleToolingProcAvionics.cs | 85 +-------------------- Source/Utilities/SphericalTankUtilities.cs | 45 ----------- 7 files changed, 45 insertions(+), 185 deletions(-) delete mode 100644 Source/Utilities/SphericalTankUtilities.cs diff --git a/GameData/RP-1/Tree/ProceduralAvionics.cfg b/GameData/RP-1/Tree/ProceduralAvionics.cfg index 2eb4a1e105f..19a69e0c50c 100644 --- a/GameData/RP-1/Tree/ProceduralAvionics.cfg +++ b/GameData/RP-1/Tree/ProceduralAvionics.cfg @@ -7,7 +7,7 @@ %vesselType = Probe %maxTemp = 1073.15 %skinMaxTemp = 1073.15 - %roTankType = service + %roTankType = battery %MODULE[AdjustableCoMShifter] {} diff --git a/GameData/RP-1/Tree/ResourceTechs.cfg b/GameData/RP-1/Tree/ResourceTechs.cfg index c9ac17178ed..56043a8b023 100644 --- a/GameData/RP-1/Tree/ResourceTechs.cfg +++ b/GameData/RP-1/Tree/ResourceTechs.cfg @@ -125,6 +125,27 @@ // =============================================================================== // Part Upgrade patches // =============================================================================== +@PARTUPGRADE[RFTech-Battery-II]:FOR[xxxRP0] +{ + %techRequired = electronicsHuman + %entryCost = 0 + %cost = 0 +} + +@PARTUPGRADE[RFTech-Battery-III]:FOR[xxxRP0] +{ + %techRequired = electronicsAdvCapsules + %entryCost = 0 + %cost = 0 +} + +@PARTUPGRADE[RFTech-Battery-IV]:FOR[xxxRP0] +{ + %techRequired = electronicsLunar + %entryCost = 0 + %cost = 0 +} + @PARTUPGRADE[RFTech-SM-II]:FOR[xxxRP0] { %techRequired = materialsScienceHuman diff --git a/Source/Avionics/ModuleProceduralAvionics.cs b/Source/Avionics/ModuleProceduralAvionics.cs index ab7f4ddc796..2e2dca261ad 100644 --- a/Source/Avionics/ModuleProceduralAvionics.cs +++ b/Source/Avionics/ModuleProceduralAvionics.cs @@ -1,6 +1,5 @@ using KSPAPIExtensions; using RealFuels.Tanks; -using RP0.Utilities; using System; using System.Collections.Generic; using UniLinq; @@ -16,8 +15,6 @@ public partial class ModuleProceduralAvionics : ModuleAvionics, IPartMassModifie private const string KwFormat = "{0:0.##}"; private const string WFormat = "{0:0}"; private const float FloatTolerance = 1.00001f; - internal const float InternalTanksTotalVolumeUtilization = 0.246f; //Max utilization for 2 spheres within a cylindrical container worst case scenario - internal const float InternalTanksAvailableVolumeUtilization = 0.5f; #region Fields and properties @@ -90,8 +87,6 @@ public ProceduralAvionicsTechNode CurrentProceduralAvionicsTechNode private float MaxAvionicsMass => (_cachedVolume - CurrentProceduralAvionicsTechNode.reservedRFTankVolume) * CurrentProceduralAvionicsTechNode.avionicsDensity; - public float InternalTanksVolume { get; private set; } - public bool CanSeekVolume => _seekVolumeMethod != null && _seekVolumeMethod.GetParameters().Length == 2; #endregion @@ -471,9 +466,8 @@ internal void SendRemainingVolume() { Events[nameof(OnPartVolumeChanged)].active = false; float availVol = GetAvailableVolume(); - InternalTanksVolume = SphericalTankUtilities.GetSphericalTankVolume(availVol); - Log($"SendRemainingVolume(): Cached Volume: {_cachedVolume}. AvionicsVolume: {GetAvionicsVolume()}. AvailableVolume: {availVol}. Internal Tanks: {InternalTanksVolume}"); - SendVolumeChangedEvent(InternalTanksVolume); + Log($"SendRemainingVolume(): Cached Volume: {_cachedVolume}. AvionicsVolume: {GetAvionicsVolume()}. AvailableVolume: {availVol}."); + SendVolumeChangedEvent(availVol); _rfPM?.CalculateMass(); Events[nameof(OnPartVolumeChanged)].active = true; } @@ -504,7 +498,7 @@ private void UpdateControllableMassInWindow() _window.ControllableMass = $"{controllableMass:0.###}"; } - internal float GetAvailableVolume() => Math.Max(Math.Min((_cachedVolume - GetAvionicsVolume()) * InternalTanksAvailableVolumeUtilization, _cachedVolume * InternalTanksTotalVolumeUtilization), 0); + internal float GetAvailableVolume() => Math.Max(_cachedVolume - GetAvionicsVolume(), 0); internal bool SetProcPartVolumeLimit() { diff --git a/Source/Avionics/ProceduralAvionicsWindow.cs b/Source/Avionics/ProceduralAvionicsWindow.cs index 135e819bce3..0d4286ff048 100644 --- a/Source/Avionics/ProceduralAvionicsWindow.cs +++ b/Source/Avionics/ProceduralAvionicsWindow.cs @@ -1,6 +1,5 @@ using ClickThroughFix; using RealFuels.Tanks; -using RP0.Utilities; using System; using System.Collections.Generic; using System.Reflection; @@ -11,9 +10,6 @@ namespace RP0.ProceduralAvionics { public class ProceduralAvionicsWindow : MonoBehaviour { - private const float InternalTanksAvailableVolumeUtilization = ModuleProceduralAvionics.InternalTanksAvailableVolumeUtilization; - private const float InternalTanksTotalVolumeUtilization = ModuleProceduralAvionics.InternalTanksTotalVolumeUtilization; - private static readonly int _windowId = "RP0ProcAviWindow".GetHashCode(); private Rect _windowRect = new Rect(267, 104, 400, 300); @@ -204,9 +200,9 @@ private void WindowFunction(int windowID) GUILayout.BeginHorizontal(GUILayout.Width(250)); _gc ??= new GUIContent(); _gc.text = "Additional tank volume: "; - _gc.tooltip = "How much tank volume will be left for other resources after applying the desired controllable mass and amount of EC."; + _gc.tooltip = "Amount of excess tank volume"; GUILayout.Label(_gc, HighLogic.Skin.label, GUILayout.Width(150)); - GUI.enabled = _module.CanSeekVolume; + GUI.enabled = false; _sExtraVolume = GUILayout.TextField(_sExtraVolume, HighLogic.Skin.textField); GUI.enabled = true; GUILayout.Label("l", HighLogic.Skin.label); @@ -225,7 +221,7 @@ private void WindowFunction(int windowID) GUILayout.BeginHorizontal(); _gc.text = "Apply (resize to fit)"; - _gc.tooltip = "Applies the parameters above and resizes the part to have the correct amount of volume"; + _gc.tooltip = "Applies the parameters above and resizes the part to have the optimal amount of volume"; if (GUILayout.Button(_gc, HighLogic.Skin.button)) { ApplyAvionicsSettings(shouldSeekVolume: true); @@ -366,14 +362,6 @@ private void ApplyAvionicsSettings(bool shouldSeekVolume) return; } - float extraVolumeLiters = 0; - if (_module.CanSeekVolume && (!float.TryParse(_sExtraVolume, out extraVolumeLiters) || extraVolumeLiters < 0)) - { - ScreenMessages.PostScreenMessage("Invalid Additional volume value"); - _sExtraVolume = "0"; - return; - } - if (!float.TryParse(_sECAmount, out float ecAmount) || ecAmount <= 0) { ScreenMessages.PostScreenMessage("EC amount needs to be larger than 0"); @@ -381,28 +369,11 @@ private void ApplyAvionicsSettings(bool shouldSeekVolume) return; } - // Store and sum together the volume of all resources other than EC on this part - double otherFuelVolume = 0; - var otherTanks = new List>(); - foreach (FuelTank t in _tanksDict.Values) - { - if (t == _ecTank || t.maxAmount == 0) continue; - otherTanks.Add(new KeyValuePair(t, t.maxAmount)); - otherFuelVolume += t.maxAmount / t.utilization; - } - _module.controllableMass = newControlMass; if (shouldSeekVolume && _module.CanSeekVolume) { _module.SetProcPartVolumeLimit(); - ApplyCorrectProcTankVolume(extraVolumeLiters + (float)otherFuelVolume, ecAmount); - - // Restore all the pre-resize amounts in tanks - foreach (KeyValuePair kvp in otherTanks) - { - FuelTank t = kvp.Key; - t.amount = t.maxAmount = kvp.Value; - } + ApplyCorrectProcTankVolume(0, ecAmount); } else { @@ -422,13 +393,13 @@ private void ApplyAvionicsSettings(bool shouldSeekVolume) // In this case need to clamp EC amount to ensure that it stays within the available volume float avVolume = _module.GetAvionicsVolume(); float m3AvailVol = _module.GetAvailableVolume(); - double m3CurVol = avVolume + _rfPM.totalVolume / InternalTanksAvailableVolumeUtilization / 1000; // l to m³, assume 100% RF utilization but do account for the ProcAvi internal utilization - double m3MinVol = GetNeededProcTankVolume((float)otherFuelVolume, ecAmount); + double m3CurVol = avVolume + _rfPM.totalVolume / 1000; // l to m³, assume 100% RF utilization + double m3MinVol = GetNeededProcTankVolume(0, ecAmount); double m3MissingVol = m3MinVol - m3CurVol; if (m3MissingVol > 0.0001) { ecAmount = 1; // Never remove the EC resource entirely - double m3AvailVolForEC = m3AvailVol - otherFuelVolume; + double m3AvailVolForEC = m3AvailVol; if (m3AvailVolForEC > 0) { ecAmount = GetECAmountForVolume((float)m3AvailVolForEC); @@ -458,20 +429,18 @@ private float GetNeededProcTankVolume(float extraVolumeLiters, float ecAmount) float utilization = utilizationPercent / 100; float avVolume = _module.GetAvionicsVolume(); - // The amount of final available volume that RF tanks get is calculated in 4 steps: + // The amount of final available volume that RF tanks get is calculated in 3 steps: // 1) ModuleProceduralAvionics.GetAvailableVolume() - // 2) SphericalTankUtilities.GetSphericalTankVolume() - // 3) RF tank's utilization (the slider in the PAW) - // 4) RF (internal) tank's per-resource utilization value. + // 2) RF tank's utilization (the slider in the PAW) + // 3) RF (internal) tank's per-resource utilization value. // This is currently set at 1000 for EC which means that 1l of volume can hold 1000 units of EC. // The code below runs all these but in reversed order. - float lVolStep4 = ecAmount / _ecTank.utilization; - float lVolStep3 = (lVolStep4 + extraVolumeLiters) / utilization; - float m3VolStep3 = lVolStep3 / 1000; // RF volumes are in liters but avionics uses m³ - float m3VolStep2 = SphericalTankUtilities.GetRequiredVolumeFromSphericalTankVolume(m3VolStep3); - float m3TotalVolume = Math.Max((InternalTanksAvailableVolumeUtilization * avVolume + m3VolStep2) / InternalTanksAvailableVolumeUtilization, - m3VolStep2 / InternalTanksTotalVolumeUtilization); + float lVolStep3 = ecAmount / _ecTank.utilization; + float lVolStep2 = (lVolStep3 + extraVolumeLiters) / utilization; + lVolStep2 = Math.Max(lVolStep2, _module.CurrentProceduralAvionicsTechNode.reservedRFTankVolume); + float m3VolStep2 = lVolStep2 / 1000; // RF volumes are in liters but avionics uses m³ + float m3TotalVolume = Math.Max(avVolume + m3VolStep2, m3VolStep2); return m3TotalVolume; } @@ -480,8 +449,7 @@ private float GetECAmountForVolume(float m3Volume) float utilizationPercent = _rfPM.utilization; float utilization = utilizationPercent / 100; - float m3VolStep2 = SphericalTankUtilities.GetSphericalTankVolume(m3Volume); - float step3 = m3VolStep2 * 1000 * utilization; + float step3 = m3Volume * 1000 * utilization; float ecAmount = step3 * _ecTank.utilization; return ecAmount; } diff --git a/Source/RP0.csproj b/Source/RP0.csproj index 0eafc691683..a30316da45a 100644 --- a/Source/RP0.csproj +++ b/Source/RP0.csproj @@ -201,7 +201,6 @@ - diff --git a/Source/Tooling/ModuleToolingProcAvionics.cs b/Source/Tooling/ModuleToolingProcAvionics.cs index 29254a75c03..5d78fffdfb1 100644 --- a/Source/Tooling/ModuleToolingProcAvionics.cs +++ b/Source/Tooling/ModuleToolingProcAvionics.cs @@ -1,7 +1,5 @@ using System; using RP0.ProceduralAvionics; -using RP0.Utilities; -using UnityEngine; namespace RP0 { @@ -14,8 +12,6 @@ public class ModuleToolingProcAvionics : ModuleToolingPTank private ModuleProceduralAvionics _procAvionics; public override string ToolingType => $"{MainToolingType}-{_procAvionics.CurrentProceduralAvionicsConfig.name[0]}{_procAvionics.CurrentProceduralAvionicsTechNode.techLevel}"; - private string TankToolingType => base.ToolingType; - private ToolingDefinition TankToolingDefinition => ToolingManager.Instance.GetToolingDefinition(TankToolingType); private float ControllableMass => _procAvionics?.controllableMass ?? 0f; @@ -27,25 +23,13 @@ protected override void LoadPartModules() public override string GetToolingParameterInfo() { - return $"{Math.Round(ControllableMass, 3)} t x {base.GetToolingParameterInfo()}{GetInternalTankDiameterInfo()}"; - } - - private object GetInternalTankDiameterInfo() - { - if (_procAvionics.InternalTanksVolume == 0) - { - return ""; - } - - GetDimensions(out var diameter, out var length); - var tankDiameter = GetInternalTankDiameter(diameter, length); - return $" ({TankToolingType} {tankDiameter} m)"; + return $"{Math.Round(ControllableMass, 3)} t x {base.GetToolingParameterInfo()}"; } public override float GetToolingCost() { GetDimensions(out var diameter, out var length); - return GetAvionicsToolingCost(diameter, length) + GetInternalTankToolingCost(diameter, length); + return GetAvionicsToolingCost(diameter, length); } private float GetAvionicsToolingCost(float diameter, float length) @@ -78,69 +62,19 @@ private float[] GetPerLevelToolingCosts(float diameter, float length) }; } - private float GetInternalTankToolingCost(float externalDiameter, float length) - { - if(_procAvionics.InternalTanksVolume == 0) - { - return 0; - } - - var internalTankDiameter = GetInternalTankDiameter(externalDiameter, length); - var level = ToolingDatabase.GetToolingLevel(TankToolingType, internalTankDiameter, internalTankDiameter); - var perLevelCosts = new[] { GetDiameterToolingCost(internalTankDiameter), GetLengthToolingCost(internalTankDiameter, internalTankDiameter) }; - var costMult = TankToolingDefinition?.finalToolingCostMultiplier ?? 0f; - return GetToolingCost(level, perLevelCosts) * costMult; - } - - private float GetInternalTankDiameter(float externalDiameter, float length) - { - var maxDiameter = Mathf.Min(externalDiameter * 2 / 3, length); - var internalTankDiameter = SphericalTankUtilities.GetSphericalTankRadius(_procAvionics.InternalTanksVolume) * 2; - while (internalTankDiameter > maxDiameter) { internalTankDiameter /= 2; } - - return internalTankDiameter; - } - private float GetControlledMassToolingCost() => _procAvionics.GetModuleCost(0, ModifierStagingSituation.UNSTAGED) * avionicsToolingCostMultiplier; public override float GetModuleCost(float defaultCost, ModifierStagingSituation sit) { if (!onStartFinishedFinished || HighLogic.CurrentGame.Mode != Game.Modes.CAREER) return 0f; - return GetUntooledPenaltyCost() + GetInternalTankModuleCost(); - } - - private float GetInternalTankModuleCost() - { - if (_procAvionics.InternalTanksVolume == 0) - { - return 0; - } - - GetDimensions(out var externalDiameter, out var length); - var internalTankDiameter = GetInternalTankDiameter(externalDiameter, length); - var tankCount = _procAvionics.InternalTanksVolume / SphericalTankUtilities.GetSphereVolume(internalTankDiameter / 2); - var costMultDL = TankToolingDefinition?.costMultiplierDL ?? 0f; - - return GetDimensionModuleCost(internalTankDiameter, length, costMultDL) * tankCount; + return GetUntooledPenaltyCost(); } public override void PurchaseTooling() { GetDimensions(out var diameter, out var length); ToolingDatabase.UnlockTooling(ToolingType, ControllableMass, diameter, length); - UnlockInternalTankTooling(diameter, length); - } - - private void UnlockInternalTankTooling(float diameter, float length) - { - if(_procAvionics.InternalTanksVolume == 0) - { - return; - } - - var internalTankDiameter = GetInternalTankDiameter(diameter, length); - ToolingDatabase.UnlockTooling(TankToolingType, internalTankDiameter, internalTankDiameter); } public override bool IsUnlocked() @@ -151,18 +85,7 @@ public override bool IsUnlocked() } GetDimensions(out var diameter, out var length); - return IsAvionicsTooled(diameter, length) && IsInternalTankTooled(diameter, length); - } - - private bool IsInternalTankTooled(float diameter, float length) - { - if(_procAvionics.InternalTanksVolume == 0) - { - return true; - } - - var internalTankDiameter = GetInternalTankDiameter(diameter, length); - return ToolingDatabase.GetToolingLevel(TankToolingType, internalTankDiameter, internalTankDiameter) == 2; + return IsAvionicsTooled(diameter, length); } private bool IsAvionicsTooled(float diameter, float length) => ToolingDatabase.GetToolingLevel(ToolingType, ControllableMass, diameter, length) == 3; diff --git a/Source/Utilities/SphericalTankUtilities.cs b/Source/Utilities/SphericalTankUtilities.cs deleted file mode 100644 index 5209c87259f..00000000000 --- a/Source/Utilities/SphericalTankUtilities.cs +++ /dev/null @@ -1,45 +0,0 @@ -using UnityEngine; - -namespace RP0.Utilities -{ - public class SphericalTankUtilities - { - private const int MinSpheres = 2; - private const float BaseRadius = 0.05f; - - public static float GetSphericalTankVolume(float availableVolume) - { - float radius = GetSphericalTankRadius(availableVolume); - float sphereVolume = GetSphereVolume(radius); - return GetSphereCount(availableVolume, sphereVolume) * sphereVolume; - } - - public static float GetRequiredVolumeFromSphericalTankVolume(float desiredVolume) - { - if (desiredVolume == 0) - return 0; - float radius = GetSphericalTankRadius(desiredVolume); - float sphereVolume = GetSphereVolume(radius); - float numSpheres = Mathf.Ceil(desiredVolume / sphereVolume); - return numSpheres * sphereVolume; - } - - private static float GetSphereCount(float availableVolume, float sphereVolume) => sphereVolume == 0 ? 0 : Mathf.Floor(availableVolume / sphereVolume); - - public static float GetSphereVolume(float radius) - { - return Mathf.Pow(radius, 3) * 4 / 3 * Mathf.PI; - } - - public static float GetSphericalTankRadius(float availableVolume) - { - if (availableVolume == 0) - { - return 0; - } - - var radiusExponent = Mathf.Max(0, Mathf.Log(Mathf.Pow(availableVolume / Mathf.PI * 3 / 4 / MinSpheres, 1f / 3) / BaseRadius, 2)); - return Mathf.Pow(2, Mathf.Floor(Mathf.Round(radiusExponent * 10000) / 10000)) * BaseRadius; - } - } -}