예제 #1
0
        /// <summary>
        /// Call ResourceUpdate on all part modules that have that method
        /// </summary>
        public void ResourceUpdate(VesselResources resources, double elapsed_s)
        {
            // only do this for loaded vessels. unloaded vessels will be handled in Background.cs
            if (!Vessel.loaded)
            {
                return;
            }

            if (resourceUpdateDelegates == null)
            {
                resourceUpdateDelegates = new List <ResourceUpdateDelegate>();
                foreach (var part in Vessel.parts)
                {
                    foreach (var module in part.Modules)
                    {
                        if (!module.isEnabled)
                        {
                            continue;
                        }
                        var resourceUpdateDelegate = ResourceUpdateDelegate.Instance(module);
                        if (resourceUpdateDelegate != null)
                        {
                            resourceUpdateDelegates.Add(resourceUpdateDelegate);
                        }
                    }
                }
            }

            if (resourceUpdateDelegates.Count == 0)
            {
                return;
            }

            List <ResourceInfo> allResources = resources.GetAllResources(Vessel);            // there might be some performance to be gained by caching the list of all resource

            Dictionary <string, double> availableResources = new Dictionary <string, double>();

            foreach (var ri in allResources)
            {
                availableResources[ri.ResourceName] = ri.Amount;
            }
            List <KeyValuePair <string, double> > resourceChangeRequests = new List <KeyValuePair <string, double> >();

            foreach (var resourceUpdateDelegate in resourceUpdateDelegates)
            {
                resourceChangeRequests.Clear();
                string title = resourceUpdateDelegate.invoke(availableResources, resourceChangeRequests);
                foreach (var rc in resourceChangeRequests)
                {
                    if (rc.Value > 0)
                    {
                        resources.Produce(Vessel, rc.Key, rc.Value * elapsed_s, title);
                    }
                    if (rc.Value < 0)
                    {
                        resources.Consume(Vessel, rc.Key, -rc.Value * elapsed_s, title);
                    }
                }
            }
        }
예제 #2
0
        private static void ProcessApiModule(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m,
                                             Part part_prefab, PartModule module_prefab, VesselResources resources, Dictionary <string, double> availableResources, List <KeyValuePair <string, double> > resourceChangeRequests, double elapsed_s)
        {
            resourceChangeRequests.Clear();

            try
            {
                string title = BackgroundDelegate.Instance(module_prefab).invoke(v, p, m, module_prefab, part_prefab, availableResources, resourceChangeRequests, elapsed_s);

                foreach (var cr in resourceChangeRequests)
                {
                    if (cr.Value > 0)
                    {
                        resources.Produce(v, cr.Key, cr.Value * elapsed_s, ResourceBroker.GetOrCreate(title));
                    }
                    else if (cr.Value < 0)
                    {
                        resources.Consume(v, cr.Key, -cr.Value * elapsed_s, ResourceBroker.GetOrCreate(title));
                    }
                }
            }
            catch (Exception ex)
            {
                Lib.Log("BackgroundUpdate in PartModule " + module_prefab.moduleName + " excepted: " + ex.Message + "\n" + ex.ToString());
            }
        }
예제 #3
0
        void ToEVA(GameEvents.FromToAction <Part, Part> data)
        {
            OnVesselModified(data.from.vessel);
            OnVesselModified(data.to.vessel);

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

            // get vessel resources handler
            VesselResources resources = ResourceCache.Get(data.from.vessel);

            // setup supply resources capacity in the eva kerbal
            Profile.SetupEva(data.to);

            string evaPropName = Lib.EvaPropellantName();

            // for each resource in the kerbal
            for (int i = 0; i < data.to.Resources.Count; ++i)
            {
                // get the resource
                PartResource res = data.to.Resources[i];

                // eva prop is handled differently
                if (res.resourceName == evaPropName)
                {
                    continue;
                }

                double quantity = Math.Min(resources.GetResource(data.from.vessel, res.resourceName).Amount / tot_crew, res.maxAmount);
                // remove resource from vessel
                quantity = data.from.RequestResource(res.resourceName, quantity);

                // add resource to eva kerbal
                data.to.RequestResource(res.resourceName, -quantity);
            }

            // Airlock loss
            resources.Consume(data.from.vessel, "Nitrogen", Settings.LifeSupportAtmoLoss, ResourceBroker.Generic);

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


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

            // execute script
            data.from.vessel.KerbalismData().computer.Execute(data.from.vessel, ScriptType.eva_out);

            // Start a coroutine for doing eva propellant resource transfers once the kerbal EVA is started (this is too early here)
            data.to.StartCoroutine(PostEVATweaks(data.from, data.to, evaPropName));
        }
예제 #4
0
 static void ProcessCommand(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, ModuleCommand command, VesselResources resources, double elapsed_s)
 {
     // do not consume if this is a MCM with no crew
     // rationale: for consistency, the game doesn't consume resources for MCM without crew in loaded vessels
     //            this make some sense: you left a vessel with some battery and nobody on board, you expect it to not consume EC
     if (command.minimumCrew == 0 || p.protoModuleCrew.Count > 0)
     {
         // for each input resource
         foreach (ModuleResource ir in command.resHandler.inputResources)
         {
             // consume the resource
             resources.Consume(v, ir.name, ir.rate * elapsed_s, ResourceBroker.Command);
         }
     }
 }
예제 #5
0
        void ToEVA(GameEvents.FromToAction <Part, Part> data)
        {
            OnVesselModified(data.from.vessel);
            OnVesselModified(data.to.vessel);

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

            // get vessel resources handler
            VesselResources resources = ResourceCache.Get(data.from.vessel);

            // setup supply resources capacity in the eva kerbal
            Profile.SetupEva(data.to);

            String prop_name = Lib.EvaPropellantName();

            // for each resource in the kerbal
            for (int i = 0; i < data.to.Resources.Count; ++i)
            {
                // get the resource
                PartResource res = data.to.Resources[i];

                // eva prop is handled differently
                if (res.resourceName == prop_name)
                {
                    continue;
                }

                double quantity = Math.Min(resources.GetResource(data.from.vessel, res.resourceName).Amount / tot_crew, res.maxAmount);
                // remove resource from vessel
                quantity = data.from.RequestResource(res.resourceName, quantity);

                // add resource to eva kerbal
                data.to.RequestResource(res.resourceName, -quantity);
            }

            // take as much of the propellant as possible. just imagine: there are 1.3 units left, and 12 occupants
            // in the ship. you want to send out an engineer to fix the chemical plant that produces monoprop,
            // and have to get from one end of the station to the other with just 0.1 units in the tank...
            // nope.
            double evaPropQuantity = data.from.RequestResource(prop_name, Lib.EvaPropellantCapacity());

            // We can't just add the monoprop here, because that doesn't always work. It might be related
            // to the fact that stock KSP wants to add 5 units of monoprop to new EVAs. Instead of fighting KSP here,
            // we just let it do it's thing and set our amount later in EVA.cs - which seems to work just fine.
            // don't put that into Cache.VesselInfo because that can be deleted before we get there
            Cache.SetVesselObjectsCache(data.to.vessel, "eva_prop", evaPropQuantity);

            // Airlock loss
            resources.Consume(data.from.vessel, "Nitrogen", Settings.LifeSupportAtmoLoss, ResourceBroker.Generic);

            // show warning if there is little or no EVA propellant in the suit
            if (evaPropQuantity <= 0.05 && !Lib.Landed(data.from.vessel))
            {
                Message.Post(Severity.danger,
                             Local.CallBackMsg_EvaNoMP.Format("<b>" + prop_name + "</b>"), Local.CallBackMsg_EvaNoMP2);       //Lib.BuildString("There isn't any <<1>> in the EVA suit")"Don't let the ladder go!"
            }

            // turn off headlamp light, to avoid stock bug that show them for a split second when going on eva
            KerbalEVA kerbal = data.to.FindModuleImplementing <KerbalEVA>();

            EVA.HeadLamps(kerbal, false);

            // execute script
            data.from.vessel.KerbalismData().computer.Execute(data.from.vessel, ScriptType.eva_out);
        }
예제 #6
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);
        }