Introduction
I know a few people who are trying to learn the basics of cubescript (and I'm sure there are many more out there), and so I thought I'd write a tutorial on loops - a fundamental part of any computer language. In essence, a loop is a sequence of instructions that is repeated until or while a particular condition is satisfied. I'll be discussing a few ways that loops can be utilized in cubescript.
The Basic Loop
The basic 'loop' command is quite easy to understand at its fundamental level. It goes like this,
loop i N [ body ]
This will exec body N times (i always starts at 0) increasing the value of i by 1 for each iteration. So if you wanted to quickly say the numbers 0, 1, 2… 9, you could use:
loop i 10 [ say $i ]
Also worth noting is that there is nothing special about 'i', you can just as easily use any other letter (or even strings of letters). Here's a quick exercise; see if you can find a way to quickly say all of the odd numbers from 0 to 10. Once you've had a minute to think about it, compare your answer with this,
loop i 6 [ say (* 2 $i) ]
What we're doing here is multiplying 'i' by 2 before we say it, resulting in an even number.
If you haven't played around with them to already know, sleeps in loops just don't work the way you want them to. For example, if you tried,
loop i 5 [ sleep 1000 [ echo $i ] ]
you'll notice that there is a one second pause after which the whole loop is carried out as if there was no sleep involved. And not only that, the value of 'i' seems to be off. This happens because the loop continues on while the sleeps are in progress (this might be hard to understand at first) and so, in the end, all the iterations seem to be executed as if there was one sleep in front of the entire loop. This can be fixed by increasing the sleep time for every iteration. As for the 'i', we need to refer to its value outside of the sleep, therefore we should use '@i' instead of '$i'. Putting it all together, we have:
loop i 5 [ sleep (* $i 1000) [ echo @i ] ]
This is does what we wanted the previous line of code to do; echo the numbers 0, 1, 2, 3 with a 1 second sleep between consecutive echoes.
Here's an interesting challenge: try to find a way to quickly echo the following; "0 0", "0 1", "0 2" … "0 4", "1 0", "1 1" … "1 4" … … "4 4", in other terms, a way to echo every possible way in which 2 not necessarily distinct numbers can be selected from the set {0 1 2 3 4}. After some thought, it becomes evident that we'll need to embed one loop inside of another as such,
loop i 5 [ loop k 5 [ echo (concat @i $k) ] ]
Again, we use the '@' because we are referring to the value of 'i' at a different level in the code.
Looping Through Lists
Lets say we had the list "2 3 5 7 11" and we wanted to quickly echo each element of that list in order, we could either use the normal 'loop' command and include (at "2 3 4 7 11" $i), or we could use 'looplist'. This command works as such,
looplist i L [ body ]
This is similar to loop, except now 'i' takes on each element of the list L. So, returning to the previous example, we can echo each element like this,
looplist i "2 3 5 7 11" [ echo $i ]
Pretty simple. Another exercise: find a way to quickly echo all of the names of the clients connected to a particular server. Here's how I would do it,
looplist i (listclients 1) [ echo (getclientname $i) ]
It's not hard to see that this would loop through the list of client numbers and echo the name that corresponds to each number.
Looping Through Files
Whether you knew it or not, it is in fact possible to loop through files in the sauerbraten folder using a command called 'loopfiles'. The format is like this,
loopfiles f dir ext [ body ]
This loops through the files in directory 'dir' with extension 'ext', executing 'body' for each iteration. As expected, 'f' gets assigned to the file name each iteration as well. So if we wanted to echo the names of all the screenshots in the 'screenshots' folder we could use,
loopfiles f screenshots png [ echo $f ]
Again, nothing too complicated. If we ever wanted to loop through all of the files in a certain directory with their extensions, we would simply leave 'ext' blank. So if you happen to have images that are not png files in the screenshots folder, you could use,
loopfiles f screenshots "" [ echo $f ]
You can see 'loopfiles' used in this Screenshot Script.
Looping Under a Given Condition
To loop under a certain condition we use 'while'. This command checks a condition, if it's true it executes the body of the loop, it it's false it terminates the loop. It's formatted like this,
while [ cond ] [ body ]
So if we wanted a different way to echo the numbers 0, 1, 2… 9 we could use,
var1 = 0
while [ (< $var1 10) ] [ echo $var1; var1 = (+ $var1 1) ]
The condition does indeed need to be placed into square brackets or you may encounter problems. This really isn't used that much because often times a simple 'loop' will do the job; it's still a useful tool, however.
Infinite Loops
There isn't a specific command for infinite loops, but rather a method that can be used to create them. Lets say we wanted to continuously echo "Hello World" every 3 seconds, we could do the following:
hwecho = [ echo "Hello World"; sleep 3000 [ hwecho ] ]
We are assigning a function that calls itself, and will therefore do so continuously. Issuing the command /hwecho will result in this continuous echoing. This is yet another tool that quite often comes in handy.
Loops within GUI Menus
Loops can also be used within GUI menus. For example, if we wanted 10 GUI buttons that would echo 0, 2, 3… 9 if pressed, we could create the GUI as follows,
newgui looptest [
loop i 10 [ guibutton $i [ echo @i ] ]
]
We simply have a loop within the definition of the GUI. Here you would have 10 buttons labeled 0 - 9 that would echo the number they are labeled with. This is a very basic example, you can see more sophisticated uses of loops within GUIs if you look at the ClanWar Script.
Well there you have it, loops in a nutshell. Hope you enjoyed reading it!