public void FixedUpdate() { if (HighLogic.LoadedSceneIsFlight && _attached_engine != null && _attached_reactor != null && _attached_reactor.ChargedParticlePropulsionEfficiency > 0) { _max_charged_particles_power = _attached_reactor.MaximumChargedPower * exchanger_thrust_divisor * _attached_reactor.ChargedParticlePropulsionEfficiency; _charged_particles_requested = _attached_engine.isOperational && _attached_engine.currentThrottle > 0 ? _max_charged_particles_power : 0; _charged_particles_received = consumeFNResourcePerSecond(_charged_particles_requested, ResourceManager.FNRESOURCE_CHARGED_PARTICLES); // convert reactor product into propellants when possible var chargedParticleRatio = _attached_reactor.MaximumChargedPower > 0 ? _charged_particles_received / _attached_reactor.MaximumChargedPower : 0; var consumedByEngine = _attached_warpable_engine != null ? _attached_warpable_engine.propellantUsed : 0; _hydrogenProduction = !CheatOptions.InfinitePropellant && chargedParticleRatio > 0 ? _attached_reactor.UseProductForPropulsion(chargedParticleRatio, consumedByEngine) : 0; if (!CheatOptions.IgnoreMaxTemperature) { if (_attached_engine.isOperational && _attached_engine.currentThrottle > 0) { consumeFNResourcePerSecond(_charged_particles_received, ResourceManager.FNRESOURCE_WASTEHEAT); _previous_charged_particles_received = _charged_particles_received; } else if (_previous_charged_particles_received > 1) { consumeFNResourcePerSecond(_previous_charged_particles_received, ResourceManager.FNRESOURCE_WASTEHEAT); _previous_charged_particles_received /= 2; } else { _charged_particles_received = 0; _previous_charged_particles_received = 0; } } // update Isp double current_isp = !_attached_engine.isOperational || _attached_engine.currentThrottle == 0 ? maximum_isp : Math.Min(maximum_isp, minimum_isp / Math.Pow(_attached_engine.currentThrottle, throtleExponent)); var ispPowerCostMultiplier = 1 + max_power_multiplier - Math.Log10(current_isp / minimum_isp); _requestedElectricPower = _charged_particles_received * ispPowerCostMultiplier * 0.005 * Math.Max(_attached_reactor_distance, 1); _recievedElectricPower = CheatOptions.InfiniteElectricity ? _requestedElectricPower : consumeFNResourcePerSecond(_requestedElectricPower, ResourceManager.FNRESOURCE_MEGAJOULES); var megajoules_ratio = _recievedElectricPower / _requestedElectricPower; megajoules_ratio = (double.IsNaN(megajoules_ratio) || double.IsInfinity(megajoules_ratio)) ? 0 : megajoules_ratio; FloatCurve new_isp = new FloatCurve(); new_isp.Add(0, (float)(current_isp * megajoules_ratio), 0, 0); _attached_engine.atmosphereCurve = new_isp; double atmo_thrust_factor = Math.Min(1.0, Math.Max(1.0 - Math.Pow(vessel.atmDensity, 0.2), 0)); _engineMaxThrust = 0; if (_max_charged_particles_power > 0) { double powerThrustModifier = GameConstants.BaseThrustPowerMultiplier * powerThrustMultiplier; var enginethrust_from_recieved_particles = powerThrustModifier * _charged_particles_received * megajoules_ratio * atmo_thrust_factor / current_isp / PluginHelper.GravityConstant; var max_theoretical_thrust = powerThrustModifier * _max_charged_particles_power * atmo_thrust_factor / current_isp / PluginHelper.GravityConstant; _engineMaxThrust = _attached_engine.currentThrottle > 0 ? Math.Max(enginethrust_from_recieved_particles, 0.000000001) : Math.Max(max_theoretical_thrust, 0.000000001); } var max_fuel_flow_rate = !double.IsInfinity(_engineMaxThrust) && !double.IsNaN(_engineMaxThrust) && current_isp > 0 ? _engineMaxThrust / current_isp / PluginHelper.GravityConstant / (_attached_engine.currentThrottle > 0 ? _attached_engine.currentThrottle : 1) : 0; // set maximum flow _attached_engine.maxFuelFlow = Math.Max((float)max_fuel_flow_rate, 0.0000000001f); // This whole thing may be inefficient, but it should clear up some confusion for people. if (!_attached_engine.getFlameoutState) { if (megajoules_ratio < 0.75 && _requestedElectricPower > 0) { _attached_engine.status = "Insufficient Electricity"; } else if (atmo_thrust_factor < 0.75) { _attached_engine.status = "Too dense atmospherere"; } } } else if (_attached_engine != null) { _attached_engine.maxFuelFlow = 0.0000000001f; _recievedElectricPower = 0; _charged_particles_requested = 0; _charged_particles_received = 0; _engineMaxThrust = 0; } }
// FixedUpdate is also called in the Editor public void FixedUpdate() { if (HighLogic.LoadedSceneIsEditor) { return; } if (_attached_engine == null) { return; } if (_attached_reactor != null && _attached_reactor.ChargedParticlePropulsionEfficiency > 0) { if (_attached_reactor.Part != this.part) { resourceBuffers.UpdateVariable(ResourceManager.FNRESOURCE_WASTEHEAT, this.part.mass); resourceBuffers.UpdateBuffers(); } _max_charged_particles_power = _attached_reactor.MaximumChargedPower * exchanger_thrust_divisor * _attached_reactor.ChargedParticlePropulsionEfficiency; _charged_particles_requested = _attached_engine.isOperational && _attached_engine.currentThrottle > 0 ? _max_charged_particles_power : 0; _charged_particles_received = consumeFNResourcePerSecond(_charged_particles_requested, ResourceManager.FNRESOURCE_CHARGED_PARTICLES); // convert reactor product into propellants when possible var chargedParticleRatio = _attached_reactor.MaximumChargedPower > 0 ? _charged_particles_received / _attached_reactor.MaximumChargedPower : 0; // update Isp var currentIsp = !_attached_engine.isOperational || _attached_engine.currentThrottle == 0 ? maximum_isp : Math.Min(maximum_isp, minimum_isp / Math.Pow(_attached_engine.currentThrottle, throtleExponent)); var powerThrustModifier = GameConstants.BaseThrustPowerMultiplier * powerThrustMultiplier; var max_engine_thrust_at_max_isp = powerThrustModifier * _charged_particles_received / maximum_isp / GameConstants.STANDARD_GRAVITY; var calculatedConsumptionInTon = max_engine_thrust_at_max_isp / maximum_isp / GameConstants.STANDARD_GRAVITY; // generate addition propellant from reactor fuel consumption _attached_reactor.UseProductForPropulsion(chargedParticleRatio, calculatedConsumptionInTon); calculatedConsumptionPerSecond = calculatedConsumptionInTon * 1000; if (!CheatOptions.IgnoreMaxTemperature) { if (_attached_engine.isOperational && _attached_engine.currentThrottle > 0) { consumeFNResourcePerSecond(_charged_particles_received, ResourceManager.FNRESOURCE_WASTEHEAT); _previous_charged_particles_received = _charged_particles_received; } else if (_previous_charged_particles_received > 0) { consumeFNResourcePerSecond(_previous_charged_particles_received, ResourceManager.FNRESOURCE_WASTEHEAT); _previous_charged_particles_received = 0; } else { _charged_particles_received = 0; _previous_charged_particles_received = 0; } } // calculate power cost var ispPowerCostMultiplier = 1 + max_power_multiplier - Math.Log10(currentIsp / minimum_isp); var minimumEnginePower = _attached_reactor.MagneticNozzlePowerMult * _charged_particles_received * ispPowerCostMultiplier * 0.005 * Math.Max(_attached_reactor_distance, 1); var neededBufferPower = Math.Min(Math.Max(powerBufferMax - powerBufferStore, 0), minimumEnginePower); _requestedElectricPower = minimumEnginePower + neededBufferPower; _recievedElectricPower = CheatOptions.InfiniteElectricity ? _requestedElectricPower : consumeFNResourcePerSecond(_requestedElectricPower, ResourceManager.FNRESOURCE_MEGAJOULES); // adjust power buffer var powerSurplus = _recievedElectricPower - minimumEnginePower; if (powerSurplus < 0) { var powerFromBuffer = Math.Min(-powerSurplus, powerBufferStore); _recievedElectricPower += powerFromBuffer; powerBufferStore -= powerFromBuffer; } else { powerBufferStore += powerSurplus; } // calculate Power factor megajoulesRatio = Math.Min(_recievedElectricPower / minimumEnginePower, 1); megajoulesRatio = (double.IsNaN(megajoulesRatio) || double.IsInfinity(megajoulesRatio)) ? 0 : megajoulesRatio; var scaledPowerFactor = Math.Pow(megajoulesRatio, 0.5); double atmoIspFactor = 1; _engineMaxThrust = 0; if (_max_charged_particles_power > 0) { var enginethrust_from_recieved_particles = powerThrustModifier * _charged_particles_received * scaledPowerFactor / currentIsp / GameConstants.STANDARD_GRAVITY; var effective_thrust = Math.Max(enginethrust_from_recieved_particles - (radius * radius * vessel.atmDensity * 100), 0); var max_theoretical_thrust = powerThrustModifier * _max_charged_particles_power / currentIsp / GameConstants.STANDARD_GRAVITY; atmoIspFactor = max_theoretical_thrust > 0 ? effective_thrust / max_theoretical_thrust : 0; _engineMaxThrust = _attached_engine.currentThrottle > 0 ? Math.Max(effective_thrust, 0.000000001) : Math.Max(max_theoretical_thrust, 0.000000001); } // set isp FloatCurve newAtmosphereCurve = new FloatCurve(); newAtmosphereCurve.Add(0, (float)(currentIsp * scaledPowerFactor * atmoIspFactor), 0, 0); _attached_engine.atmosphereCurve = newAtmosphereCurve; var max_fuel_flow_rate = !double.IsInfinity(_engineMaxThrust) && !double.IsNaN(_engineMaxThrust) && currentIsp > 0 ? _engineMaxThrust / currentIsp / GameConstants.STANDARD_GRAVITY / (_attached_engine.currentThrottle > 0 ? _attached_engine.currentThrottle : 1) : 0; // set maximum flow _attached_engine.maxFuelFlow = Math.Max((float)max_fuel_flow_rate, 0.0000000001f); _attached_engine.useThrustCurve = false; // This whole thing may be inefficient, but it should clear up some confusion for people. if (_attached_engine.getFlameoutState) { return; } if (_attached_engine.currentThrottle < 0.99) { _attached_engine.status = "offline"; } else if (megajoulesRatio < 0.75 && _requestedElectricPower > 0) { _attached_engine.status = "Insufficient Electricity"; } else if (atmoIspFactor < 0.01) { _attached_engine.status = "Too dense atmospherere"; } } else { _attached_engine.maxFuelFlow = 0.0000000001f; _recievedElectricPower = 0; _charged_particles_requested = 0; _charged_particles_received = 0; _engineMaxThrust = 0; } }
public void FixedUpdate() { if (HighLogic.LoadedSceneIsFlight && _attached_engine != null && _attached_engine.isOperational && _attached_reactor != null) { double joules_per_amu = _attached_reactor.CurrentMeVPerChargedProduct * 1e6 * GameConstants.ELECTRON_CHARGE / GameConstants.dilution_factor; double minimum_isp = Math.Sqrt(joules_per_amu * 2.0 / GameConstants.ATOMIC_MASS_UNIT) / PluginHelper.GravityConstant; var throttle = _attached_engine.currentThrottle; var maximum_isp = minimum_isp * 114; //113.835; var current_isp = throttle == 0 ? maximum_isp : Math.Min(maximum_isp, minimum_isp / throttle / throttle); // update Isp FloatCurve new_isp = new FloatCurve(); new_isp.Add(0, (float)current_isp, 0, 0); _attached_engine.atmosphereCurve = new_isp; _max_charged_particles_power = _attached_reactor.MaximumChargedPower * exchanger_thrust_divisor; _charged_particles_requested = throttle > 0 ? _max_charged_particles_power : 0; _charged_particles_received = consumeFNResource(_charged_particles_requested * TimeWarp.fixedDeltaTime, FNResourceManager.FNRESOURCE_CHARGED_PARTICLES) / TimeWarp.fixedDeltaTime; // convert reactor product into propellants when possible var chargedParticleRatio = _attached_reactor.MaximumChargedPower > 0 ? _charged_particles_received / _attached_reactor.MaximumChargedPower : 0; var consumedByEngine = _attached_warpable_engine != null ? _attached_warpable_engine.propellantUsed : 0; _hydrogenProduction = chargedParticleRatio > 0 ? (float)_attached_reactor.UseProductForPropulsion(chargedParticleRatio, consumedByEngine) : 0; consumeFNResource(_charged_particles_received * TimeWarp.fixedDeltaTime, FNResourceManager.FNRESOURCE_WASTEHEAT); _requestedElectricPower = _charged_particles_received * (0.01f * Math.Max(_attached_reactor_distance, 1)); _recievedElectricPower = consumeFNResource(_requestedElectricPower * TimeWarp.fixedDeltaTime, FNResourceManager.FNRESOURCE_MEGAJOULES) / TimeWarp.fixedDeltaTime; double megajoules_ratio = _recievedElectricPower / _requestedElectricPower; megajoules_ratio = (double.IsNaN(megajoules_ratio) || double.IsInfinity(megajoules_ratio)) ? 0 : megajoules_ratio; double atmo_thrust_factor = Math.Min(1.0, Math.Max(1.0 - Math.Pow(vessel.atmDensity, 0.2), 0)); _engineMaxThrust = 0; if (_max_charged_particles_power > 0) { double powerThrustModifier = GameConstants.BaseThrustPowerMultiplier * powerThrustMultiplier; var enginethrust_from_recieved_particles = powerThrustModifier * _charged_particles_received * megajoules_ratio * atmo_thrust_factor / current_isp / PluginHelper.GravityConstant; var max_theoretical_thrust = powerThrustModifier * _max_charged_particles_power * atmo_thrust_factor / current_isp / PluginHelper.GravityConstant; _engineMaxThrust = throttle > 0 ? (float)Math.Max(enginethrust_from_recieved_particles, 0.000000001) : (float)Math.Max(max_theoretical_thrust, 0.000000001); } var max_fuel_flow_rate = !double.IsInfinity(_engineMaxThrust) && !double.IsNaN(_engineMaxThrust) && current_isp > 0 ? _engineMaxThrust / current_isp / PluginHelper.GravityConstant / (throttle > 0 ? throttle : 1) : 0; // set maximum flow _attached_engine.maxFuelFlow = Math.Min(0.5f, (float)max_fuel_flow_rate); // This whole thing may be inefficient, but it should clear up some confusion for people. if (!_attached_engine.getFlameoutState) { if (megajoules_ratio < 0.75 && _requestedElectricPower > 0) { _attached_engine.status = "Insufficient Electricity"; } else if (atmo_thrust_factor < 0.75) { _attached_engine.status = "Too dense atmospherere"; } } } else if (_attached_engine != null) { _attached_engine.maxFuelFlow = 0; _recievedElectricPower = 0; _charged_particles_requested = 0; _charged_particles_received = 0; _engineMaxThrust = 0; } }