The main.scm file is processed by multiple threads.This might be one of the most difficult concepts to grasp for someone not familiar with multi-threading programming. So don't despair if you don't get it right away, you're not alone.
Up till now, we described the code as being executed opcode after opcode, sometimes jumping to a different location and continuing. Imagine this process being executed by a little guy inside your computer. He spends all day reading an opcode, executing it, determining the next opcode to execute, read it and execute it, day-in day-out. Lets call this little guy "thread".
Now image that this guys has a brother, who does exactly the same thing. Off course they're not looking at the same opcodes at the same time, his brother is working on another part of the code. Both are working independently of each other, reading opcodes, executing them, determining next opcode, ... Can you image that ??
Now image that there's a whole family of those little guys, all doing the same thing on different parts of the code.
~~~~~Welcome to the world of multi-threading. ~~~~Now how do we manage these threads ?
At the beginning there's only one thread that starts to execute at the beginning of the main.scm file, called the main-thread. Through a serie of jump's it will skip the first three sections and arrive at the beginning of the code-section. There it will perform some initialisation, until it encounters a series of "create_thread" opcodes.
That opcode creates a new "little guy" (thread) that starts executing opcodes below the given label. In this way, the main-thread creates a whole army of threads, each working on a specific part of the code, to perform a dedicated task. Some of the threads live indefinitely, just looping around the same code. Other threads only have to perform a single task once and kill them self upon encountering an "end_thread" opcode.
A thread can also kill another thread, by supplying name of its victim as a parameter to the end_thread opcode. Threads are given a name, when they execute a "name_thread" opcode, which is normally one of the first opcodes they encounter.
Create_thread may be executed from both the MAIN part as well as the MISSIONS part. The code that the thread will execute however, must be located in the MAIN part.
Missions are also executed as threads, but they are started with "start mission". This will create a special kind of thread oif which only one can exist at the same time. Furthermore, during this thread the engine continually checks whether the player is busted or wasted. In that case the "little guy" is instructed to perform a "return" opcode, which causes him to jump back to the last "gosub". This is why missions should have a special structure, in which this will lead to a failed mission. This structure will be described in one of the tutorials to come.Labels/jump/gosub
Labels are marked with a ":". These are names that are assigned to some locations in the code. It is used jump to a location in your code. You can do this with "gosub
" and "jump
You can see a label, named "MAIN_4059". Then you can see a command, with a code (01B7) called opcode. In the third line you can see another command: "jump". With the "@..." after that you indicate where the code has to jump to. So you are jumping to ":MAIN_4075".
Gosub works different, it also jumps to another label, but it goes back to the location just after the "gosub" when he reaches a "return"-command. For example:
$ONMISSION = 1 // integer values
00BA: text_styled 'BEEFY' 1000 ms 2 // Beefy Baron
start_mission 10 // Beefy Baron
0169: set_fade_color 0 0 0
fade 0 500
So it jumps with a "gosub" to ":SUB_FADE_500MS". When it reaches the "return" command (under ":LITCAS_306"), it goes back to the gosub. After the return, the code will continue with "start_mission 10").
Gosub is used when you want to use a piece of code from multiple places in your code.Conditional jump
When you use a "Conditional jump
", the code will do or not do the jump depending on some condition. You can use three notations for this, which all have the same result:
“004D: jump_if_false @boe”
In this example we check if the model is available (the model of the Greenwood, in this case). When this isn't true, it jumps to label ":SWEET4_152". When this is true, the code goes further.
With the conditional jump, you can make a loop
. Then the code waits until the condition is true. Be Aware! You have to put a wait in every loop! When you forget it, the game will crash, and, when you don't run SA in a window, you even can't go back to your desktop. The only solution is to restart your PC. So, my advise is to run SA in a window when testing your new code! An example of a loop is:
Wait 0 ms
As you can see, the code stays in this loop, until the model is available. If-then-end structure
There are other structures which you can use to check conditions. For example the if-then-end
structure. For example:
|if $choice == 0|
$money = 10
When the variable $choice equal is to 0, then the variable $money will become 10. If $choice isn't equal to 0, nothing will happen. You have to put an "end" to indicate where the code should continue when the condition is not true. You can add more things between "then" and "end" that will only be executed when the condition is true.Repeat-wait-until structure
wait 0 ms
until 03D0: wav 3 loaded
This is an example of a repeat-wait-until structure
. This is a loop, so there has to be a wait in it. This code means: do everything between repeat and until, until the condition is true. Between repeat and until there can be also other things, that will be executed over and over again until the condition is true. Instead of using repeat-wait-until, you can also write it as a conditional jump (this will behave exactly the same!):
wait 0 ms
03D0: wav 3 loaded
There are two kinds of numbers:Integer values:
1 2 3Floating-point values:
Floating-point values will be used as coordinates, angles or things like speed.
Integer values are used for most other things. The advantage of Integer values, is that computer can easy calculate with these. These numbers are for example used for waiting periods.
The Integer Values and Floating-Point values can't be mixed up, because then the code won't work.
|0004: $abc = 5000;; integer values|
0084: $def = $abc;; integer values and handles
The difference is that the first a assigns a value to a global variable. In this case 5000 to global variable $abc. Then you say, that $def has to get the same value as $abc. So this code means: $def = $abc = 5000 (But you may not use this in the main.scm, there you have to split it up) Variables
There are two kinds of variables: global and local. Global variables are indicated with a $ (for example: $abc), local are indicated with a @ at the end (for example: 2@). Local variable-names only consists of numbers, a global variable has to consist of characters and digts. When a Global Variable only consists of numbers, it will be handles differently by the compiler. This can lead to unexpected results, so you shoudl make sure that your variablenambles contain at least one character. The difference between local and global variable is that you use a global through the whole script. A local variable is applies only within one thread. When you assign a value to 1@, and you want to use that number in another thread again, it won't be avaiable, you have to assign it that value again. The value of the other thread doesn't apply any more.Calculate with variables
Sometimes you have to calculate with variable. There are some opcodes for this. Caution: there are different opcodes for integer-values and floating-point-values, and there are different opcodes for global or local variables. You can add, subtract, multiply and divide. Some examples:
|0008: $variable += 1|
|0009: $variable += 1.741|
| 0058: $variable += $variable23 // (int)|
Beware not to confuse these two opcodes:
| 0038: $variable == 1|
With this opcode, you will check if $672 is equal to 1.
With this opcode you will set the global variable $var to 1.