Celowin's Scripting Tutorial, Lesson
Two - Local Variables
Introduction
The purpose of this sequence of lessons
is to take a complete beginner to
programming, and teach him or her how to use
NWScript to write modules. The early lessons
will be very basic, and anyone that has done
any coding at all will be able to skip over
them. The goal here is to make the lessons
so that even the people that just shudder at
any type of code can learn.
Feel free to post these lessons on any
forum, print them out, or modify them.
However, just give me credit for doing them.
I am going to assume that anyone looking at
these lessons has at least played around
with the Aurora Toolset a bit. If there is
enough feedback that people don't know how
to do the simple placements that I have in
these lessons, I will consider spelling out
in more detail what needs to be done.
Let's Begin
This lesson will likely be a bit longer than
the first one, and deal with some more
advanced concepts. I'm not certain how well
I'll be explaining things here, so please
ask questions if you don't understand
something. Odds are if what I write isn't
clear to you, there are five other people
that want to know the same thing.
Let's just modify the module we started
before. Open it up in the editor.
Right click on the NPC we have, go to
properties, and go to the script tab. (We
could make a new NPC, but do we really want
this one chanting his song in the
background? It gets old really quickly....)
We're going to need two scripts this time,
both short.
Now, even though this is only one line, it
is things like this that tend to freak out
people that have never scripted before. So,
I'm going to explain this one before I go on
to the "real" script.
First off, note that we're putting this on
into a different handle than before. Any
script attached to "OnSpawn" is run exactly
once... when the NPC first loads into the
game. Because of this, it is ideal for
initializing things, which is what we are
doing here.
This one line sets up a variable.
Think back to your last math course, what
was a variable? A letter which represents a
number. That is pretty much the same thing
that we are doing here, except that instead
of using a single letter, we give it a
longer name.
The command SetLocalInt is the function that
is setting everything up. It takes in three
inputs, separated by commas.
- The first is the thing which the variable
is "attached" to.
- The second is the name we are giving to
the variable.
- The third and final is the value we are
putting into the variable.
At this point, I hope the second and third
of these make sense... we are calling our
variable SINGER_COUNT and we are giving it
the value of 0. It is the first input that
takes a bit more explanation.
Nearly everything in a module is an object.
NPCs are objects. Placeables are objects.
Waypoints are objects. Even the pcs
themselves are objects. With so many objects
floating around in a module, the tricky part
becomes making sure you are referring to the
right one.
OBJECT_SELF is one of the most handy ways to
refer to an object. As you might guess, it
is used to refer to whatever object is
calling it... in this case, our script was
attached to an NPC, so that NPC is what is
meant by OBJECT_SELF.
Putting all this together... this one line
has defined a variable called SINGER_COUNT,
given the variable a value of 0, and stored
it with the NPC SINGER.
Also of note is that the Int in SetLocalInt
stands for "Integer", or basically a whole
number. We can set it to 4, or 0, or –35,
but we can't set it to 3.8, for example.
Now, let's go on to the second script. We'll
overwrite the OnHeartbeat script from the
last time.
NWScript:
int nCount=GetLocalInt(OBJECT_SELF, "SINGER_COUNT");
void main(){
nCount = nCount+1;
ActionSpeakString("I have spoken "+IntToString(nCount)+" times.");
SetLocalInt(OBJECT_SELF, "SINGER_COUNT", nCount);
}
Save it, keeping the name tm_singer_hb
Before I explain this, it is probably a good
idea to take a look at what it actually
does. So close your script window, click OK
on your NPC, and save the module. Start up
the test module, and see how the NPC
behaves.
This is the first script I have done where
we have had anything before the void main(),
so it is worth mentioning. Everything before
that is called the "initialization" of the
script. Basically, it sets up things that
the script can refer to. Unlike the local
variable that we stored before, this nCount
only stays around as long as the script is
running. As soon as the script finishes, it
gets rid of nCount. For this reason, the
variables created in a script like this are
called "temporary variables."
Notice how many times we used "nCount"
inside the body of main. Imagine how long
and confusing the script would be if every
time we had to write something like
GetLocalInt(OBJECT_SELF, "SINGER_COUNT")
instead of just nCount. Pretty sick, eh?
Now, the name nCount is another bit of
standardization. Any time you declare a
temporary variable, the first letter is a
tag to point out what kind of value it
takes. The n stands for integer. According
to the code, you could give it any name you
want, but by naming it this way, you know
immediately that it must take an integer
value. The "Count" part of the name tells
you a bit about what it will be used for.
The "int" says we are defining an integer
variable. The "=" means "give it the value
of." And the GetLocalInt retrieves the value
of the variable SINGER_COUNT.
Note the similarity of the functions... we
used SetLocalInt to set up and store the
local variable, and GetLocalInt to retrieve
the value.
So, that very first line does a lot. It
creates a temporary variable nCount that the
script can use, and right away gives it the
value of the variable assigned to
SINGER_COUNT and stored on our NPC. So, the
first time this is called, nCount has a
value of 0, since that is what we
initialized it to in our OnSpawn script.
I know, this is a lot of explanation for one
line of code, and I doubt anyone would
digest it all on one pass. Read through it
again, and if it still isn't clear, don't
worry too much about it. This kind of thing
makes a lot more sense once you've done a
few examples.
Let's move on to the main body of the
script, then. Consider the first line:
nCount = nCount+1;
This just takes our temporary variable, and
increases it by one. For expressions like
this, it helps some people to read the word
"set" in front of the expression. So in
words, this might be read "set the variable
nCount equal to the value of nCount plus
one."
If nCount starts out with a value of 9, this
will set it to have a new value of 10.
(As an aside, another way this can be put
into NWScript is to write the line as
nCount++;
The ++ stands for "increment", that is,
increase by one. This is fine once you are
used to it, but is generally a bit more
confusing for people that are just
learning.)
The second line is an ActionSpeakString, but
the inside is kind of funny. I've done a few
things here... first, notice that we have
three things on the inside, separated with +
signs. When applied to strings (text), the +
just adds one string on to the other. So for
a simple example:
"This is a string." would be exactly the
same as "This is "+"a string."
There would be no reason to do something
like in the above line. But it comes in
handy when we introduce the middle part of
the expression: IntToString(nCount). This
does exactly what it says... nCount is an
integer. This changes the numerical value
that it has into a string, or bit of text.
This idea can be a bit confusing for a
non-coder, so let me try to make an analogy.
Suppose I say something silly like "an
elephant wearing a tutu." You immediately
get a picture in your head, and don't think
about the individual letters that go into
making up the phrase I said. It is only when
you go to write it out that you start
thinking a-n-space-e-l-e-p- and so on.
The computer is the same way. It is storing
the value of the variable, and it isn't
thinking about how to "write it out." The
IntToString tells it to do that conversion
to text so that the NPC can speak it.
The final line you should understand... it
just stores the new value of nCount back
into our local variable. Remember that the
actual nCount is only temporary, and will be
discarded once the script ends. So if we
want the variable to update, we need to
store it again.
Preview of Lesson Three
Lesson two was originally going to be two or
three times as long, but I think I'm going
to split it up into separate lessons.
However, I just can't leave our last script
in the state it is in... it has an error
that just irks me.
If you are detail oriented, you might have
cringed a bit when you first tested the
script. The very first words out of the NPC
were "I have spoken 1 times." Easy enough to
understand what is meant, but not the height
of grammar, either.
The way to get around this is by using a
"conditional" or "if-statement". I'm not
going to explain this all until Lesson
Three, but here is a script that fixes the
problem. Just replace the heartbeat script
with this
NWScript:
int nCount=GetLocalInt(OBJECT_SELF, "SINGER_COUNT");
void main(){
nCount = nCount+1;
if(nCount==1){ActionSpeakString("This is the first time I have spoken.");
}else{ActionSpeakString("I have spoken "+IntToString(nCount)+" times.");
}SetLocalInt(OBJECT_SELF, "SINGER_COUNT", nCount);
}
Hopefully, even without explanation, this
is somewhat easy to understand. And really,
once you fully understand it, you are
probably 80% of the way to writing your own
scripts.