Exemplo n.º 1
0
        // return true if the vessel is a rescue mission
        public static bool IsRescueMission(Vessel v)
        {
            // if at least one of the crew is flagged as rescue, consider it a rescue mission
            foreach (var c in Lib.CrewList(v))
            {
                if (DB.Kerbal(c.name).rescue)
                {
                    return(true);
                }
            }


            // not a rescue mission
            return(false);
        }
Exemplo n.º 2
0
        // inject instant radiation dose to the specified kerbal (can use negative amounts)
        public static void InjectRadiation(string k_name, double amount)
        {
            if (!DB.ContainsKerbal(k_name))
            {
                return;
            }
            KerbalData kd = DB.Kerbal(k_name);

            foreach (Rule rule in Profile.rules)
            {
                if (rule.modifiers.Contains("radiation"))
                {
                    RuleData rd = kd.rules[rule.name];
                    rd.problem = Math.Max(rd.problem + amount, 0.0);
                }
            }
        }
Exemplo n.º 3
0
        internal void RemovePatient(string patientName)
        {
            if (!patientList.Contains(patientName))
            {
                return;
            }

            patientList.Remove(patientName);
            KerbalData kd  = DB.Kerbal(patientName);
            string     key = resource + ",";
            int        p   = kd.sickbay.IndexOf(key, 0, StringComparison.Ordinal);

            if (p >= 0)
            {
                kd.sickbay = kd.sickbay.Remove(p, key.Length);
            }
            patients = string.Join(",", patientList.ToArray());
            if (running)
            {
                running = patientList.Count > 0 && (slots > 0 || cureEverybody);
            }
        }
Exemplo n.º 4
0
        // return true if the vessel is a rescue mission
        public static bool IsRescueMission(Vessel v)
        {
            // avoid corner-case situation on the first update : rescue vessel handling code is called
            // after the VesselData creation, causing Vesseldata evaluation to be delayed, causing anything
            // that rely on it to fail on its first update or in OnStart
            if (v.situation == Vessel.Situations.PRELAUNCH)
            {
                return(false);
            }

            // if at least one of the crew is flagged as rescue, consider it a rescue mission
            foreach (var c in Lib.CrewList(v))
            {
                if (DB.Kerbal(c.name).rescue)
                {
                    return(true);
                }
            }


            // not a rescue mission
            return(false);
        }
Exemplo n.º 5
0
        void Problem_kerbals(List <ProtoCrewMember> crew, ref List <Texture2D> icons, ref List <string> tooltips)
        {
            UInt32 health_severity = 0;
            UInt32 stress_severity = 0;

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

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

                foreach (Rule r in Profile.rules)
                {
                    RuleData rd = kd.Rule(r.name);
                    if (rd.problem > r.danger_threshold)
                    {
                        if (!r.breakdown)
                        {
                            health_severity = Math.Max(health_severity, 2);
                        }
                        else
                        {
                            stress_severity = Math.Max(stress_severity, 2);
                        }
                        tooltips.Add(Lib.BuildString(c.name, ": <b>", r.name, "</b>"));
                    }
                    else if (rd.problem > r.warning_threshold)
                    {
                        if (!r.breakdown)
                        {
                            health_severity = Math.Max(health_severity, 1);
                        }
                        else
                        {
                            stress_severity = Math.Max(stress_severity, 1);
                        }
                        tooltips.Add(Lib.BuildString(c.name, ": <b>", r.name, "</b>"));
                    }
                }
            }
            if (health_severity == 1)
            {
                icons.Add(Icons.health_yellow);
            }
            else if (health_severity == 2)
            {
                icons.Add(Icons.health_red);
            }
            if (stress_severity == 1)
            {
                icons.Add(Icons.brain_yellow);
            }
            else if (stress_severity == 2)
            {
                icons.Add(Icons.brain_red);
            }
        }
Exemplo n.º 6
0
		// return true if the vessel is a kerbal eva, and is flagged as dead
		public static bool IsDead(Vessel v)
		{
			if (!v.isEVA) return false;
			return DB.Kerbal(Lib.CrewList(v)[0].name).eva_dead;
		}
Exemplo n.º 7
0
        static void Render_crew(Panel p, List <ProtoCrewMember> crew)
        {
            // do nothing if there isn't a crew, or if there are no rules
            if (crew.Count == 0 || Profile.rules.Count == 0)
            {
                return;
            }

            // panel section
            p.AddSection(Local.TELEMETRY_VITALS);            //"VITALS"

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

                // analyze issues
                UInt32 health_severity = 0;
                UInt32 stress_severity = 0;

                // generate tooltip
                List <string> tooltips = new List <string>();
                foreach (Rule r in Profile.rules)
                {
                    // get rule data
                    RuleData rd = kd.Rule(r.name);

                    // add to the tooltip
                    tooltips.Add(Lib.BuildString("<b>", Lib.HumanReadablePerc(rd.problem / r.fatal_threshold), "</b>\t", r.title));

                    // analyze issue
                    if (rd.problem > r.danger_threshold)
                    {
                        if (!r.breakdown)
                        {
                            health_severity = Math.Max(health_severity, 2);
                        }
                        else
                        {
                            stress_severity = Math.Max(stress_severity, 2);
                        }
                    }
                    else if (rd.problem > r.warning_threshold)
                    {
                        if (!r.breakdown)
                        {
                            health_severity = Math.Max(health_severity, 1);
                        }
                        else
                        {
                            stress_severity = Math.Max(stress_severity, 1);
                        }
                    }
                }
                string tooltip = Lib.BuildString("<align=left />", String.Join("\n", tooltips.ToArray()));

                // generate kerbal name
                string name = kerbal.name.ToLower().Replace(" kerman", string.Empty);

                // render selectable title
                p.AddContent(Lib.Ellipsis(name, Styles.ScaleStringLength(30)), kd.disabled ? Lib.Color(Local.TELEMETRY_HYBERNATED, Lib.Kolor.Cyan) : string.Empty);                //"HYBERNATED"
                p.AddRightIcon(health_severity == 0 ? Textures.health_white : health_severity == 1 ? Textures.health_yellow : Textures.health_red, tooltip);
                p.AddRightIcon(stress_severity == 0 ? Textures.brain_white : stress_severity == 1 ? Textures.brain_yellow : Textures.brain_red, tooltip);
            }
        }
Exemplo n.º 8
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);
            }
        }
Exemplo n.º 9
0
        // kill a kerbal
        // note: you can't kill a kerbal while iterating over vessel crew list, do it outside the loop
        public static void Kill(Vessel v, ProtoCrewMember c)
        {
            // if on pod
            if (!v.isEVA)
            {
                // forget kerbal data
                DB.kerbals.Remove(c.name);

                // if vessel is loaded
                if (v.loaded)
                {
                    // find part
                    Part part = null;
                    foreach (Part p in v.parts)
                    {
                        if (p.protoModuleCrew.Find(k => k.name == c.name) != null)
                        {
                            part = p; break;
                        }
                    }

                    // remove kerbal from part
                    part.RemoveCrewmember(c);

                    // and from vessel
                    v.RemoveCrew(c);

                    // then kill it
                    c.Die();
                }
                // if vessel is not loaded
                else
                {
                    // find proto part
                    ProtoPartSnapshot part = null;
                    foreach (ProtoPartSnapshot p in v.protoVessel.protoPartSnapshots)
                    {
                        if (p.HasCrew(c.name))
                        {
                            part = p; break;
                        }
                    }

                    // remove from part
                    part.RemoveCrew(c.name);

                    // and from vessel
                    v.protoVessel.RemoveCrew(c);

                    // flag as dead
                    c.rosterStatus = ProtoCrewMember.RosterStatus.Dead;
                }
            }
            // else it must be an eva death
            else
            {
                // flag as eva death
                DB.Kerbal(c.name).eva_dead = true;

                // rename vessel
                v.vesselName = c.name + "'s body";
            }

            // remove reputation
            if (HighLogic.CurrentGame.Mode == Game.Modes.CAREER)
            {
                Reputation.Instance.AddReputation(-Settings.DeathReputation, TransactionReasons.Any);
            }
        }
Exemplo n.º 10
0
        public void Execute(Vessel v, VesselData vd, VesselResources resources, double elapsed_s)
        {
            // store list of crew to kill
            List <ProtoCrewMember> deferred_kills = new List <ProtoCrewMember>();

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

            // determine message variant
            uint variant = vd.EnvTemperature < Settings.LifeSupportSurvivalTemperature ? 0 : 1u;

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

            bool lifetime_enabled = PreferencesRadiation.Instance.lifetime;

            // 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);
                rd.lifetime = lifetime_enabled && lifetime;

                // influence consumption by elapsed time
                double step = elapsed_s;

                // if interval-based
                if (interval > 0.0)
                {
                    // accumulate time
                    rd.time_since += elapsed_s;

                    // determine number of intervals that has passed (can be 2 or more if elapsed_s > interval * 2)
                    step = Math.Floor(rd.time_since / interval);

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

                // if there is a resource specified
                if (res != null && rate > double.Epsilon)
                {
                    // get rate including per-kerbal variance
                    double resRate =
                        rate                                                        // consumption rate
                        * Variance(name, c, individuality)                          // kerbal-specific variance
                        * k;                                                        // product of environment modifiers

                    // determine amount of resource to consume

                    double required = resRate * step;                           // seconds elapsed or interval amount

                    // remember if a meal is consumed/produced in this simulation step
                    if (interval > 0.0)
                    {
                        double ratePerStep = resRate / interval;
                        res.UpdateIntervalRule(-required, -ratePerStep, name);
                        if (output.Length > 0)
                        {
                            ResourceCache.GetResource(v, output).UpdateIntervalRule(required * ratio, ratePerStep * ratio, name);
                        }
                    }

                    // if continuous, or if one or more intervals elapsed
                    if (step > 0.0)
                    {
                        // if there is no output
                        if (output.Length == 0)
                        {
                            // simply consume (that is faster)
                            res.Consume(required, name);
                        }
                        // if there is an output
                        else
                        {
                            // transform input into output resource
                            // - rules always dump excess overboard (because it is waste)
                            ResourceRecipe recipe = new ResourceRecipe(name);
                            recipe.AddInput(input, required);
                            recipe.AddOutput(output, required * ratio, true);
                            resources.AddRecipe(recipe);
                        }
                    }
                }

                // if continuous, or if one or more intervals elapsed
                if (step > 0.0)
                {
                    // 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(name, c, variance);                 // kerbal-specific variance
                    }
                    // else slowly recover
                    else
                    {
                        rd.problem *= 1.0 / (1.0 + Math.Max(interval, 1.0) * step * 0.002);
                    }
                }

                bool do_breakdown = false;

                if (breakdown)
                {
                    // don't do breakdowns and don't show stress message if disabled
                    if (!PreferencesComfort.Instance.stressBreakdowns)
                    {
                        return;
                    }

                    // stress level
                    double breakdown_probability = rd.problem / warning_threshold;
                    breakdown_probability = Lib.Clamp(breakdown_probability, 0.0, 1.0);

                    // use the stupidity of a kerbal.
                    // however, nobody is perfect - not even a kerbal with a stupidity of 0.
                    breakdown_probability *= c.stupidity * 0.6 + 0.4;

                    // apply the weekly error rate
                    breakdown_probability *= PreferencesComfort.Instance.stressBreakdownRate;

                    // now we have the probability for one failure per week, based on the
                    // individual stupidity and stress level of the kerbal.

                    breakdown_probability = (breakdown_probability * elapsed_s) / (Lib.DaysInYear * Lib.HoursInDay * 3600);
                    if (breakdown_probability > Lib.RandomDouble())
                    {
                        do_breakdown = true;

                        // we're stressed out and just made a major mistake, this further increases the stress level...
                        rd.problem += warning_threshold * 0.05;                         // add 5% of the warning treshold to current stress level
                    }
                }

                // kill kerbal if necessary
                if (rd.problem >= fatal_threshold)
                {
#if DEBUG || DEVBUILD
                    Lib.Log("Rule " + name + " kills " + c.name + " at " + rd.problem + " " + degeneration + "/" + k + "/" + step + "/" + Variance(name, c, variance));
#endif
                    if (fatal_message.Length > 0)
                    {
                        Message.Post(breakdown ? Severity.breakdown : Severity.fatality, Lib.ExpandMsg(fatal_message, v, c, variant));
                    }

                    if (breakdown)
                    {
                        do_breakdown = true;

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

                        // make sure next danger message 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;
                }

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

            // execute the deferred kills
            foreach (ProtoCrewMember c in deferred_kills)
            {
                Misc.Kill(v, c);
            }
        }
Exemplo n.º 11
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 < PreferencesLifeSupport.Instance.survivalTemperature ? 0 : 1u;

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

            bool lifetime_enabled = PreferencesBasic.Instance.lifetime;

            // 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);
                rd.lifetime = lifetime_enabled && lifetime;

                // 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
                    if (step > 0.99)
                    {
                        res.SetMealHappened();
                    }
                    if (output.Length > 0 && step > 0.99)
                    {
                        ResourceCache.Info(v, output).SetMealHappened();
                    }
                }

                // if continuous, or if one or more intervals elapsed
                if (step > double.Epsilon)
                {
                    double r = rate * Variance(name, c, individuality);                      // kerbal-specific variance

                    // if there is a resource specified
                    if (res != null && r > double.Epsilon)
                    {
                        // determine amount of resource to consume
                        double required = r                                   // 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 monitor is false
                        else if (!monitor)
                        {
                            // transform input into output resource
                            // - rules always dump excess overboard (because it is waste)
                            Resource_recipe recipe = new Resource_recipe((Part)null);                              // kerbals are not associated with a part
                            recipe.Input(input, required);
                            recipe.Output(output, required * ratio, true);
                            resources.Transform(recipe);
                        }
                        // if monitor then do not consume input resource and only produce output if resource percentage + monitor_offset is < 100%
                        else if ((res.amount / res.capacity) + monitor_offset < 1.0)
                        {
                            // simply produce (that is faster)
                            resources.Produce(v, output, required * ratio);
                        }
                    }

                    // 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) + monitor_offset >= 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(name, c, variance);                 // kerbal-specific variance
                    }
                    // else slowly recover
                    else
                    {
                        rd.problem *= 1.0 / (1.0 + Math.Max(interval, 1.0) * step * 0.002);
                    }
                }

                bool do_breakdown = false;

                if (breakdown && PreferencesBasic.Instance.stressBreakdowns)
                {
                    // stress level
                    double breakdown_probability = rd.problem / warning_threshold;
                    breakdown_probability = Lib.Clamp(breakdown_probability, 0.0, 1.0);

                    // use the stupidity of a kerbal.
                    // however, nobody is perfect - not even a kerbal with a stupidity of 0.
                    breakdown_probability *= c.stupidity * 0.6 + 0.4;

                    // apply the weekly error rate
                    breakdown_probability *= PreferencesBasic.Instance.stressBreakdownRate;

                    // now we have the probability for one failure per week, based on the
                    // individual stupidity and stress level of the kerbal.

                    breakdown_probability = (breakdown_probability * elapsed_s) / (Lib.DaysInYear() * Lib.HoursInDay() * 3600);
                    if (breakdown_probability > Lib.RandomDouble())
                    {
                        do_breakdown = true;

                        // we're stressed out and just made a major mistake, this further increases the stress level...
                        rd.problem += warning_threshold * 0.05;                         // add 5% of the warning treshold to current stress level
                    }
                }

                // 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)
                    {
                        do_breakdown = true;

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

                        // make sure next danger message 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;
                }

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

            // execute the deferred kills
            foreach (ProtoCrewMember c in deferred_kills)
            {
                Misc.Kill(v, c);
            }
        }
Exemplo n.º 12
0
        /// <summary>
        /// Execute the recipe and record deferred consumption/production for inputs/ouputs.
        /// This need to be called multiple times until left &lt;= 0.0 for complete execution of the recipe.
        /// return true if recipe execution is completed, false otherwise
        /// </summary>
        private bool ExecuteRecipeStep(Vessel v, VesselResources resources)
        {
            // determine worst input ratio
            // - pure input recipes can just underflow
            double worst_input = left;

            if (outputs.Count > 0)
            {
                for (int i = 0; i < inputs.Count; ++i)
                {
                    Entry        e   = inputs[i];
                    ResourceInfo res = resources.GetResource(v, e.name);

                    // handle combined inputs
                    if (e.combined != null)
                    {
                        // is combined resource the primary
                        if (e.combined != "")
                        {
                            Entry        sec_e     = inputs.Find(x => x.name.Contains(e.combined));
                            ResourceInfo sec       = resources.GetResource(v, sec_e.name);
                            double       pri_worst = Lib.Clamp((res.Amount + res.Deferred) * e.inv_quantity, 0.0, worst_input);
                            if (pri_worst > 0.0)
                            {
                                worst_input = pri_worst;
                            }
                            else
                            {
                                worst_input = Lib.Clamp((sec.Amount + sec.Deferred) * sec_e.inv_quantity, 0.0, worst_input);
                            }
                        }
                    }
                    else
                    {
                        worst_input = Lib.Clamp((res.Amount + res.Deferred) * e.inv_quantity, 0.0, worst_input);
                    }
                }
            }

            // determine worst output ratio
            // - pure output recipes can just overflow
            double worst_output = left;

            if (inputs.Count > 0)
            {
                for (int i = 0; i < outputs.Count; ++i)
                {
                    Entry e = outputs[i];
                    if (!e.dump)                     // ignore outputs that can dump overboard
                    {
                        ResourceInfo res = resources.GetResource(v, e.name);
                        worst_output = Lib.Clamp((res.Capacity - (res.Amount + res.Deferred)) * e.inv_quantity, 0.0, worst_output);
                    }
                }
            }

            // determine worst-io
            double worst_io = Math.Min(worst_input, worst_output);

            // consume inputs
            for (int i = 0; i < inputs.Count; ++i)
            {
                Entry        e   = inputs[i];
                ResourceInfo res = resources.GetResource(v, e.name);
                // handle combined inputs
                if (e.combined != null)
                {
                    // is combined resource the primary
                    if (e.combined != "")
                    {
                        Entry        sec_e = inputs.Find(x => x.name.Contains(e.combined));
                        ResourceInfo sec   = resources.GetResource(v, sec_e.name);
                        double       need  = (e.quantity * worst_io) + (sec_e.quantity * worst_io);
                        // do we have enough primary to satisfy needs, if so don't consume secondary
                        if (res.Amount + res.Deferred >= need)
                        {
                            resources.Consume(v, e.name, need, name);
                        }
                        // consume primary if any available and secondary
                        else
                        {
                            need -= res.Amount + res.Deferred;
                            res.Consume(res.Amount + res.Deferred, name);
                            sec.Consume(need, name);
                        }
                    }
                }
                else
                {
                    res.Consume(e.quantity * worst_io, name);
                }
            }

            // produce outputs
            for (int i = 0; i < outputs.Count; ++i)
            {
                Entry        e   = outputs[i];
                ResourceInfo res = resources.GetResource(v, e.name);
                res.Produce(e.quantity * worst_io, name);
            }

            // produce cures
            for (int i = 0; i < cures.Count; ++i)
            {
                Entry           entry       = cures[i];
                List <RuleData> curingRules = new List <RuleData>();
                foreach (ProtoCrewMember crew in v.GetVesselCrew())
                {
                    KerbalData kd = DB.Kerbal(crew.name);
                    if (kd.sickbay.IndexOf(entry.combined + ",", StringComparison.Ordinal) >= 0)
                    {
                        curingRules.Add(kd.Rule(entry.name));
                    }
                }

                foreach (RuleData rd in curingRules)
                {
                    rd.problem -= entry.quantity * worst_io / curingRules.Count;
                    rd.problem  = Math.Max(rd.problem, 0);
                }
            }

            // update amount left to execute
            left -= worst_io;

            // the recipe was executed, at least partially
            return(worst_io > double.Epsilon);
        }