Ejemplo n.º 1
0
        /* Returns time at which this course will complete */
        public double CompletionTime()
        {
            double start, length;

            if (Started)
            {
                start = startTime;
            }
            else
            {
                start = KSPUtils.GetUT();
            }
            length = GetTime();
            return(start + length);
        }
Ejemplo n.º 2
0
        public bool NautHasTrainingForPart(ProtoCrewMember pcm, string partName)
        {
            TrainingDatabase.SynonymReplace(partName, out partName);

            FlightLog.Entry ent = pcm.careerLog.Last();
            if (ent == null)
            {
                return(false);
            }

            bool lacksMission = IsMissionTrainingEnabled;

            for (int i = pcm.careerLog.Entries.Count; i-- > 0;)
            {
                FlightLog.Entry e = pcm.careerLog.Entries[i];
                if (lacksMission)
                {
                    if (string.IsNullOrEmpty(e.type) || string.IsNullOrEmpty(e.target))
                    {
                        continue;
                    }

                    if (e.type == TrainingType_Mission && e.target == partName)
                    {
                        double exp = GetExpiration(pcm.name, e);
                        lacksMission = exp == 0d || exp < KSPUtils.GetUT();
                    }
                }
                else
                {
                    if (string.IsNullOrEmpty(e.type) || string.IsNullOrEmpty(e.target))
                    {
                        continue;
                    }

                    if (e.type == TrainingType_Proficiency && e.target == partName)
                    {
                        return(true);
                    }
                }
            }
            return(false);
        }
Ejemplo n.º 3
0
        public void Start()
        {
            double ut = KSPUtils.GetUT();

            if (NextUpdate > ut + UpdateInterval)
            {
                // KRASH has a bad habit of not reverting state properly when exiting sims.
                // This means that the updateInterval could end up years into the future.
                NextUpdate = ut + 5;
            }

            onKctTechQueuedEvent = GameEvents.FindEvent <EventData <RDTech> >("OnKctTechQueued");
            if (onKctTechQueuedEvent != null)
            {
                onKctTechQueuedEvent.Add(AddCoursesForTechNode);
            }

            StartCoroutine(CreateCoursesRoutine());
            StartCoroutine(EnsureActiveCrewInSimulationRoutine());
        }
Ejemplo n.º 4
0
        public void Update()
        {
            if (HighLogic.CurrentGame == null || HighLogic.CurrentGame.CrewRoster == null)
            {
                return;
            }

            if (_isFirstLoad)
            {
                _isFirstLoad = false;
                ProcessFirstLoad();
            }

            if (HighLogic.LoadedSceneIsFlight && _flightLogUpdateCounter++ >= FlightLogUpdateInterval)
            {
                _flightLogUpdateCounter = 0;
                UpdateFlightLog();
            }

            double time = KSPUtils.GetUT();

            if (NextUpdate < time)
            {
                // Ensure that CrewHandler updates happen at predictable times so that accurate KAC alarms can be set.
                do
                {
                    NextUpdate += UpdateInterval;
                }while (NextUpdate < time);

                ProcessRetirements(time);
                ProcessCourses(time);
            }

            if (_inAC)
            {
                FixAstronauComplexUI();
            }
        }
Ejemplo n.º 5
0
        private void VesselRecoveryProcessing(ProtoVessel v, MissionRecoveryDialog mrDialog, float data)
        {
            Debug.Log("[RP-0] - Vessel recovery processing");

            var retirementChanges = new List <string>();
            var inactivity        = new List <string>();

            double UT = KSPUtils.GetUT();

            // normally we would use v.missionTime, but that doesn't seem to update
            // when you're not actually controlling the vessel
            double elapsedTime = UT - v.launchTime;

            Debug.Log($"[RP-0] mission elapsedTime: {KSPUtil.PrintDateDeltaCompact(elapsedTime, true, true)}");

            // When flight duration was too short, mission training should not be set as expired.
            // This can happen when an on-the-pad failure occurs and the vessel is recovered.
            // We could perhaps override this if they're not actually in flight
            // (if the user didn't recover right from the pad I think this is a fair assumption)
            if (elapsedTime < Settings.minFlightDurationSecondsForTrainingExpire)
            {
                Debug.Log($"[RP-0] - mission time too short for crew to be inactive (elapsed time was {elapsedTime}, settings set for {Settings.minFlightDurationSecondsForTrainingExpire})");
                return;
            }

            var validStatuses = new List <string>
            {
                FlightLog.EntryType.Flight.ToString(), Situation_FlightHigh, FlightLog.EntryType.Suborbit.ToString(),
                FlightLog.EntryType.Orbit.ToString(), FlightLog.EntryType.ExitVessel.ToString(),
                FlightLog.EntryType.Land.ToString(), FlightLog.EntryType.Flyby.ToString()
            };

            foreach (ProtoCrewMember pcm in v.GetVesselCrew())
            {
                Debug.Log("[RP-0] - Found ProtoCrewMember: " + pcm.displayName);

                var    allFlightsDict = new Dictionary <string, int>();
                int    curFlight      = pcm.careerLog.Last().flight;
                double inactivityMult = 0;
                double retirementMult = 0;

                foreach (FlightLog.Entry e in pcm.careerLog.Entries)
                {
                    if (e.type == "Nationality")
                    {
                        continue;
                    }
                    if (e.type == TrainingType_Mission)
                    {
                        SetExpiration(pcm.name, e, KSPUtils.GetUT());
                    }

                    if (validStatuses.Contains(e.type))
                    {
                        int situationCount;
                        var key = $"{e.target}-{e.type}";
                        if (allFlightsDict.ContainsKey(key))
                        {
                            situationCount      = allFlightsDict[key];
                            allFlightsDict[key] = ++situationCount;
                        }
                        else
                        {
                            situationCount = 1;
                            allFlightsDict.Add(key, situationCount);
                        }

                        if (e.flight != curFlight)
                        {
                            continue;
                        }

                        if (TryGetBestSituationMatch(e.target, e.type, "Retire", out double situationMult))
                        {
                            double countMult = 1 + Math.Pow(situationCount - 1, Settings.retireOffsetFlightNumPow);
                            retirementMult += situationMult / countMult;
                        }

                        if (TryGetBestSituationMatch(e.target, e.type, "Inactive", out double inactivMult))
                        {
                            inactivityMult += inactivMult;
                        }
                    }
                }

                Debug.Log("[RP-0]  retirementMult: " + retirementMult);
                Debug.Log("[RP-0]  inactivityMult: " + inactivityMult);

                double acMult = ScenarioUpgradeableFacilities.GetFacilityLevel(SpaceCenterFacility.AstronautComplex) + 1;
                Debug.Log("[RP-0]  AC multiplier: " + acMult);

                if (KerbalRetireTimes.TryGetValue(pcm.name, out double retTime))
                {
                    double stupidityPenalty = UtilMath.Lerp(Settings.retireOffsetStupidMin, Settings.retireOffsetStupidMax, pcm.stupidity);
                    Debug.Log($"[RP-0]  stupidityPenalty for {pcm.stupidity}: {stupidityPenalty}");
                    double retireOffset = retirementMult * 86400 * Settings.retireOffsetBaseMult / stupidityPenalty;

                    if (retireOffset > 0)
                    {
                        KerbalRetireIncreases.TryGetValue(pcm.name, out double retIncreaseTotal);
                        retIncreaseTotal += retireOffset;
                        if (retIncreaseTotal > Settings.retireIncreaseCap)
                        {
                            // Cap the total retirement increase at a specific number of years
                            retireOffset    -= retIncreaseTotal - Settings.retireIncreaseCap;
                            retIncreaseTotal = Settings.retireIncreaseCap;
                        }
                        KerbalRetireIncreases[pcm.name] = retIncreaseTotal;

                        string sRetireOffset = KSPUtil.PrintDateDelta(retireOffset, false, false);
                        Debug.Log("[RP-0] retire date increased by: " + sRetireOffset);

                        retTime += retireOffset;
                        KerbalRetireTimes[pcm.name] = retTime;
                        retirementChanges.Add($"\n{pcm.name}, +{sRetireOffset}, no earlier than {KSPUtil.PrintDate(retTime, false)}");
                    }
                }

                inactivityMult = Math.Max(1, inactivityMult);
                double elapsedTimeDays  = elapsedTime / 86400;
                double inactiveTimeDays = Math.Pow(Math.Max(Settings.inactivityMinFlightDurationDays, elapsedTimeDays), Settings.inactivityFlightDurationExponent) *
                                          Math.Min(Settings.inactivityMaxSituationMult, inactivityMult) / acMult;
                double inactiveTime = inactiveTimeDays * 86400;
                Debug.Log("[RP-0] inactive for: " + KSPUtil.PrintDateDeltaCompact(inactiveTime, true, false));

                pcm.SetInactive(inactiveTime, false);
                inactivity.Add($"\n{pcm.name}, until {KSPUtil.PrintDate(inactiveTime + UT, true, false)}");
            }

            if (inactivity.Count > 0)
            {
                StringBuilder sb = new StringBuilder();
                sb.Append("The following crew members will be on leave:");
                foreach (string s in inactivity)
                {
                    sb.Append(s);
                }

                if (RetirementEnabled && retirementChanges.Count > 0)
                {
                    sb.Append("\n\nThe following retirement changes have occurred:");
                    foreach (string s in retirementChanges)
                    {
                        sb.Append(s);
                    }
                }

                PopupDialog.SpawnPopupDialog(new Vector2(0.5f, 0.5f),
                                             new Vector2(0.5f, 0.5f),
                                             "CrewUpdateNotification",
                                             "Crew Updates",
                                             sb.ToString(),
                                             "OK",
                                             true,
                                             HighLogic.UISkin);
            }
        }
Ejemplo n.º 6
0
        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 (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();
                        }

                        TrainingExpiration exp = null;
                        if (expiration > 0d)
                        {
                            exp            = new TrainingExpiration();
                            exp.PcmName    = student.name;
                            exp.Expiration = expiration;
                            if (expirationUseStupid)
                            {
                                exp.Expiration *= UtilMath.Lerp(CrewHandler.Settings.trainingProficiencyStupidMin,
                                                                CrewHandler.Settings.trainingProficiencyStupidMax,
                                                                student.stupidity);
                            }
                            exp.Expiration += KSPUtils.GetUT();
                        }

                        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 == CrewHandler.TrainingType_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 == CrewHandler.TrainingType_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
        }