ERM for dummies

Official forum of the Wake of Gods mod to Heroes of Might and Magic III.
User avatar
Gaidal Cain
Round Table Hero
Round Table Hero
Posts: 6972
Joined: 26 Nov 2005
Location: Solna

ERM for dummies

Unread postby Gaidal Cain » 31 Dec 2005, 13:11

This is intended as a repost of Qurqirish Dragons' old thread , in which he tried to explain ERM so that people who've never coded before would be able to use it. Unfortunately, Forumplanet's code has messed up some of the code below, which might make it unclear on some points (this is generally true when the comparators < and > (lesser than and greater than) are used. If you see something like &gt or &lt, it's these operators). If there's something that seems incomplete in this way, please report and we'll try fixing it or at least put in a note about it.

Since ERM also isn't static, it's possible there are better ways to do some things described here, that it sin't complete or that some of the things described here no longer works at all. To avoid this causing trouble, refer to your documentation. None of it should should prevent this from being a useful introduction to ERM, though.

This thread is also intended as a good place to ask questions about ERM, and to make this easy to use, the whole first page will only contain the lessons, and not any 'general stuff'. This is why there is some "empty" posts at the bottom. Otherwise, one would have to scroll through these long lessons just to get to the discussion.

Lastly, I've marked up parts of the lessons with blue. These are either code parts in the middle of some text, or something that's being explained in the present part. This should help when you're searching for an explanation of something. However, this markup is by no way complete. I've also added some comments of my own in certain parts. They are all in dark blue. I've also taken the freedom of correcting some spelling mistakes and to add some headers for easier use, as well as clearifying one or two passages. There has also been created an index below to help finding help on a specific subject. One problem with this index is that it right now opens the link in a new window, but it might still be of some use.

We hope you'll find this useful, and help populate or sqript directories with many new, interesting scripts!

Index
Lesson 1: Introduction
Lesson 2: Time for Battle!
Lesson 3: More on messages
Lesson 4: Variables!
Lesson 5: Objects
Lesson 6: Heroes
Lesson 7: Even More Messages!
Lesson 8: The sphinx
Lesson 9: To the Battlefield!
Lesson 10: The struggle continues
Lesson 11: The Cards of Prophecy
Last edited by Gaidal Cain on 01 Jan 2006, 12:49, edited 9 times in total.

User avatar
Gaidal Cain
Round Table Hero
Round Table Hero
Posts: 6972
Joined: 26 Nov 2005
Location: Solna

Unread postby Gaidal Cain » 31 Dec 2005, 14:12

Lesson 1: Introduction

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 Tool 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 installments, 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:

Code: Select all

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):

Code: Select all

!?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:

Code: Select all

!!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:

Code: Select all

!#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 installmanet, I will explain a couple simple commands, so you can do SOMETHING. The second installment 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:

Code: Select all

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:

Code: Select all

!#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:

Code: Select all

!?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 says "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!#):

Code: Select all

!!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 arithmatic 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:

Code: Select all

!!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 or a semicolon. 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:

Code: Select all

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]
In the next installment, I will cover the FU, BA, and HE commands, and show how to do a simple battle script.


Questions/answers on lesson 1
Question: When I uncheck the "Apply event to human players" box, the box labled "Apply event to computer players" is checked. It wants one of the boxes to be checked. Is this right? I can't get both boxes unchecked.
Answer: That's OK. The only reason you do not want the player to see the event is that, well, it would look rather odd, wouldn't it?

Question: When you say the ERM help file, I assume you are talking about running erm_help\index.html. I can't find anything labled "List of the Claimed". Where is this easily found list?
Answer: There's a button "Claimed" at the top. There you'll find all claimed variables, flags, timers and fuctions(these are for pre-made scripts only! If you're making a map on your own, and don't plan to use someone else's script, please ignore the list).
Last edited by Gaidal Cain on 01 Jan 2006, 12:10, edited 4 times in total.

User avatar
Gaidal Cain
Round Table Hero
Round Table Hero
Posts: 6972
Joined: 26 Nov 2005
Location: Solna

Unread postby Gaidal Cain » 31 Dec 2005, 15:12

Lesson 2: Time for Battle!
Whenever possible, I am going to state the goal of a lesson before it begins- this way if you already know how to do what I have listed, you can feel free to skim or skip the lesson.

In this segment, 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, cyclicly. 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:

Code: Select all

!!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:

Code: Select all

!!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:

Code: Select all

!!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 visiter number [whatever], you feel the world's magic power strengthen."
We want to have another message that says "You are visiter number [whatever], you feel the world's magic power weaken."
We want to have a third message that says "You are visiter 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:

Code: Select all

!!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 and semicolons are still not allowed.

Now we need to display the new message:

Code: Select all

!!IF&y1=0:M^You are visiter 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:

Code: Select all

** 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:

Code: Select all

!?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:

Code: Select all

!!BA:E?y1; [is this a network battle?]
This is a BA receiver. The E option says "find out what kind of battle is occuring." ?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:

Code: Select all

!!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:

Code: Select all

** 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:

Code: Select all

!!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:

Code: Select all

!!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.

Code: Select all

!!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, defense, 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.

Code: Select all

!!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:

Code: Select all

!!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:

Code: Select all

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 visiter 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:

Code: Select all

** 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 want 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:

Code: Select all

!?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.

Code: Select all

!!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!
Last edited by Gaidal Cain on 01 Jan 2006, 12:10, edited 2 times in total.

User avatar
Gaidal Cain
Round Table Hero
Round Table Hero
Posts: 6972
Joined: 26 Nov 2005
Location: Solna

Unread postby Gaidal Cain » 31 Dec 2005, 15:56

Lesson 3: More on messages
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 amy 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:

Code: Select all

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:

Code: Select all

!?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:

Code: Select all

!?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:

Code: Select all

!$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, remove 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 proprieter is best.

Anyway, let's start scripting:

Code: Select all

!?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:

Code: Select all

!!OW:C?y1; [get current player color]
!!OW:Iy1/?y2; [is current player an AI?]
The C? option checks the color of the current player. You cannot change the current player, so the ? is part of the option here. I am storing this color in y1. The next line uses the I option. This lets you check a color to see if it is an AI player. The first number is the color being checked- in this case, the color 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.

Note that there's another, mayhaps easier way to check human/AI, when you're sure you're dealing with the current player(if it's a script attached to an object, for example, the only color that CAN trigger it is the current)- the flag 1000. This flag is automatically set by WoG
to 1 if the current player is a human, and to 0 if the current player is AI. It does have a different meaning in combat triggers, but it is the easiest way to check things in object scripts. GC



Now, we can ask the question.
Since this involves interfacing with the player, we again will need to use an IF receiver:

Code: Select all

!!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:

Code: Select all

!!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 color that we want to check. This value is 0 for red, 1 for blue, and so on. Check the format E1 for all the colors, 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 color set as -1. This means that we want to check the currently active color, whoever it is. We already checked the active player's color 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) color.
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.:

Code: Select all

!!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^Disappointed, the dragon turns to another potential customer.^;


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 it will spend the money. We do this with two commands:

Code: Select all

!!VRy4:S0 R1; [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.

Code: Select all

!!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:

Code: Select all

!!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:

Code: Select all

!!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:

Code: Select all

!!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:

Note: the line that was added is only partially complete in QQD's original post (probably a fault of forumplanets), and it doesn't appear in the full code listing below. I therefore omit it here. GC.
Added 3/6/2007: I have reconstructed the missing code line! it now appears here and in the completed code fragment below. -QQD

Code: Select all

!!VRy1&y1<=v2:S0; [if payment causes a change, note it]
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:

Code: Select all

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?]
!!VRy1&y1<=v2:S0; [if payment causes a change, note it]
!!VRy1&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&x1gt;0:Fd0/d0/dv3/d0; [restore attacker's power]
!!HEv6&x1gt;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/y3gt;=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]
Last edited by Gaidal Cain on 01 Jan 2006, 12:11, edited 1 time in total.

User avatar
Gaidal Cain
Round Table Hero
Round Table Hero
Posts: 6972
Joined: 26 Nov 2005
Location: Solna

Unread postby Gaidal Cain » 01 Jan 2006, 11:06

Lesson 4: Variables!
I have introduced a lot of commands in the last 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 wil 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):

Code: Select all

Month: !!VRv1:Sc+27:28;
Week: !!VRv1:Sc+6:7;
Week of the month: !!VRv1:Sc-1: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.

Not listed in the help file are the ERT z-variables. These 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:S1 R9; 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 truely random number. You may even get the same number multiple times. Thus,

Code: Select all

!!VRv1:S3 T5 T5 T5;
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 any number between 3 and 18 (with the adjusted chances that are implied by having several "dices" -GC), then

Code: Select all

!!VRv1:S3 R5 R5 R5;
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,

Code: Select all

!!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).

Questions and Answers
Question: I'm not sure what you mean when you're talking about the H# command. You're talking about flags and variables in the same statement?
Answer: There is a very nicely described example of the H option in the help file, but I will give a simple example here.

Code: Select all

!!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:

Code: Select all

!!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.
Last edited by Gaidal Cain on 01 Jan 2006, 12:11, edited 1 time in total.

User avatar
Gaidal Cain
Round Table Hero
Round Table Hero
Posts: 6972
Joined: 26 Nov 2005
Location: Solna

Unread postby Gaidal Cain » 01 Jan 2006, 11:07

Lesson 5: Objects
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:

Code: Select all

!?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:

Code: Select all

!?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:

Code: Select all

!?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. (Note: it's also possible to create a trigger square through ERM, but this is something for later. GC)

---------------
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:

Code: Select all

!!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 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 trigger 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:

Code: Select all

!!OB4/5/1:T?y1;
would set variable y1 to 17.

Code: Select all

!!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:

Code: Select all

!!OB4/5/1:U?24;
Would change it into a green-dragon dwelling. Again, it leaves the graphic as it was.
Last edited by Gaidal Cain on 01 Jan 2006, 12:12, edited 1 time in total.

User avatar
Gaidal Cain
Round Table Hero
Round Table Hero
Posts: 6972
Joined: 26 Nov 2005
Location: Solna

Unread postby Gaidal Cain » 01 Jan 2006, 11:08

Lesson 6: Heroes
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! Make 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:

Code: Select all

!!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:

Code: Select all

!!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 wil 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,

Code: Select all

!!HE5:A26;
Will give Sorsha a rib cage (artifact #26)

Code: Select all

!!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:

Code: Select all

!!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:

Code: Select all

!!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:

Code: Select all

!!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 packpack. If it is 0, then ones in the packback go first.

B0/$
This is to get or change the name of a hero. For example,

Code: Select all

!!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 wanta 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:

Code: Select all

!!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:

Code: Select all

!!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,

Code: Select all

!!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 quantitiy #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:

Code: Select all

!!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:

Code: Select all

!!HE-1:Ed1000;
To increase the hero's level by 2:

Code: Select all

!!HE-1:E?y1/d2;
F$1/$2/$3/$4
This command gets or changes the hero's attack ($1), defense ($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:

Code: Select all

!!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 spellbook. #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 spellbook equipped first- easily done with the following:

Code: Select all

!!HE-1:A2/0/0/?y1;
This checks to see if a spellbook (artifact 0) is equipped. y1 will be 1 if there is a spellbook, 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 colors. You can use this command to have a script only effect certain players, or even to cause heroes to change allegence. You can even add a new player into the game by setting to an unused color!

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 unowned 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 (male is 0, female 1. Settings it to something other than these would most likely result in a crash. GC). 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 colors 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:

Code: Select all

!!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 visiter 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 used to have this problem.

X
All the X options deal with hero specializations.

X0/$
This sets the hero's specialy 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 upgradable, also the upgrade. This involves giving all creatures of that type +1 speed, and an attack and defense 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 Mullich'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 existing 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.
Last edited by Gaidal Cain on 01 Jan 2006, 12:13, edited 1 time in total.

User avatar
Gaidal Cain
Round Table Hero
Round Table Hero
Posts: 6972
Joined: 26 Nov 2005
Location: Solna

Unread postby Gaidal Cain » 01 Jan 2006, 11:08

Lesson 7: Even More Messages!
In this section, I am going to cover the IF command. This command is for maintenance of certain variables, and dialogue boxes.

We have already seen a few of these in use, and in other threads I have explained other uses (don't worry, you won't have to search for them, I am going over all of it here)

As with the other commands I have covered in detail, IF has many options. Please look at the help within the script editor for more information. I will will only be elaborating and clarifying things here. If the help file is clear, then I will only describe things in brief.

Without further delay, here come the options for !!IF:
B#/$1/$2
This command is used to prepare an image or animation for display. You can have up to 100 prepared dialogs, and they can be in BMP, GIF, JPG or AVI formats.
Before using the command, you need to store the filename of the image in a z-variable. The index of this image (for use in other IF commands) goes in the #, and is between 1 and 100. The z-variable is placed at $1. If it is an AVI file, then $2 is a flag (1=yes, 0=no) to determine if the video should loop.
Note that this command DOES NOT show the graphic you have selected. It only prepares the graphic for later use.

D#/$1...$15
The D command is to set up (again, as with B, this does not display the dialog- it only sets it up) a dialog with a multiple-choice question. The choices to be listed are with checkboxes.
The #, again, is the index of the dialog that is being prepared (from 1 to 100). Check the help file for what all 15 parameters are- they are listed right there, and are easy to read.
Note that unlike the command for hero images (see my description of the HE command), you can have a full 256-character filename for any images used here. There is no minimum size for images, but they must be SMALLER than 100x100.

As another note, which I will reemphasize here, prepared dialogs are NOT save in a saved game file. Be certain to code in any setups immediately before you use them. Since z-variables ARE saved, you only need to store the filenames once.

E$1/$2
This command is to activate a dialog set up by IF:D
$1 is a v-variable to hold the choice made in the dialog, and $2 is the identifier of the dialog. variable z1 will always hold the text response- so do not use z1 in the setup. Of course, you should use higher-numbered z-variables anyway (check the used variable list to avoid conflicts)

As an example for the setup and use of a dialog, let's say you have images of a pile of gold (gold.bmp), a dragon (dragon.bmp) and a vampire (vamp.bmp)- all in the MAPS directory. You want to ask the player which (if any) of these things he likes- perhaps to modify later aspects of the map based on his preferences.
Then, we would code:

Code: Select all

!!VRz104:S^gold.bmp^;
!!VRz105:S^dragon.bmp^;
!!VRz106:S^vamp.bmp^;
!!VRz101:S^What do you like?^;
!!VRz102:S^Choose wisely^;
!!VRz103:S^Who are you?^;
!!VRz108:S^gold^;
!!VRz109:S^dragons^;
!!VRz110:S^vampires^;
!!VRz112:S^Do you like gold?^;
!!VRz113:S^Do you like dragons?^;
!!VRz114:S^Do you like vampires?^;
!!IF:D1/z101/z102/z103/z104/z105/z106//z108/z109/z110//z112/z113/z114/;
Note that parameters 7, 11, and 15 have been skipped- this is because there are only 3 choices, and we do not want a fourth to appear.
to set up the dialog, and

Code: Select all

!!IF:E5/1;
to save the choice made in IF:D to variable v5.
When run, a message box will appear with "What do you like?" in the title area. Under that will be the three pictures, evenly spaced. Below that will be two columns- the left will have the header "Who are you?", with a text-entry box underneath. The right column will have the header "choose wisely", with the three questions underneath. When you move the mouse pointer over an image, the description will appear in the bottom of the dialog box. When you click on a right-menu option, a checkmark will appear next to it (and disappear from the other options)

Variable v5 will have the value of -1, 1, 2, or 3. -1 will be if no choice is made when the dialog is closed. 1, 2, or 3 corresponds to the first, second, or third choices. Variable z1 will have whatever was typed in the "who are you" question box.
What you do with this information is up to you. Perhaps change the name of the player's main hero to what was typed in. Maybe give a reward of gold, dragons, or vampires later on for doing something.

F$1/../$6
Use this to add hint-text for the options in the right menu of a dialog displayed with the E command. $1 is the dialog, $2..$5 is the hint text for the four options, and $6 lets you deactivate the "cancel" button in the dialog.

G#1/../#16
Use this command to give a list of options (up to 12) You have a choice of either using a radio-button list (so only one option can be selected), or a checklist (so you can choose multiple answers).
#1 chooses the type of list. #2 is the v-variable number that will hold the result. Since there is a chance for multiple choices, this is a bit-added number. Choice 1 is valued at 1, choice 2 is 2, choice 3 is 4, and so on up to choice 12 being 2048. #3 is the default choices, set the same way. #4 is the z-variable with the window header. #5 through 16 are the indices for the z-variables containing the text for the choices.
You may recall seeing this dialog whenever you WoGify a map, with the optional map rules script active- so if you want to know how it looks, just start up a random map and look.

M
We've already used this several times. The M option lets you simply display a message.

P$
The P option displays an image that was set up with an IF:B command earlier.

Q#1/../#8^TEXT^
Again, we have already used this command. It can give a yes/no quesion, and save the result in a flag, from 1 to 10, specified in #1. The last option (which may be #4, #6, or #8) determines the type of dialogue. For just displaying a message, it should be 1. For a message with no buttons, choose 4- this is best used for messages that appear when right-clicking on something, or other similar cases. Most likely, you will use the value of 2- which asks the yes/no question. The middle numbers- 2,4, or 6 of them are the types and subtypes of up to 3 images to display. In the script we wrote above, there were 3 images. If you want fewer, simply remove the options entirely (as opposed to leaving them blank as in the example above).
In one case- the case with 2 pictures, you can also make the last option (#6) have the value 7, which lets the player choose one of the pictures (instead of a yes/no question). This only works with two pictures, since the result is still simply a flag (and so cannot choose from among 3 objects, and is pointless for only 1)

V#1/#2
This says to set flag #1 to the value #2. Remember that IF:V is used for flags, and VR is used for all other variables.

W$
Every hero in the game has 100 variables specifically for him or her. These are the w-variables, w1 through w100. Before you use one of them, however, WoG needs to know WHICH hero's w-variables you are refering to. That is where IF:W comes in. The number $ is the hero number for the hero whose w-variables you want to use. once this is used, w1 through w100 will be for the hero specified, until another IF:W command is used. If you want to refer to the hero that triggered the script, use -1 for the hero number.

X$
This calls up a sphinx riddle, use -1 for a random riddle, or another number to choose a specific one. An exact match to the riddle answer is needed for a correct response to be logged. Flag number 1 will hold the result (right (1) or wrong(0))

If you are looking at the script editor's help, there should be a link titled "Dialogue boxes" Click on it for more graphical examples of most of these interfaces.
Last edited by Gaidal Cain on 01 Jan 2006, 12:13, edited 1 time in total.

User avatar
Gaidal Cain
Round Table Hero
Round Table Hero
Posts: 6972
Joined: 26 Nov 2005
Location: Solna

Unread postby Gaidal Cain » 01 Jan 2006, 11:22

Lesson 8: The sphinx
Today's script is going to create a sphinx-like object similar to the heroes 2 version. A question will be asked- actually several questions- and if you give the correct answer to a given question, you get a reward. Failure to answer correctly results in death. The hero will also be allowed to back out- but only before seeing the question.

To do this example, I am going to assume that we are using an unscripted object, located at (2,2,0). I am going to modify the classic riddle of the sphinx.
For those who do not know it, the Riddle of the Sphinx goes like this:
"What walks on four legs at dawn, two legs at noon, and three legs at dusk?"
The answer is "a man," since at the dawn of his life- as an infant- a person crawls on all fours (legs+arms). In the middle of his life, he walks upright on two legs. In the dusk of his life -as an elderly person- he walks on three (2 legs+ a cane).

Instead of this question, we are going to ask the player how many legs he walks on. He will have three choices- morning, noon, or evening- and will have to type in the correct answer- 4, 2, or 3. We correlate these to the early, middle, and end stages of the game. In the early game, you need mostly resources to build structures, so the morning question will give a reward of 20 of each resource. In the middle game, you generally need gold to buy all those creatures and heroes to build an army, so we will give 20000 gold for the noon question. In the late game, you generally need to have movement to clean up the map, so we will give the Boots of Speed to the hero. If you disagree with my reasoning, then you can easily change the rewards as you want. This is only an example!

Now, we don't want anyone to be able to answer the same question correctly more than once. I am going to use flags 11, 12, and 13 to keep track of which questions were answered.

Let's begin:

Code: Select all

ZVSE [script begins]
!#IF:V11/0; [set flag 11 to false]
!#IF:V12/0; [set flag 12 to false]
!#IF:V13/0; [set flag 13 to false]
!?OB2/2/0; [when sphinx is visited]
Note that flag 1000 is true if a human player triggered the event. It is false if not. This is a standard feature in WoG, and will make things a lot simpler. We will use this so an AI player will ignore the question if it visits.

Code: Select all

!!IF&1000:Q1^As you approach the sphinx, a voice echoes around you:
{whoever approaches me can get a great reward, but your life is forfeit if you do not pass my challenge!}
Do you approach?^; [The hero may back out. Flag 1 holds the response. Note that flag 1000 is used so only a human player gets asked.]
Note the use of curly-brackets {}. Any text displayed within these is colored yellow. This is a standard Heroes 3 function for displaying text- not a WoG addition.

Code: Select all

!!IF&-1/1000:M^Fearing the mighty sphinx, you back away.^; [message if player declines to risk it]
!!FU1&1/1000:P; [call function 1 if player agrees to so so]

!?FU1; [beginning of main function]

** The next 13 lines sets up the dialogue for the sphinx.

!!VRz101:S^How many legs do you walk on?^;
!!VRz102:S^The time of day.^;
!!VRz103:S^The number of legs (digits only).^;
!!VRz104:S^Sunrise.bmp^;
!!VRz105:S^Noon.bmp^;
!!VRz106:S^Sunset.bmp^;
!!VRz108:S^Morning^;
!!VRz109:S^Afternoon^;
!!VRz110:S^Evening^;
!!VRz112:S^It is morning^;
!!VRz113:S^It is afternoon^;
!!VRz114:S^It is evening^;
!!IF:D1/z101/z102/z103/z104/z105/z106//z108/z109/z110//z112/z113/z114/;
Note that since the function can only be entered if a human player triggered it, we no longer need the &1000 checks when displaying the dialogue:

Code: Select all

!!IF:E1/1; [ask the question, and save the choice in v1.]
Remember that the text-answer is saved in variable z1. Now, the player was notified in the dialog to give the answer as digits, so we only need to check to see if z1 is 2, 3, or 4. If the player typed in "two", "three", or "four" then s/he didn't read the instructions. You could be nice and check for that also, but I won't be nice.
Next, so the number typed in can be passed to a function, I need to convert it to a number, from the text character. However, a command such as !!VRy1&z1=^2^:S2; does not work, so we need to set up a few extra variables. In general, you need to do this to check each valid answer for a text-comparison. It is best if you make the question specific enough to only allow a very few answers.

Code: Select all

!!VRz2:S^2^;
!!VRz3:S^3^;
!!VRz4:S^4^;
Now we can convert to a number, and save in y1:

Code: Select all

!!VRy1:S0; [initialize y1]
!!VRy1&z1=z2:S2; [if the answer was "2"]
!!VRy1&z1=z3:S3; [if the answer was "3"]
!!VRy1&z1=z4:S4; [if the answer was "4"]
Now, we make three more functions- one for each question:

Code: Select all

!!FU2&v1=1:Py1; [If morning question]
!!FU3&v1=2:Py1; [If afternoon question]
!!FU4&v1=3:Py1; [If evening question]
Finally, if the player tried to back out after it was too late (and so v1=-1), he dies anyway:

Code: Select all

!!IF&v1=-1:M^The sphinx booms:
{You insult me by refusing to answer! DIE!}^;
!!HE-1&v1=-1:K; [if answer is refused, kill the current hero]
All that we have left to do now, is to check the answers and give rewards. Remember that flags 11,12, and 13 are false if the question has never been answered correctly. They are true it it was. Also recall that x1 is the value passed into the function. It will be 0 if the player did not give an answer of 2, 3, or 4- otherwise it will have the value that was typed in.

Code: Select all

!?FU2; [morning question routine]
!!IF&x1=4/-11:M^{You are the first to answer that quesion correctly. As a reward, take 20 of each of your construction materials!}^;
!!OW&x1=4/-11:R-1/0/d20; [give wood]
!!OW&x1=4/-11:R-1/1/d20; [give mercury]
!!OW&x1=4/-11:R-1/2/d20; [give ore]
!!OW&x1=4/-11:R-1/3/d20; [give sulfur]
!!OW&x1=4/-11:R-1/4/d20; [give crystal]
!!OW&x1=4/-11:R-1/5/d20; [give gems]
!!IF&x1=4/11:M^{You are correct, but the reward has already been given. Too bad for you.}^;
!!IF&x1<>4:M^{You have answered incorrectly. Your life is mine!}^;
!!HE-1&x1<>4:K; [kill hero if a wrong answer was given]
!!IF&x1=4:V11/1; [if the question was answered correctly, set flag 11 to true]
Now we do the afternoon question:

Code: Select all

!?FU3; [afternoon question]
!!IF&x1=2/-12:M^{That is correct! I shall bestow riches upon you!}^;
!!OW&x1=2/-12:R-1/6/d20000; [give gold]
!!IF&x1=2/12:M^{You are correct, but the reward has already been given. Too bad for you.}^;
!!IF&x1<>2:M^{You have answered incorrectly. Your life is mine!}^;
!!HE-1&x1<>2:K; [kill hero if a wrong answer was given]
!!IF&x1=2:V12/1; [if the question was answered correctly, set flag 12 to true]
Finally, the evening question:

Code: Select all

!?FU4; [evening question]
!!IF&x1=3/-13:M^{You have answered correctly. As the elderly tend to move more slowly, take these boots to increase your speed.}^;
!!HE-1&x1=3/-13:A98; [give boots of speed to active hero]
!!IF&x1=3/13:M^{You are correct, but the reward has already been given. Too bad for you.}^;
!!IF&x1<>3:M^{You have answered incorrectly. Your life is mine!}^;
!!HE-1&x1<>3:K; [kill hero if a wrong answer was given]
!!IF&x1=3:V13/1; [if the question was answered correctly, set flag 13 to true]
And there you have it! The script for a brand-new sphinx!
Notice that we did not use a single command that I have not already covered. That is why, for the most part, I simply placed comments in the code, rather than full explanations.
If you really wanted to be nasty, you could even remove the killed heroes from the allowed hero list- thereby truely killing the hero. To do this, use the HE:R command to set hero-pool availability of the hero.

Some other ideas you could use is to have only a single question, but offer several rewards. You can use a different dialogue box to ask a different type of question. There are lots of things you can try.
Last edited by Gaidal Cain on 01 Jan 2006, 12:14, edited 1 time in total.

User avatar
Gaidal Cain
Round Table Hero
Round Table Hero
Posts: 6972
Joined: 26 Nov 2005
Location: Solna

Unread postby Gaidal Cain » 01 Jan 2006, 11:30

Lesson 9: To the Battlefield!
The next thing that most people want to do is modify a battle setup. Whether something simple, such as a new artifact effect, or something more involved, such as modifying creature statistics for all monsters on the battlefield.

First, I will cover the battle TRIGGERS. There are several of them, and each have a specific use. One thing they have in common is the first letter of the triggers are all "B" (for battle)

Battle scripts have three main sections: before battle, during battle, and after battle.
The before battle script is activated by use of the !?BA0 trigger. Any commands after this trigger will run as soon as a battle begins- before the battlefield even appears on the map. In fact, if you have a message displayed during this phase, it will appear while still on the adventure map screen.

Actions to be taken at the END of battle use the !?BA1 trigger. These actions take place after returning to the map screen.

If you look at the cards script I wrote (script34.erm), you will see that it has these two sections only. That is because it only changes things at the start of battle, and changes them back at the end.

If you are looking in the script editor, take a look at the help for the !?BR trigger. It contains a chart showing the order of execution of battle triggers. I am going to go over the remaining triggers in the order they appear on this list.

After BA0, the next trigger is !?BR- this is the Battle Round trigger, This activates at the beginning of every round of combat, as well as during the pre-battle setup (round -1), and tactics phases (rounds -2 and -3).
If you want something to occur only during certain rounds, then note that the current battle round is kept in variable v997. For example, if you only want something to happen every third round (such as automatically casting a spell in a manner similar to enchanters), then you would code:

Code: Select all

!?BR;
!!VRy1:Sv997%3; [set y1 to be the round number, mod 3]
!!FU1&v997>=0/y1=0:P;
This checks that the round number is positive (so it isn't a pre-battle round), and that the round number is a multiple of 3.
You would then put whatever you wanted to happen inside function 1.

Next is the BF (BattleField) trigger. This is used to set up a custom battlefield- in case you don't want the default. How to set up a custom battlefied will be covered in the !!BF receiver section below.

Finally are the paired triggers BG0 and BG1. These triggers activate before (0) and after (1) every action a monster takes. You can use these if you want to have something happen whenever a certain creature takes an action. The various receivers are used to manipulate these things.

If you are looking in the help file, you will note that there are also !?BA50 and !?BA51 triggers. See below, in the E option for the !!BA receiver, for more information about these.

Now that we know how to identify what is going on, it is time to see what can be done.

!!BA
This lets you set up a battle. For the most part, these commands make no sense in any portion of a script other than the !?BA0 section. The options here are:

B#
Use this to choose the background picture for the battle. Note that this does NOT set the terrain the battle is on, it only changes the picture.
Instead of a background number, you can use ^picture.pcx^ to use a custom background. As with hero portraits, the filename must be under 12 characters. The picture location is relative to the data folder- so it is best to keep the pictures there, so you have enough characters to name the file :-)

D#
Use this to enable or disable a battle. If it is set to 1, the battle is automatically won.

E?$
This command checks what sort of battle is taking place. It returns a value of 1 if the battle is between two human players sitting at different computers- that is, a network-multiplayer battle. The value is 2 for battles that the AI initiates against a remote player. The value is 0 otherwise.

Why do we need this command? It is because when a battle is done between two different computers, information can become unsynchronized- causing unpredictable problems. This problem is due to random effects- including but not limited to morale and luck boosts. This problem was even seen from time to time in heroes 3 before WoG.

How do things become different? Slava was able to give me a good example:
"Let's say you have a script causing a random spell to be cast. On the attacker's side, one spell is cast, but when the script runs on the defender's computer, a different random number is chosen- and so a different spell is cast. Now the two computers have different battle states.
What you need to do is generate the random effect on one side, and then pass the random value to the other side. Note that in battles, only variables v9001 through v10000 are passed. If you are not working with random effects, then this will not cause a problem- since the script itself is the same on both sides."

To help alleviate this problem, the BA50 and BA51 triggers were recently added. These triggers are used to help align the two sides in a battle. The basic idea is this:

Code: Select all

!?BA0; [start-of-battle trigger]
** here goes whatever you want to happen at the start of battle. You should use a variable that is NOT passed to be set to a specific value (in the help-file example, v10 is set to 0).
!?BA50; [start-of-battle, at defender's side]
** here, you should set the variable that was chosen above to another value (in the help-file example, v10 is set to 1).
Now, anytime a random effect is generated, store that number in one of the v9001-v10000 variables, on the attacker's side. On the defender's side, you need to duplicate the code, but instead of any random numbers, use the v-variable to keep the same value.
In the triggers, check for which side is going. Your script will look something like this:

Code: Select all

!?BG0&v10=0; [before creature action, only on attacker's side]
!!VRv9001:S0R9; [get a random number between 0 and 9]
*** code for stuff that happens using the random number

!?BG0&v10=1; [before creature action, only on defender's side]
*** same code as above, but WITHOUT the VR9001 line.
This will guarantee that the same random effect occurs on both sides of the battle.

Something similar will need to be done for each battle trigger that involves any randomness. To be safest, any combat script should duplicate as much as possible. Many of the "official" WoG scripts were written before these commands were available, which is why they tend to use the BA:E command, and deactivate in multi-computer battles.

Note that you cannot access heroes directly on the defender's side. Instead, use hero numbers -10 and -20 for the attacker's and defender's heroes.
Changes on the defender's side are not kept after the battle is done, so except in very rare cases you do not need to use !?BA51 to undo changes that were done.

H#/$
This lets you set or check the hero that is taking part in the battle. Most likely, you will use this only to check the heroes involved, but there are exceptions- for example the Hourglass of Asmodeus script.

M#1/#2/$3/$4
This option lets you check the creatures fighting in the battle. #1 is the player: Attacker is 0, defender is 1. #2 is the slot number, 0 through 6. Note that this only checks the standard 7 army slots, and does not include commanders, automatically summoned creatures, and so on. 3 and 4 are the type and quantity of creatures, respectively. They can be read in or set. Thus, !!BA:M0/0/?v1/?v2;
reads the type and number of creatures in the attacker's first army slot into v1 and v2. !!BA:M1/4/24/5; changes the 5th creature stack in the defender's army into 5 unicorns (creature 24)

O$1/$2
This gets the player who owns the attacker's (1) and defender's (2) forces. Although you will not get an error if you try to set these values, Setting them will not have any effect- so you cannot "pass control" of a battle to another player.

P#1/#2/#3
This gets the terrain type at position ($1,$2,$3) on the map, and sets the background and terrain bonuses for the battle to that of the given location.
-----------------

Next, we have the BF or Battlefield receiver. This one is used to customize the battlefield for combat. The BF commands should only appear in the BF trigger section of a script.

This receiver only has three options: C, O, and M.
C
This option is used to get a battlefield with NO obstacles on it.

O#1/#2
This command is used to place a specific obsticle (#1) in a specific location (#2) on the battlefield.
In the scripter help for the BF receiver, there is a link to a chart showing you exactly how the locations correspond to the battlefield. You will note that there are locations one space off the left and right ends of each row. Since some obstacles are more than one space wide, you may need to place things there as well. In the pictured example, one-unit wide obstacles are placed there to "frame" the battlefield. Also note in that picture that some troops appear on top of obstacles- there is nothing preventing you from doing this. However, be certain that you do not place a creature in such a way that it cannot move, or an impossible battle may result.

M#1/#2/.../#11/#12
This lets you place an obstacle of type #12 in every location indicated by #1 through #11.
Each number (1 through 11) is a single value for the corresponding row in the battlefield. You need to find the "bitimage" value for the locations. The position to the left of the row is valued as 1, the first battlefield space is 2, then 4, 8, 16, and so on until the last space in the row is 32768, and the space to the right of the row is 65536. Add the values to get a number between 0 and 131071.
If #12 is omitted, a simple rock is used for the obstacle image.
Note that you do NOT need to use the C option, if you are going to use M- the M option assumes that you want only the obstacles you specify.

For an amusing battle, try setting up a fight with no shooters, and this battlefield command:

Code: Select all

!!BF:M2184/10920/10920/10920/10920/10920/10920/10920/10920/10920/8376;
This makes the whole battlefield one, long, twisting path.
2184 is the pattern: ...X...X...X.....
10920 is the pattern:...X.X.X.X.X.X...
8376 is the pattern: .....X...X...X...
Note that the first 3 spaces are left blank- this way any troops that start out on the field will not be immobilizied. You should leave the 2, 4, 16384, and 32768 locations open, unless you are repositioning the troops as well.
Try making a maze if you want to be VERY annoying.

Next is the BG receiver. As you would expect, !!BG commands can only be used within a !?BG trigger.
The BG commands deal with the actions of an individual creature. Remember that there are two BG triggers- one before a creature acts, and one after.
BG options:

A$
Use this command to determine the type of action the creature stack will take. The value of the number gives the type of action:
0: Cancel. Note that you may not be able to force the stack to do something, even with proper ERM code.
1: Have the hero cast a spell.
2: Move to a new location
3: Defend
4: Have the hero retreat
5: Have the hero surrender
6: Move and attack
7: Shoot (if it can)
8: Wait
10: Have the monster cast a spell.

Note that many of these require targeting. This brings us to:
D$
This is the target location for the creature's action (or hero's spell)

E$
This gets the monster stack at the destination. It returns -1 if there is no stack there. You can use this in combination with D and a loop to locate targets for a move and attack or a spell.

H$
This gets the owning hero number (-1 if no hero)

N$
This gets the stack number of the current creature. There are 21 stacks for each side. The attacker's stacks are numbered 0 through 20, and the defender's are 21 through 41

Q?$
Get the side of the creature (0=left/attacker; 1=right/defender)

S$
This is to set the number of a spell to cast.

Note that automatic effects on a creature's turn (such as the enchanters casting a spell every 3rd turn, or the regeneration of a creature) occure BEFORE the !?BG0 trigger.
-----------------
Similarly, you can also give instructions to the hero, using the !!BH or Battle Hero receiver.

This has four options of its own:
C#1/#2/#3/#4
This has the hero cast spell #1 with magic skill level #3 at position #2. #4 is a check for valid target (creature exists at the target)

M$
This lets you disable (1) or enable (0) the hero to cast a spell. Note that if the hero already cast a spell in the round, re-enabling it will not take effect until the next creature turn (which includes the current stack getting a free turn via morale). Obviously, if the next creature belongs to the other side, the hero needs to wait until a creature s/he owns gets another turn.

N?$
Get the hero number.

Q#1/#2/#3
This places a hex of quicksand (#1=0) or a land mine (#1=1) at position #2.
#3 is a flag for redrawing (1=yes, 0=no), as we have seen for several other commands.
WoG automatically will check for a valid placement using this command.

I will go over the remaining batle receivers in the next post.

I realize that going through all the commands the way I have been can be a bit overwhelming- but it is the best way to be certain I didn't skip anything. However, once the battle commands are done, then all the most important commands will have been covered.So, I will start analyzing various scripts, line-by-line, so you can see exactly how all this stuff comes together. I will start with my scripts- The cards of prophecy, and possibly the creature affinities (I haven't finished that script, so I don't know if I will present it or not- it is currently in debugging).
Last edited by Gaidal Cain on 01 Jan 2006, 12:14, edited 1 time in total.

User avatar
Gaidal Cain
Round Table Hero
Round Table Hero
Posts: 6972
Joined: 26 Nov 2005
Location: Solna

Unread postby Gaidal Cain » 01 Jan 2006, 11:59

Lesson 10: the struggle continues
Continuing with the battle commands, the BM or Battle Monster receiver lets you manipulate the attribtes of a single monster stack. Changes made to a monster stack with this command are only for that specific stack of monsters, as opposed to all creatures of that type. Also, the effects do not carry over to the next battle.
Some examples of when you would want to use this would be:
1) giving a new ability to an artifact that modifies creature abilities
2) bonuses from scripted map objects
3) creating your own hero specialties.

The format for this receiver is:

Code: Select all

!!BM#:[options];
# is the monster stack number you are referring to. Normally it is between 0 and 20 for the attacker's stacks, and between 21 and 41 for the defender's.

BM options:
A$
This is to get or set the attack skill of the creature, including all bonuses.

B$
This is to get the number of creatures that were in the stack at the start of battle- very useful if you want to have ressurrection-like effects.

C#1/#2/#3/#4/#5
This is to have a spell cast, similar to the like command in my last post.
This has the monster cast spell #1 at location #2, with skill level #3. #5 is again a check for a target existing.

D$
This is like A, but for defense skill value, rather than attack skill.

E$
This gets or sets the number of spells the creature has left to cast. FOr example, if the creature stack is a supreme archangel, this will give a value of 2 at the start of battle, and 1 after the resurrection skill has been used once, and 0 after the second use. You can set this to give more or fewer castings to a creature.

F$
This is used to check the flags associated with a monster stack. If you want to check the flags, you must use one of the single-letter variables (f..t), as v-variables will not hold the values properly.
Each attribue of a creature corresponds to a specific bit:
for this chart, we have [bit number]/[decimal value]/[meaning if set]
0/1/creature is 2-hexes wide
1/2/creature can fly
2/4/creature can shoot
3/8/creature has a 2-hex (breath) attack in melee
4/16/creature is alive (and can be affected by things that affect living creatures)
5/32/creature is a catapult
6/64/creature is a seige weapon (and so has no movement)
7/128/creature can be affected by any level slayer spell (if attacked by a stack with slayer active, the attacking creature gets the bonuses)
8/256/creature can be affected by only an ADVANCED or higher slayer spell
9/512/creature can only be affected by an EXPERT slayer spell
10/1024/creature is immune to mind spells
11/2048/creature is a shooter, and has no obstacle penalty.
12/4096/creature has no melee penalty
14/16384/creature is immune to fire-school spells
15/32768/creature has two attacks (melee unit or ranged unit *if shooting*)
16/65536/creature is not retaliated against
17/131072/creature has no morale
18/262144/creature is undead (and can be affected by things that affect undead)
19/524288/creature attacks all adjacent creatures.
20/1048576/creature has an area-effect shot (such as magogs). This bit has no effect if set manually.
22 and 23/12582912/creature stack is a clone
24/16777216/creature has had a free turn due to morale this round
25/33554432/creature is waiting
26/67108864/creature has finished this round's actions
27/134217728/creature is defending
31/2147483648/creature is a dragon

You can set individual bits with the | operator in a VR command. You can clear individual bits with the & operator in a VR command. For example, you can remove the fly skill and add mind spell immunity to creature stack 2 by these commands:

Code: Select all

!!BM2:F?i; [load bits into variable i]
!!VRi:|1024; [add mind-spell immunity]
!!VRi:&2; [remove flying]
!!BM2:Fi; [set new bits]
To check an individual bit, divide by the bit value, and find the value mod 2. For example, to see if creature stack 22 is waiting, do this:

Code: Select all

!!BM22:F?i; [load bits]
!!VRi::33554432; [divide by the value of bit 25- waiting]
!!VRi:%2; [find i (mod2)]
If at this point i is 0, then the bit is unset- the creature is not waiting. If i is 1, then the creature is waiting. Note that to check for a clone, you need to check two bits. You do this the same way, but you want to find the value mod 4, and it should be 3 if both are set.

Some bits are not listed- they either do not do anything, are their functions are unknown at this time. Leave them alone.

G#/$1/$2
This is used to set or check if a spell (#) is active on the creature, for how long ($1), and at what power level ($2). Duration ($1) is 0 if the spell is not active.

H$
Set or check the hit points of the stack. This is the hit points for each creature- not the current "top" one.

I?$
Check which side the creature is on (left-0 or right-1)

J?$
Check how many spells are active on the creature.

K#
Inflict # damage to the creature stack.

L$
Hit points lost by the top monster in the stack. (for example, if an azure dragon has 875 hit points left, this value is 125.)

M#1/#2/#3
Apply spell #1 for duration #2 at skill level #3.
There are several comments on this in the scripter help- be certain to read over them. Of particular note is that although you can use the G option for most things, this command will allow you to cast dispel or cure on a creature- removing the need to check for every active spell on the monster.
Spells which are not normally permanent on a creature (or even spells that aren't combat spells!) can be used here as well. Of course, if you do not script a meaning for them, it will merely be confusing to the player.

N$
This gets or sets the current number of creatures in the stack. There is a comment on vampire lords in the help file about this number. Simply put, vampire lords will only regenerate if this number is less than the value in the B command. Therefore, if you make the stack grow larger than it started, the vampire lords will not recover.

O$
This is the army slot that the stack comes from (and returns to). (0..6) If the stack is in slot -1, then it was not in the army before the battle. This includes summoned creatures, clones, santa gremlin guards, and so on.

P$
This gets the position of the stack on the battlefield (0..186)

Q#1/#2/#3
This is identical to the BH command to place quick sand or a land mine on the field (except this is a creature triggering the spell, rather than the hero)

R$
This sets or checks the number of times a creature can retaliate. For most creatures, it starts each round at 1, and counts down after a retaliation. Griffin have it set to 2. Royal Griffin have it set to 5000 (so it isn't REALLY unlimited retaliations, but scripting a situation to let it be attacked 5000 times in one round of combat is really long!) Note that the counterstrike spell can increase this number as well as an ERM command.

S$
This is the creature's speed.

T$
This gets the creature type.

The last of the battle commands is the BU receiver. This controls a lot of the general aspects of the battle (as opposed to a specific part of it)
It has the standard form:

Code: Select all

!!BU:[options];
C?$
This is used to check if the battle finished this round (1=yes, 0=no)
There may be times when you need something done at the end of battle, but before the BA1 trigger is called. This is the way to check for this situation.

D#/?$
This checks for a dead creature stack at position #. $ contains the stack number (0..41) if there is a dead stack there (but no live stack on top of it). It is -1 for an empty hex, and -2 if a living stack is there.

E#/?$
This checks for an alive stack at position #. $ is -1 for an empty stack, otherwise it is the stack number.

O#/?$
This checks for an obstacle at position #. It is a bit-mask, to determine the type of obstacle:
$ is 0 if there is no obstacle.
the 1 bit is set if there is a magic obstacle
the 2 bit is set if there is an obstacle (not necessarily magic)
the 4 bit is set if there is quicksand (magic obstacle)
The 8 bit is set if there is a land mine (magic obstacle)

R
Redraw the battle screen.

S#1/#2/#3/#4/#5/#6
Summon a creature stack of type #1 and quantity #2 to position #3 on the #4 side of battle (0=left, 1=right). After battle, place these creatures in the hero's army slot #5 (-1 if it will disappear after battle), and redraw the battlefield (#6=1- yes, #6=0- no)
Remember that you cannot have more than 20 creature stacks on either side of a battle.

T?$
Check to see if there is a tactics phase to this battle (1=yes, 0=no)

User avatar
Gaidal Cain
Round Table Hero
Round Table Hero
Posts: 6972
Joined: 26 Nov 2005
Location: Solna

Unread postby Gaidal Cain » 01 Jan 2006, 12:30

Lesson 11: The Cards of Prophecy
This next lesson is going to take an official script- my Cards of Prophecy script- and break it down, line by line. Many comment lines will be removed, but in-line comments will be left. New commands and specific values will be explained when needed.

Note: Some of the lines of codes are pretty large. In the original post, QQD included hard line breaks along with a notation for this, since Forumplanet didn't introduce linebreaks in code. These forums do that, however, and the hard line breaks have been discarded. There might still be a couple of soft breaks here and there, but since comments generally are in hard brackets ([]) and all code lines should begin with !!, !? or !#, this shouldn't be a problem. GC

Code: Select all

ZVSE
!#UN:P34/?v1321; [is script active?]
The UN receiver is used to set and check universal aspects of the map. This includes, but is not limited to, artifact availability, and anything in WoG options. In this case, the P option is used to check for a WoG option setting. Usually, the number immediately after the P is the script number you wish to check (there are some exceptions). For this line, the script is checking to see if script 34 is active in the WoG options (script 34 is the Cards script), and sets the value (1=yes, 0=no) into variable v1321.
Note that I almost always use (permanent) v-variables in the 1300's this is because in the WoG team, we do not want to use the same variables in multiple scripts. Thus, we claim sets of variables. Similarly, all my functions are in the 13,500's.

Code: Select all

!#VRz698:Sz134001;
This is a command to load in text from an external "ERT" file. This was done for localization purposes. If you open the script editor, and look at "script34.ert", you will see a list of all the text in this script. If you speak another language, you only need to modify the text in this file, rather than hunting down all the text in the script.
Note that the z-variable index is much larger than what is normally allowed. This indicates that it is in an ERT file. The first 1 indicates and ERT file, the 34 indicates the file is script34.ert, and 001 is the index of the text. All ERT z-variables will be six digits.
z134001 contains the following text:

Code: Select all

{Cards of Prophecy}
When entering battle, a card will emerge from the deck. Each card has a different effect.
It will also bestow a +1 bonus to the luck of your army.

Code: Select all

!#HT5/47&v1321=1:T698; [set new artifact text if active]
This command sets the Hint Text for artifact 47 (the Cards) to the new text I listed above, but only if the script is active. This is the end of the main script. The rest takes place within battle triggers, since the new effects are only within battle.

Code: Select all

!?BA0&v1321=1; [start of battle]
Note the check for the script being active within the BA0 trigger command. This means that even if a battle starts, if the script is not active, then the script will not run. Thus, the check for an active script does not need to be used on every command in the script- only on the main triggers.

Code: Select all

!!BA:E?v1331; [check for multiplayer]
Note that this script was written before the BA50/BA51 triggers were available. Thus, the BA:E check is used to prevent the script from running in network multiplayer battles.

Code: Select all

!!FU13502&v1331=0:P; [if it isn't, then continue with the rest of the script.] 

Code: Select all

!?FU13502; [start of main script]
If the battle is network multiplayer, then the script ends here, since this is a new trigger- the function called in the last line.

Code: Select all

!!BA:H0/?v1300; [get attacking hero's number]
!!BA:H1/?v1310; [get defending hero's number]

!!HEv1300:A2/47/0/?v1301; [Attacker has Cards of Prophecy equipped?]
Note that my comment is written as a question. I tend to do this in many cases where I am checking a value. If you are following along with the script, you may want to keep track of what each variable holds. My v-variables for this run from 1300 through 1335.

Code: Select all

!!HEv1310&v1310>=0:A2/47/0/?v1311; [Defender has Cards of Prophecy equipped?]
Note that for the defender, there is an additional check to see if the defending hero number is non-negative. This way, the script can ignore the times when there is no defending hero.

Code: Select all

!!FU13500&v1301>0/v1300>=0:Pv1300; [if any equipped, generate bonus for attacker]
!!FU13500&v1311>0/v1310>=0:Pv1310; [if any equipped, generate bonus for defender]
This function generates the bonuses for the hero, if needed. Note that the hero number is passed into the function. Thus, x1, within the function will be the hero number for whichever hero being worked with. This ends the pre-battle script. Next comes the post-battle script, to undo any changes made.

Code: Select all

!?BA1&v1321=1/v1331=0; [end of battle]
!!FU13501&v1301>0/v1300>=0/v1307<=23: Pv1300/v1302/v1303/v1304/v1305/v1306/v1307/v1307; [undo attacker bonus]
!!FU13501&v1311>0/v1310>=0/v1317<=23: Pv1310/v1312/v1313/v1314/v1315/v1316/v1317/v1317; [undo defender bonus]
!!FU13507&v1301>0/v1300>=0/v1307>=24/v1307<=30: Pv1300/v1308/v1309/v1328/v1326/v1306/v1307/v1307; [undo attacker 1.3]
!!FU13507&v1311>0/v1310>=0/v1317>=24/v1317<=30:Pv1310/v1318/v1319/v1320/v1327/v1316/v1317/v1317;
 [undo defender 1.3]
This is entire post-battle script. Note that there are a large number of parameters here. This is because all changes that were made were stored, and by passing them in, one extra function call here (for the defender) saves the need to duplicate every line of the script.
The "1.3" lines refers to the additional cards that I added in for version 1.3 of the script- v1307 and v1317 contain the card numbers drawn, and that indicates which function is called.

Code: Select all

** function to generate card and apply its effect
!?FU13500;
!!VRv1307&x1=v1300:S0T30; [choose card number, if attacker]
!!VRv1317&x1=v1310:S0T30; [choose card number, if defender]
Note the use of the T operator to get a random value from 0 to 30.

Code: Select all

!!HEx1&x1=v1300:F?v1302/?v1303/?v1304/?v1305; [if attacker, get hero statistics]
!!HEx1&x1=v1310:F?v1312/?v1313/?v1314/?v1315; [if defender, get hero statistics]
!!HEx1:I?y10; [get hero's current spell points]
!!VRv1306&x1=v1300:Sy10; [if attacker's hero, store current spell points]
!!VRv1316&x1=v1310:Sy10; [if defender's hero, store current spell points]
Here, the original primary stats of the attacking and defending heroes are stored. Remember that in the HE:F receiver, the four stats are attack, defense, spell power, knowledge- in that order (the same order as they are displayer on the hero screen).
In retrospect, the spell points storage could have been done in two HE:I commands, rather than an HE:I and two VRs, but this is how I wrote it. I may change this in the future, but only if I am doing other changes to the script. As the adage says, "If it ain't broke, don't fix it."

Code: Select all

!!FU13504&v1307<=23/x1=v1300:Px1/v1307/v1307; [if card is an original bonus/penalty]
!!FU13504&v1317<=23/x1=v1310:Px1/v1317/v1317; [if card is an original bonus/penalty]
!!FU13505&v1307>=24/v1307<=30/x1=v1300:Px1/v1302/v1303/v1304/v1305/v1306/v1307; [if v1.3 card]
!!FU13505&v1317>=24/v1317<=30/x1=v1310:Px1/v1312/v1313/v1314/v1315/v1316/v1317; [if v1.3 card]
Functions 13504 and 13505 apply the effects of the drawn card to the hero's stats.

Code: Select all

!!HEx1:F?y1/?y2/?y3/?y4; [get modified stats]
!!VRv1308&x1=v1300:Sv1302-y1; [get -attacker's attack change]
!!VRv1309&x1=v1300:Sv1303-y2; [get -attacker's defense change]
!!VRv1328&x1=v1300:Sv1304-y3; [get -attacker's spell power change]
!!VRv1326&x1=v1300:Sv1305-y4; [get -attacker's knowledge change]
!!VRv1318&x1=v1310:Sv1302-y1; [get -defender's attack change]
!!VRv1319&x1=v1310:Sv1303-y2; [get -defender's defense change]
!!VRv1320&x1=v1310:Sv1304-y3; [get -defender's spell power change]
!!VRv1327&x1=v1310:Sv1305-y4; [get -defender's knowledge change]
** End of function 13500
To prevent possible conflicts with other scripts that modify hero stats, I used another set of eight variables to store the changes to the stats. Otherwise, a simple restoration of the previous stats may cause strange effects. For instance, if you used a berserker potion (gives +10 strength and sets spell points to 0), then your stats may not restore properly, if I simply reset the attack skill- it would likely be 10 points too high. Whenever possible, if you are making changes that need to be undone, make the restoring values relative changes rather than specific values.
I realized this problem after the original script writing, and that is why the variable numbers aren't nicely ordered here. This is another reason why it is important to keep records of what your variables do.

This applies mostly to battle scripts, or any script supposed to "wear off" (like the magic mushrooms). I the case of a script that doesn't work just in direct connection with battle(i.e. it's not triggered at battle start and end), I'd recommend using a w variable to keep track of the change. Also note that it's not just scripts that can interfere, level ups and other kind of "normal" bonuses can as well, so always keep the relative change, even if it's only for a map-specific script. GC

Code: Select all

** Function to apply bonus, if it is a statistic bonus.

!?FU13504;
!!VRx2:%4; [calculate hero primary stat]
!!VRx3::4; [calculate bonus to stat]
Note this method of getting a bonus. For the original set of cards, the card number is between 0 and 23. By getting this value mod 4, a number between 0 and 3 is found, which can associate it with the four stats. By dividing by 4, a number between 0 and 5 is found, which gives the change to be made. This is why the card number was passed in twice in the function call- it was to be modified two different ways.

Code: Select all

!!VRx3&x3=0:S-1; [if random bonus is 0, then make it -1]
This is simply to add in the penalty cards, and remove the chance of having a card do nothing.

Code: Select all

!!VRy1&x2=0:Sx3; [If primary stat is 0, set y1 to bonus]
!!VRy2&x2=1:Sx3; [If primary stat is 1, set y2 to bonus]
!!VRy3&x2=2:Sx3; [If primary stat is 2, set y3 to bonus]
!!VRy4&x2=3:Sx3; [If primary stat is 3, set y4 to bonus]
!!HEx1:Fdy1/dy2/dy3/dy4; [add bonus]
Remember that function-local variables (the y-variables) are 0 until set to something else (Note: it's still good practise to assume they aren't. Thus, if you want a random dice throw between 0 and 5, use !!VRy1:S0 T5; rather than !!VRy1:T5; Not only does this protect you from the chance they might not be empty, it's also a little bit easier to understand. GC)

Code: Select all

!!HEx1:S24/?y9; [get level of hero's intelligence skill. Specialty is ignored]
I ignore the specialty because it would have been an awful lot of extra coding for only a couple heroes. Most intelligence specialists, once high enough in level to get a significant boost, do not need the extra spell points anyway.


I don't think the extra code would be that much(2 or 5 lines, I'm not sure how the bonus works), but I still don't think it's improtant enough to write it.

Code: Select all

** calculate bonus spell points, if any

!!VRy4&x2=3/y9=0:*10; [bonus spell points with no intelligence]
!!VRy4&x2=3/y9=1:*25; [bonus spell points with basic intelligence, part 1]
!!VRy4&x2=3/y9=1::2; [bonus spell points with basic intelligence, part 2]
!!VRy4&x2=3/y9=2:*15; [bonus spell points with advanced intelligence]
!!VRy4&x2=3/y9=3:*20; [bonus spell points with expert intelligence]
!!HEx1:I?y10; [get hero's current spell points]
!!VRy10:+y4; [add bonus spell points]
!!VRy10&y10<0:S0; [if spell points somehow became negative, set to zero]
!!HEx1:Iy10; [set hero spell points to new level]
Again, this was my first script, and so some things were not done as simply as they could have. Here, if the hero has basic intelligence, I could have just written "*25:2" rather than breaking this into two lines. Spell points could become negative if the hero got a knowledge penalty, and was depleted in spell points. There were a few reports of heroes ending the battle with negative spell points, and so I added lines to be extra careful about this.

Code: Select all

** z1, z2, and z3 contain words needed for the start-of-battle message.
** Check script34.ert for actual text.
!!VRz2&x3=-1:Sz134002;
!!VRz2&x3=1:Sz134003;
!!VRz2&x3=2:Sz134004;
!!VRz2&x3=3:Sz134005;
!!VRz2&x3=4:Sz134006;
!!VRz2&x3=5:Sz134007;
!!VRz2&x2=0:+z134008;
!!VRz2&x2=1:+z134009;
!!VRz2&x2=2:+z134010;
!!VRz2&x2=3:+z134011;
!!VRz3&x2=0:Sz134012;
!!VRz3&x2=1:Sz134013;
!!VRz3&x2=2:Sz134014;
!!VRz3&x2=3:Sz134015;
!!VRz5:Sz134016;
!!VRz5&x3=-1:Sz134017;
!!HEx1:B0/?z4; [get hero name]
z134002 through z134007 contain the ranks of cards. 134008 through 134011 contain the suits. 134012 through 134015 contain the statistic names. 134016 and 134017 contain "increases" and "decreases" respectively.
These, in addition to the hero name, contain all the words that change based on the drawn card.

Code: Select all

!!HEx1:O?y6; [get hero owner]
!!OW:Iy6/?y7; [is owner an AI?- if so, message will not display]
!!IF&y7=0:M1/z134018;
If the battle doesn't involve a human player, this prevents the human players from getting a message to click through.
z134018 contains the following:

Code: Select all

As battle begins, the %Z2 emerges from the Cards of Prophecy.
%Z4's %Z3 %Z5 by %X3 for this battle.
Note how all the pieces assembled above are added into this message. If you have played a map with this script active, you have probably seen the result.

Code: Select all

** version 1.3 cards
!?FU13505;
!!VRy1:Sx2+x3+x4+x5-2; [set y1 to sum of hero stats, less 2]
!!VRy1&x7=26|x7=27:+1; [add one to y1 if Hermit or Magician card]
!!HEx1&x7=24:Fy1/0/1/1; [If Emperor, shift all primary stats to attack]
!!HEx1&x7=25:F0/y1/1/1; [If Empress, shift all primary stats to defense]
!!HEx1&x7=26:F0/0/y1/1; [If Magician, shift all primary stats to power]
!!HEx1&x7=27:F0/0/1/y1; [If Hermit, shift all primary stats to knowledge]
!!HEx1&x7=30:F0/0/1/1; [If Inverted Fool, remove all primary stats]
These are the more severe cards. Note that spell power and knowledge are not allowed to become 0, as they are a minimum of 1 anyway.

Code: Select all

!!VRy1&x7=28:+5;
!!VRy1&x7=28::4; [Get average of primary stats, rounded up, if Hierophant]
Again these lines could have been combined. The +5 includes a +2 to compensate from the two that were not added together before, and a +3 to guaranty that the division rounds up- remember that ERM truncates all divisions (except if an e variable is used)

Code: Select all

!!HEx1&x7=28:Fy1/y1/y1/y1; [If Hierophant, balance statistics]
!!FU13506&x7=29:Px1/x2/x3/x4/x5; [If Fool, call stat shuffle routine]
!!HEx1&x1=v1300:F?v1322/?v1323/?v1324/?v1325; [store new stats for attacker]
!!HEx1&x1=v1310:F?v1332/?v1333/?v1334/?v1335; [store new stats for defender]
Again these are fairly straight-forward. The stat-shuffle needed a separate function (see below).

Code: Select all

!!VRy5&x1=v1300:Sv1325; [set v5 to new knowledge skill (attacker)]
!!VRy5&x1=v1310:Sv1335; [set v5 to new knowledge skill (defender)]
!!HEx1:S24/?y9; [get level of hero's intelligence skill. Specialty is ignored]
!!VRy5&y9=0:*10; [spell points with no intelligence]
!!VRy5&y9=1:*25; [spell points with basic intelligence, part 1]
!!VRy5&y9=1::2; [spell points with basic intelligence, part 2]
!!VRy5&y9=2:*15; [spell points with advanced intelligence]
!!VRy5&y9=3:*20; [spell points with expert intelligence]
!!HEx1:Iy5; [set hero spell points to new level]
!!VRv1329&x1=v1300:Sy5-v1306; [store spell point change for attacker]
!!VRv1330&x1=v1310:Sy5-v1316; [store spell point change for defender]
This should be very familiar, but there is no negative spell-point check here. Why? Because these cards reset spell points completely, so there was no possibility of negative spell points.

Code: Select all

!!HEx1:B0/?z1; [get hero name]
!!HEx1:O?y6; [get hero owner]
!!OW:Iy6/?y7; [is owner an AI?- if so, message will not display]
!!IF&y7=0/x7=24:M1/z134019;
!!IF&y7=0/x7=25:M1/z134020;
!!IF&y7=0/x7=26:M1/z134021;
!!IF&y7=0/x7=27:M1/z134022;
!!IF&y7=0/x7=28:M1/z134023;
!!IF&y7=0/x7=30:M1/z134024;
!!IF&y7=0/x7=29:M1/z134025;
z134019 through 134025 contain customized messages for each of the Major Arcana cards. Check the ERT file for their exact contents. Of course, playing a map with this script will probably let you see all of these eventually anyway.

Code: Select all

** Fool stat-shuffle
!?FU13506;
!!VRy1:S0T22; [choose a permutation. Next 23 lines sets it. No-change permutation is not allowed]
!!HEx1&y1=0:Fx2/x3/x5/x4;
!!HEx1&y1=1:Fx2/x4/x3/x5;
!!HEx1&y1=2:Fx2/x4/x5/x3;
!!HEx1&y1=3:Fx2/x5/x3/x4;
!!HEx1&y1=4:Fx2/x5/x4/x3;
!!HEx1&y1=5:Fx3/x2/x4/x5;
!!HEx1&y1=6:Fx3/x2/x5/x4;
!!HEx1&y1=7:Fx3/x4/x2/x5;
!!HEx1&y1=8:Fx3/x4/x5/x2;
!!HEx1&y1=9:Fx3/x5/x2/x4;
!!HEx1&y1=10:Fx3/x5/x4/x2;
!!HEx1&y1=11:Fx4/x2/x3/x5;
!!HEx1&y1=12:Fx4/x2/x5/x3;
!!HEx1&y1=13:Fx4/x3/x2/x5;
!!HEx1&y1=14:Fx4/x3/x5/x2;
!!HEx1&y1=15:Fx4/x5/x2/x3;
!!HEx1&y1=16:Fx4/x5/x3/x2;
!!HEx1&y1=17:Fx5/x2/x3/x4;
!!HEx1&y1=18:Fx5/x2/x4/x3;
!!HEx1&y1=19:Fx5/x3/x2/x4;
!!HEx1&y1=20:Fx5/x3/x4/x2;
!!HEx1&y1=21:Fx5/x4/x2/x3;
!!HEx1&y1=22:Fx5/x4/x3/x2;
This is pretty straight-forward. x2 through x5 have the primary stats. A random choice is made, and then the permutation is applied.

Now comes the stat restoring functions.

Code: Select all

** function to remove card effect
!?FU13501;

!!VRx7:%4; [calculate stat effected]
!!VRx8::4; [calculate bonus given]
!!VRx8&x8=0:S-1;
!!VRx8:*-1; [invert bonus amount]
!!VRy1&x7=0:Sx8; [If primary stat is 0, set y1 to -bonus]
!!VRy2&x7=1:Sx8; [If primary stat is 1, set y2 to -bonus]
!!VRy3&x7=2:Sx8; [If primary stat is 2, set y3 to -bonus]
!!VRy4&x7=3:Sx8; [If primary stat is 3, set y4 to -bonus]
!!HEx1:Fdy1/dy2/dy3/dy4; [reset primary skills]
Note that with the exception of the inverting line, this is identical to the "bonus adding" function!

Code: Select all

!!HEx1:I?y9; [get hero's final spell points]
More spell point changes. You know what this means...

Code: Select all

!!HEx1:S24/?y8; [get level of hero's intelligence skill. Specialty is ignored]
!!VRy4&x7=3/y8=0:*10; [bonus spell points with no intelligence]
!!VRy4&x7=3/y8=1:*25; [bonus spell points with basic intelligence, part 1]
!!VRy4&x7=3/y8=1::2; [bonus spell points with basic intelligence, part 2]
!!VRy4&x7=3/y8=2:*15; [bonus spell points with advanced intelligence]
!!VRy4&x7=3/y8=3:*20; [bonus spell points with expert intelligence]
Looking back, this calculation probably should have been made a separate function, to make things easier to read. It would also have made the script shorter. (A good rule when programming is that use of copy and paste should be kept at a minimum. If you find yourself with identical code at many places, consider making a function of that piece of code. GC)

Code: Select all

!!VRy9&x1=v1300/x7=3/x8=-1:-y4; [If there was a knowledge penalty, restore lost spell points]
!!VRy9&y9&>v1306/x1=v1300/x7=3:Sv1306; [If attacker has more spell points than at start, and knowledge was changed, reset it]
!!VRy9&y9>v1316/x1=v1310/x7=3:Sv1316; [If defender has more spell points than at start, and knowledge was changed, reset it]
!!HEx1:Iy9; [set spell points for hero]
** end of function 13501
Note that spell points are only reduced here if you ended with more than you started with. Thus, any extra spell points given are indeed "bonus" points. There is a known bug with this- if you have familiars, you may legitimately have more spell points at the end of battle. I check to be certain that knowledge was changed, but that is not foolproof. Unfortunately, to completely fix this would result in a large piece of in-battle code to check every time a spell is cast for any familiar actions. It could be done, but as with the intelligence specialty, this is not a significant likelihood of happening- and only a very few spell points are affected anyway.

If you were observant, you may have noticed that only parameters x1, x7, and x8 were used here. That is because originally this function checked to see if a level was gained, and then reset the statistics, possibly with the one extra point for a level added in. However, once I reworked the script to use relative changes, this was no longer needed. However, removing the parameters would have involved going through this section of code to change all the x-variable indeces- and if one was missed, it could cause problems.

Code: Select all

** 1.3 undo routine
!?FU13507;
!!HEx1:Fdx2/dx3/dx4/dx5; [restore hero stats to pre-battle levels]
!!HEx1:I?y1; [get final spell-point total]
!!VRy1&x1=v1300:-v1329; [remove change for attacker's spell points]
!!VRy1&x1=v1310:-v1330; [remove change for defender's spell points]
!!VRy1&y1>x6:Sx6; [if spell points are more than before battle, reduce to that level]
!!VRy1&y1<0:S0; [if spell points are somehow negative, set to 0]
!!HEx1:Iy1; [set hero spell points to correct total]
The 1.3 cards have a much simpler undo routine. It seems to me that it should be usable for the origianl set of cards as well. In a future revision I may rework the undo routine to use this part only- it reads a lot more easily.

That is the entire script. Notice that except for two lines (UN:P and HT) it only uses commands that I have covered. As my comments indicate, several parts are unnecessarily complicated or lengthy. It is important to remember, however, that you want the routine to work properly first. You can simplify and pretty it up again at some later time.

User avatar
Gaidal Cain
Round Table Hero
Round Table Hero
Posts: 6972
Joined: 26 Nov 2005
Location: Solna

Unread postby Gaidal Cain » 01 Jan 2006, 12:32

That's the last of the lessons so far. Whether there will be more or not is unclear, but the thread should still be useful as a place to ask questions.
You don't want to make enemies in Nuclear Engineering. -- T. Pratchett

User avatar
Gaidal Cain
Round Table Hero
Round Table Hero
Posts: 6972
Joined: 26 Nov 2005
Location: Solna

Unread postby Gaidal Cain » 01 Jan 2006, 12:33

This space intentionally left blank.
You don't want to make enemies in Nuclear Engineering. -- T. Pratchett

User avatar
Gaidal Cain
Round Table Hero
Round Table Hero
Posts: 6972
Joined: 26 Nov 2005
Location: Solna

Unread postby Gaidal Cain » 01 Jan 2006, 12:34

This space intentionally left blank.
You don't want to make enemies in Nuclear Engineering. -- T. Pratchett

User avatar
Gaidal Cain
Round Table Hero
Round Table Hero
Posts: 6972
Joined: 26 Nov 2005
Location: Solna

Unread postby Gaidal Cain » 01 Jan 2006, 12:35

And here starts the real thread. Happy coding!
You don't want to make enemies in Nuclear Engineering. -- T. Pratchett

User avatar
Qurqirish Dragon
Genie
Genie
Posts: 1011
Joined: 06 Jan 2006
Location: Flying the skies of Ohlam

Unread postby Qurqirish Dragon » 06 Jan 2006, 18:17

I am not planning on new installments, but if there is demand, I may do so, or even break down other scripts (as I did with the cards script) :D

User avatar
Fly
Leprechaun
Leprechaun
Posts: 20
Joined: 12 Jun 2006
Location: Russia - Krasnoyarsk
Contact:

ERM

Unread postby Fly » 12 Jun 2006, 08:04

I'm from Russia so i'm very sorry for my english... :proud:
I have a little qestion about ERM: i'm trying to do the script now and have a problem. The script:

Code: Select all

!?FU22362; 
!!VRv2725:S0; 
!!VRv2726:S0; 
!!VRv2727:S0; 
!!VRv2728:S0; 
!!VRi:S0; 
!!VRf:S0; 
!!VRv2732:S0; 
!!VRv2733:S0; 
!!VRv2734:S0; 
!!VRv2750:S0; 
!!VRv2752:S0; 
!!UN:X?i/?f;  get a size of a map 
!!VRv2726:S0; 
!!VRv2727:S0; 
!!VRv2728:S0; 
!!DO22364/0/1/1&f=0:P1; 
!!DO22364/0/2/1&f=1:P1;  call a function 
!?FU22364;  set a function 
!!DO22363/0/1296/1&i=36:P;  call a function 
!!DO22363/0/5184/1&i=72:P; 
!!DO22363/0/11664/1&i=108:P; 
!!DO22363/0/20736/1&i=144:P; 
!!VRv2728:+1; 
!?FU22363;  set a function 
!!TRv2726/v2727/v2728:E?v2725; 
!!OBv2726/v2727/v2728&v2725=0:T?v2733; 
!!OBv2726/v2727/v2728&v2725=0:U?v2734; 
!!CAv2726/v2727/v2728&v2733=98/v2725=0:O?v2732; 
!!OW&v2644=0:C?v2759; 
!!VRv2750&v2725=0/v2733=98/v2734=0/v2732=v2759:+1; 
!!VRv2752&v2725=0/v2733=98/v2734=1/v2732=v2759:+1; 
!!VRv2751&v2725=0/v2732=v2759:Sv2750; 
!!VRv2751&v2725=0/v2732=v2759:+v2752; 
!!VRv2751&v2725=0/v2732=v2759:*3; 
!!VRv2726:+1; 
!!VRv2727&v2726=i:+1; 
!!VRv2726&v2726=i:S0;
This script should check for Castles and Ramparts existing. If this castles belong to player, the var should grow up in 1. But this script is too slow.

How i can to do script faster. Thanks... :) :)

User avatar
Fnord
Round Table Knight
Round Table Knight
Posts: 341
Joined: 27 Nov 2005
Location: Victoria, BC, Canada

Re: ERM

Unread postby Fnord » 12 Jun 2006, 09:16

Fly wrote:I'm from Russia so i'm very sorry for my english... :proud:
I have a little qestion about ERM: i'm trying to do the script now and have a problem. The script:

This script should check for Castles and Ramparts existing. If this castles belong to player, the var should grow up in 1. But this script is too slow.

How i can to do script faster. Thanks... :) :)
There's a function "UN:U" that searches for specific objects. It's much faster (especially when using the "fast syntax").

Code: Select all

!?FU22362;
!!VRv2750:S0; [Initialize v2750 to 0]
!!VRv2751:S0; [Initialize v2751 to 0]
!!OW:C?y1; [Current player: y1]
!!UN:U98/-1/?y2; [Count towns on map: y2]
!!VRv1:S-1; [Initialize v1 to -1 for fast UN:U searching]
!!DO22363/1/y2/1&y2>0:Py1; [Loop through all towns on map]

!?FU22363;
!!UN:U98/-1/-1/1; [Town coordinates in v1/v2/v3]
!!CAv1/v2/v3:T?y1 O?y2; [Town type: y1, Owner: y2]
!!VRv2750&y1=0/y2=x1:+1; [Add 1 to v2750 if it's a Castle and current player owns it]
!!VRv2751&y1=1/y2=x1:+1; [Add 1 to v2750 if it's a Rampart and current player owns it]
- Fnord

User avatar
Fly
Leprechaun
Leprechaun
Posts: 20
Joined: 12 Jun 2006
Location: Russia - Krasnoyarsk
Contact:

Unread postby Fly » 12 Jun 2006, 15:19

Thanks a lot. I've wrote script, like this, but i have a litlle of problems with it's using... :)


Return to “Wake of Gods”

Who is online

Users browsing this forum: No registered users and 3 guests