Beispiel #1
0
        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);
        }
Beispiel #2
0
  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);
  }
Beispiel #3
0
        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();
        }
Beispiel #4
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;
          }
        }
      }
    }
  }