Warcraft 3 documentation
vJASS & Zinc Documentation
For the latest documentation about how it works vJASS and Zinc language layers for Warcraft III, please follow these links:
Jasshelper documentation - Zinc documentation - WC3 Optimizer documentation

[Jass 101] - How to move from GUI to JASS No New Posts Jass Tutorials

Started by
moyack

0 Members and 1 Guest are viewing this topic.

[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:
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
  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. endfunction
  13.  
  14. function Trig_Test_Actions takes nothing returns nothing
  15.     call ForGroupBJ( GetUnitsInRangeOfLocMatching(512, GetUnitLoc(GetTriggerUnit()), Condition(function Trig_Test_Func001001003)), function Trig_Test_Func001A )
  16. endfunction
  17.  
  18. //===========================================================================
  19. function InitTrig_Test takes nothing returns nothing
  20.     set gg_trg_Test = CreateTrigger(  )
  21.     call TriggerAddCondition( gg_trg_Test, Condition( function Trig_Test_Conditions ) )
  22.     call TriggerAddAction( gg_trg_Test, function Trig_Test_Actions )
  23. 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
  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. endfunction
  15.  
  16. private function Actions takes nothing returns nothing
  17.     call ForGroupBJ( GetUnitsInRangeOfLocMatching(512, GetUnitLoc(GetTriggerUnit()), Condition(function GetEnemies)), function DoDamage )
  18. endfunction
  19.  
  20. //===========================================================================
  21. private function Init takes nothing returns nothing
  22.     set gg_trg_Test = CreateTrigger(  )
  23.     call TriggerAddCondition( gg_trg_Test, Condition( function Conditions ) )
  24.     call TriggerAddAction( gg_trg_Test, function Actions )
  25. endfunction
  26.  
  27. 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
  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
  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
  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
  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
  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
  1. private function Init takes nothing returns nothing
  2.     set gg_trg_Test = CreateTrigger(  )
  3.     call TriggerAddCondition( gg_trg_Test, Condition( function Conditions ) )
  4.     call TriggerAddAction( gg_trg_Test, function Actions )
  5. endfunction

And we will change this code into this:
Code: jass
  1. private function Init takes nothing returns nothing
  2.     local trigger t = CreateTrigger(  )
  3.     call TriggerAddCondition( t, Condition( function Conditions ) )
  4.     call TriggerAddAction( t, function Actions )
  5.     set t = null // we free the variable but not the handle itself... in this case it doesn't matter :)
  6. 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 »



[Jass 101] - How to move from GUI to JASS
Reply #1 on: February 11, 2013, 09:17:01 PM

Added more content.


[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



[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 »



[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.


[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


[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.


 

Started by moyack

Replies: 2
Views: 6131
WC3 Editing Tools

Started by moyack

Replies: 3
Views: 4229
Jassdoc

Started by moyack

Replies: 225
Views: 315332
WC3 Editing Tools

Started by nestharus

Replies: 0
Views: 2288
Jass Tutorials

Started by moyack

Replies: 1
Views: 8085
Tavern
Vivir aprendiendo.co - A place for learning stuff, in Spanish   Chaos Realm - The world of Game modders and wc3 addicts   Diplo, a gaming community   Power of Corruption, an altered melee featuring Naga and Demon. Play it now!!!   WC3JASS.com - The JASS Vault + vJASS and Zinc   Jetcraft - A Starcraft II mod   WormTastic Clan (wTc)   Warcraft RESOURCES Reforged: Modelos, mapas, proyectos y mas...