public override bool Initialize(PartModule pm) { base.Initialize(pm); harvester = (ModuleResourceHarvester)pm; core = pm.GetComponent <ModuleCoreHeat>(); return(harvester.GeneratesHeat); }
public override void OnStart(StartState state) { base.OnStart(state); if (HighLogic.LoadedSceneIsFlight == false) { setupExperimentGUI(); return; } //Get drill animation drillAnimation = this.part.FindModuleImplementing <ModuleAnimationGroup>(); //Harvester harvester = this.part.FindModuleImplementing <ModuleResourceHarvester>(); //Core sample state coreSampleState = CoreSampleStates.Ready; //If the biome has been unlocked yet then get the samples left if (situationIsValid() && Utils.IsBiomeUnlocked(this.part.vessel)) { coreSampleStatus = getSamplesLeft().ToString(); } else { coreSampleStatus = kUnknown; } //Setup the gui setupGUI(); }
protected void setupDrillGUI(ModuleResourceHarvester drill, string resourceName) { drill.ResourceName = resourceName; drill.StartActionName = "Start " + resourceName + " drill"; drill.StopActionName = "Stop " + resourceName + " drill"; drill.Fields["ResourceStatus"].guiName = resourceName + " rate"; }
internal ResourceHarvester(Part part) { this.part = part; harvester = part.InternalPart.Module <ModuleResourceHarvester> (); animator = part.InternalPart.Module <ModuleAnimationGroup> (); if (harvester == null || animator == null) { throw new ArgumentException("Part is not a resource harvester"); } }
public override bool Initialize(PartModule pm) { base.Initialize(pm); harvester = (ModuleResourceHarvester)pm; bool toMonitor = false; for (int i = 0; i < harvester.inputList.Count; i++) { if (harvester.inputList[i].ResourceName == "ElectricCharge") { converterEcRate = harvester.inputList[i].Ratio; toMonitor = true; } } return toMonitor; }
public static double SampleResourceAbundance(Vessel v, ModuleResourceHarvester harvester) { // get abundance AbundanceRequest request = new AbundanceRequest { ResourceType = (HarvestTypes)harvester.HarvesterType, ResourceName = harvester.ResourceName, BodyId = v.mainBody.flightGlobalsIndex, Latitude = v.latitude, Longitude = v.longitude, Altitude = v.altitude, CheckForLock = false }; return(ResourceMap.Instance.GetAbundance(request)); }
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); }
public override void OnStart(StartState state) { base.OnStart(state); harvester = this.part.FindModuleImplementing <ModuleResourceHarvester>(); drillSwitcher = this.part.FindModuleImplementing <WBIDrillSwitcher>(); if (drillSwitcher != null) { drillSwitcher.Events["ShowDrillSwitchWindow"].guiActive = false; drillSwitcher.Events["ShowDrillSwitchWindow"].guiActiveUnfocused = false; } extractionMonitor = this.part.FindModuleImplementing <WBIExtractionMonitor>(); if (extractionMonitor != null) { extractionMonitor.Fields["extractionRateChange"].guiActive = false; } overheatDisplay = this.part.FindModuleImplementing <ModuleOverheatDisplay>(); }
protected void setupDrillGUI() { if (Utils.HasResearchedNode(PathfinderSettings.drillTechNode) == false) { ModuleResourceHarvester harvester = this.part.FindModuleImplementing <ModuleResourceHarvester>(); foreach (BaseEvent baseEvent in harvester.Events) { baseEvent.guiActive = false; baseEvent.active = false; } foreach (BaseField field in harvester.Fields) { field.guiActive = false; } foreach (BaseAction action in harvester.Actions) { action.actionGroup = KSPActionGroup.None; action.defaultActionGroup = KSPActionGroup.None; } ModuleAsteroidDrill astroDrill = this.part.FindModuleImplementing <ModuleAsteroidDrill>(); foreach (BaseEvent baseEvent in astroDrill.Events) { baseEvent.guiActive = false; baseEvent.active = false; } foreach (BaseField field in astroDrill.Fields) { field.guiActive = false; } foreach (BaseAction action in astroDrill.Actions) { action.actionGroup = KSPActionGroup.None; action.defaultActionGroup = KSPActionGroup.None; } } }
public override void OnStart(StartState state) { base.OnStart(state); harvester = this.part.FindModuleImplementing <ModuleResourceHarvester>(); drillSwitcher = this.part.FindModuleImplementing <WBIDrillSwitcher>(); if (drillSwitcher != null) { drillSwitcher.Events["ShowDrillSwitchWindow"].guiActive = false; drillSwitcher.Events["ShowDrillSwitchWindow"].guiActiveUnfocused = false; } efficiencyMonitor = this.part.FindModuleImplementing <WBIEfficiencyMonitor>(); if (efficiencyMonitor != null) { efficiencyMonitor.Fields["efficiencyDisplayString"].guiActive = false; } prospector = this.part.FindModuleImplementing <WBIProspector>(); asteroidProspector = this.part.FindModuleImplementing <WBIAsteroidProspector>(); overheatDisplay = this.part.FindModuleImplementing <ModuleOverheatDisplay>(); }
protected bool situationIsValid() { //If we don't have input units and density, then we're in trouble. if (inputResourceDensity == 0f || inputResourceUnits == 0f) { ScreenMessages.PostScreenMessage("Converter stopped. No input resource density or input units found.", kMessageDisplayTime, ScreenMessageStyle.UPPER_CENTER); StopResourceConverter(); return(false); } //If we don't have a harvesting node then see if we can find one. if (nearestLode == null) { updateLastLocation(); updateNearestLode(); //If we don't have a nearby node then we're done. if (nearestLode == null) { debugLog("Converter stopped. Vessel isn't near a lode (null)."); ScreenMessages.PostScreenMessage("Converter stopped. This vessel isn't in range of a lode.", kMessageDisplayTime, ScreenMessageStyle.UPPER_CENTER); StopResourceConverter(); return(false); } else { lodeUnitsRemaining = nearestLode.amountRemaining; } } //If we're out of resource or are full then we're done. if (status.ToLower().Contains("missing") || status.ToLower().Contains("full")) { StopResourceConverter(); lodeUnitsRemaining = nearestLode.amountRemaining; return(false); } //If we aren't within harvesting range of the nearest lode, then we're done. double harvestDistance = GoldStrikeUtils.HaversineDistance(this.part.vessel.longitude, this.part.vessel.latitude, nearestLode.longitude, nearestLode.lattitude, this.part.vessel.mainBody); if (harvestDistance > maxHarvestRange) { debugLog("Converter stopped. Vessel isn't near a lode (out of range)."); ScreenMessages.PostScreenMessage("Converter stopped. This vessel isn't in range of a lode.", kMessageDisplayTime, ScreenMessageStyle.UPPER_CENTER); StopResourceConverter(); return(false); } //If we don't have any more resources to harvest then we're done. if (nearestLode.amountRemaining == 0f) { debugLog("Converter stopped. Lode is depleted."); ScreenMessages.PostScreenMessage("This vein of " + nearestLode.resourceName + " has been depleted. Time to move on...", kMessageDisplayTime, ScreenMessageStyle.UPPER_CENTER); StopResourceConverter(); return(false); } //Grab the drills if needed. We need at least one planetary or one asteroid drill. if (harvester == null) { harvester = this.part.FindModuleImplementing <ModuleResourceHarvester>(); } if (asteroidDrill == null) { asteroidDrill = this.part.FindModuleImplementing <ModuleAsteroidDrill>(); } if (harvester == null || asteroidDrill == null) { debugLog("No drill found!!!"); return(false); } //Situation is valid return(true); }
public override void OnStart(StartState state) { base.OnStart(state); harvester = this.part.FindModuleImplementing<ModuleResourceHarvester>(); }
public ProtoDrillDevice(ProtoPartModuleSnapshot drill, ModuleResourceHarvester prefab, uint part_id) { this.drill = drill; this.prefab = prefab; this.part_id = part_id; }
public DrillDevice(ModuleResourceHarvester drill) { this.drill = drill; }
void Apply(ModuleResourceHarvester m, double k) { m.Efficiency *= (float)k; }
private void OnWindow(int window_id) { try { GUILayout.BeginVertical(); // Get all modules of the selected part: var part_title = ""; Part part = null; KRnDModule rnd_module = null; List <ModuleEngines> engine_modules = null; ModuleRCS rcs_module = null; ModuleReactionWheel reaction_wheel_module = null; ModuleDeployableSolarPanel solar_panel_module = null; ModuleWheelBase landing_leg_module = null; PartResource electric_charge_resource = null; ModuleGenerator generator_module = null; PartModule fission_generator = null; List <ModuleResourceConverter> converter_modules = null; ModuleParachute parachute_module = null; ModuleDataTransmitter antenna_module = null; ModuleScienceLab science_lab = null; List <PartResource> fuel_resources = null; ModuleResourceHarvester harvester_module = null; ModuleActiveRadiator radiator_module = null; ELConverter el_converter = null; if (selectedPart != null) { foreach (var a_part in PartLoader.LoadedPartsList) { if (a_part.partPrefab.name == selectedPart.name) { part = a_part.partPrefab; part_title = a_part.title; break; } } if (part) { antenna_module = PartStats.GetModuleDataTransmitter(part); science_lab = PartStats.GetModuleScienceLab(part); rnd_module = PartStats.GetKRnDModule(part); engine_modules = PartStats.GetModuleEnginesList(part); rcs_module = PartStats.GetModuleRCS(part); reaction_wheel_module = PartStats.GetModuleReactionWheel(part); solar_panel_module = PartStats.GetModuleDeployableSolarPanel(part); landing_leg_module = PartStats.GetModuleWheelBase(part); electric_charge_resource = PartStats.GetElectricCharge(part); generator_module = PartStats.GetModuleGenerator(part); fission_generator = PartStats.GetFissionGenerator(part); converter_modules = PartStats.GetModuleResourceConverterList(part); parachute_module = PartStats.GetModuleParachute(part); fuel_resources = PartStats.GetFuelResources(part); harvester_module = PartStats.GetModuleResourceHarvester(part); radiator_module = PartStats.GetModuleActiveRadiator(part); el_converter = PartStats.GetModuleElConverter(part); } } if (!part) { // No part selected: GUILayout.BeginArea(new Rect(10, 5, _windowStyle.fixedWidth, 20)); GUILayout.Label("<b>Kerbal R&D: Select a part to improve</b>", _labelStyle); GUILayout.EndArea(); GUILayout.EndVertical(); GUI.DragWindow(); return; } if (!rnd_module) { // Invalid part selected: GUILayout.BeginArea(new Rect(10, 5, _windowStyle.fixedWidth, 20)); GUILayout.Label("<b>Kerbal R&D: Select a different part to improve</b>", _labelStyle); GUILayout.EndArea(); GUILayout.EndVertical(); GUI.DragWindow(); return; } // Get stats of the current version of the selected part: if (!KRnD.upgrades.TryGetValue(part.name, out var current_upgrade)) { current_upgrade = new PartUpgrades(); } var current_info = BuildPartInfoString(part, current_upgrade); // Create a copy of the part-stats which we can use to mock an upgrade further below: var next_upgrade = current_upgrade.Clone(); // Title: GUILayout.BeginArea(new Rect(10, 5, _windowStyle.fixedWidth, 20)); var version = rnd_module.GetVersion(); if (version != "") { version = " - " + version; } GUILayout.Label("<b>" + part_title + version + "</b>", _labelStyle); GUILayout.EndArea(); // List with upgrade-options: float options_width = 100; var options_height = _windowStyle.fixedHeight - 30 - 30 - 20; GUILayout.BeginArea(new Rect(10, 30 + 20, options_width, options_height)); GUILayout.BeginVertical(); var options = new List <string> { "Dry Mass", "Max Temp" }; if (engine_modules != null || rcs_module) { options.Add("ISP Vac"); options.Add("ISP Atm"); options.Add("Fuel Flow"); } if (antenna_module != null) { options.Add("Antenna Power"); } if (antenna_module != null && antenna_module.antennaType != AntennaType.INTERNAL) { options.Add("Packet Size"); } if (science_lab != null) { options.Add("Data Storage"); } if (reaction_wheel_module != null) { options.Add("Torque"); } if (solar_panel_module != null) { options.Add("Charge Rate"); } if (landing_leg_module != null) { options.Add("Crash Tolerance"); } if (electric_charge_resource != null) { options.Add("Battery"); } //if (fuel_resources != null) options.Add("Fuel Pressure"); if (generator_module || fission_generator) { options.Add("Generator"); } if (converter_modules != null) { options.Add("Converter"); } if (parachute_module) { options.Add("Parachute"); } if (harvester_module) { options.Add("Harvester"); } if (radiator_module) { options.Add("Radiator"); } if (el_converter) { options.Add("EL Converter"); } if (_selectedUpgradeOption >= options.Count) { _selectedUpgradeOption = 0; } _selectedUpgradeOption = GUILayout.SelectionGrid(_selectedUpgradeOption, options.ToArray(), 1, _buttonStyle); GUILayout.EndVertical(); GUILayout.EndArea(); var selected_upgrade_option = options.ToArray()[_selectedUpgradeOption]; int current_upgrade_level; int next_upgrade_level; int science_cost; float current_improvement_factor; float next_improvement_factor; UpgradeConstants u_constants; if (!KRnD.originalStats.TryGetValue(part.name, out var original_stats)) { throw new Exception("no original-stats for part '" + part.name + "'"); } //Func<PartUpgrades, int> improve_function; if (selected_upgrade_option == "ISP Vac") { //improve_function = KRnD.ImproveIspVac; current_upgrade_level = current_upgrade.ispVac; next_upgrade_level = ++next_upgrade.ispVac; u_constants = ValueConstants.GetData(StringConstants.ISP_VAC); current_improvement_factor = u_constants.CalculateImprovementFactor(current_upgrade.ispVac); next_improvement_factor = u_constants.CalculateImprovementFactor(next_upgrade.ispVac); science_cost = u_constants.CalculateScienceCost(0, next_upgrade.ispVac); } else if (selected_upgrade_option == "ISP Atm") { //improve_function = KRnD.ImproveIspAtm; current_upgrade_level = current_upgrade.ispAtm; next_upgrade_level = ++next_upgrade.ispAtm; u_constants = ValueConstants.GetData(StringConstants.ISP_ATM); current_improvement_factor = u_constants.CalculateImprovementFactor(current_upgrade.ispAtm); next_improvement_factor = u_constants.CalculateImprovementFactor(next_upgrade.ispAtm); science_cost = u_constants.CalculateScienceCost(0, next_upgrade.ispAtm); } else if (selected_upgrade_option == "Fuel Flow") { //improve_function = KRnD.ImproveFuelFlow; current_upgrade_level = current_upgrade.fuelFlow; next_upgrade_level = ++next_upgrade.fuelFlow; u_constants = ValueConstants.GetData(StringConstants.FUEL_FLOW); current_improvement_factor = u_constants.CalculateImprovementFactor(current_upgrade.fuelFlow); next_improvement_factor = u_constants.CalculateImprovementFactor(next_upgrade.fuelFlow); science_cost = u_constants.CalculateScienceCost(0, next_upgrade.fuelFlow); } else if (selected_upgrade_option == "Dry Mass") { //improve_function = KRnD.ImproveDryMass; current_upgrade_level = current_upgrade.dryMass; next_upgrade_level = ++next_upgrade.dryMass; u_constants = ValueConstants.GetData(StringConstants.DRY_MASS); current_improvement_factor = u_constants.CalculateImprovementFactor(current_upgrade.dryMass); next_improvement_factor = u_constants.CalculateImprovementFactor(next_upgrade.dryMass); science_cost = u_constants.CalculateScienceCost(original_stats.dryMass, next_upgrade.dryMass); } else if (selected_upgrade_option == "Torque") { //improve_function = KRnD.ImproveTorque; current_upgrade_level = current_upgrade.torqueStrength; next_upgrade_level = ++next_upgrade.torqueStrength; u_constants = ValueConstants.GetData(StringConstants.TORQUE); current_improvement_factor = u_constants.CalculateImprovementFactor(current_upgrade.torqueStrength); next_improvement_factor = u_constants.CalculateImprovementFactor(next_upgrade.torqueStrength); science_cost = u_constants.CalculateScienceCost(original_stats.torqueStrength, next_upgrade.torqueStrength); } else if (selected_upgrade_option == "Antenna Power") { //improve_function = KRnD.ImproveAntennaPower; current_upgrade_level = current_upgrade.antennaPower; next_upgrade_level = ++next_upgrade.antennaPower; u_constants = ValueConstants.GetData(StringConstants.ANTENNA_POWER); current_improvement_factor = u_constants.CalculateImprovementFactor(current_upgrade.antennaPower); next_improvement_factor = u_constants.CalculateImprovementFactor(next_upgrade.antennaPower); science_cost = u_constants.CalculateScienceCost((float)original_stats.antennaPower, next_upgrade.antennaPower); } else if (selected_upgrade_option == "Packet Size") { //improve_function = KRnD.ImprovePacketSize; current_upgrade_level = current_upgrade.packetSize; next_upgrade_level = ++next_upgrade.packetSize; u_constants = ValueConstants.GetData(StringConstants.PACKET_SIZE); current_improvement_factor = u_constants.CalculateImprovementFactor(current_upgrade.packetSize); next_improvement_factor = u_constants.CalculateImprovementFactor(next_upgrade.packetSize); science_cost = u_constants.CalculateScienceCost(original_stats.packetSize, next_upgrade.packetSize); } else if (selected_upgrade_option == "Data Storage") { //improve_function = KRnD.ImproveDataStorage; current_upgrade_level = current_upgrade.dataStorage; next_upgrade_level = ++next_upgrade.dataStorage; u_constants = ValueConstants.GetData(StringConstants.DATA_STORAGE); current_improvement_factor = u_constants.CalculateImprovementFactor(current_upgrade.dataStorage); next_improvement_factor = u_constants.CalculateImprovementFactor(next_upgrade.dataStorage); science_cost = u_constants.CalculateScienceCost(original_stats.dataStorage, next_upgrade.dataStorage); } else if (selected_upgrade_option == "Harvester") { //improve_function = KRnD.ImproveResourceHarvester; current_upgrade_level = current_upgrade.resourceHarvester; next_upgrade_level = ++next_upgrade.resourceHarvester; u_constants = ValueConstants.GetData(StringConstants.RESOURCE_HARVESTER); current_improvement_factor = u_constants.CalculateImprovementFactor(current_upgrade.resourceHarvester); next_improvement_factor = u_constants.CalculateImprovementFactor(next_upgrade.resourceHarvester); science_cost = u_constants.CalculateScienceCost(original_stats.resourceHarvester, next_upgrade.resourceHarvester); } else if (selected_upgrade_option == "Radiator") { //improve_function = KRnD.ImproveActiveRadiator; current_upgrade_level = current_upgrade.maxEnergyTransfer; next_upgrade_level = ++next_upgrade.maxEnergyTransfer; u_constants = ValueConstants.GetData(StringConstants.ENERGY_TRANSFER); current_improvement_factor = u_constants.CalculateImprovementFactor(current_upgrade.maxEnergyTransfer); next_improvement_factor = u_constants.CalculateImprovementFactor(next_upgrade.maxEnergyTransfer); science_cost = u_constants.CalculateScienceCost((float)original_stats.maxEnergyTransfer, next_upgrade.maxEnergyTransfer); } else if (selected_upgrade_option == "Charge Rate") { //improve_function = KRnD.ImproveChargeRate; current_upgrade_level = current_upgrade.efficiencyMult; next_upgrade_level = ++next_upgrade.efficiencyMult; u_constants = ValueConstants.GetData(StringConstants.CHARGE_RATE); current_improvement_factor = u_constants.CalculateImprovementFactor(current_upgrade.efficiencyMult); next_improvement_factor = u_constants.CalculateImprovementFactor(next_upgrade.efficiencyMult); science_cost = u_constants.CalculateScienceCost(original_stats.efficiencyMult, next_upgrade.efficiencyMult); } else if (selected_upgrade_option == "Crash Tolerance") { //improve_function = KRnD.ImproveCrashTolerance; current_upgrade_level = current_upgrade.crashTolerance; next_upgrade_level = ++next_upgrade.crashTolerance; u_constants = ValueConstants.GetData(StringConstants.CRASH_TOLERANCE); current_improvement_factor = u_constants.CalculateImprovementFactor(current_upgrade.crashTolerance); next_improvement_factor = u_constants.CalculateImprovementFactor(next_upgrade.crashTolerance); science_cost = u_constants.CalculateScienceCost(original_stats.crashTolerance, next_upgrade.crashTolerance); } else if (selected_upgrade_option == "Battery") { //improve_function = KRnD.ImproveBatteryCharge; current_upgrade_level = current_upgrade.batteryCharge; next_upgrade_level = ++next_upgrade.batteryCharge; u_constants = ValueConstants.GetData(StringConstants.BATTERY_CHARGE); current_improvement_factor = u_constants.CalculateImprovementFactor(current_upgrade.batteryCharge); next_improvement_factor = u_constants.CalculateImprovementFactor(next_upgrade.batteryCharge); science_cost = u_constants.CalculateScienceCost((float)original_stats.batteryCharge, next_upgrade.batteryCharge); } else if (selected_upgrade_option == "Fuel Pressure") { //improve_function = KRnD.ImproveFuelCapacity; current_upgrade_level = current_upgrade.fuelCapacity; next_upgrade_level = ++next_upgrade.fuelCapacity; u_constants = ValueConstants.GetData(StringConstants.FUEL_CAPACITY); current_improvement_factor = u_constants.CalculateImprovementFactor(current_upgrade.fuelCapacity); next_improvement_factor = u_constants.CalculateImprovementFactor(next_upgrade.fuelCapacity); science_cost = u_constants.CalculateScienceCost((float)original_stats.fuelCapacitiesSum, next_upgrade.fuelCapacity); } else if (selected_upgrade_option == "Generator") { //improve_function = KRnD.ImproveGeneratorEfficiency; current_upgrade_level = current_upgrade.generatorEfficiency; next_upgrade_level = ++next_upgrade.generatorEfficiency; u_constants = ValueConstants.GetData(StringConstants.GENERATOR_EFFICIENCY); current_improvement_factor = u_constants.CalculateImprovementFactor(current_upgrade.generatorEfficiency); next_improvement_factor = u_constants.CalculateImprovementFactor(next_upgrade.generatorEfficiency); science_cost = u_constants.CalculateScienceCost(0, next_upgrade.generatorEfficiency); } else if (selected_upgrade_option == "Converter") { //improve_function = KRnD.ImproveConverterEfficiency; current_upgrade_level = current_upgrade.converterEfficiency; next_upgrade_level = ++next_upgrade.converterEfficiency; u_constants = ValueConstants.GetData(StringConstants.CONVERTER_EFFICIENCY); current_improvement_factor = u_constants.CalculateImprovementFactor(current_upgrade.converterEfficiency); next_improvement_factor = u_constants.CalculateImprovementFactor(next_upgrade.converterEfficiency); science_cost = u_constants.CalculateScienceCost(0, next_upgrade.converterEfficiency); } else if (selected_upgrade_option == "Parachute") { //improve_function = KRnD.ImproveParachuteStrength; current_upgrade_level = current_upgrade.parachuteStrength; next_upgrade_level = ++next_upgrade.parachuteStrength; u_constants = ValueConstants.GetData(StringConstants.PARACHUTE_STRENGTH); current_improvement_factor = u_constants.CalculateImprovementFactor(current_upgrade.parachuteStrength); next_improvement_factor = u_constants.CalculateImprovementFactor(next_upgrade.parachuteStrength); science_cost = u_constants.CalculateScienceCost((float)original_stats.chuteMaxTemp, next_upgrade.parachuteStrength); } else if (selected_upgrade_option == "Max Temp") { //improve_function = KRnD.ImproveMaxTemperature; current_upgrade_level = current_upgrade.maxTemperature; next_upgrade_level = ++next_upgrade.maxTemperature; u_constants = ValueConstants.GetData(StringConstants.MAX_TEMPERATURE); current_improvement_factor = u_constants.CalculateImprovementFactor(current_upgrade.maxTemperature); next_improvement_factor = u_constants.CalculateImprovementFactor(next_upgrade.maxTemperature); science_cost = u_constants.CalculateScienceCost((float)original_stats.intMaxTemp, next_upgrade.maxTemperature); } else if (selected_upgrade_option == "EL Converter") { //improve_function = KRnD.ImproveMaxTemperature; current_upgrade_level = current_upgrade.elConverter; next_upgrade_level = ++next_upgrade.elConverter; u_constants = ValueConstants.GetData(StringConstants.EL_CONVERTER); current_improvement_factor = u_constants.CalculateImprovementFactor(current_upgrade.elConverter); next_improvement_factor = u_constants.CalculateImprovementFactor(next_upgrade.elConverter); science_cost = u_constants.CalculateScienceCost((float)original_stats.ELConverter, next_upgrade.elConverter); } else { throw new Exception("unexpected option '" + selected_upgrade_option + "'"); } var new_info = BuildPartInfoString(part, next_upgrade); // Calculate part-info if the selected stat was upgraded. new_info = HighlightChanges(current_info, new_info); // Current stats: GUILayout.BeginArea(new Rect(10 + options_width + 10, 30, _windowStyle.fixedWidth, 20)); GUILayout.Label("<color=#FFFFFF><b>Current:</b> " + current_upgrade_level + " (" + current_improvement_factor.ToString("+0.##%;-0.##%;-") + ")</color>", _labelStyle); GUILayout.EndArea(); var area_width = (_windowStyle.fixedWidth - 20 - options_width) / 2; var area_height = options_height; GUILayout.BeginArea(new Rect(10 + options_width, 30 + 20, area_width, area_height)); _scrollPos = GUILayout.BeginScrollView(_scrollPos, _scrollStyle, GUILayout.Width(area_width), GUILayout.Height(area_height)); GUILayout.Label(current_info, _labelStyleSmall); GUILayout.EndScrollView(); GUILayout.EndArea(); // Next stats: GUILayout.BeginArea(new Rect(10 + options_width + area_width + 10, 30, _windowStyle.fixedWidth, 20)); GUILayout.Label("<color=#FFFFFF><b>Next upgrade:</b> " + next_upgrade_level + " (" + next_improvement_factor.ToString("+0.##%;-0.##%;-") + ")</color>", _labelStyle); GUILayout.EndArea(); GUILayout.BeginArea(new Rect(10 + options_width + area_width, 30 + 20, area_width, area_height)); _scrollPos = GUILayout.BeginScrollView(_scrollPos, _scrollStyle, GUILayout.Width(area_width), GUILayout.Height(area_height)); GUILayout.Label(new_info, _labelStyleSmall); GUILayout.EndScrollView(); GUILayout.EndArea(); // Bottom-line (display only if the upgrade would have an effect): if (Math.Abs(current_improvement_factor - next_improvement_factor) > float.Epsilon) { GUILayout.BeginArea(new Rect(10, _windowStyle.fixedHeight - 25, _windowStyle.fixedWidth, 30)); float current_science = 0; if (ResearchAndDevelopment.Instance != null) { current_science = ResearchAndDevelopment.Instance.Science; } var color = "FF0000"; if (current_science >= science_cost) { color = "00FF00"; } GUILayout.Label("<b>Science: <color=#" + color + ">" + science_cost + " / " + Math.Floor(current_science) + "</color></b>", _labelStyle); GUILayout.EndArea(); if (current_science >= science_cost && ResearchAndDevelopment.Instance != null && u_constants != null /*&& improve_function != null*/) { GUILayout.BeginArea(new Rect(_windowStyle.fixedWidth - 110, _windowStyle.fixedHeight - 30, 100, 30)); if (GUILayout.Button("Research", _buttonStyle)) { //upgrade_function(part); try { if (!KRnD.upgrades.TryGetValue(part.name, out var store)) { store = new PartUpgrades(); KRnD.upgrades.Add(part.name, store); } u_constants.upgradeFunction(store); //improve_function(store); KRnD.UpdateGlobalParts(); KRnD.UpdateEditorVessel(); } catch (Exception e) { Debug.LogError("[KRnD] UpgradeIspVac(): " + e); } ResearchAndDevelopment.Instance.AddScience(-science_cost, TransactionReasons.RnDTechResearch); } GUILayout.EndArea(); } } GUILayout.EndVertical(); GUI.DragWindow(); } catch (Exception e) { Debug.LogError("[KRnD] GenerateWindow(): " + e); } }
// called at every simulation step public void FixedUpdate() { // do nothing if paused if (Lib.IsPaused()) return; // do nothing if DB isn't ready if (!DB.Ready()) return; // for each vessel foreach(Vessel vessel in FlightGlobals.Vessels) { // skip invalid vessels if (!Lib.IsVessel(vessel)) continue; // skip loaded vessels if (vessel.loaded) continue; // get vessel info from the cache vessel_info info = Cache.VesselInfo(vessel); // calculate atmospheric factor (proportion of flux not blocked by atmosphere) double atmo_factor = Sim.AtmosphereFactor(vessel.mainBody, info.position, info.sun_dir); // for each part foreach(ProtoPartSnapshot part in vessel.protoVessel.protoPartSnapshots) { // get part prefab (required for module properties) Part part_prefab = PartLoader.getPartInfoByName(part.partName).partPrefab; // store index of ModuleResourceConverter to process // rationale: a part can contain multiple resource converters int converter_index = 0; // for each module foreach(ProtoPartModuleSnapshot module in part.modules) { // command module if (module.moduleName == "ModuleCommand") { // get module from prefab ModuleCommand command = part_prefab.Modules.GetModules<ModuleCommand>()[0]; // 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 || part.protoModuleCrew.Count > 0) { // for each input resource foreach(ModuleResource ir in command.inputResources) { // consume the resource Lib.RequestResource(vessel, ir.name, ir.rate * TimeWarp.fixedDeltaTime); } } } // solar panel else if (module.moduleName == "ModuleDeployableSolarPanel") { // determine if extended bool extended = module.moduleValues.GetValue("stateString") == ModuleDeployableSolarPanel.panelStates.EXTENDED.ToString(); // if in sunlight and extended if (info.sunlight && extended) { // get module from prefab ModuleDeployableSolarPanel panel = part_prefab.Modules.GetModules<ModuleDeployableSolarPanel>()[0]; // produce electric charge Lib.RequestResource(vessel, "ElectricCharge", -PanelOutput(vessel, part, panel, info.sun_dir, info.sun_dist, atmo_factor) * TimeWarp.fixedDeltaTime * Malfunction.Penalty(part)); } } // generator // note: assume generators require all input else if (module.moduleName == "ModuleGenerator") { // determine if active bool activated = Convert.ToBoolean(module.moduleValues.GetValue("generatorIsActive")); // if active if (activated) { // get module from prefab ModuleGenerator generator = part_prefab.Modules.GetModules<ModuleGenerator>()[0]; // determine if vessel is full of all output resources bool full = true; foreach(var or in generator.outputList) { double amount = Lib.GetResourceAmount(vessel, or.name); double capacity = Lib.GetResourceCapacity(vessel, or.name); double perc = capacity > 0.0 ? amount / capacity : 0.0; full &= (perc >= 1.0 - double.Epsilon); } // if not full if (!full) { // calculate worst required resource percentual double worst_input = 1.0; foreach(var ir in generator.inputList) { double required = ir.rate * TimeWarp.fixedDeltaTime; double amount = Lib.GetResourceAmount(vessel, ir.name); worst_input = Math.Min(worst_input, amount / required); } // for each input resource foreach(var ir in generator.inputList) { // consume the resource Lib.RequestResource(vessel, ir.name, ir.rate * worst_input * TimeWarp.fixedDeltaTime); } // for each output resource foreach(var or in generator.outputList) { // produce the resource Lib.RequestResource(vessel, or.name, -or.rate * worst_input * TimeWarp.fixedDeltaTime * Malfunction.Penalty(part)); } } } } // converter // note: support multiple resource converters // note: ignore stock temperature mechanic of converters // note: ignore autoshutdown // note: ignore crew experience bonus (seem that stock ignore it too) // note: 'undo' stock behaviour by forcing lastUpdateTime to now (to minimize overlapping calculations from this and stock post-facto simulation) else if (module.moduleName == "ModuleResourceConverter") { // determine if active bool activated = Convert.ToBoolean(module.moduleValues.GetValue("IsActivated")); // if active if (activated) { // get module from prefab ModuleResourceConverter converter = part_prefab.Modules.GetModules<ModuleResourceConverter>()[converter_index++]; // determine if vessel is full of all output resources bool full = true; foreach(var or in converter.outputList) { double amount = Lib.GetResourceAmount(vessel, or.ResourceName); double capacity = Lib.GetResourceCapacity(vessel, or.ResourceName); double perc = capacity > 0.0 ? amount / capacity : 0.0; full &= (perc >= converter.FillAmount - double.Epsilon); } // if not full if (!full) { // calculate worst required resource percentual double worst_input = 1.0; foreach(var ir in converter.inputList) { double required = ir.Ratio * TimeWarp.fixedDeltaTime; double amount = Lib.GetResourceAmount(vessel, ir.ResourceName); worst_input = Math.Min(worst_input, amount / required); } // for each input resource foreach(var ir in converter.inputList) { // consume the resource Lib.RequestResource(vessel, ir.ResourceName, ir.Ratio * worst_input * TimeWarp.fixedDeltaTime); } // for each output resource foreach(var or in converter.outputList) { // produce the resource Lib.RequestResource(vessel, or.ResourceName, -or.Ratio * worst_input * TimeWarp.fixedDeltaTime * Malfunction.Penalty(part)); } } // undo stock behaviour by forcing last_update_time to now module.moduleValues.SetValue("lastUpdateTime", Planetarium.GetUniversalTime().ToString()); } } // drill // note: ignore stock temperature mechanic of harvesters // note: ignore autoshutdown // note: ignore depletion (stock seem to do the same) // note: 'undo' stock behaviour by forcing lastUpdateTime to now (to minimize overlapping calculations from this and stock post-facto simulation) else if (module.moduleName == "ModuleResourceHarvester") { // determine if active bool activated = Convert.ToBoolean(module.moduleValues.GetValue("IsActivated")); // if active if (activated) { // get module from prefab ModuleResourceHarvester harvester = part_prefab.Modules.GetModules<ModuleResourceHarvester>()[0]; // deduce crew bonus double experience_bonus = 0.0; if (harvester.UseSpecialistBonus) { foreach(ProtoCrewMember c in vessel.protoVessel.GetVesselCrew()) { experience_bonus = Math.Max(experience_bonus, (c.trait == harvester.Specialty) ? (double)c.experienceLevel : 0.0); } } double crew_bonus = harvester.SpecialistBonusBase + (experience_bonus + 1.0) * harvester.SpecialistEfficiencyFactor; // detect amount of ore in the ground AbundanceRequest request = new AbundanceRequest { Altitude = vessel.altitude, BodyId = vessel.mainBody.flightGlobalsIndex, CheckForLock = false, Latitude = vessel.latitude, Longitude = vessel.longitude, ResourceType = (HarvestTypes)harvester.HarvesterType, ResourceName = harvester.ResourceName }; double abundance = ResourceMap.Instance.GetAbundance(request); // if there is actually something (should be if active when unloaded) if (abundance > harvester.HarvestThreshold) { // calculate worst required resource percentual double worst_input = 1.0; foreach(var ir in harvester.inputList) { double required = ir.Ratio * TimeWarp.fixedDeltaTime; double amount = Lib.GetResourceAmount(vessel, ir.ResourceName); worst_input = Math.Min(worst_input, amount / required); } // for each input resource foreach(var ir in harvester.inputList) { // consume the resource Lib.RequestResource(vessel, ir.ResourceName, ir.Ratio * worst_input * TimeWarp.fixedDeltaTime); } // determine resource produced double res = abundance * harvester.Efficiency * crew_bonus * worst_input * Malfunction.Penalty(part); // accumulate ore Lib.RequestResource(vessel, harvester.ResourceName, -res * TimeWarp.fixedDeltaTime); } // undo stock behaviour by forcing last_update_time to now module.moduleValues.SetValue("lastUpdateTime", Planetarium.GetUniversalTime().ToString()); } } // asteroid drill // note: untested // note: ignore stock temperature mechanic of asteroid drills // note: ignore autoshutdown // note: 'undo' stock behaviour by forcing lastUpdateTime to now (to minimize overlapping calculations from this and stock post-facto simulation) else if (module.moduleName == "ModuleAsteroidDrill") { // determine if active bool activated = Convert.ToBoolean(module.moduleValues.GetValue("IsActivated")); // if active if (activated) { // get module from prefab ModuleAsteroidDrill asteroid_drill = part_prefab.Modules.GetModules<ModuleAsteroidDrill>()[0]; // deduce crew bonus double experience_bonus = 0.0; if (asteroid_drill.UseSpecialistBonus) { foreach(ProtoCrewMember c in vessel.protoVessel.GetVesselCrew()) { experience_bonus = Math.Max(experience_bonus, (c.trait == asteroid_drill.Specialty) ? (double)c.experienceLevel : 0.0); } } double crew_bonus = asteroid_drill.SpecialistBonusBase + (experience_bonus + 1.0) * asteroid_drill.SpecialistEfficiencyFactor; // get asteroid data ProtoPartModuleSnapshot asteroid_info = null; ProtoPartModuleSnapshot asteroid_resource = null; foreach(ProtoPartSnapshot p in vessel.protoVessel.protoPartSnapshots) { if (asteroid_info == null) asteroid_info = p.modules.Find(k => k.moduleName == "ModuleAsteroidInfo"); if (asteroid_resource == null) asteroid_resource = p.modules.Find(k => k.moduleName == "ModuleAsteroidResource"); } // if there is actually an asteroid attached to this active asteroid drill (it should) if (asteroid_info != null && asteroid_resource != null) { // get some data double mass_threshold = Convert.ToDouble(asteroid_info.moduleValues.GetValue("massThresholdVal")); double mass = Convert.ToDouble(asteroid_info.moduleValues.GetValue("currentMassVal")); double abundance = Convert.ToDouble(asteroid_resource.moduleValues.GetValue("abundance")); string res_name = asteroid_resource.moduleValues.GetValue("resourceName"); double res_density = PartResourceLibrary.Instance.GetDefinition(res_name).density; // if asteroid isn't depleted if (mass > mass_threshold && abundance > double.Epsilon) { // consume EC double ec_required = asteroid_drill.PowerConsumption * TimeWarp.fixedDeltaTime; double ec_consumed = Lib.RequestResource(vessel, "ElectricCharge", ec_required); double ec_ratio = ec_consumed / ec_required; // determine resource extracted double res_amount = abundance * asteroid_drill.Efficiency * crew_bonus * ec_ratio * TimeWarp.fixedDeltaTime; // produce mined resource Lib.RequestResource(vessel, res_name, -res_amount); // consume asteroid mass asteroid_info.moduleValues.SetValue("currentMassVal", (mass - res_density * res_amount).ToString()); } } // undo stock behaviour by forcing last_update_time to now module.moduleValues.SetValue("lastUpdateTime", Planetarium.GetUniversalTime().ToString()); } } // SCANSAT support (new version) // TODO: enable better SCANsat support /*else if (module.moduleName == "SCANsat" || module.moduleName == "ModuleSCANresourceScanner") { // get ec consumption rate PartModule scansat = part_prefab.Modules[module.moduleName]; double power = Lib.ReflectionValue<float>(scansat, "power"); double ec_required = power * TimeWarp.fixedDeltaTime; // if it was scanning if (SCANsat.wasScanning(module)) { // if there is enough ec double ec_amount = Lib.GetResourceAmount(vessel, "ElectricCharge"); double ec_capacity = Lib.GetResourceCapacity(vessel, "ElectricCharge"); if (ec_capacity > double.Epsilon && ec_amount / ec_capacity > 0.15) //< re-enable at 15% EC { // re-enable the scanner SCANsat.resumeScanner(vessel, module, part_prefab); // give the user some feedback if (DB.VesselData(vessel.id).cfg_ec == 1) Message.Post(Severity.relax, "SCANsat> sensor on <b>" + vessel.vesselName + "</b> resumed operations", "we got enough ElectricCharge"); } } // if it is scanning if (SCANsat.isScanning(module)) { // consume ec double ec_consumed = Lib.RequestResource(vessel, "ElectricCharge", ec_required); // if there isn't enough ec if (ec_consumed < ec_required * 0.99 && ec_required > double.Epsilon) { // unregister scanner, and remember it SCANsat.stopScanner(vessel, module, part_prefab); // give the user some feedback if (DB.VesselData(vessel.id).cfg_ec == 1) Message.Post(Severity.warning, "SCANsat sensor was disabled on <b>" + vessel.vesselName + "</b>", "for lack of ElectricCharge"); } } }*/ // SCANSAT support (old version) // note: this one doesn't support re-activation, is a bit slower and less clean // waiting for DMagic to fix a little bug else if (module.moduleName == "SCANsat" || module.moduleName == "ModuleSCANresourceScanner") { // determine if scanning bool scanning = Convert.ToBoolean(module.moduleValues.GetValue("scanning")); // consume ec if (scanning) { // get ec consumption PartModule scansat = part_prefab.Modules[module.moduleName]; double power = Lib.ReflectionValue<float>(scansat, "power"); // consume ec double ec_required = power * TimeWarp.fixedDeltaTime; double ec_consumed = Lib.RequestResource(vessel, "ElectricCharge", ec_required); // if there isn't enough ec if (ec_consumed < ec_required * 0.99 && ec_required > double.Epsilon) { // unregister scanner using reflection foreach(var a in AssemblyLoader.loadedAssemblies) { if (a.name == "SCANsat") { Type controller_type = a.assembly.GetType("SCANsat.SCANcontroller"); System.Object controller = controller_type.GetProperty("controller", BindingFlags.Public | BindingFlags.Static).GetValue(null, null); controller_type.InvokeMember("removeVessel", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, controller, new System.Object[]{vessel}); } } // disable scanning module.moduleValues.SetValue("scanning", false.ToString()); // give the user some feedback if (DB.VesselData(vessel.id).cfg_ec == 1) Message.Post(Severity.warning, "SCANsat sensor was disabled on <b>" + vessel.vesselName + "</b>", "for lack of ElectricCharge"); } } } // NearFutureSolar support // note: we assume deployed, this is a current limitation else if (module.moduleName == "ModuleCurvedSolarPanel") { // [unused] determine if extended //string state = module.moduleValues.GetValue("SavedState"); //bool extended = state == ModuleDeployableSolarPanel.panelStates.EXTENDED.ToString(); // if in sunlight if (info.sunlight) { // produce electric charge double output = CurvedPanelOutput(vessel, part, part_prefab, info.sun_dir, info.sun_dist, atmo_factor) * Malfunction.Penalty(part); Lib.RequestResource(vessel, "ElectricCharge", -output * TimeWarp.fixedDeltaTime); } } // KERBALISM modules else if (module.moduleName == "Scrubber") { Scrubber.BackgroundUpdate(vessel, part.flightID); } else if (module.moduleName == "Greenhouse") { Greenhouse.BackgroundUpdate(vessel, part.flightID); } else if (module.moduleName == "Malfunction") { Malfunction.BackgroundUpdate(vessel, part.flightID); } } } } }
public override void OnStart(StartState state) { base.OnStart(state); if (HighLogic.LoadedSceneIsFlight == false) { setupExperimentGUI(); return; } //Get drill animation drillAnimation = this.part.FindModuleImplementing<ModuleAnimationGroup>(); //Harvester harvester = this.part.FindModuleImplementing<ModuleResourceHarvester>(); //Core sample state coreSampleState = CoreSampleStates.Ready; //If the biome has been unlocked yet then get the samples left if (situationIsValid() && Utils.IsBiomeUnlocked(this.part.vessel)) coreSampleStatus = getSamplesLeft().ToString(); else coreSampleStatus = kUnknown; //Setup the gui setupGUI(); }
static void ProcessHarvester(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, ModuleResourceHarvester harvester, vessel_resources resources, double elapsed_s) { // note: ignore stock temperature mechanic of harvesters // note: ignore autoshutdown // note: ignore depletion (stock seem to do the same) // note: 'undo' stock behaviour by forcing lastUpdateTime to now (to minimize overlapping calculations from this and stock post-facto simulation) // if active if (Lib.Proto.GetBool(m, "IsActivated")) { // do nothing if full // note: comparing against previous amount if (resources.Info(v, harvester.ResourceName).level < harvester.FillAmount - double.Epsilon) { // deduce crew bonus int exp_level = -1; if (harvester.UseSpecialistBonus) { foreach (ProtoCrewMember c in Lib.CrewList(v)) { if (c.experienceTrait.Effects.Find(k => k.Name == harvester.ExperienceEffect) != null) { exp_level = Math.Max(exp_level, c.experienceLevel); } } } double exp_bonus = exp_level < 0 ? harvester.EfficiencyBonus * harvester.SpecialistBonusBase : harvester.EfficiencyBonus * (harvester.SpecialistBonusBase + (harvester.SpecialistEfficiencyFactor * (exp_level + 1))); // detect amount of ore in the ground AbundanceRequest request = new AbundanceRequest { Altitude = v.altitude, BodyId = v.mainBody.flightGlobalsIndex, CheckForLock = false, Latitude = v.latitude, Longitude = v.longitude, ResourceType = (HarvestTypes)harvester.HarvesterType, ResourceName = harvester.ResourceName }; double abundance = ResourceMap.Instance.GetAbundance(request); // if there is actually something (should be if active when unloaded) if (abundance > harvester.HarvestThreshold) { // create and commit recipe resource_recipe recipe = new resource_recipe(); foreach (var ir in harvester.inputList) { recipe.Input(ir.ResourceName, ir.Ratio * elapsed_s); } recipe.Output(harvester.ResourceName, abundance * harvester.Efficiency * exp_bonus * elapsed_s, true); resources.Transform(recipe); } } // undo stock behaviour by forcing last_update_time to now Lib.Proto.Set(m, "lastUpdateTime", Planetarium.GetUniversalTime()); } }
public float GetHarvesterHeat(ModuleResourceHarvester harverster) { return(harverster.TemperatureModifier); }
// called at every simulation step public void FixedUpdate() { // do nothing if paused if (Lib.IsPaused()) return; // do nothing if DB isn't ready if (!DB.Ready()) return; // for each vessel foreach(Vessel vessel in FlightGlobals.Vessels) { // skip invalid vessels if (!Lib.IsVessel(vessel)) continue; // skip loaded vessels if (vessel.loaded) continue; // get vessel data from the db vessel_data vd = DB.VesselData(vessel.id); // get vessel info from the cache vessel_info info = Cache.VesselInfo(vessel); // calculate atmospheric factor (proportion of flux not blocked by atmosphere) double atmo_factor = Sim.AtmosphereFactor(vessel.mainBody, info.position, info.sun_dir); // for each part foreach(ProtoPartSnapshot part in vessel.protoVessel.protoPartSnapshots) { // get part prefab (required for module properties) Part part_prefab = PartLoader.getPartInfoByName(part.partName).partPrefab; // store index of ModuleResourceConverter to process // rationale: a part can contain multiple resource converters int converter_index = 0; // for each module foreach(ProtoPartModuleSnapshot module in part.modules) { // something weird is going on, skip this if (!part_prefab.Modules.Contains(module.moduleName)) continue; // command module if (module.moduleName == "ModuleCommand") { // get module from prefab ModuleCommand command = part_prefab.Modules.GetModules<ModuleCommand>()[0]; // 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 || part.protoModuleCrew.Count > 0) { // for each input resource foreach(ModuleResource ir in command.inputResources) { // consume the resource Lib.RequestResource(vessel, ir.name, ir.rate * TimeWarp.fixedDeltaTime); } } } // solar panel else if (module.moduleName == "ModuleDeployableSolarPanel") { // determine if extended bool extended = module.moduleValues.GetValue("stateString") == ModuleDeployableSolarPanel.panelStates.EXTENDED.ToString(); // if in sunlight and extended if (info.sunlight && extended) { // get module from prefab ModuleDeployableSolarPanel panel = part_prefab.Modules.GetModules<ModuleDeployableSolarPanel>()[0]; // produce electric charge Lib.RequestResource(vessel, "ElectricCharge", -PanelOutput(vessel, part, panel, info.sun_dir, info.sun_dist, atmo_factor) * TimeWarp.fixedDeltaTime * Malfunction.Penalty(part)); } } // generator // note: assume generators require all input else if (module.moduleName == "ModuleGenerator") { // determine if active bool activated = Convert.ToBoolean(module.moduleValues.GetValue("generatorIsActive")); // if active if (activated) { // get module from prefab ModuleGenerator generator = part_prefab.Modules.GetModules<ModuleGenerator>()[0]; // determine if vessel is full of all output resources bool full = true; foreach(var or in generator.outputList) { double amount = Lib.GetResourceAmount(vessel, or.name); double capacity = Lib.GetResourceCapacity(vessel, or.name); double perc = capacity > 0.0 ? amount / capacity : 0.0; full &= (perc >= 1.0 - double.Epsilon); } // if not full if (!full) { // calculate worst required resource percentual double worst_input = 1.0; foreach(var ir in generator.inputList) { double required = ir.rate * TimeWarp.fixedDeltaTime; double amount = Lib.GetResourceAmount(vessel, ir.name); worst_input = Math.Min(worst_input, amount / required); } // for each input resource foreach(var ir in generator.inputList) { // consume the resource Lib.RequestResource(vessel, ir.name, ir.rate * worst_input * TimeWarp.fixedDeltaTime); } // for each output resource foreach(var or in generator.outputList) { // produce the resource Lib.RequestResource(vessel, or.name, -or.rate * worst_input * TimeWarp.fixedDeltaTime * Malfunction.Penalty(part)); } } } } // converter // note: support multiple resource converters // note: ignore stock temperature mechanic of converters // note: ignore autoshutdown // note: ignore crew experience bonus (seem that stock ignore it too) // note: 'undo' stock behaviour by forcing lastUpdateTime to now (to minimize overlapping calculations from this and stock post-facto simulation) // note: support PlanetaryBaseSystem converters // note: support NearFuture reactors else if (module.moduleName == "ModuleResourceConverter" || module.moduleName == "ModuleKPBSConverter" || module.moduleName == "FissionReactor") { // get module from prefab ModuleResourceConverter converter = part_prefab.Modules.GetModules<ModuleResourceConverter>()[converter_index++]; // determine if active bool activated = Convert.ToBoolean(module.moduleValues.GetValue("IsActivated")); // if active if (activated) { // determine if vessel is full of all output resources bool full = true; foreach(var or in converter.outputList) { double amount = Lib.GetResourceAmount(vessel, or.ResourceName); double capacity = Lib.GetResourceCapacity(vessel, or.ResourceName); double perc = capacity > 0.0 ? amount / capacity : 0.0; full &= (perc >= converter.FillAmount - double.Epsilon); } // if not full if (!full) { // calculate worst required resource percentual double worst_input = 1.0; foreach(var ir in converter.inputList) { double required = ir.Ratio * TimeWarp.fixedDeltaTime; double amount = Lib.GetResourceAmount(vessel, ir.ResourceName); worst_input = Math.Min(worst_input, amount / required); } // for each input resource foreach(var ir in converter.inputList) { // consume the resource Lib.RequestResource(vessel, ir.ResourceName, ir.Ratio * worst_input * TimeWarp.fixedDeltaTime); } // for each output resource foreach(var or in converter.outputList) { // produce the resource Lib.RequestResource(vessel, or.ResourceName, -or.Ratio * worst_input * TimeWarp.fixedDeltaTime * Malfunction.Penalty(part)); } } // undo stock behaviour by forcing last_update_time to now module.moduleValues.SetValue("lastUpdateTime", Planetarium.GetUniversalTime().ToString()); } } // drill // note: ignore stock temperature mechanic of harvesters // note: ignore autoshutdown // note: ignore depletion (stock seem to do the same) // note: 'undo' stock behaviour by forcing lastUpdateTime to now (to minimize overlapping calculations from this and stock post-facto simulation) else if (module.moduleName == "ModuleResourceHarvester") { // determine if active bool activated = Convert.ToBoolean(module.moduleValues.GetValue("IsActivated")); // if active if (activated) { // get module from prefab ModuleResourceHarvester harvester = part_prefab.Modules.GetModules<ModuleResourceHarvester>()[0]; // [disabled] reason: not working // deduce crew bonus /*double experience_bonus = 0.0; if (harvester.UseSpecialistBonus) { foreach(ProtoCrewMember c in vessel.protoVessel.GetVesselCrew()) { experience_bonus = Math.Max(experience_bonus, (c.trait == harvester.Specialty) ? (double)c.experienceLevel : 0.0); } }*/ const double crew_bonus = 1.0; //harvester.SpecialistBonusBase + (experience_bonus + 1.0) * harvester.SpecialistEfficiencyFactor; // detect amount of ore in the ground AbundanceRequest request = new AbundanceRequest { Altitude = vessel.altitude, BodyId = vessel.mainBody.flightGlobalsIndex, CheckForLock = false, Latitude = vessel.latitude, Longitude = vessel.longitude, ResourceType = (HarvestTypes)harvester.HarvesterType, ResourceName = harvester.ResourceName }; double abundance = ResourceMap.Instance.GetAbundance(request); // if there is actually something (should be if active when unloaded) if (abundance > harvester.HarvestThreshold) { // calculate worst required resource percentual double worst_input = 1.0; foreach(var ir in harvester.inputList) { double required = ir.Ratio * TimeWarp.fixedDeltaTime; double amount = Lib.GetResourceAmount(vessel, ir.ResourceName); worst_input = Math.Min(worst_input, amount / required); } // for each input resource foreach(var ir in harvester.inputList) { // consume the resource Lib.RequestResource(vessel, ir.ResourceName, ir.Ratio * worst_input * TimeWarp.fixedDeltaTime); } // determine resource produced double res = abundance * harvester.Efficiency * crew_bonus * worst_input * Malfunction.Penalty(part); // accumulate ore Lib.RequestResource(vessel, harvester.ResourceName, -res * TimeWarp.fixedDeltaTime); } // undo stock behaviour by forcing last_update_time to now module.moduleValues.SetValue("lastUpdateTime", Planetarium.GetUniversalTime().ToString()); } } // asteroid drill // note: untested // note: ignore stock temperature mechanic of asteroid drills // note: ignore autoshutdown // note: 'undo' stock behaviour by forcing lastUpdateTime to now (to minimize overlapping calculations from this and stock post-facto simulation) else if (module.moduleName == "ModuleAsteroidDrill") { // determine if active bool activated = Convert.ToBoolean(module.moduleValues.GetValue("IsActivated")); // if active if (activated) { // get module from prefab ModuleAsteroidDrill asteroid_drill = part_prefab.Modules.GetModules<ModuleAsteroidDrill>()[0]; // [disabled] reason: not working // deduce crew bonus /*double experience_bonus = 0.0; if (asteroid_drill.UseSpecialistBonus) { foreach(ProtoCrewMember c in vessel.protoVessel.GetVesselCrew()) { experience_bonus = Math.Max(experience_bonus, (c.trait == asteroid_drill.Specialty) ? (double)c.experienceLevel : 0.0); } }*/ const double crew_bonus = 1.0; //asteroid_drill.SpecialistBonusBase + (experience_bonus + 1.0) * asteroid_drill.SpecialistEfficiencyFactor; // get asteroid data ProtoPartModuleSnapshot asteroid_info = null; ProtoPartModuleSnapshot asteroid_resource = null; foreach(ProtoPartSnapshot p in vessel.protoVessel.protoPartSnapshots) { if (asteroid_info == null) asteroid_info = p.modules.Find(k => k.moduleName == "ModuleAsteroidInfo"); if (asteroid_resource == null) asteroid_resource = p.modules.Find(k => k.moduleName == "ModuleAsteroidResource"); } // if there is actually an asteroid attached to this active asteroid drill (it should) if (asteroid_info != null && asteroid_resource != null) { // get some data double mass_threshold = Convert.ToDouble(asteroid_info.moduleValues.GetValue("massThresholdVal")); double mass = Convert.ToDouble(asteroid_info.moduleValues.GetValue("currentMassVal")); double abundance = Convert.ToDouble(asteroid_resource.moduleValues.GetValue("abundance")); string res_name = asteroid_resource.moduleValues.GetValue("resourceName"); double res_density = PartResourceLibrary.Instance.GetDefinition(res_name).density; // if asteroid isn't depleted if (mass > mass_threshold && abundance > double.Epsilon) { // consume EC double ec_required = asteroid_drill.PowerConsumption * TimeWarp.fixedDeltaTime; double ec_consumed = Lib.RequestResource(vessel, "ElectricCharge", ec_required); double ec_ratio = ec_consumed / ec_required; // determine resource extracted double res_amount = abundance * asteroid_drill.Efficiency * crew_bonus * ec_ratio * TimeWarp.fixedDeltaTime; // produce mined resource Lib.RequestResource(vessel, res_name, -res_amount); // consume asteroid mass asteroid_info.moduleValues.SetValue("currentMassVal", (mass - res_density * res_amount).ToString()); } } // undo stock behaviour by forcing last_update_time to now module.moduleValues.SetValue("lastUpdateTime", Planetarium.GetUniversalTime().ToString()); } } // science lab // note: we are only simulating the EC consumption // note: there is no easy way to 'stop' the lab when there isn't enough EC else if (module.moduleName == "ModuleScienceConverter") { // get module from prefab ModuleScienceConverter lab = part_prefab.Modules.GetModules<ModuleScienceConverter>()[0]; // determine if active bool activated = Convert.ToBoolean(module.moduleValues.GetValue("IsActivated")); // if active if (activated) { Lib.RequestResource(vessel, "ElectricCharge", lab.powerRequirement * TimeWarp.fixedDeltaTime); } } // SCANSAT support else if (module.moduleName == "SCANsat" || module.moduleName == "ModuleSCANresourceScanner") { // get ec consumption rate PartModule scansat = part_prefab.Modules[module.moduleName]; double power = Lib.ReflectionValue<float>(scansat, "power"); double ec_required = power * TimeWarp.fixedDeltaTime; bool is_scanning = Lib.GetProtoValue<bool>(module, "scanning"); bool was_disabled = vd.scansat_id.Contains(part.flightID); // if its scanning if (Lib.GetProtoValue<bool>(module, "scanning")) { // consume ec double ec_consumed = Lib.RequestResource(vessel, "ElectricCharge", ec_required); // if there isn't enough ec if (ec_consumed < ec_required * 0.99 && ec_required > double.Epsilon) { // unregister scanner SCANsat.stopScanner(vessel, module, part_prefab); // remember disabled scanner vd.scansat_id.Add(part.flightID); // give the user some feedback if (DB.VesselData(vessel.id).cfg_ec == 1) Message.Post("SCANsat sensor was disabled on <b>" + vessel.vesselName + "</b>"); } } // if it was disabled else if (vd.scansat_id.Contains(part.flightID)) { // if there is enough ec double ec_amount = Lib.GetResourceAmount(vessel, "ElectricCharge"); double ec_capacity = Lib.GetResourceCapacity(vessel, "ElectricCharge"); if (ec_capacity > double.Epsilon && ec_amount / ec_capacity > 0.25) //< re-enable at 25% EC { // re-enable the scanner SCANsat.resumeScanner(vessel, module, part_prefab); // give the user some feedback if (DB.VesselData(vessel.id).cfg_ec == 1) Message.Post("SCANsat sensor resumed operations on <b>" + vessel.vesselName + "</b>"); } } // forget active scanners if (Lib.GetProtoValue<bool>(module, "scanning")) vd.scansat_id.Remove(part.flightID); } // NearFutureSolar support // note: we assume deployed, this is a current limitation else if (module.moduleName == "ModuleCurvedSolarPanel") { // if in sunlight if (info.sunlight) { PartModule curved_panel = part_prefab.Modules[module.moduleName]; double output = CurvedPanelOutput(vessel, part, part_prefab, curved_panel, info.sun_dir, info.sun_dist, atmo_factor) * Malfunction.Penalty(part); Lib.RequestResource(vessel, "ElectricCharge", -output * TimeWarp.fixedDeltaTime); } } // NearFutureElectrical support // note: fission generator ignore heat // note: radioisotope generator doesn't support easy mode else if (module.moduleName == "FissionGenerator") { PartModule generator = part_prefab.Modules[module.moduleName]; double power = Lib.ReflectionValue<float>(generator, "PowerGeneration"); // get fission reactor tweakable, will default to 1.0 for other modules var reactor = part.modules.Find(k => k.moduleName == "FissionReactor"); double tweakable = reactor == null ? 1.0 : Lib.ConfigValue(reactor.moduleValues, "CurrentPowerPercent", 100.0) * 0.01; Lib.RequestResource(vessel, "ElectricCharge", -power * tweakable * TimeWarp.fixedDeltaTime); } else if (module.moduleName == "ModuleRadioisotopeGenerator") { double mission_time = vessel.missionTime / (3600.0 * Lib.HoursInDay() * Lib.DaysInYear()); PartModule generator = part_prefab.Modules[module.moduleName]; double half_life = Lib.ReflectionValue<float>(generator, "HalfLife"); double remaining = Math.Pow(2.0, (-mission_time) / half_life); double power = Lib.ReflectionValue<float>(generator, "BasePower"); Lib.RequestResource(vessel, "ElectricCharge", -power * remaining * TimeWarp.fixedDeltaTime); } // KERBALISM modules else if (module.moduleName == "Scrubber") { Scrubber.BackgroundUpdate(vessel, part.flightID); } else if (module.moduleName == "Greenhouse") { Greenhouse.BackgroundUpdate(vessel, part.flightID); } else if (module.moduleName == "GravityRing") { GravityRing.BackgroundUpdate(vessel, part.flightID); } else if (module.moduleName == "Malfunction") { Malfunction.BackgroundUpdate(vessel, part.flightID); } } } } }
public ProtoDrillDevice(ProtoPartModuleSnapshot drill, ModuleResourceHarvester prefab, ProtoPartModuleSnapshot deploy) { this.drill = drill; this.prefab = prefab; this.deploy = deploy; }
public float GetHarvesterHeat(ModuleResourceHarvester harverster) { return harverster.TemperatureModifier; }
public PartStats(Part part) { this.mass = part.mass; if (part.partInfo.variant != null) { kRnDVariants = KRnD.getVariants(part); currentVariant = part.partInfo.variant.Name; currentVariantMass = part.partInfo.variant.Mass; variantBaseMass = part.baseVariant.Mass; } if (kRnDVariants != null) { hasVariants = true; } else { currentVariantMass = 0; variantBaseMass = 0; hasVariants = false; } this.skinMaxTemp = part.skinMaxTemp; this.intMaxTemp = part.maxTemp; // There should only be one or the other, engines or RCS: List <ModuleEngines> engineModules = KRnD.getEngineModules(part); ModuleRCS rcsModule = KRnD.getRcsModule(part); if (engineModules != null) { this.maxFuelFlows = new List <float>(); this.atmosphereCurves = new List <FloatCurve>(); for (int i = 0; i < engineModules.Count; i++) { ModuleEngines engineModule = engineModules[i]; this.maxFuelFlows.Add(engineModule.maxFuelFlow); FloatCurve atmosphereCurve = new FloatCurve(); for (int i5 = 0; i5 < engineModule.atmosphereCurve.Curve.length; i5++) { Keyframe frame = engineModule.atmosphereCurve.Curve[i5]; atmosphereCurve.Add(frame.time, frame.value); } this.atmosphereCurves.Add(atmosphereCurve); } } else if (rcsModule) { this.maxFuelFlows = new List <float>(); this.atmosphereCurves = new List <FloatCurve>(); this.maxFuelFlows.Add(rcsModule.thrusterPower); FloatCurve atmosphereCurve = new FloatCurve(); for (int i = 0; i < rcsModule.atmosphereCurve.Curve.length; i++) { Keyframe frame = rcsModule.atmosphereCurve.Curve[i]; atmosphereCurve.Add(frame.time, frame.value); } this.atmosphereCurves.Add(atmosphereCurve); } ModuleReactionWheel reactionWheel = KRnD.getReactionWheelModule(part); if (reactionWheel) { this.torque = reactionWheel.RollTorque; // There is also pitch- and yaw-torque, but they should all be the same } // WIP //ModuleDataTransmitter dataTransmitter = KRnD.getDataTransmitterModule(part); //if (dataTransmitter) //{ // this.antPower = dataTransmitter.antennaPower; //} ModuleResourceHarvester resourceHarvester = KRnD.getResourceHarvesterModule(part); if (resourceHarvester) { this.harvester = resourceHarvester.Efficiency; } ModuleActiveRadiator activeRadiator = KRnD.getActiveRadiatorModule(part); if (activeRadiator) { this.radiatorEfficiency = activeRadiator.maxEnergyTransfer; } ModuleDeployableSolarPanel solarPanel = KRnD.getSolarPanelModule(part); if (solarPanel) { this.chargeRate = solarPanel.chargeRate; } ModuleWheelBase landingLeg = KRnD.getLandingLegModule(part); if (landingLeg) { this.crashTolerance = part.crashTolerance; // Every part has a crash tolerance, but we only want to improve landing legs. } PartResource electricCharge = KRnD.getChargeResource(part); if (electricCharge != null) { this.batteryCharge = electricCharge.maxAmount; } ModuleGenerator generator = KRnD.getGeneratorModule(part); if (generator != null) { generatorEfficiency = new Dictionary <String, double>(); for (int i = 0; i < generator.resHandler.outputResources.Count; i++) { ModuleResource outputResource = generator.resHandler.outputResources[i]; generatorEfficiency.Add(outputResource.name, outputResource.rate); } } PartModule fissionGenerator = KRnD.getFissionGeneratorModule(part); if (fissionGenerator != null) { fissionPowerGeneration = KRnD.getGenericModuleValue(fissionGenerator, "PowerGeneration"); } // There might be different converter-modules in the same part with different names (eg for Fuel, Monopropellant, etc): List <ModuleResourceConverter> converterList = KRnD.getConverterModules(part); if (converterList != null) { converterEfficiency = new Dictionary <String, Dictionary <String, double> >(); for (int i = 0; i < converterList.Count; i++) { ModuleResourceConverter converter = converterList[i]; Dictionary <String, double> thisConverterEfficiency = new Dictionary <String, double>(); for (int i2 = 0; i2 < converter.outputList.Count; i2++) { ResourceRatio resourceRatio = converter.outputList[i2]; thisConverterEfficiency.Add(resourceRatio.ResourceName, resourceRatio.Ratio); } converterEfficiency.Add(converter.ConverterName, thisConverterEfficiency); } } ModuleParachute parachute = KRnD.getParachuteModule(part); if (parachute) { this.chuteMaxTemp = parachute.chuteMaxTemp; } ModuleProceduralFairing fairing = KRnD.getFairingModule(part); if (fairing) { this.fairingAreaMass = fairing.UnitAreaMass; } List <PartResource> fuelResources = KRnD.getFuelResources(part); if (fuelResources != null) { fuelCapacities = new Dictionary <string, double>(); fuelCapacitiesSum = 0; for (int i = 0; i < fuelResources.Count; i++) { PartResource fuelResource = fuelResources[i]; fuelCapacities.Add(fuelResource.resourceName, fuelResource.maxAmount); fuelCapacitiesSum += fuelResource.maxAmount; } } }
protected void updateDrill() { bool enableDrill = false; float value; string resourceName; ModuleResourceHarvester harvester = this.part.FindModuleImplementing <ModuleResourceHarvester>(); //No drill? No need to proceed. if (harvester == null) { return; } //See if the drill is enabled. if (CurrentTemplate.HasValue("enableDrill")) { enableDrill = bool.Parse(CurrentTemplate.GetValue("enableDrill")); } ModuleOverheatDisplay overheat = this.part.FindModuleImplementing <ModuleOverheatDisplay>(); if (overheat != null) { overheat.enabled = enableDrill; overheat.isEnabled = enableDrill; } ModuleCoreHeat coreHeat = this.part.FindModuleImplementing <ModuleCoreHeat>(); if (coreHeat != null) { coreHeat.enabled = enableDrill; coreHeat.isEnabled = enableDrill; } WBIDrillSwitcher drillSwitcher = this.part.FindModuleImplementing <WBIDrillSwitcher>(); if (drillSwitcher != null) { drillSwitcher.enabled = enableDrill; drillSwitcher.isEnabled = enableDrill; } WBIEfficiencyMonitor extractionMonitor = this.part.FindModuleImplementing <WBIEfficiencyMonitor>(); if (extractionMonitor != null) { extractionMonitor.enabled = enableDrill; extractionMonitor.isEnabled = enableDrill; } //Update the drill if (enableDrill) { harvester.EnableModule(); } else { harvester.DisableModule(); } //Setup drill parameters if (enableDrill) { if (CurrentTemplate.HasValue("converterName")) { harvester.ConverterName = CurrentTemplate.GetValue("converterName"); } if (CurrentTemplate.HasValue("drillStartAction")) { harvester.StartActionName = CurrentTemplate.GetValue("drillStartAction"); harvester.Events["StartResourceConverter"].guiName = CurrentTemplate.GetValue("drillStartAction"); } if (CurrentTemplate.HasValue("drillStopAction")) { harvester.StopActionName = CurrentTemplate.GetValue("drillStopAction"); harvester.Events["StopResourceConverter"].guiName = CurrentTemplate.GetValue("drillStopAction"); } if (CurrentTemplate.HasValue("drillEficiency")) { harvester.Efficiency = float.Parse(CurrentTemplate.GetValue("drillEficiency")); } if (CurrentTemplate.HasValue("drillResource")) { resourceName = CurrentTemplate.GetValue("drillResource"); harvester.ResourceName = resourceName; harvester.Fields["ResourceStatus"].guiName = resourceName + " rate"; } if (CurrentTemplate.HasValue("drillElectricCharge")) { if (float.TryParse(CurrentTemplate.GetValue("drillElectricCharge"), out value)) { ResourceRatio[] inputRatios = harvester.inputList.ToArray(); for (int inputIndex = 0; inputIndex < inputRatios.Length; inputIndex++) { if (inputRatios[inputIndex].ResourceName == "ElectricCharge") { inputRatios[inputIndex].Ratio = value; } } } } harvester.Fields["status"].guiName = "Drill Status"; MonoUtilities.RefreshContextWindows(this.part); } }
static void ProcessHarvester(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, ModuleResourceHarvester harvester, vessel_resources resources, double elapsed_s) { // note: ignore stock temperature mechanic of harvesters // note: ignore autoshutdown // note: ignore depletion (stock seem to do the same) // note: using hard-coded crew bonus values from the wiki because the module data make zero sense (DERP ALERT) // note: 'undo' stock behaviour by forcing lastUpdateTime to now (to minimize overlapping calculations from this and stock post-facto simulation) // if active if (Lib.Proto.GetBool(m, "IsActivated")) { // do nothing if full // note: comparing against previous amount if (resources.Info(v, harvester.ResourceName).level < harvester.FillAmount - double.Epsilon) { // get malfunction penalty double penalty = Reliability.Penalty(p, "Harvester"); // deduce crew bonus int exp_level = -1; if (harvester.UseSpecialistBonus) { foreach (ProtoCrewMember c in v.protoVessel.GetVesselCrew()) { exp_level = Math.Max(exp_level, c.trait == harvester.Specialty ? c.experienceLevel : -1); } } double exp_bonus = exp_level < 0 ? 1.0 : 5.0 + (double)exp_level * 4.0; // detect amount of ore in the ground AbundanceRequest request = new AbundanceRequest { Altitude = v.altitude, BodyId = v.mainBody.flightGlobalsIndex, CheckForLock = false, Latitude = v.latitude, Longitude = v.longitude, ResourceType = (HarvestTypes)harvester.HarvesterType, ResourceName = harvester.ResourceName }; double abundance = ResourceMap.Instance.GetAbundance(request); // if there is actually something (should be if active when unloaded) if (abundance > harvester.HarvestThreshold) { // create and commit recipe resource_recipe recipe = new resource_recipe(resource_recipe.harvester_priority); foreach (var ir in harvester.inputList) { recipe.Input(ir.ResourceName, ir.Ratio * elapsed_s); } recipe.Output(harvester.ResourceName, abundance * harvester.Efficiency * exp_bonus * penalty * elapsed_s); resources.Transform(recipe); } } // undo stock behaviour by forcing last_update_time to now Lib.Proto.Set(m, "lastUpdateTime", Planetarium.GetUniversalTime()); } }
public static ec_data analyze_ec(List<Part> parts, environment_data env, crew_data crew, food_data food, oxygen_data oxygen, signal_data signal) { // store data ec_data ec = new ec_data(); // calculate climate cost ec.consumed = (double)crew.count * env.temp_diff * Settings.ElectricChargePerSecond; // scan the parts foreach(Part p in parts) { // accumulate EC storage ec.storage += Lib.GetResourceAmount(p, "ElectricCharge"); // remember if we already considered a resource converter module // rationale: we assume only the first module in a converter is active bool first_converter = true; // for each module foreach(PartModule m in p.Modules) { // command if (m.moduleName == "ModuleCommand") { ModuleCommand mm = (ModuleCommand)m; foreach(ModuleResource res in mm.inputResources) { if (res.name == "ElectricCharge") { ec.consumed += res.rate; } } } // solar panel else if (m.moduleName == "ModuleDeployableSolarPanel") { ModuleDeployableSolarPanel mm = (ModuleDeployableSolarPanel)m; double solar_k = (mm.useCurve ? mm.powerCurve.Evaluate((float)env.sun_dist) : env.sun_flux / Sim.SolarFluxAtHome()); double generated = mm.chargeRate * solar_k * env.atmo_factor; ec.generated_sunlight += generated; ec.best_ec_generator = Math.Max(ec.best_ec_generator, generated); } // generator else if (m.moduleName == "ModuleGenerator") { // skip launch clamps, that include a generator if (p.partInfo.name == "launchClamp1") continue; ModuleGenerator mm = (ModuleGenerator)m; foreach(ModuleResource res in mm.inputList) { if (res.name == "ElectricCharge") { ec.consumed += res.rate; } } foreach(ModuleResource res in mm.outputList) { if (res.name == "ElectricCharge") { ec.generated_shadow += res.rate; ec.generated_sunlight += res.rate; ec.best_ec_generator = Math.Max(ec.best_ec_generator, res.rate); } } } // converter // note: only electric charge is considered for resource converters // note: we only consider the first resource converter in a part, and ignore the rest else if (m.moduleName == "ModuleResourceConverter" && first_converter) { ModuleResourceConverter mm = (ModuleResourceConverter)m; foreach(ResourceRatio rr in mm.inputList) { if (rr.ResourceName == "ElectricCharge") { ec.consumed += rr.Ratio; } } foreach(ResourceRatio rr in mm.outputList) { if (rr.ResourceName == "ElectricCharge") { ec.generated_shadow += rr.Ratio; ec.generated_sunlight += rr.Ratio; ec.best_ec_generator = Math.Max(ec.best_ec_generator, rr.Ratio); } } first_converter = false; } // harvester // note: only electric charge is considered for resource harvesters else if (m.moduleName == "ModuleResourceHarvester") { ModuleResourceHarvester mm = (ModuleResourceHarvester)m; foreach(ResourceRatio rr in mm.inputList) { if (rr.ResourceName == "ElectricCharge") { ec.consumed += rr.Ratio; } } } // active radiators else if (m.moduleName == "ModuleActiveRadiator") { ModuleActiveRadiator mm = (ModuleActiveRadiator)m; if (mm.IsCooling) { foreach(var rr in mm.inputResources) { if (rr.name == "ElectricCharge") { ec.consumed += rr.rate; } } } } // wheels else if (m.moduleName == "ModuleWheelMotor") { ModuleWheelMotor mm = (ModuleWheelMotor)m; if (mm.motorEnabled && mm.inputResource.name == "ElectricCharge") { ec.consumed += mm.inputResource.rate; } } else if (m.moduleName == "ModuleWheelMotorSteering") { ModuleWheelMotorSteering mm = (ModuleWheelMotorSteering)m; if (mm.motorEnabled && mm.inputResource.name == "ElectricCharge") { ec.consumed += mm.inputResource.rate; } } // SCANsat support else if (m.moduleName == "SCANsat" || m.moduleName == "ModuleSCANresourceScanner") { // include it in ec consumption, if deployed if (SCANsat.isDeployed(p, m)) ec.consumed += Lib.ReflectionValue<float>(m, "power"); } // NearFutureSolar support // note: assume half the components are in sunlight, and average inclination is half else if (m.moduleName == "ModuleCurvedSolarPanel") { // get total rate double tot_rate = Lib.ReflectionValue<float>(m, "TotalEnergyRate"); // get number of components int components = p.FindModelTransforms(Lib.ReflectionValue<string>(m, "PanelTransformName")).Length; // approximate output // 0.7071: average clamped cosine ec.generated_sunlight += 0.7071 * tot_rate; } } } // include cost from greenhouses artificial lighting ec.consumed += food.greenhouse_cost; // include cost from scrubbers ec.consumed += oxygen.scrubber_cost; // include relay cost for the best relay antenna ec.consumed += signal.relay_cost; // finally, calculate life expectancy of ec ec.life_expectancy_sunlight = ec.storage / Math.Max(ec.consumed - ec.generated_sunlight, 0.0); ec.life_expectancy_shadow = ec.storage / Math.Max(ec.consumed - ec.generated_shadow, 0.0); // return data return ec; }