RPGCode — Language Features — Creating Functions
Contents
Creating FunctionsCreating Your Own Commands
Editor's Note: Often, for example in the title of this page, the word function will be used synonymously with command. The former is arguably a preferred term.
Since TK2, you have been allowed to create your own commands. This makes RPGCode even more expandable and extensive. Although there are 220+ commands built into the Toolkit, you may wish to create your own to make specific tasks easier. With the use of these custom commands, you can group blocks of code together and reuse them. Apart from the built in commands, there is also a library of extended commands in the file 'system.prg', demonstrating the use of creating custom commands.
In RPGCode, you define a new command with the Method keyword. Method defines a new method. A method (or 'function', if you're familiar with C++) is basically just a command -- it works the same and looks the same. The general form of Method is:
method methodName(parameter1, parameter2, ...)
Following the Method declaration is a block of commands that tell the method what to do.
'methodName' is the name of the method. Basically, this is what the command will be called. If you want to make a command called 'Pause', then the method name would be Pause. The list of parameters allows you send variables to the method. We won't worry about that right now. The best way to understand methods is to actually see one. Here's what I'll use as an example: There is a problem with the wait() command. It will stop waiting for a keypress even if the user presses one of the arrow keys. This is usually ok, but when a player walks into a program, the buffer has a few more arrow presses, and the first few Waits() will be ignored. So I want to make a command that will just wait for the user to press a key, ignoring the arrow keys. So, I'll make a method called 'Pause()':
method pause()
{
pauseDone! = false
while (!pauseDone!)
{
pauseWait$ = wait()
switch (pauseWait$)
{
case ("LEFT", "RIGHT", "UP", "DOWN")
{
// Nothing happens
}
case (else)
{
pauseDone! = true
}
}
}
returnMethod(pause_wait$)
kill(pauseDone!, pauseWait$)
}
And there it is! Looks a little complicated, but it really isn't. I'll go over it step by step:
- First of all, the Method declaration tells us that the command name is Pause. It has no parameters (the empty brackets).
- Next, we set up a While loop. pauseDone! is the conditional variable -- the While loop will keep running as long as pause_done! is equal to false.
- Next, we wait for a key press.
- If the user did press an arrow key, the Wait command puts the text "UP/DOWN/LEFT/RIGHT" into the pauseWait$ variable. The Case command in the Switch statement checks if the key pressed was equal to "UP", "DOWN", "LEFT" or "RIGHT". If the key pressed was NOT one of those, pauseDone! becomes equal to true, which will break us out of the While loop.
- If the user did press an arrow, pauseDone! will not be set equal to true, and the while loop will start again, thus waiting for a key press again.
- Once the While loop is done, the last command (Kill) deletes the variables created by the method. It's a good idea to Kill method variables at the end of a method to free up memory. This way, the variables won't slow things down.
Ok, so how do you use this newly created command? Simple. Just type in its name:
pause()
Just like a regular command. But if you were making a program, where would the method declaration go? Well, here's an example of a program which uses the Pause() command:
// First, let's declare the method 'Pause'
// so we can use it in the program.
method pause()
{
pauseDone! = false
while (!pauseDone!)
{
pauseWait$ = wait()
switch (pauseWait$)
{
case ("LEFT","RIGHT","UP","DOWN")
{
// Nothing happens
}
case (else)
pauseDone! = true
}
}
returnMethod(pause_wait$)
kill(pauseDone!, pauseWait$)
}
// Now, I'll show some text and use the 'Pause' command:
mwin("Try pressing an arrow key!")
Pause() // Wait for the keypress, but ignore the arrow keys.
mwincls()
The actual method declaration is ignored by the computer unless it is actually called. So, after the Pause() command has been executed, the program ends, because the computer ignores the entire method block. This however, is the least efficient way of using Methods. You'll learn how to make it better next...
Remember: The way to use methods shown above is very inefficient. The efficient way will be explained next. However, if you do declare a method in the program you use it in, you should put the method at the top of the program. This is because the Toolkit searches through the entire program when a method is used. So, if the method is at the top of the program, the Toolkit won't have to search for it, thus speeding up your program.
Creating Libraries:
As you can see, a method declaration can take up quite a bit of space in your program. Wouldn't you rather use your own methods without having to type them out every time they are to be used? Well, you can. You can do this by creating libraries.
A method library is just a regular .prg file that simply contains method declarations for a number of commands. For example, we could put the method declaration for Pause() into a file called "pause.prg". We can call up this library from any program using the command #include. Here's an example of the same program but this time, the Pause() method declaration is in a file called "pause.prg":
#include "pause.prg" // Include the pause library
// Now, I'll show some text and use the 'Pause' command:
mwin("Try pressing an arrow key!")
pause() // Wait for the keypress, but ignore the arrow keys.
mwincls()
This program sure is a lot smaller and nicer looking. The Include command just opens up the file 'pause.prg' and gives you access to the methods in that file. We can then use the command Pause(), because the method declaration for Pause() is stored in 'pause.prg'.
Passing in Parameters:
So far we've made a method that does not have any parameters (the brackets were empty). However, usually you will want to send information to your method. This is done by passing parameters to the method. As an example, let's consider a method called Add that just adds two numbers together:
method add(addNum!, addNum2!)
{
addDest! = addNum! + addNum2!
returnMethod(addDest!)
}
// Now, let's use the new method called 'add'.
mwin("This is a demonstration of the Add method")
wait()
dest! = add(4, 1)
mwin("The result is <dest!>.")
This program demonstrates how to pass in parameters to your method. The method itself is sort of useless -- it only adds two numbers together. You can do that without a method. Take a look at the command itself:
dest! = add(4, 1)
This command passes two parameters to the method: 4, 1. It also returns a value to dest! (you'll learn about returning values later). What happens with these parameters? Well, let's take a look at the method declaration:
method add(addNum!, addNum2!)
As you can see, the parameters are variables. In a method declaration, the parameters must always be variables. The reason for that is so the user of the method can input their own values into those methods. So, when I used 4 and 1 as the values, you know that addNum! equals 4 and addNum2! equals 1. As you should notice, this is a handy way to send a method information.
Keep in mind: It's always good to use the Kill() command to get rid of variables that were declared inside of a method. This frees up space. However, parameter variables are automatically killed once the method ends, so you don't need to Kill() those. This is because the parameters of a method are 'scoped' directly to that method (for information on what 'scope' is, check the Advanced Features > Scope section).
Editor's Note: Using the local() function is the preferred way to manage method variables.
Now, look at the command I used after I added the variables together: ReturnMethod(add_dest!). This command takes the parameter addDest! and returns the value to a variable. How do you return a value to a variable that isn't in the method declaration though? Let's discuss that...
Returning Values:
If you're used to TK2's way of programming, you'll notice that some things have changed in commands. One change is the fact that you can now return values outside of commands (such as 'a$ = wait()'). This is a more efficient way of returning values to variables because you can now clearly distinguish between normal parameters and variables that hold returned values. In the last example used, I returned a value to the variable dest!. Let's look at the command once more:
dest! = add(4, 1)
You already know that 4 and 1 are the numbers to add together. So let's learn more about returning values.
To return a value to a variable, you need to use the ReturnMethod() command with the variables name as the parameter (in this case, 'add_dest!'). So when we see the line 'ReturnMethod(add_dest!)', we know that we're returning a value. The variable that you use to store the returned value and the variable that's in the method itself don't have to be the same (as you may have noticed already). So, if the parameter in the ReturnMethod() command is 'add_dest!', and the variable you use when you call the method aren't the same, it'll still work.
Remember that if you are returning a value, the variable must not be in the parameter list of the method declaration. If you write the method declaration like this:
method add(addNum!, addNum2!, addDest!)
You can't call the method like this:
dest! = add(4, 1)
However, methods can have returned values passed back to the parameters. To do this, you must put the variable to hold the returned value in the method declaration.
Overloading Methods
Imagine creating a method where you have parameters that you don't always need to use. Filling them in with certain values and checking if you need to use those values can get tedious (not to mention it's not efficient). Wouldn't it be ideal if you could have optional parameters in your methods, just like some of the commands have optional parameters? Of course it would! This is where method overloading comes in handy. When you overload a method, you basically recreate the method with a different parameter list, and make it do different things depending on that parameter list. Here's an example of overloading a method:
method value(val$)
{
show(val$)
}
method value(val!)
{
show(val!)
}
method value()
{
debugger("No value supplied for Value()!")
}
value("Hello") // Shows: "Hello"
value(92) // Shows: 92
value() // Pops up the debugger
As you can see, all you need to do to achieve overloading a method is giving it the same name as another method, just with different parameters. While the given example isn't very useful, you can use method overloading for many different things (another basic, but more useful example is a custom message window. You could have optional parameters for a profile image, etc.).