public BuildListVessel CreateCopy(bool RecalcTime) { BuildListVessel ret = new BuildListVessel(ShipName, LaunchSite, EffectiveCost, BuildPoints, IntegrationPoints, Flag, Cost, IntegrationCost, (int)GetEditorFacility()) { ShipNode = ShipNode.CreateCopy() }; //refresh all inventory parts to new foreach (var p in ret.ExtractedPartNodes) { ScrapYardWrapper.RefreshPart(p); } ret.Id = Guid.NewGuid(); ret.KCTPersistentID = Guid.NewGuid().ToString(); ret.TotalMass = TotalMass; ret.EmptyMass = EmptyMass; ret.Cost = Cost; ret.IntegrationCost = IntegrationCost; ret.EmptyCost = EmptyCost; ret.NumStageParts = NumStageParts; ret.NumStages = NumStages; ret.StagePartCost = StagePartCost; ret.ShipSize = ShipSize; if (RecalcTime) { ret.EffectiveCost = Utilities.GetEffectiveCost(ret.ExtractedPartNodes); ret.BuildPoints = Utilities.GetBuildTime(ret.EffectiveCost); ret.IntegrationPoints = MathParser.ParseIntegrationTimeFormula(ret); ret.IntegrationCost = (float)MathParser.ParseIntegrationCostFormula(ret); } return(ret); }
public void VesselRecoverEvent(ProtoVessel v, bool unknownAsOfNow) { KCTDebug.Log("VesselRecoverEvent"); if (!PresetManager.Instance.ActivePreset.GeneralSettings.Enabled) { return; } if (!KCTGameStates.IsSimulatedFlight && !v.vesselRef.isEVA) { if (KCTGameStates.RecoveredVessel != null && v.vesselName == KCTGameStates.RecoveredVessel.ShipName) { //rebuy the ship if ScrapYard isn't overriding funds if (!ScrapYardWrapper.OverrideFunds) { Utilities.SpendFunds(KCTGameStates.RecoveredVessel.Cost, TransactionReasons.VesselRollout); //pay for the ship again } //pull all of the parts out of the inventory //This is a bit funky since we grab the part id from our part, grab the inventory part out, then try to reapply that ontop of our part if (ScrapYardWrapper.Available) { foreach (ConfigNode partNode in KCTGameStates.RecoveredVessel.ExtractedPartNodes) { string id = ScrapYardWrapper.GetPartID(partNode); ConfigNode inventoryVersion = ScrapYardWrapper.FindInventoryPart(id); if (inventoryVersion != null) { //apply it to our copy of the part ConfigNode ourTracker = partNode.GetNodes("MODULE").FirstOrDefault(n => string.Equals(n.GetValue("name"), "ModuleSYPartTracker", StringComparison.Ordinal)); if (ourTracker != null) { ourTracker.SetValue("TimesRecovered", inventoryVersion.GetValue("_timesRecovered")); ourTracker.SetValue("Inventoried", inventoryVersion.GetValue("_inventoried")); } } } //process the vessel in ScrapYard ScrapYardWrapper.ProcessVessel(KCTGameStates.RecoveredVessel.ExtractedPartNodes); //reset the BP KCTGameStates.RecoveredVessel.BuildPoints = Utilities.GetBuildTime(KCTGameStates.RecoveredVessel.ExtractedPartNodes); KCTGameStates.RecoveredVessel.IntegrationPoints = MathParser.ParseIntegrationTimeFormula(KCTGameStates.RecoveredVessel); } if (KCTGameStates.RecoveredVessel.Type == BuildListVessel.ListType.VAB) { KCTGameStates.ActiveKSC.VABWarehouse.Add(KCTGameStates.RecoveredVessel); } else { KCTGameStates.ActiveKSC.SPHWarehouse.Add(KCTGameStates.RecoveredVessel); } KCTGameStates.ActiveKSC.Recon_Rollout.Add(new ReconRollout(KCTGameStates.RecoveredVessel, ReconRollout.RolloutReconType.Recovery, KCTGameStates.RecoveredVessel.Id.ToString())); KCTGameStates.RecoveredVessel = null; } } }
/// <summary> /// For recovered vessels /// </summary> /// <param name="vessel"></param> /// <param name="listType"></param> public BuildListVessel(Vessel vessel, ListType listType = ListType.None) { Id = Guid.NewGuid(); KCTPersistentID = Guid.NewGuid().ToString(); ShipName = vessel.vesselName; ShipNode = FromInFlightVessel(vessel, listType); if (listType != ListType.None) { Type = listType; } Cost = Utilities.GetTotalVesselCost(ShipNode); EmptyCost = Utilities.GetTotalVesselCost(ShipNode, false); TotalMass = 0; EmptyMass = 0; HashSet <int> stages = new HashSet <int>(); foreach (ProtoPartSnapshot p in vessel.protoVessel.protoPartSnapshots) { stages.Add(p.inverseStageIndex); if (p.partPrefab != null) { if (p.partPrefab.Modules.Contains <LaunchClamp>() || p.partPrefab.HasTag("PadInfrastructure")) { continue; } } TotalMass += p.mass; EmptyMass += p.mass; foreach (ProtoPartResourceSnapshot rsc in p.resources) { PartResourceDefinition def = PartResourceLibrary.Instance.GetDefinition(rsc.resourceName); if (def != null) { TotalMass += def.density * (float)rsc.amount; } } } CannotEarnScience = true; NumStages = stages.Count; // FIXME ignore stageable part count and cost - it'll be fixed when we put this back in the editor. EffectiveCost = Utilities.GetEffectiveCost(ShipNode.GetNodes("PART").ToList()); BuildPoints = Utilities.GetBuildTime(EffectiveCost); Flag = HighLogic.CurrentGame.flagURL; DistanceFromKSC = (float)SpaceCenter.Instance.GreatCircleDistance(SpaceCenter.Instance.cb.GetRelSurfaceNVector(vessel.latitude, vessel.longitude)); RushBuildClicks = 0; IntegrationPoints = MathParser.ParseIntegrationTimeFormula(this); IntegrationCost = (float)MathParser.ParseIntegrationCostFormula(this); Progress = BuildPoints + IntegrationPoints; }
public BuildListVessel(ShipConstruct s, string ls, double effCost, double bP, string flagURL) { _ship = s; ShipNode = s.SaveShip(); // Override KSP sizing of the ship construct ShipSize = Utilities.GetShipSize(s, true); ShipNode.SetValue("size", KSPUtil.WriteVector(ShipSize)); ShipName = s.shipName; Cost = Utilities.GetTotalVesselCost(ShipNode, true); EmptyCost = Utilities.GetTotalVesselCost(ShipNode, false); TotalMass = Utilities.GetShipMass(s, true, out EmptyMass, out _); HashSet <int> stages = new HashSet <int>(); NumStageParts = 0; StagePartCost = 0d; foreach (Part p in s.Parts) { if (p.stagingOn) { stages.Add(p.inverseStage); ++NumStageParts; StagePartCost += p.GetModuleCosts(p.partInfo.cost, ModifierStagingSituation.CURRENT) + p.partInfo.cost; } } NumStages = stages.Count; LaunchSite = ls; EffectiveCost = effCost; BuildPoints = bP; Progress = 0; Flag = flagURL; if (s.shipFacility == EditorFacility.VAB) { Type = ListType.VAB; FacilityBuiltIn = EditorFacility.VAB; } else if (s.shipFacility == EditorFacility.SPH) { Type = ListType.SPH; FacilityBuiltIn = EditorFacility.SPH; } else { Type = ListType.None; } Id = Guid.NewGuid(); KCTPersistentID = Guid.NewGuid().ToString(); CannotEarnScience = false; //get the crew from the editorlogic DesiredManifest = new List <string>(); if (CrewAssignmentDialog.Instance?.GetManifest()?.CrewCount > 0) { foreach (ProtoCrewMember crew in CrewAssignmentDialog.Instance.GetManifest().GetAllCrew(true) ?? new List <ProtoCrewMember>()) { DesiredManifest.Add(crew?.name ?? string.Empty); } } if (EffectiveCost == default) { // Can only happen in older saves that didn't have Effective cost persisted as a separate field // This code should be safe to remove after a while. EffectiveCost = Utilities.GetEffectiveCost(ShipNode.GetNodes("PART").ToList()); } IntegrationPoints = MathParser.ParseIntegrationTimeFormula(this); IntegrationCost = (float)MathParser.ParseIntegrationCostFormula(this); }
private static void RenderEditMode() { BuildListVessel ship = KCTGameStates.EditedVessel; if (_finishedShipBP < 0 && ship.IsFinished) { // If ship is finished, then both build and integration times can be refreshed with newly calculated values _finishedShipBP = Utilities.GetBuildTime(ship.ExtractedPartNodes); ship.BuildPoints = _finishedShipBP; ship.IntegrationPoints = MathParser.ParseIntegrationTimeFormula(ship); } Utilities.GetShipEditProgress(ship, out double newProgressBP, out double originalCompletionPercent, out double newCompletionPercent); GUILayout.Label($"Original: {Math.Max(0, Math.Round(100 * originalCompletionPercent, 2))}%"); GUILayout.Label($"Edited: {Math.Round(100 * newCompletionPercent, 2)}%"); BuildListVessel.ListType type = EditorLogic.fetch.launchSiteName == "LaunchPad" ? BuildListVessel.ListType.VAB : BuildListVessel.ListType.SPH; GUILayout.BeginHorizontal(); GUILayout.Label("Build Time at "); if (BuildRateForDisplay == null) { BuildRateForDisplay = Utilities.GetBuildRate(0, type, null).ToString(); } BuildRateForDisplay = GUILayout.TextField(BuildRateForDisplay, GUILayout.Width(75)); GUILayout.Label(" BP/s:"); List <double> rates = new List <double>(); if (ship.Type == BuildListVessel.ListType.VAB) { rates = Utilities.GetVABBuildRates(null); } else { rates = Utilities.GetSPHBuildRates(null); } if (double.TryParse(BuildRateForDisplay, out double bR)) { if (GUILayout.Button(new GUIContent("*", "Switch build line that is used for build time calculations"), GUILayout.ExpandWidth(false))) { _rateIndexHolder = (_rateIndexHolder + 1) % rates.Count; bR = rates[_rateIndexHolder]; BuildRateForDisplay = bR.ToString(); } GUILayout.EndHorizontal(); GUILayout.Label(MagiCore.Utilities.GetFormattedTime(Math.Abs(KCTGameStates.EditorBuildTime + KCTGameStates.EditorIntegrationTime - newProgressBP) / bR)); } else { GUILayout.EndHorizontal(); GUILayout.Label("Invalid Build Rate"); } GUILayout.BeginHorizontal(); if (GUILayout.Button("Save Edits")) { _finishedShipBP = -1; Utilities.SaveShipEdits(ship); } if (GUILayout.Button("Cancel Edits")) { KCTDebug.Log("Edits cancelled."); _finishedShipBP = -1; ScrapYardWrapper.ProcessVessel(KCTGameStates.EditedVessel.ExtractedPartNodes); KCTGameStates.ClearVesselEditMode(); HighLogic.LoadScene(GameScenes.SPACECENTER); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); if (GUILayout.Button("Simulate")) { _finishedShipBP = -1; _simulationConfigPosition.height = 1; EditorLogic.fetch.Lock(true, true, true, "KCTGUILock"); GUIStates.ShowSimConfig = true; double effCost = Utilities.GetEffectiveCost(EditorLogic.fetch.ship.Parts); double bp = Utilities.GetBuildTime(effCost); KCTGameStates.LaunchedVessel = new BuildListVessel(EditorLogic.fetch.ship, EditorLogic.fetch.launchSiteName, effCost, bp, EditorLogic.FlagURL); } GUILayout.EndHorizontal(); if (KCTGameStates.LaunchedVessel != null && !KCTGameStates.LaunchedVessel.AreTanksFull() && GUILayout.Button("Fill Tanks")) { foreach (Part p in EditorLogic.fetch.ship.parts) { //fill as part prefab would be filled? if (Utilities.PartIsProcedural(p)) { foreach (PartResource rsc in p.Resources) { if (GuiDataAndWhitelistItemsDatabase.ValidFuelRes.Contains(rsc.resourceName) && rsc.flowState) { rsc.amount = rsc.maxAmount; } } } else { foreach (PartResource rsc in p.Resources) { if (GuiDataAndWhitelistItemsDatabase.ValidFuelRes.Contains(rsc.resourceName) && rsc.flowState) { PartResource templateRsc = p.partInfo.partPrefab.Resources.FirstOrDefault(r => r.resourceName == rsc.resourceName); if (templateRsc != null) { rsc.amount = templateRsc.amount; } } } } } } RenderMergeSection(ship); }
private static void RenderEditMode() { BuildListVessel ship = KCTGameStates.EditedVessel; if (_finishedShipBP < 0 && ship.IsFinished) { // If ship is finished, then both build and integration times can be refreshed with newly calculated values _finishedShipBP = Utilities.GetBuildTime(ship.ExtractedPartNodes); ship.BuildPoints = _finishedShipBP; ship.IntegrationPoints = MathParser.ParseIntegrationTimeFormula(ship); } double origBP = ship.IsFinished ? _finishedShipBP : ship.BuildPoints; origBP += ship.IntegrationPoints; double buildTime = KCTGameStates.EditorBuildTime + KCTGameStates.EditorIntegrationTime; double difference = Math.Abs(buildTime - origBP); double progress; if (ship.IsFinished) { progress = origBP; } else { progress = ship.Progress; } double newProgress = Math.Max(0, progress - (1.1 * difference)); GUILayout.Label($"Original: {Math.Max(0, Math.Round(100 * (progress / origBP), 2))}%"); GUILayout.Label($"Edited: {Math.Round(100 * newProgress / buildTime, 2)}%"); BuildListVessel.ListType type = EditorLogic.fetch.launchSiteName == "LaunchPad" ? BuildListVessel.ListType.VAB : BuildListVessel.ListType.SPH; GUILayout.BeginHorizontal(); GUILayout.Label("Build Time at "); if (BuildRateForDisplay == null) { BuildRateForDisplay = Utilities.GetBuildRate(0, type, null).ToString(); } BuildRateForDisplay = GUILayout.TextField(BuildRateForDisplay, GUILayout.Width(75)); GUILayout.Label(" BP/s:"); List <double> rates = new List <double>(); if (ship.Type == BuildListVessel.ListType.VAB) { rates = Utilities.GetVABBuildRates(null); } else { rates = Utilities.GetSPHBuildRates(null); } if (double.TryParse(BuildRateForDisplay, out double bR)) { if (GUILayout.Button("*", GUILayout.ExpandWidth(false))) { _rateIndexHolder = (_rateIndexHolder + 1) % rates.Count; bR = rates[_rateIndexHolder]; BuildRateForDisplay = bR.ToString(); } GUILayout.EndHorizontal(); GUILayout.Label(MagiCore.Utilities.GetFormattedTime(Math.Abs(buildTime - newProgress) / bR)); } else { GUILayout.EndHorizontal(); GUILayout.Label("Invalid Build Rate"); } GUILayout.BeginHorizontal(); if (GUILayout.Button("Save Edits")) { _finishedShipBP = -1; Utilities.AddFunds(ship.GetTotalCost(), TransactionReasons.VesselRollout); BuildListVessel newShip = Utilities.AddVesselToBuildList(); if (newShip == null) { Utilities.SpendFunds(ship.GetTotalCost(), TransactionReasons.VesselRollout); return; } ship.RemoveFromBuildList(); newShip.Progress = newProgress; newShip.RushBuildClicks = ship.RushBuildClicks; KCTDebug.Log($"Finished? {ship.IsFinished}"); if (ship.IsFinished) { newShip.CannotEarnScience = true; } GamePersistence.SaveGame("persistent", HighLogic.SaveFolder, SaveMode.OVERWRITE); KCTGameStates.EditorShipEditingMode = false; InputLockManager.RemoveControlLock("KCTEditExit"); InputLockManager.RemoveControlLock("KCTEditLoad"); InputLockManager.RemoveControlLock("KCTEditNew"); InputLockManager.RemoveControlLock("KCTEditLaunch"); EditorLogic.fetch.Unlock("KCTEditorMouseLock"); KCTDebug.Log("Edits saved."); HighLogic.LoadScene(GameScenes.SPACECENTER); } if (GUILayout.Button("Cancel Edits")) { KCTDebug.Log("Edits cancelled."); _finishedShipBP = -1; KCTGameStates.EditorShipEditingMode = false; InputLockManager.RemoveControlLock("KCTEditExit"); InputLockManager.RemoveControlLock("KCTEditLoad"); InputLockManager.RemoveControlLock("KCTEditNew"); InputLockManager.RemoveControlLock("KCTEditLaunch"); EditorLogic.fetch.Unlock("KCTEditorMouseLock"); ScrapYardWrapper.ProcessVessel(KCTGameStates.EditedVessel.ExtractedPartNodes); HighLogic.LoadScene(GameScenes.SPACECENTER); } GUILayout.EndHorizontal(); if (KCTGameStates.LaunchedVessel != null && !KCTGameStates.LaunchedVessel.AreTanksFull() && GUILayout.Button("Fill Tanks")) { foreach (Part p in EditorLogic.fetch.ship.parts) { //fill as part prefab would be filled? if (Utilities.PartIsProcedural(p)) { foreach (PartResource rsc in p.Resources) { if (GuiDataAndWhitelistItemsDatabase.ValidFuelRes.Contains(rsc.resourceName) && rsc.flowState) { rsc.amount = rsc.maxAmount; } } } else { foreach (PartResource rsc in p.Resources) { if (GuiDataAndWhitelistItemsDatabase.ValidFuelRes.Contains(rsc.resourceName) && rsc.flowState) { PartResource templateRsc = p.partInfo.partPrefab.Resources.FirstOrDefault(r => r.resourceName == rsc.resourceName); if (templateRsc != null) { rsc.amount = templateRsc.amount; } } } } } } }