Пример #1
0
        public void FixedUpdate()
        {
            // do nothing in the editor
            if (Lib.IsEditor())
            {
                return;
            }

            // if enabled, and there is ec consumption
            if (running && ec_rate > double.Epsilon)
            {
                // get resource cache
                Resource_info ec = ResourceCache.Info(vessel, "ElectricCharge");

                // consume EC
                ec.Consume(ec_rate * Kerbalism.elapsed_s, "emitter");
            }
        }
Пример #2
0
  public void SetupRescue(Vessel v)
  {
    // do nothing if no resource on resque
    if (on_rescue <= double.Epsilon) return;

    // if the vessel has no capacity
    if (ResourceCache.Info(v, resource).capacity <= double.Epsilon)
    {
      // find the first useful part
      Part p = v.parts.Find(k => k.CrewCapacity > 0 || k.FindModuleImplementing<KerbalEVA>() != null);

      // add capacity
      Lib.AddResource(p, resource, 0.0, on_rescue);
    }

    // add resource to the vessel
    ResourceCache.Produce(v, resource, on_rescue);
  }
Пример #3
0
        public void FixedUpdate()
        {
            // do nothing in the editor
            if (Lib.IsEditor())
            {
                return;
            }

            // if has any animation playing, consume energy.
            if (Is_consuming_energy())
            {
                // get resource handler
                Resource_info ec = ResourceCache.Info(vessel, "ElectricCharge");

                // consume ec
                ec.Consume(ec_rate * Kerbalism.elapsed_s);
            }
        }
Пример #4
0
  void indicator_ec(Panel p, Vessel v)
  {
    Texture image;
    string tooltip;

    resource_info ec = ResourceCache.Info(v, "ElectricCharge");

    tooltip = ec.capacity > 0.0 ? "EC: " + Lib.HumanReadablePerc(ec.level) : "";
    image = Icons.battery_white;

    Supply supply = Profile.supplies.Find(k => k.resource == "ElectricCharge");
    double low_threshold = supply != null ? supply.low_threshold : 0.15;

    if (ec.level <= 0.005) image = Icons.battery_red;
    else if (ec.level <= low_threshold) image = Icons.battery_yellow;


    p.icon(image, tooltip);
  }
Пример #5
0
        void Indicator_Supplies(Panel p, Vessel v, Vessel_Info vi)
        {
            List <string> tooltips     = new List <string>();
            uint          max_severity = 0;

            if (vi.crew_count > 0)
            {
                foreach (Supply supply in Profile.supplies.FindAll(k => k.resource != "ElectricCharge"))
                {
                    Resource_Info res       = ResourceCache.Info(v, supply.resource);
                    double        depletion = res.Depletion(vi.crew_count);

                    if (res.capacity > double.Epsilon)
                    {
                        if (tooltips.Count == 0)
                        {
                            tooltips.Add("<align=left /><b>name\t\tlevel\tduration</b>");
                        }

                        tooltips.Add(Lib.BuildString
                                     (
                                         res.level <= 0.005 ? "<color=#ff0000>" : res.level <= supply.low_threshold ? "<color=#ffff00>" : "<color=#cccccc>",
                                         supply.resource,
                                         supply.resource != "Ammonia" ? "\t\t" : "\t", //< hack: make ammonia fit damn it
                                         Lib.HumanReadablePerc(res.level), "\t",
                                         depletion <= double.Epsilon ? "depleted" : Lib.HumanReadableDuration(depletion),
                                         "</color>"
                                     ));

                        uint severity = res.level <= 0.005 ? 2u : res.level <= supply.low_threshold ? 1u : 0;
                        max_severity = Math.Max(max_severity, severity);
                    }
                }
            }

            Texture image = max_severity == 2
        ? Icons.box_red
        : max_severity == 1
        ? Icons.box_yellow
        : Icons.box_white;

            p.SetIcon(image, string.Join("\n", tooltips.ToArray()));
        }
Пример #6
0
        State venting()
        {
            // in flight
            if (Lib.IsFlight())
            {
                // shortcuts
                resource_info vessel_atmo = ResourceCache.Info(vessel, "Atmosphere");
                PartResource  hab_atmo    = part.Resources["Atmosphere"];

                // get amount of atmosphere in part
                double hab_amount = hab_atmo.amount;

                // venting succeeded if the amount reached zero
                if (hab_amount <= double.Epsilon)
                {
                    return(State.disabled);
                }

                // determine venting speed
                double amount = volume * equalize_speed * Kerbalism.elapsed_s;

                // consume from the part, clamp amount to what's available in the part
                amount           = Math.Min(amount, hab_atmo.amount);
                hab_atmo.amount -= amount;

                // produce in all enabled habs in the vessel
                // (attempt recovery, but dump overboard if there is no capacity left)
                vessel_atmo.Produce(amount);

                // venting still in progress
                return(State.venting);
            }
            // in the editors
            else
            {
                // set amount to zero
                part.Resources["Atmosphere"].amount = 0.0;

                // return new state
                return(State.disabled);
            }
        }
Пример #7
0
        public void FixedUpdate()
        {
            if (Lib.IsEditor())
            {
                return;
            }

            if (ResourceCache.Info(vessel, "ElectricCharge").amount <= double.Epsilon && running)
            {
                Events["Toggle"].Invoke();
            }

            if (deployed && running && issue.Length == 0)
            {
                Resource_Recipe recipe = new Resource_Recipe();
                recipe.Input("ElectricCharge", ec_rate * Kerbalism.elapsed_s);
                recipe.Output(resource, rate * Kerbalism.elapsed_s, true);
                ResourceCache.Transform(vessel, recipe);
            }
        }
Пример #8
0
        public virtual void FixedUpdate()
        {
            if (FixGame(thisModule))
            {
                return;
            }

            hasEC = ResourceCache.Info(part.vessel, "ElectricCharge").amount > double.Epsilon;
            if (GetIsActive())
            {
                part.ModulesOnUpdate();
                // get resource cache
                vessel_resources resources = ResourceCache.Get(part.vessel);
                resources.Consume(part.vessel, "ElectricCharge", actualECCost * Kerbalism.elapsed_s);
            }
            else
            {
                actualECCost = 0;
            }
        }
Пример #9
0
        public static void Update(Vessel v)
        {
            // do nothing if not an eva kerbal
            if (!v.isEVA)
            {
                return;
            }

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

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

            // determine if headlamps need ec
            // - not required if there is no EC capacity in eva kerbal (no ec supply in profile)
            // - not required if no EC cost for headlamps is specified (set by the user)
            bool need_ec = ec.capacity > double.Epsilon && Settings.HeadLampsCost > double.Epsilon;

            // consume EC for the headlamps
            if (need_ec && kerbal.lampOn)
            {
                ec.Consume(Settings.HeadLampsCost * Kerbalism.elapsed_s);
            }

            // force the headlamps on/off
            HeadLamps(kerbal, kerbal.lampOn && (!need_ec || ec.amount > double.Epsilon));

            // if dead
            if (IsDead(v))
            {
                // enforce freezed state
                Freeze(kerbal);

                // disable modules
                DisableModules(kerbal);

                // remove plant flag action
                kerbal.flagItems = 0;
            }
        }
Пример #10
0
  void problem_recyclers(Vessel v, List<Recycler.partial_data> recyclers, ref List<Texture> icons, ref List<string> tooltips)
  {
    if (recyclers.Count == 0) return;

    bool no_ec_left = ResourceCache.Info(v, "ElectricCharge").amount <= double.Epsilon;
    bool disabled = false;
    foreach(var recycler in recyclers)
    {
      disabled |= !recycler.is_enabled;
    }
    if (no_ec_left)
    {
      icons.Add(icon_scrubber_danger);
      tooltips.Add("Recycler has no power");
    }
    else if (disabled)
    {
      icons.Add(icon_scrubber_warning);
      tooltips.Add("Recycler disabled");
    }
  }
Пример #11
0
 void render_supplies(Vessel v, vessel_info vi)
 {
   if (Kerbalism.supply_rules.Count > 0 || Kerbalism.ec_rule != null)
   {
     render_title("SUPPLIES");
     if (Kerbalism.ec_rule != null)
     {
       resource_info res = ResourceCache.Info(v, "ElectricCharge");
       render_content("battery", res.level > double.Epsilon ? Lib.HumanReadableDuration(Kerbalism.ec_rule.Depletion(v, res)) : "none", res.rate);
     }
     if (vi.crew_capacity > 0)
     {
       foreach(Rule r in Kerbalism.supply_rules)
       {
         resource_info res = ResourceCache.Info(v, r.resource_name);
         render_content(r.resource_name.AddSpacesOnCaps().ToLower(), res.level > double.Epsilon ? Lib.HumanReadableDuration(r.Depletion(v, res)) : "none", res.rate);
       }
     }
     render_space();
   }
 }
Пример #12
0
  void IScienceDataTransmitter.TransmitData(List<ScienceData> dataQueue)
  {
    // if there is no signal
    if (!can_transmit)
    {
      // show a message to the user
      Message.Post(Severity.warning, "No signal", "We can't send the data");

      // return data to the containers
      ReturnData(dataQueue);

      // do not transmit the data
      return;
    }

    // calculate total ec cost of transmission
    double total_amount = 0.0;
    foreach(ScienceData sd in dataQueue) total_amount += sd.dataAmount;
    double total_cost = total_amount * this.packetResourceCost;

    // if there is no EC to transmit the data
    // note: comparing against amount in previous simulation step
    if (total_cost > ResourceCache.Info(vessel, "ElectricCharge").amount)
    {
      // show a message to the user
      Message.Post(Severity.warning, Lib.BuildString("Not enough power, <b>", total_cost.ToString("F0"), " ElectricCharge</b> required"), "We can't send the data");

      // return data to the containers
      ReturnData(dataQueue);

      // do not transmit the data
      return;
    }

    // transmit the data
    ModuleDataTransmitter transmitter = (ModuleDataTransmitter)this;
    transmitter.TransmitData(dataQueue);
  }
Пример #13
0
  void indicator_supplies(Panel p, Vessel v, vessel_info vi)
  {
    List<string> tooltips = new List<string>();
    uint max_severity = 0;
    if (vi.crew_count > 0)
    {
      var supplies = Profile.supplies.FindAll(k => k.resource != "ElectricCharge");
      foreach(Supply supply in supplies)
      {
        resource_info res = ResourceCache.Info(v, supply.resource);
        if (res.capacity > double.Epsilon)
        {
          double depletion = res.Depletion(vi.crew_count);
          string deplete_str = depletion <= double.Epsilon
            ? ", depleted"
            : double.IsNaN(depletion)
            ? ""
            : Lib.BuildString(", deplete in <b>", Lib.HumanReadableDuration(depletion), "</b>");
          tooltips.Add(Lib.BuildString(supply.resource, ": <b>", Lib.HumanReadablePerc(res.level), "</b>", deplete_str));

          uint severity = res.level <= 0.005 ? 2u : res.level <= supply.low_threshold ? 1u : 0;
          max_severity = Math.Max(max_severity, severity);
        }
      }
    }

    Texture image = Icons.box_white;
    switch(max_severity)
    {
      case 0: image = Icons.box_white; break;
      case 1: image = Icons.box_yellow; break;
      case 2: image = Icons.box_red;  break;
    }
    string tooltip = string.Join("\n", tooltips.ToArray());

    p.icon(image, tooltip);
  }
Пример #14
0
  public void FixedUpdate()
  {
    // in any scene: update the RMB ui
    Status = Lib.HumanReadableRadiationRate(Math.Abs(radiation) * intensity);

    // do nothing else in the editor
    if (HighLogic.LoadedSceneIsEditor) return;

    // if there is ec consumption
    if (ec_rate > double.Epsilon)
    {
      // get vessel info from the cache
      vessel_info vi = Cache.VesselInfo(vessel);

      // do nothing if vessel is invalid
      if (!vi.is_valid) return;

      // get resource cache
      resource_info ec = ResourceCache.Info(vessel, "ElectricCharge");

      // get elapsed time
      double elapsed_s = Kerbalism.elapsed_s * vi.time_dilation;

      // if there is enough EC
      // note: comparing against amount in previous simulation step
      if (ec.amount > double.Epsilon)
      {
        // consume EC
        ec.Consume(ec_rate * intensity * elapsed_s);
      }
      // else disable it
      else
      {
        intensity = 0.0f;
      }
    }
  }
Пример #15
0
        public void FixedUpdate()
        {
            // in flight
            if (Lib.IsFlight())
            {
                // if we are transmitting using the stock system
                if (stream.transmitting())
                {
                    // get ec resource handler
                    resource_info ec = ResourceCache.Info(vessel, "ElectricCharge");

                    // if we are still linked, and there is ec left
                    if (CanTransmit() && ec.amount > double.Epsilon)
                    {
                        // compression factor
                        // - used to avoid making the user wait too much for transmissions that
                        //   don't happen in background, while keeping transmission rates realistic
                        const double compression = 16.0;

                        // transmit using the data stream
                        stream.update(DataRate * Kerbalism.elapsed_s * compression, vessel);

                        // consume ec
                        ec.Consume(DataResourceCost * Kerbalism.elapsed_s);
                    }
                    else
                    {
                        // abort transmission, return data to the vessel
                        stream.abort(vessel);

                        // inform the user
                        ScreenMessages.PostScreenMessage("Transmission aborted", 5.0f, ScreenMessageStyle.UPPER_LEFT);
                    }
                }
            }
        }
Пример #16
0
        public void Execute(Vessel v, ScriptType type)
        {
            // do nothing if there is no EC left on the vessel
            Resource_Info ec = ResourceCache.Info(v, "ElectricCharge");

            if (ec.amount <= double.Epsilon)
            {
                return;
            }

            // get the script
            if (scripts.TryGetValue(type, out Script script))
            {
                // execute the script
                script.Execute(Boot(v));

                // show message to the user
                // - unless the script is empty (can happen when being edited)
                if (script.states.Count > 0 && DB.Vessel(v).cfg_script)
                {
                    Message.Post(Lib.BuildString("Script called on vessel <b>", v.vesselName, "</b>"));
                }
            }
        }
Пример #17
0
        public void Update()
        {
            // in editor, merely update ui button label
            if (Lib.IsEditor())
            {
                Events["Toggle"].guiName = Lib.StatusToggle(title, running ? "running" : "stopped");
            }

            // if in flight, and the stock planet resource system is online
            if (Lib.IsFlight() && ResourceMap.Instance != null)
            {
                // sample abundance
                double abundance = SampleAbundance();

                // determine if resource can be extracted
                issue = DetectIssue(abundance);

                // TODO: Change Review
                double ecLeft = ResourceCache.Info(part.vessel, "ElectricCharge").amount;

                // update ui
                Events["Toggle"].guiActive    = deployed && ecLeft > double.Epsilon;
                Fields["Abundance"].guiActive = deployed && ecLeft > double.Epsilon;
                if (deployed)
                {
                    string status = !running
            ? "stopped"
            : issue.Length == 0
            ? "running"
            : Lib.BuildString("<color=yellow>", issue, "</color>");

                    Events["Toggle"].guiName = Lib.StatusToggle(title, status);
                    Abundance = abundance > double.Epsilon ? Lib.HumanReadablePerc(abundance, "F2") : "none";
                }
            }
        }
Пример #18
0
        // return name of file being transmitted from vessel specified
        public static string Transmitting(Vessel v, bool linked)
        {
            // never transmitting if science system is disabled
            if (!Features.Science)
            {
                return(string.Empty);
            }

            // not transmitting if unlinked
            if (!linked)
            {
                return(string.Empty);
            }

            // not transmitting if there is no ec left
            if (ResourceCache.Info(v, "ElectricCharge").amount <= double.Epsilon)
            {
                return(string.Empty);
            }

            // get first file flagged for transmission, AND has a ts at least 5 seconds old or is > 0.001Mb in size
            foreach (var drive in DB.Vessel(v).drives.Values)
            {
                double now = Planetarium.GetUniversalTime();
                foreach (var p in drive.files)
                {
                    if (p.Value.send && (p.Value.ts + 3 < now || p.Value.size > 0.003))
                    {
                        return(p.Key);
                    }
                }
            }

            // no file flagged for transmission
            return(string.Empty);
        }
Пример #19
0
		// return shielding factor in a vessel
		public static double shielding(Vessel v)
		{
			// the shielding factor is simply the level of shielding, scaled by the 'shielding efficiency' setting
			return ResourceCache.Info(v, "Shielding").level * Settings.ShieldingEfficiency;
		}
Пример #20
0
		// return waste level in a vessel atmosphere
		public static double poisoning(Vessel v)
		{
			// the proportion of co2 in the atmosphere is simply the level of WasteAtmo
			return ResourceCache.Info(v, "WasteAtmosphere").level;
		}
Пример #21
0
		// return normalized pressure in a vessel
		public static double pressure(Vessel v)
		{
			// the pressure is simply the atmosphere level
			return ResourceCache.Info(v, "Atmosphere").level;
		}
Пример #22
0
		// return habitat surface in a vessel in m^2
		public static double tot_surface(Vessel v)
		{
			// we use capacity: this mean that partially pressurized parts will still count,
			return ResourceCache.Info(v, "Shielding").capacity;
		}
Пример #23
0
		// return habitat volume in a vessel in m^3
		public static double tot_volume(Vessel v)
		{
			// we use capacity: this mean that partially pressurized parts will still count,
			return ResourceCache.Info(v, "Atmosphere").capacity;
		}
Пример #24
0
        // trigger a random breakdown event
        public static void Breakdown(Vessel v, ProtoCrewMember c)
        {
            // constants
            const double res_penalty = 0.1; // proportion of food lost on 'depressed' and 'wrong_valve'

            // get info
            Rule          supply = supply_rules.Count > 0 ? supply_rules[Lib.RandomInt(supply_rules.Count)] : null;
            resource_info res    = supply != null?ResourceCache.Info(v, supply.resource_name) : null;

            // compile list of events with condition satisfied
            List <KerbalBreakdown> events = new List <KerbalBreakdown>();

            events.Add(KerbalBreakdown.mumbling); //< do nothing, here so there is always something that can happen
            if (Lib.CrewCount(v) > 1)
            {
                events.Add(KerbalBreakdown.argument);               //< do nothing, add some variation to messages
            }
            if (Lib.HasData(v))
            {
                events.Add(KerbalBreakdown.fat_finger);
            }
            if (Reliability.CanMalfunction(v))
            {
                events.Add(KerbalBreakdown.rage);
            }
            if (supply != null && res.amount > double.Epsilon)
            {
                events.Add(KerbalBreakdown.depressed);
                events.Add(KerbalBreakdown.wrong_valve);
            }

            // choose a breakdown event
            KerbalBreakdown breakdown = events[Lib.RandomInt(events.Count)];

            // generate message
            string text    = "";
            string subtext = "";

            switch (breakdown)
            {
            case KerbalBreakdown.mumbling:    text = "$ON_VESSEL$KERBAL has been in space for too long"; subtext = "Mumbling incoherently"; break;

            case KerbalBreakdown.argument:    text = "$ON_VESSEL$KERBAL had an argument with the rest of the crew"; subtext = "Morale is degenerating at an alarming rate"; break;

            case KerbalBreakdown.fat_finger:  text = "$ON_VESSEL$KERBAL is pressing buttons at random on the control panel"; subtext = "Science data has been lost"; break;

            case KerbalBreakdown.rage:        text = "$ON_VESSEL$KERBAL is possessed by a blind rage"; subtext = "A component has been damaged"; break;

            case KerbalBreakdown.depressed:   text = "$ON_VESSEL$KERBAL is not respecting the rationing guidelines"; subtext = supply.resource_name + " has been lost"; break;

            case KerbalBreakdown.wrong_valve: text = "$ON_VESSEL$KERBAL opened the wrong valve"; subtext = supply.resource_name + " has been lost"; break;
            }

            // post message first so this one is shown before malfunction message
            Message.Post(Severity.breakdown, Lib.ExpandMsg(text, v, c), subtext);

            // trigger the event
            switch (breakdown)
            {
            case KerbalBreakdown.mumbling: break; // do nothing

            case KerbalBreakdown.argument: break; // do nothing

            case KerbalBreakdown.fat_finger: Lib.RemoveData(v); break;

            case KerbalBreakdown.rage: Reliability.CauseMalfunction(v); break;

            case KerbalBreakdown.depressed:
            case KerbalBreakdown.wrong_valve: res.Consume(res.amount * res_penalty); break;
            }

            // remove reputation
            if (HighLogic.CurrentGame.Mode == Game.Modes.CAREER)
            {
                Reputation.Instance.AddReputation(-Settings.BreakdownReputationPenalty, TransactionReasons.Any);
            }
        }
Пример #25
0
        void toEVA(GameEvents.FromToAction <Part, Part> data)
        {
            // use Hydrazine instead of MonoPropellant if RealFuel is installed
            string monoprop_name = detected_mods.RealFuels ? "Hydrazine" : "MonoPropellant";

            // determine if inside breathable atmosphere
            // note: the user can force the helmet + oxygen by pressing shift when going on eva
            bool breathable = Sim.Breathable(data.from.vessel) && !(Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift));

            // get total crew in the origin vessel
            double tot_crew = (double)data.from.vessel.GetVesselCrew().Count + 1.0;

            // EVA vessels start with 5 units of eva fuel, remove them
            data.to.RequestResource("EVA Propellant", 5.0);

            // determine how much MonoPropellant to get
            // note: never more that the 'share' of this kerbal
            double monoprop = Math.Min(ResourceCache.Info(data.from.vessel, monoprop_name).amount / tot_crew, Settings.MonoPropellantOnEVA);

            // get monoprop from the vessel
            monoprop = data.from.RequestResource(monoprop_name, monoprop);

            // transfer monoprop to the EVA kerbal
            data.to.RequestResource("EVA Propellant", -monoprop);

            // show warning if there isn't monoprop in the eva suit
            if (monoprop <= double.Epsilon && !Lib.Landed(data.from.vessel))
            {
                Message.Post(Severity.danger, Lib.BuildString("There isn't any <b>", monoprop_name, "</b> in the EVA suit", "Don't let the ladder go!"));
            }

            // manage resources from rules
            foreach (Rule r in rules)
            {
                if (r.resource_name.Length == 0 || r.on_eva <= double.Epsilon)
                {
                    continue;
                }

                // determine amount to take, never more that his own share
                double amount = Math.Min(ResourceCache.Info(data.from.vessel, r.resource_name).amount / tot_crew, r.on_eva);

                // deal with breathable modifier
                if (breathable && r.modifier.Contains("breathable"))
                {
                    continue;
                }

                // remove resource from the vessel
                amount = data.from.RequestResource(r.resource_name, amount);

                // create new resource in the eva kerbal
                Lib.SetupResource(data.to, r.resource_name, amount, r.on_eva);
            }

            // get KerbalEVA
            KerbalEVA kerbal = data.to.FindModuleImplementing <KerbalEVA>();

            // turn off headlamp light, to avoid stock bug that show the light for a split second when going on eva
            EVA.SetHeadlamp(kerbal, false);
            EVA.SetFlares(kerbal, false);

            // remove the helmet if inside breathable atmosphere
            // note: done in EVA::FixedUpdate(), but also done here avoid 'popping' of the helmet when going on eva
            EVA.SetHelmet(kerbal, !breathable);

            // remember if the kerbal has an helmet
            EVA.KerbalData(data.to.vessel).has_helmet = !breathable;

            // execute script on vessel computer
            if (DB.Ready())
            {
                DB.VesselData(data.from.vessel.id).computer.execute("run", "auto/eva_out", string.Empty, data.from.vessel);
            }

            // mute messages for a couple seconds to avoid warning messages from the vessel resource amounts
            Message.MuteInternal();
            base.StartCoroutine(CallbackUtil.DelayedCallback(2.0f, Message.UnmuteInternal));

            // if vessel info is open, switch to the eva kerbal
            // note: for a single tick, the EVA vessel is not valid (sun_dist is zero)
            // this make IsVessel() return false, that in turn close the vessel info instantly
            // for this reason, we wait a small amount of time before switching the info window
            if (Info.IsOpen())
            {
                Info.Open(data.to.vessel);
            }
        }
Пример #26
0
        public void FixedUpdate()
        {
            // do nothing in the editor
            if (Lib.IsEditor())
            {
                return;
            }

            // if enabled
            if (running)
            {
                // if a researcher is not required, or the researcher is present
                if (!researcher_cs || researcher_cs.check(part.protoModuleCrew))
                {
                    // get next sample to analyze
                    string sample_filename = next_sample(vessel);

                    // if there is a sample to analyze
                    if (sample_filename.Length > 0)
                    {
                        // consume EC
                        resource_info ec = ResourceCache.Info(vessel, "ElectricCharge");
                        ec.Consume(ec_rate * Kerbalism.elapsed_s);

                        // if there was ec
                        // - comparing against amount in previous simulation step
                        if (ec.amount > double.Epsilon)
                        {
                            // analyze the sample
                            analyze(vessel, sample_filename, analysis_rate * Kerbalism.elapsed_s);

                            // update status
                            status = Science.experiment(sample_filename).name;
                        }
                        // if there was no ec
                        else
                        {
                            // update status
                            status = "<color=yellow>no electric charge</color>";
                        }
                    }
                    // if there is no sample to analyze
                    else
                    {
                        // update status
                        status = "no samples to analyze";
                    }
                }
                // if a researcher is required, but missing
                else
                {
                    // update status
                    status = Lib.BuildString("<color=yellow>", researcher_cs.warning(), "</color>");
                }
            }
            // if disabled
            else
            {
                // update status
                status = "disabled";
            }
        }
Пример #27
0
        public void FixedUpdate()
        {
            // basic sanity checks
            if (Lib.IsEditor())
            {
                return;
            }
            if (!Cache.VesselInfo(vessel).is_valid)
            {
                return;
            }
            if (next_check > Planetarium.GetUniversalTime())
            {
                return;
            }

            // get ec handler
            Resource_info ec = ResourceCache.Info(vessel, "ElectricCharge");

            shrouded = part.ShieldedFromAirstream;
            issue    = TestForIssues(vessel, ec, this, privateHdId, broken,
                                     remainingSampleMass, didPrepare, shrouded, last_subject_id);

            if (string.IsNullOrEmpty(issue))
            {
                issue = TestForResources(vessel, resourceDefs, Kerbalism.elapsed_s, ResourceCache.Get(vessel));
            }

            scienceValue = Science.Value(last_subject_id, 0);
            state        = GetState(scienceValue, issue, recording, forcedRun);

            if (!string.IsNullOrEmpty(issue))
            {
                next_check = Planetarium.GetUniversalTime() + Math.Max(3, Kerbalism.elapsed_s * 3);
                return;
            }

            var subject_id = Science.Generate_subject_id(experiment_id, vessel);

            if (last_subject_id != subject_id)
            {
                dataSampled = 0;
                forcedRun   = false;
            }
            last_subject_id = subject_id;

            if (state != State.RUNNING)
            {
                return;
            }

            var exp = Science.Experiment(experiment_id);

            if (dataSampled >= exp.max_amount)
            {
                return;
            }

            // if experiment is active and there are no issues
            DoRecord(ec, subject_id);
        }
Пример #28
0
		public void Update()
		{
			// update RMB ui
			Events["Toggle"].guiName = deployed ? Localizer.Format("#KERBALISM_Generic_RETRACT") : Localizer.Format("#KERBALISM_Generic_DEPLOY");
			Events["Toggle"].active = (deploy.Length > 0) && (part.FindModuleImplementing<Habitat>() == null) && !deploy_anim.Playing() && !waitRotation && ResourceCache.Info(vessel, "ElectricCharge").amount > ec_rate;

			// in flight
			if (Lib.IsFlight())
			{
				// if deployed
				if (deployed)
				{
					// if there is no ec
					if (ResourceCache.Info(vessel, "ElectricCharge").amount < 0.01)
					{
						// pause rotate animation
						// - safe to pause multiple times
						Set_rotation(false);
					}
					// if there is enough ec instead and is not deploying
					else if (Should_start_rotation())
					{
						// resume rotate animation
						// - safe to resume multiple times
						Set_rotation(true);
					}
				}
				// stop loop animation if exist and we are retracting
				else
				{
					// Call transform.stop() if it is rotating and the Stop method wasn't called.
					Set_rotation(false);
				}

				// When is not rotating
				if (waitRotation)
				{
					if (rotateIsTransform && !rotate_transf.IsRotating())
					{
						// start retract animation in the correct direction, when is not rotating
						if (animBackwards) deploy_anim.Play(deployed, false);
						else deploy_anim.Play(!deployed, false);
						waitRotation = false;
					}
					else if (!rotateIsTransform && !rotate_anim.Playing())
					{
						if (animBackwards) deploy_anim.Play(deployed, false);
						else deploy_anim.Play(!deployed, false);
						waitRotation = false;
					}
				}

				if (rotateIsTransform && rotate_transf != null) rotate_transf.DoSpin();
			}
		}
Пример #29
0
        public void Execute(Vessel v, vessel_info vi, vessel_resources resources, double elapsed_s)
        {
            // store list of crew to kill
            List <ProtoCrewMember> deferred_kills = new List <ProtoCrewMember>();

            // get input resource handler
            resource_info res = input.Length > 0 ? resources.Info(v, input) : null;

            // determine message variant
            uint variant = vi.temperature < Settings.SurvivalTemperature ? 0 : 1u;

            // get product of all environment modifiers
            double k = Modifiers.evaluate(v, vi, resources, modifiers);

            // for each crew
            foreach (ProtoCrewMember c in Lib.CrewList(v))
            {
                // get kerbal data
                KerbalData kd = DB.Kerbal(c.name);

                // skip rescue kerbals
                if (kd.rescue)
                {
                    continue;
                }

                // skip disabled kerbals
                if (kd.disabled)
                {
                    continue;
                }

                // get kerbal property data from db
                RuleData rd = kd.Rule(name);

                // if continuous
                double step;
                if (interval <= double.Epsilon)
                {
                    // influence consumption by elapsed time
                    step = elapsed_s;
                }
                // if interval-based
                else
                {
                    // accumulate time
                    rd.time_since += elapsed_s;

                    // determine number of steps
                    step = Math.Floor(rd.time_since / interval);

                    // consume time
                    rd.time_since -= step * interval;

                    // remember if a meal is consumed/produced in this simulation step
                    res.meal_happened |= step > 0.99;
                    if (output.Length > 0)
                    {
                        ResourceCache.Info(v, output).meal_happened |= step > 0.99;
                    }
                }

                // if continuous, or if one or more intervals elapsed
                if (step > double.Epsilon)
                {
                    // if there is a resource specified
                    if (res != null && rate > double.Epsilon)
                    {
                        // determine amount of resource to consume
                        double required = rate                                    // consumption rate
                                          * k                                     // product of environment modifiers
                                          * step;                                 // seconds elapsed or number of steps

                        // if there is no output
                        if (output.Length == 0)
                        {
                            // simply consume (that is faster)
                            res.Consume(required);
                        }
                        // if there is an output and output_only is false
                        else if (!output_only)
                        {
                            // transform input into output resource
                            // - rules always dump excess overboard (because it is waste)
                            resource_recipe recipe = new resource_recipe();
                            recipe.Input(input, required);
                            recipe.Output(output, required * ratio, true);
                            resources.Transform(recipe);
                        }
                        // if output_only then do not consume input resource
                        else
                        {
                            // simply produce (that is faster)
                            resources.Produce(v, output, required);
                        }
                    }

                    // degenerate:
                    // - if the environment modifier is not telling to reset (by being zero)
                    // - if the input threshold is reached if used
                    // - if this rule is resource-less, or if there was not enough resource in the vessel
                    if (input_threshold >= double.Epsilon)
                    {
                        if (res.amount >= double.Epsilon && res.capacity >= double.Epsilon)
                        {
                            trigger = res.amount / res.capacity >= input_threshold;
                        }
                        else
                        {
                            trigger = false;
                        }
                    }
                    else
                    {
                        trigger = input.Length == 0 || res.amount <= double.Epsilon;
                    }

                    if (k > 0.0 && trigger)
                    {
                        rd.problem += degeneration                                   // degeneration rate per-second or per-interval
                                      * k                                            // product of environment modifiers
                                      * step                                         // seconds elapsed or by number of steps
                                      * Variance(c, variance);                       // kerbal-specific variance
                    }
                    // else slowly recover
                    else
                    {
                        rd.problem *= 1.0 / (1.0 + Math.Max(interval, 1.0) * step * 0.002);
                        rd.problem  = Math.Max(rd.problem, 0.0);
                    }
                }

                // kill kerbal if necessary
                if (rd.problem >= fatal_threshold)
                {
                    if (fatal_message.Length > 0)
                    {
                        Message.Post(breakdown ? Severity.breakdown : Severity.fatality, Lib.ExpandMsg(fatal_message, v, c, variant));
                    }

                    if (breakdown)
                    {
                        // trigger breakdown event
                        Misc.Breakdown(v, c);

                        // move back between warning and danger level
                        rd.problem = (warning_threshold + danger_threshold) * 0.5;

                        // make sure next danger messagen is shown
                        rd.message = 1;
                    }
                    else
                    {
                        deferred_kills.Add(c);
                    }
                }
                // show messages
                else if (rd.problem >= danger_threshold && rd.message < 2)
                {
                    if (danger_message.Length > 0)
                    {
                        Message.Post(Severity.danger, Lib.ExpandMsg(danger_message, v, c, variant));
                    }
                    rd.message = 2;
                }
                else if (rd.problem >= warning_threshold && rd.message < 1)
                {
                    if (warning_message.Length > 0)
                    {
                        Message.Post(Severity.warning, Lib.ExpandMsg(warning_message, v, c, variant));
                    }
                    rd.message = 1;
                }
                else if (rd.problem < warning_threshold && rd.message > 0)
                {
                    if (relax_message.Length > 0)
                    {
                        Message.Post(Severity.relax, Lib.ExpandMsg(relax_message, v, c, variant));
                    }
                    rd.message = 0;
                }
            }

            // execute the deferred kills
            foreach (ProtoCrewMember c in deferred_kills)
            {
                Misc.Kill(v, c);
            }
        }
Пример #30
0
        public Comforts(Vessel v, bool env_firm_ground, bool env_not_alone, bool env_call_home)
        {
            // environment factors
            firm_ground = env_firm_ground;
            not_alone   = env_not_alone;
            call_home   = env_call_home;

            // if loaded
            if (v.loaded)
            {
                // scan parts for comfort
                foreach (Comfort c in Lib.FindModules <Comfort>(v))
                {
                    switch (c.bonus)
                    {
                    case "firm-ground": firm_ground = true; break;

                    case "not-alone": not_alone = true; break;

                    case "call-home": call_home = true; break;

                    case "exercise": exercise = true; break;

                    case "panorama": panorama = true; break;

                    case "plants": plants = true; break;
                    }
                }

                // scan parts for gravity ring
                if (ResourceCache.Info(v, "ElectricCharge").amount >= 0.01)
                {
                    firm_ground |= Lib.HasModule <GravityRing>(v, k => k.deployed);
                }
            }
            // if not loaded
            else
            {
                // scan parts for comfort
                foreach (ProtoPartModuleSnapshot m in Lib.FindModules(v.protoVessel, "Comfort"))
                {
                    switch (Lib.Proto.GetString(m, "bonus"))
                    {
                    case "firm-ground": firm_ground = true; break;

                    case "not-alone": not_alone = true; break;

                    case "call-home": call_home = true; break;

                    case "exercise": exercise = true; break;

                    case "panorama": panorama = true; break;

                    case "plants": plants = true; break;
                    }
                }

                // scan parts for gravity ring
                if (ResourceCache.Info(v, "ElectricCharge").amount >= 0.01)
                {
                    firm_ground |= Lib.HasModule(v.protoVessel, "GravityRing", k => Lib.Proto.GetBool(k, "deployed"));
                }
            }

            // calculate factor
            factor = 0.1;
            if (firm_ground)
            {
                factor += PreferencesComfort.Instance.firmGround;
            }
            if (not_alone)
            {
                factor += PreferencesComfort.Instance.notAlone;
            }
            if (call_home)
            {
                factor += PreferencesComfort.Instance.callHome;
            }
            if (exercise)
            {
                factor += PreferencesComfort.Instance.exercise;
            }
            if (panorama)
            {
                factor += PreferencesComfort.Instance.panorama;
            }
            if (plants)
            {
                factor += PreferencesComfort.Instance.plants;
            }
            factor = Lib.Clamp(factor, 0.1, 1.0);
        }