The Select Function
The SELECT Function is used to perform one of several different functions
based on the current value of an analog variable. This is the most complex
function in the instruction set, but it is also very powerful.It basically
accepts an analog input value, decides which range the value is in, and
then executes instructions based on that zone. Those with programming
experience will recognize this as a modified form of the "case" or
"switch" statements available in most programming languages. Note that
the SELECT Function may not be used within a SEQUENCE block.
The basic form of the Select Block is:
SELECT( INPUTVALUE, TYPE ) OF
// CASE Definitions go here
ENDSELECT
"INPUTVALUE" is the analog value that is controlling the block and can be a
single variable or a mathematical expression. "TYPE" can be either
"POSITION" or "RANGE" and controls how the select statement operates.
Basically, if the TYPE is set to "POSITION", the Select statement will
respond to a change in its current zone by simply doing whatever is required
to exit the current zone and then doing whatever is required to enter the
new zone.
If the TYPE is set to "RANGE", the Select control responds differently
in that, while it also moves from the current zone to the new zone, it
executes all zones in between. For example if an input were to change
suddenly from zone 1 to zone 3, the POSITION type would simply exit zone
1 and enter zone 3. The "RANGE" type would exit zone 1, enter zone 2, exit
zone 2 and enter zone 3.
Of course, a "POSITION" type moved relatively slowly will do exactly the
same thing since it will pass through zone 3, there are times in game play
where controls are moved quickly enough that zone 2 might not be seen by a
"POSITION" control.
Following the Select statement is the word "OF". This is followed by
a series of "CASE" statements, each of which defines the limits of a zone
and the actions to be performed when that zone is entered or exited. These
statements begin with the word "CASE", followed by a positive numeric constant
and a colon. Entry actions are always specified. An Exit actions can also be
included by separating the Entry and Exit actions by the word "EXITCASE",
though the EXITCASE is entirely optional. The end of each case is marked
with a "BREAK" statement.
The Select Block might look something like this
SELECT( JS1.A1, RANGE ) OF
CASE 0:
B1 = TRUE;
EXITCASE:
B1 = FALSE;
BREAK;
CASE 64:
B2 = TRUE;
EXITCASE:
B2 = FALSE;
BREAK;
CASE 128:
B3 = TRUE;
EXITCASE:
B3 = FALSE;
BREAK;
CASE 192:
B4 = TRUE;
EXITCASE:
B4 = FALSE;
BREAK;
ENDSELECT
This would divide the JS1.A1 axis up into 4 zones. The standard axis range
(0..255) applies to JS1.A1 and so it would divide it in equal quarters
separated at the value 64, 128, and 192. As the control was moved through
its range, B1 would turn on in the lower quarter, then B2, B3, and finally
B4 as the control were moved from its low end to its high end, with B4
being on in the upper quarter of the controls range.
Note that the defined zones run from one value all the way to the next,
i.e. the value following "CASE" is actually the lower limit of a zone which
continues upward to next higher CASE value minus 1. The highest valued
zone is considered to be in effect for any value above its minimum value.
In the above, any value on JS1.A1 about 191 is considered to be in the
fourth zone.
If the lowest valued CASE statement is greater than zero, there's another
"do nothing" zone considered to extend from zero to one less than the
minimum case value. If the input value is less than the lowest defined
zone, then nothing will happen on entry or exit from that zone.
Each case has an EXITCASE: entry. The code between the CASE and EXITCASE
statement will be executed when the value enters that zone. The code
between the EXITCASE: and the BREAK statement will be executed when the
analog value leaves that particular zone. CMS maintains synchronization
with the character processor during zone changes, so that a character
sent in an EXITCASE statement will actually get sent before a character
set in the CASE statement for the new zone.
As mentioned above, the EXITCASE is optional. A case can be declared like
this:
CASE 100:
B1 = TRUE;
BREAK
In this case, the first time that the input variable exceeded 100, B1 would
be set. Some means would need to be provided to set B1 FALSE eventually, a
button perhaps. Otherwise it would just stay on permanently.
Statements in CASE Definitions
Only a few types of statements are allowed within the CASE definitions to
avoid some problems that can occur. The allowed statements include IF/THEN,
IF/THEN/ELSE and the SCALE statement as well as the basic assignment
operations ("="). Sequences are not allowed nor are device definitions,
though device references are perfectly acceptable.
It is possible to control these things from the Select Block, though. For
example, this would cause a sequence to execute whenever js1.a1 had a value
greater than 128 (center):
SCRIPT
// First, set it up so B1 is TRUE when we're above center.
//
SELECT( JS1.A1, POSITION ) OF
CASE 0:
BREAK;
CASE 128:
B1 = TRUE;
EXITCASE:
B1 = FALSE;
BREAK;
ENDSELECT
// Now run a sequence based on B1 (We're not in the
// select block now so anything goes);
//
SEQUENCE
WAIT( B1 ); // Wait for b1
CMS.B1 = TRUE; // Turn on CMS.B1
DELAY( 20 ); // Leave it on for about a second
CMS.B1 = FALSE; // Turn it off
ENDSEQUENCE
ENDSCRIPT
That really only scratches the surface of what can be done with this
function, but that should give some idea of what it can do and how it fits
together.