Exemple #1
0
        // return true if the vessel is a resque mission
        public static bool IsResqueMission(Vessel v)
        {
            // if db isn't ready, assume a resque mission
            if (!DB.Ready())
            {
                return(true);
            }

            // avoid re-creating dead eva kerbals in the db
            // note: no extra cost if vessel is not eva
            if (EVA.IsDead(v))
            {
                return(true);
            }

            // if at least one of the crew is flagged as resque, consider it a resque mission
            var crew_members = v.loaded ? v.GetVesselCrew() : v.protoVessel.GetVesselCrew();

            foreach (var c in crew_members)
            {
                kerbal_data kd = DB.KerbalData(c.name);
                if (kd.resque == 1)
                {
                    return(true);
                }
            }

            // not a resque mission
            return(false);
        }
Exemple #2
0
  void problem_kerbals(List<ProtoCrewMember> crew, ref List<Texture> icons, ref List<string> tooltips)
  {
    UInt32 health_severity = 0;
    UInt32 stress_severity = 0;
    foreach(ProtoCrewMember c in crew)
    {
      // get kerbal data
      kerbal_data kd = DB.KerbalData(c.name);

      // skip disabled kerbals
      if (kd.disabled == 1) continue;

      foreach(Rule r in Kerbalism.rules)
      {
        kmon_data kmon = DB.KmonData(c.name, r.name);
        if (kmon.problem > r.danger_threshold)
        {
          if (!r.breakdown) health_severity = Math.Max(health_severity, 2);
          else stress_severity = Math.Max(stress_severity, 2);
          tooltips.Add(Lib.BuildString(c.name, " (", r.name, ")"));
        }
        else if (kmon.problem > r.warning_threshold)
        {
          if (!r.breakdown) health_severity = Math.Max(health_severity, 1);
          else stress_severity = Math.Max(stress_severity, 1);
          tooltips.Add(Lib.BuildString(c.name, " (", r.name, ")"));
        }
      }

    }
    if (health_severity == 1) icons.Add(icon_health_warning);
    else if (health_severity == 2) icons.Add(icon_health_danger);
    if (stress_severity == 1) icons.Add(icon_stress_warning);
    else if (stress_severity == 2) icons.Add(icon_stress_danger);
  }
Exemple #3
0
  void render_crew(Vessel v, vessel_info vi, List<ProtoCrewMember> crew)
  {
    // get degenerative rules
    List<Rule> degen_rules = Kerbalism.rules.FindAll(k => k.degeneration > 0.0);

    // do nothing if there are no degenerative rules
    if (degen_rules.Count == 0) return;

    // do nothing if there isn't a crew
    if (crew.Count == 0) return;

    // select a kerbal
    ProtoCrewMember kerbal = crew[crew_index % crew.Count];

    // render it
    kerbal_data kd = DB.KerbalData(kerbal.name);
    render_title(Lib.Epsilon(kerbal.name.ToUpper(), 20), ref crew_index, crew.Count);
    foreach(Rule r in degen_rules)
    {
      var kmon = DB.KmonData(kerbal.name, r.name);
      var bar = Lib.ProgressBar(20, kmon.problem, r.warning_threshold, r.danger_threshold, r.fatal_threshold, kd.disabled > 0 ? "cyan" : "");
      render_content(r.name.AddSpacesOnCaps().ToLower(), bar);
    }
    render_content("specialization", kerbal.trait);
    if (Kerbalism.detected_mods.DeepFreeze) render_content("hibernated", kd.disabled > 0 ? "yes" : "no");
    if (Kerbalism.detected_mods.CLS) render_content("inside", v.isEVA ? "EVA" : Lib.Epsilon(kd.space_name.Length == 0 ? v.vesselName : kd.space_name, 24));
    render_space();
  }
Exemple #4
0
  void problem_kerbals(List<ProtoCrewMember> crew, ref List<Texture> icons, ref List<string> tooltips)
  {
    UInt32 health_severity = 0;
    UInt32 stress_severity = 0;
    foreach(ProtoCrewMember c in crew)
    {
      // get kerbal data
      kerbal_data kd = DB.KerbalData(c.name);

      // skip disabled kerbals
      if (kd.disabled == 1) continue;

      // health
      if (kd.starved > Settings.StarvedDangerThreshold) { health_severity = Math.Max(health_severity, 2); tooltips.Add(c.name + " is starving"); }
      else if (kd.starved > Settings.StarvedWarningThreshold) { health_severity = Math.Max(health_severity, 1); tooltips.Add(c.name + " is hungry"); }
      if (kd.deprived > Settings.DeprivedDangerThreshold) { health_severity = Math.Max(health_severity, 2); tooltips.Add(c.name + " is suffocating"); }
      else if (kd.deprived > Settings.DeprivedWarningThreshold) { health_severity = Math.Max(health_severity, 1); tooltips.Add(c.name + " is gasping"); }
      if (kd.temperature < -Settings.TemperatureDangerThreshold) { health_severity = Math.Max(health_severity, 2); tooltips.Add(c.name + " is freezing"); }
      else if (kd.temperature < -Settings.TemperatureWarningThreshold) { health_severity = Math.Max(health_severity, 1); tooltips.Add(c.name + " feels cold"); }
      else if (kd.temperature > Settings.TemperatureDangerThreshold) { health_severity = Math.Max(health_severity, 2); tooltips.Add(c.name + " is burning"); }
      else if (kd.temperature > Settings.TemperatureWarningThreshold) { health_severity = Math.Max(health_severity, 1); tooltips.Add(c.name + " feels hot"); }

      // radiation
      if (kd.radiation > Settings.RadiationDangerThreshold) { health_severity = Math.Max(health_severity, 2); tooltips.Add(c.name + " exposed to extreme radiation"); }
      else if (kd.radiation > Settings.RadiationWarningThreshold) { health_severity = Math.Max(health_severity, 1); tooltips.Add(c.name + " exposed to intense radiation"); }

      // stress
      if (kd.stressed > Settings.StressedDangerThreshold) { stress_severity = Math.Max(stress_severity, 2); tooltips.Add(c.name + " mind is breaking"); }
      else if (kd.stressed > Settings.StressedWarningThreshold) { stress_severity = Math.Max(stress_severity, 1); tooltips.Add(c.name + " is stressed"); }
    }
    if (health_severity == 1) icons.Add(icon_health_warning);
    else if (health_severity == 2) icons.Add(icon_health_danger);
    if (stress_severity == 1) icons.Add(icon_stress_warning);
    else if (stress_severity == 2) icons.Add(icon_stress_danger);
  }
Exemple #5
0
  // return quality-of-life bonus
  public static double Bonus(Vessel v, string k_name)
  {
    // get QoL data from db
    kerbal_data kd = DB.KerbalData(k_name);

    // calculate quality of life bonus
    return Bonus(kd.living_space, kd.entertainment, Lib.Landed(v), Signal.Link(v).linked, Lib.CrewCount(v) < 2u);
  }
Exemple #6
0
        // hook: InjectRadiation()
        public static void hook_InjectRadiation(string k_name, double amount)
        {
            if (!DB.Ready())
            {
                return;
            }
            if (!DB.Kerbals().ContainsKey(k_name))
            {
                return;
            }
            kerbal_data kd = DB.KerbalData(k_name);

            kd.radiation = Math.Max(kd.radiation + amount, 0.0);
        }
Exemple #7
0
 public override string info()
 {
   kerbal_data kd = DB.KerbalData(crew.name);
   int worst = 0;
   foreach(Rule r in Kerbalism.rules)
   {
     double problem = kd.kmon[r.name].problem;
     if (problem > r.danger_threshold) worst = Math.Max(worst, 2);
     else if (problem > r.warning_threshold) worst = Math.Max(worst, 1);
   }
   switch(worst)
   {
     case 2: return "<color=red>danger</color>";
     case 1: return "<color=yellow>warning</color>";
     default: return "<color=green>healthy</color>";
   }
 }
Exemple #8
0
  public static void update(Vessel v)
  {
    // get kerbal data from db
    kerbal_data kd = KerbalData(v);

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

    // show/hide helmet, play nice with KIS
    if (!Kerbalism.detected_mods.KIS)
    {
      SetHelmet(kerbal, kd.has_helmet);
    }
    // synchronize has_helmet state with KIS (for the headlights)
    else
    {
      kd.has_helmet = HasHelmet(kerbal);
    }

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

    // consume EC for the headlamp
    if (kd.has_helmet && kerbal.lampOn) ec.Consume(Settings.HeadlightCost * Kerbalism.elapsed_s); //< ignore time dilation

    // force the headlamp lights on/off depending on ec amount left and if it has an helmet
    // synchronize helmet flares with headlamp state
    // support case when there is no ec rule (or no profile at all)
    bool b = kd.has_helmet && kerbal.lampOn && (ec.amount > double.Epsilon || ec.capacity <= double.Epsilon);
    SetHeadlamp(kerbal, b);
    SetFlares(kerbal, b);

    // if dead
    if (kd.eva_dead)
    {
      // enforce freezed state
      SetFreezed(kerbal);

      // remove plant flag action
      kerbal.flagItems = 0;

      // remove experiment actions (game engine keeps readding them)
      RemoveExperiments(kerbal);
    }
  }
Exemple #9
0
        void updateConnectedSpaces(Vessel v, vessel_info vi)
        {
            // get CLS handler
            var cls = CLS.get();

            // calculate whole-space
            if (cls == null)
            {
                double living_space  = QualityOfLife.LivingSpace((uint)vi.crew_count, (uint)vi.crew_capacity);
                double entertainment = QualityOfLife.Entertainment(v);
                double shielding     = Radiation.Shielding(v);

                foreach (var c in v.loaded ? v.GetVesselCrew() : v.protoVessel.GetVesselCrew())
                {
                    kerbal_data kd = DB.KerbalData(c.name);
                    kd.living_space  = living_space;
                    kd.entertainment = entertainment;
                    kd.shielding     = shielding;
                    kd.space_name    = "";
                }
            }
            // calculate connected-space
            // note: avoid problem at scene change
            else if (cls.Vessel != null && cls.Vessel.Spaces.Count > 0)
            {
                // calculate internal spaces
                foreach (var space in cls.Vessel.Spaces)
                {
                    double living_space  = QualityOfLife.LivingSpace(space);
                    double entertainment = QualityOfLife.Entertainment(v, space);
                    double shielding     = Radiation.Shielding(space);

                    foreach (var c in space.Crew)
                    {
                        kerbal_data kd = DB.KerbalData(c.Kerbal.name);
                        kd.living_space  = living_space;
                        kd.entertainment = entertainment;
                        kd.shielding     = shielding;
                        kd.space_name    = space.Name;
                    }
                }
            }
        }
Exemple #10
0
        // hook: InjectRadiation()
        public static void hook_InjectRadiation(string k_name, double amount)
        {
            if (!DB.Ready())
            {
                return;
            }
            if (!DB.Kerbals().ContainsKey(k_name))
            {
                return;
            }
            kerbal_data kd = DB.KerbalData(k_name);

            foreach (Rule r in Kerbalism.rules)
            {
                if (r.modifier.Contains("radiation"))
                {
                    var kmon = DB.KmonData(k_name, r.name);
                    kmon.problem = Math.Max(kmon.problem + amount, 0.0);
                }
            }
        }
Exemple #11
0
  void render_internal_space(Vessel v, vessel_info vi, List<ProtoCrewMember> crew)
  {
    // do not render internal space info for eva vessels
    if (v.isEVA) return;

    // if there is no crew, no space will be found, so do nothing in that case
    if (crew.Count == 0) return;

    // collect set of spaces
    // note: this is guaranteed to get at least a space (because there is at least one crew member)
    List<space_details> spaces = new List<space_details>();
    foreach(var c in crew)
    {
      kerbal_data kd = DB.KerbalData(c.name);
      space_details sd = spaces.Find(k => k.name == kd.space_name);
      if (sd == null)
      {
        sd = new space_details();
        sd.name = kd.space_name;
        sd.living_space = kd.living_space;
        sd.entertainment = kd.entertainment;
        sd.shielding = kd.shielding;
        spaces.Add(sd);
      }
      ++sd.crew_count;
    }

    // select a space
    space_details space = spaces[space_index % spaces.Count];

    // render it
    string radiation_txt = vi.radiation > double.Epsilon
      ? Lib.BuildString(" <i>(", Lib.HumanReadableRadiationRate(vi.radiation * (1.0 - space.shielding)), ")</i>")
      : "";
    render_title(space.name.Length > 0 && spaces.Count > 1 ? Lib.Epsilon(space.name.ToUpper(), 20) : "VESSEL", ref space_index, spaces.Count);
    render_content("living space", QualityOfLife.LivingSpaceToString(space.living_space));
    render_content("entertainment", QualityOfLife.EntertainmentToString(space.entertainment));
    render_content("shielding", Lib.BuildString(Radiation.ShieldingToString(space.shielding), radiation_txt));
    render_space();
  }
Exemple #12
0
        void manageResqueMission(Vessel v)
        {
            // skip eva dead kerbals
            // rationale: getting the kerbal data will create it again, leading to spurious resque mission detection
            if (EVA.IsDead(v))
            {
                return;
            }

            // deal with resque missions
            foreach (ProtoCrewMember c in v.GetVesselCrew())
            {
                // get kerbal data
                kerbal_data kd = DB.KerbalData(c.name);

                // flag the kerbal as not resque at prelaunch
                if (v.situation == Vessel.Situations.PRELAUNCH)
                {
                    kd.resque = 0;
                }

                // if the kerbal belong to a resque mission
                if (kd.resque == 1)
                {
                    // give the vessel some supply
                    Lib.RequestResource(v, v.isEVA ? "EVA Propellant" : "MonoPropellant", -Settings.ResqueMonoPropellant);
                    Lib.RequestResource(v, "ElectricCharge", -Settings.ResqueElectricCharge);
                    Lib.RequestResource(v, "Food", -Settings.ResqueFood);
                    Lib.RequestResource(v, "Oxygen", -Settings.ResqueOxygen);

                    // flag the kerbal as non-resque
                    // note: enable life support mechanics for the kerbal
                    kd.resque = 0;

                    // show a message
                    Message.Post("We found <b>" + c.name + "</b>", (c.gender == ProtoCrewMember.Gender.Male ? "He" : "She") + "'s still alive!");
                }
            }
        }
Exemple #13
0
  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;
          }
        }
      }
    }
  }
Exemple #14
0
        void manageResqueMission(Vessel v)
        {
            // true if we detected this was a resque mission vessel
            bool detected = false;

            // deal with resque missions
            foreach (ProtoCrewMember c in v.GetVesselCrew())
            {
                // get kerbal data
                kerbal_data kd = DB.KerbalData(c.name);

                // flag the kerbal as not resque at prelaunch
                if (v.situation == Vessel.Situations.PRELAUNCH)
                {
                    kd.resque = 0;
                }

                // if the kerbal belong to a resque mission
                if (kd.resque == 1)
                {
                    // remember it
                    detected = true;

                    // flag the kerbal as non-resque
                    // note: enable life support mechanics for the kerbal
                    kd.resque = 0;

                    // show a message
                    Message.Post(Lib.BuildString("We found <b>", c.name, "</b>"), Lib.BuildString((c.gender == ProtoCrewMember.Gender.Male ? "He" : "She"), "'s still alive!"));
                }
            }

            // gift resources
            if (detected)
            {
                var reslib = PartResourceLibrary.Instance.resourceDefinitions;
                var parts  = Lib.GetPartsRecursively(v.rootPart);

                // give the vessel some monoprop
                string monoprop_name = v.isEVA ? "EVA Propellant" : detected_mods.RealFuels ? "Hydrazine" : "MonoPropellant";
                foreach (var part in parts)
                {
                    if (part.CrewCapacity > 0 || part.FindModuleImplementing <KerbalEVA>() != null)
                    {
                        if (part.Resources.list.Find(k => k.resourceName == monoprop_name) == null)
                        {
                            Lib.SetupResource(part, monoprop_name, 0.0, Settings.MonoPropellantOnResque);
                        }
                        break;
                    }
                }
                ResourceCache.Produce(v, monoprop_name, Settings.MonoPropellantOnResque);

                // give the vessel some supplies
                foreach (Rule r in rules)
                {
                    if (r.resource_name.Length == 0 || r.on_resque <= double.Epsilon || !reslib.Contains(r.resource_name))
                    {
                        continue;
                    }
                    foreach (var part in parts)
                    {
                        if (part.CrewCapacity > 0 || part.FindModuleImplementing <KerbalEVA>() != null)
                        {
                            if (part.Resources.list.Find(k => k.resourceName == r.resource_name) == null)
                            {
                                Lib.SetupResource(part, r.resource_name, 0.0, r.on_resque);
                            }
                            break;
                        }
                    }
                    ResourceCache.Produce(v, r.resource_name, r.on_resque);
                }
            }
        }
Exemple #15
0
  // implement life support mechanics
  public void FixedUpdate()
  {
    // 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;

    // do nothing if paused
    if (Lib.IsPaused()) return;

    // get time elapsed from last update
    double elapsed_s = TimeWarp.fixedDeltaTime;

    // for each vessel
    foreach(Vessel v in FlightGlobals.Vessels)
    {
      // skip invalid vessels
      if (!Lib.IsVessel(v)) continue;

      // skip dead eva kerbals
      if (EVA.IsDead(v)) continue;

      // get crew
      List<ProtoCrewMember> crew = v.loaded ? v.GetVesselCrew() : v.protoVessel.GetVesselCrew();

      // get vessel info from the cache
      vessel_info info = Cache.VesselInfo(v);

      // get temperature difference
      // note: for gameplay reasons, climatization doesn't consume anything landed at home
      bool landed_home = Lib.Landed(v) && v.mainBody == FlightGlobals.GetHomeBody();
      double temp_diff = landed_home ? 0.0 : Math.Abs(info.temperature - Settings.SurvivalTemperature);
      double temp_sign = landed_home ? 1.0 : info.temperature > Settings.SurvivalTemperature ? 1.0 : -1.0;

      // determine if inside breathable atmosphere
      bool breathable = BreathableAtmosphere(v);


      // 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;

        // consume ec for climate control
        double ec_required = temp_diff * Settings.ElectricChargePerSecond * elapsed_s;
        double ec_consumed = Lib.RequestResource(v, "ElectricCharge", ec_required);
        double ec_perc = ec_required > 0.0 ? ec_consumed / ec_required : 0.0;

        // reset kerbal temperature, if necessary
        if (ec_required <= double.Epsilon || ec_perc >= 1.0 - double.Epsilon)
        {
          kd.temperature = 0.0;
        }
        else
        {
          // degenerate kerbal temperature
          kd.temperature += Settings.TemperatureDegradationRate * elapsed_s * (1.0 - ec_perc) * temp_diff * temp_sign;

          // kill kerbal if necessary
          if (kd.temperature <= -Settings.TemperatureFatalThreshold)
          {
            Message.Post(Severity.fatality, KerbalEvent.climate_low, v, c);
            Kerbalism.Kill(v, c);
          }
          else if (kd.temperature >= Settings.TemperatureFatalThreshold)
          {
            Message.Post(Severity.fatality, KerbalEvent.climate_high, v, c);
            Kerbalism.Kill(v, c);
          }
          // show warnings
          else if (kd.temperature <= -Settings.TemperatureDangerThreshold && kd.msg_freezing < 2)
          {
            Message.Post(Severity.danger, KerbalEvent.climate_low, v, c);
            kd.msg_freezing = 2;
          }
          else if (kd.temperature <= -Settings.TemperatureWarningThreshold && kd.msg_freezing < 1)
          {
            Message.Post(Severity.warning, KerbalEvent.climate_low, v, c);
            kd.msg_freezing = 1;
          }
          else if (kd.temperature > -Settings.TemperatureWarningThreshold && kd.msg_freezing > 0)
          {
            Message.Post(Severity.relax, KerbalEvent.climate_low, v, c);
            kd.msg_freezing = 0;
          }
          else if (kd.temperature >= Settings.TemperatureDangerThreshold && kd.msg_burning < 2)
          {
            Message.Post(Severity.danger, KerbalEvent.climate_high, v, c);
            kd.msg_burning = 2;
          }
          else if (kd.temperature >= Settings.TemperatureWarningThreshold && kd.msg_burning < 1)
          {
            Message.Post(Severity.warning, KerbalEvent.climate_high, v, c);
            kd.msg_burning = 1;
          }
          else if (kd.temperature < Settings.TemperatureWarningThreshold && kd.msg_burning > 0)
          {
            Message.Post(Severity.relax, KerbalEvent.climate_high, v, c);
            kd.msg_burning = 0;
          }
        }


        // if its meal time for this kerbal
        kd.time_since_food += elapsed_s;
        if (kd.time_since_food >= Settings.MealFrequency)
        {
          // consume food
          const double food_required = Settings.FoodPerMeal;
          double food_consumed = Lib.RequestResource(v, "Food", food_required);
          double food_perc = food_consumed / food_required;

          // reset kerbal starvation, if necessary
          if (food_perc >= 1.0 - double.Epsilon)
          {
            kd.starved = 0.0;
            kd.time_since_food = 0.0;
          }
          else
          {
            // assure piecewise consumption
            Lib.RequestResource(v, "Food", -food_consumed);
            food_consumed = 0.0;

            // degenerate kerbal starvation
            kd.starved += Settings.StarvedDegradationRate * elapsed_s;

            // kill kerbal if necessary
            if (kd.starved >= Settings.StarvedFatalThreshold)
            {
              Message.Post(Severity.fatality, KerbalEvent.food, v, c);
              Kerbalism.Kill(v, c);
            }
            // show warnings
            else if (kd.starved >= Settings.StarvedDangerThreshold && kd.msg_starved < 2)
            {
              Message.Post(Severity.danger, KerbalEvent.food, v, c);
              kd.msg_starved = 2;
            }
            else if (kd.starved >= Settings.StarvedWarningThreshold && kd.msg_starved < 1)
            {
              Message.Post(Severity.warning, KerbalEvent.food, v, c);
              kd.msg_starved = 1;
            }
            else if (kd.starved < Settings.StarvedWarningThreshold && kd.msg_starved > 0)
            {
              Message.Post(Severity.relax, KerbalEvent.food, v, c);
              kd.msg_starved = 0;
            }
          }

          // produce waste
          Lib.RequestResource(v, "Waste", -food_consumed);
        }

        // if not inside a breathable atmosphere
        if (!breathable)
        {
          // consume oxygen
          double oxygen_required = Settings.OxygenPerSecond * elapsed_s;
          double oxygen_consumed = Lib.RequestResource(v, "Oxygen", oxygen_required);
          double oxygen_perc = oxygen_consumed / oxygen_required;

          // reset kerbal deprivation, if necessary
          if (oxygen_perc >= 1.0 - double.Epsilon)
          {
            kd.deprived = 0.0;
          }
          else
          {
            // degenerate kerbal deprivation
            kd.deprived += Settings.DeprivedDegradationRate * elapsed_s * (1.0 - oxygen_perc);

            // kill kerbal if necessary
            if (kd.deprived >= Settings.DeprivedFatalThreshold)
            {
              Message.Post(Severity.fatality, KerbalEvent.oxygen, v, c);
              Kerbalism.Kill(v, c);
            }
            // show warnings
            else if (kd.deprived >= Settings.DeprivedDangerThreshold && kd.msg_deprived < 2)
            {
              Message.Post(Severity.danger, KerbalEvent.oxygen, v, c);
              kd.msg_deprived = 2;
            }
            else if (kd.deprived >= Settings.DeprivedWarningThreshold && kd.msg_deprived < 1)
            {
              Message.Post(Severity.warning, KerbalEvent.oxygen, v, c);
              kd.msg_deprived = 1;
            }
            else if (kd.deprived < Settings.DeprivedWarningThreshold && kd.msg_deprived > 0)
            {
              Message.Post(Severity.relax, KerbalEvent.oxygen, v, c);
              kd.msg_deprived = 0;
            }
          }

          // produce CO2
          Lib.RequestResource(v, "CO2", -oxygen_consumed);
        }
      }
    }
  }
  // implement quality-of-life mechanics
  public void FixedUpdate()
  {
    // 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;

    // do nothing if paused
    if (Lib.IsPaused()) return;

    // get time elapsed from last update
    double elapsed_s = TimeWarp.fixedDeltaTime;

    // for each vessel
    foreach(Vessel v in FlightGlobals.Vessels)
    {
      // skip invalid vessels
      if (!Lib.IsVessel(v)) continue;

      // skip dead eva kerbals
      if (EVA.IsDead(v)) continue;

      // get crew
      List<ProtoCrewMember> crew = v.loaded ? v.GetVesselCrew() : v.protoVessel.GetVesselCrew();

      // calculate quality-of-life bonus
      double qol = Bonus(v);

      // 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;

        // accumulate stress
        kd.stressed += Settings.StressedDegradationRate * elapsed_s / (qol * Variance(c));

        // in case of breakdown
        if (kd.stressed >= Settings.StressedEventThreshold)
        {
          // trigger breakdown event
          Breakdown(v, c);

          // reset stress halfway between danger and event threshold
          kd.stressed = (Settings.StressedDangerThreshold + Settings.StressedEventThreshold) * 0.5;
        }
        // show warning messages
        else if (kd.stressed >= Settings.StressedDangerThreshold && kd.msg_stressed < 2)
        {
          Message.Post(Severity.danger, KerbalEvent.stress, v, c);
          kd.msg_stressed = 2;
        }
        else if (kd.stressed >= Settings.StressedWarningThreshold && kd.msg_stressed < 1)
        {
          Message.Post(Severity.warning, KerbalEvent.stress, v, c);
          kd.msg_stressed = 1;
        }
        // note: no recovery from stress
      }
    }
  }
Exemple #17
0
  public override void OnSave(ConfigNode node)
  {
    // save current version
    node.AddValue("version", current_version);

    ConfigNode kerbals_node = node.AddNode("kerbals");
    foreach(var p in kerbals)
    {
      kerbal_data kd = p.Value;
      ConfigNode kerbal_node = kerbals_node.AddNode(p.Key.Replace(" ", "___"));
      kerbal_node.AddValue("temperature", kd.temperature);
      kerbal_node.AddValue("starved", kd.starved);
      kerbal_node.AddValue("deprived", kd.deprived);
      kerbal_node.AddValue("stressed", kd.stressed);
      kerbal_node.AddValue("radiation", kd.radiation);
      kerbal_node.AddValue("time_since_food", kd.time_since_food);
      kerbal_node.AddValue("msg_freezing", kd.msg_freezing);
      kerbal_node.AddValue("msg_burning", kd.msg_burning);
      kerbal_node.AddValue("msg_starved", kd.msg_starved);
      kerbal_node.AddValue("msg_deprived", kd.msg_deprived);
      kerbal_node.AddValue("msg_stressed", kd.msg_stressed);
      kerbal_node.AddValue("msg_radiation", kd.msg_radiation);
      kerbal_node.AddValue("resque", kd.resque);
      kerbal_node.AddValue("disabled", kd.disabled);
    }

    ConfigNode vessels_node = node.AddNode("vessels");
    foreach(var p in vessels)
    {
      vessel_data vd = p.Value;
      ConfigNode vessel_node = vessels_node.AddNode(p.Key.ToString());
      vessel_node.AddValue("msg_ec", vd.msg_ec);
      vessel_node.AddValue("msg_food", vd.msg_food);
      vessel_node.AddValue("msg_oxygen", vd.msg_oxygen);
      vessel_node.AddValue("msg_signal", vd.msg_signal);
      vessel_node.AddValue("msg_belt", vd.msg_belt);
      vessel_node.AddValue("cfg_ec", vd.cfg_ec);
      vessel_node.AddValue("cfg_supply", vd.cfg_supply);
      vessel_node.AddValue("cfg_malfunction", vd.cfg_malfunction);
      vessel_node.AddValue("cfg_signal", vd.cfg_signal);
      vessel_node.AddValue("notes", vd.notes.Replace("\n", "$NEWLINE"));
      vessel_node.AddValue("group", vd.group);
    }

    ConfigNode bodies_node = node.AddNode("bodies");
    foreach(var p in bodies)
    {
      body_data bd = p.Value;
      ConfigNode body_node = bodies_node.AddNode(p.Key.Replace(" ", "___"));
      body_node.AddValue("storm_time", bd.storm_time);
      body_node.AddValue("storm_age", bd.storm_age);
      body_node.AddValue("storm_state", bd.storm_state);
      body_node.AddValue("msg_storm", bd.msg_storm);
    }

    ConfigNode notifications_node = node.AddNode("notifications");
    notifications_node.AddValue("next_death_report", notifications.next_death_report.ToString());
    notifications_node.AddValue("next_tutorial", notifications.next_tutorial.ToString());
    notifications_node.AddValue("death_counter", notifications.death_counter.ToString());
    notifications_node.AddValue("last_death_counter", notifications.last_death_counter.ToString());
    notifications_node.AddValue("first_belt_crossing", notifications.first_belt_crossing.ToString());
    notifications_node.AddValue("first_signal_loss", notifications.first_signal_loss.ToString());
    notifications_node.AddValue("first_malfunction", notifications.first_malfunction.ToString());
  }
Exemple #18
0
  public override void OnLoad(ConfigNode node)
  {
    // get version of the savegame
    // note: if there isn't a version this is either a new game, or the first public release (that didn't have versioning)
    string version = node.HasValue("version") ? node.GetValue("version") : node.HasNode("kerbals") ? "0.9.9.0" : current_version;


    kerbals.Clear();
    if (node.HasNode("kerbals"))
    {
      ConfigNode kerbals_node = node.GetNode("kerbals");
      foreach(ConfigNode kerbal_node in kerbals_node.GetNodes())
      {
        kerbal_data kd = new kerbal_data();
        kd.temperature     = Convert.ToDouble( kerbal_node.GetValue("temperature") );
        kd.starved         = Convert.ToDouble( kerbal_node.GetValue("starved") );
        kd.deprived        = Convert.ToDouble( kerbal_node.GetValue("deprived") );
        kd.stressed        = Convert.ToDouble( kerbal_node.GetValue("stressed") );
        kd.radiation       = Convert.ToDouble( kerbal_node.GetValue("radiation") );
        kd.time_since_food = Convert.ToDouble( kerbal_node.GetValue("time_since_food") );
        kd.msg_freezing    = Convert.ToUInt32( kerbal_node.GetValue("msg_freezing") );
        kd.msg_burning     = Convert.ToUInt32( kerbal_node.GetValue("msg_burning") );
        kd.msg_starved     = Convert.ToUInt32( kerbal_node.GetValue("msg_starved") );
        kd.msg_deprived    = Convert.ToUInt32( kerbal_node.GetValue("msg_deprived") );
        kd.msg_stressed    = Convert.ToUInt32( kerbal_node.GetValue("msg_stressed") );
        kd.msg_radiation   = Convert.ToUInt32( kerbal_node.GetValue("msg_radiation") );
        kd.resque          = Convert.ToUInt32( kerbal_node.GetValue("resque") );
        kd.disabled        = Convert.ToUInt32( kerbal_node.GetValue("disabled") );
        kerbals.Add(kerbal_node.name.Replace("___", " "), kd);
      }
    }

    vessels.Clear();
    if (node.HasNode("vessels"))
    {
      ConfigNode vessels_node = node.GetNode("vessels");
      foreach(ConfigNode vessel_node in vessels_node.GetNodes())
      {
        vessel_data vd = new vessel_data();
        vd.msg_ec          = Convert.ToUInt32( vessel_node.GetValue("msg_ec") );
        vd.msg_food        = Convert.ToUInt32( vessel_node.GetValue("msg_food") );
        vd.msg_oxygen      = Convert.ToUInt32( vessel_node.GetValue("msg_oxygen") );
        vd.msg_signal      = Convert.ToUInt32( vessel_node.GetValue("msg_signal") );
        vd.msg_belt        = Convert.ToUInt32( vessel_node.GetValue("msg_belt") );
        vd.cfg_ec          = Convert.ToUInt32( vessel_node.GetValue("cfg_ec") );
        vd.cfg_supply      = Convert.ToUInt32( vessel_node.GetValue("cfg_supply") );
        vd.cfg_malfunction = Convert.ToUInt32( vessel_node.GetValue("cfg_malfunction") );
        vd.cfg_signal      = Convert.ToUInt32( vessel_node.GetValue("cfg_signal") );
        vd.notes           = vessel_node.GetValue("notes").Replace("$NEWLINE", "\n");
        vd.group           = string.CompareOrdinal(version, "0.9.9.0") > 0 ? vessel_node.GetValue("group") : "NONE";
        vessels.Add(new Guid(vessel_node.name), vd);
      }
    }

    bodies.Clear();
    if (node.HasNode("bodies"))
    {
      ConfigNode bodies_node = node.GetNode("bodies");
      foreach(ConfigNode body_node in bodies_node.GetNodes())
      {
        body_data bd = new body_data();
        bd.storm_time  = Convert.ToDouble( body_node.GetValue("storm_time") );
        bd.storm_age   = Convert.ToDouble( body_node.GetValue("storm_age") );
        bd.storm_state = Convert.ToUInt32( body_node.GetValue("storm_state") );
        bd.msg_storm   = Convert.ToUInt32( body_node.GetValue("msg_storm") );
        bodies.Add(body_node.name.Replace("___", " "), bd);
      }
    }

    notifications = new notification_data();
    if (node.HasNode("notifications"))
    {
      ConfigNode notifications_node = node.GetNode("notifications");
      notifications.next_death_report   = Convert.ToUInt32( notifications_node.GetValue("next_death_report") );
      notifications.next_tutorial       = Convert.ToUInt32( notifications_node.GetValue("next_tutorial") );
      notifications.death_counter       = Convert.ToUInt32( notifications_node.GetValue("death_counter") );
      notifications.last_death_counter  = Convert.ToUInt32( notifications_node.GetValue("last_death_counter") );
      notifications.first_belt_crossing = Convert.ToUInt32( notifications_node.GetValue("first_belt_crossing") );
      notifications.first_signal_loss   = Convert.ToUInt32( notifications_node.GetValue("first_signal_loss") );
      notifications.first_malfunction   = Convert.ToUInt32( notifications_node.GetValue("first_malfunction") );
    }


    // if an old savegame was imported, log some debug info
    if (version != current_version) Lib.Log("savegame converted from version " + version);
  }
Exemple #19
0
  public override void OnSave(ConfigNode node)
  {
    // save current version
    node.AddValue("version", current_version);

    ConfigNode kerbals_node = node.AddNode("kerbals");
    foreach(var p in kerbals)
    {
      kerbal_data kd = p.Value;
      ConfigNode kerbal_node = kerbals_node.AddNode(p.Key.Replace(" ", "___"));
      kerbal_node.AddValue("resque", kd.resque);
      kerbal_node.AddValue("disabled", kd.disabled);
      kerbal_node.AddValue("living_space", kd.living_space);
      kerbal_node.AddValue("entertainment", kd.entertainment);
      kerbal_node.AddValue("shielding", kd.shielding);
      kerbal_node.AddValue("space_name", kd.space_name);
      var kmon_node = kerbal_node.AddNode("kmon");
      foreach(var q in kd.kmon)
      {
        var kmon_subnode = kmon_node.AddNode(q.Key);
        kmon_subnode.AddValue("problem", q.Value.problem);
        kmon_subnode.AddValue("message", q.Value.message);
        kmon_subnode.AddValue("time_since", q.Value.time_since);
      }
    }

    ConfigNode vessels_node = node.AddNode("vessels");
    foreach(var p in vessels)
    {
      vessel_data vd = p.Value;
      ConfigNode vessel_node = vessels_node.AddNode(p.Key.ToString());
      vessel_node.AddValue("msg_signal", vd.msg_signal);
      vessel_node.AddValue("msg_belt", vd.msg_belt);
      vessel_node.AddValue("cfg_ec", vd.cfg_ec);
      vessel_node.AddValue("cfg_supply", vd.cfg_supply);
      vessel_node.AddValue("cfg_signal", vd.cfg_signal);
      vessel_node.AddValue("cfg_malfunction", vd.cfg_malfunction);
      vessel_node.AddValue("cfg_storm", vd.cfg_storm);
      vessel_node.AddValue("cfg_highlights", vd.cfg_highlights);
      vessel_node.AddValue("cfg_showlink", vd.cfg_showlink);
      vessel_node.AddValue("notes", vd.notes.Replace("\n", "$NEWLINE"));
      vessel_node.AddValue("group", vd.group);
      var vmon_node = vessel_node.AddNode("vmon");
      foreach(var q in vd.vmon)
      {
        var vmon_subnode = vmon_node.AddNode(q.Key);
        vmon_subnode.AddValue("message", q.Value.message);
      }
      foreach(uint id in vd.scansat_id)
      {
        vessel_node.AddValue("scansat_id", id.ToString());
      }
    }

    ConfigNode bodies_node = node.AddNode("bodies");
    foreach(var p in bodies)
    {
      body_data bd = p.Value;
      ConfigNode body_node = bodies_node.AddNode(p.Key.Replace(" ", "___"));
      body_node.AddValue("storm_time", bd.storm_time);
      body_node.AddValue("storm_age", bd.storm_age);
      body_node.AddValue("storm_state", bd.storm_state);
      body_node.AddValue("msg_storm", bd.msg_storm);
    }

    ConfigNode notifications_node = node.AddNode("notifications");
    notifications_node.AddValue("next_death_report", notifications.next_death_report.ToString());
    notifications_node.AddValue("next_tutorial", notifications.next_tutorial.ToString());
    notifications_node.AddValue("death_counter", notifications.death_counter.ToString());
    notifications_node.AddValue("last_death_counter", notifications.last_death_counter.ToString());
    notifications_node.AddValue("first_belt_crossing", notifications.first_belt_crossing.ToString());
    notifications_node.AddValue("first_signal_loss", notifications.first_signal_loss.ToString());
    notifications_node.AddValue("first_malfunction", notifications.first_malfunction.ToString());
  }
Exemple #20
0
  public override void OnLoad(ConfigNode node)
  {
    // get version of the savegame
    // note: if there isn't a version this is either a new game, or the first public release (that didn't have versioning)
    string version = node.HasValue("version") ? node.GetValue("version") : node.HasNode("kerbals") ? "0.9.9.0" : current_version;

    // this is an unsupported version, attempt a total clean up and pray
    // note: currently unused
    if (string.CompareOrdinal(version, "0.9.9.0") < 0)
    {
      Lib.Log("loading save from unsupported version " + version);
      kerbals.Clear();
      vessels.Clear();
      bodies.Clear();
      notifications = new notification_data();
      return;
    }


    kerbals.Clear();
    if (node.HasNode("kerbals"))
    {
      ConfigNode kerbals_node = node.GetNode("kerbals");
      foreach(ConfigNode kerbal_node in kerbals_node.GetNodes())
      {
        kerbal_data kd = new kerbal_data();
        kd.resque          = Lib.ConfigValue(kerbal_node, "resque", 1u);
        kd.disabled        = Lib.ConfigValue(kerbal_node, "disabled", 0u);
        kd.living_space    = Lib.ConfigValue(kerbal_node, "living_space", 1.0); // since 0.9.9.4
        kd.entertainment   = Lib.ConfigValue(kerbal_node, "entertainment", 1.0); // since 0.9.9.4
        kd.shielding       = Lib.ConfigValue(kerbal_node, "shielding", 0.0); // since 0.9.9.4
        kd.space_name      = Lib.ConfigValue(kerbal_node, "space_name", ""); // since 0.9.9.4
        kd.kmon = new Dictionary<string, kmon_data>();
        if (kerbal_node.HasNode("kmon")) // since 0.9.9.5
        {
          foreach(var cfg in kerbal_node.GetNode("kmon").GetNodes())
          {
            kmon_data kmon = new kmon_data();
            kmon.problem = Lib.ConfigValue(cfg, "problem", 0.0);
            kmon.message = Lib.ConfigValue(cfg, "message", 0u);
            kmon.time_since = Lib.ConfigValue(cfg, "time_since", 0.0);
            kd.kmon.Add(cfg.name, kmon);
          }
        }
        kerbals.Add(kerbal_node.name.Replace("___", " "), kd);
      }
    }

    vessels.Clear();
    if (node.HasNode("vessels"))
    {
      ConfigNode vessels_node = node.GetNode("vessels");
      foreach(ConfigNode vessel_node in vessels_node.GetNodes())
      {
        vessel_data vd = new vessel_data();
        vd.msg_signal      = Lib.ConfigValue(vessel_node, "msg_signal", 0u);
        vd.msg_belt        = Lib.ConfigValue(vessel_node, "msg_belt", 0u);
        vd.cfg_ec          = Lib.ConfigValue(vessel_node, "cfg_ec", 1u);
        vd.cfg_supply      = Lib.ConfigValue(vessel_node, "cfg_supply", 1u);
        vd.cfg_signal      = Lib.ConfigValue(vessel_node, "cfg_signal", 1u);
        vd.cfg_malfunction = Lib.ConfigValue(vessel_node, "cfg_malfunction", 1u);
        vd.cfg_storm       = Lib.ConfigValue(vessel_node, "cfg_storm", 1u); // since 0.9.9.5
        vd.cfg_highlights  = Lib.ConfigValue(vessel_node, "cfg_highlights", 1u); // since 0.9.9.5
        vd.cfg_showlink    = Lib.ConfigValue(vessel_node, "cfg_showlink", 0u); // since 0.9.9.8
        vd.notes           = Lib.ConfigValue(vessel_node, "notes", "").Replace("$NEWLINE", "\n"); // since 0.9.9.1
        vd.group           = Lib.ConfigValue(vessel_node, "group", "NONE"); // since 0.9.9.1
        vd.vmon = new Dictionary<string, vmon_data>();
        if (vessel_node.HasNode("vmon")) // since 0.9.9.5
        {
          foreach(var cfg in vessel_node.GetNode("vmon").GetNodes())
          {
            vmon_data vmon = new vmon_data();
            vmon.message = Lib.ConfigValue(cfg, "message", 0u);
            vd.vmon.Add(cfg.name, vmon);
          }
        }
        vd.scansat_id = new List<uint>();
        foreach(string s in vessel_node.GetValues("scansat_id")) // since 0.9.9.5
        {
          vd.scansat_id.Add(Convert.ToUInt32(s));
        }
        vessels.Add(new Guid(vessel_node.name), vd);
      }
    }

    bodies.Clear();
    if (node.HasNode("bodies"))
    {
      ConfigNode bodies_node = node.GetNode("bodies");
      foreach(ConfigNode body_node in bodies_node.GetNodes())
      {
        body_data bd = new body_data();
        bd.storm_time  = Lib.ConfigValue(body_node, "storm_time", 0.0);
        bd.storm_age   = Lib.ConfigValue(body_node, "storm_age", 0.0);
        bd.storm_state = Lib.ConfigValue(body_node, "storm_state", 0u);
        bd.msg_storm   = Lib.ConfigValue(body_node, "msg_storm", 0u);
        bodies.Add(body_node.name.Replace("___", " "), bd);
      }
    }

    notifications = new notification_data();
    if (node.HasNode("notifications"))
    {
      ConfigNode n_node = node.GetNode("notifications");
      notifications.next_death_report   = Lib.ConfigValue(n_node, "next_death_report", 0u);
      notifications.next_tutorial       = Lib.ConfigValue(n_node, "next_tutorial", 0u);
      notifications.death_counter       = Lib.ConfigValue(n_node, "death_counter", 0u);
      notifications.last_death_counter  = Lib.ConfigValue(n_node, "last_death_counter", 0u);
      notifications.first_belt_crossing = Lib.ConfigValue(n_node, "first_belt_crossing", 0u);
      notifications.first_signal_loss   = Lib.ConfigValue(n_node, "first_signal_loss", 0u);
      notifications.first_malfunction   = Lib.ConfigValue(n_node, "first_malfunction", 0u);
    }


    // versions before 0.9.9.5 used a different structure to remember message sent
    // mute the message system for a few seconds to avoid the user being bombarded by messages
    if (string.CompareOrdinal(version, "0.9.9.5") < 0)
    {
      Message.MuteInternal();
      base.StartCoroutine(CallbackUtil.DelayedCallback(10.0f, Message.UnmuteInternal));
    }


    // versions before 0.9.9.5 didn't have profiles, and didn't use CRP food/oxygen values
    // scale all amounts of them in existing vessels, to not break savegames
    if (string.CompareOrdinal(version, "0.9.9.5") < 0)
    {
      foreach(Vessel v in FlightGlobals.Vessels.FindAll(k => !k.loaded))
      {
        foreach(var part in v.protoVessel.protoPartSnapshots)
        {
          var food = part.resources.Find(k => k.resourceName == "Food");
          if (food != null)
          {
            food.resourceValues.SetValue("amount", (Lib.ConfigValue(food.resourceValues, "amount", 0.0f) * 10.0f).ToString());
            food.resourceValues.SetValue("maxAmount", (Lib.ConfigValue(food.resourceValues, "maxAmount", 0.0f) * 10.0f).ToString());
          }

          var oxygen = part.resources.Find(k => k.resourceName == "Oxygen");
          if (oxygen != null)
          {
            oxygen.resourceValues.SetValue("amount", (Lib.ConfigValue(oxygen.resourceValues, "amount", 0.0f) * 1000.0f).ToString());
            oxygen.resourceValues.SetValue("maxAmount", (Lib.ConfigValue(oxygen.resourceValues, "maxAmount", 0.0f) * 1000.0f).ToString());
          }
        }
      }
    }


    // if an old savegame was imported, log some debug info
    if (version != current_version) Lib.Log("savegame converted from version " + version);
  }
Exemple #21
0
        // implement radiation mechanics
        public void FixedUpdate()
        {
            // 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;
            }

            // do nothing if paused
            if (Lib.IsPaused())
            {
                return;
            }

            // get time elapsed from last update
            double elapsed_s = TimeWarp.fixedDeltaTime;

            // for each vessel
            foreach (Vessel v in FlightGlobals.Vessels)
            {
                // skip invalid vessels
                if (!Lib.IsVessel(v))
                {
                    continue;
                }

                // skip dead eva kerbals
                if (EVA.IsDead(v))
                {
                    continue;
                }

                // get crew
                List <ProtoCrewMember> crew = v.loaded ? v.GetVesselCrew() : v.protoVessel.GetVesselCrew();

                // get crew count
                int crew_count = Lib.CrewCount(v);

                // get vessel info from the cache
                vessel_info info = Cache.VesselInfo(v);

                // get vessel data
                vessel_data vd = DB.VesselData(v.id);


                // belt warnings
                // note: we only show it for manned vesssels, but the first time we also show it for probes
                if (crew_count > 0 || DB.NotificationData().first_belt_crossing == 0)
                {
                    if (InsideBelt(v) && vd.msg_belt < 1)
                    {
                        Message.Post("<b>" + v.vesselName + "</b> is crossing <i>" + v.mainBody.bodyName + " radiation belt</i>", "Exposed to extreme radiation");
                        vd.msg_belt = 1;
                        DB.NotificationData().first_belt_crossing = 1; //< record first belt crossing
                    }
                    else if (!InsideBelt(v) && vd.msg_belt > 0)
                    {
                        // no message after crossing the belt
                        vd.msg_belt = 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;
                    }

                    // accumulate radiation
                    kd.radiation += info.radiation * elapsed_s;

                    // kill kerbal if necessary
                    if (kd.radiation >= Settings.RadiationFatalThreshold)
                    {
                        Message.Post(Severity.fatality, KerbalEvent.radiation, v, c);
                        Kerbalism.Kill(v, c);
                    }
                    // show warnings
                    else if (kd.radiation >= Settings.RadiationDangerThreshold && kd.msg_radiation < 2)
                    {
                        Message.Post(Severity.danger, KerbalEvent.radiation, v, c);
                        kd.msg_radiation = 2;
                    }
                    else if (kd.radiation >= Settings.RadiationWarningThreshold && kd.msg_radiation < 1)
                    {
                        Message.Post(Severity.danger, KerbalEvent.radiation, v, c);
                        kd.msg_radiation = 1;
                    }
                    // note: no recovery from radiations
                }
            }
        }
Exemple #22
0
  void render_info()
  {
    // find vessel
    Vessel v = FlightGlobals.Vessels.Find(k => k.id == vessel_id);

    // forget vessel if it doesn't exist anymore, or if its a dead eva kerbal
    if (v == null || EVA.IsDead(v)) { vessel_id = Guid.Empty; return; }

    // get info from the cache
    vessel_info vi = Cache.VesselInfo(v);

    render_title("ENVIRONMENT");
    render_content("Temperature:\t", Lib.HumanReadableTemp(vi.temperature));
    render_content("Radiation:\t", Lib.HumanReadableRadiationRate(vi.env_radiation));
    render_content("Atmosphere:\t", v.mainBody.atmosphere ? " yes" + (vi.breathable ? " <i>(breathable)</i>" : "") : "no");
    render_space();

    // render supplies
    if (Kerbalism.supply_rules.Count > 0 || Kerbalism.ec_rule != null)
    {
      render_title("SUPPLIES");
      if (Kerbalism.ec_rule != null)
      {
        var vmon = vi.vmon[Kerbalism.ec_rule.name];
        render_content(fix_title("Battery:"), vmon.level > double.Epsilon ? Lib.HumanReadableDuration(vmon.depletion) : "none");
      }
      if (Lib.CrewCapacity(v) > 0)
      {
        foreach(Rule r in Kerbalism.supply_rules)
        {
          var vmon = vi.vmon[r.name];
          render_content(fix_title(r.resource_name + ":"), vmon.level > double.Epsilon ? Lib.HumanReadableDuration(vmon.depletion) : "none");
        }
      }
      render_space();
    }


    // get crew
    var crew = v.loaded ? v.GetVesselCrew() : v.protoVessel.GetVesselCrew();

    // do not render internal spaces info for eva vessels
    if (!v.isEVA)
    {
      // collect set of spaces
      Dictionary<string, space_details> spaces = new Dictionary<string, space_details>();
      foreach(var c in crew)
      {
        kerbal_data kd = DB.KerbalData(c.name);
        if (!spaces.ContainsKey(kd.space_name))
        {
          space_details sd = new space_details();
          sd.living_space = kd.living_space;
          sd.entertainment = kd.entertainment;
          sd.shielding = kd.shielding;
          spaces.Add(kd.space_name, sd);
        }
        ++(spaces[kd.space_name].crew_count);
      }

      // for each space
      foreach(var space in spaces)
      {
        string space_name = space.Key;
        space_details det = space.Value;

        string radiation_txt = vi.env_radiation > double.Epsilon
          ? " <i>(" + Lib.HumanReadableRadiationRate(vi.env_radiation * (1.0 - det.shielding)) + ")</i>"
          : "";

        render_title(space_name.Length > 0 ? space_name.ToUpper() : v.isEVA ? "EVA" : "VESSEL");
        render_content("Living space:\t", QualityOfLife.LivingSpaceToString(det.living_space));
        render_content("Entertainment:\t", QualityOfLife.EntertainmentToString(det.entertainment));
        render_content("Shielding:\t", Radiation.ShieldingToString(det.shielding) + radiation_txt);
        render_space();
      }
    }

    // for each kerbal
    if (Kerbalism.rules.Count > 0)
    {
      foreach(var c in crew)
      {
        kerbal_data kd = DB.KerbalData(c.name);
        render_title(c.name.ToUpper());
        foreach(var q in Kerbalism.rules)
        {
          Rule r = q.Value;
          if (r.degeneration > double.Epsilon)
          {
            var kmon = DB.KmonData(c.name, r.name);
            var bar = Lib.ProgressBar(23, kmon.problem, r.warning_threshold, r.danger_threshold, r.fatal_threshold, kd.disabled > 0 ? "cyan" : "");
            render_content(fix_title(r.name + ":"), bar);
          }
        }
        if (kd.space_name.Length > 0 && !v.isEVA) render_content("Inside:\t\t", kd.space_name);
        if (kd.disabled > 0) render_content("Hibernated:\t", "yes");
        render_space();
      }
    }

    // for each greenhouse
    var greenhouses = Greenhouse.GetGreenhouses(v);
    foreach(var greenhouse in greenhouses)
    {
      render_title("GREENHOUSE");
      render_content("Lighting:\t\t", (greenhouse.lighting * 100.0).ToString("F0") + "%");
      render_content("Growth:\t\t", (greenhouse.growth * 100.0).ToString("F0") + "%");
      render_content("Harvest:\t\t", Lib.HumanReadableDuration(greenhouse.growing > double.Epsilon ? 1.0 / greenhouse.growing : 0.0));
      render_space();
    }
  }
Exemple #23
0
  public override void OnSave(ConfigNode node)
  {
    // save current version
    node.AddValue("version", current_version);

    ConfigNode kerbals_node = node.AddNode("kerbals");
    foreach(var p in kerbals)
    {
      kerbal_data kd = p.Value;
      ConfigNode kerbal_node = kerbals_node.AddNode(p.Key.Replace(" ", "___"));
      kerbal_node.AddValue("resque", kd.resque);
      kerbal_node.AddValue("disabled", kd.disabled);
      kerbal_node.AddValue("living_space", kd.living_space);
      kerbal_node.AddValue("entertainment", kd.entertainment);
      kerbal_node.AddValue("shielding", kd.shielding);
      kerbal_node.AddValue("space_name", kd.space_name);
      kerbal_node.AddValue("eva_dead", kd.eva_dead);
      kerbal_node.AddValue("has_helmet", kd.has_helmet);
      var kmon_node = kerbal_node.AddNode("kmon");
      foreach(var q in kd.kmon)
      {
        var kmon_subnode = kmon_node.AddNode(q.Key);
        kmon_subnode.AddValue("problem", q.Value.problem);
        kmon_subnode.AddValue("message", q.Value.message);
        kmon_subnode.AddValue("time_since", q.Value.time_since);
      }
    }

    ConfigNode vessels_node = node.AddNode("vessels");
    foreach(var p in vessels)
    {
      vessel_data vd = p.Value;
      ConfigNode vessel_node = vessels_node.AddNode(p.Key.ToString());
      vessel_node.AddValue("msg_signal", vd.msg_signal);
      vessel_node.AddValue("msg_belt", vd.msg_belt);
      vessel_node.AddValue("cfg_ec", vd.cfg_ec);
      vessel_node.AddValue("cfg_supply", vd.cfg_supply);
      vessel_node.AddValue("cfg_signal", vd.cfg_signal);
      vessel_node.AddValue("cfg_malfunction", vd.cfg_malfunction);
      vessel_node.AddValue("cfg_storm", vd.cfg_storm);
      vessel_node.AddValue("cfg_highlights", vd.cfg_highlights);
      vessel_node.AddValue("cfg_showlink", vd.cfg_showlink);
      vessel_node.AddValue("storm_time", vd.storm_time);
      vessel_node.AddValue("storm_age", vd.storm_age);
      vessel_node.AddValue("storm_state", vd.storm_state);
      vessel_node.AddValue("group", vd.group);
      var vmon_node = vessel_node.AddNode("vmon");
      foreach(var q in vd.vmon)
      {
        var vmon_subnode = vmon_node.AddNode(q.Key);
        vmon_subnode.AddValue("message", q.Value.message);
      }
      foreach(uint id in vd.scansat_id)
      {
        vessel_node.AddValue("scansat_id", id.ToString());
      }
      ConfigNode computer_node = vessel_node.AddNode("computer");
      vd.computer.save(computer_node);
    }

    ConfigNode bodies_node = node.AddNode("bodies");
    foreach(var p in bodies)
    {
      body_data bd = p.Value;
      ConfigNode body_node = bodies_node.AddNode(p.Key.Replace(" ", "___"));
      body_node.AddValue("storm_time", bd.storm_time);
      body_node.AddValue("storm_age", bd.storm_age);
      body_node.AddValue("storm_state", bd.storm_state);
      body_node.AddValue("msg_storm", bd.msg_storm);
    }

    ConfigNode landmarks_node = node.AddNode("landmarks");
    landmarks_node.AddValue("belt_crossing", landmarks.belt_crossing);
    landmarks_node.AddValue("manned_orbit", landmarks.manned_orbit);
    landmarks_node.AddValue("space_harvest", landmarks.space_harvest);
  }
Exemple #24
0
  public override void OnLoad(ConfigNode node)
  {
    // reset caches to deal with minor issues on flight revert and scene changes
    Engine.ResetCache();

    // get version of the savegame
    // note: if there isn't a version this is either a new game, or the first public release (that didn't have versioning)
    string version = node.HasValue("version") ? node.GetValue("version") : node.HasNode("kerbals") ? "0.9.9.0" : current_version;

    // this is an unsupported version, attempt a total clean up and pray
    if (string.CompareOrdinal(version, "0.9.9.5") < 0)
    {
      Lib.Log("loading save from unsupported version " + version);
      kerbals.Clear();
      vessels.Clear();
      bodies.Clear();
      landmarks = new landmarks_data();
      return;
    }

    kerbals.Clear();
    if (node.HasNode("kerbals"))
    {
      ConfigNode kerbals_node = node.GetNode("kerbals");
      foreach(ConfigNode kerbal_node in kerbals_node.GetNodes())
      {
        kerbal_data kd = new kerbal_data();
        kd.resque          = Lib.ConfigValue(kerbal_node, "resque", 1u);
        kd.disabled        = Lib.ConfigValue(kerbal_node, "disabled", 0u);
        kd.living_space    = Lib.ConfigValue(kerbal_node, "living_space", 1.0);
        kd.entertainment   = Lib.ConfigValue(kerbal_node, "entertainment", 1.0);
        kd.shielding       = Lib.ConfigValue(kerbal_node, "shielding", 0.0);
        kd.space_name      = Lib.ConfigValue(kerbal_node, "space_name", "");
        kd.eva_dead        = Lib.ConfigValue(kerbal_node, "eva_dead", false);
        kd.has_helmet      = Lib.ConfigValue(kerbal_node, "has_helmet", false);
        if (kerbal_node.HasNode("kmon"))
        {
          foreach(var cfg in kerbal_node.GetNode("kmon").GetNodes())
          {
            kmon_data kmon = new kmon_data();
            kmon.problem = Lib.ConfigValue(cfg, "problem", 0.0);
            kmon.message = Lib.ConfigValue(cfg, "message", 0u);
            kmon.time_since = Lib.ConfigValue(cfg, "time_since", 0.0);
            kd.kmon.Add(cfg.name, kmon);
          }
        }
        kerbals.Add(kerbal_node.name.Replace("___", " "), kd);
      }
    }

    vessels.Clear();
    if (node.HasNode("vessels"))
    {
      ConfigNode vessels_node = node.GetNode("vessels");
      foreach(ConfigNode vessel_node in vessels_node.GetNodes())
      {
        vessel_data vd = new vessel_data();
        vd.msg_signal      = Lib.ConfigValue(vessel_node, "msg_signal", 0u);
        vd.msg_belt        = Lib.ConfigValue(vessel_node, "msg_belt", 0u);
        vd.cfg_ec          = Lib.ConfigValue(vessel_node, "cfg_ec", 1u);
        vd.cfg_supply      = Lib.ConfigValue(vessel_node, "cfg_supply", 1u);
        vd.cfg_signal      = Lib.ConfigValue(vessel_node, "cfg_signal", 1u);
        vd.cfg_malfunction = Lib.ConfigValue(vessel_node, "cfg_malfunction", 1u);
        vd.cfg_storm       = Lib.ConfigValue(vessel_node, "cfg_storm", 1u);
        vd.cfg_highlights  = Lib.ConfigValue(vessel_node, "cfg_highlights", 1u);
        vd.cfg_showlink    = Lib.ConfigValue(vessel_node, "cfg_showlink", 0u);
        vd.storm_time      = Lib.ConfigValue(vessel_node, "storm_time", 0.0);
        vd.storm_age       = Lib.ConfigValue(vessel_node, "storm_age", 0.0);
        vd.storm_state     = Lib.ConfigValue(vessel_node, "storm_state", 0u);
        vd.group           = Lib.ConfigValue(vessel_node, "group", "NONE");

        if (vessel_node.HasNode("vmon"))
        {
          foreach(var cfg in vessel_node.GetNode("vmon").GetNodes())
          {
            vmon_data vmon = new vmon_data();
            vmon.message = Lib.ConfigValue(cfg, "message", 0u);
            vd.vmon.Add(cfg.name, vmon);
          }
        }
        foreach(string s in vessel_node.GetValues("scansat_id"))
        {
          vd.scansat_id.Add(Lib.Parse.ToUInt(s));
        }
        if (vessel_node.HasNode("computer"))
        {
          vd.computer = new Computer(vessel_node.GetNode("computer"));
        }
        // import old notes into new computer system
        else if (string.CompareOrdinal(version, "1.1.1.0") < 0)
        {
          vd.computer.files["doc/notes"].content = Lib.ConfigValue(vessel_node, "notes", "").Replace("$NEWLINE", "\n");
        }
        vessels.Add(new Guid(vessel_node.name), vd);
      }
    }

    bodies.Clear();
    if (node.HasNode("bodies"))
    {
      ConfigNode bodies_node = node.GetNode("bodies");
      foreach(ConfigNode body_node in bodies_node.GetNodes())
      {
        body_data bd = new body_data();
        bd.storm_time  = Lib.ConfigValue(body_node, "storm_time", 0.0);
        bd.storm_age   = Lib.ConfigValue(body_node, "storm_age", 0.0);
        bd.storm_state = Lib.ConfigValue(body_node, "storm_state", 0u);
        bd.msg_storm   = Lib.ConfigValue(body_node, "msg_storm", 0u);
        bodies.Add(body_node.name.Replace("___", " "), bd);
      }
    }

    landmarks = new landmarks_data();
    if (node.HasNode("landmarks"))
    {
      ConfigNode landmarks_node = node.GetNode("landmarks");
      landmarks.belt_crossing = Lib.ConfigValue(landmarks_node, "belt_crossing", 0u);
      landmarks.manned_orbit  = Lib.ConfigValue(landmarks_node, "manned_orbit", 0u);
      landmarks.space_harvest = Lib.ConfigValue(landmarks_node, "space_harvest", 0u);
    }
    // import old notifications data into new landmark system
    else if (string.CompareOrdinal(version, "1.1.2.0") < 0)
    {
      if (node.HasNode("notifications"))
      {
        ConfigNode n_node = node.GetNode("notifications");
        landmarks.belt_crossing = Lib.ConfigValue(n_node, "first_belt_crossing", 0u);
        landmarks.manned_orbit  = Lib.ConfigValue(n_node, "manned_orbit_contract", 0u);
        landmarks.space_harvest = Lib.ConfigValue(n_node, "first_space_harvest", 0u);
      }
    }

    // if an old savegame was imported, log some debug info
    if (version != current_version) Lib.Log("savegame converted from version " + version);
  }