An Introduction to Uscript Fundamentals
Scope of this document
This tutorial is intended for people who are new to Uscript and
is geared more towards people who are not experienced programmers.
The basic building blocks of Uscript will be covered, as well as the
general stylistic conventions of the Uscript community. With the
fundamental building blocks being well understood, it is possible to
begin reading and writing code, which is by far the best way to
learn the language. This document may be completely boring to people
who are experienced coders. In that case, I refer you to one of the
many tutorials out there that will be better suited to your
needs.
What is Uscript?
Uscript is a scripting language in which the “rules” of Unreal
and Unreal Tournament are defined. It is through Uscript that the
Unreal engine can understand what a rocket launcher is, or how high
a player can jump. This definition is overly simplistic, but is a
good approximation for a beginning coder.
Whoa... that sounds scary!
Just starting out, it seems impossible to understand what the
code actually means. However, at its base, it is a completely
logical and comprehensive definition of a set of rules. Once you
understand the logic behind the code, it becomes much easier to
comprehend. Through time and practice, the ability to read and
understand code will become second nature. The best advice for an
aspiring Uscript programmer is to start with small projects and
understand them completely before moving on to bigger ones.
Ok, I’m willing to give this a shot.
Good. The first thing an aspiring UScripter should do is obtain
the necessary tools. Lists of popular tools can be found at Chimeric
and The Mutation Device. Is it also possible to use UnrealED, but,
personally, I prefer using an editor combined with Uclasses. What
tools you pick are all a matter of style, but choose wisely. If
something doesn’t seem to be working... try some other tools. Be
sure you are working with tools that you can use comfortably and
naturally.
The second thing that is necessary is to open up UnrealED and
export the Uscript source. This is described in detail in GreenMarine’s Mod
Authoring for Unreal Tournament.
Right. Now I have a bunch of directories in my UT directory full
of .uc files... what the heck are these?
These .uc files contain raw (uncompiled) code from Unreal
Tournament. “Uncompiled code” basically means that the code is in a
state where it is readable by humans using nothing more
sophisticated than text editiors. Human-readable code is called
either “uncompiled” or “source code.” In order for the machine to be
able to understand the code, it must be compiled. A compiler is a
piece of software that changes source into a machine-readable form.
Such code is usually called either “compiled code” or
“built.”
Now go to the “classes” directory in the directory
called “engine” and open the file called “mutator.uc” in any text
editor. Notepad will work, but see the above section about tools.
You should get some source code that begins like this:
//=============================================================================
// Mutator.
// called by the IsRelevant() function of DeathMatchPlus
// by adding new mutators, you can change actors in the level without requiring
// a new game class. Multiple mutators can be linked together.
//=============================================================================
class Mutator expands Info
native;
var Mutator NextMutator;
var Mutator NextDamageMutator;
var Mutator NextMessageMutator;
var Mutator NextHUDMutator;
var bool bHUDMutator;
var class DefaultWeapon;
event PreBeginPlay()
{
//Don't call Actor PreBeginPlay()
}
simulated event PostRender( canvas Canvas );
function ModifyPlayer(Pawn Other)
{
// called by GameInfo.RestartPlayer()
if ( NextMutator != None )
NextMutator.ModifyPlayer(Other);
}
function bool HandleRestartGame()
{
if ( NextMutator != None )
return NextMutator.HandleRestartGame();
return false;
}
Oh my god. This makes absolutely no sense.
Don’t worry. You’re not supposed to understand it yet. We’re
going to take this a piece at a time.
The very top piece looks like this:
//=============================================================================
// Mutator.
// called by the IsRelevant() function of DeathMatchPlus
// by adding new mutators, you can change actors in the level without requiring
// a new game class. Multiple mutators can be linked together.
//=============================================================================
This seems easy enough to understand. But what’s it doing in
source code? Can a compiler really understand this?
The answer is no. Code such as this is called “commented” and the
double slash mark in front of each line tells the compiler to ignore
that line. These lines have no effect on the rules of the game.
So why use commenting at all? Simply because commenting can make
code easier to read. For example, reading the commented block above
is much easier than trying to figure out what a mutator does by
looking at the code itself. As a programmer, you should use
commenting especially when you are working with other coders. Think
of it as notes in the margin of a book.
The second important statment is this:
class Mutator expands Info;
This line says quite a lot in a relatively small amount of space.
But in order to really understand it, it is necessary to understand
exactly what a class is. In order to understand classes, we must
first understand the idea of “objects.”
In an object-oriented language, such as Uscript, an object may be
roughly defined as, “Something which has properties and/or uses.”
This doesn’t make much sense right now, but it will make more sense
when we delve into variables and functions. In UT, examples of
objects are rocket launchers, mutators, players, and even the HUD
itself. Don’t worry about understanding how a HUD can be an object
yet, just keep reading.
A class is like a “mold” for objects. Classes basically outline
what uses and properties that objects have. When creating a new
object, you merely need to tell the compiler what class it is, this
will be dealt with in more detail later.
So now we understand (kind of) the first part of the statement.
It is a line telling the compiler that this file contains the code
defining the uses and properties for a class called a “Mutator.” But
what about the second part? What does “expands Info” mean?
It means that the class in this file, “Mutator” is a so-called
subclass of a class named “Info.” A subclass has all the properties
and uses of the class of which it was subclassed from, in addition
to its own uses and properties. A way to think of it would be that
“Mutator” is a specialized form of “Info” with uses and properties
above and beyond “Info”.
For now, we don’t worry about the “native” statement. It is
beyond the scope of this document.
The next series of lines looks like this:
var Mutator NextMutator;
var Mutator NextDamageMutator;
var Mutator NextMessageMutator;
var Mutator NextHUDMutator;
var bool bHUDMutator;
var class DefaultWeapon;
They all begin with “var” and have two words after them, and they
terminate with a semicolon. These statements define variables, which
are the “properties” of an object. Let us examine one of these
statements in greater detail.
var bool bHUDMutator;
The “var” basically tells the compiler that the following
information pertains to a variable. These statments are called
“variable declarations” and tell the compiler what kind of
properties an object of a class has. The second part tells the
compiler what type of variable it is, and the third statement is a
name for the variable. So a generic statement would look like this:
var type VariableName;
Where type is the type of variable that is being defined, and
VariableName is the name by which you will refer to this variable in
your code.
There are two major flavors of variable types. A variable can be
a “Primitive type” or an “Reference.”
There are a couple primitive variable types. Here are a few:
Integers: Integers hold a non fractional (whole number)
value.
Example: var int CurrentAmmo;
Floating Point: Floating point numbers are decimals, and
can be non-whole numbers.
Example: var float
RespawnTime;
Boolean: Boolean variables are either true or false. They
cannot be any other value. As a convention, thier names begin with a
lowecase “b”
Example: var bool
bHUDMutator;
String: String variables contain a word or a set of letters and
numbers.
Example: var string MyName;
References are a bit different. Instead of having a primitive
type, they have a type defined by a class. This is because
references are used to “point to” another object. The line var
Mutator NextMutator; points to another mutator object
somewhere.
All the statements here end in a semicolon. That’s basically your
way of telling the compiler that what you’ve written constitutes a
complete command. You will notice semicolons at the end of almost
every line, with a few logical exceptions.
Of course, this is not a comprehensive list, and it might not
make any sense at the moment, but refer back to these definitions as
you see them in code. Types don’t make much sense until you actually
see and understand them being used. We are just trying to establish
a general overview of the code before we get more technical. The
main idea you should grasp at this point is that variables are used
to describe the changing properties of an object. They keep track of
how much ammo your rocket launcher has, or at what angle the flak
cannon shoots shrapnel.
Now, referring back to our definition of an Uscript “object”, we
now understand how the computer is made to understand the properties
of each object, but what about its uses? The uses of an object are
called “functions.”
Functions can be baffling for the first time programmer, but they
are among the most useful tools in the programmer’s arsenal. Without
functions, none of the properties of the objects can be used.
A function declaration looks like this:
function ModifyPlayer(Pawn Other)
{
// called by GameInfo.RestartPlayer()
if ( NextMutator != None )
NextMutator.ModifyPlayer(Other);
}
We’re going to break this down again.
This is called a function declaration. A function
basically is a series of things that the object will do when you
want it to.
Most functions begin with the word “function”, there are a few
exceptions, however, but they won’t be dealt with at this time. The
“function” tells the compiler that the following data pertains to a
function.
The second part in our example function, “ModifyPlayer”, is the
name of the function. When you want to execute the code of this
function, you refer to it by name. It’ll make sense in a bit.
The third part is a bit more complicated. The “Pawn Other” in
parenthesis is called the function’s argument. In order to
execute this function, you have to “send it” a reference to a Pawn
object, since it requires a “target” or something to act upon. In an
abstract example, let’s say you had a Wrench object, and it had a
TurnBolt function. The function declaration might look like
this:
function TurnBolt (Bolt TargetBolt)
In essence, the Wrench object and its TurnBolt function need to
know which bolt needs to be turned. When writing code, you
must be completely specific.
Immediately after the declaration there is a curly bracket on its
own line. This signals to the compiler where the function begins.
There is no semicolon after the function declaration, this is
because all the code within the curly brackets is, roughly speaking,
“part of” the declaration. The code that the function executes is
within the curly brackets. The commands inside the curly brackets
are what the function actually does. It can change variables, or it
can call other functions.
It is important to note that the subclass of a class “inherits”
all the functions and variables of the class from which it is
derived. When a function in a subclass redefines a function in the
class from which it is derived, the subclass overrides the parent
function.
Oh. So functions and variables are like “uses” and “properties”,
but how are they used? And what about the rest of the code in that
function up there? Huh? This still doesn’t make any sense,
dammit!
Relax. Now we are going to look at a simple mutator included with
the game, called “Fat Boy.”
Here is the source code for “Fat Boy.”
//=============================================================================
// FatBoy
// makes all players fat
//=============================================================================
class FatBoy expands Mutator;
function ScoreKill(Pawn Killer, Pawn Other)
{
if ((Killer != Other) && (Other != None) && (Killer != None))
{
// Normal kill.
if (Killer.Fatness >= 240)
Killer.Fatness = 255;
else
Killer.Fatness += 10;
Other.Fatness -= 10;
if (Other.Fatness < 60)
Other.Fatness = 60;
}
if ( (Other != None) && ((Killer == None) || (Killer == Other)) )
{
// Suicide.
Other.Fatness -= 10;
if (Other.Fatness < 60)
Other.Fatness = 60;
}
Super.ScoreKill(Killer, Other);
}
defaultproperties
{
}
Most likely, you can now understand bits and pieces of this
code. You know that this is a type of mutator called “Fatboy” and
that it has a function called “Scorekill” in it that executes a
whole wad of stuff that you are likely completely lost on.
First, let’s refer back to the mutator class. If you look
inside mutator.uc, you’ll find a function that looks like this:
function ScoreKill(Pawn Killer, Pawn Other)
{
// called by GameInfo.ScoreKill()
if ( NextMutator != None )
NextMutator.ScoreKill(Killer, Other);
}
The function ScoreKill in mutator is overridden by the function
ScoreKill in Fat Boy. What this means that when the game calls the
ScoreKill function to the current mutator, it will have a different
result depending on whether the mutator is a “Fat Boy” mutator or
just a regular mutator that doesn’t override ScoreKill. This idea of
overriding is VERY important. When you’ve learned enough you should
play with it until your comfortable.
Now, back to “Fat Boy.” The ScoreKill function is called by the
GameInfo (which we won’t worry about until later) whenever someone
is killed. The arguments for the function are the the Pawn (A Pawn
is something in the game that moves and reacts to the environment,
like players and bots) that killed the player, who will be referred
to as “Killer.” The other argument of the function (a list of more
than one argument is separated by commas) is the Pawn who was
killed. The mutator needs to know this information in order to
understand what it’s supposed to do when someone kills someone
else.
The first line inside the curly brackets is this:
if ((Killer != Other) && (Other != None) &&
(Killer != None))
This statement is called a conditional statement. It tells the
compiler to do something when certain conditions are met. The
conditions themselves are placed inside the parenthesis.
The sentence above could roughly translate out to English about
like this:
“If the Killer is not the one who was killed and someone was
killed and someone killed them.”
This sounds awful, of course, but the compiler needs to know
EXACTLY what conditions under which to execute the code associated
with the “if” statement. We’ll break it up for easier
understanding.
The keyword “if” tells the compiler that the following info
pertains to a conditional statement.
The outside pair of parenthesis are used to encapsulate the
conditions under which the code should be executed. The three inside
groups of parenthesis are optional grouping marks that help you to
read the code more easily.
The first condition is: (Killer != Other )
This condition
checks to see if the Killer that was sent to the function is the
same as the reference to Other that was sent to the function. It
basically checks to see if the killer and the one killed are the
same person. If they are not, than this condition has been met. The
“!=” operator between the two signifies, basically “is not” or this
condition is true is Killer is not Other.
After the first condition, there is a “&&” which appears.
This signifies “and”, meaning that this code should execute if the
first condition AND the second condition AND the third condition are
met.
The second condition checks to see if Other != None. None is a
special word in Uscript, and it basically means “no object.” This
condition checks to see if the object that was killed, called
“Other” by the function, still exists.
The third condition checks to see if Killer != None. This checks
to see if the Killer of the pawn is a Pawn and that the killer still
exists. If all three of these conditions are met, the code inside
the curly brackets underneath the conditional statement is executed.
Let’s have a look at this code.
if ((Killer != Other) && (Other != None) && (Killer != None))
{
// Normal kill.
if (Killer.Fatness >= 240)
Killer.Fatness = 255;
else
Killer.Fatness += 10;
Other.Fatness -= 10;
if (Other.Fatness < 60)
Other.Fatness = 60;
}
Once again, we see another conditional statement, but inside
the condition of the conditional statement are strange. What is
Killer.Fatness? What does >= mean? Why do they use 240 there?
What’s going on?
When you see a dot after a variable reference to another object,
it means to access either that objects variables or functions. So,
Killer.Fatness is the Fatness variable of the Killer Pawn. For
simplicity’s sake, I will not go into detail about the Fatness
variable, save for it tells the game how “fat” something should be
rendered. The Fatness variable is a primitive variable of type
"byte”, which means that it can contain any whole number from 0 to
255.
As for “>=” , it means “greater than or equal to”, which is a
numerical comparison between two variables or numbers. The condition
under which the code for this conditional statement is executed is
if the value of the Killer’s Fatness being greater than 240. If the
Killer’s fatness is greater than 240, the conditional statement is
true, and the code is executed.
You might notice that there are no curly brackets beneath the
“if” statement. If the code that is to be executed if the statement
is true is only one line long, you don’t need the brackets, but you
can put them in if you feel more comfortable in doing so. Which is
to say that this:
if (Killer.Fatness >= 240)
Killer.Fatness = 255;
Is equal to this:
if (Killer.Fatness >= 240)
{
Killer.Fatness = 255;
}
It’s a style thing. Personally, I prefer not to use the brackets
if there is only one line, but some people like to be
consistent.
So, we know that if the Fatness of the Killer Pawn is greater
than or equal to 240 the line Killer.Fatness = 255; is executed. But
what does that mean?
The single equals sign means to set the left expression equal to
the right expression. The left expression is the only one that is
changed by this operation. Only one variable is allowed on the left
side of the equation, while, depending on the circumstances, you may
have several on the right side, especially if you are working with
numerical values. So this line makes the Killer’s Fatness variable
equal to 255 (the maximum value).
After this we see another new statement: “else”. The else
statement appears after a conditional statement. The code associated
with the else statement executes if the condition(s) of the if
statement that come before it are false. So think of it this way: if
the Killer’s fatness is greater than or equal to 240, do one thing,
and if it’s not, so something else. The else statement is not,
strictly speaking, necessary. You could make a logically equivalent
statement simply by using an if statement like this: if(
Killer.Fatness < 240 ), which will if the killer’s fatness is
less than 240. But else is very convenient and appears often in many
classes you will be working with, so you should understand what it
means.
The line that is executed in the “else” statement is
Killer.Fatness += 10; which is simply a compressed way
of writing Killer.Fatness = Killer.Fatness + 10;
This means that the Fatness of the Killer is increased by ten
units over its previous value, or the new Killer.Fatness is ten
units greater than the old Killer.Fatness. Don’t be confused by the
appearance of the same variable on both sides of the equation. The
one on the left side is the only one that changes, so the net effect
is to increase the Fatness of the Killer by ten.
The next line is: Other.Fatness -= 10;
This is similar to Killer.Fatness += 10; except that
it’s subtracting ten instead of adding it. This makes the Fatness of
the player that has been killed decrement by ten units.
You should be able to understand the next two statements. There’s
a simple conditional to check to see if the fatness of player who
was killed is less than sixty, and if it is, set it equal to sixty.
This makes sure that the player’s fatness doesn’t go below
sixty.
Now, let’s recap what we know about the “Fat Boy” mutator thus
far. The “Fat Boy” mutator has a function called ScoreKill that is
called by the game whenever someone gets killed. If the person who
was killed didn’t kill him or herself, and the thing that was killed
is a Pawn and still exists, and the killer of the thing that was
killed is a pawn and still exists, then the Killer’s fatness should
increase to a maximum of 255, and the player who was killed should
lose ten units of fatness to a minimum of 60.
The second conditional should be child’s play for you to figure
out now.
if ( (Other != None) && ((Killer == None) || (Killer == Other)) )
{
// Suicide.
Other.Fatness -= 10;
if (Other.Fatness < 60)
Other.Fatness = 60;
}
However, you might be a bit confused by the presence of the “||”
symbol. This symbol means “or”, which means that the conditional
code will execute if one condition, the other condition, or both
conditions are true, but it won’t execute otherwise. This
conditional statement can be roughly translated to English like
so:
“If someone was killed and if nobody killed them or the player
killed itself”
This is where the inner parenthesis become especially important.
The parenthesis basically mean that the conditions are in a group.
This is really important given the fact that that a statement can
mean something completely different if the position of the
parenthesis are moved. For example:
if ( (Other != None) && ((Killer == None) ||
(Killer == Other)) )
is different from:
if ( ( (Other != None) && (Killer == None) ) ||
(Killer == Other) )
How are they different? Well, the first statement translates
roughly to:
“If someone was killed and if nobody killed them or the player
killed itself”
And the second:
“If someone was killed and nobody killed them or if the player
killed itself”
If you are not familiar with logic, this might require some
thought. Once you understand the basics of coding, you can play with
different situations and begin to fully understand difference
between the two statements.
Moving on, we have a set of statements which we have seen
before:
// Suicide.
Other.Fatness -= 10;
if (Other.Fatness < 60)
Other.Fatness = 60;
It begins with a comment, then there is some familiar code.
Bascially, if you kill yourself, you lose ten fatness units.
Now, the final line of the function probably makes no sense.
Super.ScoreKill(Killer, Other);
According to what we know so far, This function would execute the
ScoreKill function of some object that we have named “Super.”
Unfortunately, this is not what it does at all.
“Super” is a special reference which points to the superclass (or
class from which the current class is derived) of the current class.
So a call to Super.ScoreKill(Killer, Other); calls the parent
version of the function, which can be found in the mutator class.
This is really useful when you want a function to do something new
in addition to what it does in the parent class. As a side note,
this doesn’t ever need to be done with variables.
By now, you should feel pretty comfortable with the “Fat Boy”
mutator, and the basic framework of Uscript. Now, we can go into
detail about the smallest units of Uscript: the operators, keywords,
primitive variable types, and syntax.
A short UnrealScript Reference:
Here is a short reference of some of the most basic elements on
Uscript. You will likely run into more advanced concepts later on,
and for that I direct you to the UnrealScript Language
Reference.
Commenting:
Use: To help keep track of what code is doing. Comments are
useful as notes. Comments are not executed by the compiler.
Examples:
Single line comment: //
// This is a comment
Multiple line comment: /* */
/* This is a commented block.
Nothing within the markers
is executed */
Note: Comments are very useful when you are working on a team
with others.
Basic Variables and Variable Types:
Use: Variables are used to store pieces of data. They hold
information about an object.
Declaration:
Class-wide variables: var type VariableName
Class-wide variables can be accessed anywhere within the class,
or, using references, from other classes.
Local variables: local type VariableName
Local variables are temporary variables used inside functions.
They are created when a function is called and destroyed immediately
afterward. They cannot be accessed through references, but they can
be returned through functions. (See below)
There are a few useful types of variables, a comprehensive list
can be found in Tim Sweeney’s
UnrealScript Language Reference. A variable’s type determines
the possible values it can have.
Integers( int ): Integers hold a non fractional (whole
number) value.
Declaration Example: var int
CurrentAmmo;
Floating Point( float ) : Floating point numbers are
decimals, and can be non-whole numbers.
Declaration
Example: var float RespawnTime;
Boolean( bool ): A boolean value holds a logically true or
false value. By convention, a lowercase “b” is placed at the
beginning of a boolean variable name.
Declaration Example:
var bool bHUDMutator;
String( string ): A string variable contains a word or a
set of letters and numbers.
Declaration Example: var
string MyName;
Byte( byte ): A variable containing whole number from 0 to
255
Declaration Example: var byte
Opacity;
References: A reference to another object that is a class
or a subclass of the specified type.
Declaration Example:
var Actor Target;
You can access an object’s variables by using the reference name
and the variable name:
Other.Fatness = 100;
You can also execute functions of another object through
references:
Other.ClientMessage(“Hello!”);
Basic Variable Operators:
Operator = (The assignment operator)
The assignment operator sets the variable on to its left equal to
the expression on the right. The variable and the expression must be
of the SAME TYPE. You cannot assign a string to a floating point
variable, and the compiler will warn you when you make errors. You
must declare variables before you use them.
local string MyName;
MyName = “Fred”; //Sets the local
MyName variable equal to Fred.
Operators +, -, *, / (The mathematical operators)
These operators are used to do mathematical operations on an
numerical expression. They must be used in conjunction with the
assignment operator to be useful.
Total = (2 * 4) + 3; // Sets the Total variable equal to
the expression (2 * 4) + 3, or 11.
Conditional Statements:
Use: Conditional statements are used to execute code only when
certain conditions are met.
Syntax:
if( condition)
{
//execute conditional code
}
The condition must reduce to a logical true or false. The
simplest example of this is with a boolean variable (which has a
value either of logical truth or falsehood.)
if( bIsFlying )
{
//execute if the boolean variable
bIsFlying is True
}
For other variables, you can use the so-called logical operators
to create statements that will return true or false. Two variables
compared using logical operators usually must be of the SAME TYPE. A
float and a string cannot be compared directly. The logical
operators are as follows:
Operator == (The equivalence check) (Any variable type may
use)
The operator == checks to see if two variables are equal. If the
two variables are numeric, it compares them numerically. If the two
variables are strings, the expression is true if they are the same
string. If the two variables are references to objects, the
expression is true if they refer to the same object.
if( Height == 30)
{
//Executes if the Height variable
is equal to 30
}
if( MyName == “Elvis” )
{
//Executes if the MyName
variable contains the string Elvis.
}
if( Killer == Other )
{
//Executes if the Killer
reference refers to the same object as the Other
reference.
}
Operator != (The inequivalence check) (Any variable type may
use)
The operator != checks to see if two variables are not equal. If
the two variables on either side of the operator are different
values (but the same type) the statement is logically true.
if( Killer != Other )
{
//Executes if the Killer
reference doesn’t refer to the same object as the Other
//reference
}
Operators >, >=, <=, <, (Numerical Comparison
Checks, and string length checking) (Variable types byte, int,
float, string)
These operators compare two numbers and return a logical true if
the comparison made is true. For strings, it compares the lengths of
two strings.
if( Height >= 30 )
{
//Executes if the value of
the height variable is greater than or equal to 30.
}
if(MyName < “Elvis”)
{
//Executes if the string
contained within MyName is shorter than Elvis.
}
Operator ! (Unary Negation) (Usually used with Boolean
values)
This operator checks to see if a boolean expression is not true,
and returns true if it is. The ! operators is a unary operator,
meaning it needs one argument.
if(!bDontExecute)
{
//Executes if bDontExecute is not
true
}
Operator || ( Logical OR ) (Used with two complete
expressions)
This operator requires two complete logical expressions and is
true if one, the other, or both expressions are true.
if(!bDontExecute || Height == 30)
{
//Executes if
bDontExecute is False or Height is equal to thirty, or
both.
}
Operator &&( Logical AND ) (Used with two complete
expressions)
This operator requires two complete logical expressions and is
true only if both expressions are true.
if( !bDontExecute && Height == 30)
{
//Executes if bDontExecute is False and Height is equal to
thirty
}
Flow-Control Keywords:
The For Statement
The for statement is used to execute code repeatedly. This is
convenient especially when you want to do something a variable
number of times, or until a certain condition is met.
The structure of the “for” command is as follows:
for( initial condition; ending condition; iteration
command)
Where initial condition initalizes the loop variable to a certain
value. The for loop will execute repeatedly until the “ending
condition” is no longer true. Each time the loop “goes through” a
cycle, the iteration command is executed once. This is hard to
understand, but very useful. Here is an example:
local int P;
for( P = 0; P <= 5; P = P + 1)
{
//The code inside
this block will be executed five times
}
There is a shorthand notation for P = P + 1, and this is often
seen. P = P + 1 is in all ways the same as using P++.
The While Statement
The while statement is like the for statement, in the regards
that it executes while a certain condition is true. Unlike the for
statement, it does not have an initialization or an iteration
command. This loop merely executes while a certain condition is
true.
while( bExecute)
{
//This block executes while
bExecute is true.
}
Functions
Use: A function is a bit of code that executes when it is called.
Functions can be used to create objects, alter variables, and call
other functions. All the coding you will be doing will be either
overriding functions or creating new ones.
Declaration Syntax:
Depending on what kind of function it is, the function
declaration is written differently. The simplest type of function is
written like this:
function FunctionName()
{
//Call some
code
}
Sometimes you want to perform a function given certain data, such
as an object you want it to be performed on, or some numerical value
you want to be associated with the function. For these cases,
arguments are very useful. Without arguments, it is necessary to set
all sorts of class-wide variables, and this becomes quickly
unmanagable.
function FunctionName(type ArgumentName)
{
//Call
some code
}
When specifying the names of the arguments you’re going to use,
you must also specify the type. For example, here is a function you
could call to make yourself fat to a specific degree:
function MakeMeFat(Pawn Other, byte
NewFatness)
{
Other.Fatness = NewFatness;
}
Arguments increase the versatility of your functions. Use them
when your function calls require localized information from other
places.
The third type of function is the function with a return value.
These are functions that send a variable back to the place that
called it. For example.
function bool AmIFat( Pawn Other )
{
if(Other.Fatness > 128)
return true;
if(Other.Fatness <= 128)
return false;
}
When this function is called, it checks the fatness of the
reference given in the argument. If it is fat, it returns a “true”
boolean value. If it is not fat, it returns a “false” boolean
value.
Somewhere else in the program, we could see this function:
function Heckle( Pawn Target )
{
local bool bFatCheck;
bFatCheck = AmIFat(Target);
if(bFatCheck)
HeckleFatPlayer(Target);
else
HeckleSkinnyPlayer(Target);
}
Note two things especially. First, while the reference is passed
to the Heckle function under the name “Target”, it is used in the
AmIFat function as a reference named “Other”. That is, the name of
the variable in the argument declaration is the name it uses in that
function.
The second thing to take note of is the fact that it is possible
to assign the result of a function to a variable if it has a return
type. This might be a bit confusing at first, but once you learn to
use it, it will be both logical and useful. In all respects, a
function that returns a value acts like a variable, except for the
fact that you can’t assign values to it, you can only take values
from it. So, it would be possible to write the above code in
condensed form:
function Heckle( Pawn Target )
{
if( AmIFat(Target) )
HeckleFatPlayer(Target);
else
HeckleSkinnyPlayer(Target);
}
I found something in the source code that wasn’t listed
here!
This list is not comprehensive, not is it a complete reference,
it’s just a quick reference to help you learn to read code. If you
find something that isn’t listed here, there is a good chance you’ll
find it once of two places: if it’s a function or a variable, you’ll
likely find it elsewhere in the source, if it’s a keyword or an
operator, check Tim Sweeney’s
UnrealScript Language reference. Things like arrays and casting
are not included here for simplicity’s sake, but they are
indispensible Uscript tools.
Where to get more information:
These websites are part of every Uscripter’s arsenal, and since
this document is not at all comprehensive, I recommend that you
visit these sites and learn from the best:
http://www.planetunreal.com/chimeric
Has good tutorials for you to peruse.
http://www.planetunreal.com/unrealtower
Home of the very useful Uclasses utility
http://www.planetunreal.com/mutation
More tutorials here, and home of the [I was going to
put something here, but it would be attributed to Adaption, and
that's just not fair on him :P -- JbP]
http://unreal.epicgames.com/
Be sure to check out GM’s Mod Authoring for Unreal Tournament and
the UnrealScript Language Reference.