Warcraft III: MapsModelsSkinsIconsSpellsToolsTutorials
WC3 JASS: Code SnippetsJASS and vJASS Spells and SystemsJass Tutorials
Chat @Discord

Author Topic: [Jass 101] - How to move from GUI to JASS  (Read 12800 times)

  • Site Owner
  • Administrator
  • Starter - level 4
  • *
  • Posts: 988
  • WC3 Models: 32
  • WC3 Tutorials: 13
  • WC3 Tools: 10
  • WC3 Maps: 11
  • WC3 Skins: 6
  • WC3 Icons: 2
  • WC3 Spells: 5
  • Reputation: 1153
  • Site Admin - I love fix things
    • View Profile
    • Blizzard Modding Information Center
[Jass 101] - How to move from GUI to JASS
« on: February 10, 2013, 12:48:19 PM »
JASS 101 - How to move from GUI to JASS

The purpose of this chapter is to introduce in the process to start coding in jass using Jass New Generation Pack (JNGP)

Let's start!!

Here we assume that you have installed and configured properly JNGP. If you haven't done this, please refer to this tutorial.
  • Open Jass New Gen Pack
  • If you have no map to test it, use the one that started the Editor.
  • Open the Trigger Editor in the menu Module > Trigger Editor or simply press F4.
  • You will see the following interface:


    As you can see any new map will start with a trigger which will start some configurations for a melee style game. The important parts of this trigger are the Events, the Conditions and the Actions
  • Now to the interesting part. As you may know, GUI is in fact an "cover" for the code inside the editor, so we need to tell the World Editor that we don't want to see this cover. To do that please go to the menu Edit > Convert to Custom Text as shown in the following picture:

  • After setting this you will see the following code:

    function Trig_Melee_Initialization_Actions takes nothing returns nothing
        call MeleeStartingVisibility(  )
        call MeleeStartingHeroLimit(  )
        call MeleeGrantHeroItems(  )
        call MeleeStartingResources(  )
        call MeleeClearExcessUnits(  )
        call MeleeStartingUnits(  )
        call MeleeStartingAI(  )
        call MeleeInitVictoryDefeat(  )
    endfunction

    //===========================================================================
    function InitTrig_Melee_Initialization takes nothing returns nothing
        set gg_trg_Melee_Initialization = CreateTrigger(  )
        call TriggerAddAction( gg_trg_Melee_Initialization, function Trig_Melee_Initialization_Actions )
    endfunction

    In order to understand it I'd suggest to read it from the bottom to the top. The first thing you will see is that we manage something called functions. All in Jass is a matter of developing functions to be honest. The functions has 3 parts: the name, the input arguments (takes) and the output argument (returns) sets the type of data or handle the functions will obtain.

Important tip: From now on you will work in the TESH editor environment . It's important to clarify that the undo and redo in the toolbar are not functional in the text edition, instead you have to right click over the code text and there will be a menu which will offer this feature in the code.


Trying some GUI code.

Well, we've made some test with an easy code, pretty straight. Now let's try with something more elaborated but simple to understand. As a sample, we'll do a trigger that makes Abominations Deals damage upon death. We clarify that we won't make it leakless or efficient in order to make it readable to see how this will look in Jass.


And here's the GUI for that:
Trigger: Test 1532945339
   
           
  • Test
  •     Events
  •         Unit - A unit Dies
  •     Conditions
  •         (Unit-type of (Triggering unit)) Equal to Abomination
  •     Actions
  •         Unit Group - Pick every unit in (Units within 512.00 of (Position of (Triggering unit)) matching (((Matching unit) belongs to an enemy of (Owner of (Triggering unit))) Equal to True)) and do (Actions)
  •             Loop - Actions
  •                 Unit - Cause (Triggering unit) to damage (Picked unit), dealing 250.00 damage of attack type Chaos and damage type Acid
           
And then, let's convert it into Jass. The result is the following:
Code: jass  [Select]
  1. function Trig_Test_Conditions takes nothing returns boolean
  2.     if ( not ( GetUnitTypeId(GetTriggerUnit()) == 'uabo' ) ) then
  3.         return false
  4.     endif
  5.     return true
  6. endfunction
  7.  
  8. function Trig_Test_Func001001003 takes nothing returns boolean
  9. endfunction
  10.  
  11. function Trig_Test_Func001A takes nothing returns nothing
  12.     call UnitDamageTargetBJ( GetTriggerUnit(), GetEnumUnit(), 250.00, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_ACID )
  13. endfunction
  14.  
  15. function Trig_Test_Actions takes nothing returns nothing
  16.     call ForGroupBJ( GetUnitsInRangeOfLocMatching(512, GetUnitLoc(GetTriggerUnit()), Condition(function Trig_Test_Func001001003)), function Trig_Test_Func001A )
  17. endfunction
  18.  
  19. //===========================================================================
  20. function InitTrig_Test takes nothing returns nothing
  21.     set gg_trg_Test = CreateTrigger(  )
  22.     call TriggerRegisterAnyUnitEventBJ( gg_trg_Test, EVENT_PLAYER_UNIT_DEATH )
  23.     call TriggerAddCondition( gg_trg_Test, Condition( function Trig_Test_Conditions ) )
  24.     call TriggerAddAction( gg_trg_Test, function Trig_Test_Actions )
  25. endfunction

As you can see, it generates 5 functions. From bottom to top: InitTrig_Test, Trig_Test_Actions, Trig_Test_Func001A, Trig_Test_Func001001003 and Trig_Test_Conditions. The first one will run at map initialization loading the trigger condition and action. the second will execute the actions block. The third will be executed for each unit near to the abomination and it will deal damage to it. The fourth filters all the units which are the enemies of the dying unit. And the fifth will check if the unit is of the type, if true, it will trigger the actions.

So in the end, all this GUI blocks form a long and non easy to read code. And the worst thing is that it does in an inefficient way. You see the long names?? they're done in this way some any function gets unique in the whole code.

How the code is arranged?? at the end, the code is armed in one file which will have a *.j extension. It will be the core of the map and will manage all the internal things in the map.

Now let's talk about the functions itself. Have you noticed that some of them are in cursive and others are in bold? the ones in cursive are functions from a library called blizzard.j, and the other are from the MAIN library called common.j and they are called natives.

The functions that we want to use more are the natives because they are the fastest in execution and in Jass are the most preferred. Blizzard.j what it does?? well, this library is the connector from GUI to JASS. Most of the code done in blizzard.j is repetitive and does unnecessary steps. that's the reason GUI is slower than coding directly in JASS.


The first optimization

As you see, this code tends to be scary, so let's do a first try to make it look prettier. Let's start with the whole set of functions. You can see that these functions have strange names, that's because they need to be totally different from any other function defined in the triggers. We can  do a simplification in that part using a feature offered in vJASS called Scope. Scopes allow to differentiate the code. All that is inside a scope will be only valid inside the scope unless you define a set of prefixes (this part will be treated later). Meanwhile we'll use this to make it look nice.

Code: jass  [Select]
  1. scope Test initializer Init
  2.  
  3. private function Conditions takes nothing returns boolean
  4.     if ( not ( GetUnitTypeId(GetTriggerUnit()) == 'uabo' ) ) then
  5.         return false
  6.     endif
  7.     return true
  8. endfunction
  9.  
  10. private function GetEnemies takes nothing returns boolean
  11. endfunction
  12.  
  13. private function DoDamage takes nothing returns nothing
  14.     call UnitDamageTargetBJ( GetTriggerUnit(), GetEnumUnit(), 250.00, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_ACID )
  15. endfunction
  16.  
  17. private function Actions takes nothing returns nothing
  18.     call ForGroupBJ( GetUnitsInRangeOfLocMatching(512, GetUnitLoc(GetTriggerUnit()), Condition(function GetEnemies)), function DoDamage )
  19. endfunction
  20.  
  21. //===========================================================================
  22. private function Init takes nothing returns nothing
  23.     set gg_trg_Test = CreateTrigger(  )
  24.     call TriggerRegisterAnyUnitEventBJ( gg_trg_Test, EVENT_PLAYER_UNIT_DEATH )
  25.     call TriggerAddCondition( gg_trg_Test, Condition( function Conditions ) )
  26.     call TriggerAddAction( gg_trg_Test, function Actions )
  27. endfunction
  28.  
  29. endscope

Now is more readable: functions have names that let you get clearly its purpose. Scopes allow to define a function that runs at map initialization, very convenient to set variables of that specific part of the trigger. In addition, it provide context to the functions to only the trigger, no matter the name. We achieve this with a new keyword: private this makes those functions only valid inside the scope, allowing you to write faster your functions and make them more readable for you.

Well, the general optimization is done, now to the functions themselves. Let's start with Conditions.

Conditions function
Code: jass  [Select]
  1. private function Conditions takes nothing returns boolean
  2.     if ( not ( GetUnitTypeId(GetTriggerUnit()) == 'uabo' ) ) then
  3.         return false
  4.     endif
  5.     return true
  6. endfunction
I personally don't get why it evaluate too many stuff. If you use == the result will be a boolean. Comparing a boolean to obtain the same boolean is a waste of code we just simple do this:
Code: jass  [Select]
  1. private function Conditions takes nothing returns boolean
  2.     return GetUnitTypeId(GetTriggerUnit()) == 'uabo'
  3. endfunction
As you see, we passed from 6 line of code to 3 lines. As you see too, it's straight to the point, hence for efficient.

Actions Function

Code: jass  [Select]
  1. private function Actions takes nothing returns nothing
  2.     call ForGroupBJ( GetUnitsInRangeOfLocMatching(512, GetUnitLoc(GetTriggerUnit()), Condition(function GetEnemies)), function DoDamage )
  3. endfunction
  4.  
Well, this function is pretty straight, so what can be optimized?? well, first of all it leaks variables, that means an object is created but their reference is lost so it keeps alive for the rest of the game without being removed and nullified. For that reason we'll set variables to call them later and remove them when they are not needed anymore. Additionally we have a function ForgroupBJ this one is a Blizzard.j function so it has one or more process inside it. In JNGP, in the trigger editor, click on the text area and press CTRL, if you hover the mouse over those BJ functions you'll see they show as an hiperlink. if you click on it you'll see this code:
Code: jass  [Select]
  1. function ForGroupBJ takes group whichGroup, code callback returns nothing
  2.     // If the user wants the group destroyed, remember that fact and clear
  3.     // the flag, in case it is used again in the callback.
  4.     local boolean wantDestroy = bj_wantDestroyGroup
  5.     set bj_wantDestroyGroup = false
  6.  
  7.     call ForGroup(whichGroup, callback)
  8.  
  9.     // If the user wants the group destroyed, do so now.
  10.     if (wantDestroy) then
  11.         call DestroyGroup(whichGroup)
  12.     endif
  13. endfunction
  14.  
What we need actually is the function in line 7. As you see these BJ functions do a lot of unnecessary stuff, and normally they swap arguments to the natives, making most of them slow. Now let's see how it looks the code now using the native ForGroup():
Code: jass  [Select]
  1. private function Actions takes nothing returns nothing
  2.     local group g = CreateGroup()
  3.     local unit u = GetTriggerUnit()
  4.     call GroupEnumUnitsInRange(g, GetUnitX(u), GetUnitY(u), 512., Condition(function GetEnemies))
  5.     call ForGroup(g, function DoDamage )
  6.     call DestroyGroup(g)
  7.     set g = null
  8.     set u = null
  9. endfunction

Now we have just natives in our code and when we call an object, we can remove and clean the variables properly. And in this using local variables, we've made the code MUI (Multi Unit Instanciable) which means that this will run safely for each units without any collision in their information (we'll talk later about the importance of this).

Init Function

In the init function we don't want to create a global variable to store a trigger which won't be used or modified later, in fact in spells we need a code that triggers during all the game. So storing the trigger in a global is a waste of variables, in fact we can make it leak, because we don't need to refer to the trigger later. Here's the original code:
Code: jass  [Select]
  1. private function Init takes nothing returns nothing
  2.     set gg_trg_Test = CreateTrigger(  )
  3.     call TriggerRegisterAnyUnitEventBJ( gg_trg_Test, EVENT_PLAYER_UNIT_DEATH )
  4.     call TriggerAddCondition( gg_trg_Test, Condition( function Conditions ) )
  5.     call TriggerAddAction( gg_trg_Test, function Actions )
  6. endfunction

And we will change this code into this:
Code: jass  [Select]
  1. private function Init takes nothing returns nothing
  2.     local trigger t = CreateTrigger(  )
  3.     call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_DEATH )
  4.     call TriggerAddCondition( t, Condition( function Conditions ) )
  5.     call TriggerAddAction( t, function Actions )
  6.     set t = null // we free the variable but not the handle itself... in this case it doesn't matter :)
  7. endfunction

Now we manage the trigger as a local variable, this usage of locals makes easy to port code from one map to another.

To be continued...

It's time to move and we're ready to code. Please check for the following tutorial to see about the structure of the code and its features.

« Last Edit: February 19, 2013, 05:20:45 AM by moyack »

We can give you full hosting for your projects, a complete page!!

A custom altered melee map where you can play Naga and Demons. Check it out!!
Use Dropbox...

  • Site Owner
  • Administrator
  • Starter - level 4
  • *
  • Posts: 988
  • WC3 Models: 32
  • WC3 Tutorials: 13
  • WC3 Tools: 10
  • WC3 Maps: 11
  • WC3 Skins: 6
  • WC3 Icons: 2
  • WC3 Spells: 5
  • Reputation: 1153
  • Site Admin - I love fix things
    • View Profile
    • Blizzard Modding Information Center
[Jass 101] - How to move from GUI to JASS
« Reply #1 on: February 11, 2013, 09:17:01 PM »
Added more content.

We can give you full hosting for your projects, a complete page!!

A custom altered melee map where you can play Naga and Demons. Check it out!!
Use Dropbox...

  • Awesome Global Code Moderator
  • Recognized User
  • Rookie - level 2
  • *
  • Posts: 83
  • WC3 Models: 0
  • WC3 Tutorials: 0
  • WC3 Tools: 0
  • WC3 Maps: 0
  • WC3 Skins: 0
  • WC3 Icons: 0
  • WC3 Spells: 0
  • Reputation: 516
  • vJass Incarnate
    • View Profile
[Jass 101] - How to move from GUI to JASS
« Reply #2 on: February 13, 2013, 09:04:33 AM »
This is cool! ^.^

Moving from GUI to JASS directly via code conversion could work for a lot of people. In fact, that's what I did to learn JASS :P

  • Site Owner
  • Administrator
  • Starter - level 4
  • *
  • Posts: 988
  • WC3 Models: 32
  • WC3 Tutorials: 13
  • WC3 Tools: 10
  • WC3 Maps: 11
  • WC3 Skins: 6
  • WC3 Icons: 2
  • WC3 Spells: 5
  • Reputation: 1153
  • Site Admin - I love fix things
    • View Profile
    • Blizzard Modding Information Center
[Jass 101] - How to move from GUI to JASS
« Reply #3 on: February 13, 2013, 09:38:18 AM »
This is cool! ^.^

Moving from GUI to JASS directly via code conversion could work for a lot of people. In fact, that's what I did to learn JASS :P
Yay!!! in fact I believe in the Rosseta Stone learning procedure because it's quite effective in languages.

I'm planning to add a basic formatting section to this tutorial so they can compare the raw code generated in GUI with the one optimized with vJASS and empathize the good aspects of writing directly in Jass code.
« Last Edit: February 13, 2013, 09:48:31 AM by moyack »

We can give you full hosting for your projects, a complete page!!

A custom altered melee map where you can play Naga and Demons. Check it out!!
Use Dropbox...

  • Your Awesome Site Director
  • Recognized User
  • Starter - level 1
  • *
  • Posts: 382
  • WC3 Models: 0
  • WC3 Tutorials: 0
  • WC3 Tools: 0
  • WC3 Maps: 0
  • WC3 Skins: 0
  • WC3 Icons: 0
  • WC3 Spells: 0
  • Reputation: 677
    • View Profile
[Jass 101] - How to move from GUI to JASS
« Reply #4 on: February 13, 2013, 11:41:17 PM »
*Puts seat belt*

Mind if I join the ride?
Chronicles of Darkness
by: SonofJay

A BlizzMod Hosted Project

They can hate, let them hate, make them hate.

  • aka Drunken_Jackal
  • Recognized User
  • Rookie - level 4
  • *
  • Posts: 179
  • WC3 Models: 0
  • WC3 Tutorials: 0
  • WC3 Tools: 0
  • WC3 Maps: 0
  • WC3 Skins: 0
  • WC3 Icons: 0
  • WC3 Spells: 0
  • Reputation: 558
    • View Profile
[Jass 101] - How to move from GUI to JASS
« Reply #5 on: February 14, 2013, 05:19:35 AM »
Good job there boss! Hope this turns out to be a series :D


gucci mane

  • Site Owner
  • Administrator
  • Starter - level 4
  • *
  • Posts: 988
  • WC3 Models: 32
  • WC3 Tutorials: 13
  • WC3 Tools: 10
  • WC3 Maps: 11
  • WC3 Skins: 6
  • WC3 Icons: 2
  • WC3 Spells: 5
  • Reputation: 1153
  • Site Admin - I love fix things
    • View Profile
    • Blizzard Modding Information Center
[Jass 101] - How to move from GUI to JASS
« Reply #6 on: February 14, 2013, 06:29:25 AM »
*Puts seat belt*

Mind if I join the ride?
Yes!!! that's the idea :D

Good job there boss! Hope this turns out to be a series :D
Of course there's is :) right now I'm working in the linking of this chapter with the next one so they can have total coherence.

We can give you full hosting for your projects, a complete page!!

A custom altered melee map where you can play Naga and Demons. Check it out!!
Use Dropbox...

 

The Jass NewGen Pack (JNGP) 2.0 vs Warcraft III's patch 1.27a

Started by ApelliBoard General Help and WC3 Discussion

Replies: 9
Views: 5076
Last post March 21, 2016, 06:32:55 AM
by LembidiZ
Jass Newgen Pack 2.0 Alpha - Recruiting for testing

Started by moyackBoard General Help and WC3 Discussion

Replies: 84
Views: 45490
Last post July 17, 2013, 09:37:47 AM
by moyack
What's the best jass preprocessor? pjass or zoxc jassparser?

Started by moyackBoard Jass Theory & Questions

Replies: 2
Views: 8500
Last post December 14, 2012, 02:58:27 PM
by moyack
The Jass NewGen Pack (JNGP) 2.0

Started by moyackBoard WC3 Editing Tools

Replies: 213
Views: 189387
Last post August 01, 2017, 04:16:29 AM
by Glowackos
Jass NewGen Pack Update

Started by PurgeandfireBoard General Jass Discussion

Replies: 4
Views: 12216
Last post July 29, 2012, 03:28:05 PM
by Purgeandfire
Blizzard Modding Information Center Starcraft II Modding Information Center Wacraft III Modding Information Center WC3JASS.com - The JASS Vault Chronicles of Darkness - A Warcraft III mod Jetcraft - A Starcraft II mod Troll Smash - A Warcraft III Arena
  Mod DB - Change the Game Power of Corruption - A Warcraft III altered melee map Chaos Realm - The world of Game modders and wc3 addicts Follow us on Facebook!!