Toggle syntax - KSPSnark/IndicatorLights GitHub Wiki

What's a "toggle"?

In IndicatorLights, a "toggle" is a type of object that exposes a single boolean value, which may change dynamically at run time. This can be used to control the behavior of color sources on the ship.

IndicatorLights provides a variety of toggle syntax options to allow achieving various complex effects. This page describes the syntax of toggle parameters and provides some examples.

Please see the IndicatorLights syntax overview for a high-level summary of the syntax language, a discussion of the various other types of syntax available besides toggles, and debugging tips.

Note that toggles, like all IndicatorLights syntax, can be nested to form complex expressions. For example:

and(toggle1, or(toggle2, toggle3), gt(someScalar, 0.5)) ...would evaluate to true if toggle1 is true, and at least one of toggle2 or toggle3 is true, and the value of someScalar is greater than 0.5.

Where's the code?

See Toggles.cs for the source code in IndicatorLights that handles the parsing of toggles.


Types of toggle

The following types of togglesyntax are supported:

  • Constants (e.g. "true", "false")
  • Reference (e.g. an identifier for some toggle module on the part)
  • Parameterized (e.g. "take the logical AND of <some toggle module> and <some other toggle module>")

The following sections describe the syntax for each of these types of toggle.

Special modifier: The ! operator

You can use a ! sign as a prefix on any legitimate toggle syntax. This is a convenient syntactic shorthand meaning "take the logical NOT of".

Thus, for example, if "foo" evaluates as a legitimate toggle reference, then "!foo" would be legal syntax meaning "the opposite of whatever foo's toggle output value is."


Constants

The following two special constants are supported in toggle syntax:

  • true
  • false

...they mean exactly what you'd think.

As a practical matter, these typically aren't used much in "real" config, since they're not really directly useful-- in general, any expression with one of these in it can be written in a simplified form to remove the need.

However, they're provided as a useful tool for debugging your syntax; you can stick them in to a complex expression as useful placeholders while whittling down the behavior to exactly what you want.


Reference

This is a simple but powerful feature that enables using the output of toggle modules to control a color.

A "toggle module" is one that supports the IToggle interface. An example of this would be ModuleResourceEnabledIndicator, whose toggle value is true when the resource is enabled, false when it's disabled. Please see the controller reference for documentation on individual controller types, including which ones support IToggle.

The reference syntax is very simple.

  • By controller name: The ModuleEmissiveController base class (and therefore all its subclasses) has a controllerName property. (See Setting up a ModuleEmissiveController for details.) You can use that name as a toggle reference, if the module is one of the types supporting IToggle. If a controller on the part has set its controllerName to "foo", for example, then you can simply use the string "foo" as a toggle value, which means "go find the controller whose name is 'foo' and use its current output toggle value".
  • By class: If a controller doesn't set its controllerName property (i.e. the value is empty or null), then you can refer to it by its class name, e.g "ModuleResourceEnabledIndicator" or "ModuleToggleLED" or whatever.
  • By field & module name: You can specify any arbitrary boolean field of any PartModule with syntax like this: fieldname@modulename.
    • Example: motorEnabled@ModuleWheelMotor
    • This syntax variant is useful in that it allows you to toggle any boolean field of any PartModule (not just IndicatorLights modules): e.g. stock modules, or even modules from other mods.
    • However, it does have some important limitations to be aware of. It only works on public fields that are annotated as "KSPField". Also, for non-IndicatorLights module, there's no way to distinguish individual modules by name-- only by module type. So if you target someField@ModuleFoo, it will just use the first ModuleFoo that it finds; there's no way to pick "which one" if there happens to be more than one ModuleFoo on the part.
    • See example file ArbitraryFieldInputs.cfg for how to use this syntax.

Note that you can only use the class name for a controller if it doesn't set a controllerName. Essentially, what using the class name does is, "find the first module on the part of this type that doesn't have a controllerName set, and use the output value of that."


Parameterized

This is the most complex (but most flexible and powerful) type of toggle syntax. It allows specifying some complex behaviors by using parameters.

A parameterized toggle has the form:

functionName(param1,param2,param3,...)

The number and type of parameters will depend on what the function is.

The following functions are currently supported (more may be added in the future):

and

This takes the logical AND of two or more toggle inputs.

and(toggle1, toggle2, ...)

Parameters:

  • Each input parameter is a toggle expression.
  • The output value of this expression will equal the logical AND of all the inputs.

Example: and(a, b, c) will evaluate to true if a, b, and c are all true, false otherwise.

or

This takes the logical OR of two or more toggle inputs.

or(toggle1, toggle2, ...)

Parameters:

  • Each input parameter is a toggle expression.
  • The output value of this expression will equal the logical OR of all the inputs.

Example: or(a, b, c) will evaluate to false if a, b, and c are all false, true otherwise.

gt

"gt" for "greater than". This converts an input scalar value to a toggle, whose value is true if the input's value is greater than the specified amount.

gt(input, minimum)

Parameters:

  • input: A scalar value to transform.
  • minimum: A static value representing the lowest allowable value. Output is true if the input is greater than this, false if it's less than or equal to it.

Example: gt(foo, 0) means "return true if foo > 0, false if foo <= 0".

lt

"lt" for "less than". This converts an input scalar value to a toggle, whose value is true if the input's value is less than the specified amount.

lt(input, maximum)

Parameters:

  • input: A scalar value to transform.
  • maximum: A static value representing the highest allowable value. Output is true if the input is less than this, false if it's greater than or equal to it.

Example: lt(foo, 0) means "return true if foo < 0, false if foo >= 0".

ge

"ge" for "greater than or equal". This converts an input scalar value to a toggle, whose value is true if the input's value is greater than or equal to the specified amount.

ge(input, minimum)

Parameters:

  • input: A scalar value to transform.
  • minimum: A static value representing the lowest allowable value. Output is true if the input is greater than or equal to this, false if it's less than it.

Example: ge(foo, 0) means "return true if foo >= 0, false if foo < 0".

le

"le" for "less than or equal". This converts an input scalar value to a toggle, whose value is true if the input's value is less than or equal to the specified amount.

le(input, maximum)

Parameters:

  • input: A scalar value to transform.
  • maximum: A static value representing the highest allowable value. Output is true if the input is less than or equal to this, false if it's greater than it.

Example: le(foo, 0) means "return true if foo <= 0, false if foo > 0".

between

This converts an input scalar value to a toggle, whose value is true if the input's value is between the specified maximum and minimum values, inclusive.

between(input, minimum, maximum)

Parameters:

Example: between(foo, 0, 1) means "return true if foo >= 0 and false if foo <= 0". This yields exactly the same result as if you had said and(ge(foo, 0), le(foo, 1)), but with simpler syntax and (potentially) somewhat better performance.

situation

This is a toggle that evaluates to true if the current vessel's situation matches any of a specified list. You can use this if, for example, you want to have an indicator like "show one thing if I'm landed, something else if I'm not."

situation(situation1, situation2, ...)

Parameters:

  • Must specify one or more situations.
  • Each situation provided must be one of the Vessel.Situations enum values. Here's the list of valid ones (note, if you make a mistake, there will be a logged error message that tells you what all the valid values are):
    • LANDED
    • SPLASHED
    • PRELAUNCH
    • FLYING
    • SUB_ORBITAL
    • ORBITING
    • ESCAPING
    • DOCKED

Example: situation(LANDED, SPLASHED, PRELAUNCH) means "return true if the vessel is landed, splashed, or hasn't left the launchpad yet". See the VesselSituation.cfg example file for a working example of how this syntax can be used.

controlLevel

This is a toggle that evaluates to true if the current vessel's control level (e.g. due to CommNet status) matches any of a specified list.

controlLevel(level1, level2, ...)

Parameters:

  • Must specify one or more control levels.
  • Each control level provided must be one of the Vessel.ControlLevel enum values. Here's the list of valid ones (note, if you make a mistake, there will be a logged error message that tells you what all the valid values are):
    • NONE
    • PARTIAL_UNMANNED
    • PARTIAL_MANNED
    • FULL

Example: controlLevel(FULL, PARTIAL_UNMANNED, PARTIAL_MANNED) means "return true if the vessel has any control at all". See the VesselControlLevel.cfg example file for a working example of how this syntax can be used.

hasCrewEffect

This is a toggle that evaluates to true if the crew in the part has a particular specified skill (such as "can operate drills" or "can reset science experiments"). It can be set up to apply either to a particular crew slot, or to the part as a whole.

hasCrewEffect(effectName, slot)

hasCrewEffect(effectName, slot, minLevel)

Parameters:

  • effectName: Required. A string, giving the name of a particular effect for some type of kerbal. Here is the list of all effect names in the stock game (note that mods could add additional effect types):
    • AutopilotSkill
    • ConverterSkill
    • DrillSkill
    • ExternalExperimentSkill
    • FullVesselControlSkill
    • GeeForceTolerance
    • PartScienceReturn
    • RepairSkill
    • ScienceResetSkill
    • ScienceSkill
    • SpecialExperimentSkill
    • VesselScienceReturn
  • slot: Required. A static value specifying which crew slot has to match the required effect in order for the toggle to evaluate to true. If this is set to 0 or greater, it specifies a particular crew slot on the part. If it's set to a negative number, it means "evaluate to true if any crew slot matches."
  • minLevel: Optional. A static value specifying the minimum level of that effect required for the toggle to evaluate to true. If omitted, defaults to "no minimum, any level is okay".

Example 1: hasCrewEffect(DrillSkill, -1, 2) means "evaluate to true if any crew on the part has the DrillSkill and is level 2 or higher."

Example 2: hasCrewEffect(ScienceSkill, 0) means "evaluate to true if the crew in slot 0 has the ScienceSkill at all (even if it's only level zero)". See scienceLab.cfg for a working example of this usage.