/// <summary> /// We're always going to call you for resource handling. You tell us what to produce or consume. Here's how it'll look when your vessel is NOT loaded /// </summary> /// <param name="v">the vessel (unloaded)</param> /// <param name="part_snapshot">proto part snapshot (contains all non-persistant KSPFields)</param> /// <param name="module_snapshot">proto part module snapshot (contains all non-persistant KSPFields)</param> /// <param name="proto_part_module">proto part module snapshot (contains all non-persistant KSPFields)</param> /// <param name="proto_part">proto part snapshot (contains all non-persistant KSPFields)</param> /// <param name="availableResources">key-value pair containing all available resources and their currently available amount on the vessel. if the resource is not in there, it's not available</param> /// <param name="resourceChangeRequest">key-value pair that contains the resource names and the units per second that you want to produce/consume (produce: positive, consume: negative)</param> /// <param name="elapsed_s">how much time elapsed since the last time. note this can be very long, minutes and hours depending on warp speed</param> /// <returns>the title to be displayed in the resource tooltip</returns> public static string BackgroundUpdate(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, PartModule pm, Part part, Dictionary <string, double> availableResources, List <KeyValuePair <string, double> > resourceChangeRequest, double elapsed_s) { PassiveShield passiveShield = pm as PassiveShield; if (passiveShield == null) { return(string.Empty); } if (passiveShield.ec_rate > 0) { return(string.Empty); } bool deployed = Lib.Proto.GetBool(m, "deployed"); if (deployed) { resourceChangeRequest.Add(new KeyValuePair <string, double>("ElectricCharge", -passiveShield.ec_rate)); } return(passiveShield.title); }
// return the total environent radiation at position specified public static double Compute(Vessel v, Vector3d position, double gamma_transparency, double sunlight, out bool blackout, out bool magnetosphere, out bool inner_belt, out bool outer_belt, out bool interstellar, out double shieldedRadiation) { // prepare out parameters blackout = false; magnetosphere = false; inner_belt = false; outer_belt = false; interstellar = false; shieldedRadiation = 0.0; // no-op when Radiation is disabled if (!Features.Radiation) { return(0.0); } // store stuff Space gsm; Vector3 p; double D; double r; // accumulate radiation double radiation = 0.0; CelestialBody body = v.mainBody; while (body != null) { // Compute radiation values from overlapping 3d fields (belts + magnetospheres) RadiationBody rb = Info(body); RadiationModel mf = rb.model; // activity is [-0.15..1.05] var activity = rb.SolarActivity(false); if (mf.Has_field()) { // transform to local space once var scaled_position = ScaledSpace.LocalToScaledSpace(position); // generate radii-normalized GSM space gsm = Gsm_space(rb, true); // move the point in GSM space p = gsm.Transform_in(scaled_position); // accumulate radiation and determine pause/belt flags if (mf.has_inner) { D = mf.Inner_func(p); inner_belt |= D < 0; // allow for radiation field to grow/shrink with solar activity D -= activity * 0.25 / mf.inner_radius; r = RadiationInBelt(D, mf.inner_radius, rb.radiation_inner_gradient); radiation += r * rb.radiation_inner * (1 + activity * 0.3); } if (mf.has_outer) { D = mf.Outer_func(p); outer_belt |= D < 0; // allow for radiation field to grow/shrink with solar activity D -= activity * 0.25 / mf.outer_radius; r = RadiationInBelt(D, mf.outer_radius, rb.radiation_outer_gradient); radiation += r * rb.radiation_outer * (1 + activity * 0.3); } if (mf.has_pause) { gsm = Gsm_space(rb, false); p = gsm.Transform_in(scaled_position); D = mf.Pause_func(p); radiation += Lib.Clamp(D / -0.1332f, 0.0f, 1.0f) * rb.RadiationPause(); magnetosphere |= D < 0.0f && !Lib.IsSun(rb.body); //< ignore heliopause interstellar |= D > 0.0f && Lib.IsSun(rb.body); //< outside heliopause } } if (rb.radiation_surface > 0 && body != v.mainBody) { Vector3d direction; double distance; if (Sim.IsBodyVisible(v, position, body, v.KerbalismData().EnvVisibleBodies, out direction, out distance)) { var r0 = RadiationR0(rb); var r1 = DistanceRadiation(r0, distance); // clamp to max. surface radiation. when loading on a rescaled system, the vessel can appear to be within the sun for a few ticks radiation += Math.Min(r1, rb.radiation_surface); #if DEBUG_RADIATION if (v.loaded) { Lib.Log("Radiation " + v + " from surface of " + body + ": " + Lib.HumanReadableRadiation(radiation) + " gamma: " + Lib.HumanReadableRadiation(r1)); } #endif } } // avoid loops in the chain body = (body.referenceBody != null && body.referenceBody.referenceBody == body) ? null : body.referenceBody; } // add extern radiation radiation += Settings.ExternRadiation / 3600.0; #if DEBUG_RADIATION if (v.loaded) { Lib.Log("Radiation " + v + " extern: " + Lib.HumanReadableRadiation(radiation) + " gamma: " + Lib.HumanReadableRadiation(Settings.ExternRadiation)); } #endif // apply gamma transparency if inside atmosphere radiation *= gamma_transparency; #if DEBUG_RADIATION if (v.loaded) { Lib.Log("Radiation " + v + " after gamma: " + Lib.HumanReadableRadiation(radiation) + " transparency: " + gamma_transparency); } #endif // add surface radiation of the body itself if (Lib.IsSun(v.mainBody) && v.altitude < v.mainBody.Radius) { if (v.altitude > v.mainBody.Radius) { radiation += DistanceRadiation(RadiationR0(Info(v.mainBody)), v.altitude); } } #if DEBUG_RADIATION if (v.loaded) { Lib.Log("Radiation " + v + " from current main body: " + Lib.HumanReadableRadiation(radiation) + " gamma: " + Lib.HumanReadableRadiation(DistanceRadiation(RadiationR0(Info(v.mainBody)), v.altitude))); } #endif shieldedRadiation = radiation; // if there is a storm in progress if (Storm.InProgress(v)) { // inside a magnetopause (except heliosphere), blackout the signal // outside, add storm radiations modulated by sun visibility if (magnetosphere) { blackout = true; } else { var vd = v.KerbalismData(); var activity = Info(vd.EnvMainSun.SunData.body).SolarActivity(false) / 2.0; var strength = PreferencesRadiation.Instance.StormRadiation * sunlight * (activity + 0.5); radiation += strength; shieldedRadiation += vd.EnvHabitatInfo.AverageHabitatRadiation(strength); } } // add emitter radiation after atmosphere transparency var emitterRadiation = Emitter.Total(v); radiation += emitterRadiation; shieldedRadiation += emitterRadiation; #if DEBUG_RADIATION if (v.loaded) { Lib.Log("Radiation " + v + " after emitters: " + Lib.HumanReadableRadiation(radiation) + " shielded " + Lib.HumanReadableRadiation(shieldedRadiation)); } #endif // for EVAs, add the effect of nearby emitters if (v.isEVA) { var nearbyEmitters = Emitter.Nearby(v); radiation += nearbyEmitters; shieldedRadiation += nearbyEmitters; #if DEBUG_RADIATION if (v.loaded) { Lib.Log("Radiation " + v + " nearby emitters " + Lib.HumanReadableRadiation(nearbyEmitters)); } #endif } var passiveShielding = PassiveShield.Total(v); shieldedRadiation -= passiveShielding; #if DEBUG_RADIATION if (v.loaded) { Lib.Log("Radiation " + v + " passiveShielding " + Lib.HumanReadableRadiation(passiveShielding)); } if (v.loaded) { Lib.Log("Radiation " + v + " before clamp: " + Lib.HumanReadableRadiation(radiation) + " shielded " + Lib.HumanReadableRadiation(shieldedRadiation)); } #endif // clamp radiation to positive range // note: we avoid radiation going to zero by using a small positive value radiation = Math.Max(radiation, Nominal); shieldedRadiation = Math.Max(shieldedRadiation, Nominal); #if DEBUG_RADIATION if (v.loaded) { Lib.Log("Radiation " + v + " after clamp: " + Lib.HumanReadableRadiation(radiation) + " shielded " + Lib.HumanReadableRadiation(shieldedRadiation)); } #endif // return radiation return(radiation); }