// 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 / PluginHelper.GravityConstant;
                var calculatedConsumptionInTon   = max_engine_thrust_at_max_isp / maximum_isp / PluginHelper.GravityConstant;

                // 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 / PluginHelper.GravityConstant;

                    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 / PluginHelper.GravityConstant;

                    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 / 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);
                _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 override void OnStart(PartModule.StartState state)
        {
            try
            {
                Debug.Log("[KSPI]: Start ElectricEngineControllerFX");

                if (state != StartState.Editor)
                {
                    if (vessel.FindPartModulesImplementing <FNGenerator>().Any(m => m.isHighPower) == false)
                    {
                        if (powerThrustMultiplier == 1 && powerThrustMultiplierWithoutReactors > 0)
                        {
                            powerThrustMultiplier = powerThrustMultiplierWithoutReactors;
                        }

                        if (powerReqMult == 1 && powerReqMultWithoutReactor > 0)
                        {
                            powerReqMult = powerReqMultWithoutReactor;
                        }
                    }
                }

                ScaleParameters();

                // initialise resources
                this.resources_to_supply = new[] { ResourceManager.FNRESOURCE_WASTEHEAT };
                base.OnStart(state);

                AttachToEngine();
                DetermineTechLevel();
                powerCapacityModifier = PowerCapacityModifier;

                _initializationCountdown = 10;
                _ispFloatCurve           = new FloatCurve();
                _ispFloatCurve.Add(0, (float)baseISP);
                _speedOfLight          = GameConstants.speedOfLight * PluginHelper.SpeedOfLightMult;
                _hasGearTechnology     = String.IsNullOrEmpty(gearsTechReq) || PluginHelper.UpgradeAvailable(gearsTechReq);
                _modifiedEngineBaseIsp = baseISP * PluginHelper.ElectricEngineIspMult;
                _hasrequiredupgrade    = this.HasTechsRequiredToUpgrade();

                if (_hasrequiredupgrade && (isupgraded || state == StartState.Editor))
                {
                    upgradePartModule();
                }

                UpdateEngineTypeString();

                _resourceBuffers = new ResourceBuffers();
                _resourceBuffers.AddConfiguration(new ResourceBuffers.TimeBasedConfig(ResourceManager.FNRESOURCE_WASTEHEAT, wasteHeatMultiplier, 2.0e+4, true));
                _resourceBuffers.UpdateVariable(ResourceManager.FNRESOURCE_WASTEHEAT, (double)(decimal)this.part.mass);
                _resourceBuffers.Init(this.part);

                InitializePropellantMode();

                SetupPropellants(true);

                _attachedEngine.maxThrust = (float)maximumThrustFromPower;
            }
            catch (Exception e)
            {
                Debug.LogError("[KSPI]: Error OnStart ElectricEngineControllerFX " + e.Message);
            }
            Debug.Log("[KSPI]: End Initializing ElectricEngineControllerFX");
        }
        public void FixedUpdate() // FixedUpdate is also called when not activated
        {
            try
            {
                if (!HighLogic.LoadedSceneIsFlight)
                {
                    return;
                }

                if (!active)
                {
                    base.OnFixedUpdate();
                }

                if (resourceBuffers != null)
                {
                    resourceBuffers.UpdateVariable(ResourceManager.FNRESOURCE_WASTEHEAT, radiatorIsEnabled ? this.part.mass : this.part.mass * 1e-3);
                    resourceBuffers.UpdateBuffers();
                }

                // get resource bar ratio at start of frame
                ResourceManager wasteheatManager = getManagerForVessel(ResourceManager.FNRESOURCE_WASTEHEAT);

                if (Double.IsNaN(wasteheatManager.TemperatureRatio))
                {
                    Debug.LogError("[KSPI]: FNRadiator: FixedUpdate Single.IsNaN detected in TemperatureRatio");
                    return;
                }

                // ToDo replace wasteheatManager.SqrtResourceBarRatioBegin by ResourceBarRatioBegin after generators hotbath takes into account expected temperature
                radiator_temperature_temp_val = external_temperature + Math.Min(maximumTemperatureDifferenceWithExternal * wasteheatManager.TemperatureRatio, currentTemperatureDifferenceWithExternal);

                var deltaTemp            = Math.Max(radiator_temperature_temp_val - Math.Max(external_temperature * Math.Min(1, vessel.atmDensity), PhysicsGlobals.SpaceTemperature), 0);
                var deltaTempToPowerFour = deltaTemp * deltaTemp * deltaTemp * deltaTemp;

                if (radiatorIsEnabled)
                {
                    if (!CheatOptions.IgnoreMaxTemperature && wasteheatManager.ResourceBarRatioBegin >= 1 && CurrentRadiatorTemperature >= maxRadiatorTemperature)
                    {
                        explode_counter++;
                        if (explode_counter > 25)
                        {
                            part.explode();
                        }
                    }
                    else
                    {
                        explode_counter = 0;
                    }

                    thermalPowerDissipPerSecond = (double)wasteheatManager.RadiatorEfficiency * deltaTempToPowerFour * stefanArea;

                    if (Double.IsNaN(thermalPowerDissipPerSecond))
                    {
                        Debug.LogWarning("[KSPI]: FNRadiator: FixedUpdate Single.IsNaN detected in thermalPowerDissipPerSecond");
                    }

                    radiatedThermalPower = canRadiateHeat ? consumeWasteHeatPerSecond(thermalPowerDissipPerSecond, wasteheatManager) : 0;

                    if (Double.IsNaN(radiatedThermalPower))
                    {
                        Debug.LogError("[KSPI]: FNRadiator: FixedUpdate Single.IsNaN detected in radiatedThermalPower after call consumeWasteHeat (" + thermalPowerDissipPerSecond + ")");
                    }

                    instantaneous_rad_temp = CalculateInstantaniousRadTemp(external_temperature);

                    CurrentRadiatorTemperature = instantaneous_rad_temp;

                    if (_moduleDeployableRadiator)
                    {
                        _moduleDeployableRadiator.hasPivot = pivotEnabled;
                    }
                }
                else
                {
                    thermalPowerDissipPerSecond = (double)wasteheatManager.RadiatorEfficiency * deltaTempToPowerFour * stefanArea * 0.5;

                    radiatedThermalPower = canRadiateHeat ? consumeWasteHeatPerSecond(thermalPowerDissipPerSecond, wasteheatManager) : 0;

                    instantaneous_rad_temp = CalculateInstantaniousRadTemp(external_temperature);

                    CurrentRadiatorTemperature = instantaneous_rad_temp;
                }

                if (vessel.atmDensity > 0)
                {
                    atmosphere_modifier = vessel.atmDensity * convectiveBonus + vessel.speed.Sqrt();

                    var heatTransferCooficient = 0.0005; // 500W/m2/K
                    var temperatureDifference  = Math.Max(0, CurrentRadiatorTemperature - external_temperature);
                    var submergedModifier      = Math.Max(part.submergedPortion * 10, 1);

                    var convPowerDissip = (double)wasteheatManager.RadiatorEfficiency * atmosphere_modifier * temperatureDifference * effectiveRadiatorArea * heatTransferCooficient * submergedModifier;

                    if (!radiatorIsEnabled)
                    {
                        convPowerDissip = convPowerDissip * 0.25;
                    }

                    convectedThermalPower = canRadiateHeat ? consumeWasteHeatPerSecond(convPowerDissip, wasteheatManager) : 0;

                    if (radiator_deploy_delay >= DEPLOYMENT_DELAY)
                    {
                        DeployMentControl();
                    }
                }
                else
                {
                    convectedThermalPower = 0;

                    if (radiatorIsEnabled || !isAutomated || !canRadiateHeat || !showControls || radiator_deploy_delay < DEPLOYMENT_DELAY)
                    {
                        return;
                    }

                    Debug.Log("[KSPI]: FixedUpdate Automated Deployment ");
                    Deploy();
                }
            }
            catch (Exception e)
            {
                Debug.LogError("[KSPI]: Exception on " + part.name + " durring FNRadiator.FixedUpdate with message " + e.Message);
            }
        }
 public override void OnFixedUpdate() // OnFixedUpdate is only called when (force) activated
 {
     _resourceBuffers.UpdateVariable(ResourceSettings.Config.WasteHeatInMegawatt, part.mass);
     _resourceBuffers.UpdateBuffers();
 }
        public override void OnStart(StartState state)
        {
            try
            {
                if (state.ToString().Contains(StartState.PreLaunch.ToString()))
                {
                    Debug.Log("[KSPI]: PreLaunch uses InitialGearRatio:" + InitialGearRatio);
                    SelectedIsp = ((MaxIsp - MinIsp) * Math.Max(0, Math.Min(1, InitialGearRatio))) + MinIsp;
                }

                Fields["selectedFuel"].guiName = fuelSwitchName;

                Fields["currentMaximumPowerRequirement"].guiActive = powerRequirement > 0;
                Fields["laserWasteheat"].guiActive    = powerRequirement > 0 && fusionWasteHeat > 0;
                Fields["absorbedWasteheat"].guiActive = powerRequirement > 0 && fusionWasteHeat > 0;
                Fields["fusionRatio"].guiActive       = powerRequirement > 0;

                Fields["powerRequirement"].guiActiveEditor          = powerRequirement > 0;
                Fields["powerRequirementUpgraded1"].guiActiveEditor = powerRequirementUpgraded1 > 0;
                Fields["powerRequirementUpgraded2"].guiActiveEditor = powerRequirementUpgraded2 > 0;
                Fields["powerRequirementUpgraded3"].guiActiveEditor = powerRequirementUpgraded3 > 0;
                Fields["powerRequirementUpgraded4"].guiActiveEditor = powerRequirementUpgraded4 > 0;

                Fields["fusionWasteHeat"].guiActiveEditor          = fusionWasteHeat > 0;
                Fields["fusionWasteHeatUpgraded1"].guiActiveEditor = !String.IsNullOrEmpty(upgradeTechReq1);
                Fields["fusionWasteHeatUpgraded2"].guiActiveEditor = !String.IsNullOrEmpty(upgradeTechReq2);
                Fields["fusionWasteHeatUpgraded3"].guiActiveEditor = !String.IsNullOrEmpty(upgradeTechReq3);
                Fields["fusionWasteHeatUpgraded4"].guiActiveEditor = !String.IsNullOrEmpty(upgradeTechReq4);

                part.maxTemp             = maxTemp;
                part.thermalMass         = 1;
                part.thermalMassModifier = 1;

                curEngineT = this.part.FindModuleImplementing <ModuleEngines>();
                if (curEngineT == null)
                {
                    Debug.LogError("[KSPI]: FusionEngine OnStart Engine not found");
                    return;
                }
                BaseFloatCurve = curEngineT.atmosphereCurve;

                curveMaxISP = GetMaxKey(BaseFloatCurve);
                if (hasMultipleConfigurations)
                {
                    FcSetup();
                }

                InitializeKerbalismEmitter();

                DetermineTechLevel();

                resourceBuffers = new ResourceBuffers();
                resourceBuffers.AddConfiguration(new ResourceBuffers.TimeBasedConfig(ResourceManager.FNRESOURCE_WASTEHEAT, wasteHeatMultiplier, 1.0e+4, true));
                resourceBuffers.UpdateVariable(ResourceManager.FNRESOURCE_WASTEHEAT, this.part.mass);
                resourceBuffers.Init(this.part);

                if (state != StartState.Editor)
                {
                    part.emissiveConstant = maxTempatureRadiators > 0 ? 1 - coldBathTemp / maxTempatureRadiators : 0.01;
                }

                base.OnStart(state);

                Fields["localIsp"].guiActive       = selectableIsp;
                Fields["localIsp"].guiActiveEditor = selectableIsp;
            }
            catch (Exception e)
            {
                Debug.LogError("[KSPI]: FusionEngine OnStart eception: " + e.Message);
            }
        }
        public override void OnStart(PartModule.StartState state)
        {
            if (state == StartState.Editor)
            {
                return;
            }

            megaJouleSolarPowerSupplyField = Fields["megaJouleSolarPowerSupply"];
            solarMaxSupplyField            = Fields["solarMaxSupply"];

            if (part.Modules.Contains("SolarPanelFixer"))
            {
                solarPanelFixer = part.Modules["SolarPanelFixer"];

                _field_kerbalism_nominalRate = solarPanelFixer.Fields["nominalRate"];
                _field_kerbalism_panelStatus = solarPanelFixer.Fields["panelStatus"];
            }

            // calculate Astronomical unit on homeworld semiMajorAxis when missing
            if (astronomicalUnit == 0)
            {
                astronomicalUnit = FlightGlobals.GetHomeBody().orbit.semiMajorAxis;
            }

            _microwavePowerReceiver = part.FindModuleImplementing <BeamedPowerReceiver>();

            _solarPanel = (ModuleDeployableSolarPanel)this.part.FindModuleImplementing <ModuleDeployableSolarPanel>();
            if (_solarPanel == null)
            {
                return;
            }

            if (this.part.FindModuleImplementing <ModuleJettison>() == null)
            {
                UnityEngine.Debug.Log("[KSPI]: FNSolarPanelWasteHeatModule Force Activated  " + part.name);
                part.force_activate();
            }

            String[] resources_to_supply = { ResourceManager.FNRESOURCE_MEGAJOULES };
            this.resources_to_supply = resources_to_supply;
            base.OnStart(state);

            outputResource = _solarPanel.resHandler.outputResources.FirstOrDefault();
            resourceName   = _solarPanel.resourceName;

            if (resourceName == ResourceManager.FNRESOURCE_MEGAJOULES)
            {
                _outputType = ResourceType.megajoule;
            }
            else if (resourceName == ResourceManager.STOCK_RESOURCE_ELECTRICCHARGE)
            {
                _outputType = ResourceType.electricCharge;
            }
            else
            {
                _outputType = ResourceType.other;
            }

            // only manage power buffer when microwave receiver is not available
            if (_outputType != ResourceType.other && _microwavePowerReceiver == null)
            {
                _resourceBuffers = new ResourceBuffers();
                _resourceBuffers.AddConfiguration(new ResourceBuffers.TimeBasedConfig(ResourceManager.FNRESOURCE_MEGAJOULES));
                _resourceBuffers.AddConfiguration(new ResourceBuffers.TimeBasedConfig(ResourceManager.STOCK_RESOURCE_ELECTRICCHARGE));
                _resourceBuffers.UpdateVariable(ResourceManager.FNRESOURCE_MEGAJOULES, _outputType == ResourceType.electricCharge ? _solarPanel.chargeRate * 0.001f : _solarPanel.chargeRate);
                _resourceBuffers.UpdateVariable(ResourceManager.STOCK_RESOURCE_ELECTRICCHARGE, _outputType == ResourceType.electricCharge ? _solarPanel.chargeRate : _solarPanel.chargeRate * 1000);
                _resourceBuffers.Init(part);
            }

            _stars = KopernicusHelper.Stars;
        }
Example #7
0
        // ReSharper disable once UnusedMember.Global
        public void FixedUpdate()
        {
            if (_initializationCountdown > 0)
            {
                _initializationCountdown--;
            }

            if (vesselChangedSIOCountdown > 0)
            {
                vesselChangedSIOCountdown--;
            }

            if (!HighLogic.LoadedSceneIsFlight)
            {
                return;
            }

            if (_attachedEngine == null)
            {
                return;
            }

            CalculateTimeDialation();

            if (_attachedEngine is ModuleEnginesFX)
            {
                GetAllPropellants().ForEach(prop => part.Effect(prop.ParticleFXName, 0, -1)); // set all FX to zero
            }
            if (Current_propellant == null)
            {
                return;
            }

            resourceBuffers.UpdateVariable(ResourceManager.FNRESOURCE_WASTEHEAT, (double)(decimal)this.part.mass);
            resourceBuffers.UpdateBuffers();

            if (!this.vessel.packed && !_warpToReal)
            {
                storedThrotle = vessel.ctrlState.mainThrottle;
            }

            // retrieve power
            maxEffectivePower = MaxEffectivePower;
            var sumOfAllEffectivePower = vessel.FindPartModulesImplementing <ElectricEngineControllerFX>().Where(ee => ee.IsOperational).Sum(ee => ee.MaxEffectivePower);

            _electrical_share_f = sumOfAllEffectivePower > 0 ? maxEffectivePower / sumOfAllEffectivePower : 1;

            maxThrottlePower = maxEffectivePower * ModifiedThrotte;
            var currentPropellantEfficiency = CurrentPropellantEfficiency;

            //var availablePower = Math.Max(getStableResourceSupply(ResourceManager.FNRESOURCE_MEGAJOULES) - getCurrentHighPriorityResourceDemand(ResourceManager.FNRESOURCE_MEGAJOULES), 0);
            var availablePower = getAvailableResourceSupply(ResourceManager.FNRESOURCE_MEGAJOULES);

            maxThrustInSpace          = EvaluateMaxThrust(availablePower * _electrical_share_f);
            _attachedEngine.maxThrust = (float)Math.Max(maxThrustInSpace, 0.001);

            if (CheatOptions.InfiniteElectricity)
            {
                power_request = maxThrottlePower;
            }
            else
            {
                var megaJoulesBarRatio         = getResourceBarRatio(ResourceManager.FNRESOURCE_MEGAJOULES);
                var effectiveResourceThrotling = megaJoulesBarRatio > OneThird ? 1 : megaJoulesBarRatio * 3;
                var powerPerEngine             = effectiveResourceThrotling * ModifiedThrotte * maxThrustInSpace * CurrentIspMultiplier * _modifiedEngineBaseIsp / GetPowerThrustModifier() * GameConstants.STANDARD_GRAVITY;
                power_request = currentPropellantEfficiency <= 0 ? 0 : Math.Min(powerPerEngine / currentPropellantEfficiency, maxThrottlePower);
            }

            var powerReceived = CheatOptions.InfiniteElectricity
                ? power_request
                : consumeFNResourcePerSecond(power_request, ResourceManager.FNRESOURCE_MEGAJOULES);

            // produce waste heat
            var heatToProduce = powerReceived * (1 - currentPropellantEfficiency) * Current_propellant.WasteHeatMultiplier;

            _heat_production_f = CheatOptions.IgnoreMaxTemperature
                ? heatToProduce
                : supplyFNResourcePerSecond(heatToProduce, ResourceManager.FNRESOURCE_WASTEHEAT);

            // update GUI Values
            _electrical_consumption_f = powerReceived;

            var effectiveIsp = _modifiedCurrentPropellantIspMultiplier * _modifiedEngineBaseIsp * ThrottleModifiedIsp();

            var throtteModifier = ispGears == 1 ? 1 : ModifiedThrotte;

            var effectivePower = timeDilation * currentPropellantEfficiency * CurrentPropellantThrustMultiplier * throtteModifier * GetPowerThrustModifier() * powerReceived;

            curThrustInSpace = effectivePower / effectiveIsp / GameConstants.STANDARD_GRAVITY;

            _maxIsp            = _modifiedEngineBaseIsp * _modifiedCurrentPropellantIspMultiplier * CurrentPropellantThrustMultiplier * ThrottleModifiedIsp();
            _spaceFuelFlowRate = _maxIsp <= 0 ? 0 : curThrustInSpace / _maxIsp / GameConstants.STANDARD_GRAVITY;

            var maxThrustWithCurrentThrottle = curThrustInSpace * throtteModifier;

            calculated_thrust = Current_propellant.SupportedEngines == 8
                ? maxThrustWithCurrentThrottle
                : Math.Max(maxThrustWithCurrentThrottle - (exitArea * vessel.staticPressurekPa), 0);

            var throttle = _attachedEngine.currentThrottle > 0 ? Math.Max((double)(decimal)_attachedEngine.currentThrottle, 0.01) : 0;

            if (throttle > 0)
            {
                if (IsValidPositiveNumber(calculated_thrust) && IsValidPositiveNumber(maxThrustWithCurrentThrottle))
                {
                    _atmosphereThrustEfficiency = Math.Min(1, calculated_thrust / maxThrustWithCurrentThrottle);

                    _atmosphereThrustEfficiencyPercentage = _atmosphereThrustEfficiency * 100;

                    UpdateIsp(_atmosphereThrustEfficiency);

                    _fuelFlowModifier = ispGears == 1
                        ? 1 / throttle
                        : ModifiedThrotte / throttle;

                    _maxFuelFlowRate            = _atmosphereThrustEfficiency * _spaceFuelFlowRate * _fuelFlowModifier;
                    _attachedEngine.maxFuelFlow = (float)Math.Max(_maxFuelFlowRate, 0.00000000001);
                }
                else
                {
                    UpdateIsp(1);
                    _atmosphereThrustEfficiency = 0;
                    _attachedEngine.maxFuelFlow = 0.00000000001f;
                }

                if (!this.vessel.packed)
                {
                    // allow throtle to be used up to Geeforce treshold
                    TimeWarp.GThreshold = GThreshold;

                    _isFullyStarted = true;
                    _ispPersistent  = (double)(decimal)_attachedEngine.realIsp;

                    thrust_d = (double)(decimal)_attachedEngine.requestedMassFlow * GameConstants.STANDARD_GRAVITY * _ispPersistent;
                }
                else if (this.vessel.packed && _attachedEngine.enabled && FlightGlobals.ActiveVessel == vessel && _initializationCountdown == 0)
                {
                    _warpToReal = true; // Set to true for transition to realtime

                    thrust_d = calculated_thrust;

                    if (PersistHeading())
                    {
                        PersistantThrust((double)(decimal)TimeWarp.fixedDeltaTime, Planetarium.GetUniversalTime(), this.part.transform.up, this.vessel.totalMass, thrust_d, _ispPersistent);
                    }
                }
                else
                {
                    IdleEngine();
                }
            }
            else
            {
                IdleEngine();
            }

            if (_attachedEngine is ModuleEnginesFX && particleEffectMult > 0)
            {
                var engineFuelFlow     = (double)(decimal)_attachedEngine.maxFuelFlow * (double)(decimal)_attachedEngine.currentThrottle;
                var max_fuel_flow_rate = (double)(decimal)_attachedEngine.maxThrust / (double)(decimal)_attachedEngine.realIsp / GameConstants.STANDARD_GRAVITY;

                effectPower = Math.Min(1, particleEffectMult * (engineFuelFlow / max_fuel_flow_rate));

                if (String.IsNullOrEmpty(EffectName))
                {
                    _particleFXName = Current_propellant.ParticleFXName;
                }
                else
                {
                    _particleFXName = EffectName;
                }

                this.part.Effect(_particleFXName, (float)effectPower, -1);
            }

            var vacuumPlasmaResource = part.Resources[InterstellarResourcesConfiguration.Instance.VacuumPlasma];

            if (isupgraded && vacuumPlasmaResource != null)
            {
                var calculatedConsumptionInTon = this.vessel.packed ? 0 : curThrustInSpace / engineIsp / GameConstants.STANDARD_GRAVITY;
                vacuumPlasmaResource.maxAmount = Math.Max(0.0000001, calculatedConsumptionInTon * 200 * (double)(decimal)TimeWarp.fixedDeltaTime);
                part.RequestResource(InterstellarResourcesConfiguration.Instance.VacuumPlasma, -vacuumPlasmaResource.maxAmount);
            }
        }
Example #8
0
        public override void OnFixedUpdateResourceSuppliable(double fixedDeltaTime)
        {
            temperatureStr = part.temperature.ToString("F0") + "K / " + part.maxTemp.ToString("F0") + "K";
            MinIsp         = BaseFloatCurve.Evaluate((float)altitude);

            resourceBuffers.UpdateVariable(ResourceSettings.Config.WasteHeatInMegawatt, part.mass);
            resourceBuffers.UpdateBuffers();

            if (curEngineT == null || !curEngineT.isEnabled)
            {
                return;
            }

            if (curEngineT.requestedThrottle > 0)
            {
                if (radHazard && rad_safety_features)
                {
                    ShutDown(Localizer.Format("#LOC_KSPIE_FusionECU2_PostMsg2"));//"Engines throttled down as they presently pose a radiation hazard"
                }
            }

            KillKerbalsWithRadiation(fusionRatio);

            hasIspThrottling = HasIspThrottling();

            ShowIspThrottle = hasIspThrottling;

            availablePower = Math.Max(GetResourceAvailability(ResourceSettings.Config.ElectricPowerInMegawatt), GetAvailablePrioritizedStableSupply(ResourceSettings.Config.ElectricPowerInMegawatt));

            currentMaximumPowerProduction  = GetCurrentMaximumPowerProduction();
            currentMaximumPowerRequirement = GetCurrentMaximumPowerRequirement();

            requiredPowerPerSecond = curEngineT.currentThrottle * currentMaximumPowerRequirement;

            if (curEngineT.currentThrottle > 0)
            {
                requestedPowerPerSecond = Math.Min(requiredPowerPerSecond, availablePower);

                recievedPowerPerSecond = requestedPowerPerSecond <= 0 ? 0
                    : CheatOptions.InfiniteElectricity
                        ? requiredPowerPerSecond
                        : ConsumeFnResourcePerSecond(requestedPowerPerSecond, ResourceSettings.Config.ElectricPowerInMegawatt);

                fusionRatio = requiredPowerPerSecond > 0 ? Math.Min(1, recievedPowerPerSecond / requiredPowerPerSecond) : 1;

                var inefficiency = 1 - LaserEfficiency;

                laserWasteheat         = recievedPowerPerSecond * inefficiency;
                producedPowerPerSecond = fusionRatio * currentMaximumPowerProduction;

                if (!CheatOptions.InfiniteElectricity && currentMaximumPowerProduction > 0)
                {
                    SupplyFnResourcePerSecondWithMax(producedPowerPerSecond, currentMaximumPowerProduction, ResourceSettings.Config.ElectricPowerInMegawatt);
                }

                // Lasers produce Wasteheat
                if (!CheatOptions.IgnoreMaxTemperature && laserWasteheat > 0)
                {
                    SupplyFnResourcePerSecondWithMax(laserWasteheat, currentMaximumPowerRequirement * inefficiency, ResourceSettings.Config.WasteHeatInMegawatt);
                }

                // The Absorbed wasteheat from Fusion
                rateMultplier        = hasIspThrottling ? Math.Pow(SelectedIsp / MinIsp, 2) : 1;
                neutronbsorbionBonus = hasIspThrottling ? 1 - NeutronAbsorptionFractionAtMinIsp * (1 - ((SelectedIsp - MinIsp) / (MaxIsp - MinIsp))) : 0.5;
                absorbedWasteheat    = FusionWasteHeat * fusionRatio * curEngineT.currentThrottle * neutronbsorbionBonus;
                SupplyFnResourcePerSecond(absorbedWasteheat, ResourceSettings.Config.WasteHeatInMegawatt);

                SetRatios();

                currentIsp = hasIspThrottling ? SelectedIsp : MinIsp;
                UpdateAtmosphereCurve(currentIsp);
                maximumThrust = hasIspThrottling ? MaximumThrust : FullTrustMaximum;

                // Update FuelFlow
                maxFuelFlow = fusionRatio * maximumThrust / currentIsp / PhysicsGlobals.GravitationalAcceleration;

                if ((maxAtmosphereDensity >= 0 && vessel.atmDensity > maxAtmosphereDensity) ||
                    (_currentActiveConfiguration.maxAtmosphereDensity >= 0 && vessel.atmDensity > _currentActiveConfiguration.maxAtmosphereDensity))
                {
                    ScreenMessages.PostScreenMessage(Localizer.Format("#LOC_KSPIE_FusionECU2_PostMsg1"), 1.0f, ScreenMessageStyle.UPPER_CENTER);
                    curEngineT.maxFuelFlow = 1e-10f;
                    curEngineT.maxThrust   = Mathf.Max((float)maximumThrust, 0.0001f);
                    HideExhaust();
                }
                else if (MinIsp < _currentActiveConfiguration.minIsp)
                {
                    ScreenMessages.PostScreenMessage(Localizer.Format("#LOC_KSPIE_FusionECU2_PostMsg3"), 1.0f, ScreenMessageStyle.UPPER_CENTER);
                    curEngineT.maxFuelFlow = 1e-10f;
                    curEngineT.maxThrust   = Mathf.Max((float)maximumThrust, 0.0001f);
                    HideExhaust();
                }
                else
                {
                    curEngineT.maxFuelFlow = Mathf.Max((float)maxFuelFlow, 1e-10f);
                    curEngineT.maxThrust   = Mathf.Max((float)maximumThrust, 0.0001f);
                }

                if (!curEngineT.getFlameoutState && fusionRatio < 0.9 && recievedPowerPerSecond > 0)
                {
                    curEngineT.status = Localizer.Format("#LOC_KSPIE_FusionECU2_statu1");//"Insufficient Electricity"
                }
            }
            else
            {
                absorbedWasteheat       = 0;
                laserWasteheat          = 0;
                requestedPowerPerSecond = 0;
                recievedPowerPerSecond  = 0;

                fusionRatio = requiredPowerPerSecond > 0 ? Math.Min(1, availablePower / requiredPowerPerSecond) : 1;

                currentIsp    = hasIspThrottling ? SelectedIsp : MinIsp;
                maximumThrust = hasIspThrottling ? MaximumThrust : FullTrustMaximum;

                UpdateAtmosphereCurve(currentIsp);

                rateMultplier = hasIspThrottling ? Math.Pow(SelectedIsp / MinIsp, 2) : 1;

                maxFuelFlow = fusionRatio * maximumThrust / currentIsp / PhysicsGlobals.GravitationalAcceleration;

                if ((maxAtmosphereDensity >= 0 && vessel.atmDensity > maxAtmosphereDensity) ||
                    (_currentActiveConfiguration.maxAtmosphereDensity >= 0 && vessel.atmDensity > _currentActiveConfiguration.maxAtmosphereDensity))
                {
                    curEngineT.maxFuelFlow = 1e-10f;
                    curEngineT.maxThrust   = Mathf.Max((float)maximumThrust, 0.0001f);
                    HideExhaust();
                }
                else if (MinIsp < _currentActiveConfiguration.minIsp)
                {
                    curEngineT.maxFuelFlow = 1e-10f;
                    curEngineT.maxThrust   = Mathf.Max((float)maximumThrust, 0.0001f);
                    HideExhaust();
                }
                else
                {
                    curEngineT.maxFuelFlow = Mathf.Max((float)maxFuelFlow, 1e-10f);
                    curEngineT.maxThrust   = Mathf.Max((float)maximumThrust, 0.0001f);
                }

                SetRatios();
            }

            coldBathTemp          = FNRadiator.GetAverageRadiatorTemperatureForVessel(vessel);
            maxTempatureRadiators = FNRadiator.GetAverageMaximumRadiatorTemperatureForVessel(vessel);
            radiatorPerformance   = Math.Max(1 - (coldBathTemp / maxTempatureRadiators), 0.000001);
            partEmissiveConstant  = part.emissiveConstant;
        }
Example #9
0
        public override void OnStart(StartState state)
        {
            String[] resourcesToSupply = { ResourceManager.FNRESOURCE_WASTEHEAT };
            this.resources_to_supply = resourcesToSupply;

            base.OnStart(state);

            radiatedThermalPower       = 0;
            convectedThermalPower      = 0;
            CurrentRadiatorTemperature = 0;
            update_count          = 0;
            radiator_deploy_delay = 0;
            explode_counter       = 0;

            DetermineGenerationType();

            maxRadiatorTemperature = (float)MaxRadiatorTemperature;

            if (hasSurfaceAreaUpgradeTechReq)
            {
                part.emissiveConstant = 1.6;
            }

            radiatorType = RadiatorType;

            effectiveRadiatorArea = EffectiveRadiatorArea;

            deployRadiatorEvent  = Events["DeployRadiator"];
            retractRadiatorEvent = Events["RetractRadiator"];

            thermalPowerConvStrField = Fields["thermalPowerConvStr"];
            radiatorIsEnabledField   = Fields["radiatorIsEnabled"];
            isAutomatedField         = Fields["isAutomated"];
            pivotEnabledField        = Fields["pivotEnabled"];

            var preventDeplyField = Fields["preventShieldedDeploy"];

            preventDeplyField.guiActive       = isDeployable;
            preventDeplyField.guiActiveEditor = isDeployable;

            Actions["DeployRadiatorAction"].guiName = Events["DeployRadiator"].guiName = "Deploy Radiator";
            Actions["ToggleRadiatorAction"].guiName = String.Format("Toggle Radiator");

            Actions["RetractRadiatorAction"].guiName = "Retract Radiator";
            Events["RetractRadiator"].guiName        = "Retract Radiator";

            var myAttachedEngine = part.FindModuleImplementing <ModuleEngines>();

            if (myAttachedEngine == null)
            {
                partMass = part.mass;
                Fields["partMass"].guiActiveEditor        = true;
                Fields["partMass"].guiActive              = true;
                Fields["convectiveBonus"].guiActiveEditor = true;
            }

            if (!String.IsNullOrEmpty(thermalAnim))
            {
                heatStates = PluginHelper.SetUpAnimation(thermalAnim, this.part);

                if (heatStates != null)
                {
                    SetHeatAnimationRatio(0);
                }
            }

            deployAnimation = part.FindModelAnimators(animName).FirstOrDefault();
            if (deployAnimation != null)
            {
                deployAnimation[animName].layer = 1;
                deployAnimation[animName].speed = 0;

                deployAnimation[animName].normalizedTime = radiatorIsEnabled ? 1 : 0;
            }

            _moduleActiveRadiator = part.FindModuleImplementing <ModuleActiveRadiator>();
            if (_moduleActiveRadiator != null)
            {
                _moduleActiveRadiator.Events["Activate"].guiActive = false;
                _moduleActiveRadiator.Events["Shutdown"].guiActive = false;
            }
            _moduleDeployableRadiator = part.FindModuleImplementing <ModuleDeployableRadiator>();
            if (_moduleDeployableRadiator != null)
            {
                radiatorState = _moduleDeployableRadiator.deployState;
            }

            var radiatorfield = Fields["radiatorIsEnabled"];

            radiatorfield.guiActive        = showControls;
            radiatorfield.guiActiveEditor  = showControls;
            radiatorfield.OnValueModified += radiatorIsEnabled_OnValueModified;

            var automatedfield = Fields["isAutomated"];

            automatedfield.guiActive       = showControls;
            automatedfield.guiActiveEditor = showControls;

            var pivotfield = Fields["pivotEnabled"];

            pivotfield.guiActive       = showControls;
            pivotfield.guiActiveEditor = showControls;

            if (_moduleActiveRadiator != null)
            {
                _maxEnergyTransfer = radiatorArea * 1000 * Math.Pow(1 + ((int)CurrentGenerationType), 2);
                _moduleActiveRadiator.maxEnergyTransfer = _maxEnergyTransfer;
                _moduleActiveRadiator.overcoolFactor    = 0.20 + ((int)CurrentGenerationType * 0.025);
            }

            if (state == StartState.Editor)
            {
                return;
            }

            var depth = 0;

            star = FlightGlobals.currentMainBody;
            while (depth < 10 && star != null && star.GetTemperature(0) < 2000)
            {
                star = star.referenceBody;
                depth++;
            }
            if (star == null)
            {
                star = FlightGlobals.Bodies[0];
            }

            if (ResearchAndDevelopment.Instance != null)
            {
                upgradeCostStr = ResearchAndDevelopment.Instance.Science + "/" + upgradeCost.ToString("0") + " Science";
            }

            renderArray = part.FindModelComponents <Renderer>().ToArray();

            if (radiatorInit == false)
            {
                radiatorInit = true;
            }

            part.maxTemp = maxRadiatorTemperature;

            radiatorTempStr = maxRadiatorTemperature + "K";

            maxVacuumTemperature     = String.IsNullOrEmpty(surfaceAreaUpgradeTechReq) ? Math.Min((float)PluginHelper.RadiatorTemperatureMk3, maxRadiatorTemperature) :  Math.Min(maxVacuumTemperature, maxRadiatorTemperature);
            maxAtmosphereTemperature = String.IsNullOrEmpty(surfaceAreaUpgradeTechReq) ? Math.Min((float)PluginHelper.RadiatorTemperatureMk3, maxRadiatorTemperature) : Math.Min(maxAtmosphereTemperature, maxRadiatorTemperature);

            resourceBuffers = new ResourceBuffers();
            resourceBuffers.AddConfiguration(new ResourceBuffers.TimeBasedConfig(ResourceManager.FNRESOURCE_WASTEHEAT, wasteHeatMultiplier, 2.0e+6));
            resourceBuffers.UpdateVariable(ResourceManager.FNRESOURCE_WASTEHEAT, this.part.mass);
            resourceBuffers.Init(this.part);
        }
Example #10
0
        public void FixedUpdate() // FixedUpdate is also called when not activated
        {
            try
            {
                if (!HighLogic.LoadedSceneIsFlight)
                {
                    return;
                }

                if (!active)
                {
                    base.OnFixedUpdate();
                }

                resourceBuffers.UpdateVariable(ResourceManager.FNRESOURCE_WASTEHEAT, this.part.mass);
                resourceBuffers.UpdateBuffers();

                // get resource bar ratio at start of frame
                wasteheatManager = getManagerForVessel(ResourceManager.FNRESOURCE_WASTEHEAT);
                wasteheatRatio   = wasteheatManager.ResourceBarRatioBegin;

                if (Double.IsNaN(wasteheatRatio))
                {
                    Debug.LogError("FNRadiator: FixedUpdate Single.IsNaN detected in wasteheatRatio");
                    return;
                }

                radiator_temperature_temp_val = external_temperature + Math.Min(temperatureDifferenceMaximumWithExternal * Math.Sqrt(wasteheatRatio), temperatureDifferenceCurrentWithExternal);

                var deltaTemp = Math.Max(radiator_temperature_temp_val - Math.Max(external_temperature * normalizedAtmosphere, 2.7), 0);

                if (radiatorIsEnabled)
                {
                    if (!CheatOptions.IgnoreMaxTemperature && wasteheatRatio >= 1 && CurrentRadiatorTemperature >= maxRadiatorTemperature)
                    {
                        explode_counter++;
                        if (explode_counter > 25)
                        {
                            part.explode();
                        }
                    }
                    else
                    {
                        explode_counter = 0;
                    }

                    var efficiency = CalculateEfficiency();
                    thermalPowerDissipPerSecond = efficiency * Math.Pow(deltaTemp, 4) * GameConstants.stefan_const * effectiveRadiatorArea / 1e6;

                    if (Double.IsNaN(thermalPowerDissipPerSecond))
                    {
                        Debug.LogWarning("FNRadiator: FixedUpdate Single.IsNaN detected in fixed_thermal_power_dissip");
                    }

                    radiatedThermalPower = canRadiateHeat ? consumeWasteHeatPerSecond(thermalPowerDissipPerSecond) : 0;

                    if (Double.IsNaN(radiatedThermalPower))
                    {
                        Debug.LogError("FNRadiator: FixedUpdate Single.IsNaN detected in radiatedThermalPower after call consumeWasteHeat (" + thermalPowerDissipPerSecond + ")");
                    }

                    instantaneous_rad_temp = CalculateInstantaniousRadTemp();

                    CurrentRadiatorTemperature = instantaneous_rad_temp;

                    if (_moduleDeployableRadiator)
                    {
                        _moduleDeployableRadiator.hasPivot = pivotEnabled;
                    }
                }
                else
                {
                    var efficiency = CalculateEfficiency();
                    thermalPowerDissipPerSecond = efficiency * Math.Pow(Math.Max(deltaTemp - external_temperature, 0), 4) * GameConstants.stefan_const * effectiveRadiatorArea / 0.5e7;

                    radiatedThermalPower = canRadiateHeat ? consumeWasteHeatPerSecond(thermalPowerDissipPerSecond) : 0;

                    instantaneous_rad_temp = CalculateInstantaniousRadTemp();

                    CurrentRadiatorTemperature = instantaneous_rad_temp;
                }

                if (vessel.atmDensity > 0)
                {
                    dynamic_pressure   = 0.60205 * vessel.atmDensity * vessel.srf_velocity.sqrMagnitude / 101325;
                    vessel.atmDensity += dynamic_pressure;

                    var efficiency      = CalculateEfficiency();
                    var convPowerDissip = efficiency * vessel.atmDensity * Math.Max(0, CurrentRadiatorTemperature - external_temperature) * effectiveRadiatorArea * 0.001 * convectiveBonus * Math.Max(part.submergedPortion * 10, 1);

                    if (!radiatorIsEnabled)
                    {
                        convPowerDissip = convPowerDissip / 2;
                    }

                    convectedThermalPower = canRadiateHeat ? consumeWasteHeatPerSecond(convPowerDissip) : 0;

                    if (update_count == DEPLOYMENT_DELAY)
                    {
                        DeployMentControl(dynamic_pressure);
                    }
                }
                else
                {
                    convectedThermalPower = 0;

                    if (radiatorIsEnabled || !isAutomated || !canRadiateHeat || !showControls ||
                        update_count != DEPLOYMENT_DELAY)
                    {
                        return;
                    }

                    Debug.Log("[KSPI] - FixedUpdate Automated Deplotment ");
                    Deploy();
                }
            }
            catch (Exception e)
            {
                Debug.LogError("[KSPI] - Exception on " + part.name + " durring FNRadiator.FixedUpdate with message " + e.Message);
            }
        }
Example #11
0
        public override void OnFixedUpdate()
        {
            temperatureStr = part.temperature.ToString("0.00") + "K / " + part.maxTemp.ToString("0.00") + "K";

            if (curEngineT == null)
            {
                return;
            }

            throttle = curEngineT.currentThrottle > MinThrottleRatio ? curEngineT.currentThrottle : 0;

            if (throttle > 0)
            {
                if (vessel.atmDensity > maxAtmosphereDensity)
                {
                    ShutDown("Inertial Fusion cannot operate in atmosphere!");
                }

                if (radhazard && rad_safety_features)
                {
                    ShutDown("Engines throttled down as they presently pose a radiation hazard");
                }
            }

            KillKerbalsWithRadiation(throttle);

            resourceBuffers.UpdateVariable(ResourceManager.FNRESOURCE_WASTEHEAT, this.part.mass);
            resourceBuffers.UpdateBuffers();

            if (throttle > 0)
            {
                // Calculate Fusion Ratio
                enginePowerRequirement = CurrentPowerRequirement;

                var recievedPower = CheatOptions.InfiniteElectricity
                    ? enginePowerRequirement
                    : consumeFNResourcePerSecond(enginePowerRequirement, ResourceManager.FNRESOURCE_MEGAJOULES);

                var plasma_ratio = recievedPower / enginePowerRequirement;
                fusionRatio = plasma_ratio >= 1 ? 1 : plasma_ratio > 0.75 ? plasma_ratio * plasma_ratio * plasma_ratio * plasma_ratio * plasma_ratio * plasma_ratio : 0;

                laserWasteheat = recievedPower * (1 - LaserEfficiency);

                // The Aborbed wasteheat from Fusion
                var rateMultplier        = minISP / SelectedIsp;
                var neutronbsorbionBonus = 1 - NeutronAbsorptionFractionAtMinIsp * (1 - ((SelectedIsp - minISP) / (MaxIsp - minISP)));
                absorbedWasteheat = FusionWasteHeat * wasteHeatMultiplier * fusionRatio * throttle * neutronbsorbionBonus;

                // Lasers produce Wasteheat
                if (!CheatOptions.IgnoreMaxTemperature)
                {
                    supplyFNResourcePerSecond(laserWasteheat, ResourceManager.FNRESOURCE_WASTEHEAT);
                    supplyFNResourcePerSecond(absorbedWasteheat, ResourceManager.FNRESOURCE_WASTEHEAT);
                }

                // change ratio propellants Hydrogen/Fusion
                curEngineT.propellants.FirstOrDefault(pr => pr.name == InterstellarResourcesConfiguration.Instance.LqdDeuterium).ratio = (float)(standard_deuterium_rate / rateMultplier);
                curEngineT.propellants.FirstOrDefault(pr => pr.name == InterstellarResourcesConfiguration.Instance.LqdTritium).ratio   = (float)(standard_tritium_rate / rateMultplier);

                // Update ISP
                var currentIsp = SelectedIsp;
                var newISP     = new FloatCurve();
                newISP.Add(0, currentIsp);
                newISP.Add(1, 0);
                curEngineT.atmosphereCurve = newISP;

                // Update FuelFlow
                var maxFuelFlow = fusionRatio * MaximumThrust / currentIsp / PluginHelper.GravityConstant;
                curEngineT.maxFuelFlow = (float)maxFuelFlow;
                curEngineT.maxThrust   = MaximumThrust;

                maximumThrust = MaximumThrust;

                if (!curEngineT.getFlameoutState && plasma_ratio < 0.75 && recievedPower > 0)
                {
                    curEngineT.status = "Insufficient Electricity";
                }
            }
            else
            {
                enginePowerRequirement = 0;
                absorbedWasteheat      = 0;
                laserWasteheat         = 0;
                fusionRatio            = 0;

                var currentIsp = SelectedIsp;
                var newISP     = new FloatCurve();
                newISP.Add(0, currentIsp);
                newISP.Add(1, 0);
                curEngineT.atmosphereCurve = newISP;
                curEngineT.maxThrust       = MaximumThrust;
                var rateMultplier = minISP / SelectedIsp;

                var maxFuelFlow = MaximumThrust / currentIsp / PluginHelper.GravityConstant;
                curEngineT.maxFuelFlow = (float)maxFuelFlow;
                curEngineT.propellants.FirstOrDefault(pr => pr.name == InterstellarResourcesConfiguration.Instance.LqdDeuterium).ratio = (float)(standard_deuterium_rate / rateMultplier);
                curEngineT.propellants.FirstOrDefault(pr => pr.name == InterstellarResourcesConfiguration.Instance.LqdTritium).ratio   = (float)(standard_tritium_rate / rateMultplier);
            }

            coldBathTemp          = FNRadiator.getAverageRadiatorTemperatureForVessel(vessel);
            maxTempatureRadiators = FNRadiator.getAverageMaximumRadiatorTemperatureForVessel(vessel);
            radiatorPerformance   = Math.Max(1 - (coldBathTemp / maxTempatureRadiators), 0.000001);
            partEmissiveConstant  = part.emissiveConstant;
        }
        public override void OnFixedUpdate()
        {
            base.OnFixedUpdate();

            if (_attached_engine == null)
            {
                return;
            }

            if (_attached_engine.currentThrottle > 0 && !exhaustAllowed)
            {
                string message = AttachedReactor.MayExhaustInLowSpaceHomeworld
                    ? Localizer.Format("#LOC_KSPIE_MagneticNozzleControllerFX_PostMsg1")  //"Engine halted - Radioactive exhaust not allowed towards or inside homeworld atmosphere"
                    : Localizer.Format("#LOC_KSPIE_MagneticNozzleControllerFX_PostMsg2"); //"Engine halted - Radioactive exhaust not allowed towards or near homeworld atmosphere"

                ScreenMessages.PostScreenMessage(message, 5, ScreenMessageStyle.UPPER_CENTER);
                vessel.ctrlState.mainThrottle = 0;

                // Return to realtime
                if (vessel.packed)
                {
                    TimeWarp.SetRate(0, true);
                }
            }

            _chargedParticleMaximumPercentageUsage = _attached_reactor != null ? _attached_reactor.ChargedParticlePropulsionEfficiency : 0;

            if (_chargedParticleMaximumPercentageUsage > 0)
            {
                if (_attached_reactor.Part != this.part)
                {
                    resourceBuffers.UpdateVariable(ResourceSettings.Config.WasteHeatInMegawatt, this.part.mass);
                    resourceBuffers.UpdateBuffers();
                }

                maximumChargedPower = _attached_reactor.MaximumChargedPower;
                var currentMaximumChargedPower = maximum_isp == minimum_isp ? maximumChargedPower * _attached_engine.currentThrottle : maximumChargedPower;

                _max_charged_particles_power = currentMaximumChargedPower * exchanger_thrust_divisor * _attached_reactor.ChargedParticlePropulsionEfficiency;
                _charged_particles_requested = exhaustAllowed && _attached_engine.isOperational && _attached_engine.currentThrottle > 0 ? _max_charged_particles_power : 0;

                _charged_particles_received = _charged_particles_requested > 0 ? consumeFNResourcePerSecond(_charged_particles_requested, ResourceSettings.Config.ChargedParticleInMegawatt) : 0;

                // update Isp
                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;

                UpdatePropellantBuffer(calculatedConsumptionInTon);

                // convert reactor product into propellants when possible and generate addition propellant from reactor fuel consumption
                chargedParticleRatio = currentMaximumChargedPower > 0 ? _charged_particles_received / currentMaximumChargedPower : 0;
                _attached_reactor.UseProductForPropulsion(chargedParticleRatio, calculatedConsumptionInTon);

                calculatedConsumptionPerSecond = calculatedConsumptionInTon * 1000;

                if (!CheatOptions.IgnoreMaxTemperature)
                {
                    if (_attached_engine.isOperational && _attached_engine.currentThrottle > 0)
                    {
                        wasteheatConsumption = _charged_particles_received > _previous_charged_particles_received
                            ? _charged_particles_received + (_charged_particles_received - _previous_charged_particles_received)
                            : _charged_particles_received - (_previous_charged_particles_received - _charged_particles_received);

                        _previous_charged_particles_received = _charged_particles_received;
                    }
                    //else if (_previous_charged_particles_received > 0)
                    //{
                    //    wasteheatConsumption = _previous_charged_particles_received;
                    //    _previous_charged_particles_received = 0;
                    //}
                    else
                    {
                        wasteheatConsumption                 = 0;
                        _charged_particles_received          = 0;
                        _previous_charged_particles_received = 0;
                    }

                    consumeFNResourcePerSecond(wasteheatConsumption, ResourceSettings.Config.WasteHeatInMegawatt);
                }

                if (_charged_particles_received == 0)
                {
                    _chargedParticleMaximumPercentageUsage = 0;

                    UpdateRunningEffect();
                    UpdatePowerEffect();
                }

                // 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(getResourceAvailability(ResourceSettings.Config.ElectricPowerInMegawatt), Math.Min(Math.Max(powerBufferMax - powerBufferStore, 0), minimumEnginePower));
                _requestedElectricPower = minimumEnginePower + neededBufferPower;

                _recievedElectricPower = CheatOptions.InfiniteElectricity || _requestedElectricPower == 0
                    ? _requestedElectricPower
                    : consumeFNResourcePerSecond(_requestedElectricPower, ResourceSettings.Config.ElectricPowerInMegawatt);

                // 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 effectiveThrustRatio = 1;

                _engineMaxThrust = 0;
                if (_max_charged_particles_power > 0)
                {
                    var max_thrust = powerThrustModifier * _charged_particles_received * scaledPowerFactor / currentIsp / GameConstants.STANDARD_GRAVITY;

                    var effective_thrust = Math.Max(max_thrust - (radius * radius * vessel.atmDensity * 100), 0);

                    effectiveThrustRatio = max_thrust > 0 ? effective_thrust / max_thrust : 0;

                    _engineMaxThrust = _attached_engine.currentThrottle > 0
                        ? Math.Max(effective_thrust, 1e-9)
                        : Math.Max(max_thrust, 1e-9);
                }

                // set isp
                FloatCurve newAtmosphereCurve = new FloatCurve();
                engineIsp = _attached_engine.currentThrottle > 0 ? (currentIsp * scaledPowerFactor * effectiveThrustRatio) : currentIsp;
                newAtmosphereCurve.Add(0, (float)engineIsp, 0, 0);
                _attached_engine.atmosphereCurve = newAtmosphereCurve;

                var max_effective_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;

                max_theoretical_thrust         = powerThrustModifier * maximumChargedPower * _chargedParticleMaximumPercentageUsage / currentIsp / GameConstants.STANDARD_GRAVITY;
                max_theoratical_fuel_flow_rate = max_theoretical_thrust / currentIsp / GameConstants.STANDARD_GRAVITY;

                // set maximum flow
                engineFuelFlow = _attached_engine.currentThrottle > 0 ? Math.Max((float)max_effective_fuel_flow_rate, 1e-9f) : (float)max_theoratical_fuel_flow_rate;

                _attached_engine.maxFuelFlow    = engineFuelFlow;
                _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.01)
                {
                    _attached_engine.status = Localizer.Format("#LOC_KSPIE_MagneticNozzleControllerFX_statu1");//"offline"
                }
                else if (megajoulesRatio < 0.75 && _requestedElectricPower > 0)
                {
                    _attached_engine.status = Localizer.Format("#LOC_KSPIE_MagneticNozzleControllerFX_statu2");//"Insufficient Electricity"
                }
                else if (effectiveThrustRatio < 0.01 && vessel.atmDensity > 0)
                {
                    _attached_engine.status = Localizer.Format("#LOC_KSPIE_MagneticNozzleControllerFX_statu3");//"Too dense atmospherere"
                }
            }
            else
            {
                _chargedParticleMaximumPercentageUsage = 0;
                _attached_engine.maxFuelFlow           = 0.0000000001f;
                _recievedElectricPower       = 0;
                _charged_particles_requested = 0;
                _charged_particles_received  = 0;
                _engineMaxThrust             = 0;
            }

            currentThrust = _attached_engine.GetCurrentThrust();
        }
Example #13
0
        public override void OnStart(PartModule.StartState state)
        {
            String[] resources_to_supply = { ResourceManager.FNRESOURCE_MEGAJOULES, ResourceManager.FNRESOURCE_WASTEHEAT, ResourceManager.FNRESOURCE_THERMALPOWER, ResourceManager.FNRESOURCE_CHARGED_PARTICLES };
            this.resources_to_supply = resources_to_supply;

            resourceBuffers = new ResourceBuffers();
            resourceBuffers.AddConfiguration(new ResourceBuffers.TimeBasedConfig(ResourceManager.FNRESOURCE_WASTEHEAT, wasteHeatMultiplier, 2.0e+5, true));
            resourceBuffers.AddConfiguration(new ResourceBuffers.TimeBasedConfig(ResourceManager.FNRESOURCE_MEGAJOULES));
            resourceBuffers.AddConfiguration(new ResourceBuffers.TimeBasedConfig(ResourceManager.STOCK_RESOURCE_ELECTRICCHARGE, 1000 / powerOutputMultiplier));
            resourceBuffers.UpdateVariable(ResourceManager.FNRESOURCE_WASTEHEAT, this.part.mass);
            resourceBuffers.Init(this.part);

            base.OnStart(state);

            targetMass  = part.prefabMass * storedMassMultiplier;
            initialMass = part.prefabMass * storedMassMultiplier;

            if (initialMass == 0)
            {
                initialMass = part.prefabMass;
            }
            if (targetMass == 0)
            {
                targetMass = part.prefabMass;
            }

            InitializeEfficiency();
            Fields["powerCapacity"].guiActiveEditor = !isLimitedByMinThrotle;
            Fields["partMass"].guiActive            = Fields["partMass"].guiActiveEditor = calculatedMass;
            Fields["powerPercentage"].guiActive     = Fields["powerPercentage"].guiActiveEditor = showSpecialisedUI;
            Fields["radius"].guiActiveEditor        = showSpecialisedUI;

            if (state == StartState.Editor)
            {
                if (this.HasTechsRequiredToUpgrade())
                {
                    isupgraded         = true;
                    hasrequiredupgrade = true;
                    upgradePartModule();
                }
                part.OnEditorAttach  += OnEditorAttach;
                part.OnEditorDetach  += OnEditorDetach;
                part.OnEditorDestroy += OnEditorDetach;

                part.OnJustAboutToBeDestroyed += OnDestroyed;
                part.OnJustAboutToDie         += OnDestroyed;

                FindAndAttachToPowerSource();
                return;
            }

            if (this.HasTechsRequiredToUpgrade())
            {
                hasrequiredupgrade = true;
            }

            // only force activate if no certain partmodules are not present and not limited by minimum throtle
            if (!isLimitedByMinThrotle && part.FindModuleImplementing <MicrowavePowerReceiver>() == null)
            {
                Debug.Log("[KSPI] - Generator on " + part.name + " was Force Activated");
                part.force_activate();
            }

            anim = part.FindModelAnimators(animName).FirstOrDefault();
            if (anim != null)
            {
                anim[animName].layer = 1;
                if (!IsEnabled)
                {
                    anim[animName].normalizedTime = 1;
                    anim[animName].speed          = -1;
                }
                else
                {
                    anim[animName].normalizedTime = 0;
                    anim[animName].speed          = 1;
                }
                anim.Play();
            }

            if (generatorInit == false)
            {
                IsEnabled = true;
            }

            if (isupgraded)
            {
                upgradePartModule();
            }

            FindAndAttachToPowerSource();

            UpdateHeatExchangedThrustDivisor();
        }
        // ReSharper disable once UnusedMember.Global
        public override void OnFixedUpdateResourceSuppliable(double fixedDeltaTime)
        {
            if (_attachedEngine == null || !HighLogic.LoadedSceneIsFlight)
            {
                return;
            }

            if (_initializationCountdown > 0)
            {
                _initializationCountdown--;
            }

            if (_vesselChangedSIOCountdown > 0)
            {
                _vesselChangedSIOCountdown--;
            }

            CalculateTimeDialation();

            if (_attachedEngine is ModuleEnginesFX)
            {
                GetAllPropellants().ForEach(prop => part.Effect(prop.ParticleFXName, 0, -1)); // set all FX to zero
            }
            if (CurrentPropellant == null)
            {
                return;
            }

            _resourceBuffers.UpdateVariable(ResourceManager.FNRESOURCE_WASTEHEAT, (double)(decimal)part.mass);
            _resourceBuffers.UpdateBuffers();

            if (!vessel.packed && !_warpToReal)
            {
                storedThrotle = vessel.ctrlState.mainThrottle;
            }

            maxEffectivePower           = MaxEffectivePower;
            currentPropellantEfficiency = CurrentPropellantEfficiency;

            var sumOfAllEffectivePower = vessel.FindPartModulesImplementing <ElectricEngineControllerFX>().Where(ee => ee.IsOperational).Sum(ee => ee.MaxEffectivePower);

            _electrical_share_f = sumOfAllEffectivePower > 0 ? maxEffectivePower / sumOfAllEffectivePower : 1;

            modifiedThrotte          = ModifiedThrotte;
            modifiedMaxThrottlePower = maxEffectivePower * modifiedThrotte;

            totalPowerSupplied = getTotalPowerSupplied(ResourceManager.FNRESOURCE_MEGAJOULES);
            megaJoulesBarRatio = getResourceBarRatio(ResourceManager.FNRESOURCE_MEGAJOULES);

            effectiveResourceThrotling = megaJoulesBarRatio > 0.1 ? 1 : megaJoulesBarRatio * 10;

            availableMaximumPower = getAvailablePrioritisedStableSupply(ResourceManager.FNRESOURCE_MEGAJOULES);
            availableCurrentPower = getAvailablePrioritisedCurrentSupply(ResourceManager.FNRESOURCE_MEGAJOULES);

            maximumAvailablePowerForEngine = availableMaximumPower * _electrical_share_f;
            currentAvailablePowerForEngine = availableCurrentPower * _electrical_share_f;

            maximumThrustFromPower = EvaluateMaxThrust(maximumAvailablePowerForEngine);
            currentThrustFromPower = EvaluateMaxThrust(currentAvailablePowerForEngine);

            effectiveMaximumAvailablePowerForEngine = maximumAvailablePowerForEngine * effectiveResourceThrotling;
            effectiveCurrentAvailablePowerForEngine = currentAvailablePowerForEngine * effectiveResourceThrotling;

            modifiedMaximumPowerForEngine = effectiveMaximumAvailablePowerForEngine * modifiedThrotte;
            modifiedCurrentPowerForEngine = effectiveCurrentAvailablePowerForEngine * modifiedThrotte;

            maximum_power_request = CheatOptions.InfiniteElectricity
                ? modifiedMaximumPowerForEngine
                : currentPropellantEfficiency <= 0
                    ? 0
                    : Math.Min(modifiedMaximumPowerForEngine, modifiedMaxThrottlePower);

            current_power_request = CheatOptions.InfiniteElectricity
                ? modifiedCurrentPowerForEngine
                : currentPropellantEfficiency <= 0
                    ? 0
                    : Math.Min(modifiedCurrentPowerForEngine, modifiedMaxThrottlePower);

            // request electric power
            actualPowerReceived = CheatOptions.InfiniteElectricity
                ? current_power_request
                : consumeFNResourcePerSecond(current_power_request, maximum_power_request, ResourceManager.FNRESOURCE_MEGAJOULES);

            simulatedPowerReceived = Math.Min(effectiveMaximumAvailablePowerForEngine, maxEffectivePower);

            // produce waste heat
            var heatModifier     = (1 - currentPropellantEfficiency) * CurrentPropellant.WasteHeatMultiplier;
            var heatToProduce    = actualPowerReceived * heatModifier;
            var maxHeatToProduce = maximumAvailablePowerForEngine * heatModifier;

            _heat_production_f = CheatOptions.IgnoreMaxTemperature
                ? heatToProduce
                : supplyFNResourcePerSecondWithMax(heatToProduce, maxHeatToProduce, ResourceManager.FNRESOURCE_WASTEHEAT);

            // update GUI Values
            _electrical_consumption_f = actualPowerReceived;

            _effectiveIsp = _modifiedEngineBaseIsp * _modifiedCurrentPropellantIspMultiplier * ThrottleModifiedIsp();
            _maxIsp       = _effectiveIsp * CurrentPropellantThrustMultiplier;

            var throtteModifier = ispGears == 1 ? 1 : ModifiedThrotte;

            effectivePowerThrustModifier = timeDilation * currentPropellantEfficiency * CurrentPropellantThrustMultiplier * GetPowerThrustModifier();

            effectiveRecievedPower  = effectivePowerThrustModifier * actualPowerReceived * throtteModifier;
            effectiveSimulatedPower = effectivePowerThrustModifier * simulatedPowerReceived;

            currentThrustInSpace   = _effectiveIsp <= 0 ? 0 : effectiveRecievedPower / _effectiveIsp / GameConstants.STANDARD_GRAVITY;
            simulatedThrustInSpace = _effectiveIsp <= 0 ? 0 : effectiveSimulatedPower / _effectiveIsp / GameConstants.STANDARD_GRAVITY;

            _attachedEngine.maxThrust = (float)Math.Max(simulatedThrustInSpace, 0.001);

            _currentSpaceFuelFlowRate   = _maxIsp <= 0 ? 0 : currentThrustInSpace / _maxIsp / GameConstants.STANDARD_GRAVITY;
            _simulatedSpaceFuelFlowRate = _maxIsp <= 0 ? 0 : simulatedThrustInSpace / _maxIsp / GameConstants.STANDARD_GRAVITY;

            var maxThrustWithCurrentThrottle = currentThrustInSpace * throtteModifier;

            calculated_thrust = CurrentPropellant.SupportedEngines == 8
                ? maxThrustWithCurrentThrottle
                : Math.Max(maxThrustWithCurrentThrottle - (exitArea * vessel.staticPressurekPa), 0);

            simulated_max_thrust = CurrentPropellant.SupportedEngines == 8
                ? simulatedThrustInSpace
                : Math.Max(simulatedThrustInSpace - (exitArea * vessel.staticPressurekPa), 0);

            var throttle = _attachedEngine.getIgnitionState && _attachedEngine.currentThrottle > 0 ? Math.Max(_attachedEngine.currentThrottle, 0.01) : 0;

            if (throttle > 0)
            {
                if (IsValidPositiveNumber(calculated_thrust) && IsValidPositiveNumber(maxThrustWithCurrentThrottle))
                {
                    _atmosphereThrustEfficiency = Math.Min(1, calculated_thrust / maxThrustWithCurrentThrottle);

                    _atmosphereThrustEfficiencyPercentage = _atmosphereThrustEfficiency * 100;

                    UpdateIsp(_atmosphereThrustEfficiency);

                    _fuelFlowModifier = ispGears == 1
                        ? 1 / throttle
                        : ModifiedThrotte / throttle;

                    _maxFuelFlowRate            = (float)Math.Max(_atmosphereThrustEfficiency * _currentSpaceFuelFlowRate * _fuelFlowModifier, 1e-11);
                    _attachedEngine.maxFuelFlow = _maxFuelFlowRate;
                }
                else
                {
                    UpdateIsp(1);
                    _atmosphereThrustEfficiency = 0;
                    _maxFuelFlowRate            = 1e-11f;
                    _attachedEngine.maxFuelFlow = _maxFuelFlowRate;
                }

                if (!this.vessel.packed)
                {
                    // allow throtle to be used up to Geeforce treshold
                    TimeWarp.GThreshold = GThreshold;

                    _isFullyStarted = true;
                    _ispPersistent  = _attachedEngine.realIsp;

                    thrust_d = _attachedEngine.requestedMassFlow * GameConstants.STANDARD_GRAVITY * _ispPersistent;

                    ratioHeadingVersusRequest = 0;
                }
                else if (this.vessel.packed && _attachedEngine.isEnabled && FlightGlobals.ActiveVessel == vessel && _initializationCountdown == 0)
                {
                    _warpToReal = true; // Set to true for transition to realtime

                    thrust_d = calculated_thrust;

                    ratioHeadingVersusRequest = _attachedEngine.PersistHeading(_vesselChangedSIOCountdown > 0, ratioHeadingVersusRequest == 1);

                    if (ratioHeadingVersusRequest == 1)
                    {
                        PersistantThrust((double)(decimal)TimeWarp.fixedDeltaTime, Planetarium.GetUniversalTime(), this.part.transform.up, this.vessel.totalMass, thrust_d, _ispPersistent);
                    }
                }
                else
                {
                    IdleEngine();
                }
            }
            else
            {
                IdleEngine();
            }

            if (_attachedEngine is ModuleEnginesFX && particleEffectMult > 0)
            {
                var engineFuelFlow  = _attachedEngine.maxFuelFlow * _attachedEngine.currentThrottle;
                var maxFuelFlowRate = _attachedEngine.maxThrust / _attachedEngine.realIsp / GameConstants.STANDARD_GRAVITY;

                effectPower = Math.Min(1, particleEffectMult * (engineFuelFlow / maxFuelFlowRate));

                _particleFXName = String.IsNullOrEmpty(EffectName) ? CurrentPropellant.ParticleFXName : EffectName;

                this.part.Effect(_particleFXName, (float)effectPower, -1);
            }

            var vacuumPlasmaResource = part.Resources[InterstellarResourcesConfiguration.Instance.VacuumPlasma];

            if (isupgraded && vacuumPlasmaResource != null)
            {
                var calculatedConsumptionInTon = this.vessel.packed ? 0 : currentThrustInSpace / engineIsp / GameConstants.STANDARD_GRAVITY;
                vacuumPlasmaResource.maxAmount = Math.Max(0.0000001, calculatedConsumptionInTon * 200 * (double)(decimal)TimeWarp.fixedDeltaTime);
                part.RequestResource(InterstellarResourcesConfiguration.Instance.VacuumPlasma, -vacuumPlasmaResource.maxAmount);
            }
        }
        // ReSharper disable once UnusedMember.Global
        public void FixedUpdate()
        {
            if (_initializationCountdown > 0)
            {
                _initializationCountdown--;
            }

            if (!HighLogic.LoadedSceneIsFlight)
            {
                return;
            }

            CalculateTimeDialation();

            if (_attachedEngine == null)
            {
                return;
            }

            if (_attachedEngine is ModuleEnginesFX)
            {
                GetAllPropellants().ForEach(prop => part.Effect(prop.ParticleFXName, 0, -1)); // set all FX to zero
            }
            if (Current_propellant == null)
            {
                return;
            }

            resourceBuffers.UpdateVariable(ResourceManager.FNRESOURCE_WASTEHEAT, this.part.mass);
            resourceBuffers.UpdateBuffers();

            if (!this.vessel.packed && !_warpToReal)
            {
                storedThrotle = vessel.ctrlState.mainThrottle;
            }

            // retrieve power
            maxEffectivePower = MaxEffectivePower;
            var sumOfAllEffectivePower = vessel.FindPartModulesImplementing <ElectricEngineControllerFX>().Where(ee => ee.IsOperational).Sum(ee => ee.MaxEffectivePower);

            _electrical_share_f = sumOfAllEffectivePower > 0 ? maxEffectivePower / sumOfAllEffectivePower : 1;

            maxThrottlePower = maxEffectivePower * ModifiedThrotte;
            var currentPropellantEfficiency = CurrentPropellantEfficiency;

            if (CheatOptions.InfiniteElectricity)
            {
                power_request = maxThrottlePower;
            }
            else
            {
                var availablePower     = Math.Max(getStableResourceSupply(ResourceManager.FNRESOURCE_MEGAJOULES) - getCurrentHighPriorityResourceDemand(ResourceManager.FNRESOURCE_MEGAJOULES), 0);
                var megaJoulesBarRatio = getResourceBarRatio(ResourceManager.FNRESOURCE_MEGAJOULES);

                var effectiveResourceThrotling = megaJoulesBarRatio > OneThird ? 1 : megaJoulesBarRatio * 3;

                var powerPerEngine = effectiveResourceThrotling * ModifiedThrotte * EvaluateMaxThrust(availablePower * _electrical_share_f) * CurrentIspMultiplier * _modifiedEngineBaseIsp / GetPowerThrustModifier() * PluginHelper.GravityConstant;
                power_request = currentPropellantEfficiency <= 0 ? 0 : Math.Min(powerPerEngine / currentPropellantEfficiency, maxThrottlePower);
            }

            var powerReceived = CheatOptions.InfiniteElectricity
                ? power_request
                : consumeFNResourcePerSecond(power_request, ResourceManager.FNRESOURCE_MEGAJOULES);

            // produce waste heat
            var heatToProduce = powerReceived * (1 - currentPropellantEfficiency) * Current_propellant.WasteHeatMultiplier;

            var heatProduction = CheatOptions.IgnoreMaxTemperature
                ? heatToProduce
                : supplyFNResourcePerSecond(heatToProduce, ResourceManager.FNRESOURCE_WASTEHEAT);

            // update GUI Values
            _electrical_consumption_f = powerReceived;
            _heat_production_f        = heatProduction;

            var effectiveIsp = _modifiedCurrentPropellantIspMultiplier * _modifiedEngineBaseIsp * ThrottleModifiedIsp();

            var maxThrustInSpace = timeDilation * timeDilation * currentPropellantEfficiency * CurrentPropellantThrustMultiplier * ModifiedThrotte * GetPowerThrustModifier() * powerReceived / (effectiveIsp * PluginHelper.GravityConstant);

            _maxIsp          = _modifiedEngineBaseIsp * _modifiedCurrentPropellantIspMultiplier * CurrentPropellantThrustMultiplier * ThrottleModifiedIsp();
            _maxFuelFlowRate = _maxIsp <= 0 ? 0 : maxThrustInSpace / _maxIsp / PluginHelper.GravityConstant;

            var maxThrustWithCurrentThrottle = maxThrustInSpace * ModifiedThrotte;

            throtle_max_thrust = Current_propellant.SupportedEngines == 8
                ? maxThrustWithCurrentThrottle
                : Math.Max(maxThrustWithCurrentThrottle - (exitArea * FlightGlobals.getStaticPressure(vessel.transform.position)), 0);

            var throttle = _attachedEngine.currentThrottle > 0 ? Mathf.Max(_attachedEngine.currentThrottle, 0.01f) : 0;

            //if (ModifiedThrotte > 0)
            if (throttle > 0 && !this.vessel.packed)
            {
                if (IsValidPositiveNumber(throtle_max_thrust) && IsValidPositiveNumber(maxThrustWithCurrentThrottle))
                {
                    UpdateIsp(throtle_max_thrust / maxThrustWithCurrentThrottle);
                    _attachedEngine.maxFuelFlow = (float)Math.Max(_maxFuelFlowRate * (ModifiedThrotte / _attachedEngine.currentThrottle), 0.0000000001);
                }
                else
                {
                    UpdateIsp(0.000001);
                    _attachedEngine.maxFuelFlow = 0.0000000001f;
                }

                if (_attachedEngine is ModuleEnginesFX)
                {
                    this.part.Effect(Current_propellant.ParticleFXName, Mathf.Min((float)Math.Pow(_electrical_consumption_f / maxEffectivePower, 0.5), _attachedEngine.finalThrust / _attachedEngine.maxThrust), -1);
                }
            }
            else if (this.vessel.packed && _attachedEngine.enabled && FlightGlobals.ActiveVessel == vessel && throttle > 0 && _initializationCountdown == 0)
            {
                _warpToReal = true; // Set to true for transition to realtime

                PersistantThrust(TimeWarp.fixedDeltaTime, Planetarium.GetUniversalTime(), this.part.transform.up, this.vessel.GetTotalMass());
            }
            else
            {
                throtle_max_thrust = 0;
                var projected_max_thrust = Math.Max(maxThrustInSpace - (exitArea * FlightGlobals.getStaticPressure(vessel.transform.position)), 0);

                if (IsValidPositiveNumber(projected_max_thrust) && IsValidPositiveNumber(maxThrustInSpace))
                {
                    UpdateIsp(projected_max_thrust / maxThrustInSpace);
                    _attachedEngine.maxFuelFlow = (float)Math.Max(_maxFuelFlowRate, 0.0000000001);
                }
                else
                {
                    UpdateIsp(1);
                    _attachedEngine.maxFuelFlow = 0.0000000001f;
                }

                if (_attachedEngine is ModuleEnginesFX)
                {
                    this.part.Effect(Current_propellant.ParticleFXName, 0, -1);
                }
            }

            var vacuumPlasmaResource = part.Resources[InterstellarResourcesConfiguration.Instance.VacuumPlasma];

            if (isupgraded && vacuumPlasmaResource != null)
            {
                var calculatedConsumptionInTon = this.vessel.packed ? 0 : throtle_max_thrust / engineIsp / PluginHelper.GravityConstant;
                vacuumPlasmaResource.maxAmount = Math.Max(0.0000001, calculatedConsumptionInTon * 200 * TimeWarp.fixedDeltaTime);
                part.RequestResource(InterstellarResourcesConfiguration.Instance.VacuumPlasma, -vacuumPlasmaResource.maxAmount);
            }
        }
Example #16
0
        public override void OnStart(StartState state)
        {
            if (state.ToString().Contains(StartState.PreLaunch.ToString()))
            {
                Debug.Log("[KSPI]: PreLaunch uses InitialGearRatio:" + InitialGearRatio);
                SelectedIsp = ((MaxIsp - MinIsp) * Math.Max(0, Math.Min(1, InitialGearRatio))) + MinIsp;
            }

            Fields[nameof(selectedFuel)].guiName = fuelSwitchName;

            Fields[nameof(currentMaximumPowerRequirement)].guiActive = powerRequirement > 0;
            Fields[nameof(laserWasteheat)].guiActive    = powerRequirement > 0 && fusionWasteHeat > 0;
            Fields[nameof(absorbedWasteheat)].guiActive = powerRequirement > 0 && fusionWasteHeat > 0;
            Fields[nameof(fusionRatio)].guiActive       = powerRequirement > 0;

            Fields[nameof(powerRequirementMax)].guiActiveEditor = powerRequirement > 0;
            Fields[nameof(fusionWasteHeatMax)].guiActiveEditor  = fusionWasteHeat > 0;

            part.maxTemp             = maxTemp;
            part.thermalMass         = 1;
            part.thermalMassModifier = 1;

            curEngineT = part.FindModuleImplementing <ModuleEngines>();
            if (curEngineT == null)
            {
                Debug.LogError("[KSPI]: FusionEngine OnStart Engine not found");
                return;
            }
            BaseFloatCurve = curEngineT.atmosphereCurve;

            curveMaxISP = GetMaxKey(BaseFloatCurve);
            if (hasMultipleConfigurations)
            {
                FcSetup();
            }

            InitializeKerbalismEmitter();

            DetermineTechLevel();
            powerRequirementMax = PowerRequirementMaximum;
            fusionWasteHeatMax  = FusionWasteHeat;

            resourceBuffers = new ResourceBuffers();
            resourceBuffers.AddConfiguration(new WasteHeatBufferConfig(wasteHeatMultiplier, 1.0e+4, true));
            resourceBuffers.UpdateVariable(ResourceSettings.Config.WasteHeatInMegawatt, part.mass);
            resourceBuffers.Init(this.part);

            if (state != StartState.Editor)
            {
                part.emissiveConstant = maxTempatureRadiators > 0 ? 1 - coldBathTemp / maxTempatureRadiators : 0.01;
            }

            base.OnStart(state);

            var localIspField = Fields[nameof(VistaECU2.localIsp)];

            if (localIspField != null)
            {
                localIspField.guiActive       = selectableIsp;
                localIspField.guiActiveEditor = selectableIsp;
            }
        }
Example #17
0
        public override void OnFixedUpdate()
        {
            temperatureStr = part.temperature.ToString("0.00") + "K / " + part.maxTemp.ToString("0.00") + "K";

            resourceBuffers.UpdateVariable(ResourceManager.FNRESOURCE_WASTEHEAT, this.part.mass);
            resourceBuffers.UpdateBuffers();

            if (curEngineT == null)
            {
                return;
            }

            float throttle = curEngineT.currentThrottle > 0 ? Mathf.Max(curEngineT.currentThrottle, 0.01f) : 0;

            //double atmo_thrust_factor = Math.Min(1.0, Math.Max(1.0 - Math.Pow(vessel.atmDensity, 0.2), 0));

            if (throttle > 0)
            {
                if (vessel.atmDensity > maxAtmosphereDensity)
                {
                    ShutDown("Inertial Fusion cannot operate in atmosphere!");
                }

                if (radhazard && rad_safety_features)
                {
                    ShutDown("Engines throttled down as they presently pose a radiation hazard");
                }
            }

            KillKerbalsWithRadiation(throttle);

            coldBathTemp          = (float)FNRadiator.getAverageRadiatorTemperatureForVessel(vessel);
            maxTempatureRadiators = (float)FNRadiator.getAverageMaximumRadiatorTemperatureForVessel(vessel);

            if (throttle > 0)
            {
                // Calculate Fusion Ratio
                var recievedPower = CheatOptions.InfiniteElectricity
                    ? powerRequirement
                    : consumeFNResourcePerSecond(powerRequirement, ResourceManager.FNRESOURCE_MEGAJOULES);

                var plasma_ratio = recievedPower / powerRequirement;
                var fusionRatio  = plasma_ratio >= 1 ? 1 : plasma_ratio > 0.75 ? plasma_ratio * plasma_ratio * plasma_ratio * plasma_ratio * plasma_ratio * plasma_ratio : 0;

                if (!CheatOptions.IgnoreMaxTemperature)
                {
                    // Lasers produce Wasteheat
                    supplyFNResourcePerSecond(recievedPower * (1 - efficiency), ResourceManager.FNRESOURCE_WASTEHEAT);

                    // The Aborbed wasteheat from Fusion
                    supplyFNResourcePerSecond(FusionWasteHeat * wasteHeatMultiplier * fusionRatio, ResourceManager.FNRESOURCE_WASTEHEAT);
                }

                // change ratio propellants Hydrogen/Fusion
                curEngineT.propellants.FirstOrDefault(pr => pr.name == InterstellarResourcesConfiguration.Instance.LqdDeuterium).ratio = (float)(standard_deuterium_rate / throttle / throttle);
                curEngineT.propellants.FirstOrDefault(pr => pr.name == InterstellarResourcesConfiguration.Instance.LqdTritium).ratio   = (float)(standard_tritium_rate / throttle / throttle);

                // Update ISP
                var newISP     = new FloatCurve();
                var currentIsp = Math.Max(minISP * fusionRatio / throttle, minISP / 10);
                newISP.Add(0, (float)currentIsp);
                curEngineT.atmosphereCurve = newISP;

                // Update FuelFlow
                var maxFuelFlow = fusionRatio * MaximumThrust / currentIsp / PluginHelper.GravityConstant;
                curEngineT.maxFuelFlow = Math.Max((float)maxFuelFlow, 0.0000001f);

                if (!curEngineT.getFlameoutState)
                {
                    if (plasma_ratio < 0.75 && recievedPower > 0)
                    {
                        curEngineT.status = "Insufficient Electricity";
                    }
                }
            }
            else
            {
                var currentIsp = minISP * 100;

                var newISP = new FloatCurve();
                newISP.Add(0, (float)currentIsp);
                curEngineT.atmosphereCurve = newISP;

                var maxFuelFlow = MaximumThrust / currentIsp / PluginHelper.GravityConstant;
                curEngineT.maxFuelFlow = (float)maxFuelFlow;

                curEngineT.propellants.FirstOrDefault(pr => pr.name == InterstellarResourcesConfiguration.Instance.LqdDeuterium).ratio = (float)(standard_deuterium_rate);
                curEngineT.propellants.FirstOrDefault(pr => pr.name == InterstellarResourcesConfiguration.Instance.LqdTritium).ratio   = (float)(standard_tritium_rate);
            }

            radiatorPerformance  = (float)Math.Max(1 - (float)(coldBathTemp / maxTempatureRadiators), 0.000001);
            partEmissiveConstant = (float)part.emissiveConstant;
        }
        public override void OnFixedUpdate()
        {
            temperatureStr = part.temperature.ToString("0.00") + "K / " + part.maxTemp.ToString("0.00") + "K";
            MinIsp         = OrigFloatCurve.Evaluate((float)Altitude);

            // part.ona

            if (curEngineT == null)
            {
                return;
            }

            throttle = curEngineT.currentThrottle > MinThrottleRatio ? curEngineT.currentThrottle : 0;

            if (throttle > 0)
            {
                if (vessel.atmDensity > maxAtmosphereDensity)
                {
                    ShutDown(Localizer.Format("#LOC_KSPIE_VistaEngineControllerAdv_PostMsg1"));//"Inertial Fusion cannot operate in atmosphere!"
                }
                if (radhazard && rad_safety_features)
                {
                    ShutDown(Localizer.Format("#LOC_KSPIE_VistaEngineControllerAdv_PostMsg2"));//"Engines throttled down as they presently pose a radiation hazard"
                }
                if (SelectedIsp <= 10)
                {
                    ShutDown(Localizer.Format("#LOC_KSPIE_VistaEngineControllerAdv_PostMsg4"));//"Engine Stall"
                }
            }

            KillKerbalsWithRadiation(throttle);

            resourceBuffers.UpdateVariable(ResourceManager.FNRESOURCE_WASTEHEAT, this.part.mass);
            resourceBuffers.UpdateBuffers();

            if (throttle > 0)
            {
                // Calculate Fusion Ratio
                enginePowerRequirement = CurrentPowerRequirement;

                var recievedPowerFixed = CheatOptions.InfiniteElectricity
                    ? enginePowerRequirement
                    : consumeFNResourcePerSecond(enginePowerRequirement, ResourceManager.FNRESOURCE_MEGAJOULES);

                var plasma_ratio = recievedPowerFixed / enginePowerRequirement;
                fusionRatio = plasma_ratio >= 1 ? 1 : plasma_ratio > 0.75f ? Mathf.Pow((float)plasma_ratio, 6) : 0;

                laserWasteheat = recievedPowerFixed * (1 - LaserEfficiency);

                // Lasers produce Wasteheat
                if (!CheatOptions.IgnoreMaxTemperature)
                {
                    supplyFNResourcePerSecond(enginePowerRequirement, ResourceManager.FNRESOURCE_WASTEHEAT);
                }

                // The Absorbed wasteheat from Fusion
                var rateMultplier        = MinIsp / SelectedIsp;
                var neutronbsorbionBonus = 1 - NeutronAbsorptionFractionAtMinIsp * (1 - ((SelectedIsp - MinIsp) / (MaxIsp - MinIsp)));
                absorbedWasteheat = FusionWasteHeat * wasteHeatMultiplier * fusionRatio * throttle * neutronbsorbionBonus;
                supplyFNResourcePerSecond(absorbedWasteheat, ResourceManager.FNRESOURCE_WASTEHEAT);

                // change ratio propellants Hydrogen/Fusion
                curEngineT.propellants.FirstOrDefault(pr => pr.name == InterstellarResourcesConfiguration.Instance.LqdDeuterium).ratio = (float)standard_deuterium_rate / rateMultplier;
                curEngineT.propellants.FirstOrDefault(pr => pr.name == InterstellarResourcesConfiguration.Instance.LqdTritium).ratio   = (float)standard_tritium_rate / rateMultplier;

                // Update ISP
                var currentIsp = SelectedIsp;
                UpdateISP();

                // Update FuelFlow
                var maxFuelFlow = fusionRatio * MaximumThrust / currentIsp / GameConstants.STANDARD_GRAVITY;
                maximumThrust = (float)MaximumThrust;

                curEngineT.maxFuelFlow = (float)maxFuelFlow;
                curEngineT.maxThrust   = maximumThrust;


                if (!curEngineT.getFlameoutState && plasma_ratio < 0.75 && recievedPowerFixed > 0)
                {
                    curEngineT.status = Localizer.Format("#LOC_KSPIE_VistaEngineControllerAdv_statu");//"Insufficient Electricity"
                }
            }
            else
            {
                enginePowerRequirement = 0;
                absorbedWasteheat      = 0;
                laserWasteheat         = 0;
                fusionRatio            = 0;
                var currentIsp = SelectedIsp;

                UpdateISP();
                curEngineT.maxThrust = (float)MaximumThrust;
                var rateMultplier = MinIsp / SelectedIsp;

                var maxFuelFlow = MaximumThrust / currentIsp / GameConstants.STANDARD_GRAVITY;
                curEngineT.maxFuelFlow = (float)maxFuelFlow;
                curEngineT.propellants.FirstOrDefault(pr => pr.name == InterstellarResourcesConfiguration.Instance.LqdDeuterium).ratio = (float)(standard_deuterium_rate) / rateMultplier;
                curEngineT.propellants.FirstOrDefault(pr => pr.name == InterstellarResourcesConfiguration.Instance.LqdTritium).ratio   = (float)(standard_tritium_rate) / rateMultplier;
            }

            coldBathTemp          = (float)FNRadiator.getAverageRadiatorTemperatureForVessel(vessel);
            maxTempatureRadiators = (float)FNRadiator.getAverageMaximumRadiatorTemperatureForVessel(vessel);
            radiatorPerformance   = Mathf.Max(1 - (coldBathTemp / maxTempatureRadiators), 0.000001f);
            partEmissiveConstant  = (float)part.emissiveConstant;
        }
Example #19
0
        public override void OnStart(PartModule.StartState state)
        {
            if (state == StartState.Editor)
            {
                return;
            }

            _mjSolarSupplyField = Fields[nameof(mjSolarSupply)];
            _mjMaxSupplyField   = Fields[nameof(mjMaxSupply)];

            if (part.Modules.Contains("SolarPanelFixer"))
            {
                _solarPanelFixer = part.Modules["SolarPanelFixer"];

                _fieldKerbalismNominalRate = _solarPanelFixer.Fields["nominalRate"];
                _fieldKerbalismPanelStatus = _solarPanelFixer.Fields["panelStatus"];
            }

            // calculate Astronomical unit on homeworld semiMajorAxis when missing
            if (astronomicalUnit <= 0)
            {
                astronomicalUnit = FlightGlobals.GetHomeBody().orbit.semiMajorAxis;
            }

            _microwavePowerReceiver = part.FindModuleImplementing <BeamedPowerReceiver>();

            _solarPanel = part.FindModuleImplementing <ModuleDeployableSolarPanel>();
            if (_solarPanel == null || _solarPanel.chargeRate <= 0)
            {
                return;
            }

            if (part.FindModuleImplementing <ModuleJettison>() == null)
            {
                Debug.Log("[KSPI]: FNSolarPanelWasteHeatModule Force Activated  " + part.name);
                part.force_activate();
            }

            string[] resourcesToSupply = { ResourceSettings.Config.ElectricPowerInMegawatt };
            this.resourcesToSupply = resourcesToSupply;
            base.OnStart(state);

            _outputResource = _solarPanel.resHandler.outputResources.FirstOrDefault();

            resourceName = _solarPanel.resourceName;

            if (resourceName == ResourceSettings.Config.ElectricPowerInMegawatt)
            {
                _outputType = ResourceType.megajoule;
            }
            else if (resourceName == ResourceSettings.Config.ElectricPowerInKilowatt)
            {
                _outputType = ResourceType.electricCharge;
            }
            else
            {
                _outputType = ResourceType.other;
            }

            // only manage power buffer when microwave receiver is not available
            if (_outputType != ResourceType.other && _microwavePowerReceiver == null)
            {
                _resourceBuffers = new ResourceBuffers();
                _resourceBuffers.AddConfiguration(new ResourceBuffers.TimeBasedConfig(ResourceSettings.Config.ElectricPowerInMegawatt));

                _resourceBuffers.UpdateVariable(ResourceSettings.Config.ElectricPowerInMegawatt, _outputType == ResourceType.electricCharge ? _solarPanel.chargeRate / GameConstants.ecPerMJ : _solarPanel.chargeRate);
                if (!Kerbalism.IsLoaded)
                {
                    _resourceBuffers.AddConfiguration(new ResourceBuffers.TimeBasedConfig(ResourceSettings.Config.ElectricPowerInKilowatt));
                    _resourceBuffers.UpdateVariable(ResourceSettings.Config.ElectricPowerInKilowatt, _outputType == ResourceType.electricCharge ? _solarPanel.chargeRate : _solarPanel.chargeRate * GameConstants.ecPerMJ);
                }

                _resourceBuffers.Init(part);
            }

            _stars = KopernicusHelper.Stars;
        }
        public override void OnFixedUpdate()
        {
            temperatureStr = part.temperature.ToString("0.00") + "K / " + part.maxTemp.ToString("0.00") + "K";
            MinIsp         = BaseFloatCurve.Evaluate((float)Altitude);

            resourceBuffers.UpdateVariable(ResourceManager.FNRESOURCE_WASTEHEAT, this.part.mass);
            resourceBuffers.UpdateBuffers();

            if (curEngineT == null || !curEngineT.isEnabled)
            {
                return;
            }

            if (curEngineT.currentThrottle > 0)
            {
                if (maxAtmosphereDensity >= 0 && vessel.atmDensity > maxAtmosphereDensity)
                {
                    ShutDown(Localizer.Format("#LOC_KSPIE_FusionECU2_PostMsg1"));//"Inertial Fusion cannot operate in atmosphere!"
                }
                if (radhazard && rad_safety_features)
                {
                    ShutDown(Localizer.Format("#LOC_KSPIE_FusionECU2_PostMsg2"));//"Engines throttled down as they presently pose a radiation hazard"
                }
                if (SelectedIsp <= 10)
                {
                    ShutDown(Localizer.Format("#LOC_KSPIE_FusionECU2_PostMsg3"));//"Engine Stall"
                }
            }

            KillKerbalsWithRadiation(fusionRatio);

            hasIspThrottling = HasIspThrottling();

            ShowIspThrottle = hasIspThrottling;

            availablePower = Math.Max(getResourceAvailability(ResourceManager.FNRESOURCE_MEGAJOULES), getAvailablePrioritisedStableSupply(ResourceManager.FNRESOURCE_MEGAJOULES));

            if (curEngineT.currentThrottle > 0)
            {
                requiredPowerPerSecond = curEngineT.currentThrottle * CurrentMaximumPowerRequirement;

                requestedPowerPerSecond = Math.Min(requiredPowerPerSecond, availablePower);

                recievedPowerPerSecond = requestedPowerPerSecond <= 0 ? 0
                    : CheatOptions.InfiniteElectricity
                        ? requiredPowerPerSecond
                        : consumeFNResourcePerSecond(requestedPowerPerSecond, ResourceManager.FNRESOURCE_MEGAJOULES);

                fusionRatio = requiredPowerPerSecond > 0 ? Math.Min(1, recievedPowerPerSecond / requiredPowerPerSecond) : 1;

                laserWasteheat = recievedPowerPerSecond * (1 - LaserEfficiency);

                // Lasers produce Wasteheat
                if (!CheatOptions.IgnoreMaxTemperature && laserWasteheat > 0)
                {
                    supplyFNResourcePerSecond(laserWasteheat, ResourceManager.FNRESOURCE_WASTEHEAT);
                }

                // The Aborbed wasteheat from Fusion
                rateMultplier        = hasIspThrottling ? Math.Pow(SelectedIsp / MinIsp, 2) : 1;
                neutronbsorbionBonus = hasIspThrottling ? 1 - NeutronAbsorptionFractionAtMinIsp * (1 - ((SelectedIsp - MinIsp) / (MaxIsp - MinIsp))) : 0.5;
                absorbedWasteheat    = FusionWasteHeat * wasteHeatMultiplier * fusionRatio * curEngineT.currentThrottle * neutronbsorbionBonus;
                supplyFNResourcePerSecond(absorbedWasteheat, ResourceManager.FNRESOURCE_WASTEHEAT);

                SetRatios();

                currentIsp = hasIspThrottling ? SelectedIsp : MinIsp;
                UpdateAtmosphereCurve(currentIsp);
                maximumThrust = hasIspThrottling ? MaximumThrust : FullTrustMaximum;

                // Update FuelFlow
                maxFuelFlow = fusionRatio * maximumThrust / currentIsp / GameConstants.STANDARD_GRAVITY;

                curEngineT.maxFuelFlow = (float)maxFuelFlow;
                curEngineT.maxThrust   = (float)maximumThrust;

                if (!curEngineT.getFlameoutState && fusionRatio < 0.9 && recievedPowerPerSecond > 0)
                {
                    curEngineT.status = Localizer.Format("#LOC_KSPIE_FusionECU2_statu1");//"Insufficient Electricity"
                }
            }
            else
            {
                absorbedWasteheat       = 0;
                laserWasteheat          = 0;
                requestedPowerPerSecond = 0;
                recievedPowerPerSecond  = 0;

                requiredPowerPerSecond = CurrentMaximumPowerRequirement;

                fusionRatio = requiredPowerPerSecond > 0 ? Math.Min(1, availablePower / requiredPowerPerSecond) : 1;

                currentIsp    = hasIspThrottling ? SelectedIsp : MinIsp;
                maximumThrust = hasIspThrottling ? MaximumThrust : FullTrustMaximum;

                UpdateAtmosphereCurve(currentIsp);

                rateMultplier = hasIspThrottling ? Math.Pow(SelectedIsp / MinIsp, 2) : 1;

                maxFuelFlow = fusionRatio * maximumThrust / currentIsp / GameConstants.STANDARD_GRAVITY;

                curEngineT.maxFuelFlow = (float)maxFuelFlow;
                curEngineT.maxThrust   = (float)maximumThrust;

                SetRatios();
            }

            coldBathTemp          = FNRadiator.getAverageRadiatorTemperatureForVessel(vessel);
            maxTempatureRadiators = FNRadiator.getAverageMaximumRadiatorTemperatureForVessel(vessel);
            radiatorPerformance   = Math.Max(1 - (coldBathTemp / maxTempatureRadiators), 0.000001);
            partEmissiveConstant  = part.emissiveConstant;
            base.OnFixedUpdate();
        }
Example #21
0
 private void UpdateElectricChargeBuffer(double currentPowerUsage)
 {
     resourceBuffers.UpdateVariable(InterstellarResourcesConfiguration.Instance.ElectricCharge, currentPowerUsage);
     resourceBuffers.UpdateBuffers();
 }
Example #22
0
        public override void OnFixedUpdate()
        {
            temperatureStr = part.temperature.ToString("0.00") + "K / " + part.maxTemp.ToString("0.00") + "K";
            MinIsp         = BaseFloatCurve.Evaluate((float)Altitude);

            resourceBuffers.UpdateVariable(ResourceManager.FNRESOURCE_WASTEHEAT, this.part.mass);
            resourceBuffers.UpdateBuffers();

            if (curEngineT == null || !curEngineT.isEnabled)
            {
                return;
            }

            throttle = curEngineT.currentThrottle > MinThrottleRatio ? curEngineT.currentThrottle : 0;

            if (throttle > 0)
            {
                if (maxAtmosphereDensity >= 0 && vessel.atmDensity > maxAtmosphereDensity)
                {
                    ShutDown("Inertial Fusion cannot operate in atmosphere!");
                }

                if (radhazard && rad_safety_features)
                {
                    ShutDown("Engines throttled down as they presently pose a radiation hazard");
                }

                if (SelectedIsp <= 10)
                {
                    ShutDown("Engine Stall");
                }
            }

            KillKerbalsWithRadiation(fusionRatio);

            hasIspThrottling = HasIspThrottling();

            ShowIspThrottle = hasIspThrottling;

            if (throttle > 0)
            {
                // Calculate Fusion Ratio
                enginePowerRequirement = CurrentPowerRequirement;
                var requestedPowerPerSecond = enginePowerRequirement;

                var availablePower          = getAvailableStableSupply(ResourceManager.FNRESOURCE_MEGAJOULES);
                var resourceBarRatio        = getResourceBarRatio(ResourceManager.FNRESOURCE_MEGAJOULES);
                var effectivePowerThrotling = resourceBarRatio > ResourceManager.ONE_THIRD ? 1 : resourceBarRatio * 3;

                var requestedPower = Math.Min(requestedPowerPerSecond, availablePower * effectivePowerThrotling);

                var recievedPowerPerSecond = CheatOptions.InfiniteElectricity || requestedPower <= 0
                    ? requestedPowerPerSecond
                    : consumeFNResourcePerSecond(requestedPower, ResourceManager.FNRESOURCE_MEGAJOULES);

                fusionRatio = requestedPowerPerSecond > 0 ? recievedPowerPerSecond / requestedPowerPerSecond : 1;

                laserWasteheat = recievedPowerPerSecond * (1 - LaserEfficiency);

                // Lasers produce Wasteheat
                if (!CheatOptions.IgnoreMaxTemperature)
                {
                    supplyFNResourcePerSecond(laserWasteheat, ResourceManager.FNRESOURCE_WASTEHEAT);
                }

                // The Aborbed wasteheat from Fusion
                rateMultplier        = hasIspThrottling ? Math.Pow(SelectedIsp / MinIsp, 2) : 1;
                neutronbsorbionBonus = hasIspThrottling ? 1 - NeutronAbsorptionFractionAtMinIsp * (1 - ((SelectedIsp - MinIsp) / (MaxIsp - MinIsp))) : 0.5;
                absorbedWasteheat    = FusionWasteHeat * wasteHeatMultiplier * fusionRatio * throttle * neutronbsorbionBonus;
                supplyFNResourcePerSecond(absorbedWasteheat, ResourceManager.FNRESOURCE_WASTEHEAT);

                SetRatios();

                currentIsp = hasIspThrottling ? SelectedIsp : MinIsp;
                UpdateAtmosphereCurve(currentIsp);
                maximumThrust = hasIspThrottling ? MaximumThrust : FullTrustMaximum;

                // Update FuelFlow
                var maxFuelFlow = fusionRatio * maximumThrust / currentIsp / GameConstants.STANDARD_GRAVITY;

                curEngineT.maxFuelFlow = (float)maxFuelFlow;
                curEngineT.maxThrust   = (float)maximumThrust;

                if (!curEngineT.getFlameoutState && fusionRatio < 0.75 && recievedPowerPerSecond > 0)
                {
                    curEngineT.status = "Insufficient Electricity";
                }
            }
            else
            {
                enginePowerRequirement = 0;
                absorbedWasteheat      = 0;
                laserWasteheat         = 0;
                fusionRatio            = 0;
                currentIsp             = hasIspThrottling ? SelectedIsp : MinIsp;
                maximumThrust          = hasIspThrottling ? MaximumThrust : FullTrustMaximum;

                UpdateAtmosphereCurve(currentIsp);
                curEngineT.maxThrust = (float)maximumThrust;
                rateMultplier        = hasIspThrottling ? Math.Pow(SelectedIsp / MinIsp, 2) : 1;

                var maxFuelFlow = maximumThrust / currentIsp / GameConstants.STANDARD_GRAVITY;
                curEngineT.maxFuelFlow = (float)maxFuelFlow;

                SetRatios();
            }

            coldBathTemp          = FNRadiator.getAverageRadiatorTemperatureForVessel(vessel);
            maxTempatureRadiators = FNRadiator.getAverageMaximumRadiatorTemperatureForVessel(vessel);
            radiatorPerformance   = Math.Max(1 - (coldBathTemp / maxTempatureRadiators), 0.000001);
            partEmissiveConstant  = part.emissiveConstant;
            base.OnFixedUpdate();
        }
        public override void OnStart(StartState state)
        {
            String[] resourcesToSupply = { ResourceManager.FNRESOURCE_WASTEHEAT };
            this.resources_to_supply = resourcesToSupply;

            base.OnStart(state);

            radiatedThermalPower       = 0;
            convectedThermalPower      = 0;
            CurrentRadiatorTemperature = 0;
            radiator_deploy_delay      = 0;

            DetermineGenerationType();

            isGraphene = !String.IsNullOrEmpty(surfaceAreaUpgradeTechReq);
            maximumRadiatorTempInSpace = (float)RadiatorProperties.RadiatorTemperatureMk6;
            maxSpaceTempBonus          = maximumRadiatorTempInSpace - maximumRadiatorTempAtOneAtmosphere;
            temperatureRange           = maximumRadiatorTempInSpace - drapperPoint;

            kspShader = Shader.Find(kspShaderLocation);
            maxRadiatorTemperature = (float)MaxRadiatorTemperature;

            part.heatConvectiveConstant = convectiveBonus;
            if (hasSurfaceAreaUpgradeTechReq)
            {
                part.emissiveConstant = 1.6;
            }

            radiatorType = RadiatorType;

            effectiveRadiatorArea = EffectiveRadiatorArea;
            stefanArea            = PhysicsGlobals.StefanBoltzmanConstant * effectiveRadiatorArea * 1e-6;

            startWithCircradiator      = part.name.StartsWith("circradiator");
            startWithRadialRadiator    = part.name.StartsWith("RadialRadiator");
            startWithLargeFlatRadiator = part.name.StartsWith("LargeFlatRadiator");

            deployRadiatorEvent  = Events["DeployRadiator"];
            retractRadiatorEvent = Events["RetractRadiator"];

            thermalPowerConvStrField = Fields["thermalPowerConvStr"];
            radiatorIsEnabledField   = Fields["radiatorIsEnabled"];
            isAutomatedField         = Fields["isAutomated"];
            pivotEnabledField        = Fields["pivotEnabled"];

            var preventDeplyField = Fields["preventShieldedDeploy"];

            preventDeplyField.guiActive       = isDeployable;
            preventDeplyField.guiActiveEditor = isDeployable;

            Actions["DeployRadiatorAction"].guiName  = Events["DeployRadiator"].guiName = "Deploy Radiator";
            Actions["ToggleRadiatorAction"].guiName  = String.Format("Toggle Radiator");
            Actions["RetractRadiatorAction"].guiName = "Retract Radiator";

            Events["RetractRadiator"].guiName = "Retract Radiator";

            var myAttachedEngine = part.FindModuleImplementing <ModuleEngines>();

            if (myAttachedEngine == null)
            {
                partMass = part.mass;
                Fields["partMass"].guiActiveEditor        = true;
                Fields["partMass"].guiActive              = true;
                Fields["convectiveBonus"].guiActiveEditor = true;
            }

            if (!String.IsNullOrEmpty(thermalAnim))
            {
                heatStates = PluginHelper.SetUpAnimation(thermalAnim, this.part);

                if (heatStates != null)
                {
                    SetHeatAnimationRatio(0);
                }
            }

            deployAnimation = part.FindModelAnimators(animName).FirstOrDefault();
            if (deployAnimation != null)
            {
                deployAnimation[animName].layer = 1;
                deployAnimation[animName].speed = 0;

                deployAnimation[animName].normalizedTime = radiatorIsEnabled ? 1 : 0;
            }

            _moduleActiveRadiator = part.FindModuleImplementing <ModuleActiveRadiator>();

            if (_moduleActiveRadiator != null)
            {
                _moduleActiveRadiator.Events["Activate"].guiActive = false;
                _moduleActiveRadiator.Events["Shutdown"].guiActive = false;
            }
            _moduleDeployableRadiator = part.FindModuleImplementing <ModuleDeployableRadiator>();
            if (_moduleDeployableRadiator != null)
            {
                radiatorState = _moduleDeployableRadiator.deployState;
            }

            var radiatorfield = Fields["radiatorIsEnabled"];

            radiatorfield.guiActive        = showControls;
            radiatorfield.guiActiveEditor  = showControls;
            radiatorfield.OnValueModified += radiatorIsEnabled_OnValueModified;

            var automatedfield = Fields["isAutomated"];

            automatedfield.guiActive       = showControls;
            automatedfield.guiActiveEditor = showControls;

            var pivotfield = Fields["pivotEnabled"];

            pivotfield.guiActive       = showControls;
            pivotfield.guiActiveEditor = showControls;

            if (_moduleActiveRadiator != null)
            {
                _maxEnergyTransfer = radiatorArea * PhysicsGlobals.StefanBoltzmanConstant * Math.Pow(MaxRadiatorTemperature, 4) * 0.001;

                _moduleActiveRadiator.maxEnergyTransfer = _maxEnergyTransfer;
                _moduleActiveRadiator.overcoolFactor    = 0.20 + ((int)CurrentGenerationType * 0.025);

                if (radiatorIsEnabled)
                {
                    _moduleActiveRadiator.Activate();
                }
                else
                {
                    _moduleActiveRadiator.Shutdown();
                }
            }

            if (state == StartState.Editor)
            {
                return;
            }

            if (isAutomated && !isDeployable)
            {
                ActivateRadiator();
            }

            for (var i = 0; i < 20; i++)
            {
                radTempQueue.Enqueue(currentRadTemp);
            }

            InitializeTemperatureColorChannels();

            ApplyColorHeat();

            if (ResearchAndDevelopment.Instance != null)
            {
                upgradeCostStr = ResearchAndDevelopment.Instance.Science + "/" + upgradeCost.ToString("0") + " Science";
            }

            renderArray = part.FindModelComponents <Renderer>().ToArray();

            if (radiatorInit == false)
            {
                radiatorInit = true;
            }

            radiatorTempStr = maxRadiatorTemperature + "K";

            maxVacuumTemperature     = isGraphene ? Math.Min(maxVacuumTemperature, maxRadiatorTemperature) : Math.Min(RadiatorProperties.RadiatorTemperatureMk4, maxRadiatorTemperature);
            maxAtmosphereTemperature = isGraphene ? Math.Min(maxAtmosphereTemperature, maxRadiatorTemperature) : Math.Min(RadiatorProperties.RadiatorTemperatureMk3, maxRadiatorTemperature);

            UpdateMaxCurrentTemperature();

            if (keepMaxPartTempEqualToMaxRadiatorTemp)
            {
                var partSkinTemperature = Math.Min(part.skinTemperature, maxCurrentRadiatorTemperature * 0.99);
                if (double.IsNaN(partSkinTemperature) == false)
                {
                    part.skinTemperature = partSkinTemperature;
                }

                var partTemperature = Math.Min(part.temperature, maxCurrentRadiatorTemperature * 0.99);
                if (double.IsNaN(partTemperature) == false)
                {
                    part.temperature = partTemperature;
                }

                if (double.IsNaN(maxCurrentRadiatorTemperature) == false)
                {
                    part.skinMaxTemp = maxCurrentRadiatorTemperature;
                    part.maxTemp     = maxCurrentRadiatorTemperature;
                }
            }

            if (maintainResourceBuffers)
            {
                resourceBuffers = new ResourceBuffers();
                resourceBuffers.AddConfiguration(new ResourceBuffers.TimeBasedConfig(ResourceManager.FNRESOURCE_WASTEHEAT, wasteHeatMultiplier, 2.0e+6));
                resourceBuffers.UpdateVariable(ResourceManager.FNRESOURCE_WASTEHEAT, this.part.mass);
                resourceBuffers.Init(this.part);
            }
        }