RPGCode — Language Features — Program Flow
Contents
Programming constructs- The if statement
- Else and elseif
- First practical program
- The while loop
- The for loop
- The switch statement
Programming Constructs
Up to this point, we've seen how to work with functions and variables, but the example programs haven't been particularly useful (save for the purpose of learning!). In this section, we will take a look at how different decisions can be made in our code to make our programs more useful in situations that we might face in-game. So I'll start you off by getting your feet wet in the world of constructs and program flow before we plunge into our first practical program.
The If Statement:
How does a program pop up a menu when you click a button? How does it respond when you provide input? To begin with, many programs that you write will need to do a certain amount of decision making. Decisions are made when conditions are met. Program flow is dependent on these conditional statements and decisions. One such construct is the if control structure, that allows certain code to run if the given expression evaluates to a non-zero value. In RPGCode, an if statement looks like this:
if (expression) { statements }
As said just before, statements will only be run if expression evaluates to a non-zero value. This can be any valid expression in RPGCode. Statements can be one or more RPGCode statements.
When I say that something is evaluated to a non-zero value, it means that the expression produces a result like 1, 15, -2, etc. As long as it is not 0, the code associated with the if control structure will be executed. To give you an example of what this means, try running the following code:
if (0) { mwin("This will not run."); wait(); } if (1) { mwin("This will run. :)"); wait(); }
You should see that the code in the first construct, where the expression is 0 (if (0)
) does not run, but the code in the second where the expression is non-zero (if (1)
) is run.
But how does this help in a real game situation? Like I said, any valid expression may be given to an if statement — not just numbers, but variables, comparisons, the return value of a function, etc. In the next example, we will see how to compare two values in an if statement with the equality operator.
x = 5; if (x == 0) { mwin("This will not run."); wait(); } if (x == 5) { mwin("This will run. :)"); wait(); }
Here, we first set the variable x
to 5. Then, we use an if statement to compare x
to the value 0. The equality operator can be thought of as a function: If the operand on the left (x
) is equal to the operand on the right (0), then it returns 1, otherwise it returns 0. Since x
is not equal to 0, the expression x == 0
will evaluate to 0 and the code associated with the first if statement will not be run.
However, the second if statement uses the expression x == 5
. x
is equal to 5, and so this expression will return 1, and the code associated with this if statement will be run. Try it out! A list of comparison operators can be found at the bottom of this page, and I encourage that you play with a few.
Please note that there are times when you should omit the semi-colon at the end of a statement. In the previous examples, there are no semi-colons after the if statement or curly braces. Here's a simple rule: If the next line should be an opening curly brace ({), or the line itself is just an opening or closing curly brace, don't use the semi-colon.
Else and ElseIf:
Testing the equality of one expression and then another works fine, but sometimes you will have a situation where the control structure needs to encompass more than just two equality comparisons; you may instead want to test for the equality of one variable, and if that evaluates to 0, you want to have something to fall back on regardless of what the variable actually is: So enters the else statement.
x = 5; if (x == 5) { mwin("x is equal to 5!"); wait(); } else { mwin("x is not equal to 5!"); wait(); }
If you run this example, the message "x is equal to 5!" will be shown on the screen, because the expression in the if statement returns 1. Try changing the value of x
. If it is something other than 5, the first conditional expression will return 0 and the code associated with the if statement will not be run, but the code associated with the else statement will automatically run. An else statement is only ever run if the preceding if statement is not run, otherwise it is skipped.
But what if you wanted to retain the first two if statements from the first example and still include the else statement? The else statement is only considerate of the preceding if statement. That is to say, if the first if statement's associated code is run and the second if statement's isn't, but the second if statement has an else statement attached, the else statement will still run! A little confusing? Try this code to see what I mean:
x = 5; if (x == 5) { mwin("This will run as intended."); } if (x == 0) { mwin("This won't run!"); } else { mwin("This will run, but it wasn't intended to!"); } wait();
In this example, the first conditional expression, x == 5
, is evaluated to 1, and so the following mwin
is run; the second conditional expression is evaluated to 0 and so the code after is not run; the else statement will run, though it is not intended to, because the previous expression in the if statement was not evaluated to 1.
However, this is very easy to fix: The elseif statement can be used to link multiple if statements to a final else statement. Try the code once more, but instead of two if statements, we will be replacing the second with an elseif statement:
x = 5; if (x == 5) { mwin("x is equal to 5."); } elseif (x == 0) { mwin("x is equal to 0."); } else { mwin("x is not equal to either 5 or 0."); } wait();
As you can see, with the use of control structures like if, elseif, and else, you can control the flow of a program so that some parts are only conditionally executed. Experiment with them and with the operators that are discussed later on and see what you can come up with!
First Practical Program:
Now we're going to put together all the things we've learned so far (functions, variables, conditional expressions, etc.) and create a program that asks the user for input, and depending on the input that's given, we will decide what to output to the message window.
mwin("You should try typing something. Here are your options:"); mwin("Press 1 and I'll tell you a secret."); mwin("Press 2 and I'll tell you another secret."); input = wait(); mwinCls(); if (input == 1) { mwin("There's still more to learn after this!"); wait(); } elseif (input == 2) { mwin("It's always good to indent code between curly braces with tabs!"); wait(); }
Firstly, three lines of text are displayed in the message window, giving the user their options. Then the wait
function is used to retrieve what key the user pressed on their keyboard. The returned value is stored in the variable input
. Next, the message window is cleared with mwinCls
, and we evaluate the expression input == 1
in the first if statement. If it is evaluated to 1 (the user pressed the 1 key), then we show a message in the message window. If it is not, then we try to evaluate the next elseif statement's expression.
The program works, but we are presented with a problem: What happens if the user presses a key other than 1 or 2? We only expect those two to be pressed. We could add an else statement, but what if we want to have them try again if they press the wrong key? This is explained next.
The While Loop:
The while loop is another control structure which allows you to repeat one or more statements while the conditional expression evaluates to 1. The form of a while control structure is as follows:
while (expression) { statements }
As you can see, this is very similar to the if statement, the only difference in its appearance is that it uses the while
keyword instead of if
. It works in much the same way, but when there are no more statements left to run in the while control structure, the expression is reevaluated, and if it still returns 1, the statements repeat; this happens until the expression returns 0.
count = 0; while (count < 5) { count++; mwin(count); } wait();
If you run this code, you will see the numbers 1, 2, 3, 4, and 5 shown in the message window. The expression count < 5
will evaluate to 1 if the left operand, count
, is less than the right operand, 5. count
is initially set to 0, so this will evaluate to 1 (it is less than 5). The first statement associated with the while loop, count++
, just adds 1 to the variable count
. When it is shown in the message window the first time, it will show the number 1. Since there are no more statements, the expression is reevaluated: count
is now 1, but it is still less than 5, so the statements will be run again. count
is incremented to 2, and 2 is shown in the message window. This goes on until count
is equal to 5.
Let's revisit our program that asks for user input, and this time we will use a while loop to repeat the code until the user presses the desired keys: 1 or 2.
mwin("You should try typing something. Here are your options:"); mwin("Press 1 and I'll tell you a secret."); mwin("Press 2 and I'll tell you another secret."); input = wait(); bLoop = true; while (bLoop) { if (input == 1) { mwinCls(); mwin("There's still more to learn after this!"); bLoop = false; } elseif (input == 2) { mwinCls(); mwin("It's always good to indent code between curly braces with tabs!"); bLoop = false; } input = wait(); }
If you press the wrong key when running this program, it will wait for you to press another key. It will keep looping until you press 1 or 2, and once you finally do, the program will end. There are two new things here though: The values true
and false
are used in the code, assigned to a variable.
These are the boolean true and false values, and in RPGCode they are synonymous with 1 and 0 respectively. When bLoop
is assigned true
, and then it is given to the while loop as its expression, it is like writing while (1)
(and as we learned earlier, the code associated with a control structure like if or while will be run if the conditional expression returns 1).
When the user presses 1 or 2 and either the if or elseif code is run, bLoop
is set to false
. Since false
is synonymous with 0, when the while loop reevaluates the expression, 0 is returned and it will not loop.
While loops, if statements, and the like can all be very powerful ways to control the flow of a program: You can make events happen once, multiple times, or not at all depending on conditional expressions. In almost any programming application, whether it's coding with RPGCode or otherwise, you will find yourself using these constructs a lot.
The For Loop:
In the example we saw where a while loop was used to print the numbers 1 through 5, a few things happened: Firstly, a variable was initialized with the value 0. Secondly, an expression was evaluated to see if the variable was less than 5. Thirdly, the number was shown and the variable was incremented (1 was added).
This same process can be achieved in fewer lines of code with the for loop. A for loop takes on the following form:
for (initialization; expression; increment) { statements }
The first part of the for loop inside of the parentheses is the initialization: Here you can assign an initial value to a variable. The second part is the expression, which, like the rest of the control structures, can take any valid expression. Lastly is the increment portion: This can also be any valid expression, but generally it is used to increment the variable that was initialized in the first section. statements will be run if the expression is evaluated to 1. Let's see the while loop example again, but this time with a for loop.
for (count = 0; count < 5; count++) { mwin(count); } wait();
This code works almost exactly the same way as the while loop example. The only difference that you will notice is that it shows the numbers 0 through 4 instead of 1 through 5!
When you are working with code where there is an initialization variable, an expression, and incrementation (or decrementation), it is safe to say that a for loop should suffice over a while loop to create more tightly knit code.
The Switch Statement:
When you are dealing with multiple cases of equality comparisons with a long chain of if...elseif
, you may opt to use the switch control structure instead. It allows you to compare a given expression against other expressions with cases. This is the form that a switch structure takes on:
switch (expression) { case expression2: { statements1 } case expression3: { statements2 } // etc... }
Where expressionN is compared to expression, and statementsN is the statements that are run if that case's value matches the value it's compared to. For example, we can check if the variable x
is equal to 1 or 2 with this switch...case structure:
x = 2; switch (x) { case 1: { mwin("x is equal to 1!"); } case 2: { mwin("x is equal to 2!"); } } wait();
We can also emulate an else statement with the default keyword:
x = 42; switch (x) { case 1: { mwin("x is equal to 1!"); } case 2: { mwin("x is equal to 2!"); } default: { mwin("x is equal to " + x + "!"); } } wait();
In this second example, x
is neither 1 or 2, so the first two case statements will fail. Instead, the default case will be run because no others were (and so "x is equal to 42!" will be shown).
Operators
Operators are used to perform operations on data like addition and multiplication. There are operators for arithmetic, logical and relational comparisons, bitwise operations, etc. It should be noted that each operator returns a value (even in the case of assignment operators such as x = (y += 1) + 1
), and so each example onward is a valid expression.
Arithmetic Operators:
Addition (+)
Returns the sum of the left and right operands.
a + b
Addition Assignment (+=)
Adds the right operand's value to the left's.
a += b
Subtraction (-)
Returns the difference between the left and right operands.
a - b
Subtraction Assignment (-=)
Subtracts the right operand's value from the left's.
a -= b
Multiplication (*)
Returns the left operand multiplied by the right.
a * b
Multiplication Assignment (*=)
Multiplies the left operand's value by the right's.
a *= b
Division (/)
Returns the left operand divided by the right.
a / b
Division Assignment (/=)
Divides the left operand's value by the right's.
a /= b
Power (^)
Returns the left operand's value to the power of the right's.
a ^ b
Power Assignment (^=)
Raises the left operand's value to the power of the right.
a ^= b
Modulo (%)
Returns the remainder of the left operand's value divided by the right's.
a % b
Modulo Assignment (%=)
Assigns the remainder of a division between the left and right operands to the left operand.
a %= b
Prefix Increment (++)
Increments its operand's value by 1 and returns the incremented value.
++a
Postfix Increment (++)
Increments its operand's value by 1 and returns the original value.
a++
Prefix Decrement (--)
Decrements its operand's value by 1 and returns the decremented value.
--a
Postfix Decrement (--)
Decrements its operand's value by 1 and returns the original value.
a--
Comparison Operators:
Equal To (==)
Returns 1 if both the left and right operands are equal, otherwise it returns 0.
a == b
Not Equal To (~=)
Returns 1 if the left and right operands are not equal, otherwise it returns 0.
a ~= b
Greater Than (>)
Returns 1 if the left operand is greater than the right, otherwise it returns 0.
a > b
Greater Than or Equal To (>=)
Returns 1 if the left operand is greater than or equal to the right, otherwise it returns 0.
a >= b
Less Than (<)
Returns 1 if the left operand is less than the right, otherwise it returns 0.
a < b
Less Than or Equal To (<=)
Returns 1 if the left operand is less than or equal to the right, otherwise it returns 0.
a <= b
Logical AND (&&, AND)
Returns 1 if both the left and right operands are non-zero, otherwise it returns 0.
a && b a AND b
Logical OR (||, OR)
Returns 1 if either the left or right operand is non-zero, otherwise it returns 0.
a || b a OR b
Logical NOT (!)
Returns 1 if its operand is 0, otherwise it returns 0.
!a
Bitwise Operators:
Bitwise AND (&)
Compares each bit in the left operand to each corresponding bit in the right operand, returning 1 if the two corresponding bits are 1; otherwise 0.
a & b
Bitwise AND Assignment (&=)
Compares each bit in the left operand to each corresponding bit in the right operand, returning 1 if the two corresponding bits are 1, 0 otherwise, and assigns the resulting value to the left operand.
a &= b
Bitwise OR (|)
Compares each bit in the left operand to each corresponding bit in the right operand, returning 1 if either of the corresponding bits are 1; otherwise 0.
a | b
Bitwise OR Assignment (|=)
Compares each bit in the left operand to each corresponding bit in the right operand, returning 1 if either of the corresponding bits are 1, 0 otherwise, and assigns the resulting value to the left operand.
a |= b
Bitwise NOT (~)
Performs logical negation of each bit in its operand, changing bits that were 1 to 0 and bits that were 0 to 1.
~a
Bitwise XOR (`)
Compares each bit in the left operand to each corresponding bit in the right operand, returning 1 if the two bits are not the same; otherwise 0.
a ` b
Bitwise XOR Assignment (`=)
Compares each bit in the left operand to each corresponding bit in the right operand, returning 1 if the two bits are not the same, 0 otherwise, and assigns the resulting value to the left operand.
a `= b
Other Operators:
Ternary (?:)
Returns b if a is non-zero, otherwise it returns c.
a ? b : c