Prog Section 3

From Immwiki
Jump to: navigation, search

Control Structures

"We offered them ORDER!" 
   -- Khan, Star Trek: Episode 24: Space Seed
As we have seen, control structures allow us to alter the normally linear order
in which program commands are executed.

If Checks

The most common type of control structure is the if check, which tests to see if
a certain aspect of the game world is true or false. An if check alters the flow of
the program so that if it is true, a block of commands following the check will be
executed. If it is false, these commands will not be executed, and execution of the
program will skip past them. Every if statement appears before a block of commands,
and must always have a matching endif statement, to mark the end of this block of
commands. The syntax of an if check is generally:
if check([<argument1>]) <logical operator> <argument2>
[block of commands]
endif
The check is the actual if check. The check is really a function, which tests an
aspect of something in the game world. This can be something as simple as whether
or not a target is a pc, or as complex as a person’s percentage in a particular
skill or spell. The argument 1 is the pc, mobile, object, number, or other entity
which is being checked. Generally, the target is a variable. It can, however, be a
number, or the literal name of the pc or npc in question. A check can also have a
blank argument, in the case of checks which do not require a target. The logical
operator expresses a logical relationship between the argument1 and the argument2
of the if check. The operator can either be numerical (if either side resolves to
a number), or a string operator (if either side resolves to a string.)
The following are numerical operators:
   == equality 
   != negation of equality (i.e., "is not equal to") 
   < less than 
   <= less than or equal to 
   > greater than 
   >= greater than or equal to 
   & Bitwise and 
   | Bitwise or 
The following are string operators:
   == Exact equality 
   != Strings do not match 
   / String contains the given text 
   !/ String does not contain the given text 
As can be seen, not every logical operator works for every if check. In
general, if the result of a check’s evaluation is not numerical, only the first
two operators can be used (as these are the only ones which do not require a
number to appear to either side.)
The argument2 is an argument which is compared to the result of the check. Generally
speaking, this can be a variable that represents a pc, mobile, object, a number, or
some other form of data. So, putting this all together, let’s consider a few examples
of some if checks.
   greet_prog 100
   if ispc($n)
   say Hello, $N. 
   endif
   say $N just entered the room.
This is a simple program, that will greet a pc if they enter the room, then let everyone
know the name of anything that enters a room, even if it’s not a pc. So, in this prog,
we can see that:
- The check is ‘ispc’
- The argument1 is ‘$n’
- There is no logical operator.
- There is no argument2.
- The if block is one line: "say Hello, $N".
- The endif comes right after that.
Remember, the only required thing for an if check is the if, the check, and the endif.
Now, let’s suppose Jolinn, and his (Charmed) Ethron Love NPC were to enter a room, and
this prog is on a hen. (Yes, a hen.) Someone standing in the room would see:
The hen says, ‘Hello, Jolinn’
The hen says, ‘Jolinn just entered the room.’
The hen says, ‘The hawt ethron love slave has just entered the room.’
As we can see, since the ethron love slave is not a pc, the commands in the if block
are not executed.
Now, what have if checks really allowed us to do? Basically, we can now say, "If a
condition is TRUE, then execute a specified list of commands." But, what if we want to
say, "If a condition is TRUE, then execute a specified set of commands. However, if it’s
FALSE, execute a different set of commands"? To help us with this scenario, we have the
else command. This command allows you to specify alternate set of commands in a body of
an if check, to be executed in the event that the check does not return a true result.
To see how else works, let’s return to our example.
   greet_prog 100
   if ispc($n)
   say Hello, $N. 
   else
   say I would say hello, $N, but you’re just a mobile.
   endif
   say $N just entered the room.
In this case, if Jolinn and his ethron entered the room, they would see:
The hen says, ‘Hello, Jolinn.’
The hen says, ‘Jolinn just entered the room.’
The hen says, ‘I would say hello, a hawt ethron love slave, but you’re just a mobile.’
The hen says, ‘A hawt ethron love slave just entered the room.’
As we can see, the commands after the else statement are executed for the ethron, since
the ethron is NOT a pc, and therefore the else block has its triggered.
Now, suppose that we have an effect which we want to occur under multiple conditions. An
example might be: A mob who will speak either to an aelin OR a nefortu when given a sum
of a gold. Now, we can easily do this by having two (or more) if check blocks in a row,
but this requires us to unnecessarily duplicate commands. To this end, we introduce the
or statement, which allows us to have an if-block that executes on any of multiple conditions
being satisfied.
Consider the following example:
   speech_prog p Hello
   if race($n) == aelin
   or race($n) == nefortu
   say Why hello to you too, $N.
   else
   say Hmph. Whatever, wingless person! You are dead to me!
   endif
So, if:
An aelin said "Hello", they would see: ‘Why hello to you too, aelin.’
A nefortu said "Hello", they would see ‘Why hello to you too, nefortu.’
An ethron said "Hello", they would see ‘Hmph. Whatever, wingless person! You are dead to me!’
So, the or check allows multiple possible conditions to trigger the same if block.
Now, what if we want to execute a block of commands when two (or more) simultaneous
conditions hold true at once. For example, suppose we want a mob that attacks a target
if it both a pc AND an ethron. Or, suppose we have a sword that requires you be good
AND lawful to wield. We can even imagine situations where we might want three, four,
five, or even an arbitrary number of conditions to hold true.
To support this functionality, progs support the "nesting" of if check. "Nesting" means
that you can put one if check (including its body, else statement, endif) inside of another
if check. So, in essence, we would have:
   if check1(var)
       if check2(var)
       command
       command
       command
       else (optional)
       command
       endif
   else (optional)
   endif
Essentially, the if block of check2 is a subset of the if block of check1. The commands
in check2’s block are only executed if both check1 and check2 are true. To illustrate how
this works, let’s consider a concrete example. Suppose that this prog appeared on a hen:
   prog add speech_prog p Hello
   if ispc($n)
     if race($n) == ethron
     say Why hello there, $N, you beautiful green thing, you!
     else
     say Why hello there, $N.
     endif
   else
   say You’re nothing more than a drone, $N!
   endif
Let’s suppose we have Jolinn, who is a human, Aeolis, who is an ethron, and a hot ethron
love slave, who is an npc who is an ethron.
If...
Jolinn says, "Hello", he would see:
The hen says, "Why hello there, Jolinn."
Aeolis says, "Hello", he would see:
The hen says, "Why hello there, Aeolis, you beautiful green thing, you!"
A hawt ethron love slave says, "Hello", she would see:
The hen says, "You’re nothing more than a drone, hawt ethron love slave!"
As we can see, "nesting" results in a block of commands which is executed only if BOTH
checks are true. This is perfectly equivalent to the logical AND, "If A AND B are true,
then do C".


Loops

Often times, we may wish to repeat a command a certain number of times in a program.
Now, clearly, we could do this just by including that number of copies of the command,
but this solution leaves certain things to be desired. Firstly, it is inefficient
(what if we want to execute a command a hundred times?). Secondly, and most importantly,
it does not allow us to execute a command a variable number of times.
Loop Syntax:
   Loop <low number> to <high number>
   command_1
   command_2
   .
   .
   command_n
   endloop
This will execute the commands in the loop (1-n), a number of times equal to high
number - low number. In general, low number and high number are both numbers, or variables
whose values resolve to being numbers. Just like if checks, you can "nest" loops, by placing
one loop block inside of another one.
In a loop, you can reference the "iteration", or number the loop is on, by the $v variable,
adjoined to a number. The number represents the "depth" of the loop you are currently in.
So, by default, $v1 references the outermost loop’s current iteration. $v2 references the
next innermost loop iteration, and so on, until $vn, where n is the innermost loop iteration.
This can be a little confusing, so let’s give a concrete example. Suppose that our favorite
counting hen has a prog that reads:
   prog add speech_prog p Loopy
   loop 1 to 3
     say The outermost loop is on number $v1.
     loop 1 to 2
       say The second loop check is on number $v2.
       loop 7 to 8
         say The innermost loop check is on number $v3.
       endloop
     endloop
   endloop
   say The loop now, is ended.
So, if you were to say "Loopy" to the hen, you would see the following:
   The hen says, ‘The outermost loop is on number 1.’ 
   The hen says, ‘The second loop check is on number 1.’ 
   The hen says, ‘The innermost loop check is on number 7.’ 
   The hen says, ‘The innermost loop check is on number 8.’ 
   The hen says, ‘The second loop check is on number 2.’ 
   The hen says, ‘The innermost loop check is on number 7.’
   The hen says, ‘The innermost loop check is on number 8.’
   The hen says, ‘The outermost loop is on number 2.’
   The hen says, ‘The second loop check is on number 1.’
   The hen says, ‘The innermost loop check is on number 7.’
   The hen says, ‘The innermost loop check is on number 8.’
   The hen says, ‘The second loop check is on number 2.’
   The hen says, ‘The innermost loop check is on number 7.’
   The hen says, ‘The innermost loop check is on number 8.’
   The hen says, ‘The outermost loop is on number 3.’
   The hen says, ‘The second loop check is on number 1.’
   The hen says, ‘The innermost loop check is on number 7.’
   The hen says, ‘The innermost loop check is on number 8.’
   The hen says, ‘The second loop check is on number 2.’
   The hen says, ‘The innermost loop check is on number 7.’
   The hen says, ‘The innermost loop check is on number 8.’
   The hen says, ‘The loop now, is ended.’
As we can see, loops are interpreted from the "outside in". Begin with the outermost
loop, then execute its contents. If those contents contain a loop statement, execute
that loop. Continue until the innermost loop is reached.
And, as we can see, $v1, $v2, and $v3 are variables which refer to iteration of the
corresponding loop.


Break

Finally, it is sometimes necessary to terminate execution of a prog entirely. In this
instance, the break command accomplishes this effect. The moment this command is executed,
the prog will stop. This is particularly useful for terminating out of certain branches
of if checks.