Click for more information!

     

An Introduction to Uscript Fundamentals.

Author: Adaption
Date: July 4, 2000

 

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.

 

New ArchivesMutator NewsMartin's Unrealscript DiaryUnrealscript TutorialsMutator and coding utilitiesThe definitive Mutator FAQSay somethingSubmit news, mutators, tutorials