Field Data Types
|
- Data Types should not be confused with Archetypes. An archetype is a descriptor for a class, which is a collection of different fields.
Data Types are the descriptors for individual fields. Data Types are also used to declare variables.
Overview
Datatypes are used in the CLI, and in HeroScript. Some respective datatypes are not entirely consistent. Please see below for more information.
Description
- When a field is created via the CLI, it must be declared as to what type of data it will contain.
- Variables also have datatypes. There are two ways to declare a variable in HeroScript
- Immediately declare its type
- Declare it with the VAR keyword, in which case its type will not be assigned until the first time that it is set to a particular value, and then that type will become its permanent datatype.
Data Types
TODO: Add description of the FSGUID and RawData data types.
CLI | HeroScript equivalent | Description |
NONE | -- | For more information, see the NONE section below. |
ARRAY | ARRAY | Maintains a fixed length group of values of a given type. This is like LIST but much more efficient -- it specifies exactly how many elements it has to be ahead of time (and this cannot change). The default values will be the default for whatever type is contained within the array. CLI Syntax: ARRAY 5 OF STRING . HeroScript syntax: groovy as array[5] of string loop i from 1 to groovy.sizeX
|
-- | ASSOCIATION | A complex datatype which can only be used to declare variables, and not field types. An association has three sub data elements, which are accessed as though they were subfields: source , associationtype , and target , all of which are set to NULL when a variable is created. Possible values for the Associationtype data element are defined in the DOM. For more information, see Associations.
|
BOOLEAN | BOOLEAN | Logical field which can be set to "true" or "false". The default is false. |
CUBIC | CUBIC | Maintains a fixed sized three-dimensional group of a given type. This is like a TABLE, but with three dimensions. The default value will be the default for whatever type is contained within the group. CLI Syntax: cubic 4 5 6 of string . HeroScript syntax: x as cubic[4,5,6] of string
|
ENUM | ENUM | A field of this type will contain a value that references one constant on an enumerated list of constants (called, interestingly enough, the "enumerator list"). The default value is the first value of the enumeration, if it has values. Otherwise it is an invalid value. Please see the section on Enumeration for more info. |
FLOAT | FLOAT | This is a standard 32-bit floating point value, such as 0.0, 2.6, 3.2037. Leading zeroes are not required. The default value is 0.0 |
GUICONTROL | -- | For defining GUIXML elements. |
CLASS <classname> |
CLASS <classname> |
This is a field which contains a class (and thus that class's fields). In this way it is possible to have any arbitrary complex nested structure in various classes. For more information, please see the section below on subclasses. Default is the default of all the individual subfields |
ID | ID | This field stores a numerical identifier which corresponds to some sort of definition, node or prototype, etc. Although it is an integer value, it can be a very large one (UINT - unsigned 64-bit integer) so it is necessary to use fields/variables of type ID for all Global Unique Identifiers (GUID), as an integer will not do. The default value is 0. |
INTEGER | INTEGER | A signed 64-bit integer which can be positive or negative. The default value is 0. |
LIST OF <typename> |
LIST OF <typename> |
Please see the section on List Information. Defaults to an empty list. |
LOOKUPLIST | LOOKUPLIST | A key/pair list. Please see the section on List Information. Defaults to an empty list. |
NODEREF | NODEREF | Declares a pointer to a node. Note that if a class is not specified, a WHERE will be needed if it is desired to access fields on the node. Defaults to no reference (NONE) |
NODEREF OF CLASS <classname> |
NODEREF OF CLASS <classname> |
Declares a noderef of a specific class, which makes it easier to access its fields. Important: A NODEREF type is a pointer to a node in the GOM, so setting a variable of type NODEREF is just changing what it points to - not creating a node or copying its values. Defaults to an invalid reference (NONE) |
SCRIPTREF | SCRIPTREF | References a script. It can be set to a script name such as fallScript or test_four . Defaults to an invalid reference (NONE)
|
STRING | STRING | An unlimited-length string value, such as "this is a string" or "27" or "Michelangelo". To determine its current length via HeroScript, check <string>.length. Defaults to an empty string ("") |
TABLE | TABLE | Maintains a fixed sized two-dimensional group of a given type. Defaults to the default value of whatever type is contained within the table. CLI Syntax: table 4 5 of integer . HeroScript syntax: x as table[4,5] of integer
|
Date Time | Date Time | A type used to display or track the current date/time |
Time Interval | TimeInterval | A literal time interval is of the form HH:MM:SS.SSS where HH is the hours, MM the minutes, and SS.SSS is the seconds (the fractional part is optional). |
TIMER | TIMER | A collection of different types. Please see the TIMER section for more information. |
VECTOR3 | VECTOR3 | Has fields: x, y, and z. Can be added/subtracted to other vectors, or multiplied/divided by a float. Operations affect all fields. Default is (0,0,0). Syntax: q as vector3 . See Vector Functions
|
Memory Footprints
In HeroEngine, each datatype is a "Union" type. The normal scalar types all use the same amount of memory. Complex types use more. If given a choice between using a simple data type or a complex one, it is more efficient to use a simple type.
Conversion
Note: To convert an integer to a float, simply set it.
f as float f = 1 f = 0.3 f = .2 // Note that a leading zero is not required
There are many other options for Auto Conversion.
The NONE Data Type
There is a special keyword NONE
which is used for dealing with ScriptRef and NodeRef variables:
- The variables can be cleared by setting them to NONE
- They can be checked in an expression using the equals/not-equals operators
- A noderef will be equal to NONE if:
- It is null; or
- The noderef is invalid; or
- The node that it referred to is no longer loaded in the game.
- A scriptref will be equal to NONE if:
- It is null; or
- The script reference is invalid.
- A noderef will be equal to NONE if:
Adding classes to nodes
There are different ways of either defining the class that a node is, or of adding additional fields to that node.
- When it is created, a node is defined as a particular class, such as with
CreateNodeFromClass()
. This is its "base class".
- If a node's class is later modified, to inherit from another class, or fields are added to that class, then all existing nodes of that class will inherit the new fields.
- An existing node can have another class attached to it. This is called "glomming", and can be achieved with the
glomClass()
function in HeroScript, or commands such as CNAC (Create Node Add Class) via the CLI.
- A node can have fields of type
class
, which allow for it have subfields. These do not change or add to the classes of the node, but do allow for access to other fields via that node (see "subfields" below for more information).
It is also worth noting that while adding a class to a node will increase the number of fields available to that node, it will not add field *data* to that node. Adding the class is simply adding more locations in which data can later be stored.
If multiple classes are added to a node, and any of the classes have the same field names, then the node will only have *one* instance of that field. If it has never had the field before, the field is added with a NULL value. If it already had the field, and a new class is added which has the same field name, there is no change to that field's data on the existing node. The only difference will be that the node will then gain access to the other fields on that class which it didn't have yet.
Subfields -- Creating fields which are classes
Sometimes it may be desired to have a node which is of 1 or more classes, which also has access to other classes and fields, without being of those classes. Or, it might be desired to have a complex nesting structure where one node has many different possible types of data that it needs to keep separate, such as to have many different damage
fields which are capable of storing different data even though they're on the same node. The way this is accomplished is via subfields -- adding fields to the node which are of type class
, and thereby allowing access to those classes' fields, without affecting the data in the node's other fields.
In this way you could have any arbitrary complex nested structure in a class. For example, create a field definition:
: cfd "field_which_is_class", class "that_class_name"
Define a class which uses that field
: ccd <classholder>, asset; "field_which_is_class"
Add that created class to a node.
: mnac <node id>; <classholder>
And then it is possible to modify the node's subfields which were based on that class:
: MN <node id>; field_which_is_class.field_in_that_class_name=<value>
For a more specific example, there might be a noderef which is a pointer to a node of a nine-headed hydra. Each head can be in a different location, doing something different, and taking different amounts of damage. There are of course many different ways to accomplish this, but for the purpose of this example, one way might be create a class hydra
and as part of that class, create a field which was an array of class hydrahead
. The hydrahead
class would have its own fields such as damage
and location
. In this way, each of the nine heads would have its own field data.
: cfd heads, array 9 of class hydrahead // Create the "heads" field definition : mcdaf hydra, heads // Modify the "hydra" class to add the "heads" array : cnfc hydra // Create node ID #2, from class "hydra"
Then to access the subfields, the dot (.) connector would be used:
: mn 2; heads[1].damage=3 : mn 2; heads[2].damage=27 : mn 2; heads[4].location=(1, 3, 5)
This technique could be further extended, with subfields being defined to be of type class and having their own subfields, ad infinitum:
: mn 342; orc.arm.left.hand.damage=.5
VECTOR3 Example
Create a variable of type VECTOR3 and set its fields
// the old way v as vector3 v.x = 1.0 v.y = 2.0 v.z = 3.0 printV3(v) // or as of version 1.23 var v2 = (1.0, 2.0, 3.0)
would produce an output of:
(1.0, 2.0, 3.0)
And
printV3(v * v.y)
would result in:
(2.0, 4.0, 6.0)
(v*v) would result in an error. Vectors can only be multiplied or divided by floats, and can only be added or subtracted by other vectors.
Lookuplist Examples
ll as lookupList by string of integer ll["test"] = 3 if (ll has "test") // list uses remove <list> at <offset> remove ll entry "test" // or: remove "test" from ll .
l2 as lookuplist indexed by enum Tolkien of string l2[frodo] = "hmm" l2[bilbo] = "dork" remove frodo from l2 if (l2 has frodo) println("frodo="+l2[frodo]) .
Example field dataypes
- integer
- list of class foo
- lookup list of list of class fruit