IPTSCRAE SCRIPTING LESSON EIGHT
Up the River with a Hula Hoop - Flow Commands
Up until now, everything that you have been scripting runs pretty much in a logical order, from top to bottom. Controlling the flow of your code, much like controlling the flow of a river, can have some powerful implications. Maybe you can't generate electricity, but you CAN simulate it with several lightning bolts...all drawn from the same routine! In addition, you may want a certain thing to happen ONLY if certain criteria are met. Or, perhaps you would like something DIFFERENT to happen when these criteria are not met.

Truth or Dare!
You can test the truth of an expression and react appropriately with the following:

{ <atomList> } condition IF
Almost all of the examples you've done for your homework so far have used the IF command, so this should look pretty familiar by now. For example:

{ "Hi there!" SAY } CHATSTR "hello" == IF

The <atomlist> in this example is: { " Hi there!" SAY }. Everything between the { and the } is the <atomList>. The condition is: CHATSTR "hello" ==. In other words, you are testing to see that the words said are equal to "hello". If they ARE, then the condition evaluates to TRUE and a 1 is placed on the stack. If the words do NOT match, a 0 (zero) is placed on the stack. The IF command pulls the first item from the stack and looks at it. If it's value is 1 or more (TRUE) then it executes the code in the <atomList>. If the value pulled from the stack is 0 (FALSE) then the code in the <atomList> is NOT executed, it doesn't run, it is skipped over.

This command is used to create a conditional statement. Any operator (or logical series of operators) may be used to describe the condition being checked for. For example:

{ <atomList> } 4 3 > IF

will cause the code in <atomList> to run if 4 is GREATER than 3. Or:

{ <atomList> } WHOCHAT WHONAME != USERNAME IF

will cause the code in <atomList> to run if the person talking is NOT you. (Depending on where in your cyborg it is!)

{ <trueAtomList> } { <falseAtomList>} condition IFELSE
In this case, when the truth of your condition is tested, one or the other of the atomLists will be run. If the condition evaluates to TRUE (1 or greater) then the first section of code, the trueAtomList, will be run. If the condition evaluates to FALSE, the code in falseAtomList is run. An example would be:

{ "Up" SAY } { "Down" SAY } POSY 192 < IFELSE

POSY, of course, is your current vertical position. If it is less than 192, you're in the upper half of the screen, and you say "Up". If you're in the lower half of the screen, you say "Down".

Loop-d-Loo
Suppose you wanted to make the same lightning bolt 5 times, in different places on the screen? Up until now, you would have to write it 5 times. With the following command, you can now write it once, but have your routine "loop" through it as many times as you wish.

{ <atomList> } { condition } WHILE
This command creates a loop in which atomlist will continue iterating until condition evaluates to TRUE (1 or greater). Any operator (or logical series of operators) may be used to describe the condition being checked for. For instance:
{ num ITOA SAY
  num 1 + num =
} { num 5 < } WHILE
will cause you to say the numbers zero through four, then quit. As the contents in the atomList are run each time, it says the number (the variable num). num should be equal to zero when you start, although if it's been used before, it may not be. It is a good idea to set the starting values just before you run a loop to be SURE they are what you want them to be. For the above example, you would say:
0 num =
{ num ITOA SAY
  num 1 + num =
} { num 5 < } WHILE
just to be on the safe side. You assign num the value of 0 to begin with. As the loop is run, you SAY the number. Then 1 is added to num. Thus, num will be equal to 1 after the first time through, 2 after the second time through, etc. This means that when num is equal to 5, (it is no longer less than five,) you will have just finished SAYing the number "4".

A cautionary note here: be SURE that whatever you are using for a counter, or criterion for your loop is being changed each time! In this case, you are adding 1 to the variable num, and that is what is being tested in your condition for the loop. If you forget to do this, you will loop forever, possibly flooding the server and getting yourself terminated from whatever Palace you're connected to. If you find yourself in this situation, you can abort your entire script by pressing the ESC key. (If you are on a PC.) This stops the execution of your currently running script.

Escape Hatches
In addition to testing criteria, and repeating sections of code, there may be times when it is useful to quit a routine before your loop or routine has been completed. The following commands will accomplish this:

BREAK
This command breaks out of a WHILE or FOREACH (the FOREACH command was discussed in Lesson 7) loop. It may be that, during your loop, a set of conditions will happen that negates the running of the rest of the loop. Perhaps, while testing a series of strings, you find the one you want. The BREAK command will allow you to exit without executing the rest of your WHILE loop.

RETURN
This command breaks out of an atomList. An atomList is a group of commands and functions enclosed in curlybraces. This command will cause the flow to break out of that list completely.

EXIT
This command stops the currently running script. It is useful for breaking out of looping errors that might otherwise flood the server or lock up the client. This one is not to be taken lightly. It MAY stop your cyborg completely, depending on where in your code it is located. Generally, you should be writing code that tests your conditions and acts on them without having to resort to this command.

It's all in the Timing!
By now, I'm sure you've noticed that your routines don't always do things when you want them to. Sometimes you may want a delayed response to some input. You may want some routine to execute slower for "visual effect". There are two commands that affect the timing of events.

{ <atomList> } <ticks>ALARMEXEC
This command schedules an atomlist to be executed at a pre-specified time (after so many "ticks" have elapsed). The user's subjective duration of a "tick" depends on the speed of both the client and server as well as network load at the moment, but it is considered to be 1/60th of a second. So, a delay of 1 second would be 60 "ticks", of one minute would be 3600 "ticks". For example:

{ -10 -10 MOVE } 300 ALARMEXEC

would move you up 10 pixels and 10 pixels to the left after 5 seconds have passed.

number DELAY
This command causes a delay affecting ALL activity on the client -- events, alarms, queued commands and even prop animations -- for the duration specified by number. Unlike most time-based commands (which measure time in ticks), the DELAY command is based on units of 0.05 seconds (1/20th of a second). This is the equivalent of three ticks. In other words: 1 second == 60 ticks == 20 DELAY units. Note that ALARMEXEC is preferred since it doesn't lock up all processes on the client, although use of the DELAY command might be appropriate in a game.

Variability
It's time to talk a little more about variables. You've been using them all along, but now we want to examine them in a little more depth. As you know, a variable is simply a name, or symbol for a piece of data. When you are constructing your code, you can assign a piece of data to a variable:

42 num =

and then use the variable name throughout your routine:

64 num + num =

will add 64 to the value stored in num and then reassign the total of that computation to num.

Variables can hold strings, numerical values or arrays. And, in Iptscrae, you can change the type of data stored in a variable "on the fly", as it were. A variable that contained a numerical value during one command can contain a string value during another command.

Only your memory or a naming convention, (such as giving your string variables names ending in "Str", for example), is going to help you remember which is which. Variable names must start with a letter, and may contain any combination of letters, numbers and the underscore ( _ ) character. The names may not contain any spaces.

Variables provide a handy way to specify data in one part of a routine, then recall or change that data, and still use the same name for it. For instance, you could say:

MOUSEPOS y = x =

This would put two pieces of data, the horizontal and vertical positions of the mouse, in that order, on the stack. Then, those values would be assigned to "y" and "x". (We assign the y (vertical) value first because it was the LAST information put on the stack!) Now, you can manipulate these values in your code. For example:

WHOME WHOPOS y = x =
"Speak here!" x 44 - y SAYAT

Which would cause you to SAY the words, "Speak here!" higher on the screen than you would normally.

If you want to save the value of your variable between uses, or to use the value in another handler, you must make that variable visible (persistent) throughout your routines. To do that you use:

symbol GLOBAL
This command declares the symbol as a global variable, which allows it to be shared among event handlers. The GLOBAL command must be used in EVERY event handler in which the global variable is used, even in the same room. It is good practice to declare your globals as soon as you enter the handler in which they will be used; this makes it easy to remember which ones you need and what you were doing.

This lets you put a piece of data into a variable with one routine, then recall it later for use by another routine. Without that, any data you put into a variable is lost when the routine is finished. This is often used in "status" variables - a variable that signals if a given routine is "on" or "off". For instance:

ON OUTCHAT {
  bot GLOBAL
  { 1 bot =
  } CHATSTR "bot on" == IF
  . .
}  

Would let you set a variable named bot to 1 when you said, "bot on". Then, for the routines you would want the bot to run (most of them are usually in the INCHAT handler, since it responds to something someone says), you would simply do this:

ON INCHAT {
  bot GLOBAL
  { code for bot routines
  } 1 bot == IF
}  

If bot was NOT equal to 1 (off), none of the bot routines inside the {} would be run. If it was on, equal to 1, then those routines would be checked, and run if applicable.

HOMEWORK:
1. Start creating your own bot! Make it so that you can turn it on by saying "bot on" and turn it off with "bot off". When the bot is on, have these two routines in it:

a. If someone says "Who taught you?", say "<teacherName> taught me!"
b. If someone says "shut up" anywhere in their conversation, say "That's not polite!"

2. Make two routines to create a self-spoofing routine. The first sets two variables when you say "set talk". It calculates the row and column differences between your position and the mouse position. The second one is triggered when you say "ss <whatever>" It will say the <whatever> the specified amounts away from your center.

3. Make a routine that will slowly move you in a large circle around the middle of the screen. Have at least 8 stops along the circle (which would make it an octagon, I suppose), with you taking five seconds between each hop. Have it all triggered when you say the word "orbit".

4. Make a routine that, if anyone mentions the word "spot" in conversation, you respond saying, "that's <number>", where number is how many times you've heard the word "spot". In other words: "that's 1", "that's 2", etc.

CHALLENGE:
Write a routine that explains an Iptscrae command, function or other programming principle. This script is one that you would run to show OTHER people how the command or function works.

NOTES:
ALARMEXEC is a special kind of command. It will delay whatever is inside it's OWN atomList, but all the rest of your code in your routine will run normally. In addition, it does NOT see variables declared above it, unless they are declared as GLOBAL and then are declared inside it's own atomList. For example:

WHOME WHOPOS y = x =
  -code that changes your position-
{ x y SETPOS } 600 ALARMEXEC

will NOT return you to your original position! ALARMEXEC will not know what the previous values of x and y are. Instead, you will need to declare those variables as GLOBAL: This example:

x GLOBAL y GLOBAL
WHOME WHOPOS y = x =
  -code that changes your position-
{ x GLOBAL y GLOBAL x y SETPOS } 600 ALARMEXEC

will work as you expected.

<Previous> <Iptscrae> <Next>