private void UpdateAtmosphereBuffer()
 {
     if (intakeOpen && resourceBuffers != null)
     {
         resourceBuffers.UpdateBuffers();
     }
 }
Example #2
0
 private void UpdateAtmosphereBuffer()
 {
     if (intakeOpen)
     {
         resourceBuffers?.UpdateBuffers();
     }
 }
        public override void OnFixedUpdateResourceSuppliable(double fixedDeltaTime)
        {
            if (_moduleGenerator == null)
            {
                return;
            }

            if (_outputType == ResourceType.other)
            {
                return;
            }

            var generatorRate = _moduleOutputResource.rate;

            _mockInputResource.rate = generatorRate;

            double generatorSupply = _outputType == ResourceType.megajoule ? generatorRate :
                                     generatorRate / GameConstants.ecPerMJ;

            if (maintainsBuffer)
            {
                _resourceBuffers.UpdateBuffers();
            }

            megaJouleGeneratorPowerSupply = supplyFNResourcePerSecondWithMax(generatorSupply, generatorSupply, ResourceSettings.Config.ElectricPowerInMegawatt);
        }
Example #4
0
        public override void OnFixedUpdate() // OnFixedUpdate is only called when (force) activated
        {
            _resourceBuffers.UpdateVariable(ResourceManager.FNRESOURCE_WASTEHEAT, this.part.mass);
            _resourceBuffers.UpdateBuffers();

            var wasteheatResource = part.Resources["WasteHeat"];
        }
Example #5
0
        public override void OnFixedUpdateResourceSuppliable(double fixedDeltaTime)
        {
            try
            {
                if (moduleGenerator == null)
                {
                    return;
                }

                if (outputType == resourceType.other)
                {
                    return;
                }

                double generatorRate = moduleOutputResource.rate;
                mockInputResource.rate = generatorRate;

                double generatorSupply = outputType == resourceType.megajoule ? generatorRate : generatorRate / 1000;

                resourceBuffers.UpdateBuffers();

                megaJouleGeneratorPowerSupply = supplyFNResourcePerSecondWithMax(generatorSupply, generatorSupply, ResourceManager.FNRESOURCE_MEGAJOULES);
            }
            catch (Exception e)
            {
                Debug.LogError("[KSPI] - Exception in FNGeneratorAdapter.OnFixedUpdateResourceSuppliable " + e.Message);
                throw;
            }
        }
        private void UpdateElectricChargeBuffer(double currentPowerUsage)
        {
            if (resourceBuffers == null)
            {
                return;
            }

            resourceBuffers.UpdateVariable(ResourceSettings.Config.ElectricPowerInKilowatt, currentPowerUsage);
            resourceBuffers.UpdateBuffers();
        }
        private void UpdateElectricChargeBuffer(double currentPowerUsage)
        {
            if (resourceBuffers == null)
            {
                return;
            }

            resourceBuffers.UpdateVariable(InterstellarResourcesConfiguration.Instance.ElectricCharge, currentPowerUsage);
            resourceBuffers.UpdateBuffers();
        }
Example #8
0
        public override void OnFixedUpdate()
        {
            base.OnFixedUpdate();

            resourceBuffers.UpdateVariable("Megajoules", currentPowerSupply);
            resourceBuffers.UpdateVariable("ElectricCharge", currentPowerSupply);
            resourceBuffers.UpdateBuffers();

            currentPowerSupply = 0;
        }
Example #9
0
        public override void OnFixedUpdate()
        {
            base.OnFixedUpdate();

            resourceBuffers.UpdateVariable(ResourceSettings.Config.ElectricPowerInMegawatt, currentPowerSupply);
            resourceBuffers.UpdateVariable(ResourceSettings.Config.ElectricPowerInKilowatt, currentPowerSupply);
            resourceBuffers.UpdateBuffers();

            currentPowerSupply = 0;
        }
        public override void OnFixedUpdateResourceSuppliable(double fixedDeltaTime)
        {
            try
            {
                if (microwavePowerReceiver != null)
                {
                    return;
                }

                if (solarPanel == null)
                {
                    return;
                }

                if (outputType == resourceType.other)
                {
                    return;
                }

                // readout kerbalism solar power output so we use it
                if (_field_kerbalism_output != null)
                {
                    // if GUI is inactive, then Panel doesn't produce power since Kerbalism doesn't reset the value on occlusion
                    // to be fixed in Kerbalism!
                    kerbalismPowerOutput = _field_kerbalism_output.guiActive == true?_field_kerbalism_output.GetValue <double>(warpfixer) : 0;
                }

                // solarPanel.resHandler.outputResource[0].rate is zeroed by Kerbalism, flowRate is bogus.
                // So we need to assume that Kerbalism Power Output is ok (if present),
                // since calculating output from flowRate (or _flowRate) will not be possible.
                double solar_rate = kerbalismPowerOutput > 0 ? kerbalismPowerOutput :
                                    solarPanel.flowRate > 0 ? solarPanel.flowRate :
                                    solarPanel.panelType == ModuleDeployableSolarPanel.PanelType.FLAT ? solarPanel._flowRate :
                                    solarPanel._flowRate * solarPanel.chargeRate;

                double maxSupply = solarPanel._distMult > 0
                    ? solarPanel.chargeRate * solarPanel._distMult * solarPanel._efficMult
                    : solar_rate;

                resourceBuffers.UpdateBuffers();

                // extract power otherwise we end up with double power
                // TODO MISSING IMPLEMENTATION

                solar_supply    = outputType == resourceType.megajoule ? solar_rate : solar_rate / 1000;
                solar_maxSupply = outputType == resourceType.megajoule ? maxSupply : maxSupply / 1000;

                megaJouleSolarPowerSupply = supplyFNResourcePerSecondWithMax(solar_supply, solar_maxSupply, ResourceManager.FNRESOURCE_MEGAJOULES);
            }
            catch (Exception e)
            {
                Debug.LogError("[KSPI] - Exception in FNSolarPanelWasteHeatModule.OnFixedUpdateResourceSuppliable " + e.Message);
                throw;
            }
        }
        public override void OnFixedUpdateResourceSuppliable(double fixedDeltaTime)
        {
            if (_solarPanel == null)
            {
                return;
            }

            if (_outputType == ResourceType.other)
            {
                return;
            }

            flowRate       = _solarPanel.flowRate;
            chargeRate     = _solarPanel.chargeRate;
            efficiencyMult = _solarPanel.efficiencyMult;
            _efficMult     = _solarPanel._efficMult;

            calculatedEfficency = _solarPanel._efficMult > 0
                ? _solarPanel._efficMult
                : (double)(decimal)_solarPanel.temperatureEfficCurve.Evaluate((Single)part.skinTemperature) * (double)(decimal)_solarPanel.timeEfficCurve.Evaluate((Single)((Planetarium.GetUniversalTime() - _solarPanel.launchUT) * 1.15740740740741E-05)) * (double)(decimal)_solarPanel.efficiencyMult;

            double maxSupply = 0;
            double solarRate = 0;

            sunAOA = 0;
            CalculateSolarFlowRate(calculatedEfficency / scale, ref maxSupply, ref solarRate);

            if (_resourceBuffers != null)
            {
                _resourceBuffers.UpdateBuffers();
            }

            // extract power otherwise we end up with double power
            if (flowRate > 0 && solarRate > 0)
            {
                part.RequestResource(_solarPanel.resourceName, flowRate * fixedDeltaTime);
            }
            else
            {
                part.RequestResource(_solarPanel.resourceName, solarRate * fixedDeltaTime);
            }

            // provide power to supply manager
            solar_supply   = _outputType == ResourceType.megajoule ? solarRate : solarRate * 0.001;
            solarMaxSupply = _outputType == ResourceType.megajoule ? maxSupply : maxSupply * 0.001;

            megaJouleSolarPowerSupply = supplyFNResourcePerSecondWithMax(solar_supply, solarMaxSupply, ResourceManager.FNRESOURCE_MEGAJOULES);
        }
Example #12
0
        public override void OnFixedUpdateResourceSuppliable(double fixedDeltaTime)
        {
            try
            {
                if (moduleGenerator == null)
                {
                    return;
                }
                if (_field_status == null)
                {
                    return;
                }
                if (_field_generated == null)
                {
                    return;
                }

                bool status = _field_status.GetValue <bool>(moduleGenerator);

                float generatorRate = status ? _field_generated.GetValue <float>(moduleGenerator) : 0;
                float generatorMax  = _field_max.GetValue <float>(moduleGenerator);

                // extract power otherwise we end up with double power
                if (_field_addedToTanks != null)
                {
                    part.RequestResource(ResourceManager.STOCK_RESOURCE_ELECTRICCHARGE, _field_addedToTanks.GetValue <float>(moduleGenerator));
                }

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

                megaJouleGeneratorPowerSupply = supplyFNResourcePerSecondWithMax(generatorRate / 1000, generatorMax / 1000, ResourceManager.FNRESOURCE_MEGAJOULES);

                if (!CheatOptions.IgnoreMaxTemperature)
                {
                    supplyFNResourcePerSecond(generatorRate / 10000.0d, ResourceManager.FNRESOURCE_WASTEHEAT);
                }
            }
            catch (Exception e)
            {
                Debug.LogError("[KSPI] - Exception in FNFissionGeneratorAdapter.OnFixedUpdateResourceSuppliable " + e.Message);
                throw;
            }
        }
Example #13
0
        public override void OnFixedUpdateResourceSuppliable(double fixedDeltaTime)
        {
            if (_moduleGenerator == null || _fieldStatus == null || _fieldGenerated == null)
            {
                return;
            }

            bool status = _fieldStatus.GetValue <bool>(_moduleGenerator);

            float generatorRate       = status ? _fieldGenerated.GetValue <float>(_moduleGenerator) : 0;
            float generatorMax        = _fieldMax.GetValue <float>(_moduleGenerator);
            float generatorEfficiency = _fieldEfficiency.GetValue <float>(_moduleGenerator);

            efficiency = generatorEfficiency.ToString("P2");

            //extract power otherwise we end up with double power
            part.RequestResource(ResourceSettings.Config.ElectricPowerInKilowatt, generatorRate * fixedDeltaTime);

            double megajoulesRate    = generatorRate / GameConstants.ecPerMJ;
            double maxMegajoulesRate = generatorMax / GameConstants.ecPerMJ;

            _resourceBuffers.UpdateVariable(ResourceSettings.Config.ElectricPowerInMegawatt, megajoulesRate);
            _resourceBuffers.UpdateVariable(ResourceSettings.Config.WasteHeatInMegawatt, part.mass);
            _resourceBuffers.UpdateBuffers();

            megaJouleGeneratorPowerSupply = supplyFNResourcePerSecondWithMax(megajoulesRate, maxMegajoulesRate, ResourceSettings.Config.ElectricPowerInMegawatt);

            if (CheatOptions.IgnoreMaxTemperature)
            {
                return;
            }

            double maxWasteheat       = generatorEfficiency > 0.0 ? maxMegajoulesRate * (1.0 / generatorEfficiency - 1.0) : maxMegajoulesRate;
            double throttledWasteheat = generatorEfficiency > 0.0 ? megajoulesRate * (1.0 / generatorEfficiency - 1.0) : megajoulesRate;

            supplyFNResourcePerSecondWithMax(throttledWasteheat, maxWasteheat, ResourceSettings.Config.WasteHeatInMegawatt);
        }
        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;

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

            if (throttle > 0)
            {
                var requestedPowerPerSecond = throttle * CurrentMaximumPowerRequirement;

                //var resourceBarRatio = getResourceBarRatio(ResourceManager.FNRESOURCE_MEGAJOULES);
                //var effectivePowerThrotling = useMegajouleBattery ? 1 : resourceBarRatio > 0.1 ? 1 : resourceBarRatio * 10;

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

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

                fusionRatio = requestedPowerPerSecond > 0 ? recievedPowerPerSecond / requestedPowerPerSecond : 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 * throttle * 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 = "Insufficient Electricity";
                }
            }
            else
            {
                enginePowerRequirement = 0;
                absorbedWasteheat      = 0;
                laserWasteheat         = 0;

                var requestedPowerPerSecond = CurrentMaximumPowerRequirement;

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

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

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

                maxFuelFlow            = fusionRatio * 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();
        }
        // FixedUpdate is also called in the Editor
        public void FixedUpdate()
        {
            if (HighLogic.LoadedSceneIsEditor)
            {
                return;
            }

            if (_attached_engine == null)
            {
                return;
            }

            if (_attached_reactor != null && _attached_reactor.ChargedParticlePropulsionEfficiency > 0)
            {
                if (_attached_reactor.Part != this.part)
                {
                    resourceBuffers.UpdateVariable(ResourceManager.FNRESOURCE_WASTEHEAT, this.part.mass);
                    resourceBuffers.UpdateBuffers();
                }

                _max_charged_particles_power = _attached_reactor.MaximumChargedPower * exchanger_thrust_divisor * _attached_reactor.ChargedParticlePropulsionEfficiency;
                _charged_particles_requested = _attached_engine.isOperational && _attached_engine.currentThrottle > 0 ? _max_charged_particles_power : 0;
                _charged_particles_received  = consumeFNResourcePerSecond(_charged_particles_requested, ResourceManager.FNRESOURCE_CHARGED_PARTICLES);

                // convert reactor product into propellants when possible
                var chargedParticleRatio = _attached_reactor.MaximumChargedPower > 0 ? _charged_particles_received / _attached_reactor.MaximumChargedPower : 0;

                // update Isp
                var currentIsp = !_attached_engine.isOperational || _attached_engine.currentThrottle == 0 ? maximum_isp : Math.Min(maximum_isp, minimum_isp / Math.Pow(_attached_engine.currentThrottle, throtleExponent));

                var powerThrustModifier          = GameConstants.BaseThrustPowerMultiplier * powerThrustMultiplier;
                var max_engine_thrust_at_max_isp = powerThrustModifier * _charged_particles_received / maximum_isp / GameConstants.STANDARD_GRAVITY;
                var calculatedConsumptionInTon   = max_engine_thrust_at_max_isp / maximum_isp / GameConstants.STANDARD_GRAVITY;

                // generate addition propellant from reactor fuel consumption
                _attached_reactor.UseProductForPropulsion(chargedParticleRatio, calculatedConsumptionInTon);

                calculatedConsumptionPerSecond = calculatedConsumptionInTon * 1000;

                if (!CheatOptions.IgnoreMaxTemperature)
                {
                    if (_attached_engine.isOperational && _attached_engine.currentThrottle > 0)
                    {
                        consumeFNResourcePerSecond(_charged_particles_received, ResourceManager.FNRESOURCE_WASTEHEAT);
                        _previous_charged_particles_received = _charged_particles_received;
                    }
                    else if (_previous_charged_particles_received > 0)
                    {
                        consumeFNResourcePerSecond(_previous_charged_particles_received, ResourceManager.FNRESOURCE_WASTEHEAT);
                        _previous_charged_particles_received = 0;
                    }
                    else
                    {
                        _charged_particles_received          = 0;
                        _previous_charged_particles_received = 0;
                    }
                }

                // calculate power cost
                var ispPowerCostMultiplier = 1 + max_power_multiplier - Math.Log10(currentIsp / minimum_isp);
                var minimumEnginePower     = _attached_reactor.MagneticNozzlePowerMult * _charged_particles_received * ispPowerCostMultiplier * 0.005 * Math.Max(_attached_reactor_distance, 1);
                var neededBufferPower      = Math.Min(Math.Max(powerBufferMax - powerBufferStore, 0), minimumEnginePower);
                _requestedElectricPower = minimumEnginePower + neededBufferPower;

                _recievedElectricPower = CheatOptions.InfiniteElectricity
                    ? _requestedElectricPower
                    : consumeFNResourcePerSecond(_requestedElectricPower, ResourceManager.FNRESOURCE_MEGAJOULES);

                // adjust power buffer
                var powerSurplus = _recievedElectricPower - minimumEnginePower;
                if (powerSurplus < 0)
                {
                    var powerFromBuffer = Math.Min(-powerSurplus, powerBufferStore);
                    _recievedElectricPower += powerFromBuffer;
                    powerBufferStore       -= powerFromBuffer;
                }
                else
                {
                    powerBufferStore += powerSurplus;
                }

                // calculate Power factor
                megajoulesRatio = Math.Min(_recievedElectricPower / minimumEnginePower, 1);
                megajoulesRatio = (double.IsNaN(megajoulesRatio) || double.IsInfinity(megajoulesRatio)) ? 0 : megajoulesRatio;
                var scaledPowerFactor = Math.Pow(megajoulesRatio, 0.5);

                double atmoIspFactor = 1;

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

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

                    var max_theoretical_thrust = powerThrustModifier * _max_charged_particles_power / currentIsp / GameConstants.STANDARD_GRAVITY;

                    atmoIspFactor = max_theoretical_thrust > 0 ? effective_thrust / max_theoretical_thrust : 0;

                    _engineMaxThrust = _attached_engine.currentThrottle > 0
                        ? Math.Max(effective_thrust, 0.000000001)
                        : Math.Max(max_theoretical_thrust, 0.000000001);
                }

                // set isp
                FloatCurve newAtmosphereCurve = new FloatCurve();
                newAtmosphereCurve.Add(0, (float)(currentIsp * scaledPowerFactor * atmoIspFactor), 0, 0);
                _attached_engine.atmosphereCurve = newAtmosphereCurve;

                var max_fuel_flow_rate = !double.IsInfinity(_engineMaxThrust) && !double.IsNaN(_engineMaxThrust) && currentIsp > 0
                    ? _engineMaxThrust / currentIsp / GameConstants.STANDARD_GRAVITY / (_attached_engine.currentThrottle > 0 ? _attached_engine.currentThrottle : 1)
                    : 0;

                // set maximum flow
                _attached_engine.maxFuelFlow    = Math.Max((float)max_fuel_flow_rate, 0.0000000001f);
                _attached_engine.useThrustCurve = false;

                // This whole thing may be inefficient, but it should clear up some confusion for people.
                if (_attached_engine.getFlameoutState)
                {
                    return;
                }

                if (_attached_engine.currentThrottle < 0.99)
                {
                    _attached_engine.status = "offline";
                }
                else if (megajoulesRatio < 0.75 && _requestedElectricPower > 0)
                {
                    _attached_engine.status = "Insufficient Electricity";
                }
                else if (atmoIspFactor < 0.01)
                {
                    _attached_engine.status = "Too dense atmospherere";
                }
            }
            else
            {
                _attached_engine.maxFuelFlow = 0.0000000001f;
                _recievedElectricPower       = 0;
                _charged_particles_requested = 0;
                _charged_particles_received  = 0;
                _engineMaxThrust             = 0;
            }
        }
Example #16
0
        // 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.totalMass);
            }
            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 : maxThrustInSpace / engineIsp / PluginHelper.GravityConstant;
                vacuumPlasmaResource.maxAmount = Math.Max(0.0000001, calculatedConsumptionInTon * 200 * TimeWarp.fixedDeltaTime);
                part.RequestResource(InterstellarResourcesConfiguration.Instance.VacuumPlasma, -vacuumPlasmaResource.maxAmount);
            }
        }
Example #17
0
        public override void OnFixedUpdateResourceSuppliable(double fixedDeltaTime)
        {
            try
            {
                last_active_time = Planetarium.GetUniversalTime();

                powerGeneratorPowerOutput = 0;
                powerGeneratorPowerInput  = 0;

                if (moduleGenerator == null)
                {
                    return;
                }

                if (outputType == ResourceType.other)
                {
                    return;
                }

                if (!moduleGenerator.generatorIsActive && !moduleGenerator.isAlwaysActive)
                {
                    mockInputResource.rate = 0;
                    supplyFNResourcePerSecondWithMax(0, 0, ResourceManager.FNRESOURCE_MEGAJOULES);
                    return;
                }

                if (maintainsBuffer)
                {
                    resourceBuffers.UpdateBuffers();
                }

                if (maximumPowerGeneration != 0)
                {
                    currentMegajoulesDemand = Math.Max(0, GetCurrentUnfilledResourceDemand(ResourceManager.FNRESOURCE_MEGAJOULES));
                    currentMegajoulesSupply = Math.Min(currentMegajoulesDemand, maximumPowerGeneration);
                }

                if (moduleInputResource != null)
                {
                    if (currentMegajoulesSupply > 0)
                    {
                        moduleInputResource.rate = currentMegajoulesSupply;
                    }
                    else
                    {
                        moduleInputResource.rate = initialInputAmount;
                    }

                    part.GetConnectedResourceTotals(moduleInputResource.id, out inputAmount, out inputMaxAmount);

                    var availableRatio = Math.Min(1, inputAmount / (moduleInputResource.rate * fixedDeltaTime));

                    currentMegajoulesSupply  *= availableRatio;
                    moduleInputResource.rate *= availableRatio;

                    generatorInputRate       = moduleInputResource.rate;
                    powerGeneratorPowerInput = inputType == ResourceType.megajoule ? generatorInputRate : generatorInputRate / 1000;
                }

                if (moduleOutputResource != null)
                {
                    generatorOutputRateInElectricCharge = maximumPowerGeneration > 0
                        ? currentMegajoulesSupply * (outputType == ResourceType.megajoule ? 1 : 1000)
                        : initialOutputAmount;

                    if (maximumPowerGeneration > 0)
                    {
                        moduleOutputResource.rate = 1 + generatorOutputRateInElectricCharge;
                    }
                    else
                    {
                        moduleOutputResource.rate = 1 + generatorOutputRateInElectricCharge;
                    }

                    mockInputResource.rate = generatorOutputRateInElectricCharge;

                    double generatorSupplyInMegajoules = outputType == ResourceType.megajoule ? generatorOutputRateInElectricCharge : generatorOutputRateInElectricCharge / 1000;

                    powerGeneratorPowerOutput = supplyFNResourcePerSecondWithMax(generatorSupplyInMegajoules, generatorSupplyInMegajoules, ResourceManager.FNRESOURCE_MEGAJOULES);
                }
            }
            catch (Exception e)
            {
                Debug.LogError("[KSPI]: Exception in FNGeneratorAdapter.OnFixedUpdateResourceSuppliable " + e.Message);
                throw;
            }
        }
Example #18
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);
                var deltaTempToPowerFour = deltaTemp * deltaTemp * deltaTemp * deltaTemp;

                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 * deltaTempToPowerFour * 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 * deltaTempToPowerFour * 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 #19
0
        public override void OnFixedUpdateResourceSuppliable(double fixedDeltaTime)
        {
            last_active_time = Planetarium.GetUniversalTime();

            powerGeneratorPowerOutput = 0;
            powerGeneratorPowerInput  = 0;

            if (moduleGenerator == null)
            {
                return;
            }

            if (outputType == ResourceType.other)
            {
                return;
            }

            if (!moduleGenerator.generatorIsActive && !moduleGenerator.isAlwaysActive)
            {
                mockInputResource.rate = 0;
                SupplyFnResourcePerSecondWithMax(0, 0, ResourceSettings.Config.ElectricPowerInMegawatt);
                return;
            }

            if (maintainsBuffer)
            {
                resourceBuffers.UpdateBuffers();
            }

            if (maximumPowerGeneration != 0)
            {
                currentMegajoulesDemand = Math.Max(0, GetCurrentUnfilledResourceDemand(ResourceSettings.Config.ElectricPowerInMegawatt));
                currentMegajoulesSupply = Math.Min(currentMegajoulesDemand, maximumPowerGeneration);
            }

            if (moduleInputResource != null)
            {
                moduleInputResource.rate = currentMegajoulesSupply > 0 ? currentMegajoulesSupply : initialInputAmount;

                part.GetConnectedResourceTotals(moduleInputResource.id, out inputAmount, out inputMaxAmount);

                var availableRatio = Math.Min(1, inputAmount / (moduleInputResource.rate * fixedDeltaTime));

                currentMegajoulesSupply  *= availableRatio;
                moduleInputResource.rate *= availableRatio;

                generatorInputRate       = moduleInputResource.rate;
                powerGeneratorPowerInput = inputType == ResourceType.megajoule ?
                                           generatorInputRate : generatorInputRate / GameConstants.ecPerMJ;
            }

            if (moduleOutputResource != null)
            {
                if (Kerbalism.IsLoaded)
                {
                    moduleOutputResource.rate = 0;
                }

                generatorOutputRateInElectricCharge = maximumPowerGeneration > 0
                    ? currentMegajoulesSupply * (outputType == ResourceType.megajoule ? 1 : GameConstants.ecPerMJ)
                    : initialOutputAmount;

                if (maximumPowerGeneration > 0)
                {
                    moduleOutputResource.rate = 1 + generatorOutputRateInElectricCharge;
                }
                else
                {
                    moduleOutputResource.rate = 1 + generatorOutputRateInElectricCharge;
                }

                mockInputResource.rate = generatorOutputRateInElectricCharge;

                double generatorSupplyInMegajoules = outputType == ResourceType.megajoule ?
                                                     generatorOutputRateInElectricCharge : generatorOutputRateInElectricCharge / GameConstants.ecPerMJ;

                powerGeneratorPowerOutput = SupplyFnResourcePerSecondWithMax(generatorSupplyInMegajoules, generatorSupplyInMegajoules, ResourceSettings.Config.ElectricPowerInMegawatt);
            }
        }
        public override void OnFixedUpdateResourceSuppliable(double fixedDeltaTime)
        {
            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.requestedThrottle > 0)
            {
                //if (vessel.atmDensity > maxAtmosphereDensity || vessel.atmDensity > _currentActiveConfiguration.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 (MinIsp <= 100)
                //    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));

            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, ResourceManager.FNRESOURCE_MEGAJOULES);

                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, ResourceManager.FNRESOURCE_MEGAJOULES);
                }

                // Lasers produce Wasteheat
                if (!CheatOptions.IgnoreMaxTemperature && laserWasteheat > 0)
                {
                    supplyFNResourcePerSecondWithMax(laserWasteheat, currentMaximumPowerRequirement * inefficiency, 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;

                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 / GameConstants.STANDARD_GRAVITY;

                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;
            //base.OnFixedUpdate();
        }
Example #21
0
        public override void OnFixedUpdateResourceSuppliable(double fixedDeltaTime)
        {
            if (_solarPanel == null)
            {
                return;
            }

            if (_fieldKerbalismNominalRate != null)
            {
                kerbalism_nominalRate = _fieldKerbalismNominalRate.GetValue <double>(_solarPanelFixer);
                kerbalism_panelState  = _fieldKerbalismPanelStatus.GetValue <string>(_solarPanelFixer);

                var kerbalismPanelStateArray = kerbalism_panelState.Split(' ');

                kerbalism_panelOutput = kerbalismPanelStateArray[0];

                double.TryParse(kerbalism_panelOutput, out kerbalism_panelPower);
            }

            if (_outputResource != null && _solarPanel.deployState == ModuleDeployablePart.DeployState.EXTENDED)
            {
                outputResourceRate           = _outputResource.rate;
                outputResourceCurrentRequest = _outputResource.currentRequest;
            }
            else
            {
                outputResourceRate           = 0;
                outputResourceCurrentRequest = 0;
            }

            if (_outputType == ResourceType.other)
            {
                return;
            }

            chargeRate = _solarPanel.chargeRate;

            double age = (Planetarium.GetUniversalTime() - _solarPanel.launchUT) * 1.15740740740741E-05;

            calculatedEfficency = _solarPanel._efficMult > 0 ? _solarPanel._efficMult :
                                  _solarPanel.temperatureEfficCurve.Evaluate((float)part.skinTemperature) *
                                  _solarPanel.timeEfficCurve.Evaluate((float)age) * _solarPanel.efficiencyMult;

            double maxSupply = 0.0, solarRate = 0.0;

            sunAOA = 0;
            CalculateSolarFlowRate(calculatedEfficency / scale, ref maxSupply, ref solarRate);

            _resourceBuffers?.UpdateBuffers();

            if (_outputResource != null)
            {
                if (Kerbalism.IsLoaded)
                {
                    //if (kerbalism_panelPower > 0)
                    //    part.RequestResource(_solarPanel.resourceName, kerbalism_panelPower * fixedDeltaTime);
                }
                else if (_outputResource != null)
                {
                    _outputResource.rate = 0;
                }
                else
                {
                    part.RequestResource(_solarPanel.resourceName, solarRate * fixedDeltaTime);
                }
            }

            // provide power to supply manager
            solar_supply   = _outputType == ResourceType.megajoule ? solarRate : solarRate / GameConstants.ecPerMJ;
            solarMaxSupply = _outputType == ResourceType.megajoule ? maxSupply : maxSupply / GameConstants.ecPerMJ;

            if (!Kerbalism.IsLoaded)
            {
                mjSolarSupply = PluginHelper.GetFormattedPowerString(SupplyFnResourcePerSecondWithMax(solar_supply, solarMaxSupply, ResourceSettings.Config.ElectricPowerInMegawatt));
                mjMaxSupply   = PluginHelper.GetFormattedPowerString(solarMaxSupply);
            }
        }
        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 #23
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 / GameConstants.STANDARD_GRAVITY;
                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 / GameConstants.STANDARD_GRAVITY;
                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 OnFixedUpdateResourceSuppliable(double fixedDeltaTime)
        {
            if (_solarPanel == null)
            {
                return;
            }

            if (_field_kerbalism_nominalRate != null)
            {
                kerbalism_nominalRate = _field_kerbalism_nominalRate.GetValue <double>(solarPanelFixer);
                kerbalism_panelState  = _field_kerbalism_panelStatus.GetValue <string>(solarPanelFixer);

                var kerbalism_panelStateArray = kerbalism_panelState.Split(' ');

                kerbalism_panelOutput = kerbalism_panelStateArray[0];

                double.TryParse(kerbalism_panelOutput, out kerbalism_panelPower);
            }

            if (outputResource != null && _solarPanel.deployState == ModuleDeployablePart.DeployState.EXTENDED)
            {
                outputResourceRate           = outputResource.rate;
                outputResourceCurrentRequest = outputResource.currentRequest;
            }
            else
            {
                outputResourceRate           = 0;
                outputResourceCurrentRequest = 0;
            }

            if (_outputType == ResourceType.other)
            {
                return;
            }

            chargeRate     = _solarPanel.chargeRate;
            efficiencyMult = _solarPanel.efficiencyMult;
            _efficMult     = _solarPanel._efficMult;

            calculatedEfficency = _solarPanel._efficMult > 0
                ? _solarPanel._efficMult
                : _solarPanel.temperatureEfficCurve.Evaluate((float)part.skinTemperature) * _solarPanel.timeEfficCurve.Evaluate((float)((Planetarium.GetUniversalTime() - _solarPanel.launchUT) * 1.15740740740741E-05)) * _solarPanel.efficiencyMult;

            maxSupply = 0;
            solarRate = 0;
            sunAOA    = 0;
            CalculateSolarFlowRate(calculatedEfficency / scale, ref maxSupply, ref solarRate);

            if (_resourceBuffers != null)
            {
                _resourceBuffers.UpdateBuffers();
            }

            if (kerbalism_panelPower > 0)
            {
                part.RequestResource(_solarPanel.resourceName, kerbalism_panelPower * fixedDeltaTime);
            }
            else if (outputResourceCurrentRequest > 0)
            {
                part.RequestResource(_solarPanel.resourceName, outputResourceCurrentRequest);
            }
            else
            {
                part.RequestResource(_solarPanel.resourceName, solarRate * fixedDeltaTime);
            }

            // provide power to supply manager
            solar_supply   = _outputType == ResourceType.megajoule ? solarRate : solarRate * 0.001;
            solarMaxSupply = _outputType == ResourceType.megajoule ? maxSupply : maxSupply * 0.001;

            megaJouleSolarPowerSupply = supplyFNResourcePerSecondWithMax(solar_supply, solarMaxSupply, ResourceManager.FNRESOURCE_MEGAJOULES);
        }
 public override void OnFixedUpdate() // OnFixedUpdate is only called when (force) activated
 {
     _resourceBuffers.UpdateVariable(ResourceSettings.Config.WasteHeatInMegawatt, this.part.mass);
     _resourceBuffers.UpdateBuffers();
 }
        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()
        {
            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 / GameConstants.STANDARD_GRAVITY;
                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 / 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          = FNRadiator.getAverageRadiatorTemperatureForVessel(vessel);
            maxTempatureRadiators = FNRadiator.getAverageMaximumRadiatorTemperatureForVessel(vessel);
            radiatorPerformance   = Math.Max(1 - (coldBathTemp / maxTempatureRadiators), 0.000001);
            partEmissiveConstant  = part.emissiveConstant;
        }
        // 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;
            }

            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;

            availablePower     = getAvailablePrioritisedStableSupply(ResourceManager.FNRESOURCE_MEGAJOULES);
            maxThrustFromPower = EvaluateMaxThrust(availablePower * _electrical_share_f);

            var megaJoulesBarRatio = getResourceBarRatio(ResourceManager.FNRESOURCE_MEGAJOULES);

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

            availablePowerForEngine = availablePower * effectiveResourceThrotling * _electrical_share_f;
            currentPowerForEngine   = availablePowerForEngine * modifiedThrotte;

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

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

            simulatedPowerReceived = Math.Min(availablePowerForEngine, maxEffectivePower);

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

            _heat_production_f = CheatOptions.IgnoreMaxTemperature
                ? heatToProduce
                : supplyFNResourcePerSecond(heatToProduce, 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 = Current_propellant.SupportedEngines == 8
                ? maxThrustWithCurrentThrottle
                : Math.Max(maxThrustWithCurrentThrottle - (exitArea * vessel.staticPressurekPa), 0);

            simulated_max_thrust = Current_propellant.SupportedEngines == 8
                ? simulatedThrustInSpace
                : Math.Max(simulatedThrustInSpace - (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            = (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  = (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 : currentThrustInSpace / engineIsp / GameConstants.STANDARD_GRAVITY;
                vacuumPlasmaResource.maxAmount = Math.Max(0.0000001, calculatedConsumptionInTon * 200 * (double)(decimal)TimeWarp.fixedDeltaTime);
                part.RequestResource(InterstellarResourcesConfiguration.Instance.VacuumPlasma, -vacuumPlasmaResource.maxAmount);
            }
        }
Example #29
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(throttle);

            hasIspThrottling = HasIspThrottling();

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

                var availablePower          = getAvailableResourceSupply(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);

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

                laserWasteheat = recievedPowerPerSecond * (1 - LaserEfficiency);

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

                // The Aborbed wasteheat from Fusion

                var rateMultplier = hasIspThrottling ? MinIsp / SelectedIsp : 1;
                neutronbsorbionBonus = hasIspThrottling ? 1 - NeutronAbsorptionFractionAtMinIsp * (1 - ((SelectedIsp - MinIsp) / (MaxIsp - MinIsp))) : 0.5;
                absorbedWasteheat    = FusionWasteHeat * wasteHeatMultiplier * fusionRatio * throttle * neutronbsorbionBonus;
                supplyFNResourcePerSecond(absorbedWasteheat, ResourceManager.FNRESOURCE_WASTEHEAT);

                // change ratio propellants Hydrogen/Fusion
                SetRatio(InterstellarResourcesConfiguration.Instance.LqdDeuterium, (float)(standard_deuterium_rate / rateMultplier));
                SetRatio(InterstellarResourcesConfiguration.Instance.LqdTritium, (float)(standard_tritium_rate / rateMultplier));

                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 && plasmaRatio < 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;
                var rateMultplier = hasIspThrottling ? MinIsp / SelectedIsp : 1;

                var maxFuelFlow = maximumThrust / currentIsp / GameConstants.STANDARD_GRAVITY;
                curEngineT.maxFuelFlow = (float)maxFuelFlow;
                SetRatio(InterstellarResourcesConfiguration.Instance.LqdDeuterium, (float)(standard_deuterium_rate / rateMultplier));
                SetRatio(InterstellarResourcesConfiguration.Instance.LqdTritium, (float)(standard_tritium_rate / rateMultplier));
            }

            coldBathTemp          = FNRadiator.getAverageRadiatorTemperatureForVessel(vessel);
            maxTempatureRadiators = FNRadiator.getAverageMaximumRadiatorTemperatureForVessel(vessel);
            radiatorPerformance   = Math.Max(1 - (coldBathTemp / maxTempatureRadiators), 0.000001);
            partEmissiveConstant  = part.emissiveConstant;
            base.OnFixedUpdate();
        }
Example #30
0
        public void FixedUpdate() // FixedUpdate is also called when not activated
        {
            try
            {
                if (!HighLogic.LoadedSceneIsFlight)
                {
                    return;
                }

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

                resourceBuffers.UpdateBuffers();

                effectiveRadiatorArea = EffectiveRadiatorArea;

                var external_temperature = FlightGlobals.getExternalTemperature(part.transform.position);

                wasteheatManager = getManagerForVessel(ResourceManager.FNRESOURCE_WASTEHEAT);

                // get resource bar ratio at start of frame
                wasteheatRatio = wasteheatManager.ResourceBarRatioBegin;

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

                var normalized_atmosphere = Math.Min(vessel.atmDensity, 1);

                maxCurrentTemperature = maxAtmosphereTemperature * Math.Max(normalized_atmosphere, 0) + maxVacuumTemperature * Math.Max(Math.Min(1 - vessel.atmDensity, 1), 0);

                radiator_temperature_temp_val = external_temperature + Math.Min((maxRadiatorTemperature - external_temperature) * Math.Sqrt(wasteheatRatio), maxCurrentTemperature - external_temperature);

                var efficiency = 1 - Math.Pow(1 - wasteheatRatio, 400);
                var delta_temp = Math.Max(radiator_temperature_temp_val - Math.Max(external_temperature * normalized_atmosphere, 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 thermal_power_dissip_per_second = efficiency * Math.Pow(delta_temp, 4) * GameConstants.stefan_const * effectiveRadiatorArea / 1e6;

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

                    radiatedThermalPower = canRadiateHeat ? consumeWasteHeatPerSecond(thermal_power_dissip_per_second) : 0;

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

                    instantaneous_rad_temp = Math.Max(radiator_temperature_temp_val, Math.Max(FlightGlobals.getExternalTemperature(vessel.altitude, vessel.mainBody), 2.7));

                    if (Double.IsNaN(instantaneous_rad_temp))
                    {
                        Debug.LogError("FNRadiator: FixedUpdate Single.IsNaN detected in instantaneous_rad_temp after reading external temperature");
                    }

                    CurrentRadiatorTemperature = instantaneous_rad_temp;

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

                    radiatedThermalPower = canRadiateHeat ? consumeWasteHeatPerSecond(thermal_power_dissip_per_second) : 0;

                    instantaneous_rad_temp = Math.Max(radiator_temperature_temp_val, Math.Max(FlightGlobals.getExternalTemperature(vessel.altitude, vessel.mainBody), 2.7));

                    CurrentRadiatorTemperature = instantaneous_rad_temp;
                }

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

                    var splashBonus           = Math.Max(part.submergedPortion * 10, 1);
                    var convection_delta_temp = Math.Max(0, CurrentRadiatorTemperature - external_temperature);
                    var conv_power_dissip     = efficiency * pressure * convection_delta_temp * effectiveRadiatorArea * 0.001 * convectiveBonus * splashBonus;

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

                    convectedThermalPower = canRadiateHeat ? consumeWasteHeatPerSecond(conv_power_dissip) : 0;

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

                    if (!radiatorIsEnabled && isAutomated && canRadiateHeat && showControls && update_count == DEPLOYMENT_DELAY)
                    {
                        Debug.Log("[KSPI] - FixedUpdate Automated Deplotment ");
                        Deploy();
                    }
                }
            }
            catch (Exception e)
            {
                Debug.LogError("[KSPI] - Exception on " + part.name + " durring FNRadiator.FixedUpdate with message " + e.Message);
            }
        }