FLAGS AND VARIABLES
This section explains the use of conditional flags and variables in ERM scripts.
Introduction
Flags and variables are at the very heart of the ability of ERM to
transform Heroes into a highly dynamic game that responds to the actions and
choices made by the players. While ERM scripts can be written without using
flags or variables, learning to use them will greatly enhance your options,
and in fact, a number of the commands require their use.
Conditional
Flags
Conditional Flags are also referred to as flags or CFs.
A flag is a conditional switch that is either true (1) or false (0). Like a
binary number, it has only two states and no other. Initially, all flags are
set to false (0). A value of 1 (true) is sometimes referred to as the flag
being "set" while a value of 0 (false) is sometimes referred as a
flag being "not set".
Setting
Flags
In ERM, there are 1000 conditional flags and these are each represented by a
number from 1 to 1000. Flags are set with the IF
receiver using the V# command. To set a flag to true, use the value 1 and
to set it to false, use 0.
Example: to set flag number 4 to true, use:
!!IF:V4/1;
In addition to the V command, there are also several IF commands for setting the first 10 flags all at once. Refer to the IF receiver page for the specific syntax of these commands.
Using
Conditional Flags
The most common use of a flag is to control whether or not a piece of ERM code
(such as a trigger or receiver) executes under certain conditions in the game.
For example, if you want a map object to display a message the first time any
hero visits it but never after, you could use a flag for this purpose; it
would display the message if the flag was false (not set) and a following
command would then set the flag to true (1) so that next time the object was
visited, no message would be displayed.
The symbol for indicating a flag (or variable) test is the ampersand (&)
which is placed immediately prior to the colon of a receiver statement, or
prior to the semicolon of a trigger statement. The ampersand is immediately
followed by the flag number used for the test. If a test for a true flag (a
flag that has been set to 1) is made, the number alone is used. If the test is
for a false flag (not set, or set to 0), a negative sign is placed in front of
the number. So to test if flag number 5 is true, you would use &5, and to
test if flag number 5 is false, you would use &-5.
Example of code:
ZVSE
!?OB10/14/0; [object at
x=10,y=15,level=surface is visited by a hero]
!!IF&-5:M^Come in. I have been expecting you.^; [display if flag
5 is false]
!!IF:V5/1; [set flag 5 to 1 (true)]
Checking Multiple Flags
At times, you may want to check for more than one conditional flag (or
variable). To do this, separate each subsequent number with a slash (/). When
there are multiple flags or variables to test for, ALL conditions must be met
before the statement executes. For example, if you were testing for flag
number 7 being true, flag 8 being false and flag 10 being true, then if even
one of those flags had a different value, the statement would not be carried
out.
Example of code:
ZVSE
!?OB10/14/0; [object at
x=10,y=15,level=surface is visited by a hero]
!!IF&7/-8/10:M^Come in. I have been expecting you.^;
[The above
message is displayed only if flags 7 and 10 are true and 8 is false]
Initializing Flags
While all flags initially begin as "not set" (i.e., value of 0 or
false), flags 501 to 1000 will retain their last value when you begin a new
map (or the same map over) without first quitting and restarting the Heroes
game. This is so they can be used for making campaigns in which you want
certain flag values to carry over to the next map in the campaign. If you wish
to avoid potentially having flags that aren't set to 0 at the start of a game,
either stick to using flags 500 and below or initialize to 0 at the start of
your map or script (with IF:V statements) all flags that you wish to use.
Special Flags
There are three flags that have special significance in the game.
Flag 1
is used by certain commands to return a result and will also return the result
of a conditional check of values (see below). Therefore, it's a good idea to
never use flag 1 for any long term storage. Or to be safe, don't use it at all
and stick to higher numbered flags.
The second flag is Flag 999, which is set to 1 if the current player (when trigger
executes) is a
player "here" and 0 if he or she is at another PC. The AI has it always
set to 0. If flag 999 is set, you can be sure that this is human and he
is here. It's working for all triggers.
The
third flag that's significant is flag 1000. This flag will be set to true when a hero owned by a human player visits
a map object or is the subject of a trigger such as a timer or level gain
check. If a computer (AI) hero visits an object, flag 1000 will be set to
false. Again, you can set this flag yourself but it's probably safest not to,
since you may wish to check its value in a script to determine if the subject
is a human or AI player.
On other way : -1000 means AI and 1000 means Human.
Displaying the Value of Flags in Messages
To display the value of a flag (0 or 1) in a message, use %F followed by the
flag number you wish to display (1 to 1000). So to display flag number 4
within a message, you would use %F4. Displaying the value of flags may be useful
primarily as a tool to help in debugging scripts.
Example:
!!IF:M^The value of flag number 4 is %F4.^;
Comparing Values
To compare the game parameter to a particular value you can use the following way: ...[compare
operator] value... The result of comparing is stored in flag 1. You can use its value for further ERM
statements.
Examples of Value Comparison using the GE Receiver:
|
!!GE100:F5 |
Set first day to 5 for Time event (standard syntax) |
|
!!GE100:F=5 |
Check if first day is 5 and set Cond.Flag1 (CF1) |
|
!!GE100:F<>5 |
Check if first day is NOT 5 and set Cond.Flag1 (CF1) |
|
!!GE100:F><5 |
The same as above |
|
!!GE100:F>5 |
Check if first day is greater than 5 and set CF1 |
|
!!GE100:F>=5 |
Check if first day is greater or equal to 5 and set CF1 |
|
!!GE100:F=>5 |
The same as above |
|
!!GE100:F<5 |
Check if first day is below than 5 and set CF1 |
|
!!GE100:F<=5 |
Check if first day is below or equal to 5 and set CF1 |
|
!!GE100:F=<5 |
The same as above |
Variables
Aditional usefull information can be found in the VR receiver easily explained (ERM for dummies, by Qurqirish Dragon)
Storing
Variables
There are several ways of storing a value in a
variable. The
Here is the example:
Function local floating point variables (e1..e100)
They
are used the same way as y vars:
- not stored in the saved game;
- are local in every function;
- filled with 0 at every function/cycle start;
- restored when return from other function call.
You may use them to set parameters but the main feature is to use
it to calculate floating point expression and then store it to integer
variable.
You can use +,-,* and : commands of VR receiver for e vars in
floating point calculations though all numbers should be integer in
the expression.
You can also put e vars in the message with %E# command. In this
case only 3 digits after dot is shown.
!#VRe5:S32; !#IF:M^e5 is "%E5"^;
[ e5=32.0 ]
!#VRe5:*5; !#IF:M^e5 is "%E5"^;
[ e5=160.0 ]
!#VRe5::200; !#IF:M^e5 is "%E5"^;
[ e5=0.8 ]
!#VRe5:+e5*10+5:10; !#IF:M^e5 is "%E5"^;
[ e5=2.1 ]
!#VRv100:Se5; !#IF:M^v100 is "%V100"^;
[ v100=2 ]
String variables (z1-z1000) store strings of characters (one or more)
and cannot be used to store numeric values; they could store a number as text
but that number couldn't be compared or manipulated numerically in any
fashion. z variables can be concatenated (joined together) but have a maximum
size of 512 characters each. They can also be
compared to another z variable to see if they match each other exactly. When
comparing two z variables for a match, the comparison is NOT case-sensitive.
So if z1 stores "This" it will match z2 storing "thIS" or
any other combination of upper and lower case. Leading blank spaces or lines
are also ignored in z variable comparisons. The 500 new z variables added in
the ERM 2.60 update (WoG 3.57) are identical to the original 500, but note
that z501-z1000 will not keep their values between different maps.
Continue to use z301-z500 for this purpose.
Note: Since
string variables handle text messages, be aware that a string
cannot contain the ;
,
^ characters. Example:
!!VRz567:S^wrong text ; it contains ^special
elements^. ^;
!!VRz567:S^this is a correct text. It contains no "special elements".
^;
!!IF:M^this is a correct text. It contains no "special elements".
^;
Function local string variables (z-1-z-10) are similar to their y
variable counterparts but store string values like z variables. If you set one
and then call a function or function loop that sets another value, when you
return to the original function you will have the variable value you set
before the function call. However they differ from y variables in that they
will keep their value when you initially call the function, so they may be
used to pass strings to functions, but cannot be used to return values. Like
regular z variables, they have a maximum size of 512 characters.
Special Variables
There are several variables in ERM that have special significance. Like the
flags 1 and 1000, special variables can still be set by to anything you like
at any time, but it is advisable to do with some degree of caution, since
other commands may make use of them.
The v1 variable is occasionally used to store the results of a few commands.
This isn't a common occurrence so it can still be used in your scripts, but
it's advisable to not use it for long-term storage of a value; in other words,
don't store a value in v1 if you need to guarantee that it remains unchanged
at some later point in the game.
The z1 variable is used to store the text entered by a player in an extended
dialog box. If you don't use extended dialog boxes, you won't need to worry
about this, but it's still a good idea not to use z1 for long-term storage.
The v variables v998, v999, and v1000 always store the position of the object
or event that a hero is currently visiting when a corresponding trigger is
used, or in some cases the location of the hero him or herself (for example,
the !?HM trigger). It's best to leave these variables alone except to compare
their values or copy their values to other variables.
The x16 variable (used in functions called with the DO
Receiver), stores the current cycle number of the function. For example,
if the function is being repeated 12 times (from 1 to 12), the first time
through, x16 will equal 1, the second time 2 and so on. If you change the x16
variable, you can actually "speed up" or "slow down" a
function loop, or even exit from it completely by setting x16 equal to the end
value (or higher) that was specified in the DO receiver.
Initializing Variables
Like flags, all variables begin the game with an initial value of 0. However,
also like flags, certain variable ranges will NOT be reset between maps
without restarting the Heroes game. Again, this is to allow those variables to
"carry over" their values to another map as part of a multi-map
campaign.
When you start a new map, the
following variables
will be reset to zero (0) or a void string "" for z variables: f...t,
v1...v500, v1001-v10000, z1...z300, z501-z1000, w1-w50.
The following variables will retain their current values between games (unless
you quit and restart Heroes): v501-v1000, z301-z500, w51-w100.
Displaying Variables in Messages
Like flags, the values of variables may be
displayed in messages by using special codes for the type of variable followed
by the variable number as shown below:
%V# Shows a quick or v variable of the specified number. # = f to t or 1
to 10000.
%W# Shows a hero variable of the specified number. # = 1 to 100.
%X# Shows a parameter variable of the specified number. # = 1 to 16.
%Y# Shows a local function variable of the specified number. # = 1 to
100.
%Z# Shows a string variable of the specified number. # = 1 to 500.
%$macro$ Shows a variable associated with the macro name "macro".
It's important to note that the code for displaying a variable is always an
uppercase letter after the %letter is always uppercase while a regular
variable reference is always a lowercase letter.
Example showing the display of quick variable j,
standard variable v21 and z variable z100 within a message string:
!!IF:M^Sorry, %Z100, but you only have %Vj gold left
and you need at least %V21 gold to buy this artifact.^;
Assuming that z100 had previously been used to store
the hero's name (let's say it's Clancy) and j to store the current player's
gold (let's say it's 750) and v21 to store the cost of some artifact in gold
(let's say it's 2000), the message would appear as:
Sorry, Clancy, but you only have 750 gold left and you
need at least 2000 gold to buy this artifact.
Including Variables as Part of a String Variable
By using the same commands you use for displaying a variable in a message (see
above), you can include a variable as part of a string variable. This is handy
way of concatenating strings made up of several z variables and possibly some
other variable values all at once.
Example of combining several z variables and v
variables together in one z variable:
!!VRz10:S^Clancy^; [set z10 to
"Clancy"]
!!VRz11:S^green^; [set z11 to "green"]
!!VRz12:S^red^; [set z12 to
"red"]
!!VRv25:S1 R1000; [store a random number between 1 and
1000 in v25]
!!VRz100:S^%Z10 always wished he had a %Z11 horse but instead he had a bright
%Z12 one. He was %V25 years old now and %Z10 had never owned a %Z11 horse in
his life!^; [store text in z100]
!!IF:M^%Z100.^; [display text stored in z100]
Assuming the random number generated and stored in
the v25 variable is 247, the following message would display to the player:
Clancy always wished he had a green horse but instead he
had a bright red one. He was 247 years old now and Clancy had never owned a
green horse in his life!
Indirect Reference of Variables
Several receivers requiring map locations (x, y and level values) can be used
with an indirect variable reference. This is a single number that is the
starting index number of consecutive v variables storing the x, y and level
values to be used. Thus, if you have stored an x value in v100, y value in
v101 and level value in v102, you could use the number 100 in the receiver in
place of these values.
Example of using a local event receiver with an
indirect reference:
!!VRv100:S10; [number to be used for x
value]
!!VRv101:S15; [number to be used for y value]
!!VRv102:S0; [number to be used for level value]
!!LE100:M^Strangely, there is no sound of life here.^;
[set message of event at location stored in v100, v101, v102 variables]
Indexed Variables
Sometimes it's useful to be able to refer to a variable index (e.g., the
number between 1 and 1000 for a v variable) with another variable. In this
fashion you could use a repeated function loop such as the DO
Receiver to store information in a series of variables. Instead of putting
a number after the v, you would put another variable and the value it stores
would be the number of the v variable.
Example of a referencing a v variable with a y
variable:
!!VRy10:S7;
!!VRvy10:S5;
!!IF:M^The value of v7 is %V7.^;
This would display the following:
The value of v7 is 5.
This is because y10 has the value 7. And vy10 then means v at the index number
stored in y10, which in this case is 7. Thus v7 stores the value 5.
Macros
If you want to be able to refer to a variable by a more meaningful name, you
can set up a macro with the MC receiver. The macro can then be used almost any
place the variable can be used and is interchangeable with the variable. A
macro is referenced with the name enclosed by dollar signs, e.g., $treasure$.
For more information on macros, see the MC Receiver
page.
A Guide to Suggested Variable Use
You can use any combination of variable numbers you like in your scripts
but to make scripts easier to keep track of, change or transfer to other maps,
it's a good idea to use a series of contiguous index numbers such as v100
through v120 or however many you need. It's also a good idea to use Quick
Variables to only store temporary numbers and to keep the low numbered v and z
variables also for this purpose, using only higher numbered v variables and z
variables for long-term storage of values. Furthermore, where possible, it's
good to make use of local y variables within functions, thus keeping more
non-local variables available for general use elsewhere in your map scripts.
The hero variables (w variables) will generally only be useful for specific
purposes, but do make use of them when the situation arises, since every
single hero has their own set.
Using y Variables Outside Functions
There is one global set of y vars [1...100]. Every time you
use it. But every function trigger storied all current y vals in a
stack, sets them all to 0 and after executing of the latest receiver
them all are restored back.
But of course you can use this global set anywhere.
Example:
ZVSE
!#VRy15:S3;
....
!?...;
!!IF:M^%Y15^; it shows 3
...
!!FU234:P;
!!IF:M^%Y15^; it shows 3
...
!?FU234;
!!IF:M^%Y15^; it shows 0
!!VRy15:S5;
!!IF:M^%Y15^; it shows 5
!?FU234;
!!IF:M^%Y15^; it shows 0
!!VRy15:S7;
!!IF:M^%Y15^; it shows 7