Difference between revisions of "SCM language"

From GTAMods Wiki
Jump to navigation Jump to search
(Article corrected according to the reverse engineering applied to R* compiler left in the android version of GTA Vice City 10th Anniversary (thanks a lot to Link2012 too).)
(Time to publish the reworked article in its current state for historical reasons.)
 
(42 intermediate revisions by 6 users not shown)
Line 1: Line 1:
{{This|This section deals with the native SCM syntax of GTA 3 series, nothing other than [[GTA 3|III]], [[GTA VC|VC]], [[GTA SA|SA]], [[GTA LCS|LCS]] and [[GTA VCS|VCS]].<br/>
+
{{Cleanup-rewrite}}
It may contain non-standard SCM definitions as R* hasn't published enough documentation about it yet.}}
+
{{This|This article deals with the native scripting language syntax of GTA 3 series, nothing other than [[GTA 3|III]], [[GTA VC|VC]], [[GTA SA|SA]], [[GTA LCS|LCS]] and [[GTA VCS|VCS]].<br/>
{{TocRight}}On the occasion of the GTAIII's tenth anniversary, after a long period of darkness where we fell about the real ''SCM'' syntax, R* finally treated us by attaching part of its own original source code into the GTAIII Anniversary game, available for iOS and Android devices. As far back as 2001, a snip of some debugging scripts has been already provided with ''main.sc'' and ''debug.sc'' files. However, many secrets are unrevealed yet, thus some things cannot be documented fully and so they can be only guessed. The ''SCM'' format abbreviation is one of countless proofs of this inconvenience, which may stand for ''Script Multifile''. Other doubts come with source files, whose ''SC'' extension appears to be very close to ''Mission SCript''. At first, someone could have asked oneself how R* named its own programming language: ''R#''? ''R-Sharp''? ''Rockstar Sharp''? Who knows. We simply call it '''SCM language''' due to the lack of information. Nevertheless, the '''SCR language''' name is cropping up gradually. However, it is definitely based on [[Wikipedia:BASIC|BASIC]].
+
It may incorporate nonstandard specifications due to the fact R* hasn't published enough documentation about yet.}}
 +
{{TocRight}}On the occasion of the "Grand Theft Auto III 10th Anniversary", after a long period of darkness where we fell about the real scripting language syntax, R* finally treated us (or was it, as it seems, a [[Wikipedia:War Drum Studios|War Drum Studios]] sloppy oversight?) by attaching part of its own original source code into the Mobile release, available for iOS and Android devices. A year later, the so-called official compiler, somewhat customized for the sake of convenience, was shipped via the remastered edition of Vice City. As far back as 2001, a snip of some debugging scripts has been already provided with ''main.sc'' and ''debug.sc'' script files that were allegedly meaningful for a sort of script version checker uncut on debug builds. Nonetheless, many secrets are still unrevealed, thus some stuff cannot be fully documented at the moment, hopefully, and so they can be merely guessed. The .scm format abbreviation is one of countless proofs of such a downside which probably stands for '''Script Multifile''', while .scc might be in turn the short form of '''Compiled Script'''. No doubt comes with source files, whose .sc extension is the contraction of '''Mission Script'''. Although we have enough information to suppose the currently unknown mysteries of the used language, we still have no safe clue about what was its original denomination. Furthermore, it is a matter of fact that R* developers have been left intact the '''miss2''' executable filename of third generation compilers since the chapter 2. In this connection, we could imagine the newer language is a variant or an evolution of the '''GTA2script''' which label, initially referred to as '''GBHscript''', expressly popped up in the ancient documentation by [[Wikipedia:DMA Design|DMA Design Ltd.]] (at present [[Wikipedia:Rockstar North|Rockstar North]]). On those grounds, we are almost sure to say the name of the scripting language targeting each game with all peculiar but minimal enhancements or regressions is most likely '''GTA3script''' (as-is casing) for III, '''GTAVCscript''' for Vice City, '''GTASAscript''' for San Andreas, '''GTALCSscript''' for Liberty City Stories and lastly '''GTAVCSscript''' for Vice City Stories. However, it is definitely based on [[Wikipedia:BASIC|BASIC]].
  
 
<span style="font-size: 14pt">Preliminary remarks</span>
 
----
 
This article makes use of formatted codes to improve the reading comprehension. Note that:
 
 
* ''Square brackets'' mean everything inside may be omitted.
 
* ''Curly brackets'' denote the presence of useful codes but not necessarily needed.
 
* ''Vertical bars'' divide what can be chosen alternatively.<br/><br/>
 
 
=Fundamentals=
 
=Fundamentals=
  
 
==Comments==
 
==Comments==
 +
Codes are usually self-explanatory for the author but large sources can compromise everyone's management capability, that means some annotation can save much time on the long-term particularly when being stuck trying to understand old stuff which should never happen in the first place, not to mention team mates would certainly blame the original writer on each revision and slow down the completion of cooperative projects. Sometimes, it is also required to temporarily/permanently disable code lines for testing purposes. Fortunately, the language supports the following typologies of comments:
  
A ''comment'' is an additional text that may be helpful for the code writer or other users, in short for the reader. It is the only part of the source code which gets always ignored when compiling.
+
* ''Line'' comment, prefixed with // (two forward slashes), which extends till the end of the line. Everything is ignored inside: <code>// Some comment.</code>;
 
+
* ''Block'' comment, enclosed with a pair of /* (a slash plus an asterisk) and */ (the other way around), which embodies a circumscribed text area. Several blocks can be nested together: <code>/* Some /* comment */ . */</code>.
===Inline===
 
 
 
An ''inline comment'', denoted by '''//''' (two slashes), makes everything that follows some plain text:
 
 
 
[...] // Some inline comment
 
 
 
===Multiline===
 
 
 
A ''multiline comment'' embraces a particular area of the source code, starting by the opening tag '''/*''' (slash and asterisk) and ending with '''*/''' (asterisk and slash):
 
 
 
[...]
 
/*
 
  * Some multiline comment
 
  * ...
 
  */
 
[...]
 
Currently, more than one multiline comment is allowed per line:
 
 
 
[...] /* Some inline comment */ [...] /* Some inline comment */ [...]
 
 
 
==Highlighters==
 
 
 
''Highlighters'' behaviour sounds trivial, that's to say they simply highlight one or more [[#Arguments|arguments]] per [[#Commands|command]] within ''round brackets'', individually or together. However, a ''comma'' can be used aswell to distinguish each argument. In {{icon|3}}, they appear to be used only for '''SETUP_ZONE_PED_INFO''' (in a various order) and ''GXT keys'':
 
 
 
SETUP_ZONE_PED_INFO FISHFAC DAY (0) 0 0 0 (0 0 0 0) 0
 
PRINT_BIG (T4X4_1) 5000 2
 
 
 
==Scopes==
 
  
''Scopes'' are delimited by ''curly brackets'' (or ''multiline brackets'') which act like a [[#Local|local]] [[#Variables|variable]] [[#Scope|scopes]]. Essentially, they enclose the code where local variables are used, including [[#Timers|timers]]. They can be opened and closed many times in a [[#Structure|script]]:
+
==Delimiters==
 +
Conventionally, lines can be splitted into various regions in order to enhance the code legibility through bracket-delimited and/or comma-separated elements. As being pure whitespaces, the opening parenthesis delimiter doesn't necessarily need to match the closing counterpart and viceversa. The only tangible use of separators carried out in public sources is related to inline declaration of multiple variables, text keys of print-commands and <code>SETUP_ZONE_PED_INFO</code> but codes can be organized to one's liking. Here are some demonstrations:
  
  {
+
  VAR_INT joeys_buggy, swank_taxi
    [...]
+
PRINT_NOW (ASUKA) 2000 1
  }
+
  SETUP_ZONE_PED_INFO CHINA DAY (30) 350 600 0 (0 0 0 0) 0
  
;Limit
+
==Integers and Floating-points==
:Scopes cannot be nested.
+
Numeric values are used extensively throughout the whole script following no particular notation besides the decimal one. The specializing number representation tells whether a literal is an integer or a floating-point value: an appending <code>f</code> or <code>F</code> floatifies a number, whose suffix becomes superfluous if a radix point, discerning decimals from integral digits, is supplied. Float parts are alternatively omissible hence a 0 digit is implied if one and only one of them is missing. Literal parsing starts from the minus sign, radix point or number digit and stops at the first non number character after a series of digits, leading and/or trailing an eventual radix point, or float suffix. To sum things up, these values are valid numbers: <code>1</code>, <code>-0</code>, <code>1f</code>, <code>-0f</code>, <code>1.0</code>, <code>1.0f</code>, <code>1.</code>, <code>1.f</code>, <code>.0</code>, <code>.0f</code> and also <code>1-2</code> (ill-formed on basic or compound assignments), <code>1..2</code>, <code>1f2</code>, producing <code>1</code> (<code>1f-2</code> is ill-formed a priori). In the first Trilogy chapter, the fixed-point format was chosen meaning precision was guaranteed to not get lost if the decimal part wasn't lesser than just one-tenth.
  
==Labels==
+
==Labels, Text labels and Strings==
 +
Thanks to the beneficial code fragmentation, the source is subject to script file inclusions, favouring modularity, and sparse goto branches, involving embedded code blocks diversification. Both kinds of partitioning are accomplished respectively through the specification of:
  
A ''label'' is a ''sequence of characters'' which identifiy a location of the source code useful for ''jumps''. It can be accessed by any part of the source code. To define a label just append ''':''' (colon) to its name:
+
* ''Filenames'', that is special labels which somehow resemble legit pathnames, starting with any valid pathname character but not containing whitespaces. They are relative to the root path deriving from the .sc extension removal of the main script full path where files are searched in by default: <code>X:\folder\main</code>. Subfolders are scanned as well:
 +
** Till the first tree level if inside one of the subdirectories: <code>X:\parent\main\child</code>;
 +
** Till the second tree level if inside one of the parent directories: <code>X:\parent</code> or <code>X:\parent\main</code>;
 +
** Indefinitely (unlimited recursion till the maximum path length allowed).
 +
:The .sc extension at the end of filenames is mandatory else an argument mismatch is warned, by contrast the main script can have any extension to which ''m'' (multifile) or ''c'' (compiled) is appended in the target pathname. Due to a [[Cd image]] system limitation, all sorts of filename must be shorter than 20 characters and conventionally they must be free of extra dots for streamed scripts;
 +
* ''Labels'', that is unique identifiers suffixed by a colon which identify a precise location of the source code representing the target position of goto-like, script starter, subroutine or function caller commands: <code>my_label:</code> (on a new line). Weirdly enough, they may begin with any character alike filenames or be empty despite being susceptible to the same restrictions of string identifiers whenever passed as arguments but, regardless, must not exceed 39 characters (colon included, yet blanked out) and whereas these are not commands, anything else can follow next to and be inlined so long as a splitting character is inserted.
 +
:Labels store a reference depicting either an absolute address falling within the main script space (including main extensions and generic subscripts) or a relative and negative address pointing to a place of the mission script space or that of a particular streamed script. Albeit addresses are zero-based anyway, it is discouraged to use a <code>WHILE</code> construct at or branch by hand to the almost very top of a mission/streamed script file or even communicate between different script spaces with gotos.
  
[...]
+
That said, labels are basically user-supplied identifiers whose existence is verified. The text label or text [[Wikipedia:String (computer science)|string]] counterpart is not fully compliant to this standard (script names are exempt, for instance) since string identifiers are massively employed as main/mission text keys or whatever referring to an internal resource, which the game handles according to a well-defined associative scheme. As a general rule, these are primarily supposed to be at most 7 characters long and must begin with a letter and never end with a colon or either begin with an underscore or an alphanumeric character in the last Trilogy and Stories chapter where text label variables are supported, provided that here their literals are not valid integer or floating-point numbers taking the precedence over string identifiers on parsing:
 
{lblname}:
 
[...]
 
  
At the compiling time, they are automatically converted into an [[#Offsets|offset]].
+
LOAD_SPECIAL_CHARACTER 1 eight
 +
CUSTOM_PLATE_FOR_NEXT_CAR CAR_TAMPA _FELTCH_
 +
SCRIPT_NAME 99red
  
==Variables==
+
In the last Trilogy chapter and nowhere else, longer text labels were introduced, some sort of [[Wikipedia:String (computer_science)#Length-prefixed|Pascal strings]] having a variable length of maximum 40 characters for literals or a fixed length of 16 bytes for variables, twice as big as the shorter text label ones. Speaking of which, it is prohibited to get or handle a longer text label using a variable of shorter length but this one is rather passable to those text label parameters also permitting long-lengthed literals. Notoriously, identifiers length is anything but expensive for readability reasons, in addition they do not even offer the ability to insert whitespaces or other inadmissible characters owing to the by-design absence of delimiting tokens. At this matter, debug texts are sent as 127-character string literals enclosed by double quotes:
  
A ''variable'' is a ''storage location'' assigned to a ''symbolic name'' which contains a ''value'' of any ''type''.
+
SAVE_STRING_TO_DEBUG_FILE "current_wanted_list = "
  
===Value===
+
These quoted strings are, in essence, made up of four text labels aligned to 32 bytes (at the highest power of two possible per parameter) individually accessible as a result of a compiler bug, cause the first character of each literal-only argument is trimmed out as a quotemark &ndash; during the line reconstruction phase, the opening and closing quotemarks along with <code>&nbsp;</code> <code>/</code> <code>,</code> <code>(</code> <code>)</code ><code>\t</code> are swapped to <code>A</code> <code>\0</code> <code>\xD1</code>-<code>\xD6</code> and back again on code generation (the <code>NUL</code>-terminator at the end of string literals makes them rightmost arguments, ignoring the rest).<br/>
 +
Unlike string literals, empty text labels are impracticable though <code>$</code> alone compiles a <code>NUL</code>-string identifier in the last Stories chapter<sup>[no source]</sup> &ndash; as reported by some indiscreet speculations, the rearrangement of crucial commands signals a syntax enhancement the language has undergone which sees delimited strings superseding text labels, lowly probable because string constants are still disallowed for multi-type parameters. In San Andreas, text labels are implicitly comparable against <code>NUL</code>-string identifiers but no syntactical facility accommodates an explicit use.<br/>
 +
It's worth noting text labels and string literals are not interchangeable because of their syntactic differences even if they present semantic similarities, moreover text labels do not ever interfere with command names and string constants. A final quirk to note concerning labels as a whole is they are automatically converted to upper case: this obvious evidence proves identifiers and whatnot are all case insensitive with the exemption that string literals are left as-is for remastered game builds.
  
A ''value'' represents ''any data of any type'' it is.
+
==Data types==
 +
Forasmuch as the language obeys the [[Wikipedia:Strong and weak typing|strong typing]] paradigm, the syntactic elements that denote a value during execution do have fixed data types, most of which are appended as a suffix at variable declaration. Their conspicuous assortment is listed below:
  
===Scope===
+
{|class=wikitable style="text-align: center"
----
 
The usage of a variable depends on the ''scope'', that is the context where a specific variable is declared. At this point, we can distinguish the ''global'' and ''local'' scope.
 
 
 
====Global====
 
 
 
The ''global scope'' grasps the ''whole source code''. Variables defined as ''globals'' are visible in ''any [[#Structure|script]]''. They are declared by appending the '''VAR''' prefix.
 
 
 
====Local====
 
----
 
The ''local scope'' wraps a ''localized part of the source code''. Variables defined as ''locals'' are visible only in the ''code enclosed by curly brackets''. You can put them everywhere and as many times as you want in the source code. They are declared by appending the '''LVAR''' prefix.
 
 
 
=====Timers=====
 
 
 
A ''timer'' is a ''special local variable'' whose value rises automatically. It starts incrementing since the beginning of the script where it has been placed and grows endlessly. There are ''2 usable timers'' which are already defined as '''TIMERA''' and '''TIMERB''', therefore they do not need to be declared.
 
 
 
===Types===
 
----
 
Among the available types, some are equivalent to the most known programming types. Their length is up to 4, 8 and 16 bytes. Each type is appended as a suffix in the ''variable declaration''.
 
 
 
====INT====
 
 
 
The '''INT''' type handles ''32-bit signed integers''. It is also used to store [[#Value|values]] with less bytes, such as a [[Wikipedia:Primitive_data_type#Booleans|bool]], a [[Wikipedia:Character_(computing)#char|char]] and a [[Wikipedia:Integer_(computer_science)#Short_integer|short int]].
 
 
 
====FLOAT====
 
 
 
The '''FLOAT''' type handles ''32-bit floating-points''. As it normally does, decimal precision of a [[Wikipedia:Floating_point|float]] is usually stuck to 6 digits beyond which it may get lost.
 
 
 
====TEXT_LABEL====
 
 
 
The '''TEXT_LABEL''' type handles ''8-byte strings''. Generally, a [[Wikipedia:String_(computer_science)|string]] is an ''array of 1-byte characters''. It requires ''7 characters plus the [[Wikipedia:Null_character|null-terminator]]'' (a blank byte meaning the ''end of the string''). It is used to hold ''GXT keys'' (those of ''town zones'', ''interiors'', ''help textes'' or ''dialogue subtitles'') ''script names'' or any short string.
 
 
 
;Limit
 
:'''TEXT_LABEL''' variables are supported in {{icon|sa}} and {{icon|vcs}}.
 
 
 
====STRING====
 
 
 
The '''STRING''' type handles ''16-byte strings''. Like the previous, this type holds ''15 characters plus the null-terminator''. It is used to store ''model and texture names of player clothes'', ''animation names'' or any long string. It may be a ghost type as later R* compilers might choose between the two string types automatically according to the length of the string itself.
 
 
 
;Limit
 
:'''STRING''' variables and values are supported in {{icon|sa}}.
 
 
 
====OFFSET====
 
 
 
The '''OFFSET''' type handles ''16-byte strings''. They can refer to either a ''[[#Labels|label]] name'' or a ''file name''.
 
 
 
;Limit
 
:'''OFFSET''' variables aren't available.
 
 
 
====NUMBER (pseudo)====
 
 
 
The '''NUMBER''' type handles ''32-bit signed integers'' or ''32-bit floating-points''. It is used only to assign and compare ''numbers'' to '''INT''' or '''FLOAT''' variables. It is a pseudo type of '''INT''' or '''FLOAT'''.
 
 
 
====CONSTANT (pseudo)====
 
 
 
The '''CONSTANT''' type handles ''32-bit signed integers''. It is used only to assign and compare [[#Constants|constants]] to '''INT''' variables regarding ''model [[#Identifiers|identifiers]]'', ''task statuses'', ''ped events'' and such. It is a pseudo type of '''INT'''.
 
 
 
;Limit
 
:The [[#Arithmetic|assignment]] and [[#Comparison|comparison]] of '''CONSTANT''' values are supported since {{icon|vc}}.
 
 
 
====BUFFER====
 
 
 
The '''BUFFER''' type handles ''128-byte strings''. It holds ''127 characters plus the null-terminator''. Strings of such type must be put in ''quotation marks'':
 
 
 
SAVE_STRING_TO_DEBUG_FILE "128B TEXT"
 
 
 
;Limits
 
:'''BUFFER''' values are supported since {{icon|sa}}.
 
:'''BUFFER''' variables aren't available.
 
 
 
====VARLEN====
 
 
 
The '''VARLEN''' type handles ''N-byte strings''. It holds ''N characters plus the null-terminator''. Strings of this type mustn't exceed 255 characters.
 
 
 
;Limits
 
:'''VARLEN''' values are supported since {{icon|sa}}.
 
:'''VARLEN''' variables aren't available.
 
 
 
===Declaration===
 
----
 
''Defining a variable'' means ''assigning a token string to a memory cell'' at the compiling time. Variables must be declared in the following manner:
 
 
 
{varscope}_{vartype} {varname0}[,] [... {varnameN}]
 
 
 
As mentioned in the sections above, local variables have to be put within curly brackets:
 
 
 
{
 
    {varscope}_{vartype} {varname0}[,] [... {varnameN}]
 
 
    [...]
 
}
 
 
 
''Inline variable declaration'' is allowed, you just have to separate them by ''spaces'' or ''tabulations''. Adding a preceding ''comma'' before these characters is optional.
 
 
 
;Limit
 
:Whereas the ''variable buffer'' is limited, you can declare a certain amount of globals and locals. [[#INT|INT]] and [[#FLOAT|FLOAT]]) types take 1 variable, while [[#TEXT_LABEL|TEXT_LABEL]] and [[#STRING|STRING]] types occupy respectively 2 and 4 variables to store their data (have a look [[#Variables_2|here]] for further details).
 
 
 
====Arrays====
 
 
 
A ''array'' is a ''collection of variables'' having the same type which can be accessed by an ''index'', a 1-based integer lesser than or equal to the size specified, enclosed by ''square brackets'':
 
 
 
{
 
    {varscope}_{vartype} {varname0}{[arrsize0]}[,] [... {varnameN}{[arrsizeN]}]
 
 
    [...]
 
}
 
 
 
;Limits
 
:The usage of arrays is allowed since {{icon|vc}}.
 
:Variable indices are quite buggy in {{icon|vc}} and therefore unrecommended, but they are fully supported since {{icon|sa}}.
 
 
 
====Handles====
 
 
 
A ''handle'' is an univocal identifier assigned to a game entity. It is given by the following statement:
 
<source lang=cpp>short nHandle = (iEntityIndexInPool << 8) | ucEntityFlag;</source>
 
R* compiler won't let you assign different entity types to the same variable or using a variable which hasn't been assigned to any '''CREATE_*''' or '''ADD_*''' entity [[#Commands|commands]].
 
 
 
==Operators==
 
 
 
In general, an ''operator'' is a token string that represents a math calculation or an operation of any other kind, in order to make the code understanding clearer at a glance.
 
 
 
===Arithmetic===
 
 
 
''Arithmetic operators'' compute some of the most common algebric calculations between either a [[#Variables|variable]] and a [[#Value|value]] or two variables. As well as in some programming language happens, [[#CONSTANT|CONSTANT]], [[#TEXT_LABEL|TEXT_LABEL]] and [[#STRING|STRING]] types are free from these operators, except for the ''basic assigment''  (see also [[#Operators composition|Operators composition]]):
 
 
 
{|class=wikitable
 
!width=70px|Operator
 
!width=200px colspan=2|Name
 
!width=200px|Syntax
 
!width=500px|Description
 
 
|-
 
|-
!<code>=</code>
+
!style="text-align: left"|Name
|align=center colspan=2|Assignment
+
!Format
|align=center|<code>expr0 '''=''' expr1</code>
+
!Size
|Store ''expr1'' to ''expr0''
+
!Range
 +
!width=36px|Is<br/>main
 +
!width=36px|Is<br/>basic
 +
!Derivative data types
 +
!width=70px|Immediate<br/>support
 +
!width=70px|Variable<br/>support
 
|-
 
|-
!<code>+</code>
+
|colspan=9|'''NONE'''
|align=center colspan=2|Addition
 
|align=center|<code>expr0 '''+''' expr1</code>
 
|Add ''expr1'' to ''expr0''
 
 
|-
 
|-
!<code>-</code>
+
|rowspan=2 align=left|'''LABEL'''||String identifier<br/><span style="font-size: 0.75em">(translated to address)</span>||rowspan=3|1, 2 or 4||1 to 38||rowspan=2|
|align=center colspan=2|Subtraction
+
|rowspan=2|
|align=center|<code>expr0 '''-''' expr1</code>
+
|rowspan=2|
|Subtract ''expr1'' from ''expr0''
+
|rowspan=2|Since {{icon|3}}||rowspan=2|
 
|-
 
|-
!<code>*</code>
+
|Filename<br/><span style="font-size: 0.75em">(translated to address or index)</span>||1 to 19
|align=center colspan=2|Multiplication
 
|align=center|<code>expr0 '''*''' expr1</code>
 
|Multiply ''expr0'' by ''expr1''
 
 
|-
 
|-
!<code>/</code>
+
|align=left|'''INT'''||Signed integer||{{hint|-2<sup>n-1</sup> to 2<sup>n-1</sup>-1|-128 to 127&#10;-32,768 to 32,767&#10;-2,147,483,648 to 2,147,483,647}}<br/><span style="font-size: 0.75em">(where n is 8, 16 or 32)</span>||&#x2713;||&#x2713;||'''VAR_INT''', '''VAR_INT_OPT''',<br/>'''LVAR_INT''', '''LVAR_INT_OPT''',<br/><span style="font-size: 0.75em">(Vice City Stories apart)</span><br/>'''INPUT_INT''', '''OUTPUT_INT'''||rowspan=3 colspan=2|Since {{icon|3}}
|align=center colspan=2|Division
 
|align=center|<code>expr0 '''/''' expr1</code>
 
|Divide ''expr0'' by ''expr1''
 
 
|-
 
|-
!<code>+@</code>
+
|rowspan=2 align=left|'''FLOAT'''||[[Wikipedia:Q (number format)|Q11.4 fixed-point]]<br/><span style="font-size: 0.75em">(III only)</span>||2||{{hint|-2<sup>11</sup> to 2<sup>11</sup>-2<sup>-4</sup>|-2,048 to 2,047.9375}}||rowspan=2|&#x2713;||rowspan=2|&#x2713;||rowspan=2|'''VAR_FLOAT''', '''VAR_FLOAT_OPT''',<br/>'''LVAR_FLOAT''', '''LVAR_FLOAT_OPT''',<br/><span style="font-size: 0.75em">(Vice City Stories apart)</span><br/>'''INPUT_FLOAT''', '''OUTPUT_FLOAT'''
|align=center colspan=2|Timed addition
 
|align=center|<code>expr0 '''+@''' expr1</code>
 
|Multiply ''expr2'' by delta time and add the result to ''expr1''
 
 
|-
 
|-
!<code>-@</code>
+
|[[Wikipedia:Floating point|IEEE-754 floating-point]]<br/><span style="font-size: 0.75em">(packed in Stories)</span>||1-4||{{hint|&plusmn;2<sup>-126</sup> to &plusmn;2<sup>127</sup>(2-2<sup>-23</sup>)|&plusmn;1.1754942e-38 to &plusmn;3.4028235e+38}}
|align=center colspan=2|Timed subtraction
 
|align=center|<code>expr0 '''-@''' expr1</code>
 
|Multiply ''expr2'' by delta time and subtract the result from ''expr1''
 
 
|-
 
|-
!rowspan=2|<code>++</code>
+
|align=left|'''TEXT_LABEL'''||String identifier<br/><span style="font-size: 0.75em">(NUL-terminated)</span>||8||1 to 7||
|align=center rowspan=2|Increment
+
|&#x2713;||'''VAR_TEXT_LABEL''', '''VAR_TEXT_LABEL_OPT''',<br/>'''LVAR_TEXT_LABEL''', '''LVAR_TEXT_LABEL_OPT''',<br/><span style="font-size: 0.75em">(Vice City Stories apart)</span><br/>'''INPUT_TEXT_LABEL''', '''OUTPUT_TEXT_LABEL'''<br/><span style="font-size: 0.75em">(Vice City Stories only)</span>||Since {{icon|3}}||{{icon|sa}} and {{icon|vcs}}
|align=center|Pre{{ref|preinc|[*]}}
 
|align=center|<code>'''++''' expr0</code>
 
|rowspan=2|Increment ''expr0'' by 1 and store the result to ''expr0''
 
 
|-
 
|-
|align=center|Post
+
|rowspan=2 align=left|'''TEXT_LABEL16'''||rowspan=2|String identifier<br/><span style="font-size: 0.75em">(if non variable-only, accepts<br/>'''TEXT_LABEL''' variables)</span>||9-41<br/><span style="font-size: 0.75em">(Pascal string)</span>||8 to n<br/><span style="font-size: 0.75em">(where n is <= 40)</span>||rowspan=2|
|align=center|<code>expr0 '''++'''</code>
+
|rowspan=2|&#x2713;||rowspan=2|'''VAR_TEXT_LABEL16''', '''VAR_TEXT_LABEL16_OPT''',<br/>'''LVAR_TEXT_LABEL16''', '''LVAR_TEXT_LABEL16_OPT'''||rowspan=2 colspan=2|{{icon|sa}} only
 
|-
 
|-
!rowspan=2|<code>--</code>
+
|16||1 to 15
|align=center rowspan=2|Decrement
 
|align=center|Pre{{ref|preinc|[*]}}
 
|align=center|<code>'''--''' expr0</code>
 
|rowspan=2|Decrement ''expr0'' by 1 and store the result to ''expr0''
 
|-
 
|align=center|Post
 
|align=center|<code>expr0 '''--'''</code>
 
|}
 
 
 
;Note
 
:{{note|preinc}} Pre and post increments have no difference unlike what you would expect.
 
 
 
Yet, you can put the ''assignment'' and ''algebric'' operators together inline as follows:
 
 
 
{|class=wikitable
 
!width=70px|Operators
 
!width=200px|Name
 
!width=200px|Syntax
 
!width=500px|Description
 
 
|-
 
|-
!<code>= +</code>
+
|rowspan=2|'''TEXT_LABEL32'''<span style="font-size: 0.75em">||String identifier<br/><span style="font-size: 0.75em">(NUL-terminated)</span>||32||1 to 39<br/><span style="font-size: 0.75em">(bugged)</span>||rowspan=2|
|align=center|Addition and assignment
+
|rowspan=2|
|align=center|<code>expr0 '''=''' expr1{{ref|expr01|[*]}} '''+''' expr2</code>
+
|rowspan=2|
|Add ''expr2'' to ''expr1'' and store the result to ''expr0''
+
|rowspan=2|{{icon|sa}} only||rowspan=2|
 
|-
 
|-
!<code>= -</code>
+
|String literal<br/><span style="font-size: 0.75em">(NUL-terminated)</span>||32&times;4||1 to 127
|align=center|Subtraction and assignment
 
|align=center|<code>expr0 '''=''' expr1{{ref|expr01|[*]}} '''-''' expr2</code>
 
|Subtract ''expr2'' from ''expr1'' and store the result to ''expr0''
 
 
|-
 
|-
!<code>= *</code>
+
|rowspan=2 align=left|'''INPUT'''<br/><span style="font-size: 0.75em">(optional)</span>||colspan=3|Includes '''INT''' and '''FLOAT'''||rowspan=2|
|align=center|Multiplication and assignment
+
|rowspan=2|
|align=center|<code>expr0 '''=''' expr1{{ref|expr01|[*]}} '''*''' expr2</code>
+
|rowspan=2|
|Multiply ''expr1'' by ''expr2'' and store the result to ''expr0''
+
|rowspan=2 colspan=2|
 
|-
 
|-
!<code>= /</code>
+
|colspan=3|Includes '''TEXT_LABEL'''<br/><span style="font-size: 0.75em">(Vice City Stories only)</span>
|align=center|Division and assignment
 
|align=center|<code>expr0 '''=''' expr1{{ref|expr01|[*]}} '''/''' expr2</code>
 
|Divide ''expr1'' by ''expr2'' and store the result to ''expr0''
 
 
|-
 
|-
!<code>= +@</code>
+
|align=left|'''STRING'''<br/><span style="font-size: 0.75em">(internal only)</span>||Label,<br/>Variable name,<br/>String constant{{ref|strconst|[*]}},<br/>Text labels,<br/>Quoted string||
|align=center|Timed addition and assignment
+
|
|align=center|<code>expr0 '''=''' expr1{{ref|expr01|[*]}} '''+@''' expr2</code>
+
|&#x2713;||
|Multiply ''expr2'' by delta time, add the result to ''expr1'' and store everything to ''expr0''
+
|
 +
|colspan=2|
 
|-
 
|-
!<code>= -@</code>
+
|colspan=9|'''UNKNOWN'''
|align=center|Timed subtraction and assignment
 
|align=center|<code>expr0 '''=''' expr1{{ref|expr01|[*]}} '''-@''' expr2</code>
 
|Multiply ''expr2'' by delta time, subtract the result from ''expr1'' and store everything to ''expr0''
 
 
|}
 
|}
  
;Note
+
{{note|strconst}} String constants are only compatible with '''INPUT_INT''' data type but default constants favour '''INT''' regardless.
:{{note|expr01}} ''expr1'' can represent ''expr0'' too.
 
  
;Limit
+
==Immediates and Variables==
:Multiple algebric operators per line are not allowed.
+
Data can take the appearance of a few expressions varying from numeric, text label and string literals each of which occupies a certain area of storage with unfixed size. Immediates can also be preserved for later use and therefore reserve space over the private script memory corresponding to a variable. The strongly-typed language property imposes to explicitly declare variables anywhere in the current scope, namely the context inside which they are visible for usage. Sensibly, declarations should figure beforehand but likewise it is allowed for accessing backward declarations. Variables accessible from any location are marked as globals (starting from offset 8 or more, occupying lots of space in the script multifile, up to 64 kibibytes) and their declaration is achieved by prepending the <code>VAR</code> wording followed by one of the basic data types (multiple declarations of the same type can be inlined), both separated by an in-between underscore:
  
===Compound assignment===
+
VAR_INT player scplayer
 +
VAR_FLOAT x_float, y_float, z_float
 +
VAR_TEXT_LABEL interior_name
 +
VAR_TEXT_LABEL16 shop_item
  
''Compound assignment operators'' store [[#Value|values]] or [[#Variables|variable]] content to other variables having a particular type afterwards the computation of an arithmetic operation, to squeeze the code and clear it up from granted repetitions:
+
Globals are capable of being selectively marked as saveable using the <code>SAVE_VAR</code> prefix, in order to restore their value on savegame loading and free generic variables. In Trilogy chapters, if enabled properly in a hacky manner, these are solely common variable declarations with no additional purpose, a plan not gone through. On the other hand, globals declared within the mission context are not visible outside in Stories chapters since they overlap the same space, making a discernment among true and al-most globals. However, there's no exact rule for variable naming apart they must begin with a specific character and never end with a colon just like string identifiers, expanding till a maximum of 39 characters. It's preferable definitions shall not contain operator tokens to prevent any parsing ambiguity plus, most importantly, they must not conflict with string constants and local timers. Nevertheless, text labels and variable names semantics may collide: in this case, the formers have priority over the latters unless a preceding dollar sign is added:
  
{|class=wikitable
+
PRINT_BIG TEXTKEY 5000 2  // Compiles a text label literal.
!width=70px|Operator
+
PRINT_BIG $textkey 5000 2 // Compiles a text label variable.
!width=200px|Name
 
!width=200px|Syntax
 
!width=500px|Description
 
|-
 
!<code>+=</code>
 
|align=center|Addition assignment
 
|align=center|<code>expr0 '''+=''' expr1</code>
 
|Add ''expr1'' to ''expr0'' and store the result to ''expr0''
 
|-
 
!<code>-=</code>
 
|align=center|Subtraction assignment
 
|align=center|<code>expr0 '''-=''' expr1</code>
 
|Subtract ''expr1'' from ''expr0'' and store the result to ''expr0''
 
|-
 
!<code>*=</code>
 
|align=center|Multiplication assignment
 
|align=center|<code>expr0 '''*=''' expr1</code>
 
|Multiply ''expr0'' by ''expr1'' and store the result to ''expr0''
 
|-
 
!<code>/=</code>
 
|align=center|Division assignment
 
|align=center|<code>expr0 '''/=''' expr1</code>
 
|Divide ''expr0'' by ''expr1'' and store the result to ''expr0''
 
|-
 
!<code>+=@</code>
 
|align=center|Timed addition assignment
 
|align=center|<code>expr0 '''+=@''' expr1</code>
 
|Multiply ''expr1'' by delta time, add the result to ''expr0'' and store everything to ''expr0''
 
|-
 
!<code>-=@</code>
 
|align=center|Timed subtraction assignment
 
|align=center|<code>expr0 '''-=@''' expr1</code>
 
|Multiply ''expr1'' by delta time, subtract the result from ''expr0'' and store everything to ''expr0''
 
|}
 
  
===Uncompounded assignment===
+
Despite variables are freed and zero-initialized at runtime on new/load game or script allocation in broad terms, statistical information are still gathered whenever they are read before being written, besides if they are never read or never written (passing a variable as reference has no effect onto the content). Furthermore, if a variable is set to hold an entity handle (alias unique index) returned by a specific create-command it cannot be assigned to any other entity-command of different kind or none, including the forseeable assignment operations. This restriction propagates on script and function callings as well: starting/streaming the same script or calling the same function multiple times with variables of dissimilar entity types is forbidden if triggers are encountered prior the script or function lexical scope is fetched, in which case entities are explicitly initialized in the form of unreachable code:
  
''Uncompounded assignment operators'' are those on their own, or rather they are neither derivable nor decomposable similarly as those [[#Compound assignment|compounds]]:
+
{
 +
    LVAR_INT fellow_char robbery_car money_bag sanity
 +
 +
    sanity = 0
 +
    IF sanity = -1
 +
        CREATE_CHAR PEDTYPE_CIVMALE male01 0f 0f 0f fellow_char
 +
        CREATE_CAR admiral 0f 0f 0f robbery_car
 +
        CREATE_OBJECT woodenbox 0f 0f 0f money_bag
 +
    ENDIF
 +
}
  
{|class=wikitable
+
==Lexical scope==
!width=70px|Operator
+
Once a script is launched, a local storage space consisting of a context-dependent set of variables (16+2 in III/Vice City, 32+2 in San Andreas and 40+2 on Mobile, 96+8+2 in Stories) ready for use is also reserved. As opposed to global variables, locals have visibility only inside a particular region of the source code and are preceded by the <code>LVAR</code> wording at declaration within a nonnestable block embraced by <code>{</code> and <code>}</code>:
!width=200px|Name
 
!width=200px|Syntax
 
!width=500px|Description
 
|-
 
!<code>=#</code>
 
|align=center|Conversion assignment
 
|align=center|<code>expr0 '''=#''' expr1</code>
 
|Convert ''expr1'' to any other type and store the result to ''expr0''
 
|}
 
  
;Limit
+
{
:Supported conversions are [[#FLOAT|FLOAT]] to [[#INT|INT]] and '''INT''' to '''FLOAT'''.
+
    LVAR_INT pickup message_num
 
+
}
===Logical===
 
 
 
''Logical operators'' influence the way conditions are evalueted and enable to test more of them at a time. More than anything, they are built-in statements:
 
 
 
{|class=wikitable
 
!width=70px|Operators
 
!width=200px|Name
 
!width=200px|Syntax
 
!width=500px|Description
 
|-
 
!<code>NOT</code>
 
|align=center|Logical negation
 
|align=center|<code>IF '''NOT''' condition0</code>
 
|Test if ''condition0'' is false
 
|-
 
!<code>AND</code>
 
|align=center|Logical conjunction
 
|align=center|<code>IF condition0<br/>'''AND''' condition8</code>
 
|Test if both ''condition0'' and ''conditionN'' are true
 
|-
 
!<code>OR</code>
 
|align=center|Logical disjunction
 
|align=center|<code>IF condition0<br/>'''OR''' condition8</code>
 
|Test if either ''condition0'' or ''conditionN'' is true
 
|}
 
 
 
===Comparison===
 
 
 
''Comparison operators'' test the truth or falsity of the relation between either a [[#Variables|variable]] and a [[#Value|value]], a value and a variable or two variables:
 
  
{|class=wikitable
+
Local names do not override global definitions, they must not collide together otherwise a warn is issued. Beyond user-defined locals, predefined <code>TIMERA</code> and <code>TIMERB</code> variables are provided: these timers measures the playing time milliseconds passed since the script beginning but they can be reset just fine. In the last Trilogy chapter, mission locals are mainly static variables starting from index 34 or 42 on Mobile whose space (having a size of 4 kibibytes) is shared among each mission thus being reasonably more abundant in this scenario but, as a side effect, local timers are unavailable. Transferring the control over and above the lexical scope boundaries or to another multiscript leaves the active context and hides local definitions, thereby switching across lexical scopes is bad practice and can lead to unpredictable results if contexts are not strictly equivalent in the variable declarations.
!width=70px|Operator
 
!width=200px|Name
 
!width=200px|Syntax
 
!width=500px|Description
 
|-
 
!<code>=</code>
 
|align=center|Equal to
 
|align=center|<code>IF expr0 '''=''' expr1</code>
 
|Test if ''expr0'' and ''expr1'' are equal
 
|-
 
!<code>></code>
 
|align=center|Greater than
 
|align=center|<code>IF expr0 '''>''' expr1</code>
 
|Test if ''expr0'' is greater than ''expr1''
 
|-
 
!<code><</code>
 
|align=center|Lesser than
 
|align=center|<code>IF expr0 '''<''' expr1</code>
 
|Test if ''expr0'' is lesser than ''expr1''
 
|-
 
!<code>>=</code>
 
|align=center|Greater than or equal to
 
|align=center|<code>IF expr0 '''>=''' expr1</code>
 
|Test if ''expr0'' is greater than or equal to ''expr1''
 
|-
 
!<code><=</code>
 
|align=center|Lesser than or equal to
 
|align=center|<code>IF expr0 '''<=''' expr1</code>
 
|Test if ''expr0'' is lesser than or equal to ''expr1''
 
|}
 
  
Theorically, [[#STRING|STRING]] values should be compared with the first operator only, but the presence of '''COMPARE_STRING''' increase the doubts concerning the existence of such operator for this type.
+
==Arrays==
 +
Since the last Trilogy chapter, instead of declaring multiple scalar variables of same type, a one-dimensional indexed array can be defined. Each element is accessed through either a zero-based<sup>[no source]</sup> positive number or a variable index (local-only in Stories) in a subscript expression on assignment or argument passing. On declaration, a pair of square brackets enclose the array size which mustn't be bigger than 255 units:
  
==Commands==
+
VAR_INT prop_assets[32]
 +
CREATE_FORSALE_PROPERTY_PICKUP -1969.27 282.47 34.6 50000 PROP_3 prop_assets[0]
  
A ''command'' is a ''symbolic name'' associated to an [[#Opcodes|opcode]] which executes a ''portion of code'' that specifies the operation to be performed by passing ''zero or more [[#Arguments|arguments]]''. Opcodes do not return [[#Value|values]] that can be assigned to a [[#Variables|variable]], even though the boolean flag is kept whenever they are used as ''conditions''. It follows the common programming syntax adopted for ''procedure or function calls'':
+
In sooth, one-based arrays were already supported in the second Trilogy chapter but in a manner which is defective and incomplete: they missed the intrinsic data type, giving no reference point on how to interpret the compiled operands, producing corrupted intermediate code because of fall-through reading. There is no precedent to safely assert that arrays became zero-based later on the language evolution but what is certain is this sort of indexing lines up immediate with variable indices. Oddly, as a result of the uni-dimensionality constraint implementation, a complementary yet nonfactual identifier can follow the closing bracket immediately afterwards with no redundancy notice (i.e. <code>prop_assets[0]anything</code>). Moreover, scalar variables have an implicit array size of one element which is needlessly accessible and plus the index part of the first element of an array is in turn omissible, everything notwithstanding the misleading declaration. Granted that brackets do not encompass any separator character or identifiers wider than 39 characters, array indices reject string constants but admit local timers.
  
{commandname} [{anyvalue0|varname0} ... {anyvalueN|varnameN}]
+
==String constants==
 +
Very often, numeric literals express arbitrary values which are far from being self-documenting without descriptive labels belonging to a list of predefined names. These strings or enumerators are guaranteed to store an immutable constant and must forcibly pertain to the required enumeration if passed as arguments unless, if and only if no enumeration is set, the enumeration-free default constants <code>TRUE</code>/<code>FALSE</code>, <code>ON</code>/<code>OFF</code>, <code>DAY</code>/<code>NIGHT</code> or <code>KILLFRENZY</code> enumerators are supplied:
  
===Built-in===
+
CHANGE_BLIP_DISPLAY blip1_jm1 BLIP_ONLY
 +
flag_car_blip_displayed_jm1 = TRUE
  
''Built-in commands'' are those which are associated to more [[#Opcodes|opcodes]] that differ each other by [[#Arguments|argument]] types or actions:
+
Assignments and comparisons do not suffer such a restriction and, what's more, in case of too long lines (wider than 255 characters) immediates can safely replace string constants to shorten the exceeding length and fall within the limits. Of course, string constants are bound to the same parsing rules as string identifiers but, as being mainly hardcoded, they are just as limitless in length.<br/>
 +
During the development stage, the game's map experiences lots of continuous changes that make the management of objects, as a result of having a fixed indexing, pretty awkward without taking into account their bulk amount. In this respect, parameters expecting level objects are able to define the used objects (no more longer than 23 characters) under the hood, bringing them together in a sorted array whose criteria depends on the order of their appearance, something other than the default models which are hardcoded (for peds, cars, weapons, wheels, cutscene objects and the like). A blank, unavailable object is always reserved, shifting ahead each next negated position becoming one-based. Negative indices assure models fit in the used objects array, according to which the runtime matches the right index through a lookup table:
  
* {{icon|3}} {{icon|vc}} {{icon|sa}} {{icon|lcs}} {{icon|vcs}}:
+
REQUEST_MODEL bridgefuka // First use ever. It compiles -1 from now on.
** '''OPERATORS'''
+
REQUEST_MODEL bridgefukb // First use again. This time it compiles -2.
** '''ABS'''
+
LOAD_ALL_MODELS_NOW
* {{icon|sa}}:
+
CREATE_OBJECT_NO_OFFSET bridgefuka 715.746 -937.908 40.194 damagea
** '''IS_TEXT_LABEL_NULL'''
+
CREATE_OBJECT_NO_OFFSET bridgefukb 787.835 -939.24 38.971 damageb
** '''IS_STRING_NULL'''
 
** '''IS_BIT_SET'''
 
** '''SET_BIT'''
 
** '''CLEAR_BIT'''
 
** '''COMPARE_STRING'''
 
* {{icon|lcs}} {{icon|vcs}}:
 
** '''CALL'''
 
  
{{incomplete}}
+
The lack of error-checking requires a meticulous handwriting to avoid script deadlocks at runtime, the reason why default models of which undefined names follow the format <code>NOT_USED%d</code> (where <code>%d</code> is a model index from 0 to 299) and level objects are loaded straight from [[Item Definition|IDE]] files for Vice City's remastered build. Nonetheless, iterating among several objects can be very expensive for a poorly optimized, rough compiler even on fast machines, not to mention enumerators are likely to collide without specializing prefixes (i.e. <code>SNIPER</code> camera mode and weapon name, formerly <code>WEAPON_SNIPER</code>), enough to revert back thereafter.<br/>
 +
Assignments and comparisons have no clue about used objects and are therefore not designed to accommodate or implicitly define one on their own, because they are supposed to be strict with the identifier existence as being more prone to work out with variables. This concept somehow extends to those parameters not featuring used objects as a general rule. If an unusual application needs to take place, making use of non-inlined <code>CONSTANT_INT</code> declarations would hint the compiler to treat unequivocally the specified string constants as used objects, truly defining a new one on the first practical usage wherever it occurs and not yielding an undefined variable error:
  
===WAIT===
+
CONSTANT_INT cj_pizza_1
 
+
CONSTANT_INT cj_pizza_2
'''WAIT''' skips the execution of a [[#Structure|script]] according to some milliseconds after which it will resume again. Indeed, it is absolutely necessary into ''infinite loops'' or those that break after more than one frame, such as the [[#WHILE|WHILE]] statement. In this case, a [[#INT|INT]] equal to 0 is passed.
+
VAR_INT food_model1 food_model2
 
+
===GOTO===
+
REQUEST_MODEL pizzahigh  // -1
 +
food_model1 = cj_pizza_1 // -2
 +
food_model2 = cj_pizza_2 // -3
 +
REQUEST_MODEL food_model1
 +
REQUEST_MODEL food_model2
  
'''GOTO''' jumps to the [[#Labels|label]] of any location of the source code. It is also used internally to build other [[#Statements|statements]] or singularly but then it mustn't point off the current context:
+
Any string constant passed in place of an object model compiles a used object indiscriminately assuming no <code>CONSTANT_INT</code> declaration, also preventing redefinitions towards default constants, enumerators and variable names, does exist. Messing around with frequent compiler tool recompilations can be tedious solely to establish broad, same-indexed or math-related string constants but fortunately, in the last Trilogy chapter, the language offers the opportunity to settle user-supplied default constants for numeric literals using <code>CONST</code>-prefixed declarations (maximum 39 characters long) which, alike for variables and <code>CONSTANT_INT</code>s, are backwards accessible:
  
  // File: any.sc
+
  CONST_INT gf_date_active 1
 +
CONST_FLOAT math_pi 3.1415927
 
   
 
   
  jump0:
+
  SET_BIT gf_date_flags gf_date_active
  GOTO jumpN
+
  rad_angle = deg_angle * math_pi
 +
rad_angle /= 180.0
  
// File: any.sc
+
Given that default models are also default constants in Stories chapters<sup>[no source]</sup>, default constants and used objects count as pseudoconstants: contrary to what non-default enumerators entail, generic alternatives are favoured on assignment or comparison command matching. It should be pointed out that, due to a critical compiler bug, the high-order word of the value held by any enumerator is unexpectedly discarded on assignment or comparison and that, if set, the 16th bit yields a nonexistent variable error (i.e. <code>THREAT_GANG9</code> flag) prior Stories chapters, after which a default constant is compiled instead (buggy behaviour) and recognized only if the low-order word represents a value not equal to -1<sup>[no source]</sup>:
 
jumpN:
 
GOTO jump0
 
  
===ANDOR===
+
{|style="table-layout: fixed; margin-bottom: -8px" width=100% cellspacing=0 cellpadding=0
 +
|width=50%|'''Mission script'''
 +
|width=16px rowspan=2|
 +
|width=50%|'''Script multifile'''
 +
|-
 +
|style="vertical-align: top"|
 +
<pre style="white-space: pre; overflow-x: scroll">
 +
SET_CHAR_THREAT_SEARCH npc_char THREAT_GANG_GOLFER
 +
SET_CHAR_THREAT_SEARCH npc_char THREAT_GANG9
 +
SET_CHAR_THREAT_SEARCH npc_char THREAT_EMERGENCY
 +
threat_flag = THREAT_GANG_GOLFER
 +
threat_flag = THREAT_GANG9 // Ill-formed in Trilogy.
 +
threat_flag = THREAT_EMERGENCY
 +
</pre>
 +
|style="vertical-align: top"|
 +
<pre style="white-space: pre; overflow-x: scroll">
 +
SET_CHAR_THREAT_SEARCH npc_char 16384
 +
SET_CHAR_THREAT_SEARCH npc_char 32768
 +
SET_CHAR_THREAT_SEARCH npc_char 65536
 +
SET_VAR_INT_TO_CONSTANT threat_flag 16384
 +
SET_VAR_INT threat_flag 32768
 +
SET_VAR_INT_TO_CONSTANT threat_flag 0
 +
</pre>
 +
|}
  
'''ANDOR''' set out the way the comparison among more conditions have to occur (see also [[#Comparing rule|Comparing rule]]).
+
This drawback unwittingly affects real code in Liberty City Stories in one circumstance. On a final note, string constants are incompatible with optional arguments and thus taking advantage of a temporary variable would overcome this syntactic limitation.
  
===GOTO_IF_TRUE===
+
==Operators==
 +
As soon as a numeric or text label variable is declared, it can be subjected to algebric operations and/or logical comparisons by virtue of several operators. Their support is sadly very primitive, in fact the ability to establish complex expressions with parentheses and such is not featured albeit one and only binary operation is enabled to follow the basic assignment. In this regard, the variable being assigned to the lvalue cannot be the same as the outer rvalue for non-commutative operations: <code>VAR1 = THING - VAR1</code>, <code>VAR1 = THING / VAR1</code>, <code>VAR1 = THING +@ VAR1</code> and <code>VAR1 = THING -@ VAR1</code> are all ill-formed (where <code>THING</code> &ne; <code>VAR1</code>). This issue arises because the explicit usage of a temporary variable is needed which would be harmful for the compiler to waste by itself under the hood, thus here expressions are necessarily made up of distinct two-operand instructions, that is the lvalue content is initialized prior encoding any supplementary rvalue arithmetic:
  
'''GOTO_IF_TRUE''' operates in conjunction with [[#ANDOR|ANDOR]] and jumps to a [[#Labels|label]] if the returned boolean flag is true.
+
{|style="table-layout: fixed; margin-bottom: -8px" width=100% cellspacing=0 cellpadding=0
 +
|width=50%|'''Mission script'''
 +
|width=16px rowspan=2|
 +
|width=50%|'''Script multifile'''
 +
|-
 +
|style="vertical-align: top"|
 +
<pre style="white-space: pre; overflow-x: scroll">
 +
VAR1 = 1 - VAR1 // Invalid, cause VAR1 = 1; VAR1 -= VAR1 doesn't make sense.
 +
                // It would perform 1 - 1 = 0. Workaround needed.
 +
VAR1 = 1 / VAR1 // Invalid, cause VAR1 = 1; VAR1 /= VAR1 does no effect.
 +
                // It would perform 1 / 1 = 1. Workaround needed.
 +
VAR1 = 1 - VAR2 // Valid, cause VAR1 = 1; VAR1 -= VAR2 doesn't null itself like above.
 +
                // It performs x = 1 - y.
 +
VAR1 = 1 + VAR1 // Valid, addition (as well as multiplication) is commutative so VAR1 += 1.
 +
                // It performs x = x + 1.
 +
</pre>
 +
|style="vertical-align: top"|
 +
<pre style="white-space: pre; overflow-x: scroll">
 +
NEGATE VAR1 // Unknown command (speculative). It would do x = -x.
 +
ADD_THING_TO_THING VAR1 1
 +
ONEOVER VAR1 // Unknown command (speculative). It would do x = 1 / x.
 +
MULT_THING_BY_THING VAR1 1
 +
SET VAR1 1
 +
SUB_THING_FROM_THING VAR1 VAR2
 +
ADD_THING_TO_THING VAR1 1
  
===GOTO_IF_FALSE===
+
</pre>
 
+
|}
Unlike [[#GOTO_IF_TRUE|GOTO_IF_TRUE]], '''GOTO_IF_FALSE''' jumps to the disired [[#Labels|label]] only if the comparison returns false.
 
 
 
===SAVE_STRING_TO_DEBUG_FILE===
 
 
 
'''SAVE_STRING_TO_DEBUG_FILE''' accepts an [[#Arguments|argument]] which can admit up to ''127 characters plus the null-terminator''. In the compiling process, the argument is skipped but its string is copied to a predefined ''128-bytes buffer'', compiled afterwards. These are the predetermined bytes that seem to do nothing:
 
 
 
00 00 41 00 09 2E 00 00 00 00 00 00 <span style="color: silver">00</span> 00 00 00
 
<span style="color: blue">09 2E 00 00</span> 00 00 00 00 1C FB 12 00 D8 A8 41 00
 
00 00 41 00 09 2E 00 00 00 00 00 00 <span style="color: silver">01</span> 00 00 00
 
<span style="color: blue">09 2E 00 00</span> 00 00 00 00 1C FB 12 00 D8 A8 41 00
 
00 00 41 00 09 2E 00 00 00 00 00 00 <span style="color: silver">02</span> 00 00 00
 
<span style="color: blue">09 2E 00 00</span> 00 00 00 00 1C FB 12 00 D8 A8 41 00
 
00 00 41 00 09 2E 00 00 00 00 00 00 <span style="color: silver">03</span> 00 00 00
 
<span style="color: blue">09 2E 00 00</span> 00 00 00 00 1C FB 12 00 D8 A8 41 00
 
 
 
Dynamic values within a block are marked in <span style="color: silver">grey</span>, while those which differs among each block are coloured in <span style="color: blue">blue</span>. Possibly rubbish data.
 
 
 
==Constants==
 
 
 
A ''constant'' is a ''symbolic name'' associated to a specific [[#Value|value]]. When compiling, their caption is converted in the assigned value. In {{icon|3}} and {{icon|vc}}, they are hardcoded as everything inside the compiler. Since {{icon|vc}}, names and identifiers of objects within [[OBJS]] and [[TOBJ]] blocks are loaded from every ''IDE'' file defined into [[gta.dat|gta_vc.dat]], then those of vehicles and pedestrians within [[PEDS]] and [[CARS]] blocks are retrieved from [[default.ide]]. In {{icon|sa}}, they are listed into ''TXT'' files, whose name follows the [[Wikipedia:CamelCase|Pascal Case]] (eg. ''AudioEvents.txt''). These files respect the syntax below:
 
 
 
{constname0} {constvalue0}
 
 
{constnameN} {constvalueN}
 
 
 
''Constant names and values'' are divided by as many ''spaces'' or ''tabulations'' as you want. ''Constant lines'' are distinguished by two '''\n''' (new line) characters. The ''model names'' which aren't assigned to a constant are still valid (see also [[#Identifiers|Identifiers]]). Keep in mind [[#Arguments|arguments]] of some [[#Commands|commands]] having the [[#CONSTANT|CONSTANT]] type accept only ''constant values'' of a single ''namespace''.
 
  
==Formatting==
+
The subtraction of positive or negative rvalues necessitates a splitting character in order to discern the infix operator unambiguously, which would be treated as part of the literal or a variable decrement otherwise (i.e. <code>VAR1 = VAR1 -1</code> or <code>VAR1 = VAR1 --1</code>). Typically, string constants are not suitable for math calculations because of the lack of matchable alternative commands but even so they are semantically contemplated as long as a non-default enumerator is provided as the inner rvalue of a ternary operation or a default constant or enumerator is passed to any rvalue (i.e. <code>VAR1 = PAD1 + 1</code>, <code>VAR1 = DAY + 1</code> or <code>VAR1 = 1 + KILLFRENZY_INITIALLY</code>). Another clear limitation is prefix and postfix operators do not apply onto arguments, hence there's no concrete differentiation. However, the language introduces the timed addition/subtraction to looply update a variable in a frame-rate independent way, the cast assignment to do a mutual conversion between integers and floats but it doesn't give support for the modulo operation as its predecessor. The inequality comparison was planned but quickly gone obsolete<sup>[no source]</sup> &ndash; availing of the negated form of the equality operator would have sounded more intuitive but one should be aware the not-flag is not bundled with the command index when matching alternative commands. Due to a negligence of the programmers in charge, liable for forgetting some assets of the scripting environment, the local-global in/equality comparison between integer or float variables is not feasible except in the last chapter of Trilogy and Stories series. Surprisingly enough, the basic assignment may prepend <code>ABS</code> which in so doing would be capable of receiving numeric literals because of the pre-empted rvalue assigning (i.e. <code>VAR = ABS THING</code>). In principle, <code>SET</code> is not compiled only if both lvalue and rvalue (whether inner or outer) of a ternary operation or <code>ABS</code> assignment collide (identity).
  
Everything is ''case-insensitive'', that means the uppercase and lowercase letters are computed as the same character. Usually, the source code is formatted as shown in this table:
+
<span style="display: block; margin: 1em 0; font-size: 1.17em; font-weight: bold; color: black" id="Arithmetic_operators">Arithmetic operators</span>
  
 
{|class=wikitable
 
{|class=wikitable
!
 
!Uppercase
 
!Lowercase
 
 
|-
 
|-
|[[#Label|Label]]||||align=center|X
+
!colspan=2 width=192px style="text-align: left"|Name
 +
!width=148px|Syntax
 +
!width=112px|INT
 +
!width=112px|FLOAT
 +
!width=112px|TEXT_LABEL/16
 
|-
 
|-
|[[#Declaration|Declaration]]||align=center|X||
+
|colspan=2|Basic assignment||align=center|<pre style="margin: 0">VAR = THING</pre>||align=center|&#x2713;||align=center|&#x2713;||align=center|&#x2713;
 
|-
 
|-
|[[#Variables|Variable]]||||align=center|X
+
|colspan=2|Addition||align=center|<pre style="margin: 0">THING + THING</pre>||align=center|&#x2713;||align=center|&#x2713;||
 
|-
 
|-
|[[#Commands|Command]]||align=center|X||
+
|colspan=2|Subtraction||align=center|<pre style="margin: 0">THING - THING</pre>||align=center|&#x2713;||align=center|&#x2713;||
 
|-
 
|-
|[[#Constants|Constant]]||align=center|X||
+
|colspan=2|Multiplication||align=center|<pre style="margin: 0">THING * THING</pre>||align=center|&#x2713;||align=center|&#x2713;||
 
|-
 
|-
|[[#Statements|Statement]]||align=center|X||
+
|colspan=2|Division||align=center|<pre style="margin: 0">THING / THING</pre>||align=center|&#x2713;||align=center|&#x2713;||
|}
 
 
 
=Compiling=
 
 
 
==Structure==
 
 
 
The source code is split up into several ''SC'' files which comprehend ''main file'', ''foreign gosubs'', ''subscripts'', ''mission scripts'', and ''triggers''.
 
 
 
===Main file===
 
----
 
The ''main file'' is the most significant part of the whole source. It can include many script files and/or embedded ''gosubs'', ''scripts'' or ''functions''. Originally, it is characterized by the absence of the [[#Local|local]] [[#Scope|scope]]. It must be put outside the directory, having the same name as the main script file, where all other foreign scripts must be. R* compiler will search into subfolders too:
 
 
 
<directory>
 
| main
 
|  | gosub
 
|  |  |- gosub1.sc
 
|  |  \- gosubN.sc
 
|  | subscript
 
|  |  |- subscript1.sc
 
|  |  \- subscriptN.sc
 
|  | mission_guy
 
|  |  |- mission_guy1.sc
 
|  |  \- mission_guyN.sc
 
|  |- gosub.sc
 
|  |- subscript.sc
 
|  \- mission.sc
 
\- main.sc
 
 
 
===Foreign gosubs===
 
----
 
''Foreign gosubs'' (also called ''subroutines'') are ''main extension files''. They are called using the '''GOSUB_FILE''' [[#Commands|command]] which jumps to a specific [[#Labels|label]] and executes some code that returns back to the place where it has been called with '''RETURN'''. You are able to specify the gosub label to start jumping at aswell:
 
 
 
// File: main.sc
 
 
GOSUB_FILE gosub0 gosub.sc
 
 
 
// File: gosub.sc
 
 
gosub0:
 
{
 
    [...]
 
}
 
RETURN
 
 
 
;Limit
 
:Foreign gosubs were introduced since {{icon|3}}. They were unused in {{icon|vc}} and got removed in {{icon|sa}}, but then they were reimplemented in {{icon|lcs}} and {{icon|vcs}}.
 
 
 
====Gosubs====
 
 
 
As mentioned, ''gosubs'' are also embedded in any script file. They follow almost the same rules, except they are called by '''GOSUB''' and can actually inehrit the [[#Local|local]] [[#Scope|scope]] of the parent script:
 
 
 
// File: any.sc
 
 
GOSUB gosub0
 
 
 
// File: any.sc
 
 
gosub0:
 
{
 
    [...]
 
}
 
RETURN
 
 
 
;Note
 
:R* compiler doesn't take care if the code within a scope jumps to a gosub inside which another scope is declared. It is strongly recommended to pay attention at this issue or you will fall down into an irreparable local [[#Variables|variable]] mismatch.
 
 
 
===Subscripts===
 
----
 
''Subscripts'' are code blocks which take part of a ''queue of other scripts''. They are denoted by the presence of '''MISSION_START''' at the very top of the mission file. As long as they aren't ended with '''MISSION_END''', their execution never expires till the end of the game process. Each one works independently, even though they are able to share [[#Global|global]] [[#Variables|variables]]:
 
 
 
// File: main.sc
 
 
LAUNCH_MISSION subscript.sc
 
 
 
// File: subscript.sc
 
 
MISSION_START
 
 
[VAR_{vartype} {varname0}[,] [... {varnameN}]]
 
 
SCRIPT_NAME main
 
 
subscript_loop:
 
{
 
    [LVAR_{vartype} {varname0}[,] [... {varnameN}]]
 
 
    [...]
 
}
 
//GOTO subscript_loop
 
MISSION_END
 
 
 
;Note
 
:'''MISSION_START''' is a special and fake directive that isn't assigned to any [[#Commands|command]].
 
 
 
====Scripts====
 
 
 
As for [[#Gosubs|gosubs]], ''scripts'' can be embedded everywhere in a script file. They are started by '''START_NEW_SCRIPT''' which has an undefined amount of [[#Arguments|arguments]], whose type must match with those of each [[#Local|local]] variable of the starting script in order to be passed, else the compilation will interrupt. Unlike subscripts, they get terminated by '''TERMINATE_THIS_SCRIPT''' or '''TERMINATE_ALL_SCRIPTS_WITH_THIS_NAME''' (elsewhere in another script):
 
 
 
// File: any.sc
 
 
START_NEW_SCRIPT script [{anyvalue0|varname0} ... {anyvalueN|varnameN}]
 
 
 
// File: any.sc
 
 
script:
 
{
 
    SCRIPT_NAME script
 
 
script_loop:
 
 
    [LVAR_{vartype} {varname0}[,] [... {varnameN}]]
 
 
    [...]
 
 
    //GOTO script_loop
 
    TERMINATE_THIS_SCRIPT
 
}
 
 
 
;Notes
 
:Scripts must have a local [[#Scope|scope]].
 
:Script commands must be inserted within or after the local scope.
 
:Since {{icon|vc}}, the ''opening curly bracket'' must be put before the script [[#Labels|label]] when more arguments are passed.
 
 
 
====Functions====
 
 
 
{{incomplete}}
 
 
 
===Mission scripts===
 
----
 
''Mission scripts'' are [[#Subscripts|subscripts]] which take part of the ''mission block'', which is basically a subscript started once. When they are launched with '''LOAD_AND_LAUNCH_MISSION''', the pointer is moved to the corresponding mission [[#Offsets|offset]] located somewhere in the mission block. Do not forget to begin a mission with '''MISSION_START''' and end it with '''MISSION_END''':
 
 
 
// File: main.sc
 
 
LOAD_AND_LAUNCH_MISSION mission.sc
 
 
 
// File: mission.sc
 
 
MISSION_START
 
 
GOSUB mission_start
 
 
IF HAS_DEATHARREST_BEEN_EXECUTED
 
    GOSUB mission_failed
 
ENDIF
 
 
GOSUB mission_cleanup
 
 
MISSION_END
 
 
[VAR_{vartype} {varname0}[,] [... {varnameN}]]
 
 
mission_start:
 
 
REGISTER_MISSION_GIVEN
 
SCRIPT_NAME mission
 
 
// Variables initialization
 
 
{
 
    [LVAR_{vartype} {varname0}[,] [... {varnameN}]]
 
 
    [...]
 
}
 
GOTO mission_passed
 
 
mission_failed:
 
[...]
 
RETURN
 
 
mission_passed:
 
REGISTER_MISSION_PASSED mission
 
//PLAYER_MADE_PROGRESS 1
 
[...]
 
RETURN
 
 
mission_cleanup:
 
// Mark everything as no longer needed
 
[...]
 
RETURN
 
 
 
===Triggers===
 
----
 
{{incomplete}}
 
 
 
==Statements==
 
 
 
As usual, the evolution of something implies its development over the years. Alongside, the ''statements'' implementation has been distributed equally into every chapter. Their definitions are similar to those used in ''pseudocodes'' resulting in a ''raw source code''. However, you are still able to build your own control flows:
 
 
 
ANDOR {value}
 
  [NOT] {condition0}
 
  [[NOT] {condition8}]
 
GOTO_IF_FALSE ELSE
 
    {consequence}
 
    [GOTO ENDIF]
 
ELSE:
 
    [{alternative}
 
ENDIF:]
 
 
 
===IF===
 
 
 
'''IF''' is one of the most widespread ''conditional statements'' which executes some codes by evaluating a boolean flag, the returning value of one or more conditions. According to the returning value, either the ''consequence'' or the ''alternative'' will be performed. The condition result can be inverted by appending the '''NOT''' [[#Logical|logical operator]] before. More conditions require the use of the remaining logical operators, they are '''AND''', when verifying if all ''checks'' are true, and '''OR''', while testing if one of all checks is true. The syntax below summarize the whole explanation:
 
 
 
IF [NOT] {condition0}
 
[AND|OR [NOT] {condition8}]
 
    {consequence}
 
[ELSE
 
    {alternative}]
 
ENDIF
 
 
 
;Limit
 
:More than ''9 conditions'' per statement are't allowed.
 
 
 
===IFNOT===
 
 
 
'''IFNOT''' is a variation of the '''IF''' statement as already stated. As opposed to its closest relative, the conditions evaluetion is reversed, that is the ''consequence'' is perfomed when the boolean flag is false, else the ''alternative'' is executed:
 
 
 
IFNOT [NOT] {condition0}
 
[AND|OR [NOT] {condition8}]
 
    {consequence}
 
[ELSE
 
    {alternative}]
 
ENDIF
 
 
 
;Limit
 
:It is supported since {{icon|lcs}}.
 
 
 
===WHILE===
 
 
 
Alike the '''IF''' ''construct'', '''WHILE''' is a conditional statement. The only difference consists in how it performs the ''consequence'', that is it ''loops'' every line of code built into if the boolean flag is true:
 
 
 
WHILE [NOT] {condition0}
 
[AND|OR [NOT] {condition8}]
 
    {consequence}
 
ENDWHILE
 
 
 
===WHILENOT===
 
 
 
'''WHILENOT''' acts seemingly like the '''WHILE''' statement, as all condition truths are inverted and therefore the ''consequence'' is performed over and over again until the boolean flag becomes true:
 
 
 
WHILENOT [NOT] {condition0}
 
[AND|OR [NOT] {condition8}]
 
    {consequence}
 
ENDWHILE
 
 
 
;Limit
 
:It is supported since {{icon|lcs}}.
 
 
 
===REPEAT===
 
 
 
Similar to the '''WHILE''' construct, '''REPEAT''' ''iterates'' the ''consequence'' repeatedly depending on a 0-value incremental [[#Variables|variable]] which rises till the times specified:
 
 
 
REPEAT {times} {varname}
 
    {consequence}
 
ENDREPEAT
 
 
 
;Limits
 
:It is supported since {{icon|vc}}.
 
:The times must be positive.
 
:The code will be read at least once in any case.
 
 
 
===CASE===
 
 
 
Basically, '''CASE''' is a ''group of concatenated '''IF''' statements''. When a condition is false the next ''case'' gets performed, otherwise the ''consequence'' is executed and the code jumps to the end of the construct. If none of the cases is true, an '''ELSE''' clause may be carried out:
 
 
 
CASE {varname}
 
    WHEN {value0}
 
        {consequence}
 
    [WHEN {valueN}
 
        {consequence}]
 
    [ELSE
 
        {alternative}]
 
ENDCASE
 
 
 
;Limits
 
:It is supported since {{icon|sa}}.
 
:The '''WHEN''' clause allows the use of integer values only.
 
:In {{icon|sa}}, values must be sorted.
 
:Multiple cases per ''consequence'' aren't allowed.
 
 
 
=Decompiling=
 
 
 
==Structure==
 
 
 
For further information about the SCM file format, read [[Mission_Scripting (Overview)|this]] article. Take into account the compiling order of each ''SC'' file is [[#Main file|main file]] - [[#Foreign gosubs|foreign gosubs]] - [[#Subscripts|subscripts]] - [[#Mission scripts|mission scripts]] apart from the reading order of the commands used to include them. [[#Triggers|triggers]] are compiled individually into the ''script.img'' file. On the other hand, [[#Functions|functions]] are compiled like [[#Gosubs|gosubs]].
 
 
 
==Identifiers==
 
 
 
''Undefined [[#Constants|constants]]'' of model identifiers, whose name refers to a [[DFF]] which is presumably archived into any of the [[IMG]]s, loaded by the game, are overwritten by a decrementing value in the order they get compiled. These ''model names'' are then put into the second segment of the ''SCM header''. Those of [[#Mission scripts|mission scripts]] and [[#Triggers|triggers]] respect the same rule except the fact they are turned into a 0-based growing identifier.
 
 
 
==Offsets==
 
 
 
An ''offset'' is a ''32-bit signed integer'' which points to a location of the source code. Those within the [[#Main file|main file]], [[#Foreign gosubs|foreign gosubs]] and [[#Subscripts|subscripts]] are ''absolute offsets'' that start from the beginning of the main script, while the ones inside [[#Mission scripts|mission scripts]] and [[#Triggers|triggers]] are ''relative offsets'' starting from their beginning. The offset is related to [[#Global|global]] [[#Variables|variables]] aswell, whose interval goes from ''8'' and ends to ''FFFC'', each one is aligned to the nearest 4 bytes.
 
 
 
==Variables==
 
 
 
The following table shows the [[#Variables|variables]] range of the [[#Local|local]] [[#Scope|scope]] for each game version:
 
 
 
{|class=wikitable style=text-align:center
 
!width=125px|Context
 
!width=50px|{{icon|3}}
 
!width=50px|{{icon|vc}}
 
!width=50px|{{icon|sa}}
 
!width=50px|{{icon|lcs}}
 
!width=50px|{{icon|vcs}}
 
|-
 
|align=left|[[#Foreign gosubs|Foreign gosub]]/[[#Gosubs|Gosub]]||0-15||0-15||n/a||0-95||0-95
 
 
|-
 
|-
|align=left|[[#Subscripts|Subscript]]/[[#Scripts|Script]]||0-15||0-15||0-31||0-95||0-95
+
|colspan=2|Timed addition||align=center|<pre style="margin: 0">THING +@ THING</pre>||||align=center|&#x2713;||
 
|-
 
|-
|align=left|[[#Mission scripts|Mission script]]{{ref|mblock|[*]}}||0-15||0-15||0-1023||0-95||0-95
+
|colspan=2|Timed subtraction||align=center|<pre style="margin: 0">THING -@ THING</pre>||||align=center|&#x2713;||
 
|-
 
|-
|align=left|[[#Triggers|Trigger]]||n/a||n/a||0-31||n/a||n/a
+
|rowspan=2|Increment||Prefix||align=center|<pre style="margin: 0">++ VAR</pre>||rowspan=2 align=center|&#x2713;||rowspan=2|
 +
|rowspan=2|
 
|-
 
|-
|align=left|[[#Functions|Function]]||n/a||n/a||n/a||0-95||0-95
+
|Postfix||align=center|<pre style="margin: 0">VAR ++</pre>
 
|-
 
|-
!colspan=6|
+
|rowspan=2|Decrement||Prefix||align=center|<pre style="margin: 0">-- VAR</pre>||rowspan=2 align=center|&#x2713;||rowspan=2|
 +
|rowspan=2|
 
|-
 
|-
|align=left|[[#Timers|Timer]]||16-17||16-17||32-33||10-11?||254-255
+
|Postfix||align=center|<pre style="margin: 0">VAR --</pre>
 
|}
 
|}
  
;Note
+
<span style="display: block; margin: 1em 0; font-size: 1.17em; font-weight: bold; color: black" id="Compound_assignment_operators">Compound assignment operators</span>
:{{note|mblock}} Although the mission block is allocated as an ''unique subscript'', locals point to the same storage location, therefore they are some kind of [[#Globals|globals]] for missions uniquely.
 
 
 
==Operators composition==
 
 
 
As far as you wouldn't know, SCM's [[#Operators|operators]] always take two operands to compute an operation. Their composition is listed below:
 
  
 
{|class=wikitable
 
{|class=wikitable
!width=70px|Operator/s
 
!width=200px colspan=2|Name
 
!width=200px|Syntax
 
!width=180px|Composition
 
|-
 
!rowspan=2|<code>++</code>
 
|align=center rowspan=2|Increment
 
|align=center|Pre
 
|align=center|<code>'''++''' expr0</code>
 
|align=center rowspan=2|<code>expr0 '''+=''' 1</code>
 
|-
 
|align=center|Post
 
|align=center|<code>expr0 '''++'''</code>
 
 
|-
 
|-
!rowspan=2|<code>--</code>
+
!width=192px style="text-align: left"|Name
|align=center rowspan=2|Decrement
+
!width=148px|Syntax
|align=center|Pre
+
!Meaning
|align=center|<code>'''--''' expr0</code>
+
!width=112px|INT
|align=center rowspan=2|<code>expr0 '''-=''' 1</code>
+
!width=112px|FLOAT
 
|-
 
|-
|align=center|Post
+
|Addition assignment||align=center|<pre style="margin: 0">VAR += THING</pre>||align=center|<pre style="margin: 0">VAR1 = VAR1 + THING</pre>||align=center|&#x2713;||align=center|&#x2713;
|align=center|<code>expr0 '''--'''</code>
 
 
|-
 
|-
!<code>= +</code>
+
|Subtraction assignment||align=center|<pre style="margin: 0">VAR -= THING</pre>||align=center|<pre style="margin: 0">VAR1 = VAR1 - THING</pre>||align=center|&#x2713;||align=center|&#x2713;
|align=center colspan=2|Addition and assignment
 
|align=center|<code>expr0 '''=''' expr1 '''+''' expr2</code>
 
|align=center|<code>expr0 '''=''' expr1<br/>expr0 '''+=''' expr2</code>
 
 
|-
 
|-
!<code>= -</code>
+
|Multiplication assignment||align=center|<pre style="margin: 0">VAR *= THING</pre>||align=center|<pre style="margin: 0">VAR1 = VAR1 * THING</pre>||align=center|&#x2713;||align=center|&#x2713;
|align=center colspan=2|Subtraction and assignment
 
|align=center|<code>expr0 '''=''' expr1 '''-''' expr2</code>
 
|align=center|<code>expr0 '''=''' expr1<br/>expr0 '''-=''' expr2</code>
 
 
|-
 
|-
!<code>= *</code>
+
|Division assignment||align=center|<pre style="margin: 0">VAR /= THING</pre>||align=center|<pre style="margin: 0">VAR1 = VAR1 / THING</pre>||align=center|&#x2713;||align=center|&#x2713;
|align=center colspan=2|Multiplication and assignment
 
|align=center|<code>expr0 '''=''' expr1 '''*''' expr2</code>
 
|align=center|<code>expr0 '''=''' expr1<br/>expr0 '''*=''' expr2</code>
 
 
|-
 
|-
!<code>= /</code>
+
|Timed addition assignment||align=center|<pre style="margin: 0">VAR +=@ THING</pre>||align=center|<pre style="margin: 0">VAR1 = VAR1 +@ THING</pre>||align=center|&nbsp;||align=center|&#x2713;
|align=center colspan=2|Division and assignment
 
|align=center|<code>expr0 '''=''' expr1 '''/''' expr2</code>
 
|align=center|<code>expr0 '''=''' expr1<br/>expr0 '''/=''' expr2</code>
 
 
|-
 
|-
!<code>= +@</code>
+
|Timed subtraction assignment||align=center|<pre style="margin: 0">VAR -=@ THING</pre>||align=center|<pre style="margin: 0">VAR1 = VAR1 -@ THING</pre>||||align=center|&#x2713;
|align=center colspan=2|Timed addition and assignment
 
|align=center|<code>expr0 '''=''' expr1 '''+@''' expr2</code>
 
|align=center|<code>expr0 '''=''' expr1<br/>expr0 '''+=@''' expr2</code>
 
 
|-
 
|-
!<code>= -@</code>
+
|Cast assignment||align=center|<pre style="margin: 0">VAR =# THING</pre>||align=center|AS IS||align=center|&#x2713;||align=center|&#x2713;
|align=center colspan=2|Timed subtraction and assignment
 
|align=center|<code>expr0 '''=''' expr1 '''-@''' expr2</code>
 
|align=center|<code>expr0 '''=''' expr1<br/>expr0 '''-=@''' expr2</code>
 
 
|}
 
|}
  
==Opcodes==
+
<span style="display: block; margin: 1em 0; font-size: 1.17em; font-weight: bold; color: black" id="Comparison_operators.2Frelational_operators">Comparison operators/relational operators</span>
  
An ''opcode'' is a ''16-bit unsigned integer'' referring to a portion of code the game executes when it is called by passing an undefined or absent amount of ''arguments''. The maximum number of available opcodes is ''0x7FFF'', since the last bit (''0x8000'') is set whenever they are used as ''negative conditions'' (those with the '''NOT''' [[#Logical|logical operator]]).
+
{|class=wikitable
 
 
===Arguments===
 
 
 
An ''argument'' is some data given as input to an opcode. Normally, opcodes have a defined amount of arguments up to 32. Those not, such as '''START_NEW_SCRIPT''', can pass as many arguments as the available [[#Local|local]] [[#Variables|variables]] are, except [[#Timers|timers]]. This limitation is game specific.
 
 
 
===Internal===
 
 
 
Here is the list of all commands handled arbitrarily by the R* compiler:
 
 
 
'''Legend:'''
 
* '''Variable:'''<code>
 
** V, [[#Value|VALUE]]
 
** G, [[#Global|GLOBAL]]
 
** L, [[#Local|LOCAL]]
 
</code>
 
* '''Type:'''<code>
 
** I, [[#INT|INT]]
 
** F, [[#FLOAT|FLOAT]]
 
** T, [[#TEXT_LABEL|TEXT_LABEL]]
 
** S, [[#STRING|STRING]]
 
** O, [[#OFFSET|OFFSET]]
 
** N, [[#NUMBER|NUMBER]]
 
** C, [[#CONSTANT|CONSTANT]]
 
** B, [[#BUFFER|BUFFER]]
 
** V, [[#VARLEN|VARLEN]]
 
</code>
 
'''List:'''
 
{|class=wikitable style=text-align:center
 
!rowspan=2 colspan=2|Command
 
!rowspan=2|Opcode
 
!rowspan=2|Args<br/>count
 
!colspan=20|Arguments
 
 
|-
 
|-
!width=20px|1
+
!width=192px style="text-align: left"|Name
!width=20px|2
+
!width=148px|Syntax
!width=20px|3
+
!width=112px|INT
!width=20px|4
+
!width=112px|FLOAT
!width=20px|5
+
!width=112px|TEXT_LABEL/16
!width=20px|6
 
!width=20px|7
 
!width=20px|8
 
!width=20px|9
 
!width=20px|10
 
!width=20px|11
 
!width=20px|12
 
!width=20px|13
 
!width=20px|14
 
!width=20px|15
 
!width=20px|16
 
!width=20px|17
 
!width=20px|18
 
!width=20px|...
 
!width=20px|19
 
 
|-
 
|-
|colspan=25|{{icon|3}} {{icon|vc}} {{icon|sa}} {{icon|lcs}} {{icon|vcs}}
+
|Equal to||align=center|<pre style="margin: 0">VAR = THING</pre>||align=center|&#x2713;||align=center|&#x2713;||align=center|&#x2713;
 
|-
 
|-
!colspan=2|MISSION_START{{ref|misdef|[*]}}
+
|Not equal to<sup>[no source]</sup>||align=center|<pre style="margin: 0">VAR <> THING</pre>||align=center|&#x2713;||align=center|&#x2713;||
|
 
!0
 
|colspan=20|
 
 
|-
 
|-
!colspan=2|GOTO{{ref|statem|[*]}}
+
|Greater than||align=center|<pre style="margin: 0">THING > THING</pre>||align=center|&#x2713;||align=center|&#x2713;||
|0002
 
!1
 
|VO||colspan=19|
 
 
|-
 
|-
|colspan=25|{{icon|3}} {{icon|vc}} {{icon|sa}} {{icon|lcs}}
+
|Less than||align=center|<pre style="margin: 0">THING < THING</pre>||align=center|&#x2713;||align=center|&#x2713;||
 
|-
 
|-
!rowspan=4|=!!SET_VAR_INT
+
|Greater than or equal to||align=center|<pre style="margin: 0">THING >= THING</pre>||align=center|&#x2713;||align=center|&#x2713;||
|0004
 
!rowspan=4|2
 
|GI||VI||colspan=18|
 
 
|-
 
|-
!SET_VAR_FLOAT
+
|Less than or equal to||align=center|<pre style="margin: 0">THING <= THING</pre>||align=center|&#x2713;||align=center|&#x2713;||
|0005||GF||VF||colspan=18|
+
|}
 +
 
 +
<span style="display: block; margin: 1em 0; font-size: 1.17em; font-weight: bold; color: black" id="Logical_operators">Logical operators</span>
 +
 
 +
{|class=wikitable
 
|-
 
|-
!SET_LVAR_INT
+
!width=192px style="text-align: left"|Name
|0006||LI||VI||colspan=18|
+
!width=148px|Syntax
 
|-
 
|-
!SET_LVAR_FLOAT
+
|Logical negation||align=center|<pre style="margin: 0">NOT</pre>
|0007||LF||VF||colspan=18|
 
 
|-
 
|-
!rowspan=4|+=!!ADD_VAL_TO_INT_VAR
+
|Logical conjunction||align=center|<pre style="margin: 0">AND</pre>
|0008
 
!rowspan=4|2
 
|GI||VI||colspan=18|
 
 
|-
 
|-
!ADD_VAL_TO_FLOAT_VAR
+
|Logical disjunction||align=center|<pre style="margin: 0">OR</pre>
|0009||GF||VF||colspan=18|
+
|}
 +
 
 +
==Commands==
 +
The [[Wikipedia:Imperative programming|imperative programming]] paradigm provides for a conglomerate of commands the script is filled up of and structured in, which are seen as orders to instruct the execution of the relative built-in portion of game code at runtime. Their invocation is faithful to [[Wikipedia:Functional programming|procedure]] calls: they may feature zero or more parameters (up to 16+ in III\Vice City, 32+ in San Andreas and Stories) of any type or indefinite, depending on whether or not qualified as optional, and receive as much as arguments either by-value or by-reference affecting the read/written access accordingly (do note a pure reference does not initialize anything). Alike procedures, no assignable result is returned but a boolean state is caught anyway on conditional evaluation. One major peculiarity is command names are usually identified by a verb in its imperative form:
 +
 
 +
GIVE_WEAPON_TO_CHAR mafia_1X WEAPONTYPE_UZI 999
 +
 
 +
Command names are leftmost identifiers not ending with a colon (not a label) and not preceded or followed by an operator token (not a variable). On code generation, their definition is turned into a 15-bit index reflecting the position the name is matched at in a list of command descriptors and packed with the not-flag stored in the most significant bit, accompained by a known or indeterminate number of typified, somewhat typified or thorougly nontypified operands completing several [[Wikipedia:Opcode|instructions]] which are arranged in order to bring forth the intermediate script [[Wikipedia:Bytecode|bytecode]]. At every command corresponds an output except for variable, string constant and lexical scope declarators or for the classic <code>NOP</code> ([[Wikipedia:NOP|no operation]]). Operand immediates mainly use the shortest representation for size optimization, yet label references always yield 32-bit addresses.<br/>
 +
Game progress rely on many countable stuff to determine the percentage acquired at any given time which are extremely time spending and easily error-prone to quantize manually. Counter-commands come to aid, sort of adaptive counters featuring a possibly zero-valued argument updated automatically during the compilation process that keeps track of the times a few commands are used or of the total sum of some argument value of certain commands, discarding nonimmediates:
 +
 
 +
{|class=wikitable style="text-align: left"
 
|-
 
|-
!ADD_VAL_TO_INT_LVAR
+
!Initializer
|000A||LI||VI||colspan=18|
+
!Dependency
 +
!width=50px|Is<br/>addend
 
|-
 
|-
!ADD_VAL_TO_FLOAT_LVAR
+
|<code>SET_COLLECTABLE1_TOTAL</code>||<code>CREATE_COLLECTABLE1</code>||
|000B||LF||VF||colspan=18|
 
 
|-
 
|-
!rowspan=4|-=!!SUB_VAL_FROM_INT_VAR
+
|<code>SET_PROGRESS_TOTAL</code>||<code>PLAYER_MADE_PROGRESS</code>||align=center|&#x2713;
|000C
 
!rowspan=4|2
 
|GI||VI||colspan=18|
 
 
|-
 
|-
!SUB_VAL_FROM_FLOAT_VAR
+
|rowspan=2|<code>SET_TOTAL_NUMBER_OF_MISSIONS</code>||<code>REGISTER_MISSION_PASSED</code>||
|000D||GF||VF||colspan=18|
 
 
|-
 
|-
!SUB_VAL_FROM_INT_LVAR
+
|<code>REGISTER_ODDJOB_MISSION_PASSED</code>||
|000E||LI||VI||colspan=18|
 
 
|-
 
|-
!SUB_VAL_FROM_FLOAT_LVAR
+
|<code>SET_MISSION_RESPECT_TOTAL</code>||<code>AWARD_PLAYER_MISSION_RESPECT</code>||align=center|&#x2713;
|000F||LF||VF||colspan=18|
+
|}
 +
 
 +
Condition-based statements and counter-commands along with the file includers outside of the main script or main extensions, where labels are expected instead of filenames, are mostly parameterized regardless of their own descriptor (the type-check is still done though), while another category consisting of multicommands is able to look for the matching prototype into a list of akin commands on the basis of the data type of the passed arguments and choose, accordingly, the equivalent alternative in a direct and effortless way. Although the alternative commands are also accessible by and can share the same definition, the selection process is not entirely conform to [[Wikipedia:Function overloading|function overloading]] because these still retain their exclusive name as being plainly resolved through weak aliases. A complete listing is shown below:
 +
 
 +
{|width=100% cellspacing=0 cellpadding=0
 
|-
 
|-
!rowspan=4|*=!!MULT_INT_VAR_BY_VAL
+
|width=50%|<span style="display: block; margin: 0; font-size: 1.17em; font-weight: bold; color: black">Trilogy and first Stories chapters</span>||width=50%|<span style="display: block; margin: 0; font-size: 1.17em; font-weight: bold; color: black">Second Stories chapter</span>
|0010
 
!rowspan=4|2
 
|GI||VI||colspan=18|
 
 
|-
 
|-
!MULT_FLOAT_VAR_BY_VAL
+
|valign=top|<div style="overflow: auto; float: left" width=auto>
|0011||GF||VF||colspan=18|
+
{|class=wikitable style="margin-bottom: 0" width=100%
 
|-
 
|-
!MULT_INT_LVAR_BY_VAL
+
!colspan=2 width=420px style="text-align: left"|Command
|0012||LI||VI||colspan=18|
+
!rowspan=2 width=64px|Game<br/>support
 
|-
 
|-
!MULT_FLOAT_LVAR_BY_VAL
+
!width=16px|
|0013||LF||VF||colspan=18|
+
!style="text-align: left"|Alternative
 +
|}
 +
{|class="wikitable mw-collapsible mw-collapsed" style="margin: -1px auto 0" width=100%
 
|-
 
|-
!rowspan=4|/=!!DIV_INT_ANY_BY_VAL
+
!colspan=2 style="background-color: inherit; text-align: left; font-weight: normal"|<code>SET</code> (<code>=</code>)
|0014
+
|width=64px align=center|Since {{icon|3}}
!rowspan=4|2
 
|GI||VI||colspan=18|
 
 
|-
 
|-
!DIV_FLOAT_VAR_BY_VAL
+
|rowspan=18 width=16px|
|0015||GF||VF||colspan=18|
+
|<code>SET_VAR_INT</code>||rowspan=12|
 
|-
 
|-
!DIV_INT_LVAR_BY_VAL
+
|<code>SET_VAR_FLOAT</code>
|0016||LI||VI||colspan=18|
 
 
|-
 
|-
!DIV_FLOAT_LVAR_BY_VAL
+
|<code>SET_LVAR_INT</code>
|0017||LF||VF||colspan=18|
 
 
|-
 
|-
!rowspan=16|>!!IS_INT_VAR_GREATER_THAN_NUMBER
+
|<code>SET_LVAR_FLOAT</code>
|0018
 
!rowspan=16|2
 
|GI||VN||colspan=18|
 
 
|-
 
|-
!IS_INT_LVAR_GREATER_THAN_NUMBER
+
|<code>SET_VAR_INT_TO_VAR_INT</code>
|0019||LI||VN||colspan=18|
 
 
|-
 
|-
!IS_NUMBER_GREATER_THAN_INT_VAR
+
|<code>SET_LVAR_INT_TO_LVAR_INT</code>
|001A||VN||GI||colspan=18|
 
 
|-
 
|-
!IS_NUMBER_GREATER_THAN_INT_LVAR
+
|<code>SET_VAR_FLOAT_TO_VAR_FLOAT</code>
|001B||VN||LI||colspan=18|
 
 
|-
 
|-
!IS_INT_VAR_GREATER_THAN_INT_VAR
+
|<code>SET_LVAR_FLOAT_TO_LVAR_FLOAT</code>
|001C||GI||GI||colspan=18|
 
 
|-
 
|-
!IS_INT_LVAR_GREATER_THAN_INT_LVAR
+
|<code>SET_VAR_FLOAT_TO_LVAR_FLOAT</code>
|001D||LI||LI||colspan=18|
 
 
|-
 
|-
!IS_INT_VAR_GREATER_THAN_INT_LVAR
+
|<code>SET_LVAR_FLOAT_TO_VAR_FLOAT</code>
|001E||GI||LI||colspan=18|
 
 
|-
 
|-
!IS_INT_LVAR_GREATER_THAN_INT_VAR
+
|<code>SET_VAR_INT_TO_LVAR_INT</code>
|001F||LI||GI||colspan=18|
 
 
|-
 
|-
!IS_FLOAT_VAR_GREATER_THAN_NUMBER
+
|<code>SET_LVAR_INT_TO_VAR_INT</code>
|0020||GF||VN||colspan=18|
 
 
|-
 
|-
!IS_FLOAT_LVAR_GREATER_THAN_NUMBER
+
|<code>SET_VAR_INT_TO_CONSTANT</code>||rowspan=2 align=center|Since {{icon|vc}}
|0021||LF||VN||colspan=18|
 
 
|-
 
|-
!IS_NUMBER_GREATER_THAN_FLOAT_VAR
+
|<code>SET_LVAR_INT_TO_CONSTANT</code>
|0022||VN||GF||colspan=18|
 
 
|-
 
|-
!IS_NUMBER_GREATER_THAN_FLOAT_LVAR
+
|<code>SET_VAR_TEXT_LABEL</code>||rowspan=4 align=center|{{icon|sa}} only
|0023||VN||LF||colspan=18|
 
 
|-
 
|-
!IS_FLOAT_VAR_GREATER_THAN_FLOAT_VAR
+
|<code>SET_LVAR_TEXT_LABEL</code>
|0024||GF||GF||colspan=18|
 
 
|-
 
|-
!IS_FLOAT_LVAR_GREATER_THAN_FLOAT_LVAR
+
|<code>SET_VAR_TEXT_LABEL16</code>
|0025||LF||LF||colspan=18|
 
 
|-
 
|-
!IS_FLOAT_VAR_GREATER_THAN_FLOAT_LVAR
+
|<code>SET_LVAR_TEXT_LABEL16</code>
|0026||GF||LF||colspan=18|
+
|}
 +
{|class="wikitable mw-collapsible mw-collapsed" style="margin: -1px auto 0" width=100%
 
|-
 
|-
!IS_FLOAT_LVAR_GREATER_THAN_FLOAT_VAR
+
!colspan=2 style="background-color: inherit; text-align: left; font-weight: normal"|<code>CSET</code> (<code>=#</code>)
|0027||LF||GF||colspan=18|
+
|width=64px align=center|Since {{icon|3}}
 
|-
 
|-
!rowspan=16|>=!!IS_INT_VAR_GREATER_OR_EQUAL_TO_NUMBER
+
|rowspan=8 width=16px|
|0028
+
|<code>CSET_VAR_INT_TO_VAR_FLOAT</code>||rowspan=8|
!rowspan=16|2
 
|GI||VN||colspan=18|
 
 
|-
 
|-
!IS_INT_LVAR_GREATER_OR_EQUAL_TO_NUMBER
+
|<code>CSET_VAR_FLOAT_TO_VAR_INT</code>
|0029||LI||VN||colspan=18|
 
 
|-
 
|-
!IS_NUMBER_GREATER_OR_EQUAL_TO_INT_VAR
+
|<code>CSET_LVAR_INT_TO_VAR_FLOAT</code>
|002A||VN||GI||colspan=18|
 
 
|-
 
|-
!IS_NUMBER_GREATER_OR_EQUAL_TO_INT_LVAR
+
|<code>CSET_LVAR_FLOAT_TO_VAR_INT</code>
|002B||VN||LI||colspan=18|
 
 
|-
 
|-
!IS_INT_VAR_GREATER_OR_EQUAL_TO_INT_VAR
+
|<code>CSET_VAR_INT_TO_LVAR_FLOAT</code>
|002C||GI||GI||colspan=18|
 
 
|-
 
|-
!IS_INT_LVAR_GREATER_OR_EQUAL_TO_INT_LVAR
+
|<code>CSET_VAR_FLOAT_TO_LVAR_INT</code>
|002D||LI||LI||colspan=18|
 
 
|-
 
|-
!IS_INT_VAR_GREATER_OR_EQUAL_TO_INT_LVAR
+
|<code>CSET_LVAR_INT_TO_LVAR_FLOAT</code>
|002E||GI||LI||colspan=18|
 
 
|-
 
|-
!IS_INT_LVAR_GREATER_OR_EQUAL_TO_INT_VAR
+
|<code>CSET_LVAR_FLOAT_TO_LVAR_INT</code>
|002F||LI||GI||colspan=18|
+
|}
 +
{|class="wikitable mw-collapsible mw-collapsed" style="margin: -1px auto 0" width=100%
 
|-
 
|-
!IS_FLOAT_VAR_GREATER_OR_EQUAL_TO_NUMBER
+
!colspan=2 style="background-color: inherit; text-align: left; font-weight: normal"|<code>ADD_THING_TO_THING</code> (<code>+=</code>)
|0030||GF||VN||colspan=18|
+
|width=64px align=center|Since {{icon|3}}
 
|-
 
|-
!IS_FLOAT_LVAR_GREATER_OR_EQUAL_TO_NUMBER
+
|rowspan=12 width=16px|
|0031||LF||VN||colspan=18|
+
|<code>ADD_VAL_TO_INT_VAR</code>||rowspan=12|
 
|-
 
|-
!IS_NUMBER_GREATER_OR_EQUAL_TO_FLOAT_VAR
+
|<code>ADD_VAL_TO_FLOAT_VAR</code>
|0032||VN||GF||colspan=18|
 
 
|-
 
|-
!IS_NUMBER_GREATER_OR_EQUAL_TO_FLOAT_LVAR
+
|<code>ADD_VAL_TO_INT_LVAR</code>
|0033||VN||LF||colspan=18|
 
 
|-
 
|-
!IS_FLOAT_VAR_GREATER_OR_EQUAL_TO_FLOAT_VAR
+
|<code>ADD_VAL_TO_FLOAT_LVAR</code>
|0034||GF||GF||colspan=18|
 
 
|-
 
|-
!IS_FLOAT_LVAR_GREATER_OR_EQUAL_TO_FLOAT_LVAR
+
|<code>ADD_INT_VAR_TO_INT_VAR</code>
|0035||LF||LF||colspan=18|
 
 
|-
 
|-
!IS_FLOAT_VAR_GREATER_OR_EQUAL_TO_FLOAT_LVAR
+
|<code>ADD_FLOAT_VAR_TO_FLOAT_VAR</code>
|0036||GF||LF||colspan=18|
 
 
|-
 
|-
!IS_FLOAT_LVAR_GREATER_OR_EQUAL_TO_FLOAT_VAR
+
|<code>ADD_INT_LVAR_TO_INT_LVAR</code>
|0037||LF||GF||colspan=18|
 
 
|-
 
|-
!rowspan=10|=!!IS_INT_VAR_EQUAL_TO_NUMBER
+
|<code>ADD_FLOAT_LVAR_TO_FLOAT_LVAR</code>
|0038
 
!rowspan=10|2
 
|GI||VN||colspan=18|
 
 
|-
 
|-
!IS_INT_LVAR_EQUAL_TO_NUMBER
+
|<code>ADD_INT_VAR_TO_INT_LVAR</code>
|0039||LI||VN||colspan=18|
 
 
|-
 
|-
!IS_INT_VAR_EQUAL_TO_INT_VAR
+
|<code>ADD_FLOAT_VAR_TO_FLOAT_LVAR</code>
|003A||GI||GI||colspan=18|
 
 
|-
 
|-
!IS_INT_LVAR_EQUAL_TO_INT_LVAR
+
|<code>ADD_INT_LVAR_TO_INT_VAR</code>
|003B||LI||LI||colspan=18|
 
 
|-
 
|-
!IS_INT_VAR_EQUAL_TO_INT_LVAR
+
|<code>ADD_FLOAT_LVAR_TO_FLOAT_VAR</code>
|003C||GI||LI||colspan=18|
+
|}
 +
{|class="wikitable mw-collapsible mw-collapsed" style="margin: -1px auto 0" width=100%
 
|-
 
|-
!IS_FLOAT_VAR_EQUAL_TO_NUMBER
+
!colspan=2 style="background-color: inherit; text-align: left; font-weight: normal"|<code>SUB_THING_FROM_THING</code> (<code>-=</code>)
|0042||GF||VN||colspan=18|
+
|width=64px align=center|Since {{icon|3}}
 
|-
 
|-
!IS_FLOAT_LVAR_EQUAL_TO_NUMBER
+
|rowspan=12 width=16px|
|0043||LF||VN||colspan=18|
+
|<code>SUB_VAL_FROM_INT_VAR</code>||rowspan=12|
 
|-
 
|-
!IS_FLOAT_VAR_EQUAL_TO_FLOAT_VAR
+
|<code>SUB_VAL_FROM_FLOAT_VAR</code>
|0044||GF||GF||colspan=18|
 
 
|-
 
|-
!IS_FLOAT_LVAR_EQUAL_TO_FLOAT_LVAR
+
|<code>SUB_VAL_FROM_INT_LVAR</code>
|0045||LF||LF||colspan=18|
 
 
|-
 
|-
!IS_FLOAT_VAR_EQUAL_TO_FLOAT_LVAR
+
|<code>SUB_VAL_FROM_FLOAT_LVAR</code>
|0046||GF||LF||colspan=18|
 
 
|-
 
|-
!colspan=2|GOTO_IF_FALSE{{ref|statem|[*]}}
+
|<code>SUB_INT_VAR_FROM_INT_VAR</code>
|004D
 
!1
 
|VO||colspan=19|
 
 
|-
 
|-
!colspan=2|TERMINATE_THIS_SCRIPT
+
|<code>SUB_FLOAT_VAR_FROM_FLOAT_VAR</code>
|rowspan=2|004E
 
!rowspan=2|0
 
|rowspan=2 colspan=20|
 
 
|-
 
|-
!colspan=2|MISSION_END
+
|<code>SUB_INT_LVAR_FROM_INT_LVAR</code>
 
|-
 
|-
!colspan=2|START_NEW_SCRIPT{{ref|undefa|[*]}}
+
|<code>SUB_FLOAT_LVAR_FROM_FLOAT_LVAR</code>
|004F
 
!1
 
|VO||colspan=19|_ _ _
 
 
|-
 
|-
!colspan=2|GOSUB
+
|<code>SUB_INT_VAR_FROM_INT_LVAR</code>
|0050
 
!1
 
|VO||colspan=19|
 
 
|-
 
|-
!colspan=2|RETURN
+
|<code>SUB_FLOAT_VAR_FROM_FLOAT_LVAR</code>
|0051
 
!0
 
|colspan=20|
 
 
|-
 
|-
!rowspan=8|+=!!ADD_INT_VAR_TO_INT_VAR
+
|<code>SUB_INT_LVAR_FROM_INT_VAR</code>
|0058
 
!rowspan=8|2
 
|GI||GI||colspan=18|
 
 
|-
 
|-
!ADD_FLOAT_VAR_TO_FLOAT_VAR
+
|<code>SUB_FLOAT_LVAR_FROM_FLOAT_VAR</code>
|0059||GF||GF||colspan=18|
+
|}
 +
{|class="wikitable mw-collapsible mw-collapsed" style="margin: -1px auto 0" width=100%
 
|-
 
|-
!ADD_INT_LVAR_TO_INT_LVAR
+
!colspan=2 style="background-color: inherit; text-align: left; font-weight: normal"|<code>MULT_THING_BY_THING</code> (<code>*=</code>)
|005A||LI||LI||colspan=18|
+
|width=64px align=center|Since {{icon|3}}
 
|-
 
|-
!ADD_FLOAT_LVAR_TO_FLOAT_LVAR
+
|rowspan=12 width=16px|
|005B||LF||LF||colspan=18|
+
|<code>MULT_INT_VAR_BY_VAL</code>||rowspan=12|
 
|-
 
|-
!ADD_INT_VAR_TO_INT_LVAR
+
|<code>MULT_FLOAT_VAR_BY_VAL</code>
|005C||LI||GI||colspan=18|
 
 
|-
 
|-
!ADD_FLOAT_VAR_TO_FLOAT_LVAR
+
|<code>MULT_INT_LVAR_BY_VAL</code>
|005D||LF||GF||colspan=18|
 
 
|-
 
|-
!ADD_INT_LVAR_TO_INT_VAR
+
|<code>MULT_FLOAT_LVAR_BY_VAL</code>
|005E||GI||LI||colspan=18|
 
 
|-
 
|-
!ADD_FLOAT_LVAR_TO_FLOAT_VAR
+
|<code>MULT_INT_VAR_BY_INT_VAR</code>
|005F||GF||LF||colspan=18|
 
 
|-
 
|-
!rowspan=8|-=!!SUB_INT_VAR_FROM_INT_VAR
+
|<code>MULT_FLOAT_VAR_BY_FLOAT_VAR</code>
|0060|
 
!rowspan=8|2
 
|GI||GI||colspan=18|
 
 
|-
 
|-
!SUB_FLOAT_VAR_FROM_FLOAT_VAR
+
|<code>MULT_INT_LVAR_BY_INT_LVAR</code>
|0061||GF||GF||colspan=18|
 
 
|-
 
|-
!SUB_INT_LVAR_FROM_INT_LVAR
+
|<code>MULT_FLOAT_LVAR_BY_FLOAT_LVAR</code>
|0062||LI||LI||colspan=18|
 
 
|-
 
|-
!SUB_FLOAT_LVAR_FROM_FLOAT_LVAR
+
|<code>MULT_INT_VAR_BY_INT_LVAR</code>
|0063||LF||LF||colspan=18|
 
 
|-
 
|-
!SUB_INT_VAR_FROM_INT_LVAR
+
|<code>MULT_FLOAT_VAR_BY_FLOAT_LVAR</code>
|0064||LI||GI||colspan=18|
 
 
|-
 
|-
!SUB_FLOAT_VAR_FROM_FLOAT_LVAR
+
|<code>MULT_INT_LVAR_BY_INT_VAR</code>
|0065||LF||GF||colspan=18|
 
 
|-
 
|-
!SUB_INT_LVAR_FROM_INT_VAR
+
|<code>MULT_FLOAT_LVAR_BY_FLOAT_VAR</code>
|0066||GI||LI||colspan=18|
+
|}
 +
{|class="wikitable mw-collapsible mw-collapsed" style="margin: -1px auto 0" width=100%
 
|-
 
|-
!SUB_FLOAT_LVAR_FROM_FLOAT_VAR
+
!colspan=2 style="background-color: inherit; text-align: left; font-weight: normal"|<code>DIV_THING_BY_THING</code> (<code>/=</code>)
|0067||GF||LF||colspan=18|
+
|width=64px align=center|Since {{icon|3}}
 
|-
 
|-
!rowspan=8|*=!!MULT_INT_VAR_BY_INT_VAR
+
|rowspan=12 width=16px|
|0068
+
|<code>DIV_INT_VAR_BY_VAL</code>||rowspan=12|
!rowspan=8|2
 
|GI||GI||colspan=18|
 
 
|-
 
|-
!MULT_FLOAT_VAR_BY_FLOAT_VAR
+
|<code>DIV_FLOAT_VAR_BY_VAL</code>
|0069||GF||GF||colspan=18|
 
 
|-
 
|-
!MULT_INT_LVAR_BY_INT_LVAR
+
|<code>DIV_INT_LVAR_BY_VAL</code>
|006A||LI||LI||colspan=18|
 
 
|-
 
|-
!MULT_FLOAT_LVAR_BY_FLOAT_LVAR
+
|<code>DIV_FLOAT_LVAR_BY_VAL</code>
|006B||LF||LF||colspan=18|
 
 
|-
 
|-
!MULT_INT_VAR_BY_INT_LVAR
+
|<code>DIV_INT_VAR_BY_INT_VAR</code>
|006C||GI||LI||colspan=18|
 
 
|-
 
|-
!MULT_FLOAT_VAR_BY_FLOAT_LVAR
+
|<code>DIV_FLOAT_VAR_BY_FLOAT_VAR</code>
|006D||GF||LF||colspan=18|
 
 
|-
 
|-
!MULT_INT_LVAR_BY_INT_VAR
+
|<code>DIV_INT_LVAR_BY_INT_LVAR</code>
|006E||LI||GI||colspan=18|
 
 
|-
 
|-
!MULT_FLOAT_LVAR_BY_FLOAT_VAR
+
|<code>DIV_FLOAT_LVAR_BY_FLOAT_LVAR</code>
|006F||LF||GF||colspan=18|
 
 
|-
 
|-
!rowspan=8|/=!!DIV_INT_VAR_BY_INT_VAR
+
|<code>DIV_INT_VAR_BY_INT_LVAR</code>
|0070
 
!rowspan=8|2
 
|GI||GI||colspan=18|
 
 
|-
 
|-
!DIV_FLOAT_VAR_BY_FLOAT_VAR
+
|<code>DIV_FLOAT_VAR_BY_FLOAT_LVAR</code>
|0071||GF||GF||colspan=18|
 
 
|-
 
|-
!DIV_INT_LVAR_BY_INT_LVAR
+
|<code>DIV_INT_LVAR_BY_INT_VAR</code>
|0072||LI||LI||colspan=18|
 
 
|-
 
|-
!DIV_FLOAT_LVAR_BY_FLOAT_LVAR
+
|<code>DIV_FLOAT_LVAR_BY_FLOAT_VAR</code>
|0073||LF||LF||colspan=18|
+
|}
 +
{|class="wikitable mw-collapsible mw-collapsed" style="margin: -1px auto 0" width=100%
 
|-
 
|-
!DIV_INT_VAR_BY_INT_LVAR
+
!colspan=2 style="background-color: inherit; text-align: left; font-weight: normal"|<code>IS_THING_EQUAL_TO_THING</code> (<code>=</code>)
|0074||GI||LI||colspan=18|
+
|width=64px align=center|Since {{icon|3}}
 
|-
 
|-
!DIV_FLOAT_VAR_BY_FLOAT_LVAR
+
|rowspan=18 width=16px|
|0075||GF||LF||colspan=18|
+
|<code>IS_INT_VAR_EQUAL_TO_NUMBER</code>||rowspan=5|
 
|-
 
|-
!DIV_INT_LVAR_BY_INT_VAR
+
|<code>IS_INT_LVAR_EQUAL_TO_NUMBER</code>
|0076||LI||GI||colspan=18|
 
 
|-
 
|-
!DIV_FLOAT_LVAR_BY_FLOAT_VAR
+
|<code>IS_INT_VAR_EQUAL_TO_INT_VAR</code>
|0077||LF||GF||colspan=18|
 
 
|-
 
|-
!rowspan=6|+=@!!ADD_TIMED_VAL_TO_FLOAT_VAR
+
|<code>IS_INT_LVAR_EQUAL_TO_INT_LVAR</code>
|0078
 
!rowspan=6|2
 
|GF||FV||colspan=18|
 
 
|-
 
|-
!ADD_TIMED_VAL_TO_FLOAT_LVAR
+
|<code>IS_INT_VAR_EQUAL_TO_INT_LVAR</code>
|0079||LF||FV||colspan=18|
 
 
|-
 
|-
!ADD_TIMED_FLOAT_VAR_TO_FLOAT_VAR
+
|<code>IS_INT_LVAR_EQUAL_TO_INT_VAR</code>||align=center|{{icon|sa}} only
|007A||GF||GF||colspan=18|
 
 
|-
 
|-
!ADD_TIMED_FLOAT_LVAR_TO_FLOAT_LVAR
+
|<code>IS_FLOAT_VAR_EQUAL_TO_NUMBER</code>||rowspan=5|
|007B||LF||LF||colspan=18|
 
 
|-
 
|-
!ADD_TIMED_FLOAT_LVAR_TO_FLOAT_VAR
+
|<code>IS_FLOAT_LVAR_EQUAL_TO_NUMBER</code>
|007C||LF||GF||colspan=18|
 
 
|-
 
|-
!ADD_TIMED_FLOAT_VAR_TO_FLOAT_LVAR
+
|<code>IS_FLOAT_VAR_EQUAL_TO_FLOAT_VAR</code>
|007D||GF||LF||colspan=18|
 
 
|-
 
|-
!rowspan=6|-=@!!SUB_TIMED_VAL_FROM_FLOAT_VAR
+
|<code>IS_FLOAT_LVAR_EQUAL_TO_FLOAT_LVAR</code>
|007E
 
!rowspan=6|2
 
|GF||FV||colspan=18|
 
 
|-
 
|-
!SUB_TIMED_VAL_FROM_FLOAT_LVAR
+
|<code>IS_FLOAT_VAR_EQUAL_TO_FLOAT_LVAR</code>
|007F||LF||FV||colspan=18|
 
 
|-
 
|-
!SUB_TIMED_FLOAT_VAR_FROM_FLOAT_VAR
+
|<code>IS_FLOAT_LVAR_EQUAL_TO_FLOAT_VAR</code>||align=center|{{icon|sa}} only
|0080||GF||GF||colspan=18|
 
 
|-
 
|-
!SUB_TIMED_FLOAT_LVAR_FROM_FLOAT_LVAR
+
|<code>IS_INT_VAR_EQUAL_TO_CONSTANT</code>||rowspan=2 align=center|Since {{icon|vc}}
|0081||LF||LF||colspan=18|
 
 
|-
 
|-
!SUB_TIMED_FLOAT_LVAR_FROM_FLOAT_VAR
+
|<code>IS_INT_LVAR_EQUAL_TO_CONSTANT</code>
|0082||LF||GF||colspan=18|
 
 
|-
 
|-
!SUB_TIMED_FLOAT_VAR_FROM_FLOAT_LVAR
+
|<code>IS_VAR_TEXT_LABEL_EQUAL_TO_TEXT_LABEL</code>||rowspan=4 align=center|{{icon|sa}} only
|0083||GF||LF||colspan=18|
 
 
|-
 
|-
!rowspan=8|=!!SET_VAR_INT_TO_VAR_INT
+
|<code>IS_LVAR_TEXT_LABEL_EQUAL_TO_TEXT_LABEL</code>
|0084|
 
!rowspan=8|2
 
|GI||GI||colspan=18|
 
 
|-
 
|-
!SET_LVAR_INT_TO_LVAR_INT
+
|<code>IS_VAR_TEXT_LABEL16_EQUAL_TO_TEXT_LABEL</code>
|0085||LI||LI||colspan=18|
 
 
|-
 
|-
!SET_VAR_FLOAT_TO_VAR_FLOAT
+
|<code>IS_LVAR_TEXT_LABEL16_EQUAL_TO_TEXT_LABEL</code>
|0086||GF||GF||colspan=18|
+
|}
 +
{|class="wikitable mw-collapsible mw-collapsed" style="margin: -1px auto 0" width=100%
 
|-
 
|-
!SET_LVAR_FLOAT_TO_LVAR_FLOAT
+
!colspan=2 style="background-color: inherit; text-align: left; font-weight: normal"|<code>IS_THING_NOT_EQUAL_TO_THING</code> (<code><></code>)
|0087||LF||LF||colspan=18|
+
|width=64px align=center|Since {{icon|3}}
 
|-
 
|-
!SET_VAR_FLOAT_TO_LVAR_FLOAT
+
|rowspan=12 width=16px|
|0088||GF||LF||colspan=18|
+
|<code>IS_INT_VAR_NOT_EQUAL_TO_NUMBER</code>||rowspan=5|
 
|-
 
|-
!SET_LVAR_FLOAT_TO_VAR_FLOAT
+
|<code>IS_INT_LVAR_NOT_EQUAL_TO_NUMBER</code>
|0089||LF||GF||colspan=18|
 
 
|-
 
|-
!SET_VAR_INT_TO_LVAR_INT
+
|<code>IS_INT_VAR_NOT_EQUAL_TO_INT_VAR</code>
|008A||GI||LI||colspan=18|
 
 
|-
 
|-
!SET_LVAR_INT_TO_VAR_INT
+
|<code>IS_INT_LVAR_NOT_EQUAL_TO_INT_LVAR</code>
|008B||LI||GI||colspan=18|
 
 
|-
 
|-
!rowspan=8|=#!!CSET_VAR_INT_TO_VAR_FLOAT
+
|<code>IS_INT_VAR_NOT_EQUAL_TO_INT_LVAR</code>
|008C|
 
!rowspan=8|2
 
|GI||GF||colspan=18|
 
 
|-
 
|-
!CSET_VAR_FLOAT_TO_VAR_INT
+
|<code>IS_INT_LVAR_NOT_EQUAL_TO_INT_VAR</code>||align=center|{{icon|sa}} only
|008D||GF||GI||colspan=18|
 
 
|-
 
|-
!CSET_LVAR_INT_TO_VAR_FLOAT
+
|<code>IS_FLOAT_VAR_NOT_EQUAL_TO_NUMBER</code>||rowspan=5|
|008E||LI||GF||colspan=18|
 
 
|-
 
|-
!CSET_LVAR_FLOAT_TO_VAR_INT
+
|<code>IS_FLOAT_LVAR_NOT_EQUAL_TO_NUMBER</code>
|008F||LF||GI||colspan=18|
 
 
|-
 
|-
!CSET_VAR_INT_TO_LVAR_FLOAT
+
|<code>IS_FLOAT_VAR_NOT_EQUAL_TO_FLOAT_VAR</code>
|0090||GI||LF||colspan=18|
 
 
|-
 
|-
!CSET_VAR_FLOAT_TO_LVAR_INT
+
|<code>IS_FLOAT_LVAR_NOT_EQUAL_TO_FLOAT_LVAR</code>
|0091||GF||LI||colspan=18|
 
 
|-
 
|-
!CSET_LVAR_INT_TO_LVAR_FLOAT
+
|<code>IS_FLOAT_VAR_NOT_EQUAL_TO_FLOAT_LVAR</code>
|0092||LI||LF||colspan=18|
 
 
|-
 
|-
!CSET_LVAR_FLOAT_TO_LVAR_INT
+
|<code>IS_FLOAT_LVAR_NOT_EQUAL_TO_FLOAT_VAR</code>||align=center|{{icon|sa}} only
|0093||LF||LI||colspan=18|
+
|}
 +
{|class="wikitable mw-collapsible mw-collapsed" style="margin: -1px auto 0" width=100%
 
|-
 
|-
!rowspan=4|ABS!!ABS_VAR_INT
+
!colspan=2 style="background-color: inherit; text-align: left; font-weight: normal"|<code>IS_THING_GREATER_THAN_THING</code> (<code>></code>, <code><=</code>)
|0094
+
|width=64px align=center|Since {{icon|3}}
!rowspan=4|1
 
|GI||colspan=19|
 
 
|-
 
|-
!ABS_LVAR_INT
+
|rowspan=20 width=16px|
|0095||LI||colspan=19|
+
|<code>IS_INT_VAR_GREATER_THAN_NUMBER</code>||rowspan=16|
 
|-
 
|-
!ABS_VAR_FLOAT
+
|<code>IS_INT_LVAR_GREATER_THAN_NUMBER</code>
|0096||GF||colspan=19|
 
 
|-
 
|-
!ABS_LVAR_FLOAT
+
|<code>IS_NUMBER_GREATER_THAN_INT_VAR</code>
|0097||LF||colspan=19|
 
 
|-
 
|-
!colspan=2|ANDOR{{ref|statem|[*]}}
+
|<code>IS_NUMBER_GREATER_THAN_INT_LVAR</code>
|00D6
 
!1
 
|VI||colspan=19|
 
 
|-
 
|-
!colspan=2|LAUNCH_MISSION
+
|<code>IS_INT_VAR_GREATER_THAN_INT_VAR</code>
|00D7
 
!1
 
|VO||colspan=19|
 
 
|-
 
|-
|colspan=25|{{icon|3}} {{icon|vc}} {{icon|sa}}
+
|<code>IS_INT_LVAR_GREATER_THAN_INT_LVAR</code>
 
|-
 
|-
!colspan=2|LOAD_AND_LAUNCH_MISSION
+
|<code>IS_INT_VAR_GREATER_THAN_INT_LVAR</code>
|0417
 
!1
 
|VO||colspan=19|
 
 
|-
 
|-
|colspan=25|{{icon|3}} {{icon|vc}}
+
|<code>IS_INT_LVAR_GREATER_THAN_INT_VAR</code>
 
|-
 
|-
!colspan=2|GOSUB_FILE
+
|<code>IS_FLOAT_VAR_GREATER_THAN_NUMBER</code>
|02CD
 
!2
 
|VO||VO||colspan=18|
 
 
|-
 
|-
|colspan=25|{{icon|vc}} {{icon|sa}}
+
|<code>IS_FLOAT_LVAR_GREATER_THAN_NUMBER</code>
 
|-
 
|-
!rowspan=4|=!!IS_INT_VAR_EQUAL_TO_CONSTANT
+
|<code>IS_NUMBER_GREATER_THAN_FLOAT_VAR</code>
|04A3
 
!rowspan=4|2
 
|GC||VC||colspan=18|
 
 
|-
 
|-
!IS_INT_LVAR_EQUAL_TO_CONSTANT
+
|<code>IS_NUMBER_GREATER_THAN_FLOAT_LVAR</code>
|04A4||LC||VC||colspan=18|
 
 
|-
 
|-
!SET_VAR_INT_TO_CONSTANT
+
|<code>IS_FLOAT_VAR_GREATER_THAN_FLOAT_VAR</code>
|04AE||GC||VC||colspan=18|
 
 
|-
 
|-
!SET_LVAR_INT_TO_CONSTANT
+
|<code>IS_FLOAT_LVAR_GREATER_THAN_FLOAT_LVAR</code>
|04AF||LC||VC||colspan=18|
 
 
|-
 
|-
!rowspan=4|>!!IS_INT_VAR_GREATER_THAN_CONSTANT
+
|<code>IS_FLOAT_VAR_GREATER_THAN_FLOAT_LVAR</code>
|04B0
 
!rowspan=4|2
 
|GC||VC||colspan=18|
 
 
|-
 
|-
!IS_INT_LVAR_GREATER_THAN_CONSTANT
+
|<code>IS_FLOAT_LVAR_GREATER_THAN_FLOAT_VAR</code>
|04B1||LC||VC||colspan=18|
 
 
|-
 
|-
!IS_CONSTANT_GREATER_THAN_INT_VAR
+
|<code>IS_INT_VAR_GREATER_THAN_CONSTANT</code>||rowspan=4 align=center|Since {{icon|vc}}
|04B2
 
|VC||GC||colspan=18|
 
 
|-
 
|-
!IS_CONSTANT_GREATER_THAN_INT_LVAR
+
|<code>IS_INT_LVAR_GREATER_THAN_CONSTANT</code>
|04B3||VC||LC||colspan=18|
 
 
|-
 
|-
!rowspan=4|>=!!IS_INT_VAR_GREATER_OR_EQUAL_TO_CONSTANT
+
|<code>IS_CONSTANT_GREATER_THAN_INT_VAR</code>
|04B4
 
!rowspan=4|2
 
|GC||VC||colspan=18|
 
 
|-
 
|-
!IS_INT_LVAR_GREATER_OR_EQUAL_TO_CONSTANT
+
|<code>IS_CONSTANT_GREATER_THAN_INT_LVAR</code>
|04B5||LC||VC||colspan=18|
+
|}
 +
{|class="wikitable mw-collapsible mw-collapsed" style="margin: -1px auto 0" width=100%
 
|-
 
|-
!IS_CONSTANT_GREATER_OR_EQUAL_TO_INT_VAR
+
!colspan=2 style="background-color: inherit; text-align: left; font-weight: normal"|<code>IS_THING_GREATER_OR_EQUAL_TO_THING</code> (<code>>=</code>, <code><</code>)
|04B6
+
|width=64px align=center|Since {{icon|3}}
|VC||GV||colspan=18|
 
 
|-
 
|-
!IS_CONSTANT_GREATER_OR_EQUAL_TO_INT_LVAR
+
|rowspan=20 width=16px|
|04B7||VC||LC||colspan=18|
+
|<code>IS_INT_VAR_GREATER_OR_EQUAL_TO_NUMBER</code>||rowspan=16|
 
|-
 
|-
|colspan=25|{{icon|sa}}
+
|<code>IS_INT_LVAR_GREATER_OR_EQUAL_TO_NUMBER</code>
 
|-
 
|-
!rowspan=20|=!!rowspan=3|SET_ANY_TEXT_LABEL_TO_VAR_TEXT_LABEL{{ref|likely|[*]}}
+
|<code>IS_NUMBER_GREATER_OR_EQUAL_TO_INT_VAR</code>
|rowspan=3|05A9
 
!rowspan=20|2
 
|GT||VT||colspan=18|
 
 
|-
 
|-
|GT||GT||colspan=18|
+
|<code>IS_NUMBER_GREATER_OR_EQUAL_TO_INT_LVAR</code>
 
|-
 
|-
|GT||LT||colspan=18|
+
|<code>IS_INT_VAR_GREATER_OR_EQUAL_TO_INT_VAR</code>
 
|-
 
|-
!rowspan=3|SET_ANY_TEXT_LABEL_TO_LVAR_TEXT_LABEL{{ref|likely|[*]}}
+
|<code>IS_INT_LVAR_GREATER_OR_EQUAL_TO_INT_LVAR</code>
|rowspan=3|05AA
 
|LT||VT||colspan=18|
 
 
|-
 
|-
|LT||GT||colspan=18|
+
|<code>IS_INT_VAR_GREATER_OR_EQUAL_TO_INT_LVAR</code>
 
|-
 
|-
|LT||LT||colspan=18|
+
|<code>IS_INT_LVAR_GREATER_OR_EQUAL_TO_INT_VAR</code>
 
|-
 
|-
!rowspan=3|IS_TEXT_LABEL_VAR_EQUAL_TO_TEXT_LABEL_ANY{{ref|likely|[*]}}
+
|<code>IS_FLOAT_VAR_GREATER_OR_EQUAL_TO_NUMBER</code>
|rowspan=3|05AD
 
|GT||VT||colspan=18|
 
 
|-
 
|-
|GT||GT||colspan=18|
+
|<code>IS_FLOAT_LVAR_GREATER_OR_EQUAL_TO_NUMBER</code>
 
|-
 
|-
|GT||LT||colspan=18|
+
|<code>IS_NUMBER_GREATER_OR_EQUAL_TO_FLOAT_VAR</code>
 
|-
 
|-
!rowspan=3|IS_TEXT_LABEL_LVAR_EQUAL_TO_TEXT_LABEL_ANY{{ref|likely|[*]}}
+
|<code>IS_NUMBER_GREATER_OR_EQUAL_TO_FLOAT_LVAR</code>
|rowspan=3|05AE
 
|LT||VT||colspan=18|
 
 
|-
 
|-
|LT||GT||colspan=18|
+
|<code>IS_FLOAT_VAR_GREATER_OR_EQUAL_TO_FLOAT_VAR</code>
 
|-
 
|-
|LT||LT||colspan=18|
+
|<code>IS_FLOAT_LVAR_GREATER_OR_EQUAL_TO_FLOAT_LVAR</code>
 
|-
 
|-
!rowspan=3|SET_ANY_STRING_TO_VAR_STRING{{ref|likely|[*]}}
+
|<code>IS_FLOAT_VAR_GREATER_OR_EQUAL_TO_FLOAT_LVAR</code>
|rowspan=3|06D1
 
|GS||VS||colspan=18|
 
 
|-
 
|-
|GS||GS||colspan=18|
+
|<code>IS_FLOAT_LVAR_GREATER_OR_EQUAL_TO_FLOAT_VAR</code>
 
|-
 
|-
|GS||LS||colspan=18|
+
|<code>IS_INT_VAR_GREATER_OR_EQUAL_TO_CONSTANT</code>||rowspan=4 align=center|Since {{icon|vc}}
 
|-
 
|-
!rowspan=3|SET_ANY_STRING_TO_LVAR_STRING{{ref|likely|[*]}}
+
|<code>IS_INT_LVAR_GREATER_OR_EQUAL_TO_CONSTANT</code>
|rowspan=3|06D2
 
|LS||VS||colspan=18|
 
 
|-
 
|-
|LS||GS||colspan=18|
+
|<code>IS_CONSTANT_GREATER_OR_EQUAL_TO_INT_VAR</code>
 
|-
 
|-
|LS||LS||colspan=18|
+
|<code>IS_CONSTANT_GREATER_OR_EQUAL_TO_INT_LVAR</code>
 +
|}
 +
{|class="wikitable mw-collapsible mw-collapsed" style="margin: -1px auto 0" width=100%
 
|-
 
|-
!IS_INT_LVAR_EQUAL_TO_INT_VAR
+
!colspan=2 style="background-color: inherit; text-align: left; font-weight: normal"|<code>ADD_THING_TO_THING_TIMED</code> (<code>+=@</code>)
|07D6||LI||GI||colspan=18|
+
|width=64px align=center|Since {{icon|3}}
 
|-
 
|-
!IS_FLOAT_LVAR_EQUAL_TO_FLOAT_VAR
+
|rowspan=6 width=16px|
|07D7||LF||GF||colspan=18|
+
|<code>ADD_TIMED_VAL_TO_FLOAT_VAR</code>||rowspan=6|
 
|-
 
|-
!rowspan=2|IS_TEXT_LABEL_NULL!!IS_TEXT_LABEL_NULL_VAR_TEXT_LABEL{{ref|likely|[*]}}
+
|<code>ADD_TIMED_VAL_TO_FLOAT_LVAR</code>
|0844
 
!rowspan=2|1
 
|GT||colspan=19|
 
 
|-
 
|-
!IS_TEXT_LABEL_NULL_LVAR_TEXT_LABEL{{ref|likely|[*]}}
+
|<code>ADD_TIMED_FLOAT_VAR_TO_FLOAT_VAR</code>
|0845||LT||colspan=19|
 
 
|-
 
|-
!rowspan=2|IS_STRING_NULL!!IS_STRING_NULL_VAR_STRING{{ref|likely|[*]}}
+
|<code>ADD_TIMED_FLOAT_LVAR_TO_FLOAT_LVAR</code>
|0846
 
!rowspan=2|1
 
|GS||colspan=19|
 
 
|-
 
|-
!IS_STRING_NULL_LVAR_STRING{{ref|likely|[*]}}
+
|<code>ADD_TIMED_FLOAT_LVAR_TO_FLOAT_VAR</code>
|0847||LS||colspan=19|
 
 
|-
 
|-
!rowspan=2 colspan=2|INIT_TABLE_OF_GOTO{{ref|statem|[*]}}{{ref|likely|[*]}}
+
|<code>ADD_TIMED_FLOAT_VAR_TO_FLOAT_LVAR</code>
|rowspan=2|0871
+
|}
!rowspan=2|18
+
{|class="wikitable mw-collapsible mw-collapsed" style="margin: -1px auto 0" width=100%
|GI||VI||VI||VO||VI||VO||VI||VO||VI||V0||VI||VO||VI||VO||VI||VO||VI||VO||colspan=2|
 
 
|-
 
|-
|LI||VI||VI||VO||VI||VO||VI||VO||VI||VO||VI||VO||VI||VO||VI||VO||VI||VO||colspan=2|
+
!colspan=2 style="background-color: inherit; text-align: left; font-weight: normal"|<code>SUB_THING_FROM_THING_TIMED</code> (<code>-=@</code>)
 +
|width=64px align=center|Since {{icon|3}}
 
|-
 
|-
!colspan=2|APPEND_GOTO_TO_TABLE{{ref|statem|[*]}}{{ref|likely|[*]}}
+
|rowspan=6 width=16px|
|0872
+
|<code>SUB_TIMED_VAL_FROM_FLOAT_VAR</code>||rowspan=6|
!18
 
|VI||VO||VI||VO||VI||VO||VI||VO||VI||VO||VI||VO||VI||VO||VI||VO||VI||VO||colspan=2|
 
 
|-
 
|-
!rowspan=6|IS_BIT_SET!!IS_BIT_SET_VAR_INT_NUMBER{{ref|likely|[*]}}
+
|<code>SUB_TIMED_VAL_FROM_FLOAT_LVAR</code>
|08B4
 
!rowspan=6|2
 
|GI||VN||colspan=18|
 
 
|-
 
|-
!IS_BIT_SET_VAR_INT_VAR_INT{{ref|likely|[*]}}
+
|<code>SUB_TIMED_FLOAT_VAR_FROM_FLOAT_VAR</code>
|08B5||GI||GI||colspan=18|
 
 
|-
 
|-
!IS_BIT_SET_VAR_INT_LVAR_INT{{ref|likely|[*]}}
+
|<code>SUB_TIMED_FLOAT_LVAR_FROM_FLOAT_LVAR</code>
|08B6||GI||LI||colspan=18|
 
 
|-
 
|-
!IS_BIT_SET_LVAR_INT_NUMBER{{ref|likely|[*]}}
+
|<code>SUB_TIMED_FLOAT_LVAR_FROM_FLOAT_VAR</code>
|08B7||LI||VN||colspan=18|
 
 
|-
 
|-
!IS_BIT_SET_LVAR_INT_VAR_INT{{ref|likely|[*]}}
+
|<code>SUB_TIMED_FLOAT_VAR_FROM_FLOAT_LVAR</code>
|08B8||LI||GI||colspan=18|
+
|}
 +
{|class="wikitable mw-collapsible mw-collapsed" style="margin: -1px auto 0" width=100%
 
|-
 
|-
!IS_BIT_SET_LVAR_INT_LVAR_INT{{ref|likely|[*]}}
+
!colspan=2 style="background-color: inherit; text-align: left; font-weight: normal"|<code>ABS</code>
|08B9||LI||LI||colspan=18|
+
|width=64px align=center|Since {{icon|3}}
 
|-
 
|-
!rowspan=6|SET_BIT_SET!!SET_BIT_VAR_INT_NUMBER{{ref|likely|[*]}}
+
|rowspan=4 width=16px|
|08BA
+
|<code>ABS_VAR_INT</code>||rowspan=4|
!rowspan=6|2
 
|GI||VN||colspan=18|
 
 
|-
 
|-
!SET_BIT_VAR_INT_VAR_INT{{ref|likely|[*]}}
+
|<code>ABS_LVAR_INT</code>
|08BB||GI||GI||colspan=18|
 
 
|-
 
|-
!SET_BIT_VAR_INT_LVAR_INT{{ref|likely|[*]}}
+
|<code>ABS_VAR_FLOAT</code>
|08BC||GI||LI||colspan=18|
 
 
|-
 
|-
!SET_BIT_LVAR_INT_NUMBER{{ref|likely|[*]}}
+
|<code>ABS_LVAR_FLOAT</code>
|08BD||LI||VN||colspan=18|
+
|}
 +
{|class="wikitable mw-collapsible mw-collapsed" style="margin: -1px auto 0" width=100%
 
|-
 
|-
!SET_BIT_LVAR_INT_VAR_INT{{ref|likely|[*]}}
+
!colspan=2 style="background-color: inherit; text-align: left; font-weight: normal"|<code>IS_EMPTY</code>
|08BE||LI||GI||colspan=18|
+
|width=64px align=center|{{icon|sa}} only
 
|-
 
|-
!SET_BIT_LVAR_INT_LVAR_INT{{ref|likely|[*]}}
+
|rowspan=4 width=16px|
|08BF||LI||LI||colspan=18|
+
|<code>IS_VAR_TEXT_LABEL_EMPTY</code>||rowspan=4|
 
|-
 
|-
!rowspan=6|CLEAR_BIT_SET!!CLEAR_BIT_VAR_INT_NUMBER{{ref|likely|[*]}}
+
|<code>IS_LVAR_TEXT_LABEL_EMPTY</code>
|08C0
 
!rowspan=6|2
 
|GI||VN||colspan=18|
 
 
|-
 
|-
!CLEAR_BIT_VAR_INT_VAR_INT{{ref|likely|[*]}}
+
|<code>IS_VAR_TEXT_LABEL16_EMPTY</code>
|08C1||GI||GI||colspan=18|
 
 
|-
 
|-
!CLEAR_BIT_VAR_INT_LVAR_INT{{ref|likely|[*]}}
+
|<code>IS_LVAR_TEXT_LABEL16_EMPTY</code>
|08C2||GI||LI||colspan=18|
+
|}
 +
{|class="wikitable mw-collapsible mw-collapsed" style="margin: -1px auto 0" width=100%
 
|-
 
|-
!CLEAR_BIT_LVAR_INT_NUMBER{{ref|likely|[*]}}
+
!colspan=2 style="background-color: inherit; text-align: left; font-weight: normal"|<code>IS_BIT_SET</code>
|08C3||LI||VN||colspan=18|
+
|width=64px align=center|{{icon|sa}} only
 
|-
 
|-
!CLEAR_BIT_LVAR_INT_VAR_INT{{ref|likely|[*]}}
+
|rowspan=6 width=16px|
|08C4||LI||GI||colspan=18|
+
|<code>IS_GLOBAL_VAR_BIT_SET_CONST</code>||rowspan=6|
 
|-
 
|-
!CLEAR_BIT_LVAR_INT_LVAR_INT{{ref|likely|[*]}}
+
|<code>IS_GLOBAL_VAR_BIT_SET_VAR</code>
|08C5||LI||LI||colspan=18|
 
 
|-
 
|-
!rowspan=6|=<br/>COMPARE_STRING{{ref|likely|[*]}}!!rowspan=3|IS_STRING_VAR_EQUAL_TO_STRING_ANY{{ref|likely|[*]}}<br/>COMPARE_STRING_VAR_STRING_ANY_STRING{{ref|likely|[*]}}
+
|<code>IS_GLOBAL_VAR_BIT_SET_LVAR</code>
|rowspan=3|08F9
 
!rowspan=6|2
 
|GS||VS||colspan=18|
 
 
|-
 
|-
|GS||GS||colspan=18|
+
|<code>IS_LOCAL_VAR_BIT_SET_CONST</code>
 
|-
 
|-
|GS||LS||colspan=18|
+
|<code>IS_LOCAL_VAR_BIT_SET_VAR</code>
 
|-
 
|-
!rowspan=3|IS_STRING_LVAR_EQUAL_TO_STRING_ANY{{ref|likely|[*]}}<br/>COMPARE_STRING_LVAR_STRING_ANY_STRING{{ref|likely|[*]}}
+
|<code>IS_LOCAL_VAR_BIT_SET_LVAR</code>
|rowspan=3|08FA
+
|}
|LS||VS||colspan=18|
+
{|class="wikitable mw-collapsible mw-collapsed" style="margin: -1px auto 0" width=100%
 
|-
 
|-
|LS||GS||colspan=18|
+
!colspan=2 style="background-color: inherit; text-align: left; font-weight: normal"|<code>SET_BIT</code>
 +
|width=64px align=center|{{icon|sa}} only
 
|-
 
|-
|LS||LS||colspan=18|
+
|rowspan=6 width=16px|
 +
|<code>SET_GLOBAL_VAR_BIT_CONST</code>||rowspan=6|
 
|-
 
|-
|colspan=25|{{icon|lcs}}
+
|<code>SET_GLOBAL_VAR_BIT_VAR</code>
 
|-
 
|-
!colspan=2|GOTO_IF_TRUE{{ref|statem|[*]}}
+
|<code>SET_GLOBAL_VAR_BIT_LVAR</code>
|004C
 
!1
 
|VI||colspan=19|
 
 
|-
 
|-
!colspan=2|RETURN_TRUE
+
|<code>SET_LOCAL_VAR_BIT_CONST</code>
|00C5
 
!0
 
|colspan=20|
 
 
|-
 
|-
!colspan=2|RETURN_FALSE
+
|<code>SET_LOCAL_VAR_BIT_VAR</code>
|00C6
 
!0
 
|colspan=20|
 
 
|-
 
|-
!colspan=2|ANDOR{{ref|statem|[*]}}
+
|<code>SET_LOCAL_VAR_BIT_LVAR</code>
|00DB
+
|}
!1
+
{|class="wikitable mw-collapsible mw-collapsed" style="margin: -1px auto 0" width=100%
|VI||colspan=19|
 
 
|-
 
|-
!colspan=2|LAUNCH_MISSION
+
!colspan=2 style="background-color: inherit; text-align: left; font-weight: normal"|<code>CLEAR_BIT</code>
|00DC
+
|width=64px align=center|{{icon|sa}} only
!1
 
|VO||colspan=19|
 
 
|-
 
|-
!colspan=2|GOSUB_FILE
+
|rowspan=6 width=16px|
|02D2
+
|<code>CLEAR_GLOBAL_VAR_BIT_CONST</code>||rowspan=6|
!2
 
|VO||VO||colspan=18|
 
 
|-
 
|-
!colspan=2|LOAD_AND_LAUNCH_MISSION
+
|<code>CLEAR_GLOBAL_VAR_BIT_VAR</code>
|041C
 
!1
 
|VO||colspan=19|
 
 
|-
 
|-
!rowspan=4|=!!IS_INT_VAR_EQUAL_TO_CONSTANT
+
|<code>CLEAR_GLOBAL_VAR_BIT_LVAR</code>
|04A8
 
!rowspan=4|2
 
|GC||VC||colspan=18|
 
 
|-
 
|-
!IS_INT_LVAR_EQUAL_TO_CONSTANT
+
|<code>CLEAR_LOCAL_VAR_BIT_CONST</code>
|04A9||LC||VC||colspan=18|
 
 
|-
 
|-
!SET_VAR_INT_TO_CONSTANT
+
|<code>CLEAR_LOCAL_VAR_BIT_VAR</code>
|04B3||GC||VC||colspan=18|
 
 
|-
 
|-
!SET_LVAR_INT_TO_CONSTANT
+
|<code>CLEAR_LOCAL_VAR_BIT_LVAR</code>
|04B4||LC||VC||colspan=18|
+
|}
 +
</div>
 +
|valign=top|<div style="overflow: auto; float: left" width=auto>
 +
{|class=wikitable style="margin-bottom: 0" width=100%
 
|-
 
|-
!rowspan=4|>!!IS_INT_VAR_GREATER_THAN_CONSTANT
+
!colspan=2 width=420px style="text-align: left"|Command
|04B5
 
!rowspan=4|2
 
|GC||VC||colspan=18|
 
 
|-
 
|-
!IS_INT_LVAR_GREATER_THAN_CONSTANT
+
!width=16px|
|04B6||LC||VC||colspan=18|
+
!style="text-align: left"|Alternative
 +
|}
 +
{|class="wikitable mw-collapsible mw-collapsed" style="margin: -1px auto 0" width=100%
 
|-
 
|-
!IS_CONSTANT_GREATER_THAN_INT_VAR
+
!colspan=2 style="background-color: inherit; text-align: left; font-weight: normal"|<code>SET</code> (<code>=</code>)
|04B7||VC||GC||colspan=18|
 
 
|-
 
|-
!IS_CONSTANT_GREATER_THAN_INT_LVAR
+
|rowspan=7 width=16px|
|04B8||VC||LC||colspan=18|
+
|<code>SET_VAR_INT</code>
 
|-
 
|-
!rowspan=4|>=!!IS_INT_VAR_GREATER_OR_EQUAL_TO_CONSTANT
+
|<code>SET_VAR_FLOAT</code>
|04B9
 
!rowspan=4|2
 
|GC||VC||colspan=18|
 
 
|-
 
|-
!IS_INT_LVAR_GREATER_OR_EQUAL_TO_CONSTANT
+
|<code>SET_VAR_TEXT_LABEL</code>
|04BA||LC||VC||colspan=18|
 
 
|-
 
|-
!IS_CONSTANT_GREATER_OR_EQUAL_TO_INT_VAR
+
|<code>SET_VAR_INT_TO_VAR_INT</code>
|04BB||VC||GV||colspan=18|
 
 
|-
 
|-
!IS_CONSTANT_GREATER_OR_EQUAL_TO_INT_LVAR
+
|<code>SET_VAR_FLOAT_TO_VAR_FLOAT</code>
|04BC||VC||LC||colspan=18|
 
 
|-
 
|-
!rowspan=2|CALL{{ref|undefa|[*]}}{{ref|argvar|[*]}}!!CALL_05AE
+
|<code>SET_VAR_TEXT_LABEL_TO_VAR_TEXT_LABEL</code>
|05AE
 
!rowspan=2|1
 
|rowspan=2|VO
 
|rowspan=2 colspan=19|_ _ _
 
 
|-
 
|-
!CALL_05AF
+
|<code>SET_VAR_INT_TO_CONSTANT</code>
|05AF
+
|}
 +
{|class="wikitable mw-collapsible mw-collapsed" style="margin: -1px auto 0" width=100%
 
|-
 
|-
|colspan=25|{{icon|vcs}}
+
!colspan=2 style="background-color: inherit; text-align: left; font-weight: normal"|<code>CSET</code> (<code>=#</code>)
 
|-
 
|-
!rowspan=6|=!!rowspan=2|SET_ANY_INT
+
|rowspan=2 width=16px|
|rowspan=2|0004
+
|<code>CSET_VAR_INT_TO_VAR_FLOAT</code>
!rowspan=6|2
 
|GI||VI||colspan=18|
 
 
|-
 
|-
|LI||VI||colspan=18|
+
|<code>CSET_VAR_FLOAT_TO_VAR_INT</code>
 +
|}
 +
{|class="wikitable mw-collapsible mw-collapsed" style="margin: -1px auto 0" width=100%
 
|-
 
|-
!rowspan=2|SET_ANY_FLOAT
+
!colspan=2 style="background-color: inherit; text-align: left; font-weight: normal"|<code>ADD_THING_TO_THING</code> (<code>+=</code>)
|rowspan=2|0005
 
|GF||VF||colspan=18|
 
 
|-
 
|-
|LF||VF||colspan=18|
+
|rowspan=4 width=16px|
 +
|<code>ADD_VAL_TO_INT_VAR</code>
 
|-
 
|-
!rowspan=2|SET_ANY_TEXT_LABEL
+
|<code>ADD_VAL_TO_FLOAT_VAR</code>
|rowspan=2|0006
 
|GT||VT||colspan=18|
 
 
|-
 
|-
|LT||VT||colspan=18|
+
|<code>ADD_INT_VAR_TO_INT_VAR</code>
 
|-
 
|-
!rowspan=4|+=!!rowspan=2|ADD_VAL_TO_INT_ANY
+
|<code>ADD_FLOAT_VAR_TO_FLOAT_VAR</code>
|rowspan=2|0007
+
|}
!rowspan=4|2
+
{|class="wikitable mw-collapsible mw-collapsed" style="margin: -1px auto 0" width=100%
|GI||VI||colspan=18|
 
 
|-
 
|-
|LI||VI||colspan=18|
+
!colspan=2 style="background-color: inherit; text-align: left; font-weight: normal"|<code>SUB_THING_FROM_THING</code> (<code>-=</code>)
 
|-
 
|-
!rowspan=2|ADD_VAL_TO_FLOAT_ANY
+
|rowspan=4 width=16px|
|rowspan=2|0008
+
|<code>SUB_VAL_FROM_INT_VAR</code>
|GF||VF||colspan=18|
 
 
|-
 
|-
|LF||VF||colspan=18|
+
|<code>SUB_VAL_FROM_FLOAT_VAR</code>
 
|-
 
|-
!rowspan=4|-=!!rowspan=2|SUB_VAL_FROM_INT_ANY
+
|<code>SUB_INT_VAR_FROM_INT_VAR</code>
|rowspan=2|0009
 
!rowspan=4|2
 
|GI||VI||colspan=18|
 
 
|-
 
|-
|LI||VI||colspan=18|
+
|<code>SUB_FLOAT_VAR_FROM_FLOAT_VAR</code>
 +
|}
 +
{|class="wikitable mw-collapsible mw-collapsed" style="margin: -1px auto 0" width=100%
 
|-
 
|-
!rowspan=2|SUB_VAL_FROM_FLOAT_ANY
+
!colspan=2 style="background-color: inherit; text-align: left; font-weight: normal"|<code>MULT_THING_BY_THING</code> (<code>*=</code>)
|rowspan=2|000A
 
|GF||VF||colspan=18|
 
 
|-
 
|-
|LF||VF||colspan=18|
+
|rowspan=4 width=16px|
 +
|<code>MULT_INT_VAR_BY_VAL</code>
 
|-
 
|-
!rowspan=4|*=!!rowspan=2|MULT_INT_ANY_BY_VAL
+
|<code>MULT_FLOAT_VAR_BY_VAL</code>
|rowspan=2|000B
 
!rowspan=4|2
 
|GI||VI||colspan=18|
 
 
|-
 
|-
|LI||VI||colspan=18|
+
|<code>MULT_INT_VAR_BY_INT_VAR</code>
 
|-
 
|-
!rowspan=2|MULT_FLOAT_ANY_BY_VAL
+
|<code>MULT_FLOAT_VAR_BY_FLOAT_VAR</code>
|rowspan=2|000C
+
|}
|GF||VF||colspan=18|
+
{|class="wikitable mw-collapsible mw-collapsed" style="margin: -1px auto 0" width=100%
 
|-
 
|-
|LF||VF||colspan=18|
+
!colspan=2 style="background-color: inherit; text-align: left; font-weight: normal"|<code>DIV_THING_BY_THING</code> (<code>/=</code>)
 
|-
 
|-
!rowspan=4|/=!!rowspan=2|DIV_INT_ANY_BY_VAL
+
|rowspan=4 width=16px|
|rowspan=2|000D
+
|<code>DIV_INT_VAR_BY_VAL</code>
!rowspan=4|2
 
|GI||VI||colspan=18|
 
 
|-
 
|-
|LI||VI||colspan=18|
+
|<code>DIV_FLOAT_VAR_BY_VAL</code>
 
|-
 
|-
!rowspan=2|DIV_FLOAT_ANY_BY_VAL
+
|<code>DIV_INT_VAR_BY_INT_VAR</code>
|rowspan=2|000E
 
|GF||VF||colspan=18|
 
 
|-
 
|-
|LF||VF||colspan=18|
+
|<code>DIV_FLOAT_VAR_BY_FLOAT_VAR</code>
 +
|}
 +
{|class="wikitable mw-collapsible mw-collapsed" style="margin: -1px auto 0" width=100%
 
|-
 
|-
!rowspan=16|>!!rowspan=2|IS_INT_ANY_GREATER_THAN_NUMBER
+
!colspan=2 style="background-color: inherit; text-align: left; font-weight: normal"|<code>IS_THING_EQUAL_TO_THING</code> (<code>=</code>)
|rowspan=2|000F
 
!rowspan=16|2
 
|GI||VN||colspan=18|
 
 
|-
 
|-
|LI||VN||colspan=18|
+
|rowspan=7 width=16px|
 +
|<code>IS_INT_VAR_EQUAL_TO_NUMBER</code>
 
|-
 
|-
!rowspan=2|IS_NUMBER_GREATER_THAN_INT_ANY
+
|<code>IS_INT_VAR_EQUAL_TO_INT_VAR</code>
|rowspan=2|0010
 
|VN||GI||colspan=18|
 
 
|-
 
|-
|VN||LI||colspan=18|
+
|<code>IS_FLOAT_VAR_EQUAL_TO_NUMBER</code>
 
|-
 
|-
!rowspan=4|IS_INT_ANY_GREATER_THAN_INT_ANY
+
|<code>IS_FLOAT_VAR_EQUAL_TO_FLOAT_VAR</code>
|rowspan=4|0011
 
|GI||GI||colspan=18|
 
 
|-
 
|-
|GI||LI||colspan=18|
+
|<code>IS_TEXT_LABEL_VAR_EQUAL_TO_TEXT_LABEL</code>
 
|-
 
|-
|LI||GI||colspan=18|
+
|<code>IS_TEXT_LABEL_VAR_EQUAL_TO_TEXT_LABEL_VAR</code>
 
|-
 
|-
|LI||LI||colspan=18|
+
|<code>IS_INT_VAR_EQUAL_TO_CONSTANT</code>
 +
|}
 +
{|class="wikitable mw-collapsible mw-collapsed" style="margin: -1px auto 0" width=100%
 
|-
 
|-
!rowspan=2|IS_FLOAT_ANY_GREATER_THAN_NUMBER
+
!colspan=2 style="background-color: inherit; text-align: left; font-weight: normal"|<code>IS_THING_GREATER_THAN_THING</code> (<code>></code>, <code><=</code>)
|rowspan=2|0012
 
|GF||VN||colspan=18|
 
 
|-
 
|-
|LF||VN||colspan=18|
+
|rowspan=8 width=16px|
 +
|<code>IS_INT_VAR_GREATER_THAN_NUMBER</code>
 
|-
 
|-
!rowspan=2|IS_NUMBER_GREATER_THAN_FLOAT_ANY
+
|<code>IS_NUMBER_GREATER_THAN_INT_VAR</code>
|rowspan=2|0013
 
|VN||GF||colspan=18|
 
 
|-
 
|-
|VN||LF||colspan=18|
+
|<code>IS_INT_VAR_GREATER_THAN_INT_VAR</code>
 
|-
 
|-
!rowspan=4|IS_FLOAT_ANY_GREATER_THAN_FLOAT_ANY
+
|<code>IS_FLOAT_VAR_GREATER_THAN_NUMBER</code>
|rowspan=4|0014
 
|GF||GF||colspan=18|
 
 
|-
 
|-
|GF||LF||colspan=18|
+
|<code>IS_NUMBER_GREATER_THAN_FLOAT_VAR</code>
 
|-
 
|-
|LF||GF||colspan=18|
+
|<code>IS_FLOAT_VAR_GREATER_THAN_FLOAT_VAR</code>
 
|-
 
|-
|LF||LF||colspan=18|
+
|<code>IS_INT_VAR_GREATER_THAN_CONSTANT</code>
 
|-
 
|-
!rowspan=16|>=!!rowspan=2|IS_INT_ANY_GREATER_OR_EQUAL_TO_NUMBER
+
|<code>IS_CONSTANT_GREATER_THAN_INT_VAR</code>
|rowspan=2|0015
+
|}
!rowspan=16|2
+
{|class="wikitable mw-collapsible mw-collapsed" style="margin: -1px auto 0" width=100%
|GI||VN||colspan=18|
 
 
|-
 
|-
|LI||VN||colspan=18|
+
!colspan=2 style="background-color: inherit; text-align: left; font-weight: normal"|<code>IS_THING_GREATER_OR_EQUAL_TO_THING</code> (<code>>=</code>, <code><</code>)
 
|-
 
|-
!rowspan=2|IS_NUMBER_GREATER_OR_EQUAL_TO_INT_ANY
+
|rowspan=8 width=16px|
|rowspan=2|0016
+
|<code>IS_INT_VAR_GREATER_OR_EQUAL_TO_NUMBER</code>
|VN||GI||colspan=18|
 
 
|-
 
|-
|VN||LI||colspan=18|
+
|<code>IS_NUMBER_GREATER_OR_EQUAL_TO_INT_VAR</code>
 
|-
 
|-
!rowspan=4|IS_INT_ANY_GREATER_OR_EQUAL_TO_INT_ANY
+
|<code>IS_INT_VAR_GREATER_OR_EQUAL_TO_INT_VAR</code>
|rowspan=4|0017
 
|GI||GI||colspan=18|
 
 
|-
 
|-
|GI||LI||colspan=18|
+
|<code>IS_FLOAT_VAR_GREATER_OR_EQUAL_TO_NUMBER</code>
 
|-
 
|-
|LI||GI||colspan=18|
+
|<code>IS_NUMBER_GREATER_OR_EQUAL_TO_FLOAT_VAR</code>
 
|-
 
|-
|LI||LI||colspan=18|
+
|<code>IS_FLOAT_VAR_GREATER_OR_EQUAL_TO_FLOAT_VAR</code>
 
|-
 
|-
!rowspan=2|IS_FLOAT_ANY_GREATER_OR_EQUAL_TO_NUMBER
+
|<code>IS_INT_VAR_GREATER_OR_EQUAL_TO_CONSTANT</code>
|rowspan=2|0018
 
|GF||VN||colspan=18|
 
 
|-
 
|-
|LF||VN||colspan=18|
+
|<code>IS_CONSTANT_GREATER_OR_EQUAL_TO_INT_VAR</code>
 +
|}
 +
{|class="wikitable mw-collapsible mw-collapsed" style="margin: -1px auto 0" width=100%
 
|-
 
|-
!rowspan=2|IS_NUMBER_GREATER_OR_EQUAL_TO_FLOAT_ANY
+
!colspan=2 style="background-color: inherit; text-align: left; font-weight: normal"|<code>ADD_THING_TO_THING_TIMED</code> (<code>+=@</code>)
|rowspan=2|0019
 
|VN||GF||colspan=18|
 
 
|-
 
|-
|VN||LF||colspan=18|
+
|rowspan=2 width=16px|
 +
|<code>ADD_TIMED_VAL_TO_FLOAT_VAR</code>
 
|-
 
|-
!rowspan=4|IS_FLOAT_ANY_GREATER_OR_EQUAL_TO_FLOAT_ANY
+
|<code>ADD_TIMED_FLOAT_VAR_TO_FLOAT_VAR</code>
|rowspan=4|001A
+
|}
|GF||GF||colspan=18|
+
{|class="wikitable mw-collapsible mw-collapsed" style="margin: -1px auto 0" width=100%
 
|-
 
|-
|GF||LF||colspan=18|
+
!colspan=2 style="background-color: inherit; text-align: left; font-weight: normal"|<code>SUB_THING_FROM_THING_TIMED</code> (<code>-=@</code>)
 
|-
 
|-
|LF||GF||colspan=18|
+
|rowspan=2 width=16px|
 +
|<code>SUB_TIMED_VAL_FROM_FLOAT_VAR</code>
 
|-
 
|-
|LF||LF||colspan=18|
+
|<code>SUB_TIMED_FLOAT_VAR_FROM_FLOAT_VAR</code>
 +
|}
 +
{|class="wikitable mw-collapsible mw-collapsed" style="margin: -1px auto 0" width=100%
 
|-
 
|-
!rowspan=12|=!!rowspan=2|IS_INT_ANY_EQUAL_TO_NUMBER
+
!colspan=2 style="background-color: inherit; text-align: left; font-weight: normal"|<code>ABS</code>
|rowspan=2|001B
 
!rowspan=12|2
 
|GI||VN||colspan=18|
 
 
|-
 
|-
|LI||VN||colspan=18|
+
|rowspan=2 width=16px|
 +
|<code>ABS_VAR_INT</code>
 
|-
 
|-
!rowspan=4|IS_INT_ANY_EQUAL_TO_INT_ANY
+
|<code>ABS_VAR_FLOAT</code>
|rowspan=4|001C
+
|}
|GI||GI||colspan=18|
+
</div>
|-
 
|GI||LI||colspan=18|
 
|-
 
|LI||GI||colspan=18|
 
|-
 
|LI||LI||colspan=18|
 
|-
 
!rowspan=2|IS_FLOAT_ANY_EQUAL_TO_NUMBER
 
|rowspan=2|001D
 
|GF||VN||colspan=18|
 
|-
 
|LF||VN||colspan=18|
 
|-
 
!rowspan=4|IS_FLOAT_ANY_EQUAL_TO_FLOAT_ANY
 
|rowspan=4|001E
 
|GF||GF||colspan=18|
 
|-
 
|GF||LF||colspan=18|
 
|-
 
|LF||GF||colspan=18|
 
|-
 
|LF||LF||colspan=18|
 
|-
 
!rowspan=6|=!!rowspan=2|IS_TEXT_LABEL_ANY_EQUAL_TO_TEXT_LABEL
 
|rowspan=2|001F
 
!rowspan=6|2
 
|GT||VT||colspan=18|
 
|-
 
|LT||VT||colspan=18|
 
|-
 
!rowspan=4|IS_ANY_TEXT_LABEL_EQUAL_TO_TEXT_LABEL_ANY
 
|rowspan=4|0020
 
|GT||GT||colspan=18|
 
|-
 
|GT||LT||colspan=18|
 
|-
 
|LT||GT||colspan=18|
 
|-
 
|LT||LT||colspan=18|
 
|-
 
!colspan=2|GOTO_IF_TRUE{{ref|statem|[*]}}
 
|0021
 
!1
 
|VO||colspan=19|
 
|-
 
!colspan=2|GOTO_IF_FALSE{{ref|statem|[*]}}
 
|0022
 
!1
 
|VO||colspan=19|
 
|-
 
!colspan=2|TERMINATE_THIS_SCRIPT
 
|rowspan=2|0023
 
!rowspan=2|0
 
|rowspan=2 colspan=20|
 
|-
 
!colspan=2|MISSION_END
 
|-
 
!colspan=2|START_NEW_SCRIPT{{ref|undefa|[*]}}
 
|0024
 
!1
 
|VO||colspan=20|_ _ _
 
|-
 
!colspan=2|GOSUB
 
|0025
 
!1
 
|VO||colspan=20|
 
|-
 
!colspan=2|RETURN
 
|0026
 
!0
 
|colspan=20|
 
|-
 
!rowspan=8|+=!!rowspan=4|ADD_INT_ANY_TO_INT_ANY
 
|rowspan=4|0029
 
!rowspan=8|2
 
|GI||GI||colspan=18|
 
|-
 
|GI||LI||colspan=18|
 
|-
 
|LI||GI||colspan=18|
 
|-
 
|LI||LI||colspan=18|
 
|-
 
!rowspan=4|ADD_FLOAT_ANY_FLOAT_ANY
 
|rowspan=4|002A
 
|GF||GF||colspan=18|
 
|-
 
|GF||LF||colspan=18|
 
|-
 
|LF||GF||colspan=18|
 
|-
 
|LF||LF||colspan=18|
 
|-
 
!rowspan=8|-=!!rowspan=4|SUB_INT_ANY_FROM_INT_ANY
 
|rowspan=4|002B
 
!rowspan=8|2
 
|GI||GI||colspan=18|
 
|-
 
|GI||LI||colspan=18|
 
|-
 
|LI||GI||colspan=18|
 
|-
 
|LI||LI||colspan=18|
 
|-
 
!rowspan=4|SUB_FLOAT_ANY_FROM_FLOAT_ANY
 
|rowspan=4|002C
 
|GF||GF||colspan=18|
 
|-
 
|GF||LF||colspan=18|
 
|-
 
|LF||GF||colspan=18|
 
|-
 
|LF||LF||colspan=18|
 
|-
 
!rowspan=8|*=!!rowspan=4|MULT_INT_ANY_BY_INT_ANY
 
|rowspan=4|002D
 
!rowspan=8|2
 
|GI||GI||colspan=18|
 
|-
 
|GI||LI||colspan=18|
 
|-
 
|LI||GI||colspan=18|
 
|-
 
|LI||LI||colspan=18|
 
|-
 
!rowspan=4|MULT_FLOAT_ANY_BY_FLOAT_ANY
 
|rowspan=4|002E
 
|GF||GF||colspan=18|
 
|-
 
|GF||LF||colspan=18|
 
|-
 
|LF||GF||colspan=18|
 
|-
 
|LF||LF||colspan=18|
 
|-
 
!rowspan=8|/=!!rowspan=4|DIV_INT_ANY_BY_INT_ANY
 
|rowspan=4|002F
 
!rowspan=8|2
 
|GI||GI||colspan=18|
 
|-
 
|GI||LI||colspan=18|
 
|-
 
|LI||GI||colspan=18|
 
|-
 
|LI||LI||colspan=18|
 
|-
 
!rowspan=4|DIV_FLOAT_ANY_BY_FLOAT_ANY
 
|rowspan=4|0030
 
|GF||GF||colspan=18|
 
|-
 
|GF||LF||colspan=18|
 
|-
 
|LF||GF||colspan=18|
 
|-
 
|LF||LF||colspan=18|
 
|-
 
!rowspan=6|+=@!!rowspan=2|ADD_TIMED_VAL_TO_FLOAT_ANY
 
|rowspan=2|0031
 
!rowspan=6|2
 
|GF||VF||colspan=18|
 
|-
 
|LF||VF||colspan=18|
 
|-
 
!rowspan=4|ADD_TIMED_FLOAT_ANY_TO_FLOAT_ANY
 
|rowspan=4|0032
 
|GF||GF||colspan=18|
 
|-
 
|GF||LF||colspan=18|
 
|-
 
|LF||GF||colspan=18|
 
|-
 
|LF||LF||colspan=18|
 
|-
 
!rowspan=6|-=@!!rowspan=2|SUB_TIMED_VAL_FROM_FLOAT_ANY
 
|rowspan=2|0033
 
!rowspan=6|2
 
|GF||VF||colspan=18|
 
|-
 
|LF||VF||colspan=18|
 
|-
 
!rowspan=4|SUB_TIMED_FLOAT_ANY_FROM_FLOAT_ANY
 
|rowspan=4|0034
 
|GF||GF||colspan=18|
 
|-
 
|GF||LF||colspan=18|
 
|-
 
|LF||GF||colspan=18|
 
|-
 
|LF||LF||colspan=18|
 
|-
 
!rowspan=12|=!!rowspan=4|SET_ANY_INT_TO_ANY_INT
 
|rowspan=4|0035
 
!rowspan=12|2
 
|GI||GI||colspan=18|
 
|-
 
|GI||LI||colspan=18|
 
|-
 
|LI||GI||colspan=18|
 
|-
 
|LI||LI||colspan=18|
 
|-
 
!rowspan=4|SET_ANY_FLOAT_TO_ANY_FLOAT
 
|rowspan=4|0036
 
|GF||GF||colspan=18|
 
|-
 
|GF||LF||colspan=18|
 
|-
 
|LF||GF||colspan=18|
 
|-
 
|LF||LF||colspan=18|
 
|-
 
!rowspan=4|SET_ANY_TEXT_LABEL_TO_ANY_TEXT_LABEL
 
|rowspan=4|0037
 
|GT||GT||colspan=18|
 
|-
 
|GT||LT||colspan=18|
 
|-
 
|LT||GT||colspan=18|
 
|-
 
|LT||LT||colspan=18|
 
|-
 
!rowspan=8|=#!!rowspan=4|CSET_ANY_INT_TO_ANY_FLOAT
 
|rowspan=4|0038
 
!rowspan=8|2
 
|GI||GF||colspan=18|
 
|-
 
|GI||LF||colspan=18|
 
|-
 
|LI||GF||colspan=18|
 
|-
 
|LI||LF||colspan=18|
 
|-
 
!rowspan=4|CSET_ANY_FLOAT_TO_ANY_INT
 
|rowspan=4|0039
 
|GF||GI||colspan=18|
 
|-
 
|GF||LI||colspan=18|
 
|-
 
|LF||GI||colspan=18|
 
|-
 
|LF||LI||colspan=18|
 
|-
 
!rowspan=4|ABS!!rowspan=2|ABS_ANY_INT
 
|rowspan=2|003A
 
!rowspan=4|1
 
|GI||colspan=19|
 
|-
 
|LI||colspan=19|
 
|-
 
!rowspan=2|ABS_ANY_FLOAT
 
|rowspan=2|003B
 
|GF||colspan=19|
 
|-
 
|LF||colspan=19|
 
|-
 
!colspan=2|RETURN_TRUE
 
|005E
 
!0
 
|colspan=20|
 
|-
 
!colspan=2|RETURN_FALSE
 
|005F
 
!0
 
|colspan=20|
 
|-
 
!colspan=2|ANDOR{{ref|statem|[*]}}
 
|0078
 
!1
 
|VI||colspan=19|
 
|-
 
!colspan=2|LAUNCH_MISSION
 
|0079
 
!1
 
|VI||colspan=19|
 
|-
 
!colspan=2|GOSUB_FILE
 
|01BA
 
!2
 
|VO||VO||colspan=18|
 
|-
 
!colspan=2|LOAD_AND_LAUNCH_MISSION
 
|0289
 
!1
 
|IV||colspan=19|
 
|-
 
!rowspan=4|=!!rowspan=2|IS_INT_ANY_EQUAL_TO_CONSTANT
 
|rowspan=2|02DB
 
!rowspan=4|2
 
|GC||VC||colspan=18|
 
|-
 
|LC||VC||colspan=18|
 
|-
 
!rowspan=2|SET_ANY_INT_TO_CONSTANT
 
|rowspan=2|02E2
 
|GC||VC||colspan=18|
 
|-
 
|LC||VC||colspan=18|
 
|-
 
!rowspan=4|>!!rowspan=2|IS_INT_ANY_GREATER_THAN_CONSTANT
 
|rowspan=2|02E3
 
!rowspan=4|2
 
|GC||VC||colspan=18|
 
|-
 
|LC||VC||colspan=18|
 
|-
 
!rowspan=2|IS_CONSTANT_GREATER_THAN_INT_ANY
 
|rowspan=2|02E4
 
|VC||GC||colspan=18|
 
|-
 
|VC||LC||colspan=18|
 
|-
 
!rowspan=4|>=!!rowspan=2|IS_INT_ANY_GREATER_OR_EQUAL_TO_CONSTANT
 
|rowspan=2|02E5
 
!rowspan=4|2
 
|GC||VC||colspan=18|
 
|-
 
|LC||VC||colspan=18|
 
|-
 
!rowspan=2|IS_CONSTANT_GREATER_OR_EQUAL_TO_INT_ANY
 
|rowspan=2|02E6
 
|VC||GV||colspan=18|
 
|-
 
|VC||LC||colspan=18|
 
|-
 
!rowspan=2|CALL{{ref|undefa|[*]}}{{ref|argvar|[*]}}!!CALL_037A
 
|037A
 
!rowspan=2|1
 
|rowspan=2|VO
 
|rowspan=2 colspan=19|_ _ _
 
|-
 
!CALL_037B
 
|037B
 
 
|}
 
|}
  
;Notes
+
==Control flows==
:{{note|misdef}} A special [[#Mission scripts|mission]] directive which is never compiled.
+
Insofar as subprograms, scripts are organized in a systematic arrangement through which goto branches, subroutine branches, function calls and returns or cutscene area markers are executed to form control flow statements and structures. These alter the [[Wikipedia:Program Counter|program counter]] most of the time affecting the top-down order all commands are fetched by. Facing off code duplication is quite recurring especially when the tasks to perform vary only in the input data, the case where a piece of code or subroutine, built once in the source, is invoked many times from various different places and returns back, as if the <code>GOSUB</code> statement is substituted in-place by the subroutine's body without <code>RETURN</code> during the control transferring, to shrink long codes and reduce the script overall size. In the last Trilogy chapter, a region of code can be marked as a nonnestable cutscene area wherein the rest of commands within <code>SKIP_CUTSCENE_START..SKIP_CUTSCENE_END</code> is skipped to the pressure of some key/button at the next script tick. The flow of execution can also be broken up conditionally by means of:
:{{note|statem}} It is used also to build [[#Statements|statements]] internally.
+
 
:{{note|undefa}} It has an undefined amount of [[#Arguments|arguments]].
+
* ''Decision-making structures'' (<code>IF</code>, <code>IFNOT</code>, <code>SWITCH</code>), which evaluate the result of one or more conditions and choose what path to follow based off the trueness or falseness of the check being tested. Been deemed the most basic tool of [[Wikipedia:Structured programming|structured programming]], <code>IF</code> is a bidirectional statement that proceeds with the execution of the underneath code only if the test carried out evaluates to true otherwise it transfers the control next to <code>ENDIF</code> instantly, unless a preceding and optional <code>ELSE</code> clause, establishing an alternative path, is specified. In the first Trilogy and both Stories chapters where <code>GOTO_IF_TRUE</code> is handled by game code, the barely used <code>IFNOT</code> can be deployed as a placeholder to easily invert the compare-flag, a boolean state which is set or cleared as a result of the bitwise [[Wikipedia:Bitwise operation#AND|conjunction]] or [[Wikipedia:Bitwise operation#OR|disjunction]] with the true/false state caught by a condition, applying the inversion according to the presence of the not-flag before accumulating. Logical operators make possible the connection among multiple conditions via the <code>AND</code> [[Wikipedia:Logical conjunction|conjunction]] and <code>OR</code> [[Wikipedia:Logical disjunction|disjunction]] giving the chance to verify if conditions are all true or if just one of them is satisfied bearing in mind that the <code>NOT</code> [[Wikipedia:Logical negation|negation]], inverting the boolean state of a single condition, may be supplied. Connectivity information are held by <code>ANDOR</code>, whose argument depicts a value in the range <code>[1,8)</code> or <code>[21,28)</code> (end-inclusive in Stories) for logical conjunction and disjunction respectively, limiting the amount of total conditions to provide to a maximum of 8 per check (the prominent intervals discrepancy also suggests <code>NAND</code> and <code>NOR</code> operators might have been a plan at some point). A value of 0 does nothing relevant functional-wise at runtime, what led developers to not compile said command in such a situation for Stories chapters and also make the argument one-based so that it effectively counts the number of commands used in a multi-condition check. The inability to create subexpressions enforces not to combine <code>AND</code> with <code>OR</code> in a check, plus evaluations are eager and therefore not short-circuited meaning all conditions are executed prior potentially branching through <code>GOTO_IF_FALSE</code> in the common case after the compare-flag gets processed. <code>IF-GOTO</code> and <code>IFNOT-GOTO</code> constructs are also viable to inline a bogus one-way control transferer, targeting an arbitrary location, nearby a one-condition check with no end-ing statement.
:{{note|likely}} It is a likely definition of the standard command.
+
:Nesting lots of <code>IF-ELSE-ENDIF</code> structures of one-condition checks testing the equality of the same variable against a few integer literals or string constants can add a ridiculous code redundancy and performance overhead, sorted out in the last Trilogy chapter thanks to the introduction of the <code>SWITCH</code> statement, a multiway statement either branching to the switch section labelled by fall-through <code>CASE</code> statements of which one passses a value that shall match the variable content to compare or optionally branching to <code>DEFAULT</code> in the worst-case scenario, each ending with a nonmandatory <code>BREAK</code> statement goto-ing past <code>ENDSWITCH</code>. On compilation, the implementation somehow mimics the pattern of a [[Wikipedia:Jump table|jump table]] sorting case label references by value to fulfil the runtime's [[Wikipedia:Binary search|binary search]] among at least 1 of 75 entries (default case aside);
:{{note|argvar}} Arguments amount varies when compiling.
+
* ''Looping structures'' (<code>WHILE</code>, <code>WHILENOT</code>, <code>REPEAT</code>), which repeatedly execute a block of code certain number of times or by constantly and successfully evaluating a check. The only condition-controlled loop statement featured is the widespread <code>WHILE</code>, a cyclical <code>IF</code> statement as well as <code>IFNOT</code> is for <code>WHILENOT</code>, repeating the embedded code over and over again if the verified check is true or till it becomes false when reaching <code>ENDWHILE</code>. Alongside well-known constructs the language supports a singular count-controlled structure, <code>REPEAT-ENDREPEAT</code>, looping some code at least once by advancing an integer variable at each iteration until the times specified (literal-only). Despite [[Wikipedia:Considered harmful|considered harmful]] in the programming literature for [[Wikipedia:High-level programming language|high-level programming languages]], an unconditional branch is the only way to go for breaking loops beforehand and enhance paradoxically the simplistic code logic or for creating infinite loops with a backward <code>GOTO</code>.
 +
 
 +
Control flows intersection is, arguably, trouble-free and it's up to the writer to not ruin the code integrity, but still substatements must match the closest opening statement they belong to. Optimization is not of compiler concern meaning control flows are encapsulated as-is with no code reduction even for empty blocks, resulting in goto-es branching right after or piled up in sequence.
  
{{incomplete}}
+
<span style="display: block; margin: 1em 0; font-size: 1.17em; font-weight: bold; color: black" id="GOSUB">Subroutine structure: GOSUB</span>
  
===Uncommon===
+
GOSUB subroutine
 +
COMMAND
 +
GOTO somewhere
 +
 +
subroutine:
 +
COMMAND
 +
RETURN
  
[[#Arguments|Arguments]] of some commands keep uncommon [[#Value|values]] which look familiar after encoding:
+
<span style="display: block; margin: 1em 0; font-size: 1.17em; font-weight: bold; color: black" id="SKIP_CUTSCENE_START_and_SKIP_CUTSCENE_END">Cutscene area structure: SKIP_CUTSCENE_START and SKIP_CUTSCENE_END</span>
  
{|class=wikitable style=text-align:center
+
{|style="table-layout: fixed" width=100% cellspacing=0 cellpadding=0
!rowspan=2|Command
+
|width=50%|'''Mission script'''
!rowspan=2|Arg ID
+
|width=16px rowspan=2|
!rowspan=2|Syntax
+
|width=50%|'''Script multifile'''
!colspan=2|Encoded
 
 
|-
 
|-
!Value
+
|style="vertical-align: top"|
!Type
+
<pre style="white-space: pre; overflow-x: scroll">
 +
// Formerly thought as MARK_CUTSCENE_START.
 +
SKIP_CUTSCENE_START
 +
    COMMAND
 +
    WAIT 0
 +
    COMMAND
 +
// Formerly thought as MARK_CUTSCENE_END.
 +
SKIP_CUTSCENE_END
 +
</pre>
 +
|style="vertical-align: top"|
 +
<pre style="white-space: pre; overflow-x: scroll">
 +
// Formerly thought as CUTSCENE_SCROLL?
 +
SKIP_CUTSCENE_START_INTERNAL SPECIAL_LABEL_SKIP_CUTSCENE_STARTS_0
 +
    COMMAND
 +
    WAIT 0
 +
    COMMAND
 +
SPECIAL_LABEL_SKIP_CUTSCENE_STARTS_0:
 +
SKIP_CUTSCENE_END
 +
</pre>
 +
|}
 +
 
 +
<span style="display: block; margin: 1em 0; font-size: 1.17em; font-weight: bold; color: black" id="IF_and_IFNOT">Decision-making structures: IF and IFNOT</span>
 +
 
 +
{|style="table-layout: fixed" width=100% cellspacing=0 cellpadding=0
 +
|width=50%|'''Mission script'''
 +
|width=16px rowspan=2|
 +
|width=50%|'''Script multifile'''
 
|-
 
|-
|colspan=5|{{icon|3}} {{icon|vc}} {{icon|sa}} {{icon|lcs}} {{icon|vcs}}
+
|style="vertical-align: top"|
 +
<pre style="white-space: pre; overflow-x: scroll">
 +
IF COMMAND
 +
    COMMAND
 +
ELSE
 +
    COMMAND
 +
ENDIF
 +
</pre>
 +
|style="vertical-align: top"|
 +
<pre style="white-space: pre; overflow-x: scroll">
 +
ANDOR 0
 +
COMMAND
 +
GOTO_IF_FALSE SPECIAL_LABEL_IFS_ELSE_0
 +
    COMMAND
 +
    GOTO SPECIAL_LABEL_IFS_0
 +
SPECIAL_LABEL_IFS_ELSE_0:
 +
    COMMAND
 +
SPECIAL_LABEL_IFS_0:
 +
</pre>
 +
|}
 +
 
 +
{|style="table-layout: fixed" width=100% cellspacing=0 cellpadding=0
 +
|width=50%|'''Mission script'''
 +
|width=16px rowspan=2|
 +
|width=50%|'''Script multifile'''
 
|-
 
|-
!GOTO
+
|style="vertical-align: top"|
|1
+
<pre style="white-space: pre; overflow-x: scroll">
|Any label
+
IF COMMAND
|Offset
+
AND NOT COMMAND
|INT
+
    COMMAND
 +
ENDIF
 +
</pre>
 +
|style="vertical-align: top"|
 +
<pre style="white-space: pre; overflow-x: scroll">
 +
ANDOR 1
 +
COMMAND
 +
NOT COMMAND
 +
GOTO_IF_FALSE SPECIAL_LABEL_IFS_1
 +
    COMMAND
 +
SPECIAL_LABEL_IFS_1:
 +
</pre>
 +
|}
 +
 
 +
{|style="table-layout: fixed" width=100% cellspacing=0 cellpadding=0
 +
|width=50%|'''Mission script'''
 +
|width=16px rowspan=2|
 +
|width=50%|'''Script multifile'''
 
|-
 
|-
!GOTO_IF_FALSE
+
|style="vertical-align: top"|
|1
+
<pre style="white-space: pre; overflow-x: scroll">
|Any label
+
IFNOT COMMAND
|Offset
+
OR NOT COMMAND
|INT
+
    COMMAND
 +
ENDIF
 +
</pre>
 +
|style="vertical-align: top"|
 +
<pre style="white-space: pre; overflow-x: scroll">
 +
ANDOR 21
 +
COMMAND
 +
NOT COMMAND
 +
GOTO_IF_TRUE SPECIAL_LABEL_IFS_2
 +
    COMMAND
 +
SPECIAL_LABEL_IFS_2:
 +
</pre>
 +
|}
 +
 
 +
{|style="table-layout: fixed" width=100% cellspacing=0 cellpadding=0
 +
|width=50%|'''Mission script'''
 +
|width=16px rowspan=2|
 +
|width=50%|'''Script multifile'''
 
|-
 
|-
!GOSUB
+
|style="vertical-align: top"|
|1
+
<pre style="white-space: pre; overflow-x: scroll">
|[[#Gosubs|Gosub]] label
+
IF COMMAND GOTO somewhere
|Offset
+
</pre>
|INT
+
|style="vertical-align: top"|
|-
+
<pre style="white-space: pre; overflow-x: scroll">
!rowspan=2|GOSUB_FILE
+
ANDOR 0
|1
+
COMMAND
|Gosub label
+
GOTO_IF_TRUE somewhere
|rowspan=2|0-based offset
+
</pre>
|rowspan=2|INT
+
|}
|-
+
 
|2
+
{|style="table-layout: fixed" width=100% cellspacing=0 cellpadding=0
|[[#Foreign gosubs|Foreign gosub]] file
+
|width=50%|'''Mission script'''
|-
+
|width=16px rowspan=2|
!START_NEW_SCRIPT
+
|width=50%|'''Script multifile'''
|1
 
|[[#Scripts|Script]] label
 
|0-based offset
 
|INT
 
|-
 
!LAUNCH_MISSION
 
|1
 
|[[#Subscripts|Subscript]] file
 
|0-based offset
 
|INT
 
 
|-
 
|-
!LOAD_AND_LAUNCH_MISSION
+
|style="vertical-align: top"|
|1
+
<pre style="white-space: pre; overflow-x: scroll">
|[[#Mission scripts|Mission script]] file
+
IFNOT COMMAND GOTO somewhere
|Mission [[#Identifiers|identifier]]
+
</pre>
|INT
+
|style="vertical-align: top"|
|-
+
<pre style="white-space: pre; overflow-x: scroll">
|colspan=5|{{icon|lcs}} {{icon|vcs}}
+
ANDOR 0
|-
+
COMMAND
!GOTO_IF_TRUE
+
GOTO_IF_FALSE somewhere
|1
+
</pre>
|Any label
 
|Offset
 
|INT
 
|-
 
!rowspan=4|CALL
 
|1
 
|rowspan=4|[[#Functions|Function]] label
 
|Function arguments
 
|rowspan=4|INT
 
|-
 
|2
 
|Returning arguments
 
|-
 
|3
 
|Parent script [[#Local|locals]]
 
|-
 
|4
 
|Offset
 
 
|}
 
|}
  
{{incomplete}}
+
<span style="display: block; margin: 1em 0; font-size: 1.17em; font-weight: bold; color: black" id="SWITCH">Decision-making structure: SWITCH</span>
  
===Comparing rule===
+
{|style="table-layout: fixed" width=100% cellspacing=0 cellpadding=0
 +
|width=50%|'''Mission script'''
 +
|width=16px rowspan=2|
 +
|width=50%|'''Script multifile'''
 +
|-
 +
|style="vertical-align: top"|
 +
<pre style="white-space: pre; overflow-x: scroll">
 +
VAR_INT check
 +
SWITCH check
 +
    CASE 0
 +
        COMMAND
 +
        BREAK
 +
    CASE 1
 +
    CASE 3
 +
        COMMAND
 +
        BREAK
 +
    CASE 2
 +
        COMMAND
 +
        BREAK
 +
    CASE 4
 +
    CASE 6
 +
    CASE 5
 +
    CASE 7
 +
        COMMAND
 +
        //BREAK
 +
ENDSWITCH
 +
</pre>
 +
|style="vertical-align: top"|
 +
<pre style="white-space: pre; overflow-x: scroll">
 +
SWITCH_START check 8 FALSE SPECIAL_LABEL_SWITCHES_0 0 SPECIAL_LABEL_SWITCHES_CASE_0_0 1 SPECIAL_LABEL_SWITCHES_CASE_1_0 2 SPECIAL_LABEL_SWITCHES_CASE_2_0 3 SPECIAL_LABEL_SWITCHES_CASE_1_0 4 SPECIAL_LABEL_SWITCHES_CASE_3_0 5 SPECIAL_LABEL_SWITCHES_CASE_3_0 6 SPECIAL_LABEL_SWITCHES_CASE_3_0
 +
SWITCH_CONTINUED 7 SPECIAL_LABEL_SWITCHES_CASE_3_0 -1 SPECIAL_LABEL_SWITCHES_0 -1 SPECIAL_LABEL_SWITCHES_0 -1 SPECIAL_LABEL_SWITCHES_0 -1 SPECIAL_LABEL_SWITCHES_0 -1 SPECIAL_LABEL_SWITCHES_0 -1 SPECIAL_LABEL_SWITCHES_0 -1 SPECIAL_LABEL_SWITCHES_0 -1 SPECIAL_LABEL_SWITCHES_0
 +
SPECIAL_LABEL_SWITCHES_CASE_0_0:
 +
    COMMAND
 +
    GOTO SPECIAL_LABEL_SWITCHES_0
 +
SPECIAL_LABEL_SWITCHES_CASE_1_0:
 +
    COMMAND
 +
    GOTO SPECIAL_LABEL_SWITCHES_0
 +
SPECIAL_LABEL_SWITCHES_CASE_2_0:
 +
    COMMAND
 +
    GOTO SPECIAL_LABEL_SWITCHES_0
 +
SPECIAL_LABEL_SWITCHES_CASE_3_0:
 +
    COMMAND
 +
    //GOTO SPECIAL_LABEL_SWITCHES_0
 +
SPECIAL_LABEL_SWITCHES_0:
 +
</pre>
 +
|}
  
The ''comparing rule'' can handle up to ''9 checks'' per construct. ''006D'' ({{icon|3}}, {{icon|vc}}, {{icon|sa}}), ''00DB'' ({{icon|lcs}}) and ''0078'' ({{icon|vcs}}) indicate you are verifying a single check (0) or multiple checks with either '''AND''' (1 to 8) or '''OR''' (21 to 28) [[#Logical|logical operators]] (see also [[#ANDOR|ANDOR]]).
+
{|style="table-layout: fixed" width=100% cellspacing=0 cellpadding=0
 +
|width=50%|'''Mission script'''
 +
|width=16px rowspan=2|
 +
|width=50%|'''Script multifile'''
 +
|-
 +
|style="vertical-align: top"|
 +
<pre style="white-space: pre; overflow-x: scroll">
 +
{
 +
    LVAR_INT check
 +
    SWITCH check
 +
        CASE -2
 +
        CASE -1
 +
            COMMAND
 +
            BREAK
 +
        CASE 1
 +
        CASE 2
 +
            COMMAND
 +
            BREAK
 +
        CASE 0
 +
        DEFAULT
 +
            COMMAND
 +
            //BREAK
 +
    ENDSWITCH
 +
}
 +
</pre>
 +
|style="vertical-align: top"|
 +
<pre style="white-space: pre; overflow-x: scroll">
 +
SWITCH_START check 5 TRUE SPECIAL_LABEL_SWITCHES_DEFAULT_1 -2 SPECIAL_LABEL_SWITCHES_CASE_0_1 -1 SPECIAL_LABEL_SWITCHES_CASE_0_1 0 SPECIAL_LABEL_SWITCHES_DEFAULT_1 1 SPECIAL_LABEL_SWITCHES_CASE_1_1 2 SPECIAL_LABEL_SWITCHES_CASE_1_1 -1 SPECIAL_LABEL_SWITCHES_1 -1 SPECIAL_LABEL_SWITCHES_1
 +
SPECIAL_LABEL_SWITCHES_CASE_0_1:
 +
    COMMAND
 +
    GOTO SPECIAL_LABEL_SWITCHES_1
 +
SPECIAL_LABEL_SWITCHES_CASE_1_1:
 +
    COMMAND
 +
    GOTO SPECIAL_LABEL_SWITCHES_1
 +
SPECIAL_LABEL_SWITCHES_DEFAULT_1:
 +
    COMMAND
 +
    //GOTO SPECIAL_LABEL_SWITCHES_1
 +
SPECIAL_LABEL_SWITCHES_1:
 +
</pre>
 +
|}
  
==Analysis==
+
<span style="display: block; margin: 1em 0; font-size: 1.17em; font-weight: bold; color: black" id="WHILE_and_WHILENOT">Looping structures: WHILE and WHILENOT</span>
  
As an overview of the compiled source, [[#Statements|statements]] are literally nested meaning that the code is unoptimized. Furthermore, the jump of an embedded construct doesn't get merged with that of the construct itself, which consists of a benefit for the code parsing.
+
{|style="table-layout: fixed" width=100% cellspacing=0 cellpadding=0
 +
|width=50%|'''Mission script'''
 +
|width=16px rowspan=2|
 +
|width=50%|'''Script multifile'''
 +
|-
 +
|style="vertical-align: top"|
 +
<pre style="white-space: pre; overflow-x: scroll">
 +
WHILE COMMAND
 +
    COMMAND
 +
ENDWHILE
 +
</pre>
 +
|style="vertical-align: top"|
 +
<pre style="white-space: pre; overflow-x: scroll">
 +
SPECIAL_LABEL_WHILES_A_0:
 +
ANDOR 0
 +
COMMAND
 +
GOTO_IF_FALSE SPECIAL_LABEL_WHILES_B_0
 +
    COMMAND
 +
    GOTO SPECIAL_LABEL_WHILES_A_0
 +
SPECIAL_LABEL_WHILES_B_0:
 +
</pre>
 +
|}
  
===IF===
+
{|style="table-layout: fixed" width=100% cellspacing=0 cellpadding=0
 
+
|width=50%|'''Mission script'''
As regards the [[#IF|IF]] statement, if the whole check is true the ''consequence'' is performed and the code jumps to the end of the construct, otherwise it skips to the ''alternative'' (see also [[#Comparing rule|Comparing rule]]):
+
|width=16px rowspan=2|
 +
|width=50%|'''Script multifile'''
 +
|-
 +
|style="vertical-align: top"|
 +
<pre style="white-space: pre; overflow-x: scroll">
 +
WHILE COMMAND
 +
AND NOT COMMAND
 +
    COMMAND
 +
ENDWHILE
 +
</pre>
 +
|style="vertical-align: top"|
 +
<pre style="white-space: pre; overflow-x: scroll">
 +
SPECIAL_LABEL_WHILES_A_1:
 +
ANDOR 1
 +
COMMAND
 +
NOT COMMAND
 +
GOTO_IF_FALSE SPECIAL_LABEL_WHILES_B_1
 +
    COMMAND
 +
    GOTO SPECIAL_LABEL_WHILES_A_1
 +
SPECIAL_LABEL_WHILES_B_1:
 +
</pre>
 +
|}
  
{|width=100%
+
{|style="table-layout: fixed" width=100% cellspacing=0 cellpadding=0
!width=50%|Decompiled
+
|width=50%|'''Mission script'''
!width=1px|{{icon|3}} {{icon|vc}} {{icon|sa}}
+
|width=16px rowspan=2|
!width=1px|{{icon|lcs}}
+
|width=50%|'''Script multifile'''
!width=1px|{{icon|vcs}}
 
!Compiled
 
 
|-
 
|-
|
+
|style="vertical-align: top"|
IF [NOT] {condition0}
+
<pre style="white-space: pre; overflow-x: scroll">
[AND|OR [NOT] {condition8}]
+
WHILENOT COMMAND
    {consequence}
+
OR NOT COMMAND
[ELSE
+
    COMMAND
    {alternative}]
+
ENDWHILE
ENDIF
+
</pre>
|
+
|style="vertical-align: top"|
{006D}
+
<pre style="white-space: pre; overflow-x: scroll">
{....}
+
SPECIAL_LABEL_WHILES_A_2:
{....}
+
ANDOR 21
{004D}
+
COMMAND
{....}
+
NOT COMMAND
{0002}
+
GOTO_IF_TRUE SPECIAL_LABEL_WHILES_B_2
  ----  
+
    COMMAND
{....}
+
    GOTO SPECIAL_LABEL_WHILES_A_2
  ----
+
SPECIAL_LABEL_WHILES_B_2:
|
+
</pre>
{00DB}
 
{....}
 
{....}
 
{004D}
 
{....}
 
{0002}
 
  ----
 
{....}
 
  ----
 
|
 
{0078}
 
{....}
 
{....}
 
{0022}
 
{....}
 
{0002}
 
  ----  
 
{....}
 
  ----
 
|
 
ANDOR {value}
 
    [NOT] {condition0}
 
    [[NOT] {condition8}]
 
GOTO_IF_FALSE ELSE
 
    {consequence}
 
    [GOTO ENDIF]
 
ELSE:
 
    [{alternative}
 
ENDIF:]
 
 
|}
 
|}
  
===IFNOT===
+
<span style="display: block; margin: 1em 0; font-size: 1.17em; font-weight: bold; color: black" id="REPEAT">Looping structure: REPEAT</span>
  
Not that much to say more than the preceding construct, the [[#IFNOT|IFNOT]] statement is built nearly in the same way. In fact, the '''ELSE''' clause points to the ''alternative'', whereas the [[#GOTO|GOTO]] jumps to its end. The substantial difference consists in the substitution of [[#GOTO_IF_FALSE|GOTO_IF_FALSE]] with [[#GOTO_IF_TRUE|GOTO_IF_TRUE]]:
+
{|style="table-layout: fixed" width=100% cellspacing=0 cellpadding=0
 
+
|width=50%|'''Mission script'''
{|width=100%
+
|width=16px rowspan=2|
!width=50%|Decompiled
+
|width=50%|'''Script multifile'''
!width=1px|{{icon|lcs}}
 
!width=1px|{{icon|vcs}}
 
!Compiled
 
 
|-
 
|-
|
+
|style="vertical-align: top"|
IFNOT [NOT] {condition0}
+
<pre style="white-space: pre; overflow-x: scroll">
[AND|OR [NOT] {condition8}]
+
VAR_INT steps
    {consequence}
+
REPEAT 4 steps // 0 or lesser still implies 1 step.
[ELSE
+
    COMMAND
    {alternative}]
+
ENDREPEAT
ENDIF
+
</pre>
|
+
|style="vertical-align: top"|
{00DB}
+
<pre style="white-space: pre; overflow-x: scroll">
{....}
+
SET_VAR_INT steps 0
{....}
+
SPECIAL_LABEL_REPEATS_0:
{004C}
+
    COMMAND
{....}
+
    ADD_VAL_TO_INT_VAR steps 1
{0002}
+
// Here ANDOR is accidentally missing in Trilogy.
  ----
+
IS_INT_VAR_GREATER_OR_EQUAL_TO_NUMBER steps 4
{....}
+
GOTO_IF_FALSE SPECIAL_LABEL_REPEATS_0
  ----
+
</pre>
|
 
{0078}
 
{....}
 
{....}
 
{0021}
 
{....}
 
{0002}
 
  ----
 
{....}
 
  ----  
 
|
 
ANDOR {value}
 
    [NOT] {condition0}
 
    [[NOT] {condition8}]
 
GOTO_IF_TRUE ELSE
 
    {consequence}
 
    [GOTO ENDIF]
 
ELSE:
 
    [{alternative}
 
ENDIF:]
 
 
|}
 
|}
  
===WHILE===
+
{|style="table-layout: fixed" width=100% cellspacing=0 cellpadding=0
 
+
|width=50%|'''Mission script'''
The [[#WHILE|WHILE]] statement is pretty much similar to the previous, even though when the ''consequence'' is read the code is moved to the beginning of the construct:
+
|width=16px rowspan=2|
 
+
|width=50%|'''Script multifile'''
{|width=100%
 
!width=50%|Decompiled
 
!width=1px|{{icon|3}} {{icon|vc}} {{icon|sa}}
 
!width=1px|{{icon|lcs}}
 
!width=1px|{{icon|vcs}}
 
!Compiled
 
 
|-
 
|-
|
+
|style="vertical-align: top"|
WHILE [NOT] {condition0}
+
<pre style="white-space: pre; overflow-x: scroll">
[AND|OR [NOT] {condition8}]
+
{
    {consequence}
+
    LVAR_INT steps
ENDWHILE
+
    REPEAT 8 steps
|
+
        COMMAND
  ----  
+
    ENDREPEAT
{006D}
+
}
{....}
+
</pre>
{....}
+
|style="vertical-align: top"|
{004D}
+
<pre style="white-space: pre; overflow-x: scroll">
{....}
+
SET_LVAR_INT steps 0
{0002}
+
SPECIAL_LABEL_REPEATS_1:
  ----
+
    COMMAND
|
+
    ADD_VAL_TO_INT_LVAR steps 1
  ----
+
IS_INT_LVAR_GREATER_OR_EQUAL_TO_NUMBER steps 8
{00DB}
+
GOTO_IF_FALSE SPECIAL_LABEL_REPEATS_1
{....}
+
</pre>
{....}
 
{004D}
 
{....}
 
{0002}
 
  ----
 
|
 
  ----
 
{0078}
 
{....}
 
{....}
 
{0022}
 
{....}
 
{0002}
 
  ----
 
|
 
WHILE:
 
ANDOR {value}
 
    [NOT] {condition0}
 
    [[NOT] {condition8}]
 
GOTO_IF_FALSE ENDWHILE
 
    {consequence}
 
    GOTO WHILE
 
ENDWHILE:
 
 
|}
 
|}
  
===WHILENOT===
+
<span style="display: block; margin: 1em 0; font-size: 1.17em; font-weight: bold; color: black" id="Backward_GOTO">Infinite looping structure: backward GOTO</span>
  
To say the least, [[#WHILENOT|WHILENOT]] statement follows the same constitution of both [[#WHILE|WHILE]] and [[#IFNOT|IFNOT]] constructs, by exchanging [[#GOTO_IF_FALSE|GOTO_IF_FALSE]] with [[#GOTO_IF_TRUE|GOTO_IF_TRUE]]:
+
loopstart:
 +
WAIT 0
 +
COMMAND
 +
GOTO loopstart
  
{|width=100%
+
=Multiscripts=
!width=50%|Decompiled
 
!width=1px|{{icon|lcs}}
 
!width=1px|{{icon|vcs}}
 
!Compiled
 
|-
 
|
 
WHILENOT [NOT] {condition0}
 
[AND|OR [NOT] {condition8}]
 
    {consequence}
 
ENDWHILE
 
|
 
  ----
 
{00DB}
 
{....}
 
{....}
 
{004C}
 
{....}
 
{0002}
 
  ----
 
|
 
  ----
 
{0078}
 
{....}
 
{....}
 
{0021}
 
{....}
 
{0002}
 
  ----
 
|
 
WHILENOT:
 
ANDOR {value}
 
    [NOT] {condition0}
 
    [[NOT] {condition8}]
 
GOTO_IF_TRUE ENDWHILE
 
    {consequence}
 
    GOTO WHILENOT
 
ENDWHILE:
 
|}
 
  
===REPEAT===
+
The whole GTA series started as a world subdivided into several levels, each one per urban area spread across fewer cities, albeit 3D era titles has got a single-leveled design covering the entire game scene. Every level is shipped with a main script and a number of ancillary script files, simply called multiscripts, which are bundled inside a folder bearing the same name as the main script filename without extension. The robust scripting engine allows more scripts to cooperate simultaneously at runtime to let writing codes in a multithreading fashion but with no actual concurrency. A script is a unit of execution which, upon starting, is enqueued to a list of active scripts as long as an explicit termination, moving the script back to a list of idle scripts, occurs with <code>TERMINATE_THIS_SCRIPT</code> while <code>TERMINATE_ALL_SCRIPTS_NAMED</code> halts all instances of a script if the specified name, definitely unique to avert compiler complains, was ever set by <code>SCRIPT_NAME</code>. Running scripts are processed sequentially in a non-prioritized order and are paused pending one of the next script ticks using <code>WAIT</code> to delay the script execution of an instance some milliseconds ahead or at the earliest opportunity if 0.
  
Seemingly, the [[#REPEAT|REPEAT]] statement is the first construct ever optimized as a result of a possible R* compiler fault. Moreover, it sounds ambiguous as it loops at least once. This was probably the intention of R* programmers, that is iterating at least once else the construct is useless. However, there are few chance they decide to use such structure to avoid some conflict with some other constructs:
+
{{Incomplete}}
  
{|width=100%
+
==Main script and Main extensions==
!width=50%|Decompiled
 
!colspan=2|G/L {{icon|vc}} {{icon|sa}} {{icon|lcs}}
 
!width=1px|G/L {{icon|vcs}}
 
!Compiled
 
|-
 
|
 
REPEAT {times} {varname}
 
    {consequence}
 
ENDREPEAT
 
|width=1px|
 
{0004}
 
  ----
 
{....}
 
{0008}
 
{0028}
 
{004D}
 
|width=1px|
 
{0005}
 
  ----
 
{....}
 
{0009}
 
{0029}
 
{004D}
 
|
 
{0004}
 
  ----
 
{....}
 
{0007}
 
{0015}
 
{0022}
 
|
 
{varname} = {value0}
 
LOOP:
 
{consequence}
 
++ {varname}
 
    {varname} >= {valueN}
 
GOTO_IF_FALSE LOOP
 
|}
 
  
===CASE===
+
{{Incomplete}}
  
In {{icon|sa}}, the [[#CASE|CASE]] statement is more complex and efficient because the game uses internally a [[Wikipedia:Binary_search_algorithm|binary search algorithm]] to jump at the [[#Labels|label]] that matches with the value of a particular case. This method requires a known amount of cases which is up to 75. When a case is true, a ''consequence'' is executed and the code jumps to the end of the construct, otherwise the ''alternative'' may be performed. As the code is unoptimized, the [[#GOTO|GOTO]] of the last case is still compiled even though its label points to the end of the jump itself:
+
==Scripts and Streamed scripts==
  
{|width=100%
+
{{Incomplete}}
!width=20%|Decompiled
 
!width=1px|{{icon|sa}}
 
!Compiled
 
|-
 
|
 
CASE {varname}
 
    WHEN {value0}
 
        {consequence}
 
    [WHEN {valueN}
 
        {consequence}]
 
    [ELSE
 
        {alternative}]
 
ENDCASE
 
|
 
{0871}
 
{0872}
 
  ----
 
{....}
 
{0002}
 
  ----
 
{....}
 
{0002}
 
  ----
 
{....}
 
{0002}
 
  ----
 
|
 
{varname} {cases} {iselse} ELSE {value0} WHEN0 {valueN} WHENN -1 ENDCASE -1 ENDCASE -1 ENDCASE -1 ENDCASE -1 ENDCASE
 
[-1 ENDCASE -1 ENDCASE -1 ENDCASE -1 ENDCASE -1 ENDCASE -1 ENDCASE -1 ENDCASE -1 ENDCASE -1 ENDCASE]
 
WHEN0:
 
    {consequence}
 
    GOTO ENDCASE
 
[WHENN:
 
    {consequence}
 
    GOTO ENDCASE]
 
[ELSE:
 
    {alternative}
 
    GOTO ENDCASE]
 
ENDCASE:
 
|}
 
  
In {{icon|lcs}} and {{icon|vcs}}, such statement is a set of nested [[#IF|IF]] constructs which causes a very slight loss of performance by considering that ''00DB'' ({{icon|lcs}}) and ''0078'' ({{icon|vcs}} aren't compiled:
+
==Subscripts and Mission scripts==
  
{|width=100%
+
{{Incomplete}}
!width=50%|Decompiled
 
!colspan=2|G/L {{icon|lcs}}
 
!width=1px|G/L {{icon|vcs}}
 
!Compiled
 
|-
 
|
 
CASE {varname}
 
    WHEN {value0}
 
        {consequence}
 
    [WHEN {valueN}
 
        {consequence}]
 
    [ELSE
 
        {alternative}]
 
ENDCASE
 
|width=1px|
 
  ----
 
{0038}
 
{004D}
 
{....}
 
{0002}
 
  ----
 
{0038}
 
{004D}
 
{....}
 
{0002}
 
  ----
 
{....}
 
  ----
 
  ----
 
|width=1px|
 
  ----
 
{0039}
 
{004D}
 
{....}
 
{0002}
 
  ----
 
{0039}
 
{004D}
 
{....}
 
{0002}
 
  ----
 
{....}
 
  ----
 
  ----
 
|
 
  ----
 
{001B}
 
{0022}
 
{....}
 
{0002}
 
  ----
 
{001B}
 
{0022}
 
{....}
 
{0002}
 
  ----
 
{....}
 
  ----
 
  ----
 
|
 
WHEN0:
 
    {varname} = {value0}
 
GOTO_IF_FALSE WHENN
 
    {consequence}
 
    [GOTO ENDCASE0]
 
WHENN:
 
        [{varname} = {valueN}
 
    GOTO_IF_FALSE ELSE
 
        {consequence}
 
        [GOTO ENDCASEN]
 
    ELSE:
 
        [{alternative}
 
    ENDCASEN:]]
 
ENDCASE0:
 
|}
 
  
==Optimization==
+
=Tools=
  
In {{icon|lcs}} and {{icon|vcs}}, whenever a ''single condition'' is checked ''00DB'' ({{icon|lcs}}) and ''0078'' ({{icon|vcs}}) don't get compiled cause no [[#Logical|logical operator]] ('''AND''', '''OR''') is used and so they become really useless. Its lack increase the script efficiency a lot. However, the jump of the '''ELSE''' clause of an [[#IF|IF]] statement which points to the end of the construct is still compiled after a [[#GOTO|GOTO]]. Furthermore, ''Stories Games'' come with an improved data type managing which causes a considerable decrease of the compiled file size.
+
{{GTAF|566450|SCRambl}}, first ever attempt for a now discontinued third-party compiler by {{U|Deji}}<br/>
 +
{{GTAF|876530|GTA3script Toolchain}}, second and still work-in-progress attempt for an unofficial compiler by {{U|Link2012}}
  
 
=External links=
 
=External links=
  
*{{icon|2}} [http://projectcerbera.com/gta/2/tutorials/scripting DMA's GBHScript information]
+
{{GTAF|876461|Learn GTA3script in Y minutes}}, tutorial for deep diving into the language in a short time by {{U|Link2012}}<br/>
*{{icon|3}} [http://alexander.sannybuilder.com/?category=various&altname=gta_3_script_sources SC source files (no main.sc)]
+
[https://gtamodding.github.io/gta3script-specs/ GTA3script Language Specifications], community-based specifications of the language led and maintained by {{U|Link2012}}
  
{{N|SA|VC|3}}
+
=See also=
  
[[Category:Mission Script]]
+
[[SCM language III/VC definitions]]

Latest revision as of 01:25, 14 November 2021

40px-Ambox rewrite orange.svg.png This article may need to be rewritten.
Please help improve this article. The discussion page may contain suggestions.
This article deals with the native scripting language syntax of GTA 3 series, nothing other than III, VC, SA, LCS and VCS.
It may incorporate nonstandard specifications due to the fact R* hasn't published enough documentation about yet.

On the occasion of the "Grand Theft Auto III 10th Anniversary", after a long period of darkness where we fell about the real scripting language syntax, R* finally treated us (or was it, as it seems, a War Drum Studios sloppy oversight?) by attaching part of its own original source code into the Mobile release, available for iOS and Android devices. A year later, the so-called official compiler, somewhat customized for the sake of convenience, was shipped via the remastered edition of Vice City. As far back as 2001, a snip of some debugging scripts has been already provided with main.sc and debug.sc script files that were allegedly meaningful for a sort of script version checker uncut on debug builds. Nonetheless, many secrets are still unrevealed, thus some stuff cannot be fully documented at the moment, hopefully, and so they can be merely guessed. The .scm format abbreviation is one of countless proofs of such a downside which probably stands for Script Multifile, while .scc might be in turn the short form of Compiled Script. No doubt comes with source files, whose .sc extension is the contraction of Mission Script. Although we have enough information to suppose the currently unknown mysteries of the used language, we still have no safe clue about what was its original denomination. Furthermore, it is a matter of fact that R* developers have been left intact the miss2 executable filename of third generation compilers since the chapter 2. In this connection, we could imagine the newer language is a variant or an evolution of the GTA2script which label, initially referred to as GBHscript, expressly popped up in the ancient documentation by DMA Design Ltd. (at present Rockstar North). On those grounds, we are almost sure to say the name of the scripting language targeting each game with all peculiar but minimal enhancements or regressions is most likely GTA3script (as-is casing) for III, GTAVCscript for Vice City, GTASAscript for San Andreas, GTALCSscript for Liberty City Stories and lastly GTAVCSscript for Vice City Stories. However, it is definitely based on BASIC.

Fundamentals

Comments

Codes are usually self-explanatory for the author but large sources can compromise everyone's management capability, that means some annotation can save much time on the long-term particularly when being stuck trying to understand old stuff which should never happen in the first place, not to mention team mates would certainly blame the original writer on each revision and slow down the completion of cooperative projects. Sometimes, it is also required to temporarily/permanently disable code lines for testing purposes. Fortunately, the language supports the following typologies of comments:

  • Line comment, prefixed with // (two forward slashes), which extends till the end of the line. Everything is ignored inside: // Some comment.;
  • Block comment, enclosed with a pair of /* (a slash plus an asterisk) and */ (the other way around), which embodies a circumscribed text area. Several blocks can be nested together: /* Some /* comment */ . */.

Delimiters

Conventionally, lines can be splitted into various regions in order to enhance the code legibility through bracket-delimited and/or comma-separated elements. As being pure whitespaces, the opening parenthesis delimiter doesn't necessarily need to match the closing counterpart and viceversa. The only tangible use of separators carried out in public sources is related to inline declaration of multiple variables, text keys of print-commands and SETUP_ZONE_PED_INFO but codes can be organized to one's liking. Here are some demonstrations:

VAR_INT joeys_buggy, swank_taxi
PRINT_NOW (ASUKA) 2000 1
SETUP_ZONE_PED_INFO CHINA DAY (30) 350 600 0 (0 0 0 0) 0

Integers and Floating-points

Numeric values are used extensively throughout the whole script following no particular notation besides the decimal one. The specializing number representation tells whether a literal is an integer or a floating-point value: an appending f or F floatifies a number, whose suffix becomes superfluous if a radix point, discerning decimals from integral digits, is supplied. Float parts are alternatively omissible hence a 0 digit is implied if one and only one of them is missing. Literal parsing starts from the minus sign, radix point or number digit and stops at the first non number character after a series of digits, leading and/or trailing an eventual radix point, or float suffix. To sum things up, these values are valid numbers: 1, -0, 1f, -0f, 1.0, 1.0f, 1., 1.f, .0, .0f and also 1-2 (ill-formed on basic or compound assignments), 1..2, 1f2, producing 1 (1f-2 is ill-formed a priori). In the first Trilogy chapter, the fixed-point format was chosen meaning precision was guaranteed to not get lost if the decimal part wasn't lesser than just one-tenth.

Labels, Text labels and Strings

Thanks to the beneficial code fragmentation, the source is subject to script file inclusions, favouring modularity, and sparse goto branches, involving embedded code blocks diversification. Both kinds of partitioning are accomplished respectively through the specification of:

  • Filenames, that is special labels which somehow resemble legit pathnames, starting with any valid pathname character but not containing whitespaces. They are relative to the root path deriving from the .sc extension removal of the main script full path where files are searched in by default: X:\folder\main. Subfolders are scanned as well:
    • Till the first tree level if inside one of the subdirectories: X:\parent\main\child;
    • Till the second tree level if inside one of the parent directories: X:\parent or X:\parent\main;
    • Indefinitely (unlimited recursion till the maximum path length allowed).
The .sc extension at the end of filenames is mandatory else an argument mismatch is warned, by contrast the main script can have any extension to which m (multifile) or c (compiled) is appended in the target pathname. Due to a Cd image system limitation, all sorts of filename must be shorter than 20 characters and conventionally they must be free of extra dots for streamed scripts;
  • Labels, that is unique identifiers suffixed by a colon which identify a precise location of the source code representing the target position of goto-like, script starter, subroutine or function caller commands: my_label: (on a new line). Weirdly enough, they may begin with any character alike filenames or be empty despite being susceptible to the same restrictions of string identifiers whenever passed as arguments but, regardless, must not exceed 39 characters (colon included, yet blanked out) and whereas these are not commands, anything else can follow next to and be inlined so long as a splitting character is inserted.
Labels store a reference depicting either an absolute address falling within the main script space (including main extensions and generic subscripts) or a relative and negative address pointing to a place of the mission script space or that of a particular streamed script. Albeit addresses are zero-based anyway, it is discouraged to use a WHILE construct at or branch by hand to the almost very top of a mission/streamed script file or even communicate between different script spaces with gotos.

That said, labels are basically user-supplied identifiers whose existence is verified. The text label or text string counterpart is not fully compliant to this standard (script names are exempt, for instance) since string identifiers are massively employed as main/mission text keys or whatever referring to an internal resource, which the game handles according to a well-defined associative scheme. As a general rule, these are primarily supposed to be at most 7 characters long and must begin with a letter and never end with a colon or either begin with an underscore or an alphanumeric character in the last Trilogy and Stories chapter where text label variables are supported, provided that here their literals are not valid integer or floating-point numbers taking the precedence over string identifiers on parsing:

LOAD_SPECIAL_CHARACTER 1 eight
CUSTOM_PLATE_FOR_NEXT_CAR CAR_TAMPA _FELTCH_
SCRIPT_NAME 99red

In the last Trilogy chapter and nowhere else, longer text labels were introduced, some sort of Pascal strings having a variable length of maximum 40 characters for literals or a fixed length of 16 bytes for variables, twice as big as the shorter text label ones. Speaking of which, it is prohibited to get or handle a longer text label using a variable of shorter length but this one is rather passable to those text label parameters also permitting long-lengthed literals. Notoriously, identifiers length is anything but expensive for readability reasons, in addition they do not even offer the ability to insert whitespaces or other inadmissible characters owing to the by-design absence of delimiting tokens. At this matter, debug texts are sent as 127-character string literals enclosed by double quotes:

SAVE_STRING_TO_DEBUG_FILE "current_wanted_list = "

These quoted strings are, in essence, made up of four text labels aligned to 32 bytes (at the highest power of two possible per parameter) individually accessible as a result of a compiler bug, cause the first character of each literal-only argument is trimmed out as a quotemark – during the line reconstruction phase, the opening and closing quotemarks along with   / , ( )\t are swapped to A \0 \xD1-\xD6 and back again on code generation (the NUL-terminator at the end of string literals makes them rightmost arguments, ignoring the rest).
Unlike string literals, empty text labels are impracticable though $ alone compiles a NUL-string identifier in the last Stories chapter[no source] – as reported by some indiscreet speculations, the rearrangement of crucial commands signals a syntax enhancement the language has undergone which sees delimited strings superseding text labels, lowly probable because string constants are still disallowed for multi-type parameters. In San Andreas, text labels are implicitly comparable against NUL-string identifiers but no syntactical facility accommodates an explicit use.
It's worth noting text labels and string literals are not interchangeable because of their syntactic differences even if they present semantic similarities, moreover text labels do not ever interfere with command names and string constants. A final quirk to note concerning labels as a whole is they are automatically converted to upper case: this obvious evidence proves identifiers and whatnot are all case insensitive with the exemption that string literals are left as-is for remastered game builds.

Data types

Forasmuch as the language obeys the strong typing paradigm, the syntactic elements that denote a value during execution do have fixed data types, most of which are appended as a suffix at variable declaration. Their conspicuous assortment is listed below:

Name Format Size Range Is
main
Is
basic
Derivative data types Immediate
support
Variable
support
NONE
LABEL String identifier
(translated to address)
1, 2 or 4 1 to 38 Since GTA III
Filename
(translated to address or index)
1 to 19
INT Signed integer -2n-1 to 2n-1-1
(where n is 8, 16 or 32)
VAR_INT, VAR_INT_OPT,
LVAR_INT, LVAR_INT_OPT,
(Vice City Stories apart)
INPUT_INT, OUTPUT_INT
Since GTA III
FLOAT Q11.4 fixed-point
(III only)
2 -211 to 211-2-4 VAR_FLOAT, VAR_FLOAT_OPT,
LVAR_FLOAT, LVAR_FLOAT_OPT,
(Vice City Stories apart)
INPUT_FLOAT, OUTPUT_FLOAT
IEEE-754 floating-point
(packed in Stories)
1-4 ±2-126 to ±2127(2-2-23)
TEXT_LABEL String identifier
(NUL-terminated)
8 1 to 7 VAR_TEXT_LABEL, VAR_TEXT_LABEL_OPT,
LVAR_TEXT_LABEL, LVAR_TEXT_LABEL_OPT,
(Vice City Stories apart)
INPUT_TEXT_LABEL, OUTPUT_TEXT_LABEL
(Vice City Stories only)
Since GTA III San Andreas and Vice City Stories
TEXT_LABEL16 String identifier
(if non variable-only, accepts
TEXT_LABEL variables)
9-41
(Pascal string)
8 to n
(where n is <= 40)
VAR_TEXT_LABEL16, VAR_TEXT_LABEL16_OPT,
LVAR_TEXT_LABEL16, LVAR_TEXT_LABEL16_OPT
San Andreas only
16 1 to 15
TEXT_LABEL32 String identifier
(NUL-terminated)
32 1 to 39
(bugged)
San Andreas only
String literal
(NUL-terminated)
32×4 1 to 127
INPUT
(optional)
Includes INT and FLOAT
Includes TEXT_LABEL
(Vice City Stories only)
STRING
(internal only)
Label,
Variable name,
String constant[*],
Text labels,
Quoted string
UNKNOWN

^ String constants are only compatible with INPUT_INT data type but default constants favour INT regardless.

Immediates and Variables

Data can take the appearance of a few expressions varying from numeric, text label and string literals each of which occupies a certain area of storage with unfixed size. Immediates can also be preserved for later use and therefore reserve space over the private script memory corresponding to a variable. The strongly-typed language property imposes to explicitly declare variables anywhere in the current scope, namely the context inside which they are visible for usage. Sensibly, declarations should figure beforehand but likewise it is allowed for accessing backward declarations. Variables accessible from any location are marked as globals (starting from offset 8 or more, occupying lots of space in the script multifile, up to 64 kibibytes) and their declaration is achieved by prepending the VAR wording followed by one of the basic data types (multiple declarations of the same type can be inlined), both separated by an in-between underscore:

VAR_INT player scplayer
VAR_FLOAT x_float, y_float, z_float
VAR_TEXT_LABEL interior_name
VAR_TEXT_LABEL16 shop_item

Globals are capable of being selectively marked as saveable using the SAVE_VAR prefix, in order to restore their value on savegame loading and free generic variables. In Trilogy chapters, if enabled properly in a hacky manner, these are solely common variable declarations with no additional purpose, a plan not gone through. On the other hand, globals declared within the mission context are not visible outside in Stories chapters since they overlap the same space, making a discernment among true and al-most globals. However, there's no exact rule for variable naming apart they must begin with a specific character and never end with a colon just like string identifiers, expanding till a maximum of 39 characters. It's preferable definitions shall not contain operator tokens to prevent any parsing ambiguity plus, most importantly, they must not conflict with string constants and local timers. Nevertheless, text labels and variable names semantics may collide: in this case, the formers have priority over the latters unless a preceding dollar sign is added:

PRINT_BIG TEXTKEY 5000 2  // Compiles a text label literal.
PRINT_BIG $textkey 5000 2 // Compiles a text label variable.

Despite variables are freed and zero-initialized at runtime on new/load game or script allocation in broad terms, statistical information are still gathered whenever they are read before being written, besides if they are never read or never written (passing a variable as reference has no effect onto the content). Furthermore, if a variable is set to hold an entity handle (alias unique index) returned by a specific create-command it cannot be assigned to any other entity-command of different kind or none, including the forseeable assignment operations. This restriction propagates on script and function callings as well: starting/streaming the same script or calling the same function multiple times with variables of dissimilar entity types is forbidden if triggers are encountered prior the script or function lexical scope is fetched, in which case entities are explicitly initialized in the form of unreachable code:

{
    LVAR_INT fellow_char robbery_car money_bag sanity

    sanity = 0
    IF sanity = -1
        CREATE_CHAR PEDTYPE_CIVMALE male01 0f 0f 0f fellow_char
        CREATE_CAR admiral 0f 0f 0f robbery_car
        CREATE_OBJECT woodenbox 0f 0f 0f money_bag
    ENDIF
}

Lexical scope

Once a script is launched, a local storage space consisting of a context-dependent set of variables (16+2 in III/Vice City, 32+2 in San Andreas and 40+2 on Mobile, 96+8+2 in Stories) ready for use is also reserved. As opposed to global variables, locals have visibility only inside a particular region of the source code and are preceded by the LVAR wording at declaration within a nonnestable block embraced by { and }:

{
    LVAR_INT pickup message_num
}

Local names do not override global definitions, they must not collide together otherwise a warn is issued. Beyond user-defined locals, predefined TIMERA and TIMERB variables are provided: these timers measures the playing time milliseconds passed since the script beginning but they can be reset just fine. In the last Trilogy chapter, mission locals are mainly static variables starting from index 34 or 42 on Mobile whose space (having a size of 4 kibibytes) is shared among each mission thus being reasonably more abundant in this scenario but, as a side effect, local timers are unavailable. Transferring the control over and above the lexical scope boundaries or to another multiscript leaves the active context and hides local definitions, thereby switching across lexical scopes is bad practice and can lead to unpredictable results if contexts are not strictly equivalent in the variable declarations.

Arrays

Since the last Trilogy chapter, instead of declaring multiple scalar variables of same type, a one-dimensional indexed array can be defined. Each element is accessed through either a zero-based[no source] positive number or a variable index (local-only in Stories) in a subscript expression on assignment or argument passing. On declaration, a pair of square brackets enclose the array size which mustn't be bigger than 255 units:

VAR_INT prop_assets[32]
CREATE_FORSALE_PROPERTY_PICKUP -1969.27 282.47 34.6 50000 PROP_3 prop_assets[0]

In sooth, one-based arrays were already supported in the second Trilogy chapter but in a manner which is defective and incomplete: they missed the intrinsic data type, giving no reference point on how to interpret the compiled operands, producing corrupted intermediate code because of fall-through reading. There is no precedent to safely assert that arrays became zero-based later on the language evolution but what is certain is this sort of indexing lines up immediate with variable indices. Oddly, as a result of the uni-dimensionality constraint implementation, a complementary yet nonfactual identifier can follow the closing bracket immediately afterwards with no redundancy notice (i.e. prop_assets[0]anything). Moreover, scalar variables have an implicit array size of one element which is needlessly accessible and plus the index part of the first element of an array is in turn omissible, everything notwithstanding the misleading declaration. Granted that brackets do not encompass any separator character or identifiers wider than 39 characters, array indices reject string constants but admit local timers.

String constants

Very often, numeric literals express arbitrary values which are far from being self-documenting without descriptive labels belonging to a list of predefined names. These strings or enumerators are guaranteed to store an immutable constant and must forcibly pertain to the required enumeration if passed as arguments unless, if and only if no enumeration is set, the enumeration-free default constants TRUE/FALSE, ON/OFF, DAY/NIGHT or KILLFRENZY enumerators are supplied:

CHANGE_BLIP_DISPLAY blip1_jm1 BLIP_ONLY
flag_car_blip_displayed_jm1 = TRUE

Assignments and comparisons do not suffer such a restriction and, what's more, in case of too long lines (wider than 255 characters) immediates can safely replace string constants to shorten the exceeding length and fall within the limits. Of course, string constants are bound to the same parsing rules as string identifiers but, as being mainly hardcoded, they are just as limitless in length.
During the development stage, the game's map experiences lots of continuous changes that make the management of objects, as a result of having a fixed indexing, pretty awkward without taking into account their bulk amount. In this respect, parameters expecting level objects are able to define the used objects (no more longer than 23 characters) under the hood, bringing them together in a sorted array whose criteria depends on the order of their appearance, something other than the default models which are hardcoded (for peds, cars, weapons, wheels, cutscene objects and the like). A blank, unavailable object is always reserved, shifting ahead each next negated position becoming one-based. Negative indices assure models fit in the used objects array, according to which the runtime matches the right index through a lookup table:

REQUEST_MODEL bridgefuka // First use ever. It compiles -1 from now on.
REQUEST_MODEL bridgefukb // First use again. This time it compiles -2.
LOAD_ALL_MODELS_NOW
CREATE_OBJECT_NO_OFFSET bridgefuka 715.746 -937.908 40.194 damagea
CREATE_OBJECT_NO_OFFSET bridgefukb 787.835 -939.24 38.971 damageb

The lack of error-checking requires a meticulous handwriting to avoid script deadlocks at runtime, the reason why default models of which undefined names follow the format NOT_USED%d (where %d is a model index from 0 to 299) and level objects are loaded straight from IDE files for Vice City's remastered build. Nonetheless, iterating among several objects can be very expensive for a poorly optimized, rough compiler even on fast machines, not to mention enumerators are likely to collide without specializing prefixes (i.e. SNIPER camera mode and weapon name, formerly WEAPON_SNIPER), enough to revert back thereafter.
Assignments and comparisons have no clue about used objects and are therefore not designed to accommodate or implicitly define one on their own, because they are supposed to be strict with the identifier existence as being more prone to work out with variables. This concept somehow extends to those parameters not featuring used objects as a general rule. If an unusual application needs to take place, making use of non-inlined CONSTANT_INT declarations would hint the compiler to treat unequivocally the specified string constants as used objects, truly defining a new one on the first practical usage wherever it occurs and not yielding an undefined variable error:

CONSTANT_INT cj_pizza_1
CONSTANT_INT cj_pizza_2
VAR_INT food_model1 food_model2

REQUEST_MODEL pizzahigh  // -1
food_model1 = cj_pizza_1 // -2
food_model2 = cj_pizza_2 // -3
REQUEST_MODEL food_model1
REQUEST_MODEL food_model2

Any string constant passed in place of an object model compiles a used object indiscriminately assuming no CONSTANT_INT declaration, also preventing redefinitions towards default constants, enumerators and variable names, does exist. Messing around with frequent compiler tool recompilations can be tedious solely to establish broad, same-indexed or math-related string constants but fortunately, in the last Trilogy chapter, the language offers the opportunity to settle user-supplied default constants for numeric literals using CONST-prefixed declarations (maximum 39 characters long) which, alike for variables and CONSTANT_INTs, are backwards accessible:

CONST_INT gf_date_active 1
CONST_FLOAT math_pi 3.1415927

SET_BIT gf_date_flags gf_date_active
rad_angle = deg_angle * math_pi
rad_angle /= 180.0

Given that default models are also default constants in Stories chapters[no source], default constants and used objects count as pseudoconstants: contrary to what non-default enumerators entail, generic alternatives are favoured on assignment or comparison command matching. It should be pointed out that, due to a critical compiler bug, the high-order word of the value held by any enumerator is unexpectedly discarded on assignment or comparison and that, if set, the 16th bit yields a nonexistent variable error (i.e. THREAT_GANG9 flag) prior Stories chapters, after which a default constant is compiled instead (buggy behaviour) and recognized only if the low-order word represents a value not equal to -1[no source]:

Mission script Script multifile
SET_CHAR_THREAT_SEARCH npc_char THREAT_GANG_GOLFER
SET_CHAR_THREAT_SEARCH npc_char THREAT_GANG9
SET_CHAR_THREAT_SEARCH npc_char THREAT_EMERGENCY
threat_flag = THREAT_GANG_GOLFER
threat_flag = THREAT_GANG9 // Ill-formed in Trilogy.
threat_flag = THREAT_EMERGENCY
SET_CHAR_THREAT_SEARCH npc_char 16384
SET_CHAR_THREAT_SEARCH npc_char 32768
SET_CHAR_THREAT_SEARCH npc_char 65536
SET_VAR_INT_TO_CONSTANT threat_flag 16384
SET_VAR_INT threat_flag 32768
SET_VAR_INT_TO_CONSTANT threat_flag 0

This drawback unwittingly affects real code in Liberty City Stories in one circumstance. On a final note, string constants are incompatible with optional arguments and thus taking advantage of a temporary variable would overcome this syntactic limitation.

Operators

As soon as a numeric or text label variable is declared, it can be subjected to algebric operations and/or logical comparisons by virtue of several operators. Their support is sadly very primitive, in fact the ability to establish complex expressions with parentheses and such is not featured albeit one and only binary operation is enabled to follow the basic assignment. In this regard, the variable being assigned to the lvalue cannot be the same as the outer rvalue for non-commutative operations: VAR1 = THING - VAR1, VAR1 = THING / VAR1, VAR1 = THING +@ VAR1 and VAR1 = THING -@ VAR1 are all ill-formed (where THINGVAR1). This issue arises because the explicit usage of a temporary variable is needed which would be harmful for the compiler to waste by itself under the hood, thus here expressions are necessarily made up of distinct two-operand instructions, that is the lvalue content is initialized prior encoding any supplementary rvalue arithmetic:

Mission script Script multifile
VAR1 = 1 - VAR1 // Invalid, cause VAR1 = 1; VAR1 -= VAR1 doesn't make sense.
                // It would perform 1 - 1 = 0. Workaround needed.
VAR1 = 1 / VAR1 // Invalid, cause VAR1 = 1; VAR1 /= VAR1 does no effect.
                // It would perform 1 / 1 = 1. Workaround needed.
VAR1 = 1 - VAR2 // Valid, cause VAR1 = 1; VAR1 -= VAR2 doesn't null itself like above.
                // It performs x = 1 - y.
VAR1 = 1 + VAR1 // Valid, addition (as well as multiplication) is commutative so VAR1 += 1.
                // It performs x = x + 1.
NEGATE VAR1 // Unknown command (speculative). It would do x = -x.
ADD_THING_TO_THING VAR1 1
ONEOVER VAR1 // Unknown command (speculative). It would do x = 1 / x.
MULT_THING_BY_THING VAR1 1
SET VAR1 1
SUB_THING_FROM_THING VAR1 VAR2
ADD_THING_TO_THING VAR1 1

The subtraction of positive or negative rvalues necessitates a splitting character in order to discern the infix operator unambiguously, which would be treated as part of the literal or a variable decrement otherwise (i.e. VAR1 = VAR1 -1 or VAR1 = VAR1 --1). Typically, string constants are not suitable for math calculations because of the lack of matchable alternative commands but even so they are semantically contemplated as long as a non-default enumerator is provided as the inner rvalue of a ternary operation or a default constant or enumerator is passed to any rvalue (i.e. VAR1 = PAD1 + 1, VAR1 = DAY + 1 or VAR1 = 1 + KILLFRENZY_INITIALLY). Another clear limitation is prefix and postfix operators do not apply onto arguments, hence there's no concrete differentiation. However, the language introduces the timed addition/subtraction to looply update a variable in a frame-rate independent way, the cast assignment to do a mutual conversion between integers and floats but it doesn't give support for the modulo operation as its predecessor. The inequality comparison was planned but quickly gone obsolete[no source] – availing of the negated form of the equality operator would have sounded more intuitive but one should be aware the not-flag is not bundled with the command index when matching alternative commands. Due to a negligence of the programmers in charge, liable for forgetting some assets of the scripting environment, the local-global in/equality comparison between integer or float variables is not feasible except in the last chapter of Trilogy and Stories series. Surprisingly enough, the basic assignment may prepend ABS which in so doing would be capable of receiving numeric literals because of the pre-empted rvalue assigning (i.e. VAR = ABS THING). In principle, SET is not compiled only if both lvalue and rvalue (whether inner or outer) of a ternary operation or ABS assignment collide (identity).

Arithmetic operators

Name Syntax INT FLOAT TEXT_LABEL/16
Basic assignment
VAR = THING
Addition
THING + THING
Subtraction
THING - THING
Multiplication
THING * THING
Division
THING / THING
Timed addition
THING +@ THING
Timed subtraction
THING -@ THING
Increment Prefix
++ VAR
Postfix
VAR ++
Decrement Prefix
-- VAR
Postfix
VAR --

Compound assignment operators

Name Syntax Meaning INT FLOAT
Addition assignment
VAR += THING
VAR1 = VAR1 + THING
Subtraction assignment
VAR -= THING
VAR1 = VAR1 - THING
Multiplication assignment
VAR *= THING
VAR1 = VAR1 * THING
Division assignment
VAR /= THING
VAR1 = VAR1 / THING
Timed addition assignment
VAR +=@ THING
VAR1 = VAR1 +@ THING
 
Timed subtraction assignment
VAR -=@ THING
VAR1 = VAR1 -@ THING
Cast assignment
VAR =# THING
AS IS

Comparison operators/relational operators

Name Syntax INT FLOAT TEXT_LABEL/16
Equal to
VAR = THING
Not equal to[no source]
VAR <> THING
Greater than
THING > THING
Less than
THING < THING
Greater than or equal to
THING >= THING
Less than or equal to
THING <= THING

Logical operators

Name Syntax
Logical negation
NOT
Logical conjunction
AND
Logical disjunction
OR

Commands

The imperative programming paradigm provides for a conglomerate of commands the script is filled up of and structured in, which are seen as orders to instruct the execution of the relative built-in portion of game code at runtime. Their invocation is faithful to procedure calls: they may feature zero or more parameters (up to 16+ in III\Vice City, 32+ in San Andreas and Stories) of any type or indefinite, depending on whether or not qualified as optional, and receive as much as arguments either by-value or by-reference affecting the read/written access accordingly (do note a pure reference does not initialize anything). Alike procedures, no assignable result is returned but a boolean state is caught anyway on conditional evaluation. One major peculiarity is command names are usually identified by a verb in its imperative form:

GIVE_WEAPON_TO_CHAR mafia_1X WEAPONTYPE_UZI 999

Command names are leftmost identifiers not ending with a colon (not a label) and not preceded or followed by an operator token (not a variable). On code generation, their definition is turned into a 15-bit index reflecting the position the name is matched at in a list of command descriptors and packed with the not-flag stored in the most significant bit, accompained by a known or indeterminate number of typified, somewhat typified or thorougly nontypified operands completing several instructions which are arranged in order to bring forth the intermediate script bytecode. At every command corresponds an output except for variable, string constant and lexical scope declarators or for the classic NOP (no operation). Operand immediates mainly use the shortest representation for size optimization, yet label references always yield 32-bit addresses.
Game progress rely on many countable stuff to determine the percentage acquired at any given time which are extremely time spending and easily error-prone to quantize manually. Counter-commands come to aid, sort of adaptive counters featuring a possibly zero-valued argument updated automatically during the compilation process that keeps track of the times a few commands are used or of the total sum of some argument value of certain commands, discarding nonimmediates:

Initializer Dependency Is
addend
SET_COLLECTABLE1_TOTAL CREATE_COLLECTABLE1
SET_PROGRESS_TOTAL PLAYER_MADE_PROGRESS
SET_TOTAL_NUMBER_OF_MISSIONS REGISTER_MISSION_PASSED
REGISTER_ODDJOB_MISSION_PASSED
SET_MISSION_RESPECT_TOTAL AWARD_PLAYER_MISSION_RESPECT

Condition-based statements and counter-commands along with the file includers outside of the main script or main extensions, where labels are expected instead of filenames, are mostly parameterized regardless of their own descriptor (the type-check is still done though), while another category consisting of multicommands is able to look for the matching prototype into a list of akin commands on the basis of the data type of the passed arguments and choose, accordingly, the equivalent alternative in a direct and effortless way. Although the alternative commands are also accessible by and can share the same definition, the selection process is not entirely conform to function overloading because these still retain their exclusive name as being plainly resolved through weak aliases. A complete listing is shown below:

Trilogy and first Stories chapters Second Stories chapter
Command Game
support
Alternative
SET (=) Since GTA III
SET_VAR_INT
SET_VAR_FLOAT
SET_LVAR_INT
SET_LVAR_FLOAT
SET_VAR_INT_TO_VAR_INT
SET_LVAR_INT_TO_LVAR_INT
SET_VAR_FLOAT_TO_VAR_FLOAT
SET_LVAR_FLOAT_TO_LVAR_FLOAT
SET_VAR_FLOAT_TO_LVAR_FLOAT
SET_LVAR_FLOAT_TO_VAR_FLOAT
SET_VAR_INT_TO_LVAR_INT
SET_LVAR_INT_TO_VAR_INT
SET_VAR_INT_TO_CONSTANT Since Vice City
SET_LVAR_INT_TO_CONSTANT
SET_VAR_TEXT_LABEL San Andreas only
SET_LVAR_TEXT_LABEL
SET_VAR_TEXT_LABEL16
SET_LVAR_TEXT_LABEL16
CSET (=#) Since GTA III
CSET_VAR_INT_TO_VAR_FLOAT
CSET_VAR_FLOAT_TO_VAR_INT
CSET_LVAR_INT_TO_VAR_FLOAT
CSET_LVAR_FLOAT_TO_VAR_INT
CSET_VAR_INT_TO_LVAR_FLOAT
CSET_VAR_FLOAT_TO_LVAR_INT
CSET_LVAR_INT_TO_LVAR_FLOAT
CSET_LVAR_FLOAT_TO_LVAR_INT
ADD_THING_TO_THING (+=) Since GTA III
ADD_VAL_TO_INT_VAR
ADD_VAL_TO_FLOAT_VAR
ADD_VAL_TO_INT_LVAR
ADD_VAL_TO_FLOAT_LVAR
ADD_INT_VAR_TO_INT_VAR
ADD_FLOAT_VAR_TO_FLOAT_VAR
ADD_INT_LVAR_TO_INT_LVAR
ADD_FLOAT_LVAR_TO_FLOAT_LVAR
ADD_INT_VAR_TO_INT_LVAR
ADD_FLOAT_VAR_TO_FLOAT_LVAR
ADD_INT_LVAR_TO_INT_VAR
ADD_FLOAT_LVAR_TO_FLOAT_VAR
SUB_THING_FROM_THING (-=) Since GTA III
SUB_VAL_FROM_INT_VAR
SUB_VAL_FROM_FLOAT_VAR
SUB_VAL_FROM_INT_LVAR
SUB_VAL_FROM_FLOAT_LVAR
SUB_INT_VAR_FROM_INT_VAR
SUB_FLOAT_VAR_FROM_FLOAT_VAR
SUB_INT_LVAR_FROM_INT_LVAR
SUB_FLOAT_LVAR_FROM_FLOAT_LVAR
SUB_INT_VAR_FROM_INT_LVAR
SUB_FLOAT_VAR_FROM_FLOAT_LVAR
SUB_INT_LVAR_FROM_INT_VAR
SUB_FLOAT_LVAR_FROM_FLOAT_VAR
MULT_THING_BY_THING (*=) Since GTA III
MULT_INT_VAR_BY_VAL
MULT_FLOAT_VAR_BY_VAL
MULT_INT_LVAR_BY_VAL
MULT_FLOAT_LVAR_BY_VAL
MULT_INT_VAR_BY_INT_VAR
MULT_FLOAT_VAR_BY_FLOAT_VAR
MULT_INT_LVAR_BY_INT_LVAR
MULT_FLOAT_LVAR_BY_FLOAT_LVAR
MULT_INT_VAR_BY_INT_LVAR
MULT_FLOAT_VAR_BY_FLOAT_LVAR
MULT_INT_LVAR_BY_INT_VAR
MULT_FLOAT_LVAR_BY_FLOAT_VAR
DIV_THING_BY_THING (/=) Since GTA III
DIV_INT_VAR_BY_VAL
DIV_FLOAT_VAR_BY_VAL
DIV_INT_LVAR_BY_VAL
DIV_FLOAT_LVAR_BY_VAL
DIV_INT_VAR_BY_INT_VAR
DIV_FLOAT_VAR_BY_FLOAT_VAR
DIV_INT_LVAR_BY_INT_LVAR
DIV_FLOAT_LVAR_BY_FLOAT_LVAR
DIV_INT_VAR_BY_INT_LVAR
DIV_FLOAT_VAR_BY_FLOAT_LVAR
DIV_INT_LVAR_BY_INT_VAR
DIV_FLOAT_LVAR_BY_FLOAT_VAR
IS_THING_EQUAL_TO_THING (=) Since GTA III
IS_INT_VAR_EQUAL_TO_NUMBER
IS_INT_LVAR_EQUAL_TO_NUMBER
IS_INT_VAR_EQUAL_TO_INT_VAR
IS_INT_LVAR_EQUAL_TO_INT_LVAR
IS_INT_VAR_EQUAL_TO_INT_LVAR
IS_INT_LVAR_EQUAL_TO_INT_VAR San Andreas only
IS_FLOAT_VAR_EQUAL_TO_NUMBER
IS_FLOAT_LVAR_EQUAL_TO_NUMBER
IS_FLOAT_VAR_EQUAL_TO_FLOAT_VAR
IS_FLOAT_LVAR_EQUAL_TO_FLOAT_LVAR
IS_FLOAT_VAR_EQUAL_TO_FLOAT_LVAR
IS_FLOAT_LVAR_EQUAL_TO_FLOAT_VAR San Andreas only
IS_INT_VAR_EQUAL_TO_CONSTANT Since Vice City
IS_INT_LVAR_EQUAL_TO_CONSTANT
IS_VAR_TEXT_LABEL_EQUAL_TO_TEXT_LABEL San Andreas only
IS_LVAR_TEXT_LABEL_EQUAL_TO_TEXT_LABEL
IS_VAR_TEXT_LABEL16_EQUAL_TO_TEXT_LABEL
IS_LVAR_TEXT_LABEL16_EQUAL_TO_TEXT_LABEL
IS_THING_NOT_EQUAL_TO_THING (<>) Since GTA III
IS_INT_VAR_NOT_EQUAL_TO_NUMBER
IS_INT_LVAR_NOT_EQUAL_TO_NUMBER
IS_INT_VAR_NOT_EQUAL_TO_INT_VAR
IS_INT_LVAR_NOT_EQUAL_TO_INT_LVAR
IS_INT_VAR_NOT_EQUAL_TO_INT_LVAR
IS_INT_LVAR_NOT_EQUAL_TO_INT_VAR San Andreas only
IS_FLOAT_VAR_NOT_EQUAL_TO_NUMBER
IS_FLOAT_LVAR_NOT_EQUAL_TO_NUMBER
IS_FLOAT_VAR_NOT_EQUAL_TO_FLOAT_VAR
IS_FLOAT_LVAR_NOT_EQUAL_TO_FLOAT_LVAR
IS_FLOAT_VAR_NOT_EQUAL_TO_FLOAT_LVAR
IS_FLOAT_LVAR_NOT_EQUAL_TO_FLOAT_VAR San Andreas only
IS_THING_GREATER_THAN_THING (>, <=) Since GTA III
IS_INT_VAR_GREATER_THAN_NUMBER
IS_INT_LVAR_GREATER_THAN_NUMBER
IS_NUMBER_GREATER_THAN_INT_VAR
IS_NUMBER_GREATER_THAN_INT_LVAR
IS_INT_VAR_GREATER_THAN_INT_VAR
IS_INT_LVAR_GREATER_THAN_INT_LVAR
IS_INT_VAR_GREATER_THAN_INT_LVAR
IS_INT_LVAR_GREATER_THAN_INT_VAR
IS_FLOAT_VAR_GREATER_THAN_NUMBER
IS_FLOAT_LVAR_GREATER_THAN_NUMBER
IS_NUMBER_GREATER_THAN_FLOAT_VAR
IS_NUMBER_GREATER_THAN_FLOAT_LVAR
IS_FLOAT_VAR_GREATER_THAN_FLOAT_VAR
IS_FLOAT_LVAR_GREATER_THAN_FLOAT_LVAR
IS_FLOAT_VAR_GREATER_THAN_FLOAT_LVAR
IS_FLOAT_LVAR_GREATER_THAN_FLOAT_VAR
IS_INT_VAR_GREATER_THAN_CONSTANT Since Vice City
IS_INT_LVAR_GREATER_THAN_CONSTANT
IS_CONSTANT_GREATER_THAN_INT_VAR
IS_CONSTANT_GREATER_THAN_INT_LVAR
IS_THING_GREATER_OR_EQUAL_TO_THING (>=, <) Since GTA III
IS_INT_VAR_GREATER_OR_EQUAL_TO_NUMBER
IS_INT_LVAR_GREATER_OR_EQUAL_TO_NUMBER
IS_NUMBER_GREATER_OR_EQUAL_TO_INT_VAR
IS_NUMBER_GREATER_OR_EQUAL_TO_INT_LVAR
IS_INT_VAR_GREATER_OR_EQUAL_TO_INT_VAR
IS_INT_LVAR_GREATER_OR_EQUAL_TO_INT_LVAR
IS_INT_VAR_GREATER_OR_EQUAL_TO_INT_LVAR
IS_INT_LVAR_GREATER_OR_EQUAL_TO_INT_VAR
IS_FLOAT_VAR_GREATER_OR_EQUAL_TO_NUMBER
IS_FLOAT_LVAR_GREATER_OR_EQUAL_TO_NUMBER
IS_NUMBER_GREATER_OR_EQUAL_TO_FLOAT_VAR
IS_NUMBER_GREATER_OR_EQUAL_TO_FLOAT_LVAR
IS_FLOAT_VAR_GREATER_OR_EQUAL_TO_FLOAT_VAR
IS_FLOAT_LVAR_GREATER_OR_EQUAL_TO_FLOAT_LVAR
IS_FLOAT_VAR_GREATER_OR_EQUAL_TO_FLOAT_LVAR
IS_FLOAT_LVAR_GREATER_OR_EQUAL_TO_FLOAT_VAR
IS_INT_VAR_GREATER_OR_EQUAL_TO_CONSTANT Since Vice City
IS_INT_LVAR_GREATER_OR_EQUAL_TO_CONSTANT
IS_CONSTANT_GREATER_OR_EQUAL_TO_INT_VAR
IS_CONSTANT_GREATER_OR_EQUAL_TO_INT_LVAR
ADD_THING_TO_THING_TIMED (+=@) Since GTA III
ADD_TIMED_VAL_TO_FLOAT_VAR
ADD_TIMED_VAL_TO_FLOAT_LVAR
ADD_TIMED_FLOAT_VAR_TO_FLOAT_VAR
ADD_TIMED_FLOAT_LVAR_TO_FLOAT_LVAR
ADD_TIMED_FLOAT_LVAR_TO_FLOAT_VAR
ADD_TIMED_FLOAT_VAR_TO_FLOAT_LVAR
SUB_THING_FROM_THING_TIMED (-=@) Since GTA III
SUB_TIMED_VAL_FROM_FLOAT_VAR
SUB_TIMED_VAL_FROM_FLOAT_LVAR
SUB_TIMED_FLOAT_VAR_FROM_FLOAT_VAR
SUB_TIMED_FLOAT_LVAR_FROM_FLOAT_LVAR
SUB_TIMED_FLOAT_LVAR_FROM_FLOAT_VAR
SUB_TIMED_FLOAT_VAR_FROM_FLOAT_LVAR
ABS Since GTA III
ABS_VAR_INT
ABS_LVAR_INT
ABS_VAR_FLOAT
ABS_LVAR_FLOAT
IS_EMPTY San Andreas only
IS_VAR_TEXT_LABEL_EMPTY
IS_LVAR_TEXT_LABEL_EMPTY
IS_VAR_TEXT_LABEL16_EMPTY
IS_LVAR_TEXT_LABEL16_EMPTY
IS_BIT_SET San Andreas only
IS_GLOBAL_VAR_BIT_SET_CONST
IS_GLOBAL_VAR_BIT_SET_VAR
IS_GLOBAL_VAR_BIT_SET_LVAR
IS_LOCAL_VAR_BIT_SET_CONST
IS_LOCAL_VAR_BIT_SET_VAR
IS_LOCAL_VAR_BIT_SET_LVAR
SET_BIT San Andreas only
SET_GLOBAL_VAR_BIT_CONST
SET_GLOBAL_VAR_BIT_VAR
SET_GLOBAL_VAR_BIT_LVAR
SET_LOCAL_VAR_BIT_CONST
SET_LOCAL_VAR_BIT_VAR
SET_LOCAL_VAR_BIT_LVAR
CLEAR_BIT San Andreas only
CLEAR_GLOBAL_VAR_BIT_CONST
CLEAR_GLOBAL_VAR_BIT_VAR
CLEAR_GLOBAL_VAR_BIT_LVAR
CLEAR_LOCAL_VAR_BIT_CONST
CLEAR_LOCAL_VAR_BIT_VAR
CLEAR_LOCAL_VAR_BIT_LVAR
Command
Alternative
SET (=)
SET_VAR_INT
SET_VAR_FLOAT
SET_VAR_TEXT_LABEL
SET_VAR_INT_TO_VAR_INT
SET_VAR_FLOAT_TO_VAR_FLOAT
SET_VAR_TEXT_LABEL_TO_VAR_TEXT_LABEL
SET_VAR_INT_TO_CONSTANT
CSET (=#)
CSET_VAR_INT_TO_VAR_FLOAT
CSET_VAR_FLOAT_TO_VAR_INT
ADD_THING_TO_THING (+=)
ADD_VAL_TO_INT_VAR
ADD_VAL_TO_FLOAT_VAR
ADD_INT_VAR_TO_INT_VAR
ADD_FLOAT_VAR_TO_FLOAT_VAR
SUB_THING_FROM_THING (-=)
SUB_VAL_FROM_INT_VAR
SUB_VAL_FROM_FLOAT_VAR
SUB_INT_VAR_FROM_INT_VAR
SUB_FLOAT_VAR_FROM_FLOAT_VAR
MULT_THING_BY_THING (*=)
MULT_INT_VAR_BY_VAL
MULT_FLOAT_VAR_BY_VAL
MULT_INT_VAR_BY_INT_VAR
MULT_FLOAT_VAR_BY_FLOAT_VAR
DIV_THING_BY_THING (/=)
DIV_INT_VAR_BY_VAL
DIV_FLOAT_VAR_BY_VAL
DIV_INT_VAR_BY_INT_VAR
DIV_FLOAT_VAR_BY_FLOAT_VAR
IS_THING_EQUAL_TO_THING (=)
IS_INT_VAR_EQUAL_TO_NUMBER
IS_INT_VAR_EQUAL_TO_INT_VAR
IS_FLOAT_VAR_EQUAL_TO_NUMBER
IS_FLOAT_VAR_EQUAL_TO_FLOAT_VAR
IS_TEXT_LABEL_VAR_EQUAL_TO_TEXT_LABEL
IS_TEXT_LABEL_VAR_EQUAL_TO_TEXT_LABEL_VAR
IS_INT_VAR_EQUAL_TO_CONSTANT
IS_THING_GREATER_THAN_THING (>, <=)
IS_INT_VAR_GREATER_THAN_NUMBER
IS_NUMBER_GREATER_THAN_INT_VAR
IS_INT_VAR_GREATER_THAN_INT_VAR
IS_FLOAT_VAR_GREATER_THAN_NUMBER
IS_NUMBER_GREATER_THAN_FLOAT_VAR
IS_FLOAT_VAR_GREATER_THAN_FLOAT_VAR
IS_INT_VAR_GREATER_THAN_CONSTANT
IS_CONSTANT_GREATER_THAN_INT_VAR
IS_THING_GREATER_OR_EQUAL_TO_THING (>=, <)
IS_INT_VAR_GREATER_OR_EQUAL_TO_NUMBER
IS_NUMBER_GREATER_OR_EQUAL_TO_INT_VAR
IS_INT_VAR_GREATER_OR_EQUAL_TO_INT_VAR
IS_FLOAT_VAR_GREATER_OR_EQUAL_TO_NUMBER
IS_NUMBER_GREATER_OR_EQUAL_TO_FLOAT_VAR
IS_FLOAT_VAR_GREATER_OR_EQUAL_TO_FLOAT_VAR
IS_INT_VAR_GREATER_OR_EQUAL_TO_CONSTANT
IS_CONSTANT_GREATER_OR_EQUAL_TO_INT_VAR
ADD_THING_TO_THING_TIMED (+=@)
ADD_TIMED_VAL_TO_FLOAT_VAR
ADD_TIMED_FLOAT_VAR_TO_FLOAT_VAR
SUB_THING_FROM_THING_TIMED (-=@)
SUB_TIMED_VAL_FROM_FLOAT_VAR
SUB_TIMED_FLOAT_VAR_FROM_FLOAT_VAR
ABS
ABS_VAR_INT
ABS_VAR_FLOAT

Control flows

Insofar as subprograms, scripts are organized in a systematic arrangement through which goto branches, subroutine branches, function calls and returns or cutscene area markers are executed to form control flow statements and structures. These alter the program counter most of the time affecting the top-down order all commands are fetched by. Facing off code duplication is quite recurring especially when the tasks to perform vary only in the input data, the case where a piece of code or subroutine, built once in the source, is invoked many times from various different places and returns back, as if the GOSUB statement is substituted in-place by the subroutine's body without RETURN during the control transferring, to shrink long codes and reduce the script overall size. In the last Trilogy chapter, a region of code can be marked as a nonnestable cutscene area wherein the rest of commands within SKIP_CUTSCENE_START..SKIP_CUTSCENE_END is skipped to the pressure of some key/button at the next script tick. The flow of execution can also be broken up conditionally by means of:

  • Decision-making structures (IF, IFNOT, SWITCH), which evaluate the result of one or more conditions and choose what path to follow based off the trueness or falseness of the check being tested. Been deemed the most basic tool of structured programming, IF is a bidirectional statement that proceeds with the execution of the underneath code only if the test carried out evaluates to true otherwise it transfers the control next to ENDIF instantly, unless a preceding and optional ELSE clause, establishing an alternative path, is specified. In the first Trilogy and both Stories chapters where GOTO_IF_TRUE is handled by game code, the barely used IFNOT can be deployed as a placeholder to easily invert the compare-flag, a boolean state which is set or cleared as a result of the bitwise conjunction or disjunction with the true/false state caught by a condition, applying the inversion according to the presence of the not-flag before accumulating. Logical operators make possible the connection among multiple conditions via the AND conjunction and OR disjunction giving the chance to verify if conditions are all true or if just one of them is satisfied bearing in mind that the NOT negation, inverting the boolean state of a single condition, may be supplied. Connectivity information are held by ANDOR, whose argument depicts a value in the range [1,8) or [21,28) (end-inclusive in Stories) for logical conjunction and disjunction respectively, limiting the amount of total conditions to provide to a maximum of 8 per check (the prominent intervals discrepancy also suggests NAND and NOR operators might have been a plan at some point). A value of 0 does nothing relevant functional-wise at runtime, what led developers to not compile said command in such a situation for Stories chapters and also make the argument one-based so that it effectively counts the number of commands used in a multi-condition check. The inability to create subexpressions enforces not to combine AND with OR in a check, plus evaluations are eager and therefore not short-circuited meaning all conditions are executed prior potentially branching through GOTO_IF_FALSE in the common case after the compare-flag gets processed. IF-GOTO and IFNOT-GOTO constructs are also viable to inline a bogus one-way control transferer, targeting an arbitrary location, nearby a one-condition check with no end-ing statement.
Nesting lots of IF-ELSE-ENDIF structures of one-condition checks testing the equality of the same variable against a few integer literals or string constants can add a ridiculous code redundancy and performance overhead, sorted out in the last Trilogy chapter thanks to the introduction of the SWITCH statement, a multiway statement either branching to the switch section labelled by fall-through CASE statements of which one passses a value that shall match the variable content to compare or optionally branching to DEFAULT in the worst-case scenario, each ending with a nonmandatory BREAK statement goto-ing past ENDSWITCH. On compilation, the implementation somehow mimics the pattern of a jump table sorting case label references by value to fulfil the runtime's binary search among at least 1 of 75 entries (default case aside);
  • Looping structures (WHILE, WHILENOT, REPEAT), which repeatedly execute a block of code certain number of times or by constantly and successfully evaluating a check. The only condition-controlled loop statement featured is the widespread WHILE, a cyclical IF statement as well as IFNOT is for WHILENOT, repeating the embedded code over and over again if the verified check is true or till it becomes false when reaching ENDWHILE. Alongside well-known constructs the language supports a singular count-controlled structure, REPEAT-ENDREPEAT, looping some code at least once by advancing an integer variable at each iteration until the times specified (literal-only). Despite considered harmful in the programming literature for high-level programming languages, an unconditional branch is the only way to go for breaking loops beforehand and enhance paradoxically the simplistic code logic or for creating infinite loops with a backward GOTO.

Control flows intersection is, arguably, trouble-free and it's up to the writer to not ruin the code integrity, but still substatements must match the closest opening statement they belong to. Optimization is not of compiler concern meaning control flows are encapsulated as-is with no code reduction even for empty blocks, resulting in goto-es branching right after or piled up in sequence.

Subroutine structure: GOSUB

GOSUB subroutine
COMMAND
GOTO somewhere

subroutine:
COMMAND
RETURN

Cutscene area structure: SKIP_CUTSCENE_START and SKIP_CUTSCENE_END

Mission script Script multifile
// Formerly thought as MARK_CUTSCENE_START.
SKIP_CUTSCENE_START
    COMMAND
    WAIT 0
    COMMAND
// Formerly thought as MARK_CUTSCENE_END.
SKIP_CUTSCENE_END
// Formerly thought as CUTSCENE_SCROLL?
SKIP_CUTSCENE_START_INTERNAL SPECIAL_LABEL_SKIP_CUTSCENE_STARTS_0
    COMMAND
    WAIT 0
    COMMAND
SPECIAL_LABEL_SKIP_CUTSCENE_STARTS_0:
SKIP_CUTSCENE_END

Decision-making structures: IF and IFNOT

Mission script Script multifile
IF COMMAND
    COMMAND
ELSE
    COMMAND
ENDIF
ANDOR 0
COMMAND
GOTO_IF_FALSE SPECIAL_LABEL_IFS_ELSE_0
    COMMAND
    GOTO SPECIAL_LABEL_IFS_0
SPECIAL_LABEL_IFS_ELSE_0:
    COMMAND
SPECIAL_LABEL_IFS_0:
Mission script Script multifile
IF COMMAND
AND NOT COMMAND
    COMMAND
ENDIF
ANDOR 1
COMMAND
NOT COMMAND
GOTO_IF_FALSE SPECIAL_LABEL_IFS_1
    COMMAND
SPECIAL_LABEL_IFS_1:
Mission script Script multifile
IFNOT COMMAND
OR NOT COMMAND
    COMMAND
ENDIF
ANDOR 21
COMMAND
NOT COMMAND
GOTO_IF_TRUE SPECIAL_LABEL_IFS_2
    COMMAND
SPECIAL_LABEL_IFS_2:
Mission script Script multifile
IF COMMAND GOTO somewhere
ANDOR 0
COMMAND
GOTO_IF_TRUE somewhere
Mission script Script multifile
IFNOT COMMAND GOTO somewhere
ANDOR 0
COMMAND
GOTO_IF_FALSE somewhere

Decision-making structure: SWITCH

Mission script Script multifile
VAR_INT check
SWITCH check
    CASE 0
        COMMAND
        BREAK
    CASE 1
    CASE 3
        COMMAND
        BREAK
    CASE 2
        COMMAND
        BREAK
    CASE 4
    CASE 6
    CASE 5
    CASE 7
        COMMAND
        //BREAK
ENDSWITCH
SWITCH_START check 8 FALSE SPECIAL_LABEL_SWITCHES_0 0 SPECIAL_LABEL_SWITCHES_CASE_0_0 1 SPECIAL_LABEL_SWITCHES_CASE_1_0 2 SPECIAL_LABEL_SWITCHES_CASE_2_0 3 SPECIAL_LABEL_SWITCHES_CASE_1_0 4 SPECIAL_LABEL_SWITCHES_CASE_3_0 5 SPECIAL_LABEL_SWITCHES_CASE_3_0 6 SPECIAL_LABEL_SWITCHES_CASE_3_0
SWITCH_CONTINUED 7 SPECIAL_LABEL_SWITCHES_CASE_3_0 -1 SPECIAL_LABEL_SWITCHES_0 -1 SPECIAL_LABEL_SWITCHES_0 -1 SPECIAL_LABEL_SWITCHES_0 -1 SPECIAL_LABEL_SWITCHES_0 -1 SPECIAL_LABEL_SWITCHES_0 -1 SPECIAL_LABEL_SWITCHES_0 -1 SPECIAL_LABEL_SWITCHES_0 -1 SPECIAL_LABEL_SWITCHES_0
SPECIAL_LABEL_SWITCHES_CASE_0_0:
    COMMAND
    GOTO SPECIAL_LABEL_SWITCHES_0
SPECIAL_LABEL_SWITCHES_CASE_1_0:
    COMMAND
    GOTO SPECIAL_LABEL_SWITCHES_0
SPECIAL_LABEL_SWITCHES_CASE_2_0:
    COMMAND
    GOTO SPECIAL_LABEL_SWITCHES_0
SPECIAL_LABEL_SWITCHES_CASE_3_0:
    COMMAND
    //GOTO SPECIAL_LABEL_SWITCHES_0
SPECIAL_LABEL_SWITCHES_0:
Mission script Script multifile
{
    LVAR_INT check
    SWITCH check
        CASE -2
        CASE -1
            COMMAND
            BREAK
        CASE 1
        CASE 2
            COMMAND
            BREAK
        CASE 0
        DEFAULT
            COMMAND
            //BREAK
    ENDSWITCH
}
SWITCH_START check 5 TRUE SPECIAL_LABEL_SWITCHES_DEFAULT_1 -2 SPECIAL_LABEL_SWITCHES_CASE_0_1 -1 SPECIAL_LABEL_SWITCHES_CASE_0_1 0 SPECIAL_LABEL_SWITCHES_DEFAULT_1 1 SPECIAL_LABEL_SWITCHES_CASE_1_1 2 SPECIAL_LABEL_SWITCHES_CASE_1_1 -1 SPECIAL_LABEL_SWITCHES_1 -1 SPECIAL_LABEL_SWITCHES_1
SPECIAL_LABEL_SWITCHES_CASE_0_1:
    COMMAND
    GOTO SPECIAL_LABEL_SWITCHES_1
SPECIAL_LABEL_SWITCHES_CASE_1_1:
    COMMAND
    GOTO SPECIAL_LABEL_SWITCHES_1
SPECIAL_LABEL_SWITCHES_DEFAULT_1:
    COMMAND
    //GOTO SPECIAL_LABEL_SWITCHES_1
SPECIAL_LABEL_SWITCHES_1:

Looping structures: WHILE and WHILENOT

Mission script Script multifile
WHILE COMMAND
    COMMAND
ENDWHILE
SPECIAL_LABEL_WHILES_A_0:
ANDOR 0
COMMAND
GOTO_IF_FALSE SPECIAL_LABEL_WHILES_B_0
    COMMAND
    GOTO SPECIAL_LABEL_WHILES_A_0
SPECIAL_LABEL_WHILES_B_0:
Mission script Script multifile
WHILE COMMAND
AND NOT COMMAND
    COMMAND
ENDWHILE
SPECIAL_LABEL_WHILES_A_1:
ANDOR 1
COMMAND
NOT COMMAND
GOTO_IF_FALSE SPECIAL_LABEL_WHILES_B_1
    COMMAND
    GOTO SPECIAL_LABEL_WHILES_A_1
SPECIAL_LABEL_WHILES_B_1:
Mission script Script multifile
WHILENOT COMMAND
OR NOT COMMAND
    COMMAND
ENDWHILE
SPECIAL_LABEL_WHILES_A_2:
ANDOR 21
COMMAND
NOT COMMAND
GOTO_IF_TRUE SPECIAL_LABEL_WHILES_B_2
    COMMAND
    GOTO SPECIAL_LABEL_WHILES_A_2
SPECIAL_LABEL_WHILES_B_2:

Looping structure: REPEAT

Mission script Script multifile
VAR_INT steps
REPEAT 4 steps // 0 or lesser still implies 1 step.
    COMMAND
ENDREPEAT
SET_VAR_INT steps 0
SPECIAL_LABEL_REPEATS_0:
    COMMAND
    ADD_VAL_TO_INT_VAR steps 1
// Here ANDOR is accidentally missing in Trilogy.
IS_INT_VAR_GREATER_OR_EQUAL_TO_NUMBER steps 4
GOTO_IF_FALSE SPECIAL_LABEL_REPEATS_0
Mission script Script multifile
{
    LVAR_INT steps
    REPEAT 8 steps
        COMMAND
    ENDREPEAT
}
SET_LVAR_INT steps 0
SPECIAL_LABEL_REPEATS_1:
    COMMAND
    ADD_VAL_TO_INT_LVAR steps 1
IS_INT_LVAR_GREATER_OR_EQUAL_TO_NUMBER steps 8
GOTO_IF_FALSE SPECIAL_LABEL_REPEATS_1

Infinite looping structure: backward GOTO

loopstart:
WAIT 0
COMMAND
GOTO loopstart

Multiscripts

The whole GTA series started as a world subdivided into several levels, each one per urban area spread across fewer cities, albeit 3D era titles has got a single-leveled design covering the entire game scene. Every level is shipped with a main script and a number of ancillary script files, simply called multiscripts, which are bundled inside a folder bearing the same name as the main script filename without extension. The robust scripting engine allows more scripts to cooperate simultaneously at runtime to let writing codes in a multithreading fashion but with no actual concurrency. A script is a unit of execution which, upon starting, is enqueued to a list of active scripts as long as an explicit termination, moving the script back to a list of idle scripts, occurs with TERMINATE_THIS_SCRIPT while TERMINATE_ALL_SCRIPTS_NAMED halts all instances of a script if the specified name, definitely unique to avert compiler complains, was ever set by SCRIPT_NAME. Running scripts are processed sequentially in a non-prioritized order and are paused pending one of the next script ticks using WAIT to delay the script execution of an instance some milliseconds ahead or at the earliest opportunity if 0.

This section is incomplete. You can help by fixing and expanding it.

Main script and Main extensions

This section is incomplete. You can help by fixing and expanding it.

Scripts and Streamed scripts

This section is incomplete. You can help by fixing and expanding it.

Subscripts and Mission scripts

This section is incomplete. You can help by fixing and expanding it.

Tools

GTA Net GTAForums: SCRambl, first ever attempt for a now discontinued third-party compiler by Deji
GTA Net GTAForums: GTA3script Toolchain, second and still work-in-progress attempt for an unofficial compiler by Link2012

External links

GTA Net GTAForums: Learn GTA3script in Y minutes, tutorial for deep diving into the language in a short time by Link2012
GTA3script Language Specifications, community-based specifications of the language led and maintained by Link2012

See also

SCM language III/VC definitions