public Vessel_info(Vessel v, UInt64 vessel_id, UInt64 inc) { // NOTE: anything used here can't in turn use cache, unless you know what you are doing // NOTE: you can't cache vessel position // at any point in time all vessel/body positions are relative to a different frame of reference // so comparing the current position of a vessel, with the cached one of another make no sense // associate with an unique incremental id this.inc = inc; // determine if this is a valid vessel is_vessel = Lib.IsVessel(v); if (!is_vessel) { return; } // determine if this is a rescue mission vessel is_rescue = Misc.IsRescueMission(v); if (is_rescue) { return; } // dead EVA are not valid vessels if (EVA.IsDead(v)) { return; } // shortcut for common tests is_valid = true; // generate id once id = vessel_id; // calculate crew info for the vessel crew_count = Lib.CrewCount(v); crew_capacity = Lib.CrewCapacity(v); // get vessel position Vector3d position = Lib.VesselPosition(v); // this should never happen again if (Vector3d.Distance(position, v.mainBody.position) < 1.0) { throw new Exception("Shit hit the fan for vessel " + v.vesselName); } // determine if there is enough EC for a powered state powered = ResourceCache.Info(v, "ElectricCharge").amount > double.Epsilon; // determine if in sunlight, calculate sun direction and distance sunlight = Sim.RaytraceBody(v, position, FlightGlobals.Bodies[0], out sun_dir, out sun_dist) ? 1.0 : 0.0; // environment stuff atmo_factor = Sim.AtmosphereFactor(v.mainBody, position, sun_dir); gamma_transparency = Sim.GammaTransparency(v.mainBody, v.altitude); underwater = Sim.Underwater(v); breathable = Sim.Breathable(v, underwater); landed = Lib.Landed(v); zerog = !landed && (!v.mainBody.atmosphere || v.mainBody.atmosphereDepth < v.altitude); if (v.mainBody.flightGlobalsIndex != 0 && TimeWarp.CurrentRate > 1000.0f) { highspeedWarp(v); } // temperature at vessel position temperature = Sim.Temperature(v, position, sunlight, atmo_factor, out solar_flux, out albedo_flux, out body_flux, out total_flux); temp_diff = Sim.TempDiff(temperature, v.mainBody, landed); // radiation radiation = Radiation.Compute(v, position, gamma_transparency, sunlight, out blackout, out magnetosphere, out inner_belt, out outer_belt, out interstellar); // extended atmosphere thermosphere = Sim.InsideThermosphere(v); exosphere = Sim.InsideExosphere(v); // malfunction stuff malfunction = Reliability.HasMalfunction(v); critical = Reliability.HasCriticalFailure(v); // communications info connection = new ConnectionInfo(v, powered, blackout); transmitting = Science.Transmitting(v, connection.linked && connection.rate > double.Epsilon); // habitat data volume = Habitat.Tot_volume(v); surface = Habitat.Tot_surface(v); pressure = Habitat.Pressure(v); evas = (uint)(Math.Max(0, ResourceCache.Info(v, "Nitrogen").amount - 330) / PreferencesLifeSupport.Instance.evaAtmoLoss); poisoning = Habitat.Poisoning(v); humidity = Habitat.Humidity(v); shielding = Habitat.Shielding(v); living_space = Habitat.Living_space(v); volume_per_crew = Habitat.Volume_per_crew(v); comforts = new Comforts(v, landed, crew_count > 1, connection.linked && connection.rate > double.Epsilon); // data about greenhouses greenhouses = Greenhouse.Greenhouses(v); // other stuff gravioli = Sim.Graviolis(v); }
public vessel_info(Vessel v, uint vessel_id, UInt64 inc) { // NOTE: anything used here can't in turn use cache, unless you know what you are doing // NOTE: you can't cache vessel position // at any point in time all vessel/body positions are relative to a different frame of reference // so comparing the current position of a vessel, with the cached one of another make no sense // associate with an unique incremental id this.inc = inc; // determine if this is a valid vessel is_vessel = Lib.IsVessel(v); if (!is_vessel) return; // determine if this is a rescue mission vessel is_rescue = Misc.IsRescueMission(v); if (is_rescue) return; // dead EVA are not valid vessels if (EVA.IsDead(v)) return; // shortcut for common tests is_valid = true; // generate id once id = vessel_id; // calculate crew info for the vessel crew_count = Lib.CrewCount(v); crew_capacity = Lib.CrewCapacity(v); // get vessel position Vector3d position = Lib.VesselPosition(v); // this should never happen again if (Vector3d.Distance(position, v.mainBody.position) < 1.0) { throw new Exception("Shit hit the fan for vessel " + v.vesselName); } // determine if in sunlight, calculate sun direction and distance sunlight = Sim.RaytraceBody(v, position, FlightGlobals.Bodies[0], out sun_dir, out sun_dist) ? 1.0 : 0.0; // at the two highest timewarp speed, the number of sun visibility samples drop to the point that // the quantization error first became noticeable, and then exceed 100% // to solve this, we switch to an analytical estimation of the portion of orbit that was in sunlight // - we check against timewarp rate, instead of index, to avoid issues during timewarp blending if (v.mainBody.flightGlobalsIndex != 0 && TimeWarp.CurrentRate > 1000.0f) { sunlight = 1.0 - Sim.ShadowPeriod(v) / Sim.OrbitalPeriod(v); } // environment stuff atmo_factor = Sim.AtmosphereFactor(v.mainBody, position, sun_dir); gamma_transparency = Sim.GammaTransparency(v.mainBody, v.altitude); underwater = Sim.Underwater(v); breathable = Sim.Breathable(v, underwater); landed = Lib.Landed(v); // temperature at vessel position temperature = Sim.Temperature(v, position, sunlight, atmo_factor, out solar_flux, out albedo_flux, out body_flux, out total_flux); temp_diff = Sim.TempDiff(temperature, v.mainBody, landed); // radiation radiation = Radiation.Compute(v, position, gamma_transparency, sunlight, out blackout, out magnetosphere, out inner_belt, out outer_belt, out interstellar); // extended atmosphere thermosphere = Sim.InsideThermosphere(v); exosphere = Sim.InsideExosphere(v); // malfunction stuff malfunction = Reliability.HasMalfunction(v); critical = Reliability.HasCriticalFailure(v); // signal info antenna = new AntennaInfo(v); avoid_inf_recursion.Add(v.id); connection = Signal.connection(v, position, antenna, blackout, avoid_inf_recursion); transmitting = Science.transmitting(v, connection.linked); relaying = Signal.relaying(v, avoid_inf_recursion); avoid_inf_recursion.Remove(v.id); // habitat data volume = Habitat.tot_volume(v); surface = Habitat.tot_surface(v); pressure = Habitat.pressure(v); poisoning = Habitat.poisoning(v); shielding = Habitat.shielding(v); living_space = Habitat.living_space(v); comforts = new Comforts(v, landed, crew_count > 1, connection.linked); // data about greenhouses greenhouses = Greenhouse.Greenhouses(v); // other stuff gravioli = Sim.Graviolis(v); }
private void EvaluateEnvironment(double elapsedSeconds) { UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.VesselData.EvaluateStatus"); // we use analytic mode if more than 2 minutes of game time has passed since last evaluation (~ x6000 timewarp speed) isAnalytic = elapsedSeconds > 120.0; // get vessel position Vector3d position = Lib.VesselPosition(Vessel); // this should never happen again if (Vector3d.Distance(position, Vessel.mainBody.position) < 1.0) { throw new Exception("Shit hit the fan for vessel " + Vessel.vesselName); } // situation underwater = Sim.Underwater(Vessel); breathable = Sim.Breathable(Vessel, EnvUnderwater); landed = Lib.Landed(Vessel); inAtmosphere = Vessel.mainBody.atmosphere && Vessel.altitude < Vessel.mainBody.atmosphereDepth; zeroG = !EnvLanded && !inAtmosphere; visibleBodies = Sim.GetLargeBodies(position); // get solar info (with multiple stars / Kopernicus support) // get the 'visibleBodies' and 'sunsInfo' lists, the 'mainSun', 'solarFluxTotal' variables. // require the situation variables to be evaluated first UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.VesselData.Sunlight"); SunInfo.UpdateSunsInfo(this, position); UnityEngine.Profiling.Profiler.EndSample(); sunBodyAngle = Sim.SunBodyAngle(Vessel, position, mainSun.SunData.body); // temperature at vessel position UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.VesselData.Temperature"); temperature = Sim.Temperature(Vessel, position, solarFluxTotal, out albedoFlux, out bodyFlux, out totalFlux); tempDiff = Sim.TempDiff(EnvTemperature, Vessel.mainBody, EnvLanded); UnityEngine.Profiling.Profiler.EndSample(); // radiation UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.VesselData.Radiation"); gammaTransparency = Sim.GammaTransparency(Vessel.mainBody, Vessel.altitude); bool new_innerBelt, new_outerBelt, new_magnetosphere; radiation = Radiation.Compute(Vessel, position, EnvGammaTransparency, mainSun.SunlightFactor, out blackout, out new_magnetosphere, out new_innerBelt, out new_outerBelt, out interstellar, out shieldedRadiation); if (new_innerBelt != innerBelt || new_outerBelt != outerBelt || new_magnetosphere != magnetosphere) { innerBelt = new_innerBelt; outerBelt = new_outerBelt; magnetosphere = new_magnetosphere; if (Evaluated) { API.OnRadiationFieldChanged.Notify(Vessel, innerBelt, outerBelt, magnetosphere); } } UnityEngine.Profiling.Profiler.EndSample(); thermosphere = Sim.InsideThermosphere(Vessel); exosphere = Sim.InsideExosphere(Vessel); inStorm = Storm.InProgress(Vessel); vesselSituations.Update(); // other stuff gravioli = Sim.Graviolis(Vessel); UnityEngine.Profiling.Profiler.EndSample(); }
public static void applyRules(Vessel v, vessel_info vi, vessel_data vd, vessel_resources resources, double elapsed_s) { // get crew List<ProtoCrewMember> crew = v.loaded ? v.GetVesselCrew() : v.protoVessel.GetVesselCrew(); // get breathable modifier double breathable = vi.breathable ? 0.0 : 1.0; // get temp diff modifier double temp_diff = v.altitude < 2000.0 && v.mainBody == FlightGlobals.GetHomeBody() ? 0.0 : Sim.TempDiff(vi.temperature); // for each rule foreach(Rule r in Kerbalism.rules) { // get resource handler resource_info res = r.resource_name.Length > 0 ? resources.Info(v, r.resource_name) : null; // if a resource is specified if (res != null) { // get data from db vmon_data vmon = DB.VmonData(v.id, r.name); // message obey user config bool show_msg = (r.resource_name == "ElectricCharge" ? vd.cfg_ec > 0 : vd.cfg_supply > 0); // no messages with no capacity if (res.capacity > double.Epsilon) { // manned/probe message variant uint variant = crew.Count > 0 ? 0 : 1u; // manage messages if (res.level <= double.Epsilon && vmon.message < 2) { if (r.empty_message.Length > 0 && show_msg) Message.Post(Severity.danger, Lib.ExpandMsg(r.empty_message, v, null, variant)); vmon.message = 2; } else if (res.level < r.low_threshold && vmon.message < 1) { if (r.low_message.Length > 0 && show_msg) Message.Post(Severity.warning, Lib.ExpandMsg(r.low_message, v, null, variant)); vmon.message = 1; } else if (res.level > r.low_threshold && vmon.message > 0) { if (r.refill_message.Length > 0 && show_msg) Message.Post(Severity.relax, Lib.ExpandMsg(r.refill_message, v, null, variant)); vmon.message = 0; } } } // for each crew foreach(ProtoCrewMember c in crew) { // get kerbal data kerbal_data kd = DB.KerbalData(c.name); // skip resque kerbals if (kd.resque == 1) continue; // skip disabled kerbals if (kd.disabled == 1) continue; // get supply data from db kmon_data kmon = DB.KmonData(c.name, r.name); // get product of all environment modifiers double k = 1.0; foreach(string modifier in r.modifier) { switch(modifier) { case "breathable": k *= breathable; break; case "temperature": k *= temp_diff; break; case "radiation": k *= vi.radiation * (1.0 - kd.shielding); break; case "qol": k /= QualityOfLife.Bonus(kd.living_space, kd.entertainment, vi.landed, vi.link.linked, vi.crew_count == 1); break; } } // if continuous double step; if (r.interval <= double.Epsilon) { // influence consumption by elapsed time step = elapsed_s; } // if interval-based else { // accumulate time kmon.time_since += elapsed_s; // determine number of steps step = Math.Floor(kmon.time_since / r.interval); // consume time kmon.time_since -= step * r.interval; // remember if a meal is consumed in this simulation step res.meal_consumed |= step > 0.99; } // if continuous, or if one or more intervals elapsed if (step > double.Epsilon) { // indicate if we must degenerate bool must_degenerate = true; // if there is a resource specified, and this isn't just a monitoring rule if (res != null && r.rate > double.Epsilon) { // determine amount of resource to consume double required = r.rate // rate per-second or per interval * k // product of environment modifiers * step; // seconds elapsed or number of steps // if there is no waste if (r.waste_name.Length == 0) { // simply consume (that is faster) res.Consume(required); } // if there is waste else { // transform resource into waste resource_recipe recipe = new resource_recipe(resource_recipe.rule_priority); recipe.Input(r.resource_name, required); recipe.Output(r.waste_name, required * r.waste_ratio); resources.Transform(recipe); } // reset degeneration when consumed, or when not required at all // note: evaluating amount from previous simulation step if (required <= double.Epsilon || res.amount > double.Epsilon) { // slowly recover instead of instant reset kmon.problem *= 1.0 / (1.0 + Math.Max(r.interval, 1.0) * step * 0.002); kmon.problem = Math.Max(kmon.problem, 0.0); // do not degenerate must_degenerate = false; } } // degenerate if this rule is resource-less, or if there was not enough resource in the vessel if (must_degenerate) { kmon.problem += r.degeneration // degeneration rate per-second or per-interval * k // product of environment modifiers * step // seconds elapsed or by number of steps * Variance(c, r.variance); // kerbal-specific variance } // determine message variant uint variant = vi.temperature < Settings.SurvivalTemperature ? 0 : 1u; // kill kerbal if necessary if (kmon.problem >= r.fatal_threshold) { if (r.fatal_message.Length > 0) Message.Post(r.breakdown ? Severity.breakdown : Severity.fatality, Lib.ExpandMsg(r.fatal_message, v, c, variant)); if (r.breakdown) { Kerbalism.Breakdown(v, c); kmon.problem = r.danger_threshold * 1.01; //< move back to danger threshold } else { Kerbalism.Kill(v, c); } } // show messages else if (kmon.problem >= r.danger_threshold && kmon.message < 2) { if (r.danger_message.Length > 0) Message.Post(Severity.danger, Lib.ExpandMsg(r.danger_message, v, c, variant)); kmon.message = 2; } else if (kmon.problem >= r.warning_threshold && kmon.message < 1) { if (r.warning_message.Length > 0) Message.Post(Severity.warning, Lib.ExpandMsg(r.warning_message, v, c, variant)); kmon.message = 1; } else if (kmon.problem < r.warning_threshold && kmon.message > 0) { if (r.relax_message.Length > 0) Message.Post(Severity.relax, Lib.ExpandMsg(r.relax_message, v, c, variant)); kmon.message = 0; } } } } }