Пример #1
0
		private void Process_apiModule(PartModule m, EnvironmentAnalyzer env, VesselAnalyzer va)
		{
			List<KeyValuePair<string, double>> resourcesList = new List<KeyValuePair<string, double>>();

			Dictionary<string, double> environment = new Dictionary<string, double>();
			environment["altitude"] = env.altitude;
			environment["orbital_period"] = env.orbital_period;
			environment["shadow_period"] = env.shadow_period;
			environment["shadow_time"] = env.shadow_time;
			environment["albedo_flux"] = env.albedo_flux;
			environment["solar_flux"] = env.solar_flux;
			environment["sun_dist"] = env.sun_dist;
			environment["temperature"] = env.temperature;
			environment["total_flux"] = env.total_flux;
			environment["temperature"] = env.temperature;
			environment["sunlight"] = Planner.Sunlight == Planner.SunlightState.Shadow ? 0 : 1;

			Lib.Log("resource count before call " + resourcesList.Count);

			string title = apiDelegates[m.moduleName].Invoke(m, resourcesList, env.body, environment);

			Lib.Log("resource count after call " + resourcesList.Count);

			foreach (var p in resourcesList)
			{
				var res = Resource(p.Key);
				if (p.Value >= 0)
					res.Produce(p.Value, title);
				else
					res.Consume(-p.Value, title);
			}
		}
Пример #2
0
        /// <summary>determine if the resources involved are restricted to a part, and then process a rule</summary>
        public void Process_rule(List <Part> parts, Rule r, EnvironmentAnalyzer env, VesselAnalyzer va)
        {
            // evaluate modifiers
            double k = Modifiers.Evaluate(env, va, this, r.modifiers);

            Process_rule_inner_body(k, null, r, env, va);
        }
Пример #3
0
 void Process_harvester(Harvester harvester, VesselAnalyzer va)
 {
     if (harvester.running && harvester.simulated_abundance > harvester.min_abundance)
     {
         SimulatedRecipe recipe = new SimulatedRecipe(harvester.part, "harvester");
         if (harvester.ec_rate > double.Epsilon)
         {
             recipe.Input("ElectricCharge", harvester.ec_rate);
         }
         recipe.Output(
             harvester.resource,
             Harvester.AdjustedRate(harvester, new CrewSpecs("Engineer@0"), va.crew, harvester.simulated_abundance),
             dump: false);
         recipes.Add(recipe);
     }
 }
Пример #4
0
		/// <summary>
		/// run simulator to get statistics a fraction of a second after the vessel would spawn
		/// in the configured environment (celestial body, orbit height and presence of sunlight)
		/// </summary>
		public void Analyze(List<Part> parts, EnvironmentAnalyzer env, VesselAnalyzer va)
		{
			// reach steady state, so all initial resources like WasteAtmosphere are produced
			// it is assumed that one cycle is needed to produce things that don't need inputs
			// another cycle is needed for processes to pick that up
			// another cycle may be needed for results of those processes to be picked up
			// two additional cycles are for having some margin
			for (int i = 0; i < 5; i++)
			{
				RunSimulator(parts, env, va);
			}

			// Do the actual run people will see from the simulator UI
			foreach (SimulatedResource r in resources.Values)
			{
				r.ResetSimulatorDisplayValues();
			}
			RunSimulator(parts, env, va);
		}
Пример #5
0
		void Process_harvester(ModuleResourceHarvester harvester, VesselAnalyzer va)
		{
			// calculate experience bonus
			float exp_bonus = harvester.UseSpecialistBonus
			  ? harvester.EfficiencyBonus * (harvester.SpecialistBonusBase + (harvester.SpecialistEfficiencyFactor * (va.crew_engineer_maxlevel + 1)))
			  : 1.0f;

			// use part name as recipe name
			// - include crew bonus in the recipe name
			string recipe_name = Lib.BuildString(harvester.part.partInfo.title, " (efficiency: ", Lib.HumanReadablePerc(exp_bonus), ")");

			// generate recipe
			SimulatedRecipe recipe = new SimulatedRecipe(harvester.part, recipe_name);
			foreach (ResourceRatio res in harvester.inputList)
			{
				recipe.Input(res.ResourceName, res.Ratio);
			}
			recipe.Output(harvester.ResourceName, harvester.Efficiency * exp_bonus, true);
			recipes.Add(recipe);
		}
Пример #6
0
		/// <summary>run a single timestamp of the simulator</summary>
		private void RunSimulator(List<Part> parts, EnvironmentAnalyzer env, VesselAnalyzer va)
		{
			// clear previous resource state
			resources.Clear();

			// get amount and capacity from parts
			foreach (Part p in parts)
			{
				for (int i = 0; i < p.Resources.Count; ++i)
				{
					Process_part(p, p.Resources[i].resourceName);
#if DEBUG_RESOURCES
					p.Resources[i].isVisible = true;
					p.Resources[i].isTweakable = true;
#endif
				}
			}

			// process all rules
			foreach (Rule r in Profile.rules)
			{
				if (r.input.Length > 0 && r.rate > 0.0)
				{
					Process_rule(parts, r, env, va);
				}
			}

			// process all processes
			foreach (Process p in Profile.processes)
			{
				Process_process(parts, p, env, va);
			}

			// process all modules
			foreach (Part p in parts)
			{
				// get planner controller in the part
				PlannerController ctrl = p.FindModuleImplementing<PlannerController>();

				// ignore all modules in the part if specified in controller
				if (ctrl != null && !ctrl.considered)
					continue;

				// for each module
				foreach (PartModule m in p.Modules)
				{
					// skip disabled modules
					// rationale: the Selector disable non-selected modules in this way
					if (!m.isEnabled)
						continue;

					if (IsApiModule(m))
					{
						Process_apiModule(m, env, va);
					}
					else
					{
						switch (m.moduleName)
						{
							case "Greenhouse":
								Process_greenhouse(m as Greenhouse, env, va);
								break;
							case "GravityRing":
								Process_ring(m as GravityRing);
								break;
							case "Emitter":
								Process_emitter(m as Emitter);
								break;
							case "Laboratory":
								Process_laboratory(m as Laboratory);
								break;
							case "Experiment":
								Process_experiment(m as Experiment);
								break;
							case "ModuleCommand":
								Process_command(m as ModuleCommand);
								break;
							case "ModuleGenerator":
								Process_generator(m as ModuleGenerator, p);
								break;
							case "ModuleResourceConverter":
								Process_converter(m as ModuleResourceConverter, va);
								break;
							case "ModuleKPBSConverter":
								Process_converter(m as ModuleResourceConverter, va);
								break;
							case "ModuleResourceHarvester":
								Process_harvester(m as ModuleResourceHarvester, va);
								break;
							case "ModuleScienceConverter":
								Process_stocklab(m as ModuleScienceConverter);
								break;
							case "ModuleActiveRadiator":
								Process_radiator(m as ModuleActiveRadiator);
								break;
							case "ModuleWheelMotor":
								Process_wheel_motor(m as ModuleWheelMotor);
								break;
							case "ModuleWheelMotorSteering":
								Process_wheel_steering(m as ModuleWheelMotorSteering);
								break;
							case "ModuleLight":
							case "ModuleColoredLensLight":
							case "ModuleMultiPointSurfaceLight":
								Process_light(m as ModuleLight);
								Process_light(m as ModuleLight);
								Process_light(m as ModuleLight);
								break;
							case "KerbalismScansat":
								Process_scanner(m as KerbalismScansat);
								break;
							case "FissionGenerator":
								Process_fission_generator(p, m);
								break;
							case "ModuleRadioisotopeGenerator":
								Process_radioisotope_generator(p, m);
								break;
							case "ModuleCryoTank":
								Process_cryotank(p, m);
								break;
							case "ModuleRTAntennaPassive":
							case "ModuleRTAntenna":
								Process_rtantenna(m);
								break;
							case "ModuleDataTransmitter":
								Process_datatransmitter(m as ModuleDataTransmitter);
								break;
							case "ModuleEngines":
								Process_engines(m as ModuleEngines);
								break;
							case "ModuleEnginesFX":
								Process_enginesfx(m as ModuleEnginesFX);
								break;
							case "ModuleRCS":
								Process_rcs(m as ModuleRCS);
								break;
							case "ModuleRCSFX":
								Process_rcsfx(m as ModuleRCSFX);
								break;
							case "SolarPanelFixer":
								Process_solarPanel(m as SolarPanelFixer, env);
								break;
						}
					}
				}
			}

			// execute all possible recipes
			bool executing = true;
			while (executing)
			{
				executing = false;
				for (int i = 0; i < recipes.Count; ++i)
				{
					SimulatedRecipe recipe = recipes[i];
					if (recipe.left > double.Epsilon)
					{
						executing |= recipe.Execute(this);
					}
				}
			}
			recipes.Clear();

			// clamp all resources
			foreach (KeyValuePair<string, SimulatedResource> pair in resources)
				pair.Value.Clamp();
		}
Пример #7
0
		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)));
			}
		}
Пример #8
0
		/// <summary>
		/// determine if the resources involved are restricted to a part, and then process
		/// the process and add/remove the resources from the simulator
		/// </summary>
		/// <remarks>while rules are usually input or output only, processes transform input to output</remarks>
		public void Process_process(List<Part> parts, Process pr, EnvironmentAnalyzer env, VesselAnalyzer va)
		{
			Process_process_vessel_wide(pr, env, va);
		}
Пример #9
0
		/// <summary>process the process and add/remove the resources from the simulator for the entire vessel at once</summary>
		private void Process_process_vessel_wide(Process pr, EnvironmentAnalyzer env, VesselAnalyzer va)
		{
			// evaluate modifiers
			double k = Modifiers.Evaluate(env, va, this, pr.modifiers);
			Process_process_inner_body(k, null, pr, env, va);
		}
Пример #10
0
		/// <summary>process the process and add/remove the resources from the simulator</summary>
		private void Process_process_inner_body(double k, Part p, Process pr, EnvironmentAnalyzer env, VesselAnalyzer va)
		{
			// prepare recipe
			SimulatedRecipe recipe = new SimulatedRecipe(p, pr.name);
			foreach (KeyValuePair<string, double> input in pr.inputs)
			{
				recipe.Input(input.Key, input.Value * k);
			}
			foreach (KeyValuePair<string, double> output in pr.outputs)
			{
				recipe.Output(output.Key, output.Value * k, pr.dump.Check(output.Key));
			}
			recipes.Add(recipe);
		}
Пример #11
0
		/// <summary>process a rule and add/remove the resources from the simulator</summary>
		private void Process_rule_inner_body(double k, Part p, Rule r, EnvironmentAnalyzer env, VesselAnalyzer va)
		{
			// deduce rate per-second
			double rate = va.crew_count * (r.interval > 0.0 ? r.rate / r.interval : r.rate);

			// prepare recipe
			if (r.output.Length == 0)
			{
				Resource(r.input).Consume(rate * k, r.name);
			}
			else if (rate > double.Epsilon)
			{
				// - rules always dump excess overboard (because it is waste)
				SimulatedRecipe recipe = new SimulatedRecipe(p, r.name);
				recipe.Input(r.input, rate * k);
				recipe.Output(r.output, rate * k * r.ratio, true);
				recipes.Add(recipe);
			}
		}