public double Evaluate(RPMVesselComputer comp, PersistenceAccessor persistence)
        {
            float result = comp.ProcessVariable(sourceVariable, persistence).MassageToFloat();

            Vector2 sourceRange;

            if (!string.IsNullOrEmpty(sourceMinStr))
            {
                sourceRange.x = comp.ProcessVariable(sourceMinStr, persistence).MassageToFloat();
            }
            else
            {
                sourceRange.x = sourceMin;
            }

            if (!string.IsNullOrEmpty(sourceMaxStr))
            {
                sourceRange.y = comp.ProcessVariable(sourceMaxStr, persistence).MassageToFloat();
            }
            else
            {
                sourceRange.y = sourceMax;
            }

            return(JUtil.DualLerp(mappedRange, sourceRange, result));
        }
        public double Evaluate(RPMVesselComputer comp, PersistenceAccessor persistence)
        {
            float result = comp.ProcessVariable(sourceVariable, persistence).MassageToFloat();

            Vector2 sourceRange;
            if (!string.IsNullOrEmpty(sourceMinStr))
            {
                sourceRange.x = comp.ProcessVariable(sourceMinStr, persistence).MassageToFloat();
            }
            else
            {
                sourceRange.x = sourceMin;
            }

            if (!string.IsNullOrEmpty(sourceMaxStr))
            {
                sourceRange.y = comp.ProcessVariable(sourceMaxStr, persistence).MassageToFloat();
            }
            else
            {
                sourceRange.y = sourceMax;
            }

            return JUtil.DualLerp(mappedRange, sourceRange, result);
        }
        public void Start()
        {
            if (string.IsNullOrEmpty(soundURL))
            {
                JUtil.LogMessage(this, "JSIInternalBackgroundNoise called with no soundURL");
                Destroy(this);
                return;
            }

            if (needsElectricCharge)
            {
                RPMVesselComputer comp = RPMVesselComputer.Instance(vessel);
                comp.UpdateDataRefreshRate(soundCheckRate);
                electricChargeReserve = comp.ProcessVariable(resourceName).MassageToFloat();
            }
            audioOutput            = new FXGroup("RPM" + internalModel.internalName + vessel.id);
            audioOutput.audio      = internalModel.gameObject.AddComponent <AudioSource>();
            audioOutput.audio.clip = GameDatabase.Instance.GetAudioClip(soundURL.EnforceSlashes());
            audioOutput.audio.Stop();
            audioOutput.audio.volume       = GameSettings.SHIP_VOLUME * soundVolume;
            audioOutput.audio.rolloffMode  = AudioRolloffMode.Logarithmic;
            audioOutput.audio.maxDistance  = 10f;
            audioOutput.audio.minDistance  = 8f;
            audioOutput.audio.dopplerLevel = 0f;
            audioOutput.audio.panStereo    = 0f;
            audioOutput.audio.playOnAwake  = false;
            audioOutput.audio.priority     = 255;
            audioOutput.audio.loop         = true;
            audioOutput.audio.pitch        = 1f;
        }
        public static string ProcessString(string input, RPMVesselComputer comp)
        {
            try
            {
                if (input.IndexOf(JUtil.VariableListSeparator[0], StringComparison.Ordinal) >= 0)
                {
                    string[] tokens = input.Split(JUtil.VariableListSeparator, StringSplitOptions.RemoveEmptyEntries);
                    if (tokens.Length != 2)
                    {
                        return("FORMAT ERROR");
                    }
                    else
                    {
                        string[] vars = tokens[1].Split(JUtil.VariableSeparator, StringSplitOptions.RemoveEmptyEntries);

                        var variables = new object[vars.Length];
                        for (int i = 0; i < vars.Length; i++)
                        {
                            variables[i] = comp.ProcessVariable(vars[i]);
                        }
                        string output = string.Format(fp, tokens[0], variables);
                        return(output.TrimEnd());
                    }
                }
            }
            catch (Exception e)
            {
                JUtil.LogErrorMessage(comp, "Bad format on string {0}", input);
                throw e;
            }

            return(input.TrimEnd());
        }
        public override void OnUpdate()
        {
            if (!JUtil.UserIsInPod(part))
            {
                StopPlaying();
                return;
            }

            if (needsElectricCharge)
            {
                soundCheckCountdown--;
                if (soundCheckCountdown <= 0)
                {
                    RPMVesselComputer comp = RPMVesselComputer.Instance(vessel);
                    soundCheckCountdown   = soundCheckRate;
                    electricChargeReserve = comp.ProcessVariable(resourceName).MassageToFloat();
                    if (electricChargeReserve < 0.01f)
                    {
                        StopPlaying();
                        return;
                    }
                }
            }

            StartPlaying();
        }
Example #6
0
        public override void OnUpdate()
        {
            if (!JUtil.UserIsInPod(part))
            {
                StopPlaying();
                return;
            }

            if (needsElectricCharge)
            {
                soundCheckCountdown--;
                if (soundCheckCountdown <= 0)
                {
                    RPMVesselComputer comp = RPMVesselComputer.Instance(vessel);
                    soundCheckCountdown   = soundCheckRate;
                    electricChargeReserve = (float)comp.ProcessVariable("SYSR_ELECTRICCHARGE");
                    if (electricChargeReserve < 0.01f)
                    {
                        StopPlaying();
                        return;
                    }
                }
            }

            StartPlaying();
        }
        public static string ProcessString(string input, RPMVesselComputer comp, PersistenceAccessor persistence)
        {
            try
            {
                if (input.IndexOf(JUtil.VariableListSeparator[0], StringComparison.Ordinal) >= 0)
                {
                    string[] tokens = input.Split(JUtil.VariableListSeparator, StringSplitOptions.RemoveEmptyEntries);
                    if (tokens.Length != 2)
                    {
                        return "FORMAT ERROR";
                    }
                    else
                    {
                        string[] vars = tokens[1].Split(JUtil.VariableSeparator, StringSplitOptions.RemoveEmptyEntries);

                        var variables = new object[vars.Length];
                        for (int i = 0; i < vars.Length; i++)
                        {
                            variables[i] = comp.ProcessVariable(vars[i], persistence);
                        }
                        string output = string.Format(fp, tokens[0], variables);
                        return output.TrimEnd();
                    }
                }
            }
            catch (Exception e)
            {
                JUtil.LogMessage(comp, "Bad format on string {0}", input);
                throw e;
            }
            return input.TrimEnd();
        }
        /// <summary>
        /// Evaluate the variable, returning it in destination.
        /// </summary>
        /// <param name="destination"></param>
        /// <param name="comp"></param>
        /// <returns></returns>
        public bool Get(out double destination, RPMVesselComputer comp)
        {
            if (type == VoNType.ConstantString)
            {
                destination = 0.0;
                return(false);
            }
            else if (type == VoNType.VariableValue)
            {
                numericValue = comp.ProcessVariable(variableName).MassageToDouble();
                if (double.IsNaN(numericValue) || double.IsInfinity(numericValue))
                {
                    if (!warningMade)
                    {
                        JUtil.LogMessage(this, "Warning: {0} can fail to produce a usable number.", variableName);
                        warningMade = true;
                    }
                    destination = numericValue;
                    return(false);
                }
            }

            destination = numericValue;
            return(true);
        }
 private void CheckForElectricCharge()
 {
     if (needsElectricCharge)
     {
         RPMVesselComputer comp = RPMVesselComputer.Instance(vessel);
         electricChargeReserve = comp.ProcessVariable(resourceName).MassageToFloat();
     }
 }
 private void CheckForElectricCharge()
 {
     if (needsElectricCharge)
     {
         RPMVesselComputer comp = RPMVesselComputer.Instance(vessel);
         electricChargeReserve = (double)comp.ProcessVariable("SYSR_ELECTRICCHARGE", null);
     }
 }
        public void Start()
        {
            if (HighLogic.LoadedSceneIsEditor)
            {
                return;
            }

            try
            {
                ConfigNode moduleConfig = null;
                foreach (ConfigNode node in GameDatabase.Instance.GetConfigNodes("PROP"))
                {
                    if (node.GetValue("name") == internalProp.propName)
                    {
                        if (string.IsNullOrEmpty(variableName))
                        {
                            JUtil.LogErrorMessage(this, "Configuration failed in prop {0} ({1}), no variableName.", internalProp.propID, internalProp.propName);
                            throw new ArgumentNullException();
                        }

                        moduleConfig = node.GetNodes("MODULE")[moduleID];
                        ConfigNode[] variableNodes = moduleConfig.GetNodes("VARIABLESET");

                        for (int i = 0; i < variableNodes.Length; i++)
                        {
                            try
                            {
                                variableSets.Add(new CallbackAnimationSet(variableNodes[i], variableName, internalProp));
                            }
                            catch (ArgumentException e)
                            {
                                JUtil.LogErrorMessage(this, "Error in building prop number {1} - {0}", e.Message, internalProp.propID);
                            }
                        }
                        break;
                    }
                }


                RPMVesselComputer comp = RPMVesselComputer.Instance(vessel);
                del = (Action <RPMVesselComputer, float>)Delegate.CreateDelegate(typeof(Action <RPMVesselComputer, float>), this, "OnCallback");
                float value = comp.ProcessVariable(variableName).MassageToFloat();
                for (int i = 0; i < variableSets.Count; ++i)
                {
                    variableSets[i].Update(comp, value);
                }
                comp.RegisterCallback(variableName, del);
                JUtil.LogMessage(this, "Configuration complete in prop {1} ({2}), supporting {0} callback animators.", variableSets.Count, internalProp.propID, internalProp.propName);
            }
            catch
            {
                JUtil.AnnoyUser(this);
                enabled = false;
                throw;
            }
        }
            public void Update(double time, RPMVesselComputer comp)
            {
                double value = isFlat ? flatValue : comp.ProcessVariable(variableName).MassageToDouble();

                if (double.IsNaN(value) || double.IsInfinity(value))
                {
                    return;
                }
                points.Add(new Vector2d(time, value));
                if (points.Count > maxPoints)
                {
                    points.RemoveRange(0, points.Count - maxPoints);
                }
            }
        public static string ProcessString(StringProcessorFormatter formatter, RPMVesselComputer comp)
        {
            if (formatter.usesComp)
            {
                for (int i = 0; i < formatter.sourceVariables.Length; ++i)
                {
                    formatter.sourceValues[i] = comp.ProcessVariable(formatter.sourceVariables[i]);
                }

                return(string.Format(formatter.formatString, formatter.sourceValues));
            }
            else
            {
                return(formatter.formatString);
            }
        }
Example #14
0
        public void Start()
        {
            RPMVesselComputer comp = RPMVesselComputer.Instance(vessel);

            Transform textObjTransform = internalProp.FindModelTransform(transformName);

            textObj = InternalComponents.Instance.CreateText(fontName, fontSize, textObjTransform, string.Empty);
            // Force oneshot if there's no variables:
            oneshot |= !labelText.Contains("$&$");
            string sourceString = labelText.UnMangleConfigText();

            // Alow a " character to escape leading whitespace
            if (sourceString[0] == '"')
            {
                sourceString = sourceString.Substring(1);
            }
            spf = new StringProcessorFormatter(sourceString);

            if (!oneshot)
            {
                comp.UpdateDataRefreshRate(refreshRate);
            }

            if (!(string.IsNullOrEmpty(variableName) || string.IsNullOrEmpty(positiveColor) || string.IsNullOrEmpty(negativeColor) || string.IsNullOrEmpty(zeroColor)))
            {
                positiveColorValue = ConfigNode.ParseColor32(positiveColor);
                negativeColorValue = ConfigNode.ParseColor32(negativeColor);
                zeroColorValue     = ConfigNode.ParseColor32(zeroColor);
                del = (Action <RPMVesselComputer, float>)Delegate.CreateDelegate(typeof(Action <RPMVesselComputer, float>), this, "OnCallback");
                comp.RegisterCallback(variableName, del);

                // Initialize the text color.
                float value = comp.ProcessVariable(variableName).MassageToFloat();
                if (value < 0.0f)
                {
                    textObj.text.Color = negativeColorValue;
                }
                else if (value > 0.0f)
                {
                    textObj.text.Color = positiveColorValue;
                }
                else
                {
                    textObj.text.Color = zeroColorValue;
                }
            }
        }
 public object Evaluate(RPMVesselComputer comp)
 {
     if (type == VoNType.ConstantNumeric)
     {
         return(numericValue);
     }
     else if (type == VoNType.ConstantString)
     {
         return(stringValue);
     }
     else if (type == VoNType.VariableValue)
     {
         return(comp.ProcessVariable(variableName));
     }
     else
     {
         return(null);
     }
 }
        /// <summary>
        /// Evaluate the variable, returning it in destination.
        /// </summary>
        /// <param name="destination"></param>
        /// <param name="comp"></param>
        /// <returns></returns>
        public bool Get(out float destination, RPMVesselComputer comp)
        {
            if (!string.IsNullOrEmpty(variableName))
            {
                value = comp.ProcessVariable(variableName).MassageToFloat();
                if (float.IsNaN(value) || float.IsInfinity(value))
                {
                    if (!warningMade)
                    {
                        JUtil.LogMessage(this, "Warning: {0} can fail to produce a usable number.", variableName);
                        warningMade = true;
                    }
                    destination = value;
                    return(false);
                }
            }

            destination = value;
            return(true);
        }
Example #17
0
        public override void OnUpdate()
        {
            if (HighLogic.LoadedSceneIsEditor)
            {
                return;
            }

            if (!startupComplete)
            {
                return;
            }

            if (!JUtil.IsActiveVessel(vessel))
            {
                if (loopingOutput != null && currentState == true)
                {
                    loopingOutput.audio.volume = 0.0f;
                }
                return;
            }
            else if (loopingOutput != null && currentState == true && loopingOutput.Active)
            {
                loopingOutput.audio.volume = loopingSoundVolume * GameSettings.SHIP_VOLUME;
            }

            if (consumingWhileActive && currentState && !forcedShutdown)
            {
                float requesting = (consumeWhileActiveAmount * TimeWarp.deltaTime);
                float extracted  = part.RequestResource(consumeWhileActiveName, requesting);
                if (Math.Abs(extracted - requesting) > Math.Abs(requesting / 2))
                {
                    // We don't have enough of the resource or can't produce more negative resource, so we should shut down...
                    forcedShutdown = true;
                    JUtil.LogMessage(this, "Could not consume {0}, asked for {1}, got {2} shutting switch down.", consumeWhileActiveName, requesting, extracted);
                }
            }

            // Bizarre, but looks like I need to animate things offscreen if I want them in the right condition when camera comes back.
            // So there's no check for internal cameras.

            bool newState;

            if (isPluginAction && !string.IsNullOrEmpty(stateVariable))
            {
                try
                {
                    RPMVesselComputer comp = RPMVesselComputer.Instance(vessel);
                    newState = (comp.ProcessVariable(stateVariable, -1).MassageToInt()) > 0;
                }
                catch
                {
                    newState = currentState;
                }
            }
            else if (isCustomAction)
            {
                if (string.IsNullOrEmpty(switchTransform) && !string.IsNullOrEmpty(perPodPersistenceName))
                {
                    if (switchGroupIdentifier >= 0)
                    {
                        int activeGroupId = rpmComp.GetVar(persistentVarName, 0);
                        newState         = (switchGroupIdentifier == activeGroupId);
                        customGroupState = newState;
                    }
                    else
                    {
                        // If the switch transform is not given, and the global comp.Persistence value is, this means this is a slave module.
                        newState = rpmComp.GetBool(persistentVarName, false);
                    }
                }
                else
                {
                    // Otherwise it's a master module. But it still might have to follow the clicks on other copies of the same prop...
                    if (!string.IsNullOrEmpty(perPodPersistenceName))
                    {
                        if (switchGroupIdentifier >= 0)
                        {
                            int activeGroupId = rpmComp.GetVar(persistentVarName, 0);
                            newState         = (switchGroupIdentifier == activeGroupId);
                            customGroupState = newState;
                        }
                        else
                        {
                            newState = rpmComp.GetBool(persistentVarName, customGroupState);
                        }
                    }
                    else
                    {
                        newState = customGroupState;
                    }
                }
            }
            else
            {
                newState = vessel.ActionGroups[kspAction];
            }

            // If needsElectricCharge is true and there is no charge, the state value is overridden to false and the click action is reexecuted.
            if (needsElectricChargeValue)
            {
                lightCheckCountdown--;
                if (lightCheckCountdown <= 0)
                {
                    RPMVesselComputer comp = RPMVesselComputer.Instance(vessel);
                    lightCheckCountdown = refreshRate;
                    forcedShutdown     |= currentState && comp.ProcessVariable(resourceName).MassageToFloat() < 0.01f;
                }
            }

            if (!string.IsNullOrEmpty(perPodMasterSwitchName))
            {
                bool switchEnabled = rpmComp.GetBool(perPodMasterSwitchName, false);
                if (!switchEnabled)
                {
                    // If the master switch is 'off', this switch needs to turn off
                    newState       = false;
                    forcedShutdown = true;
                }
            }

            if (masterVariable != null)
            {
                RPMVesselComputer comp = RPMVesselComputer.Instance(vessel);
                if (!masterVariable.IsInRange(comp))
                {
                    newState       = false;
                    forcedShutdown = true;
                }
            }

            if (forcedShutdown)
            {
                if (currentState)
                {
                    Click();
                }
                newState       = false;
                forcedShutdown = false;
            }

            if (newState != currentState)
            {
                // If we're consuming resources on toggle, do that now.
                if ((consumingOnToggleUp && newState) || (consumingOnToggleDown && !newState))
                {
                    float extracted = part.RequestResource(consumeOnToggleName, consumeOnToggleAmount);
                    if (Math.Abs(extracted - consumeOnToggleAmount) > Math.Abs(consumeOnToggleAmount / 2))
                    {
                        // We don't have enough of the resource, so we force a shutdown on the next loop.
                        // This ensures the animations will play at least once.
                        forcedShutdown = true;
                    }
                }

                if (audioOutput != null && (CameraManager.Instance.currentCameraMode == CameraManager.CameraMode.IVA ||
                                            CameraManager.Instance.currentCameraMode == CameraManager.CameraMode.Internal))
                {
                    audioOutput.audio.Play();
                }

                if (loopingOutput != null && (CameraManager.Instance.currentCameraMode == CameraManager.CameraMode.IVA ||
                                              CameraManager.Instance.currentCameraMode == CameraManager.CameraMode.Internal))
                {
                    if (newState)
                    {
                        loopingOutput.audio.Play();
                    }
                    else
                    {
                        loopingOutput.audio.Stop();
                    }
                }

                if (anim != null)
                {
                    if (newState ^ reverse)
                    {
                        anim[animationName].normalizedTime = 0;
                        anim[animationName].speed          = 1f * customSpeed;
                        anim.Play(animationName);
                    }
                    else
                    {
                        anim[animationName].normalizedTime = 1;
                        anim[animationName].speed          = -1f * customSpeed;
                        anim.Play(animationName);
                    }
                }
                else if (colorShiftMaterial != null)
                {
                    colorShiftMaterial.SetColor(colorName, (newState ^ reverse ? enabledColorValue : disabledColorValue));
                }
                currentState = newState;
            }
        }
Example #18
0
        public void Click()
        {
            bool switchEnabled = true;

            if (!forcedShutdown)
            {
                if (!string.IsNullOrEmpty(perPodMasterSwitchName))
                {
                    switchEnabled = rpmComp.GetBool(perPodMasterSwitchName, false);
                }
                if (masterVariable != null)
                {
                    RPMVesselComputer comp = RPMVesselComputer.Instance(vessel);
                    switchEnabled = masterVariable.IsInRange(comp);
                }
            }
            if (!switchEnabled)
            {
                // If the master switch is 'off' and we're not here because
                // of a forced shutdown, don't allow this switch to work.
                // early return
                return;
            }

            if (isCustomAction)
            {
                if (switchGroupIdentifier >= 0)
                {
                    if (!forcedShutdown && !customGroupState)
                    {
                        customGroupState = true;
                        if (!string.IsNullOrEmpty(persistentVarName))
                        {
                            rpmComp.SetVar(persistentVarName, switchGroupIdentifier);
                        }
                    }
                    // else: can't turn off a radio group switch.
                }
                else if (customAction == CustomActions.Plugin && !string.IsNullOrEmpty(stateVariable))
                {
                    RPMVesselComputer comp = RPMVesselComputer.Instance(vessel);
                    int ivalue             = comp.ProcessVariable(stateVariable, -1).MassageToInt();
                    customGroupState = (ivalue < 1) && !forcedShutdown;
                }
                else
                {
                    customGroupState = !customGroupState;
                    if (!string.IsNullOrEmpty(persistentVarName))
                    {
                        rpmComp.SetVar(persistentVarName, customGroupState);
                    }
                }
            }
            else
            {
                vessel.ActionGroups.ToggleGroup(kspAction);
            }
            // Now we do extra things that with regular actions can't happen.
            switch (customAction)
            {
            case CustomActions.IntLight:
                SetInternalLights(customGroupState);
                break;

            case CustomActions.Plugin:
                actionHandler(customGroupState);
                break;

            case CustomActions.Stage:
                if (InputLockManager.IsUnlocked(ControlTypes.STAGING))
                {
                    Staging.ActivateNextStage();
                }
                break;

            case CustomActions.Transfer:
                if (!string.IsNullOrEmpty(stateVariable))
                {
                    // stateVariable can disable the button functionality.
                    RPMVesselComputer comp = RPMVesselComputer.Instance(vessel);
                    int ivalue             = comp.ProcessVariable(stateVariable, -1).MassageToInt();
                    if (ivalue < 1)
                    {
                        return;     // early - button disabled
                    }
                }
                if (!string.IsNullOrEmpty(transferGetter))
                {
                    RPMVesselComputer comp  = RPMVesselComputer.Instance(vessel);
                    float             value = comp.ProcessVariable(transferGetter, internalProp.propID).MassageToFloat();
                    rpmComp.SetVar(transferPersistentName, (int)value);
                }
                else if (rpmComp.HasVar(transferPersistentName))
                {
                    transferSetter((double)rpmComp.GetVar(transferPersistentName));
                }
                break;
            }
        }
Example #19
0
        public void Start()
        {
            if (HighLogic.LoadedSceneIsEditor)
            {
                return;
            }

            try
            {
                RPMVesselComputer comp = RPMVesselComputer.Instance(vessel);

                if (!groupList.ContainsKey(actionName) && !customGroupList.ContainsKey(actionName))
                {
                    JUtil.LogErrorMessage(this, "Action \"{0}\" is not supported.", actionName);
                    return;
                }

                // Parse the needs-electric-charge here.
                if (!string.IsNullOrEmpty(needsElectricCharge))
                {
                    switch (needsElectricCharge.ToLowerInvariant().Trim())
                    {
                    case "true":
                    case "yes":
                    case "1":
                        needsElectricChargeValue = true;
                        break;

                    case "false":
                    case "no":
                    case "0":
                        needsElectricChargeValue = false;
                        break;
                    }
                }

                // Now parse consumeOnToggle and consumeWhileActive...
                if (!string.IsNullOrEmpty(consumeOnToggle))
                {
                    string[] tokens = consumeOnToggle.Split(',');
                    if (tokens.Length == 3)
                    {
                        consumeOnToggleName = tokens[0].Trim();
                        if (!(PartResourceLibrary.Instance.GetDefinition(consumeOnToggleName) != null &&
                              float.TryParse(tokens[1].Trim(), NumberStyles.Any, CultureInfo.InvariantCulture,
                                             out consumeOnToggleAmount)))
                        {
                            JUtil.LogErrorMessage(this, "Could not parse \"{0}\"", consumeOnToggle);
                        }
                        switch (tokens[2].Trim().ToLower())
                        {
                        case "on":
                            consumingOnToggleUp = true;
                            break;

                        case "off":
                            consumingOnToggleDown = true;
                            break;

                        case "both":
                            consumingOnToggleUp   = true;
                            consumingOnToggleDown = true;
                            break;

                        default:
                            JUtil.LogErrorMessage(this, "So should I consume resources when turning on, turning off, or both in \"{0}\"?", consumeOnToggle);
                            break;
                        }
                    }
                }

                if (!string.IsNullOrEmpty(consumeWhileActive))
                {
                    string[] tokens = consumeWhileActive.Split(',');
                    if (tokens.Length == 2)
                    {
                        consumeWhileActiveName = tokens[0].Trim();
                        if (!(PartResourceLibrary.Instance.GetDefinition(consumeWhileActiveName) != null &&
                              float.TryParse(tokens[1].Trim(),
                                             NumberStyles.Any, CultureInfo.InvariantCulture,
                                             out consumeWhileActiveAmount)))
                        {
                            JUtil.LogErrorMessage(this, "Could not parse \"{0}\"", consumeWhileActive);
                        }
                        else
                        {
                            consumingWhileActive = true;
                            JUtil.LogMessage(this, "Switch in prop {0} prop id {1} will consume {2} while active at a rate of {3}", internalProp.propName,
                                             internalProp.propID, consumeWhileActiveName, consumeWhileActiveAmount);
                        }
                    }
                }

                if (groupList.ContainsKey(actionName))
                {
                    kspAction    = groupList[actionName];
                    currentState = vessel.ActionGroups[kspAction];
                    // action group switches may not belong to a radio group
                    switchGroupIdentifier = -1;
                }
                else
                {
                    isCustomAction = true;
                    switch (actionName)
                    {
                    case "intlight":
                        persistentVarName = internalLightName;
                        if (!string.IsNullOrEmpty(internalLightName))
                        {
                            Light[] availableLights = internalModel.FindModelComponents <Light>();
                            if (availableLights != null && availableLights.Length > 0)
                            {
                                List <Light> lights = new List <Light>(availableLights);
                                for (int i = lights.Count - 1; i >= 0; --i)
                                {
                                    if (lights[i].name != internalLightName)
                                    {
                                        lights.RemoveAt(i);
                                    }
                                }
                                if (lights.Count > 0)
                                {
                                    lightObjects              = lights.ToArray();
                                    needsElectricChargeValue |= string.IsNullOrEmpty(needsElectricCharge) || needsElectricChargeValue;
                                }
                                else
                                {
                                    actionName = "dummy";
                                }
                            }
                        }
                        else
                        {
                            actionName = "dummy";
                        }
                        break;

                    case "plugin":
                        persistentVarName = string.Empty;
                        comp.UpdateDataRefreshRate(refreshRate);

                        foreach (ConfigNode node in GameDatabase.Instance.GetConfigNodes("PROP"))
                        {
                            if (node.GetValue("name") == internalProp.propName)
                            {
                                foreach (ConfigNode pluginConfig in node.GetNodes("MODULE")[moduleID].GetNodes("PLUGINACTION"))
                                {
                                    if (pluginConfig.HasValue("name") && pluginConfig.HasValue("actionMethod"))
                                    {
                                        string action = pluginConfig.GetValue("name").Trim() + ":" + pluginConfig.GetValue("actionMethod").Trim();
                                        actionHandler = (Action <bool>)comp.GetMethod(action, internalProp, typeof(Action <bool>));

                                        if (actionHandler == null)
                                        {
                                            JUtil.LogErrorMessage(this, "Failed to instantiate action handler {0}", action);
                                        }
                                        else
                                        {
                                            if (pluginConfig.HasValue("stateMethod"))
                                            {
                                                string state = pluginConfig.GetValue("name").Trim() + ":" + pluginConfig.GetValue("stateMethod").Trim();
                                                stateVariable = "PLUGIN_" + state;
                                            }
                                            else if (pluginConfig.HasValue("stateVariable"))
                                            {
                                                stateVariable = pluginConfig.GetValue("stateVariable").Trim();
                                            }
                                            isPluginAction = true;
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                        if (actionHandler == null)
                        {
                            actionName = "dummy";
                            JUtil.LogMessage(this, "Plugin handlers did not start, reverting to dummy mode.");
                        }
                        break;

                    case "transfer":
                        persistentVarName = string.Empty;
                        comp.UpdateDataRefreshRate(refreshRate);

                        foreach (ConfigNode node in GameDatabase.Instance.GetConfigNodes("PROP"))
                        {
                            if (node.GetValue("name") == internalProp.propName)
                            {
                                foreach (ConfigNode pluginConfig in node.GetNodes("MODULE")[moduleID].GetNodes("TRANSFERACTION"))
                                {
                                    if ((pluginConfig.HasValue("name") || pluginConfig.HasValue("getVariable")) && pluginConfig.HasValue("perPodPersistenceName"))
                                    {
                                        transferPersistentName = pluginConfig.GetValue("perPodPersistenceName").Trim();
                                        if (pluginConfig.HasValue("stateMethod"))
                                        {
                                            string state = pluginConfig.GetValue("name").Trim() + ":" + pluginConfig.GetValue("stateMethod").Trim();
                                            stateVariable = "PLUGIN_" + state;
                                        }
                                        else if (pluginConfig.HasValue("stateVariable"))
                                        {
                                            stateVariable = pluginConfig.GetValue("stateVariable").Trim();
                                        }
                                        if (pluginConfig.HasValue("setMethod"))
                                        {
                                            string action = pluginConfig.GetValue("name").Trim() + ":" + pluginConfig.GetValue("setMethod").Trim();
                                            transferSetter = (Action <double>)comp.GetMethod(action, internalProp, typeof(Action <double>));

                                            if (transferSetter == null)
                                            {
                                                JUtil.LogErrorMessage(this, "Failed to instantiate transfer handler {0}", pluginConfig.GetValue("name"));
                                            }
                                            else
                                            {
                                                //JUtil.LogMessage(this, "Got setter {0}", action);
                                                break;
                                            }
                                        }
                                        else if (pluginConfig.HasValue("getMethod"))
                                        {
                                            string action = pluginConfig.GetValue("name").Trim() + ":" + pluginConfig.GetValue("getMethod").Trim();
                                            var    getter = (Func <double>)comp.GetMethod(action, internalProp, typeof(Func <double>));

                                            if (getter == null)
                                            {
                                                JUtil.LogErrorMessage(this, "Failed to instantiate transfer handler {0}", pluginConfig.GetValue("name"));
                                            }
                                            else
                                            {
                                                transferGetter = "PLUGIN_" + action;
                                                //JUtil.LogMessage(this, "Got getter {0}", action);
                                                break;
                                            }
                                        }
                                        else if (pluginConfig.HasValue("getVariable"))
                                        {
                                            transferGetter = pluginConfig.GetValue("getVariable").Trim();
                                        }
                                    }
                                }
                            }
                        }
                        if (string.IsNullOrEmpty(transferGetter) && transferSetter == null)
                        {
                            actionName    = "dummy";
                            stateVariable = string.Empty;
                            JUtil.LogMessage(this, "Transfer handlers did not start, reverting to dummy mode.");
                        }
                        break;

                    default:
                        persistentVarName = "switch" + internalProp.propID + "_" + moduleID;
                        break;
                    }
                    if (!string.IsNullOrEmpty(perPodPersistenceName))
                    {
                        persistentVarName = perPodPersistenceName;
                    }
                    else
                    {
                        // If there's no persistence name, there's no valid group id for this switch
                        switchGroupIdentifier = -1;
                    }
                }

                if (customGroupList.ContainsKey(actionName))
                {
                    customAction = customGroupList[actionName];
                }

                if (needsElectricChargeValue || !string.IsNullOrEmpty(persistentVarName) || !string.IsNullOrEmpty(perPodMasterSwitchName) || !string.IsNullOrEmpty(masterVariableName) ||
                    !string.IsNullOrEmpty(transferGetter) || transferSetter != null)
                {
                    rpmComp = RasterPropMonitorComputer.Instantiate(internalProp);

                    comp.UpdateDataRefreshRate(refreshRate);

                    if (!string.IsNullOrEmpty(masterVariableName))
                    {
                        string[] range = masterVariableRange.Split(',');
                        if (range.Length == 2)
                        {
                            masterVariable = new VariableOrNumberRange(masterVariableName, range[0], range[1]);
                        }
                        else
                        {
                            masterVariable = null;
                        }
                    }
                }

                // set up the toggle switch
                if (!string.IsNullOrEmpty(switchTransform))
                {
                    if (momentarySwitch)
                    {
                        SmarterButton.CreateButton(internalProp, switchTransform, Click, Click);
                    }
                    else
                    {
                        SmarterButton.CreateButton(internalProp, switchTransform, Click);
                    }
                }

                if (isCustomAction)
                {
                    if (isPluginAction && !string.IsNullOrEmpty(stateVariable))
                    {
                        try
                        {
                            currentState = (comp.ProcessVariable(stateVariable, -1).MassageToInt()) > 0;
                        }
                        catch
                        {
                            // no-op
                        }
                    }
                    else
                    {
                        if (rpmComp != null && !string.IsNullOrEmpty(persistentVarName))
                        {
                            if (switchGroupIdentifier >= 0)
                            {
                                int activeSwitch = rpmComp.GetVar(persistentVarName, 0);

                                currentState = customGroupState = (switchGroupIdentifier == activeSwitch);
                            }
                            else
                            {
                                currentState = customGroupState = rpmComp.GetBool(persistentVarName, initialState);
                            }

                            if (customAction == CustomActions.IntLight)
                            {
                                // We have to restore lighting after reading the
                                // persistent variable.
                                SetInternalLights(customGroupState);
                            }
                        }
                    }
                }

                if (rpmComp != null && !rpmComp.HasVar(persistentVarName))
                {
                    if (switchGroupIdentifier >= 0)
                    {
                        if (currentState)
                        {
                            rpmComp.SetVar(persistentVarName, switchGroupIdentifier);
                        }
                    }
                    else
                    {
                        rpmComp.SetVar(persistentVarName, currentState);
                    }
                }

                if (!string.IsNullOrEmpty(animationName))
                {
                    // Set up the animation
                    Animation[] animators = animateExterior ? part.FindModelAnimators(animationName) : internalProp.FindModelAnimators(animationName);
                    if (animators.Length > 0)
                    {
                        anim = animators[0];
                    }
                    else
                    {
                        JUtil.LogErrorMessage(this, "Could not find animation \"{0}\" on {2} \"{1}\"",
                                              animationName, animateExterior ? part.name : internalProp.name, animateExterior ? "part" : "prop");
                        return;
                    }
                    anim[animationName].wrapMode = WrapMode.Once;

                    if (currentState ^ reverse)
                    {
                        anim[animationName].speed          = float.MaxValue;
                        anim[animationName].normalizedTime = 0;
                    }
                    else
                    {
                        anim[animationName].speed          = float.MinValue;
                        anim[animationName].normalizedTime = 1;
                    }
                    anim.Play(animationName);
                }
                else if (!string.IsNullOrEmpty(coloredObject))
                {
                    // Set up the color shift.
                    Renderer colorShiftRenderer = internalProp.FindModelComponent <Renderer>(coloredObject);
                    disabledColorValue = ConfigNode.ParseColor32(disabledColor);
                    enabledColorValue  = ConfigNode.ParseColor32(enabledColor);
                    colorShiftMaterial = colorShiftRenderer.material;
                    colorShiftMaterial.SetColor(colorName, (currentState ^ reverse ? enabledColorValue : disabledColorValue));
                }
                else
                {
                    JUtil.LogMessage(this, "Warning, neither color nor animation are defined in prop {0} #{1} (this may be okay).", internalProp.propName, internalProp.propID);
                }

                audioOutput = JUtil.SetupIVASound(internalProp, switchSound, switchSoundVolume, false);

                if (!string.IsNullOrEmpty(loopingSound) && loopingSoundVolume > 0.0f)
                {
                    loopingOutput = JUtil.SetupIVASound(internalProp, loopingSound, loopingSoundVolume, true);
                }

                startupComplete = true;
            }
            catch
            {
                JUtil.AnnoyUser(this);
                enabled = false;
                throw;
            }
        }
        public void RenderData(RenderTexture screen, RPMVesselComputer comp)
        {
            float leftVal, rightVal;

            if (!scale[0].Get(out leftVal, comp) || !scale[1].Get(out rightVal, comp))
            {
                return; // bad values - can't render
            }

            float eval = comp.ProcessVariable(variableName).MassageToFloat();

            if (float.IsInfinity(eval) || float.IsNaN(eval))
            {
                return; // bad value - can't render
            }

            float ratio = Mathf.InverseLerp(leftVal, rightVal, eval);

            if (thresholdMode)
            {
                if (ratio >= threshold.x && ratio <= threshold.y)
                {
                    if (flashingDelay > 0.0f)
                    {
                        if (lastStateChange + flashingDelay < Planetarium.GetUniversalTime())
                        {
                            lastStateChange = Planetarium.GetUniversalTime();
                            lastState       = 1.0f - lastState;
                        }

                        ratio = lastState;
                    }
                    else
                    {
                        ratio = 1.0f;
                    }
                }
                else
                {
                    ratio = 0.0f;
                }
            }

            if (reverse)
            {
                ratio = 1.0f - ratio;
            }

            switch (graphType)
            {
            case GraphType.VerticalDown:
                DrawVerticalDown(ratio);
                break;

            case GraphType.VerticalUp:
                DrawVerticalUp(ratio);
                break;

            case GraphType.VerticalSplit:
                DrawVerticalSplit(ratio);
                break;

            case GraphType.HorizontalLeft:
                DrawHorizontalLeft(ratio);
                break;

            case GraphType.HorizontalRight:
                DrawHorizontalRight(ratio);
                break;

            case GraphType.HorizontalSplit:
                DrawHorizontalSplit(ratio);
                break;

            case GraphType.Lamp:
                DrawLamp(ratio);
                break;

            default:
                throw new NotImplementedException("Unimplemented graphType " + graphType.ToString());
            }
        }
Example #21
0
        private void UpdateOdometer()
        {
            double thisUpdate = Planetarium.GetUniversalTime();
            float  dT         = (float)(thisUpdate - lastUpdate) * odometerRotationScalar;

            RPMVesselComputer comp = RPMVesselComputer.Instance(vessel);
            float             value;

            if (!string.IsNullOrEmpty(perPodPersistenceName))
            {
                bool state = rpmComp.GetBool(perPodPersistenceName, false);
                value = comp.ProcessVariable((state) ? altVariable : variable).MassageToFloat();
            }
            else
            {
                value = comp.ProcessVariable(variable).MassageToFloat();
            }
            // Make sure the value isn't going to be a problem.
            if (float.IsNaN(value))
            {
                value = 0.0f;
            }

            if (value < 0.0f)
            {
                signGoalCoord = 0.625f;
            }
            else if (value > 0.0f)
            {
                signGoalCoord = 0.875f;
            }
            else
            {
                signGoalCoord = 0.75f;
            }

            signCurrentCoord = JUtil.DualLerp(signCurrentCoord, signGoalCoord, 0.0f, 1.0f, dT);

            value = Mathf.Abs(value);

            if (oMode == OdometerMode.SI)
            {
                float leadingDigitExponent;
                if (value < 0.001f)
                {
                    leadingDigitExponent = -3.0f;
                }
                else
                {
                    leadingDigitExponent = Mathf.Floor(Mathf.Log10(value));
                }

                // siExponent is the location relative to the original decimal of
                // the SI prefix.  Is is always the greatest multiple-of-3 less
                // than the leadingDigitExponent.
                int siIndex = (int)Mathf.Floor(leadingDigitExponent / 3.0f);
                if (siIndex > 3)
                {
                    siIndex = 3;
                }
                int siExponent = siIndex * 3;

                prefixGoalCoord    = (float)(siIndex + 1) * 0.125f;
                prefixCurrentCoord = JUtil.DualLerp(prefixCurrentCoord, prefixGoalCoord, 0.0f, 1.0f, dT);

                float scaledValue = value / Mathf.Pow(10.0f, (float)(siExponent - 3));
                int   intValue    = (int)(scaledValue);

                for (int i = 5; i >= 0; --i)
                {
                    float thisCoord = (float)(intValue % 10) / 10.0f;
                    if (i == 5)
                    {
                        // So we can display fractional values:
                        // However, we also quantize it to make it easier to
                        // read during the transition from 9 to 0.
                        thisCoord = Mathf.Floor((scaledValue % 10.0f) * 2.0f) / 20.0f;
                    }
                    intValue          = intValue / 10;
                    goalCoordinate[i] = thisCoord;
                }
            }
            else if (oMode == OdometerMode.TIME_HHHMMSS)
            {
                // Clamp the value
                value = Mathf.Min(value, 59.0f + 59.0f * 60.0f + 999.0f * 60.0f * 24.0f);

                // seconds
                float thisCoord = Mathf.Floor((value % 10.0f) * 2.0f) / 20.0f;
                goalCoordinate[6] = thisCoord;
                int intValue = (int)(value) / 10;

                // tens of seconds
                thisCoord         = (float)(intValue % 6) / 10.0f;
                goalCoordinate[5] = thisCoord;
                intValue         /= 6;

                // minutes
                thisCoord         = (float)(intValue % 10) / 10.0f;
                goalCoordinate[4] = thisCoord;
                intValue         /= 10;

                // tens of minutes
                thisCoord         = (float)(intValue % 6) / 10.0f;
                goalCoordinate[3] = thisCoord;
                intValue         /= 6;

                for (int i = 2; i >= 0; --i)
                {
                    thisCoord         = (float)(intValue % 10) / 10.0f;
                    intValue          = intValue / 10;
                    goalCoordinate[i] = thisCoord;
                }
            }
            else
            {
                int intValue = (int)(value);

                for (int i = 7; i >= 0; --i)
                {
                    float thisCoord = (float)(intValue % 10) / 10.0f;
                    if (i == 7)
                    {
                        thisCoord = Mathf.Floor((value % 10.0f) * 2.0f) / 20.0f;
                    }
                    intValue          = intValue / 10;
                    goalCoordinate[i] = thisCoord;
                }
            }

            // Update interpolants
            for (int i = 0; i < 8; ++i)
            {
                if (currentCoordinate[i] != goalCoordinate[i])
                {
                    float startingPoint;
                    float endingPoint;
                    if (Mathf.Abs(currentCoordinate[i] - goalCoordinate[i]) <= 0.5f)
                    {
                        startingPoint = currentCoordinate[i];
                        endingPoint   = goalCoordinate[i];
                    }
                    else if (goalCoordinate[i] < currentCoordinate[i])
                    {
                        startingPoint = currentCoordinate[i];
                        endingPoint   = goalCoordinate[i] + 1.0f;
                    }
                    else
                    {
                        startingPoint = currentCoordinate[i] + 1.0f;
                        endingPoint   = goalCoordinate[i];
                    }

                    // This lerp causes a rotation that starts quickly but
                    // slows down close to the goal.  It actually looks
                    // pretty good for typical incrementing counts, while the
                    // rapid spinning of small values is chaotic enough that
                    // you can't really tell what's going on, anyway.
                    float goal = JUtil.DualLerp(startingPoint, endingPoint, 0.0f, 1.0f, dT);
                    if (goal > 1.0f)
                    {
                        goal -= 1.0f;
                    }
                    currentCoordinate[i] = goal;
                }
            }
            lastUpdate = thisUpdate;
        }
 public void Update(double time, RPMVesselComputer comp, PersistenceAccessor persistence)
 {
     double value = isFlat ? flatValue : comp.ProcessVariable(variableName, persistence).MassageToDouble();
     if (double.IsNaN(value) || double.IsInfinity(value))
     {
         return;
     }
     points.Add(new Vector2d(time, value));
     if (points.Count > maxPoints)
     {
         points.RemoveRange(0, points.Count - maxPoints);
     }
 }
        public void RenderData(RenderTexture screen, RPMVesselComputer comp)
        {
            float leftVal, rightVal;
            if (!scale[0].Get(out leftVal, comp) || !scale[1].Get(out rightVal, comp))
            {
                return; // bad values - can't render
            }

            float eval = comp.ProcessVariable(variableName).MassageToFloat();
            if (float.IsInfinity(eval) || float.IsNaN(eval))
            {
                return; // bad value - can't render
            }

            float ratio = Mathf.InverseLerp(leftVal, rightVal, eval);

            if (thresholdMode)
            {
                if (ratio >= threshold.x && ratio <= threshold.y)
                {
                    if (flashingDelay > 0.0f)
                    {
                        if (lastStateChange + flashingDelay < Planetarium.GetUniversalTime())
                        {
                            lastStateChange = Planetarium.GetUniversalTime();
                            lastState = 1.0f - lastState;
                        }

                        ratio = lastState;
                    }
                    else
                    {
                        ratio = 1.0f;
                    }
                }
                else
                {
                    ratio = 0.0f;
                }
            }

            if (reverse)
            {
                ratio = 1.0f - ratio;
            }

            switch (graphType)
            {
                case GraphType.VerticalDown:
                    DrawVerticalDown(ratio);
                    break;
                case GraphType.VerticalUp:
                    DrawVerticalUp(ratio);
                    break;
                case GraphType.VerticalSplit:
                    DrawVerticalSplit(ratio);
                    break;
                case GraphType.HorizontalLeft:
                    DrawHorizontalLeft(ratio);
                    break;
                case GraphType.HorizontalRight:
                    DrawHorizontalRight(ratio);
                    break;
                case GraphType.HorizontalSplit:
                    DrawHorizontalSplit(ratio);
                    break;
                case GraphType.Lamp:
                    DrawLamp(ratio);
                    break;
                default:
                    throw new NotImplementedException("Unimplemented graphType " + graphType.ToString());
            }
        }
Example #24
0
        public void Click()
        {
            RPMVesselComputer comp = RPMVesselComputer.Instance(vessel);
            bool switchEnabled     = true;

            if (!forcedShutdown)
            {
                if (perPodMasterSwitchValid)
                {
                    switchEnabled = comp.GetPersistentVariable(perPodMasterSwitchName, false);
                }
                if (masterVariable != null)
                {
                    switchEnabled = masterVariable.IsInRange(comp);
                }
            }
            if (!switchEnabled)
            {
                // If the master switch is 'off' and we're not here because
                // of a forced shutdown, don't allow this switch to work.
                // early return
                return;
            }

            if (isCustomAction)
            {
                if (switchGroupIdentifier >= 0)
                {
                    if (!forcedShutdown && !customGroupState)
                    {
                        customGroupState = true;
                        if (persistentVarValid)
                        {
                            comp.SetPersistentVariable(persistentVarName, switchGroupIdentifier);
                        }
                    }
                    // else: can't turn off a radio group switch.
                }
                else if (customAction == CustomActions.Plugin && stateVariableValid)
                {
                    int ivalue = comp.ProcessVariable(stateVariable).MassageToInt();
                    customGroupState = (ivalue < 1) && !forcedShutdown;
                }
                else
                {
                    customGroupState = !customGroupState;
                    if (persistentVarValid)
                    {
                        comp.SetPersistentVariable(persistentVarName, customGroupState);
                    }
                }
            }
            else
            {
                vessel.ActionGroups.ToggleGroup(kspAction);
            }

            // Now we do extra things that with regular actions can't happen.
            switch (customAction)
            {
            case CustomActions.IntLight:
                SetInternalLights(customGroupState);
                break;

            case CustomActions.Plugin:
                actionHandler(customGroupState);
                break;

            case CustomActions.Stage:
                if (InputLockManager.IsUnlocked(ControlTypes.STAGING))
                {
                    StageManager.ActivateNextStage();
                }
                break;

            case CustomActions.TransferToPersistent:
                if (stateVariableValid)
                {
                    // stateVariable can disable the button functionality.
                    int ivalue = comp.ProcessVariable(stateVariable).MassageToInt();
                    if (ivalue < 1)
                    {
                        return;     // early - button disabled
                    }
                }
                float getValue = comp.ProcessVariable(transferGetter).MassageToFloat();
                comp.SetPersistentVariable(transferPersistentName, getValue);
                break;

            case CustomActions.TransferFromPersistent:
                if (stateVariableValid)
                {
                    // stateVariable can disable the button functionality.
                    int ivalue = comp.ProcessVariable(stateVariable).MassageToInt();
                    if (ivalue < 1)
                    {
                        return;     // early - button disabled
                    }
                }
                if (comp.HasPersistentVariable(transferPersistentName))
                {
                    transferSetter(comp.GetPersistentVariable(transferPersistentName, 0.0).MassageToDouble());
                }
                break;

            case CustomActions.TransferFromVariable:
                if (stateVariableValid)
                {
                    // stateVariable can disable the button functionality.
                    int ivalue = comp.ProcessVariable(stateVariable).MassageToInt();
                    if (ivalue < 1)
                    {
                        return;     // early - button disabled
                    }
                }
                double xferValue = comp.ProcessVariable(transferGetter).MassageToDouble();
                transferSetter(xferValue);
                break;

            case CustomActions.Transfer:
                JUtil.LogInfo(this, "The deprecated CustomActions.Transfer path was executed");

                /*if (stateVariableValid)
                 * {
                 *  // stateVariable can disable the button functionality.
                 *  int ivalue = comp.ProcessVariable(stateVariable).MassageToInt();
                 *  if (ivalue < 1)
                 *  {
                 *      return; // early - button disabled
                 *  }
                 * }
                 * if (!string.IsNullOrEmpty(transferGetter))
                 * {
                 *  float value = comp.ProcessVariable(transferGetter).MassageToFloat();
                 *  comp.SetPersistentVariable(transferPersistentName, value);
                 * }
                 * else if (comp.HasPersistentVariable(transferPersistentName))
                 * {
                 *  transferSetter(comp.GetPersistentVariable(transferPersistentName, 0.0).MassageToDouble());
                 * }*/
                break;
            }
        }
        /// <summary>
        /// Evaluate the variable, returning it in destination.
        /// </summary>
        /// <param name="destination"></param>
        /// <param name="comp"></param>
        /// <returns></returns>
        public bool Get(out float destination, RPMVesselComputer comp)
        {
            if (!string.IsNullOrEmpty(variableName))
            {
                value = comp.ProcessVariable(variableName).MassageToFloat();
                if (float.IsNaN(value) || float.IsInfinity(value))
                {
                    if (!warningMade)
                    {
                        JUtil.LogMessage(this, "Warning: {0} can fail to produce a usable number.", variableName);
                        warningMade = true;
                    }
                    destination = value;
                    return false;
                }
            }

            destination = value;
            return true;
        }