Author Topic: Variables and tokens summed up  (Read 14782 times)

Pfeil

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4647
  • RTFM
Variables and tokens summed up
« on: October 06, 2020, 08:37:53 PM »
For more advanced VoiceAttack logic, it is highly likely at some point you will need variables, tokens, or a combination of both.

This topic will attempt to sum up basic information on both of these concepts.

Note that this topic is not intended as a replacement for the official documentation; For detailed information on VoiceAttack's features, you can press F1 while VoiceAttack has focus to open VoiceAttackHelp.pdf in your default PDF viewer.


Starting off with variables, they are what your computer uses to store information in its working memory (E.G. in RAM); By creating a variable, you're reserving a piece of memory that will hold the information you're storing.


In VoiceAttack, a variable has three important components: A type, a name, and a value.

The type of a variable determines what kind of information can be stored in it.

The name is used to reference the variable whenever you want to read from, or write to it.

The value is the actual information you've stored.


VoiceAttack, like the C# programming language it's written in, is strongly-typed. This means you must tell the computer beforehand which kind of information you're going to store, both so the correct amount of memory can be reserved, and so the computer knows how to process that information.

VoiceAttack (v1.8.6 at the time of writing) currently provides the following types:
Small Integer
Integer
Decimal
Text
Boolean
Date/Time

The Small Integer and Integer types both store integer (meaning whole) numbers. The only functional difference is that the former is limited to storing numbers between -32768 and 32767, whereas the latter can store numbers between -2147483648 and 2147483647

Small Integer is a holdover from early versions of VoiceAttack, where it was the only variable type (which meant you could only store integer numbers in those versions). As VoiceAttack now has many other variable types available, it is highly recommended to use the regular Integer type instead (the intention is to phase out Small Integer entirely at some point).


The Decimal type can store non-integer numbers, I.E. numbers with digits after the decimal separator. It can store values between -79228162514264337593543950335 and 79228162514264337593543950335


The Text type stores a string of encoded characters. This means that, while you can store characters that represent a number, those characters are not directly usable for mathematical operations, or other features that expect a non-text variable.
Text variables can store enough characters that you shouldn't run into the actual limit, though not all fields will let you enter large amounts of characters.


The Boolean type stores a Boolean value, which can be used to represent a state of either True, or False
As an example, if you want to keep track of whether your landing gear is deployed, you can use a Boolean variable that's set to True when the gear is deployed, and False when it's stowed.


The Date/Time type stores a given point in time, with a precision of up to 100ns (nanoseconds), though for VoiceAttack you're unlikely to need that level of precision.
Note that it stores a point in time, not an amount of time. If you want to store the amount of seconds that have elapsed since a certain event, for example, you'd have to use an Integer variable for that.


Aside from each of these type-specific values, each variable can also have a value of "Not set", which means there is no value to retrieve.
This can occur when a variable has not been created yet, if its value has been removed, or if the variable has been removed from memory (E.G. using the "Clear value (set value to Not Set)" option).


Variable names can consist of up to 512 characters of text, and cannot contain ':', or ';' characters, unless they are part of a token; '{' and  '}' are technically allowed, but using them outside of tokens may cause issues, and is not recommended. It is also recommended not to have your variable name end with a "#" character, as this is used to make VoiceAttack trigger events (an advanced feature for use in inline functions and plugins).
They are not case-sensitive, meaning "my variable", "MY VARIABLE", and "mY vARiaBle" all reference the same variable.

You are free to type in whichever variable name describes to you what the variable is for (E.G. an Integer variable could be named "Missiles remaining")
The only exception to this is when passing variable values using the "Passed Values (Advanced)" feature of the "Execute Another Command" action, in which case VoiceAttack will create new variables with the passed values; Documentation on these predetermined names can be found in VoiceAttackHelp.pdf

It is also worth noting each type of variable has its own collection of variable names, meaning you can technically have a Text variable named "My Variable", as well as an Integer variable named "My Variable" (and, given that they're different types, they will coexist; The type of variable a given field expects determines which of the two would be used internally), and so on for each type, however for the sake of readability it is recommended to use unique variables names, regardless of type.


Variable values can be set by you, the user, using the appropriate "Set a" action for the type of information you're storing, or by other VoiceAttack features, like the "Wait For Spoken Response" and "Loop Start - Repeat a Certain Number of Times" actions, as well as third-party plugins.

Once a variable value is set, it will not change unless it is explicitly changed again, either using a "Set a" action, or another action that sets variables.



Onto tokens: One important thing to keep in mind, is that tokens are not variables; Variables store information, tokens either retrieve information, or process information, but they do not store it.

Tokens can be used in fields that explicitly state that they accept tokens; This is normally mentioned in the tooltip (shown when hovering the mouse cursor over the edge of the field), and the documentation in VoiceAttackHelp.pdf


There are four main kinds of token:

Tokens that retrieve a predetermined piece of information, E.G. the "{TIME}" token, which retrieves the current system time in a specific format (hours and minutes, separated by a colon, in a 24-hour format).

Tokens that retrieve a user-selectable piece of information, E.G. the "{TXT:}" token, which retrieves the value of a Text variable.

Tokens that perform an operation on information given by the user, E.G. the "{RANDOM:}" token, which takes two numbers, and returns a random number that either equals, or falls within the value of the given numbers.

Tokens that perform an operation, and retrieve user-selectable information to use in that operation, E.G. the "{TXTLEN:}" token, which can take a variable name, retrieve the contents of that variable internally, and perform an operation on that retrieved value, in this case counting the amount of characters in that text variables' value.


When a token is processed, the output of the token (E.G. the information retrieved, or the result of an operation) will replace the literal text of the token itself. This means that a token always, without a singular exception, is text. As mentioned in the section on variables, while text can look like a number, it is in fact a series of encoded characters.
E.G. if you input "{DATEYEAR}" into a field, that will be replaced by "2020" (at the time of writing) when the action runs. To most actions that parse tokens, this is identical to manually typing "2020" into that field.
Note that some fields will take both variable names or tokens, in which case not using a token can cause literal text to be interpreted as a variable name, rather than a literal value.

Note that tokens are case-sensitive, meaning "{TimeHour}", "{timehour}", or "{tiMEhOur}" will not work, only "{TIMEHOUR}" will.
With the singular exception of the "{time}" token, all tokens are written fully uppercase.


A very useful action in both experimenting with tokens, and testing commands, is the "Write a Value to the Event Log" action.
If you're unsure what a token will do, or how to write out its parameters, this action is invaluable, as it will show what the token will be replaced with directly in the log on VoiceAttack's main window (if you're dealing with values that may contain or especially consist solely of whitespace characters like spaces, you'll want to wrap the token in double quotes, or similar delimiters, so you can tell the difference between blank, and whitespace)


As mentioned, tokens are equivalent to literal text in most fields that accept them.

This means that they can substitute parts of literal text as well (I.E. a field does not have to be filled with either a token or literal text; As they are equivalent, you can use both at the same time).
A common example usage is in the "Say Something with Text-To-Speech" action, E.G.
Code: [Select]
Say, 'The time is now {TIME}'
Provided the "Use Nested Tokens" option on the "System / Advanced" tab of the VoiceAttack options window is enabled (which it is by default), it is also possible to nest multiple tokens inside each other. Nested tokens are processed from the innermost token outward.

A non-practical example would be
Code: [Select]
Set text [Text Variable containing "riab"] to 'riab'
Set text [Text Variable containing "M"] to 'M'
Set text [Text Variable containing "E"] to 'E'
Say, 'The time is now {TI{TXT:Text Va{TXT:Text Variable containing "riab"}le containing "M"}{TXT:Text Variable containing "E"}}'
where parts of tokens are substituted by other tokens, up to three tokens deep (there is no hard limit on how many levels you can nest tokens, though at some point you'll probably want to consider other methods in addition to, or instead of a stack of tokens, just to keep it readable/maintainable).

In the above example, '{TXT:Text Variable containing "riab"}' is processed first, which then forms the second token to be processed, '{TXT:Text Variable containing "M"}'. Next, '{TXT:Text Variable containing "E"}' is processed; At this point the text is 'The time is now {TIME}', which is then processed to reflect the current system time, E.G. 'The time is now 11:30', before being spoken by the text-to-speech system.



Advanced: Variable scope

Variable scope refers to the accessibility and lifetime of a given variable.

By default, all variables are globally-scoped, meaning they can be accessed from any command, in any profile, and they aren't removed until VoiceAttack itself shuts down (which removes all variables within all scopes), or an action is used to explicitly remove them.

In VoiceAttack, variable scope is determined by the characters at the beginning of the variable name.

If a variable name begins with ">", it is only available while the current profile is the active profile, and it will be removed if your change profiles.

If a variable name begins with ">>" it is only available while the current profile is the active profile, but changing profiles will not remove it, meaning if you switch back to the profile in which the variable was created, it will still be available.

If a variable name begins with "~", it is only available within the command in which it is created, and will be removed once that command has finished executing.

If a variable name begins with "~~", it is only available within the command in which it is created, and any commands started from that command using the "Execute Another Command" action provided the "Wait until this command completes before continuing" is enabled; In this case the variable will be removed when the original command has finished executing.
If that option is not enabled, the executed command will create its own copy of the variable, separate from the original, meaning that changes to that variable's value made in one command will not be propagated to the other. In this case, each command will remove its own copy of the variable when it has finished executing


Variable scope can be useful if you want to run multiple instances of the same command without having them interfere with each other, if you want to reuse sets of actions in multiple commands, or to have a known state when a command starts (E.G. if you use a "~" prefixed variable, you can be sure that when the command starts, it will be "Not set", so there is no risk of a value being left over from another execution).
« Last Edit: October 07, 2020, 10:20:56 AM by Pfeil »