• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

What and Hows about Jass

Status
Not open for further replies.
Level 6
Joined
Feb 5, 2012
Messages
1,685
Hi am neo_sluf and i want to learn jass..

May i ask..


What are those triggers that starts with function_ and those with library or those with scope..

What are different ways to start a trigger?.. do spell starts with library or function_ or scope?..

Those private.. what are those?.. do you need to write private to create a variable?..

I know that you will say READ JASS TUTORIALS but the truth i am confused about it also.. so pls. answer this..
 
Level 6
Joined
Feb 5, 2012
Messages
1,685
Ok another question...

I am reading tutorials about JASS but it makes me laugh that they don't tell about the spaces..

Thus space affect the trigger?.. i mean look call have 1 space from the left while the next function will have 2 space others are 3.. i really confused.. HOW IS THE SPACE AFFECT THE TRIGGER?.. or WHEN DO I USE A CERTAIN AMOUNT OF SPACE like when i space once?.. or twice? ..
 
Level 18
Joined
Sep 14, 2012
Messages
3,413
JASS and vJASS are somewhat the same...
JASS is the scripting system of warcraft 3.
vJASS is an extension to JASS.
So infact if you learn vJASS you'll learn JASS too :)
I suggest you try to do some basic spells in vJASS to learn.
It's easier to understand JASS because you can convert GUI triggers to see how to do many things.

In my own experience i started JASS ( because i didn't know there was vJASS xD ! ) and when i knew about JNGP and an extension for vJASS i learned it.
 
Hi am neo_sluf and i want to learn jass..

May i ask..

What are those triggers that starts with function_ and those with library or those with scope..

What are different ways to start a trigger?.. do spell starts with library or function_ or scope?..

Those private.. what are those?.. do you need to write private to create a variable?..

Library (vJASS) -> All code in a library block are moved to the top of the script. This was created so that code would not have to be placed in the map header in order for the scripts to be used in other triggers.
JASS:
library 
    function AngleBetweenPoints takes real x1, real y1, real x2, real y2 returns real
         return Atan2(y2 - y1, x2 - x1)
    endfunction
endlibrary

Scope (vJASS) -> Scopes serve two main purposes. (1) You can declare an initializer, which will be a function that is run on map initialization. Normally in vanilla JASS, you would prefix a function "InitTrig_" for it to be ran on initialization. It usually registers the events/trigger related options. In vJASS, you will usually declare either a scope or a library and make an initializer:
JASS:
scope X initializer Init  // run function "Init" on initialization
    function SpellCast takes nothing returns boolean
        return GetSpellAbilityId() == 'A000'
    endfunction

    function Init takes nothing returns nothing 
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddCondition(t, Condition(function SpellCast))
    endfunction
endscope
There is technically another method of making a function run on initialization in vJASS. It has something to do with making it public and naming it "Init", or something similar (it was occasionally used a really long time ago). However, you don't need to know this.

(2) Encapsulation. This means you can make things public or private. private means that you can't use the function outside the scope/library it is in. It will prefix the function with the scope/library name and a random number of underscores to prevent name collisions, misuse, etc. This is especially useful for naming functions. Once upon a time, every function had to be prefixed properly. You couldn't just name something "Init" or "Actions" because it would likely collide with other triggers. That was why there was a standard, known as JESP, for how to properly code spell resources.

However, that is a thing of the past since vJASS. By making a function "private", you can use the same function name in different scopes:
JASS:
scope A
    private function Actions takes nothing returns nothing 
    endfunction
endscope

scope B
    private function Actions takes nothing returns nothing 
    endfunction
endscope
The keyword public means that, in order to call the function, you must call it via SCOPENAME_FunctionName. Example:
JASS:
scope A
    private function PrivateFunction takes nothing returns nothing 
    endfunction
    public function PublicFunction takes nothing returns nothing 
    endfunction
endscope

scope B
    private function Test takes nothing returns nothing 
        call A_PrivateFunction() // error, function is private
        call PrivateFunction() // error, no such function (it is private in A)
        call A_PublicFunction() // no error! :)
    endfunction
endscope

As for things that start off with "function_", that doesn't really exist. However, you may be looking at vanilla JASS resources. Those do not require JASSHelper (integrated in JNGP), and as such they don't have blocks such as "scope" or "library". They are just put as normal functions.

Ok another question...

I am reading tutorials about JASS but it makes me laugh that they don't tell about the spaces..

Thus space affect the trigger?.. i mean look call have 1 space from the left while the next function will have 2 space others are 3.. i really confused.. HOW IS THE SPACE AFFECT THE TRIGGER?.. or WHEN DO I USE A CERTAIN AMOUNT OF SPACE like when i space once?.. or twice? ..

Spacing doesn't matter. JASS is not indentation based. This:
JASS:
set    garfunkel = GetRandomInt    (0,     1 )
Is the same as:
JASS:
set garfunkel = GetRandomInt(0, 1)

It is just a matter of personal preference. You'll develop your own coding style after some time. Just try not to make it too ugly. Proper indentation is always a plus.
 
Level 6
Joined
Feb 5, 2012
Messages
1,685
So Purgeandfire if i say

GetLocalPlayer () is it the same as GetLocalPlayer ( ) ?.. do i get an error?..

Are there any rules on CAPITALIZATION?.. like the word private... some are Private some are just private.. so when i use a capital letter and when i won't?...
 
So Purgeandfire if i say

GetLocalPlayer () is it the same as GetLocalPlayer ( ) ?.. do i get an error?..

It is the same.

Are there any rules on CAPITALIZATION?.. like the word private... some are Private some are just private.. so when i use a capital letter and when i won't?...

Yes. JASS is case sensitive. Private is not the same as private. Ex:
JASS:
function Test takes nothing returns nothing 
endfunction

function Example takes nothing returns nothing 
    call test() // syntax error, no such function
    call Test() // no error
endfunction
 
That's why i am asking when do i use Private and private?..

"Private" is not a keyword. You can't use it.

You can use "private" though. Usually, if you want someone to be able to access your function, don't add the "private" keyword. Just leave it as a regular function and give it a good name.

For all other intents and purposes, you can usually affix "private" to it. There are cases where you might want to use public (avoid name collision, but allow access), but you needn't worry about it too much--especially if you name your functions well.
 
Level 6
Joined
Feb 5, 2012
Messages
1,685
so in vJASS to create a variable let say an interger you don't need to create Integer in the Variable creator.. right?.. you just type it?..

Also what are those global?.. i found that in most spells before the variables there is a global on the top and below are the variable.. what does global mean?..
 
Level 18
Joined
Sep 14, 2012
Messages
3,413
You can create globals variables that can be used everywhere in your script and private globals that can be used only on the corresponding library/scope, and public globals that can be used only by timing the scope/library prefix.

JASS:
library A
    globals
        integer a = 0  //This global can be used anywhere i want
        private integer b = 0   //This global can be used only in my library
        public integer c = 0  //This global can be used only by typing "A_c"
    endglobals
endlibrary

You can also use local variables that can be used only in the function they are declared :

JASS:
function DoSomething takes nothing returns nothing
    local unit u = CreateUnit( Player(0), 'hfoo', 0, 0, 0 )
    local integer a = 0
    //Do some stuff
    set u = null
endfunction

( I write set u = null because the unit type is a handle so it's must be nullify otherwise it's a leak. )
 
Yes. You will use the regular destroy/remove expressions. It depends on what kind of handle you've created, though. If you made a location (in GUI, a "point"), you use call RemoveLocation(<loc>). If you made a timer, then you would use call DestroyTimer(<timer>).

The one thing to note is that if you make a new handle in a local variable, such as:
JASS:
local timer t = CreateTimer()
Then you should null the local variable after you destroy it:
JASS:
local timer t = CreateTimer()
// .. some code later
call DestroyTimer(t)
set t = null

This is to prevent certain memory attached to the handle from staying in memory/remaining unrecycled, most notably the handle ID. You don't need to fully understand this statement I just made, but as a general rule of thumb you should null local handles at the end of a function (by "handles", I mean anything that is not a real, integer, boolean, code, or string variable). There are more rules on it, but you can't really go wrong with just nulling any local handle variable at the end of a function. Here is another example:
JASS:
function Test takes nothing returns nothing 
    local unit u = GetTriggerUnit()
    call SetWidgetLife(u, GetWidgetLife(u) + 100) // heal the unit for 100
    set u = null
endfunction
 
so everytime i remove a leak i will set it to null?..

In general, you should null any local handle variable at the end of a function (technically--agents, not handles. but just for ease of memorization, null any handle)

can i make a variable like this integer[1] = 1234?.. in vJASS

Yes. If you want a local integer variable array then it would look like this:
JASS:
function Example takes nothing returns nothing 
    local integer array int 
    set int[0] = 0432 // example  
    set int[1] = 1234 // example
    set int[2] = 5678 // example
endfunction

If you want to make a global:
JASS:
globals
    integer array int
endglobals

function Example takes nothing returns nothing 
     set int[0] = 0432 // example 
     set int[1] = 1234 // example 
     set int[2] = 5678 // example
endfunction
 
Level 18
Joined
Sep 14, 2012
Messages
3,413
Normally you should not use location.
If you use them use :
JASS:
private function Test takes nothing returns nothing
    local location l
    local group g
    local unit u
    local effect t
    //Do some stuff with them
    call RemoveLocation( l )
    call DestroyEffect( t )
    call DestroyGroup( g )
    set l = null
    set g = null
    set t = null
    set u = null
endfunction

But if you want an instant effect use :
call DestroyEffect( AddSpecialEffect( model, x, y ) )
or
call DestroyEffect( AddSpecialEffectTarget( model, unit, attachment ) )
 
Level 18
Joined
Sep 14, 2012
Messages
3,413
Ok thanks.
So here's a little list of most used handles and what to do with them :
- unit :
JASS:
local unit u
//Do some stuff
set u = null

- effect :
JASS:
local effect t
//Do some stuff
call DestroyEffect( t )
set t = null

- group
JASS:
local group g = CreateGroup () //To declare a group you must use the native CreateGroup
//Do some stuff
call DestroyGroup( g )
set g = null

- timer
JASS:
local timer t = CreateTimer() //To declare a timer you need to use the native CreateTimer().
//Do some stuff
call DestroyTimer( t )
set t = null

- trigger
JASS:
local trigger t = CreateTrigger() //To declare a trigger you must use the native CreateTrigger()
//Do some stuff
set t = null //Only if you plan to destroy the trigger with the native DestroyTrigger().
 
Level 6
Joined
Feb 5, 2012
Messages
1,685
so another question..

in function Test takes nothing returns nothing

when a function becames nothing? in return and takes?..

so if i want to add a condtion in the function how i can do it?.. and if i can then how can i add multiple condition like and/or ?..
 
Level 18
Joined
Sep 14, 2012
Messages
3,413
A trigger works like this :

EVENT -> CONDITION -> ACTIONS (at least in basics xD).

So to create a trigger in JASS first you will have to create a trigger and to convert it to custom text ^^.

Then you'll see something like this :
JASS:
function Trig_MyTrigger_Actions takes nothing returns nothing
endfunction

//===========================================================================
function InitTrig_MyTrigger takes nothing returns nothing
    set gg_trg_MyTrigger = CreateTrigger(  )
    call TriggerAddAction( gg_trg_MyTrigger, function Trig_MyTrigger_Actions )
endfunction

Ok here we are, there is a init function.
But what is a function. A function is something that can take argument and return one. Infact this init function takes no argument ("nothing") and return nothing :)
An init function in JASS/vJASS creates the trigger.

Now let's see what's inside this init function :
set gg_trg_MyTrigger.
In GUI every trigger got a variable name : gg_trg_TriggerName.
And in every init function they are assigned to a new trigger.
But in JASS we don't want to use that much variables so we'll use a local variable for this trigger.
We'll replace set gg_trg_MyTrigger = CreateTrigger( ) with local trigger MyTrigger = CreateTrigger( ).

Now to add events/conditions/actions.

1.) Events.
To add an event to a trigger we mostly use :
JASS:
local trigger MyTrigger = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( MyTrigger, EVENT_PLAYER_UNIT_SPELL_EFFECT  ) //If you want the event "Event - A Unit starts the effect of an ability

If you don't know the events you can add the event in GUI and then convert.

2.) Conditions.
To add a condition to a trigger use :
JASS:
function Condition takes nothing returns nothing
    return ( GetSpellAbilityId() == SPELL_ID ) //In the case of checking which spell has been casted.
endfunction 

function Init_Trig_MyTrigger takes nothing returns nothing
    local trigger MyTrigger = CreateTrigger( )
    call TriggerRegisterAnyUnitEventBJ( MyTrigger, EVENT_PLAYER_UNIT_SPELL_CAST )
    call TriggerAddCondition( MyTrigger, Condition( function Condition ) )
endfunction
In this case we created another function.
This one takes nothing but returns something a boolean.
This function check the spell which has been casted and return true if the spell has been casted is the one with the SPELL_ID and else it returns false.

3.) Actions.
To add actions to a trigger :
JASS:
function Actions takes nothing returns nothing
    //Do some stuff dude :D
endfunction

function Condition takes nothing returns nothing
    return ( GetSpellAbilityId() == SPELL_ID ) //In the case of checking which spell has been casted.
endfunction 

function Init_Trig_MyTrigger takes nothing returns nothing
    local trigger MyTrigger = CreateTrigger( )
    call TriggerRegisterAnyUnitEventBJ( MyTrigger, EVENT_PLAYER_UNIT_SPELL_CAST )
    call TriggerAddCondition( MyTrigger, Condition( function Condition ) )
    call TriggerAddActions( MyTrigger, function Actions )
endfunction

We add another function that is the actions of the trigger.
You just have to code inside this now :)

And now here the finish product with the local trigger leak removed :
JASS:
function Actions takes nothing returns nothing
    //Do some stuff dude :D
endfunction

function Condition takes nothing returns nothing
    return ( GetSpellAbilityId() == SPELL_ID ) //In the case of checking which spell has been casted.
endfunction 

function Init_Trig_MyTrigger takes nothing returns nothing
    local trigger MyTrigger = CreateTrigger( )
    call TriggerRegisterAnyUnitEventBJ( MyTrigger, EVENT_PLAYER_UNIT_SPELL_CAST )
    call TriggerAddCondition( MyTrigger, Condition( function Condition ) )
    call TriggerAddActions( MyTrigger, function Actions )
    set MyTrigger = null
endfunction
 
Level 6
Joined
Feb 5, 2012
Messages
1,685
So as what i understand from your explanation..

each time i want to add an event i will put call TriggerRegister..
how about those AnyUnitEvenBJ?.. is that a category?.. Enter's A Region is under that category?.. how about Player - Select Unit?.. i will use AnyPlayerEventBJ i am right?..

each time i want to add a condition i will put call TriggerAddCondition right?.. how about the function Condition?.. do i add like function UnitIsAlive?..
 
Level 18
Joined
Sep 14, 2012
Messages
3,413
For the event i don't know all the event so for an unique player event just use TriggerRegisterPlayerEvent. Just type it in GUI and convert the most of the time.

For the conditions. The fonction Condition called a function that takes nothing and returns a boolean, this boolean will be the answer do the condition. If it's true then actions will continue if it's false the trigger will not run his actions.

You can put many conditions :
JASS:
function Conditions takes nothing returns boolean
    return ( GetSpellAbilityId() == SPELL_ID ) and ( IsUnitAlive( unit ) )
endfunction

I don't made an equation for IsUnitAlive because it already returns a boolean :)
 
Ahah ^^
Purge and me could write a basic tutorial at this rate xD !

haha, I always wanted to.. but it takes a good amount of time to write it. I'm a little busy atm. Besides, I just approved a really nice tutorial recently:
http://www.hiveworkshop.com/forums/jass-ai-scripts-tutorials-280/jass-what-func-238298/

But what could be nice is an updated guide to spell making or something like that.

A JASS tutorial could be made, but writing it manually is so last century, and it has been done quite a few times. If I were to write one, I would make the entire thing out of random images and funny pictures. I bet it would work, too.
 
Level 6
Joined
Feb 5, 2012
Messages
1,685
Actually i read a lot of tutorials about vJASS and JASS but they thought something that i did not understand i mean they not include even the very basic.. but now because of this thread i understand more..

Now may i ask... How does spell arranged?..

Just like this?...

GLOBAL VARIABLES

then

ACTIONS FOR THE SPELLS

then

EVENT OF THE TRIGGER

....


Cause i am really confused where do i put the event.. at the bottom?..
 
Level 18
Joined
Sep 14, 2012
Messages
3,413
I can copy you one of my spells, i know it isn't very simple but he has everything you may want to know about vJASS :
JASS:
scope Shreding initializer Init
//==========================================================================
//=============================SETUP========================================
//==========================================================================

    globals
        private constant integer SPELL_ID = 'B000'
        private constant real perte = 0.9    //La vie sera multipliée par ce nombre
        private constant string model = "Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl"
    endglobals

    private function Targ takes unit targ returns boolean
        return (GetWidgetLife( targ ) > 0.405 ) and ( IsUnitType( targ, UNIT_TYPE_MAGIC_IMMUNE ) == false ) and ( IsUnitAlly( targ, GetOwningPlayer( GetSpellAbilityUnit() ) ) == false )
    endfunction
    
    private function Range takes integer level returns integer
        return 400 + 10 * level
    endfunction
    
    private function Damage takes integer level returns integer
        return 75 * level
    endfunction
    
    private function Armor takes integer level returns integer
        return 3*level
    endfunction
    
    private function MoveSpeed takes integer level returns real
        return I2R( 10 + 5 * level )
    endfunction
    
    private function AttackSpeed takes integer level returns integer
        return 10 + 5 * level
    endfunction
//==========================================================================
//=============================END SETUP====================================
//==========================================================================
    globals
        group g
        boolexpr b
    endglobals
    
    private function Pick takes nothing returns boolean
        return Targ( GetFilterUnit() )
    endfunction
    
    private function Cond takes nothing returns boolean
        local unit u = GetTriggerUnit()
        local integer level
        local real x
        local real y
        local unit f
        if ( GetSpellAbilityId() == SPELL_ID ) then
            set level = GetUnitAbilityUnit( u, SPELL_ID )
            set x = GetUnitX( u )
            set y = GetUnitY( u )
            call GroupEnumUnitsInRange( g, x, y, Range( level ), b )
            loop
                set f = FirstOfGroup( g )
                exitwhen ( f == null )
                call GroupRemoveUnit( g, f )
                call UnitDamageTarget( u, f, Damage( level ), true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, null )
                call Debuff.UnitAddDoubleSlowReducArmor( f, 6, MoveSpeed( level ), AttackSpeed( level ), Armor( level ) )
            endloop
            call SetWidgetLife( u, GetWidgetLife( u )  * perte )
            call DestroyEffect( AddSpecialEffect( model, x, y ) )
        endif
        set u = null
        return false
    endfunction
//===========================================================================
    private function Init takes nothing returns nothing
        local trigger Shreding = CreateTrigger(  )
        call TriggerRegisterAnyUnitEventBJ( Shreding, EVENT_PLAYER_UNIT_SPELL_EFFECT ) 
        call TriggerAddCondition( Shreding, Condition( function Cond ) )
        
        //Set globals
        set g = CreateGroup()
        set b = Condition( function Pick )
        
        //Preloading effect
        call Preload( model )
        
        //Preloading ability
        set bj_lastCreatedUnit = CreateUnit( Player(15), dummy, 0, 0, 0 )
        call UnitAddAbility( bj_lastCreatedUnit, SPELL_ID )
        call KillUnit( bj_lastCreatedUnit )
        set Shreding = null
    endfunction
endscope

This spell is like a Thunder Clap that reduces armor added to the slows. Beside the caster got his life multiplier by the variable "perte" meaning ~ "lost" in english.

Ok first it's JESP because i made a setup at the begginning, that means i can change the values of the spell without going further in the code.
In this setup there is two parts : the globals and the functions.
The globals are the spell id inside the object editor, a life multiplier factor ( french inside sorry xD ), and the path of the model i will use.

Then i set the area of effect around the caster, the damage the ennemies will take, the armor they will loose, the movement speed they will loose ( in percentage ), the attack speed they will loose ( in percentage ).
It's a bit difficult because i made a custom debuff system that handles those debuff that's why it is a bit disturbing.

Just take a look at the other globals block after the setup, those globals won't be change by the user. They're a part of the code.

Ok now let's take a look about the last part XD !
The Init Part, i create a local trigger var that i use for everything. I add the event, the condition. Oh yes another disturbing thing, I'm trying to not use action block since you can do everything in one single block ( and there is another technical reason i forgot ^^ ).
I set the globals g and b.
I preload the effect and the abilities to prevent lags.

Now let's take a look at the condition function. First i declare some locals, I need the caster, his coordinates, the level of the ability for the unit and a tampon unit for the FirstOfGroup method.

Then i check the Spell_ID of the spell being casted.

Then i set some vars. I pick every units that are in range with the boolexpr condition.

Then i create loop with the FirstOfGroup method to damage everyone and to apply the debuff to everyone.

At the end of the loop I set the life of the caster to his life * the multiplier and at last I create the beautiful effect :)

At last don't forget to clean leaks :)

Ok I made this quite fast so if you have any questions go ahead.
 
Although I wouldn't personally set it up to register it to all players(it runs through to Player(15)), as not only does it use useless processing to register through all the players, but everytime a unit casts a spell, it runs the trigger everytime one does.

There is a better and more highly efficient way of registering a casting unit. For instance, whenever a unit is created it can be registered to the right trigger or you could register it to specific players that have a likelihood or having a unit that would cast the right spell.

Edit: fixed cause Almia.
 
Last edited:
Level 18
Joined
Sep 14, 2012
Messages
3,413
So where should i put this in your example :
JASS:
        local trigger Shreding = CreateTrigger(  )
        call TriggerRegisterAnyUnitEventBJ( Shreding, EVENT_PLAYER_UNIT_SPELL_EFFECT ) 
        call TriggerAddCondition( Shreding, Condition( function Cond ) )
        
        set g = CreateGroup()
        set b = Condition( function Pick )
        
        //Preloading effect
        call Preload( model )
        
        //Preloading ability
        set bj_lastCreatedUnit = CreateUnit( Player(15), dummy, 0, 0, 0 )
        call UnitAddAbility( bj_lastCreatedUnit, SPELL_ID )
        call KillUnit( bj_lastCreatedUnit )
        set Shreding = null
 
Status
Not open for further replies.
Top