/// <summary>obtain information on resource metrics for any resource contained within simulated vessel</summary> public SimulatedResource Resource(string name) { SimulatedResource res; if (!resources.TryGetValue(name, out res)) { res = new SimulatedResource(name); resources.Add(name, res); } return res; }
///<summary> Add habitat sub-panel, including tooltips </summary> private static void AddSubPanelHabitat(Panel p) { SimulatedResource atmo_res = resource_sim.Resource("Atmosphere"); SimulatedResource waste_res = resource_sim.Resource("WasteAtmosphere"); SimulatedResource moist_res = resource_sim.Resource("MoistAtmosphere"); // generate tooltips string atmo_tooltip = atmo_res.Tooltip(); string waste_tooltip = waste_res.Tooltip(true); string moist_tooltip = moist_res.Tooltip(true); // generate status string for scrubbing string waste_status = !Features.Poisoning //< feature disabled ? "n/a" : waste_res.produced <= double.Epsilon //< unnecessary ? "not required" : waste_res.consumed <= double.Epsilon //< no scrubbing ? "<color=#ffff00>none</color>" : waste_res.produced > waste_res.consumed * 1.001 //< insufficient scrubbing ? "<color=#ffff00>inadequate</color>" : "good"; //< sufficient scrubbing // generate status string for humidity string moist_status = !Features.Humidity //< feature disabled ? "n/a" : moist_res.produced <= double.Epsilon //< unnecessary ? "not required" : moist_res.consumed <= double.Epsilon //< no humidity control ? "<color=#ffff00>none</color>" : moist_res.produced > moist_res.consumed * 1.001 //< insufficient humidity control ? "<color=#ffff00>inadequate</color>" : "good"; //< sufficient humidity control // generate status string for pressurization string atmo_status = !Features.Pressure //< feature disabled ? "n/a" : atmo_res.consumed <= double.Epsilon //< unnecessary ? "not required" : atmo_res.produced <= double.Epsilon //< no pressure control ? "<color=#ffff00>none</color>" : atmo_res.consumed > atmo_res.produced * 1.001 //< insufficient pressure control ? "<color=#ffff00>inadequate</color>" : "good"; //< sufficient pressure control p.AddSection("HABITAT", string.Empty, () => { p.Prev(ref environment_index, panel_environment.Count); update = true; }, () => { p.Next(ref environment_index, panel_environment.Count); update = true; }); p.AddContent("volume", Lib.HumanReadableVolume(vessel_analyzer.volume), "volume of enabled habitats"); p.AddContent("surface", Lib.HumanReadableSurface(vessel_analyzer.surface), "surface of enabled habitats"); p.AddContent("scrubbing", waste_status, waste_tooltip); p.AddContent("humidity", moist_status, moist_tooltip); p.AddContent("pressurization", atmo_status, atmo_tooltip); p.AddContent("EVA's available", env_analyzer.breathable ? "infinite" : Lib.HumanReadableInteger(vessel_analyzer.evas), env_analyzer.breathable ? "breathable atmosphere" : "approx (derived from stored N2)"); }
///<summary> Add electric charge sub-panel, including tooltips </summary> private static void AddSubPanelEC(Panel p) { // get simulated resource SimulatedResource res = resource_sim.Resource("ElectricCharge"); // create tooltip string tooltip = res.Tooltip(); // render the panel section p.AddSection(Local.Planner_ELECTRICCHARGE); //"ELECTRIC CHARGE" p.AddContent(Local.Planner_storage, Lib.HumanReadableAmount(res.storage), tooltip); //"storage" p.AddContent(Local.Planner_consumed, Lib.HumanReadableRate(res.consumed), tooltip); //"consumed" p.AddContent(Local.Planner_produced, Lib.HumanReadableRate(res.produced), tooltip); //"produced" p.AddContent(Local.Planner_duration, Lib.HumanReadableDuration(res.Lifetime())); //"duration" }
///<summary> Add supply resource sub-panel, including tooltips </summary> ///<remarks> /// does not include electric charge /// does not include special resources like waste atmosphere /// restricted to resources that are configured explicitly in the profile as supplies ///</remarks> private static void AddSubPanelResource(Panel p, string res_name) { // get simulated resource SimulatedResource res = resource_sim.Resource(res_name); // create tooltip string tooltip = res.Tooltip(); // render the panel section p.AddSection(Lib.SpacesOnCaps(res_name).ToUpper(), string.Empty, () => { p.Prev(ref resource_index, panel_resource.Count); update = true; }, () => { p.Next(ref resource_index, panel_resource.Count); update = true; }); p.AddContent("storage", Lib.HumanReadableAmount(res.storage), tooltip); p.AddContent("consumed", Lib.HumanReadableRate(res.consumed), tooltip); p.AddContent("produced", Lib.HumanReadableRate(res.produced), tooltip); p.AddContent("duration", Lib.HumanReadableDuration(res.Lifetime())); }
///<summary> Add supply resource sub-panel, including tooltips </summary> ///<remarks> /// does not include electric charge /// does not include special resources like waste atmosphere /// restricted to resources that are configured explicitly in the profile as supplies ///</remarks> private static void AddSubPanelResource(Panel p, string res_name) { // get simulated resource SimulatedResource res = resource_sim.Resource(res_name); // create tooltip string tooltip = res.Tooltip(); var resource = PartResourceLibrary.Instance.resourceDefinitions[res_name]; // render the panel section p.AddSection(Lib.SpacesOnCaps(resource.displayName).ToUpper(), string.Empty, () => { p.Prev(ref resource_index, panel_resource.Count); enforceUpdate = true; }, () => { p.Next(ref resource_index, panel_resource.Count); enforceUpdate = true; }); p.AddContent(Local.Planner_storage, Lib.HumanReadableAmount(res.storage), tooltip); //"storage" p.AddContent(Local.Planner_consumed, Lib.HumanReadableRate(res.consumed), tooltip); //"consumed" p.AddContent(Local.Planner_produced, Lib.HumanReadableRate(res.produced), tooltip); //"produced" p.AddContent(Local.Planner_duration, Lib.HumanReadableDuration(res.Lifetime())); //"duration" }
///<summary> Add habitat sub-panel, including tooltips </summary> private static void AddSubPanelHabitat(Panel p) { SimulatedResource atmo_res = resource_sim.Resource("Atmosphere"); SimulatedResource waste_res = resource_sim.Resource("WasteAtmosphere"); // generate tooltips string atmo_tooltip = atmo_res.Tooltip(); string waste_tooltip = waste_res.Tooltip(true); // generate status string for scrubbing string waste_status = !Features.Poisoning //< feature disabled ? "n/a" : waste_res.produced <= double.Epsilon //< unnecessary ? Local.Planner_scrubbingunnecessary //"not required" : waste_res.consumed <= double.Epsilon //< no scrubbing ? Lib.Color(Local.Planner_noscrubbing, Lib.Kolor.Orange) //"none" : waste_res.produced > waste_res.consumed * 1.001 //< insufficient scrubbing ? Lib.Color(Local.Planner_insufficientscrubbing, Lib.Kolor.Yellow) //"inadequate" : Lib.Color(Local.Planner_sufficientscrubbing, Lib.Kolor.Green); //"good" //< sufficient scrubbing // generate status string for pressurization string atmo_status = !Features.Pressure //< feature disabled ? "n/a" : atmo_res.consumed <= double.Epsilon //< unnecessary ? Local.Planner_pressurizationunnecessary //"not required" : atmo_res.produced <= double.Epsilon //< no pressure control ? Lib.Color(Local.Planner_nopressurecontrol, Lib.Kolor.Orange) //"none" : atmo_res.consumed > atmo_res.produced * 1.001 //< insufficient pressure control ? Lib.Color(Local.Planner_insufficientpressurecontrol, Lib.Kolor.Yellow) //"inadequate" : Lib.Color(Local.Planner_sufficientpressurecontrol, Lib.Kolor.Green); //"good" //< sufficient pressure control p.AddSection(Local.Planner_HABITAT, string.Empty, //"HABITAT" () => { p.Prev(ref environment_index, panel_environment.Count); enforceUpdate = true; }, () => { p.Next(ref environment_index, panel_environment.Count); enforceUpdate = true; }); p.AddContent(Local.Planner_volume, Lib.HumanReadableVolume(vessel_analyzer.volume), Local.Planner_volume_tip); //"volume""volume of enabled habitats" p.AddContent(Local.Planner_habitatssurface, Lib.HumanReadableSurface(vessel_analyzer.surface), Local.Planner_habitatssurface_tip); //"surface""surface of enabled habitats" p.AddContent(Local.Planner_scrubbing, waste_status, waste_tooltip); //"scrubbing" p.AddContent(Local.Planner_pressurization, atmo_status, atmo_tooltip); //"pressurization" }
void Process_greenhouse(Greenhouse g, EnvironmentAnalyzer env, VesselAnalyzer va) { // skip disabled greenhouses if (!g.active) return; // shortcut to resources SimulatedResource ec = Resource("ElectricCharge"); SimulatedResource res = Resource(g.crop_resource); // calculate natural and artificial lighting double natural = env.solar_flux; double artificial = Math.Max(g.light_tolerance - natural, 0.0); // if lamps are on and artificial lighting is required if (artificial > 0.0) { // consume ec for the lamps ec.Consume(g.ec_rate * (artificial / g.light_tolerance), "greenhouse"); } // execute recipe SimulatedRecipe recipe = new SimulatedRecipe(g.part, "greenhouse"); foreach (ModuleResource input in g.resHandler.inputResources) { // WasteAtmosphere is primary combined input if (g.WACO2 && input.name == "WasteAtmosphere") recipe.Input(input.name, env.breathable ? 0.0 : input.rate, "CarbonDioxide"); // CarbonDioxide is secondary combined input else if (g.WACO2 && input.name == "CarbonDioxide") recipe.Input(input.name, env.breathable ? 0.0 : input.rate, ""); // if atmosphere is breathable disable WasteAtmosphere / CO2 else if (!g.WACO2 && (input.name == "CarbonDioxide" || input.name == "WasteAtmosphere")) recipe.Input(input.name, env.breathable ? 0.0 : input.rate, ""); else recipe.Input(input.name, input.rate); } foreach (ModuleResource output in g.resHandler.outputResources) { // if atmosphere is breathable disable Oxygen if (output.name == "Oxygen") recipe.Output(output.name, env.breathable ? 0.0 : output.rate, true); else recipe.Output(output.name, output.rate, true); } recipes.Add(recipe); // determine environment conditions bool lighting = natural + artificial >= g.light_tolerance; bool pressure = va.pressurized || g.pressure_tolerance <= double.Epsilon; bool radiation = (env.landed ? env.surface_rad : env.magnetopause_rad) * (1.0 - va.shielding) < g.radiation_tolerance; // if all conditions apply // note: we are assuming the inputs are satisfied, we can't really do otherwise here if (lighting && pressure && radiation) { // produce food res.Produce(g.crop_size * g.crop_rate, "greenhouse"); // add harvest info res.harvests.Add(Lib.BuildString(g.crop_size.ToString("F0"), " in ", Lib.HumanReadableDuration(1.0 / g.crop_rate))); } }
// execute the recipe public bool Execute(ResourceSimulator sim) { // determine worst input ratio double worst_input = left; if (outputs.Count > 0) { for (int i = 0; i < inputs.Count; ++i) { Resource_recipe.Entry e = inputs[i]; SimulatedResourceView res = sim.Resource(e.name).GetSimulatedResourceView(loaded_part); // handle combined inputs if (e.combined != null) { // is combined resource the primary if (e.combined != "") { Resource_recipe.Entry sec_e = inputs.Find(x => x.name.Contains(e.combined)); SimulatedResourceView sec = sim.Resource(sec_e.name).GetSimulatedResourceView(loaded_part); double pri_worst = Lib.Clamp(res.amount * e.inv_quantity, 0.0, worst_input); if (pri_worst > 0.0) { worst_input = pri_worst; } else { worst_input = Lib.Clamp(sec.amount * sec_e.inv_quantity, 0.0, worst_input); } } } else { worst_input = Lib.Clamp(res.amount * e.inv_quantity, 0.0, worst_input); } } } // determine worst output ratio double worst_output = left; if (inputs.Count > 0) { for (int i = 0; i < outputs.Count; ++i) { Resource_recipe.Entry e = outputs[i]; if (!e.dump) // ignore outputs that can dump overboard { SimulatedResourceView res = sim.Resource(e.name).GetSimulatedResourceView(loaded_part); worst_output = Lib.Clamp((res.capacity - res.amount) * 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) { Resource_recipe.Entry e = inputs[i]; SimulatedResource res = sim.Resource(e.name); // handle combined inputs if (e.combined != null) { // is combined resource the primary if (e.combined != "") { Resource_recipe.Entry sec_e = inputs.Find(x => x.name.Contains(e.combined)); SimulatedResourceView sec = sim.Resource(sec_e.name).GetSimulatedResourceView(loaded_part); 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 >= need) { res.Consume(need, name); } // consume primary if any available and secondary else { need -= res.amount; res.Consume(res.amount, name); sec.Consume(need, name); } } } else { res.Consume(e.quantity * worst_io, name); } } // produce outputs for (int i = 0; i < outputs.Count; ++i) { Resource_recipe.Entry e = outputs[i]; SimulatedResourceView res = sim.Resource(e.name).GetSimulatedResourceView(loaded_part); res.Produce(e.quantity * worst_io, name); } // update amount left to execute left -= worst_io; // the recipe was executed, at least partially return(worst_io > double.Epsilon); }
public Simulated_resource_view_impl(Part p, string resource_name, SimulatedResource i) { info = i; location = info.vessel_wide_location; }