Types of variables
There are three types of variables in the TES script language: short, long and float. According to the manual these cover the following data ranges:
Short -32,768 to 32,767 (signed integer)
Long -2,147,483,648 to 2,147,483,647 ( long signed integer)
Float 3.4E +/- 38 (float, 7 digits)
Apparently the boundaries for Long given here are only partly correct, in the TES-CS you can assign a maximum value of 2147483520 (Forum info / Argent).
Theoretically there should be string variables too, but to my knowledge these are not implemented. Unfortunately there are also no data types to store Object_Id's, which limits the power of the scripting language to a certain extent.
Variables can be grouped into local variables (valid only in the script that declares them) and global variables (valid in every script).
Note: A long global is effectively a float! In a script, local to that script a long will have a full 32 bits of precision. But used as a global, the number of bits of precision drops to 24, as when it exists globally a long is a float. Mental Elf discovered this when attempting to use "bit packing" to get 32 flags into a global long (forum info / mental elf).
A Note about Floats:
Floating point numbers in a computer are stored in a format similar to that used for scientific or engineering notation. The number is rounded off to a fixed number of significant digits, any leading or trailing zeros are dropped, and an exponent is added to indicate the correct location of the decimal or binary point.
The number 2385901045 would be stored similar to this:
2.385901x109
In fitting the number into a fixed number of bytes, we have lost the end 3 digits, so the number is no longer quite what you set it to.
If you set a float to a small number, like 5.5, it would still be stored as 5.5, because as it doesn’t take up much room, no numbers need to be cut off.
The advantage of this format is that a wide range of values can be expressed using a relatively small number of digits or bytes. The disadvantage is that the rounding off means floating point numbers don't have the precision of an integer, so they shouldn't be used when you need to make exact comparisons or keep track of exact counts.
For example, a floating point variable is fine if you just need to check if a distance is greater or less than a certain value. But if you need to check if the player has specific number of some item in their inventory, then you want to use a long or short integer variable for the count.
(Forum info / DinkumThinkum)
An example by BungaDunga shows that when doing math with floats, the answer isn’t always what you expect:
Float num1
Float num2
Float num3
Set num1 to ( 1 / 3 )
;num1 is now 0.3333333
Set num2 to 3
;num2 is now 3
set num3 to num1 * num2
;num3 is now 0.9999999, rather than what you would expect, 1.
if ( num3 == 1 )
; Never happens.
endif
A lot of functions return float values (e.g. GetDistance, GetScale, GetSecondsPassed…): the same thing applies. Test a range, not an exact value! E.g.:
if ( ( GetPos x ) == 500 )
;will be false if it's 499.9999, or 500.0001, etc
endif
but this will work:
if ( ( GetPos x ) > 499.5 )
if ( ( GetPos x ) < 500.5 )
;it's close enough for me
endif
endif
Another common mistake is to check if the GameHour is an exact number. As the Gamehour variable is increased every frame, and every frame is a slightly diffrent length, the Gamehour variable soon ends up with a value like this, 10.12853. So never test if the gamehour is exatly equal to a value, as it is very unlikley to happen, test if it is greater than or equal to a value.
Local variables
Local variables these have to be declared in the script:
Float floatvarname
Short shortvarname
Long longvarname
Local variables are unique to a specific instance of a local script. This means that the local variables in multiple objects with the same script do not influence each other. The names you use for variables are pretty much up to you as long as they start with a letter, but you have to avoid using function names (this will result in errors during runtime) and reserved characters (e.g. - + / * = " )( etc.) which will result in compiler errors. E.g. "variable-1" will not work as a variable name. Underscores as in "my_variable" are ok, but avoid leading underscores. A dot has a reserved meaning as well (see "Referencing variables in other local scripts" below).
Global variables
To declare a global variable go to the Gameplay menu and select Globals. Right click for "new", name it, and set the type and starting value for the new global variable, if one is needed. By default it will be 0. Global variables are very useful for involved quests when you need to keep track of things over an extended time and space. They are also a simple way to share information between different scripts
Note: if you declare a local variable with the same name as a global variable, the global variable will become invisible for this script. Do NOT declare a global variable as a local!
Referencing variables on other objects and scripts
Set … to
If a unique object has a local script running on it you can change variables from outside the script in the following way:
Set MyObject.variable to 100
or
Set MyObject.variable to local_variable
This method changes a local variable in the object’s script. The object must have a script on it for this to be valid. The object does not have to be in an active cell when setting the variable, but it will only work if the cell containing the target object/(script) has previously loaded -(Cyran0). Note: The scripting system looks at the first object in the database, thus you should only reference objects that are unique (exist only once).
Note that the reverse does not work:
Set local_variable to MyObject.variable ;this doesn't work!
Use a global variable to transfer information in this way, or set local_variable from the other script using the syntax above.
if ( anotherobject.x > 0 )
apparently works.
Furthermore I realized only recently that this syntax also works for global scripts:
set Global_script_name.variable to 1
This is useful to avoid using more global variables then necessary or also as a console command to debug global scripts.
Note: If your object or global script starts with a number, you need to put quotes around it.
"11NPC01".RemoteVar ;---Good
"11NPC01.RemoteVar" ;---BAD
11NPC01.RemoteVar ;---BAD
A caution when setting variables from outside the script (DinkumThinkum):
If you recompile the target script (i.e., the local script on 'MyObject'), it's a good idea to also recompile any scripts that reference variables in that script. Reason: if the target 'variable' winds up in a different position in the target script's list of variables, then any scripts trying to set that variable will break if they're not recompiled.
I.e., if 'variable' is the 14th variable declared in the local script on 'MyObject', and you add a new variable ahead of it so that 'variable' is now the 15th variable declared, other scripts will need to be recompiled in order to find 'variable' in its new position, otherwise the script will end up changing the wrong variable, leading to very strange bugs.
One way to reduce the chances of this tripping you up is declare variables referenced by other scripts first, before other variables that aren't referenced externally. Then just be careful to only add or remove variables after the block of externally referenced variables. However (to be safe), it's still a good idea to recompile scripts that reference variables in other scripts any time you've added or removed variables in the other scripts.
Using variables in functions
Unfortunately it is one of the limitations of TES script that only certain functions accept variables as parameters, which poses some definite limits. The type of arguments functions accept is indicated in the list of functions below.
Note: For some functions where both a Get-Function and a Set-Function exist, a workaround can be constructed by using the while function (see below).