Ejemplo n.º 1
0
 /// <summary>
 /// Gets whether the kerbal is available for assignment.
 /// </summary>
 /// <param name="crew"></param>
 /// <returns></returns>
 private static bool IsAssignable(ProtoCrewMember crew, CrewableList alreadyAssigned)
 {
     return((crew != null) &&
            (crew.type == ProtoCrewMember.KerbalType.Crew) && // we never want to assign tourists
            (crew.rosterStatus == ProtoCrewMember.RosterStatus.Available) &&
            !alreadyAssigned.IsAssigned(crew));
 }
Ejemplo n.º 2
0
 /// <summary>
 /// Find the highest and lowest level kerbal of the specified profession that's available for assignment.
 /// Returns true if found, false if not.
 /// </summary>
 private static bool FindHighestLowestAvailable(
     string profession,
     int minimumLevel,
     CrewableList alreadyAssigned,
     out ProtoCrewMember highest,
     out ProtoCrewMember lowest)
 {
     highest = null;
     lowest  = null;
     foreach (ProtoCrewMember candidate in Roster.Crew)
     {
         if (IsAssignable(candidate, alreadyAssigned) &&
             profession.Equals(candidate.trait) &&
             (candidate.experienceLevel >= minimumLevel) &&
             !alreadyAssigned.IsAssigned(candidate))
         {
             if ((highest == null) || (candidate.experience > highest.experience))
             {
                 highest = candidate;
             }
             if ((lowest == null) || (candidate.experience > lowest.experience))
             {
                 lowest = candidate;
             }
         }
     }
     return(highest != null);
 }
Ejemplo n.º 3
0
        /// <summary>
        /// Persist all assignments so that they'll be available after saving/reloading the ship.
        /// </summary>
        /// <param name="crewables"></param>
        public static void PersistKerbalAssignments(ShipConstruct construct)
        {
            CrewableList crewables = new CrewableList(construct);

            foreach (Crewable crewable in crewables.All)
            {
                crewable.PersistAssignments();
            }

            Logging.Log("Persisted assignments.");
        }
Ejemplo n.º 4
0
        /// <summary>
        /// If the ship has no probe cores with SAS, try to make sure that there's at least one pilot.
        /// Returns the available SAS level (-1 if no SAS present).
        /// </summary>
        /// <param name="construct"></param>
        /// <param name="crewables"></param>
        private static int TryEnsureSAS(ShipConstruct construct, CrewableList crewables)
        {
            // Do we have SAS?
            int sasLevel = GetHighestSASLevel(construct);

            // get the highest-level pilot
            ProtoCrewMember highestPilot = GetHighestAssignedLevel(crewables.Command, PILOT_PROFESSION);
            int             pilotLevel   = (highestPilot == null) ? -1 : highestPilot.experienceLevel;

            int maxSas = (sasLevel > pilotLevel) ? sasLevel : pilotLevel;

            if (maxSas >= 0)
            {
                // we already have SAS on the ship, don't need to add a pilot
                if ((sasLevel < 0) && (pilotLevel > sasLevel))
                {
                    Logging.Log(Logging.ToString(highestPilot) + " is already assigned and will provide SAS");
                }
                return(maxSas);
            }

            // There's no SAS control, we need to add a pilot somewhere.

            // Try to find a slot to put a pilot
            CrewSlot pilotSlot = Crewable.FindEmptySlot(crewables.Command);

            if (pilotSlot == null)
            {
                Logging.Warn("SAS will be unavailable (no probe cores, no open slots to add a pilot)");
                return(maxSas);
            }

            // Try to find a pilot to assign.
            ProtoCrewMember lowestPilot;

            if (!FindHighestLowestAvailable(PILOT_PROFESSION, 0, crewables, out highestPilot, out lowestPilot))
            {
                Logging.Warn("SAS will be unavailable (no probe cores, no available pilots)");
                return(maxSas);
            }

            Logging.Log("Assigning " + Logging.ToString(highestPilot) + " to provide SAS");
            pilotSlot.Occupant = highestPilot;
            return(highestPilot.experienceLevel);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// As needed, assign additional crew members to fulfill part requirements.
        /// </summary>
        /// <param name="crewables"></param>
        /// <param name="construct"></param>
        private static void FulfillPartRequirements(CrewableList crewables, ShipConstruct construct)
        {
            // Find any professions that are required on the ship
            Dictionary <string, ModuleCrewRequirement> requirements = FindRequiredProfessions(construct);

            if (requirements.Count == 0)
            {
                return;                          // there aren't any requirements
            }
            // We can ignore any that are already provided for
            List <string> ignoreList = new List <string>();

            foreach (string requiredProfession in requirements.Keys)
            {
                int requiredLevel = requirements[requiredProfession].minimumLevel;
                if (HasProfession(crewables.All, requiredProfession, requiredLevel))
                {
                    ignoreList.Add(requiredProfession);
                }
            }
            foreach (string ignoreProfession in ignoreList)
            {
                requirements.Remove(ignoreProfession);
            }
            if (requirements.Count == 0)
            {
                return;                          // all requirements already taken care of
            }
            // We now have a set of required professions that we want to have on board,
            // but haven't yet satisfied. There might not be enough slots to hold them all,
            // so build a prioritized list with the most-desired profession first.
            List <String> prioritizedRequirements = new List <string>(requirements.Keys);

            if (prioritizedRequirements.Count > 1)
            {
                // Sort our remaining requirements in descending order of importance
                Comparison <string> byPriority = (profession1, profession2) =>
                {
                    // First, sort by *declared* importance from the parts. i.e. if the
                    // Mystery Goo asks for a scientist and assigns importance 0, and the
                    // ISRU asks for an engineer and assigns importance 1, then the ISRU wins.
                    int importance1 = requirements[profession1].importance;
                    int importance2 = requirements[profession2].importance;
                    if (importance1 > importance2)
                    {
                        return(-1);
                    }
                    if (importance2 > importance1)
                    {
                        return(1);
                    }
                    // In case of a tie (e.g. one part asks for a scientist with importance 1
                    // and the other asks for an engineer with importance 1), then pick the
                    // profession that's "better".
                    importance1 = ProfessionImportance(profession1);
                    importance2 = ProfessionImportance(profession2);
                    if (importance1 > importance2)
                    {
                        return(-1);
                    }
                    if (importance2 > importance1)
                    {
                        return(1);
                    }
                    return(0);
                };
                prioritizedRequirements.Sort(byPriority);
            }

            // Now go through our prioritized profession requirements and try to find
            // an empty slot (and available unassigned crew member) to satisfy each one.
            foreach (string requiredProfession in prioritizedRequirements)
            {
                ModuleCrewRequirement requirement = requirements[requiredProfession];
                string          part = Logging.ToString(requirement.part);
                ProtoCrewMember highest;
                ProtoCrewMember lowest;
                if (FindHighestLowestAvailable(requiredProfession, requirement.minimumLevel, crewables, out highest, out lowest))
                {
                    // Got a crew member to fulfill the requirement. In the case of pilots,
                    // we want the lowest-level possible (to leave the highest freed up to
                    // satisfy SAS requirements for other ships). But for anyone else, we
                    // want the highest available.
                    ProtoCrewMember crew = PILOT_PROFESSION.Equals(requiredProfession) ? lowest : highest;
                    // Is there a command slot available?
                    CrewSlot slot = Crewable.FindEmptySlot(crewables.Command);
                    if (slot == null)
                    {
                        // okay then, how about a non-command slot?
                        slot = Crewable.FindEmptySlot(crewables.All);
                    }
                    if (slot == null)
                    {
                        Logging.Warn("No open slot is available to assign a " + requirement.Description + " to operate " + part);
                    }
                    else
                    {
                        slot.Occupant = crew;
                        Logging.Log("Assigning " + Logging.ToString(crew) + " to operate " + part);
                    }
                }
                else
                {
                    // there's nobody to fill the slot
                    Logging.Warn("No " + requirement.Description + " is available to operate " + part + ", not assigning anyone");
                }
            } // for each required profession
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Here when we need to make a pass through the ship and assign kerbals everywhere.
        /// </summary>
        /// <param name="construct"></param>
        public static CrewableList AssignKerbals(ShipConstruct construct)
        {
            // Find what we need to crew
            CrewableList crewables = new CrewableList(construct);

            // Clear out any prior assignments
            crewables.ClearAssignments();

            int iteration      = 0;
            int iterationLimit = 10;

            while (crewables.NeedsCrew && (iteration < iterationLimit))
            {
                // Fill out all slots that specify a kerbal by name. This takes
                // priority over everything else, since these represent conscious choices by the player.
                Logging.Log("<Assigning kerbals by name>");
                AssignKerbalsByName(crewables.All);
                if (!crewables.NeedsCrew)
                {
                    break;
                }

                // Make sure we have SAS (assign a pilot if necessary).
                Logging.Log("<Ensuring SAS>");
                int sasLevel = TryEnsureSAS(construct, crewables);
                if (!crewables.NeedsCrew)
                {
                    break;
                }

                // Fill out all command module slots that specify a kerbal by profession.
                Logging.Log("<Assigning kerbals to command modules by profession>");
                AssignKerbalsByProfession(crewables.Command, sasLevel);
                if (!crewables.NeedsCrew)
                {
                    break;
                }

                // Fill all remaining slots that specify a kerbal by profession.
                Logging.Log("<Assigning kerbals to all modules by profession>");
                AssignKerbalsByProfession(crewables.All, int.MaxValue); // pretend like we have infinite SAS so it will pick low-level pilots
                if (!crewables.NeedsCrew)
                {
                    break;
                }

                // Add any crew that we need to fulfill requirements of various parts.
                Logging.Log("<Fulfilling part requirements>");
                FulfillPartRequirements(crewables, construct);
                if (!crewables.NeedsCrew)
                {
                    break;
                }

                // Fill all remaining command slots that want a warm body
                Logging.Log("<Assigning any kerbals to command modules>");
                AssignAnyKerbals(crewables.Command);
                if (!crewables.NeedsCrew)
                {
                    break;
                }

                // And everything else
                Logging.Log("<Assigning any kerbals to all modules>");
                AssignAnyKerbals(crewables.All);
                if (!crewables.NeedsCrew)
                {
                    break;
                }

                ++iteration;
            }
            if (iteration >= iterationLimit)
            {
                Logging.Error("Runaway crew assignment hit iteration limit");
            }

            // Count 'em up
            int slotCount     = 0;
            int assignedCount = 0;

            foreach (Crewable crewable in crewables.All)
            {
                foreach (CrewSlot slot in crewable.Slots)
                {
                    ++slotCount;
                    if (slot.Occupant != null)
                    {
                        ++assignedCount;
                    }
                }
            }
            int emptySlots = slotCount - assignedCount;

            Logging.Log("Crew assignment complete. Assigned " + assignedCount + " kerbals, left " + emptySlots + " slots empty.");
            return(crewables);
        }