Skip to content

Commit cba194c

Browse files
committed
add new chapter on loops
1 parent f9aaa1e commit cba194c

12 files changed

Lines changed: 399 additions & 5 deletions

astro.config.mjs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ export default defineConfig({
7575
],
7676
},
7777
{
78-
label: 'Chapter II: Loops',
78+
label: 'Chapter II: Introducing Loops',
7979
items: [
8080
{ label: 'Variables', slug: 'variables' },
8181
{ label: 'WAIT command', slug: 'wait' },
@@ -103,6 +103,16 @@ export default defineConfig({
103103
{label: 'Debug Messages', slug: 'debug-messages'},
104104

105105
]
106+
},
107+
{
108+
label: "Chapter V: Advanced Loops",
109+
items: [
110+
{ label: 'Constants', slug: 'constants' },
111+
{ label: 'FOR Loop', slug: 'for-loop' },
112+
{ label: 'REPEAT..UNTIL Loop', slug: 'repeat-until' },
113+
{ label: 'Continue and Break', slug: 'continue-break' },
114+
{ label: 'Hands-on: Bonus Counter', slug: 'script-bonus-counter' },
115+
]
106116
}
107117
],
108118
}),

src/content/docs/ch00/03-sanny-builder.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ description: How to compile and disassemble scripts using Sanny Builder
44
slug: sanny-builder
55
---
66

7-
In essense, a CLEO _script_ is a set of instructions. It's original text form is called _source code_. Sanny Builder is the tool that reads the source and encodes each instruction into a format the game understands. It outputs a binary file, usually with a file extension `.cs` or `.scm`. This process is called _compilation_. The game reads the compiled script and executes the instructions in order, one at a time.
7+
In essence, a CLEO _script_ is a set of instructions. It's original text form is called _source code_. Sanny Builder is the tool that reads the source and encodes each instruction into a format the game understands. It outputs a binary file, usually with a file extension `.cs` or `.scm`. This process is called _compilation_. The game reads the compiled script and executes the instructions in order, one at a time.
88

99
Sanny Builder can be downloaded from [https://sannybuilder.com](https://sannybuilder.com).
1010

src/content/docs/ch01/05-comments.mdx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,13 @@ Or:
1919
terminate_this_script // End of script
2020
```
2121

22-
Block comments start with `/*` and end with `*/`. They can span multiple lines:
22+
There are two ways to write block comments. The first is using curly braces `{` and `}`:
23+
24+
```sb
25+
wait {comments here} 0
26+
```
27+
28+
The second is using `/*` and `*/`, similar to C++. They can span multiple lines:
2329

2430
```sb
2531
/*
@@ -34,6 +40,10 @@ Or used in the middle of the code:
3440
set_time_of_day /* hours */ 12 /* minutes */ 30
3541
```
3642

43+
:::note
44+
`{}` comments may look similar to directives like `{$CLEO .cs}` which we will learn about next. The difference is that directives always start with `{$`. Everything else inside `{}` is treated as a comment.
45+
:::
46+
3747
Block comments can not be nested. For example, the following code is invalid:
3848

3949
```sb

src/content/docs/ch02/03-while.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ slug: while
66

77
Many things in the game are extended in time or depend on the player feedback. A car driving to a destination, a model file loading from the disk, a button awaiting to be pressed all require a specific condition to become true. Did the car reach the point, was the specific button pressed, is the model available for use? If not, wait and check again later.
88

9-
We can validate certain condition continuosly, each frame, or with some delay. To achieve this in the code, a special construct exists: a loop.
9+
We can validate certain condition continuously, each frame, or with some delay. To achieve this in the code, a special construct exists: a loop.
1010

1111
The most common type of loop is a while loop. It will execute a block of code as long as the condition is true.
1212

src/content/docs/ch02/04-while-true.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ slug: while-true
66

77
`while true` is an infinite loop. It ends only with the `break` command or when the script is ended (e.g. using `terminate_this_script`).
88

9-
It is often used to create a main body of a CLEO script, which contantly awaits for a key press to trigger some action.
9+
It is often used to create a main body of a CLEO script, which constantly awaits for a key press to trigger some action.
1010

1111
```sb
1212
while true
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
---
2+
title: Constants
3+
description: Using constants to name fixed values in CLEO scripts
4+
slug: constants
5+
---
6+
7+
So far, we've been using raw numbers directly in the code. For example, in the [vehicle spawning script](/script-spawn-vehicle), the model number `415` appeared several times. If you wanted to change the vehicle, you'd have to find and update every occurrence. This is error-prone and makes the code harder to read.
8+
9+
A _constant_ solves this problem. It is a named value that the compiler replaces with the actual value during compilation. Unlike a variable, a constant cannot be changed at runtime.
10+
11+
To declare a constant, use the `const` keyword:
12+
13+
```sb
14+
const MODEL = 415
15+
```
16+
17+
Now, `MODEL` can be used anywhere in the code instead of `415`:
18+
19+
```sb
20+
const MODEL = 415
21+
22+
request_model MODEL
23+
24+
while not has_model_loaded MODEL
25+
wait 0
26+
end
27+
28+
Car vehicle = create_car MODEL at 2488.6963 -1660.1608 13.3359
29+
mark_model_as_no_longer_needed MODEL
30+
```
31+
32+
If you decide to switch from a Cheetah to a different car, you only need to update one line.
33+
34+
You can declare multiple constants on a single line, separated by commas:
35+
36+
```sb
37+
const KEY_F5 = 116, KEY_F6 = 117
38+
```
39+
40+
Or use a `const..end` block for better readability:
41+
42+
```sb
43+
const
44+
KEY_F5 = 116
45+
KEY_F6 = 117
46+
BONUS = 100
47+
end
48+
```
49+
50+
Constants can hold string values too:
51+
52+
```sb
53+
const GREETING = "Hello!"
54+
const GXT_HELP = 'SAN_AND'
55+
```
56+
57+
:::tip
58+
Use constants for values that appear more than once or have a non-obvious meaning. A name like `KEY_F5` is much clearer than the raw number `116`.
59+
:::
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
---
2+
title: FOR Loop
3+
description: Counting iterations with the FOR loop
4+
slug: for-loop
5+
---
6+
7+
In [Chapter II](/while), we learned about the `while` loop which repeats as long as a condition is true. But what if you know exactly how many times you want to repeat something? The `for` loop is designed for exactly that.
8+
9+
## Syntax
10+
11+
```sb
12+
for <variable> = <start> to <end>
13+
<body>
14+
end
15+
```
16+
17+
The loop variable starts at `<start>` and increases by `1` after each iteration until it passes `<end>`.
18+
19+
For example, to add money to the player 5 times:
20+
21+
```sb
22+
int i
23+
for i = 1 to 5
24+
add_score 0 100
25+
wait 250
26+
end
27+
```
28+
29+
The variable `i` will take values `1`, `2`, `3`, `4`, `5`, and the loop body will execute 5 times. After the loop, the player has $500 more.
30+
31+
## Counting Backwards with DOWNTO
32+
33+
To count in the opposite direction, use `downto` instead of `to`. The loop variable decreases by `1` after each iteration:
34+
35+
```sb
36+
int i
37+
for i = 5 downto 1
38+
print_formatted_now "Countdown: %d" 1000 i
39+
wait 1000
40+
end
41+
42+
print_string_now "Go!" 2000
43+
```
44+
45+
This displays `5`, `4`, `3`, `2`, `1` and then `Go!`.
46+
47+
## Custom Step
48+
49+
By default, the loop variable changes by `1` on each iteration. You can change this with the `step` keyword:
50+
51+
```sb
52+
int i
53+
for i = 0 to 100 step 10
54+
print_formatted_now "Value: %d" 500 i
55+
wait 500
56+
end
57+
```
58+
59+
This displays `0`, `10`, `20`, `30`, ..., `100`.
60+
61+
`step` works with `downto` as well:
62+
63+
```sb
64+
int i
65+
for i = 100 downto 0 step 25
66+
print_formatted_now "Value: %d" 500 i
67+
wait 500
68+
end
69+
```
70+
71+
## Using Constants with FOR
72+
73+
Constants pair nicely with `for` loops to make the code easy to configure:
74+
75+
```sb
76+
const MAX_ROUNDS = 10
77+
const REWARD = 50
78+
79+
int round
80+
for round = 1 to MAX_ROUNDS
81+
add_score 0 REWARD
82+
wait 500
83+
end
84+
```
85+
86+
Changing `MAX_ROUNDS` or `REWARD` at the top of the script instantly adjusts the loop behavior.
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
---
2+
title: REPEAT..UNTIL Loop
3+
description: A loop that always executes at least once
4+
slug: repeat-until
5+
---
6+
7+
The `while` loop checks its condition _before_ each iteration. If the condition is false from the start, the body never runs at all. Sometimes that's not what you want -- you need the body to execute at least once, and only then decide whether to keep going.
8+
9+
The `repeat..until` loop does exactly that. It runs the body first, then checks the condition. If the condition is true, the loop stops. If it's false, the loop repeats.
10+
11+
## Syntax
12+
13+
```sb
14+
repeat
15+
<body>
16+
until <condition>
17+
```
18+
19+
Compare this with `while`:
20+
21+
| | Checks condition | Guaranteed to run at least once? |
22+
| --- | --- | --- |
23+
| `while` | Before each iteration | No |
24+
| `repeat..until` | After each iteration | Yes |
25+
26+
## Example
27+
28+
Here is a simple `repeat..until` loop that waits for the player to press `F5`:
29+
30+
```sb
31+
repeat
32+
wait 0
33+
until is_key_pressed 116
34+
```
35+
36+
The `wait 0` always executes at least once, giving the game a chance to process input before the first check. Compare it with the equivalent `while` version:
37+
38+
```sb
39+
while not is_key_pressed 116
40+
wait 0
41+
end
42+
```
43+
44+
Both achieve the same result, but notice how the condition is inverted: `while` needs `not is_key_pressed` (keep going while the key is _not_ pressed), whereas `repeat..until` uses `is_key_pressed` directly (stop when the key _is_ pressed).
45+
46+
## Practical Example
47+
48+
This script counts how many seconds the player waits before pressing `F5`:
49+
50+
```sb
51+
int seconds = 0
52+
53+
repeat
54+
wait 1000
55+
seconds += 1
56+
print_formatted_now "Waiting... %d seconds" 1000 seconds
57+
until is_key_pressed 116
58+
59+
print_formatted_now "You waited %d seconds!" 3000 seconds
60+
```
61+
62+
Because `repeat..until` always runs the body first, the counter starts at `1` even if the player presses `F5` immediately.
63+
64+
:::tip
65+
Use `repeat..until` when you need the loop body to execute at least once -- for example, displaying a prompt before checking the player's response. Use `while` when the body should be skipped entirely if the condition is already false.
66+
:::
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
---
2+
title: Continue and Break
3+
description: Controlling loop execution with Continue and Break
4+
slug: continue-break
5+
---
6+
7+
We briefly saw `break` in [Chapter II](/while-true) where it was used to exit an infinite `while true` loop. Let's look at `break` and its counterpart `continue` in more detail.
8+
9+
## Break
10+
11+
The `break` command immediately stops the current loop and moves execution to the first command after the loop:
12+
13+
```sb
14+
int i
15+
for i = 1 to 100
16+
if i == 6
17+
then
18+
break
19+
end
20+
print_formatted_now "i = %d" 500 i
21+
wait 500
22+
end
23+
24+
// execution continues here after break
25+
print_string_now "Loop stopped" 2000
26+
```
27+
28+
This displays values `1` through `5`. When `i` becomes `6`, the `break` command exits the loop and the script displays `"Loop stopped"`. It works the same way in `while` and `for` loops.
29+
30+
## Continue
31+
32+
The `continue` command skips the rest of the current iteration and moves on to the next one:
33+
34+
```sb
35+
int i
36+
for i = 1 to 5
37+
if i == 3
38+
then
39+
continue
40+
end
41+
print_formatted_now "i = %d" 500 i
42+
wait 500
43+
end
44+
```
45+
46+
This displays `1`, `2`, `4`, `5`. The value `3` is skipped because `continue` jumps to the next iteration before `print_formatted_now` is reached.
47+
48+
## Practical Example
49+
50+
Here is a more practical use of `break`. This script gives the player money every second, but stops early if the `F6` key is pressed:
51+
52+
```sb
53+
const KEY_F6 = 117
54+
55+
int i
56+
for i = 1 to 10
57+
if is_key_pressed KEY_F6
58+
then
59+
break
60+
end
61+
add_score 0 100
62+
print_formatted_now "+$100 (round %d of 10)" 1000 i
63+
wait 1000
64+
end
65+
```
66+
67+
Without `break`, the only way to achieve this would be a `while` loop with a more complex condition. `break` gives you a clean way to exit early when something unexpected happens.
68+
69+
:::note
70+
`break` and `continue` work in all loop types: `while`, `while true`, `for`, and `repeat..until`.
71+
:::

0 commit comments

Comments
 (0)