diff --git a/CKAN/SystemHeat-CryoTanks.netkan b/CKAN/SystemHeat-CryoTanks.netkan
new file mode 100644
index 0000000..1ef19ee
--- /dev/null
+++ b/CKAN/SystemHeat-CryoTanks.netkan
@@ -0,0 +1,29 @@
+{
+ "spec_version": "v1.4",
+ "identifier": "SystemHeat-CryoTanks",
+ "name": "System Heat - Cryo Tanks Configuration",
+ "$kref": "#/ckan/github/post-kerbin-mining-corporation/SystemHeat",
+ "$vref": "#/ckan/ksp-avc",
+ "abstract": "This System Heat config package changes zero boiloff cryogenic tanks to need cooling instead of power. WARNING: potentially vessel-breaking.",
+ "author": "Nertea (Chris Adderley)",
+ "license": "CC-BY-NC-SA-4.0",
+ "resources": {
+ "homepage": "https://forum.kerbalspaceprogram.com/index.php?/topic/193909-1",
+ "repository": "https://github.com/post-kerbin-mining-corporation/SystemHeat"
+ },
+ "depends": [
+ { "name": "ModuleManager" },
+ { "name": "SystemHeat" },
+ { "name": "CommunityResourcePack" }
+ ],
+ "suggests": [
+ { "name": "SystemHeatConverters" },
+ { "name": "SystemHeatFissionReactors" },
+ { "name": "SystemHeatHarvesters" },
+ { "name": "NearFuturePropulsion" }
+ ],
+ "install": [ {
+ "find": "SystemHeatBoiloff",
+ "install_to": "GameData"
+ } ]
+}
diff --git a/Extras/SystemHeatBoiloff/CryoTanks/CryoTanksSystemHeat.cfg b/Extras/SystemHeatBoiloff/CryoTanks/CryoTanksSystemHeat.cfg
new file mode 100644
index 0000000..272d23b
--- /dev/null
+++ b/Extras/SystemHeatBoiloff/CryoTanks/CryoTanksSystemHeat.cfg
@@ -0,0 +1,39 @@
+@PART[*]:HAS[@MODULE[ModuleCryoTank]]:AFTER[zzz_CryoTanks]
+{
+ MODULE
+ {
+ name = ModuleSystemHeat
+ volume = #$../mass$
+ volume *= 0.5
+ moduleID = tank
+ iconName = Icon_Snow
+ }
+
+ @MODULE[ModuleCryoTank]
+ {
+
+ @name = ModuleSystemHeatCryoTank
+ systemHeatModuleID = tank
+
+ @BOILOFFCONFIG:HAS[#FuelName[LqdHydrogen]]
+ {
+ CoolingHeatCost = 0.3
+ CryocoolerTemperature = 300
+ }
+ @BOILOFFCONFIG:HAS[#FuelName[LqdMethane]]
+ {
+ CoolingHeatCost = 0.15
+ CryocoolerTemperature = 400
+ }
+ @BOILOFFCONFIG:HAS[#FuelName[LqdHe3]]
+ {
+ CoolingHeatCost = 0.22
+ CryocoolerTemperature = 350
+ }
+ @BOILOFFCONFIG:HAS[#FuelName[LqdDeuterium]]
+ {
+ CoolingHeatCost = 0.25
+ CryocoolerTemperature = 300
+ }
+ }
+}
\ No newline at end of file
diff --git a/Extras/SystemHeatConverters/genericConverters.cfg b/Extras/SystemHeatConverters/genericConverters.cfg
index 4aa7ea5..adbbbdc 100644
--- a/Extras/SystemHeatConverters/genericConverters.cfg
+++ b/Extras/SystemHeatConverters/genericConverters.cfg
@@ -25,10 +25,12 @@
key = 1000 1.0
key = 1300 0.0
}
+
systemPower = #$INPUT_RESOURCE:HAS[#ResourceName[ElectricCharge]]/Ratio$ //set the heat ouput as proportional to the EC usage.
@systemPower *= .90 //lets assume 90% of EC usage turns into heat.
!ThermalEfficiency {}
!TemperatureModifier {}
@GeneratesHeat = false //disable stock heating
+
}
}
diff --git a/Extras/SystemHeatFissionReactors/NearFutureElectrical/NearFutureElectricalUSIReactors.cfg b/Extras/SystemHeatFissionReactors/NearFutureElectrical/NearFutureElectricalUSIReactors.cfg
new file mode 100644
index 0000000..02a976a
--- /dev/null
+++ b/Extras/SystemHeatFissionReactors/NearFutureElectrical/NearFutureElectricalUSIReactors.cfg
@@ -0,0 +1,772 @@
+// Near Future Electrical USI Reactors compatibility
+// Changes USI reactors to behave like NFE reactors
+@PART[USI_Nuke_625]:FOR[SystemHeatFissionReactors]
+{
+ MODULE
+ {
+ name = ModuleSystemHeat
+ volume = 0.25
+ moduleID = reactor
+ iconName = Icon_Nuclear
+ }
+
+ !MODULE[ModuleUpdateOverride] {}
+ !MODULE[FissionReactor] {}
+ !MODULE[FissionGenerator] {}
+ !MODULE[ModuleCoreHeatNoCatchup] {}
+ !MODULE[RadioactiveStorageContainer] {}
+ MODULE
+ {
+ name = ModuleUpdateOverride
+ }
+
+ MODULE
+ {
+ name = ModuleSystemHeatFissionReactor
+ moduleID = reactor
+
+ // -- Heat stuff
+ // ModuleSystemHeat instance to link to
+ systemHeatModuleID = reactor
+
+ // Heat kW
+ HeatGeneration
+ {
+ key = 0 0 0 0
+ key = 100 136 0 0
+ }
+
+ // Above this temp, risky
+ NominalTemperature = 750
+
+ // Above this temp, reactor takes damage
+ CriticalTemperature = 1300
+
+ // Amount of damage taken by core when over critical temp
+ // %/s/K, so with value 0.001, at 200 K over CriticalTemp, reactor takes 0.2% damage/s
+ CoreDamageRate = 0.005
+
+ // When repairing, amount of core damage to heal (%)
+ RepairAmountPerKit = 25
+
+ CurrentPowerPercent = 100
+ ThrottleIncreaseRate = 5
+ MinimumThrottle = 25
+
+ // -- Electrical stuff
+ // Power generated
+ ElectricalGeneration
+ {
+ key = 0 0
+ key = 100 36
+ }
+
+ // --- Fuel stuff
+ // Base lifetime calculations off this resource
+ FuelName = EnrichedUranium
+
+ INPUT_RESOURCE
+ {
+ ResourceName = EnrichedUranium
+ Ratio = 0.000000126785
+ FlowMode = NO_FLOW
+ }
+
+ OUTPUT_RESOURCE
+ {
+ ResourceName = DepletedFuel
+ Ratio = 0.000000126785
+ DumpExcess = false
+ FlowMode = NO_FLOW
+ }
+
+ EngineerLevelForRepair = 5
+ MaxRepairPercent = 75
+ MaxTempForRepair = 330
+ }
+
+ MODULE
+ {
+ name = ModuleSystemHeatFissionFuelContainer
+ EngineerLevelForTransfer = 3
+ ResourceNames = EnrichedUranium, DepletedFuel
+ }
+}
+
+@PART[USI_Nuke_125_S]:FOR[SystemHeatFissionReactors]
+{
+ MODULE
+ {
+ name = ModuleSystemHeat
+ volume = 0.5
+ moduleID = reactor
+ iconName = Icon_Nuclear
+ }
+
+ !MODULE[ModuleUpdateOverride] {}
+ !MODULE[FissionReactor] {}
+ !MODULE[FissionGenerator] {}
+ !MODULE[ModuleCoreHeatNoCatchup] {}
+ !MODULE[RadioactiveStorageContainer] {}
+
+ MODULE
+ {
+ name = ModuleSystemHeatFissionReactor
+ moduleID = reactor
+
+ // -- Heat stuff
+ // ModuleSystemHeat instance to link to
+ systemHeatModuleID = reactor
+
+ // Heat kW
+ HeatGeneration
+ {
+ key = 0 0 0 0
+ key = 100 325 0 0
+ }
+
+ // Above this temp, risky
+ NominalTemperature = 775
+
+ // Above this temp, reactor takes damage
+ CriticalTemperature = 1300
+
+ // Amount of damage taken by core when over critical temp
+ // %/s/K, so with value 0.001, at 200 K over CriticalTemp, reactor takes 0.2% damage/s
+ CoreDamageRate = 0.01
+
+ // When repairing, amount of core damage to heal (%)
+ RepairAmountPerKit = 20
+
+ CurrentPowerPercent = 100
+ ThrottleIncreaseRate = 5
+ MinimumThrottle = 25
+
+ // -- Electrical stuff
+ // Power generated
+ ElectricalGeneration
+ {
+ key = 0 0
+ key = 100 100
+ }
+
+ // --- Fuel stuff
+ // Base lifetime calculations off this resource
+ FuelName = EnrichedUranium
+
+ INPUT_RESOURCE
+ {
+ ResourceName = EnrichedUranium
+ Ratio = 0.00000034414
+ FlowMode = NO_FLOW
+ }
+
+ OUTPUT_RESOURCE
+ {
+ ResourceName = DepletedFuel
+ Ratio = 0.00000034414
+ DumpExcess = false
+ FlowMode = NO_FLOW
+ }
+ }
+
+ MODULE
+ {
+ name = ModuleSystemHeatFissionFuelContainer
+ EngineerLevelForTransfer = 3
+ ResourceNames = EnrichedUranium, DepletedFuel
+ }
+}
+
+@PART[USI_Nuke_125]:FOR[SystemHeatFissionReactors]
+{
+ MODULE
+ {
+ name = ModuleSystemHeat
+ volume = 1
+ moduleID = reactor
+ iconName = Icon_Nuclear
+ }
+
+ !MODULE[ModuleUpdateOverride] {}
+ !MODULE[FissionReactor] {}
+ !MODULE[FissionGenerator] {}
+ !MODULE[ModuleCoreHeatNoCatchup] {}
+ !MODULE[RadioactiveStorageContainer] {}
+
+ MODULE
+ {
+ name = ModuleSystemHeatFissionReactor
+ moduleID = reactor
+
+ // -- Heat stuff
+ // ModuleSystemHeat instance to link to
+ systemHeatModuleID = reactor
+
+ // Heat kW
+ HeatGeneration
+ {
+ key = 0 0 0 0
+ key = 100 650 0 0
+ }
+
+ // Above this temp, risky
+ NominalTemperature = 800
+
+ // Above this temp, reactor takes damage
+ CriticalTemperature = 1300
+
+ // Amount of damage taken by core when over critical temp
+ // %/s/K, so with value 0.001, at 200 K over CriticalTemp, reactor takes 0.2% damage/s
+ CoreDamageRate = 0.01
+
+ // When repairing, amount of core damage to heal (%)
+ RepairAmountPerKit = 20
+
+ CurrentPowerPercent = 100
+ ThrottleIncreaseRate = 5
+ MinimumThrottle = 25
+
+ // -- Electrical stuff
+ // Power generated
+ ElectricalGeneration
+ {
+ key = 0 0
+ key = 100 200
+ }
+
+ // --- Fuel stuff
+ // Base lifetime calculations off this resource
+ FuelName = EnrichedUranium
+
+ INPUT_RESOURCE
+ {
+ ResourceName = EnrichedUranium
+ Ratio = 0.00000065205
+ FlowMode = NO_FLOW
+ }
+
+ OUTPUT_RESOURCE
+ {
+ ResourceName = DepletedFuel
+ Ratio = 0.00000065205
+ DumpExcess = false
+ FlowMode = NO_FLOW
+ }
+ }
+
+ MODULE
+ {
+ name = ModuleSystemHeatFissionFuelContainer
+ EngineerLevelForTransfer = 3
+ ResourceNames = EnrichedUranium, DepletedFuel
+ }
+}
+
+@PART[USI_Nuke_250]:FOR[SystemHeatFissionReactors]
+{
+ MODULE
+ {
+ name = ModuleSystemHeat
+ volume = 2
+ moduleID = reactor
+ iconName = Icon_Nuclear
+ }
+
+ !MODULE[ModuleUpdateOverride] {}
+ !MODULE[FissionReactor] {}
+ !MODULE[FissionGenerator] {}
+ !MODULE[ModuleCoreHeatNoCatchup] {}
+ !MODULE[RadioactiveStorageContainer] {}
+
+
+ MODULE
+ {
+ name = ModuleSystemHeatFissionReactor
+ moduleID = reactor
+
+ // -- Heat stuff
+ // ModuleSystemHeat instance to link to
+ systemHeatModuleID = reactor
+
+ // Heat kW
+ HeatGeneration
+ {
+ key = 0 0 0 0
+ key = 100 2900 0 0
+ }
+
+ // Above this temp, risky
+ NominalTemperature = 850
+ // Above this temp, reactor takes damage
+ CriticalTemperature = 1300
+ // Amount of damage taken by core when over critical temp
+ // %/s/K, so with value 0.001, at 200 K over CriticalTemp, reactor takes 0.2% damage/s
+ CoreDamageRate = 0.01
+
+ // When repairing, amount of core damage to heal (%)
+ RepairAmountPerKit = 15
+
+ CurrentPowerPercent = 100
+ ThrottleIncreaseRate = 5
+ MinimumThrottle = 25
+
+ // -- Electrical stuff
+ // Power generated
+ ElectricalGeneration
+ {
+ key = 0 0
+ key = 100 1000
+ }
+
+ // --- Fuel stuff
+ // Base lifetime calculations off this resource
+ FuelName = EnrichedUranium
+
+ INPUT_RESOURCE
+ {
+ ResourceName = EnrichedUranium
+ Ratio = 0.0000027169
+ FlowMode = NO_FLOW
+ }
+
+ OUTPUT_RESOURCE
+ {
+ ResourceName = DepletedFuel
+ Ratio = 0.0000027169
+ DumpExcess = false
+ FlowMode = NO_FLOW
+ }
+ }
+ MODULE
+ {
+ name = ModuleSystemHeatFissionFuelContainer
+ EngineerLevelForTransfer = 3
+ ResourceNames = EnrichedUranium, DepletedFuel
+ }
+}
+
+@PART[USI_Nuke_375]:FOR[SystemHeatFissionReactors]
+{
+ MODULE
+ {
+ name = ModuleSystemHeat
+ volume = 4
+ moduleID = reactor
+ iconName = Icon_Nuclear
+ }
+
+ !MODULE[ModuleUpdateOverride] {}
+ !MODULE[FissionReactor] {}
+ !MODULE[FissionGenerator] {}
+ !MODULE[ModuleCoreHeatNoCatchup] {}
+ !MODULE[RadioactiveStorageContainer] {}
+
+ MODULE
+ {
+ name = ModuleSystemHeatFissionReactor
+ moduleID = reactor
+
+ // -- Heat stuff
+ // ModuleSystemHeat instance to link to
+ systemHeatModuleID = reactor
+
+ // Heat kW
+ HeatGeneration
+ {
+ key = 0 0 0 0
+ key = 100 9000 0 0
+ }
+
+ // Above this temp, risky
+ NominalTemperature = 900
+
+ // Above this temp, reactor takes damage
+ CriticalTemperature = 1300
+
+ // Amount of damage taken by core when over critical temp
+ // %/s/K, so with value 0.001, at 200 K over CriticalTemp, reactor takes 0.2% damage/s
+ CoreDamageRate = 0.01
+
+ // When repairing, amount of core damage to heal (%)
+ RepairAmountPerKit = 10
+
+ CurrentPowerPercent = 100
+ ThrottleIncreaseRate = 5
+ MinimumThrottle = 25
+
+ // -- Electrical stuff
+ // Power generated
+ ElectricalGeneration
+ {
+ key = 0 0
+ key = 100 4000
+ }
+
+ // --- Fuel stuff
+ // Base lifetime calculations off this resource
+ FuelName = EnrichedUranium
+
+ INPUT_RESOURCE
+ {
+ ResourceName = EnrichedUranium
+ Ratio = 0.000010143
+ FlowMode = NO_FLOW
+ }
+
+ OUTPUT_RESOURCE
+ {
+ ResourceName = DepletedFuel
+ Ratio = 0.000010143
+ DumpExcess = false
+ FlowMode = NO_FLOW
+ }
+ }
+
+ MODULE
+ {
+ name = ModuleSystemHeatFissionFuelContainer
+ EngineerLevelForTransfer = 3
+ ResourceNames = EnrichedUranium, DepletedFuel
+ }
+}
+
+@PART[FTT_Service_375_01]:FOR[SystemHeatFissionReactors]
+{
+ MODULE
+ {
+ name = ModuleSystemHeat
+ volume = 4
+ moduleID = reactor
+ iconName = Icon_Nuclear
+ }
+
+ !MODULE[ModuleUpdateOverride] {}
+ !MODULE[FissionReactor] {}
+ !MODULE[FissionGenerator] {}
+ !MODULE[ModuleCoreHeatNoCatchup] {}
+ !MODULE[RadioactiveStorageContainer] {}
+
+ MODULE
+ {
+ name = ModuleSystemHeatFissionReactor
+ moduleID = reactor
+
+ // -- Heat stuff
+ // ModuleSystemHeat instance to link to
+ systemHeatModuleID = reactor
+
+ // Heat kW
+ HeatGeneration
+ {
+ key = 0 0 0 0
+ key = 100 8000 0 0
+ }
+
+ // Above this temp, risky
+ NominalTemperature = 900
+
+ // Above this temp, reactor takes damage
+ CriticalTemperature = 1300
+
+ // Amount of damage taken by core when over critical temp
+ // %/s/K, so with value 0.001, at 200 K over CriticalTemp, reactor takes 0.2% damage/s
+ CoreDamageRate = 0.005
+
+ // When repairing, amount of core damage to heal (%)
+ RepairAmountPerKit = 10
+
+ CurrentPowerPercent = 100
+ ThrottleIncreaseRate = 5
+ MinimumThrottle = 25
+
+ // -- Electrical stuff
+ // Power generated
+ ElectricalGeneration
+ {
+ key = 0 0
+ key = 100 4500
+ }
+
+ // --- Fuel stuff
+ // Base lifetime calculations off this resource
+ FuelName = EnrichedUranium
+
+ INPUT_RESOURCE
+ {
+ ResourceName = EnrichedUranium
+ Ratio = 0.0000089658
+ FlowMode = NO_FLOW
+ }
+
+ OUTPUT_RESOURCE
+ {
+ ResourceName = DepletedFuel
+ Ratio = 0.0000089658
+ DumpExcess = false
+ FlowMode = NO_FLOW
+ }
+ }
+
+ MODULE
+ {
+ name = ModuleSystemHeatFissionFuelContainer
+ EngineerLevelForTransfer = 3
+ ResourceNames = EnrichedUranium, DepletedFuel
+ }
+}
+
+@PART[FTT_Reactor_500_01]:FOR[SystemHeatFissionReactors]
+{
+ MODULE
+ {
+ name = ModuleSystemHeat
+ volume = 8
+ moduleID = reactor
+ iconName = Icon_Nuclear
+ }
+
+ !MODULE[ModuleUpdateOverride] {}
+ !MODULE[FissionReactor] {}
+ !MODULE[FissionGenerator] {}
+ !MODULE[ModuleCoreHeatNoCatchup] {}
+ !MODULE[RadioactiveStorageContainer] {}
+
+ MODULE
+ {
+ name = ModuleSystemHeatFissionReactor
+ moduleID = reactor
+
+ // -- Heat stuff
+ // ModuleSystemHeat instance to link to
+ systemHeatModuleID = reactor
+
+ // Heat kW
+ HeatGeneration
+ {
+ key = 0 0 0 0
+ key = 100 16000 0 0
+ }
+
+ // Above this temp, risky
+ NominalTemperature = 950
+
+ // Above this temp, reactor takes damage
+ CriticalTemperature = 1300
+
+ // Amount of damage taken by core when over critical temp
+ // %/s/K, so with value 0.001, at 200 K over CriticalTemp, reactor takes 0.2% damage/s
+ CoreDamageRate = 0.005
+
+ // When repairing, amount of core damage to heal (%)
+ RepairAmountPerKit = 10
+
+ CurrentPowerPercent = 100
+ ThrottleIncreaseRate = 5
+ MinimumThrottle = 25
+
+ // -- Electrical stuff
+ // Power generated
+ ElectricalGeneration
+ {
+ key = 0 0
+ key = 100 8000
+ }
+
+ // --- Fuel stuff
+ // Base lifetime calculations off this resource
+ FuelName = EnrichedUranium
+
+ INPUT_RESOURCE
+ {
+ ResourceName = EnrichedUranium
+ Ratio = 0.0000190184
+ FlowMode = NO_FLOW
+ }
+
+ OUTPUT_RESOURCE
+ {
+ ResourceName = DepletedFuel
+ Ratio = 0.0000190184
+ DumpExcess = false
+ FlowMode = NO_FLOW
+ }
+ }
+
+ MODULE
+ {
+ name = ModuleSystemHeatFissionFuelContainer
+ EngineerLevelForTransfer = 3
+ ResourceNames = EnrichedUranium, DepletedFuel
+ }
+}
+
+@PART[Duna_PDU]:FOR[SystemHeatFissionReactors]
+{
+ MODULE
+ {
+ name = ModuleSystemHeat
+ volume = 2
+ moduleID = reactor
+ iconName = Icon_Nuclear
+ }
+
+ !MODULE[ModuleUpdateOverride] {}
+ !MODULE[FissionReactor] {}
+ !MODULE[FissionGenerator] {}
+ !MODULE[ModuleCoreHeatNoCatchup] {}
+ !MODULE[RadioactiveStorageContainer] {}
+
+ MODULE
+ {
+ name = ModuleSystemHeatFissionReactor
+ moduleID = reactor
+
+ // -- Heat stuff
+ // ModuleSystemHeat instance to link to
+ systemHeatModuleID = reactor
+
+ // Heat kW
+ HeatGeneration
+ {
+ key = 0 0 0 0
+ key = 100 3250 0 0
+ }
+
+ // Above this temp, risky
+ NominalTemperature = 750
+
+ // Above this temp, reactor takes damage
+ CriticalTemperature = 1300
+
+ // Amount of damage taken by core when over critical temp
+ // %/s/K, so with value 0.001, at 200 K over CriticalTemp, reactor takes 0.2% damage/s
+ CoreDamageRate = 0.005
+
+ // When repairing, amount of core damage to heal (%)
+ RepairAmountPerKit = 15
+
+ CurrentPowerPercent = 100
+ ThrottleIncreaseRate = 5
+ MinimumThrottle = 25
+
+ // -- Electrical stuff
+ // Power generated
+ ElectricalGeneration
+ {
+ key = 0 0
+ key = 100 750
+ }
+
+ // --- Fuel stuff
+ // Base lifetime calculations off this resource
+ FuelName = EnrichedUranium
+
+ INPUT_RESOURCE
+ {
+ ResourceName = EnrichedUranium
+ Ratio = 0.00000326
+ FlowMode = NO_FLOW
+ }
+
+ OUTPUT_RESOURCE
+ {
+ ResourceName = DepletedFuel
+ Ratio = 0.00000326
+ DumpExcess = false
+ FlowMode = NO_FLOW
+ }
+ }
+
+ MODULE
+ {
+ name = ModuleSystemHeatFissionFuelContainer
+ EngineerLevelForTransfer = 3
+ ResourceNames = EnrichedUranium, DepletedFuel
+ }
+}
+
+@PART[Tundra_PDU]:FOR[SystemHeatFissionReactors]
+{
+ MODULE
+ {
+ name = ModuleSystemHeat
+ volume = 4
+ moduleID = reactor
+ iconName = Icon_Nuclear
+ }
+
+ !MODULE[ModuleUpdateOverride] {}
+ !MODULE[FissionReactor] {}
+ !MODULE[FissionGenerator] {}
+ !MODULE[ModuleCoreHeatNoCatchup] {}
+ !MODULE[RadioactiveStorageContainer] {}
+
+ MODULE
+ {
+ name = ModuleSystemHeatFissionReactor
+ moduleID = reactor
+
+ // -- Heat stuff
+ // ModuleSystemHeat instance to link to
+ systemHeatModuleID = reactor
+
+ // Heat kW
+ HeatGeneration
+ {
+ key = 0 0 0 0
+ key = 100 4700 0 0
+ }
+
+ // Above this temp, risky
+ NominalTemperature = 900
+
+ // Above this temp, reactor takes damage
+ CriticalTemperature = 1300
+
+ // Amount of damage taken by core when over critical temp
+ // %/s/K, so with value 0.001, at 200 K over CriticalTemp, reactor takes 0.2% damage/s
+ CoreDamageRate = 0.005
+
+ // When repairing, amount of core damage to heal (%)
+ RepairAmountPerKit = 10
+
+ CurrentPowerPercent = 100
+ ThrottleIncreaseRate = 5
+ MinimumThrottle = 25
+
+ // -- Electrical stuff
+ // Power generated
+ ElectricalGeneration
+ {
+ key = 0 0
+ key = 100 1200
+ }
+
+ // --- Fuel stuff
+ // Base lifetime calculations off this resource
+ FuelName = EnrichedUranium
+
+ INPUT_RESOURCE
+ {
+ ResourceName = EnrichedUranium
+ Ratio = 0.00000652
+ FlowMode = NO_FLOW
+ }
+
+ OUTPUT_RESOURCE
+ {
+ ResourceName = DepletedFuel
+ Ratio = 0.00000652
+ DumpExcess = false
+ FlowMode = NO_FLOW
+ }
+ }
+
+ MODULE
+ {
+ name = ModuleSystemHeatFissionFuelContainer
+ EngineerLevelForTransfer = 3
+ ResourceNames = EnrichedUranium, DepletedFuel
+ }
+}
diff --git a/Extras/SystemHeatHarvesters/genericHarvesters.cfg b/Extras/SystemHeatHarvesters/genericHarvesters.cfg
index 9d896ed..6afa681 100644
--- a/Extras/SystemHeatHarvesters/genericHarvesters.cfg
+++ b/Extras/SystemHeatHarvesters/genericHarvesters.cfg
@@ -11,7 +11,8 @@
!MODULE[ModuleOverheatDisplay]{}
- @MODULE[ModuleResourceHarvester]:HAS[@INPUT_RESOURCE:HAS[#ResourceName[ElectricCharge]]]{ //Ive seen some converters that dont use electric charge, those things need thier own patch, as we calculate produced heat based on EC consumption.
+ @MODULE[ModuleResourceHarvester]:HAS[@INPUT_RESOURCE:HAS[#ResourceName[ElectricCharge]]] {
+ //Ive seen some converters that dont use electric charge, those things need thier own patch, as we calculate produced heat based on consumption.
@name = ModuleSystemHeatHarvester
moduleID = #$ConverterName$ //this should be the localization string or the actual name, either way, unique.
systemHeatModuleID = harvester
@@ -24,10 +25,9 @@
key = 650 0.0
}
systemPower = #$INPUT_RESOURCE:HAS[#ResourceName[ElectricCharge]]/Ratio$
- @systemPower *= #$Efficiency$ //set the heat ouput as proportional to the EC usage.
// I *think* that all the energy goes into heat.
- !Thermalefficiency {}
+ !ThermalEfficiency {}
!TemperatureModifier {}
- @generatesHeat = false //disable stock heating
+ @GeneratesHeat = false //disable stock heating
}
}
diff --git a/Extras/SystemHeatIonEngines/NearFuturePropulsion/NFPSystemHeatVASIMR.cfg b/Extras/SystemHeatIonEngines/NearFuturePropulsion/NFPSystemHeatVASIMR.cfg
index ef07445..2e25261 100644
--- a/Extras/SystemHeatIonEngines/NearFuturePropulsion/NFPSystemHeatVASIMR.cfg
+++ b/Extras/SystemHeatIonEngines/NearFuturePropulsion/NFPSystemHeatVASIMR.cfg
@@ -18,7 +18,7 @@
{
name = ModuleSystemHeatEngine
// must be unique
- moduleID = engine
+ moduleID = engineA
// ModuleSystemHeat to link to
systemHeatModuleID = engine
@@ -41,7 +41,7 @@
{
name = ModuleSystemHeatEngine
// must be unique
- moduleID = engine
+ moduleID = engineX
// ModuleSystemHeat to link to
systemHeatModuleID = engine
@@ -81,7 +81,7 @@
{
name = ModuleSystemHeatEngine
// must be unique
- moduleID = engine
+ moduleID = engineA
// ModuleSystemHeat to link to
systemHeatModuleID = engine
@@ -105,7 +105,7 @@
{
name = ModuleSystemHeatEngine
// must be unique
- moduleID = engine
+ moduleID = engineX
// ModuleSystemHeat to link to
systemHeatModuleID = engine
@@ -145,7 +145,7 @@
{
name = ModuleSystemHeatEngine
// must be unique
- moduleID = engine
+ moduleID = engineA
// ModuleSystemHeat to link to
systemHeatModuleID = engine
@@ -169,7 +169,7 @@
{
name = ModuleSystemHeatEngine
// must be unique
- moduleID = engine
+ moduleID = engineX
// ModuleSystemHeat to link to
systemHeatModuleID = engine
diff --git a/GameData/SystemHeat/Localization/en-us.cfg b/GameData/SystemHeat/Localization/en-us.cfg
index 7d124ee..e522ad4 100644
--- a/GameData/SystemHeat/Localization/en-us.cfg
+++ b/GameData/SystemHeat/Localization/en-us.cfg
@@ -10,8 +10,8 @@ Localization
#LOC_SystemHeat_ToolbarPanel_OutgoingFluxTitle = Total Generation
#LOC_SystemHeat_ToolbarPanel_IncomingFluxTile = Total Rejection
- #LOC_SystemHeat_ToolbarPanel_OutgoingFluxValue = <<1>> kW
- #LOC_SystemHeat_ToolbarPanel_IncomingFluxValue = <<1>> kW
+ #LOC_SystemHeat_ToolbarPanel_OutgoingFluxValue = <<1>>W
+ #LOC_SystemHeat_ToolbarPanel_IncomingFluxValue = <<1>>W
#LOC_SystemHeat_ToolbarPanel_LoopCountTitle = Loop Count
#LOC_SystemHeat_ToolbarPanel_LoopCountValue = <<1>>
@@ -38,13 +38,13 @@ Localization
#LOC_SystemHeat_ToolbarPanel_LoopTemperatureTitle = • Temperature
#LOC_SystemHeat_ToolbarPanel_LoopTemperatureValue = <<1>>/<<2>> K
#LOC_SystemHeat_ToolbarPanel_LoopFluxTitle = • Net Flux
- #LOC_SystemHeat_ToolbarPanel_LoopFluxValue = <<1>><<2>> kW
+ #LOC_SystemHeat_ToolbarPanel_LoopFluxValue = <<1>><<2>>W
// OVERLAY PANEL
// ------------
- #LOC_SystemHeat_OverlayPanel_UpperText = Temperature Output <<1>> K \nWaste Heat <<2>> kW
- #LOC_SystemHeat_OverlayPanel_UpperTextNoTemp = Waste Heat <<1>> kW
- #LOC_SystemHeat_OverlayPanel_LowerText = Loop Status\n Temperature <<1>>/<<2>> K \n Net Flux <<3>> kW \n Volume <<4>> m³
+ #LOC_SystemHeat_OverlayPanel_UpperText = Temperature Output <<1>> K \nWaste Heat <<2>>W
+ #LOC_SystemHeat_OverlayPanel_UpperTextNoTemp = Waste Heat <<1>>W
+ #LOC_SystemHeat_OverlayPanel_LowerText = Loop Status\n Temperature <<1>>/<<2>> K \n Net Flux <<3>>W \n Volume <<4>> m³
// REACTOR TOOLBAR
// ------------
@@ -52,7 +52,7 @@ Localization
#LOC_SystemHeat_ReactorPanel_NoReactors = No reactors detected on vessel
#LOC_SystemHeat_ReactorPanel_ReactorOnToggleLabel = ON
#LOC_SystemHeat_ReactorPanel_Field_HeatGeneratedTitle = Heat Generated
- #LOC_SystemHeat_ReactorPanel_Field_HeatGenerated = <<1>> kW
+ #LOC_SystemHeat_ReactorPanel_Field_HeatGenerated = <<1>>W
#LOC_SystemHeat_ReactorPanel_Field_PowerGeneratedTitle = Power Generated
#LOC_SystemHeat_ReactorPanel_Field_PowerGenerated = <<1>> Ec/s
#LOC_SystemHeat_ReactorPanel_Field_CoreLifeTitle = Core Life
@@ -64,12 +64,13 @@ Localization
// ENGINEER'S REPORT
// ------------
#LOC_SystemHeat_EngineerReport_LoopFluxTest_ConcernTitle = Loops Need Additional Cooling Capacity
- #LOC_SystemHeat_EngineerReport_LoopFluxTest_ConcernDescription = Loop <<1>> has a net heat flux of <<2>> kW! <<3>>
+ #LOC_SystemHeat_EngineerReport_LoopFluxTest_ConcernDescription = Loop <<1>> has a net heat flux of <<2>>W! <<3>>
#LOC_SystemHeat_EngineerReport_LoopTemperatureTest_ConcernTitle = Loop Temperature Too High
#LOC_SystemHeat_EngineerReport_LoopTemperatureTest_ConcernDescription = One or more loops has a nominal temperature that is too high for its members!
#LOC_SystemHeat_Units_K = K
+ #LOC_SystemHeat_Units_W = W
#LOC_SystemHeat_Units_kW = kW
// PART MODULES
@@ -88,25 +89,25 @@ Localization
// ModuleSystemHeatRadiator
/// =================================
#LOC_SystemHeat_ModuleSystemHeatRadiator_DisplayName = Heat Radiator
- #LOC_SystemHeat_ModuleSystemHeatRadiator_PartInfo = Cools systems on vessels by pumping coolant through radiating surfaces.\n\nThermal Parameters:\n - Radiates <<1>> kW at <<2>> K\n - Radiates <<3>> kW at <<4>> K\n \n\nLegacy Core Heat Parameters
+ #LOC_SystemHeat_ModuleSystemHeatRadiator_PartInfo = Cools systems on vessels by pumping coolant through radiating surfaces.\n\nThermal Parameters:\n - Radiates <<1>>W at <<2>> K\n - Radiates <<3>>W at <<4>> K\n \n\nLegacy Core Heat Parameters
#LOC_SystemHeat_ModuleSystemHeatRadiator_GroupName = Heat Radiator
#LOC_SystemHeat_ModuleSystemHeatRadiator_RadiatorStatus_Title = Radiative Flux
- #LOC_SystemHeat_ModuleSystemHeatRadiator_RadiatorStatus_Running = <<1>> kW
+ #LOC_SystemHeat_ModuleSystemHeatRadiator_RadiatorStatus_Running = <<1>>W
#LOC_SystemHeat_ModuleSystemHeatRadiator_RadiatorEfficiency_Title = Radiator Efficiency
#LOC_SystemHeat_ModuleSystemHeatRadiator_RadiatorEfficiency_Running = <<1>>%
#LOC_SystemHeat_ModuleSystemHeatRadiator_RadiatorEfficiency_Offline = Offline
#LOC_SystemHeat_ModuleSystemHeatRadiator_ConvectionStatus_Title = Convective Flux
- #LOC_SystemHeat_ModuleSystemHeatRadiator_ConvectionStatus_Running = <<1>> kW
+ #LOC_SystemHeat_ModuleSystemHeatRadiator_ConvectionStatus_Running = <<1>>W
// ModuleSystemHeatEngine
/// =================================
#LOC_SystemHeat_ModuleSystemHeatEngine_DisplayName = Engine Heat
- #LOC_SystemHeat_ModuleSystemHeatEngine_PartInfo = Thermal Parameters:\n - Waste Heat: <<1>> kW\n -Outlet Temperature: <<2>> K\n -Max. Temperature <<3>> K
+ #LOC_SystemHeat_ModuleSystemHeatEngine_PartInfo = Thermal Parameters:\n - Waste Heat: <<1>>W\n -Outlet Temperature: <<2>> K\n -Max. Temperature <<3>> K
#LOC_SystemHeat_ModuleSystemHeatEngine_Field_HeatGeneration = Engine Heat Generation
- #LOC_SystemHeat_ModuleSystemHeatEngine_Field_HeatGeneration_Running = <<1>> kW
+ #LOC_SystemHeat_ModuleSystemHeatEngine_Field_HeatGeneration_Running = <<1>>W
#LOC_SystemHeat_ModuleSystemHeatEngine_Field_Temperature = Engine System Temperature
#LOC_SystemHeat_ModuleSystemHeatEngine_Field_Temperature_Running = <<1>>/<<2>> K
#LOC_SystemHeat_ModuleSystemHeatEngine_Message_Overheat = Engine system maximum temperature of <<1>> K was exceeded on <<2>>! Emergency shutdown!
@@ -115,7 +116,7 @@ Localization
/// =================================
#LOC_SystemHeat_ModuleSystemHeatFissionReactor_UIGroup_Title = Fission Reactor
#LOC_SystemHeat_ModuleSystemHeatFissionReactor_ModuleName = Fission Reactor
- #LOC_SystemHeat_ModuleSystemHeatFissionReactor_PartInfo = Electrical Power: <<1>> Ec/s\nResponse Speed: <<8>>%/s\nMinimum Power: <<9>>%\nCore Life: <<2>>\n\nThermal Parameters:\n - Waste Heat: <<3>> kW\n - Outlet Temperature: <<4>> K\n - Optimal Temp.: <<5>> K \n - Damage Temp.: <<6>> K\n - Meltdown Temp.: <<7>> K
+ #LOC_SystemHeat_ModuleSystemHeatFissionReactor_PartInfo = Electrical Power: <<1>> Ec/s\nResponse Speed: <<8>>%/s\nMinimum Power: <<9>>%\nCore Life: <<2>>\n\nThermal Parameters:\n - Waste Heat: <<3>>W\n - Outlet Temperature: <<4>> K\n - Optimal Temp.: <<5>> K \n - Damage Temp.: <<6>> K\n - Meltdown Temp.: <<7>> K
#LOC_SystemHeat_ModuleSystemHeatFissionReactor_Action_TogglePanelAction = Toggle Reactor Panel
#LOC_SystemHeat_ModuleSystemHeatFissionReactor_Action_StartActionName = Start Reactor
@@ -169,14 +170,14 @@ Localization
#LOC_SystemHeat_ModuleSystemHeatFissionReactor_Action_TogglePanelAction = Toggle Reactor Panel
- #LOC_SystemHeat_ModuleSystemHeatFissionEngine_PartInfo = Generates thrust through nuclear fission. \n\nElectrical Power <<1>> Ec/s\nResponse Speed: <<8>>%/s\nMinimum Power: <<9>>%\nCore Life: <<2>>\n\nThermal Parameters:\n - Waste Heat: <<3>> kW\n - Exhaust Cooling: <<10>>%\n - Outlet Temperature: <<4>> K\n\n - Optimal Temp.: <<5>> K \n - Damage Temp.: <<6>> K\n - Meltdown Temp.: <<7>> K
+ #LOC_SystemHeat_ModuleSystemHeatFissionEngine_PartInfo = Generates thrust through nuclear fission. \n\nElectrical Power <<1>> Ec/s\nResponse Speed: <<8>>%/s\nMinimum Power: <<9>>%\nCore Life: <<2>>\n\nThermal Parameters:\n - Waste Heat: <<3>>W\n - Exhaust Cooling: <<10>>%\n - Outlet Temperature: <<4>> K\n\n - Optimal Temp.: <<5>> K \n - Damage Temp.: <<6>> K\n - Meltdown Temp.: <<7>> K
#LOC_SystemHeat_ModuleSystemHeatFissionReactor_Action_TogglePanelAction = Toggle Reactor Panel
- #LOC_SystemHeat_ModuleSystemHeatFissionEngine_PartInfo_NoPower = Generates thrust through nuclear fission. \n\nResponse Speed: <<7>>%/s\nMinimum Power: <<8>>%\nCore Life: <<1>>\n\nThermal Parameters:\n - Waste Heat: <<2>> kW\n - Exhaust Cooling: <<9>>%\n - Outlet Temperature: <<3>> K\n - Optimal Temp.: <<>> K \n - Damage Temp.: <<5>> K\n - Meltdown Temp.: <<6>> K
+ #LOC_SystemHeat_ModuleSystemHeatFissionEngine_PartInfo_NoPower = Generates thrust through nuclear fission. \n\nResponse Speed: <<7>>%/s\nMinimum Power: <<8>>%\nCore Life: <<1>>\n\nThermal Parameters:\n - Waste Heat: <<2>>W\n - Exhaust Cooling: <<9>>%\n - Outlet Temperature: <<3>> K\n - Optimal Temp.: <<>> K \n - Damage Temp.: <<5>> K\n - Meltdown Temp.: <<6>> K
#LOC_SystemHeat_ModuleSystemHeatFissionReactor_Action_TogglePanelAction = Toggle Reactor Panel
#LOC_SystemHeat_ModuleSystemHeatFissionEngine_Field_CurrentExhaustCooling = Exhaust Cooling
- #LOC_SystemHeat_ModuleSystemHeatFissionEngine_Field_CurrentExhaustCooling_Running = <<1>> kW
+ #LOC_SystemHeat_ModuleSystemHeatFissionEngine_Field_CurrentExhaustCooling_Running = <<1>>W
#LOC_SystemHeat_ModuleSystemHeatFissionEngine_Field_CurrentExhaustCooling_EngineOff = Engine Off
#LOC_SystemHeat_ModuleSystemHeatFissionEngine_Message_Shutdown = Reactor shutdown on <<1>>, engine shutdown...
@@ -209,12 +210,12 @@ Localization
/// =================================
#LOC_SystemHeat_ModuleSystemHeatSink_UIGroup_Title = Heat Sink
#LOC_SystemHeat_ModuleSystemHeatSink_ModuleName = Heat Sink
- #LOC_SystemHeat_ModuleSystemHeatSink_PartInfo = Stores or releases heat on demand. \n\nThermal Parameters:\n - Max. Heat Stored: <<1>> MJ \n - Heat Storage Rate: <<2>> kW
+ #LOC_SystemHeat_ModuleSystemHeatSink_PartInfo = Stores or releases heat on demand. \n\nThermal Parameters:\n - Max. Heat Stored: <<1>> MJ \n - Heat Storage Rate: <<2>>W
#LOC_SystemHeat_ModuleSystemHeatSink_Field_HeatStorageDumpRate = Dump Rate
#LOC_SystemHeat_ModuleSystemHeatSink_Field_SystemHeatGeneration = Storage Accepted
#LOC_SystemHeat_ModuleSystemHeatSink_Field_SystemHeatGeneration_Dump = Storage Dumping
- #LOC_SystemHeat_ModuleSystemHeatSink_Field_SystemHeatGeneration_Storing = <<1>>/<<2>> kW
+ #LOC_SystemHeat_ModuleSystemHeatSink_Field_SystemHeatGeneration_Storing = <<1>>/<<2>>W
#LOC_SystemHeat_ModuleSystemHeatSink_Field_SystemTemperature = Storage Temperature
#LOC_SystemHeat_ModuleSystemHeatSink_Field_SystemTemperature_Running = <<1>> K
@@ -228,20 +229,20 @@ Localization
/// ModuleSystemHeatExchanger
/// =================================
#LOC_SystemHeat_ModuleSystemHeatExchanger_ModuleName = Heat Exchanger
- #LOC_SystemHeat_ModuleSystemHeatExchanger_UIGroup_Title = Heat Exchanger
- #LOC_SystemHeat_ModuleSystemHeatExchanger_PartInfo = Transfers heat from one loop to another, optionally modifying the second loop's temperature. \n\nPower Used\n - ΔT of <<1>> K needs <<2>> Ec/s\n - ΔT of <<3>> K needs <<4>> Ec/s\n\nWaste Heat Produced\n - ΔT of <<1>> K generates <<5>> kW\n - ΔT of <<3>> K generates <<6>> kW
+ #LOC_SystemHeat_ModuleSystemHeatExchanger_UIGroup_Title = Heat Exchanger, optionally modifying the second loop's temperature. \n\nPower Used\n - ΔT of <<1>> K needs <<2>> Ec/s\n - ΔT of <<3>> K needs <<4>> Ec/s\n\nWaste Heat Produced\n - ΔT of <<1>> K generates <<5>>W\n - ΔT of <<3>> K generates <<6>>W
+ #LOC_SystemHeat_ModuleSystemHeatExchanger_PartInfo = Transfers heat from one loop to another
#LOC_SystemHeat_ModuleSystemHeatExchanger_Field_Direction = Transfer Direction
#LOC_SystemHeat_ModuleSystemHeatExchanger_Field_Direction_String = Loop <<1>> -> Loop <<2>>
#LOC_SystemHeat_ModuleSystemHeatExchanger_Field_Status = Exchanger Status
- #LOC_SystemHeat_ModuleSystemHeatExchanger_Field_Status_Active = Output Temperature: <<1>> K\nOutput Flux: <<2>> kW
+ #LOC_SystemHeat_ModuleSystemHeatExchanger_Field_Status_Active = Output Temperature: <<1>> K\nOutput Flux: <<2>>W
#LOC_SystemHeat_ModuleSystemHeatExchanger_Field_Status_NoPower = Not enough ElectricCharge!
#LOC_SystemHeat_ModuleSystemHeatExchanger_Field_Status_TooHot = Destination loop overheated!
#LOC_SystemHeat_ModuleSystemHeatExchanger_Field_Status_Disabled = Disabled
#LOC_SystemHeat_ModuleSystemHeatExchanger_Field_MaxHeatTransfer = Max Heat Transfer
#LOC_SystemHeat_ModuleSystemHeatExchanger_Field_TemperatureAdjust = Temperature Adjustment
#LOC_SystemHeat_ModuleSystemHeatExchanger_Field_PowerCost = Power Usage
- #LOC_SystemHeat_ModuleSystemHeatExchanger_Field_PowerCost_Active = <<1>> kW
+ #LOC_SystemHeat_ModuleSystemHeatExchanger_Field_PowerCost_Active = <<1>>W
#LOC_SystemHeat_ModuleSystemHeatExchanger_Event_EnableExchanger = Enable Exchanger
#LOC_SystemHeat_ModuleSystemHeatExchanger_Event_DisableExchanger = Disable Exchanger
@@ -254,7 +255,7 @@ Localization
/// ModuleSystemHeatBaseConverterAdapter
/// =================================
- #LOC_SystemHeat_ModuleSystemHeatBaseConverterAdapter_PartInfo = \n\nThermal Parameters:\n - Heat Generated: <<1>> kW\n - Outlet Temperature: <<2>> K\n - Max. Temperature: <<3>> K
+ #LOC_SystemHeat_ModuleSystemHeatBaseConverterAdapter_PartInfo = \n\nThermal Parameters:\n - Heat Generated: <<1>>W\n - Outlet Temperature: <<2>> K\n - Max. Temperature: <<3>> K
#LOC_SystemHeat_ModuleSystemHeatBaseConverterAdapter_ModuleName = Taco Module
#LOC_SystemHeat_ModuleSystemHeatBaseConverterAdapter_Message_Shutdown = Converter overheated on <<1>>! Emergency shutdown!
@@ -262,7 +263,7 @@ Localization
/// ModuleSystemHeatConverter
/// =================================
- #LOC_SystemHeat_ModuleSystemHeatConverter_PartInfoAdd = \n\nThermal Parameters:\n - Heat Generated: <<1>> kW\n - Outlet Temperature: <<2>> K\n - Max. Temperature: <<3>> K
+ #LOC_SystemHeat_ModuleSystemHeatConverter_PartInfoAdd = \n\nThermal Parameters:\n - Heat Generated: <<1>>W\n - Outlet Temperature: <<2>> K\n - Max. Temperature: <<3>> K
#LOC_SystemHeat_ModuleSystemHeatConverter_Field_Efficiency = Efficiency [<<1>>]
#LOC_SystemHeat_ModuleSystemHeatConverter_Field_Efficiency_Value = <<1>>%
@@ -272,13 +273,44 @@ Localization
/// ModuleSystemHeatHarvester
/// =================================
- #LOC_SystemHeat_ModuleSystemHeatHarvester_PartInfoAdd = \n\nThermal Parameters:\n - Heat Generated: <<1>> kW\n - Outlet Temperature: <<2>> K\n - Max. Temperature: <<3>> K
+ #LOC_SystemHeat_ModuleSystemHeatHarvester_PartInfoAdd = \n\nThermal Parameters:\n - Heat Generated: <<1>>W\n - Outlet Temperature: <<2>> K\n - Max. Temperature: <<3>> K
#LOC_SystemHeat_ModuleSystemHeatHarvester_Field_Efficiency = Efficiency
#LOC_SystemHeat_ModuleSystemHeatHarvester_Field_Efficiency_Value = <<1>>%
#LOC_SystemHeat_ModuleSystemHeatHarvester_Field_SimulateEditor = Editor Simulate [<<1>>]
#LOC_SystemHeat_ModuleSystemHeatHarvester_Message_Shutdown = Harvester overheated on <<1>>! Emergency shutdown!
+ /// ModuleSystemCryoTank
+ /// =================================
+
+ #LOC_SystemHeat_ModuleSystemHeatCryoTank_ModuleName = Cryogenic Tank
+ #LOC_SystemHeat_ModuleSystemHeatCryoTank_PartInfoUncooled = Cryogenic fuels evaporate over time\n
+ #LOC_SystemHeat_ModuleSystemHeatCryoTank_PartInfoCooled = Cryogenic fuels evaporate over time if uncooled<<1>>
+ #LOC_SystemHeat_ModuleSystemHeatCryoTank_PartInfoBoiloff = \n<<1>>:\n - Boiloff Rate: <<2>>%/hr\n - Heat Generated: <<3>>W per 1000 units\n - Max. Temperature: <<4>> K\n
+ #LOC_SystemHeat_ModuleSystemHeatCryoTank_PartInfoBoiloffOutput = \n- Generates <<1>>: +<<2>>%/hr
+
+ #LOC_SystemHeat_ModuleSystemHeatCryoTank_UIGroup_Title = Cryogenic Tank
+
+ #LOC_SystemHeat_ModuleSystemHeatCryoTank_Field_BoiloffStatus = Boiloff
+ #LOC_SystemHeat_ModuleSystemHeatCryoTank_Field_BoiloffStatus_NoFuel = No Fuel
+ #LOC_SystemHeat_ModuleSystemHeatCryoTank_Field_BoiloffStatus_Insulated = Stable
+ #LOC_SystemHeat_ModuleSystemHeatCryoTank_Field_BoiloffStatus_Boiloff = Losing <<1>> u/<<2>>
+
+ #LOC_SystemHeat_ModuleSystemHeatCryoTank_TimeInterval_Second_Abbrev = s
+ #LOC_SystemHeat_ModuleSystemHeatCryoTank_TimeInterval_Hour_Abbrev = hr
+ #LOC_SystemHeat_ModuleSystemHeatCryoTank_TimeInterval_Minute_Abbrev = min
+
+ #LOC_SystemHeat_ModuleSystemHeatCryoTank_Field_CoolingStatus = Cooling
+ #LOC_SystemHeat_ModuleSystemHeatCryoTank_Field_CoolingStatus_Editor = Waste Heat: <<1>>W
+ #LOC_SystemHeat_ModuleSystemHeatCryoTank_Field_CoolingStatus_NoFuel = No Fuel
+ #LOC_SystemHeat_ModuleSystemHeatCryoTank_Field_CoolingStatus_Disabled = Disabled
+ #LOC_SystemHeat_ModuleSystemHeatCryoTank_Field_CoolingStatus_Uncooled = Uncooled
+ #LOC_SystemHeat_ModuleSystemHeatCryoTank_Field_CoolingStatus_Cooling = Waste Heat: <<1>>W
+
+ #LOC_SystemHeat_ModuleSystemHeatCryoTank_Event_Enable = Enable Cooling
+ #LOC_SystemHeat_ModuleSystemHeatCryoTank_Event_Disable = Disable Cooling
+
+
// PARTS
// ------------
#LOC_SystemHeat_manufacturer_pkmc_title = Post-Kebin Mining Corporation
diff --git a/GameData/SystemHeat/Plugin/SystemHeat.dll b/GameData/SystemHeat/Plugin/SystemHeat.dll
index 297b0d7..fb44574 100644
Binary files a/GameData/SystemHeat/Plugin/SystemHeat.dll and b/GameData/SystemHeat/Plugin/SystemHeat.dll differ
diff --git a/GameData/SystemHeat/Settings.cfg b/GameData/SystemHeat/Settings.cfg
index 07153a2..9fdf295 100644
--- a/GameData/SystemHeat/Settings.cfg
+++ b/GameData/SystemHeat/Settings.cfg
@@ -8,10 +8,10 @@ SYSTEMHEAT
OverlayPadding = 0.4
// Debug Settings
- DebugUI = true
- DebugOverlay = true
+ DebugUI = false
+ DebugOverlay = false
DebugSimulation = false
- DebugModules = true
+ DebugModules = false
DebugPartUI = false
diff --git a/GameData/SystemHeat/Versioning/SystemHeat.version b/GameData/SystemHeat/Versioning/SystemHeat.version
index 01b90ff..9b30533 100644
--- a/GameData/SystemHeat/Versioning/SystemHeat.version
+++ b/GameData/SystemHeat/Versioning/SystemHeat.version
@@ -5,15 +5,15 @@
"VERSION":
{
"MAJOR":0,
- "MINOR":5,
- "PATCH":6,
+ "MINOR":6,
+ "PATCH":0,
"BUILD":0
},
"KSP_VERSION":
{
"MAJOR":1,
"MINOR":12,
- "PATCH":2
+ "PATCH":3
},
"KSP_VERSION_MIN":{
"MAJOR":1,
diff --git a/README.md b/README.md
index bc9b85d..bbd102b 100644
--- a/README.md
+++ b/README.md
@@ -58,6 +58,7 @@ Please note that these extras may break your ships in flight as they will make e
* **SystemHeatConverters**: Converts converters to use SystemHeat
* **SystemHeatFissionReactors**: Converts nuclear reactors to use SystemHeat
* **SystemHeatFissionEngines**: When installed, nuclear engines will have integrated reactors
+* **SystemHeatCryoTanks**: When installed, tanks configured by CryoTanks will not use power and instead require cooling
## Contributing
diff --git a/SystemHeat/SystemHeat/HeatLoop.cs b/SystemHeat/SystemHeat/HeatLoop.cs
index 3be8208..623377d 100644
--- a/SystemHeat/SystemHeat/HeatLoop.cs
+++ b/SystemHeat/SystemHeat/HeatLoop.cs
@@ -114,11 +114,8 @@ public void RemoveHeatModule(ModuleSystemHeat heatModule)
Volume -= heatModule.volume;
modules.Remove(heatModule);
-
// Recalculate the nominal temperature
NominalTemperature = CalculateNominalTemperature();
-
-
}
public void ResetTemperatures()
@@ -126,7 +123,8 @@ public void ResetTemperatures()
Temperature = GetEnvironmentTemperature();
for (int i = 0; i < modules.Count; i++)
{
- modules[i].currentLoopTemperature = GetEnvironmentTemperature();
+ if (modules[i].moduleUsed)
+ modules[i].currentLoopTemperature = GetEnvironmentTemperature();
}
}
@@ -170,7 +168,8 @@ protected float CalculateNetFlux()
float currentNetFlux = 0f;
for (int i = 0; i < modules.Count; i++)
{
- currentNetFlux += modules[i].totalSystemFlux;
+ if (modules[i].moduleUsed)
+ currentNetFlux += modules[i].totalSystemFlux;
}
return currentNetFlux;
}
@@ -183,7 +182,8 @@ protected float CalculatePositiveFlux()
float currentNetFlux = 0f;
for (int i = 0; i < modules.Count; i++)
{
- currentNetFlux = modules[i].totalSystemFlux > 0 ? modules[i].totalSystemFlux + currentNetFlux : currentNetFlux;
+ if (modules[i].moduleUsed)
+ currentNetFlux = modules[i].totalSystemFlux > 0 ? modules[i].totalSystemFlux + currentNetFlux : currentNetFlux;
}
return currentNetFlux;
}
@@ -246,7 +246,7 @@ void SimulateIteration(float simTimeStep)
{
Temperature += deltaTemperatureIdeal;
}
-
+
else
{
// do nothing
@@ -258,7 +258,8 @@ void SimulateIteration(float simTimeStep)
// Propagate to all modules
for (int i = 0; i < modules.Count; i++)
{
- modules[i].UpdateSimulationValues(NominalTemperature, Temperature, NetFlux);
+ if (modules[i].moduleUsed)
+ modules[i].UpdateSimulationValues(NominalTemperature, Temperature, NetFlux);
}
}
protected void AllocateFlux(float totalFlux)
@@ -296,6 +297,7 @@ protected void AllocateFlux(float totalFlux)
}
void SimulateConvection(float simTimeStep)
{
+
ConvectionTemperature = simulator.AtmoSim.ExternalTemperature;
ConvectionFlux = SystemHeatSettings.ConvectionBaseCoefficient * simulator.AtmoSim.ConvectiveCoefficient * simTimeStep;
}
@@ -335,7 +337,8 @@ protected float CalculateLoopVolume()
float total = 0f;
for (int i = 0; i < modules.Count; i++)
{
- total += modules[i].volume;
+ if (modules[i].moduleUsed)
+ total += modules[i].volume;
}
return total;
}
@@ -350,7 +353,7 @@ protected float CalculateNominalTemperature()
for (int i = 0; i < modules.Count; i++)
{
- if (!modules[i].ignoreTemperature && modules[i].volume >= 0f && modules[i].totalSystemFlux >= 0f)
+ if (modules[i].moduleUsed && !modules[i].ignoreTemperature && modules[i].volume >= 0f && modules[i].totalSystemFlux >= 0f)
{
temp += modules[i].systemNominalTemperature * modules[i].volume;
totalVolume += modules[i].volume;
@@ -362,5 +365,19 @@ protected float CalculateNominalTemperature()
else
return GetEnvironmentTemperature();
}
+
+ public int GetActiveModuleCount()
+ {
+ int count = 0;
+ for (int i = 0; i < modules.Count; i++)
+ {
+ if (modules[i].moduleUsed)
+ {
+ count++;
+ }
+ }
+ return count;
+ }
+
}
}
diff --git a/SystemHeat/SystemHeat/Modules/BoiloffFuel.cs b/SystemHeat/SystemHeat/Modules/BoiloffFuel.cs
new file mode 100644
index 0000000..615bb5a
--- /dev/null
+++ b/SystemHeat/SystemHeat/Modules/BoiloffFuel.cs
@@ -0,0 +1,159 @@
+using System;
+using System.Collections.Generic;
+
+namespace SystemHeat
+{
+ ///
+ /// Represents a fuel resource on a part that boils off
+ ///
+ [System.Serializable]
+ public class BoiloffFuel
+ {
+ ///
+ /// Fuel name
+ ///
+ public string fuelName;
+
+ ///
+ /// Boiloff rate in %/hr
+ ///
+ public float boiloffRate;
+
+ ///
+ /// Boiloff temp
+ ///
+ public float cryoTemperature;
+
+ ///
+ /// Cooling cost in kW/1000u
+ ///
+ public float coolingHeatCost;
+
+ public PartResource resource;
+ public List outputs;
+ public float boiloffRateSeconds = 0f;
+
+ public bool fuelPresent = false;
+ int id = -1;
+ Part part;
+
+ ///
+ /// Constructor
+ ///
+ ///
+ ///
+ public BoiloffFuel(ConfigNode node, Part p)
+ {
+ part = p;
+ node.TryGetValue("FuelName", ref fuelName);
+ node.TryGetValue("BoiloffRate", ref boiloffRate);
+ node.TryGetValue("CryocoolerTemperature", ref cryoTemperature);
+ node.TryGetValue("CoolingHeatCost", ref coolingHeatCost);
+
+
+ ConfigNode[] outNodes = node.GetNodes("OUTPUT_RESOURCE");
+
+ if (outNodes.Length > 0 || outputs == null)
+ outputs = new List();
+ {
+ for (int i = 0; i < outNodes.Length; i++)
+ {
+ ResourceRatio r = new ResourceRatio();
+ r.Load(outNodes[i]);
+ outputs.Add(r);
+ }
+ }
+ }
+
+ ///
+ /// Initialize the fuel
+ ///
+ public void Initialize()
+ {
+ id = PartResourceLibrary.Instance.GetDefinition(fuelName).id;
+ resource = part.Resources.Get(id);
+ boiloffRateSeconds = boiloffRate / 100f / 3600f;
+ fuelPresent = true;
+ }
+
+ ///
+ /// Returns the max amount of the fuel on the part
+ ///
+ ///
+ public double FuelAmountMax()
+ {
+ if (fuelPresent)
+ return resource.maxAmount;
+ return 0d;
+ }
+
+ ///
+ /// Returns the amount of the fuel on the part
+ ///
+ ///
+ public double FuelAmount()
+ {
+ if (fuelPresent)
+ return resource.amount;
+ return 0d;
+ }
+
+ ///
+ /// Returns the heating cost to cool the fuel
+ ///
+ ///
+ public float FuelCoolingHeatCost()
+ {
+ if (fuelPresent)
+ return coolingHeatCost;
+ return 0f;
+ }
+
+ ///
+ /// Returns the cryo temp of the fuel
+ ///
+ ///
+ public float FuelCryocoolerTemperature()
+ {
+ if (fuelPresent)
+ return cryoTemperature;
+ return -1f;
+ }
+
+
+
+ ///
+ /// Returns the cost to cool fuel not considering current contents
+ ///
+ ///
+ public float FuelConfiguredCoolingHeatCost()
+ {
+ return coolingHeatCost;
+ }
+
+ ///
+ /// Appplies boiloff, given a time interval and a scale
+ ///
+ ///
+ ///
+ public void Boiloff(double seconds, double scale)
+ {
+ if (fuelPresent)
+ {
+ double toBoil = resource.amount * (1.0 - Math.Pow(1.0 - boiloffRateSeconds, seconds)) * scale;
+
+ double boilResult = part.RequestResource(resource.info.id, toBoil, ResourceFlowMode.NO_FLOW);
+
+ /// Generate outputs
+ if (outputs.Count > 0)
+ {
+ for (int i = 0; i < outputs.Count; i++)
+ {
+ part.RequestResource(outputs[i].ResourceName, -boilResult * outputs[i].Ratio, outputs[i].FlowMode);
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/SystemHeat/SystemHeat/Modules/ModuleSystemHeat.cs b/SystemHeat/SystemHeat/Modules/ModuleSystemHeat.cs
index 2a05921..e7997c3 100644
--- a/SystemHeat/SystemHeat/Modules/ModuleSystemHeat.cs
+++ b/SystemHeat/SystemHeat/Modules/ModuleSystemHeat.cs
@@ -10,6 +10,7 @@ namespace SystemHeat
/// The simulation interface to the heat system. All heat producing or consuming modules
/// on a vessel interact with an instance of this module to add and remove heat.
///
+
public class ModuleSystemHeat : PartModule
{
// Unique name of the module on a part
@@ -31,6 +32,9 @@ public class ModuleSystemHeat : PartModule
[KSPField(isPersistant = false)]
public int priority = 1;
+ // Whether this module should be used by the heat system at all
+ public bool moduleUsed = true;
+
// -- System level data storage --
// Current total system temperature of all associated modules
[KSPField(isPersistant = true, guiActive = false, guiName = "System Temp")]
@@ -41,8 +45,6 @@ public class ModuleSystemHeat : PartModule
public float totalSystemFlux = 0f;
public float consumedSystemFlux = 0f;
-
-
public float systemNominalTemperature = 0f;
// -- Loop level data storage --
@@ -82,7 +84,8 @@ public class ModuleSystemHeat : PartModule
public HeatLoop Loop
{
- get {
+ get
+ {
if (simulator != null)
{
return simulator.Loop(currentLoopID);
@@ -165,7 +168,7 @@ public void Start()
Fields["currentLoopFlux"].guiActive = SystemHeatSettings.DebugPartUI;
Fields["currentLoopFlux"].guiActiveEditor = SystemHeatSettings.DebugPartUI;
-
+
Utils.Log("[ModuleSystemHeat]: Setup complete", LogType.Modules);
}
@@ -315,7 +318,7 @@ public float GetFlux(string id)
return fluxes.Where(x => x.Key != id).Sum(x => x.Value) * (float)(PhysicsGlobals.InternalHeatProductionFactor / 0.025d);
-
+
}
return 0f;
}
@@ -327,34 +330,85 @@ public void UpdateSimulationValues(float nominalTemp, float currentTemp, float c
currentLoopFlux = currentNetFlux;
}
- protected void FixedUpdate()
+ public void SetSystemHeatModuleEnabled(bool enabled)
{
- SystemFluxUI = String.Format("{0:F0} kW", totalSystemFlux);
- LoopTemperatureUI = String.Format("{0:F0} / {1:F0} K", currentLoopTemperature, nominalLoopTemperature);
- if (totalSystemFlux > 0f)
+ if (simulator == null)
+ FindSimulator();
+
+
+ if (enabled && !moduleUsed)
{
+ Utils.Log($"[ModuleSystemHeat] seting module {moduleID} system state from {moduleUsed} to {enabled}", LogType.Modules);
+ moduleUsed = enabled;
+ if (simulator != null)
+ simulator.AddHeatModule(this);
+
+ // turn things on
Fields["SystemTemperatureUI"].guiActive = true;
Fields["SystemTemperatureUI"].guiActiveEditor = true;
- SystemTemperatureUI = String.Format("{0:F0} K", totalSystemTemperature);
+ Fields["SystemFluxUI"].guiActive = true;
+ Fields["SystemFluxUI"].guiActiveEditor = true;
+ Fields["LoopTemperatureUI"].guiActive = true;
+ Fields["LoopTemperatureUI"].guiActiveEditor = true;
+ Fields["currentLoopID"].guiActive = true;
+ Fields["currentLoopID"].guiActiveEditor = true;
}
- else
+ if (!enabled && moduleUsed)
{
+ Utils.Log($"[ModuleSystemHeat] seting module {moduleID} system state from {moduleUsed} to {enabled}", LogType.Modules);
+ moduleUsed = enabled;
+ if (simulator != null)
+ simulator.RemoveHeatModule(this);
+
+ // turn things off
Fields["SystemTemperatureUI"].guiActive = false;
Fields["SystemTemperatureUI"].guiActiveEditor = false;
+ Fields["SystemFluxUI"].guiActive = false;
+ Fields["SystemFluxUI"].guiActiveEditor = false;
+ Fields["LoopTemperatureUI"].guiActive = false;
+ Fields["LoopTemperatureUI"].guiActiveEditor = false;
+ Fields["currentLoopID"].guiActive = false;
+ Fields["currentLoopID"].guiActiveEditor = false;
+ }
+ }
+
+ protected void FixedUpdate()
+ {
+ if (moduleUsed)
+ {
+ SystemFluxUI = String.Format("{0}W", Utils.ToSI(totalSystemFlux, "F0"));
+ LoopTemperatureUI = String.Format("{0:F0} / {1:F0} K", currentLoopTemperature, nominalLoopTemperature);
+ if (totalSystemFlux > 0f)
+ {
+ Fields["SystemTemperatureUI"].guiActive = true;
+ Fields["SystemTemperatureUI"].guiActiveEditor = true;
+ SystemTemperatureUI = String.Format("{0:F0} K", totalSystemTemperature);
+ }
+ else
+ {
+ Fields["SystemTemperatureUI"].guiActive = false;
+ Fields["SystemTemperatureUI"].guiActiveEditor = false;
+ }
}
+
if (simulator == null)
{
- if (HighLogic.LoadedSceneIsFlight)
-
- simulator = part.vessel.GetComponent().Simulator;
-
- if (HighLogic.LoadedSceneIsEditor)
-
- simulator = SystemHeatEditor.Instance.Simulator;
-
+ FindSimulator();
+
}
}
+ protected void FindSimulator()
+ {
+ if (HighLogic.LoadedSceneIsFlight)
+
+ simulator = part.vessel.GetComponent().Simulator;
+
+ if (HighLogic.LoadedSceneIsEditor)
+
+ simulator = SystemHeatEditor.Instance.Simulator;
+ }
+
}
diff --git a/SystemHeat/SystemHeat/Modules/ModuleSystemHeatAsteroidHarvester.cs b/SystemHeat/SystemHeat/Modules/ModuleSystemHeatAsteroidHarvester.cs
index 33be5c0..425a3bf 100644
--- a/SystemHeat/SystemHeat/Modules/ModuleSystemHeatAsteroidHarvester.cs
+++ b/SystemHeat/SystemHeat/Modules/ModuleSystemHeatAsteroidHarvester.cs
@@ -50,7 +50,7 @@ public override string GetInfo()
return info;
else
return info.Substring(0, pos) + Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatHarvester_PartInfoAdd",
- systemPower.ToString("F0"),
+ Utils.ToSI(systemPower,"F0"),
systemOutletTemperature.ToString("F0"),
shutdownTemperature.ToString("F0")
) + info.Substring(pos);
diff --git a/SystemHeat/SystemHeat/Modules/ModuleSystemHeatBaseConverterAdapter.cs b/SystemHeat/SystemHeat/Modules/ModuleSystemHeatBaseConverterAdapter.cs
index d995788..b13058f 100644
--- a/SystemHeat/SystemHeat/Modules/ModuleSystemHeatBaseConverterAdapter.cs
+++ b/SystemHeat/SystemHeat/Modules/ModuleSystemHeatBaseConverterAdapter.cs
@@ -28,7 +28,7 @@ public class ModuleSystemHeatBaseConverterAdapter : PartModule
///
[KSPField(isPersistant = false)]
public float systemPower = 0f;
-
+
///
/// Index of the converter module
///
@@ -54,12 +54,13 @@ public class ModuleSystemHeatBaseConverterAdapter : PartModule
public string EditConverterModuleInfo(string source)
{
- string msg = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatBaseConverterAdapter_PartInfo", systemPower.ToString("F0"),
+ string msg = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatBaseConverterAdapter_PartInfo",
+ Utils.ToSI(systemPower, "F0"),
systemOutletTemperature.ToString("F0"),
shutdownTemperature.ToString("F0"));
if (source.Contains(msg))
- return source;
+ return source;
int pos = source.IndexOf("\n\n");
if (pos < 0)
@@ -75,11 +76,11 @@ public override void OnIconCreate()
public void Start()
{
heatModule = ModuleUtils.FindHeatModule(this.part, systemHeatModuleID);
-
+
if (converterModuleIndex != -1)
{
- base.part.partInfo.moduleInfos[converterModuleIndex].info = EditConverterModuleInfo(base.part.partInfo.moduleInfos[converterModuleIndex].info);
-
+ base.part.partInfo.moduleInfos[converterModuleIndex].info = EditConverterModuleInfo(base.part.partInfo.moduleInfos[converterModuleIndex].info);
+
converterModule = base.part.Modules[converterModuleIndex] as BaseConverter;
if (converterModule == null)
{
diff --git a/SystemHeat/SystemHeat/Modules/ModuleSystemHeatConverter.cs b/SystemHeat/SystemHeat/Modules/ModuleSystemHeatConverter.cs
index 0de843f..d816aae 100644
--- a/SystemHeat/SystemHeat/Modules/ModuleSystemHeatConverter.cs
+++ b/SystemHeat/SystemHeat/Modules/ModuleSystemHeatConverter.cs
@@ -65,7 +65,7 @@ public override string GetInfo()
return info;
else
return info.Substring(0, pos) + Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatConverter_PartInfoAdd",
- systemPower.ToString("F0"),
+ Utils.ToSI(systemPower,"F0"),
systemOutletTemperature.ToString("F0"),
shutdownTemperature.ToString("F0")
) + info.Substring(pos);
diff --git a/SystemHeat/SystemHeat/Modules/ModuleSystemHeatCryoTank.cs b/SystemHeat/SystemHeat/Modules/ModuleSystemHeatCryoTank.cs
new file mode 100644
index 0000000..007e098
--- /dev/null
+++ b/SystemHeat/SystemHeat/Modules/ModuleSystemHeatCryoTank.cs
@@ -0,0 +1,872 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using UnityEngine;
+using KSP.Localization;
+
+namespace SystemHeat
+{
+ public class ModuleSystemHeatCryoTank : PartModule
+ {
+
+ // Module ID
+ [KSPField(isPersistant = false)]
+ public string moduleID = "CryoModule";
+
+ // SYSTEM HEAT FIELDS
+ // This should correspond to the related ModuleSystemHeat
+ [KSPField(isPersistant = false)]
+ public string systemHeatModuleID;
+
+ // the current thermal cost to cool the tank
+ [KSPField(isPersistant = false)]
+ public double currentHeatGeneration = 0.0;
+
+ // UI Fields
+
+ /// Cost to cool off u/s per 1000 u
+ [KSPField(isPersistant = false)]
+ public float CoolingHeatCost = 0.0f;
+
+ // The current heat cost to cool the tank
+ [KSPField(isPersistant = false)]
+ public double currentCoolingHeatCost = 0.0;
+
+
+ // Last timestamp that boiloff occurred
+ [KSPField(isPersistant = true)]
+ public double LastUpdateTime = 0;
+
+ // Whether active tank refrigeration is allowed on the part
+ [KSPField(isPersistant = true)]
+ public bool CoolingAllowed = true;
+
+ // Whether active tank refrigeration is occurring on the part
+ [KSPField(isPersistant = true)]
+ public bool CoolingEnabled = true;
+
+ // Whether the tank is CURRENTLY cooled or not
+ [KSPField(isPersistant = true)]
+ public bool BoiloffOccuring = false;
+
+ // Special Heat-based-cooling parameters
+ // Does longwave (energy emitted by planets) affect boiloff?
+ [KSPField(isPersistant = false)]
+ public bool LongwaveFluxAffectsBoiloff = false;
+
+ // Does shortwave (energy emitted by solar sources) affect boiloff?
+ [KSPField(isPersistant = false)]
+ public bool ShortwaveFluxAffectsBoiloff = false;
+
+ // Percent of solar energy reflected
+ [KSPField(isPersistant = false)]
+ public float Albedo = 0.5f;
+
+ // The baseline solar flux (measured at Kerbin)
+ [KSPField(isPersistant = false)]
+ public float ShortwaveFluxBaseline = 0.7047f;
+
+ // The baseline planetary flux (measured at Kerbin)
+ [KSPField(isPersistant = false)]
+ public float LongwaveFluxBaseline = 0.1231f;
+
+ // The mimum scaling for boiloff
+ [KSPField(isPersistant = false)]
+ public double MinimumBoiloffScale = 0.1f;
+
+ // The maximum scaling for boiloff
+ [KSPField(isPersistant = false)]
+ public double MaximumBoiloffScale = 5f;
+
+ // How much to scale cooling if this module has been jettisioned
+ [KSPField(isPersistant = false)]
+ public double JettisonCoolingScale = 1d;
+
+ // How much to scale boiloff if this module has been jettisioned
+ [KSPField(isPersistant = false)]
+ public double JettisonBoiloffScale = 1d;
+
+ ///
+ /// Indicates whether there are any boilable resources currently on the part
+ ///
+ public bool HasAnyBoiloffResource { get; private set; } = false;
+
+ // PRIVATE
+ private double finalCoolingHeatCost = 0.0;
+ private List fuels;
+
+ private double fuelAmount = 0.0;
+ private double maxFuelAmount = 0.0;
+
+ // Thermal
+ private double solarFlux = 1.0;
+ private double planetFlux = 1.0;
+ private double fluxScale = 1.0;
+
+ protected ModuleSystemHeat heatModule;
+ protected PartModule jettisonModule;
+ protected bool isJettisoned = false;
+ // UI FIELDS/ BUTTONS
+ // Status string
+ [KSPField(isPersistant = false, guiActive = true, guiName = "#LOC_SystemHeat_ModuleSystemHeatCryoTank_Field_BoiloffStatus", groupName = "cryotank", groupDisplayName = "#LOC_SystemHeat_ModuleSystemHeatCryoTank_UIGroup_Title")]
+ public string BoiloffStatus = "N/A";
+
+ [KSPField(isPersistant = false, guiActive = false, guiName = "#LOC_SystemHeat_ModuleSystemHeatCryoTank_Field_CoolingStatus", groupName = "cryotank", groupDisplayName = "#LOC_SystemHeat_ModuleSystemHeatCryoTank_UIGroup_Title")]
+ public string CoolingStatus = "N/A";
+
+ [KSPEvent(guiActive = false, guiName = "#LOC_SystemHeat_ModuleSystemHeatCryoTank_Event_Enable", active = true, groupName = "cryotank", groupDisplayName = "#LOC_SystemHeat_ModuleSystemHeatCryoTank_UIGroup_Title")]
+ public void Enable()
+ {
+ CoolingEnabled = true;
+ }
+ [KSPEvent(guiActive = false, guiName = "#LOC_SystemHeat_ModuleSystemHeatCryoTank_Event_Disable", active = false, groupName = "cryotank", groupDisplayName = "#LOC_SystemHeat_ModuleSystemHeatCryoTank_UIGroup_Title")]
+ public void Disable()
+ {
+ CoolingEnabled = false;
+ }
+
+ // DEBUG FIELDS
+
+ [KSPField(isPersistant = true)]
+ public bool DebugMode = false;
+
+ [KSPField(isPersistant = false, guiActive = false, guiName = "Albedo")]
+ public string D_Albedo = "N/A";
+
+ [KSPField(isPersistant = false, guiActive = false, guiName = "Emissivity")]
+ public string D_Emiss = "N/A";
+
+ [KSPField(isPersistant = false, guiActive = false, guiName = "SW_In(kW)")]
+ public string D_InSolar = "N/A";
+
+ [KSPField(isPersistant = false, guiActive = false, guiName = "LW_In(kW)")]
+ public string D_InPlanet = "N/A";
+
+ [KSPField(isPersistant = false, guiActive = false, guiName = "NetRad_In(kW)")]
+ public string D_NetRad = "N/A";
+
+ // ACTIONS
+ [KSPAction(guiName = "#LOC_SystemHeat_ModuleSystemHeatCryoTank_Action_EnableAction")]
+ public void EnableAction(KSPActionParam param) { Enable(); }
+
+ [KSPAction(guiName = "#LOC_SystemHeat_ModuleSystemHeatCryoTank_Action_DisableAction")]
+ public void DisableAction(KSPActionParam param) { Disable(); }
+
+ [KSPAction(guiName = "#LOC_SystemHeat_ModuleSystemHeatCryoTank_Action_ToggleAction")]
+ public void ToggleAction(KSPActionParam param)
+ {
+ CoolingEnabled = !CoolingEnabled;
+ }
+
+
+ public override string GetModuleDisplayName()
+ {
+ return Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatCryoTank_ModuleName");
+ }
+ ///
+ /// BUilds the loc string
+ ///
+ ///
+ public override string GetInfo()
+ {
+ string msg;
+ string fuelDisplayName;
+ if (IsConfiguredAsCoolable())
+ {
+ string sub = "";
+ float baseCooling = CoolingHeatCost;
+ foreach (BoiloffFuel fuel in fuels)
+ {
+ fuelDisplayName = PartResourceLibrary.Instance.GetDefinition(fuel.fuelName).displayName;
+ sub += Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatCryoTank_PartInfoBoiloff",
+ fuelDisplayName,
+ (fuel.boiloffRate).ToString("F2"),
+ (baseCooling + fuel.coolingHeatCost).ToString("F2"),
+ fuel.cryoTemperature
+ );
+ if (fuel.outputs.Count > 0)
+ {
+ foreach (ResourceRatio output in fuel.outputs)
+ {
+ string outputDisplayName = PartResourceLibrary.Instance.GetDefinition(output.ResourceName).displayName;
+ sub += Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatCryoTank_PartInfoBoiloffOutput",
+ outputDisplayName,
+ (fuel.boiloffRate * output.Ratio).ToString("F2"));
+ }
+ }
+ }
+ msg = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatCryoTank_PartInfoCooled", sub);
+ }
+ else
+ {
+ msg = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatCryoTank_PartInfoUncooled");
+ foreach (BoiloffFuel fuel in fuels)
+ {
+ fuelDisplayName = PartResourceLibrary.Instance.GetDefinition(fuel.fuelName).displayName;
+ msg += Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatCryoTank_PartInfoBoiloff", fuelDisplayName, (fuel.boiloffRate).ToString("F2"));
+ if (fuel.outputs.Count > 0)
+ {
+ foreach (ResourceRatio output in fuel.outputs)
+ {
+ string outputDisplayName = PartResourceLibrary.Instance.GetDefinition(output.ResourceName).displayName;
+ msg += Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatCryoTank_PartInfoBoiloffOutput",
+ outputDisplayName,
+ (fuel.boiloffRate * output.Ratio).ToString("F2"));
+ }
+ }
+ }
+ }
+ return msg;
+ }
+
+
+ public void Start()
+ {
+
+ heatModule = ModuleUtils.FindHeatModule(this.part, systemHeatModuleID);
+
+ jettisonModule = part.Modules.GetModule("ModuleBdbJettison");
+
+ if (jettisonModule != null)
+ Utils.Log($"Found {jettisonModule.GUIName} on {part.partInfo.title}");
+
+ if (HighLogic.LoadedSceneIsFlight || HighLogic.LoadedSceneIsEditor)
+ {
+ ReloadDatabaseNodes();
+ SetDebugMode(DebugMode);
+ }
+
+ if (HighLogic.LoadedSceneIsFlight)
+ {
+ /// Check to see if there's any boiloff resources on this part
+ HasAnyBoiloffResource = false;
+ foreach (BoiloffFuel fuel in fuels)
+ {
+ if (IsPartResourcePresent(fuel.fuelName, part))
+ {
+ HasAnyBoiloffResource = true;
+ fuel.Initialize();
+ }
+ else
+ {
+ fuel.fuelPresent = false;
+ }
+ }
+ /// if no resources turn off the UI and return
+ if (!HasAnyBoiloffResource)
+ {
+ Events["Disable"].guiActive = false;
+ Events["Enable"].guiActive = false;
+ Fields["BoiloffStatus"].guiActive = false;
+ heatModule.SetSystemHeatModuleEnabled(false);
+ return;
+ }
+
+ maxFuelAmount = GetTotalMaxResouceAmount();
+
+ planetFlux = LongwaveFluxBaseline;
+ solarFlux = ShortwaveFluxBaseline;
+
+ if (GetTotalCoolingCost() > 0.0)
+ {
+ finalCoolingHeatCost = maxFuelAmount / 1000.0 * GetTotalCoolingCost();
+ Events["Disable"].guiActive = true;
+ Events["Enable"].guiActive = true;
+ Events["Enable"].guiActiveEditor = true;
+ Events["Disable"].guiActiveEditor = true;
+ heatModule.SetSystemHeatModuleEnabled(true);
+ }
+ else
+ {
+ heatModule.SetSystemHeatModuleEnabled(false);
+ }
+ // Catchup
+ DoCatchup();
+ }
+ Utils.Log("[ModuleSystemHeatCryoTank] Setup completed", LogType.Modules);
+ }
+
+ ///
+ /// Sets the UI debug fields to active
+ ///
+ ///
+ void SetDebugMode(bool debug)
+ {
+
+ Fields["D_NetRad"].guiActive = debug;
+ Fields["D_InSolar"].guiActive = debug;
+ Fields["D_InPlanet"].guiActive = debug;
+ Fields["D_InPlanet"].guiActive = debug;
+ Fields["D_Albedo"].guiActive = debug;
+ Fields["D_Emiss"].guiActive = debug;
+
+ }
+ void ReloadDatabaseNodes()
+ {
+ if (fuels == null || fuels.Count == 0)
+ {
+ Utils.Log(String.Format("[ModuleSystemHeatCryoTank] Reloading ConfigNodes for {0}", part.partInfo.name), LogType.Modules);
+
+ ConfigNode cfg;
+ foreach (UrlDir.UrlConfig pNode in GameDatabase.Instance.GetConfigs("PART"))
+ {
+ if (pNode.name.Replace("_", ".") == part.partInfo.name)
+ {
+ List cryoNodes = pNode.config.GetNodes("MODULE").ToList().FindAll(n => n.GetValue("name") == moduleName);
+ if (cryoNodes.Count > 1)
+ {
+ try
+ {
+ ConfigNode node = cryoNodes.Single(n => n.GetValue("moduleID") == moduleID);
+ OnLoad(node);
+ }
+ catch (InvalidOperationException)
+ {
+ // Thrown if predicate is not fulfilled, ie moduleName is not unqiue
+ Utils.Log(String.Format("[ModuleSystemHeatCryoTank] Critical configuration error: Multiple ModuleCryoTank nodes found with identical or no moduleName"), LogType.Modules);
+ }
+ catch (ArgumentNullException)
+ {
+
+ // Thrown if ModuleCryoTank is not found (a Large Problem (tm))
+ Utils.Log(String.Format("[ModuleSystemHeatCryoTank] Critical configuration error: No ModuleCryoTank nodes found in part"), LogType.Modules);
+ }
+ }
+ else
+ {
+ OnLoad(cryoNodes[0]);
+ }
+ }
+ }
+ }
+ }
+
+ ///
+ /// Loads data from config node
+ ///
+ ///
+ public override void OnLoad(ConfigNode node)
+ {
+ base.OnLoad(node);
+
+ ConfigNode[] varNodes = node.GetNodes("BOILOFFCONFIG");
+
+ if (fuels == null)
+ fuels = new List();
+ if (varNodes.Length > 0)
+ {
+
+ for (int i = 0; i < varNodes.Length; i++)
+ {
+ fuels.Add(new BoiloffFuel(varNodes[i], this.part));
+ }
+ }
+ }
+
+ ///
+ /// Execute a boiloff catchup operation, which looks at elapsed time to see how long we've been away and subtracts
+ /// resources appropriately
+ ///
+ public void DoCatchup()
+ {
+ if (part.vessel.missionTime > 0.0)
+ {
+ if (BoiloffOccuring)
+ {
+ double elapsedTime = Planetarium.GetUniversalTime() - LastUpdateTime;
+ if (elapsedTime > 0d)
+ {
+
+ Utils.Log($"[ModuleSystemHeatCryoTank] Catching up {elapsedTime} s of time on load", LogType.Modules);
+ for (int i = 0; i < fuels.Count; i++)
+ {
+ fuels[i].Boiloff(elapsedTime, 1.0);
+ }
+ }
+ }
+ }
+ }
+
+ public void Update()
+ {
+ if (HighLogic.LoadedSceneIsFlight && HasAnyBoiloffResource)
+ {
+ /// Show the insulation status field if there is a cooling cost
+ if (IsCoolable())
+ {
+ Fields["CoolingStatus"].guiActive = true;
+ Fields["BoiloffStatus"].guiActive = true;
+
+
+ if (Events["Enable"].active == CoolingEnabled || Events["Disable"].active != CoolingEnabled)
+ {
+ Events["Disable"].active = CoolingEnabled;
+ Events["Enable"].active = !CoolingEnabled;
+ }
+
+ heatModule.SetSystemHeatModuleEnabled(true);
+ }
+ else
+ {
+ Fields["CoolingStatus"].guiActive = false;
+ Events["Disable"].active = false;
+ Events["Enable"].active = false;
+
+ heatModule.SetSystemHeatModuleEnabled(false);
+ }
+
+ /// if there is no more fuel, hide the boiloff status
+ if (fuelAmount == 0.0)
+ {
+ Fields["BoiloffStatus"].guiActive = false;
+ heatModule.SetSystemHeatModuleEnabled(false);
+ }
+ }
+ else if (HighLogic.LoadedSceneIsEditor)
+ {
+ /// Check for the presence of any resource
+ HasAnyBoiloffResource = false;
+ foreach (BoiloffFuel fuel in fuels)
+ {
+ if (IsPartResourcePresent(fuel.fuelName, part))
+ {
+ HasAnyBoiloffResource = true;
+ fuel.Initialize();
+ }
+ else
+ {
+ fuel.fuelPresent = false;
+ }
+ }
+
+ if (IsCoolable() && HasAnyBoiloffResource)
+ {
+ Fields["CoolingStatus"].guiActiveEditor = true;
+ Fields["CoolingStatus"].guiActiveEditor = true;
+
+ double max = GetTotalMaxResouceAmount();
+
+ CoolingStatus = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatCryoTank_Field_CoolingStatus_Editor", (GetTotalCoolingCost() * (float)(max / 1000.0)).ToString("F2"));
+
+ Events["Disable"].guiActiveEditor = true;
+ Events["Enable"].guiActiveEditor = true;
+
+ if (Events["Enable"].active == CoolingEnabled || Events["Disable"].active != CoolingEnabled)
+ {
+ Events["Disable"].active = CoolingEnabled;
+ Events["Enable"].active = !CoolingEnabled;
+ }
+ heatModule.SetSystemHeatModuleEnabled(true);
+ }
+ else
+ {
+ Fields["CoolingStatus"].guiActiveEditor = false;
+ Events["Disable"].guiActiveEditor = false;
+ Events["Enable"].guiActiveEditor = false;
+ heatModule.SetSystemHeatModuleEnabled(false);
+ }
+ }
+ }
+
+ protected void ClearHeat()
+ {
+ heatModule.AddFlux(moduleID, 0f, 0f, false);
+ }
+
+ protected void FixedUpdate()
+ {
+
+ if (HighLogic.LoadedSceneIsFlight && HasAnyBoiloffResource)
+ {
+ if (jettisonModule != null && bool.Parse(jettisonModule.Fields.GetValue("isJettisoned").ToString()))
+ isJettisoned = true;
+ else
+ isJettisoned = false;
+ fluxScale = CalculateRadiativeEffects();
+ fuelAmount = GetTotalResouceAmount();
+
+ // If we have no fuel, no need to do any calculations
+ if (fuelAmount == 0.0)
+ {
+ BoiloffStatus = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatCryoTank_Field_BoiloffStatus_NoFuel");
+ CoolingStatus = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatCryoTank_Field_CoolingStatus_NoFuel");
+ currentCoolingHeatCost = 0.0;
+ ClearHeat();
+ return;
+ }
+
+
+ // If the tank is not coolable we must boil off
+ if (!IsCoolable())
+ {
+ BoiloffOccuring = true;
+ BoiloffStatus = FormatRate(GetTotalBoiloffRate() * fuelAmount * fluxScale);
+ currentCoolingHeatCost = 0.0;
+ ClearHeat();
+ }
+ // else check cooling state
+ else
+ {
+ if (!CoolingEnabled)
+ {
+ BoiloffOccuring = true;
+ BoiloffStatus = FormatRate(GetTotalBoiloffRate() * fuelAmount * fluxScale);
+ CoolingStatus = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatCryoTank_Field_CoolingStatus_Disabled");
+ currentCoolingHeatCost = 0.0;
+ ClearHeat();
+ }
+ else
+ {
+ BoiloffOccuring = ResolveHeat();
+ currentCoolingHeatCost = finalCoolingHeatCost;
+ }
+ }
+
+ if (BoiloffOccuring)
+ {
+ DoBoiloff();
+ }
+ if (part.vessel.missionTime > 0.0)
+ {
+
+ }
+ }
+ if (HighLogic.LoadedSceneIsFlight && DebugMode)
+ {
+ D_Albedo = String.Format("{0:F4}", Albedo);
+ D_Emiss = String.Format("{0:F4}", part.emissiveConstant);
+ D_InPlanet = String.Format("{0:F4}", planetFlux);
+ D_InSolar = String.Format("{0:F4}", solarFlux * Albedo);
+ D_NetRad = String.Format("{0:F4}", fluxScale);
+ }
+ if (HighLogic.LoadedSceneIsEditor && HasAnyBoiloffResource)
+ {
+ if (jettisonModule != null && bool.Parse(jettisonModule.Fields.GetValue("isJettisoned").ToString()))
+ isJettisoned = true;
+ else
+ isJettisoned = false;
+
+ if (!IsCoolable())
+ {
+
+
+ currentCoolingHeatCost = 0.0;
+ ClearHeat();
+ }
+ else
+ {
+ if (CoolingEnabled)
+ {
+ if (GetTotalCoolingCost() > 0.0)
+ {
+
+ currentCoolingHeatCost = GetTotalCoolingCost() * GetTotalMaxResouceAmount() / 1000d;
+ if (isJettisoned)
+ currentCoolingHeatCost *= JettisonCoolingScale;
+
+ heatModule.AddFlux(moduleID, GetSourceTemperature(), (float)currentCoolingHeatCost, true);
+ }
+ else
+ {
+ currentCoolingHeatCost = 0.0;
+ ClearHeat();
+ }
+ }
+ else
+ {
+ currentCoolingHeatCost = 0.0;
+ ClearHeat();
+ }
+ }
+ }
+ }
+
+ ///
+ /// Calcualates boiloff scaling by radiation
+ ///
+ /// Scaling factor for boiloff depending on radiation
+ protected double CalculateRadiativeEffects()
+ {
+ if (part.ptd != null)
+ {
+ if (LongwaveFluxAffectsBoiloff)
+ planetFlux = part.ptd.bodyFlux;
+
+ if (ShortwaveFluxAffectsBoiloff)
+ solarFlux = part.ptd.sunFlux / part.emissiveConstant;
+ }
+
+ if (ShortwaveFluxAffectsBoiloff || LongwaveFluxAffectsBoiloff)
+ {
+ fluxScale = Math.Max((planetFlux / LongwaveFluxBaseline + (solarFlux * Albedo) / ShortwaveFluxBaseline) / 2.0f, MinimumBoiloffScale);
+ }
+ else
+ {
+ fluxScale = 1.0;
+ }
+ return fluxScale;
+ }
+
+ ///
+ /// Sets the boiloff state
+ ///
+ /// Whether boiloff is occuring or not
+ /// The total cost of the boiloff
+ public double SetBoiloffState(bool isBoiling)
+ {
+ if (CoolingEnabled && IsCoolable())
+ {
+ if (isBoiling)
+ {
+ BoiloffOccuring = true;
+ BoiloffStatus = FormatRate(GetTotalBoiloffRate() * fuelAmount * fluxScale);
+ CoolingStatus = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatCryoTank_Field_CoolingStatus_Uncooled");
+ }
+ else
+ {
+
+ BoiloffOccuring = false;
+ BoiloffStatus = String.Format("Insulated");
+ CoolingStatus = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatCryoTank_Field_CoolingStatus_Cooling", finalCoolingHeatCost.ToString("F2"));
+
+ }
+ return (double)finalCoolingHeatCost;
+ }
+ return 0d;
+ }
+ public override void OnSave(ConfigNode node)
+ {
+ LastUpdateTime = Planetarium.GetUniversalTime();
+ base.OnSave(node);
+ }
+
+ ///
+ /// Adds heat and evaluates whether boiloff should be happening
+ ///
+ ///
+ public bool ResolveHeat()
+ {
+ bool boiloff = false;
+ if (CoolingEnabled && IsCoolable())
+ {
+
+ if (isJettisoned)
+ heatModule.AddFlux(moduleID, GetSourceTemperature(), (float)(finalCoolingHeatCost * JettisonCoolingScale), true);
+ else
+ heatModule.AddFlux(moduleID, GetSourceTemperature(), (float)finalCoolingHeatCost, true);
+
+ if (heatModule.LoopTemperature <= GetMaxSourceTemperature())
+ {
+ boiloff = false;
+ BoiloffStatus = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatCryoTank_Field_BoiloffStatus_Insulated");
+ CoolingStatus = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatCryoTank_Field_CoolingStatus_Cooling", finalCoolingHeatCost.ToString("F2"));
+ }
+ else
+ {
+ boiloff = true;
+ BoiloffStatus = FormatRate(GetTotalBoiloffRate() * fuelAmount * fluxScale);
+ CoolingStatus = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatCryoTank_Field_CoolingStatus_Uncooled");
+ }
+ }
+ return boiloff;
+ }
+
+
+ ///
+ /// Iteractes through the fuels and applies boiloff
+ ///
+ protected void DoBoiloff()
+ {
+ double boiloffScale = fluxScale;
+
+ if (isJettisoned)
+ boiloffScale *= JettisonBoiloffScale;
+
+ // Apply settings stuff
+ if (!SystemHeatGameSettings_Boiloff.BoiloffEnabled)
+ {
+ boiloffScale = 0f;
+ }
+ else
+ {
+ boiloffScale *= SystemHeatGameSettings_Boiloff.BoiloffScale;
+ }
+
+ for (int i = 0; i < fuels.Count; i++)
+ {
+
+ if (!CoolingEnabled)
+ {
+ fuels[i].Boiloff(TimeWarp.fixedDeltaTime, boiloffScale);
+ }
+ else
+ {
+ if (heatModule.LoopTemperature > fuels[i].cryoTemperature)
+ {
+ fuels[i].Boiloff(TimeWarp.fixedDeltaTime, boiloffScale);
+ }
+ }
+ }
+ }
+
+
+
+ ///
+ /// Get the total fuel amount of the tank (sum of all boilable fuels)
+ ///
+ /// Total fuel
+ protected double GetTotalResouceAmount()
+ {
+ double max = 0d;
+ for (int i = 0; i < fuels.Count; i++)
+ max += fuels[i].FuelAmount();
+ return max;
+ }
+
+ ///
+ /// Gets the total fuel maximum of the part (sum of all boilable fuels)
+ ///
+ /// Total max fuel
+ protected double GetTotalMaxResouceAmount()
+ {
+ double max = 0d;
+ for (int i = 0; i < fuels.Count; i++)
+ max += fuels[i].FuelAmountMax();
+ return max;
+ }
+
+ ///
+ /// Returns the total amount of fuel (units) boiling off per second
+ ///
+ /// Total fuel boiloff per second
+ protected double GetTotalBoiloffRate()
+ {
+ double max = 0d;
+ for (int i = 0; i < fuels.Count; i++)
+ {
+
+ if (!CoolingEnabled && CoolingAllowed)
+ max += fuels[i].boiloffRateSeconds;
+ else if (heatModule.LoopTemperature >= fuels[i].cryoTemperature)
+ max += fuels[i].boiloffRateSeconds;
+
+ if (isJettisoned)
+ max *= JettisonBoiloffScale;
+ }
+ return max;
+ }
+
+ ///
+ /// Returns the total cooling cost per 1000 units of the tank (Base + added by fuels)
+ ///
+ /// Cooling cost, per 1000 units
+ protected float GetTotalCoolingCost()
+ {
+ float total = CoolingHeatCost;
+ for (int i = 0; i < fuels.Count; i++)
+ total += fuels[i].FuelCoolingHeatCost();
+ return total;
+ }
+
+
+ ///
+ /// Returns the source temperature of the module, which is the lowest temperature of all boiloff fuels on the part
+ ///
+ /// source temperature
+ protected float GetSourceTemperature()
+ {
+ float min = 2000f;
+ for (int i = 0; i < fuels.Count; i++)
+ {
+ float temp = fuels[i].FuelCryocoolerTemperature();
+ if (temp < min && temp > 0f)
+ min = temp;
+ }
+ return min;
+ }
+ protected float GetMaxSourceTemperature()
+ {
+ float max = 0;
+ for (int i = 0; i < fuels.Count; i++)
+ {
+ float temp = fuels[i].FuelCryocoolerTemperature();
+ if (temp > max)
+ max = temp;
+ }
+ return max;
+ }
+ ///
+ /// Determines if the tank is currently coolable (ie, can create waste heat to stop boiloff)
+ ///
+ /// True if the tank can be cooled
+ protected bool IsCoolable()
+ {
+ if (!CoolingAllowed)
+ return false;
+
+ for (int i = 0; i < fuels.Count; i++)
+ {
+ if (fuels[i].FuelCoolingHeatCost() > 0.0f)
+ return true;
+ }
+ if (CoolingHeatCost > 0.0f)
+ return true;
+
+ return false;
+ }
+
+ ///
+ /// Determines if the tank is currently coolable (ie, can generate heat to stop boiloff)
+ ///
+ /// True if the tank can be cooled
+ protected bool IsConfiguredAsCoolable()
+ {
+ if (!CoolingAllowed)
+ return false;
+
+ for (int i = 0; i < fuels.Count; i++)
+ {
+ if (fuels[i].FuelConfiguredCoolingHeatCost() > 0.0f)
+ return true;
+ }
+ if (CoolingHeatCost > 0.0f)
+ return true;
+
+ return false;
+ }
+
+
+ ///
+ /// Produces a friendly string describing boiloff rate
+ ///
+ /// The rate in seconds to format
+ /// String describing rate
+ public string FormatRate(double rate)
+ {
+ double adjRate = rate;
+ string interval = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatCryoTank_TimeInterval_Second_Abbrev");
+ if (adjRate < 0.01)
+ {
+ adjRate = adjRate * 60.0;
+ interval = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatCryoTank_TimeInterval_Minute_Abbrev");
+ }
+ if (adjRate < 0.01)
+ {
+ adjRate = adjRate * 60.0;
+ interval = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatCryoTank_TimeInterval_Hour_Abbrev");
+ }
+ return Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatCryoTank_Field_BoiloffStatus_Boiloff", adjRate.ToString("F2"), interval.ToString());
+ }
+
+ public bool IsPartResourcePresent(string resourceName, Part p)
+ {
+ if (!SystemHeatGameSettings_Boiloff.BoiloffEnabled) return false;
+ int id = PartResourceLibrary.Instance.GetDefinition(resourceName).id;
+ PartResource res = p.Resources.Get(id);
+ if (res == null)
+ return false;
+ return true;
+ }
+ }
+}
diff --git a/SystemHeat/SystemHeat/Modules/ModuleSystemHeatEngine.cs b/SystemHeat/SystemHeat/Modules/ModuleSystemHeatEngine.cs
index b58a60b..36d3dd2 100644
--- a/SystemHeat/SystemHeat/Modules/ModuleSystemHeatEngine.cs
+++ b/SystemHeat/SystemHeat/Modules/ModuleSystemHeatEngine.cs
@@ -66,7 +66,7 @@ public override string GetInfo()
string msg = "";
ModuleEnginesFX[] engines = part.GetComponents();
msg += Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatEngine_PartInfo",
- systemPower.ToString("F0"),
+ Utils.ToSI(systemPower,"F0"),
systemOutletTemperature.ToString("F0"),
temperatureCurve.Curve.keys[temperatureCurve.Curve.keys.Length - 1].time.ToString("F0")
);
@@ -125,12 +125,14 @@ protected void GenerateHeatEditor()
Fields["systemHeatGeneration"].guiActiveEditor = true;
Fields["systemTemperature"].guiActiveEditor = true;
heatModule.AddFlux(moduleID, systemOutletTemperature, engineFraction * systemPower, true);
- systemHeatGeneration = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatEngine_Field_HeatGeneration_Running", (engineFraction * systemPower).ToString("F0"));
+ systemHeatGeneration = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatEngine_Field_HeatGeneration_Running",
+ Utils.ToSI((engineFraction * systemPower),"F0"));
}
else
{
- systemHeatGeneration = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatEngine_Field_HeatGeneration_Running", (engineFraction * systemPower).ToString("F0"));
+ systemHeatGeneration = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatEngine_Field_HeatGeneration_Running",
+ Utils.ToSI((engineFraction * systemPower),"F0"));
heatModule.AddFlux(moduleID, 0f, engineFraction * systemPower, false);
Fields["systemHeatGeneration"].guiActiveEditor = false;
Fields["systemTemperature"].guiActiveEditor = false;
@@ -144,7 +146,8 @@ protected void GenerateHeatEditor()
Fields["systemHeatGeneration"].guiActiveEditor = true;
Fields["systemTemperature"].guiActiveEditor = true;
heatModule.AddFlux(moduleID, systemOutletTemperature, engineFraction * systemPower, true);
- systemHeatGeneration = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatEngine_Field_HeatGeneration_Running", (engineFraction * systemPower).ToString("F0"));
+ systemHeatGeneration = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatEngine_Field_HeatGeneration_Running",
+ Utils.ToSI((engineFraction * systemPower), "F0"));
}
}
@@ -162,7 +165,8 @@ protected void GenerateHeatFlight()
heatModule.AddFlux(moduleID, systemOutletTemperature, engineFraction * systemPower, true);
Fields["systemHeatGeneration"].guiActive = true;
Fields["systemTemperature"].guiActive = true;
- systemHeatGeneration = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatEngine_Field_HeatGeneration_Running", (engineFraction * systemPower).ToString("F0"));
+ systemHeatGeneration = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatEngine_Field_HeatGeneration_Running",
+ Utils.ToSI((engineFraction * systemPower),"F0"));
systemTemperature = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatEngine_Field_Temperature_Running", heatModule.currentLoopTemperature.ToString("F0"), systemOutletTemperature.ToString("F0"));
}
else
@@ -170,7 +174,8 @@ protected void GenerateHeatFlight()
heatModule.AddFlux(moduleID, 0f, 0f, false);
Fields["systemHeatGeneration"].guiActive = false;
Fields["systemTemperature"].guiActive = false;
- systemHeatGeneration = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatEngine_Field_HeatGeneration_Running", (engineFraction * systemPower).ToString("F0"));
+ systemHeatGeneration = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatEngine_Field_HeatGeneration_Running",
+ Utils.ToSI((engineFraction * systemPower),"F0"));
systemTemperature = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatEngine_Field_Temperature_Running", heatModule.currentLoopTemperature.ToString("F0"), systemOutletTemperature.ToString("F0"));
}
diff --git a/SystemHeat/SystemHeat/Modules/ModuleSystemHeatExchanger.cs b/SystemHeat/SystemHeat/Modules/ModuleSystemHeatExchanger.cs
index c94b55f..4e23079 100644
--- a/SystemHeat/SystemHeat/Modules/ModuleSystemHeatExchanger.cs
+++ b/SystemHeat/SystemHeat/Modules/ModuleSystemHeatExchanger.cs
@@ -126,10 +126,11 @@ public override string GetModuleDisplayName()
public override string GetInfo()
{
string msg = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatExchanger_PartInfo",
- 0f.ToString("F0"), temperatureDeltaCostCurve.Evaluate(0f).ToString("F0"),
+ 0f.ToString("F0"),
+ temperatureDeltaCostCurve.Evaluate(0f).ToString("F0"),
1000f.ToString("F0"), temperatureDeltaCostCurve.Evaluate(1000f).ToString("F0"),
- temperatureDeltaHeatCurve.Evaluate(0).ToString("F0"),
- temperatureDeltaHeatCurve.Evaluate(1000f).ToString("F0")
+ Utils.ToSI(temperatureDeltaHeatCurve.Evaluate(0), "F0"),
+ Utils.ToSI(temperatureDeltaHeatCurve.Evaluate(1000f), "F0")
);
return msg;
@@ -147,7 +148,7 @@ public void Start()
{
sourceModule = heatModule1;
destModule = heatModule2;
-
+
}
else
{
@@ -214,7 +215,7 @@ public void FixedUpdate()
private void ToggleDirection(BaseField field, object oldFieldValueObj)
{
- DoToggleDirection();
+ DoToggleDirection();
}
private void DoToggleDirection()
@@ -268,7 +269,10 @@ protected void GenerateHeatEditor()
outputHeat = Mathf.Min(-sourceModule.consumedSystemFlux, HeatRate) + temperatureDeltaHeatCurve.Evaluate(OutletAdjustement);
PowerStatus = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatExchanger_Field_PowerCost_Active", powerCost.ToString("F0"));
- Status = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatExchanger_Field_Status_Active", outletTemperature.ToString("F0"), outputHeat.ToString("F0"), sourceModule.consumedSystemFlux.ToString("F1"));
+ Status = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatExchanger_Field_Status_Active",
+ outletTemperature.ToString("F0"),
+ Utils.ToSI(outputHeat, "F0"),
+ Utils.ToSI(sourceModule.consumedSystemFlux, "F0"));
destModule.AddFlux(moduleID, outletTemperature, outputHeat, true);
}
else
@@ -324,7 +328,9 @@ protected void GenerateHeatFlight()
outputHeat = Mathf.Min(-sourceModule.consumedSystemFlux, HeatRate) + temperatureDeltaHeatCurve.Evaluate(OutletAdjustement);
PowerStatus = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatExchanger_Field_PowerCost_Active", powerCost.ToString("F1"));
- Status = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatExchanger_Field_Status_Active", outletTemperature.ToString("F0"), outputHeat.ToString("F0"));
+ Status = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatExchanger_Field_Status_Active",
+ outletTemperature.ToString("F0"),
+ Utils.ToSI(outputHeat, "F0"));
destModule.AddFlux(moduleID, outletTemperature, outputHeat, true);
}
else
diff --git a/SystemHeat/SystemHeat/Modules/ModuleSystemHeatFissionEngine.cs b/SystemHeat/SystemHeat/Modules/ModuleSystemHeatFissionEngine.cs
index 553ce5e..f9fc1a3 100644
--- a/SystemHeat/SystemHeat/Modules/ModuleSystemHeatFissionEngine.cs
+++ b/SystemHeat/SystemHeat/Modules/ModuleSystemHeatFissionEngine.cs
@@ -68,7 +68,7 @@ public override string GetInfo()
Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatFissionEngine_PartInfo",
ElectricalGeneration.Evaluate(100f).ToString("F0"),
FindTimeRemaining(this.part.Resources.Get(PartResourceLibrary.Instance.GetDefinition(FuelName).id).amount, baseRate),
- (HeatGeneration.Evaluate(100f) - ElectricalGeneration.Evaluate(100f)).ToString("F0"),
+ Utils.ToSI((HeatGeneration.Evaluate(100f) - ElectricalGeneration.Evaluate(100f)), "F0"),
NominalTemperature.ToString("F0"),
NominalTemperature.ToString("F0"),
CriticalTemperature.ToString("F0"),
@@ -79,7 +79,7 @@ public override string GetInfo()
return
Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatFissionEngine_PartInfo_NoPower",
FindTimeRemaining(this.part.Resources.Get(PartResourceLibrary.Instance.GetDefinition(FuelName).id).amount, baseRate),
- HeatGeneration.Evaluate(100f).ToString("F0"),
+ Utils.ToSI(HeatGeneration.Evaluate(100f), "F0"),
NominalTemperature.ToString("F0"),
NominalTemperature.ToString("F0"),
CriticalTemperature.ToString("F0"),
diff --git a/SystemHeat/SystemHeat/Modules/ModuleSystemHeatFissionFuelHandler.cs b/SystemHeat/SystemHeat/Modules/ModuleSystemHeatFissionFuelHandler.cs
index 0591f95..cf67fe2 100644
--- a/SystemHeat/SystemHeat/Modules/ModuleSystemHeatFissionFuelHandler.cs
+++ b/SystemHeat/SystemHeat/Modules/ModuleSystemHeatFissionFuelHandler.cs
@@ -4,10 +4,11 @@
using System.Text;
using UnityEngine;
using KSP.Localization;
+using Expansions.Missions.Adjusters;
namespace SystemHeat.Modules
{
- public class ModuleSystemHeatFissionFuelContainer: PartModule
+ public class ModuleSystemHeatFissionFuelContainer : PartModule
{
///
@@ -22,11 +23,17 @@ public class ModuleSystemHeatFissionFuelContainer: PartModule
[KSPField(isPersistant = false)]
public int EngineerLevelForTransfer = 3;
+ ///
+ /// If this is toggled, we'll override the required engineer level in the settings
+ ///
+ [KSPField(isPersistant = false)]
+ public bool OverrideEngineerLevelSettings = false;
+
private string[] resourceNames;
public override string GetInfo()
{
- return Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatFissionFuelContainer_PartInfo",
+ return Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatFissionFuelContainer_PartInfo",
EngineerLevelForTransfer.ToString(), ResourceNames
);
}
@@ -40,7 +47,7 @@ public override void OnAwake()
base.OnAwake();
if (HighLogic.LoadedSceneIsFlight)
{
- GameEvents.onCrewBoardVessel.Add(new EventData>.OnEvent(OnCrewBoardVessel));
+ GameEvents.onCrewBoardVessel.Add(new EventData>.OnEvent(OnCrewBoardVessel));
GameEvents.onVesselCrewWasModified.Add(new EventData.OnEvent(onVesselCrewWasModified));
}
}
@@ -74,7 +81,7 @@ public void Start()
if (HighLogic.LoadedSceneIsFlight)
{
resourceNames = ResourceNames.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(p => p.Trim()).ToArray(); ;
-
+
HandleTransferModes();
}
}
@@ -112,9 +119,19 @@ public int GetCrewLevel()
///
public void HandleTransferModes()
{
- if (GetCrewLevel() >= EngineerLevelForTransfer)
+ int targetCrewLevel = EngineerLevelForTransfer;
+ if (SystemHeatGameSettings_NuclearFuel.RequireEngineersForTransfer)
{
-
+ if (!OverrideEngineerLevelSettings)
+ targetCrewLevel = SystemHeatGameSettings_NuclearFuel.EngineerLevel;
+ }
+ else
+ {
+ targetCrewLevel = 0;
+ }
+ if (GetCrewLevel() >= targetCrewLevel)
+ {
+
foreach (string resN in resourceNames)
{
Utils.Log($"[ModuleSystemHeatFissionFuelContainer]: Crew level is {GetCrewLevel()}, setting transfer for resource {resN} to PUMP", LogType.Modules);
@@ -123,7 +140,7 @@ public void HandleTransferModes()
}
else
{
-
+
foreach (string resN in resourceNames)
{
Utils.Log($"[ModuleSystemHeatFissionFuelContainer]: Crew level is {GetCrewLevel()}, setting transfer for resource {resN} to NONE", LogType.Modules);
@@ -131,6 +148,6 @@ public void HandleTransferModes()
}
}
}
-
+
}
}
diff --git a/SystemHeat/SystemHeat/Modules/ModuleSystemHeatFissionReactor.cs b/SystemHeat/SystemHeat/Modules/ModuleSystemHeatFissionReactor.cs
index 7fe7145..5b20dc4 100644
--- a/SystemHeat/SystemHeat/Modules/ModuleSystemHeatFissionReactor.cs
+++ b/SystemHeat/SystemHeat/Modules/ModuleSystemHeatFissionReactor.cs
@@ -177,6 +177,13 @@ public class ModuleSystemHeatFissionReactor : PartModule, IContractObjectiveModu
// REPAIR VARIABLES
// integrity of the core
+
+ ///
+ /// If this is toggled, we'll override the the settings
+ ///
+ [KSPField(isPersistant = false)]
+ public bool OverrideRepairSettings = false;
+
[KSPField(isPersistant = true)]
public float CoreIntegrity = 100f;
@@ -320,7 +327,7 @@ public override string GetInfo()
Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatFissionReactor_PartInfo",
ElectricalGeneration.Evaluate(100f).ToString("F0"),
FindTimeRemaining(this.part.Resources.Get(PartResourceLibrary.Instance.GetDefinition(FuelName).id).amount, baseRate),
- (HeatGeneration.Evaluate(100f) - ElectricalGeneration.Evaluate(100f)).ToString("F0"),
+ Utils.ToSI((HeatGeneration.Evaluate(100f) - ElectricalGeneration.Evaluate(100f)), "F0"),
NominalTemperature.ToString("F0"),
NominalTemperature.ToString("F0"),
CriticalTemperature.ToString("F0"),
@@ -680,7 +687,7 @@ protected virtual void HandleHeatGeneration()
}
else
{
- ReactorOutput = String.Format("{0:F1} {1}", CurrentHeatGeneration, Localizer.Format("#LOC_SystemHeat_Units_kW"));
+ ReactorOutput = String.Format("{0:F1} {1}", Utils.ToSI(CurrentHeatGeneration, "F0"), "W");
}
if (heatModule)
@@ -726,8 +733,9 @@ private void HandleCore()
// If overheated too much, damage the core
if (critExceedance > 0f && TimeWarp.CurrentRate < 100f)
{
+ if (SystemHeatGameSettings_ReactorDamage.ReactorDamage)
// core is damaged by Rate * temp exceedance * time
- CoreIntegrity = Mathf.MoveTowards(CoreIntegrity, 0f, CoreDamageRate * critExceedance * TimeWarp.fixedDeltaTime);
+ CoreIntegrity = Mathf.MoveTowards(CoreIntegrity, 0f, CoreDamageRate * critExceedance * TimeWarp.fixedDeltaTime);
}
}
@@ -869,15 +877,23 @@ protected float GetEnvironmentTemperature()
#region Repair
public bool TryRepairReactor()
{
-
- if (CoreIntegrity <= MinRepairPercent)
+ float repairThreshold = SystemHeatGameSettings_ReactorDamage.RepairThreshold * 100f;
+ int engineerLevel = SystemHeatGameSettings_ReactorDamage.EngineerLevel;
+ float maxRepair = SystemHeatGameSettings_ReactorDamage.RepairMax * 100f;
+ if (OverrideRepairSettings)
+ {
+ repairThreshold = MinRepairPercent;
+ engineerLevel = EngineerLevelForRepair;
+ maxRepair = MaxRepairPercent;
+ }
+ if (CoreIntegrity <= repairThreshold)
{
ScreenMessages.PostScreenMessage(new ScreenMessage(Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatFissionReactor_Message_Repair_CoreTooDamaged"), 5.0f, ScreenMessageStyle.UPPER_CENTER));
return false;
}
- if (FlightGlobals.ActiveVessel.VesselValues.RepairSkill.value < EngineerLevelForRepair)
+ if (FlightGlobals.ActiveVessel.VesselValues.RepairSkill.value < engineerLevel)
{
- ScreenMessages.PostScreenMessage(new ScreenMessage(Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatFissionReactor_Message_Repair_EngineerLevelTooLow", EngineerLevelForRepair.ToString("F0")), 5.0f, ScreenMessageStyle.UPPER_CENTER));
+ ScreenMessages.PostScreenMessage(new ScreenMessage(Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatFissionReactor_Message_Repair_EngineerLevelTooLow", engineerLevel.ToString("F0")), 5.0f, ScreenMessageStyle.UPPER_CENTER));
return false;
}
if (FlightGlobals.ActiveVessel.evaController.ModuleInventoryPartReference.TotalAmountOfPartStored("evaRepairKit") < 1)
@@ -897,21 +913,28 @@ public bool TryRepairReactor()
return false;
}
- //if (CoreIntegrity >= MaxRepairPercent)
- //{
- // ScreenMessages.PostScreenMessage(new ScreenMessage(Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatFissionReactor_Message_Repair_CoreAlreadyRepaired", MaxRepairPercent.ToString("F0")),
- // 5.0f, ScreenMessageStyle.UPPER_CENTER));
- // return false;
- //}
+ if (CoreIntegrity >= maxRepair)
+ {
+ ScreenMessages.PostScreenMessage(new ScreenMessage(Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatFissionReactor_Message_Repair_CoreAlreadyRepaired", maxRepair.ToString("F0")),
+ 5.0f, ScreenMessageStyle.UPPER_CENTER));
+ return false;
+ }
return true;
}
// Repair the reactor to max Repair percent
public void DoReactorRepair()
{
+ float repairPercent = SystemHeatGameSettings_ReactorDamage.RepairPerKit * 100f;
+ float maxRepair = SystemHeatGameSettings_ReactorDamage.RepairMax * 100f;
+ if (OverrideRepairSettings)
+ {
+ maxRepair = MaxRepairPercent;
+ repairPercent = RepairAmountPerKit;
+ }
FlightGlobals.ActiveVessel.evaController.ModuleInventoryPartReference.RemoveNPartsFromInventory("evaRepairKit", 1, playSound: true);
- this.CoreIntegrity = Mathf.Clamp(this.CoreIntegrity + RepairAmountPerKit, 0f, 100f);
+ this.CoreIntegrity = Mathf.Clamp(this.CoreIntegrity + repairPercent, 0f, maxRepair);
ScreenMessages.PostScreenMessage(new ScreenMessage(Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatFissionReactor_Message_Repair_RepairSuccess",
this.CoreIntegrity.ToString("F0")), 5.0f, ScreenMessageStyle.UPPER_CENTER));
}
diff --git a/SystemHeat/SystemHeat/Modules/ModuleSystemHeatHarvester.cs b/SystemHeat/SystemHeat/Modules/ModuleSystemHeatHarvester.cs
index c442a2e..3219056 100644
--- a/SystemHeat/SystemHeat/Modules/ModuleSystemHeatHarvester.cs
+++ b/SystemHeat/SystemHeat/Modules/ModuleSystemHeatHarvester.cs
@@ -62,7 +62,7 @@ public override string GetInfo()
return info;
else
return info.Substring(0, pos) + Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatHarvester_PartInfoAdd",
- systemPower.ToString("F0"),
+ Utils.ToSI(systemPower,"F0"),
systemOutletTemperature.ToString("F0"),
shutdownTemperature.ToString("F0")
) + info.Substring(pos);
diff --git a/SystemHeat/SystemHeat/Modules/ModuleSystemHeatMultiJettison.cs b/SystemHeat/SystemHeat/Modules/ModuleSystemHeatMultiJettison.cs
new file mode 100644
index 0000000..607719c
--- /dev/null
+++ b/SystemHeat/SystemHeat/Modules/ModuleSystemHeatMultiJettison.cs
@@ -0,0 +1,283 @@
+using System;
+
+
+public class ModuleSystemHeatMultiJettison : PartModule, IScalarModule, IPartMassModifier, IMultipleDragCube
+{
+
+
+ [KSPField()]
+ public string jettisonName = "jettison";
+
+ [KSPField()]
+ public Vector3 jettisonDirection = Vector3.up;
+
+ [KSPField()]
+ public float jettisonForce = 5.0f;
+
+ [KSPField()]
+ public float jettisonedObjectMass = 0.01f;
+
+ private Transform[] jettisons;
+
+ [KSPField(isPersistant = true, guiActiveEditor = true, guiName = "Fairing"), UI_Toggle(affectSymCounterparts = UI_Scene.Editor, disabledText = "Installed", enabledText = "Removed")]
+ public bool isJettisoned = false;
+
+ [KSPField]
+ public string toggleJettisonEditorGuiName = "Fairing";
+
+ [KSPField]
+ public string jettisonGuiName = "Jettison";
+
+ [KSPField]
+ public bool enableDisabledModules = false;
+
+ [KSPField]
+ public string fxGroupName = "jettison";
+
+ private const string DRAG_CUBE_JETTISONED = "Jettisoned";
+ private const string DRAG_CUBE_COVERED = "Covered";
+
+ [UI_Toggle(scene = UI_Scene.All, disabledText = "No", enabledText = "Yes")]
+ [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "Auto-Deploy Fairing")]
+ public bool autoDeploy = true;
+
+ [UI_FloatRange(minValue = 0f, maxValue = 100f, stepIncrement = 1f, scene = UI_Scene.All)]
+ [KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "Autodeploy Altitude (km)")]
+ public float deployAltitude = float.NaN;
+
+
+ public override void OnAwake()
+ {
+ OnMovingEvent = new EventData("OnMovingEvent");
+ OnStopEvent = new EventData("OnStopEvent");
+
+ jettisons = part.FindModelTransforms(jettisonName);
+
+ base.OnAwake();
+ }
+
+ public override void OnStart(StartState state)
+ {
+ if (jettisons.Length == 0)
+ isJettisoned = true;
+
+ SetJettisoned(isJettisoned);
+
+ Fields[nameof(isJettisoned)].uiControlEditor.onFieldChanged = OnEditorToggleJettisoned;
+ Fields[nameof(isJettisoned)].guiName = toggleJettisonEditorGuiName;
+
+ Events[nameof(Jettison)].active = !isJettisoned;
+ Events[nameof(Jettison)].guiName = jettisonGuiName;
+
+ Actions[nameof(JettisonAction)].active = !isJettisoned;
+ Actions[nameof(JettisonAction)].guiName = jettisonGuiName;
+
+ Fields[nameof(autoDeploy)].uiControlEditor.onFieldChanged = OnToggleAutodeploy;
+ Fields[nameof(autoDeploy)].uiControlFlight.onFieldChanged = OnToggleAutodeploy;
+
+ CalculateAutodeployAltitude();
+ UpdateDeployAltitudeVisibility();
+ }
+
+ private void OnEditorToggleJettisoned(BaseField field, object oldValue)
+ {
+ if (!HighLogic.LoadedSceneIsEditor)
+ return;
+
+ OnMoving.Fire(isJettisoned ? 0 : 1, isJettisoned ? 1 : 0);
+
+ if (jettisons.Length > 0)
+ {
+ SetJettisoned(isJettisoned);
+ }
+
+ OnStop.Fire(isJettisoned ? 1 : 0);
+
+ part.UpdateStageability(true, true);
+ }
+
+ private void OnToggleAutodeploy(BaseField field, object oldValue)
+ {
+ UpdateDeployAltitudeVisibility();
+ }
+
+ public virtual void FixedUpdate()
+ {
+ if (isJettisoned || !autoDeploy || HighLogic.LoadedSceneIsEditor || !part.started) return;
+
+ if (deployAltitude * 1000f < vessel.altitude) Jettison();
+ }
+
+ [KSPEvent(guiActive = true, guiName = "Jettison")]
+ public void Jettison()
+ {
+ if (isJettisoned)
+ return;
+
+ if (jettisons.Length == 0)
+ return;
+
+ OnMoving.Fire(0, 1);
+
+ for (int i = 0; i < jettisons.Length; i++)
+ {
+ Rigidbody rb = physicalObject.ConvertToPhysicalObject(part, jettisons[i].gameObject).rb;
+ rb.useGravity = true;
+ rb.mass = jettisonedObjectMass / jettisons.Length;
+ rb.maxAngularVelocity = PhysicsGlobals.MaxAngularVelocity;
+ rb.angularVelocity = part.Rigidbody.angularVelocity;
+ rb.velocity = part.Rigidbody.velocity + Vector3.Cross(part.Rigidbody.worldCenterOfMass - vessel.CurrentCoM, vessel.angularVelocity);
+
+ Vector3 d = jettisonDirection;
+ if (d == Vector3.zero)
+ d = Vector3.Normalize(rb.transform.position - part.transform.position);
+ else
+ d = part.transform.TransformDirection(d);
+
+ //rb.AddForce(part.transform.TransformDirection(jettisonDirection) * (jettisonForce * 0.5f), ForceMode.Force);
+ rb.AddForceAtPosition(d * (jettisonForce * 0.5f), part.transform.position, ForceMode.Force);
+ part.Rigidbody.AddForce(d * (-jettisonForce * 0.5f), ForceMode.Force);
+ }
+
+ jettisons = new Transform[0];
+
+ if (part.temperature < part.skinMaxTemp)
+ part.skinTemperature = part.temperature;
+
+ isJettisoned = true;
+
+ SetJettisoned(isJettisoned);
+
+ OnStop.Fire(1);
+
+ EnableOtherModules();
+
+ FXGroup effect = part.findFxGroup(fxGroupName);
+ if (effect != null)
+ {
+ effect.Burst();
+ }
+
+ GameEvents.onVesselWasModified.Fire(vessel);
+ }
+
+ [KSPAction("Deploy")]
+ public void JettisonAction(KSPActionParam param)
+ {
+ Jettison();
+ }
+
+ public override void OnActive()
+ {
+ Jettison();
+ }
+
+ private void EnableOtherModules()
+ {
+ if (enableDisabledModules)
+ {
+ foreach (PartModule pm in part.Modules)
+ {
+ if (!pm.moduleIsEnabled)
+ pm.moduleIsEnabled = true;
+ }
+ }
+ }
+
+ private void SetJettisoned(bool b)
+ {
+ SetDragCube(b);
+ JettisonsSetActive(!b);
+
+ Events[nameof(Jettison)].active = !b;
+ Actions[nameof(JettisonAction)].active = !b;
+ Fields[nameof(autoDeploy)].guiActive = !b;
+ Fields[nameof(autoDeploy)].guiActiveEditor = !b;
+ UpdateDeployAltitudeVisibility();
+ }
+
+ private void UpdateDeployAltitudeVisibility()
+ {
+ Fields[nameof(deployAltitude)].guiActive = !isJettisoned && autoDeploy;
+ Fields[nameof(deployAltitude)].guiActiveEditor = !isJettisoned && autoDeploy;
+ }
+
+ public override bool IsStageable()
+ {
+ return !isJettisoned;
+ }
+
+ public override bool StagingToggleEnabledEditor()
+ {
+ return true;
+ }
+
+ private void SetDragCube(bool deployed)
+ {
+ if (deployed)
+ {
+ part.DragCubes.SetCubeWeight(DRAG_CUBE_JETTISONED, 1);
+ part.DragCubes.SetCubeWeight(DRAG_CUBE_COVERED, 0);
+ }
+ else
+ {
+ part.DragCubes.SetCubeWeight(DRAG_CUBE_JETTISONED, 0);
+ part.DragCubes.SetCubeWeight(DRAG_CUBE_COVERED, 1);
+ }
+ }
+
+ private void JettisonsSetActive(bool b)
+ {
+ for (int i = 0; i < jettisons.Length; i++)
+ jettisons[i].gameObject.SetActive(b);
+ }
+
+ private void CalculateAutodeployAltitude()
+ {
+ UI_FloatRange deployAltitudeControl;
+ if (HighLogic.LoadedSceneIsEditor)
+ deployAltitudeControl = (UI_FloatRange)Fields[nameof(deployAltitude)].uiControlEditor;
+ else
+ deployAltitudeControl = (UI_FloatRange)Fields[nameof(deployAltitude)].uiControlFlight;
+
+ float newDeployAltitude;
+
+ CelestialBody home = Planetarium.fetch.Home;
+ if (home != null)
+ {
+ newDeployAltitude = Mathf.Round((float)home.atmosphereDepth * 0.70f / 1000f);// / 5f) * 5f;
+ deployAltitudeControl.maxValue = (float)home.atmosphereDepth / 1000f;
+ }
+ else
+ {
+ Debug.LogError($"[{part.name} {GetType().Name}] Cannot find home celestial body to set altitude from");
+ autoDeploy = false;
+ newDeployAltitude = 100f;
+ deployAltitudeControl.maxValue = 200f;
+ }
+
+ if (float.IsNaN(deployAltitude)) deployAltitude = newDeployAltitude;
+ }
+
+ #region IPartMassModifier
+ public float GetModuleMass(float defaultMass, ModifierStagingSituation sit)
+ {
+ float mass = 0;
+ switch (sit)
+ {
+ case ModifierStagingSituation.CURRENT:
+ if (!isJettisoned)
+ mass = jettisonedObjectMass;
+ break;
+ case ModifierStagingSituation.UNSTAGED:
+ mass = jettisonedObjectMass;
+ break;
+ }
+ return mass;
+ }
+
+ public ModifierChangeWhen GetModuleMassChangeWhen()
+ {
+ return ModifierChangeWhen.STAGED;
+ }
+}
diff --git a/SystemHeat/SystemHeat/Modules/ModuleSystemHeatRadiator.cs b/SystemHeat/SystemHeat/Modules/ModuleSystemHeatRadiator.cs
index 45bbea2..4356a51 100644
--- a/SystemHeat/SystemHeat/Modules/ModuleSystemHeatRadiator.cs
+++ b/SystemHeat/SystemHeat/Modules/ModuleSystemHeatRadiator.cs
@@ -149,9 +149,9 @@ public override string GetInfo()
{
string message = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatRadiator_PartInfo",
- temperatureCurve.Curve.keys[0].time.ToString("F0"),
- temperatureCurve.Evaluate(temperatureCurve.Curve.keys[0].time).ToString("F0"),
- temperatureCurve.Evaluate(temperatureCurve.Curve.keys[temperatureCurve.Curve.keys.Length - 1].time).ToString("F0"),
+ Utils.ToSI(temperatureCurve.Curve.keys[0].time, "F0"),
+ temperatureCurve.Evaluate(temperatureCurve.Curve.keys[0].time).ToString("F0"),
+ Utils.ToSI(temperatureCurve.Evaluate(temperatureCurve.Curve.keys[temperatureCurve.Curve.keys.Length - 1].time), "F0"),
temperatureCurve.Curve.keys[temperatureCurve.Curve.keys.Length - 1].time.ToString("F0")
);
message += base.GetInfo();
@@ -187,7 +187,8 @@ public override void FixedUpdate()
}
- ConvectionStatus = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatRadiator_ConvectionStatus_Running", convectiveFlux.ToString("F1"));
+ ConvectionStatus = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatRadiator_ConvectionStatus_Running",
+ Utils.ToSI(convectiveFlux, "F0"));
}
else
{
@@ -199,7 +200,8 @@ public override void FixedUpdate()
RadiatorEfficiency = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatRadiator_RadiatorEfficiency_Running",
(-radiativeFlux / temperatureCurve.Evaluate(temperatureCurve.Curve.keys[temperatureCurve.Curve.keys.Length - 1].time) * 100f).ToString("F0"));
- RadiatorStatus = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatRadiator_RadiatorStatus_Running", radiativeFlux.ToString("F1"));
+ RadiatorStatus = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatRadiator_RadiatorStatus_Running",
+ Utils.ToSI(radiativeFlux, "F0"));
if (scalarModule != null)
{
@@ -246,10 +248,11 @@ public override void FixedUpdate()
//Utils.Log($"tD {tDelta}, tC, {lp.ConvectionTemperature} tL {heatModule.LoopTemperature}, tMax {temperatureCurve.Curve.keys[temperatureCurve.Curve.keys.Length - 1].time}, convA {convectiveArea}");
}
-
+
heatModule.AddFlux(moduleID, 0f, radiativeFlux + convectiveFlux, false);
- ConvectionStatus = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatRadiator_ConvectionStatus_Running", convectiveFlux.ToString("F1"));
+ ConvectionStatus = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatRadiator_ConvectionStatus_Running",
+ Utils.ToSI(convectiveFlux, "F0"));
RadiatorEfficiency = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatRadiator_RadiatorEfficiency_Running",
((temperatureCurve.Evaluate(heatModule.LoopTemperature) / temperatureCurve.Evaluate(temperatureCurve.Curve.keys[temperatureCurve.Curve.keys.Length - 1].time)) * 100f).ToString("F0"));
}
diff --git a/SystemHeat/SystemHeat/Modules/ModuleSystemHeatSink.cs b/SystemHeat/SystemHeat/Modules/ModuleSystemHeatSink.cs
index 9a7a948..e2837ad 100644
--- a/SystemHeat/SystemHeat/Modules/ModuleSystemHeatSink.cs
+++ b/SystemHeat/SystemHeat/Modules/ModuleSystemHeatSink.cs
@@ -101,7 +101,7 @@ public override string GetInfo()
// Need to update this to strip the CoreHeat stuff from it
string message = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatSink_PartInfo",
(heatStorageMaximum / 1000f).ToString("F0"),
- maxHeatRate.ToString("F0")
+ Utils.ToSI(maxHeatRate, "F0")
);
return message;
}
@@ -188,7 +188,9 @@ public void FixedUpdate()
GenerateHeatFlight();
systemTemperature = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatSink_Field_SystemTemperature_Running", storageTemperature.ToString("F0"));
systemHeatStored = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatSink_Field_SystemHeatStored_Fraction", (heatStored / heatStorageMaximum * 100f).ToString("F0"));
- systemHeatGeneration = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatSink_Field_SystemHeatGeneration_Storing", (-heatModule.consumedSystemFlux).ToString("F0"), maxHeatRate.ToString("F0"));
+ systemHeatGeneration = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatSink_Field_SystemHeatGeneration_Storing",
+ Utils.ToSI((-heatModule.consumedSystemFlux), "F0"),
+ Utils.ToSI(maxHeatRate, "F0"));
}
if (HighLogic.LoadedSceneIsEditor)
@@ -196,7 +198,9 @@ public void FixedUpdate()
GenerateHeatEditor();
systemTemperature = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatSink_Field_SystemTemperature_Running", storageTemperature.ToString("F0"));
systemHeatStored = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatSink_Field_SystemHeatStored_Fraction", (heatStored / heatStorageMaximum * 100f).ToString("F0"));
- systemHeatGeneration = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatSink_Field_SystemHeatGeneration_Storing", (-heatModule.consumedSystemFlux).ToString("F0"), maxHeatRate.ToString("F0"));
+ systemHeatGeneration = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatSink_Field_SystemHeatGeneration_Storing",
+ Utils.ToSI((-heatModule.consumedSystemFlux), "F0"),
+ Utils.ToSI(maxHeatRate, "F0"));
}
}
diff --git a/SystemHeat/SystemHeat/SystemHeat.csproj b/SystemHeat/SystemHeat/SystemHeat.csproj
index 20f8ba3..02e43b7 100644
--- a/SystemHeat/SystemHeat/SystemHeat.csproj
+++ b/SystemHeat/SystemHeat/SystemHeat.csproj
@@ -1,5 +1,5 @@
-
+
Debug
AnyCPU
@@ -10,7 +10,7 @@
Properties
SystemHeat
SystemHeat
- v4.5
+ v4.8
512
@@ -81,10 +81,12 @@
+
+
@@ -102,6 +104,7 @@
+
diff --git a/SystemHeat/SystemHeat/SystemHeatAtmosphereSimulator.cs b/SystemHeat/SystemHeat/SystemHeatAtmosphereSimulator.cs
index 3891d58..3a44fa7 100644
--- a/SystemHeat/SystemHeat/SystemHeatAtmosphereSimulator.cs
+++ b/SystemHeat/SystemHeat/SystemHeatAtmosphereSimulator.cs
@@ -46,6 +46,8 @@ public void CalculateConstants(CelestialBody body, float speed, double altitude)
atmoTemp = body.GetFullTemperature(altitude, atmosphereTemperatureOffset);
density = body.GetDensity(staticPressurekPa, atmoTemp);
mach = CalculateMachNumber(body, speed, staticPressurekPa, density);
+
+
staticPressurekPa = body.GetPressure(altitude);
convectiveMachScale = Math.Pow(UtilMath.Clamp01(
(mach - PhysicsGlobals.NewtonianMachTempLerpStartMach) / (PhysicsGlobals.NewtonianMachTempLerpEndMach - PhysicsGlobals.NewtonianMachTempLerpStartMach)),
@@ -56,6 +58,10 @@ public void CalculateConstants(CelestialBody body, float speed, double altitude)
public float CalculateMachNumber(CelestialBody body, float speed, double staticPressure, double atmDensity)
{
double speedOfSound = body.GetSpeedOfSound(staticPressure, atmDensity);
+
+ if (speedOfSound < 0.00001)
+ return 0f;
+
return speed/(float)speedOfSound;
}
public virtual float CalculateShockTemperature(CelestialBody body, float machNumber, float speed)
diff --git a/SystemHeat/SystemHeat/SystemHeatGameSettings.cs b/SystemHeat/SystemHeat/SystemHeatGameSettings.cs
new file mode 100644
index 0000000..a0272b9
--- /dev/null
+++ b/SystemHeat/SystemHeat/SystemHeatGameSettings.cs
@@ -0,0 +1,385 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SystemHeat
+{
+
+ public class SystemHeatGameSettings_ReactorDamage : GameParameters.CustomParameterNode
+ {
+
+ [GameParameters.CustomParameterUI("Allow Reactor Damage",
+ toolTip = "If enabled, overheated reactors will take damage",
+ autoPersistance = true)]
+ public bool reactorDamage = true;
+
+ [GameParameters.CustomParameterUI("Allow Reactor Repairs",
+ toolTip = "If enabled, damaged fission reactors can be repaired",
+ autoPersistance = true)]
+ public bool reactorRepairs = true;
+
+ [GameParameters.CustomIntParameterUI("Engineer Level Required",
+ maxValue = 5, minValue = 1, stepSize = 1,
+ toolTip = "Engineer level needed to repair a reactor",
+ autoPersistance = true)]
+ public int engineerLevel = 5;
+
+
+ [GameParameters.CustomFloatParameterUI("Amount Repaired per Repair Kit",
+ maxValue = 100f, minValue = 5f, asPercentage = true, stepCount = 20,
+ toolTip = "The amount of repairs a single kit makes", autoPersistance = true)]
+ public float repairPerKit = 25f;
+
+ [GameParameters.CustomFloatParameterUI("Minimum Repairable level",
+ maxValue = 100f, minValue = 5f, asPercentage = true, stepCount = 20,
+ toolTip = "If a reactor is below this level it can't be repaired", autoPersistance = true)]
+ public float repairThreshold = 10f;
+
+
+ [GameParameters.CustomFloatParameterUI("Maximum Allowed Repair Amount",
+ maxValue = 100f, minValue = 5f, asPercentage = true, stepCount = 20,
+ toolTip = "The maximum amount you are allowed to repair a reactor", autoPersistance = true)]
+ public float repairMax = 75f;
+
+ public override string DisplaySection
+ {
+ get
+ {
+ return Section;
+ }
+ }
+
+ public override string Section
+ {
+ get
+ {
+ return "System Heat";
+ }
+ }
+
+ public override string Title
+ {
+ get
+ {
+ return "Fission Reactor Damage";
+ }
+ }
+
+ public override int SectionOrder
+ {
+ get
+ {
+ return 3;
+ }
+ }
+
+ public override GameParameters.GameMode GameMode
+ {
+ get
+ {
+ return GameParameters.GameMode.ANY;
+ }
+ }
+
+ public override bool HasPresets
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public override bool Enabled(System.Reflection.MemberInfo member, GameParameters parameters)
+ {
+ if (reactorDamage || member.Name == "reactorDamage")
+ return true;
+ else
+ return false;
+ }
+
+ public static bool ReactorDamage
+ {
+ get
+ {
+ if (HighLogic.LoadedScene == GameScenes.MAINMENU)
+ return true;
+ SystemHeatGameSettings_ReactorDamage settings = HighLogic.CurrentGame.Parameters.CustomParams();
+ return settings.reactorDamage;
+ }
+
+ set
+ {
+ SystemHeatGameSettings_ReactorDamage settings = HighLogic.CurrentGame.Parameters.CustomParams();
+ settings.reactorDamage = value;
+ }
+ }
+
+ public static int EngineerLevel
+ {
+ get
+ {
+ SystemHeatGameSettings_ReactorDamage settings = HighLogic.CurrentGame.Parameters.CustomParams();
+ return settings.engineerLevel;
+ }
+
+ set
+ {
+ SystemHeatGameSettings_ReactorDamage settings = HighLogic.CurrentGame.Parameters.CustomParams();
+ settings.engineerLevel = value;
+ }
+ }
+
+ public static float RepairPerKit
+ {
+ get
+ {
+ SystemHeatGameSettings_ReactorDamage settings = HighLogic.CurrentGame.Parameters.CustomParams();
+ return settings.repairPerKit;
+ }
+
+ set
+ {
+ SystemHeatGameSettings_ReactorDamage settings = HighLogic.CurrentGame.Parameters.CustomParams();
+ settings.repairPerKit = value;
+ }
+ }
+ public static float RepairThreshold
+ {
+ get
+ {
+ SystemHeatGameSettings_ReactorDamage settings = HighLogic.CurrentGame.Parameters.CustomParams();
+ return settings.repairThreshold;
+ }
+
+ set
+ {
+ SystemHeatGameSettings_ReactorDamage settings = HighLogic.CurrentGame.Parameters.CustomParams();
+ settings.repairThreshold = value;
+ }
+ }
+
+
+ public static float RepairMax
+ {
+ get
+ {
+ SystemHeatGameSettings_ReactorDamage settings = HighLogic.CurrentGame.Parameters.CustomParams();
+ return settings.repairMax;
+ }
+
+ set
+ {
+ SystemHeatGameSettings_ReactorDamage settings = HighLogic.CurrentGame.Parameters.CustomParams();
+ settings.repairMax = value;
+ }
+ }
+
+ }
+}
+
+public class SystemHeatGameSettings_NuclearFuel : GameParameters.CustomParameterNode
+{
+ [GameParameters.CustomParameterUI("Nuclear Fuel Transfer Needs Engineers",
+ toolTip = "If enabled, nuclear fuel transfer needs experienced engineers",
+ autoPersistance = true)]
+ public bool requireEngineersForTransfer = true;
+
+ [GameParameters.CustomIntParameterUI("Engineer Level Required",
+ maxValue = 5, minValue = 1, stepSize = 1,
+ toolTip = "Engineer level needed to transfer",
+ autoPersistance = true)]
+ public int engineerLevel = 3;
+
+ public override string DisplaySection
+ {
+ get
+ {
+ return Section;
+ }
+ }
+
+ public override string Section
+ {
+ get
+ {
+ return "System Heat";
+ }
+ }
+
+ public override string Title
+ {
+ get
+ {
+ return "Nuclear Fuel";
+ }
+ }
+
+ public override int SectionOrder
+ {
+ get
+ {
+ return 1;
+ }
+ }
+
+ public override GameParameters.GameMode GameMode
+ {
+ get
+ {
+ return GameParameters.GameMode.ANY;
+ }
+ }
+
+ public override bool HasPresets
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public override bool Enabled(System.Reflection.MemberInfo member, GameParameters parameters)
+ {
+ if (requireEngineersForTransfer || member.Name == "requireEngineersForTransfer")
+ return true;
+ else
+ return false;
+ }
+
+ public static bool RequireEngineersForTransfer
+ {
+ get
+ {
+ if (HighLogic.LoadedScene == GameScenes.MAINMENU)
+ return true;
+ SystemHeatGameSettings_NuclearFuel settings = HighLogic.CurrentGame.Parameters.CustomParams();
+ return settings.requireEngineersForTransfer;
+ }
+
+ set
+ {
+ SystemHeatGameSettings_NuclearFuel settings = HighLogic.CurrentGame.Parameters.CustomParams();
+ settings.requireEngineersForTransfer = value;
+ }
+ }
+
+ public static int EngineerLevel
+ {
+ get
+ {
+ SystemHeatGameSettings_NuclearFuel settings = HighLogic.CurrentGame.Parameters.CustomParams();
+ return settings.engineerLevel;
+ }
+
+ set
+ {
+ SystemHeatGameSettings_NuclearFuel settings = HighLogic.CurrentGame.Parameters.CustomParams();
+ settings.engineerLevel = value;
+ }
+ }
+
+}
+
+public class SystemHeatGameSettings_Boiloff : GameParameters.CustomParameterNode
+{
+ [GameParameters.CustomParameterUI("Fuel Boiloff",
+ toolTip = "If enabled, configured fuels that need coolin", autoPersistance = true)]
+ public bool boiloffEnabled = true;
+
+ [GameParameters.CustomFloatParameterUI("Fuel Boiloff Rate",
+ maxValue = 5.0f, minValue = 0.01f, asPercentage = true, stepCount = 100,
+ toolTip = "Modifies base boiloff rate", autoPersistance = true)]
+ public float boiloffRate = 1.0f;
+
+ public override string DisplaySection
+ {
+ get
+ {
+ return Section;
+ }
+ }
+
+ public override string Section
+ {
+ get
+ {
+ return "System Heat";
+ }
+ }
+
+ public override string Title
+ {
+ get
+ {
+ return "Boiloff";
+ }
+ }
+
+ public override int SectionOrder
+ {
+ get
+ {
+ return 1;
+ }
+ }
+
+ public override GameParameters.GameMode GameMode
+ {
+ get
+ {
+ return GameParameters.GameMode.ANY;
+ }
+ }
+
+ public override bool HasPresets
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public override bool Enabled(System.Reflection.MemberInfo member, GameParameters parameters)
+ {
+ if (boiloffEnabled || member.Name == "boiloffEnabled")
+ return true;
+ else
+ return false;
+ }
+
+ public static bool BoiloffEnabled
+ {
+ get
+ {
+ if (HighLogic.LoadedScene == GameScenes.MAINMENU)
+ return true;
+ SystemHeatGameSettings_Boiloff settings = HighLogic.CurrentGame.Parameters.CustomParams();
+ return settings.boiloffEnabled;
+ }
+
+ set
+ {
+ SystemHeatGameSettings_Boiloff settings = HighLogic.CurrentGame.Parameters.CustomParams();
+ settings.boiloffEnabled = value;
+ }
+ }
+
+ public static float BoiloffScale
+ {
+ get
+ {
+ SystemHeatGameSettings_Boiloff settings = HighLogic.CurrentGame.Parameters.CustomParams();
+ return settings.boiloffRate;
+ }
+
+ set
+ {
+ SystemHeatGameSettings_Boiloff settings = HighLogic.CurrentGame.Parameters.CustomParams();
+ settings.boiloffRate = value;
+ }
+ }
+
+
+}
diff --git a/SystemHeat/SystemHeat/SystemHeatSimulator.cs b/SystemHeat/SystemHeat/SystemHeatSimulator.cs
index c760a5f..338aadf 100644
--- a/SystemHeat/SystemHeat/SystemHeatSimulator.cs
+++ b/SystemHeat/SystemHeat/SystemHeatSimulator.cs
@@ -130,7 +130,7 @@ public virtual void Simulate()
{
if (SimulationBody != null)
atmoSim.SimulateAtmosphere(SimulationBody, SimulationSpeed, SimulationAltitude);
-
+
foreach (HeatLoop loop in HeatLoops)
{
loop.Simulate(TimeWarp.fixedDeltaTime);
@@ -147,7 +147,9 @@ public virtual void SimulateEditor()
if (HeatLoops != null)
{
if (SimulationBody != null)
+ {
atmoSim.SimulateAtmosphere(SimulationBody, SimulationSpeed, SimulationAltitude);
+ }
foreach (HeatLoop loop in HeatLoops)
{
loop.Simulate(SystemHeatSettings.SimulationRateEditor);
@@ -161,7 +163,8 @@ public virtual void SimulateEditor()
/// the module to add
public void AddHeatModule(ModuleSystemHeat module)
{
- AddHeatModuleToLoop(module.currentLoopID, module);
+ if (module.moduleUsed)
+ AddHeatModuleToLoop(module.currentLoopID, module);
}
///
@@ -171,21 +174,26 @@ public void AddHeatModule(ModuleSystemHeat module)
/// the module to add
public void AddHeatModuleToLoop(int loopID, ModuleSystemHeat module)
{
- // Build a new heat loop as needed
- if (!HasLoop(loopID))
+ if (module.moduleUsed)
{
- HeatLoops.Add(new HeatLoop(this, loopID));
+ // Build a new heat loop as needed
+ if (!HasLoop(loopID))
+ {
+ if (HeatLoops != null)
+ HeatLoops.Add(new HeatLoop(this, loopID));
+ Utils.Log(String.Format("[SystemHeatSimulator]: Created new Heat Loop {0}", loopID), LogType.Simulator);
+ }
+ if (HeatLoops != null)
+ {
+ foreach (HeatLoop loop in HeatLoops)
+ {
+ if (loop.ID == loopID)
+ loop.AddHeatModule(module);
+ }
+ }
- Utils.Log(String.Format("[SystemHeatSimulator]: Created new Heat Loop {0}", loopID), LogType.Simulator);
- }
- foreach (HeatLoop loop in HeatLoops)
- {
- if (loop.ID == loopID)
- loop.AddHeatModule(module);
+ Utils.Log(String.Format("[SystemHeatSimulator]: Added module {0} to Heat Loop {1}", module.moduleID, loopID), LogType.Simulator);
}
-
-
- Utils.Log(String.Format("[SystemHeatSimulator]: Added module {0} to Heat Loop {1}", module.moduleID, loopID), LogType.Simulator);
}
///
diff --git a/SystemHeat/SystemHeat/SystemHeatVessel.cs b/SystemHeat/SystemHeat/SystemHeatVessel.cs
index 286e9da..cea638f 100644
--- a/SystemHeat/SystemHeat/SystemHeatVessel.cs
+++ b/SystemHeat/SystemHeat/SystemHeatVessel.cs
@@ -37,6 +37,7 @@ protected override void OnStart()
simulator = new SystemHeatSimulator();
// These events need to trigger a refresh
+ GameEvents.onVesselChange.Add(new EventData.OnEvent(OnVesselChanged));
GameEvents.onVesselGoOnRails.Add(new EventData.OnEvent(RefreshVesselData));
GameEvents.onVesselWasModified.Add(new EventData.OnEvent(RefreshVesselData));
GameEvents.onVesselDocking.Add(new EventData.OnEvent(OnVesselsDocked));
@@ -51,6 +52,7 @@ void OnDestroy()
GameEvents.OnVesselRollout.Remove(OnVesselRollout);
GameEvents.onVesselDocking.Remove(OnVesselsDocked);
GameEvents.onVesselsUndocking.Remove(OnVesselsUndocked);
+ GameEvents.onVesselChange.Remove(OnVesselChanged);
}
void FixedUpdate()
@@ -96,6 +98,18 @@ protected void RefreshVesselData(ConfigNode node)
Utils.Log(String.Format("[SystemHeatVessel]: Refreshing VesselData from save node event", this.GetType().Name), LogType.Simulator);
}
+ protected void OnVesselChanged(Vessel v)
+ {
+ Utils.Log(String.Format("[SystemHeatVessel]: Vessel changed", this.GetType().Name), LogType.Simulator);
+ ResetSimulation();
+
+ SystemHeatOverlay.Instance.ResetOverlay();
+ if (FlightGlobals.ActiveVessel == this.vessel)
+ {
+ SystemHeatOverlay.Instance.AssignSimulator(simulator);
+ SystemHeatUI.Instance.toolbarPanel.AssignSimulator(simulator);
+ }
+ }
protected void OnVesselsDocked(uint v1, uint v2)
{
Utils.Log(String.Format("[SystemHeatVessel]: Vessel docked", this.GetType().Name), LogType.Simulator);
diff --git a/SystemHeat/SystemHeat/UI/Overlay/OverlayLoop.cs b/SystemHeat/SystemHeat/UI/Overlay/OverlayLoop.cs
index 1ed96c6..40f5f83 100644
--- a/SystemHeat/SystemHeat/UI/Overlay/OverlayLoop.cs
+++ b/SystemHeat/SystemHeat/UI/Overlay/OverlayLoop.cs
@@ -67,18 +67,21 @@ protected void UpdateLinePositions()
public void GenerateLinePoints()
{
+ int moduleCount = heatLoop.GetActiveModuleCount();
// Collect positions of all heat modules
- Vector3[] systemCoords = new Vector3[heatLoop.LoopModules.Count];
- for (int i = 0; i < heatLoop.LoopModules.Count; i++)
+ Vector3[] systemCoords = new Vector3[moduleCount];
+ for (int i = 0; i < moduleCount; i++)
{
- if (HighLogic.LoadedSceneIsEditor)
- {
- systemCoords[i] = heatLoop.LoopModules[i].part.transform.position;
- }
-
- if (HighLogic.LoadedSceneIsFlight)
- {
- systemCoords[i] = heatLoop.LoopModules[i].part.vessel.vesselTransform.InverseTransformPoint(heatLoop.LoopModules[i].part.transform.position);
+ if (heatLoop.LoopModules[i].moduleUsed) {
+ if (HighLogic.LoadedSceneIsEditor)
+ {
+ systemCoords[i] = heatLoop.LoopModules[i].part.transform.position;
+ }
+
+ if (HighLogic.LoadedSceneIsFlight)
+ {
+ systemCoords[i] = heatLoop.LoopModules[i].part.vessel.vesselTransform.InverseTransformPoint(heatLoop.LoopModules[i].part.transform.position);
+ }
}
}
diff --git a/SystemHeat/SystemHeat/UI/Overlay/OverlayPanel.cs b/SystemHeat/SystemHeat/UI/Overlay/OverlayPanel.cs
index 28c2f9e..26d2cb4 100644
--- a/SystemHeat/SystemHeat/UI/Overlay/OverlayPanel.cs
+++ b/SystemHeat/SystemHeat/UI/Overlay/OverlayPanel.cs
@@ -80,15 +80,15 @@ public void LateUpdate()
{
if (heatModule.totalSystemFlux <= 0f)
{
- infoPanelUpperText.text = Localizer.Format("#LOC_SystemHeat_OverlayPanel_UpperTextNoTemp", heatModule.totalSystemFlux.ToString("F0"));
+ infoPanelUpperText.text = Localizer.Format("#LOC_SystemHeat_OverlayPanel_UpperTextNoTemp", Utils.ToSI(heatModule.totalSystemFlux,"F0"));
infoPanelTop.sizeDelta = new Vector2(infoPanelTop.sizeDelta.x, 26f);
} else
{
- infoPanelUpperText.text = Localizer.Format("#LOC_SystemHeat_OverlayPanel_UpperText", heatModule.systemNominalTemperature.ToString("F0"), heatModule.totalSystemFlux.ToString("F0"));
+ infoPanelUpperText.text = Localizer.Format("#LOC_SystemHeat_OverlayPanel_UpperText", heatModule.systemNominalTemperature.ToString("F0"), Utils.ToSI(heatModule.totalSystemFlux, "F0"));
infoPanelTop.sizeDelta = new Vector2(infoPanelTop.sizeDelta.x, 48f);
}
- infoPanelLowerText.text = Localizer.Format("#LOC_SystemHeat_OverlayPanel_LowerText", loop.Temperature.ToString("F0"), loop.NominalTemperature.ToString("F0"), loop.NetFlux.ToString("F0"), loop.Volume.ToString("F2"));
+ infoPanelLowerText.text = Localizer.Format("#LOC_SystemHeat_OverlayPanel_LowerText", loop.Temperature.ToString("F0"), loop.NominalTemperature.ToString("F0"), Utils.ToSI(loop.NetFlux,"F0"), loop.Volume.ToString("F2"));
}
float nominalTempDelta = loop.NominalTemperature - heatModule.systemNominalTemperature;
diff --git a/SystemHeat/SystemHeat/UI/Overlay/SystemHeatOverlay.cs b/SystemHeat/SystemHeat/UI/Overlay/SystemHeatOverlay.cs
index 1f5a42c..46e2f88 100644
--- a/SystemHeat/SystemHeat/UI/Overlay/SystemHeatOverlay.cs
+++ b/SystemHeat/SystemHeat/UI/Overlay/SystemHeatOverlay.cs
@@ -202,7 +202,7 @@ protected void LateUpdate()
if (simulator != null && !(HighLogic.LoadedSceneIsFlight && MapView.MapIsEnabled))
{
- if (simulator.HeatLoops == null || simulator.HeatLoops.Count == 0 && overlayLoops.Count >0)
+ if (simulator.HeatLoops == null || simulator.HeatLoops.Count == 0 && overlayLoops.Count > 0)
{
Utils.Log(String.Format("[SystemHeatOverlay]: No loops, destroying overlay"), LogType.Overlay);
@@ -245,6 +245,7 @@ protected void LateUpdate()
foreach (ModuleSystemHeat system in loop.LoopModules)
{
int index = overlayPanels.FindIndex(f => f.heatModule == system);
+
if (index == -1)
{
Utils.Log($"[SystemHeatOverlay]: Building new OverlayPanel for system {system.moduleID}", LogType.Overlay);
@@ -254,14 +255,30 @@ protected void LateUpdate()
newUIPanel.transform.localPosition = Vector3.zero;
OverlayPanel panel = newUIPanel.AddComponent();
panel.parentCanvas = UIMasterController.Instance.appCanvas;
- panel.SetupLoop(loop, system, (SystemHeatUI.Instance.OverlayMasterState && SystemHeatUI.Instance.OverlayLoopState(loop.ID)));
+ if (system.moduleUsed)
+ {
+ panel.SetupLoop(loop, system, (SystemHeatUI.Instance.OverlayMasterState && SystemHeatUI.Instance.OverlayLoopState(loop.ID)));
+ }
+ else
+ {
+ panel.SetupLoop(loop, system, (false && SystemHeatUI.Instance.OverlayLoopState(loop.ID)));
+ }
overlayPanels.Add(panel);
+
}
else
{
// Update the panel
- overlayPanels[index].UpdateLoop(loop, system, (SystemHeatUI.Instance.OverlayMasterState && SystemHeatUI.Instance.OverlayLoopState(loop.ID)));
+ if (system.moduleUsed)
+ {
+ overlayPanels[index].UpdateLoop(loop, system, (SystemHeatUI.Instance.OverlayMasterState && SystemHeatUI.Instance.OverlayLoopState(loop.ID)));
+ }
+ else
+ {
+ overlayPanels[index].UpdateLoop(loop, system, (false && SystemHeatUI.Instance.OverlayLoopState(loop.ID)));
+ }
+
}
}
}
@@ -309,10 +326,6 @@ public void SetVisible(bool visible)
SetLoopVisiblity(visible);
SetPanelVisiblity(visible);
- //foreach (int id in overlayLoopVisibility.Keys.ToList())
- //{
- // overlayLoopVisibility[id] = visible;
- //}
}
public void SetVisible(bool visible, int loopID)
{
@@ -321,8 +334,6 @@ public void SetVisible(bool visible, int loopID)
SetLoopVisiblity(visible, loopID);
SetPanelVisiblity(visible, loopID);
-
- // overlayLoopVisibility[loopID] = visible;
}
private void SetPanelVisiblity(bool visible)
{
@@ -331,8 +342,10 @@ private void SetPanelVisiblity(bool visible)
{
if (overlayPanels[i] != null)
{
-
- overlayPanels[i].SetVisibility(visible);
+ if (overlayPanels[i].heatModule.moduleUsed)
+ overlayPanels[i].SetVisibility(visible);
+ else
+ overlayPanels[i].SetVisibility(false);
}
}
}
@@ -343,7 +356,10 @@ private void SetPanelVisiblity(bool visible, int loopID)
{
if (overlayPanels[i] != null && overlayPanels[i].loop.ID == loopID)
{
- overlayPanels[i].SetVisibility(visible);
+ if (overlayPanels[i].heatModule.moduleUsed)
+ overlayPanels[i].SetVisibility(visible);
+ else
+ overlayPanels[i].SetVisibility(false);
}
}
}
diff --git a/SystemHeat/SystemHeat/UI/ReactorUI/ReactorWidget.cs b/SystemHeat/SystemHeat/UI/ReactorUI/ReactorWidget.cs
index 2033b4a..493faf8 100644
--- a/SystemHeat/SystemHeat/UI/ReactorUI/ReactorWidget.cs
+++ b/SystemHeat/SystemHeat/UI/ReactorUI/ReactorWidget.cs
@@ -225,7 +225,8 @@ protected void FixedUpdate()
if (module.moduleName == "FusionReactor" || module.moduleName == "ModuleFusionEngine")
{
nominalTemp = float.Parse(module.Fields.GetValue("SystemOutletTemperature").ToString());
- datafields["heatGenerated"].SetValue(Localizer.Format("#LOC_SystemHeat_ReactorPanel_Field_HeatGenerated", float.Parse(module.Fields.GetValue("SystemPower").ToString()).ToString("F0")));
+ datafields["heatGenerated"].SetValue(Localizer.Format("#LOC_SystemHeat_ReactorPanel_Field_HeatGenerated",
+ Utils.ToSI(float.Parse(module.Fields.GetValue("SystemPower").ToString()), "F0")));
datafields["powerGenerated"].SetValue(Localizer.Format("#LOC_SystemHeat_ReactorPanel_Field_PowerGenerated", float.Parse(module.Fields.GetValue("CurrentPowerProduced").ToString()).ToString("F0")));
datafields["lifetime"].SetValue(Localizer.Format("#LOC_SystemHeat_ReactorPanel_Field_CoreLife", module.Fields.GetValue("FuelInput")));
datafields["temperature"].SetValue(Localizer.Format("#LOC_SystemHeat_ReactorPanel_Field_CoreTemperature", heatModule.LoopTemperature.ToString("F0")));
@@ -263,7 +264,8 @@ protected void FixedUpdate()
if (module.moduleName == "ModuleSystemHeatFissionReactor" || module.moduleName == "ModuleSystemHeatFissionEngine")
{
nominalTemp = float.Parse(module.Fields.GetValue("NominalTemperature").ToString());
- datafields["heatGenerated"].SetValue(Localizer.Format("#LOC_SystemHeat_ReactorPanel_Field_HeatGenerated", float.Parse(module.Fields.GetValue("CurrentHeatGeneration").ToString()).ToString("F0")));
+ datafields["heatGenerated"].SetValue(Localizer.Format("#LOC_SystemHeat_ReactorPanel_Field_HeatGenerated",
+ Utils.ToSI(float.Parse(module.Fields.GetValue("CurrentHeatGeneration").ToString()), "F0")));
datafields["powerGenerated"].SetValue(Localizer.Format("#LOC_SystemHeat_ReactorPanel_Field_PowerGenerated", float.Parse(module.Fields.GetValue("CurrentElectricalGeneration").ToString()).ToString("F0")));
datafields["lifetime"].SetValue(Localizer.Format("#LOC_SystemHeat_ReactorPanel_Field_CoreLife", module.Fields.GetValue("FuelStatus")));
diff --git a/SystemHeat/SystemHeat/UI/ToolbarPanel.cs b/SystemHeat/SystemHeat/UI/ToolbarPanel.cs
index 1c42b81..90a6160 100644
--- a/SystemHeat/SystemHeat/UI/ToolbarPanel.cs
+++ b/SystemHeat/SystemHeat/UI/ToolbarPanel.cs
@@ -350,8 +350,8 @@ protected void Update()
}
totalLoopsValue.text = simulator.HeatLoops.Count.ToString();
- totalOutgoingFluxValue.text = Localizer.Format("#LOC_SystemHeat_ToolbarPanel_OutgoingFluxValue", simulator.TotalHeatRejection.ToString("F0"));
- totalIncomingFluxValue.text = Localizer.Format("#LOC_SystemHeat_ToolbarPanel_IncomingFluxValue", simulator.TotalHeatGeneration.ToString("F0"));
+ totalOutgoingFluxValue.text = Localizer.Format("#LOC_SystemHeat_ToolbarPanel_OutgoingFluxValue", Utils.ToSI(simulator.TotalHeatRejection,"F0"));
+ totalIncomingFluxValue.text = Localizer.Format("#LOC_SystemHeat_ToolbarPanel_IncomingFluxValue", Utils.ToSI(simulator.TotalHeatGeneration, "F0"));
}
}
void DestroyLoopWidgets()
diff --git a/SystemHeat/SystemHeat/UI/ToolbarPanelLoopWidget.cs b/SystemHeat/SystemHeat/UI/ToolbarPanelLoopWidget.cs
index d50d85b..f9cbf2d 100644
--- a/SystemHeat/SystemHeat/UI/ToolbarPanelLoopWidget.cs
+++ b/SystemHeat/SystemHeat/UI/ToolbarPanelLoopWidget.cs
@@ -95,7 +95,7 @@ void Update()
prefix = "";
fluxTextValue.text = Localizer.Format("#LOC_SystemHeat_ToolbarPanel_LoopFluxValue", prefix,
- lp.NetFlux.ToString("F1"));
+ Utils.ToSI(lp.NetFlux,"F0"));
if (lp.Temperature >= lp.NominalTemperature)
{
diff --git a/SystemHeat/SystemHeat/Utils.cs b/SystemHeat/SystemHeat/Utils.cs
index 3a4317a..67bf2a7 100644
--- a/SystemHeat/SystemHeat/Utils.cs
+++ b/SystemHeat/SystemHeat/Utils.cs
@@ -53,6 +53,35 @@ public static void LogError(string toLog)
{
Debug.LogError(String.Format("[{0}]{1}", logTag, toLog));
}
+
+
+ public static string ToSI(float d, string format = null, float factor= 1000f)
+ {
+ if (d == 0.0)
+ return d.ToString(format);
+
+ char[] incPrefixes = new[] { 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y' };
+ char[] decPrefixes = new[] { 'm', '\u03bc', 'n', 'p', 'f', 'a', 'z', 'y' };
+
+ d *= factor;
+
+ int degree = Mathf.Clamp((int)Math.Floor(Math.Log10(Math.Abs(d)) / 3), -8, 8);
+ if (degree == 0)
+ return d.ToString(format);
+
+ double scaled = d * Math.Pow(1000, -degree);
+
+ char? prefix = null;
+
+ switch (Math.Sign(degree))
+ {
+ case 1: prefix = incPrefixes[degree - 1]; break;
+ case -1: prefix = decPrefixes[-degree - 1]; break;
+ }
+
+ return scaled.ToString(format) + " " + prefix;
+ }
+
}
public static class TransformDeepChildExtension
@@ -73,6 +102,7 @@ public static Transform FindDeepChild(this Transform aParent, string aName)
return null;
}
+
/*
//Depth-first search
public static Transform FindDeepChild(this Transform aParent, string aName)
diff --git a/changelog.txt b/changelog.txt
index 5b9827f..8f261a2 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,3 +1,17 @@
+v0.6.0
+------
+- Most UI fields now report in SI-prefixed units for flux (W, kW, MW, etc). This is not (yet) true for all modules though.
+- Added new functionality to cool fuel tanks with radiators and the SH system
+- Added optional patch to apply this to CryoTanks
+- Added some guardrails around the handling of Kopernicus planets that might have inconsistently configured atmospheres
+- Added ingame settings. The following things can be customized per game
+-- Boiloff: enabled and scale
+-- Nuclear fuel transfer: require engineers, what level
+-- Fission reactor damage: allowed, various tuning variables
+- Fixed engine heat for VASIMR argon modes
+- Support USI reactors
+- Fixes to universal harvester patch
+
v0.5.6
------
- Added action groups to ModuleSystemHeatExchanger for Enable, Disable, Toggle and Toggle Direction
diff --git a/readme.txt b/readme.txt
index 5f3cce8..4f9d60e 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,10 +1,9 @@
================
-SystemHeat 0.5.5
+SystemHeat 0.6.0
================
A mod for Kerbal Space Program, intended to provide a better experience for heat management, particularly geared towards resource extraction, high energy engines, and nuclear reactors.
-
============
DEPENDENCIES
============
@@ -31,6 +30,8 @@ WARNING: Please note that these extras may break your ships in flight as they wi
- SystemHeatConverters: Converts converters to use SystemHeat
- SystemHeatFissionReactors: Converts nuclear reactors to use SystemHeat
- SystemHeatFissionEngines: When installed, nuclear engines will have integrated reactors
+- SystemHeatIonEngines: When installed, ion engines will generate heat
+- SystemHeatBoiloff: When installed, CryoTanks boiloff will require cooling instead of electricity
=======
KSP-AVC