示例#1
0
        // execute a script
        public void Execute(Vessel v, ScriptType type)
        {
            // do nothing if there is no EC left on the vessel
            Resource_info ec = ResourceCache.Info(v, "ElectricCharge");

            if (ec.amount <= double.Epsilon)
            {
                return;
            }

            // get the script
            Script script;

            if (scripts.TryGetValue(type, out script))
            {
                // execute the script
                script.Execute(Boot(v));

                // show message to the user
                // - unless the script is empty (can happen when being edited)
                if (script.states.Count > 0 && DB.Vessel(v).cfg_script)
                {
                    Message.Post(Lib.BuildString(Localizer.Format("#KERBALISM_UI_scriptvessel"), " <b>", v.vesselName, "</b>"));
                }
            }
        }
示例#2
0
        public KeyValuePair <bool, double> modReturn;               // Return from DeviceEC

        public override void OnStart(StartState state)
        {
            // don't break tutorial scenarios & do something only in Flight scenario
            if (Lib.DisableScenario(this) || !Lib.IsFlight())
            {
                return;
            }

            // cache list of modules
            module = part.FindModulesImplementing <PartModule>().FindLast(k => k.moduleName == type);

            // get energy from cache
            resources = ResourceCache.Info(vessel, "ElectricCharge");
            hasEnergy = resources.amount > double.Epsilon;

            // Force the update to run at least once
            lastBrokenState       = !isBroken;
            hasEnergyChanged      = !hasEnergy;
            hasFixedEnergyChanged = !hasEnergy;

#if DEBUG
            // setup UI
            Fields["actualCost"].guiActive = true;
            Fields["isBroken"].guiActive   = true;
#endif
        }
示例#3
0
        void Indicator_ec(Panel p, Vessel v, Vessel_info vi)
        {
#if !KSP170 && !KSP16 && !KSP15 && !KSP14
            if (v.vesselType == VesselType.DeployedScienceController)
            {
                return;
            }
#endif

            Resource_info ec            = ResourceCache.Info(v, "ElectricCharge");
            Supply        supply        = Profile.supplies.Find(k => k.resource == "ElectricCharge");
            double        low_threshold = supply != null ? supply.low_threshold : 0.15;
            double        depletion     = ec.Depletion(vi.crew_count);

            string tooltip = Lib.BuildString
                             (
                "<align=left /><b>name\tlevel\tduration</b>\n",
                ec.level <= 0.005 ? "<color=#ff0000>" : ec.level <= low_threshold ? "<color=#ffff00>" : "<color=#cccccc>",
                "EC\t",
                Lib.HumanReadablePerc(ec.level), "\t",
                depletion <= double.Epsilon ? "depleted" : Lib.HumanReadableDuration(depletion),
                "</color>"
                             );

            Texture2D image = ec.level <= 0.005
                          ? Icons.battery_red
                          : ec.level <= low_threshold
                          ? Icons.battery_yellow
                          : Icons.battery_white;

            p.AddIcon(image, tooltip);
        }
示例#4
0
        // return total radiation emitted in a vessel
        public static double Total(Vessel v)
        {
            // get resource cache
            Resource_info ec = ResourceCache.Info(v, "ElectricCharge");

            double tot = 0.0;

            if (v.loaded)
            {
                foreach (var emitter in Lib.FindModules <Emitter>(v))
                {
                    if (ec.amount > double.Epsilon || emitter.ec_rate <= double.Epsilon)
                    {
                        tot += emitter.running ? emitter.radiation : 0.0;
                    }
                }
            }
            else
            {
                foreach (ProtoPartModuleSnapshot m in Lib.FindModules(v.protoVessel, "Emitter"))
                {
                    if (ec.amount > double.Epsilon || Lib.Proto.GetDouble(m, "ec_rate") <= double.Epsilon)
                    {
                        tot += Lib.Proto.GetBool(m, "running") ? Lib.Proto.GetDouble(m, "radiation") : 0.0;
                    }
                }
            }
            return(tot);
        }
示例#5
0
		static void Render_supplies(Panel p, Vessel v, Vessel_info vi, Vessel_resources resources)
		{
			// for each supply
			int supplies = 0;
			foreach (Supply supply in Profile.supplies)
			{
				// get resource info
				Resource_info res = resources.Info(v, supply.resource);

				// only show estimate if the resource is present
				if (res.amount <= 1e-10) continue;

				// render panel title, if not done already
				if (supplies == 0) p.AddSection("SUPPLIES");

				// rate tooltip
				string rate_tooltip = Math.Abs(res.rate) >= 1e-10 ? Lib.BuildString
				(
				  res.rate > 0.0 ? "<color=#00ff00><b>" : "<color=#ffaa00><b>",
				  Lib.HumanReadableRate(Math.Abs(res.rate)),
				  "</b></color>"
				) : string.Empty;

				// determine label
				string label = supply.resource == "ElectricCharge"
				  ? "battery"
				  : Lib.SpacesOnCaps(supply.resource).ToLower();

				// finally, render resource supply
				p.AddContent(label, Lib.HumanReadableDuration(res.Depletion(vi.crew_count)), rate_tooltip);
				++supplies;
			}
		}
示例#6
0
        public void FixedUpdate()
        {
            // do nothing in the editor
            if (Lib.IsEditor())
            {
                return;
            }

            // if enabled
            if (running)
            {
                // if a researcher is not required, or the researcher is present
                if (!researcher_cs || researcher_cs.Check(part.protoModuleCrew))
                {
                    // get next sample to analyze
                    current_sample = NextSample(vessel);

                    // if there is a sample to analyze
                    if (current_sample != null)
                    {
                        // consume EC
                        ec = ResourceCache.Info(vessel, "ElectricCharge");
                        ec.Consume(ec_rate * Kerbalism.elapsed_s);

                        // if there was ec
                        // - comparing against amount in previous simulation step
                        if (ec.amount > double.Epsilon)
                        {
                            // analyze the sample
                            Analyze(vessel, current_sample, analysis_rate * Kerbalism.elapsed_s);
                            status = Status.RUNNING;
                        }
                        // if there was no ec
                        else
                        {
                            status = Status.NO_EC;
                        }
                    }
                    // if there is no sample to analyze
                    else
                    {
                        status = Status.NO_SAMPLE;
                    }
                }
                // if a researcher is required, but missing
                else
                {
                    status = Status.NO_RESEARCHER;
                }
            }
            // if disabled
            else
            {
                status = Status.DISABLED;
            }
        }
示例#7
0
        public void FixedUpdate()
        {
            if (!loaded)
            {
                return;
            }
            Resource_info ec = ResourceCache.Info(vessel, "ElectricCharge");

            RunProcessTick(vessel, Kerbalism.elapsed_s, ec_produced, resourcesProduced, ec_consumed, resourcesConsumed, ec, ResourceCache.Get(vessel));
        }
示例#8
0
        static void ProcessConverter(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, ModuleResourceConverter converter, Vessel_resources resources, double elapsed_s)
        {
            // note: ignore stock temperature mechanic of converters
            // note: ignore auto shutdown
            // note: non-mandatory resources 'dynamically scale the ratios', that is exactly what mandatory resources do too (DERP ALERT)
            // note: 'undo' stock behavior by forcing lastUpdateTime to now (to minimize overlapping calculations from this and stock post-facto simulation)

            // if active
            if (Lib.Proto.GetBool(m, "IsActivated"))
            {
                // determine if vessel is full of all output resources
                // note: comparing against previous amount
                bool full = true;
                foreach (var or in converter.outputList)
                {
                    Resource_info res = resources.Info(v, or.ResourceName);
                    full &= (res.level >= converter.FillAmount - double.Epsilon);
                }

                // if not full
                if (!full)
                {
                    // deduce crew bonus
                    int exp_level = -1;
                    if (converter.UseSpecialistBonus)
                    {
                        foreach (ProtoCrewMember c in Lib.CrewList(v))
                        {
                            if (c.experienceTrait.Effects.Find(k => k.Name == converter.ExperienceEffect) != null)
                            {
                                exp_level = Math.Max(exp_level, c.experienceLevel);
                            }
                        }
                    }
                    double exp_bonus = exp_level < 0
                                          ? converter.EfficiencyBonus * converter.SpecialistBonusBase
                                          : converter.EfficiencyBonus * (converter.SpecialistBonusBase + (converter.SpecialistEfficiencyFactor * (exp_level + 1)));

                    // create and commit recipe
                    Resource_recipe recipe = new Resource_recipe(p);
                    foreach (var ir in converter.inputList)
                    {
                        recipe.Input(ir.ResourceName, ir.Ratio * exp_bonus * elapsed_s);
                    }
                    foreach (var or in converter.outputList)
                    {
                        recipe.Output(or.ResourceName, or.Ratio * exp_bonus * elapsed_s, or.DumpExcess);
                    }
                    resources.Transform(recipe);
                }

                // undo stock behavior by forcing last_update_time to now
                Lib.Proto.Set(m, "lastUpdateTime", Planetarium.GetUniversalTime());
            }
        }
示例#9
0
        private void DoRecord(Resource_info ec, string subject_id)
        {
            var stored = DoRecord(this, subject_id, vessel, ec, privateHdId,
                                  ResourceCache.Get(vessel), resourceDefs,
                                  remainingSampleMass, dataSampled, out dataSampled, out remainingSampleMass);

            if (!stored)
            {
                issue = insufficient_storage;
            }
        }
示例#10
0
		public static void Update(Vessel v)
		{
			// do nothing if not an eva kerbal
			if (!v.isEVA) return;

			// get KerbalEVA module
			KerbalEVA kerbal = Lib.FindModules<KerbalEVA>(v)[0];

			Vessel_info vi = Cache.VesselInfo(v);

			// Stock KSP adds 5 units of monoprop to EVAs. We want to limit that amount
			// to whatever was available in the ship, so we don't magically create EVA prop out of nowhere
			if(Cache.HasVesselObjectsCache(v, "eva_prop"))
			{
				Lib.Log("### have eva_prop for " + v);
				var quantity = Cache.VesselObjectsCache<double>(v, "eva_prop");
				Cache.RemoveVesselObjectsCache(v, "eva_prop");
				Lib.Log("### adding " + quantity + " eva prop");
				Lib.SetResource(kerbal.part, Lib.EvaPropellantName(), quantity, Lib.EvaPropellantCapacity());
			}

			// get resource handler
			Resource_info ec = ResourceCache.Info(v, "ElectricCharge");

			// determine if headlamps need ec
			// - not required if there is no EC capacity in eva kerbal (no ec supply in profile)
			// - not required if no EC cost for headlamps is specified (set by the user)
			bool need_ec = ec.capacity > double.Epsilon && Settings.HeadLampsCost > double.Epsilon;

			// consume EC for the headlamps
			if (need_ec && kerbal.lampOn)
			{
				ec.Consume(Settings.HeadLampsCost * Kerbalism.elapsed_s, "headlamp");
			}

			// force the headlamps on/off
			HeadLamps(kerbal, kerbal.lampOn && (!need_ec || ec.amount > double.Epsilon));

			// if dead
			if (IsDead(v))
			{
				// enforce freezed state
				Freeze(kerbal);

				// disable modules
				DisableModules(kerbal);

				// remove plant flag action
				kerbal.flagItems = 0;
			}
		}
示例#11
0
        public override void OnUpdate()
        {
            if (!Lib.IsFlight() || module == null)
            {
                return;
            }

            // get energy from cache
            resources = ResourceCache.Info(vessel, "ElectricCharge");
            hasEnergy = resources.amount > double.Epsilon;

            // Update UI only if hasEnergy has changed or if is broken state has changed
            if (isBroken)
            {
                if (isBroken != lastBrokenState)
                {
                    lastBrokenState = isBroken;
                    Update_UI(!isBroken);
                }
            }
            else if (hasEnergyChanged != hasEnergy)
            {
                Lib.DebugLog("Energy state has changed: {0}", hasEnergy);

                hasEnergyChanged = hasEnergy;
                lastBrokenState  = false;
                // Update UI
                Update_UI(hasEnergy);
            }
            // Constantly Update UI for special modules
            if (isBroken)
            {
                Constant_OnGUI(!isBroken);
            }
            else
            {
                Constant_OnGUI(hasEnergy);
            }

            if (!hasEnergy || isBroken)
            {
                actualCost  = 0;
                isConsuming = false;
            }
            else
            {
                isConsuming = GetIsConsuming();
            }
        }
示例#12
0
        public virtual void Update()
        {
            if (Lib.IsFlight() && Features.Deploy)
            {
                // get ec resource handler
                resourceInfo = ResourceCache.Info(vessel, "ElectricCharge");
                hasEC        = resourceInfo.amount > double.Epsilon;

                isConsuming = GetisConsuming;
                if (!isConsuming)
                {
                    actualECCost = 0;
                }
            }
        }
示例#13
0
		public void FixedUpdate()
		{
			// do nothing in the editor
			if (Lib.IsEditor()) return;

			// if has any animation playing, consume energy.
			if (Is_consuming_energy())
			{
				// get resource handler
				Resource_info ec = ResourceCache.Info(vessel, "ElectricCharge");

				// consume ec
				ec.Consume(ec_rate * Kerbalism.elapsed_s);
			}
		}
示例#14
0
        public void Execute(Vessel v, VesselData vd, Vessel_resources resources)
        {
            // get crew
            List <ProtoCrewMember> crew = Lib.CrewList(v);

            // get resource handler
            Resource_info res = resources.Info(v, resource);

            // get data from db
            SupplyData sd = DB.Vessel(v).Supply(resource);

            // message obey user config
            bool show_msg = resource == "ElectricCharge" ? vd.cfg_ec : vd.cfg_supply;

            // messages are shown only if there is some capacity and the vessel is manned
            // special case: ElectricCharge related messages are shown for unmanned vessels too
            if (res.capacity > double.Epsilon && (crew.Count > 0 || resource == "ElectricCharge"))
            {
                // manned/probe message variant
                uint variant = crew.Count > 0 ? 0 : 1u;

                // manage messages
                if (res.level <= double.Epsilon && sd.message < 2)
                {
                    if (empty_message.Length > 0 && show_msg)
                    {
                        Message.Post(Severity.danger, Lib.ExpandMsg(empty_message, v, null, variant));
                    }
                    sd.message = 2;
                }
                else if (res.level < low_threshold && sd.message < 1)
                {
                    if (low_message.Length > 0 && show_msg)
                    {
                        Message.Post(Severity.warning, Lib.ExpandMsg(low_message, v, null, variant));
                    }
                    sd.message = 1;
                }
                else if (res.level > low_threshold && sd.message > 0)
                {
                    if (refill_message.Length > 0 && show_msg)
                    {
                        Message.Post(Severity.relax, Lib.ExpandMsg(refill_message, v, null, variant));
                    }
                    sd.message = 0;
                }
            }
        }
示例#15
0
        private static void RunProcessTick(Vessel v, double elapsed_s,
                                           double ec_produced, List <KeyValuePair <string, double> > resourcesProduced,
                                           double ec_consumed, List <KeyValuePair <string, double> > resourcesConsumed,
                                           Resource_info ec, Vessel_resources resources)
        {
            // evaluate process rate
            double rate = 1;

            if (ec_consumed < ec.amount)
            {
                rate = ec.amount / ec_consumed;
            }

            foreach (var consumed in resourcesConsumed)
            {
                var ri = resources.Info(v, consumed.Key);
                rate = Math.Min(rate, Lib.Clamp(ri.amount / (consumed.Value * elapsed_s), 0, 1));
            }

            foreach (var produced in resourcesProduced)
            {
                var ri = resources.Info(v, produced.Key);
                var capacityAvailable = ri.capacity - ri.amount;
                var amountProduced    = produced.Value * elapsed_s;
                if (capacityAvailable < amountProduced)
                {
                    rate = Math.Min(rate, Lib.Clamp(capacityAvailable / amountProduced, 0, 1));
                }
            }

            // produce/consume according to rate
            if (rate < double.Epsilon)
            {
                return;
            }

            ec.Consume(ec_consumed * elapsed_s * rate, "module process");
            ec.Produce(ec_produced * elapsed_s * rate, "module process");

            foreach (var consumed in resourcesConsumed)
            {
                resources.Info(v, consumed.Key).Consume(consumed.Value * elapsed_s * rate, "module process");
            }
            foreach (var produced in resourcesProduced)
            {
                resources.Info(v, produced.Key).Produce(produced.Value * elapsed_s * rate, "module process");
            }
        }
示例#16
0
        public void FixedUpdate()
        {
            // do nothing in the editor
            if (Lib.IsEditor())
            {
                return;
            }

            // if enabled, and there is ec consumption
            if (running && ec_rate > double.Epsilon)
            {
                // get resource cache
                Resource_info ec = ResourceCache.Info(vessel, "ElectricCharge");

                // consume EC
                ec.Consume(ec_rate * Kerbalism.elapsed_s);
            }
        }
示例#17
0
        // return a resource handler
        public Resource_info Info(Vessel v, string resource_name)
        {
            // try to get existing entry if any
            Resource_info res;

            if (resources.TryGetValue(resource_name, out res))
            {
                return(res);
            }

            // create new entry
            res = new Resource_info(v, resource_name);

            // remember new entry
            resources.Add(resource_name, res);

            // return new entry
            return(res);
        }
示例#18
0
        void Indicator_supplies(Panel p, Vessel v, Vessel_info vi)
        {
            List <string> tooltips     = new List <string>();
            uint          max_severity = 0;

            if (vi.crew_count > 0)
            {
                foreach (Supply supply in Profile.supplies.FindAll(k => k.resource != "ElectricCharge"))
                {
                    Resource_info res       = ResourceCache.Info(v, supply.resource);
                    double        depletion = res.Depletion(vi.crew_count);

                    if (res.capacity > double.Epsilon)
                    {
                        if (tooltips.Count == 0)
                        {
                            tooltips.Add(String.Format("<align=left /><b>{0,-18}\tlevel\tduration</b>", "name"));
                        }
                        tooltips.Add(Lib.BuildString
                                     (
                                         res.level <= 0.005 ? "<color=#ff0000>" : res.level <= supply.low_threshold ? "<color=#ffff00>" : "<color=#cccccc>",
                                         String.Format("{0,-18}\t{1}\t{2}", supply.resource, Lib.HumanReadablePerc(res.level),
                                                       depletion <= double.Epsilon ? "depleted" : Lib.HumanReadableDuration(depletion)),
                                         "</color>"
                                     ));

                        uint severity = res.level <= 0.005 ? 2u : res.level <= supply.low_threshold ? 1u : 0;
                        max_severity = Math.Max(max_severity, severity);
                    }
                }
            }

            Texture2D image = max_severity == 2
                          ? Icons.box_red
                          : max_severity == 1
                          ? Icons.box_yellow
                          : Icons.box_white;

            p.AddIcon(image, string.Join("\n", tooltips.ToArray()));
        }
示例#19
0
		public static void Update(Vessel v)
		{
			// do nothing if not an eva kerbal
			if (!v.isEVA) return;

			// get KerbalEVA module
			KerbalEVA kerbal = Lib.FindModules<KerbalEVA>(v)[0];

			// get resource handler
			Resource_info ec = ResourceCache.Info(v, "ElectricCharge");

			// determine if headlamps need ec
			// - not required if there is no EC capacity in eva kerbal (no ec supply in profile)
			// - not required if no EC cost for headlamps is specified (set by the user)
			bool need_ec = ec.capacity > double.Epsilon && Settings.HeadLampsCost > double.Epsilon;

			// consume EC for the headlamps
			if (need_ec && kerbal.lampOn)
			{
				ec.Consume(Settings.HeadLampsCost * Kerbalism.elapsed_s);
			}

			// force the headlamps on/off
			HeadLamps(kerbal, kerbal.lampOn && (!need_ec || ec.amount > double.Epsilon));

			// if dead
			if (IsDead(v))
			{
				// enforce freezed state
				Freeze(kerbal);

				// disable modules
				DisableModules(kerbal);

				// remove plant flag action
				kerbal.flagItems = 0;
			}
		}
示例#20
0
 public static void BackgroundUpdate(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, Emitter emitter, Resource_info ec, double elapsed_s)
 {
     // if enabled, and EC is required
     if (Lib.Proto.GetBool(m, "running") && emitter.ec_rate > double.Epsilon)
     {
         // consume EC
         ec.Consume(emitter.ec_rate * elapsed_s);
     }
 }
示例#21
0
        private static string TestForIssues(Vessel v, Resource_info ec, Experiment experiment, uint hdId, bool broken,
                                            double remainingSampleMass, bool didPrepare, bool isShrouded, string last_subject_id)
        {
            var subject_id = Science.Generate_subject_id(experiment.experiment_id, v);

            if (broken)
            {
                return("broken");
            }

            if (isShrouded && !experiment.allow_shrouded)
            {
                return("shrouded");
            }

            bool needsReset = experiment.crew_reset.Length > 0 &&
                              !string.IsNullOrEmpty(last_subject_id) && subject_id != last_subject_id;

            if (needsReset)
            {
                return("reset required");
            }

            if (ec.amount < double.Epsilon && experiment.ec_rate > double.Epsilon)
            {
                return("no Electricity");
            }

            if (!string.IsNullOrEmpty(experiment.crew_operate))
            {
                var cs = new CrewSpecs(experiment.crew_operate);
                if (!cs && Lib.CrewCount(v) > 0)
                {
                    return("crew on board");
                }
                else if (cs && !cs.Check(v))
                {
                    return(cs.Warning());
                }
            }

            if (!experiment.sample_collecting && remainingSampleMass < double.Epsilon && experiment.sample_mass > double.Epsilon)
            {
                return("depleted");
            }

            if (!didPrepare && !string.IsNullOrEmpty(experiment.crew_prepare))
            {
                return("not prepared");
            }

            string situationIssue = Science.TestRequirements(experiment.experiment_id, experiment.requires, v);

            if (situationIssue.Length > 0)
            {
                return(Science.RequirementText(situationIssue));
            }

            var    experimentSize = Science.Experiment(subject_id).max_amount;
            double chunkSize      = Math.Min(experiment.data_rate * Kerbalism.elapsed_s, experimentSize);
            Drive  drive          = GetDrive(experiment, v, hdId, chunkSize, subject_id);

            var    isFile    = experiment.sample_mass < double.Epsilon;
            double available = 0;

            if (isFile)
            {
                available  = drive.FileCapacityAvailable();
                available += Cache.WarpCache(v).FileCapacityAvailable();
            }
            else
            {
                available = drive.SampleCapacityAvailable(subject_id);
            }

            if (Math.Min(experiment.data_rate * Kerbalism.elapsed_s, experimentSize) > available)
            {
                return(insufficient_storage);
            }

            return(string.Empty);
        }
示例#22
0
        public static void BackgroundUpdate(Vessel v, ProtoPartModuleSnapshot m, Experiment experiment, Resource_info ec, Vessel_resources resources, double elapsed_s)
        {
            bool   didPrepare          = Lib.Proto.GetBool(m, "didPrepare", false);
            bool   shrouded            = Lib.Proto.GetBool(m, "shrouded", false);
            string last_subject_id     = Lib.Proto.GetString(m, "last_subject_id", "");
            double remainingSampleMass = Lib.Proto.GetDouble(m, "remainingSampleMass", 0);
            bool   broken      = Lib.Proto.GetBool(m, "broken", false);
            bool   forcedRun   = Lib.Proto.GetBool(m, "forcedRun", false);
            bool   recording   = Lib.Proto.GetBool(m, "recording", false);
            uint   privateHdId = Lib.Proto.GetUInt(m, "privateHdId", 0);

            string issue = TestForIssues(v, ec, experiment, privateHdId, broken,
                                         remainingSampleMass, didPrepare, shrouded, last_subject_id);

            if (string.IsNullOrEmpty(issue))
            {
                issue = TestForResources(v, KerbalismProcess.ParseResources(experiment.resources), elapsed_s, resources);
            }

            Lib.Proto.Set(m, "issue", issue);

            if (!string.IsNullOrEmpty(issue))
            {
                return;
            }

            var subject_id = Science.Generate_subject_id(experiment.experiment_id, v);

            Lib.Proto.Set(m, "last_subject_id", subject_id);

            double dataSampled = Lib.Proto.GetDouble(m, "dataSampled");

            if (last_subject_id != subject_id)
            {
                dataSampled = 0;
                Lib.Proto.Set(m, "forcedRun", false);
            }

            double scienceValue = Science.Value(last_subject_id);

            Lib.Proto.Set(m, "scienceValue", scienceValue);

            var state = GetState(scienceValue, issue, recording, forcedRun);

            if (state != State.RUNNING)
            {
                return;
            }
            if (dataSampled >= Science.Experiment(subject_id).max_amount)
            {
                return;
            }

            var stored = DoRecord(experiment, subject_id, v, ec, privateHdId,
                                  resources, KerbalismProcess.ParseResources(experiment.resources),
                                  remainingSampleMass, dataSampled, out dataSampled, out remainingSampleMass);

            if (!stored)
            {
                Lib.Proto.Set(m, "issue", insufficient_storage);
            }

            Lib.Proto.Set(m, "dataSampled", dataSampled);
            Lib.Proto.Set(m, "remainingSampleMass", remainingSampleMass);
        }
示例#23
0
        private static double Rate(Vessel v, double chunkSize, double maxCapacity, double elapsed, Resource_info ec, double ec_rate, Vessel_resources resources, List <KeyValuePair <string, double> > resourceDefs)
        {
            double result = Lib.Clamp(maxCapacity / chunkSize, 0, 1);

            result = Math.Min(result, Lib.Clamp(ec.amount / (ec_rate * elapsed), 0, 1));

            foreach (var p in resourceDefs)
            {
                var ri = resources.Info(v, p.Key);
                result = Math.Min(result, Lib.Clamp(ri.amount / (p.Value * elapsed), 0, 1));
            }

            return(result);
        }
示例#24
0
        private static bool DoRecord(Experiment experiment, string subject_id, Vessel vessel, Resource_info ec, uint hdId,
                                     Vessel_resources resources, List <KeyValuePair <string, double> > resourceDefs,
                                     double remainingSampleMass, double dataSampled,
                                     out double sampledOut, out double remainingSampleMassOut)
        {
            // default output values for early returns
            sampledOut             = dataSampled;
            remainingSampleMassOut = remainingSampleMass;

            var exp = Science.Experiment(subject_id);

            if (Done(exp, dataSampled))
            {
                return(true);
            }

            double elapsed   = Kerbalism.elapsed_s;
            double chunkSize = Math.Min(experiment.data_rate * elapsed, exp.max_amount);
            double massDelta = experiment.sample_mass * chunkSize / exp.max_amount;

            Drive drive = GetDrive(experiment, vessel, hdId, chunkSize, subject_id);

            // on high time warp this chunk size could be too big, but we could store a sizable amount if we process less
            bool   isFile      = experiment.sample_mass < float.Epsilon;
            double maxCapacity = isFile ? drive.FileCapacityAvailable() : drive.SampleCapacityAvailable(subject_id);

            Drive warpCacheDrive = null;

            if (isFile)
            {
                if (drive.GetFileSend(subject_id))
                {
                    warpCacheDrive = Cache.WarpCache(vessel);
                }
                if (warpCacheDrive != null)
                {
                    maxCapacity += warpCacheDrive.FileCapacityAvailable();
                }
            }

            double factor = Rate(vessel, chunkSize, maxCapacity, elapsed, ec, experiment.ec_rate, resources, resourceDefs);

            if (factor < double.Epsilon)
            {
                return(false);
            }

            chunkSize *= factor;
            massDelta *= factor;
            elapsed   *= factor;

            bool stored = false;

            if (chunkSize > double.Epsilon)
            {
                if (isFile)
                {
                    if (warpCacheDrive != null)
                    {
                        double s = Math.Min(chunkSize, warpCacheDrive.FileCapacityAvailable());
                        stored = warpCacheDrive.Record_file(subject_id, s, true);

                        if (chunkSize > s)                        // only write to persisted drive if the data cannot be transmitted in this tick
                        {
                            stored &= drive.Record_file(subject_id, chunkSize - s, true);
                        }
                    }
                    else
                    {
                        stored = drive.Record_file(subject_id, chunkSize, true);
                    }
                }
                else
                {
                    stored = drive.Record_sample(subject_id, chunkSize, massDelta);
                }
            }

            if (!stored)
            {
                return(false);
            }

            // consume resources
            ec.Consume(experiment.ec_rate * elapsed, "experiment");
            foreach (var p in resourceDefs)
            {
                resources.Consume(vessel, p.Key, p.Value * elapsed, "experiment");
            }

            dataSampled += chunkSize;
            dataSampled  = Math.Min(dataSampled, exp.max_amount);
            sampledOut   = dataSampled;
            if (!experiment.sample_collecting)
            {
                remainingSampleMass -= massDelta;
                remainingSampleMass  = Math.Max(remainingSampleMass, 0);
            }
            remainingSampleMassOut = remainingSampleMass;
            return(true);
        }
示例#25
0
        // call scripts automatically when conditions are met
        public void Automate(Vessel v, Vessel_info vi, Vessel_resources resources)
        {
            // do nothing if automation is disabled
            if (!Features.Automation)
            {
                return;
            }

            // get current states
            Resource_info ec             = resources.Info(v, "ElectricCharge");
            bool          sunlight       = vi.sunlight > double.Epsilon;
            bool          power_low      = ec.level < 0.2;
            bool          power_high     = ec.level > 0.8;
            bool          radiation_low  = vi.radiation < 0.000005552;   //< 0.02 rad/h
            bool          radiation_high = vi.radiation > 0.00001388;    //< 0.05 rad/h
            bool          signal         = vi.connection.linked;

            // get current situation
            bool landed = false;
            bool atmo   = false;
            bool space  = false;

            switch (v.situation)
            {
            case Vessel.Situations.LANDED:
            case Vessel.Situations.SPLASHED:
                landed = true;
                break;

            case Vessel.Situations.FLYING:
                atmo = true;
                break;

            case Vessel.Situations.SUB_ORBITAL:
            case Vessel.Situations.ORBITING:
            case Vessel.Situations.ESCAPING:
                space = true;
                break;
            }


            // compile list of scripts that need to be called
            var to_exec = new List <Script>();

            foreach (var p in scripts)
            {
                ScriptType type   = p.Key;
                Script     script = p.Value;
                if (script.states.Count == 0)
                {
                    continue;                                           //< skip empty scripts (may happen during editing)
                }
                switch (type)
                {
                case ScriptType.landed:
                    if (landed && script.prev == "0")
                    {
                        to_exec.Add(script);
                    }
                    script.prev = landed ? "1" : "0";
                    break;

                case ScriptType.atmo:
                    if (atmo && script.prev == "0")
                    {
                        to_exec.Add(script);
                    }
                    script.prev = atmo ? "1" : "0";
                    break;

                case ScriptType.space:
                    if (space && script.prev == "0")
                    {
                        to_exec.Add(script);
                    }
                    script.prev = space ? "1" : "0";
                    break;

                case ScriptType.sunlight:
                    if (sunlight && script.prev == "0")
                    {
                        to_exec.Add(script);
                    }
                    script.prev = sunlight ? "1" : "0";
                    break;

                case ScriptType.shadow:
                    if (!sunlight && script.prev == "0")
                    {
                        to_exec.Add(script);
                    }
                    script.prev = !sunlight ? "1" : "0";
                    break;

                case ScriptType.power_high:
                    if (power_high && script.prev == "0")
                    {
                        to_exec.Add(script);
                    }
                    script.prev = power_high ? "1" : "0";
                    break;

                case ScriptType.power_low:
                    if (power_low && script.prev == "0")
                    {
                        to_exec.Add(script);
                    }
                    script.prev = power_low ? "1" : "0";
                    break;

                case ScriptType.rad_low:
                    if (radiation_low && script.prev == "0")
                    {
                        to_exec.Add(script);
                    }
                    script.prev = radiation_low ? "1" : "0";
                    break;

                case ScriptType.rad_high:
                    if (radiation_high && script.prev == "0")
                    {
                        to_exec.Add(script);
                    }
                    script.prev = radiation_high ? "1" : "0";
                    break;

                case ScriptType.linked:
                    if (signal && script.prev == "0")
                    {
                        to_exec.Add(script);
                    }
                    script.prev = signal ? "1" : "0";
                    break;

                case ScriptType.unlinked:
                    if (!signal && script.prev == "0")
                    {
                        to_exec.Add(script);
                    }
                    script.prev = !signal ? "1" : "0";
                    break;
                }
            }

            // if there are scripts to call
            if (to_exec.Count > 0)
            {
                // get list of devices
                // - we avoid creating it when there are no scripts to be executed, making its overall cost trivial
                var devices = Boot(v);

                // execute all scripts
                foreach (Script script in to_exec)
                {
                    script.Execute(devices);
                }

                // show message to the user
                if (DB.Vessel(v).cfg_script)
                {
                    Message.Post(Lib.BuildString("Script called on vessel <b>", v.vesselName, "</b>"));
                }
            }
        }
示例#26
0
        public void FixedUpdate()
        {
            // basic sanity checks
            if (Lib.IsEditor())
            {
                return;
            }
            if (!Cache.VesselInfo(vessel).is_valid)
            {
                return;
            }
            if (next_check > Planetarium.GetUniversalTime())
            {
                return;
            }

            // get ec handler
            Resource_info ec = ResourceCache.Info(vessel, "ElectricCharge");

            shrouded = part.ShieldedFromAirstream;
            issue    = TestForIssues(vessel, ec, this, privateHdId, broken,
                                     remainingSampleMass, didPrepare, shrouded, last_subject_id);

            if (string.IsNullOrEmpty(issue))
            {
                issue = TestForResources(vessel, resourceDefs, Kerbalism.elapsed_s, ResourceCache.Get(vessel));
            }

            scienceValue = Science.Value(last_subject_id, 0);
            state        = GetState(scienceValue, issue, recording, forcedRun);

            if (!string.IsNullOrEmpty(issue))
            {
                next_check = Planetarium.GetUniversalTime() + Math.Max(3, Kerbalism.elapsed_s * 3);
                return;
            }

            var subject_id = Science.Generate_subject_id(experiment_id, vessel);

            if (last_subject_id != subject_id)
            {
                dataSampled = 0;
                forcedRun   = false;
            }
            last_subject_id = subject_id;

            if (state != State.RUNNING)
            {
                return;
            }

            var exp = Science.Experiment(experiment_id);

            if (dataSampled >= exp.max_amount)
            {
                return;
            }

            // if experiment is active and there are no issues
            DoRecord(ec, subject_id);
        }
示例#27
0
        public void FixedUpdate()
        {
            // do nothing in the editor
            if (Lib.IsEditor())
            {
                return;
            }

            // if enabled and not ready for harvest
            if (active && growth < 0.99)
            {
                // get vessel info from the cache
                // - if the vessel is not valid (eg: flagged as debris) then solar flux will be 0 and landed false (but that's okay)
                Vessel_info vi = Cache.VesselInfo(vessel);

                // get resource cache
                Vessel_resources resources = ResourceCache.Get(vessel);
                Resource_info    ec        = resources.Info(vessel, "ElectricCharge");

                // deal with corner cases when greenhouse is assembled using KIS
                if (double.IsNaN(growth) || double.IsInfinity(growth))
                {
                    growth = 0.0;
                }

                // calculate natural and artificial lighting
                natural    = vi.solar_flux;
                artificial = Math.Max(light_tolerance - natural, 0.0);

                // consume EC for the lamps, scaled by artificial light intensity
                if (artificial > double.Epsilon)
                {
                    ec.Consume(ec_rate * (artificial / light_tolerance) * Kerbalism.elapsed_s, "greenhouse");
                }

                // reset artificial lighting if there is no ec left
                // - comparing against amount in previous simulation step
                if (ec.amount <= double.Epsilon)
                {
                    artificial = 0.0;
                }

                // execute recipe
                Resource_recipe recipe = new Resource_recipe(part, "greenhouse");
                foreach (ModuleResource input in resHandler.inputResources)
                {
                    // WasteAtmosphere is primary combined input
                    if (WACO2 && input.name == "WasteAtmosphere")
                    {
                        recipe.Input(input.name, vi.breathable ? 0.0 : input.rate * Kerbalism.elapsed_s, "CarbonDioxide");
                    }
                    // CarbonDioxide is secondary combined input
                    else if (WACO2 && input.name == "CarbonDioxide")
                    {
                        recipe.Input(input.name, vi.breathable ? 0.0 : input.rate * Kerbalism.elapsed_s, "");
                    }
                    // if atmosphere is breathable disable WasteAtmosphere / CO2
                    else if (!WACO2 && (input.name == "CarbonDioxide" || input.name == "WasteAtmosphere"))
                    {
                        recipe.Input(input.name, vi.breathable ? 0.0 : input.rate, "");
                    }
                    else
                    {
                        recipe.Input(input.name, input.rate * Kerbalism.elapsed_s);
                    }
                }
                foreach (ModuleResource output in resHandler.outputResources)
                {
                    // if atmosphere is breathable disable Oxygen
                    if (output.name == "Oxygen")
                    {
                        recipe.Output(output.name, vi.breathable ? 0.0 : output.rate * Kerbalism.elapsed_s, true);
                    }
                    else
                    {
                        recipe.Output(output.name, output.rate * Kerbalism.elapsed_s, true);
                    }
                }
                resources.Transform(recipe);

                // determine environment conditions
                bool lighting  = natural + artificial >= light_tolerance;
                bool pressure  = pressure_tolerance <= double.Epsilon || vi.pressure >= pressure_tolerance;
                bool radiation = radiation_tolerance <= double.Epsilon || vi.radiation * (1.0 - vi.shielding) < radiation_tolerance;

                // determine input resources conditions
                // - comparing against amounts in previous simulation step
                bool   inputs      = true;
                string missing_res = string.Empty;
                bool   dis_WACO2   = false;
                foreach (ModuleResource input in resHandler.inputResources)
                {
                    // combine WasteAtmosphere and CO2 if both exist
                    if (input.name == "WasteAtmosphere" || input.name == "CarbonDioxide")
                    {
                        if (dis_WACO2 || Cache.VesselInfo(vessel).breathable)
                        {
                            continue;                                                                              // skip if already checked or atmosphere is breathable
                        }
                        if (WACO2)
                        {
                            if (resources.Info(vessel, "WasteAtmosphere").amount <= double.Epsilon && resources.Info(vessel, "CarbonDioxide").amount <= double.Epsilon)
                            {
                                inputs      = false;
                                missing_res = "CarbonDioxide";
                                break;
                            }
                            dis_WACO2 = true;
                            continue;
                        }
                    }
                    if (resources.Info(vessel, input.name).amount <= double.Epsilon)
                    {
                        inputs      = false;
                        missing_res = input.name;
                        break;
                    }
                }

                // if growing
                if (lighting && pressure && radiation && inputs)
                {
                    // increase growth
                    growth += crop_rate * Kerbalism.elapsed_s;
                    growth  = Math.Min(growth, 1.0);

                    // notify the user when crop can be harvested
                    if (growth >= 0.99)
                    {
                        Message.Post(Lib.BuildString("On <b>", vessel.vesselName, "</b> the crop is ready to be harvested"));
                        growth = 1.0;
                    }
                }

                // update time-to-harvest
                tta = (1.0 - growth) / crop_rate;

                // update issues
                issue =
                    !inputs?Lib.BuildString("missing ", missing_res)
                        : !lighting ? "insufficient lighting"
                                : !pressure ? "insufficient pressure"
                                : !radiation ? "excessive radiation"
                                : string.Empty;
            }
        }
示例#28
0
        public static void BackgroundUpdate(Vessel vessel, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, KerbalismScansat kerbalismScansat,
                                            Part part_prefab, VesselData vd, Resource_info ec, double elapsed_s)
        {
            List <ProtoPartModuleSnapshot> scanners = Cache.VesselObjectsCache <List <ProtoPartModuleSnapshot> >(vessel, "scansat_" + p.flightID);

            if (scanners == null)
            {
                scanners = Lib.FindModules(p, "SCANsat");
                if (scanners.Count == 0)
                {
                    scanners = Lib.FindModules(p, "ModuleSCANresourceScanner");
                }
                Cache.SetVesselObjectsCache(vessel, "scansat_" + p.flightID, scanners);
            }

            if (scanners.Count == 0)
            {
                return;
            }
            var scanner = scanners[0];

            bool is_scanning = Lib.Proto.GetBool(scanner, "scanning");

            if (is_scanning && kerbalismScansat.ec_rate > double.Epsilon)
            {
                ec.Consume(kerbalismScansat.ec_rate * elapsed_s, "scanner");
            }

            if (!Features.Science)
            {
                if (is_scanning && ec.amount < double.Epsilon)
                {
                    SCANsat.StopScanner(vessel, scanner, part_prefab);
                    is_scanning = false;

                    // remember disabled scanner
                    vd.scansat_id.Add(p.flightID);

                    // give the user some feedback
                    if (vd.cfg_ec)
                    {
                        Message.Post(Lib.BuildString("SCANsat sensor was disabled on <b>", vessel.vesselName, "</b>"));
                    }
                }
                else if (vd.scansat_id.Contains(p.flightID))
                {
                    // if there is enough ec
                    // note: comparing against amount in previous simulation step
                    // re-enable at 25% EC
                    if (ec.level > 0.25)
                    {
                        // re-enable the scanner
                        SCANsat.ResumeScanner(vessel, m, part_prefab);
                        is_scanning = true;

                        // give the user some feedback
                        if (vd.cfg_ec)
                        {
                            Message.Post(Lib.BuildString("SCANsat sensor resumed operations on <b>", vessel.vesselName, "</b>"));
                        }
                    }
                }

                // forget active scanners
                if (is_scanning)
                {
                    vd.scansat_id.Remove(p.flightID);
                }

                return;
            }             // if(!Feature.Science)

            string body_name     = Lib.Proto.GetString(m, "body_name");
            int    sensorType    = (int)Lib.Proto.GetUInt(m, "sensorType");
            double body_coverage = Lib.Proto.GetDouble(m, "body_coverage");
            double warp_buffer   = Lib.Proto.GetDouble(m, "warp_buffer");

            double new_coverage = SCANsat.Coverage(sensorType, vessel.mainBody);

            if (body_name == vessel.mainBody.name && new_coverage < body_coverage)
            {
                // SCANsat sometimes reports a coverage of 0, which is wrong
                new_coverage = body_coverage;
            }

            if (vessel.mainBody.name != body_name)
            {
                body_name     = vessel.mainBody.name;
                body_coverage = new_coverage;
            }
            else
            {
                double coverage_delta = new_coverage - body_coverage;
                body_coverage = new_coverage;

                if (is_scanning)
                {
                    Science.Generate_subject(kerbalismScansat.experimentType, vessel);
                    var    subject_id = Science.Generate_subject_id(kerbalismScansat.experimentType, vessel);
                    var    exp        = Science.Experiment(subject_id);
                    double size       = exp.max_amount * coverage_delta / 100.0;               // coverage is 0-100%
                    size += warp_buffer;

                    if (size > double.Epsilon)
                    {
                        // store what we can
                        foreach (var d in Drive.GetDrives(vessel))
                        {
                            var available = d.FileCapacityAvailable();
                            var chunk     = Math.Min(size, available);
                            if (!d.Record_file(subject_id, chunk, true))
                            {
                                break;
                            }
                            size -= chunk;

                            if (size < double.Epsilon)
                            {
                                break;
                            }
                        }
                    }

                    if (size > double.Epsilon)
                    {
                        // we filled all drives up to the brim but were unable to store everything
                        if (warp_buffer < double.Epsilon)
                        {
                            // warp buffer is empty, so lets store the rest there
                            warp_buffer = size;
                            size        = 0;
                        }
                        else
                        {
                            // warp buffer not empty. that's ok if we didn't get new data
                            if (coverage_delta < double.Epsilon)
                            {
                                size = 0;
                            }
                            // else we're scanning too fast. stop.
                        }
                    }

                    // we filled all drives up to the brim but were unable to store everything
                    // cancel scanning and annoy the user
                    if (size > double.Epsilon || ec.amount < double.Epsilon)
                    {
                        warp_buffer = 0;
                        SCANsat.StopScanner(vessel, scanner, part_prefab);
                        vd.scansat_id.Add(p.flightID);
                        if (vd.cfg_ec)
                        {
                            Message.Post(Lib.BuildString("SCANsat sensor was disabled on <b>", vessel.vesselName, "</b>"));
                        }
                    }
                }
                else if (vd.scansat_id.Contains(p.flightID))
                {
                    var vi = Cache.VesselInfo(vessel);
                    if (ec.level >= 0.25 && (vi.free_capacity / vi.total_capacity > 0.9))
                    {
                        SCANsat.ResumeScanner(vessel, scanner, part_prefab);
                        vd.scansat_id.Remove(p.flightID);
                        if (vd.cfg_ec)
                        {
                            Message.Post(Lib.BuildString("SCANsat sensor resumed operations on <b>", vessel.vesselName, "</b>"));
                        }
                    }
                }
            }

            Lib.Proto.Set(m, "warp_buffer", warp_buffer);
            Lib.Proto.Set(m, "body_coverage", body_coverage);
            Lib.Proto.Set(m, "body_name", body_name);
        }
示例#29
0
        public static void BackgroundUpdate(Vessel v, ProtoPartModuleSnapshot m, Greenhouse g,
                                            Vessel_info vi, Vessel_resources resources, double elapsed_s)
        {
            // get protomodule data
            bool   active = Lib.Proto.GetBool(m, "active");
            double growth = Lib.Proto.GetDouble(m, "growth");

            // if enabled and not ready for harvest
            if (active && growth < 0.99)
            {
                // get resource handler
                Resource_info ec = resources.Info(v, "ElectricCharge");

                // calculate natural and artificial lighting
                double natural    = vi.solar_flux;
                double artificial = Math.Max(g.light_tolerance - natural, 0.0);

                // consume EC for the lamps, scaled by artificial light intensity
                if (artificial > double.Epsilon)
                {
                    ec.Consume(g.ec_rate * (artificial / g.light_tolerance) * elapsed_s, "greenhouse");
                }

                // reset artificial lighting if there is no ec left
                // note: comparing against amount in previous simulation step
                if (ec.amount <= double.Epsilon)
                {
                    artificial = 0.0;
                }

                // execute recipe
                Resource_recipe recipe = new Resource_recipe(g.part, "greenhouse");
                foreach (ModuleResource input in g.resHandler.inputResources)                 //recipe.Input(input.name, input.rate * elapsed_s);
                {
                    // WasteAtmosphere is primary combined input
                    if (g.WACO2 && input.name == "WasteAtmosphere")
                    {
                        recipe.Input(input.name, vi.breathable ? 0.0 : input.rate * elapsed_s, "CarbonDioxide");
                    }
                    // CarbonDioxide is secondary combined input
                    else if (g.WACO2 && input.name == "CarbonDioxide")
                    {
                        recipe.Input(input.name, vi.breathable ? 0.0 : input.rate * elapsed_s, "");
                    }
                    // if atmosphere is breathable disable WasteAtmosphere / CO2
                    else if (!g.WACO2 && (input.name == "CarbonDioxide" || input.name == "WasteAtmosphere"))
                    {
                        recipe.Input(input.name, vi.breathable ? 0.0 : input.rate, "");
                    }
                    else
                    {
                        recipe.Input(input.name, input.rate * elapsed_s);
                    }
                }
                foreach (ModuleResource output in g.resHandler.outputResources)
                {
                    // if atmosphere is breathable disable Oxygen
                    if (output.name == "Oxygen")
                    {
                        recipe.Output(output.name, vi.breathable ? 0.0 : output.rate * elapsed_s, true);
                    }
                    else
                    {
                        recipe.Output(output.name, output.rate * elapsed_s, true);
                    }
                }
                resources.Transform(recipe);

                // determine environment conditions
                bool lighting  = natural + artificial >= g.light_tolerance;
                bool pressure  = g.pressure_tolerance <= double.Epsilon || vi.pressure >= g.pressure_tolerance;
                bool radiation = g.radiation_tolerance <= double.Epsilon || vi.radiation * (1.0 - vi.shielding) < g.radiation_tolerance;

                // determine inputs conditions
                // note: comparing against amounts in previous simulation step
                bool   inputs      = true;
                string missing_res = string.Empty;
                bool   dis_WACO2   = false;
                foreach (ModuleResource input in g.resHandler.inputResources)
                {
                    // combine WasteAtmosphere and CO2 if both exist
                    if (input.name == "WasteAtmosphere" || input.name == "CarbonDioxide")
                    {
                        if (dis_WACO2 || vi.breathable)
                        {
                            continue;                                                        // skip if already checked or atmosphere is breathable
                        }
                        if (g.WACO2)
                        {
                            if (resources.Info(v, "WasteAtmosphere").amount <= double.Epsilon && resources.Info(v, "CarbonDioxide").amount <= double.Epsilon)
                            {
                                inputs      = false;
                                missing_res = "CarbonDioxide";
                                break;
                            }
                            dis_WACO2 = true;
                            continue;
                        }
                    }
                    if (resources.Info(v, input.name).amount <= double.Epsilon)
                    {
                        inputs      = false;
                        missing_res = input.name;
                        break;
                    }
                }

                // if growing
                if (lighting && pressure && radiation && inputs)
                {
                    // increase growth
                    growth += g.crop_rate * elapsed_s;
                    growth  = Math.Min(growth, 1.0);

                    // notify the user when crop can be harvested
                    if (growth >= 0.99)
                    {
                        Message.Post(Lib.BuildString("On <b>", v.vesselName, "</b> the crop is ready to be harvested"));
                        growth = 1.0;
                    }
                }

                // update time-to-harvest
                double tta = (1.0 - growth) / g.crop_rate;

                // update issues
                string issue =
                    !inputs?Lib.BuildString("missing ", missing_res)
                        : !lighting ? "insufficient lighting"
                                : !pressure ? "insufficient pressure"
                                : !radiation ? "excessive radiation"
                                : string.Empty;

                // update protomodule data
                Lib.Proto.Set(m, "natural", natural);
                Lib.Proto.Set(m, "artificial", artificial);
                Lib.Proto.Set(m, "tta", tta);
                Lib.Proto.Set(m, "issue", issue);
                Lib.Proto.Set(m, "growth", growth);
            }
        }
示例#30
0
		public static void BackgroundUpdate(Vessel vessel, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, GravityRing ring, Resource_info ec, double elapsed_s)
		{
			// if the module is either non-deployable or deployed
			if (ring.deploy.Length == 0 || Lib.Proto.GetBool(m, "deployed"))
			{
				// consume ec
				ec.Consume(ring.ec_rate * elapsed_s);
			}
		}