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

[JASS] Some questions, please

Status
Not open for further replies.

Ardenian

A

Ardenian

Hello, I have some questions regarding Jass and I would be glad to receive an answer.

1. One script can have unlimited functions, no matter whether for any purpose or being events, but considering the order that every function you call has to be above the line where you call it, right ?

1.B Can a function be transferred from one trigger to another ? Example, if I call a function in a GUI trigger although it is somewhere in a Jass script ?

2. That being said, do I have to create an actual trigger like a GUI one with Jass ? Couldn't I simply, for a periodic event, for example, add a function that calls another one for the actions ? Why would I have to create an actual trigger ?

3. What can I add to a function that takes something and returns something ? I saw functions taking and returning nothing having actions, but if a function does take and return something, can I add common lines there, like ' set I = I + I' ? Where would they have to be, before returns or after it ?


4. Is it possible to detect particular lines with Jass ?

Example:

If anywhwere in any trigger this line is used:
  • Unit - Add Ability to Unit
Then a function is called.
Can I somehow, without adding anything to the trigger this line is in, detect it is used/executed and call a function ?
Like making an action an event for a function ?


5. Can I check in a function for unlimited arrays ?
This question is a bit complicated, I will try to explain it as good as I can.

Example:
  • set Integer[1] = 1
  • set Integer[2] = 2
  • set Integer[3] = 3
JASS:
//This function should retrieve all integers out of the Integer[ARRAY] variables, but how can I make sure it stops if an Integer[ARRAY] does not exist anymore ( here null) ? I mean, do I have to limit the function checks ( 5 in this example) and check with a condition if == null ?
  • call CalInteger( 1, 2, 3, 4, 5)
How would a function look like ? I forgot how it is built if you would like to add information retrieved, not only calling the function. Do I add it to function ?

JASS:
function CallInteger( integer I, integer A, integer B) takes nothing returns nothing
    set local integer I = udg_Integer[1]
    set local integer A = udg_Integer[2]
    set local integer B = udg_Integer[3]
endfunction
I cannot remember where I add it
 
Level 24
Joined
Aug 1, 2013
Messages
4,658
1, yes

1b, -_- GUI = JASS

2, You have to create actual triggers when you want them to
a, run on events.
b, store a runnable function in array format
c, reset operation limit (reset operation count rather than changing the limit ofc :D)
d, disable/enable a function
e, be able to change the response of any call (either direct call or event) from anywhere in your code
f, be able to run a specific function from anywhere in your code (by running the trigger)
(and maybe a few more)

3, a return statement prevents all the remaining stuff in the function from running (lets not take a look at stuff like "finally blocks" because they dont exist in JASS) anything that is placed after the return statement will not be executed.

A function can have parameters and a return type+value.
When you want to load some data or convert some data by a function, you return the value by a return statement inside that function.
If you want a function to do his actions relative on some variables that can change at any time, you most probably want to give them as parameters which basically make local variables out of it and set them to the given values at the function call.

"set I = I + 1" is a very vague statement.
I can be a global variable, I can be a local variable or I can be a parameter (which is the same a local variable).
In any case, this would run properly.
If I is none of the above, this will return an error in the JASSHelper.

4, In any code language, this is a pretty silly thing... until you use something like an editor which you cannot really modify.
So in our case, it actually does exist. It is called a hook.
A hook, hooks a function to any non-native function to every place in your code. (Please note that the declaration still has to be above the call.)
JASS:
hook foo blablabla

function foo takes integer id, real value returns string

endfunction

function blablabla takes integer id, real value returns string

endfunction
//Every time "foo" is called, "blablabla" will be called before that with the same parameters.

A hook will always run before the actual function you hooked your function on.
You cannot prevent the "foo" from running except if you have a thread crash inside "blablabla".
 

Ardenian

A

Ardenian

Thank you!

1B So a function call in a GUI Conf trigger would successfully call a function from a Jass script ?

2. Alright!

3. Hm, that means:

JASS:
function DoubleInteger takes integer I returns I*2
    set local integer I = udg_Integer
returns 
endfunction
would work, but not:
JASS:
function CallInteger takes integer I returns I*2
returns 
    set local integer I = udg_Integer
endfunction

4. Does that mean I cannot retrieve information from the hooked action ?

In my example, could not retrieve what ability was added, since the function calls before the actual GUI action ?

5. okay, this question is mixed up. To clarify, how do I build a function so I can write that:
  • call CallFunction( Boolean, integer, integer, real)
ìn GUI ?
 
Level 17
Joined
Dec 11, 2014
Messages
2,004
Oh my.

JASS:
function DoubleInteger takes integer I returns I*2
    set local integer I = udg_Integer
returns 
endfunction
would work, but not:
JASS:
function CallInteger takes integer I returns I*2
returns 
    set local integer I = udg_Integer
endfunction

That will have errors. BOTH.
First, you can't create a local local. When you give a function a Parameter (integer I), it's already local.
Second, returns and return:
JASS:
function sth returns nothing
returns // this is wrong
return // this is right
// you use "returns" for function sth returns nothing and "return" for inside the function. else, there will be errors.
endfunction

Third, the "returns" part should be followed by a Variable type, like integer, boolean or etc. If you need to return I*2, use:
JASS:
function Test takes integer i returns integer
return i * 2 // notice the space between. You can use spaces for better understanding from what you write.
endfunction

Fourth, empty return is EXACTLY:
  • Skip remaining actions
So if you have a "returns sth" at the top of the Function you have to use:
JASS:
return sthfrommyvartype
else, returns nothing, you will have empty returns, like:
JASS:
return // done. nothing more

Anything under "return" won't run. No errors.

Fifth, for "call CallFunction( Boolean, integer, integer, real)":
JASS:
function CallFunction takes boolean flag, integer i, integer i2, real r returns nothing
 //I Hope this doesn't return.
 if flag == true then
 call BJDebugMsg("This be true, mon.")
 else
 call BJDebugMsg("This be false, mon.")
 endif
set udg_i = i * 2 // Examples!
set udg_i2 = i2 / 5 // Examples!
set udg_real = Atan2(r) // Examples!
endfunction


======
SO:

JASS:
function ultimatetest takes integer i returns integer
 local integer i // is wrong. don't use.
call BJDebugMsg("This WILL run. (I used a bj, but you don't!)")
return i * 2 // spaces!
call BJDebugMsg("I won't run. I have already returned, why should I bother?")
endfunction


Also hook is vJASS, and maybe not THAT useful for beginners and maybe confusing. Let's forget that for now.
 

Ardenian

A

Ardenian

Alright, thanks.

So this will work:

JASS:
function DoubleInteger takes integer I returns integer
    set i = i + 3
return i * 2
endfunction

How do I set locals outside a function, if it is not a function parameter ?
 
If you want to call a function periodicly you don't need a trigger in JASS,
but can go with a timer that fires periodicly. A timer in JASS is directly able to run a function when expired.

Locals outside function are no locals, so do not exist.

JASS is case senitive, in your "DoubleInteger" function you must operate with "I" not with "i".
Also it does I + 3 then I *2 instead of only double it, but I think you see it?^^.
 

Ardenian

A

Ardenian

Is there an example how that timer code looks like ?

Uh, I meant inside a function, but not as a parameter of the function.

Uh, it is supposed to be i + 3 and that value is doubled with*2, what do you refer to ?
 
Level 24
Joined
Aug 1, 2013
Messages
4,658
1b, Yes.

2, I guess Arad explained it well enoug.

4, I missed something, hooks can ONLY be applied on Common.j (natives) or Blizzard.j functions.

5, you cant.
You cant make a function in GUI.
You can however make it in custom scripts but I ensure you that you dont want to do that.
In any case, the syntax is the same as any other function:
JASS:
function CallFunction takes boolean b, integer i, integer i2, real r returns nothing
endfunction



Yes the function you have now would work properly.
However, I do recommend the return I to be of proper align with the other statements.

When you create a block of code, you tab everything inside the block one place further.
When you end a block of code, you tab back to normal.
So:
JASS:
library Lib
    
    function foo takes nothing returns nothing
        local integer i = 0
        
        call BJDebugMsg("Test")
        loop
            exitwhen i > 10
            call BJDebugMsg(I2S(i))
            set i = i +1
        endloop
        
    endfunction
    
    function foo2 takes nothing returns nothing
        local real r = 1/0
    endfunction
    
endlibrary

You see "library", "funciton", "loop" creating a new block of code so everything inside it will be tabbed one tab further.
Other block statements are "if", "method", "globals", "scope", "struct" (and maybe a few more).

Also, spacing (and empty lines as well) are more user preference than basic standard.
Some people will tell you to place a space between everything, other people will tell you to use them when you want to show that things are separate:
JASS:
function calculate takes real a, real b, real c returns real
    return a*2 + b / (c-10)
endfunction
Note the spaces around the "+" to clarify that b/(c-10) will run as its own block (we all know how it works).

Empty lines are sometimes used horribly, but in most cases, you really want them.
Use them to separate different pieces of code that have a different meaning.
Use them at the beginning/end of a block if not breaking the rule above.
Use them to simulate switch cases:
JASS:
function GetAttackType takes string attackTypeName returns attacktype
    
    if attackTypeName == "ATTACK_TYPE_CHAOS" then
        return ATTACK_TYPE_CHAOS
        
    elseif attackTypeName == "ATTACK_TYPE_HERO" then
        return ATTACK_TYPE_HERO
        
    elseif attackTypeName == "ATTACK_TYPE_MAGIC" then
        return ATTACK_TYPE_MAGIC
        
    elseif attackTypeName == "ATTACK_TYPE_MELEE" then
        return ATTACK_TYPE_MELEE
        
    elseif attackTypeName == "ATTACK_TYPE_NORMAL" then
        return ATTACK_TYPE_NORMAL
        
    elseif attackTypeName == "ATTACK_TYPE_PIERCE" then
        return ATTACK_TYPE_PIERCE
        
    elseif attackTypeName == "ATTACK_TYPE_SIEGE" then
        return ATTACK_TYPE_SIEGE
        
    endif
        return null
        
endfunction
(Also note the return null be one tab further than normal, but that is just my preference when having a "switch case". It is all about user preference after all.)

You cannot set locals outside of a function.
That is not what you want to use locals for.
For that, you have globals.
Locals basically mean that you can have this function run multiple times but having different values for each instance.



call StartTimer(CreateTimer(), 1, true, function foo)
This will create a new timer that runs repeatedly with an interval of 1 second that runs "foo" each time it expires.
(Ofcourse, you can use a timer variable.)

Inside a function, you declare local variables like this:
JASS:
function foo takes nothing returns integer
    local integer i
    local integer i2 = 2
    
    set i = 2
    
    return i2 * i
endfunction
You first place the "local" keyword, followed by the variable-type, followed by the name of the variable and optionally an initial value.
Be aware that referring to variables that have no value (not null, but no value at all) will crash the thread.

The function is named "DoubleInteger", which makes us think that it will double the integer, but instead it adds 6 to it as well, so the title is not really discribing what it does.
Which is a glitch :D (It won't give an error or crash but still has undesired results.)
 
Level 17
Joined
Dec 11, 2014
Messages
2,004
JASS:
function DoubleInteger takes integer I returns integer
    set i = i + 3
return i * 2
endfunction

I'd prefer to change it to:

JASS:
function DoubleInteger takes integer I returns integer
return (i + 3) * 2
endfunction

When using a TimerStart, you should put a function at the code parameter that takes nothing and returns nothing. Wietlol, how did you miss that?


Also I think you should put vJASS away for now, It's too hard to understand for new people to JASS (All those Structs, Globals, Methods, Scopes, Libraries, static, private, public, "." between name of a call (related to structs) and etc.).
 
Level 24
Joined
Aug 1, 2013
Messages
4,658
I'd prefer to change it to:

JASS:
function DoubleInteger takes integer I returns integer
return (i + 3) * 2
endfunction

No you dont.
You want it to be:
JASS:
function DoubleInteger takes integer i returns integer
    return (i+3) * 2
endfunction
*parameter name I -> i
*return statement tab +1
*spacing changed to represent the order of which the calculations are done.
 
Level 24
Joined
Aug 1, 2013
Messages
4,658
When using a TimerStart, you should put a function at the code parameter that takes nothing and returns nothing. Wietlol, how did you miss that?
It indeed requires you to not have parameters, but you can return something... however, it is useless when executed from the timer.

Also I think you should put vJASS away for now, It's too hard to understand for new people to JASS (All those Structs, Globals, Methods, Scopes, Libraries, static, private, public, "." between name of a call (related to structs) and etc.).
I was only naming some code block (key)words.
The actual implementation is irrelevant.
 

Ardenian

A

Ardenian

4. Uh, that means ? I can use this as orientation what works and what doesn't ?

5. Ah yes, that is what I was searching for, thank you!

So, a library allows me to call a function form anywhere, but if I don't use it, but a simple function, I would have to copy it in the map header to make it work, right ?

Alright, thank you guys for clarification!
 
Level 24
Joined
Aug 1, 2013
Messages
4,658
4, well, there is a slightly easier way to check it.
In JASS (if you have TESH), natives and BJ functions are highlighted.
Your custom functions are not.
Highlighted functions (except sharpcraft functions... which you dont use at all for the upcoming months) can be used.

What happens when you save the map is that all your GUI triggers will be converted to JASS and all JASS scripts will then be placed under each other.
Then the functions have to be declared before they are used.
The header of a map is placed above all other triggers which ensures that the functions there will be able to be called from any other script in your map.

A library goes even further.
It will place the code inside the library even higher than the header so you can use anything from anywhere in your map (even the header).

When you have multiple libraries, you can do library Lib1 uses Lib2 which makes Lib2 be placed above Lib1 so Lib1 can use functions from Lib2.
Ofcourse, you cannot use Lib1 in Lib2 with this.

Ofcourse you only want to use the header file (preferably not) or a library when you want any code to access the function.
For example, it is really good to have your "Math" functions inside a library named "Math" (or something meaningfull).
But when you have a spell and your spell uses a function very specifically for that spell, then you dont have to place it in a library.
There is no need for it at the very least.
 

Ardenian

A

Ardenian

Ah I understand, thank you! Sad libraries are only available in vJass.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,287
1. One script can have unlimited functions, no matter whether for any purpose or being events, but considering the order that every function you call has to be above the line where you call it, right ?
If called directly. You can call them via other means in an order independent way. For example you can pass arguments with register global variables and then use the special run time call native which takes a string of the function name to call.

1.B Can a function be transferred from one trigger to another ? Example, if I call a function in a GUI trigger although it is somewhere in a Jass script ?
What you are asking does not make any sense. Functions can be called anywhere as long as they are declared above where you are calling them from.

The map script is generated in order of decleration. This means that the far top node in GUI becomes the top of the user generated section while the far bottom trigger becomes the end of the user generated section. Above the user generated section are various initialization calls (drop tables, global variables etc) with the far top of the script always being global variable declarations. Below the user generated section are various auto generated functions that deal with map initialization and even lobby initialization. There is also the main trigger initialization function which in turn calls all separate trigger initialization functions during map load.

Generally you will be defining two types of function.
  • Single use functions which will only be bound or called by a single site with very specific purposes. An example being trigger initialization, conditions and actions.
  • Multi use functions which will be called by many sites to perform a generic purpose. An example being a Ln (log natural) function implementation which may be used by many trigger enhanced abilities, formula or miscellaneous purposes.

2. That being said, do I have to create an actual trigger like a GUI one with Jass ? Couldn't I simply, for a periodic event, for example, add a function that calls another one for the actions ? Why would I have to create an actual trigger ?
Triggers are entry points to running JASS script. Specifically they create a thread when an event occurs. For some events (eg periodic 1 second trigger) it becomes more efficient to execute several jobs in the same thread as the thread creation overhead for triggers is quite large. If each function does a job and you want that job run every same period then calling all of those functions in response to a single periodic event is far more efficient than having separate periodic events for each.

You want separate triggers when you do not want to couple the execution of code together. For example a missile system and a lightning system will want different triggers for their periodic update despite sharing the same period since there can be a situation where there are only missiles and no lightning meaning that only missile code should be running every period.

Another situation you want separate triggers is if you are having operation limit issues and do not care about performance. Each time a trigger executes it creates a separate thread and hence separate operation limit. If you run too much on a single trigger execution the thread will crash due to hitting the operation limit. If you cause the code to run off multiple triggers you can bypass this limit. In the case of simple loop iteration this can be very useful as those have minimal performance overhead and eat into the operation limit quite badly. In the case of more complex operations such as unit movement doing this will generally cause the game to become unresponsive for multiple frames which is bad for user experience.

3. What can I add to a function that takes something and returns something ? I saw functions taking and returning nothing having actions, but if a function does take and return something, can I add common lines there, like ' set I = I + I' ? Where would they have to be, before returns or after it ?
Obviously before the return. Once execution processes the return the function is exited and execution resumes from where it was called. If the entry point was a trigger or timer then the thread effectively terminates.

Most languages will warn you or even throw a syntax error if you try to run code after a return.

4. Is it possible to detect particular lines with Jass ?
If the data for the lines is placed into some data structure then you can use one of many line intersection algorhtims to detect any overlap.

If you mean "is it possible at runtime for JASS to get specific lines from one of its parsed scripts as a string?" then no it is not. JASS does not support file I/O, at least of this type.
 

Ardenian

A

Ardenian

Thank you, Dr Super Good, for the detailed explanation.

For 1B: I only have to make sure the Jass script is above the GUI conf in order ( e.g.) ? Then I can call function with a custom script using GUI ? ( the other way would be to copy it into the map header)

For 4.: So it is not possible to hook a particular struct, like:
JASS:
native UnitAddAbility               takes unit whichUnit, integer abilityId returns boolean
and get the ability of this struct, for example, every time it is used anywhere in the whole triggers ?
 
Level 24
Joined
Aug 1, 2013
Messages
4,658
There is no struct.
There has never been a struct.
And there will never be a struct.

Apart from that...
JASS:
function foo takes unit whichUnit, integer abilityId returns boolean
    call BJDebugMsg(GetUnitName(whichUnit) + " has gained the ability " + GetObjectName(abilityId))
endfunction

hook UnitAddAbility foo
 
Level 24
Joined
Aug 1, 2013
Messages
4,658
Let me rephrase myself:
"There is no struct involved in the question that you asked in this thread related to hooks, natives and triggers that is relevant to the answer provided by either me, DSG or anyone else.
There has never been a struct involved in the question that you asked in this thread related to hooks, natives and triggers that is relevant to the answer provided by either me, DSG or anyone else.
And there will never be a struct involved in the question that you asked in this thread related to hooks, natives and triggers that is relevant to the answer provided by either me, DSG or anyone else."

But I don't like writing so:
"There is no struct.
There has never been a struct.
And there will never be a struct."
 
Status
Not open for further replies.
Top