static void ProcessLight(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, ModuleLight light, Resource_Info ec, double elapsed_s) { if (light.useResources && Lib.Proto.GetBool(m, "isOn")) { ec.Consume(light.resourceAmount * elapsed_s); } }
public static void BackgroundUpdate(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, Laboratory lab, Resource_Info ec, double elapsed_s) { // if enabled if (Lib.Proto.GetBool(m, "running")) { // if a researcher is not required, or the researcher is present CrewSpecs researcher_cs = new CrewSpecs(lab.researcher); int qtty = 0, crewlvl = 0; if (!researcher_cs || researcher_cs.Check(p.protoModuleCrew, out qtty, out crewlvl)) { // get sample to analyze string sample_filename = Next_sample(v); // if there is a sample to analyze if (sample_filename.Length > 0) { // consume EC ec.Consume(lab.ec_rate * elapsed_s); // if there was ec // - comparing against amount in previous simulation step if (ec.amount > double.Epsilon) { double analysis_rateAVG = lab.analysis_rate; if (researcher_cs) { analysis_rateAVG *= qtty * crewlvl; } // analyze the sample Analyze(v, sample_filename, analysis_rateAVG * elapsed_s); } } } } }
public virtual void FixedUpdate() { if (!Lib.IsFlight() || module == null) { return; } if (broken) { if (broken != lastFixedBrokenState) { lastFixedBrokenState = broken; FixModule(!broken); } } else if (hasFixedEnergyChanged != hasEnergy) { // Wait 1 second before start consum EC. if (hasEnergy) { Lib.Delay(1f); } hasFixedEnergyChanged = hasEnergy; lastFixedBrokenState = false; // Update module FixModule(hasEnergy); } // If isConsuming if (isConsuming && resources != null) { resources.Consume(actualCost * Kerbalism.elapsed_s); } }
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); } }
static void ProcessStockLab(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, ModuleScienceConverter lab, Resource_Info ec, double elapsed_s) { // note: we are only simulating the EC consumption // note: there is no easy way to 'stop' the lab when there isn't enough EC // if active if (Lib.Proto.GetBool(m, "IsActivated")) { // consume ec ec.Consume(lab.powerRequirement * elapsed_s); } }
public virtual void FixedUpdate() { if (Lib.IsFlight() && Features.Deploy) { if (isConsuming) { if (resourceInfo != null) { resourceInfo.Consume(actualECCost * Kerbalism.elapsed_s); } } } }
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); } }
static void ProcessCryoTank(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, PartModule simple_boiloff, Vessel_Resources resources, double elapsed_s) { // note: cryotank module already does a post-facto simulation of background boiling, and we could use that for the boiling // however, it also does simulate the ec consumption that way, so we have to disable the post-facto simulation // get fuel name string fuel_name = Lib.ReflectionValue <string>(simple_boiloff, "FuelName"); // get resource handlers Resource_Info ec = resources.Info(v, "ElectricCharge"); Resource_Info fuel = resources.Info(v, fuel_name); // if there is some fuel // note: comparing against amount in previous simulation step if (fuel.amount > double.Epsilon) { // get capacity in the part double capacity = p.resources.Find(k => k.resourceName == fuel_name).maxAmount; // if cooling is enabled and there was enough ec // note: comparing against amount in previous simulation step if (Lib.Proto.GetBool(m, "CoolingEnabled") && ec.amount > double.Epsilon) { // get cooling ec cost per 1000 units of fuel, per-second double cooling_cost = Lib.ReflectionValue <float>(simple_boiloff, "CoolingCost"); // consume ec ec.Consume(cooling_cost * capacity * 0.001 * elapsed_s); } // if there wasn't ec, or if cooling is disabled else { // get boiloff rate in proportion to fuel amount, per-second double boiloff_rate = Lib.ReflectionValue <float>(simple_boiloff, "BoiloffRate") * 0.00000277777; // let it boil off fuel.Consume(capacity * (1.0 - Math.Pow(1.0 - boiloff_rate, elapsed_s))); } } // disable post-facto simulation Lib.Proto.Set(m, "LastUpdateTime", v.missionTime); }
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; } }
public void FixedUpdate() { // in flight if (Lib.IsFlight()) { // if we are transmitting using the stock system if (stream.Transmitting()) { // get ec resource handler Resource_Info ec = ResourceCache.Info(vessel, "ElectricCharge"); // if we are still linked, and there is ec left if (CanTransmit() && ec.amount > double.Epsilon) { // compression factor // - used to avoid making the user wait too much for transmissions that // don't happen in background, while keeping transmission rates realistic const double compression = 16.0; // transmit using the data stream stream.Update(DataRate * Kerbalism.elapsed_s * compression, vessel); // consume ec ec.Consume(DataResourceCost * Kerbalism.elapsed_s); } else { // abort transmission, return data to the vessel stream.Abort(vessel); // inform the user ScreenMessages.PostScreenMessage("Transmission aborted", 5.0f, ScreenMessageStyle.UPPER_LEFT); } } } }
static void ProcessCryoTank(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, PartModule simple_boiloff, Vessel_Resources resources, double elapsed_s) { // note: cryotank module already does a post-facto simulation of background boiling, and we could use that for the boiling // however, it also does simulate the ec consumption that way, so we have to disable the post-facto simulation // As far as I know, Simple_boiloff consumes fuel and EC only if the fuel is on the Fuel List (previously added in Game Load) // The test that I did, I was able to enable to "Enable Cooling" only when fuel was into List<BoiloffFuel> fuels // get fuel name: FuelName in Simple_Boiloff is always NULL, this Get doesn't make sense, but I will leave here. string fuel_name = Lib.ReflectionValue <string>(simple_boiloff, "FuelName"); // get resource handlers Resource_Info ec = resources.Info(v, "ElectricCharge"); // if fuel_name is null as expected, this would cause error if (string.IsNullOrEmpty(fuel_name)) { // Take name from fuel list inside part System.Collections.IList fuelList = Lib.ReflectionValue <System.Collections.IList>(simple_boiloff, "fuels"); foreach (var item in fuelList) { fuel_name = (string)item.GetType().GetField("fuelName").GetValue(item); // if fuel_name still null, do anything if (fuel_name == null) { continue; } Resource_Info fuel = resources.Info(v, fuel_name); // if there is some fuel // note: comparing against amount in previous simulation step if (fuel.amount > double.Epsilon) { // Try find resource "fuel_name" into PartResources ProtoPartResourceSnapshot protoPartResource = p.resources.Find(k => k.resourceName == fuel_name); // If part doesn't have the fuel, do anything. if (protoPartResource == null) { continue; } // get capacity in the part double capacity = protoPartResource.maxAmount; // if cooling is enabled and there was enough ec // note: comparing against amount in previous simulation step if (Lib.Proto.GetBool(m, "CoolingEnabled") && ec.amount > double.Epsilon) { // get cooling ec cost per 1000 units of fuel, per-second double cooling_cost = Lib.ReflectionValue <float>(simple_boiloff, "CoolingCost"); // consume ec ec.Consume(cooling_cost * capacity * 0.001 * elapsed_s); } // if there wasn't ec, or if cooling is disabled else { // get boiloff rate in proportion to fuel amount, per-second double boiloff_rate = Lib.ReflectionValue <float>(simple_boiloff, "BoiloffRate") * 0.00000277777; // let it boil off fuel.Consume(capacity * (1.0 - Math.Pow(1.0 - boiloff_rate, elapsed_s))); } } // disable post-facto simulation Lib.Proto.Set(m, "LastUpdateTime", v.missionTime); } } else { Resource_Info fuel = resources.Info(v, fuel_name); // if there is some fuel // note: comparing against amount in previous simulation step if (fuel.amount > double.Epsilon) { // Try find resource "fuel_name" into PartResources ProtoPartResourceSnapshot protoPartResource = p.resources.Find(k => k.resourceName == fuel_name); // If part doesn't have the fuel, do anything. if (protoPartResource == null) { return; } // get capacity in the part double capacity = protoPartResource.maxAmount; // if cooling is enabled and there was enough ec // note: comparing against amount in previous simulation step if (Lib.Proto.GetBool(m, "CoolingEnabled") && ec.amount > double.Epsilon) { // get cooling ec cost per 1000 units of fuel, per-second double cooling_cost = Lib.ReflectionValue <float>(simple_boiloff, "CoolingCost"); // consume ec ec.Consume(cooling_cost * capacity * 0.001 * elapsed_s); } // if there wasn't ec, or if cooling is disabled else { // get boiloff rate in proportion to fuel amount, per-second double boiloff_rate = Lib.ReflectionValue <float>(simple_boiloff, "BoiloffRate") * 0.00000277777; // let it boil off fuel.Consume(capacity * (1.0 - Math.Pow(1.0 - boiloff_rate, elapsed_s))); } } // disable post-facto simulation Lib.Proto.Set(m, "LastUpdateTime", v.missionTime); } }
public void Execute(Vessel v, Vessel_Info vi, Vessel_Resources resources, double elapsed_s) { // store list of crew to kill List <ProtoCrewMember> deferred_kills = new List <ProtoCrewMember>(); // get input resource handler Resource_Info res = input.Length > 0 ? resources.Info(v, input) : null; // determine message variant uint variant = vi.temperature < Settings.SurvivalTemperature ? 0 : 1u; // get product of all environment modifiers double k = Modifiers.Evaluate(v, vi, resources, modifiers); // for each crew foreach (ProtoCrewMember c in Lib.CrewList(v)) { // get kerbal data KerbalData kd = DB.Kerbal(c.name); // skip rescue kerbals if (kd.rescue) { continue; } // skip disabled kerbals if (kd.disabled) { continue; } // get kerbal property data from db RuleData rd = kd.Rule(name); // if continuous double step; if (interval <= double.Epsilon) { // influence consumption by elapsed time step = elapsed_s; } // if interval-based else { // accumulate time rd.time_since += elapsed_s; // determine number of steps step = Math.Floor(rd.time_since / interval); // consume time rd.time_since -= step * interval; // remember if a meal is consumed/produced in this simulation step res.meal_happened |= step > 0.99; if (output.Length > 0) { ResourceCache.Info(v, output).meal_happened |= step > 0.99; } } // if continuous, or if one or more intervals elapsed if (step > double.Epsilon) { // if there is a resource specified if (res != null && rate > double.Epsilon) { // determine amount of resource to consume double required = rate // consumption rate * k // product of environment modifiers * step; // seconds elapsed or number of steps // if there is no output if (output.Length == 0) { // simply consume (that is faster) res.Consume(required); } // if there is an output else { // transform input into output resource // - rules always dump excess overboard (because it is waste) Resource_Recipe recipe = new Resource_Recipe(); recipe.Input(input, required); recipe.Output(output, required * ratio, true); resources.Transform(recipe); } } // degenerate: // - if the environment modifier is not telling to reset (by being zero) // - if this rule is resource-less, or if there was not enough resource in the vessel if (k > 0.0 && (input.Length == 0 || res.amount <= double.Epsilon)) { rd.problem += degeneration // degeneration rate per-second or per-interval * k // product of environment modifiers * step // seconds elapsed or by number of steps * Variance(c, variance); // kerbal-specific variance } // else slowly recover else { rd.problem *= 1.0 / (1.0 + Math.Max(interval, 1.0) * step * 0.002); rd.problem = Math.Max(rd.problem, 0.0); } } // kill kerbal if necessary if (rd.problem >= fatal_threshold) { if (fatal_message.Length > 0) { Message.Post(breakdown ? Severity.breakdown : Severity.fatality, Lib.ExpandMsg(fatal_message, v, c, variant)); } if (breakdown) { // trigger breakdown event Misc.Breakdown(v, c); // move back between warning and danger level rd.problem = (warning_threshold + danger_threshold) * 0.5; // make sure next danger messagen is shown rd.message = 1; } else { deferred_kills.Add(c); } } // show messages else if (rd.problem >= danger_threshold && rd.message < 2) { if (danger_message.Length > 0) { Message.Post(Severity.danger, Lib.ExpandMsg(danger_message, v, c, variant)); } rd.message = 2; } else if (rd.problem >= warning_threshold && rd.message < 1) { if (warning_message.Length > 0) { Message.Post(Severity.warning, Lib.ExpandMsg(warning_message, v, c, variant)); } rd.message = 1; } else if (rd.problem < warning_threshold && rd.message > 0) { if (relax_message.Length > 0) { Message.Post(Severity.relax, Lib.ExpandMsg(relax_message, v, c, variant)); } rd.message = 0; } } // execute the deferred kills foreach (ProtoCrewMember c in deferred_kills) { Misc.Kill(v, c); } }
//trigger a random breakdown event public static void Breakdown(Vessel v, ProtoCrewMember c) { // constants const double res_penalty = 0.1; // proportion of food lost on 'depressed' and 'wrong_valve' // get a supply resource at random Resource_Info res = null; if (Profile.supplies.Count > 0) { Supply supply = Profile.supplies[Lib.RandomInt(Profile.supplies.Count)]; res = ResourceCache.Info(v, supply.resource); } // compile list of events with condition satisfied List <KerbalBreakdown> events = new List <KerbalBreakdown>(); events.Add(KerbalBreakdown.mumbling); //< do nothing, here so there is always something that can happen if (Lib.HasData(v)) { events.Add(KerbalBreakdown.fat_finger); } if (Reliability.CanMalfunction(v)) { events.Add(KerbalBreakdown.rage); } if (res != null && res.amount > double.Epsilon) { events.Add(KerbalBreakdown.wrong_valve); } // choose a breakdown event KerbalBreakdown breakdown = events[Lib.RandomInt(events.Count)]; // generate message string text = ""; string subtext = ""; switch (breakdown) { case KerbalBreakdown.mumbling: text = "$ON_VESSEL$KERBAL has been in space for too long"; subtext = "Mumbling incoherently"; break; case KerbalBreakdown.fat_finger: text = "$ON_VESSEL$KERBAL is pressing buttons at random on the control panel"; subtext = "Science data has been lost"; break; case KerbalBreakdown.rage: text = "$ON_VESSEL$KERBAL is possessed by a blind rage"; subtext = "A component has been damaged"; break; case KerbalBreakdown.wrong_valve: text = "$ON_VESSEL$KERBAL opened the wrong valve"; subtext = res.resource_name + " has been lost"; break; } // post message first so this one is shown before malfunction message Message.Post(Severity.breakdown, Lib.ExpandMsg(text, v, c), subtext); // trigger the event switch (breakdown) { case KerbalBreakdown.mumbling: break; // do nothing case KerbalBreakdown.fat_finger: Lib.RemoveData(v); break; case KerbalBreakdown.rage: Reliability.CauseMalfunction(v); break; case KerbalBreakdown.wrong_valve: res.Consume(res.amount * res_penalty); break; } // remove reputation if (HighLogic.CurrentGame.Mode == Game.Modes.CAREER) { Reputation.Instance.AddReputation(-Settings.BreakdownReputation, TransactionReasons.Any); } }
public void FixedUpdate() { // do nothing in the editor if (Lib.IsEditor()) { return; } // if enabled if (running) { int qtty = 0, crewlvl = 0; // if a researcher is not required, or the researcher is present if (!researcher_cs || researcher_cs.Check(part.protoModuleCrew, out qtty, out crewlvl)) { // get next sample to analyze string sample_filename = Next_sample(vessel); // if there is a sample to analyze if (sample_filename.Length > 0) { // consume EC Resource_Info 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) { analysis_rateAVG = analysis_rate; if (researcher_cs) { analysis_rateAVG *= qtty * crewlvl; } // analyze the sample Analyze(vessel, sample_filename, analysis_rateAVG * Kerbalism.elapsed_s); //Analyze(vessel, sample_filename, analysis_rate * Kerbalism.elapsed_s); // update status status = Science.Experiment(sample_filename).name; } // if there was no ec else { // update status status = "<color=yellow>no electric charge</color>"; } } // if there is no sample to analyze else { // update status status = "no samples to analyze"; } } // if a researcher is required, but missing else { // update status status = Lib.BuildString("<color=yellow>", researcher_cs.Warning(), "</color>"); } } // if disabled else { // update status status = "disabled"; } }
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); } // 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(); foreach (ModuleResource input in resHandler.inputResources) { recipe.Input(input.name, input.rate * Kerbalism.elapsed_s); } foreach (ModuleResource output in resHandler.outputResources) { 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; foreach (ModuleResource input in resHandler.inputResources) { 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; } }
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); } // 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(); foreach (ModuleResource input in g.resHandler.inputResources) { recipe.Input(input.name, input.rate * elapsed_s); } foreach (ModuleResource output in g.resHandler.outputResources) { 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; foreach (ModuleResource input in g.resHandler.inputResources) { 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); } }
static void ProcessScanner(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, PartModule scanner, Part part_prefab, VesselData vd, Resource_Info ec, double elapsed_s) { // get ec consumption rate double power = SCANsat.EcConsumption(scanner); // if the scanner doesn't require power to operate, we aren't interested in simulating it if (power <= double.Epsilon) { return; } // get scanner state bool is_scanning = Lib.Proto.GetBool(m, "scanning"); // if its scanning if (is_scanning) { // consume ec ec.Consume(power * elapsed_s); // if there isn't ec // - comparing against amount in previous simulation step if (ec.amount <= double.Epsilon) { // unregister scanner SCANsat.StopScanner(v, m, 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>", v.vesselName, "</b>")); } } } // if it was disabled in background else if (vd.scansat_id.Contains(p.flightID)) { // if there is enough ec // note: comparing against amount in previous simulation step if (ec.level > 0.25) //< re-enable at 25% EC { // re-enable the scanner SCANsat.ResumeScanner(v, 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>", v.vesselName, "</b>")); } } } // forget active scanners if (is_scanning) { vd.scansat_id.Remove(p.flightID); } }
State Equalize() { // in flight if (Lib.IsFlight()) { // shortcuts Resource_Info vessel_atmo = ResourceCache.Info(vessel, "Atmosphere"); PartResource hab_atmo = part.Resources["Atmosphere"]; // get level of atmosphere in vessel and part double vessel_level = vessel_atmo.level; double hab_level = Lib.Level(part, "Atmosphere", true); // equalization succeeded if the levels are the same // note: this behave correctly in the case the hab is the only enabled one or not if (Math.Abs(vessel_level - hab_level) < 0.01) { return(State.enabled); } // in case vessel pressure is dropping during equalization, it mean that pressure // control is not enough so we just enable the hab while not fully equalized if (vessel_atmo.rate < 0.0) { return(State.enabled); } // determine equalization speed // we deal with the case where a big hab is sucking all atmosphere from the rest of the vessel double amount = Math.Min(Cache.VesselInfo(vessel).volume, volume) * equalize_speed * Kerbalism.elapsed_s; // vessel pressure is higher if (vessel_level > hab_level) { // clamp amount to what's available in the vessel and what can fit in the part amount = Math.Min(amount, vessel_atmo.amount); amount = Math.Min(amount, hab_atmo.maxAmount - hab_atmo.amount); // consume from all enabled habs in the vessel vessel_atmo.Consume(amount); // produce in the part hab_atmo.amount += amount; } // vessel pressure is lower else { // consume from the part, clamp amount to what's available in the part amount = Math.Min(amount, hab_atmo.amount); hab_atmo.amount -= amount; // produce in all enabled habs in the vessel // (attempt recovery, but dump overboard if there is no capacity left) vessel_atmo.Produce(amount); } // equalization still in progress return(State.equalizing); } // in the editors else { // set amount to max capacity PartResource hab_atmo = part.Resources["Atmosphere"]; hab_atmo.amount = hab_atmo.maxAmount; // return new state return(State.enabled); } }