Andrewgosu
The Silent Pandaren Helper
- Reaction score
- 716
Lesson I
Before we get started, You should download a professional program do deal with JASS, if You haven’t got one already. I will be using JassCraft, but any other JASS editing program with native list, highlighting and etc. will do just fine, too.
- Declaring variables
To get things started, lets learn how to declare variables. I am sure You are familiar with declaring global variables in GUI – You had to create the variable in the Variable Editor and You could pass the data stored in the variable to any trigger(function); hence the name, global variable.
Problem I: How to set global variables in JASS?
Yes, indeed. In JASS, all global variables have to have an „udg_” (without the quotes, means undefined global variable) prefix to separate them from local variables. Lets say, You create a global variable, point type, in the Variable Editor, named „tmpPoint”. In GUI, one would use the „ Set variable” action to set it.
Code:
[b]S[/b]et tmpPoint = (Position of (Triggering unit))
But in JASS, it’s a little different – all spaces are replaced with „_” and there is the „udg_” prefix(Note the punctuation, JASS is case sensitive)
Code:
[b]s[/b]et [b]udg_[/b]tmpPoint = GetUnitLoc(GetTriggerUnit())
Also, one can set the global variable anywhere in the function, in the beginning, middle or in the end. This all is fairly easy to remember. Now, lets go to declaring local variables.
Problem II: How to declare local variables?
The syntax for declaring local variables is following,
Code:
[b]local[/b] variable type variable name = ( expression )
Local variables do not have the „udg_” prefix and all local variables must be defined in the beginning of the function. Also, local variables can only be referenced within the function they were created initially – thus the name, local variables. Local variables are not overwritten, unlike global variables, because they are initialized every time the function is entered.
The syntax for declaring local arrays is following,
Code:
[B]local[/B] variable type [B]array[/B] variable name
Local arrays cannot have an initial value. But the rest, which applied to local variables, applies to local arrays, too – they have to be declared in the beginning of the function and they can only be referenced within the function they were created in.
Code:
function ArrayExample takes nothing returns nothing
local unit array tmpUnits
set tmpUnits[0] = GetTriggerUnit()
set tmpUnits[1] = GetSpellTargetUnit()
call KillUnit(tmpUnits[GetRandomInt( 0, 1 )])
endfunction
Now, Lets change the global point typed variable above into a local one ( You can call Your variables whatever You desire, but, I suggest You to give informative names. It pays off, especially in (very) long functions).
Code:
local location tmpPoint = GetUnitLoc(GetTriggerUnit())
Ehhh, what happened with the point type? Why it suddenly changed into a location?
Note, legal and illegal local variable declerations,
Legal
Code:
function ExampleFunction_Good takes nothing returns nothing
local unit a = GetTriggerUnit()
call PolledWait(2.5)
call KillUnit(a)
endfunction
Legal
Code:
function ExampleFunction_Good takes nothing returns nothing
local unit a
call PolledWait(2.5)
set a = GetTriggerUnit()
call KillUnit(a)
endfunction
Illegal
Code:
function ExampleFunction_Bad takes nothing returns nothing
call PolledWait(2.5)
local unit a = GetTriggerUnit()
call KillUnit(a)
endfunction
Problem III: What are the variable types in JASS?
As seen above, the point type variable suddenly changed into a location type variable. As a matter of fact, they are the same thing! Only, named differently. GUI uses point, whereas JASS names the point into a location.
At this moment, the little helper - JassCraft - comes into play. Load JassCraft and open the „Common.j” file. The first thing You see, are the native types. Examine the references, e.g „type unit extends widget”. The „unit” there is basically the variable type. You might wonder, where did, for example, Floating Text type dissapear. No worries, it is named „texttag” in JASS.
Some common variable types, which have different names in JASS,
Code:
GUI [B][COLOR="RoyalBlue"]JASS[/COLOR][/B]
Point - [B][COLOR="RoyalBlue"]location[/COLOR][/B]
Floating Text - [B][COLOR="RoyalBlue"]texttag[/COLOR][/B]
Unit Group - [B][COLOR="RoyalBlue"]group[/COLOR][/B]
Player Group - [B][COLOR="RoyalBlue"]force[/COLOR][/B]
Region - [B][COLOR="RoyalBlue"]rect[/COLOR][/B]
Special Effect - [COLOR="RoyalBlue"][B]effect[/B][/COLOR]
Mini-test for everyone: can You put the right variable type into the brackets?
Code:
function MiniTest takes nothing returns nothing
local (___) u = GetTriggerUnit()
local (___) tt = CreateTextTag()
local (___) g = CreateGroup()
local (___) f = CreateForce()
local (___) l = GetUnitLoc(u)
local (___) t = GetTriggeringTrigger()
local (___) r = 2.35
local (___) b = Condition( function RandomFunction ) //A tough one. ;-)
local (___) i = 1 //2 options.
local (___) e = AddSpecialEffectTarget( "", u, "origin" ) // :-)
endfunction
- Effective Triggering
I bet You have heard most JASSers saying something along these lines, „Oh the noez, why don’t You optimize your code and get rid of those BJ functions?”, and then wondered, „What the is he talking about?”. Or, heard that You are using too many unneeded function calls. We’ll get into that matter in a second.
Problem IV: What are BJ functions and why they are bad?
BJ (Blizzard Jass) functions are there, because of the Graphical User Interface. They exist because of, … Well, they shouldn’t exist at all! The idea I want to send to You is that stay away from them. Speed is very important in effective triggering and clean JASS offers that. By clean, I mean code which uses native functions. It’s best to explain this with an example. Lets convert the „Unit – Add Ability” into JASS. As You can see, it has a „BJ” suffix. Copy-paste the „UnitAddAbilityBJ” into the native list, in JassCraft, and click on the equivalent found.
Code:
function UnitAddAbilityBJ takes integer abilityId, unit whichUnit returns boolean
return UnitAddAbility(whichUnit, abilityId)
endfunction
As You can see, the BJ function is calling another function. Why does it do that? No idea…BJ functions „rule”. Anyway, like I said, speed is important in efficient triggering and I bet, that any rookie can tell, that 2 function calls are slower than 1.
Probably You didn’t notice, but there is a catch. Usually, native functions take the same arguments as the BJ one, but in different order(there are exceptions).
Code:
function [B]UnitAddAbilityBJ[/B] takes [B][COLOR="RoyalBlue"]integer[/COLOR][/B] abilityId, [B][COLOR="YellowGreen"]unit[/COLOR][/B] whichUnit returns boolean
return UnitAddAbility(whichUnit, abilityId)
endfunction
Code:
native [B]UnitAddAbility[/B] takes [COLOR="YellowGreen"][B]unit[/B][/COLOR] whichUnit, [B][COLOR="RoyalBlue"]integer[/COLOR][/B] abilityId returns boolean
So, to recap, BJ functions are bad, because they usually just call the native function, which makes the coding slower. To distinguish BJ functions from native ones, just search for the BJ suffix(there are few exceptions). To get rid of BJ functions, just use a JASS editing program, copy the BJ function in the native list search and find the native equivalent to the BJ.
A mini-exercise for everyone: can You find the equivalent natives to the BJ functions with the correct argument list?
Code:
function SetUnitLifeBJ takes unit whichUnit, real newValue returns nothing
(___)
endfunction
function SetPlayerStateBJ takes player whichPlayer, playerstate whichPlayerState, integer value returns nothing
//Modify only the gold of a player.
(___)
endfunction
function UnitRemoveAbilityBJ takes integer abilityId, unit whichUnit returns boolean
(___)
endfunction
function ModifyHeroStat takes integer whichStat, unit whichHero, integer modifyMethod, integer value returns nothing
//Lets say You want to modify only the agility of a hero.
(___)
endfunction
There is another way, to further optimize Your code: variables. I tend to follow this rule: if I have a value, which I needs to be passed to more than 1 function, I set it into a variable. An example, if I may!
Problem V: How to use variables to optimize code?
Code:
function LessFunctionCalls takes nothing returns nothing
local real x = GetUnitX(GetTriggerUnit())
local real y = GetUnitY(GetTriggerUnit())
local real r = GetUnitFacing(GetTriggerUnit())
local race c = GetUnitRace(GetTriggerUnit())
endfunction
That is not efficient. 4 local variable declarations, which use "Triggering unit". That's clearly too many. Plus, it's slow, because it calls the triggering unit 4 times.
Code:
function LessFunctionCalls takes nothing returns nothing
local unit a = GetTriggerUnit()
local real x = GetUnitX(a)
local real y = GetUnitY(a)
local real r = GetUnitFacing(a)
local race c = GetUnitRace(a)
endfunction
Setting the triggering unit into a variable and using the variable in the argument lists makes it more efficient, because there are 3 calls less (Well, actually GetTriggerUnit() is an event response).
Mini-test for all users: can You optimize these pieces of code?
Code:
function LessFunctionCalls takes nothing returns nothing
local playercolor pc = GetPlayerColor(GetTriggerPlayer())
local mapcontrol mc = GetPlayerController(GetTriggerPlayer())
local real handicap = GetPlayerHandicap(GetTriggerPlayer())
endfunction
Code:
function LessFunctionCalls takes nothing returns nothing
call SetItemPosition( i, GetUnitX(GetTriggerUnit()), GetUnitY(GetTriggerUnit()) )
call SetImagePosition( whichImage, GetUnitX(GetTriggerUnit(), GetUnitY(GetTriggerUnit()), 0 )
call SetCameraPosition( GetUnitX(GetTriggerUnit()), GetUnitY(GetTriggerUnit()) )
call SetTextTagPos( t, GetUnitX(GetTriggerUnit()), GetUnitY(GetTriggerUnit()), 200 )
endfunction