Contents:
1.0 - Introduction
2.0 - Basics of a function
2.1 - Operators
2.2 - Declaring locals
2.3 - GUI vs JASS variables
2.4 - JASS and GUI variables
2.5 - Loops
2.5 - Handles
3.0 - vJASS
4.0 - Scopes and Libraries
5.0 - Private and Public members
5.1 - ADD ON - Constants
5.2 - ADD ON - Globals and Structs
6.0 - Goodbye
Introduction
Many people think that JASS is the l33tz00rdz language, this is not true. Basicly, when making GUI, you also create JASS lines. Example:
is the same as
Yes, I know this looks complicated, but it is not. The 1 is the number of units created, the 'hfoo' is the raw code (Go to your object editor, press CTRL + D to view raw codes of units), Player(0) is the player id (Remember, that player 0 is player 1, player 1 is player 2, etc.). GetRectCenter(GetPlayableMapRect()) is where the unit is created, in this case the center of the map (A rect is the same as a region), and finally the bj_UNIT_FACING is the default facing of a unit, in this case, 270.00.
Not to hard when explained, right?
Basics of a function
A function is everything. A function is the same as above. Functions are the things that makes everything run.
This is a native function:
(Taken from JASSHelper in Jass NewGen Pack)
And this is a BJ:
They does the same thing, only that the BJ is slower. (In JNGP (Jass NewGen Pack), BJ are red and natives purple. Why is a BJ slower, and what is a BJ? Well, a BJ is slower because it calls a native function, and a BJ is a totally useless function made by Blizzard. (Well, some BJs are really nice though.) GUI uses BJs. There is some BJs who are usefull though. Nonfunction BJs (such as the bj_lastCreatedUnit instead of GetLastCreatedUnit(), bj_mapInitialPlayableArea instead of GetPlayableMapRect() and so on), but the most usefull BJ is probably the BJDebugMsg. This is used by the most JASSers to find out bugs, and basicly it displays a message to all players. This can be used for finding out which functions runs and which doesn't.
Yes, this is rather complicated, but don't hesitate with reading it again.
When you use a function, you always need the call before the function name, and when you have typed the function name, you create a ( , then type in the arguments, and when done, you create a ). Wolla, you created an argument! Example:call UnitApplyTimedLife(GetTriggerUnit(), 'BTLF', 2.00)
1. This is where you call. 2. The function name. 3. The (. 4. The unit I want to have timed life. 5. The raw code of the buff, just use this always. 6.The real which shows have long the timed life is. 7. The end ).
Now, many functions takes Arguements, such as the UnitApplyTimedLife functions. Example:
Most systems uses arguements (Check out my Knockback System. When you call the function KS_SingleKnock(...) Everything inside the () is arguements. The unit being knocked back, the range and so on)
Now, functions can also return.
The GetTriggerUnit() doesn't take arguements, but it returns a unit. If it didn't return the unit, the function would do nothing. When you refer to GetTriggerUnit(), it returns a unit for the function, so that the functions knows which unit to take.
Got it? Great! Then let's move on!
Operators
The operators are as following:
not = When used in an if/then/else, it can be used to "negativize", meaning that if you put a not, it will if the condition is not then do etc., etc.
== represents Equal To.
!= represents Not Equal To.
> represents Greater Than.
>= represents Greater Than Or Equal To.
< represents Less Than.
<= represents Less Than Or Equal To.
These are mostly used in if/then/elses. Example:
This is executed if not my Boolean is true. So this will actually happen when my Boolean is everything else than true.
Got it? Then let's go on.
Declaring locals
Locals are variables that can only be used in that function they are declared in. Example:
Now, this would give us a JASShelper error: "Undeclared variable testint", because testint doesn't excist in the function syntaxerror.
Globals are the brother of locals. They can be used in any function, and will cause errors if another local, global or function is declared with the same name as the global. Unless they are private or public, of course. (More about this later on)
GUI variables are globals.
REMEMBER: Locals always need to be in top of the function(s), and globals needs to be inside a globals statement. Example:
NOTICE - variables with arrays cannot be initialized!
GUI vs JASS variables
Many people go wrong about this. In WEU, in your GUI create variables box, there is a () where there stands the variables name in JASS. Now, I think (correct me if I'm wrong) that you can also see this in JASSCraft.
Example:
In JASS, unittypes are types such as heroes, structures. (These are declared with UNIT_TYPE_HERO) And in GUI, unittypes are things such as peasants, footmans etc. I'll leave this for you.
Loops
Loops can be used for many things, and is the same as a GUI
Well, you need a little bit more lines. Example:
That's a loop.
Now, there are more complex versions of a loop. In GUI, it's normally just from one integer to another, here you can do it with every single condition with the exitwhen. In many spells, they use a loop for damaging instead of damaging a point (if they don't want allies to be damaged), because sometimes damaging groups can cause problems on macs.
Well, this is the loop they use:
Got it? Great!
Handles
Now, this is the hard piece;
These are reals. When you are done with your trigger, and are about to clear leaks, these do not leaks, but because they are kind of "native handles". Now, this leaks:
Why? This is why:
locations extends handles!
EVERY SINGLE LOCAL THAT EXTENDS A HANDLE NEEDS TO BE REMOVED AND NULLED. ELSE IT WILL LEAK.
It is very important that you understant exactly this. Why? Because too many leaks can cause server splits.
Well, I can tell you which locals that doesn't extends a handle.
reals
integers
booleans
string
(How to find out if a local extends a handle? Most people uses JASSCraft)
These are basicly the locals that doesn't extend a handle.
(You can't null or destroy strings, you when cleaning strings, just do
set MyString = ""
)
If you get this, then you clearly are able to move on to vJASS. If not, read everything all over.
vJASS
vJASS is an extended JASS language which are available in JNGP. If you write vJASS in normal WE, your WE will crash and your map become unplayable and unopenable.
vJASS are great because of these "things":
It got public members.
It got private members.
It got scopes.
It got libraries.
You will learn about this later on.
JNGP is downloadable here: http://wc3campaigns.net/showthread.php?t=90999
Scopes and Libraries.
A Scope is mostly used for spells, but can be used for everything, though libraries are most appreciated for systems.
Example:
private and public members are only available in scopes and libraries. (A member is something put before the function keyword. (Can also be other things, such as globals))
You can have a scope inside a scope. Example:
But you cannot have a library inside a library. Example:
A library is placed in the map header when compiling (saving) the map in wc3, (the map's script), so a trigger inside a library doesn't need an InitTrig.
A library can have requirements. The only thing the requirements does, is that before the map can save, you need the required libraries. This is good for making people remembering subsystems.
Now, a scope can have initializers. They actually does the same things as InitTrigs, just that you can name your InitTrig everything you like.
NOTICE - Libraries can actually have initializers too!
Example:
This would do the exact same thing as a normal InitTrig.
And then there are requires/uses/needs:
The requires/uses/needs is mostly for making people have one syntax error than many when they don't got the used library.
Got it? Then we go on to the purpose of libraries and scopes, the members.
Private and Public members.
Get it? It's actually the same with public members, just that a public member isn't generated randomly. It will be generated to <YourScopeOrLibraryName>_<YourFunctionName>. This is mostly used for systems where you call a function.
Simple, isn't it?
Constants
Now, constants are mostly used for conditions, global variables (see lower down) and returning-functions. Well, a constant basicly makes the function/variable non-editable throughout the game.
Globals and Structs
Globals
Before vJASS, you had to use functions for every single thing, such as raw codes. So you had to make a gigantic function, just for returning a raw code. Pretty unpractical. Now, with vJASS, you can use globals, example:
Simplifies the whole process a lot, right? It does the same thing - returns a value.
Structs
Structs are basicly integers, but can be used to store data in. This is where Struct Attaching Systems gets into the picture. Structs are used to store in, like, we maybe had a unit named caster in it, a unit named target in it and a timer. Like this:
Okay? Now, when using structs, you can do various things, but in this example we will use local structs and SAS (Struct Attaching Systems). This time we'll use TimerUtils by Vexorian.
NOTICE - Inside structs, there can be methods, but I do not know much about that, so I suggest you reading the JASSHelper Manual by Vexorian.
Now, the bolded lines are those who you should be paying attention to.
local MyData d = MyData.create() - This is where you create your MyData struct, so you can use it in your function. The MyData parts must always be the same as your struct name.
call SetTimerData(d.tim, d) - This is where we set the data which should be attached to the specified timer, d.tim. d.tim is the timer argument, and d is our struct.
local MyData d = GetTimerData(GetExpiredTimer()) - This is where we recieve our data. We cannot use d.tim here, because we haven't created the struct when it compiles, so it gives us syntax errors. It must always be GetExpiredTimer().
Got it? Great!
Goodbye
Well, I hope you learned something from this tutorial. I look forward to reviewing any of you JASS spells!
1.0 - Introduction
2.0 - Basics of a function
2.1 - Operators
2.2 - Declaring locals
2.3 - GUI vs JASS variables
2.4 - JASS and GUI variables
2.5 - Loops
2.5 - Handles
3.0 - vJASS
4.0 - Scopes and Libraries
5.0 - Private and Public members
5.1 - ADD ON - Constants
5.2 - ADD ON - Globals and Structs
6.0 - Goodbye
Introduction
Many people think that JASS is the l33tz00rdz language, this is not true. Basicly, when making GUI, you also create JASS lines. Example:
Code:
Unit - Create 1 Footman for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees
JASS:
call CreateNUnitsAtLoc( 1, 039;hfoo039;, Player(0), GetRectCenter(GetPlayableMapRect()), bj_UNIT_FACING )
Yes, I know this looks complicated, but it is not. The 1 is the number of units created, the 'hfoo' is the raw code (Go to your object editor, press CTRL + D to view raw codes of units), Player(0) is the player id (Remember, that player 0 is player 1, player 1 is player 2, etc.). GetRectCenter(GetPlayableMapRect()) is where the unit is created, in this case the center of the map (A rect is the same as a region), and finally the bj_UNIT_FACING is the default facing of a unit, in this case, 270.00.
Not to hard when explained, right?
Basics of a function
A function is everything. A function is the same as above. Functions are the things that makes everything run.
This is a native function:
Code:
native UnitApplyTimedLife takes unit whichUnit, integer buffId, real duration returns nothing
And this is a BJ:
JASS:
function UnitApplyTimedLifeBJ takes real duration, integer buffId, unit whichUnit returns nothing
call UnitApplyTimedLife(whichUnit, buffId, duration)
endfunction
They does the same thing, only that the BJ is slower. (In JNGP (Jass NewGen Pack), BJ are red and natives purple. Why is a BJ slower, and what is a BJ? Well, a BJ is slower because it calls a native function, and a BJ is a totally useless function made by Blizzard. (Well, some BJs are really nice though.) GUI uses BJs. There is some BJs who are usefull though. Nonfunction BJs (such as the bj_lastCreatedUnit instead of GetLastCreatedUnit(), bj_mapInitialPlayableArea instead of GetPlayableMapRect() and so on), but the most usefull BJ is probably the BJDebugMsg. This is used by the most JASSers to find out bugs, and basicly it displays a message to all players. This can be used for finding out which functions runs and which doesn't.
Yes, this is rather complicated, but don't hesitate with reading it again.
When you use a function, you always need the call before the function name, and when you have typed the function name, you create a ( , then type in the arguments, and when done, you create a ). Wolla, you created an argument! Example:call UnitApplyTimedLife(GetTriggerUnit(), 'BTLF', 2.00)
1. This is where you call. 2. The function name. 3. The (. 4. The unit I want to have timed life. 5. The raw code of the buff, just use this always. 6.The real which shows have long the timed life is. 7. The end ).
Now, many functions takes Arguements, such as the UnitApplyTimedLife functions. Example:
JASS:
call UnitApplyTimedLife(The first one(GetTriggerUnit()) is the unit arguement, the second one(039;BTLF039;) is an integer raw code, and the last one(2.00) is a real arguement)
Most systems uses arguements (Check out my Knockback System. When you call the function KS_SingleKnock(...) Everything inside the () is arguements. The unit being knocked back, the range and so on)
Now, functions can also return.
The GetTriggerUnit() doesn't take arguements, but it returns a unit. If it didn't return the unit, the function would do nothing. When you refer to GetTriggerUnit(), it returns a unit for the function, so that the functions knows which unit to take.
Got it? Great! Then let's move on!
Operators
The operators are as following:
not = When used in an if/then/else, it can be used to "negativize", meaning that if you put a not, it will if the condition is not then do etc., etc.
== represents Equal To.
!= represents Not Equal To.
> represents Greater Than.
>= represents Greater Than Or Equal To.
< represents Less Than.
<= represents Less Than Or Equal To.
These are mostly used in if/then/elses. Example:
JASS:
This is executed if not my Boolean is true. So this will actually happen when my Boolean is everything else than true.
Got it? Then let's go on.
Declaring locals
Locals are variables that can only be used in that function they are declared in. Example:
JASS:
Now, this would give us a JASShelper error: "Undeclared variable testint", because testint doesn't excist in the function syntaxerror.
Globals are the brother of locals. They can be used in any function, and will cause errors if another local, global or function is declared with the same name as the global. Unless they are private or public, of course. (More about this later on)
GUI variables are globals.
REMEMBER: Locals always need to be in top of the function(s), and globals needs to be inside a globals statement. Example:
Code:
globals
unit testunit
endglobals
NOTICE - variables with arrays cannot be initialized!
GUI vs JASS variables
Many people go wrong about this. In WEU, in your GUI create variables box, there is a () where there stands the variables name in JASS. Now, I think (correct me if I'm wrong) that you can also see this in JASSCraft.
Example:
In JASS, unittypes are types such as heroes, structures. (These are declared with UNIT_TYPE_HERO) And in GUI, unittypes are things such as peasants, footmans etc. I'll leave this for you.
Loops
Loops can be used for many things, and is the same as a GUI
JASS:
For each (Integer A) from 1 to 10, do (Actions)
Loop - Actions
Well, you need a little bit more lines. Example:
JASS:
function MyTestLoop takes nothing returns nothing
local integer StartLoop = 1
local integer EndLoop = 10
loop
exitwhen StartLoop > EndLoop
call UnitApplyTimedLife(GetTriggerUnit(), 039;BTLF039;, 2.00)
set StartLoop = StartLoop + 1
endloop
endfunction
That's a loop.
Now, there are more complex versions of a loop. In GUI, it's normally just from one integer to another, here you can do it with every single condition with the exitwhen. In many spells, they use a loop for damaging instead of damaging a point (if they don't want allies to be damaged), because sometimes damaging groups can cause problems on macs.
Well, this is the loop they use:
JASS:
function Damage takes nothing returns nothing
local group g = (This is just your group)
local unit u // We do not set this one yet
loop
set u = FirstOfGroup(g)
exitwhen u == null
call UnitDamageTarget(...)
call GroupRemoveUnit(g, u)
endloop
endfunction
Got it? Great!
Handles
Now, this is the hard piece;
JASS:
local real x = GetUnitX(GetTriggerUnit())
local real y = GetUnitY(GetTriggerUnit())
These are reals. When you are done with your trigger, and are about to clear leaks, these do not leaks, but because they are kind of "native handles". Now, this leaks:
JASS:
local location l = GetUnitLoc(GetTriggerUnit())
Why? This is why:
locations extends handles!
EVERY SINGLE LOCAL THAT EXTENDS A HANDLE NEEDS TO BE REMOVED AND NULLED. ELSE IT WILL LEAK.
It is very important that you understant exactly this. Why? Because too many leaks can cause server splits.
Well, I can tell you which locals that doesn't extends a handle.
reals
integers
booleans
string
(How to find out if a local extends a handle? Most people uses JASSCraft)
These are basicly the locals that doesn't extend a handle.
(You can't null or destroy strings, you when cleaning strings, just do
set MyString = ""
)
If you get this, then you clearly are able to move on to vJASS. If not, read everything all over.
vJASS
vJASS is an extended JASS language which are available in JNGP. If you write vJASS in normal WE, your WE will crash and your map become unplayable and unopenable.
vJASS are great because of these "things":
It got public members.
It got private members.
It got scopes.
It got libraries.
You will learn about this later on.
JNGP is downloadable here: http://wc3campaigns.net/showthread.php?t=90999
Scopes and Libraries.
A Scope is mostly used for spells, but can be used for everything, though libraries are most appreciated for systems.
Example:
private and public members are only available in scopes and libraries. (A member is something put before the function keyword. (Can also be other things, such as globals))
You can have a scope inside a scope. Example:
JASS:
scope Test1
scope Test2
endscope
endscope
But you cannot have a library inside a library. Example:
JASS:
library Test1
library Test2
endlibrary
library
A library is placed in the map header when compiling (saving) the map in wc3, (the map's script), so a trigger inside a library doesn't need an InitTrig.
A library can have requirements. The only thing the requirements does, is that before the map can save, you need the required libraries. This is good for making people remembering subsystems.
Now, a scope can have initializers. They actually does the same things as InitTrigs, just that you can name your InitTrig everything you like.
NOTICE - Libraries can actually have initializers too!
Example:
JASS:
scope Test initializer haha
function haha takes nothing returns nothing
set gg_trg_Test = CreateTrigger()
endfunction
endscope
This would do the exact same thing as a normal InitTrig.
And then there are requires/uses/needs:
JASS:
library Test initializer haha uses (Could be requires or needs too) MySystem
function haha takes nothing returns nothing
set gg_trg_Test = CreateTrigger()
endfunction
endscope
The requires/uses/needs is mostly for making people have one syntax error than many when they don't got the used library.
Got it? Then we go on to the purpose of libraries and scopes, the members.
Private and Public members.
Example:JASSHelper said:The way private work is actually by automatically prefixing scopename(random digit)__ to the identifier names of the private members
Get it? It's actually the same with public members, just that a public member isn't generated randomly. It will be generated to <YourScopeOrLibraryName>_<YourFunctionName>. This is mostly used for systems where you call a function.
Simple, isn't it?
Constants
Now, constants are mostly used for conditions, global variables (see lower down) and returning-functions. Well, a constant basicly makes the function/variable non-editable throughout the game.
Globals and Structs
Globals
Before vJASS, you had to use functions for every single thing, such as raw codes. So you had to make a gigantic function, just for returning a raw code. Pretty unpractical. Now, with vJASS, you can use globals, example:
JASS:
globals
constant integer AbilityRawCode = 039;A000039;
endglobals
Simplifies the whole process a lot, right? It does the same thing - returns a value.
Structs
Structs are basicly integers, but can be used to store data in. This is where Struct Attaching Systems gets into the picture. Structs are used to store in, like, we maybe had a unit named caster in it, a unit named target in it and a timer. Like this:
Okay? Now, when using structs, you can do various things, but in this example we will use local structs and SAS (Struct Attaching Systems). This time we'll use TimerUtils by Vexorian.
JASS:
scope MySpell
private struct MyData
unit caster
unit target
timer tim
endstruct
private function TimerActions takes nothing returns nothing
<b>local MyData d = GetTimerData(GetExpiredTimer())</b>
// Do actions with d.target here...
endfunction
private function Actions takes nothing returns nothing
<b>local MyData d = MyData.create()</b> // This is always needed. When "initializing" a struct, you must do that!
set d.caster = GetTriggerUnit()
set d.target = GetSpellTargetUnit()
set d.tim = <b>NewTimer()</b>
<b>call SetTimerData(d.tim, d)</b>
call TimerStart(d.tim, 0.03, true, function TimerActions)
endfunction
endscope
NOTICE - Inside structs, there can be methods, but I do not know much about that, so I suggest you reading the JASSHelper Manual by Vexorian.
Now, the bolded lines are those who you should be paying attention to.
local MyData d = MyData.create() - This is where you create your MyData struct, so you can use it in your function. The MyData parts must always be the same as your struct name.
call SetTimerData(d.tim, d) - This is where we set the data which should be attached to the specified timer, d.tim. d.tim is the timer argument, and d is our struct.
local MyData d = GetTimerData(GetExpiredTimer()) - This is where we recieve our data. We cannot use d.tim here, because we haven't created the struct when it compiles, so it gives us syntax errors. It must always be GetExpiredTimer().
Got it? Great!
Goodbye
Well, I hope you learned something from this tutorial. I look forward to reviewing any of you JASS spells!