// Returns the number of crew-members that have a given trait (eg "Pilot"): public static int GetCrewCountWithTrait(Vessel vessel, string trait) { var traitCount = 0; foreach (var crewMember in TargetVessel.GetCrew(vessel)) { if (crewMember.trait == trait) { traitCount++; } } return(traitCount); }
// Shows a list of all available target-vessels and returns true, if the player has selected one: public bool DisplayList() { GUILayout.Label("<size=14><b>Target:</b></size>"); scrollPos = GUILayout.BeginScrollView(scrollPos, GUI.scrollStyle); string green = "#00FF00"; string red = "#FF0000"; // Build a list with all valid vessels: List <Vessel> validTargets = new List <Vessel>(); foreach (Vessel vessel in FlightGlobals.Vessels) { if (!TargetVessel.IsValidTarget(vessel)) { continue; } validTargets.Add(vessel); } if (selectedIndex >= validTargets.Count) { selectedIndex = -1; targetVessel = null; } if (validTargets.Count == 0) { // No valid targest available: GUILayout.Label("No valid targets in orbit."); } else { // Show list with all possible vessels: List <GUIContent> contents = new List <GUIContent>(); List <int> filteredIndices = new List <int>(); // Target-vessels which fall out of the defined filters will get noted here. int index = 0; foreach (Vessel vessel in validTargets) { bool filterThisTarget = false; if (!TargetVessel.IsValidTarget(vessel)) { continue; } List <string> descriptions = new List <string>(); descriptions.Add("<color=#F9FA86><b>" + vessel.vesselName + "</b></color><color=#FFFFFF>"); // Orbital-Parameters: descriptions.Add("<b>Apoapsis:</b> " + GUI.FormatAltitude(vessel.orbit.ApA) + ", <b>Periapsis:</b> " + GUI.FormatAltitude(vessel.orbit.PeA) + ", <b>MET:</b> " + GUI.FormatDuration(vessel.missionTime)); // Docking-Port Types: List <string> dockingPortsTranslated = new List <string>(); foreach (string dockingPortType in TargetVessel.GetVesselDockingPortTypes(vessel)) { dockingPortsTranslated.Add(TargetVessel.TranslateDockingPortName(dockingPortType)); } if (dockingPortsTranslated.Count > 0) { descriptions.Add("<b>Docking-Ports:</b> " + string.Join(", ", dockingPortsTranslated.ToArray())); } // Resources: double capacity = 0; foreach (PayloadResource availableResource in TargetVessel.GetFreeResourcesCapacities(vessel)) { capacity += availableResource.amount * availableResource.mass; } if (capacity > 0) { descriptions.Add("<b>Resource Capacity:</b> " + capacity.ToString("#,##0.00t")); } // Crew: int seats = TargetVessel.GetCrewCapacity(vessel); int crew = TargetVessel.GetCrew(vessel).Count; if (seats > 0) { descriptions.Add("<b>Crew:</b> " + crew.ToString() + "/" + seats.ToString()); } // Maybe apply additional filters and show their attributes: List <string> filterAttributes = new List <string>();; if (filterVesselType != null) { bool isValidType = vessel.vesselType == (VesselType)filterVesselType; string color = isValidType ? green : red; filterAttributes.Add("<b>Type:</b> <color=" + color + ">" + vessel.vesselType.ToString() + "</color>"); if (!isValidType) { filterThisTarget = true; } } if (filterHasCrewTrait != null) { int traitCount = TargetVessel.GetCrewCountWithTrait(vessel, filterHasCrewTrait); int requiredCount = 1; if (filterHasCrewTraitCount != null) { requiredCount = (int)filterHasCrewTraitCount; } string color = traitCount >= requiredCount ? green : red; filterAttributes.Add("<b>" + filterHasCrewTrait + "s:</b> <color=" + color + ">" + traitCount.ToString() + "/" + requiredCount.ToString() + "</color>"); if (traitCount < requiredCount) { filterThisTarget = true; } } if (filterAttributes.Count > 0) { descriptions.Add(String.Join(" ", filterAttributes.ToArray())); } contents.Add(new GUIContent(String.Join("\n", descriptions.ToArray()) + "</color>")); if (filterThisTarget) { filteredIndices.Add(index); // If there were filters, which did not match, we still show the target, but don't allow to select it. } index++; } int newSelection = GUILayout.SelectionGrid(selectedIndex, contents.ToArray(), 1, GUI.selectionGridStyle); if (newSelection >= 0 && !filteredIndices.Contains(newSelection)) { // The player has selected a payload: selectedIndex = newSelection; targetVessel = validTargets[selectedIndex]; } } GUILayout.EndScrollView(); return(targetVessel != null); }
public override void OnSave(ConfigNode node) { try { /* * When transporting an available kerbal to a ship or recovering one from orbit, we manipulate the (unloaded) vessel's crew * as well as the roster-status of the kerbal. This is apparently not expected by KSP's core functionality, because there * seems to be a secret list of roster-status which is enforced when the game is safed: * * [WRN 15:16:14.678] [ProtoCrewMember Warning]: Crewmember Sierina Kerman found inside a part but status is set as missing. Vessel must have failed to save earlier. Restoring assigned status. * [WRN 15:17:42.913] [ProtoCrewMember Warning]: Crewmember Sierina Kerman found assigned but no vessels reference him. Sierina Kerman set as missing. * * Afterwards these kerbals would be lost for the player, which is why we have to use the workaround below to revert these * changes and make sure each kerbal has the correct status. This effectively disables the "missing" status as these kerbals * will always respawn, but I haven't seen a valid use-case for this thus far, so it is probably fine. */ if (HighLogic.CurrentGame.CrewRoster.Count > 0 && FlightGlobals.Vessels.Count > 0) { // Build a list of all Kerbals which are assigned to vessels: List <string> vesselCrewNames = new List <string>(); foreach (Vessel vessel in FlightGlobals.Vessels) { foreach (ProtoCrewMember crewMember in TargetVessel.GetCrew(vessel)) { vesselCrewNames.Add(crewMember.name); } } // Build a list of all kerbals which we could have manipulated: List <ProtoCrewMember> kerbals = new List <ProtoCrewMember>(); foreach (ProtoCrewMember kerbal in HighLogic.CurrentGame.CrewRoster.Kerbals(ProtoCrewMember.KerbalType.Crew)) { kerbals.Add(kerbal); } foreach (ProtoCrewMember kerbal in HighLogic.CurrentGame.CrewRoster.Kerbals(ProtoCrewMember.KerbalType.Tourist)) { kerbals.Add(kerbal); } // Check those kerbals against our vessel-list and maybe restore their correct status: foreach (ProtoCrewMember kerbal in kerbals) { if (kerbal.rosterStatus == ProtoCrewMember.RosterStatus.Dead) { continue; } if (vesselCrewNames.Contains(kerbal.name) && kerbal.rosterStatus != ProtoCrewMember.RosterStatus.Assigned) { Debug.Log("[KSTS] setting kerbal " + kerbal.name + " from " + kerbal.rosterStatus.ToString() + " to Assigned (see code for more info)"); kerbal.rosterStatus = ProtoCrewMember.RosterStatus.Assigned; } else if (!vesselCrewNames.Contains(kerbal.name) && kerbal.rosterStatus != ProtoCrewMember.RosterStatus.Available) { Debug.Log("[KSTS] setting kerbal " + kerbal.name + " from " + kerbal.rosterStatus.ToString() + " to Available (see code for more info)"); kerbal.rosterStatus = ProtoCrewMember.RosterStatus.Available; } } } FlightRecorder.SaveRecordings(node); MissionController.SaveMissions(node); } catch (Exception e) { Debug.LogError("[KSTS] OnSave(): " + e.ToString()); } }
// Shows a list of all available crew-members which the player can choose to transport and returns true, if the selection is valid: public bool DisplayList() { var targetCrewCapacity = 0; if (targetVessel != null) { targetCrewCapacity = TargetVessel.GetCrewCapacity(targetVessel); } else if (targetTemplate != null) { targetCrewCapacity = targetTemplate.GetCrewCapacity(); } if (missionProfile.crewCapacity == 0 && missionProfile.missionType == MissionProfileType.TRANSPORT) // We only care about the seats on the transport-vessel during transport-missions. { GUILayout.Label("There are no available seats in the selected mission-profile."); return(true); } else if (targetCrewCapacity == 0) // If the target has no seats, we can't transport anyone. { GUILayout.Label("The selected target-vessel can not hold any crew-members."); return(true); } else { // Target-vessel summary: var targetOverload = false; string headline; if (targetVessel != null) // Existing vessel (in- & outboud transfers possible) { // Display capacity and transfer deltas: var targetVesselCrew = TargetVessel.GetCrew(targetVessel); if (targetVesselCrew.Count + crewToDeliver.Count - crewToCollect.Count > targetCrewCapacity) { targetOverload = true; } headline = "<b>" + targetVessel.vesselName + ":</b> " + targetVesselCrew.Count.ToString() + "/" + targetCrewCapacity.ToString(); var transfers = " inbound: " + crewToDeliver.Count.ToString("+#;-#;0") + ", outbound: " + (-crewToCollect.Count).ToString("+#;-#;0"); if (targetOverload) { transfers = "<color=#FF0000>" + transfers + "</color>"; } GUILayout.Label(headline + transfers); // Display Crew that is stationed on the target vessel: foreach (var kerbonaut in targetVesselCrew) { var details = " <b>" + kerbonaut.name + "</b> (Level " + kerbonaut.experienceLevel.ToString() + " " + kerbonaut.trait + ")"; if (missionProfile.oneWayMission || MissionController.GetKerbonautsMission(kerbonaut.name) != null || missionProfile.missionType != MissionProfileType.TRANSPORT) { GUILayout.Label(" • " + details); // Do not transport kerbals, which are flagged for another mission or there isn't even a return-trip or transport happening } else { var selected = GUILayout.Toggle(crewToCollect.Contains(kerbonaut.name), details); if (selected && !crewToCollect.Contains(kerbonaut.name)) { crewToCollect.Add(kerbonaut.name); } else if (!selected && crewToCollect.Contains(kerbonaut.name)) { crewToCollect.Remove(kerbonaut.name); } } } GUILayout.Label(""); } else if (targetTemplate != null) // New vessel (only inbound transfers possible) { // Display capacity: if (crewToDeliver.Count > targetCrewCapacity) { targetOverload = true; } headline = "<b>" + targetTemplate.template.shipName + ":</b> "; var seats = crewToDeliver.Count.ToString() + " / " + targetCrewCapacity.ToString() + " seat"; if (targetCrewCapacity != 1) { seats += "s"; } if (targetOverload) { seats = "<color=#FF0000>" + seats + "</color>"; } GUILayout.Label(headline + seats); } // Display Transport-vessel summary, if this is a transport-mission: var transportOutboundOverload = false; var transportInboundOverload = false; if (missionProfile.missionType == MissionProfileType.TRANSPORT) { if (crewToDeliver.Count > missionProfile.crewCapacity) { transportOutboundOverload = true; } if (crewToCollect.Count > missionProfile.crewCapacity) { transportInboundOverload = true; } headline = "<b>" + missionProfile.vesselName + ":</b> "; var outbound = "outbound: " + crewToDeliver.Count.ToString() + "/" + missionProfile.crewCapacity.ToString(); if (transportOutboundOverload) { outbound = "<color=#FF0000>" + outbound + "</color>"; } var inbound = ""; if (!missionProfile.oneWayMission) { inbound = ", inbound: " + crewToCollect.Count.ToString() + "/" + missionProfile.crewCapacity.ToString(); if (transportInboundOverload) { inbound = "<color=#FF0000>" + inbound + "</color>"; } } else { inbound += ", inbound: -"; } GUILayout.Label(headline + outbound + inbound); } // Display crew-rowster: foreach (var kerbonaut in GetCrewRoster()) { var details = " <b>" + kerbonaut.name + "</b> (Level " + kerbonaut.experienceLevel.ToString() + " " + kerbonaut.trait.ToString() + ")"; if (MissionController.GetKerbonautsMission(kerbonaut.name) != null) { GUILayout.Label(" • " + details); // Do not transport kerbals, which are flagged for another mission } else { var selected = GUILayout.Toggle(crewToDeliver.Contains(kerbonaut.name), details); if (selected && !crewToDeliver.Contains(kerbonaut.name)) { crewToDeliver.Add(kerbonaut.name); } else if (!selected && crewToDeliver.Contains(kerbonaut.name)) { crewToDeliver.Remove(kerbonaut.name); } } } // Check if the selection is valid (it neither overloads the target nor the transport): if (!targetOverload && !transportOutboundOverload && !transportInboundOverload) { return(true); } return(false); } }