static void ProcessCommand(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, ModuleCommand command, Vessel_resources 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); } } }
private static bool DoRecord(Experiment experiment, string subject_id, Vessel vessel, Resource_info ec, uint hdId, Vessel_resources resources, List <KeyValuePair <string, double> > resourceDefs, double remainingSampleMass, double dataSampled, out double sampledOut, out double remainingSampleMassOut) { // default output values for early returns sampledOut = dataSampled; remainingSampleMassOut = remainingSampleMass; var exp = Science.Experiment(subject_id); if (Done(exp, dataSampled)) { return(true); } double elapsed = Kerbalism.elapsed_s; double chunkSize = Math.Min(experiment.data_rate * elapsed, exp.max_amount); double massDelta = experiment.sample_mass * chunkSize / exp.max_amount; Drive drive = GetDrive(experiment, vessel, hdId, chunkSize, subject_id); // on high time warp this chunk size could be too big, but we could store a sizable amount if we process less bool isFile = experiment.sample_mass < float.Epsilon; double maxCapacity = isFile ? drive.FileCapacityAvailable() : drive.SampleCapacityAvailable(subject_id); Drive warpCacheDrive = null; if (isFile) { if (drive.GetFileSend(subject_id)) { warpCacheDrive = Cache.WarpCache(vessel); } if (warpCacheDrive != null) { maxCapacity += warpCacheDrive.FileCapacityAvailable(); } } double factor = Rate(vessel, chunkSize, maxCapacity, elapsed, ec, experiment.ec_rate, resources, resourceDefs); if (factor < double.Epsilon) { return(false); } chunkSize *= factor; massDelta *= factor; elapsed *= factor; bool stored = false; if (chunkSize > double.Epsilon) { if (isFile) { if (warpCacheDrive != null) { double s = Math.Min(chunkSize, warpCacheDrive.FileCapacityAvailable()); stored = warpCacheDrive.Record_file(subject_id, s, true); if (chunkSize > s) // only write to persisted drive if the data cannot be transmitted in this tick { stored &= drive.Record_file(subject_id, chunkSize - s, true); } } else { stored = drive.Record_file(subject_id, chunkSize, true); } } else { stored = drive.Record_sample(subject_id, chunkSize, massDelta); } } if (!stored) { return(false); } // consume resources ec.Consume(experiment.ec_rate * elapsed, "experiment"); foreach (var p in resourceDefs) { resources.Consume(vessel, p.Key, p.Value * elapsed, "experiment"); } dataSampled += chunkSize; dataSampled = Math.Min(dataSampled, exp.max_amount); sampledOut = dataSampled; if (!experiment.sample_collecting) { remainingSampleMass -= massDelta; remainingSampleMass = Math.Max(remainingSampleMass, 0); } remainingSampleMassOut = remainingSampleMass; return(true); }
void ToEVA(GameEvents.FromToAction <Part, Part> data) { Cache.PurgeObjects(data.from.vessel); Cache.PurgeObjects(data.to.vessel); // get total crew in the origin vessel double tot_crew = Lib.CrewCount(data.from.vessel) + 1.0; // get vessel resources handler Vessel_resources 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.Info(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", PreferencesLifeSupport.Instance.evaAtmoLoss, "airlock"); // 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, Lib.BuildString("There isn't any <b>", prop_name, "</b> 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 DB.Vessel(data.from.vessel).computer.Execute(data.from.vessel, ScriptType.eva_out); }
private static bool DoRecord(Experiment experiment, string subject_id, Vessel vessel, Resource_info ec, uint hdId, Vessel_resources resources, List <KeyValuePair <string, double> > resourceDefs, double remainingSampleMass, double dataSampled, out double sampledOut, out double remainingSampleMassOut) { var exp = Science.Experiment(subject_id); if (Done(exp, dataSampled)) { sampledOut = dataSampled; remainingSampleMassOut = remainingSampleMass; return(true); } double elapsed = Kerbalism.elapsed_s; double chunkSize = Math.Min(experiment.data_rate * elapsed, exp.max_amount); double massDelta = experiment.sample_mass * chunkSize / exp.max_amount; Drive drive = GetDrive(experiment, vessel, hdId, chunkSize, subject_id); // on high time warp this chunk size could be too big, but we could store a sizable amount if we process less bool isFile = experiment.sample_mass < float.Epsilon; double maxCapacity = isFile ? drive.FileCapacityAvailable() : drive.SampleCapacityAvailable(subject_id); if (maxCapacity < chunkSize) { double factor = maxCapacity / chunkSize; chunkSize *= factor; massDelta *= factor; elapsed *= factor; } foreach (var p in resourceDefs) { resources.Consume(vessel, p.Key, p.Value * elapsed, "experiment"); } bool stored = false; if (isFile) { stored = drive.Record_file(subject_id, chunkSize, true); } else { stored = drive.Record_sample(subject_id, chunkSize, massDelta); } if (stored) { // consume ec ec.Consume(experiment.ec_rate * elapsed, "experiment"); dataSampled += chunkSize; dataSampled = Math.Min(dataSampled, exp.max_amount); sampledOut = dataSampled; if (!experiment.sample_collecting) { remainingSampleMass -= massDelta; remainingSampleMass = Math.Max(remainingSampleMass, 0); } remainingSampleMassOut = remainingSampleMass; return(true); } sampledOut = dataSampled; remainingSampleMassOut = remainingSampleMass; return(false); }
// execute the recipe public bool Execute(Vessel v, Vessel_resources 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]; Resource_info res = resources.Info(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)); Resource_info sec = resources.Info(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 { Resource_info res = resources.Info(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]; // 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)); Resource_info sec = resources.Info(v, sec_e.name); Resource_info res = resources.Info(v, 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); } // consume primary if any available and secondary else { need -= res.amount + res.deferred; resources.Consume(v, e.name, res.amount + res.deferred); resources.Consume(v, sec_e.name, need); } } } else { resources.Consume(v, e.name, e.quantity * worst_io); } } // produce outputs for (int i = 0; i < outputs.Count; ++i) { Entry e = outputs[i]; resources.Produce(v, e.name, e.quantity * worst_io); } // update amount left to execute left -= worst_io; // the recipe was executed, at least partially return(worst_io > double.Epsilon); }