ERM
TUTORIALS
This file deals with ERM programing concepts at basic,
advanced and trained levels.
The ERM Tutorials is a new page in
the html ERM Help. It was intended to clear out the basics and various info
for the newbies, to ease the access to the scripting for all users and
potential programmers, as well as to offer a structured guiding tutorial.
For Polish modders, i strongly suggest to start with this tutorial.
Interface | |
|||
![]() |
The top
"keyboard" |
![]() |
||
The side menus for various pages are displayed here | The Anexe information. The Formats and the Index are displayed here, along with other information. |
1. The Top "Keyboard"
Contains various buttons and the the entire Receivers section detailed on
separate receivers: AI through VR.
Since most of scripting uses receivers as programming commands those buttons
were supposed to be at hand.
The rest of the buttons will link you to various information which could be
helpful: formats (data tables), objects, and separate explanations for some
issues.
This frame is redirected to the second region (side menus)
and to the central page display.
2. The Side Menus
Will apear if the pages in the top "Keyboard" section do posses such menus.
Almost all Receiver pages have them and some of the other pages too.
For the Receiver pages, the side menus will display Identifiers in
alphabetical order, two rows. The Identifiers will link you further to the
main display, bringing up the information, with the Conditions.
3. The Anexe
This part of the page
dispays information mostly from ERM Formats
and Index , but could
ocasionally offer some other various info. The ERM Formats contain game data
tabels, data necesary for most of the scripts.
4. The Main Display
This is the main display where the "heavy" text is placed
This being cleared out, on the left you have the side menu for this page to
help you to gain access rapidly to the various information here.
1.
How to... Create your first script
2. How to... Create your first script
(part2)
3. How to... Create your first script
(part3)
4.
VR receiver and
Variables easily explained
5.
OB trigger & receiver easily explained
6.
HE receiver easily explained
7. Basics: Universal Format
How to... | CREATE YOUR FIRST SCRIPT |
Erm For Dummies, by Qurqirish Dragon |
The first thing to know is that any script you
place in a map must be placed in a timed event. That is, in
the map editor, go to the Tools
menu, then select Map Specifications,
and click on the Timed Events tab.
Since you generally will not want the script to appear as a
timed event, be certain to uncheck the box that says
apply event to human
players.
Also, since you will often want to have timed events that
do appear to the player, it is
strongly recommended that you use a high day number- days 500+
are suggested, since maps seldom take over a year game time to
finish, and so it is very unlikely that timed events will be
needed here. This conveniently gathers
all your scripts at the end of the event list.
Finally, you should give the event a name that describes the
script.
Now, put the script in the message portion of the event. You
can type the event directly in here, or you can (and this is
how I suggest you do it) write the script in the script
editor, and copy it into the event.
If you do use the script editor, then be certain to follow the
following procedure- this will avoid a very common source of
errors:
1) If you have made any changes to the script since you last
saved it, then save it again.
2) Select the whole script (ctrl-A does this), and copy it
(ctrl-C)
3) Go to the map editor, and paste the script (ctrl-V)
If you used any other editor (such as notepad) to write the
script, then open the script editor, copy the script into it,
and re-save. Many editors- particularly WordPad and word
processors- place non-printing characters and visual
formatting codes in the file, and these will cause ERM errors.
----------------------
Now, on to actual scripting. I will assume here, and in all
future instalments, that you are using a recent version of
the ERM script editor, and you have the highlighter ON (that's
the H button at the bottom of the scripter window). Other than
that, I will not assume you know ANYTHING but what I have
discussed in these posts.
First, whenever you are working on a script, I suggest you
first write down on a separate sheet of paper- and I actually
mean to write, not use a text editor- what you want the script
to do. Do some brainstorming to see how you like it to be, and
do a general sketch of the script's flow.
For example, I wrote a script that modifies the Card of
Prophecy (this is script34.erm in your /data/s folder) to play
around with a hero's stats, when entering battle. Fortunately,
I kept my notes on the script, and can share them here. Note
that when I first started this, I had
NEVER EVEN LOOKED at ERM scripting before.
I started by writing the following:
Artifact that gives, at start of battle,
a random primary stat of -1 to +4. Attach to any given
artifact for testing.
That was the whole idea. Seems simple right? I thought so too.
NExt, I wrote the basic steps down:
Start of battle - check if art. is
equipped
no - end
yes- set flag, choose random number (1,2,3,4) for stat
And so on. just a general sketch. I will not go into any more
detail here, I just wanted to show what I did before sitting
down at the scripter. Believe me, if you do this first, things
will go a lot more smoothly.
-------------------------
Now, time to write code!
The first line of any script is:
ZVSE
This tells WoG that the timed event is a script. Without it,
all your hard work will be ignored by the game.
All commands are four characters long, and are one of three
basic types, not including ZVSE. In the script editor,
commands are displayed in dark red.
Triggers are commands that
say "If something occurs in the game, start executing the
script that follows. Almost all Triggers begin with the
characters !?
For example, take this line of code from my Cards script
(again, that is script34.erm if you are following along
there):
!?BA0&v1321=1; [start of battle]
This is the first trigger in my script. Don't worry about what
the command does yet- I'll explain that later. However, do
note the semicolon. All ERM commands END
with a semicolon. Anything after that is considered a comment.
In the scripter, anything that is a comment is shown in green.
Receivers are commands that
set, check, or modify something in the game. They are
not executed, unless they follow a
trigger. All receivers begin with !!
For example:
!!BA:E?v1331; [check for multiplayer]
Again, note the semicolon to end the command. From the comment
you can tell what this command is for, but that is for later.
Finally, instructions are
just like receivers, except that they run only one time- when
the map begins. They always begin with
!#
For example:
!#UN:P34/?v1321; [is script active?]
For those looking at the script, note all the green lines that
start with ** I use a
double-asterisk to introduce a comment line. This is not
necessary, and other script writers use other commenting
methods. As long as you do not begin a line with a command,
the line is ignored by ERM. I like to force comment lines to
be recognized as such, so they stand out in green.
To wrap up this first instalment, I will explain a couple
simple commands, so you can do SOMETHING. The second
instalment will give you a bit more to work with- but feel
free to experiment.
This script will simply count how often any hero has visited
the upper-left corner of the map's surface layer- coordinates
(0,0,0). Whenever I introduce a command, feel free to look it
up in the ERM help.
The first line is, of course:
ZVSE
Next, we need to set a counter to 0. Since we want the counter
to start at 0, and not wait for a hero to visit (0,0,0), we
use an instruction. The instruction to assign a value to a
variable is !#VR
Before we can go further, we need to choose a variable to hold
the count. Normally, you should consult the
List
of the Claimed, easily found in the ERM help
file- just choose it off the index, and choose a variable that
is free. For purposes of my tutorials, however, I will always
use low-numbered v variables. V
variables are the ones you will use most often. I will
introduce the other types as needed.
So, now use the command:
!#VRv1:S0;
This, broken down, says:
!#VR ...
Perform a variable command at the start of the map
... v1 ...
operating on variable v1
... : ...
Any command which does anything
uses a colon to separate the command from the action being
taken. Triggers will not have them, but other commands will.
... S0 ...
The S option for VR says you want to Set
the value of the variable. In this case, we are setting it to
0.
... ;
As I mentioned above, a semicolon ends the command.
Now, we need to set an event trigger. In the map, place an
event at (0,0,0). It does not need to have anything in it, you
just need it to be there, and allow all players to activate
it, and allow it to be used multiple times.
Now, we set the trigger:
!?LE0/0/0;
The LE trigger says "When the event at the given map
coordinates activates..." The three numbers are the x,y, and z
coordinates of the event, in that order.
If you are looking at the ERM help for the !?LE trigger, you
will notice there is also a !$LE
trigger (a dollar-sign instead of a question-mark). This say
"After the event at the given coordinates is finished..." If
the map event does something without ERM, you may want the
script to run after it, instead of before. In this example, it
doesn't matter which one we use, since the event is blank.
Next, we need to add one to the counter. This uses another VR
command, but this time we use a receiver (!! instead of !#):
!!VRv1:+1;
ERM uses a + to indicate addition, as you would expect. So
this command says "add 1 to variable v1." The other math
operators are:
subtraction uses - (a minus sign)
multiplication uses * (an asterisk)
division uses : (a colon)
modulus (remainder when dividing) uses % (a percent sign)
Note that except when using an e
variable, all arithmetic is done as integers, so 7 divided by
4 is 1, not 1.75.
Finally, we need to show a message to the player saying how
often anyone has come to this spot:
!!IF:M^You are visitor number %V1 to the Northwest
corner of the surface!^;
IF is the command to open an interface with the player. This
can be as simple as displaying a message- as I have done here-
or to ask questions, give dialogues, display images, and so
on.
The M option says "Display the message between the carats."
There are only a few restrictions with what can be in a
message. You cannot use a carat, a semicolon, or a comma. You
also need to be careful with a percent- it is special. If you
want to display a %, you need to type %%.
You probably noticed I have a single % in the message. If you
use a single %, then the next thing is something special you
need. In this case, %V1 (note that the V is capitalized, even
though the variable uses a
lower-case v) shows the value of variable v1. If you look at
the help for !!IF, you will see the list of % commands.
That's it for the script. So, placing it all together in one
place, we have, with comments added:
ZVSE
!#VRv1:S0; [set variable v1 to 0]
!?LE0/0/0; [when event at NW corner of surface is visited]
!!VRv1:+1; [add 1 to v1]
!!IF:M^You are visitor number %V1 to the Northwest
corner of the surface!^;
[show message]
How to... | CREATE YOUR FIRST SCRIPT (part2) |
Erm For Dummies, by Qurqirish Dragon |
I am going to take the 5-line script developed at the end of
part 1, and expand it. What the script will do is make it so
that every 10 times anyone visits the NW corner of the map,
the world become magically strong, weak, or normal, cyclically.
In other words, after 10 heroes have visited, all heroes'
spell powers, in combat, will be doubled. After 20, combat
spell power will be set to 1, and after 30, spell power will
be reset to normal. The cycle then repeats.
First, we are going to insert a new line, between the !!VR and
!!IF commands. This line will check to see if you are the (10*n)th
visitor to the site. Since this value is not needed to be kept
after the script runs, I will use a temporary variable. The
temporary variables in ERM are the y
variables. They are not saved between scripts, so you cannot
use them for permanent storage. However, you can also rest
assured that you will not mess up other's scripts when using
them. So let's add the line:
!!VRy1:Sv1%10; [is v1 a multiple of 10?]
This command uses two operators in one statement. All math is
done from left to right in ERM. Remember that if you have
several operations to perform- it may be easier to split it
into several lines. In this case, we first set variable y1 to
the value of v1, and then find the remainder when divided by
10. If y1 is 0, then we know that v1 is a multiple of 10.
Now, if it isn't a multiple of 10, then nothing will happen,
and we can just display the message that we had before.
However, a small change needs to be made:
!!IF&y1<>0:M^You are visitor number %V1 to the Northwest
corner of the
surface!^; [show message if nothing else happens]
Aside from a change in the comment, I have added,
before the colon, the condition
&y1<>0 The ampersand says
"only do this command if the following is true." the rest says
that y1 is not equal to 0. Thus, this message will only be
displayed if nothing else happens, other than the counter
increasing.
Now, if v1 *IS* a multiple of ten, we want to have the message
indicate that magic as been shuffled around. But for this, we
need to find out which change is being made. So, we will use
another y-variable to check this:
!!VRy2:Sv1:10%3; [find magic change type]
This takes v1 and divides it by 10, then finds the remainder
when this is divided by 3. This will give variable y2 the
value of 0 if v1 is less than 10, between 30 and 39, between
60 and 69, and so on. y2 will be 1 if v1 is between 10 and 19,
40 and 49, etc. y2 will be 2 in the other areas. Note that
even if v1 is NOT a multiple of 10, this is being calculated.
Now we need three more IF commands- one for each type of
change. However, I can introduce a few more concepts by taking
a slightly longer route.
We want to have a message that says "You are visitor number
[whatever], you feel the world's magic power strengthen."
We want to have another message that says "You are
visitor
number [whatever], you feel the world's magic power weaken."
We want to have a third message that says "You are
visitor
number [whatever], you feel the world's magic power return to
normal."
Notice that these three things say almost the exact same
sentence- only a couple words change. We really don't want to
do all that typing. This is particularly true if we later want
to add more possibilities.
For this, we are going to use a z
variable. z variables are the only ones that can store actual
text values. Just like v variables, z variables are
permanently kept. However there are a few z variables that are
temporary, like the y variables. A quick look at
Flags and Variables in the ERM
help shows that the temporary z's are z-1 through z-10. Let's
use variable z-1 to hold that little bit of text that changes.
This will take three lines:
!!VRz-1&y2=0:S^return to normal.^; [for visit 30, 60, 90, ...]
!!VRz-1&y2=1:S^strengthen.^; [for visit 10, 40, 70,...]
!!VRz-1&y2=2:S^weaken.^; [for visit 20, 50, 80, ...]
At this point you should be able to understand these lines
completely. Together, they set variable z-1 to the appropriate
end of the message we want to display. Note that the rules for
placing text in a z variable are identical to the rules for
placing text in an IF:M command: You can use % commands to use
other variables within them, if you need to, and you need to
type %% for a percent character. Carats, semicolons, and
commas are still not allowed.
Now we need to display the new message:
!!IF&y1=0:M^You are visitor number %V1, you feel the
world's magic power %Z-1.^; [show change message]
This time, the condition is that y1
equals 0. We only want this message to appear if a
change is happening.
We have now gotten all of our messages out of the way. Next
comes the code to modify hero statistics in battle.
I am going to add a comment line here- remember that in the
script editor this will appear in green:
** in-battle effects routine starts here
We need to check for a battle starting. This means we need a
new trigger- for the start of a battle:
!?BA0;
Since we have used a new trigger, the previous code will stop
running when it gets here. The BA trigger looks for battles.
BA0 (that's a zero, not an o) is the trigger for the
start of a battle. We will need
another trigger for the end of the battle as well.
Now, as many of you will know from reading other threads,
battle scripts often have problems in human-vs.-human, network
multiplayer battles. Although this script should not have a
problem here, I am going to check for this case, and not allow
the script to run in this case. There is a special command for
this check:
!!BA:E?y1; [is this a network battle?]
This is a BA receiver. The E option says "find out what kind
of battle is occurring." ?y1 says take the result of the BA:E
command and store it in y1. Note that I am reusing y1 from
before- that is the advantage of temporary variables: you
don't have to worry about old contents when you want to use
them.
Checking the ERM help will tell you what values y1 may now
have:
If the battle is between an AI hero and a human player, on the
AIs turn, at a computer other than the host, then y1 is set to
2.
If it is between two humans, other than hot-seat, y1 is set to
1.
Otherwise, y1 is set to 0.
Now, we only want the script to run in the last case. Until
you learn what types of battle scripts work in cases 1 and 2,
it is safest to do this. We now had the next line:
!!FU1&y1=0:Pv1; [if not, continue the script]
This is a new receiver. The FU receiver calls another script
function, in this case function 1. Again, we have the
condition that y1 is 0. If not, the function will not start.
The option P means that the following parameters need to be
passed into the function. Although it is not necessary in this
case, I have passed in variable v1. This will let me
manipulate v1 inside the function, without changing the stored
value.
We do not need to do anything else at the start of a battle,
so we can now go right on to the function.
We start by using a function trigger, to indicate a new code
section, along with a comment:
** start of pre-battle
!?FU1;
Since we want to modify the spell power of any heroes in the
battle, we need to know which heroes are fighting, if any, on
both the attacking and defending sides. This is done with two
battle receivers:
!!BA:H0/?v5; [get attacking hero's hero number]
!!BA:H1/?v6; [get defending hero's hero number]
The H option asks for a hero number. H0 refers to the
attacker, H1 refers to the defender. If there is NO defending
hero, then BA:H1 returns a value of -2. All the hero numbers
are listed in the ERM help file under
format H, but since we are applying this routine to all
heroes, we don't care about specific numbers. I chose to use
v5 and v6 to hold these numbers, because I have a special
purpose intended for v3 and v4 later, and I wanted the hero
numbers in adjacent variables, for my bookkeeping.
Now, we need to find out what kind of spell power change to
apply. Since we stored that in a y variable above, we may not
still have the value in memory- and we should assume not.
However, we do have the counter in v1. So, let's get the
change type again:
!!VRx1::10%3; [get magic change type]
This looks familiar, but there have been a few changes. First,
note that I used variable x1,
not v1. This is because this
statement is changing the value of the variable, but we do not
want to change the counter. x variables are numbered from x1
through x15, and they contain the parameters that were passed
into the function from the FU receiver. Since I passed in v1,
x1 has that value. There is also an x16, and you
can pass in a 16th variable, but
x16 has a special purpose (which will be dealt with later),
and so you should avoid using it if possible. Also note that x
variables can only hold integer values, so you cannot pass in
a z-variable to a function.
Also, do not be worried about the double colon. The first
colon separates the VR receiver from the options. The second
is the division operator. Now, x1 contains the value that y2
did in the first part of the script.
We are almost ready now. We simply need to find out what the
heroes' spell powers are.
!!HEv5:F?y5/?y6/?y3/?y7; [get attacker's stats]
!!HEv6&v6>=0:F?y5/?y6/?y4/?y7; [get defender's stats]
The HE receiver is used to modify any and all aspects of a
hero. The first line looks at the hero whose number is in v5,
the second line at v6. In the second line, we add in the check
v6>=0, so that if there is no defender, WoG doesn't try to
look for hero -2. This would cause an error when the script
ran.
The F option says to look at the hero's primary skills. the
next four numbers are separated by slashes, and are the
attack, defence, spell power, and knowledge skills, in that
order. If you just place a number or variable there, it
changes the hero's stat to that value. If you place a ? before
a variable name, then it takes the current value and stores it
in the variable. In this case, variables y3 and y4 will
contain the spell powers for the heroes. variables y5, y6, and
y7 are only there as place-holders, and so I could reuse them.
At this point, I should note that it is a good idea to keep
track on a separate paper what every variable holds. This will
help if you should forget.
Now, we need to set up the changes- specifically, figure out
exactly how much of a change will be done to the spell power.
Since we will need to know what the change is later (when we
restore the old values), we will store these in two more
v-variables. I will use variables v3 and v4, corresponding to
y3 and y4. This is why I skipped them earlier.
!!VRv3&x1=1:Sy3; [if magic strengthened, spell power
increases]
!!VRv3&x1=2:S1-y3; [if magic is weakened, spell power reduces to 1]
!!VRv4&x1=1/v6>=0:Sy4; [if magic strengthened, spell
power increases]
!!VRv4&x1=2/v6>=0:S1-y4; [if magic is weakened, spell power reduces to 1]
The new thing seen here is in the 3rd and 4th lines. The slash
in the conditions is the same as a logical "and". So,
&x1=1/v6>=0 says "if x1=1 and v6>=0, then do the command."
Now we just need to make the changes:
!!HEv5&x1<>0:Fd0/d0/dv3/d0; [modify spell power]
!!HEv6&x1<>0/v6>=0:Fd0/d0/dv4/d0; [same for defender]
Here, we are modifying the heroes' stats, but only if x1 is
not 0. Remember that if x1 is 0, then our counter indicated
that there is no change to magic power. Again, we use the HE:F
command. The d before any
number or variable says that the number or variable should be
ADDED to the current stat. d0 leaves the statistic alone.
We have now finished the before-battle function!
To recap, our script now looks like:
ZVSE
!#VRv1:S0; [set variable v1 to 0]
!?LE0/0/0; [when event at NW corner of surface is visited]
!!VRv1:+1; [add 1 to v1]
!!VRy1:Sv1%10; [is v1 a multiple of 10?]
!!IF&y1<>0:M^You are visitor number %V1 to the Northwest
corner of the
surface!^; [show message if nothing else happens]
!!VRy2:Sv1:10%3; [find magic change type]
!!VRz-1&y2=0:S^return to normal.^; [for visit 30, 60, 90, ...]
!!VRz-1&y2=1:S^strengthen.^; [for visit 10, 40, 70,...]
!!VRz-1&y2=2:S^weaken.^; [for visit 20, 50, 80, ...]
!!IF&y1=0:M^You are visitor number %V1, you feel the
world's
magic power %Z-1.^; [show change message]
** in-battle effects routine starts here
!?BA0;
!!BA:E?y1; [is this a network battle?]
!!FU1&y1=0:Pv1; [if not, continue the script]
** start of pre-battle
!?FU1;
!!BA:H0/?v5; [get attacking hero's hero number]
!!BA:H1/?v6; [get defending hero's hero number]
!!VRx1::10%3; [get magic change type]
!!HEv5:F?y5/?y6/?y3/?y7; [get attacker's stats]
!!HEv6&y2>0:F?y5/?y6/?y4/?y7; [get defender's stats]
!!VRv3&x1=1:Sy3; [if magic strengthened, spell power
increases]
!!VRv3&x1=2:S1-y3; [if magic is weakened, spell power reduces to 1]
!!VRv4&x1=1/v6>=0:Sy4; [if magic strengthened, spell
power increases]
!!VRv4&x1=2/v6>=0:S1-y4; [if magic is weakened, spell power reduces to 1]
!!HEv5&x1<>0:Fd0/d0/dv3/d0; [modify spell power]
!!HEv6&x1<>0/v6>=0:Fd0/d0/dv4/d0; [same for defender]
Note how the comment lines help see the sections.
Now, after the battle, we need to undo the changes. First, we
do a post-battle trigger:
** post-battle starts here
!?BA1;
!!BA:E?y1; [network battle?]
!!FU2&y1=0:Pv1; [if not, undo changes]
Looks familiar, right? well, the only changes are in the
trigger, and the function number. The trigger is now BA1,
this means this triggers at the END of battle. And, since we
ant to change the stats back, we need a separate function.
Fortunately, we stored the hero numbers and changes in
v-variables, so we don't need to calculate them again.
Let's start the clean-up:
!?FU2;
!!VRx1::10%3; [get change type]
!!VRv3:*-1; [negate attacker's changed stat]
!!VRv4:*-1; [negate defender's changed stat]
Since v3 and v4 have the changes to spell power, we multiply
by -1. Now, if we add them as we did before, it will undo our
change.
!!HEv5&x1<>0:Fd0/d0/dv3/d0; [restore attacker's power]
!!HEv6&x1<>0/v6>=0:Fd0/d0/dv4/d0; [restore defender's
power]
Again, we have the check that spell power was altered, and
that there was a defender in the second line.
We had to store the hero numbers because if a hero was beaten,
it will be in the hero pool, not the battlefield at this time-
we would not be able to get the number at this point.
Our script is now done!
How to... | CREATE YOUR FIRST SCRIPT (part3) |
Erm For Dummies, by Qurqirish Dragon |
Up to now, the script that we have been designing only
activates when someone visits the NW corner of the map. Why
would anyone send his hero over there? Well, you could always
place an event on the map (either as a site or a timed event),
notifying the player of the special place, but I won't do
that, as you don't use ERM for that. Instead, I am going to
create an attraction for a player. I'll do this by placing a
new object on the map. If you are following along with the map
editor, look at the Towns page. If
you haven't looked here before, you will find there are a lot
of objects here after the 10 towns you are used to seeing (9
town types, and random). Most of these objects are unscripted-
that means that if you place them on a map, even if you wogify
the map, they do not do anything. We are going to use one of
them.
For this script, I am going to use the 4th object in the 3rd
row. It looks like a pentagram with small obelisks on the
points, and a large obelisk in the middle. Place this on the
map, as close to the corner as you can, without cutting any of
the image off. If you do not normally have it on, turn on the
passibility tool- this places red
and yellow squares on the map. Any red square cannot be passed
by a hero. Any yellow square is a trigger square for the
object.
If C=no block, R=red, and Y=yellow, then this object, to the
editor, looks like:
CCCCC
CRCRC
RCYCR
CCRCC
Placed as I suggested, the yellow square should be located at
(2,2,0).
Now, let's modify the script to use this object, instead of
the event we placed. If you have been actually doing these
tutorials, you can delete the site event from the map- I will
not be using it again.
Now, we are going to replace the !?LE line, to attach our
script to the yellow square. Recall, the old line was:
!?LE0/0/0; [when event at NW corner of surface is visited]
Now, we simply change the location to the yellow square
(2,2,0), and change the command from LE to OB:
!?OB2/2/0; [when object at (2,2,0) is visited]
Notice that the OB trigger is exactly the same as an LE
trigger in format. If you had no problems with what LE did,
then you'll have no problems with OB. Just remember that LE
stands for Local
Event, and OB stands for
OBject, and you will know when
to use each one.
Now the script will work just as it did before, except now the
site we just placed will activate it. However, I am going to
make one more change to the line:
!$OB2/2/0; [AFTER object at (2,2,0) is visited]
I have changed this from a pre-visit trigger (!?), to a
post-visit trigger (!$). Currently, this doesn't have any
effect on the script, but it will after we add something else
to the script- we are going to add in a resident to the site,
who will give you the option to advance the magic counter by
five if you pay 100 gold, otherwise it will count only one.
Further, We are going to place an existing object there- since
it makes sense, move the pentagram, and replace it with a
star-axis. This is just my choice- if you want, replace it
with any Shadow of Death site that has a function. Just be
certain to only place an object that has only one yellow
square, and place that square at (2,2,0).
If you ran the map now, then when you visit this star axis
(and only THIS star axis),
you will get your usual +1 spell power (or nothing if your
hero was there previously), and then the counter will
increase.
Now, let us script in a creature with a "mystical magic stand"
set up outside the star axis. I think that due to the nature
of the script, a faerie dragon proprietor is best.
Anyway, let's start scripting:
!?OB2/2/0; [When object at (2,2,0) is visited]
This is simply the pre-visit trigger, just as the post-visit
trigger looked, since the same object is being visited.
Now, we need to code in a yes/no question.
The first thing we have to realize is that we are going to ask
a question that needs to be answered. This causes a problem if
the AI sends a hero to visit the site. So, we need to see if
the current player is human or AI. We do this with the
OW receiver. OW lets you check
or set almost anything having to do with a player (rather than
a hero). So, we script:
!!OW:C?y1; [get current player colour]
!!OW:Iy1/?y2; [is current player an AI?]
The C? option checks the colour of the current player. You
cannot change the current player, so the ? is part of the
option here. I am storing this colour in y1. The next line uses
the I option. This lets you check a colour to see if it is an
AI player. The first number is the colour being checked- in
this case, the colour we want is that of the current player, so
I placed y1 there. The second number is the value 1 for an AI,
or 0 for a human. You can actually set this to add or remove a
human player from a map! For now, we just want to read this
in. So now, if it is an AI's turn, y2 will get the value 1,
otherwise y2 will be 0.
Now, we can ask the question.
Since this involves interfacing with the player, we again will
need to use an IF receiver:
!!IF&y2=0:Q1/6/0/21/134/33/0/2^You notice a small stand
set up near the star axis. A
faerie dragon
calls out to you, "Have fun with the nature of magic! Only 100
gold will advance the magic
counter five
times as much as it normally would when visiting the axis!"^;
As you see, I added the condition y2=0 here. If the AI visits
the site, it will NOT ask the question!
Anyway, there are a LOT of numbers in this command, aren't
there? There are eight of them. I am going to break this down
into several parts. If you have the ERM script editor open, go
to the !!IF command, and click on options
and scroll down to
Q#1/#2/#3/#4/#5/#6/#7/#8^Text^ to see similar
information.
First is the option, Q. This stands for
question. Next is the number 1. This is the
flag that will hold your answer.
Flags are like variables, but they can only hold two values: 0
(false) and 1 (true). Unlike variables, there is no letter to
indicate a variable type. For instance, v-variable 1 is
written as "v1", z-variable 1 is "z1", flag 1, however, is
just 1. I'll come back to this when we use the flag later.
The next six numbers add pictures to the dialogue, under the
text that is written. Each pair of numbers refers to a single
picture. The first one is the object TYPE, and the second is
the object SUBTYPE. What each type and subtype is can be found
by going to Type and subtype of Pictures
using the IF:Q command.
In this case we have the first image listed as 6/0. Type 6 is
a resource- specifically gold. The subtype for a resource is
the amount you want displayed underneath. Since I made it
subtype 0, there is no amount displayed- just the picture of
the gold resource.
The second image is 21/134. Type 21 is a monster picture. The
subtype is the type of monster. If you click on the link in
the help file, you will be given a list of them. In this case,
subtype 134 is a faerie dragon.
The third image is 33/0. Type 33 is for a primary statistic,
in this case spell power. Again, the subtype is the amount,
and by using 0, no amount is shown. So, when this script runs,
under the text will be the images of gold, a faerie dragon,
and the spell-power icon.
The final number, 2, says that we want a yes/no question
asked. When run, below the pictures will the the familiar
accept and cancel buttons. If you select accept, the flag is
set to true (1), if you select cancel, the flag is set to 0.
Now, we need to check to see if the player has the 100 gold to
spend! Again, we do this with the OW receiver. So, we code the
next line:
!!OW:R-1/6/?y3; [find out how much gold the current player has]
The R option means that we want to do something with a
player's resources. The first number is the player
colour that we want to check.
This value is 0 for red, 1 for blue, and so on. Check the
format E1 for all the colours, but
basically they are numbered 0 through 7, and go in the order
they are listed in the game. For this script, however, I have
the player colour set as -1. This means that we want to check
the currently active colour, whoever it is. We already checked
the active player's colour above (it is stored in y1,
remember), but I chose to use this to illustrate a
possibility. You need to check the syntax for each option to
see if -1 can be used for the current player. It sometimes has
other uses. For instance, -1 sometimes refers to the neutral (unowned)
colour.
The 6 is the resource we want to check, in this case gold. The
final number is what we want to set the gold to. In this case,
we are using the variable y3, and as before the use of a ?
means we are reading in the amount, rather than setting it.
Next, we check to see what the player's answer was, and if he
could afford the price. We will display an appropriate
response for each case. This needs 3 IF commands- one for a no
answer, one for yes and the player can afford it, and one for
yes and the player cannot afford it.:
!!IF&y2=0/-1:M^Disappointed, the dragon turns to another potential
customer.^;
!!IF&y2=0/1/y3>=100:M^"Very good! I knew you'd want to
do it!"^;
!!IF&y2=0/1/y3<100:M^"I'm glad you are interested, but you
don't seem to have the
gold on hand. Do come again!"^;
Here, the condition that it is a human player is is in all
three. The second condition checks the flag- flag number 1-
which we set based on the player's answer. In the first line,
the flag number is negative. That means that we want the the
flag to be FALSE for the condition to be met. In the other
lines, the flag is positive, meaning we need the flag to be
TRUE. In the third line, we have an additional check- do you
have enough cash?
Before we actually deduct the 100 gold from the player's
treasury, we need to decide what the AI will do. Let us make
the AI flip a coin- a 50% chance that i will spend the money.
We do this with two commands:
!!VRy4:S0R1; [coin flip]
!!IF&y2=1:V1/y4; [set the flag to the flip]
You will recognize the first line, but with a new option that
we haven't used before- the R option. The R option generates a
random number between 0 and the value after R (in this case
1), and adds that to the previous value. So, this VR receiver
sets y4 to 0, and then adds either 0 or 1 to it. Effectively,
this is the coin flip that we wanted.
The next line is our old friend, IF again. This time, the
condition is that it IS an
AI's turn. The V option is used to set a flag's value. In this
case, flag 1 is set to the result of the coin flip.
Now that we are done with the decisions, we code in the
deduction, using the OW command from above.
!!OW&1/y3>=100:R-1/6/d-100; [deduct 100 gold, if appropriate]
The two conditions here should be clear, but just to recap,
the first condition is for the flag to be set- either by the
coin toss for the AI, or by the player saying "yes." The
second condition is that the player has enough gold. As with
the spell power commands from before, we use the d operator to
subtract 100 from the current value of the gold amount (well,
technically we are adding -100).
We only need to do one more thing, and that is note that the
payment was made. Since we haven't used variable v2 yet, I
will do that here:
!!VRv2:S0; [initialize v2 to 0]
!!VRv2&1/y3>=100:+4; [set v2 to 4 if payment was made]
Note that although the player's gold has changed, y3 still has
the amount from before the payment. Thus, the same check that
we had in the OW command will work here. This part of the code
is now done. However, we need to modify the part of the code
we already wrote, since we need to make the counter jump, and
still give the proper message.
Recall the following lines from the start of the script:
!!VRv1:+1; [add 1 to v1]
!!VRy1:Sv1%10; [is v1 a multiple of 10?]
In this part of the script, y1 is the units digit of the
counter. Which message displayed depends on whether or not y1
is 0. First, we modify the first line to read:
!!VRv1:+1+v2; [add 1+v2 to v1]
If payment was made, then this will add 5 to v1, otherwise it
will only add 1.
Next, we add a line after the y1 calculation:
!!VRy1&y1<=v2:S0; [reset y1 if the multiple of 10 was
jumped over]
If the addition of 5 caused v1 to skip over a multiple of 10,
then it means that v2 was 4, and so y1 is between 1 and 4. So,
if y1 is less than or equal to v2, it means that the magic
status should flip- so we set y1 to 0. The rest of the code
can stay as it is!
So now, after a slight change to the text messages, are entire
script now reads:
ZVSE
!#VRv1:S0; [set variable v1 to 0]
** post-visit trigger
!$OB2/2/0; [AFTER object at (2,2,0) is visited]
!!VRv1:+1+v2; [add 1+v2 to v1]
!!VRy1:Sv1%10; [is v1 a multiple of 10?]
<code>!!VRy1&y1<=v2:S0; [reset y1 if the multiple of 10
was jumped over]
!!IF&y1<>0:M^Welcome to the star axis. The magic
counter is now %V1^;
[show message if nothing else happens]
!!VRy2:Sv1:10%3; [find magic change type]
!!VRz-1&y2=0:S^return to normal.^; [for visit 30, 60, 90, ...]
!!VRz-1&y2=1:S^strengthen.^; [for visit 10, 40, 70,...]
!!VRz-1&y2=2:S^weaken.^; [for visit 20, 50, 80, ...]
!!IF&y1=0:M^The magic counter is now %V1 you feel the
world's magic power %Z-1.^; [show change message]
** in-battle effects routine starts here
!?BA0;
!!BA:E?y1; [is this a network battle?]
!!FU1&y1=0:Pv1; [if not, continue the script]
** start of pre-battle
!?FU1;
!!BA:H0/?v5; [get attacking hero's hero number]
!!BA:H1/?v6; [get defending hero's hero number]
!!VRx1::10%3; [get magic change type]
!!HEv5:F?y5/?y6/?y3/?y7; [get attacker's stats]
!!HEv6&v6>0:F?y5/?y6/?y4/?y7; [get defender's stats]
!!VRv3&x1=1:Sy3; [if magic strengthened, spell power
increases]
!!VRv3&x1=2:S1-y3; [if magic is weakened, spell power reduces to 1]
!!VRv4&x1=1/v6>=0:Sy4; [if magic strengthened, spell
power increases]
!!VRv4&x1=2/v6>=0:S1-y4; [if magic is weakened, spell power reduces to 1]
!!HEv5&x1<>0:Fd0/d0/dv3/d0; [modify spell power]
!!HEv6&x1<>0/v6>=0:Fd0/d0/dv4/d0; [same for
defender]
** post-battle starts here
!?BA1;
!!BA:E?y1; [network battle?]
!!FU2&y1=0:Pv1; [if not, undo changes]
!?FU2;
!!VRx1::10%3; [get change type]
!!VRv3:*-1; [negate attacker's changed stat]
!!VRv4:*-1; [negate defender's changed stat]
!!HEv5&x1<>0:Fd0/d0/dv3/d0; [restore attacker's power]
!!HEv6&x1<>0/v6>=0:Fd0/d0/dv4/d0; [restore
defender's power]
** pre-visit trigger
!?OB2/2/0; [When object at (2,2,0) is visited]
!!OW:C?y1; [get current player color]
!!OW:Iy1/?y2; [is current player an AI?]
!!IF&y2=0:Q1/6/0/21/134/33/0/2^You
notice
a small stand
set up
near the star
axis. A faerie dragon calls
out to you, "Have fun with the
nature of magic!
Only 100 gold
will advance
the magic counter five times
as much as it normally would when visiting the axis!"^;
!!OW:R-1/6/?y3; [find out how much gold the current player has]
!!IF&y2=0/-1:M^Disappointed, the dragon turns to another
potential customer.^;
!!IF&y2=0/1/y3>=100:M^"Very good! I knew you'd
want to do it!"^;
!!IF&y2=0/1/y3<100:M^"I'm glad you are interested,
but you don't seem to have the gold on hand. Do
come again!"^;
!!VRy4:S0R1; [coin flip]
!!IF&y2=1:V1/y4; [set the flag to the flip]
!!OW&1/y3>=100:R-1/6/d-100; [deduct 100 gold, if appropriate]
!!VRv2:S0; [initialize v2 to 0]
!!VRv2&1/y3>=100:+4; [set v2 to 4 if payment was made]
Basics | VR RECEIVER & VARIABLES EASILY EXPLAINED |
Erm For Dummies, by Qurqirish Dragon |
I have introduced a lot of commands in this script. If you
were looking in the script editor's help file, you almost
certainly noticed that many of the commands have many more
options than I have introduced. I am therefore going to
elaborate on some of the commands in more detail.
Please note that I will be following along with the help file
within the editor, and so if a command is documented well
enough in there, then I will only mention what an option does,
but not go into the details.
Going in order through the script, the first command seen is
VR.
In the help file, you will see the syntax at the first line:
!!VR@:XXXX
Any place you see an @ in the help is a place for a variable
name- specifically the one that the command is working with.
XXXX always indicates that there are options that can be used
with the command. If you click on Options,
you will get a list of them.
Most of the variables are well explained here, but I will
elaborate on a few:
c stores the current day- it does not store month/week/day.
Thus, the 4th day of month 2 week 3 is stored as 46, as it is
the 46th day of the game. If you need the month or week of the
map, you can find them this way (and store in v1):
Month: !!VRv1:Sc+27:28;
Week: !!VRv1:Sc+6:7;
Week of the month: !!VRv1:Sc+6:7%4+1;
Day of the week: !!VRv1:Sc%7+1;
d is used to modify a value. You can add or subtract a number,
but you can only ADD a variable. So, if you wanted to subtract
variable v1, you would first need to negate it, in a separate
instruction. In most cases, it is best to use another,
temporary variable to hold the negation, so you do not change
what you are holding onto. If you keep good records of your
permanent variables when scripting, then do whatever you are
more comfortable with.
e variables are the only ones that can hold a floating point
value. In most cases, you won't need to use one, as the
numeric range of the variables is very large, and so you can
multiply by a fraction simply by multiplying by the numerator,
and then dividing by the denominator. Only if you are going to
use very large numbers in a fraction will you need these. When
displayed in a message, an e-variable only gives the first
three decimal places, but the stored precision is much more.
w variables are actually 155 variables each- one for each hero
in the game. Thus, variable w1 holds 155 values- one for each
hero. w2 holds 155 values, and so on. You must use the IF:W
command to tell ERM which of the 155 values you want.
ERT z-variables are special variables
that take in text from a supplementary file. They were
introduced to make regionalization of scripts easier. In
general, you should not need to worry about them, and this is
all I will say on them, as it doesn't apply to basic
scripting.
Options for VR:
In the options, if you see a $, it means that you can either
set the value (by putting a number or variable in the
position) or you can read in the value to a variable by
prefixing the variable name with a ?.
If you see ?$, then you can only read in the variable.
If you see #, then you can only set a value. Most of the time
common sense will tell you what is allowed. For example,
!!VRv1:+?v2; makes no sense- you can't add a number that will
be stored; the number must already be available to be added.
Going through the list, we have:
C$1/$2/.../$16
This allows you to read in and/or set multiple values in one
statement. Up to 16 consecutive
v-variables can be worked with. Thus, if you have 6
numbers in the list, and the VR command is operating on
variable 57, then this will set or read variables 57 through 62.
Rx
This generates a random integer between 0 and x, and ADDS it
to the variable in the VR command. Note that in the help file,
this should read R#, as you
can use any stored value for the limit or the random number.
If you want to generate a number between 1 and 10, you would
code it as !!VRv1:S1R9; This sets v1 to 1, and adds a number
between 0 and 9 to it.
S#
This sets the variable to the number given.
T$
This is another random number routine. Again, it should read
T#, as it makes no sense to
set a random number- it isn't random then, is it? There is an
advantage and a disadvantage to using T instead of R. The T
option is a time-based generator. This makes the numbers more
random than the R option, which isn't. However, if you need to
generate multiple random numbers without any delay (such as
showing a message), then it is likely that the system clock of
your computer will not have advanced enough to give a truly
random number. You may even get the same number multiple
times. Thus,
!!VRv1:S3T5T5T5;
will not generate a number between 3 and 18 (simulating a roll
of three dice), but rather give a random number from the
choice of 3,6,9,12,15,18. If you need to do this, then
!!VRv1:S3R5R5R5;
is the better choice.
Logical operators:
These are actually used anywhere you want to use a conditional
expression, but since they are explained here in the help and
are very useful to know in general, I will list them here.
They are explained quite well in the help file.
Use & to indicate a logical AND in your conditions
Use | to indicate a logical OR
Use X to indicate a logical XOR (exclusive or)
Use / to indicate the same operator as previously used.
You must have all AND conditions first, and ll OR conditions
next. Note that if you have both, All the ANDs are counted
together first, and then the ORs, so if at least one OR is
true, the whole statement is true. This is because ERM
evaluates expressions left-to-right. This also makes multiple
XORs very hard, if at all possible, to code.
Arithmetic operators
These were covered above, but in summary,
+ is addition
- is subtraction
* is multiplication
: is division
% is modulus
Again, all math is done left-to-right. Thus,
!!VRv1:S0+5+6*3+2;
gives v1 the value of 35 (5+6=11; 11*3=33; 33+2=35) and not
25, as algebraic order would say (6*3=18; 5+18+2=25)
String operators
H#
Set flag # to true if the z-variable is empty, and false if
not.
S^TEXT^
Set the z-variable to the text between the carats. Remember
that ^ and ; cannot be used in the text.
Within the text string, you can show the contents of a
variable by using a % followed by the variable name, using a
capitol letter instead of a lower-case one. For flags, which
have no letter normally, use an F. For common variables that
have no numbers, prefix them with a V. Although not listed in
the help file, %Z can be used for z-variables. To display a
percent-sign, use %%.
+
When working with strings, + is used to concatenate two
strings. either string may be a z-variable or text (within
carats).
There is a very nicely described
example of the H option in the help file, but I will give a
simple example here.
!!VRz1:H1;
This takes a look at (text) variable z1. If it is a null
string (say you set it with !!VRz1:S^^;),
then flag number 1 is set to false (0). If there are only
spaces, tabs, new lines, etc. in z1, flag 1 wil also be 0. If
there is actual text in z1, then flag 1 will be set to 1.
Copying from the help file:
!!VRz100:S^Hello!^;
!!VRz101:S^^;
!!VRz102:S^ ^;
!!VRz100:H300; flag300=1
!!VRz101:H301; flag301=0
!!VRz102:H302; flag302=0
Note that anything after the ; in any given line is a comment.
Basics | OB TRIGGER & RECEIVER EASILY EXPLAINED |
Erm For Dummies, by Qurqirish Dragon |
One of the things that most people want to do is to create or
change a map site. This is because sometimes there is
something you want to do on a map, but there is no way to do
it. Take the script from earlier in this thread. There is no
map site that lets you alter the global effect of spell power,
so we had to create one.
In this lesson, I am going to start with the OB commands.
First, the trigger:
As with all triggers, the command begins with
!?. Since map objects often have
hard-coded effects, such as the star axis, there are two forms
of the trigger.
!?OB is a trigger for a
script that will run before the
normal effect of the map object.
!$OB is a trigger for a
script that will run after the
normal effect of the map object.
If you use an object which has no hard-coded effect, then
either form will work. However, consider that other scripts
may use the site also, and so all pre-visit scripts will run
before any post-visit scripts.
Both the pre-visit and post-visit triggers work the same, so I
will only explain the pre-visit trigger's format. The only
difference in post-visit is using !$ instead of !?
You can have up to three numbers follow the trigger, each form
has a different meaning:
With one number, all objects of the same type as the number
will cause the script to run. For example:
!?OB17;
Will trigger any time a creature dwelling (type 17) is
visited. For a list of map objects, look at the
Format OB list.
With two numbers, all objects of the same type as the first
number, and the same subtype of the second number will cause
the script to run. On the OB format page, anything which has
subtypes has a link to the appropriate list. Example:
!?OB17/81;
Will trigger whenever a Diamond Dragon dwelling (type 17,
subtype 81) is visited.
With three numbers, only the object at the (x,y,level)
location will trigger the code. Example:
!?OB2/2/0;
Will trigger only when the object at (2,2) on the surface
layer is visited. Note that in this last case, the location
must be seen in the map editor as a
yellow square when the
passability feature is turned on.
---------------
The OB receiver has a
different use. It is used to check or modify the attributes of
an existing object. The general form for this command is:
!!OB#1/#2/#3:XXXX;
The three numbers indicate the location (x,y,level) of the
object. Note that some objects have more than one yellow
square, so if you are working with one of those, you need to
duplicate your instructions for each such place. Of course,
you could make an object with two yellow squares do different
things at each. (say an "entrance" and an "exit" space). As
always, XXXX indicates that there are options that can be used
with this command.
Finally, before I describe the options, note that some map
objects have special receivers, and have additional options
that are not part of the general OB formats.
Check the list of
Other Objects
(Miscellaneous object receivers)
to see if there are extra functions available for the object
you are scripting. In general, these are objects that give
resources, artifacts, or secondary skills. They have commands
to let you specify more exactly what you want. There are 23 of
these special object receivers. Note that these are only extra
receivers. For a trigger, the OB
receiver is always sufficient, regardless of the object type.
Now, the general !!OB options. Note that I skip the C option,
as I am uncertain of its function.:
B
This removes a description hint for the object. If the objects
has a default hint text, this option will restore it to this
message. Thus, if you make an object revert to its normal
function, you can restore the hint text without manually
replacing it.
D#
This prevents a particular player from using this object. You
may find this more convenient than hiding something behind a
border guard.
E#
This allows a particular player to use the object. Note that
by combining D and E commands, you can create your own style
of quests, which may not be available for a seer's hut. Simply
prevent a player from using an object (with D), and then when
certain conditions are met, you can re-enable it (with E).
This will also allow you to have multiple players able to
complete the same quest.
H$
Read or set the hint text for an object to/from a z-variable.
Remember that you do not need to store the default text- the B
option lets you restore that.
M$1/$2/$3
This command lets you automatically force an answer of "no" to
a yes/no type question. As the help file indicates, this
command is still in testing, so you can check there if you
want the full details. In general, if you want to force a
particular action at a site that normally has a question, it
would be best to disable the object, and code in what you want
to happen in an OB trigger command.
R and S
These are, respectively, enable and disable commands which
apply to all players. This way you don't have to use eight D
or E commands to completely turn an object on or off.
T$
This is to get or set the type of object visited. For example,
if you had a diamond dragon dwelling at (4,5,1), then:
!!OB4/5/1:T?y1;
would set variable y1 to 17.
!!OB4/5/1:T2;
Would leave the graphics the same, but change the dwelling
into an Altar of Sacrifice (object type 2)
U$
This sets the subtype of the object. Thus, if we left the type
as 17, and gave the command:
!!OB4/5/1:U?24; Would change it into
a green-dragon dwelling. Again, it leaves the graphic as it
was.
That's all for the OB commands. My next post here will cover
the fairly extensive list of !!HE options.
Basics | HE RECEIVER EASILY EXPLAINED |
Erm For Dummies, by Qurqirish Dragon |
The next thing that most people want to do, is to be able to
manipulate the attributes of a hero. This can be to add new
skills- or remove them! Makee them faster, change their
specialty skills, and so on. Most of these changes are
gathered together in the extremely powerful !!HE receiver. I
only used a small fraction of this command's ability in the
sample script above.
There are three ways to identify a hero with this receiver.
You can identify a hero by location, by hero number or by a
trigger.
To identify a hero by location, you can use the standard
three-number method, as we have used before:
!!HE4/7/0:XXXX
This says to do XXXX to the hero located at (4,7) on the
surface.
To address a hero directly, you use just the hero number:
!!HE5:XXXX
will apply the options (remember that XXXX is a placeholder!)
to hero number 5 (Sorsha)
You can find all the hero numbers by checking Format H- there
is a link on the !!HE receiver help page.
If a hero has triggered some code, then you can identify him
or her by using the direct format, with the hero number being
-1. This is most useful if you want to make multiple sites do
something, or if you want to have an artifact do something
when equipped or removed- so you cannot tell where a hero will
be when a script is activated.
Now for the options, and there are a lot of them!
There are four options dealing with artifacts.
A#
This is used to give or take an artifact from a hero. To take
an artifact, make it negative. Check format list A1 for the
artifact numbers. For example,
!!HE5:A26;
Will give Sorsha a rib cage (artifact #26)
!!HE5:A-7;
Will remove any Centaur's Axes (artifact #7) from her backpack
and from her hand, if equipped. Any artifact that is given
this way will be placed in the hero's pack.
A1/$1/$2;
This command equips an artifact on the hero. $1 is the
artifact number, and $2 is the location to be equipped. Format
AP has the list of positions.
If we wanted Sorsha to equip that rib cage we just gave her,
we would code:
!!HE5:A1/26/5;
Equipment position #5 is the torso, the place that the rib
cage should be placed. If there is already an artifact
equipped there, then flag number 1 will be set to 0, otherwise
it will be set to 1. You may want to have a script do
something special if an artifact is already equipped where you
want to place another. This also helps for equipping a
miscellaneous artifact, as there are five places it can go,
and some may be used. You may want to check if a slot is open
first by coding:
!!HE5:A1/?y1/5;
y1 will have the number of the artifact on the torso.
A2/$1/$2/$3;
This checks to see if an artifact is owned or equipped. the
first number is the artifact number, the second number is the
quantity of that artifact owned, and the third is the number
equipped. These numbers cannot be set- if you try, ERM will
ignore you.
An example from my Cards of Prophecy script:
!!HEv1300:A2/47/0/?v1301; [Attacker has Cards of Prophecy
equipped?]
This checks to see if the hero, whose number is stored in
variable v1300, has any Cards (artifact 47) equipped, with the
result placed in v1301. It turns out that this command runs in
a battle, so my comment reflects this- the attacking hero
number was stored in v1300. The 0 for the quantity owned is
purely a place-holder. As I said, you cannot set this number.
A3/$1/$2/$3
This command is to remove some (but not necessarily all)
copies of an artifact. Again, the first number is the artifact
number. The second number says how many of these to remove,
and the third number is a flag. If the flag is 1, then an
equipped artifact will be removed before ones in the backpack.
If it is 0, then ones in the backpack go first.
B0/$
This is to get or change the name of a hero. For example,
!!VRz1:S^Sara^; [store text]
!!HE5:B0/z1; [set new name]
Will change Sorsha's name to Sara for the remainder of the map
(or, of course, until changed again). This is useful if you
want a story map, but allow the player to choose a starting
hero- at the start of the map, you change the name of the hero
at the place this one starts, and change his/her name.
B1/$
This command will change the biography of a hero. Maybe after
a major battle, you want to acknowledge this in the hero's
bio. For example:
!!HE5:B1/?z1; [store old bio]
!!VRz2:S^ She has conquered the Lich King's armies.^; [store
text]
!!VRz1:+z2; [add text to old bio]
!!HE5:B1/z1; [set new bio]
I think the comments explain this well enough.
Next are a set of monster commands. After all, a hero will
usually be accompanied by one to seven monster stacks- it
would be nice to be able to work with them. There are four
such options.
C0/#1/$2/$3
This will take the monster stack (or lack thereof) in the
hero's army slot numbered #1 and set or check the type ($2)
and quantity ($3) of those creatures.
The hero's army slots are numbered 0 though 6. Let's say we
want to change all the creatures in the current hero's first
army slot into peasants. Yes, this is a nasty thing to do in
general, but why not? We code this as:
!!HE-1:C0/0/139/d;
Recall that for hero numbers, -1 means the hero that triggered
whatever is happening. the 0 refers to the first slot. 139 is
the monster number for a peasant. The d in the last position
is a placeholder, leaving it alone- since we do not wish to
change the quantity. Remember that the value d is used to add
whatever number follows the d to the number in that position.
Since there is no number after the d, no change is made. d0
would have had the same (lack of) effect.
C1/#1/$2/$3
This works similar to C0, but instead of looking at creatures
in slot #1, is changes all
creatures of type #1 to type $2. So,
!!HE-1:C1/132/139/d;
Will change all of a hero's azure dragons (type 132) into
peasants. (This is not an action a map designer should take
lightly, as you may find nobody will play your maps anymore!
:-)
C2/#1/#2/#3
This gives a stack of monsters of type #1 and quantity #2 to
the hero. #3 is an instruction for what to do if there are no
open army slots. If #3 is 1, then the player will get the
"make room for these creatures" dialogue. If it is 2, then the
AI will make the choice automatically. Most of the time, you
will want to check if the hero is owned by a human or the AI,
and set the flag accordingly.
C#1/#2/.../#14
This is similar to C2, but gives up to 7 extra stacks of
monsters. You must supply all 14
parameters. The odd numbered positions are the creature types,
and the even numbered positions are the quantities. Use -1 to
indicate no creature (so you can give less than 7 stacks.
For instance, if you want to offer one of each of the
Armageddon's Blade dragons to Fafnir (hero 37), you would
code:
!!HE37:C132/1/133/1/134/1/135/1/-1/0/-1/0/-1/0;
For all remaining examples, I will be
using hero -1 (current hero), if it is allowed.
D
This calls an upgrade dialogue- similar to the one you get at
a hill fort.
E$
E$1/$2
These are used to check or modify a hero's experience. If you
have two numbers, the first number is for experience total,
the second is for the hero level. Do NOT set both of them. I
strongly suggest that you only use the one-number version if
you are changing a hero's experience total, and use the
two-number form to check the hero's level. In the two-number
form, you can also add a /1 to the end, which will prevent the
game from redrawing the screen. In some cases, this may
prevent graphical artifacts from appearing on the screen when
the script runs. several other options also have a no-redraw
command. Check the help file for which ones do.
Thus, to give 1000 experience, you would code:
!!HE-1:Ed1000;
To increase the hero's level by 2:
!!HE-1:E?y1/d2;
F$1/$2/$3/$4
This command gets or changes the hero's attack ($1), defence
($2), spell power ($3), and knowledge ($4). If you are
checking the statistics only, then
you can use the /1 option at the end. This will give you the
hero's base statistics, rather than their values after
artifacts are included. You may recall this one being used in
our spell-power script.
H$1/$2/$3/$4
This lets you set the monsters for new heroes in the hero
pool, when they appear in the tavern. This sets the monsters
in slot $1 to type $2, with a range of $3 through $4. You can
only set the first three slots (0,1,2) for these heroes. Also,
the game randomly decides if there will be 2 or 3 monster
stacks for new heroes, so you can force a hero to have 2
monster stacks by setting slot 2 to creature type -1, but you
cannot force a hero to get three creature stacks. You can, of
course, set slot 1 to -1 also to force only one stack.
Also note that any heroes that are
currently available in any player's taverns will not
have his or her armies modified until the next week.
Also, note that the examples in the help file may be missing
the colons in the syntax (it may be fixed in an update I
haven't installed yet). Otherwise they are correct.
For example, to have Orrin start with only one creature in
slot 1, you would code:
!!HE0:H0/?y1/1/1;
I read in the creature type, so it is not altered.
I$
I$/1
Similar to the F option, this options lets you change the
spell point total. Note that it is possible to give a hero
negative spell points with this command. It won't cause a
problem, but it can be confusing to the player to see spell
points listed as -6/30 or something similar. Obviously, you
cannot cast spells if you have less than 0 spell points.
K
This command kills the hero, immediately. I don't think
further explanation is needed here.
L#^path\filename.pcx^
This lets you change the portraits of the hero. If # is 1,
then you are setting the small portrait- such as the one in
the hero list. If the # is 2, you are setting the large
portrait- like the one in the hero screen. Inside the carats
is the location of the pcx file, relative to the
DATA directory in the heroes3
folder.
The total length of the path+filename can only be 12
characters, so it is best to have these files in the data
directory, rather than elsewhere. For instance, if you have
the pictures in the maps directory, the filename would have to
start with "..\maps\" this already uses eight of your 12
characters.
L3
This restores the portraits to the defaults.
L#/$
If # is 0, the portrait of the hero is set to portrait number
$; IF # is 4, both the large and small portraits are set.
I am uncertain of the use for the L5 option, and of the
indexing in L0 and L4 (although I believe portrait number $ is
the portrait of hero number $)
M#1/$2
This checks or sets a spell inside a hero's spell book. #1 is
the spell- format SP lists all the spell codes, and $2 is a
flag. If the flag is 0, the spell is not in the book (or will
be removed if you set it). If the flag is 1, then the spell is
in the book (or will be added). You should check to see that a
hero has a spell book equipped first- easily done with the
following:
!!HE-1:A2/0/0/?y1;
This checks to see if a spell book (artifact 0) is equipped. y1
will be 1 if there is a spell book, and it will be 0 if not.
N?$
This gets the hero number for the hero. This is good if you
want a site to work differently for different heroes. You can
use the hero-location, or triggering hero form of the !!HE
receiver for the script, and get the hero number with this
option.
O$
This sets or checks the owner of a hero. -1 indicates no
owner, and 0 through 7 indicates the various colours. You can
use this command to have a script only effect certain players,
or even to cause heroes to change allegiance. You can even add
a new player into the game by setting to an unused colour!
P$1/$2/$3
This command moves the hero to location ($1,$2,$3). You can
use this to teleport a hero without a lith, or to bring a hero
out of the hero pool, directly onto the map. Of course, moving
an un-owned hero onto the map should be followed by an HE:O
command, to give ownership of the hero to one of the players.
If you want a teleport sound when moving a hero, then you can
add an additional /$ to the end of the option. if $ is not 0,
you will get a sound. According to the help file, you cannot
use this option with the active player's hero. I have not
tested this, so cannot confirm or deny this.
R#/$
This sets or checks various small parameters for a hero. If #
is 0, then you are setting or checking the hero's morale. This
is, of course, only guaranteed to be accurate until a battle.
If # is 1, you are setting or checking luck. If # is 2, you
are checking the hero gender. Some dialogues will sound better
if you check this first, and modify the text to get pronouns
correct. If # is 4, then you are checking the tactics control
of the hero. -1 indicates it is enabled, 0 indicates disabled.
R3/$1/$2
This sets the availability of a hero to be hired. If $1 is 1,
the hero can be hired. If it is 0, then the hero cannot. If $2
is left out, this is for all players. If $2 is present, it is
checking for individual players. This uses the bit-notation
value, so red=1, blue=2, tan=4, green=8, and so on. Add the
numbers for all the colours you want to set.
Disabling an active hero will kill it.
S#1/$2
This option is used to set or check what secondary skills a
hero has. The first number is the skill number (format SS
lists them), and the second number is the skill level, with 0
being no skill, 1 being basic, 2 being advanced, and 3 being
expert.
If a hero is given more than 8 secondary skills, s/he will
still gain the benefits of all of them, but only the first 8
will be seen on the hero screen. For example, in my Cards
script, if knowledge is changed, I need to adjust the spell
points as well. To do this, I need to check if the hero has
the intelligence skill (skill 24), so I used this line:
!!HEx1:S24/?y9;
Here, x1 is the first parameter passed into a function- my
script sends the hero number for the effected hero this way.
T$1/$2/$3/$4/$5
This forces a hero into a battle against monsters of type $4,
and quantity $5. The battle will take place on the terrain of
the type found at location ($1,$2,$3) on the map. The hero
will not move to that place- the location is only to get
things such as native terrain bonuses, and the background
picture.
U$1/$2/$3
This command will check or alter the patrol area for an AI
hero. Although the patrol cannot be moved to another level,
the x and y location for the center of the patrol can be set
to ($1,$2), with a radius of $3. A patrol radius of -1 frees
the hero from patrolling.
V#1/$2
V#1/#2/$3
This is used to set or check if a map site has been visited.
This is specifically for 10 objects- they are all listed in
the scripter help file. For both forms, the first number is
the type of map site.
In the first form, the second number is the bit-value of all
32 sites. (you cannot have more than 32 of certain objects on
the map). Thus, 1=the first site, 2= the second, 4=the third,
and so on, up to 2,147,483,648 for the 32nd site. Add the
numbers to set all of them- if the site has been visited, add
in its value, if not skip it. Obviously, if you only have a
few sites on the map, you don't need to worry about the
high-powers of 2 that appear. Use the calculator that comes
with Windows to type the number in binary, and convert to
decimal if you don't want to chance making an error by hand.
If you don't want to check or set all of them- and usually you
will only be interested in one at a time, then you use the
second form. In this form, the second number is a number from
0 through 31- indicating which of the sites you want to set.
$3 is a flag value, set to 1 if the hero has visited the site,
and set to 0 if not. By use of this, you can allow heroes to
revisit sites that are normally one-time only.
The help file has several good examples, so check them out if
you need them.
W$
This lets you check or modify the hero's movement points. 100
movement points is roughly equal to one step horizontally or
vertically, on terrain with no penalty or road. Note that if a
hero has movement changed, then even if the hero has not moved
that day, s/he will be unable to dig for the grail. The
double-movement Wogify option had this problem. I believe that
it was fixed for 3.57f, but the change may not have made it
(and will appear in a script update sometime soon)
X
All the X options deal with hero specializations.
X0/$
This sets the hero's specially to the secondary skill with
number $. Not all secondary skills make sense for a specialty-
but of course you could always write a script that does make,
say, a wisdom specialist have meaning.
X1/$
This makes the hero a creature master, of creature type $, and
if the creature is upgradeable, also the upgrade. This involves
giving all creatures of that type +1 speed, and an attack and
defence bonus proportional to the hero level divided by the
creature level. (always at least 1 bonus point to each)
X2/$
This makes the hero generate resource of type $ daily.
X3/$
This makes the hero specialty spell number $. Again, not all
spells make sense- for instance what does a specialization in
dispel do?
X4$1/$2/$3/$4
This gives the hero a creature specialty in creature type $1,
giving a flat bonus of $2 attack, $3 defense, and $4 damage.
Again, if the creature has an upgrade, it will gain the bonus
also.
X5/2
This is to set the specialty to Sir Mulloch's specialty (+2
creature speed to all creatures).
X6/$1/$2/$3
This allows the hero to upgrade creatures of types $1 and $2
(and possibly their upgrades, if any) to type $3. Cost will be
the difference in purchase price between the base and upgraded
forms.
X7/$1/$2
This makes the hero's specialty a flat attack ($1) and defense
($2) bonus to all dragons.
X8/1
This causes the hero to spread a shroud of darkness wherever
s/he travels.
X8/2
This allows the hero to rebuild towns that have been destroyed
as any town type (rather than just the old type or the hero's
type)
Y$1/$2/$3/$4
This sets or changes a blessing or curse that has been placed
on the hero. The blessing or curse type is type $1- and there
is a list of them in the scripter help. The link is in the
HE:Y description. $2 is the power of the curse or blessing
(how severe it is). $4 says what to do with the curse. If $4
is 0, then the blessing or curse is removed. If $4 is 1, then
the curse or blessing is to last for $3 days. If $4 is 2, then
the duration of the curse or blessing will be extended by the
amount $3. A negative value in $3 will reduce the duration of
an existic blessing or curse of the same type (if one is
present)
Y2/$2/$3/#
Curse type 2 prevents a hero from using a particular artifact
slot. $2 is which slot is sealed. If $2 is -1, then a random
slot is chosen. $3 is the duration, as above, and # is the
set/remove/extend option, as $4 in the other curses.
I have left out examples for many of the options. Feel free to
ask for an example. I think my explanations are good enough,
but I could be wrong :-/
Basics | UNIVERSAL FORMAT |
All Triggers,
Receivers and
Instructions share a common format:
Header [:Body]
;
Optional elements are in square brackets. In particular,
triggers have no Body.
Header contains information about what kind of object
it denotes: Trigger (T), Receiver (R) or Instruction (I), also it contains
optional information whether the object executable.
Body contains executable
ERM commands, according to type of the object (R or I).
All ERM commands (receivers, instructions) have to use at least one parameter in
order to work correctly.
Headers
have the following
format:
!{?|!|#}AB
[ Identifier ] [ Conditions
]
Select only one element from elements in braces
separated by '|'( '?','!','#'- means T, R, I accordingly ).
String 'AB' defines
- type of the T, R or I (see later).
Identifier - number denotes object.
Conditions - conditions of "execution" of the following Body for R
and I or all R-s for T.
If there are no Conditions, then T, R, I executes
"unconditionally".
Identifiers have the following format:
N[/N[/N[...]]]
Symbols 'N' mean decimal numbers, number of which
depends on type T, R, I (see later).
Conditions have
the following format:
&N[/N[/N[...]]]
Symbol '&' separates numbers in Conditions from
Identifier.
Execution can depend on Conditional Flags
(CF) (there are 1000 of them). If you want to make T, R or I dependent on
a CF, you should write its number (from 1 to 1000) between these numbers.
If
the flag number is positive, then condition is - "if flag is set", if
negative, then - "if flag is not set".
Variables comparisons can also be used as conditions of execution. See the VR
receiver section for more information on variables.
Body has format,
depending on type of T, R, I (see later).
If a command parameter is shown as $ it means that its value can be stored in
a variable. If it's shown as # it means that it can only be set, but not read.
And if it's shown as ?$ it means it can be read but not set.
Example:
!!LE10/33/1&1/-2/5:E500 O2 L0;
This is a Receiver of type LE (event on map) with coordinates X=10, Y=33, Level=Underground. Receiver Body has 3 commands:
E, O and L (see: LE Receiver). These commands (Body) would be executed only if at
the execution moment, the 1st and 5th of the conditional flags are set, but
the 2nd is not set. Otherwise, the Body won't execute.
Whenever a player activates a trigger it causes some actions on one or more
receivers. A trigger can be an event, object or hero that a player's hero
visits, or it could be an ERM function called by other ERM code or even a
timer set up to trigger at a specific time or interval (e.g., every 14 days). The properties of the trigger event
or object do not matter for purposes of it being a trigger. The action of the
trigger must be described in a timed event. Instructions use the basic same
format as receivers, except that they start with a slightly different code.
Unlike receivers, Instructions execute only once when the map is loaded.
For detailed information about triggers, including a complete list, see the
Triggers
Page.
For detailed information about Receivers and Instructions, including a
complete list, see the Receivers Page.
You cannot use a semicolon or ^ inside message
text (text enclosed in ^ symbols, used to display a message on the screen).
So ^This is a message, this is also^ is correct.
And ^This is a message; this is also^ is Incorrect.
What is the purpose of 3 WOG different Object files (ZA, ZE, and Z)?
ZObjects.txt - used for Heroes executable
(h3wog.exe)
ZEObjcts.txt - used for map editor.
ZAObjcts.txt - used for Heroes executable random map generator.