Tutorial Learning JASS

Vestras

Retired
Reaction score
248
Introduction

First part - why JASS?
Why JASS and not GUI? Because JASS is:
- easy to make MUI.
- more efficient.
- you get more control over your code.
- easier to use. (yes, actually.)
And to you who doesn't know: you can't say that GUI is better and another thing than JASS. Why? Because GUI is JASS.

Second part - Goodies and badies?
Yes, there is goodies and badies - the goodies are stuff named "natives" and the badies are stuff named "BJs". BJs are functions (explained below) that are created by Blizzard (well, everything in JASS is.), which they used for GUI. The reason BJs is badies is:
- they use natives to work.
- they are slower than natives.

NOTICE - don't worry! I will explain what natives, BJs and functions is below this piece!

But, there is also good BJs! The BJ-variables. Now, in GUI, when you use "Get Last Created Unit", you actually use the function named "GetLastCreatedUnit()" in JASS. Now, all that GetLastCreatedUnit() does, is that it returns a BJ variable - this one:

This is a variable, also created by Blizzard, but because it doesn't call another function, it isn't slow. Therefore: goodie.

NOTICE - there is also good BJs! When debuging, many people uses this function:
JASS:
call BJDebugMsg("myMsg")

this displays a message to all players, and can be used to check which triggers run and which doesn't. There is of course also much more good BJs, try looking around in the function list in TESH!

Third part - JASS basics.
JASS is basicly made up by functions and variables. Now, in functions, there is "subcategories", named natives and BJs.

Functions.
A function would be the following:
JASS:
call UnitApplyTimedLife(myUnit, myBuff, myDuration)

Now, this is a function - this would be adding a life timer in GUI. So, this function requires:
- myUnit - a unit variable. (doesn't have to be a variable though.)
- myBuff - a buff raw code. (in object editor, press ctrl + d to view raw codes)
- myDuration - this is a real. If I placed "2" in this one, the unit (myUnit) would die after 2 seconds. (just an example.)

NOTICE - a function calling another function that you have made, can't be over the function you call!
JASS:
function A takes nothing returns nothing
  call B ()
endfunction

function B takes nothing returns nothing
endfunction
// That will cause syntax errors.


Creating your own function.
Now, to create your own function for use, you'll have to do this:
JASS:
function myFunction takes nothing returns nothing
endfunction

This will create a function for use. Now, this function can content other function calls, which will make this function do something.

Then there are something named arguments, like this:
JASS:
function myFunction takes unit u returns nothing
endfunction


There, you could do something with unit u, and when calling the function, you would do this:
JASS:
call myFunction(myUnit)

Just like when calling the native function above!
If you about to get this, I suggest you to read that all over.

NOTICE - you can have more arguments by adding commas, like this:
JASS:
function myFunc takes unit u, integer i returns nothing
endfunction


Now, we do miss something, don't we? Returns..?
JASS:
function myFunc takes unit u, integer i returns integer
  return 0
endfunction

The "returns integer" part - the integer is the returned variable type. This could have been boolean, unit, group, everything as well though. Now, what is returning? A lot of functions, native and BJ, returns stuff, example:
JASS:
constant native function GetTriggerUnit takes nothing returns unit

This is a function you use for getting the triggering unit, right? Now, for making this function have an effect, it has to return something. Basicly, if a function doesn't take anything and doesn't return anything and doesn't set some variable, it pretty much does nothing. (Isn't always true though.) Now, set can actually set a variable to a return. Example:

JASS:
set myUnit = GetTriggerUnit()


Now, actually, myUnit isn't set to the function GetTriggerUnit(), it is set to the variable the function returns. Get it? Good!

Calling a function.
Now, every single time you need a function, you'll have to call it - what does that mean? Basicly calling is the same as executing something, like if you wanted to take a step, your mind would "call" a function that made you walk.
When using a function, you'll always need to place call before the function name.
JASS:


NOTICE - when calling functions, you cannot have

You'll have to use (), where there needs to be the variables you want to call the function with inside the ()s! If the function doesn't take any arguments, you'll just go straigth ()!

Variables.
Locals.
In JASS variables, there are two types of variables - locals and globals. (globals requires vJASS, which is found in NewGen.) Locals are variable types which only are available for use in the function they were declared in.
JASS:
function myFunc takes nothing returns nothing
   local integer int = 0
   local unit u = GetTriggerUnit()
endfunction


NOTICE - locals will cause syntax errors if another variable or function has the same name as the local!

If I used the variables int and u in other functions, I would have syntax errors.
Globals. (Requires vJASS!)
Globals, as the opposite of locals, can be accessed in every function in the map, and will, like globals, cause syntax errors if a variable or function is declared with the same name as the global.

Globals always needs to be in global "tags", like this:
JASS:
globals
  integer i = 1
  unit u = null
  real r = 2.00
  // and so on...
endglobals


These variables will be able to be accessed all over the map.

Arrays.
Now, an arrayed variable is a variable "with more of the same type in it". If you got an arrayed variable, you can set more of the same variable, example:
JASS:
local integer array i
set i[1] = 0
set i[2] = 1
set i[3] = 2
set i[4] = 3
// and so on...


NOTICE - arrayed variables can't be initialized!

Constants.
A constant variable can't be changed throughout the game, and will cause syntax errors if you try.

JASS:
globals
  constant integer i = 0 // This will stay 0 throughout the whole game.
  unit u = null // This one can be changed, because it's non-constant
  constant real r = 2.00 // Again, can't be changed
endglobals


Now, locals can't be constants.
Why is this useful? This can be useful for ability raw codes and condition functions.

NOTICE - functions can be constant too!

previous - home - next
 

Vestras

Retired
Reaction score
248
Intermediate JASS​

At this part, we are going to expand what we just learned. We are going to create a little more advanced functions, events, conditions and actions.

Creating Events.
When you convert your trigger into custom text, you will always have a function named InitTrig_TriggerName, and in there, the events, conditions and actions is.

JASS:
function InitTrig_MyTrig takes nothing returns nothing
   set gg_trg_MyTrig = CreateTrigger()
// gg_trg_MyTrig is a trigger variable which is created for each trigger
   call TriggerRegisterAnyUnitEventBJ(gg_trg_MyTrig, EVENT_PLAYER_UNIT_SPELL_EFFECT)
// here we register when any unit starts the effect of an ability
// and so on...
endfunction


This will register when a unit starts the effect of an ability, and then, to add conditions and actions, we would do this:
JASS:
function InitTrig_MyTrig takes nothing returns nothing
   set gg_trg_MyTrig = CreateTrigger()
// gg_trg_MyTrig is a trigger variable which is created for each trigger
   call TriggerRegisterAnyUnitEventBJ(gg_trg_MyTrig, EVENT_PLAYER_UNIT_SPELL_EFFECT)
// here we register when any unit starts the effect of an ability
   call TriggerAddCondition(gg_trg_MyTrig, Condition(function Conditions))
// adding conditions... Condition(...) is a function which causes syntax errors if not the function, here Conditions, doesn't return a boolean. Basicly, this function takes a trigger argument and a boolexpr (boolean expression) argument
   call TriggerAddAction(gg_trg_MyTrig, function Actions)
// adds actions, very basic
// and so on...
endfunction


NOTICE - remember, that you can add more events, conditions and actions by having more calls of the same function names!

To find out new events, just convert some GUI events into JASS. There are some rather tricky ones out there, so watch it!
Remember, that in normal JASS, without NewGen, you will always have to have a function like:

JASS:
function InitTrig_MyTriggerName takes nothing returns nothing


Else it won't compile! And unless you are calling the functions in the trigger, you will always need an InitTrig to add events and stuff!

Function Names and Indentation
This is a little bit unnecessary you might think, but no - if you want people to read your code easilier, you will have to have good function names and indentation!

NOTICE - I might not be the best example at indentation, but just create your own indentation methods if you want.

Indentation
Now, what is indentation? Basicly, it's the spaces in each line of code;
JASS:
function no_indentation takes nothing returns nothing
local unit u
local real x
local real y
local real angle
local unit t
local location l
endfunction


Pretty hard to read, right? This is a bit easier:
JASS:
function with_indentation takes nothing returns nothing
    local unit u
    local real x
    local real y
    local real angle
    local unit t
    local location l
        
        call SetUnitAnimation(u,"spell")
        // and so on...


A bit easier to read, right?
Well, it can get too much sometimes though:
JASS:
function toomuch_indentation takes nothing returns nothing
        local unit u
    local real x
            local real y
local real angle
                local unit t
    local location l
                                    // and so on...
endfunction


Got it? Great!

Function Names
Like indentation, these can be important too.
People probably won't read your code if your function names are like "MyFunctionName_lololo995830__75" (just an example of a pretty stupid name.), but more people will probably read it if it's like "Actions_Init" or "onSpellEffect" and stuff like that. This was very short, but very important if you would like to get better.

previous - home - next
 

Vestras

Retired
Reaction score
248
Subchapter: Coding Conventions​
By Eleandor.
Coding conventions are "rules" made to make code easier to be read. When you're making a jass script, at some point other people will be reading it as well. Don't let them have a hard time reading a chaotic script. Or even if the script is for personal use: avoid being confused because of bad writing habits.
A script that doesn't follow such conventions will work just as well as a script that does. However, it's like writing a letter: you start with introducing yourself and end with saying "greetings, name". It's just the way it is and makes a letter easier to read.

1) Identifiers
Identifiers are the "names" you give to variables, functions and constants.
* Constants: constants are written in capital letters. Spaces are replaced by underscores. Example: UNIT_STATE_LIFE
* Variables: variables are written entirely in lower case. Spaces are either left out or replaced by underscores. Example: player1gold
* Functions: A functionname is written lowercase, and each word starts with a capital letter. Example: GroupAddUnit

Small variations on these naming conventions are possible. Some programmers start each function with a lower case character. For instance: groupAddUnit. This is a matter of habit. However, since the original jass functions start with capital letters, it's encouraged to do the same.

The name of a function or variable should be obvious. If you only have 1 unit variable, it's enough to say:
JASS:
local unit u


If you have 2 units, naming them u1 and u2 is confusing. Name them wisely. For instance, say I have 2 units, an attacker and an attacked unit, I will call them:
JASS:
local unit attacker = GetAttacker()
local unit target = GetTriggerUnit()


2) Indentation
Indentation makes "groups" of code more visible. For instance:
JASS:
if booleanvar then
    Statements
endif

It is clear that the Statements are part of the "larger" if/then/else statement. For that reason, it's easier to see they are part of the statement by indenting them.
Following statements, among others, need to be indented:
* function / endfunction and method / endmethod
* if / else / elseif / endif
* loop / endloop
* struct / endstruct
* globals / endglobals
* More of such examples

3) Interlinear Spacing
Interlinear spacing is leaving some space between 2 lines of code. Such space is left between:
* 2 functions
* local variable declaration and the actual code
* ...​

4) Spacing
Sometimes, leaving additional spaces where they're not required can make the code easier to read.
Example:
JASS:
set a=b+1
set a = b + 1
call DisplayTextToPlayer(p,0,0,"lol")
call DisplayTextToPlayer(p, 0, 0, "lol")


An example
JASS:
globals    
    constant boolean ELEANDOR_IS_COOL = true

    integer array score
    boolean score10isvictory = false
endglobals

function UpdateScore takes player p returns nothing
    // This function increases the score of a player.
    
    local integer playerid = GetPlayerId(p)

    set score[playerid] = score[playerid] + 1
    if score[playerid] >= 10 then
        if score10isvictory then
            call DisplayTextToPlayer(p, 0, 0, "Good job, you've won the game!").
        endif
    endif
endfunction


previous - home - next
 

Vestras

Retired
Reaction score
248
Advanced JASS (Game Cache Usage, Spell Making.)

Game Cache Usage - Warning
First of all, I would like to warn you - Game Cache usage is an outdated method of storing data, newer methods would be vJASS, struct using, stuff like that. These stuff will not be included in this tutorial however, if you want to learn about that, I suggest you to read Moving From JASS To vJASS by Art.

Game Cache Usage - Starting
Before we can start using our game cache, which will be named gc for the rest of this chapter, we need 2 things;

- A global game cache variable, created via the GUI Variable Editor. (CTRL + B)
- A function for initializing and returning the game cache variable, like this:

JASS:
function gc takes nothing returns gamecache
    if udg_cache==null then
        call FlushGameCache(InitGameCache("data.gc"))
        set udg_cache=InitGameCache("data.gc")
    endif
 return udg_cache
endfunction


The "data.gc" could be any name you would want.
This is the function we call every single time we use our gc.

Now, we will create our function for usage of the cache.
Basically, everything that you store in a cache you store with a name, so you will have to remember that name...

JASS:
function gc takes nothing returns gamecache
    if udg_cache==null then
        call FlushGameCache(InitGameCache("data.gc"))
        set udg_cache=InitGameCache("data.gc")
    endif
 return udg_cache
endfunction

function Get takes nothing returns integer
    return GetStoredInteger(gc(),"gc","myInt")
endfunction

function Set takes integer i returns nothing
    call StoreInteger(gc(),"gc","myInt",i)
endfunction


It's really simple. Now, storing and getting units is a pain in the ass, and everything else than boolean, string, integer and real is nearly impossible, or very annoying to do all the time, to do without a system.

Therefore, we got Local Handle Vars or Attachable Vars.
Those are both game cache systems, which can be very useful when using game caches. I myself have never used LHV, only AV.

Local Handle Vars.
Attachable Vars.

I have attached maps where I use LHV and AV.

That was basically it, ready to go on for some game cache spell making? Great, let's go!

Spell Making - The Beginning
We are going to make a simple damage over time spell, where will need a game cache.
It is suggested that you don't use this spell in your map.

So, we know that we need our gc function... Then we need an inittrig, condition function and action function.

JASS:
function gc takes nothing returns gamecache
    if udg_cache==null then
        call FlushGameCache(InitGameCache("data.gc"))
        set udg_cache=InitGameCache("data.gc")
    endif
 return udg_cache
endfunction

constant function DoT_Conditions takes nothing returns boolean
    return GetSpellAbilityId()==DoT_ID() // DoT_ID() is a configuration function that we haven't created yet
endfunction

function DoT_Actions takes nothing returns nothing
endfunction

function InitTrig_DoT takes nothing returns nothing
    local trigger t=CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t,Condition(function DoT_Conditions))
    call TriggerAddAction(t,DoT_Actions)
endfunction


Now we need the configuring functions -

JASS:
// !!!! CONFIGURATION !!!! \\

constant function DoT_ID takes nothing returns integer
    // The raw code of spell
    return 'A000'
endfunction

constant function DoT_Damage takes integer lvl returns real
    // The damage dealt depending on level
    if lvl==1 then
        return 4.
    elseif lvl==2 then
        return 7.
    elseif lvl==3 then
        return 10.
    endif
    return 0. // This one just... has to be there (well, probably not, I just do it)
endfunction

constant function DoT_Effect takes nothing returns string
    // The special effect of the spell
    return "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl"
endfunction

constant function DoT_Interval takes nothing returns real
    // The timer interval
    return 0.75
endfunction

// !!!! SPELL    CODE !!!! \\

function gc takes nothing returns gamecache
    if udg_cache==null then
        call FlushGameCache(InitGameCache("data.gc"))
        set udg_cache=InitGameCache("data.gc")
    endif
 return udg_cache
endfunction

constant function DoT_Conditions takes nothing returns boolean
    return GetSpellAbilityId()==DoT_ID()
endfunction

function DoT_Actions takes nothing returns nothing
endfunction

function InitTrig_DoT takes nothing returns nothing
    set gg_trg_DoT=CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(gg_trg_DoT,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(gg_trg_DoT,Condition(function DoT_Conditions))
    call TriggerAddAction(gg_trg_DoT,function DoT_Actions)
endfunction


Got everything? Great!
Then we go on to creating the actual actions.

JASS:
// WARNING!!!! THIS SPELL IS UNSAFE!!!!

// !!!! CONFIGURATION !!!! \\

constant function DoT_ID takes nothing returns integer
    // The raw code of spell
    return 'A000'
endfunction

constant function DoT_DummyID takes nothing returns integer // Notice this - we now need a dummy!
    // The raw code of the dummy unit
    return 'h000'
endfunction

constant function DoT_Damage takes integer lvl returns real
    // The damage dealt depending on level
    if lvl==1 then
        return 4.
    elseif lvl==2 then
        return 7.
    elseif lvl==3 then
        return 10.
    endif
    return 0. // This one just... has to be there (well, probably not, I just do it)
endfunction

constant function DoT_Effect takes nothing returns string
    // The special effect of the spell
    return "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl"
endfunction

constant function DoT_Attach takes nothing returns string
    // The special effect attachment point
    return "chest"
endfunction

constant function DoT_Interval takes nothing returns real
    // The timer interval
    return 0.75
endfunction

// !!!! SPELL    CODE !!!! \\

function gc takes nothing returns gamecache
    if udg_cache==null then
        call FlushGameCache(InitGameCache("data.gc"))
        set udg_cache=InitGameCache("data.gc")
    endif
 return udg_cache
endfunction

function H2I takes handle h returns integer
    return h
    return 0
endfunction

function I2H takes integer i returns handle
    return i
    return null
endfunction

function H2U takes handle h returns unit
    return h
    return null
endfunction

constant function DoT_Conditions takes nothing returns boolean
    return GetSpellAbilityId()==DoT_ID()
endfunction

function DoT_Timer takes nothing returns nothing
    local unit t=H2U(I2H(GetStoredInteger(gc(),"gc","t")))
    local integer id=GetStoredInteger(gc(),"gc","p")
    local integer lvl=GetStoredInteger(gc(),"gc","lvl")
    local real x=GetUnitX(t)
    local real y=GetUnitY(t)
    local unit d=CreateUnit(Player(id),DoT_DummyID(),x,y,0)
        
        call UnitDamageTarget(d,t,DoT_Damage(lvl),false,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,null)
        call DestroyEffect(AddSpecialEffectTarget(DoT_Effect(),t,DoT_Attach()))
endfunction

function DoT_Actions takes nothing returns nothing
    local unit u=GetTriggerUnit()
    local unit t=GetSpellTargetUnit()
    local integer i=GetPlayerId(GetOwningPlayer(u))
    local integer lvl=GetUnitAbilityLevel(u,DoT_ID())
    local timer tmr=CreateTimer()
        call StoreInteger(gc(),"gc","p",i) // Storing the player id, 
        // so that we can create the dummy and the caster will still get credit
        call StoreInteger(gc(),"gc","lvl",lvl) // Storing the unit ability level,
        // so that we can deal damage depending on level
        call StoreInteger(gc(),"gc","t",H2I(t)) // Storing the target unit via the unsafe
        // H2I to I2H functions. Do never use those in your map
        call TimerStart(tmr,DoT_Interval,true,function DoT_Timer)
    set tmr=null
    set u=null
    set t=null
endfunction

function InitTrig_DoT takes nothing returns nothing
    set gg_trg_DoT=CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(gg_trg_DoT,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(gg_trg_DoT,Condition(function DoT_Conditions))
    call TriggerAddAction(gg_trg_DoT,function DoT_Actions)
endfunction


Now the spell actually does something... Now, we don't want the spell to last forever, do we? No, we don't, therefore we create the counting part.

JASS:
// WARNING!!!! THIS SPELL IS UNSAFE!!!!

// !!!! CONFIGURATION !!!! \\

constant function DoT_ID takes nothing returns integer
    // The raw code of spell
    return 'A000'
endfunction

constant function DoT_DummyID takes nothing returns integer // Notice this - we now need a dummy!
    // The raw code of the dummy unit
    return 'h000'
endfunction

constant function DoT_Damage takes integer lvl returns real
    // The damage dealt depending on level
    if lvl==1 then
        return 4.
    elseif lvl==2 then
        return 7.
    elseif lvl==3 then
        return 10.
    endif
    return 0. // This one just... has to be there (well, probably not, I just do it)
endfunction

constant function DoT_Effect takes nothing returns string
    // The special effect of the spell
    return "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl"
endfunction

constant function DoT_Attach takes nothing returns string
    // The special effect attachment point
    return "chest"
endfunction

constant function DoT_Interval takes nothing returns real
    // The timer interval
    return 0.40
endfunction

constant function DoT_Duration takes nothing returns real
    // The duration of the spell
    return 5.
endfunction

// !!!! SPELL    CODE !!!! \\

function gc takes nothing returns gamecache
    if udg_cache==null then
        call FlushGameCache(InitGameCache("data.gc"))
        set udg_cache=InitGameCache("data.gc")
    endif
 return udg_cache
endfunction

function H2I takes handle h returns integer
    return h
    return 0
endfunction

function I2H takes integer i returns handle
    return i
    return null
endfunction

function H2U takes handle h returns unit
    return h
    return null
endfunction

constant function DoT_Conditions takes nothing returns boolean
    return GetSpellAbilityId()==DoT_ID()
endfunction

function DoT_Timer takes nothing returns nothing
    local unit t=H2U(I2H(GetStoredInteger(gc(),"gc","t")))
    local integer id=GetStoredInteger(gc(),"gc","p")
    local integer lvl=GetStoredInteger(gc(),"gc","lvl")
    local real ti=GetStoredReal(gc(),"gc","ti")
    local real x=GetUnitX(t)
    local real y=GetUnitY(t)
    local unit d=CreateUnit(Player(id),DoT_DummyID(),x,y,0)
        
        call UnitDamageTarget(d,t,DoT_Damage(lvl),false,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,null)
        call DestroyEffect(AddSpecialEffectTarget(DoT_Effect(),t,DoT_Attach()))
        set ti=ti+DoT_Interval()
        call FlushStoredMission(gc(),"gc") // This clears our category "gc", so that we store the new values
        if ti>=DoT_Duration() then
            call PauseTimer(GetExpiredTimer())
            call DestroyTimer(GetExpiredTimer())
            return
        else
            call StoreInteger(gc(),"gc","t",H2I(t))
            call StoreInteger(gc(),"gc","p",id)
            call StoreInteger(gc(),"gc","lvl",lvl)
            call StoreReal(gc(),"gc","ti",ti)
        endif
endfunction

function DoT_Actions takes nothing returns nothing
    local unit u=GetTriggerUnit()
    local unit t=GetSpellTargetUnit()
    local integer i=GetPlayerId(GetOwningPlayer(u))
    local integer lvl=GetUnitAbilityLevel(u,DoT_ID())
    local timer tmr=CreateTimer()
    local real ti=0
        call StoreInteger(gc(),"gc","p",i) // Storing the player id, 
        // so that we can create the dummy and the caster will still get credit
        call StoreInteger(gc(),"gc","lvl",lvl) // Storing the unit ability level,
        // so that we can deal damage depending on level
        call StoreInteger(gc(),"gc","t",H2I(t)) // Storing the target unit via the unsafe
        // H2I to I2H functions. Do never use those in your map
        call StoreReal(gc(),"gc","ti",ti) // Storing our counter
        call TimerStart(tmr,DoT_Interval,true,function DoT_Timer)
    set tmr=null
    set u=null
    set t=null
endfunction

function InitTrig_DoT takes nothing returns nothing
    set gg_trg_DoT=CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(gg_trg_DoT,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(gg_trg_DoT,Condition(function DoT_Conditions))
    call TriggerAddAction(gg_trg_DoT,function DoT_Actions)
endfunction


That was it. It works, nothing is really wrong with it, except that it's unsafe. Because it's unsafe, I recommend you not to use this spell.

I have attached the map where it is implemented.
Now, you pretty much learned everything. Go get yourself some exercises, and yeah... enjoy what you've learned!

previous - home - next
 

Flare

Stops copies me!
Reaction score
662
Can you take the quote from Eleandor out of
tags, and just create him at the top? The quote is ugly-ing up the JASS tags

Also, that link to WC3C
1) Forced login - may be alright for someone who has an account, but for those who don't, they shouldn't have to register just to look at a few threads
2)
Sorry - no matches. Please try some different terms.

If you're gonna link to WC3C tutorials, link to them specifically (I don't think individual threads have the forced login), or link to some stuff at TH

And you're still showing people how to f*ck things up, by using LHV/AV without structs... (wouldn't be half as bad if you used structs, or arrayed globals, but no, it had to be the risky method :|). There are more than enough problems with JASS already, no point showing people how to make it worse :p
 

Vestras

Retired
Reaction score
248
> Can you take the quote from Eleandor out of
tags, and just create him at the top? The quote is ugly-ing up the JASS tags

Yeah.

> 1) Forced login - may be alright for someone who has an account, but for those who don't, they shouldn't have to register just to look at a few threads

> If you're gonna link to WC3C tutorials, link to them specifically (I don't think individual threads have the forced login), or link to some stuff at TH

I'll delete it then.

> And you're still showing people how to f*ck things up, by using LHV/AV without structs... (wouldn't be half as bad if you used structs, or arrayed globals, but no, it had to be the risky method :|)

It's a part of normal JASS, it's not my fault that Blizzard created it that unsafe and un-userfriendly. Structs and globals are vJASS, this isn't learning vJASS. And I tell people that it's outdated and that they shouldn't use it, but it's good to know.
 

Flare

Stops copies me!
Reaction score
662
it's not my fault that Blizzard created it that unsafe and un-userfriendly
I2H isn't specifically Blizzard's fault (even though the fact that the abuse exists would be their fault, but who was to know that people would uncover such a bug, and use it for 'good')

globals are vJASS
Globals aren't vJASS... free globals, yes, but globals themselves are available in the standard WE. Get your facts right, please.

but it's good to know.
It's good to know something which, when used, has the potential to screw up your map? Riiiiight, you keep thinking that way...
 
Reaction score
456
> Do they know about it?
And even if they did, I believe it still has to be written it's submitter :).

* Variables: variables are written entirely in lower case. Spaces are either left out or replaced by underscores. Example: player1gold
I begin globals with upper-case letter.

I didn't read the thread at all (scrolled over), because it looks very messy. I like well organized tutorials more.
 

Vestras

Retired
Reaction score
248
Flare said:
I2H isn't specifically Blizzard's fault (even though the fact that the abuse exists would be their fault, but who was to know that people would uncover such a bug, and use it for 'good')

Yeah, but it's one of the only methods of passing data without using a system and not using vJASS.

Flare said:
It's good to know something which, when used, has the potential to screw up your map? Riiiiight, you keep thinking that way...

I don't think you understand it the way I do... I mean, it's good to know different methods, and know what to prefer over others.

AceHart said:
Where is all of this coming from?
Do they know about it?

I first submitted it at www.wc3creations.net, as a pretty bad tut. Then I remade it, and submitted it here.

Uberplayer said:
And even if they did, I believe it still has to be written it's submitter .

I created this, if that's the question.

Uberplayer said:
I begin globals with upper-case letter.

I didn't read the thread at all (scrolled over), because it looks very messy. I like well organized tutorials more.

I think that that quote is locals.
Yeah, it looks messy, that's why you can shift to each part instead of it being so messy.

Joker(DiV) said:
HandleVars is soooo outdated, and unsafe.

Yeah, but it's a part of game cache using in JASS.
 

Flare

Stops copies me!
Reaction score
662
one of the only methods of passing data
Then use one of the other methods that don't require vJASS (yes, there is another method, so don't try and say otherwise)... it doesn't take a genius to think of that.

and know what to prefer over others.
So, you're giving people an excuse to prefer something that's broken over something that works? By showing people how to use it, you are, pretty much, condoning it's usage (even though you may say otherwise, but one line of text can be easily missed, or ignored)

I don't think you understand it the way I do... I mean, it's good to know different methods
Why would you want to know how to break your map? Knowing different methods is fine, but knowing how to break your map generally isn't a good thing...
 
Reaction score
456
> By Eleandor.
If I am not mistaken, your nick is not Eleandor.

> Because GUI is JASS.
You cannot compare an interface to a coding language. Preferably say "GUI is an graphical interface for JASS".

> The BJ-variables
Variables that have bj_ suffix aren't called BJ's I believe :p. The BJ would be GetLastCreatedUnit().

> This is a variable, also created by Blizzard, but because it doesn't call another function
This makes me feel like there was (a) variable(s) that call functions.

> Now, set can actually set a variable to a return.
What?

... and so on. I suggest you to re-read the whole tutorial, and fix every little mistake there.

I also found it very weird that you have:
Third part - JASS basics.
JASS is basicly made up by functions and variables. Now, in functions, there is "subcategories", named natives and BJs.
Instead of giving information about natives and BJs, you're talking about writing own functions.
 

Sevion

The DIY Ninja
Reaction score
413
Requires:
- Advanced GUI knowledge.
- Advanced WE knowledge.
- NewGen. (The easiest way, but you can also use JASSCraft.)

You don't require 'Advanced GUI knowledge'.

You don't require 'Advanced WE knowledge'.

You don't require NewGen for JASS.

- more efficient.

Only if you know how to use JASS.

Yes, there is goodies and badies - the goodies are stuff named "natives" and the badies are stuff named "BJs". BJs are functions (explained below) that are created by Blizzard (well, everything in JASS is.), which they used for GUI. The reason BJs is badies is:
- they use natives to work.
- they are slower than natives.

Nothing good about BJ's? Riiiiight...... What about "Cleaner Code"? BJ helps with that. And who's going to notice like 0.000001 seconds of delay between a BJ and Native?

Functions.
A function would be the following:
Jass:
call UnitApplyTimedLife(myUnit, myBuff, myDuration)
Now, this is a function - this would be adding a life timer in GUI. So, this function requires:
- myUnit - a unit variable. (doesn't have to be a variable though.)
- myBuff - a buff raw code. (in object editor, press ctrl + d to view raw codes)
- myDuration - this is a real. If I placed "2" in this one, the unit (myUnit) would die after 2 seconds. (just an example.)

That's not a function, that's calling a function.

Globals. (Requires vJASS!)

No.

Creating Events.

Why is that in "Intermediate JASS"?

Should be in Basic.

and the step right now would probably be to learn vJASS.

IMO learning vJASS first is better than learning JASS as to learn JASS, you have to unlearn a lot.
 

Vestras

Retired
Reaction score
248
I don't think I'm gonna change most of those, Sevion, because I think it's the best method. I'm not saying I'm right, I'm just saying that that is what I think.

If I am not mistaken, your nick is not Eleandor.
He/she just wrote it when I wrote it, and my version was crappy. I made everything else.

Variables that have bj_ suffix aren't called BJ's I believe :p. The BJ would be GetLastCreatedUnit().
Surely not, but it's just for the comparing, because then the reader can have it easier to understand, because they are both made by Blizzard, so one big deal.
 

Darius34

New Member
Reaction score
30
Personally, I don't find the tutorial useful in its purpose. It barely touches on the basics of JASS. You're targeting the absolute JASS beginner only assumed to have some GUI experience, and yet you're using jargon and programming terminology in excess, and not actually explaining anything in-depth. For example:

Third part - JASS basics.
JASS is basicly made up by functions and variables. Now, in functions, there is "subcategories", named natives and BJs.
A JASS beginner would ask, "What are functions?" Natives and BJs (and the generally-inconsequential effect of swapping them for optimization) are hardly the important, relevant parts that should be covered here. GUI is not modular, and hence the concept of a function would generally be alien.

Also, in your GC section, you have 1-2 lines of explanation in between relatively large additions of chunks of code. Would a newbie understand the concept of a timer just like that, or that of callback functon? Quite unlikely IMO.

Bluntly put, my point is that your tutorial isn't successful in what it aims to accomplish. An experienced user wouldn't get anything out of it (you're actually covering indentation in a substantial part of the whole tutorial; indenting code is hardly the point!), and a newbie wouldn't understand half of it.

I'm not saying I'm right, I'm just saying that that is what I think.
And if you're just wrong? Sevion makes some good points. There's very little grey area when dealing with definitions.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top