The FHQ Mini Scripting Guide - Printable Version +- Comrades in Arms Discussion Board (http://forum.ciahome.net) +-- Forum: Comrades in Arms Life (http://forum.ciahome.net/forumdisplay.php?fid=3) +--- Forum: Mission Making (http://forum.ciahome.net/forumdisplay.php?fid=8) +--- Thread: The FHQ Mini Scripting Guide (/showthread.php?tid=3863) |
The FHQ Mini Scripting Guide - Varanon - 07-18-2019 Introduction A lot of people see scripting as an arcane thing that no one can fully understand, and while it's true that scripting topics can go from the trivial to the extreme, most practical scripting used by mission designers is actually pretty simple. The daunting part is always that, when faced with an SQF code, and without the knowledge of what exactly it is you are seeing, everything looks arcane and incomprehensible. But at it's core, it's rather simple. I will use this thread as sort of mini scripting guide. The goal is to give you just enough scripting knowledge to do simple scripts that allow you to do what you need them to do within your mission. It's goal is not an exhaustive programming course, and with what I present here, you might not be able to write complex code, but again, this is not the intention. Script organization Scripts are usually organized in files ending in ".sqf". When such a file is executed, the script interpreter in Arma starts executing the commands in the file starting with the first command, and then going on to the next, and the next, and so on. This is an important thing to note, and even though it might sound trivial, it's the essence of how a script works. Some scripts, like init.sqf, are executed automatically at the start of the mission. A full table of all those "automatic" scripts can be found here, but for our purposes, we will stick to init.sqf as the root of all scripting in Arma. If you need something initialized, this is where to put it. You can call other scripts from within init.sqf using certain script commands, which we will touch on later. Another way of executing script commands is from within the editor's console. This is useful for testing small script pieces and/or verifying the result of script commands. Anything entered into the Execute field can be executed either locally (LOCAL EXEC), on the server (SERVER EXEC, multiplayer only) or on all clients and the server (GLOBAL EXEC, multiplayer only). The Watch fields can be filled with code that produces a result, and the result will be displayed below the field. To summarize what this chapter introduced:
RE: The FHQ Mini Scripting Guide - Varanon - 07-27-2019 Data Types Every piece of data is expressed as one of the existing data types. You can think of data types as a classification of the data. For example, you do know that 1.254 is a number, while "Hello World" is a string of characters. SQF knows several data type, some more frequently used, some less so. The most commonly used data types are:
Numbers Number are exactly what you would think they are. 1 is a number. 3.1415 is a number. -1000 is a number. Very large or small numbers can be written as powers of ten by using 'E' or 'e': 1e3 is 1 times ten to the third power (1000), while 2e-3 is 2 times 10 to the power of -3 (0.002). Note that SQF does not make any distinction between whole numbers and floating point numbers. Strings Strings are squences of characters, enclosed in either double (") or single (') quotes. "This is a string" is an example of a double-quoted string. 'This is a single-quoted string' is another example of a (this time single-quoted) string. Note that a double quote must be closed by another double quote and vice versa. So, "This is not a string' is not correct. Strings are used as names and for other purposes. Booleans A boolean is a truth value. It can either be true, or false. Their use is mainly for conditions (see later chapter), but just like numbers ans strings can be used in other expressions. We'll be talking about this in detail later. Objects Objects are "handles" for anything in game. The player is an object. Any vehicle is an object. Enemy AI are objects. Basically, everything that manifests itself in the game world is an object, even triggers and modules (Exception of this rule: Markers are not objects). A special object is defined as well, the "null object", which represents nothin. In SQF, it's expressed as objNull. Code Code is anything you can execute. In SQF, code has it's own data type. It is written as a sequence of statements enclosed in curly braces. Examples for code data types:
Arrays Finally, we have arrays. An array is a special datatype in that it's a collection of multiple items of data of varying types. Arrays are written as comma separated lists of items, enclosed in square brackets []. The order in which items are listed is significant. The first item is always item number 0, the second one is 1, and the last one is the n-1st item (if there are n item in an array). For beginners, this is probably the most difficult data type to understand, so let's see a few examples:
Arrays can be manipulated in a number of ways. We'll look at them in an extra chapter. As mentioned above, some data types are rarely used. For example, tasks, briefings and groups are data types in their own right, comparable to objects. For groups, there's even the same null group, "grpNull" To summarize:
RE: The FHQ Mini Scripting Guide - Varanon - 10-15-2019 Variables As we've seen in the previous chapter, data can be represented in SQF as different types. To store data, we need to make sure we can retrieve it again when we need it. To easily do it, we tie data to a name. This is called a variable. A variable is simply a named data item of a distinct data type. To define a variable, we have to assign it a type: myVariable = 1; This definition does several things: It declares a variable called "myVariable", gives it the value of 1, and also determines that it's data type is a number. Unlike other programming languages, the data type itself can change, though. myVariable = "A"; This reassigns the value of myVariable to be "A", i.e. a string. A variable can take the place of any data item. Thus myVariable = 10; myOtherVariable = 100; myOtherVariable = myOtherVariable + myVariable; assigns myOtherVariable the value 110. Naming Variable names can consist of characters (a - z, A- Z), numbers (0 - 9) and the underscore character ("_"). They must NOT start with a number, though. As such, these a valid names: myVariable MyVaRiAbLe some_variable0 _someVariable And these are invalid 0xxx -ky some-illegal-variable-name Scope Variables starting with an underscore character ("_") are considered local, while characters starting with a letter are considered global. A global variable is known on the current client or server anywhere, not only in the currently executed script, but also in other scripts. On the other hand, local variables are only known in the current scope. The current scope is either the current script file, the current function, or the current control structure. We'll discuss these things later. Suffice to say for now that local variables are not known outside the currently running script, while global variables are known everywhere on the current machine. Network considerations Variables as such are only visible on the current machine. That is, even if you define a global variable "myGlobalVariable" on your client, it will ONLY be visible on this client, not on any other client. To make it known beyond the boundaries of your current machine, you can broadcast it via the publicVariable command: myVariable = 1; publicVariable "myVariable"; This distributes the variable among all clients and server in the current game session. Note, though, that this ONLY transfers the current state. So, after executing the above line, myVariable will be known on any client/server and will have the value 1 on each. Now, if you execute myVariable = myVariable + 1; on a client, then the variable will be 2 on that client but 1 everywhere else. This is an important point when working with networks. Arrays Arrays are handled somewhat differently. They are not copied and modification of one modifies the other. For example: array1 = ["A", "B", "C"]; array2 = array1; array1 set [1, "D"]; // Set = array set[x, value] sets element number x to value will make array1have the value ["A", "D", "C"], and attay2 hast the same elements. This is a so called assignment by reference in contrast to an assignment by value as in the other cases To make a real copy, use array2 = +array1; To summarize:
RE: The FHQ Mini Scripting Guide - Varanon - 11-28-2019 Statements Up to now, we were talking about data. But scripting means writing something that operates on that data. This is where statements come in. Basically, a statement is one single line of script that "does something". The following line is a statment: _test = 0; This statement is a simple assignment. The value 0 is assigned to the variable _test. A statement is always ended with a semicolon (";") character. If you forget the semicolon, the game will complain about a script error. Multiple statements can be written on the same line, or on different lines: _object = player; _object moveInDriver _car; _object assignAsDriver _car; The script can also be written like this: _object = player; _object moveInDriver _car; _object assignAsDriver _car; Or like this: _object = player; _object moveInDriver _car; _object assignAsDriver _car; The important thing is the order: A script always executes one statement at a time. So the _object = player; would be executed first, followed by the second statment, and the third statement. In the next chapter, we'll learn how to deviate from that order (with the use of conditional execution). Remember the code datatype that we discussed briefly in the section about data types ? The code datatype is nothing else but a sequence of statements that are assigned to a variable. For example: _code = {_object = player; _object moveInDriver _car; _object assignAsDriver _car;}; The code in curly braces is not executed directly, but written into a variable. Note: The same rules apply to code written as data as normal code: A Semicolon must end every statement, and the line can be broken in any way. So the above could be written as _code = { _object = player; _object moveInDriver _car; _object assignAsDriver _car; }; or even _code = { _object = player; _object moveInDriver _car; _object assignAsDriver _car; }; if you are feeling funky. We will go into more detail on how to use code in variables when we discuss functions (including passing values into the function), but for now, suffice to say that the code in _code can be executed by call _code; To summarize:
RE: The FHQ Mini Scripting Guide - Varanon - 12-03-2019 Flow control, part 1 In itself, an unbroken sequence of statments can not do much. Sometimes, you need to react to certain conditions being present, and branch out into different parts of your script. This is where flow control comes in. Flow control encompasses everything that changes the flow of statements. It allows you to execute different sequences of statements when a condition is fulfilled, or repeat statements a defined (or undefined) number of times. Conditions Most flow control works with conditions, which is why we first take a look at those. A condition is something that always evaluates to either true or false (in other words, a boolean data item). A few examples will make this clearer. The follwoing are conditions
if a and b are conditions, then:
To summarize:
RE: The FHQ Mini Scripting Guide - Varanon - 03-17-2020 Flow Control, part 2 The most fundamental flow control is deciding which of two possible code blocks to execute. This is done with the "if" statement. In it's simplest form, it tests a condition, and, if true, executes a piece of code if (condition) then { // code to execute }; The following are working examples of if statements:
The second example checks whether _x is zero, and sets _y to 1 if it is. Note that the block following then is not executed if the condition is false, which means that in case _x is not zero, _y will be undefined. The second form of an if statement tests a condition, and then executes one of two possible code blocks depending on the result: if (condition) then { // code to run when condition is true } else { // code to run when condition is false }; Examples of this:
if ... then and if ... then ... else statements allow for a wide variety of possibilities. In fact, this and the while construct discussed in the next chapter are actually all that is needed. Any other constructs are purely "cosmetically" and just make the script easier to read. SQF scripting allows another use of the if statement that is uncommon and not usually found in other languages: The if statement can be used in an assignment. You can often find this in scripts in a case like this: allUnits = (if (isMultiplayer) then {playableUnits} else {switchableUnits}); playableUnits returns all playable units in a multiplayer game, but has no effect in single player. Conversely, switchableUnits shows all units the player can switch to in a single player match, but returns an empty list in multiplayer. The above line, then, checks if the game is in multiplayer (if (isMultiplayer)) and if it is returns playableUnits, else it retuns switchableUnits. The result is assigned to allUnits. To recapture:
|