Rheias
New Helper (I got over 2000 posts)
- Reaction score
- 232
Functions
Introduction
This tutorial (or rather, mini-tutorial) is for anyone who has a basic knowledge of JASS and is interested in learning a bit more. In this tutorial I will discuss that 3 types of functions, natives, BJs and finally the core of the tutorial, user designed functions. I will explain things that you are probably doing already, however this explanation will aid you in making things which are more advanced. In this tutorial I’m assuming you know the basics of JASS already (as I said already) so do not attempt to read this if you don’t.
You should use a JASS software in order to understand this tutorial properly (I use JassCraft, my favorite software).
What I expect you to know is basically how to create a simple trigger in JASS using locals, commands, etc. You should know the difference between “local”, “set” and “call” and know how to use each one, things of that kind.
Please note as well that English is a second language to me.
Natives
Let’s start with the basic form of functions, those are called natives. Natives are the core of JASS and everything (well almost everything some common.ai are independent) is built from those, whether it’s a BJ function or user-designed function. Natives execute a certain action which is assigned to them, these function can’t be modified (well they can, but most likely you wouldn’t do that). If you are using JassCraft (or a similar software) native functions will have the word native in them (or constant) when you click them. Here are few native examples:
JASS:
SetUnitPosition (native SetUnitPosition takes unit whichUnit, real newX, real newY returns nothing)
SetPlayerState (native SetPlayerState takes player whichPlayer, playerstate whichPlayerState, integer value returns nothing )
KillUnit (native KillUnit takes unit whichUnit returns nothing )
GetTriggerUnit (constant native GetTriggerUnit takes nothing returns unit)
CreateUnit (native CreateUnit takes player id, integer unitid, real x, real y, real face returns unit)
etc…
Those are all natives, now let’s take one and analyze it. For example “KillUnit”. First of all we see the word “native” thus it is native, good, it shouldn’t tell you much now, soon enough you will know what it means that a function is native. After that you can see the function’s name which is KillUnit, thus we call the function by typing:
JASS:
call KillUnit(etc.)
Now you see it says “takes unit”? That means we need to give the native a unit so it could do something with it (most natives take more then one value, for example CreateUnit). Examples:
JASS:
call KillUnit(GetTriggerUnit())
call KillUnit(GetEnumUnit())
call KillUnit(GetAttacker())
local unit caster = GetTriggerUnit()
call KillUnit(caster)
etc…
And then we see “returns nothing” which means we don’t get a value from the function “KillUnit”. Let’s check another native, called GetTriggerUnit. You probably know that it returns triggering unit. “Constant native” That means it a native that doesn’t change its value. “Takes nothing” that means that in order to work the function doesn’t need anything to take (this is why we put “()” after using GetTriggerUnit, to show that this functions takes nothing) and then we see “returns unit” which means when we use this function we get refer to a unit, in this case triggering unit. So if we know that we can tell that a local unit can store this function. Example:
JASS:
local unit monkey = GetTriggerUnit()
This will returns triggering unit and put it inside a variable called monkey.
So let’s summarize it for a second to make sure you understand what happened here so far. We can recognize native functions by looking for the work “native” when clicking on them in one of the JASS programs. Natives can take something and return something. If they take something we put it between the () after them (separating values with commas, as you should know), if they take nothing we leave the “()” empty. If they return something it means we can store them inside a variable and refer to them easily. For example if you look at CreateUnit function you can see that it returns a unit, thus:
JASS:
local unit created = CreateUnit(etc.) // This will create a unit, and return it, the fact that it returns the unit means that we can store it inside variable, and this is what we are doing.
As you might have noticed, natives do different things, KillUnit, does something (kills a unit) while GetTriggerUnit simply finds a unit and gives it to use allowing us to refer to it, and CreateUnit does an action (creats a unit) and also returns it.
Alright so those are natives, you can go on and re-read this if you didn’t understand something, you should keep in mind that it’s easier that it looks, basically natives take something (or nothing) and then do with it something (usually), sometimes it returns a value and some times it doesn’t.
With that, I think you can move on and read about BJs.
Blizzard Jass
BJs stands for Blizzard JASS (Blizzard.j), BJs are functions made by Blizzard which store in them natives (or sometimes other BJs). What that means is that when you are calling a BJ, it will call another function/s, which means it will slows down the trigger. Why is that? Allow me to give you an example, say you want to get an apple, what would be faster, asking someone to bring it to you, or asking someone to ask from someone else to bring it to you? Usually you will get the apple quicker in the first situation, right? So do functions work.
So, we might ask ourselves why in the lord’s name did Blizzard create BJs? Well, it’s all because of GUI, almost all BJs were created to serve the GUIers, that’s why when you are converting a GUI trigger you would get loads of BJs instead of clean natives. However, there are few examples were BJs simply short long functions to make it easier for us (such as PolarProjectionBJ, ModifyGateBJ, etc.)
The next question is how can we recognize BJs? Well most BJs have swapped, BJ or other funny word in the end of them (like PolarProjectionBJ, ModifyGateBJ, AddHeroXPSwapped, UnitAddItemSwapped, etc.), however some of them don’t have those words in their end (such as DistanceBetweenPoints) and we need to check in one of the JASS programs if it’s a BJ or not. If when you click on the function there is no “native” in the start of it then it is BJ, BJs are always presented as a function with one or more actions in it which do something (usually takes values assigned to it and passes them to natives).
You should avoid using BJs, while usually their slowness is not noticeable, using them a lot in short durations will cause problems. For example if you create a timer that will run every 0.003 seconds and you would use lots of BJs, the timer wouldn’t have the time to complete it’s actions (in extreme cases) and that will create problems. Anyway, doesn’t having a cleaner code make you feel better about it?
Side Note: You should note that coordinates use natives while a lot of functions regarding locations are BJs that convert the location into coordinates, thus if possible you should use coordinates. Also locations are slow because destroying them (call RemoveLocation(loc)) is very slow.
User Defined
Finally we reached this chapter, everything until now was sort of a background so you could understand this better. So, what are user defined functions? User defined functions are every function you create. Did you just type a function that checks if the spell casted is Animate Dead? You just created a user defined function. Did you create a function that deals damage to everyone around the middle of the map? Indeed, that’s another user defined function. So we can say that user defined functions are the functions which JASSers create, thus they weren’t created by Blizzard (notice the name user defined).
As you might know user defined functions are create like so:
Code:
[b]function[b] [i]func_name[/i] [b]takes[/b] [/i]arguments[/i] [b]returns[/b] [i]value[/i]
Let’s explain that. “functions” Means that you are starting a function defining line, JASS knows now that here you define a function. You might noticed that every line in JASS starts with this kind of “line defining” word, “call” calls a functions, “local” defines a local variable, “set” stores a value inside a variable and finally “function” starts a function defining line.
Next, instead of func_name you need to put the function name (case sensitive), no spaces, use “_” instead, no special characters (such as “!”,”?”,”\”,”:”,”.”,”,”,”””, etc.), and the function name may not begin with an integer (however it may have integers in it later on).
Valid names:
Worms, Hi, h_e_l_l_0, aru5264927363, I_1_3_3_7 etc...
Invalid names:
h e l l o, 2727hi, My_Name_Is_!?.,"~@^%$#)(*&^ etc...
After that there is the word “takes”, like any other function (native or BJ) a user defined function can take something to do with it something. Let’s check for a second again the native KillUnit.
You see that it takes a unit? We can do the same thing! Note that it gives the unit a name, in this case it calls it whichUnit, however you can name it however you want following the same rules as the func_name rules. The function will refer to the taken values as locals, thus you refer to them by typing in their name.Now say that we want to take few values? Let's check create unit then.
As you can see, this function takes few values, player, integer, real, another real and a third real. For each taking value it assigns a type and a name, and it separates between different values with a comma, same thing goes to user-defined functions.
Lastly there is “returns value”, the function may return something, for example if it is a condition it will return a Boolean. Let’s see an example of a function
JASS:
function tut_example1337 takes unit a13373r returns integer
return GetUnitUserData(a13373r)
endfunction
This takes a unit (a13373r) and returns its custom value. Here is another example:
JASS:
function GetAttackedUnitBJ takes nothing returns unit
return GetTriggerUnit()
endfunction
Actually there is a function like that, which is a BJ made by blizzard, I just wanted to show you that user defined functions are BJs done by you. Let’s see two final examples:
JASS:
takes two reals and converts them into a location, (coordinates to location), and finally quick example of a function that returns nothing:
JASS:
function KillingFest takes unit unlucky_soldier returns nothing
call KillUnit(unlucky_soldier)
call PolledWait(2.00)
call RemoveUnit(unlucky_soldier)
endfunction
Side Note: Return is a little tricky function. Firstly whenever the function runs a return line it skips remaining actions. Did you know that “Skip Remaining Functions” in GUI is “return” in JASS? Secondly you must have a “return” line outside a loop or if / then / else when dealing with a function that returns something. This will not work:
JASS:
You need to do this:
JASS:
Side note: When a function returns a Boolean you can simply do:
And then it will return true or false, depending if the Boolean is true or false.
Lastly you need to be careful when dealing with return functions because they can cause crashes if handled poorly (that's very rare, just keep it in mind).
Alright, we know how to create a working user defined function, now let’s see how we can call one. Calling a user-defined is just like calling a native.
JASS:
call func_name(arguments)
However, differently from native we must define the user defined function before the calling function.
Let’s give an example:
JASS:
function KillingFest takes unit unlucky_soldier returns nothing
call KillUnit(unlucky_soldier)
call PolledWait(2.00)
call RemoveUnit(unlucky_soldier)
endfunction
function KillingFestCaller takes nothing returns nothing
local unit victim = GetTriggerUnit()
call KillingFest(victim)
endfunction
This will work, it will kill the triggering unit and after 2 seconds remove it from the game. This however will cause a syntax problem (I hate JASS’s syntax checker)
JASS:
function KillingFestCaller takes nothing returns nothing
local unit victim = GetTriggerUnit()
call KillingFest(victim)
endfunction
function KillingFest takes unit unlucky_soldier returns nothing
call KillUnit(unlucky_soldier)
call PolledWait(2.00)
call RemoveUnit(unlucky_soldier)
endfunction
When the trigger reads KillingFestCaller it didn’t read yet KillingFest, thus it wouldn’t know what to do.
Important note: Keeping everything in one function is faster then dividing it into 2 functions, like natives and BJs. This is faster then the previous example:
JASS:
function Efficent_Killing_Fest takes unit nothing returns nothing
local unit unlucky_soldier = GetTriggerUnit()
call KillUnit(unlucky_soldier)
call PolledWait(2.00)
call RemoveUnit(unlucky_soldier)
endfunction
Like we said, asking someone to bring an apple is faster then asking someone to ask someone to bring an apple.
So, those are more or less the basics of functions, I hope you enjoyed, this is my first tutorial written so please be patient with your comments, thanks for reading.