Example #1
0
        /// <summary>
        /// soft filter: run on ALL vessels that pass the hard filter (CouldBeCandidate),
        /// determine if the vessel currently meets the condition (i.e. currently over location or not)
        /// </summary>
        /// <param name="label">label to add to this vessel in the status display</param>
        private bool VesselMeetsCondition(Vessel vessel, bool doUpdateLabel, out string label)
        {
            label = string.Empty;
            bool result = true;

            if (!allowUnpowered)
            {
                var powered = API.ResourceAmount(vessel, "ElectricCharge") > 0.01;
                if (!powered)
                {
                    if (doUpdateLabel)
                    {
                        label = Lib.Color("No Electricity", Lib.Kolor.Red);
                    }
                    return(false);
                }
            }

            foreach (var sp in subRequirementParameters)
            {
                if (sp.subRequirement == null)
                {
                    continue;
                }

                var state = sp.subRequirement.VesselMeetsCondition(vessel, context);
                result &= state.requirementMet;

                if (doUpdateLabel)
                {
                    var vesselLabel = sp.subRequirement.GetLabel(vessel, context, state);
                    if (!string.IsNullOrEmpty(vesselLabel))
                    {
                        if (string.IsNullOrEmpty(label))
                        {
                            label = " - " + vesselLabel;
                        }
                        else
                        {
                            label += "\n - " + vesselLabel;
                        }
                    }
                }
            }

            return(result);
        }
        internal override bool VesselsMeetCondition(List <Vessel> vessels, EvaluationContext context, out string statusLabel)
        {
            if (minSurface == 0 ||  vessels.Count == 0)
            {
                statusLabel = string.Empty;
                return(vessels.Count > 0);
            }

            Vector3d bodyPosition = context.BodyPosition(context.targetBody);

            double visible         = 100.0 * BodySurfaceObservation.VisibleSurface(vessels, context, bodyPosition, minElevation, Surfaces());
            string observedPercStr = Lib.HumanReadablePerc(visible / 100.0) + " / " + Lib.HumanReadablePerc(minSurface / 100.0);

            observedPercStr = Lib.Color(observedPercStr, visible > minSurface ? Lib.Kolor.Green : Lib.Kolor.Red);
            statusLabel     = Localizer.Format("#KerCon_XofSurfaceObserved", observedPercStr);
            return(visible > minSurface);
        }
Example #3
0
        internal override bool VesselsMeetCondition(List <Vessel> vessels, EvaluationContext context, out string statusLabel)
        {
            if (minSurface == 0 ||  vessels.Count == 0)
            {
                statusLabel = string.Empty;
                return(vessels.Count > 0);
            }

            double visible;
            double R = context.targetBody.Radius;

            if (vessels.Count == 1)
            {
                Vessel vessel = vessels[0];
                double a      = context.Altitude(vessel, context.targetBody);
                visible = 100.0 * a / (2 * (a + R));
            }
            else
            {
                ResetVisibleSurfaces();

                Vector3d bodyPosition = context.BodyPosition(context.targetBody);
                foreach (Vessel v in vessels)
                {
                    Vector3d vesselPosition = context.VesselPosition(v);
                    Vector3d viewDirection  = (vesselPosition - bodyPosition);

                    double a = R;
                    double b = R + context.Altitude(v, context.targetBody);
                    double c = Math.Sqrt(a * a + b * b);
                    double α = Math.Asin(b / c) * 180.0 / Math.PI;

                    MarkVisibleSurfaces(viewDirection.normalized, α);
                }

                visible = 100.0 * visibleSurfaces / (double)surfaces.Count;
            }

            string observedPercStr = Lib.HumanReadablePerc(visible / 100.0) + " / " + Lib.HumanReadablePerc(minSurface / 100.0);

            observedPercStr = Lib.Color(observedPercStr, visible > minSurface ? Lib.Kolor.Green : Lib.Kolor.Red);
            statusLabel     = Localizer.Format("<<1>> of surface observed", observedPercStr);
            return(visible > minSurface);
        }
        private static void ShowMessage(CelestialBody body, bool wasVisible, bool visible, RadiationFieldType field)
        {
            if (visible && !wasVisible)
            {
                StringBuilder sb      = new StringBuilder(256);
                string        message = Localizer.Format("#KerCon_FieldXofYresearched",          // <<1>>: <<2>> researched
                                                         Lib.Bold(body.bodyName), Lib.Color(RadiationField.Name(field), Lib.Kolor.Science));
                sb.Append(message);
                sb.Append("\n\n");
                sb.Append(Localizer.Format("#KerCon_FieldResearchedMessage"));

                var bd = Instance.BodyData(body);

                API.Message(sb.ToString());

                MessageSystem.Message m = new MessageSystem.Message("#KerCon_FieldResearched", sb.ToString(), MessageSystemButton.MessageButtonColor.GREEN, MessageSystemButton.ButtonIcons.ACHIEVE);
                MessageSystem.Instance.AddMessage(m);
            }
        }
Example #5
0
        ///<summary> Add habitat sub-panel, including tooltips </summary>
        private static void AddSubPanelHabitat(Panel p)
        {
            SimulatedResource atmo_res  = resource_sim.Resource("Atmosphere");
            SimulatedResource waste_res = resource_sim.Resource("WasteAtmosphere");

            // generate tooltips
            string atmo_tooltip  = atmo_res.Tooltip();
            string waste_tooltip = waste_res.Tooltip(true);

            // generate status string for scrubbing
            string waste_status = !Features.Poisoning                                        //< feature disabled
                          ? "n/a"
                          : waste_res.produced <= double.Epsilon                             //< unnecessary
                          ? Local.Planner_scrubbingunnecessary                               //"not required"
                          : waste_res.consumed <= double.Epsilon                             //< no scrubbing
                          ? Lib.Color(Local.Planner_noscrubbing, Lib.Kolor.Orange)           //"none"
                          : waste_res.produced > waste_res.consumed * 1.001                  //< insufficient scrubbing
                          ? Lib.Color(Local.Planner_insufficientscrubbing, Lib.Kolor.Yellow) //"inadequate"
                          : Lib.Color(Local.Planner_sufficientscrubbing, Lib.Kolor.Green);   //"good"                    //< sufficient scrubbing

            // generate status string for pressurization
            string atmo_status = !Features.Pressure                                                //< feature disabled
                          ? "n/a"
                          : atmo_res.consumed <= double.Epsilon                                    //< unnecessary
                          ? Local.Planner_pressurizationunnecessary                                //"not required"
                          : atmo_res.produced <= double.Epsilon                                    //< no pressure control
                          ? Lib.Color(Local.Planner_nopressurecontrol, Lib.Kolor.Orange)           //"none"
                          : atmo_res.consumed > atmo_res.produced * 1.001                          //< insufficient pressure control
                          ? Lib.Color(Local.Planner_insufficientpressurecontrol, Lib.Kolor.Yellow) //"inadequate"
                          : Lib.Color(Local.Planner_sufficientpressurecontrol, Lib.Kolor.Green);   //"good"                    //< sufficient pressure control

            p.AddSection(Local.Planner_HABITAT, string.Empty,                                      //"HABITAT"
                         () => { p.Prev(ref environment_index, panel_environment.Count); enforceUpdate = true; },
                         () => { p.Next(ref environment_index, panel_environment.Count); enforceUpdate = true; });
            p.AddContent(Local.Planner_volume, Lib.HumanReadableVolume(vessel_analyzer.volume), Local.Planner_volume_tip);                     //"volume""volume of enabled habitats"
            p.AddContent(Local.Planner_habitatssurface, Lib.HumanReadableSurface(vessel_analyzer.surface), Local.Planner_habitatssurface_tip); //"surface""surface of enabled habitats"
            p.AddContent(Local.Planner_scrubbing, waste_status, waste_tooltip);                                                                //"scrubbing"
            p.AddContent(Local.Planner_pressurization, atmo_status, atmo_tooltip);                                                             //"pressurization"
        }
        private static void RunningUpdate(Vessel v, VesselData vd, EquipmentData ed, ModuleKsmContractEquipment prefab, double elapsed_s)
        {
            double connectionRate = API.VesselConnectionRate(v);

            ed.state = GetState(v, vd, ed, prefab, connectionRate);

            bool running = ed.state == EquipmentState.nominal;

            if (running)
            {
                vd.ResHandler.ElectricCharge.Consume(prefab.RequiredEC * elapsed_s, EquipmentBroker);
            }

            KerbalismContracts.EquipmentStates.Update(v, prefab.id, ed.state);

            if (ed.loadedModule != null)
            {
                ed.loadedModule.UIState = Lib.BuildString("EC: ", Lib.HumanReadableRate(prefab.RequiredEC));
                if (prefab.RequiredBandwidth > 0)
                {
                    var color = Lib.Kolor.Green;

                    var rate = connectionRate / prefab.RequiredBandwidth;
                    if (rate <= 1.0)
                    {
                        color = Lib.Kolor.Red;
                    }
                    else if (rate <= 1.2)
                    {
                        color = Lib.Kolor.Orange;
                    }

                    ed.loadedModule.UIState += Lib.BuildString(", ",
                                                               Localizer.Format("#KerCon_DataRate", Lib.HumanReadableRate(prefab.RequiredBandwidth), Lib.Color(Lib.HumanReadableRate(connectionRate), color)));
                }
            }
        }
        protected override string GetTitle()
        {
            string result = "";
            double now    = Planetarium.GetUniversalTime();

            string remainingStr = durationType == DurationType.countdown
                                ? DurationUtil.StringValue(Math.Max(0, doneAfter - now))
                                : DurationUtil.StringValue(Math.Max(0, duration - accumulatedDuration));

            switch (durationState)
            {
            case DurationState.off:
                result = Localizer.Format("Duration: <<1>>", DurationUtil.StringValue(duration));
                if (waitDuration > 0)
                {
                    result += "\n\t - " + Localizer.Format("Time starts <<1>> after accepting the contract",
                                                           Lib.Color(DurationUtil.StringValue(waitDuration), Lib.Kolor.Yellow));
                }
                if (allowedDowntime > 0)
                {
                    result += "\n\t - " + Localizer.Format("Allows interruptions up to <<1>>",
                                                           DurationUtil.StringValue(allowedDowntime));
                }
                else
                {
                    result += "\n\t - " + "Does not allow interruptions";
                }
                if (!allowReset)
                {
                    result += "\n\t - " + Lib.Color("Will fail if interrupted beyond allowance", Lib.Kolor.Orange);
                }

                break;

            case DurationState.preRun:
                result  = Localizer.Format("Duration: <<1>>", DurationUtil.StringValue(duration));
                result += "\n\t - " + Localizer.Format("Time starts in <<1>>",
                                                       Lib.Color(DurationUtil.StringValue(Math.Max(0, startAfter - now)), Lib.Kolor.Yellow));
                if (allowedDowntime > 0)
                {
                    result += "\n\t - " + Localizer.Format("Allows interruptions up to <<1>>",
                                                           DurationUtil.StringValue(allowedDowntime));
                }

                break;

            case DurationState.running:
                result = Localizer.Format("Remaining: <<1>>", Lib.Color(remainingStr, Lib.Kolor.Green));
                if (allowedDowntime > 0)
                {
                    result += "\n\t - " + Localizer.Format("Allows interruptions up to <<1>>",
                                                           DurationUtil.StringValue(allowedDowntime));
                }

                break;

            case DurationState.preReset:
                result = Localizer.Format("Remaining: <<1>> (stop in: <<2>>)", Lib.Color(remainingStr, Lib.Kolor.Green),
                                          Lib.Color(DurationUtil.StringValue(Math.Max(0, failAfter - now)), allowReset ? Lib.Kolor.Yellow : Lib.Kolor.Red));

                break;

            case DurationState.done:
                result = "Done!";
                break;

            case DurationState.failed:
                result = "Time is up!";
                break;
            }

            titleTracker.Add(result);
            if (lastTitle != result && Root != null && (Root.ContractState == Contract.State.Active || Root.ContractState == Contract.State.Failed))
            {
                titleTracker.UpdateContractWindow(result);
                lastTitle = result;
            }
            return(result);
        }
Example #8
0
        ///<summary> Add reliability sub-panel, including tooltips </summary>
        private static void AddSubPanelReliability(Panel p)
        {
            // evaluate redundancy metric
            // - 0: no redundancy
            // - 0.5: all groups have 2 elements
            // - 1.0: all groups have 3 or more elements
            double redundancy_metric = 0.0;

            foreach (KeyValuePair <string, int> pair in vessel_analyzer.redundancy)
            {
                switch (pair.Value)
                {
                case 1:
                    break;

                case 2:
                    redundancy_metric += 0.5 / vessel_analyzer.redundancy.Count;
                    break;

                default:
                    redundancy_metric += 1.0 / vessel_analyzer.redundancy.Count;
                    break;
                }
            }

            // traduce the redundancy metric to string
            string redundancy_str = string.Empty;

            if (redundancy_metric <= 0.1)
            {
                redundancy_str = Local.Planner_none;                //"none"
            }
            else if (redundancy_metric <= 0.33)
            {
                redundancy_str = Local.Planner_poor;                //"poor"
            }
            else if (redundancy_metric <= 0.66)
            {
                redundancy_str = Local.Planner_okay;                //"okay"
            }
            else
            {
                redundancy_str = Local.Planner_great;                //"great"
            }
            // generate redundancy tooltip
            string redundancy_tooltip = string.Empty;

            if (vessel_analyzer.redundancy.Count > 0)
            {
                StringBuilder sb = new StringBuilder();
                foreach (KeyValuePair <string, int> pair in vessel_analyzer.redundancy)
                {
                    if (sb.Length > 0)
                    {
                        sb.Append("\n");
                    }
                    sb.Append(Lib.Color(pair.Value.ToString(), pair.Value == 1 ? Lib.Kolor.Red : pair.Value == 2 ? Lib.Kolor.Yellow : Lib.Kolor.Green, true));
                    sb.Append("\t");
                    sb.Append(pair.Key);
                }
                redundancy_tooltip = Lib.BuildString("<align=left />", sb.ToString());
            }

            // generate repair string and tooltip
            string repair_str     = Local.Planner_none;        //"none"
            string repair_tooltip = string.Empty;

            if (vessel_analyzer.crew_engineer)
            {
                repair_str     = "engineer";
                repair_tooltip = Local.Planner_engineer_tip;                //"The engineer on board should\nbe able to handle all repairs"
            }
            else if (vessel_analyzer.crew_capacity == 0)
            {
                repair_str     = "safemode";
                repair_tooltip = Local.Planner_safemode_tip;                //"We have a chance of repairing\nsome of the malfunctions remotely"
            }

            // render panel
            p.AddSection(Local.Planner_RELIABILITY, string.Empty,            //"RELIABILITY"
                         () => { p.Prev(ref special_index, panel_special.Count); enforceUpdate = true; },
                         () => { p.Next(ref special_index, panel_special.Count); enforceUpdate = true; });
            p.AddContent(Local.Planner_malfunctions, Lib.HumanReadableAmount(vessel_analyzer.failure_year, "/y"), Local.Planner_malfunctions_tip); //"malfunctions""average case estimate\nfor the whole vessel"
            p.AddContent(Local.Planner_highquality, Lib.HumanReadablePerc(vessel_analyzer.high_quality), Local.Planner_highquality_tip);           //"high quality""percentage of high quality components"
            p.AddContent(Local.Planner_redundancy, redundancy_str, redundancy_tooltip);                                                            //"redundancy"
            p.AddContent(Local.Planner_repair, repair_str, repair_tooltip);                                                                        //"repair"
        }
Example #9
0
        /// <summary>
        /// Shows the Network status, ControlPath, Signal strength
        /// </summary>
        public static void ConnMan(this Panel p, Vessel v)
        {
            // avoid corner-case when this is called in a lambda after scene changes
            v = FlightGlobals.FindVessel(v.id);

            // if vessel doesn't exist anymore, leave the panel empty
            if (v == null)
            {
                return;
            }

            VesselData vd = v.KerbalismData();

            // if not a valid vessel, leave the panel empty
            if (!vd.IsSimulated)
            {
                return;
            }

            // set metadata
            p.Title(Lib.BuildString(Lib.Ellipsis(v.vesselName, Styles.ScaleStringLength(40)), " ", Lib.Color("CONNECTION MANAGER", Lib.Kolor.LightGrey)));
            p.Width(Styles.ScaleWidthFloat(365.0f));
            p.paneltype = Panel.PanelType.connection;

            // time-out simulation
            if (!Lib.IsControlUnit(v) && p.Timeout(vd))
            {
                return;
            }

            // draw ControlPath section
            p.AddSection("CONTROL PATH");
            if (vd.Connection.linked)
            {
                if (vd.Connection.control_path != null)
                {
                    foreach (string[] hop in vd.Connection.control_path)
                    {
                        if (hop == null || hop.Length < 1)
                        {
                            continue;
                        }
                        string name    = hop[0];
                        string value   = hop.Length >= 2 ? hop[1] : "";
                        string tooltip = hop.Length >= 3 ? ("\n" + hop[2]) : "";
                        p.AddContent(name, value, tooltip);
                    }
                }
            }
            else
            {
                p.AddContent("<i>no connection</i>", string.Empty);
            }
        }
Example #10
0
        protected override string GetTitle()
        {
            InitStrings();

            string result = "";
            double now    = Planetarium.GetUniversalTime();

            string remainingStr = durationType == DurationType.countdown
                                ? DurationUtil.StringValue(Math.Max(0, doneAfter - now))
                                : DurationUtil.StringValue(Math.Max(0, duration - accumulatedDuration));

            switch (durationState)
            {
            case DurationState.off:
                result = KerCon_Duration_X;                         // Duration: <<1>>
                if (waitDuration > 0)
                {
                    result += "\n\t - " + KerCon_TimeStartsAfterAccepting;
                }
                if (allowedDowntime > 0)
                {
                    result += "\n\t - " + KerCon_AllowsInterruptionsUpTo;
                }
                else if (durationType == DurationType.accumulating)
                {
                    result += "\n\t - " + KerCon_AccumulatingDuration;
                }
                else
                {
                    result += "\n\t - " + KerCon_DoesNotAllowInterruptions;                             // Does not allow interruptions
                }
                if (!allowReset)
                {
                    result += "\n\t - " + KerCon_WillFailIfInterrupted;                             // Will fail if interrupted beyond allowance
                }
                break;

            case DurationState.preRun:
                result  = KerCon_Duration_X;                                   // Duration: <<1>>
                result += "\n\t - " + Localizer.Format("#KerCon_TimeStartsIn", // Time starts in <<1>>
                                                       Lib.Color(DurationUtil.StringValue(Math.Max(0, startAfter - now)), Lib.Kolor.Yellow));
                if (allowedDowntime > 0)
                {
                    result += "\n\t - " + KerCon_AllowsInterruptionsUpTo;
                }

                break;

            case DurationState.running:
                result = Localizer.Format("#KerCon_Reamining_X", Lib.Color(remainingStr, Lib.Kolor.Green));                         // Remaining: <<1>>
                //if (allowedDowntime > 0)
                //	result += "\n\t - " + Localizer.Format("#KerCon_AllowsInterruptionsUpTo", // Allows interruptions up to <<1>>
                //		DurationUtil.StringValue(allowedDowntime));

                break;

            case DurationState.preReset:
                result = Localizer.Format("#KerCon_Reamining_X_stopIn_Y", Lib.Color(remainingStr, Lib.Kolor.Green),                         // Remaining: <<1>> (stop in: <<2>>)
                                          Lib.Color(DurationUtil.StringValue(Math.Max(0, failAfter - now)), allowReset ? Lib.Kolor.Yellow : Lib.Kolor.Red));

                break;

            case DurationState.done:
                result = "#autoLOC_135144";                         // Success!!
                break;

            case DurationState.failed:
                result = "#KerCon_TimeIsUp";                         // Time is up!
                break;
            }

            if (result.StartsWith("#"))
            {
                result = Localizer.Format(result);
            }

            titleTracker.Add(result);
            if (lastTitle != result && Root != null && (Root.ContractState == Contract.State.Active || Root.ContractState == Contract.State.Failed))
            {
                titleTracker.UpdateContractWindow(result);
                lastTitle = result;
            }
            return(result);
        }
        internal override string GetLabel(Vessel vessel, EvaluationContext context, SubRequirementState state)
        {
            ExperimentRunningState runningState = (ExperimentRunningState)state;
            string label = runningState.experimentState == ExperimentState.running ? Lib.Color(Local.Generic_RUNNING, Lib.Kolor.Green) : Lib.Color(Local.Generic_STOPPED, Lib.Kolor.Red);

            if (!string.IsNullOrEmpty(shortDescription))
            {
                label = shortDescription + ": " + label;
            }
            return(label);
        }
        protected override void OnUpdate()
        {
            base.OnUpdate();
            if (ParameterCount == 0)
            {
                return;
            }
            if (state != ParameterState.Incomplete)
            {
                return;
            }

            if (!KerbalismContractsMain.KerbalismInitialized)
            {
                return;
            }

            if (lastUpdate == 0)
            {
                lastUpdate = Planetarium.GetUniversalTime();
                return;
            }

            bool childParameterChanged = false;

            if (subRequirementParameters.Count == 0)
            {
                childParameterChanged = true;
                CreateSubParameters();
            }

            var lastUpdateAge = Planetarium.GetUniversalTime() - lastUpdate;

            if (lastUpdateAge < 1.0)
            {
                return;
            }
            lastUpdate = Planetarium.GetUniversalTime();

            vessels.Clear();
            context = CreateContext(lastUpdateAge);

            foreach (var sp in subRequirementParameters)
            {
                sp.ResetContext(context);
            }

            foreach (Vessel vessel in FlightGlobals.Vessels)
            {
                if (!Utils.IsVessel(vessel))
                {
                    continue;
                }

                if (!CouldBeCandidate(vessel))
                {
                    continue;
                }

                if (arguments.requireElectricity && !API.IsPowered(vessel))
                {
                    if (!hideChildren)
                    {
                        childParameterChanged |= UpdateVesselStatus(vessel, Lib.Color("#KerCon_NoEC", Lib.Kolor.Red), false);                         // No EC
                    }
                    continue;
                }

                if (arguments.requireCommunication && !API.VesselConnectionLinked(vessel))
                {
                    if (!hideChildren)
                    {
                        childParameterChanged |= UpdateVesselStatus(vessel, Lib.Color("#KerCon_NoComms", Lib.Kolor.Red), false);                         // No Comms
                    }
                    continue;
                }

                vessels.Add(vessel);
            }

            if (!hideChildren)
            {
                foreach (var vsp in vesselStatusParameters)
                {
                    vsp.obsolete = true;
                }
            }

            List <Vessel> vesselsMeetingCondition = new List <Vessel>();

            int stepCount = context.steps.Count;

            for (int i = 0; i < stepCount; i++)
            {
                var now = context.steps[i];
                context.SetTime(now);

                vesselsMeetingCondition.Clear();
                bool doLabelUpdate = !hideChildren && i + 1 == stepCount;

                foreach (Vessel vessel in vessels)
                {
                    // Note considering early termination for performance gains:
                    // If we already know that we have enough vessels to satisfy
                    // our requirement, and if we don't have to update labels,
                    // then we don't need to test all vessels. However, this
                    // doesn't work when we have complex requirements that need
                    // to consider multiple vessels at once (like body surface
                    // observation percentage). We could change the implementation
                    // to continuously integrate one vessel at a time into the
                    // multi-vessel test and abort as soon as that one is satisfied,
                    // but if that also calculates a number visible to the user
                    // (like percentage of surface observed), that number would
                    // be wrong. So we need to test all vessels, all the time.

                    // if (!doLabelUpdate && vesselsMeetingCondition.Count >= minVessels)
                    //	break;

                    string statusLabel;

                    bool conditionMet = VesselMeetsCondition(vessel, doLabelUpdate, out statusLabel);
                    if (conditionMet)
                    {
                        vesselsMeetingCondition.Add(vessel);
                    }

                    if (doLabelUpdate)
                    {
                        childParameterChanged |= UpdateVesselStatus(vessel, statusLabel, conditionMet);
                    }
                }

                bool allConditionsMet = vesselsMeetingCondition.Count >= arguments.minVessels;
                allConditionsMet &= VesselsMeetCondition(vesselsMeetingCondition);

                if (durationParameter == null)
                {
                    SetState(allConditionsMet ? ParameterState.Complete : ParameterState.Incomplete);
                }
                else
                {
                    durationParameter.Update(allConditionsMet, now);
                    SetState(durationParameter.State);
                }

                if (state == ParameterState.Complete)
                {
                    break;
                }
            }

            childParameterChanged |= RemoveObsoleteVesselStatusParameters();
            if (childParameterChanged)
            {
                ContractConfigurator.ContractConfigurator.OnParameterChange.Fire(this.Root, this);
            }
        }