// return time left until CME is over public static double TimeLeftCME(CelestialBody body) { if (body.flightGlobalsIndex == 0) return 0.0; if (!DB.Ready()) return 0.0; body_data bd = DB.BodyData(Lib.PlanetarySystem(body).name); return Math.Max(0.0, bd.storm_time - bd.storm_age); }
// return true if a storm just ended // used to avoid sending 'signal is back' messages en-masse after the storm is over // - delta_time: time between calls to this function public static bool JustEnded(Vessel v, double delta_time) { if (!DB.Ready()) return false; // if in interplanetary space if (v.mainBody.flightGlobalsIndex == 0) { return DB.VesselData(v.id).storm_age < delta_time * 2.0; } // if inside a planetary system else { return DB.BodyData(Lib.PlanetarySystem(v.mainBody).name).storm_age < delta_time * 2.0; } }
// return true if a storm is in progress public static bool InProgress(Vessel v) { if (!DB.Ready()) return false; // if in interplanetary space if (v.mainBody.flightGlobalsIndex == 0) { return DB.VesselData(v.id).storm_state == 2; } // if inside a planetary system else { return DB.BodyData(Lib.PlanetarySystem(v.mainBody).name).storm_state == 2; } }
// return time left until CME is over public static double TimeLeftCME(Vessel v) { if (!DB.Ready()) return 0.0; // if in interplanetary space if (v.mainBody.flightGlobalsIndex == 0) { vessel_data vd = DB.VesselData(v.id); return TimeLeftCME(vd.storm_time, vd.storm_age); } // if inside a planetary system else { body_data bd = DB.BodyData(Lib.PlanetarySystem(v.mainBody).name); return TimeLeftCME(bd.storm_time, bd.storm_age); } }
// called every simulation tick public void FixedUpdate() { // do nothing if paused if (Lib.IsPaused()) return; // avoid case when DB isn't ready for whatever reason if (!DB.Ready()) return; // do nothing in the editors and the menus if (!Lib.SceneIsGame()) return; // for each celestial body foreach(CelestialBody body in FlightGlobals.Bodies) { // skip the sun if (body.flightGlobalsIndex == 0) continue; // skip moons if (body.referenceBody.flightGlobalsIndex != 0) continue; // get body data body_data bd = DB.BodyData(body.name); // generate storm time if necessary if (bd.storm_time <= double.Epsilon) { bd.storm_time = Settings.StormMinTime + (Settings.StormMaxTime - Settings.StormMinTime) * Lib.RandomDouble(); } // accumulate age bd.storm_age += TimeWarp.fixedDeltaTime * storm_frequency(body); // if storm is over if (bd.storm_age > bd.storm_time) { bd.storm_age = 0.0; bd.storm_time = 0.0; bd.storm_state = 0; } // if storm is in progress else if (bd.storm_age > bd.storm_time - Settings.StormDuration) { bd.storm_state = 2; } // if storm is incoming else if (bd.storm_age > bd.storm_time - Settings.StormDuration - time_to_impact(body)) { bd.storm_state = 1; } // send messages // note: separed from state management to support the case when the user enter the SOI of a body under storm or about to be hit if (bd.msg_storm < 2 && bd.storm_state == 2) { if (body_is_relevant(body)) { Message.Post(Severity.danger, "The coronal mass ejection hit <b>" + body.name + "</b> system", "Storm duration: " + Lib.HumanReadableDuration(TimeLeftCME(body))); } bd.msg_storm = 2; } else if (bd.msg_storm < 1 && bd.storm_state == 1) { if (body_is_relevant(body)) { Message.Post(Severity.warning, "Our observatories report a coronal mass ejection directed toward <b>" + body.name + "</b> system", "Time to impact: " + Lib.HumanReadableDuration(TimeBeforeCME(body))); } bd.msg_storm = 1; } else if (bd.msg_storm > 1 && bd.storm_state == 0) { if (body_is_relevant(body)) { Message.Post(Severity.relax, "The solar storm at <b>" + body.name + "</b> system is over"); } bd.msg_storm = 0; } } }
// return true if a storm just ended // used to avoid sending 'signal is back' messages en-masse after the storm is over // - delta_time: time between calls to this function public static bool JustEnded(CelestialBody body, double delta_time) { if (body.flightGlobalsIndex == 0) return false; return DB.Ready() && DB.BodyData(Lib.PlanetarySystem(body).name).storm_age < TimeWarp.deltaTime * 2.0; }
// return true if a storm is in progress public static bool InProgress(CelestialBody body) { if (body.flightGlobalsIndex == 0) return false; return DB.Ready() && DB.BodyData(Lib.PlanetarySystem(body).name).storm_state == 2; }
public void update(CelestialBody body, double elapsed_s) { // do nothing if storms are disabled if (Settings.StormDuration <= double.Epsilon) return; // skip the sun if (body.flightGlobalsIndex == 0) return; // skip moons // note: referenceBody is never null here if (body.referenceBody.flightGlobalsIndex != 0) return; // get body data body_data bd = DB.BodyData(body.name); // generate storm time if necessary if (bd.storm_time <= double.Epsilon) { bd.storm_time = Settings.StormMinTime + (Settings.StormMaxTime - Settings.StormMinTime) * Lib.RandomDouble(); } // accumulate age bd.storm_age += elapsed_s * storm_frequency(body.orbit.semiMajorAxis); // if storm is over if (bd.storm_age > bd.storm_time) { bd.storm_age = 0.0; bd.storm_time = 0.0; bd.storm_state = 0; } // if storm is in progress else if (bd.storm_age > bd.storm_time - Settings.StormDuration) { bd.storm_state = 2; } // if storm is incoming else if (bd.storm_age > bd.storm_time - Settings.StormDuration - time_to_impact(body.orbit.semiMajorAxis)) { bd.storm_state = 1; } // send messages // note: separed from state management to support the case when the user enter the SOI of a body under storm or about to be hit if (bd.msg_storm < 2 && bd.storm_state == 2) { if (body_is_relevant(body)) { Message.Post(Severity.danger, Lib.BuildString("The coronal mass ejection hit <b>", body.name, "</b> system"), Lib.BuildString("Storm duration: ", Lib.HumanReadableDuration(TimeLeftCME(bd.storm_time, bd.storm_age)))); } bd.msg_storm = 2; } else if (bd.msg_storm < 1 && bd.storm_state == 1) { if (body_is_relevant(body)) { Message.Post(Severity.warning, Lib.BuildString("Our observatories report a coronal mass ejection directed toward <b>", body.name, "</b> system"), Lib.BuildString("Time to impact: ", Lib.HumanReadableDuration(TimeBeforeCME(bd.storm_time, bd.storm_age)))); } bd.msg_storm = 1; } else if (bd.msg_storm > 1 && bd.storm_state == 0) { if (body_is_relevant(body)) { Message.Post(Severity.relax, Lib.BuildString("The solar storm at <b>", body.name, "</b> system is over")); } bd.msg_storm = 0; } }