HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Beginner's guide to JASS (Custom Text)

02-21-2003, 10:24 PM#1
Guest
Custom Text 201:

Disclaimer:
If you're reading this, you should know how to make a basic trigger using the WE interface, know how to assign events, conditions and actions. This is not a trigger or variable tutorial. I want to make sure you are aware that custom text can be tricky. Please don't PM me with your custom text triggers asking for help. It would be far too time consuming to help everyone that has a custom text problem.

This tutorial is only designed to help you learn how to "START" getting into custom text. It is by no means a definitive guide to custom text. Once you've read learned the basics about using custom text, use magnus99's reference manual for more complex JASS information: http://jass.sourceforge.net/doc/

If you find yourself getting lost or not understanding concepts in this tutorial, please re-read it completely a few times. If you are still having trouble, then maybe custom text isn't for you...

What do you need?:
World Editor (WE)
Notepad

What is custom text?:
BASIC triggers are made using the internal graphic user interface (GUI) in the World Editor. When your map is saved, all you're triggers are converted and compiled into a JASS script (war3map.j). Custom text triggers are ADVANCED triggers that are written in the JASS programming language (created by Blizzard for WC3). If you have prior programming knowledge, you'll find JASS very similar to other languages.

How do I start a custom text trigger?
Luckily, since the WE offers a “Convert Trigger to Custom Text� feature, you don't have to worry about extracting the .j file from the .w3m file to create custom text triggers. All you have to do is simply convert an existing trigger in the WE into a custom text and start making changes.

Why would I want to use custom text?
The main reason you'll find a need for custom text is when you can't easily accomplish the desired trigger effect using the standard GUI that comes with the WE. Custom text isn't bound by the same rules that bind the GUI interface. Among other things, you can create better if/then statements, call loops and use local variables.

How do I learn custom text?
Well, hopefully, this tutorial will give you the confidence to begin experimenting with JASS custom text. Besides this tutorial, there are a number of resources on the web you can use for other languages. You see, as mentioned above, JASS is very similar to other languages. So having understanding of how something works in JavaScript for example, will greatly improve your chances of making your function work in JASS. (you can find JavaScript tutorials at www.webmonkey.com)

OK, that's all neat and everything, but how does it work?
It all starts with the “function�. Functions are the building blocks of programming. Functions are actions that you can call over and over without having to rewrite them every time. Here's an example of a very simple function (called Test) that simply displays the message "I'm a test function." to all players in the game.

Collapse JASS:
function Test takes nothing returns nothing
    call DisplayTextToForce( GetPlayersAll(), "I'm a test function." )
endfunction

The above example only DEFINES the function. Defining a function simply means that you are telling the JASS script that everytime you call the function "Test" it will display the action you defined. IT DOES NOT ACTUALLY RUN THE FUNCTION.

To RUN the function, you will need to CALL it from within another function. Here's an example of how to CALL the above function:

Collapse JASS:
Function RunTest takes nothing returns nothing
    call DisplayTextToForce( GetPlayersAll(), "Calling the test function..." )
    call Test()
endfunction

So now, when the above "RunTest" function is called, it will
1) Display the text: "Calling the test function..."
2) Call the "Test" function, which will display the text: "I'm a test function"

You could then create an event (explained later) that would periodically call the "RunTest" function every 10 seconds. This is what is meant by using functions as your building blocks.


Defining a function:
As you likely noticed in the above examples, there are a number of parts to defining a function. All function definitions use the following format:

Collapse JASS:
function <function name> takes <parameter> returns <return value>
    <actions>
endfunction

//where:
//   <function name> = the name of the function (no spaces, needs to be unique)
//   <parameter> = a value that is passed into and used as a local variable in the function
//   <return value> = the type of value that will be returned from this function
//   <actions> = the actions that the function makes when called (run).

In the first example "Test", the parameter is nothing and the return value is nothing. This means that no outside value is taken in and used as a variable and no value is returned. The action is to display a text message.

Parameters and Return Values:
As mentioned above, parameters are values that are passed into the function when it is called and used as a local variable. Return values are the type of value that will be returned at the end of a function (example: true/false, an integer, a unit, a real value). Here's an example of a function that uses a parameter and returns an integer value:

Collapse JASS:
function Half takes integer x returns integer
   set x = x / 2
   return x
endfunction

This function "Half" takes a value "x" and returns that value after dividing it in half. It's important to realize that "x" could be called anything. "x" is simply the name of the LOCAL variable used inside the function. (LOCAL variables are only used in THAT function) Also notice that I needed to define the variable type (integer, unit, boolean, real, region, etc.) for BOTH the parameter "x" and the return value. However, notice that the return value does NOT need a variable name, just the variable type that will be returned. Here's an example of how the function "Half" would be used:

Collapse JASS:
function HalfGlobal_X takes nothing returns nothing
   set udg_Global_X = Half(10)
endfunction

*Note: udg_Global_X is a global variable. All udg_ global variables are defined in the normal manner of defining variables using the "Edit Variable List" in the WE. So if I had defined Global_X as an integer in the WE, then it would be udg_Global_X when I used it in custom text. Global variables can be called from ANY function.

The above example, "HalfGlobal_X" takes no parameter and has no return value. But as an action it sets the global variable X to equal the return value of the "Half" function, where the value "10" is passed into the "Half" function as a parameter and becomes the local variable "x". In other words, 10 = x, which is divided by 2, which then returns the value 5. So Global_X is set to 5.

While you can only have one return value, you CAN have multiple parameters if you want to pass multiple values into the function:

Collapse JASS:
   function TestMultiple takes integer x, unit y, real z returns nothing

You would call this example using the following format:
Collapse JASS:
   call TestMultiple(x,y,z)

You can also find another guide to functions that DKSlayer made in the AI & Jass Vault here.

The If/Then Statement:
One of the most useful actions in a function is the if/then statment. If/then statements are essentially conditional actions. The are used in the following format:

Collapse JASS:
   if <condition> then
      <action1>
   else
      <action2>
   endif

If you know how to use basic triggers, then you should be pretty familiar with conditions. A condition is basically a comparison of some type. The easiest way to create conditions is to make one using the GUI in the WE and then convert it to custom text. Find the "if <condition> then" line and copy it into your function.


Nested If/Then Statements:
It's also possible to use multiple if/then statements within an if/then statment. For example:

Collapse JASS:
   if <condition1> then
      if <condition2> then
         <action1>
       else
         <action2>
      endif
   else
      <action3>
   endif

This example does the following... Checks condition 1. if condition 1 is true then checks condition2, if condition2 is true does action 1, if condition 2 is not true does action 2, if condition 1 was false, then it does action3. Seems more complicated than it is... Which is why I suggest using indentations to keep track of your nested if/then statements. (whitespace doesn't matter in JASS)


The "else" and "elseif" statments:
It's also important to note that in if/then statements, the "else" is optional. You can simply end a if/then with an "endif" when there is only one desired action.

The "elseif" option is very similar to using both an "else" and an "if/then" statement in a nested if/then statement, except it doesn't need the "endif", can be used multiple times and has a much cleaner format. It is evaluated when the condition of the "if" statment is found to be false, as well as the conditions of all preceding "elseif" statments. The first and only the first of these found to be true has its actions executed. If you precede an "elseif" with an "else" then the "elseif" will be ignored in favor of the "else". For this reason, the "else" statement should always be used last. Here's an example of using an "elseif" statement.

Collapse JASS:
   if <condition1> then
      <action1>
   elseif <condition2> then
      <action2>
   elseif <condition3> then
      <action3>
   else
      <action4>
   endif

It's also important to note that "else" and "elseif" statements can't have their own "else" and "elseif" children. Only the parent "if" statement can have "else" and "elseif" children. If you wanted to do this, you would need to use a nested "if" statement instead.


Loops:
One of the other most useful actions is the loop. A loop is an action that is repeated until a condition is met. This can be wonderful and it can also be dangerous and crash your map if used improperly.

Loops use the following format:

Collapse JASS:
    loop
        exitwhen <condition>
        <action>
    endloop

*You want to avoid infinite loop situations for the most part. In most cases, you WILL crash if you create an infinite loop. An infinite loop is a loop that has no IMMEDIATE exit. When this happens the WC3 engine will just spin and spin in a circle, resulting in a crash. If the condition you want is independent of what's happening in your function (like waiting for a unit to die or enter a region or whatever), then you will need to have a wait inside the loop. This gives the WC3 engine some breathing room to do something else. I will say that in most cases, it would simply be better to create a new trigger with a new event and condition.

**The "exitwhen" condition can also be used multiple times and at ANY time within the loop. This is particularly useful in combination with if/then statements where you might want to have multiple ways to exit a loop that may or may not be dependent on certain conditions being met.


***Just like if/then statements, you can also have nested loops (or loops within loops).


A counting loop:
The most common use for a loop is a counting loop. This is a loop that counts a variable up until it meets the condition and exits the loop. If you've ever used the action, [For Each Variable A, from 1 to x, do <action>], then you have used a counting loop.

Example:

Collapse JASS:
function StartCountLoop takes nothing returns nothing
    local integer x = 0
    loop
        exitwhen x > 5
        call DisplayTextToForce( bj_FORCE_PLAYER[x], "Hello." )
        set x = x + 1
    endloop
endfunction

The above example sets a local integer "x" to zero. Then starts a loop with the condition that "x" is greater than 5. Each time this condition is not met, it displays "Hello" to player "x" and then increases "x" by 1. The loop will exit and the function end when "x" is 6 (because 6 is greater than 5).
02-21-2003, 10:27 PM#2
Guest
Local and Global Variables:
As I mentioned above, global variables are defined in the WE using the edit variable list. Simply add a udg_ to the front of your global to get it's custom text equivilent. Local variables can either 1) be defined by the function parameter (explained above) or 2) declared at the very start of the function.

You declare the local variable using the following format:
Collapse JASS:
local <variable type> <variable name>

If you look at the last loop example, you'll see I declare the variable AND set it to 0. You don't have to set the variable in the beginning, but it does have to be declared (local integer x). Declarations MUST be the first strings in the function.

Putting it all together:
All of the above becomes a very powerful tool when it's used together. For example, you could have a function that passes in parameter x. The function starts a loop that uses if/then statements to create multiple exits conditional on the value of "x". And so on...

Other functions (or actions):
The best way to find out how to use built-in functions is to convert triggers to custom text and look at how the function (action) works. Then just copy/paste it into your function and experiment with the changes.

Common.j and Blizzard.j:
I would also strongly suggest extracting the "blizzard.j" and "common.j" files from the war3patch.mpq. The "common.j" file is important because it contains the basic building block functions Blizzard uses for JASS. It's very important to look over this file if you want understand how the built-in functions work. The "blizzard.j" file contains many example functions used in the game and shows a number of different JASS tricks.

If you do look in the the "common.j", you will see a bunch of global declarations at the beginning of the file. These declarations define many of the variable "types" and native functions that are used throughout JASS.

A "native" function is located in the "hardcoded" Warcraft III engine which is exported for use by JASS programmers using those declarations at the top of the "common.j" file. Since "native" functions are located within the WC3 engine itself, you won't be making any new native functions. However, you can "CALL" existing ones, so it's worth looking over the "common.j" to see what native functions might be worth calling from one of your triggers.

"Types" are used in JASS to ensure that you use the data structure correctly. In this manner, you can't store a string as a real variable, or a unit as trigger, or add two units together. Just like the native functions, the "types" that are used in JASS are also declared in the "common.j" file and are worth looking at if you want to know all the data "types" that can be used. Unlike native functions however, "types" can be user-defined. See Magnus99's reference manual for more information: http://jass.sourceforge.net/doc/

The initialization function (very important):
As we now know, functions are the building block of programming in custom text. But functions need to be called in order to work. For custom text triggers, functions are basically actions. And like any action, they need to be attached to a trigger in order to work.

Now you may have noticed that when you convert a trigger to custom text, there is an initialization function at the VERY BOTTOM that looks like this:

Collapse JASS:
function InitTrig_<trigger name>

//   where <trigger name> = the name of your trigger

This function is important and the ONLY function NAME you can't change in your custom text. The reason you can't change the name is because it's the FIRST function that gets run when your trigger is called. If you change the name, the WC3 engine won't know what function to run when that trigger is called from another trigger or when it's initialized at map startup. It also always needs to be at the BOTTOM of your custom text because JASS doesn't allow forward references (see below). Feel free to change anything else about this function, you just can't change the NAME.


How a trigger is created:
If you convert a trigger to custom text and look at the initialization function at the very bottom, you'll see the following componets: trigger created, event added, condition added, action added. (obviously if the converted trigger didn't have an event or condition, those will be missing)

1) Creating the trigger. Every trigger is a variable that needs to be set. That's done using a line that looks like:

Collapse JASS:
   set gg_trg_<trigger name> = CreateTrigger( )

//   where <trigger name> = the name of your trigger

2) Adding an event. Every event has a different function, so you'll need to convert to text to find the one you want to use. Just make sure your trigger is the one referenced as the first parameter. Here is an example of an action used to create the event for a periodic timer event.

Collapse JASS:
    call TriggerRegisterTimerEventPeriodic( gg_trg_<trigger name>, <time between events> )

So if this format was used like so...

Collapse JASS:
call TriggerRegisterTimerEventPeriodic( gg_trg_EveryFive, 5 )

Then after every 5 seconds of game time the trigger "EveryFive" will be executed and check for conditions/run actions.

3) Adding a condition. All condition functions have a boolean return value and must return true or false. Simple insert your condition function into the line:

Collapse JASS:
    call TriggerAddCondition( gg_trg_<trigger name>, Condition( function <condition function> ) )
 
//    where <trigger name> = the name of your trigger
//    and <condition function> = the name of the function you are using as a condition

4) Adding an action. This is where you set up the trigger to call your custom functions. Same format as the condition except uses the following fomat:

Collapse JASS:
    call TriggerAddAction( gg_trg_<trigger name>, function <action function> )

//    where <trigger name> = the name of your trigger
//    and <action function> = the name of the function you are using as an action

A gg_trg_ global variable is automatically declared for you when the WE compiles the custom triggers. If you don't want to use this variable, you can create your own udg_ global variable by editing the drop down variable menu in the WE. Also just like any trigger, you can have as many events, conditions and actions as you would like. You can also setup MULTIPLE triggers in the intitilazation function by using udg_ global variables.


!IMPORTANT!
JASS is case sensitive!
Everything in JASS is very case sensitive. So remember that IF there is a capital in a variable or function, you need to captitalize that letter everytime you use it. Just about everything else besides variables and functions, is in lower case. That means you need to make sure you define your variable types as: integer, real, unit, region, etc. (not Integer, Real, Unit, Region, Etc.)

!IMPORTANT!
No Forward References!
JASS reads custom text from top to bottom. You have to define a function or variable BEFORE you use it. So for example, if you put function "A" below function "B", you will return an error if you call function "A" from function "B". Think of it as building blocks again. If you don't know what "A" is...how can you use it in "B"? This also means you can't use a circular reference (call "B" from "A" and "A" from "B"). If you think you need a circular reference, try using a loop.

!IMPORTANT!
Unique function names!
Keep in mind that when your map is compiled, all your custom functions are thrown into that same JASS script. Which means that every function name needs to be unique in that map.

!IMPORTANT!
Notation!
This last is to help you out and help out anyone who tries to read your custom text triggers. DOCUMENT EVERYTHING. Everything that follows a "//" in a given line is called a comment. Comment on all of your functions to let you and others know what it does. Be sensible with your function names. Try to use names that make sense to what it actually does. See my "GetUnitInteger" function for an example.

!IMPORTANT!
Go see the reference manual at: http://jass.sourceforge.net/doc/
Magnus99's has done a great job on this reference manual and it's extremely helpful once you start to feel comfortable with the basics. It has more technical and in-depth descriptions of everything that that's been mentioned in this tutorial and he is also developing a Syntax checker that will also be very helpful to you.
02-23-2003, 09:49 AM#3
Guest
If you are having trouble understanding the difference between local and global variables...here is a thread that may help:

What's the point in using LOCAL variables?
02-28-2003, 06:44 PM#4
Guest
Here is a great post by rwxr-xr-x about using the "return" statement.

http://www.wc3campaigns.com/showthre...802#post111802
12-14-2003, 06:40 PM#5
Daemos Hellfire
ugh i dont feel like reading
04-03-2004, 08:50 PM#6
Nemo
good tutorial.. learnd much from it.. :-)
04-04-2004, 03:13 AM#7
TheGameFreak
Nice tutorial.
as you said its very like other languages, tho a little querkier than the ones i've used.
pitty it dident cover what i really wanted to know... (using random variables, maybe its lower/higher level? meh)
04-04-2004, 04:08 PM#8
FutureHypoon
Dude, I always wanted to start JASSing warcraft, and now I can! Thanks a lot, it's a great tutorial.
04-06-2004, 01:54 PM#9
pano
Dude,I didn't get anything of the above in my head,except for the triggers...Why is JASS so hard?
04-08-2004, 02:41 PM#10
Hellhound
Yo, thnx for the Tutorial. But mine isn't working :( . Here are some things that might/are probably wrong:
-that - or / sign. i dunno what u mean.
-For example in your load code it sais: unencrypt2 = uncrypt2 + integer(10 - substring etc.... That integer, i can't get it. But what i do have is: Set unencrypt2 = (unencrypt2 + (String((Integer((10 + (Substring(unencrypt1, (Integer A), 1)))))))). Suggestions?

I've got more of those integer problems and those "-" "/" signs i dont get.
anyway. can ya help me ouT!? :(
05-03-2004, 03:42 PM#11
darksummoner
Quote:
Originally Posted by pano
Dude,I didn't get anything of the above in my head,except for the triggers...Why is JASS so hard?
Same here mate, none of that made any sense at all, and I really want to start using JASS. :(
05-15-2004, 02:05 AM#12
Xinlitik
Thanks for the great tutorial. I finally understand JASS heh..

Anyway, here's the map I experimented with.. it's utterly useless and simplistic but it's still cool lol.
06-01-2004, 08:28 PM#13
7smurfs
Awsome, AWSOME explanation. It really helps to look over those .j files. Now how about a more advanced tutorial? =D
06-09-2004, 10:32 AM#14
Doomsberg
Hmmm. Firstly I'd have to say nice job. But to me it all seems pretty basic, and doesn't help me with my problem. Anyway, i found it very similar to C++ programming, so people who are completely lost...maybe try some C++ tutorials on the net, there are tons of them and im sure with a little hard work, u will be JASSing in no time.
As i said, its a bit easy, but now im reading the advanced one at the site u provided a link for and its pretty easy aswell.
06-30-2004, 11:45 PM#15
ender_wiggin
Ok I understand everything presented in the tutorial, except two things:

(a) where does the "main" (nonfunction script) come into play. I mean, you have to have one right, otherwise there would be nowhere to start.

(b) Where can I find an extractor that would allow me to view the .j files.