public bool MeetsStudentReqs(ProtoCrewMember student) { if (!((student.type == (ProtoCrewMember.KerbalType.Crew) && (seatMax <= 0 || Students.Count < seatMax) && !student.inactive && student.rosterStatus == ProtoCrewMember.RosterStatus.Available && student.experienceLevel >= minLevel && student.experienceLevel <= maxLevel && (classes.Length == 0 || classes.Contains(student.trait)) && !Students.Contains(student)))) { return(false); } int pCount = preReqs.GetLength(0); int pACount = preReqsAny.GetLength(0); int cCount = conflicts.GetLength(0); if (pCount > 0 || cCount > 0 || pACount > 0) { for (int i = pCount; i-- > 0;) { pChecker[i] = true; } int needCount = pCount; bool needAnyStill = pACount > 0; for (int entryIdx = student.careerLog.Count; entryIdx-- > 0 && (needCount > 0 || cCount > 0 || needAnyStill);) { FlightLog.Entry e = student.careerLog.Entries[entryIdx]; string tgt = string.IsNullOrEmpty(e.target) ? string.Empty : e.target; for (int preIdx = pCount; preIdx-- > 0 && needCount > 0;) { if (pChecker[preIdx] && (e.type == preReqs[preIdx, 0] && tgt == preReqs[preIdx, 1])) { pChecker[preIdx] = false; --needCount; } } for (int anyIdx = pACount; anyIdx-- > 0 && needAnyStill;) { if (e.type == preReqsAny[anyIdx, 0] && tgt == preReqsAny[anyIdx, 1]) { needAnyStill = false; } } for (int conIdx = cCount; conIdx-- > 0;) { if (e.type == conflicts[conIdx, 0] && tgt == conflicts[conIdx, 1]) { return(false); } } } if (needCount > 0 || needAnyStill) { return(false); } } return(true); }
public void CompleteCourse() { //assign rewards to all kerbals and set them to free if (Completed) { foreach (ProtoCrewMember student in Students) { if (student == null) { continue; } if (ExpireLog != null) { foreach (ConfigNode.Value v in ExpireLog.values) { for (int i = student.careerLog.Count; i-- > 0;) { FlightLog.Entry e = student.careerLog.Entries[i]; if (CrewHandler.TrainingExpiration.Compare(v.value, e)) { e.type = "expired_" + e.type; CrewHandler.Instance.RemoveExpiration(student.name, v.value); break; } } } } if (RewardLog != null) { if (student.flightLog.Count > 0) { student.ArchiveFlightLog(); } CrewHandler.TrainingExpiration exp = null; if (expiration > 0d) { exp = new CrewHandler.TrainingExpiration(); exp.pcmName = student.name; exp.expiration = expiration; if (expirationUseStupid) { exp.expiration *= UtilMath.Lerp(CrewHandler.Instance.settings.trainingProficiencyStupidMin, CrewHandler.Instance.settings.trainingProficiencyStupidMax, student.stupidity); } exp.expiration += Planetarium.GetUniversalTime(); } bool prevMissionsAlreadyExpired = false; foreach (ConfigNode.Value v in RewardLog.values) { string[] s = v.value.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); string trainingType = s[0]; string trainingTarget = s.Length == 1 ? null : s[1]; if (!prevMissionsAlreadyExpired && trainingType == "TRAINING_mission") { // Expire any previous mission trainings because only 1 should be active at a time for (int i = student.careerLog.Count; i-- > 0;) { FlightLog.Entry e = student.careerLog.Entries[i]; if (e.type == "TRAINING_mission") { e.type = "expired_" + e.type; CrewHandler.Instance.RemoveExpiration(student.name, v.value); student.ArchiveFlightLog(); prevMissionsAlreadyExpired = true; } } } student.flightLog.AddEntry(trainingType, trainingTarget); student.ArchiveFlightLog(); if (expiration > 0d) { exp.entries.Add(v.value); } } if (expiration > 0d) { CrewHandler.Instance.AddExpiration(exp); } } if (rewardXP != 0) { student.ExtraExperience += rewardXP; } } } foreach (ProtoCrewMember student in Students) { student.inactive = false; } //fire an event }
public bool Compare(int idx, FlightLog.Entry e) { return(Compare(entries[idx], e)); }
public void Update() { if (HighLogic.CurrentGame == null || HighLogic.CurrentGame.CrewRoster == null) { return; } // Catch earlies if (firstLoad) { firstLoad = false; List <string> newHires = new List <string>(); foreach (ProtoCrewMember pcm in HighLogic.CurrentGame.CrewRoster.Crew) { if ((pcm.rosterStatus == ProtoCrewMember.RosterStatus.Assigned || pcm.rosterStatus == ProtoCrewMember.RosterStatus.Available) && !kerbalRetireTimes.ContainsKey(pcm.name)) { newHires.Add(pcm.name); OnCrewHired(pcm, int.MinValue); } } if (newHires.Count > 0) { string msgStr = "Crew will retire as follows:"; foreach (string s in newHires) { msgStr += "\n" + s + ", no earlier than " + KSPUtil.PrintDate(kerbalRetireTimes[s], false); } PopupDialog.SpawnPopupDialog(new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), "InitialRetirementDateNotification", "Initial Retirement Date", msgStr + "\n(Retirement will be delayed the more intersting flights they fly.)", "OK", false, HighLogic.UISkin); } } // Retirements double time = Planetarium.GetUniversalTime(); if (nextUpdate < time) { nextUpdate = time + updateInterval; foreach (KeyValuePair <string, double> kvp in kerbalRetireTimes) { ProtoCrewMember pcm = HighLogic.CurrentGame.CrewRoster[kvp.Key]; if (pcm == null) { toRemove.Add(kvp.Key); } else { if (pcm.rosterStatus != ProtoCrewMember.RosterStatus.Available) { if (pcm.rosterStatus != ProtoCrewMember.RosterStatus.Assigned) { toRemove.Add(kvp.Key); } continue; } if (pcm.inactive) { continue; } if (time > kvp.Value) { toRemove.Add(kvp.Key); retirees.Add(kvp.Key); pcm.rosterStatus = ProtoCrewMember.RosterStatus.Dead; } } } for (int i = ActiveCourses.Count; i-- > 0;) { ActiveCourse course = ActiveCourses[i]; if (course.ProgressTime(time)) //returns true when the course completes { ActiveCourses.RemoveAt(i); } } for (int i = expireTimes.Count; i-- > 0;) { TrainingExpiration e = expireTimes[i]; if (time > e.expiration) { ProtoCrewMember pcm = HighLogic.CurrentGame.CrewRoster[e.pcmName]; if (pcm != null) { for (int j = pcm.careerLog.Entries.Count; j-- > 0;) { int eC = e.entries.Count; if (eC == 0) { break; } FlightLog.Entry ent = pcm.careerLog[j]; for (int k = eC; k-- > 0;) { if (e.Compare(k, ent)) { ScreenMessages.PostScreenMessage(pcm.name + ": Expired: " + GetPrettyCourseName(ent.type) + ent.target); ent.type = "expired_" + ent.type; e.entries.RemoveAt(k); } } } } expireTimes.RemoveAt(i); } } // TODO remove from courses? Except I think they won't retire if inactive either so that's ok. if (toRemove.Count > 0) { string msgStr = string.Empty; foreach (string s in toRemove) { kerbalRetireTimes.Remove(s); if (HighLogic.CurrentGame.CrewRoster[s] != null) { msgStr += "\n" + s; } } if (!string.IsNullOrEmpty(msgStr)) { PopupDialog.SpawnPopupDialog(new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), "CrewRetirementNotification", "Crew Retirement", "The following retirements have occurred:\n" + msgStr, "OK", true, HighLogic.UISkin); } toRemove.Clear(); } } // UI fixing if (inAC) { if (astronautComplex == null) { KSP.UI.Screens.AstronautComplex[] mbs = GameObject.FindObjectsOfType <KSP.UI.Screens.AstronautComplex>(); int maxCount = -1; foreach (KSP.UI.Screens.AstronautComplex c in mbs) { int count = c.ScrollListApplicants.Count + c.ScrollListAssigned.Count + c.ScrollListAvailable.Count + c.ScrollListKia.Count; if (count > maxCount) { maxCount = count; astronautComplex = c; } } if (astronautComplex == null) { return; } } int newAv = astronautComplex.ScrollListAvailable.Count; int newAsgn = astronautComplex.ScrollListAssigned.Count; int newKIA = astronautComplex.ScrollListKia.Count; if (newAv != countAvailable || newKIA != countKIA || newAsgn != countAssigned) { countAvailable = newAv; countAssigned = newAsgn; countKIA = newKIA; foreach (KSP.UI.UIListData <KSP.UI.UIListItem> u in astronautComplex.ScrollListAvailable) { KSP.UI.CrewListItem cli = u.listItem.GetComponent <KSP.UI.CrewListItem>(); if (cli != null) { FixTooltip(cli); if (cli.GetCrewRef().inactive) { cli.MouseoverEnabled = false; bool notTraining = true; for (int i = ActiveCourses.Count; i-- > 0 && notTraining;) { foreach (ProtoCrewMember pcm in ActiveCourses[i].Students) { if (pcm == cli.GetCrewRef()) { notTraining = false; cli.SetLabel("Training, done " + KSPUtil.PrintDate(ActiveCourses[i].startTime + ActiveCourses[i].GetTime(ActiveCourses[i].Students), false)); break; } } } if (notTraining) { cli.SetLabel("Recovering"); } } } } foreach (KSP.UI.UIListData <KSP.UI.UIListItem> u in astronautComplex.ScrollListAssigned) { KSP.UI.CrewListItem cli = u.listItem.GetComponent <KSP.UI.CrewListItem>(); if (cli != null) { FixTooltip(cli); } } foreach (KSP.UI.UIListData <KSP.UI.UIListItem> u in astronautComplex.ScrollListKia) { KSP.UI.CrewListItem cli = u.listItem.GetComponent <KSP.UI.CrewListItem>(); if (cli != null) { if (retirees.Contains(cli.GetName())) { cli.SetLabel("Retired"); cli.MouseoverEnabled = false; } } } } } }
//This recovers Kerbals on the Stage, returning the list of their names private List<ProtoCrewMember> RecoverKerbals() { List<ProtoCrewMember> kerbals = new List<ProtoCrewMember>(); if (KerbalsOnboard.Count > 0) { //We've already removed the Kerbals, now we recover them kerbals = KerbalsOnboard; Debug.Log("[SR] Found pre-recovered Kerbals"); } else { //Recover the kerbals and get their names foreach (ProtoCrewMember pcm in vessel.protoVessel.GetVesselCrew()) { //Yeah, that's all it takes to recover a kerbal. Set them to Available from Assigned /* if (recovered && Settings.Instance.RecoverKerbals) { pcm.rosterStatus = ProtoCrewMember.RosterStatus.Available; //remove the Kerbal from the vessel ProtoPartSnapshot crewedPart = vessel.protoVessel.protoPartSnapshots.Find(p => p.HasCrew(pcm.name)); if (crewedPart != null) crewedPart.RemoveCrew(pcm.name); else Debug.Log("[SR] Can't find the part housing " + pcm.name); }*/ kerbals.Add(pcm); } } if (kerbals.Count > 0 && Settings.Instance.RecoverKerbals && recovered) { foreach (ProtoCrewMember pcm in kerbals) { Debug.Log("[SR] Recovering " + pcm.name); pcm.rosterStatus = ProtoCrewMember.RosterStatus.Available; //Way to go Squad, you now kill Kerbals TWICE instead of only once. bool TwoDeathEntries = (pcm.careerLog.Entries.Count > 1 && pcm.careerLog.Entries[pcm.careerLog.Entries.Count - 1].type == "Die" && pcm.careerLog.Entries[pcm.careerLog.Entries.Count - 2].type == "Die"); if (TwoDeathEntries) { Debug.Log("[SR] Squad has decided to kill " + pcm.name + " not once, but TWICE!"); FlightLog.Entry deathEntry0 = pcm.careerLog.Entries[pcm.careerLog.Entries.Count - 1];//pcm.careerLog.Entries.Find(e => e.type == "Die"); if (deathEntry0 != null && deathEntry0.type == "Die") { pcm.careerLog.Entries.Remove(deathEntry0); } FlightLog.Entry deathEntry = pcm.careerLog.Entries[pcm.careerLog.Entries.Count - 1]; if (deathEntry != null && deathEntry.type == "Die") { Debug.Log("[SR] Recovered kerbal registered as dead. Attempting to repair."); int flightNum = deathEntry.flight; pcm.careerLog.Entries.Remove(deathEntry); FlightLog.Entry landing = new FlightLog.Entry(flightNum, FlightLog.EntryType.Land, Planetarium.fetch.Home.bodyName); FlightLog.Entry recovery = new FlightLog.Entry(flightNum, FlightLog.EntryType.Recover); pcm.careerLog.AddEntry(landing); pcm.careerLog.AddEntry(recovery); } } else if (pcm.careerLog.Entries.Count > 0 && pcm.careerLog.Entries[pcm.careerLog.Entries.Count - 1].type == "Die") { Debug.Log("[SR] Squad has been gracious and has only killed " + pcm.name + " once, instead of twice."); FlightLog.Entry deathEntry = pcm.careerLog.Entries[pcm.careerLog.Entries.Count - 1]; if (deathEntry != null && deathEntry.type == "Die") { Debug.Log("[SR] Recovered kerbal registered as dead. Attempting to repair."); int flightNum = deathEntry.flight; pcm.careerLog.Entries.Remove(deathEntry); FlightLog.Entry landing = new FlightLog.Entry(flightNum, FlightLog.EntryType.Land, Planetarium.fetch.Home.bodyName); FlightLog.Entry recovery = new FlightLog.Entry(flightNum, FlightLog.EntryType.Recover); pcm.careerLog.AddEntry(landing); pcm.careerLog.AddEntry(recovery); } } else { Debug.Log("[SR] No death entry added, but we'll add a successful recovery anyway."); pcm.flightLog.AddEntry(FlightLog.EntryType.Land, Planetarium.fetch.Home.bodyName); pcm.flightLog.AddEntry(FlightLog.EntryType.Recover); pcm.ArchiveFlightLog(); } } } else if (KerbalsOnboard.Count > 0 && (!Settings.Instance.RecoverKerbals || !recovered)) { //kill the kerbals instead //Don't kill them twice foreach (ProtoCrewMember pcm in kerbals) { if (pcm.rosterStatus != ProtoCrewMember.RosterStatus.Dead && pcm.rosterStatus != ProtoCrewMember.RosterStatus.Missing) { pcm.rosterStatus = ProtoCrewMember.RosterStatus.Dead; pcm.Die(); } } } return kerbals; }
public static bool CheckCrewForPart(ProtoCrewMember pcm, string partName) { // lolwut. But just in case. if (pcm == null) { return(false); } bool requireTraining = HighLogic.CurrentGame.Parameters.CustomParams <RP0Settings>().IsTrainingEnabled; if (!requireTraining || EntryCostStorage.GetCost(partName) == 1) { return(true); } partName = Crew.TrainingDatabase.SynonymReplace(partName); FlightLog.Entry ent = pcm.careerLog.Last(); if (ent == null) { return(false); } int lastFlight = ent.flight; bool lacksMission = true; for (int i = pcm.careerLog.Entries.Count; i-- > 0;) { FlightLog.Entry e = pcm.careerLog.Entries[i]; if (lacksMission) { if (e.flight < lastFlight) { return(false); } if (string.IsNullOrEmpty(e.type) || string.IsNullOrEmpty(e.target)) { continue; } if (e.type == "TRAINING_mission" && e.target == partName) { lacksMission = false; } } else { if (string.IsNullOrEmpty(e.type) || string.IsNullOrEmpty(e.target)) { continue; } if (e.type == "TRAINING_proficiency" && e.target == partName) { return(true); } } } return(false); }