123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390 |
- <P><PRE>
- **
- ** GCSx language reference
- ** Original (incomplete) revision: August 22, 2006 Alexis Janson
- **
- </PRE></P>
- <P>
- TODO: constants, states, libraries w/::, (true/false/)query/nothing, comments, #names, with (and this), source, void, string subscripting<BR>
- future: extend (inheritance), import, public vs private including default<BR>
- built-in methods, properties, functions
- how to enable/disable features like automatic-stringification-of-entity-names
- array<->hash conversion?
- debug cmds (debug, trace, breakpoint, watch)
- </P>
- <H1>Introduction</H1>
- <P>
- The goal of this document is to describe all functionality of the GCSx scripting language in plain english. This document will not define language structure in a technically exact manner, but should suffice to explain it in a complete and unambiguous capacity. It is not intended to be a tutorial and assumes the reader is familiar with basic programming concepts.
- </P>
- <H1>Terminology</H1>
- <P><UL>
- <LI>Script: A program, without any in-game state information attached.
- <LI>Entity: An instance of a script, with it's own state information such as a stack and variables. Multiple entities can exist running a single script.
- <LI>Sprite: An on-screen graphical representation, often associated one-to-one with an entity.
- <LI>Object: Any in-game resource that you can manipulate in a script, such as a scene, an entity, or a sprite.
- <LI>Object Type: A type of object, such as script, scene, entity, or entities running a specific script.
- <LI>Script Type: A specific subset of object types, a script type matches all entities running a specific script.
- </UL></P>
- <H1>Basic Code Elements</H1>
- <H2>Keywords</H2>
- <P>The following keywords are reserved for current, planned, or potential use:</P>
- <P><PRE>all
- all_other
- and
- array
- as
- break
- case (unused)
- const
- continue
- default
- do
- else
- end
- extend
- false
- float
- for
- foreach
- global
- hash
- if
- import
- in
- int
- is
- local
- query
- not
- nothing
- obj_* (any word beginning with 'obj_')
- or
- private
- public
- repeat
- reply
- restart
- return
- source
- state
- static (unused)
- str
- switch (unused)
- this
- to
- true
- until
- var
- void
- while
- with
- xor</PRE></P>
- <P>All other words can be used as identifiers. Some words may be removed off this list once the language stabilizes. Keywords are not case-sensitive.</P>
- <H2>Identifiers</H2>
- <P>An identifier is a sequence of letters, numbers, and underscores, and cannot begin with a number. An identifier cannot match a built-in keyword. Identifiers are not case-sensitive. Identifiers are used to represent all user-defined items such as variables, functions, etc. as well as built-in variables, functions, etc.</P>
- <H1>Data Types</H1>
- <P>Each data type has an associated empty value, which is used whenever a variable of that type is uninitialized, or a result of that type is needed, but could not be generated. Occasionally the concept of an "undefined" value will be used- this simply means a value of the appropriate type but unknown content. For example, an undefined integer would still be an integer, but it could be any valid integer within the entire range of all possible integers.</P>
- <H2>Integers</H2>
- <P>Integers are denoted with the keyword 'int'. Integers can be written in hexadecimal as well, with the 0x prefix- 0xABCD. Integers are stored using exactly 32 bits. The empty integer value is 0.</P>
- <H2>Floating-point</H2>
- <P>Floating-point numbers are denoted with the keyword 'float'. The empty floating-point value is 0.0. Scientific notation is not currently supported. Floating-point numbers currently have a non-defined level of precision.</P>
- <H2>Strings</H2>
- <P>Strings are a primitive data type, denoted with the keyword 'str'. A string can be any length and contain any non-NUL characters. Strings do not currently support Unicode.</P>
- <P>Strings are written between "double-quotes". Use \t to represent a tab, \n for a newline, \\ for a backslash, and \" to enclose a double-quote. All other characters except NUL (ASCII 0) can be inserted directly.</P>
- <P>The empty string value is "".</P>
- <H2>Object Types</H2>
- <P>Each type of game resource that can be referenced from within a script is called an object. However, an object is not a data type- only a specific type of resource or object is a data type. In otherwords, a scene is a data type, but there is no generic catchall object data type. This is similar to how you cannot simply have a class variable in C++, but must specify which type of class it is.</P>
- <P>Object types that currently exist as data types:</P>
- <P><UL>
- <LI>obj_scene
- <LI>obj_sprite
- <LI>obj_entity
- </UL></P>
- <P>These data type keywords were chosen over shorter names (without 'obj_') to avoid conflicts with desirable variable names and because an average script will not need to refer to these data types explicitly on a regular basis.</P>
- <P>The empty object value is represented by the keyword 'nothing'. Using a 'nothing' object under most circumstances simply fails to do anything. Specific results are covered for each operator and function that works with objects.</P>
- <P>All script names can also be used as object types- these are basically subtypes of the broader obj_entity type and are referred to as "Script Types". When using a script type, it must be preceded by another data type keyword (such as 'obj_entity' or 'local') or the keyword 'as' or 'is' to clarify it is meant as an object type name and not a regular identifier. You can also enclose a script type in 'single quotes' to clarify it is a script type. This is the only way to refer to script names that contain spaces or do not match normal identifier rules. Also note that script type names are not case sensitive.</P>
- <H2>Arrays</H2>
- <P>An array must be of a specific data type previously mentioned, combined with the 'array' keyword. For example, 'int array' or 'array obj_scene'. An array contains zero or more of the specified data type, and dynamically grows as necessary.</P>
- <P>Attempting to read from a non-existant array location simply returns an empty value of the appropriate type. Attempting to write to a non-existant array location expands the array to the required size, filling any interim elements with empty values.</P>
- <P>Array literals are written as comma-separated lists between [ brackets ]. For example, [ 0, 1, 2 ]. Indexing into an array also uses brackets, containing a numeric index. For example, array_name[1]. Nested or multidimensional arrays are not natively supported.</P>
- <P>The empty array type is [ ], for any array type.</P>
- <H2>Hashes</H2>
- <P>A hash, or associative array, must be of a specific data type previously mentioned, combined with the 'hash' keyword. For example, 'str hash' or 'hash float'. A hash contains zero or more of the specified data type, referenced using arbitrary user-defined strings. Hash keys are case-sensitive.</P>
- <P>Attempting to read from a non-existant hash element simply returns an empty value of the appropriate type. Attempting to write to a non-existant hash element creates that element.</P>
- <P>Hashes cannot be written as literals. Accessing an individual hash element uses brackets, containing a string index. For example, hash_name["color"]. Nested or multidimensional hashes are not natively supported.</P>
- <P>The empty hash type is an empty hash with no elements.</P>
- <H2>Variant</H2>
- <P>Variants can contain any of the previously mentioned data types, denoted with the keyword 'var'. Variants can contain hashes or arrays, but hashes and arrays cannot contain variants. However, a variant can be restricted to containin hashes or arrays only by use of the type 'var array' or 'var hash'. This means that the variant can contain any specific type of array (or hash).</P>
- <P>In usage, a variant is somewhat restricted as you must declare it's type whenever it is used in an ambiguous context. For example, concatenating two variants will simply use the variants as strings, and assigning a variant to another variable will simply convert to that variable's type. However, adding two variants will require you to first declare one variant as floating point or BOTH variants as integers. (this is done using the 'as' keyword)</P>
- <P>Variants follow normal type conversion rules when possible; when not possible, empty values are used. An empty variant defaults to the integer 0, or if a hash or array variant, an empty integer hash or array.</P>
- <H2>Type conversion</H2>
- <P>Floating-point numbers automatically convert to integers and vice-versa as needed. (when an operation is performed between a floating-point and an integer, the result will be floating-point.)</P>
- <P>Both numeric types automatically convert to strings as needed. Strings manually convert to numbers using the 'as' operator, although a failed conversion will simply result in 0 or 0.0. When converting strings to numbers, whitespace is discarded off the front of the string, and any unrecognized characters are ignored on the end of the string. Exponents and non-base-10 numbers are not supported.</P>
- <P>An array or hash containing integers, floating-point numbers, or strings will automatically convert to the same structure containing a different type. The 'as' operator must be used if converting from strings to numbers.</P>
- <P>Different script object types can be freely and automatically converted to the broader obj_entity data type. obj_entity objects can be converted to more specific script object types by request, although if the object does not reference an object of the specified script, it will revert to a 'nothing' reference. These same rules apply to arrays or hashes containing obj_entity or script object types.</P>
- <P>No other type conversion between KNOWN types will be performed 'automatically'- if the compiler detects such an attempt, an error will result. For example, using a string where a number is expected without using 'as', or using a obj_scene where an obj_entity is required.</P>
- <P>Some situations involve UNKNOWN types, however- either due to use of variants, or unknown function parameters or return-values when communicating between entities. In these cases, conversion of strings to numbers is automatic at runtime, and if a standard conversion cannot be made, an empty value of the proper type is created instead, at runtime.</P>
- <H2>Booleans</H2>
- <P>Any value can be treated as a boolean value. Numeric 0, 0.0, "", an empty/nothing object, an empty hash, or an empty array are treated as false. All other values are treated as true. Specifically, "0" (a string) or [ 0 ] (an array containing zero) are true values.</P>
- <P>Built-in keywords 'true' and 'false' are equal to 1 and 0. All boolean operations, even if derived from other types or values, will result in an integer 1 or 0.</P>
- Code Structure
- With a few technical exceptions, scripts are a series of commands and blocks. A command is a single 'statement' of some sort, and can be terminated using a semicolon ; if desired. However, all commands are also terminated with end-of-line.
- Anywhere a single command can be used, a block of code may also be used. A code block is zero or more commands contained within { braces }. Braces automatically count as command terminators as well, if necessary.
- Functions
- Functions are defined by a data type, an identifier, an optional list of parameters, and a block of code-
- <PRE>int function(str a, str b) {
- // code goes here
- }</PRE>
- The parenthesis surrounding the parameter list are optional. A function with no parameters can be declared using () for a blank parameter list, or by simply not including a parameter list.
- Functions are called, in their simplest form, by using the identifier that represents the function, optionally followed by any parameters, optionally enclosed in parenthesis. The following are all legal function calls-
- <PRE>functionA
- functionB 1
- functionC 1, 2
- functionA()
- functionB(1)
- functionC(1, 2)</PRE>
- The compiler will generate an error if you do not use the proper number and type of parameters for a function. Built-in functions are called using the same syntax. Functions can also informally be referred to as members.
- The data type before a function name is called it's return type, and is the type of value that results when the function is called from within an expression. For example, a function that returns int can be used in an expression anywhere an integer value is allowed, and will be called at that time- the value it produces will then be used in the expression.
- A function returns a value by using the 'return' keyword, followed by the value to return. This immediately exits the function, returning the given value. (code after 'return' will never run- see the 'reply' keyword for an alternate that works in some situations.) If the end of the function is reached without a 'return' command, an empty value is returned. This can also be done if 'return' is used by itself, without a value.
- Variables
- Variables are defined by a data type with an optional scope modifier, an identifier, and an optional assignment-
- <PRE>local int variable = 10</PRE>
- Variables declared as 'local' can only be accessed from within the current block of code and any sub-blocks within it. This does not apply to functions called from within a block- only sub-blocks actually contained within a block can access that block's local variables.
- Local variables declared outside of any block are local to the entire script- any block of code, including functions, can access them. These variables are also the only variables that can be accessed by outside entities.
- Variables can also be declared as 'global'- these variables can be accessed by any script, and maintain only a single value shared by all scripts that access that variable. You must declare global variables in each script that wishes to access them, and you must always declare them with the same data type.
- Variables default to 'local' if not specified.
- Local variables outside of all blocks can be accessed by other entities, and are informally referred to as properties. You may optionally declare a local variable as 'private' to prevent it from being accessed by outside entities. This keyword has no effect on variables within blocks and may not be used with global variables.
- Note that variables and functions within the same script cannot share names.
- Expressions
- Expressions are anything that results in a value. Expressions use operators to combine literals, variables, and function calls into a single final result. Expressions can be as simple as '1' or more complex operations such as 'a + (b * 2 - sqrt(c))'. As shown, an expression is often made up of several smaller sub-expressions.
- Most operators take two expressions and return a single result; a few operators, known as unary operators, take a single expression and return a single result.
- Expressions are evaluated left-to-right, respecting operator precedence-
- Precedence 1: Parenthesis<BR>
- Precedence 2: . as<BR>
- Precedence 3: + - ~ not (all unary)<BR>
- Precedence 4: * / %<BR>
- Precedence 5: + -<BR>
- Precedence 6: << >><BR>
- Precedence 7: & | ^<BR>
- Precedence 8: #<BR>
- Precedence 9: < > <= >=<BR>
- Precedence 10: == <> != is<BR>
- Precedence 11: and or xor<BR>
- Precedence 12: =
- Parenthesis: These work as expected, overriding all other operator precedence.
- '.': The dot . operator accesses a property or method of an object. More details are in the section covering objects.
- 'as': 'as' converts between data types. The first operand is temporarily converted to the second type, which must be a data type such as 'str' or 'obj_sprite array', or even a script type. When using 'as' on known types, only valid conversions are permitted. When using 'as' on unknown types such as variants, an unsupported conversion will result in an empty value of the requested type.
- '+', '-' unary: Unary + and - simply represent the positive and negative of a numeric value. + is essentially a no-op, whereas - returns the negation of a value.
- '~' unary: Tilde ~ returns the binary negation of an integer value, flipping all bits.
- 'not' unary: 'not' returns the logical (boolean) negation of a value, returning true if false, or false if true.
- '*', '/', '+', '-': These basic mathematical operations work as expected, operating on two numeric values. '/' will produce an integer result unless at least one value involved is floating-point- if you divide two integers, the answer will be rounded down. Dividing by zero results in an undefined value.
- '%': Modulo % returns the remainder after an integer division. Floating-point values are converted to integers before the operation. Modulo by zero results in an undefined value.
- '<<', '>>': Bit-shift operators take an integer and shift it left or right a given number of bits. Floating-point values are converted to integers first. Shifting right does not sign-extend.
- '&', '|', '^': Bit operators return the binary AND &, OR |, or XOR ^ of two integer values.
- '#': Concatenation # takes two strings and returns a single string containing the two strings joined.
- '<', '>', '<=', '>=', '==', '!=', '<>': Relational operators compare two values and return true (1) if they compare favorably or false (0) if they do not. In order, the operators are less-than, greater-than, less-than-or-equal, greater-than-or-equal, equal-to, and not-equal-to. Not-equal-to can be represented by either != or <>. Two values of different types are converted to the same type before comparison- integers upgrade to floating-point, and numbers upgrade to strings. You cannot compare arrays or hashes. Objects of the same type can only be compared using equal-to and not-equal-to. String comparison is not case-sensitive.
- 'is': 'is' compares data types. The left operand is always a value, but the second may be a value or an actual data type such as 'int'. If the data types match exactly, the result is true (1) otherwise the result is false (0). No conversion is done on either value before comparing. 'var' types are not considered distinct data types for this purpose- the actual underlying type contained within the variant is used.
- 'and', 'or', 'xor': Logical operators return the logical 'and', 'or', or 'xor' of two boolean values, returning true (1) or false (0).
- '=': Assignment = is used to assign a new value to an existing variable or array or hash subscript. Although often used as a command on it's own line, assignment may also be used within a larger expression, and returns the variable being assigned to. Multiple assignments in a row are evaluated from right-to-left- 'a = b = c = 3' will assign 3 to all three variables. The left operand to = must always be a variable or array or hash subscript into a variable.
- Control Structures
- end, return
- 'end' very simply ends the script entirely. 'return' is more friendly when used in a function, returning to the previous place within the script's code. (see Functions for using 'return' with a return type, and see 'reply' for another similar keyword)
- if, else
- <PRE>if (a == 5) {
- doFive()
- }
- else if (a == 10) {
- doTen()
- }
- else {
- doOther()
- }</PRE>
- 'if' must be followed by an expression, optionally in parenthesis, then a command or block of code. This code is executed if and only if the expression is true. This may then be folowed by 'else' and another command or block of code that will be executed if and only if the expression is false. To chain multiple conditions, simply write 'else if'.
- repeat
- <PRE>repeat {
- if (leftPressed()) doStuff()
- }</PRE>
- 'repeat' is used to create an infinite loop- the command or block of code after 'repeat' will be repeated indefinately until stopped from within or by an outside force. This is designed to be used for "main" or "idle" loops that run every game cycle.
- This loop specifically differs from a manual infinite loop (such as 'while (1) { }') because it gaurantees that the loop will only run a single time each game cycle, even if the programmer does not insert their own delay. If you use other looping methods, you should be careful to ensure that your code includes a voluntary delay if you wish the loop to only execute once per cycle.
- for
- <PRE>for (i = 1 to 10) {
- output(i)
- }</PRE>
- 'for' creates a simple counting loop. 'for' is followed by a special assignment optionally enclosed in parenthesis, then a command or block of code. This assignment must consist of a variable identifier, '=', a starting value, 'to', and an ending value. No other syntax is allowed, and the variable must already exist.
- The variable will be initialized to the starting value, the loop will execture, the variable will increase or decrease by one, and then if the variable has not yet passed the ending value, the loop will repeat. In the given example, i will be equal to 11 when the loop exits. The starting and ending values are stored when the loop starts and will not be recalculated during each loop. A 'for' loop can only increase or decrease by one. Other more complex loops must be made using 'do', 'while', and 'until'.
- foreach
- <PRE>foreach (i in iArray) {
- output(i)
- }</PRE>
- 'foreach' loops through all values in an array or hash. 'foreach' is followed by a special expression optionally enclosed in parenthesis, then a command or block of code. This expression must consist of a variable identifier, 'in', and an expression that evaluates to a hash or array. No other syntax is allowed, and the variable must already exist.
- For an array, the variable will be assigned each value within the array in turn, starting with the first value. The loop will repeat for each possible value. Modifying the variable within the loop will modify the original array element. Modifying the array directly from within the loop will result in indeterminate behavior.
- For a hash, the variable will be assigned the string indexing each existing hash entry in turn, in arbitrary order. The loop will repeat for each possible value. Modifying the variable within the loop will have no effect. Modifying the hash directly from within the loop will result in indeterminate behavior.
- do, while, until
- <PRE>do {
- someStuff()
- } while (a < 10)</PRE>
- These keywords allow you to construct loops that loop based on your own conditions. These loops can be constructed in one of two ways. Prefix loops are constructed with the 'while' or 'until' keyword, then a condition optionally in parenthesis, then a statement or block of code. Postfix loops are constructed with the 'do' keyword, then a statement or block of code, then the 'while' or 'until' keyword, then a condition optionally in parenthesis.
- A prefix loop checks the condition, then executes the code, then repeats. A postfix loop executes the code, then checks the condition, then repeats. A 'while' loop repeats as long as the condition is true. An 'until' loop repeats as long as the condition is false.
- break, continue, restart
- These keywords are used for specialized loop control, and can appear in any for, foreach, do, while, until, or repeat loop.
- 'break' immediately exits the current loop, resuming execution at the code immediately following.
- 'continue' immediately jumps to the end of the loop but does not exit. Any loop variable (for and foreach loops) is updated, and the loop condition is then checked as normal and the loop may or may not repeat.
- 'restart' immediately jumps to the beginning of the loop. No condition is checked and no loop variable is updated. 'continue' and 'restart' are functionally identical for a repeat or infinite loop.
- All three keywords may optionally be followed by a loop name. Loops may be named by placing a label immediately preceding the keyword that starts the loop. A label consists of an identifier, followed by a colon. When using a keyword with a label, it causes the keyword to refer to a specific loop, instead of the innermost loop. Labels must, of course, refer to loops you are currently within. An example-
- <PRE>outer:
- while (y < 100) {
- x = 0
- while (x < 100) {
- x = x + 1
- if (check(x, y)) break outer
- }
- y = y + 1
- }</PRE>
- Objects
- Objects represent game resources and elements, including sprites and entities. Object references can be stored in variables of the appropriate type, and then acted upon by accessing methods and properties of those objects. Methods are conceptually interchangable with functions, and properties with variables, except that methods and properties are part of the object being referenced, instead of the current script/entity.
- All built-in object data types begin with obj_, such as obj_sprite or obj_entity. You can also use script names as custom object types- this is called a "script type". When doing so, you must precede them with obj_entity or another data type to clarify they are meant as an object type. You can, alternatively, enclose a script type in 'single quotes' to clarify it is meant as a data type. This also allows you to use non-identifier-friendly script names.
- At the simplest level, you access methods and properties of an object using the . dot operator. The left side of the . is the object reference, and the right side of the . is the identifier that matches the method or property you wish to access. This construct can then be used anywhere a variable (if a property) or a function (if a method) would be used, and in exactly the same way-
- <PRE>mySprite.x = 10
- enemyEntity.doStuff("flag")</PRE>
- All built-in object types (other than obj_entity) have a predefined, built-in set of methods and properties that you are limited to using. obj_entity types as well as script types allow you to access any method or property you wish to define- however, if the method or property does not exist within the referenced entity, nothing happens and/or an empty value results.
- For built-in object types, this should be sufficient to cover all cases (except for 'with', described later), but entities have several additional layers of complexity.
- Matching Entities
- Instead of using a variable or other reference to a specific entity, you can also use a string on the left side of the dot operator. This is then treated as an entity NAME. (which can be different from the name or type of script the entity is running) If calling a method, that method is called for all matching entities; if setting a property, all matching entities are modified. If reading a property, however, only one matching entity can be read (chosen arbitrarily), and of course if no matching entities are found, an empty value is used.
- The string may also contain * as a wildcard, to match zero or more of any characters, in order to perform more specialized searches. Also, note that this search is not case-sensitive. Also note that the search may match the current entity.
- You may also use 'as' to restrict the script type of matched entities. For example, '"bob" as Enemy' will match all entities named "bob", but only if they are of the 'Enemy' script type. (i.e. running the script named 'Enemy'.)
- You cannot assign a string to an obj_entity variable or a script type variable- you can only use them in this way with the dot operator. Of course, you can simply store the string in a string variable and use that variable with the dot operator if desired.
- Be careful with this syntax- it is intended for simple operations and does not work as may be expected on more complex ones. For example, '"enemy".x = "enemy".x + 1' will not properly increase the x property of every matching entity- it will read x from a single entity, and then assign that value (plus one) to every matching entity. Similar cavaets apply to expressions such as '"enemy".go("enemy".direction)'. For these types of expressions, you should use the 'with' construct.
- Note that this syntax can only find entities within the current scene or within global entities- entities on other scenes are "hidden" from this search.
- Also note that if an identifier is used on the left side of . that is unrecognized, the compiler can automatically treat it as a string to match in this way. This means that, if there is no identifier named bob, then bob.x() is treated as "bob".x() by the compiler. This is an optional feature, and may or may not default to on.
- Entity Properties
- Accessing entity properties is simple- simply follow an entity reference (or string) with a dot, and the name of a property. If the property exists, you will be able to read from or assign to it. If it does not, then reading it will produce an empty value, and assigning to it will do nothing.
- Entity Methods
- Accessing entity methods is similar- follow an entity reference (or string) with a dot, and the name of a method, optionally followed by any parameters. If the compiler can't determine whether you mean to call a method or access a property based on your syntax and/or the type of object, it will assume you mean to access a property. You can simply add an empty parameter list () to clarify this situation if needed.
- If a noted method does not exist, then nothing happens. If you use the return value of a non-existant method, an empty value will be used. If the noted method does exist, but you provide the wrong number or type of parameters, all possible conversions will be made, and any missing values will use empty values.
- Special Entities
- You can use the keyword 'all' to access all entities on the current scene and all global entities. You may restrict this with 'as' just as you would restrict string-based searches. 'all' is exactly equivalent to using "*" to search for all entities, but is cleaner and more optimized. 'all' may not be stored in a variable. 'all' also includes the current entity- use 'all_other' to access every entity except the current.
- You can use the keyword 'this' as a reference to the current entity. 'this' may be assigned to a variable.
- The keyword 'nothing' refers to no entity, and can be assigned to any obj_entity or script type variable. Using 'nothing' with the dot operator is technically valid syntax, but will have no useful effect.
- Optimizing Entity Access
- The compiler can optimize your access to entity methods and properties better if it knows what type of entity you are accessing. For this reason, using specific script types for variables is better than using obj_entity variables when you know you will only be storing references to one script type. When that is not feasible, using 'as' is almost as efficient-
- <PRE>obj_entity myEntity = findEntity("bob")
- (myEntity as bobScript).doStuff()</PRE>
- Of course, if you specify the incorrect type with 'as', then the method or property access will have no effect, as the process of attempting to change the entity reference to the more specific type will turn it into an empty reference. ('nothing')
- Return Values from Entity Methods
- When you access another entity's methods as a standalone command outside of an expression, both entities are free to continue running their script separately. Neither script will require the other to finish in order to continue. (however, see Concurrency for more details on exactly how this works)
- However, if you use an entity's method within an expression, the original script will halt at that point and wait for the requested entity to finish the entire method and return a value, so that the value can be used in the expression. This may cause a delay if the requested entity's method takes more than one game cycle to run. Improper coding may even lead the original script waiting indefinately for a value that never comes.
- Also note that if you use 'all' or a string to call a method within an expression, no more than one matching entity will have it's method called. Any remaining matches will be ignored.
- The entity method can use the 'reply' keyword at any time to return a value without actually halting. 'reply' is exactly the same as 'return', except it does not exit the function or method, but instead continues onward; it does, however, return a value to the original waiting script.
- Using 'reply' in a function that was not called as a method has no effect. 'reply' must be used from within the original method function- you cannot chain to another function and have that function use 'reply' to any effect.
- Concurrency
- (copy from outline)
|