Esempio n. 1
0
 static void ProcessLight(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, ModuleLight light, Resource_Info ec, double elapsed_s)
 {
     if (light.useResources && Lib.Proto.GetBool(m, "isOn"))
     {
         ec.Consume(light.resourceAmount * elapsed_s);
     }
 }
Esempio n. 2
0
        public static void BackgroundUpdate(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, Laboratory lab, Resource_Info ec, double elapsed_s)
        {
            // if enabled
            if (Lib.Proto.GetBool(m, "running"))
            {
                // if a researcher is not required, or the researcher is present
                CrewSpecs researcher_cs = new CrewSpecs(lab.researcher);
                int       qtty = 0, crewlvl = 0;
                if (!researcher_cs || researcher_cs.Check(p.protoModuleCrew, out qtty, out crewlvl))
                {
                    // get sample to analyze
                    string sample_filename = Next_sample(v);

                    // if there is a sample to analyze
                    if (sample_filename.Length > 0)
                    {
                        // consume EC
                        ec.Consume(lab.ec_rate * elapsed_s);

                        // if there was ec
                        // - comparing against amount in previous simulation step
                        if (ec.amount > double.Epsilon)
                        {
                            double analysis_rateAVG = lab.analysis_rate;
                            if (researcher_cs)
                            {
                                analysis_rateAVG *= qtty * crewlvl;
                            }
                            // analyze the sample
                            Analyze(v, sample_filename, analysis_rateAVG * elapsed_s);
                        }
                    }
                }
            }
        }
Esempio n. 3
0
        public virtual void FixedUpdate()
        {
            if (!Lib.IsFlight() || module == null)
            {
                return;
            }

            if (broken)
            {
                if (broken != lastFixedBrokenState)
                {
                    lastFixedBrokenState = broken;
                    FixModule(!broken);
                }
            }
            else if (hasFixedEnergyChanged != hasEnergy)
            {
                // Wait 1 second before start consum EC.
                if (hasEnergy)
                {
                    Lib.Delay(1f);
                }

                hasFixedEnergyChanged = hasEnergy;
                lastFixedBrokenState  = false;
                // Update module
                FixModule(hasEnergy);
            }

            // If isConsuming
            if (isConsuming && resources != null)
            {
                resources.Consume(actualCost * Kerbalism.elapsed_s);
            }
        }
Esempio n. 4
0
 public static void BackgroundUpdate(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, Emitter emitter, Resource_Info ec, double elapsed_s)
 {
     // if enabled, and EC is required
     if (Lib.Proto.GetBool(m, "running") && emitter.ec_rate > double.Epsilon)
     {
         // consume EC
         ec.Consume(emitter.ec_rate * elapsed_s);
     }
 }
Esempio n. 5
0
        static void ProcessStockLab(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, ModuleScienceConverter lab, Resource_Info ec, double elapsed_s)
        {
            // note: we are only simulating the EC consumption
            // note: there is no easy way to 'stop' the lab when there isn't enough EC

            // if active
            if (Lib.Proto.GetBool(m, "IsActivated"))
            {
                // consume ec
                ec.Consume(lab.powerRequirement * elapsed_s);
            }
        }
Esempio n. 6
0
 public virtual void FixedUpdate()
 {
     if (Lib.IsFlight() && Features.Deploy)
     {
         if (isConsuming)
         {
             if (resourceInfo != null)
             {
                 resourceInfo.Consume(actualECCost * Kerbalism.elapsed_s);
             }
         }
     }
 }
Esempio n. 7
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);
            }
        }
Esempio n. 8
0
        static void ProcessCryoTank(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, PartModule simple_boiloff, Vessel_Resources resources, double elapsed_s)
        {
            // note: cryotank module already does a post-facto simulation of background boiling, and we could use that for the boiling
            // however, it also does simulate the ec consumption that way, so we have to disable the post-facto simulation

            // get fuel name
            string fuel_name = Lib.ReflectionValue <string>(simple_boiloff, "FuelName");

            // get resource handlers
            Resource_Info ec   = resources.Info(v, "ElectricCharge");
            Resource_Info fuel = resources.Info(v, fuel_name);

            // if there is some fuel
            // note: comparing against amount in previous simulation step
            if (fuel.amount > double.Epsilon)
            {
                // get capacity in the part
                double capacity = p.resources.Find(k => k.resourceName == fuel_name).maxAmount;

                // if cooling is enabled and there was enough ec
                // note: comparing against amount in previous simulation step
                if (Lib.Proto.GetBool(m, "CoolingEnabled") && ec.amount > double.Epsilon)
                {
                    // get cooling ec cost per 1000 units of fuel, per-second
                    double cooling_cost = Lib.ReflectionValue <float>(simple_boiloff, "CoolingCost");

                    // consume ec
                    ec.Consume(cooling_cost * capacity * 0.001 * elapsed_s);
                }
                // if there wasn't ec, or if cooling is disabled
                else
                {
                    // get boiloff rate in proportion to fuel amount, per-second
                    double boiloff_rate = Lib.ReflectionValue <float>(simple_boiloff, "BoiloffRate") * 0.00000277777;

                    // let it boil off
                    fuel.Consume(capacity * (1.0 - Math.Pow(1.0 - boiloff_rate, elapsed_s)));
                }
            }

            // disable post-facto simulation
            Lib.Proto.Set(m, "LastUpdateTime", v.missionTime);
        }
Esempio n. 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;
            }
        }
Esempio n. 10
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);
                    }
                }
            }
        }
Esempio n. 11
0
        static void ProcessCryoTank(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, PartModule simple_boiloff, Vessel_Resources resources, double elapsed_s)
        {
            // note: cryotank module already does a post-facto simulation of background boiling, and we could use that for the boiling
            // however, it also does simulate the ec consumption that way, so we have to disable the post-facto simulation

            // As far as I know, Simple_boiloff consumes fuel and EC only if the fuel is on the Fuel List (previously added in Game Load)
            // The test that I did, I was able to enable to "Enable Cooling" only when fuel was into List<BoiloffFuel> fuels

            // get fuel name: FuelName in Simple_Boiloff is always NULL, this Get doesn't make sense, but I will leave here.
            string fuel_name = Lib.ReflectionValue <string>(simple_boiloff, "FuelName");

            // get resource handlers
            Resource_Info ec = resources.Info(v, "ElectricCharge");

            // if fuel_name is null as expected, this would cause error
            if (string.IsNullOrEmpty(fuel_name))
            {
                // Take name from fuel list inside part
                System.Collections.IList fuelList = Lib.ReflectionValue <System.Collections.IList>(simple_boiloff, "fuels");

                foreach (var item in fuelList)
                {
                    fuel_name = (string)item.GetType().GetField("fuelName").GetValue(item);
                    // if fuel_name still null, do anything
                    if (fuel_name == null)
                    {
                        continue;
                    }

                    Resource_Info fuel = resources.Info(v, fuel_name);

                    // if there is some fuel
                    // note: comparing against amount in previous simulation step
                    if (fuel.amount > double.Epsilon)
                    {
                        // Try find resource "fuel_name" into PartResources
                        ProtoPartResourceSnapshot protoPartResource = p.resources.Find(k => k.resourceName == fuel_name);

                        // If part doesn't have the fuel, do anything.
                        if (protoPartResource == null)
                        {
                            continue;
                        }

                        // get capacity in the part
                        double capacity = protoPartResource.maxAmount;

                        // if cooling is enabled and there was enough ec
                        // note: comparing against amount in previous simulation step
                        if (Lib.Proto.GetBool(m, "CoolingEnabled") && ec.amount > double.Epsilon)
                        {
                            // get cooling ec cost per 1000 units of fuel, per-second
                            double cooling_cost = Lib.ReflectionValue <float>(simple_boiloff, "CoolingCost");

                            // consume ec
                            ec.Consume(cooling_cost * capacity * 0.001 * elapsed_s);
                        }
                        // if there wasn't ec, or if cooling is disabled
                        else
                        {
                            // get boiloff rate in proportion to fuel amount, per-second
                            double boiloff_rate = Lib.ReflectionValue <float>(simple_boiloff, "BoiloffRate") * 0.00000277777;

                            // let it boil off
                            fuel.Consume(capacity * (1.0 - Math.Pow(1.0 - boiloff_rate, elapsed_s)));
                        }
                    }

                    // disable post-facto simulation
                    Lib.Proto.Set(m, "LastUpdateTime", v.missionTime);
                }
            }
            else
            {
                Resource_Info fuel = resources.Info(v, fuel_name);

                // if there is some fuel
                // note: comparing against amount in previous simulation step
                if (fuel.amount > double.Epsilon)
                {
                    // Try find resource "fuel_name" into PartResources
                    ProtoPartResourceSnapshot protoPartResource = p.resources.Find(k => k.resourceName == fuel_name);

                    // If part doesn't have the fuel, do anything.
                    if (protoPartResource == null)
                    {
                        return;
                    }

                    // get capacity in the part
                    double capacity = protoPartResource.maxAmount;

                    // if cooling is enabled and there was enough ec
                    // note: comparing against amount in previous simulation step
                    if (Lib.Proto.GetBool(m, "CoolingEnabled") && ec.amount > double.Epsilon)
                    {
                        // get cooling ec cost per 1000 units of fuel, per-second
                        double cooling_cost = Lib.ReflectionValue <float>(simple_boiloff, "CoolingCost");

                        // consume ec
                        ec.Consume(cooling_cost * capacity * 0.001 * elapsed_s);
                    }
                    // if there wasn't ec, or if cooling is disabled
                    else
                    {
                        // get boiloff rate in proportion to fuel amount, per-second
                        double boiloff_rate = Lib.ReflectionValue <float>(simple_boiloff, "BoiloffRate") * 0.00000277777;

                        // let it boil off
                        fuel.Consume(capacity * (1.0 - Math.Pow(1.0 - boiloff_rate, elapsed_s)));
                    }
                }

                // disable post-facto simulation
                Lib.Proto.Set(m, "LastUpdateTime", v.missionTime);
            }
        }
Esempio n. 12
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
                        else
                        {
                            // 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);
                        }
                    }

                    // degenerate:
                    // - if the environment modifier is not telling to reset (by being zero)
                    // - if this rule is resource-less, or if there was not enough resource in the vessel
                    if (k > 0.0 && (input.Length == 0 || res.amount <= double.Epsilon))
                    {
                        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);
            }
        }
Esempio n. 13
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 a supply resource at random
            Resource_Info res = null;

            if (Profile.supplies.Count > 0)
            {
                Supply supply = Profile.supplies[Lib.RandomInt(Profile.supplies.Count)];
                res = ResourceCache.Info(v, supply.resource);
            }

            // 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.HasData(v))
            {
                events.Add(KerbalBreakdown.fat_finger);
            }
            if (Reliability.CanMalfunction(v))
            {
                events.Add(KerbalBreakdown.rage);
            }
            if (res != null && res.amount > double.Epsilon)
            {
                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.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.wrong_valve: text = "$ON_VESSEL$KERBAL opened the wrong valve"; subtext = res.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.fat_finger: Lib.RemoveData(v); break;

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

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

            // remove reputation
            if (HighLogic.CurrentGame.Mode == Game.Modes.CAREER)
            {
                Reputation.Instance.AddReputation(-Settings.BreakdownReputation, TransactionReasons.Any);
            }
        }
Esempio n. 14
0
        public void FixedUpdate()
        {
            // do nothing in the editor
            if (Lib.IsEditor())
            {
                return;
            }

            // if enabled
            if (running)
            {
                int qtty = 0, crewlvl = 0;
                // if a researcher is not required, or the researcher is present
                if (!researcher_cs || researcher_cs.Check(part.protoModuleCrew, out qtty, out crewlvl))
                {
                    // 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)
                        {
                            analysis_rateAVG = analysis_rate;
                            if (researcher_cs)
                            {
                                analysis_rateAVG *= qtty * crewlvl;
                            }
                            // analyze the sample
                            Analyze(vessel, sample_filename, analysis_rateAVG * Kerbalism.elapsed_s);

                            //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";
            }
        }
Esempio n. 15
0
        public void FixedUpdate()
        {
            // do nothing in the editor
            if (Lib.IsEditor())
            {
                return;
            }

            // if enabled and not ready for harvest
            if (active && growth < 0.99)
            {
                // get vessel info from the cache
                // - if the vessel is not valid (eg: flagged as debris) then solar flux will be 0 and landed false (but that's okay)
                Vessel_Info vi = Cache.VesselInfo(vessel);

                // get resource cache
                Vessel_Resources resources = ResourceCache.Get(vessel);
                Resource_Info    ec        = resources.Info(vessel, "ElectricCharge");

                // deal with corner cases when greenhouse is assembled using KIS
                if (double.IsNaN(growth) || double.IsInfinity(growth))
                {
                    growth = 0.0;
                }

                // calculate natural and artificial lighting
                natural    = vi.solar_flux;
                artificial = Math.Max(light_tolerance - natural, 0.0);

                // consume EC for the lamps, scaled by artificial light intensity
                if (artificial > double.Epsilon)
                {
                    ec.Consume(ec_rate * (artificial / light_tolerance) * Kerbalism.elapsed_s);
                }

                // reset artificial lighting if there is no ec left
                // - comparing against amount in previous simulation step
                if (ec.amount <= double.Epsilon)
                {
                    artificial = 0.0;
                }

                // execute recipe
                Resource_Recipe recipe = new Resource_Recipe();
                foreach (ModuleResource input in resHandler.inputResources)
                {
                    recipe.Input(input.name, input.rate * Kerbalism.elapsed_s);
                }
                foreach (ModuleResource output in resHandler.outputResources)
                {
                    recipe.Output(output.name, output.rate * Kerbalism.elapsed_s, true);
                }
                resources.Transform(recipe);

                // determine environment conditions
                bool lighting  = natural + artificial >= light_tolerance;
                bool pressure  = pressure_tolerance <= double.Epsilon || vi.pressure >= pressure_tolerance;
                bool radiation = radiation_tolerance <= double.Epsilon || vi.radiation * (1.0 - vi.shielding) < radiation_tolerance;

                // determine input resources conditions
                // - comparing against amounts in previous simulation step
                bool   inputs      = true;
                string missing_res = string.Empty;
                foreach (ModuleResource input in resHandler.inputResources)
                {
                    if (resources.Info(vessel, input.name).amount <= double.Epsilon)
                    {
                        inputs      = false;
                        missing_res = input.name;
                        break;
                    }
                }

                // if growing
                if (lighting && pressure && radiation && inputs)
                {
                    // increase growth
                    growth += crop_rate * Kerbalism.elapsed_s;
                    growth  = Math.Min(growth, 1.0);

                    // notify the user when crop can be harvested
                    if (growth >= 0.99)
                    {
                        Message.Post(Lib.BuildString("On <b>", vessel.vesselName, "</b> the crop is ready to be harvested"));
                        growth = 1.0;
                    }
                }

                // update time-to-harvest
                tta = (1.0 - growth) / crop_rate;

                // update issues
                issue =
                    !inputs?Lib.BuildString("missing ", missing_res)
                        : !lighting  ? "insufficient lighting"
        : !pressure  ? "insufficient pressure"
        : !radiation ? "excessive radiation"
        : string.Empty;
            }
        }
Esempio n. 16
0
        public static void BackgroundUpdate(Vessel v, ProtoPartModuleSnapshot m, Greenhouse g,
                                            Vessel_Info vi, Vessel_Resources resources, double elapsed_s)
        {
            // get protomodule data
            bool   active = Lib.Proto.GetBool(m, "active");
            double growth = Lib.Proto.GetDouble(m, "growth");

            // if enabled and not ready for harvest
            if (active && growth < 0.99)
            {
                // get resource handler
                Resource_Info ec = resources.Info(v, "ElectricCharge");

                // calculate natural and artificial lighting
                double natural    = vi.solar_flux;
                double artificial = Math.Max(g.light_tolerance - natural, 0.0);

                // consume EC for the lamps, scaled by artificial light intensity
                if (artificial > double.Epsilon)
                {
                    ec.Consume(g.ec_rate * (artificial / g.light_tolerance) * elapsed_s);
                }

                // reset artificial lighting if there is no ec left
                // note: comparing against amount in previous simulation step
                if (ec.amount <= double.Epsilon)
                {
                    artificial = 0.0;
                }

                // execute recipe
                Resource_Recipe recipe = new Resource_Recipe();
                foreach (ModuleResource input in g.resHandler.inputResources)
                {
                    recipe.Input(input.name, input.rate * elapsed_s);
                }
                foreach (ModuleResource output in g.resHandler.outputResources)
                {
                    recipe.Output(output.name, output.rate * elapsed_s, true);
                }
                resources.Transform(recipe);

                // determine environment conditions
                bool lighting  = natural + artificial >= g.light_tolerance;
                bool pressure  = g.pressure_tolerance <= double.Epsilon || vi.pressure >= g.pressure_tolerance;
                bool radiation = g.radiation_tolerance <= double.Epsilon || vi.radiation * (1.0 - vi.shielding) < g.radiation_tolerance;

                // determine inputs conditions
                // note: comparing against amounts in previous simulation step
                bool   inputs      = true;
                string missing_res = string.Empty;
                foreach (ModuleResource input in g.resHandler.inputResources)
                {
                    if (resources.Info(v, input.name).amount <= double.Epsilon)
                    {
                        inputs      = false;
                        missing_res = input.name;
                        break;
                    }
                }

                // if growing
                if (lighting && pressure && radiation && inputs)
                {
                    // increase growth
                    growth += g.crop_rate * elapsed_s;
                    growth  = Math.Min(growth, 1.0);

                    // notify the user when crop can be harvested
                    if (growth >= 0.99)
                    {
                        Message.Post(Lib.BuildString("On <b>", v.vesselName, "</b> the crop is ready to be harvested"));
                        growth = 1.0;
                    }
                }

                // update time-to-harvest
                double tta = (1.0 - growth) / g.crop_rate;

                // update issues
                string issue =
                    !inputs?Lib.BuildString("missing ", missing_res)
                        : !lighting  ? "insufficient lighting"
        : !pressure  ? "insufficient pressure"
        : !radiation ? "excessive radiation"
        : string.Empty;

                // update protomodule data
                Lib.Proto.Set(m, "natural", natural);
                Lib.Proto.Set(m, "artificial", artificial);
                Lib.Proto.Set(m, "tta", tta);
                Lib.Proto.Set(m, "issue", issue);
                Lib.Proto.Set(m, "growth", growth);
            }
        }
Esempio n. 17
0
        static void ProcessScanner(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, PartModule scanner, Part part_prefab, VesselData vd, Resource_Info ec, double elapsed_s)
        {
            // get ec consumption rate
            double power = SCANsat.EcConsumption(scanner);

            // if the scanner doesn't require power to operate, we aren't interested in simulating it
            if (power <= double.Epsilon)
            {
                return;
            }

            // get scanner state
            bool is_scanning = Lib.Proto.GetBool(m, "scanning");

            // if its scanning
            if (is_scanning)
            {
                // consume ec
                ec.Consume(power * elapsed_s);

                // if there isn't ec
                // - comparing against amount in previous simulation step
                if (ec.amount <= double.Epsilon)
                {
                    // unregister scanner
                    SCANsat.StopScanner(v, m, part_prefab);
                    is_scanning = false;

                    // remember disabled scanner
                    vd.scansat_id.Add(p.flightID);

                    // give the user some feedback
                    if (vd.cfg_ec)
                    {
                        Message.Post(Lib.BuildString("SCANsat sensor was disabled on <b>", v.vesselName, "</b>"));
                    }
                }
            }
            // if it was disabled in background
            else if (vd.scansat_id.Contains(p.flightID))
            {
                // if there is enough ec
                // note: comparing against amount in previous simulation step
                if (ec.level > 0.25) //< re-enable at 25% EC
                {
                    // re-enable the scanner
                    SCANsat.ResumeScanner(v, m, part_prefab);
                    is_scanning = true;

                    // give the user some feedback
                    if (vd.cfg_ec)
                    {
                        Message.Post(Lib.BuildString("SCANsat sensor resumed operations on <b>", v.vesselName, "</b>"));
                    }
                }
            }

            // forget active scanners
            if (is_scanning)
            {
                vd.scansat_id.Remove(p.flightID);
            }
        }
Esempio n. 18
0
        State Equalize()
        {
            // in flight
            if (Lib.IsFlight())
            {
                // shortcuts
                Resource_Info vessel_atmo = ResourceCache.Info(vessel, "Atmosphere");
                PartResource  hab_atmo    = part.Resources["Atmosphere"];

                // get level of atmosphere in vessel and part
                double vessel_level = vessel_atmo.level;
                double hab_level    = Lib.Level(part, "Atmosphere", true);

                // equalization succeeded if the levels are the same
                // note: this behave correctly in the case the hab is the only enabled one or not
                if (Math.Abs(vessel_level - hab_level) < 0.01)
                {
                    return(State.enabled);
                }

                // in case vessel pressure is dropping during equalization, it mean that pressure
                // control is not enough so we just enable the hab while not fully equalized
                if (vessel_atmo.rate < 0.0)
                {
                    return(State.enabled);
                }

                // determine equalization speed
                // we deal with the case where a big hab is sucking all atmosphere from the rest of the vessel
                double amount = Math.Min(Cache.VesselInfo(vessel).volume, volume) * equalize_speed * Kerbalism.elapsed_s;

                // vessel pressure is higher
                if (vessel_level > hab_level)
                {
                    // clamp amount to what's available in the vessel and what can fit in the part
                    amount = Math.Min(amount, vessel_atmo.amount);
                    amount = Math.Min(amount, hab_atmo.maxAmount - hab_atmo.amount);

                    // consume from all enabled habs in the vessel
                    vessel_atmo.Consume(amount);

                    // produce in the part
                    hab_atmo.amount += amount;
                }
                // vessel pressure is lower
                else
                {
                    // 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);
                }

                // equalization still in progress
                return(State.equalizing);
            }
            // in the editors
            else
            {
                // set amount to max capacity
                PartResource hab_atmo = part.Resources["Atmosphere"];
                hab_atmo.amount = hab_atmo.maxAmount;

                // return new state
                return(State.enabled);
            }
        }