diff --git a/Flags/Kethane 1.png b/Flags/Kethane 1.png
new file mode 100644
index 0000000..4dc151e
Binary files /dev/null and b/Flags/Kethane 1.png differ
diff --git a/Parts/kethane_1m_converter/part.cfg b/Parts/kethane_1m_converter/part.cfg
index ee49df2..c7fe66d 100644
--- a/Parts/kethane_1m_converter/part.cfg
+++ b/Parts/kethane_1m_converter/part.cfg
@@ -47,40 +47,44 @@ fuelCrossFeed = True
MODULE
{
name = KethaneConverter
- SourceResource = Kethane
- TargetResource = LiquidFuel
- ConversionEfficiency = 0.97
- SourceConsumption = 2.25
- PowerConsumption = 6
+ Label = Rocket Fuel
+ InputRates
+ {
+ Kethane = 2.25
+ ElectricCharge = 6
+ }
+ OutputRatios
+ {
+ LiquidFuel = 0.99
+ Oxidizer = 0.99
+ }
}
MODULE
{
name = KethaneConverter
- SourceResource = Kethane
- TargetResource = Oxidizer
- ConversionEfficiency = 1.01
- SourceConsumption = 2.75
- PowerConsumption = 4
+ InputRates
+ {
+ Kethane = 1.5
+ ElectricCharge = 8
+ }
+ OutputRatios
+ {
+ MonoPropellant = 0.3
+ }
}
MODULE
{
name = KethaneConverter
- SourceResource = Kethane
- TargetResource = MonoPropellant
- ConversionEfficiency = 0.3
- SourceConsumption = 1.5
- PowerConsumption = 8
-}
-
-MODULE
-{
- name = KethaneConverter
- SourceResource = Kethane
- TargetResource = XenonGas
- ConversionEfficiency = 0.4
- SourceConsumption = 1.5
- PowerConsumption = 3
+ InputRates
+ {
+ Kethane = 1.5
+ ElectricCharge = 3
+ }
+ OutputRatios
+ {
+ XenonGas = 0.4
+ }
}
}
diff --git a/Parts/kethane_2m_converter/part.cfg b/Parts/kethane_2m_converter/part.cfg
index 8cf4290..f37a447 100644
--- a/Parts/kethane_2m_converter/part.cfg
+++ b/Parts/kethane_2m_converter/part.cfg
@@ -51,44 +51,60 @@ MODULE
MODULE
{
name = KethaneConverter
- SourceResource = Kethane
- TargetResource = LiquidFuel
- ConversionEfficiency = 1.03
- SourceConsumption = 6.75
- PowerConsumption = 12
HeatProduction = 600
+ InputRates
+ {
+ Kethane = 6.75
+ ElectricCharge = 12
+ }
+ OutputRatios
+ {
+ LiquidFuel = 1.03
+ }
}
MODULE
{
name = KethaneConverter
- SourceResource = Kethane
- TargetResource = Oxidizer
- ConversionEfficiency = 0.99
- SourceConsumption = 8.25
- PowerConsumption = 8
HeatProduction = 800
+ InputRates
+ {
+ Kethane = 8.25
+ ElectricCharge = 8
+ }
+ OutputRatios
+ {
+ Oxidizer = 0.99
+ }
}
MODULE
{
name = KethaneConverter
- SourceResource = Kethane
- TargetResource = MonoPropellant
- ConversionEfficiency = 0.85
- SourceConsumption = 3
- PowerConsumption = 10
HeatProduction = 1200
+ InputRates
+ {
+ Kethane = 3
+ ElectricCharge = 10
+ }
+ OutputRatios
+ {
+ MonoPropellant = 0.85
+ }
}
MODULE
{
name = KethaneConverter
- SourceResource = Kethane
- TargetResource = XenonGas
- ConversionEfficiency = 0.25
- SourceConsumption = 2
- PowerConsumption = 8
HeatProduction = 300
+ InputRates
+ {
+ Kethane = 2
+ ElectricCharge = 8
+ }
+ OutputRatios
+ {
+ XenonGas = 0.25
+ }
}
}
diff --git a/Parts/kethane_highGain/part.cfg b/Parts/kethane_highGain/part.cfg
index 44ebdd4..15ed157 100644
--- a/Parts/kethane_highGain/part.cfg
+++ b/Parts/kethane_highGain/part.cfg
@@ -42,6 +42,10 @@ MODULE
DetectingPeriod = 1.5
DetectingHeight = 250000
PowerConsumption = 0.8
+ Resource
+ {
+ Name = Kethane
+ }
}
MODULE
diff --git a/Parts/kethane_sensor_1m/part.cfg b/Parts/kethane_sensor_1m/part.cfg
index eb3e452..1cc8fb3 100644
--- a/Parts/kethane_sensor_1m/part.cfg
+++ b/Parts/kethane_sensor_1m/part.cfg
@@ -45,6 +45,10 @@ MODULE {
DetectingPeriod = 0.9
DetectingHeight = 1200000
PowerConsumption = 2.5
+ Resource
+ {
+ Name = Kethane
+ }
}
MODULE
diff --git a/Plugin/InstallChecker.cs b/Plugin/InstallChecker.cs
index bde00d4..2686dd2 100644
--- a/Plugin/InstallChecker.cs
+++ b/Plugin/InstallChecker.cs
@@ -6,7 +6,7 @@
namespace Kethane
{
- [KSPAddon(KSPAddon.Startup.MainMenu, true)]
+ [KSPAddonFixed(KSPAddon.Startup.MainMenu, true, typeof(InstallChecker))]
internal class InstallChecker : MonoBehaviour
{
protected void Start()
diff --git a/Plugin/KSPAddonFixed.cs b/Plugin/KSPAddonFixed.cs
new file mode 100644
index 0000000..591b4d0
--- /dev/null
+++ b/Plugin/KSPAddonFixed.cs
@@ -0,0 +1,37 @@
+using System;
+
+namespace Kethane
+{
+ ///
+ /// KSPAddon with equality checking using an additional type parameter. Fixes the issue where AddonLoader prevents multiple start-once addons with the same start scene.
+ ///
+ public class KSPAddonFixed : KSPAddon, IEquatable
+ {
+ private readonly Type type;
+
+ public KSPAddonFixed(KSPAddon.Startup startup, bool once, Type type)
+ : base(startup, once)
+ {
+ this.type = type;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj.GetType() != this.GetType()) { return false; }
+ return Equals((KSPAddonFixed)obj);
+ }
+
+ public bool Equals(KSPAddonFixed other)
+ {
+ if (this.once != other.once) { return false; }
+ if (this.startup != other.startup) { return false; }
+ if (this.type != other.type) { return false; }
+ return true;
+ }
+
+ public override int GetHashCode()
+ {
+ return this.startup.GetHashCode() ^ this.once.GetHashCode() ^ this.type.GetHashCode();
+ }
+ }
+}
diff --git a/Plugin/Kethane.csproj b/Plugin/Kethane.csproj
index bb3bdc5..4850b43 100644
--- a/Plugin/Kethane.csproj
+++ b/Plugin/Kethane.csproj
@@ -68,6 +68,7 @@
+
diff --git a/Plugin/KethaneConverter.cs b/Plugin/KethaneConverter.cs
index 280b473..af1595f 100644
--- a/Plugin/KethaneConverter.cs
+++ b/Plugin/KethaneConverter.cs
@@ -8,20 +8,26 @@ namespace Kethane
{
public class KethaneConverter : PartModule
{
- [KSPField(isPersistant = false)]
- public string SourceResource;
-
- [KSPField(isPersistant = false)]
- public string TargetResource;
+ private struct ResourceRate
+ {
+ public String Resource { get; private set; }
+ public double Rate { get; private set; }
- [KSPField(isPersistant = false)]
- public float ConversionEfficiency;
+ public ResourceRate(String resource, double rate)
+ : this()
+ {
+ Resource = resource;
+ Rate = rate;
+ }
- [KSPField(isPersistant = false)]
- public float SourceConsumption;
+ public static ResourceRate operator *(ResourceRate rate, double multiplier)
+ {
+ return new ResourceRate(rate.Resource, rate.Rate * multiplier);
+ }
+ }
[KSPField(isPersistant = false)]
- public float PowerConsumption;
+ public String Label;
[KSPField(isPersistant = false)]
public float HeatProduction;
@@ -29,6 +35,11 @@ public class KethaneConverter : PartModule
[KSPField(isPersistant = true)]
public bool IsEnabled;
+ public ConfigNode config;
+
+ private ResourceRate[] inputRates;
+ private ResourceRate[] outputRates;
+
[KSPEvent(guiActive = true, guiName = "Activate Converter", active = true)]
public void ActivateConverter()
{
@@ -61,14 +72,48 @@ public void ToggleConverterAction(KSPActionParam param)
public override string GetInfo()
{
- return String.Format("{0}:\n- Conversion Efficiency: {1:P0}\n- {4} Consumption: {2:F1}L/s\n- Power Consumption: {3:F1}/s", TargetResource, ConversionEfficiency, SourceConsumption, PowerConsumption, SourceResource);
+ return String.Format("{0} Converter:\n> Inputs:\n", Label) + String.Join("\n", inputRates.Select(r => String.Format(" - {0}: {1:N2}/s", r.Resource, r.Rate)).ToArray()) + "\n> Outputs:\n" + String.Join("\n", outputRates.Select(r => String.Format(" - {0}: {1:N2}/s", r.Resource, r.Rate)).ToArray()) + "\n";
+ }
+
+ public override void OnLoad(ConfigNode config)
+ {
+ if (this.config == null)
+ {
+ this.config = new ConfigNode();
+ config.CopyTo(this.config);
+ }
+
+ loadConfig();
+ }
+
+ private void loadConfig()
+ {
+ var definitions = PartResourceLibrary.Instance.resourceDefinitions;
+
+ inputRates = loadRates(config.GetNode("InputRates")).ToArray();
+ var inputMassRate = inputRates.Sum(p => p.Rate * definitions[p.Resource].density);
+
+ outputRates = loadRates(config.GetNode("OutputRatios")).Select(r => r * (inputMassRate / definitions[r.Resource].density)).GroupBy(r => r.Resource).Select(g => new ResourceRate(g.Key, g.Sum(r => r.Rate))).Concat(loadRates(config.GetNode("OutputRates"))).ToArray();
+
+ if (Label == null)
+ {
+ Label = String.Join("/", outputRates.Select(r => r.Resource).ToArray());
+ }
+ }
+
+ private static IEnumerable loadRates(ConfigNode config)
+ {
+ return (config ?? new ConfigNode()).values.Cast().Where(v => PartResourceLibrary.Instance.resourceDefinitions.Any(d => d.name == v.name)).Select(v => new ResourceRate(v.name, Misc.Parse(v.value, 0.0))).Where(r => r.Rate > 0);
}
public override void OnStart(PartModule.StartState state)
{
- Actions["ActivateConverterAction"].guiName = Events["ActivateConverter"].guiName = String.Format("Activate {0} Converter", TargetResource);
- Actions["DeactivateConverterAction"].guiName = Events["DeactivateConverter"].guiName = String.Format("Deactivate {0} Converter", TargetResource);
- Actions["ToggleConverterAction"].guiName = String.Format("Toggle {0} Converter", TargetResource);
+ loadConfig();
+
+ Actions["ActivateConverterAction"].guiName = Events["ActivateConverter"].guiName = String.Format("Activate {0} Converter", Label);
+ Actions["DeactivateConverterAction"].guiName = Events["DeactivateConverter"].guiName = String.Format("Deactivate {0} Converter", Label);
+ Actions["ToggleConverterAction"].guiName = String.Format("Toggle {0} Converter", Label);
+
if (state == StartState.Editor) { return; }
this.part.force_activate();
}
@@ -83,24 +128,8 @@ public override void OnFixedUpdate()
{
if (!IsEnabled) { return; }
- var conversionRatio = PartResourceLibrary.Instance.GetDefinition(SourceResource).density / PartResourceLibrary.Instance.GetDefinition(TargetResource).density;
-
- double requestedSpace = SourceConsumption * conversionRatio * ConversionEfficiency * TimeWarp.fixedDeltaTime;
- double requestedSource = SourceConsumption * TimeWarp.fixedDeltaTime;
- double requestedEnergy = PowerConsumption * TimeWarp.fixedDeltaTime;
-
- double availableSpace = 0;
- var listPartResource = Misc.GetConnectedResources(this.part, TargetResource);
- if (listPartResource.Count > 0)
- availableSpace = listPartResource.Max(r => r.maxAmount - r.amount);
- var availableSource = Misc.GetConnectedResources(this.part, SourceResource).Max(r => r.amount);
- var availableEnergy = Misc.GetConnectedResources(this.part, "ElectricCharge").Max(r => r.amount);
-
- var spaceRatio = availableSpace / requestedSpace;
- var sourceRatio = availableSource / requestedSource;
- var energyRatio = availableEnergy / requestedEnergy;
-
- var ratio = Math.Min(Math.Min(Math.Min(spaceRatio, sourceRatio), energyRatio), 1);
+ var rates = outputRates.Select(r => r * -1).Concat(inputRates).Select(r => r * TimeWarp.fixedDeltaTime).ToArray();
+ var ratio = rates.Select(r => Misc.GetConnectedResources(this.part, r.Resource).Select(c => r.Rate > 0 ? c.amount : c.maxAmount - c.amount).DefaultIfEmpty().Max() / Math.Abs(r.Rate)).Prepend(1).Min();
var heatsink = this.part.Modules.OfType().SingleOrDefault();
if (heatsink != null)
@@ -109,19 +138,10 @@ public override void OnFixedUpdate()
ratio *= heatsink.AddHeat(heatRequest) / heatRequest;
}
- requestedSource *= ratio;
-
- var drawnSource = this.part.RequestResource(SourceResource, requestedSource);
-
- ratio *= drawnSource / requestedSource;
- requestedEnergy *= ratio;
-
- var drawnEnergy = this.part.RequestResource("ElectricCharge", requestedEnergy);
-
- ratio *= drawnEnergy / requestedEnergy;
- requestedSpace *= ratio;
-
- this.part.RequestResource(TargetResource, -requestedSpace);
+ foreach (var rate in rates)
+ {
+ this.part.RequestResource(rate.Resource, rate.Rate * ratio);
+ }
}
}
}
diff --git a/Plugin/KethaneData.cs b/Plugin/KethaneData.cs
index d64da21..92fadaf 100644
--- a/Plugin/KethaneData.cs
+++ b/Plugin/KethaneData.cs
@@ -17,6 +17,10 @@ public static KethaneData Current
if (!game.scenarios.Any(p => p.moduleName == typeof(KethaneData).Name))
{
var proto = game.AddProtoScenarioModule(typeof(KethaneData), GameScenes.FLIGHT, GameScenes.TRACKSTATION);
+ if (proto.targetScenes.Contains(HighLogic.LoadedScene))
+ {
+ proto.Load(ScenarioRunner.fetch);
+ }
}
return game.scenarios.Select(s => s.moduleRef).OfType().SingleOrDefault();
diff --git a/Plugin/KethaneExtractorAnimatorLanded.cs b/Plugin/KethaneExtractorAnimatorLanded.cs
index b2df454..6f4c500 100644
--- a/Plugin/KethaneExtractorAnimatorLanded.cs
+++ b/Plugin/KethaneExtractorAnimatorLanded.cs
@@ -6,7 +6,6 @@ public class KethaneExtractorAnimatorLanded : PartModule, IExtractorAnimator
public ExtractorState CurrentState { get; private set; }
public void Deploy() { CurrentState = ExtractorState.Deployed; }
public void Retract() { CurrentState = ExtractorState.Retracted; }
- public bool CanExtract { get { return vessel.LandedOrSplashed; } }
public KethaneExtractorAnimatorLanded()
{
diff --git a/Plugin/KethaneWetMassIndicator.cs b/Plugin/KethaneWetMassIndicator.cs
index 9ef0cf2..705a2a7 100644
--- a/Plugin/KethaneWetMassIndicator.cs
+++ b/Plugin/KethaneWetMassIndicator.cs
@@ -5,9 +5,12 @@ namespace Kethane
{
public class KethaneWetMassIndicator : PartModule
{
+ [KSPField(isPersistant = false)]
+ public String Label;
+
public override string GetInfo()
{
- return String.Format("Wet Mass: {0}", (float)this.part.Resources.Cast().Sum(r => r.maxAmount * PartResourceLibrary.Instance.GetDefinition(r.resourceName).density) + this.part.mass);
+ return String.Format("{0}: {1}", Label ?? "Wet Mass", (float)this.part.Resources.Cast().Sum(r => r.maxAmount * PartResourceLibrary.Instance.GetDefinition(r.resourceName).density) + this.part.mass);
}
}
}
diff --git a/Plugin/MapOverlay.cs b/Plugin/MapOverlay.cs
index 4bf7883..daf6a87 100644
--- a/Plugin/MapOverlay.cs
+++ b/Plugin/MapOverlay.cs
@@ -213,24 +213,25 @@ public void RefreshCellColor(GeodesicGrid.Cell cell, CelestialBody body)
{
if (body != this.body) { return; }
var colors = mesh.colors32;
- refreshCellColor(cell, body, colors);
+ refreshCellColor(cell, body, colors, KethaneData.Current);
mesh.colors32 = colors;
}
private void refreshCellColors()
{
var colors = new Color32[mesh.vertexCount];
+ var data = KethaneData.Current;
foreach (var cell in grid)
{
- refreshCellColor(cell, body, colors);
+ refreshCellColor(cell, body, colors, data);
}
mesh.colors32 = colors;
}
- private void refreshCellColor(GeodesicGrid.Cell cell, CelestialBody body, Color32[] colors)
+ private void refreshCellColor(GeodesicGrid.Cell cell, CelestialBody body, Color32[] colors, KethaneData data)
{
- var deposit = KethaneData.Current.GetCellDeposit(resource.Resource, body, cell);
- var scanned = KethaneData.Current.Scans[resource.Resource][body.name][cell];
+ var deposit = data.GetCellDeposit(resource.Resource, body, cell);
+ var scanned = data.Scans[resource.Resource][body.name][cell];
var color = (revealAll ? deposit != null : scanned) ? getDepositColor(resource, deposit) : colorUnknown;
setCellColor(cell, color, colors);
}
diff --git a/Plugin/Misc.cs b/Plugin/Misc.cs
index 4d95c37..ca9eca1 100644
--- a/Plugin/Misc.cs
+++ b/Plugin/Misc.cs
@@ -90,6 +90,16 @@ public static float Parse(string s, float defaultValue)
return value;
}
+ public static double Parse(string s, double defaultValue)
+ {
+ double value;
+ if (!double.TryParse(s, out value))
+ {
+ value = defaultValue;
+ }
+ return value;
+ }
+
public static int Parse(string s, int defaultValue)
{
int value;
diff --git a/Plugin/Properties/AssemblyInfo.cs b/Plugin/Properties/AssemblyInfo.cs
index 0811b1e..c748168 100644
--- a/Plugin/Properties/AssemblyInfo.cs
+++ b/Plugin/Properties/AssemblyInfo.cs
@@ -33,4 +33,4 @@
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyInformationalVersion("0.7.5")]
\ No newline at end of file
+[assembly: AssemblyInformationalVersion("0.7.6")]
\ No newline at end of file
diff --git a/Plugin/ScaledSpaceFix.cs b/Plugin/ScaledSpaceFix.cs
index 1a71470..410cff2 100644
--- a/Plugin/ScaledSpaceFix.cs
+++ b/Plugin/ScaledSpaceFix.cs
@@ -8,6 +8,7 @@ internal class ScaledSpaceFix : MonoBehaviour
{
public void Start()
{
+ if (ScaledSpace.Instance == null || ScaledSpace.Instance.scaledSpaceTransforms == null) { return; }
ScaledSpace.Instance.scaledSpaceTransforms.RemoveAll(t => t == null);
if (HighLogic.LoadedScene == GameScenes.MAINMENU)
{
diff --git a/Plugin/SettingsManager.cs b/Plugin/SettingsManager.cs
index a71179d..d8b3f8f 100644
--- a/Plugin/SettingsManager.cs
+++ b/Plugin/SettingsManager.cs
@@ -2,7 +2,7 @@
namespace Kethane
{
- [KSPAddon(KSPAddon.Startup.Instantly, true)]
+ [KSPAddonFixed(KSPAddon.Startup.Instantly, true, typeof(SettingsManager))]
internal class SettingsManager : MonoBehaviour
{
private static ConfigNode node;