new static public SimulatedParachute New(ModuleParachute mp, ReentrySimulation.SimCurves simCurve, double startTime, int limitChutesStage) { SimulatedParachute part = new SimulatedParachute(); part.Set(mp.part, simCurve); part.Set(mp, startTime, limitChutesStage); return part; }
public static SimulatedParachute Borrow(ModuleParachute mp, ReentrySimulation.SimCurves simCurve, double startTime, int limitChutesStage) { SimulatedParachute part = pool.Borrow(); part.Init(mp.part, simCurve); part.Init(mp, startTime, limitChutesStage); return part; }
public void Set(ModuleParachute mp, double startTime, int limitChutesStage) { this.para = mp; this.state = mp.deploymentState; willDeploy = limitChutesStage != -1 && para.part.inverseStage >= limitChutesStage; // Work out when the chute was put into its current state based on the current drag as compared to the stowed, semi deployed and fully deployed drag double timeSinceDeployment = 0; switch (mp.deploymentState) { case ModuleParachute.deploymentStates.SEMIDEPLOYED: if (mp.Anim.isPlaying) timeSinceDeployment = mp.Anim[mp.semiDeployedAnimation].time; else timeSinceDeployment = 10000000; break; case ModuleParachute.deploymentStates.DEPLOYED: if (mp.Anim.isPlaying) timeSinceDeployment = mp.Anim[mp.fullyDeployedAnimation].time; else timeSinceDeployment = 10000000; break; case ModuleParachute.deploymentStates.STOWED: case ModuleParachute.deploymentStates.ACTIVE: // If the parachute is stowed then for some reason para.parachuteDrag does not reflect the stowed drag. set this up by hand. timeSinceDeployment = 10000000; break; default: // otherwise set the time since deployment to be a very large number to indcate that it has been in that state for a long time (although we do not know how long! timeSinceDeployment = 10000000; break; } this.openningTime = startTime - timeSinceDeployment; //Debug.Log("Parachute " + para.name + " parachuteDrag:" + this.parachuteDrag + " stowedDrag:" + para.stowedDrag + " semiDeployedDrag:" + para.semiDeployedDrag + " fullyDeployedDrag:" + para.fullyDeployedDrag + " part.maximum_drag:" + para.part.maximum_drag + " part.minimum_drag:" + para.part.minimum_drag + " semiDeploymentSpeed:" + para.semiDeploymentSpeed + " deploymentSpeed:" + para.deploymentSpeed + " deploymentState:" + para.deploymentState + " timeSinceDeployment:" + timeSinceDeployment); // Keep that test code until they fix the bug in the new parachute module //if ((realDrag / parachuteDrag) > 1.01d || (realDrag / parachuteDrag) < 0.99d) // Debug.Log("Parachute " + para.name + " parachuteDrag:" + this.parachuteDrag.ToString("F3") + " RealDrag:" + realDrag.ToString("F3") + " MinDrag:" + para.part.minimum_drag.ToString("F3") + " MaxDrag:" + para.part.maximum_drag.ToString("F3")); }
public override void OnStart(StartState state) { base.OnStart(state); this.chuteModule = base.part.getFirstModuleOfType<ModuleParachute>(); ModuleParachute prefabChuteModule = base.part.partInfo.partPrefab.getFirstModuleOfType<ModuleParachute>(); if (this.chuteModule == null) { return; } this.prefabDeploySpeed = prefabChuteModule.deploymentSpeed; this.prefabSemiDeploySpeed = prefabChuteModule.semiDeploymentSpeed; this.chuteModule.Fields["deploymentSpeed"].guiActiveEditor = true; this.chuteModule.Fields["deploymentSpeed"].guiName = "Deploy Spd"; this.chuteModule.Fields["deploymentSpeed"].guiFormat = "G3"; this.chuteModule.Fields["semiDeploymentSpeed"].guiActiveEditor = true; this.chuteModule.Fields["semiDeploymentSpeed"].guiName = "Semi-Deploy Spd"; this.chuteModule.Fields["semiDeploymentSpeed"].guiFormat = "G3"; var deployField = this.Fields["deploymentFactor"].uiControlCurrent() as UI_FloatRange; var semiDeployField = this.Fields["semiDeploymentFactor"].uiControlCurrent() as UI_FloatRange; float step; if (this.maxFactor >= 5f) { step = Mathf.Round(Mathf.Pow(10f, (int)Mathf.Log10(this.maxFactor) - 1)) / 2f; } else { step = 0.1f; } deployField.maxValue = this.maxFactor; deployField.minValue = 1f; deployField.stepIncrement = step; semiDeployField.maxValue = this.maxFactor; semiDeployField.minValue = 1f; deployField.stepIncrement = step; }
protected override void DI_Start(StartState state) { chute = this.part.Modules.OfType <ModuleParachute>().Single(); foreach (Part part_each in this.part.vessel.Parts) //Make sure that there is at least one other chute on the craft! { if (part_each != this.part) { foreach (PartModule module_each in part_each.Modules) { if (module_each is ModuleParachute) { this.canFail = true; } } } } }
public override void OnAwake() { base.OnAwake(); if (part && part.Modules != null) // thanks, FlowerChild! { is_engine = (part.Modules.Contains("ModuleEngines") || part.Modules.Contains("ModuleEnginesFX")); is_eva = part.Modules.Contains("KerbalEVA"); if (part.Modules.Contains("ModuleParachute")) { parachute = (ModuleParachute)part.Modules["ModuleParachute"]; } if (part.Modules.Contains("RealChuteModule")) { realChute = part.Modules["RealChuteModule"]; rCType = realChute.GetType(); } } }
public void StartPlanning() { // what is the highest point at which we could semi deploy? - look at all the parachutes in the craft, and consider the lowest semi deployment pressure. float minSemiDeployPressure = 0; float maxFullDeployHeight = 0; parachutePresent = false; // First assume that there are no parachutes. // TODO should we check if each of these parachutes is withing the staging limit? for (int i = 0; i < autoPilot.vesselState.parachutes.Count; i++) { ModuleParachute p = autoPilot.vesselState.parachutes[i]; if (p.minAirPressureToOpen > minSemiDeployPressure) // Although this is called "minSemiDeployPressure" we want to find the largest value for each of our parachutes. This can be used to calculate the corresponding height, and hence a height at which we can be guarenteed that all our parachutes will deploy if asked to. { minSemiDeployPressure = p.minAirPressureToOpen; } if (p.deployAltitude > maxFullDeployHeight) { maxFullDeployHeight = p.deployAltitude; } parachutePresent = true; } // If parachutes are present on the craft then work out the max / min semideployment heights and the starting value. if (parachutePresent) { // TODO is there benefit in running an initial simulation to calculate the height at which the ratio between vertical and horizontal velocity would be the best for being able to deply the chutes to control the landing site? // At what ASL height does the reference body have this pressure? //maxSemiDeployHeight = (this.body.atmosphereScaleHeight *1000) * -1 * Math.Log(minSemiDeployPressure / this.body.atmosphereMultiplier); #warning FIX THAT BEFORE 1.0 !! maxSemiDeployHeight = (1 * 1000) * -1 * Math.Log(minSemiDeployPressure / 1); // We have to have semi deployed by the time we fully deploy. minSemiDeployHeight = maxFullDeployHeight; maxMultiplier = maxSemiDeployHeight / minSemiDeployHeight; // Set the inital mutiplier to be the mid point. currentMultiplier = maxMultiplier / 2; } }
/// <summary> /// Keep track of the parachutes on the vessel. /// </summary> /// <param name="vessel"></param> private void UpdateVessel(Vessel vessel) { if ((vessel.persistentId == vesselId) && (vessel.parts.Count == vesselPartCount)) { // nothing has changed, there's nothing to do return; } vesselId = vessel.persistentId; vesselPartCount = vessel.parts.Count; parachutes.Clear(); for (int i = 0; i < vessel.parts.Count; ++i) { ModuleParachute chute = AsParachute(vessel.parts[i]); if (chute != null) { parachutes.Add(chute); } } }
private void AnalyzeParachutes() { parachuteDeployable = false; foreach (var pair in parachutes) { Part p = pair.Key; List <ModuleParachute> mlist = p.Modules.GetModules <ModuleParachute>(); for (int i = 0; i < mlist.Count; i++) { ModuleParachute chute = mlist[i]; if (chute.deploymentState != ModuleParachute.deploymentStates.DEPLOYED || chute.deploymentState != ModuleParachute.deploymentStates.SEMIDEPLOYED) { parachuteDeployable = true; } } } }
public override void OnStart(StartState state) { base.OnStart(state); Debug.Log("ModuleParachutePlus.Start(): v01.08"); ParachuteModule = (ModuleParachute)GetModule("ModuleParachute"); if (null == ParachuteModule) { Debug.LogWarning("ModuleParachuteFix.Start(): Did not find Parachute Module."); return; } canopy = part.FindModelTransform(ParachuteModule.canopyName); SetupStockPlus(); GameEvents.onVesselWasModified.Add(CountSiblings); CountSiblings(vessel); }
//Cuts the chute if it's deployed public override void FailPart() { chute = part.FindModuleImplementing <ModuleParachute>(); if (chute == null) { return; } if (OhScrap.highlight) { OhScrap.SetFailedHighlight(); } if (chute.vessel != FlightGlobals.ActiveVessel) { return; } if (chute.deploymentState == ModuleParachute.deploymentStates.SEMIDEPLOYED || chute.deploymentState == ModuleParachute.deploymentStates.DEPLOYED) { chute.CutParachute(); } }
public SimulatedParachute(ModuleParachute p) { this.p = p; this.state = p.deploymentState; // Work out when the chute was put into its current state based on the current drag as compared to the stoed, semi deployed and fully deployed drag double timeSinceDeployment = 0; this.targetDrag = p.targetDrag; this.parachuteDrag = p.parachuteDrag; switch (p.deploymentState) { case ModuleParachute.deploymentStates.SEMIDEPLOYED: // If the parachute is semi deployed calculate when it was semideployed by comparing the actual drag with the stowed drag and the semideployed drag. timeSinceDeployment = (p.parachuteDrag - p.stowedDrag) / (p.semiDeployedDrag - p.stowedDrag) * p.semiDeploymentSpeed; // TODO there is an error in this, because the (semi)deployment does not increase the drag in a linear way. However this will only cause a problem for simulations run during the deployment and in unlikely to cause an error in the landing location. break; case ModuleParachute.deploymentStates.DEPLOYED: // If the parachute is deployed calculate when it was deployed by comparing the actual drag with the semideployed drag and the deployed drag. timeSinceDeployment = (p.parachuteDrag - p.semiDeployedDrag) / (p.fullyDeployedDrag - p.semiDeployedDrag) * p.deploymentSpeed; // TODO there is an error in this, because the (semi)deployment does not increase the drag in a linear way. However this will only cause a problem for simulations run during the deployment and in unlikely to cause an error in the landing location. break; case ModuleParachute.deploymentStates.STOWED: case ModuleParachute.deploymentStates.ACTIVE: // If the parachute is stowed then for some reason p.parachuteDrag does not reflect the stowed drag. set this up by hand. this.parachuteDrag = this.targetDrag = p.stowedDrag; timeSinceDeployment = 10000000; break; default: // otherwise set the time since deployment to be a very large number to indcate that it has been in that state for a long time (although we do not know how long! timeSinceDeployment = 10000000; break; } this.openningTime = -timeSinceDeployment; // Debug.Log("Parachute " + p.name + " parachuteDrag:" + p.parachuteDrag + " targetDrag:" + p.targetDrag + " stowedDrag:" + p.stowedDrag + " semiDeployedDrag:" + p.semiDeployedDrag + " fullyDeployedDrag:" + p.fullyDeployedDrag + " part.maximum_drag:" + p.part.maximum_drag + " part.minimum_drag:" + p.part.minimum_drag + " semiDeploymentSpeed:" + p.semiDeploymentSpeed + " deploymentSpeed:" + p.deploymentSpeed + " deploymentState:" + p.deploymentState + " timeSinceDeployment:" + timeSinceDeployment); }
void DeployParachutes() { if (vesselState.mainBody.atmosphere && deployChutes) { for (int i = 0; i < vesselState.parachutes.Count; i++) { ModuleParachute p = vesselState.parachutes[i]; // what is the ASL at which we should deploy this parachute? It is the actual deployment height above the surface + the ASL of the predicted landing point. double LandingSiteASL = LandingAltitude; double ParachuteDeployAboveGroundAtLandingSite = p.deployAltitude * this.parachutePlan.Multiplier; double ASLDeployAltitude = ParachuteDeployAboveGroundAtLandingSite + LandingSiteASL; if (p.part.inverseStage >= limitChutesStage && p.deploymentState == ModuleParachute.deploymentStates.STOWED && ASLDeployAltitude > vesselState.altitudeASL && p.deploymentSafeState == ModuleParachute.deploymentSafeStates.SAFE) { p.Deploy(); //Debug.Log("Deploying parachute " + p.name + " at " + ASLDeployAltitude + ". (" + LandingSiteASL + " + " + ParachuteDeployAboveGroundAtLandingSite +")"); } } } }
// This methods works out if there are any parachutes that are capable of being deployed public bool ParachutesDeployable() { if (!vesselState.mainBody.atmosphere) { return(false); } if (!deployChutes) { return(false); } for (int i = 0; i < vesselState.parachutes.Count; i++) { ModuleParachute p = vesselState.parachutes[i]; if (Math.Max(p.part.inverseStage, 0) >= limitChutesStage && p.deploymentState == ModuleParachute.deploymentStates.STOWED) { return(true); } } return(false); }
public bool IsShielded(Vector3 direction) { if ((object)parachute != null) { ModuleParachute p = parachute; if (p.deploymentState == ModuleParachute.deploymentStates.DEPLOYED || p.deploymentState == ModuleParachute.deploymentStates.SEMIDEPLOYED) { return(false); } } if ((object)realChute != null) { string mainDeployState = (string)rCType.GetField("depState").GetValue(realChute); string secDeployState = (string)rCType.GetField("secDepState").GetValue(realChute); if ((mainDeployState + secDeployState).Contains("DEPLOYED")) // LOW, PRE, or just DEPLOYED { return(false); } } if (GetShieldedStateFromFAR() == true) { return(true); } Ray ray = new Ray(part.transform.position + direction.normalized * adjustCollider, direction.normalized); RaycastHit[] hits = Physics.RaycastAll(ray, 10); foreach (RaycastHit hit in hits) { if (hit.rigidbody != null && hit.collider != part.collider) { return(true); } } return(false); }
private void Init(Vessel v, ReentrySimulation.SimCurves _simCurves, double startTime, int limitChutesStage) { totalMass = 0; var oParts = v.Parts; count = oParts.Count; simCurves = _simCurves; if (parts.Capacity < count) { parts.Capacity = count; } for (int i = 0; i < count; i++) { SimulatedPart simulatedPart = null; bool special = false; for (int j = 0; j < oParts[i].Modules.Count; j++) { ModuleParachute mp = oParts[i].Modules[j] as ModuleParachute; if (mp != null && v.mainBody.atmosphere) { special = true; simulatedPart = SimulatedParachute.Borrow(mp, simCurves, startTime, limitChutesStage); } } if (!special) { simulatedPart = SimulatedPart.Borrow(oParts[i], simCurves); } parts.Add(simulatedPart); totalMass += simulatedPart.totalMass; } }
public SimulatedVessel(Vessel v, SimCurves simCurves, double startTime, int limitChutesStage) { totalMass = 0; var oParts = v.Parts; count = oParts.Count; this.simCurves = simCurves; if (parts.Capacity < count) { parts.Capacity = count; } for (int i = 0; i < count; i++) { SimulatedPart simulatedPart = null; bool special = false; for (int j = 0; j < oParts[i].Modules.Count; j++) { ModuleParachute mp = oParts[i].Modules[j] as ModuleParachute; if (mp != null && v.mainBody.atmosphere) { special = true; simulatedPart = new SimulatedParachute(mp, simCurves, startTime, limitChutesStage); } } if (!special) { simulatedPart = new SimulatedPart(oParts[i], simCurves); } parts.Add(simulatedPart); totalMass += simulatedPart.totalMass; } }
public override void OnStart(StartState state) { base.OnStart(state); Debug.Log("ModuleParachutePlus.Start(): v01.10"); ParachuteModule = (ModuleParachute)GetModule("ModuleParachute"); if (null == ParachuteModule) { Debug.LogWarning("ModuleParachuteFix.Start(): Did not find Parachute Module."); return; } canopy = part.FindModelTransform(ParachuteModule.canopyName); SetupStockPlus(); GameEvents.onVesselWasModified.Add(CountSiblings); CountSiblings(vessel); }
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); } }
public override void OnLoad(ConfigNode node) { base.OnLoad(node); parachute = this.part.Modules.OfType <ModuleParachute>().Single(); }
public SimulatedParachute(ModuleParachute p) { this.p = p; state = p.deploymentState; }
public override void OnAwake() { base.OnAwake(); if (part && part.Modules != null) // thanks, FlowerChild! { is_engine = (part.Modules.Contains("ModuleEngines") || part.Modules.Contains("ModuleEnginesFX")); is_eva = part.Modules.Contains("KerbalEVA"); if (part.Modules.Contains("ModuleParachute")) parachute = (ModuleParachute)part.Modules["ModuleParachute"]; if (part.Modules.Contains("RealChuteModule")) { realChute = part.Modules["RealChuteModule"]; rCType = realChute.GetType(); } } }
public void OnDestroy() { this.parachute = null; this.EVARepairEvent = null; }
public void Update() { Vessel vessel = FlightGlobals.ActiveVessel; // easier to use vessel // safety check if (vessel == null || !HighLogic.LoadedSceneIsFlight) { return; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // atmospheric shake // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // up the shake based on atmopshereic density and surface speed float spdDensity = (float)(vessel.atmDensity) * (float)FlightGlobals.ship_srfSpeed; // limit here, mainly for space planes spdDensity = Mathf.Clamp(spdDensity, 0, maxSpdDensityEarly); // exagerate shake if semideployed, dampen if deployed foreach (Part part in vessel.Parts) { foreach (PartModule module in part.Modules) { if (module.moduleName.Contains("ModuleParachute")) { ModuleParachute p = module as ModuleParachute; if (p.deploymentState == ModuleParachute.deploymentStates.SEMIDEPLOYED && !vessel.LandedOrSplashed) { spdDensity *= 1.25f; } if (p.deploymentState == ModuleParachute.deploymentStates.DEPLOYED && !vessel.LandedOrSplashed) { spdDensity *= 0.75f; } } // RealChute Support, reworked to be compatible with RealChute v1.2 if (module.moduleName.Contains("RealChuteModule")) { PartModule p = part.Modules["RealChuteModule"]; Type pType = p.GetType(); object parachutes = pType.GetField("parachutes").GetValue(p); foreach (object parachute in (parachutes as IEnumerable)) { Type cType = parachute.GetType(); if (cType.GetField("depState").GetValue(parachute) == "PREDEPLOYED") { spdDensity *= 1.25f; } if ((cType.GetField("depState").GetValue(parachute) == "DEPLOYED") || (cType.GetField("depState").GetValue(parachute) == "LOWDEPLOYED")) { spdDensity *= 0.75f; } } } } } // lifted from DRE (thanks r4m0n), gets the mach / reentry fx if (afx == null) { GameObject fx = GameObject.Find("FXLogic"); if (fx != null) { afx = fx.GetComponent <AerodynamicsFX>(); } } // sirhaxington special: use weird values I found to determine if mach or reentry, there has to be a better way... if ((afx != null) && (afx.FxScalar > 0.01)) { // hack, whatever the .b color value is, always is this for re-entry, .11 something if (afx.fxLight.color.b < 0.12f) { burnDownTime = atmoBurnDownTimes[0]; } // hack, whatever the .b color value is, always is this for mach fx, .21 something if (afx.fxLight.color.b > 0.20f) { // since we * 10, only do this if it's going to increase... if (afx.FxScalar > 0.1) { spdDensity *= (afx.FxScalar * 10); } } } // ease back into normal atmophere from re-entry if (burnDownTime > 0) { spdDensity *= (afx.FxScalar * burnDownTime * 1000); burnDownTime -= Time.deltaTime; } // dont go too crazy... spdDensity = Mathf.Clamp(spdDensity, 0, maxSpdDensity); if (!vessel.isEVA) { shakeAmt = ReturnLargerAmt((UnityEngine.Random.insideUnitSphere * spdDensity) / 500000, shakeAmt); shakeRot = ReturnLargerRot(Quaternion.Euler(0, 0, (UnityEngine.Random.Range(-0.1f, 0.1f) * spdDensity) / 5000), shakeRot); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // parachute open shake // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int chuteCheck = 0; // re-do this every frame, check against previous frame to see if chute opened // a chute has popped... // Note: Don't need to do this with realChutes as they tend to open slow anyway foreach (Part part in vessel.parts) { foreach (PartModule module in part.Modules) { if (module.moduleName.Contains("ModuleParachute")) { ModuleParachute p = module as ModuleParachute; if (p.deploymentState != ModuleParachute.deploymentStates.DEPLOYED) { chuteCheck++; } } } } // check against previous frames' chutes, then prep shake event if (chuteCheck < totalUndeployedChutes) { doParaFull = true; paraShakeTime = paraShakeTimes[0]; } // set this at end of check for next frame totalUndeployedChutes = chuteCheck; // do the parachute pop shake if (paraShakeTime > 0 && doParaFull) { shakeAmt = ReturnLargerAmt(UnityEngine.Random.insideUnitSphere / 500, shakeAmt); shakeRot = ReturnLargerRot(Quaternion.Euler(0, 0, UnityEngine.Random.Range(-0.5f, 0.5f)), shakeRot); paraShakeTime -= Time.deltaTime; } else if (paraShakeTime <= 0) { doParaFull = false; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // decoupler shakes // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // total is grabbed from event handler if (ejectionForceTotal > 0) { // playing around with set shake timers, not sure if I like this way but it works for now if (ejectionForceTotal <= 15) { decoupleShakeTime = decoupleShakeTimes[0]; } else if (ejectionForceTotal <= 250) { decoupleShakeTime = decoupleShakeTimes[1]; } else if (ejectionForceTotal <= 500) { decoupleShakeTime = decoupleShakeTimes[2]; } else if (ejectionForceTotal <= 1000) { decoupleShakeTime = decoupleShakeTimes[3]; } else { decoupleShakeTime = decoupleShakeTimes[4]; } decoupleShakeForce = ejectionForceTotal; doDecoupleShake = true; ejectionForceTotal = 0; } // do the decoupler shake if (decoupleShakeTime > 0 && doDecoupleShake) { shakeAmt = ReturnLargerAmt(UnityEngine.Random.insideUnitSphere * decoupleShakeForce / 500000, shakeAmt); shakeRot = ReturnLargerRot(Quaternion.Euler(0, 0, UnityEngine.Random.Range(-0.5f, 0.5f)), shakeRot); decoupleShakeTime -= Time.deltaTime; } else if (decoupleShakeTime <= 0) { doDecoupleShake = false; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // docking shakes // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // do the dock shake...we set the time from the handler, no need for other checks if (dockShakeTime > 0) { shakeAmt = ReturnLargerAmt(UnityEngine.Random.insideUnitSphere / 1000, shakeAmt); shakeRot = ReturnLargerRot(Quaternion.Euler(0, 0, UnityEngine.Random.Range(-0.07f, 0.07f)), shakeRot); dockShakeTime -= Time.deltaTime; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // launch clamp shakes // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int clampCheck = 0; // a clamp has detached... foreach (Part part in vessel.parts) { foreach (PartModule module in part.Modules) { if (module.moduleName.Contains("LaunchClamp")) { LaunchClamp lc = module as LaunchClamp; if (lc.enabled) { clampCheck++; } } } } // check against previous frames' chutes, then prep shake event if (clampCheck < totalClampedClamps) { doClamp = true; clampShakeTime = clampShakeTimes[0]; } // set this at end of check for next frame totalClampedClamps = clampCheck; // do the parachute pop shake if (clampShakeTime > 0 && doClamp) { shakeAmt = ReturnLargerAmt(UnityEngine.Random.insideUnitSphere / 500, shakeAmt); shakeRot = ReturnLargerRot(Quaternion.Euler(0, 0, UnityEngine.Random.Range(-0.7f, 0.7f)), shakeRot); clampShakeTime -= Time.deltaTime; } else if (clampShakeTime <= 0) { doClamp = false; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // engine shakes // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // check both engine types (rapier uses ModuleEnginesFX, most use ModuleEngines) then base shake on thrust amount foreach (Part part in vessel.Parts) { foreach (PartModule module in part.Modules) { if (module.moduleName.Contains("ModuleEnginesFX")) { ModuleEnginesFX e = module as ModuleEnginesFX; if (e.isOperational) { float solidScalar = 1.0f; // scale up SRBs if (e.propellants.Count > 0) { foreach (Propellant p in e.propellants) { if (p.name == "SolidFuel") { solidScalar = 2.5f; } } } engineThrustTotal += (e.finalThrust * solidScalar); } if (engineThrustTotal > 0) { doEngineShake = true; } } else if (module.moduleName.Contains("ModuleEngines")) { ModuleEngines e = module as ModuleEngines; if (e.isOperational) { float typeScalar = 1.0f; // scale up SRBs, down jets if (e.propellants.Count > 0) { foreach (Propellant p in e.propellants) { if (p.name == "SolidFuel") { typeScalar = 2.5f; } else if (p.name == "IntakeAir") { typeScalar = 0.01f; } } } engineThrustTotal += (e.finalThrust * typeScalar); } if (engineThrustTotal > 0) { doEngineShake = true; } } // don't go too crazy... engineThrustTotal = Mathf.Clamp(engineThrustTotal, 0, maxEngineForce); } } // do engine shake... if (engineThrustTotal > 0 && doEngineShake) { shakeAmt = ReturnLargerAmt((UnityEngine.Random.insideUnitSphere * (engineThrustTotal / 1000)) / 800, shakeAmt); shakeRot = ReturnLargerRot(Quaternion.Euler(0, 0, UnityEngine.Random.Range(-0.8f, 0.8f) * (engineThrustTotal / 1000)), shakeRot); } else if (engineThrustTotal <= 0) { doEngineShake = false; } // reset every frame engineThrustTotal = 0; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // nearby collision shakes // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // do the collision shake...we set the time from the handler, no need for other checks if (collisionShakeTime > 0) { shakeAmt = ReturnLargerAmt(UnityEngine.Random.insideUnitSphere / 50, shakeAmt); shakeRot = ReturnLargerRot(Quaternion.Euler(0, 0, UnityEngine.Random.Range(-1.5f, 1.5f)), shakeRot); collisionShakeTime -= Time.deltaTime; } // reset for next frame, use negative since we're looking for distance now collisionClosest = -1; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // rover ground shakes // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float spdRover = (float)FlightGlobals.ship_srfSpeed; doRover = false; float roverScalar = 1.0f; foreach (Part part in vessel.Parts) { foreach (PartModule module in part.Modules) { if (module.moduleName.Contains("ModuleWheel")) { if (part.GroundContact) { if (vessel.landedAt.Length == 0 || vessel.landedAt.ToString() == "KSC") { roverScalar = 2.0f; } // maybe later, do biome specific shakes //CBAttributeMap currentBiome = vessel.mainBody.BiomeMap; //print(currentBiome.GetAtt(vessel.latitude * Mathf.Deg2Rad, vessel.longitude * Mathf.Deg2Rad).name); //print(currentBiome.ToString()); doRover = true; } } if (module.moduleName.Contains("ModuleLandingGear")) { if (part.Landed) { if (vessel.landedAt.Length == 0 || vessel.landedAt.ToString() == "KSC") // basically, in and around KSC { roverScalar = 2.0f; } doRover = true; } } } } spdRover *= roverScalar; // dont go too crazy... spdRover = Mathf.Clamp(spdRover, 0, maxSpdRover); if (doRover && !vessel.isEVA) { shakeAmt = ReturnLargerAmt((UnityEngine.Random.insideUnitSphere * spdRover) / 50000, shakeAmt); shakeRot = ReturnLargerRot(Quaternion.Euler(0, 0, (UnityEngine.Random.Range(-0.1f, 0.1f) * spdRover) / 500), shakeRot); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // landing shakes // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // note, parts that break off may throw this off int landedCurParts = 0; foreach (Part part in vessel.Parts) { if (part.GroundContact || part.WaterContact) { landedCurParts++; } } // if more parts are touching the ground this frame... if (landedCurParts > landedPrevParts) { doLanded = true; // do I need horizontal surface speed as well? hmmm... landedShakeForce = landedPrevSrfSpd; if (landedShakeForce <= 0.5) { landedShakeTime = landedShakeTimes[0]; } else if (landedShakeForce <= 1.5) { landedShakeTime = landedShakeTimes[1]; } else if (landedShakeForce <= 3.0) { landedShakeTime = landedShakeTimes[2]; } else if (landedShakeForce <= 5.0) { landedShakeTime = landedShakeTimes[3]; } else { landedShakeTime = landedShakeTimes[4]; } if (doRover) { landedShakeForce /= 2; } landedShakeForce = Mathf.Clamp(landedShakeForce, 0, maxLandedForce); } // set the current parts for the next frame landedPrevParts = landedCurParts; // do the landing / touching ground / water shake if (doLanded && !vessel.isEVA) { if (landedShakeTime > 0) { shakeAmt = ReturnLargerAmt((UnityEngine.Random.insideUnitSphere * landedShakeForce) / 3600, shakeAmt); shakeRot = ReturnLargerRot(Quaternion.Euler(0, 0, UnityEngine.Random.Range(-0.1f, 0.1f) * landedShakeForce), shakeRot); landedShakeTime -= Time.deltaTime; } else { doLanded = false; } } // set the speed for the next frame landedPrevSrfSpd = (float)FlightGlobals.ActiveVessel.srfSpeed; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // EVA Shakes (under construction) // // to do: polish shakes (check on a few planets), rotation add back in // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// if (vessel.isEVA) { KerbalEVA eva = (KerbalEVA)vessel.rootPart.Modules["KerbalEVA"]; // if an anim has changed if (eva.fsm.currentStateName != evaAnimState) { //print(evaSrfSpedPrev); if (eva.fsm.currentStateName == "Landing") // standard landing from a jump / RCS { evaShakeTime = evaShakeTimes[2]; evaAnimShakeAmount = (int)(45000 / evaSrfSpedPrev); } else if (eva.fsm.currentStateName == "Ragdoll") // we landed too hard / jumped and landed at an odd angle { evaShakeTime = evaShakeTimes[5]; evaAnimShakeAmount = (int)(8000 / evaSrfSpedPrev); } else if (eva.fsm.currentStateName == "Low G Bound (Grounded - FPS)") // each step on a low g world should be felt { evaShakeTime = evaShakeTimes[2]; evaAnimShakeAmount = (int)(50000); } else if (eva.fsm.currentStateName == "Ladder (Acquire)") // feel the grab a bit more { evaShakeTime = evaShakeTimes[5]; evaAnimShakeAmount = (int)(1000000); } evaAnimState = eva.fsm.currentStateName; //print(evaAnimState); } else if (evaAnimState == "Ragdoll" && vessel.Landed && evaShakeTime <= 0) // when ragging and sliding along the surface, keep shaking { evaShakeTime = evaShakeTimes[5]; evaAnimShakeAmount = (int)(8000 / evaSrfSpedPrev); } else if (evaAnimState == "Ladder (Acquire)" && evaShakeTime >= 0) // when ragging and sliding along the surface or falling, update shaking { if (evaShakeTime < 0.3) { evaAnimShakeAmount = (int)(4000); } } // update shake based on timers if (evaShakeTime > 0) { shakeAmt = ReturnLargerAmt(UnityEngine.Random.insideUnitSphere / evaAnimShakeAmount, shakeAmt); evaShakeTime -= Time.deltaTime; } // RCS Cam Shake if (Math.Round(eva.Fuel, 3) != Math.Round(evaFuel, 3)) { evaFuel = eva.Fuel; shakeAmt = ReturnLargerAmt(UnityEngine.Random.insideUnitSphere / evaRCSShakeAmount, shakeAmt); Math.Round(eva.Fuel, 3); } // grab frame two behind to test against evaSrfSpedPrev = evaSrfSped; evaSrfSped = (float)vessel.srfSpeed; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // DO THE HARLEMSHAKE! o/\o // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Set isCrewed to true if not unmanned, used to remove shake in control room when using ProbeControlRoom mod bool isCrewed = false; foreach (Part part in vessel.Parts) { if (part.protoModuleCrew.Count >= 1) { isCrewed = true; } } // hopefully we've picked the largest values... also, don't shake while paused, looks dumb if (InternalCamera.Instance != null) { if (!gamePaused && InternalCamera.Instance.isActive && isCrewed) // isCrewed for shake only if not in control room { InternalCamera.Instance.camera.transform.localPosition = shakeAmt; InternalCamera.Instance.camera.transform.localRotation *= shakeRot; } } // for a different first person EVA mod... bool FPEVAMod = false; foreach (Part part in vessel.Parts) { foreach (PartModule module in part.Modules) { if (module.moduleName.Contains("EVACamera")) { FPEVAMod = true; } } } // rotation is wonky in EVA, skip if (vessel.isEVA && FlightCamera.fetch.minDistance == 0.01f && FlightCamera.fetch.maxDistance == 0.01f) { if (shakeAmt.x != 0 && shakeAmt.y != 0 && shakeAmt.z != 0) { FlightCamera.fetch.transform.localPosition += shakeAmt; } } else if (vessel.isEVA && FPEVAMod) { FlightCamera.fetch.transform.localPosition += (shakeAmt * 1000); } // reset the shake vals every frame and start over... shakeAmt = new Vector3(0.0f, 0.0f, 0.0f); shakeRot = new Quaternion(0.0f, 0.0f, 0.0f, 0.0f); }
private void HandleVessel(Vessel vessel) { if (vessel == null) { return; } Debug.Log("Strategia: VesselValueImprover.HandleVessel"); // Check for our trait bool needsIncrease = false; foreach (ProtoCrewMember pcm in VesselUtil.GetVesselCrew(vessel)) { if (pcm.experienceTrait.Config.Name == trait) { needsIncrease = true; break; } } // Find all relevant parts foreach (Part p in vessel.parts) { foreach (PartModule m in p.Modules) { switch (attribute) { case Attribute.ISP: ModuleEngines engine = m as ModuleEngines; if (engine != null) { FloatCurve curve = engine.atmosphereCurve; ConfigNode node = new ConfigNode(); curve.Save(node); // Find and adjust the vacuum ISP ConfigNode newNode = new ConfigNode(); foreach (ConfigNode.Value pair in node.values) { string[] values = pair.value.Split(new char[] { ' ' }); if (values[0] == "0") { float value = float.Parse(values[1]); float oldValue = value; SetValue(p.partInfo.name + "|" + engine.engineID, needsIncrease, ref value); values[1] = value.ToString("F1"); newNode.AddValue(pair.name, string.Join(" ", values)); Debug.Log("Setting ISP of " + p + " from " + oldValue + " to " + value); } else { newNode.AddValue(pair.name, pair.value); } } curve.Load(newNode); engine.realIsp = curve.Evaluate(0); } break; case Attribute.ParachuteDrag: ModuleParachute parachute = m as ModuleParachute; if (parachute != null) { SetValue(p.partName, needsIncrease, ref parachute.fullyDeployedDrag); } break; case Attribute.StrutStrength: CModuleStrut strut = m as CModuleStrut; if (strut != null) { SetValue(p.partName + "_linear", needsIncrease, ref strut.linearStrength); SetValue(p.partName + "_angular", needsIncrease, ref strut.angularStrength); } break; case Attribute.ReactionWheelTorque: ModuleReactionWheel reactionWheel = m as ModuleReactionWheel; if (reactionWheel != null) { SetValue(p.partName + "_pitch", needsIncrease, ref reactionWheel.PitchTorque); SetValue(p.partName + "_yaw", needsIncrease, ref reactionWheel.YawTorque); SetValue(p.partName + "_roll", needsIncrease, ref reactionWheel.RollTorque); } break; } } } }
private void SetParachuteInfo() { moduleParachute = selectedPart.GetModule<ModuleParachute>(); if (moduleParachute != null) { infoItems.Add(PartInfoItem.Create("Deployed Drag", Units.ConcatF(moduleParachute.semiDeployedDrag, moduleParachute.fullyDeployedDrag))); infoItems.Add(PartInfoItem.Create("Deployment Altitude", moduleParachute.deployAltitude.ToDistance())); infoItems.Add(PartInfoItem.Create("Deployment Pressure", moduleParachute.minAirPressureToOpen.ToString("F2"))); } }
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; } } }
// Returns the info-text of the given part with the given upgrades to be displayed in the GUI-comparison. private String getPartInfo(Part part, KRnDUpgrade upgradesToApply = null) { String info = ""; KRnDUpgrade originalUpgrades = null; try { KRnDModule rndModule = KRnD.getKRnDModule(part); if (rndModule == null || (originalUpgrades = rndModule.getCurrentUpgrades()) == null) { return(info); } // Upgrade the part to get the correct info, we revert it back to its previous values in the finally block below: KRnD.updatePart(part, upgradesToApply); List <ModuleEngines> engineModules = KRnD.getEngineModules(part); ModuleRCS rcsModule = KRnD.getRcsModule(part); ModuleReactionWheel reactionWheelModule = KRnD.getReactionWheelModule(part); ModuleDeployableSolarPanel solarPanelModule = KRnD.getSolarPanelModule(part); ModuleWheelBase landingLegModule = KRnD.getLandingLegModule(part); PartResource electricChargeResource = KRnD.getChargeResource(part); ModuleGenerator generatorModule = KRnD.getGeneratorModule(part); PartModule fissionGenerator = KRnD.getFissionGeneratorModule(part); List <ModuleResourceConverter> converterModules = KRnD.getConverterModules(part); ModuleParachute parachuteModule = KRnD.getParachuteModule(part); ModuleProceduralFairing fairingModule = KRnD.getFairingModule(part); List <PartResource> fuelResources = KRnD.getFuelResources(part); // Basic stats: info = "<color=#FFFFFF><b>Dry Mass:</b> " + part.mass.ToString("0.#### t") + "\n"; info += "<b>Max Temp.:</b> " + part.maxTemp.ToString("0.#") + "/" + part.skinMaxTemp.ToString("0.#") + " °K\n"; if (landingLegModule != null) { info += "<b>Crash Tolerance:</b> " + part.crashTolerance.ToString("0.#### m/s") + "\n"; } if (electricChargeResource != null) { info += "<b>Electric Charge:</b> " + electricChargeResource.maxAmount.ToString() + "\n"; } // Fuels: if (fuelResources != null) { foreach (PartResource fuelResource in fuelResources) { // Reformat resource-names like "ElectricCharge" to "Electric Charge": String fuelName = fuelResource.resourceName.ToString(); fuelName = Regex.Replace(fuelName, @"([a-z])([A-Z])", "$1 $2"); info += "<b>" + fuelName + ":</b> " + fuelResource.maxAmount.ToString() + "\n"; } } // Module stats: info += "\n"; if (engineModules != null) { foreach (ModuleEngines engineModule in engineModules) { info += "<color=#99FF00><b>Engine"; if (engineModules.Count > 1) { info += " (" + engineModule.engineID.ToString() + ")"; } info += ":</b></color>\n" + engineModule.GetInfo(); if (engineModules.Count > 1) { info += "\n"; } } } if (rcsModule) { info += "<color=#99FF00><b>RCS:</b></color>\n" + rcsModule.GetInfo(); } if (reactionWheelModule) { info += "<color=#99FF00><b>Reaction Wheel:</b></color>\n" + reactionWheelModule.GetInfo(); } if (solarPanelModule) { info += "<color=#99FF00><b>Solar Panel:</b></color>\n" + KRnD.getSolarPanelInfo(solarPanelModule); } if (generatorModule) { info += "<color=#99FF00><b>Generator:</b></color>\n" + generatorModule.GetInfo(); } if (fissionGenerator) { info += "<color=#99FF00><b>Fission-Generator:</b></color>\n" + fissionGenerator.GetInfo(); } if (converterModules != null) { foreach (ModuleResourceConverter converterModule in converterModules) { info += "<color=#99FF00><b>Converter " + converterModule.ConverterName + ":</b></color>\n" + converterModule.GetInfo() + "\n"; } } if (parachuteModule) { info += "<color=#99FF00><b>Parachute:</b></color>\n" + parachuteModule.GetInfo(); } if (fairingModule) { info += "<color=#99FF00><b>Fairing:</b></color>\n" + fairingModule.GetInfo(); } info += "</color>"; } catch (Exception e) { Debug.LogError("[KRnDGUI] getPartInfo(): " + e.ToString()); } finally { try { if (originalUpgrades != null) { KRnD.updatePart(part, originalUpgrades); } } catch (Exception e) { Debug.LogError("[KRnDGUI] getPartInfo() restore of part failed: " + e.ToString()); } } return(info); }
protected void StartSimulation(bool addParachuteError) { double altitudeOfPreviousPrediction = 0; double parachuteMultiplierForThisSimulation = this.parachuteSemiDeployMultiplier; if (addParachuteError) { errorSimulationRunning = true; errorStopwatch.Start(); //starts a timer that times how long the simulation takes } else { simulationRunning = true; stopwatch.Start(); //starts a timer that times how long the simulation takes } Orbit patch = GetReenteringPatch() ?? orbit; // Work out a mass for the total ship, a DragMass for everything except the parachutes that will be used (including the stowed parachutes that will not be used) and list of parchutes that will be used. double totalMass = 0; double dragMassExcludingUsedParachutes = 0; List <SimulatedParachute> usableChutes = new List <SimulatedParachute>(); foreach (Part p in vessel.parts) { if (p.IsPhysicallySignificant()) { bool partIsParachute = false; double partDrag = 0; double partMass = p.TotalMass(); totalMass += partMass; // Is this part a parachute? foreach (PartModule pm in p.Modules) { if (!pm.isEnabled) { continue; } if (pm is ModuleParachute) { ModuleParachute chute = (ModuleParachute)pm; partIsParachute = true; // This is a parachute, but is it one that will be used in the landing / rentry simulation? if (deployChutes && p.inverseStage >= limitChutesStage) { // This chute will be used in the simualtion. Add it to the list of useage parachutes. usableChutes.Add(new SimulatedParachute(chute, patch.StartUT)); } else { partDrag = p.maximum_drag; } } } if (false == partIsParachute) { // Part is not a parachute. Just use its drag value. partDrag = p.maximum_drag; } dragMassExcludingUsedParachutes += partDrag * partMass; } } // Work out what the landing altitude was of the last prediction, and use that to pass into the next simulation if (null != this.result) { if (result.outcome == ReentrySimulation.Outcome.LANDED && null != result.body) { altitudeOfPreviousPrediction = this.GetResult().endASL; // Note that we are caling GetResult here to force the it to calculate the endASL, if it has not already done this. It is not allowed to do this previously as we are only allowed to do it from this thread, not the reentry simulation thread. } } // Is this a simulation run with errors added? If so then add some error to the parachute multiple if (addParachuteError) { System.Random random = new System.Random(); parachuteMultiplierForThisSimulation *= ((double)1 + ((double)(random.Next(1000000) - 500000) / (double)10000000)); } ReentrySimulation sim = new ReentrySimulation(patch, patch.StartUT, dragMassExcludingUsedParachutes, usableChutes, totalMass, descentSpeedPolicy, decelEndAltitudeASL, vesselState.limitedMaxThrustAccel, parachuteMultiplierForThisSimulation, altitudeOfPreviousPrediction, addParachuteError, dt); //Run the simulation in a separate thread ThreadPool.QueueUserWorkItem(RunSimulation, sim); }
private void OnWindow(int windowId) { try { GUILayout.BeginVertical(); // Get all modules of the selected part: String partTitle = ""; Part part = null; KRnDModule rndModule = null; List <ModuleEngines> engineModules = null; ModuleRCS rcsModule = null; ModuleReactionWheel reactionWheelModule = null; ModuleDeployableSolarPanel solarPanelModule = null; ModuleWheelBase landingLegModule = null; PartResource electricChargeResource = null; ModuleGenerator generatorModule = null; PartModule fissionGenerator = null; List <ModuleResourceConverter> converterModules = null; ModuleParachute parachuteModule = null; List <PartResource> fuelResources = null; if (selectedPart != null) { foreach (AvailablePart aPart in PartLoader.LoadedPartsList) { if (aPart.partPrefab.name == selectedPart.name) { part = aPart.partPrefab; partTitle = aPart.title; break; } } if (part) { rndModule = KRnD.getKRnDModule(part); engineModules = KRnD.getEngineModules(part); rcsModule = KRnD.getRcsModule(part); reactionWheelModule = KRnD.getReactionWheelModule(part); solarPanelModule = KRnD.getSolarPanelModule(part); landingLegModule = KRnD.getLandingLegModule(part); electricChargeResource = KRnD.getChargeResource(part); generatorModule = KRnD.getGeneratorModule(part); fissionGenerator = KRnD.getFissionGeneratorModule(part); converterModules = KRnD.getConverterModules(part); parachuteModule = KRnD.getParachuteModule(part); fuelResources = KRnD.getFuelResources(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; } else if (!rndModule) { // 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: KRnDUpgrade currentUpgrade; if (!KRnD.upgrades.TryGetValue(part.name, out currentUpgrade)) { currentUpgrade = new KRnDUpgrade(); } String currentInfo = getPartInfo(part, currentUpgrade); // Create a copy of the part-stats which we can use to mock an upgrade further below: KRnDUpgrade nextUpgrade = currentUpgrade.clone(); // Title: GUILayout.BeginArea(new Rect(10, 5, windowStyle.fixedWidth, 20)); String version = rndModule.getVersion(); if (version != "") { version = " - " + version; } GUILayout.Label("<b>" + partTitle + version + "</b>", labelStyle); GUILayout.EndArea(); // List with upgrade-options: float optionsWidth = 100; float optionsHeight = windowStyle.fixedHeight - 30 - 30 - 20; GUILayout.BeginArea(new Rect(10, 30 + 20, optionsWidth, optionsHeight)); List <String> options = new List <String>(); options.Add("Dry Mass"); options.Add("Max Temp"); if (engineModules != null || rcsModule) { options.Add("ISP Vac"); options.Add("ISP Atm"); options.Add("Fuel Flow"); } if (reactionWheelModule != null) { options.Add("Torque"); } if (solarPanelModule != null) { options.Add("Charge Rate"); } if (landingLegModule != null) { options.Add("Crash Tolerance"); } if (electricChargeResource != null) { options.Add("Battery"); } if (fuelResources != null) { options.Add("Fuel Pressure"); } if (generatorModule || fissionGenerator) { options.Add("Generator"); } if (converterModules != null) { options.Add("Converter"); } if (parachuteModule) { options.Add("Parachute"); } if (this.selectedUpgradeOption >= options.Count) { this.selectedUpgradeOption = 0; } this.selectedUpgradeOption = GUILayout.SelectionGrid(this.selectedUpgradeOption, options.ToArray(), 1, buttonStyle); GUILayout.EndArea(); String selectedUpgradeOption = options.ToArray()[this.selectedUpgradeOption]; int currentUpgradeCount = 0; int nextUpgradeCount = 0; int scienceCost = 0; float currentImprovement = 0; float nextImprovement = 0; Func <Part, int> upgradeFunction = null; if (selectedUpgradeOption == "ISP Vac") { upgradeFunction = KRnDGUI.UpgradeIspVac; currentUpgradeCount = currentUpgrade.ispVac; nextUpgradeCount = ++nextUpgrade.ispVac; currentImprovement = KRnD.calculateImprovementFactor(rndModule.ispVac_improvement, rndModule.ispVac_improvementScale, currentUpgrade.ispVac); nextImprovement = KRnD.calculateImprovementFactor(rndModule.ispVac_improvement, rndModule.ispVac_improvementScale, nextUpgrade.ispVac); scienceCost = KRnD.calculateScienceCost(rndModule.ispVac_scienceCost, rndModule.ispVac_costScale, nextUpgrade.ispVac); } else if (selectedUpgradeOption == "ISP Atm") { upgradeFunction = KRnDGUI.UpgradeIspAtm; currentUpgradeCount = currentUpgrade.ispAtm; nextUpgradeCount = ++nextUpgrade.ispAtm; currentImprovement = KRnD.calculateImprovementFactor(rndModule.ispAtm_improvement, rndModule.ispAtm_improvementScale, currentUpgrade.ispAtm); nextImprovement = KRnD.calculateImprovementFactor(rndModule.ispAtm_improvement, rndModule.ispAtm_improvementScale, nextUpgrade.ispAtm); scienceCost = KRnD.calculateScienceCost(rndModule.ispAtm_scienceCost, rndModule.ispAtm_costScale, nextUpgrade.ispAtm); } else if (selectedUpgradeOption == "Fuel Flow") { upgradeFunction = KRnDGUI.UpgradeFuelFlow; currentUpgradeCount = currentUpgrade.fuelFlow; nextUpgradeCount = ++nextUpgrade.fuelFlow; currentImprovement = KRnD.calculateImprovementFactor(rndModule.fuelFlow_improvement, rndModule.fuelFlow_improvementScale, currentUpgrade.fuelFlow); nextImprovement = KRnD.calculateImprovementFactor(rndModule.fuelFlow_improvement, rndModule.fuelFlow_improvementScale, nextUpgrade.fuelFlow); scienceCost = KRnD.calculateScienceCost(rndModule.fuelFlow_scienceCost, rndModule.fuelFlow_costScale, nextUpgrade.fuelFlow); } else if (selectedUpgradeOption == "Dry Mass") { upgradeFunction = KRnDGUI.UpgradeDryMass; currentUpgradeCount = currentUpgrade.dryMass; nextUpgradeCount = ++nextUpgrade.dryMass; currentImprovement = KRnD.calculateImprovementFactor(rndModule.dryMass_improvement, rndModule.dryMass_improvementScale, currentUpgrade.dryMass); nextImprovement = KRnD.calculateImprovementFactor(rndModule.dryMass_improvement, rndModule.dryMass_improvementScale, nextUpgrade.dryMass); // Scale science cost with original mass: PartStats originalStats; if (!KRnD.originalStats.TryGetValue(part.name, out originalStats)) { throw new Exception("no original-stats for part '" + part.name + "'"); } float scaleReferenceFactor = 1; if (rndModule.dryMass_costScaleReference > 0) { scaleReferenceFactor = originalStats.mass / rndModule.dryMass_costScaleReference; } int scaledCost = (int)Math.Round(rndModule.dryMass_scienceCost * scaleReferenceFactor); if (scaledCost < 1) { scaledCost = 1; } scienceCost = KRnD.calculateScienceCost(scaledCost, rndModule.dryMass_costScale, nextUpgrade.dryMass); } else if (selectedUpgradeOption == "Torque") { upgradeFunction = KRnDGUI.UpgradeTorque; currentUpgradeCount = currentUpgrade.torque; nextUpgradeCount = ++nextUpgrade.torque; currentImprovement = KRnD.calculateImprovementFactor(rndModule.torque_improvement, rndModule.torque_improvementScale, currentUpgrade.torque); nextImprovement = KRnD.calculateImprovementFactor(rndModule.torque_improvement, rndModule.torque_improvementScale, nextUpgrade.torque); scienceCost = KRnD.calculateScienceCost(rndModule.torque_scienceCost, rndModule.torque_costScale, nextUpgrade.torque); } else if (selectedUpgradeOption == "Charge Rate") { upgradeFunction = KRnDGUI.UpgradeChargeRate; currentUpgradeCount = currentUpgrade.chargeRate; nextUpgradeCount = ++nextUpgrade.chargeRate; currentImprovement = KRnD.calculateImprovementFactor(rndModule.chargeRate_improvement, rndModule.chargeRate_improvementScale, currentUpgrade.chargeRate); nextImprovement = KRnD.calculateImprovementFactor(rndModule.chargeRate_improvement, rndModule.chargeRate_improvementScale, nextUpgrade.chargeRate); scienceCost = KRnD.calculateScienceCost(rndModule.chargeRate_scienceCost, rndModule.chargeRate_costScale, nextUpgrade.chargeRate); } else if (selectedUpgradeOption == "Crash Tolerance") { upgradeFunction = KRnDGUI.UpgradeCrashTolerance; currentUpgradeCount = currentUpgrade.crashTolerance; nextUpgradeCount = ++nextUpgrade.crashTolerance; currentImprovement = KRnD.calculateImprovementFactor(rndModule.crashTolerance_improvement, rndModule.crashTolerance_improvementScale, currentUpgrade.crashTolerance); nextImprovement = KRnD.calculateImprovementFactor(rndModule.crashTolerance_improvement, rndModule.crashTolerance_improvementScale, nextUpgrade.crashTolerance); scienceCost = KRnD.calculateScienceCost(rndModule.crashTolerance_scienceCost, rndModule.crashTolerance_costScale, nextUpgrade.crashTolerance); } else if (selectedUpgradeOption == "Battery") { upgradeFunction = KRnDGUI.UpgradeBatteryCharge; currentUpgradeCount = currentUpgrade.batteryCharge; nextUpgradeCount = ++nextUpgrade.batteryCharge; currentImprovement = KRnD.calculateImprovementFactor(rndModule.batteryCharge_improvement, rndModule.batteryCharge_improvementScale, currentUpgrade.batteryCharge); nextImprovement = KRnD.calculateImprovementFactor(rndModule.batteryCharge_improvement, rndModule.batteryCharge_improvementScale, nextUpgrade.batteryCharge); // Scale science cost with original battery charge: PartStats originalStats; if (!KRnD.originalStats.TryGetValue(part.name, out originalStats)) { throw new Exception("no origional-stats for part '" + part.name + "'"); } double scaleReferenceFactor = 1; if (rndModule.batteryCharge_costScaleReference > 0) { scaleReferenceFactor = originalStats.batteryCharge / rndModule.batteryCharge_costScaleReference; } int scaledCost = (int)Math.Round(rndModule.batteryCharge_scienceCost * scaleReferenceFactor); if (scaledCost < 1) { scaledCost = 1; } scienceCost = KRnD.calculateScienceCost(scaledCost, rndModule.batteryCharge_costScale, nextUpgrade.batteryCharge); } else if (selectedUpgradeOption == "Fuel Pressure") { upgradeFunction = KRnDGUI.UpgradeFuelCapacity; currentUpgradeCount = currentUpgrade.fuelCapacity; nextUpgradeCount = ++nextUpgrade.fuelCapacity; currentImprovement = KRnD.calculateImprovementFactor(rndModule.fuelCapacity_improvement, rndModule.fuelCapacity_improvementScale, currentUpgrade.fuelCapacity); nextImprovement = KRnD.calculateImprovementFactor(rndModule.fuelCapacity_improvement, rndModule.fuelCapacity_improvementScale, nextUpgrade.fuelCapacity); // Scale science cost with original fuel capacity: PartStats originalStats; if (!KRnD.originalStats.TryGetValue(part.name, out originalStats)) { throw new Exception("no origional-stats for part '" + part.name + "'"); } double scaleReferenceFactor = 1; if (rndModule.fuelCapacity_costScaleReference > 0) { scaleReferenceFactor = originalStats.fuelCapacitiesSum / rndModule.fuelCapacity_costScaleReference; } int scaledCost = (int)Math.Round(rndModule.fuelCapacity_scienceCost * scaleReferenceFactor); if (scaledCost < 1) { scaledCost = 1; } scienceCost = KRnD.calculateScienceCost(scaledCost, rndModule.fuelCapacity_costScale, nextUpgrade.fuelCapacity); } else if (selectedUpgradeOption == "Generator") { upgradeFunction = KRnDGUI.UpgradeGeneratorEfficiency; currentUpgradeCount = currentUpgrade.generatorEfficiency; nextUpgradeCount = ++nextUpgrade.generatorEfficiency; currentImprovement = KRnD.calculateImprovementFactor(rndModule.generatorEfficiency_improvement, rndModule.generatorEfficiency_improvementScale, currentUpgrade.generatorEfficiency); nextImprovement = KRnD.calculateImprovementFactor(rndModule.generatorEfficiency_improvement, rndModule.generatorEfficiency_improvementScale, nextUpgrade.generatorEfficiency); scienceCost = KRnD.calculateScienceCost(rndModule.generatorEfficiency_scienceCost, rndModule.generatorEfficiency_costScale, nextUpgrade.generatorEfficiency); } else if (selectedUpgradeOption == "Converter") { upgradeFunction = KRnDGUI.UpgradeConverterEfficiency; currentUpgradeCount = currentUpgrade.converterEfficiency; nextUpgradeCount = ++nextUpgrade.converterEfficiency; currentImprovement = KRnD.calculateImprovementFactor(rndModule.converterEfficiency_improvement, rndModule.converterEfficiency_improvementScale, currentUpgrade.converterEfficiency); nextImprovement = KRnD.calculateImprovementFactor(rndModule.converterEfficiency_improvement, rndModule.converterEfficiency_improvementScale, nextUpgrade.converterEfficiency); scienceCost = KRnD.calculateScienceCost(rndModule.converterEfficiency_scienceCost, rndModule.converterEfficiency_costScale, nextUpgrade.converterEfficiency); } else if (selectedUpgradeOption == "Parachute") { upgradeFunction = KRnDGUI.UpgradeParachuteStrength; currentUpgradeCount = currentUpgrade.parachuteStrength; nextUpgradeCount = ++nextUpgrade.parachuteStrength; currentImprovement = KRnD.calculateImprovementFactor(rndModule.parachuteStrength_improvement, rndModule.parachuteStrength_improvementScale, currentUpgrade.parachuteStrength); nextImprovement = KRnD.calculateImprovementFactor(rndModule.parachuteStrength_improvement, rndModule.parachuteStrength_improvementScale, nextUpgrade.parachuteStrength); scienceCost = KRnD.calculateScienceCost(rndModule.parachuteStrength_scienceCost, rndModule.parachuteStrength_costScale, nextUpgrade.parachuteStrength); } else if (selectedUpgradeOption == "Max Temp") { upgradeFunction = KRnDGUI.UpgradeMaxTemperature; currentUpgradeCount = currentUpgrade.maxTemperature; nextUpgradeCount = ++nextUpgrade.maxTemperature; currentImprovement = KRnD.calculateImprovementFactor(rndModule.maxTemperature_improvement, rndModule.maxTemperature_improvementScale, currentUpgrade.maxTemperature); nextImprovement = KRnD.calculateImprovementFactor(rndModule.maxTemperature_improvement, rndModule.maxTemperature_improvementScale, nextUpgrade.maxTemperature); scienceCost = KRnD.calculateScienceCost(rndModule.maxTemperature_scienceCost, rndModule.maxTemperature_costScale, nextUpgrade.maxTemperature); } else { throw new Exception("unexpected option '" + selectedUpgradeOption + "'"); } String newInfo = getPartInfo(part, nextUpgrade); // Calculate part-info if the selected stat was upgraded. newInfo = highlightChanges(currentInfo, newInfo); // Current stats: GUILayout.BeginArea(new Rect(10 + optionsWidth + 10, 30, windowStyle.fixedWidth, 20)); GUILayout.Label("<color=#FFFFFF><b>Current:</b> " + currentUpgradeCount.ToString() + " (" + currentImprovement.ToString("+0.##%;-0.##%;-") + ")</color>", labelStyle); GUILayout.EndArea(); float areaWidth = (windowStyle.fixedWidth - 20 - optionsWidth) / 2; float areaHeight = optionsHeight; GUILayout.BeginArea(new Rect(10 + optionsWidth, 30 + 20, areaWidth, areaHeight)); scrollPos = GUILayout.BeginScrollView(scrollPos, scrollStyle, GUILayout.Width(areaWidth), GUILayout.Height(areaHeight)); GUILayout.Label(currentInfo, labelStyleSmall); GUILayout.EndScrollView(); GUILayout.EndArea(); // Next stats: GUILayout.BeginArea(new Rect(10 + optionsWidth + areaWidth + 10, 30, windowStyle.fixedWidth, 20)); GUILayout.Label("<color=#FFFFFF><b>Next upgrade:</b> " + nextUpgradeCount.ToString() + " (" + nextImprovement.ToString("+0.##%;-0.##%;-") + ")</color>", labelStyle); GUILayout.EndArea(); GUILayout.BeginArea(new Rect(10 + optionsWidth + areaWidth, 30 + 20, areaWidth, areaHeight)); scrollPos = GUILayout.BeginScrollView(scrollPos, scrollStyle, GUILayout.Width(areaWidth), GUILayout.Height(areaHeight)); GUILayout.Label(newInfo, labelStyleSmall); GUILayout.EndScrollView(); GUILayout.EndArea(); // Bottom-line (display only if the upgrade would have an effect): if (currentImprovement != nextImprovement) { GUILayout.BeginArea(new Rect(10, windowStyle.fixedHeight - 25, windowStyle.fixedWidth, 30)); float currentScience = 0; if (ResearchAndDevelopment.Instance != null) { currentScience = ResearchAndDevelopment.Instance.Science; } String color = "FF0000"; if (currentScience >= scienceCost) { color = "00FF00"; } GUILayout.Label("<b>Science: <color=#" + color + ">" + scienceCost.ToString() + " / " + Math.Floor(currentScience).ToString() + "</color></b>", labelStyle); GUILayout.EndArea(); if (currentScience >= scienceCost && ResearchAndDevelopment.Instance != null && upgradeFunction != null) { GUILayout.BeginArea(new Rect(windowStyle.fixedWidth - 110, windowStyle.fixedHeight - 30, 100, 30)); if (GUILayout.Button("Research", buttonStyle)) { upgradeFunction(part); ResearchAndDevelopment.Instance.AddScience(-scienceCost, TransactionReasons.RnDTechResearch); } GUILayout.EndArea(); } } GUILayout.EndVertical(); GUI.DragWindow(); } catch (Exception e) { Debug.LogError("[KRnD] GenerateWindow(): " + e.ToString()); } }
//============================================================================================================================================ public void EngageChute() { //FAR Compatibility =) if (assemblyFARUsed == true) { foreach (Part EnabledPart in EnabledPartList) { if (EnabledPart.Modules.Contains ("RealChuteFAR")) { //FerramAerospaceResearch.RealChuteLite.RealChuteFAR RCF = new FerramAerospaceResearch.RealChuteLite.RealChuteFAR (); //RCF = EnabledPart.FindModuleImplementing<FerramAerospaceResearch.RealChuteLite.RealChuteFAR> (); ChuteFARModuleReference = EnabledPart.Modules ["RealChuteFAR"]; PropertyInfo ChuteFARModuleDeploymentState = ChuteFARModuleReference.GetType().GetProperty("deploymentState"); RoboBrakes_ParaEnabledCount++; ChuteFARDeploymentString = ChuteFARModuleReference.Fields.GetValue ("depState").ToString (); //Repack if Chute was already Cut if ((ChuteFARDeploymentString == "CUT") && (IsLanded == false) && (RoboBrakes_CHUTEAUTO == true)) { //Bypassing RealChutes Repacking Method so we don't have to EVA - Also we can't set 'canRepack' bool as it is read only :-/ ChuteFARModuleDeploymentState.SetValue(ChuteFARModuleReference, 1, null); ChuteFARModuleReference.part.Effect ("rcrepack"); ChuteFARModuleReference.part.stackIcon.SetIconColor (XKCDColors.White); ChuteFARModuleReference.part.DragCubes.SetCubeWeight ("PACKED", 1); ChuteFARModuleReference.part.DragCubes.SetCubeWeight ("RCDEPLOYED", 0); print ("ROBOBRAKES - RealChute " + EnabledPart.name + " was already Cut! Repacked Automatically!"); } //Deploy Chute if ((RoboBrakes_CHUTEREADY == true && RoboBrakes_CHUTEAUTO == true)) { RoboBrakes_CHUTEREADY = false; //Deploy Real Chute ChuteFARModuleReference.SendMessage("ActivateRC"); } //Repack Chute Automatically if (ChuteFARDeploymentString == "DEPLOYED" | ChuteFARDeploymentString == "PREDEPLOYED") { if (RoboBrakes_CUTCHUTE == true) { RoboBrakes_CUTCHUTE = false; //Cut Real Chute ChuteFARModuleReference.SendMessage("Cut"); //Bypassing RealChutes Repacking Method so we don't have to EVA - Also we can't set 'canRepack' bool as it is read only :-/ ChuteFARModuleDeploymentState.SetValue(ChuteFARModuleReference, 1, null); ChuteFARModuleReference.part.Effect ("rcrepack"); ChuteFARModuleReference.part.stackIcon.SetIconColor (XKCDColors.White); ChuteFARModuleReference.part.DragCubes.SetCubeWeight ("PACKED", 1); ChuteFARModuleReference.part.DragCubes.SetCubeWeight ("RCDEPLOYED", 0); print ("ROBOBRAKES - RealChute " + EnabledPart.name + " was Cut & Repacked Automatically!"); } } } } } foreach (Part EnabledPart in EnabledPartList) { //Module Parachutes //--------------------------------------------------------------------------------------------------------------------- if (EnabledPart.Modules.Contains ("ModuleParachute")) { ModuleParachute MPA = new ModuleParachute (); MPA = EnabledPart.FindModuleImplementing<ModuleParachute> (); RoboBrakes_ParaEnabledCount++; //Repack the Chute automatically if it has been manually cut if ((MPA.deploymentState.Equals (ModuleParachute.deploymentStates.CUT)) && (IsLanded == false) && (RoboBrakes_CHUTEAUTO == true)) { MPA.Repack (); print ("ROBOBRAKES - Chute " + EnabledPart.name + " was already Cut! Repacked Automatically!"); } //Deploy Chute if ((RoboBrakes_AUTOMATICBRAKE_ACTIVE == true && RoboBrakes_CHUTEAUTO == true)) { if (RoboBrakes_CHUTEREADY == true) { RoboBrakes_CHUTEREADY = false; MPA.Deploy (); } } //Repack Chute if (MPA.deploymentState.Equals (ModuleParachute.deploymentStates.DEPLOYED)) { if (RoboBrakes_CUTCHUTE == true) { RoboBrakes_CUTCHUTE = false; MPA.CutParachute (); MPA.Repack (); print ("ROBOBRAKES - Chute " + EnabledPart.name + " was Cut & Repacked Automatically!"); } } } } }
public Parachute(VesselWrapper VSL, ModuleParachute p) : base(VSL) { parachute = p; }
public void vesselDestroyEvent(Vessel v) { if (!KCT_GameStates.settings.enabledForSave) { return; } Dictionary <string, int> PartsRecovered = new Dictionary <string, int>(); float FundsRecovered = 0, KSCDistance = 0, RecoveryPercent = 0; StringBuilder Message = new StringBuilder(); if (FlightGlobals.fetch == null) { return; } if (v != null && !(HighLogic.LoadedSceneIsFlight && v.isActiveVessel) && v.mainBody.bodyName == "Kerbin" && (!v.loaded || v.packed) && v.altitude < 35000 && (v.situation == Vessel.Situations.FLYING || v.situation == Vessel.Situations.SUB_ORBITAL) && !v.isEVA) { double totalMass = 0; double dragCoeff = 0; bool realChuteInUse = false; float RCParameter = 0; if (!v.packed) //adopted from mission controller. { foreach (Part p in v.Parts) { p.Pack(); } } if (v.protoVessel == null) { return; } KCTDebug.Log("Attempting to recover vessel."); try { foreach (ProtoPartSnapshot p in v.protoVessel.protoPartSnapshots) { //KCTDebug.Log("Has part " + p.partName + ", mass " + p.mass); List <string> ModuleNames = new List <string>(); foreach (ProtoPartModuleSnapshot ppms in p.modules) { //Debug.Log(ppms.moduleName); ModuleNames.Add(ppms.moduleName); } totalMass += p.mass; totalMass += GetResourceMass(p.resources); bool isParachute = false; if (ModuleNames.Contains("ModuleParachute")) { KCTDebug.Log("Found parachute module on " + p.partInfo.name); //Find the ModuleParachute (find it in the module list by checking for a module with the name ModuleParachute) ProtoPartModuleSnapshot ppms = p.modules.First(mod => mod.moduleName == "ModuleParachute"); float drag = 500; if (ppms.moduleRef != null) { ModuleParachute mp = (ModuleParachute)ppms.moduleRef; mp.Load(ppms.moduleValues); drag = mp.fullyDeployedDrag; } //Add the part mass times the fully deployed drag (typically 500) to the dragCoeff variable (you'll see why later) dragCoeff += p.mass * drag; //This is most definitely a parachute part isParachute = true; } if (ModuleNames.Contains("RealChuteModule")) { KCTDebug.Log("Found realchute module on " + p.partInfo.name); ProtoPartModuleSnapshot realChute = p.modules.First(mod => mod.moduleName == "RealChuteModule"); if ((object)realChute != null) //Some of this was adopted from DebRefund, as Vendan's method of handling multiple parachutes is better than what I had. { Type matLibraryType = AssemblyLoader.loadedAssemblies .SelectMany(a => a.assembly.GetExportedTypes()) .SingleOrDefault(t => t.FullName == "RealChute.Libraries.MaterialsLibrary"); ConfigNode[] parchutes = realChute.moduleValues.GetNodes("PARACHUTE"); foreach (ConfigNode chute in parchutes) { float diameter = float.Parse(chute.GetValue("deployedDiameter")); string mat = chute.GetValue("material"); System.Reflection.MethodInfo matMethod = matLibraryType.GetMethod("GetMaterial", new Type[] { mat.GetType() }); object MatLibraryInstance = matLibraryType.GetProperty("instance").GetValue(null, null); object materialObject = matMethod.Invoke(MatLibraryInstance, new object[] { mat }); float dragC = (float)KCT_Utilities.GetMemberInfoValue(materialObject.GetType().GetMember("dragCoefficient")[0], materialObject); RCParameter += dragC * (float)Math.Pow(diameter, 2); } isParachute = true; realChuteInUse = true; } } if (!isParachute) { if (p.partRef != null) { dragCoeff += p.mass * p.partRef.maximum_drag; } else { dragCoeff += p.mass * 0.2; } } } } catch (Exception e) { Debug.LogError("[KCT] Error while attempting to recover vessel."); Debug.LogException(e); } double Vt = double.MaxValue; if (!realChuteInUse) { dragCoeff = dragCoeff / (totalMass); Vt = Math.Sqrt((250 * 6.674E-11 * 5.2915793E22) / (3.6E11 * 1.22309485 * dragCoeff)); KCTDebug.Log("Using Stock Module! Drag: " + dragCoeff + " Vt: " + Vt); } else { Vt = Math.Sqrt((8000 * totalMass * 9.8) / (1.223 * Math.PI) * Math.Pow(RCParameter, -1)); //This should work perfect for multiple identical chutes and gives an approximation for multiple differing chutes KCTDebug.Log("Using RealChute Module! Vt: " + Vt); } if (Vt < 10.0) { KCTDebug.Log("Recovered parts from " + v.vesselName); foreach (ProtoPartSnapshot p in v.protoVessel.protoPartSnapshots) { KCT_Utilities.AddPartToInventory(p.partInfo.name + KCT_Utilities.GetTweakScaleSize(p)); if (!PartsRecovered.ContainsKey(p.partInfo.title)) { PartsRecovered.Add(p.partInfo.title, 1); } else { ++PartsRecovered[p.partInfo.title]; } } Message.AppendLine("Vessel name: " + v.vesselName); Message.AppendLine("Parts recovered: "); for (int i = 0; i < PartsRecovered.Count; i++) { Message.AppendLine(PartsRecovered.Values.ElementAt(i) + "x " + PartsRecovered.Keys.ElementAt(i)); } if (KCT_Utilities.CurrentGameIsCareer()) { if (KCT_Utilities.StageRecoveryAddonActive || KCT_Utilities.DebRefundAddonActive) //Delegate funds handling to Stage Recovery or DebRefund if it's present { KCTDebug.Log("Delegating Funds recovery to another addon."); } else //Otherwise do it ourselves { bool probeCoreAttached = false; foreach (ProtoPartSnapshot pps in v.protoVessel.protoPartSnapshots) { if (pps.modules.Find(module => (module.moduleName == "ModuleCommand" && ((ModuleCommand)module.moduleRef).minimumCrew == 0)) != null) { KCTDebug.Log("Probe Core found!"); probeCoreAttached = true; break; } } float RecoveryMod = probeCoreAttached ? 1.0f : KCT_GameStates.settings.RecoveryModifier; KSCDistance = (float)SpaceCenter.Instance.GreatCircleDistance(SpaceCenter.Instance.cb.GetRelSurfaceNVector(v.protoVessel.latitude, v.protoVessel.longitude)); double maxDist = SpaceCenter.Instance.cb.Radius * Math.PI; RecoveryPercent = RecoveryMod * Mathf.Lerp(0.98f, 0.1f, (float)(KSCDistance / maxDist)); float totalReturn = 0; foreach (ProtoPartSnapshot pps in v.protoVessel.protoPartSnapshots) { float dryCost, fuelCost; totalReturn += Math.Max(ShipConstruction.GetPartCosts(pps, pps.partInfo, out dryCost, out fuelCost), 0); } float totalBeforeModifier = totalReturn; totalReturn *= RecoveryPercent; FundsRecovered = totalReturn; KCTDebug.Log("Vessel being recovered by KCT. Percent returned: " + 100 * RecoveryPercent + "%. Distance from KSC: " + Math.Round(KSCDistance / 1000, 2) + " km"); KCTDebug.Log("Funds being returned: " + Math.Round(totalReturn, 2) + "/" + Math.Round(totalBeforeModifier, 2)); Message.AppendLine("Funds recovered: " + FundsRecovered + "(" + Math.Round(RecoveryPercent * 100, 1) + "%)"); KCT_Utilities.AddFunds(FundsRecovered); } } Message.AppendLine("\nAdditional information:"); Message.AppendLine("Distance from KSC: " + Math.Round(KSCDistance / 1000, 2) + " km"); if (!realChuteInUse) { Message.AppendLine("Stock module used. Terminal velocity (less than 10 needed): " + Math.Round(Vt, 2)); } else { Message.AppendLine("RealChute module used. Terminal velocity (less than 10 needed): " + Math.Round(Vt, 2)); } if (!(KCT_Utilities.StageRecoveryAddonActive || KCT_Utilities.DebRefundAddonActive) && (KCT_Utilities.CurrentGameIsCareer() || !KCT_GUI.PrimarilyDisabled) && !(KCT_GameStates.settings.DisableAllMessages || KCT_GameStates.settings.DisableRecoveryMessages)) { KCT_Utilities.DisplayMessage("Stage Recovered", Message, MessageSystemButton.MessageButtonColor.BLUE, MessageSystemButton.ButtonIcons.MESSAGE); } } } }
public override void OnStart(StartState state) { base.OnStart(state); parachute = this.part.FindModuleImplementing <ModuleParachute>(); }
/// <summary> /// We check if the vessel was crashing. If so, we set the crashed flag /// </summary> /// <param name="v">V.</param> private void onVesselDestroy(Vessel v) { // If it has been destroyed under 10 meters above surface, it probably crashed if (v.mainBody.GetAltitude(v.CoM) - (v.terrainAltitude < 0 ? 0 : v.terrainAltitude) < 10) { eventFlags = eventFlags.Add(EventFlags.CRASHED); } // NK recycle else { try { print("*MC* Vessel " + v.name + " destroyed. Alt " + v.mainBody.GetAltitude(v.CoM) + ", body " + v.orbit.referenceBody.bodyName + ", sit = " + v.situation); } catch { } if (!HighLogic.LoadedSceneIsEditor && canRecycle && activeVessel != v && !v.isEVA && // canRecycle is false iff load requested and haven't returned to flight yet. v.name.Contains("(Unloaded)") && // check make sure it's because we're unloading it (v.situation == Vessel.Situations.FLYING || v.situation == Vessel.Situations.SUB_ORBITAL) && v.mainBody.GetAltitude(v.CoM) <= 25000 && v.orbit.referenceBody.bodyName.Equals("Kerbin") && settings.difficulty != 0) { print("*MC* Checking " + v.name); double mass = 0; double pdrag = 0.0; int cost = 0; double AUTORECYCLE_COST_MULT = 0.6; // need 70 drag per ton of vessel for 6m/s at 500m. const double PARACHUTE_DRAG_PER_TON = 70.0; try { foreach (ProtoPartSnapshot p in v.protoVessel.protoPartSnapshots) { print("Has part " + p.partName + ", mass " + p.mass + ", cost " + p.partRef.partInfo.cost); mass += p.mass; cost += p.partRef.partInfo.cost; foreach (ProtoPartModuleSnapshot m in p.modules) { if (m.moduleName.Equals("ModuleParachute")) { ModuleParachute mp = (ModuleParachute)m.moduleRef; pdrag += p.mass * mp.fullyDeployedDrag; print("Drag now " + pdrag); } } } if (mass * PARACHUTE_DRAG_PER_TON <= pdrag) { recycledName = v.name; recycledCost = (int)((double)cost * AUTORECYCLE_COST_MULT); print("*MC* Recycling vessel: enough parachutes! Val: " + cost + " * " + AUTORECYCLE_COST_MULT + " = " + recycledCost); showRecycleWindow = true; manager.recycleVessel(v, recycledCost); } } catch { } } } // We should remove the onflybywire listener, if there is one try { v.OnFlyByWire -= this.onFlyByWire; } catch { } }
public void BreakShipIntoStages() { stages.Clear(); //loop through the part tree and try to break it into stages List <Part> parts = EditorLogic.fetch.ship.parts; EditorStatItem current = new EditorStatItem(); int stageNum = 0; bool realChuteInUse = false; StageParts stage = new StageParts(); List <Part> RemainingDecouplers = new List <Part>() { parts[0] }; while (RemainingDecouplers.Count > 0) { //determine stages from the decouplers Part parent = RemainingDecouplers[0]; RemainingDecouplers.RemoveAt(0); stage = DetermineStage(parent); current = new EditorStatItem(); current.stageNumber = stageNum++; current.parts = stage.parts; RemainingDecouplers.AddRange(stage.decouplers); //compute properties foreach (Part part in stage.parts) { current.dryMass += part.mass; current.mass += part.mass + part.GetResourceMass(); double pChutes = 0; if (part.Modules.Contains("RealChuteModule")) { PartModule realChute = part.Modules["RealChuteModule"]; ConfigNode rcNode = new ConfigNode(); realChute.Save(rcNode); //This is where the Reflection starts. We need to access the material library that RealChute has, so we first grab it's Type Type matLibraryType = AssemblyLoader.loadedAssemblies .SelectMany(a => a.assembly.GetExportedTypes()) .SingleOrDefault(t => t.FullName == "RealChute.Libraries.MaterialsLibrary.MaterialsLibrary"); //We make a list of ConfigNodes containing the parachutes (usually 1, but now there can be any number of them) //We get that from the PPMS ConfigNode[] parachutes = rcNode.GetNodes("PARACHUTE"); //We then act on each individual parachute in the module foreach (ConfigNode chute in parachutes) { //First off, the diameter of the parachute. From that we can (later) determine the Vt, assuming a circular chute float diameter = float.Parse(chute.GetValue("deployedDiameter")); //The name of the material the chute is made of. We need this to get the actual material object and then the drag coefficient string mat = chute.GetValue("material"); //This grabs the method that RealChute uses to get the material. We will invoke that with the name of the material from before. System.Reflection.MethodInfo matMethod = matLibraryType.GetMethod("GetMaterial", new Type[] { mat.GetType() }); //In order to invoke the method, we need to grab the active instance of the material library object MatLibraryInstance = matLibraryType.GetProperty("Instance").GetValue(null, null); //With the library instance we can invoke the GetMaterial method (passing the name of the material as a parameter) to receive an object that is the material object materialObject = matMethod.Invoke(MatLibraryInstance, new object[] { mat }); //With that material object we can extract the dragCoefficient using the helper function above. float dragC = (float)StageRecovery.GetMemberInfoValue(materialObject.GetType().GetMember("DragCoefficient")[0], materialObject); //Now we calculate the RCParameter. Simple addition of this doesn't result in perfect results for Vt with parachutes with different diameter or drag coefficients //But it works perfectly for mutiple identical parachutes (the normal case) pChutes += dragC * (float)Math.Pow(diameter, 2); } realChuteInUse = true; } else if (part.Modules.Contains("RealChuteFAR")) //RealChute Lite for FAR { PartModule realChute = part.Modules["RealChuteFAR"]; float diameter = (float)realChute.Fields.GetValue("deployedDiameter"); // = float.Parse(realChute.moduleValues.GetValue("deployedDiameter")); float dragC = 1.0f; //float.Parse(realChute.moduleValues.GetValue("staticCd")); pChutes += dragC * (float)Math.Pow(diameter, 2); realChuteInUse = true; } else if (!realChuteInUse && part.Modules.Contains("ModuleParachute")) { double scale = 1.0; //check for Tweakscale and modify the area appropriately if (part.Modules.Contains("TweakScale")) { PartModule tweakScale = part.Modules["TweakScale"]; double currentScale = 100, defaultScale = 100; double.TryParse(tweakScale.Fields.GetValue("currentScale").ToString(), out currentScale); double.TryParse(tweakScale.Fields.GetValue("defaultScale").ToString(), out defaultScale); scale = currentScale / defaultScale; } ModuleParachute mp = (ModuleParachute)part.Modules["ModuleParachute"]; //dragCoeff += part.mass * mp.fullyDeployedDrag; pChutes += mp.areaDeployed * Math.Pow(scale, 2); } current.chuteArea += pChutes; } stages.Add(current); } ConsolidateStages(); Debug.Log("[SR] Found " + stages.Count + " stages!"); }
internal void Update() { // Load Application Launcher if (settingsWindow.launcherButton == null && settings.useStockToolbar) { OnGUIApplicationLauncherReady(); if (settingsWindow.showWindow) { settingsWindow.launcherButton.SetTrue(); } } // Destroy application launcher if (settingsWindow.launcherButton != null && settings.useStockToolbar == false) { removeApplicationLauncher(); } foreach (Part p in FlightGlobals.ActiveVessel.parts) { if (p.Modules.OfType <ModuleParachute>().Any()) { StackIcon chuteIcon = Staging.FindIcon(p); if (chuteIcon != null) { if (origTexture == null) { // First time through, set original texture origTexture = chuteIcon.Bg; } else { // Other times, reset to original first then change below as needed chuteIcon.Bg = origTexture; p.stackIcon.SetBgColor(Color.white); } ModuleParachute chute = p.Modules.GetModules <ModuleParachute>().First(); if (settings.resetOnlyDeployWhenSafe) { chute.deployAltitude = 500f; chute.minAirPressureToOpen = 0.01f; settings.resetOnlyDeployWhenSafe = false; } if (chute.deploymentState == ModuleParachute.deploymentStates.STOWED && FlightGlobals.ActiveVessel.atmDensity > 0) { if (chute.deploySafe == "Safe") { if (settings.clearBackground) { chuteIcon.Bg = settings.safeTexture; } else { p.stackIcon.SetBgColor(settings.safeColor); } } if (chute.deploySafe == "Risky") { if (settings.clearBackground) { chuteIcon.Bg = settings.riskyTexture; } else { p.stackIcon.SetBgColor(settings.riskyColor); } } if (chute.deploySafe == "Unsafe") { if (settings.clearBackground) { chuteIcon.Bg = settings.unSafeTexture; } else { p.stackIcon.SetBgColor(settings.unSafeColor); } } } if (settings.onlyDeployWhenSafe && chute.deploymentState == ModuleParachute.deploymentStates.ACTIVE && FlightGlobals.ActiveVessel.atmDensity > 0) { if (chute.deploySafe == "Safe") { p.stackIcon.SetIconColor(settings.safeColor); chute.deployAltitude = (float)FlightGlobals.ActiveVessel.altitude; chute.minAirPressureToOpen = 0.01f; } else { p.stackIcon.SetIconColor(settings.riskyColor); chute.deployAltitude = 100f; chute.minAirPressureToOpen = 100f; } } } } } }