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

Status
Not open for further replies.
Level 24
Joined
Aug 1, 2013
Messages
4,658
GetEnumUnitsInRange() doesnt exist.
GroupEnumUnitsInRange() however, clears the group and fills it with the units in that area.

When you have a group of units (no matter how they are created and filled), you can do a loop on it, it be ForGroup() or FirstOfGroup iterations, but be aware that with FirstOfGroup, you will clear the group you loop over.
So in that case, you either have to recreate the group if you want to use it later again, or use a swap group.
 
Level 20
Joined
Jul 14, 2011
Messages
877
GroupEnumUnitsInRange will just fill up a group, it doesnt really matter how, where or when you do it, as long as the group exists. If you you loop through an empty group, you wont find anything but you wont have any problems (afaik).

You can but keep in mind that the group will be emptied after a FoG loop.
If you need to reuse it, then use ForGroup.

E: Oh, I didnt see there was a 2nd page, my bad
 
Level 13
Joined
Jan 2, 2016
Messages
978
Say, is there a way to get random N units from a group, using the FoG method?

Right now I'm doing:
using FoG loop to filter the units matching condition, and I add them to ANOTHER group, and then I use "ForGroup" with "RandomSubGroup" to do the rest.

Is there any way to do this with only 1 or 2 FoG loop(s)?
 
Level 12
Joined
May 22, 2015
Messages
1,051
Say, is there a way to get random N units from a group, using the FoG method?

Right now I'm doing:
using FoG loop to filter the units matching condition, and I add them to ANOTHER group, and then I use "ForGroup" with "RandomSubGroup" to do the rest.

Is there any way to do this with only 1 or 2 FoG loop(s)?

I think the best strategy might be to move all the units into an array. Loop over the group once, destroying it, and add each unit into an array (using a counter variable to put them in different indexes and also so you know how many there are at the end).

Then you can just pick out N random ones and add them to a new unit group to process.
 
Level 12
Joined
May 22, 2015
Messages
1,051
Hmm, isn't what you suggest kind a heavier than what I'm doing? (I have no idea which functions are heavy and which aren't, but what you suggest seems to have more actions/function calls)

I am not certain what you are doing, currently.

All I know is that the "get random unit from unit group" blizzard.j function uses an O(n) algorithm (loops over the whole group) every time you call it. If you are using that, it is a fairly expensive call and my method is most likely much faster.

The blizzard.j function also undoubtedly uses ForGroup instead of a FirstOfGroup which makes it even more slow.
 
Level 13
Joined
Jan 2, 2016
Messages
978
Gosh, why doesn't this work?
JASS:
    call GroupEnumUnitsInRange( p[0] , x , y , 600 , null)
    loop
        set FoG = FirstOfGroup( p[0] )
        exitwhen FoG == null or count >= 3
        if IsUnitInGroup(FoG, p[3]) == false and IsUnitEnemy( FoG , GetOwningPlayer(c)) == true then
            call IssueTargetOrderBJ( d , "acidbomb", FoG )
            call BJDebugMsg("asd")
            set count = count + 1
            if IsUnitInGroup(FoG, p[1]) then
                call GroupAddUnit(p[2] , FoG)
                call GroupRemoveUnit(p[1], FoG)
            else
                if IsUnitInGroup(FoG, p[2]) then
                    call GroupAddUnit(p[3], FoG)
                    call GroupRemoveUnit(p[2], FoG)
                else
                    call GroupAddUnit(p[1], FoG)
                endif
            endif
            call GroupRemoveUnit(p[0], FoG)
        endif
    endloop

When I put // before the condition and before the endif - it kind a works (but it targets allies too)

I tried to conditions seperately. Each condition works, but why don't they work together?

JASS:
    call GroupEnumUnitsInRange( p[0] , x , y , 600 , null)
    loop
        set FoG = FirstOfGroup( p[0] )
        exitwhen FoG == null or count >= 3
        if IsUnitInGroup(FoG, p[3]) == false then
            if IsUnitEnemy( FoG , GetOwningPlayer(c)) == true  then
                call IssueTargetOrderBJ( d , "acidbomb", FoG )
                call BJDebugMsg("asd")
                set count = count + 1
                if IsUnitInGroup(FoG, p[1]) then
                    call GroupAddUnit(p[2] , FoG)
                    call GroupRemoveUnit(p[1], FoG)
                else
                    if IsUnitInGroup(FoG, p[2]) then
                        call GroupAddUnit(p[3], FoG)
                        call GroupRemoveUnit(p[2], FoG)
                    else
                        call GroupAddUnit(p[1], FoG)
                    endif
                endif
            endif
            call GroupRemoveUnit(p[0], FoG)
        endif
    endloop

This works.....
 
Level 12
Joined
May 22, 2015
Messages
1,051
Not certain why - I'd maybe have to look into it more.

Anyway, call IssueTargetOrderBJ( d , "acidbomb", FoG ) can be replaced with IssueTargetOrder( FoG , "acidbomb", d ) and it won't be any different - it will run very slightly faster lol.

if IsUnitInGroup(FoG, p[3]) == false then => if not IsUnitInGroup(FoG, p[3]) then
if IsUnitEnemy( FoG , GetOwningPlayer(c)) == true then => if IsUnitEnemy( FoG , GetOwningPlayer(c)) then
 
Level 13
Joined
Jan 2, 2016
Messages
978
Another question:
Is it better if I keep creating and destroying timers, or should I re-use the ones I've already created?
With the 1-st way I could keep like 10 at the same time, while with the 2-nd method the timers could reach amount larger than 100, or even 200.

So my actual question is - Is it better to have an abundance of timers that aren't being used, or should I create/destroy timers all the time?
 
Level 12
Joined
May 22, 2015
Messages
1,051
Another question:
Is it better if I keep creating and destroying timers, or should I re-use the ones I've already created?
With the 1-st way I could keep like 10 at the same time, while with the 2-nd method the timers could reach amount larger than 100, or even 200.

So my actual question is - Is it better to have an abundance of timers that aren't being used, or should I create/destroy timers all the time?

Main thing is that you have to properly reuse them. I think it is supposed to be more efficient if you do recycle them, but you have to do some set up for that.

I think TimerUtils or whatever it is called does exactly this in the background (it is a library if I understand correctly). You get new functions that will give you a timer and "destroy" a timer and they recycle automatically (just puts it into some recycle queue most likely).
 
Level 20
Joined
Jul 14, 2011
Messages
877
You remove the unit from the group inside the if:
JASS:
if IsUnitInGroup(FoG, p[3]) == false and IsUnitEnemy( FoG , GetOwningPlayer(c)) == true then
    ...
    call GroupRemoveUnit(p[0], FoG)
endif
and
JASS:
if IsUnitInGroup(FoG, p[3]) == false then
    if IsUnitEnemy( FoG , GetOwningPlayer(c)) == true  then
        ...
    endif
    call GroupRemoveUnit(p[0], FoG)
endif

Difference is, that in the second one you remove the unit if its not in the group, regardless of the second condition (which still isnt right).
To fix this do:
JASS:
if IsUnitInGroup(FoG, p[3]) == false and IsUnitEnemy( FoG , GetOwningPlayer(c)) == true then
    ...
endif
call GroupRemoveUnit(p[0], FoG)

Also, I see you are using an array of groups. Keep in mind that the first of group method empties the whole group.
About the timer recycling, you should use TimerUtils, CTL and/or TimerTools (all are in vJASS).
Personally, I have only used TimerUtils but I am pretty sure the other two have similar uses (correct me if I am wrong).
 
Level 24
Joined
Aug 1, 2013
Messages
4,658
Creating/Destroying handles is pretty heavy for WC3.
So "CreateUnit()", "CreateTimer()", "CreateTrigger()", "Location()", "CreateGroup()", "RemoveUnit()", "DestroyTimer()", "DestroyTrigger()", "RemoveLocation()", "DestroyGroup()", etc.
Location is an odd one out but I assume it also counts in this list because it is also an agent.

In any case, it is almost impossible to completely recycle units.
Triggers is also impossible because you cant remove events from it.
But groups, locations, timers, texttags, etc, can all be recycled to gain efficiency from it.

Simply said, you create a timer like you would do normally.
When you dont need it any more, you remove it.
However, instead of destroying it, you put it on pause and place it in a list.
Then whenever you want to get a new timer, you simply ask the list if there are any available ones. If so, then you remove it from the list and use that timer as your "newly created" timer. If the list is empty, you just create a new one.

Aka, use TimerUtils :D
 
Level 13
Joined
Jan 2, 2016
Messages
978
Well, from the way you described it, wouldn't it be pretty easy to make such "system" myself?
Instead of "call DestroyTmer(t)" I can just do
JASS:
function TimerSave takes timer t returns nothing
    set udg_T_Count = udg_T_Count + 1
    set udg_F_Timers[udg_T_Count] = t
    set t = null
endfunction
And when I need another trimer - I can just do
JASS:
function GetFreeTimer takes nothing returns timer
    if udg_T_Count > 0 then
        set udg_T_Count = udg_T_Count - 1
        return udg_F_Timers[udg_T_Count + 1]
    else
        return CreateTimer()
    endif
endfunction
That's pretty much it, isn't it?
 
Last edited:
Level 24
Joined
Aug 1, 2013
Messages
4,658
That is indeed recycling handles...
Except one small thing.

JASS:
function foo takes nothing returns nothing
    local timer t1 = GetFreeTimer()
    local timer t2 = t1
    
    call TimerSave(t1)
    call TimerSave(t2)
endmethod
Can you imagine what that does?
You should really remake your code if you code like that but still.

Or what would happen when you save more than 8192 timers (you then have a BIG ASS MAP but still).

But yea thats it.
TimerUtils also creates something special... a timer data.
It is an integer that you can store on the timer using a hashtable or Table (lets ignore that array part).
It is pretty useful like a unit indexer, an item indexer, etc.

And the difference between TimerUtils and your script is that TimerUtils already exists for a long long time.
It will do exactly what you did, maybe a bit more efficient even so there is not really a reason to make it yourself. (Yes I do have a modified version of TimerUtils myself :D)

But basically, there are so many systems that use TimerUtils that you will have to install it anyway, then you can better use TimerUtils right from the start.
 
Level 13
Joined
Jan 2, 2016
Messages
978
Well, why the hell would I do that? (setting 2 different variables to the same timer and "saving them" with this function).
Anyways.. I just wrote these scripts for the forum, don't have such functions on my map(s) yet. It would probobly be an improved version of this, and most likely will be using a hashtable, and timers would have Child hashtables too, with a boolean, that tells if they've already been saved or not.

Anyways.... I have 3 more questions now (tho they aren't so much JASS related):
1) What exactly happens when someone tries to save a variable into an array [8192] or above?
2) If I load a variable from an empty child hashtable - I don't need to clear the child hashtable after that, right? It doesn't create an 'artificial' variable into the field it's trying to load it from, or does it?
3) In one hashtable if parent '1' has a boolean saved in its '0', can I save a real (or anything different than boolean) in '2's '0'?
 
Level 24
Joined
Aug 1, 2013
Messages
4,658
1, then the game crashes iirc.
If you store something on [8191], then save the map, restart WC3 and load the map, it also did something wrong... either crash when you would read it or it would be reset to the default value.
2, you cant load stuff from something that is empty... can you?
3, a hashtable is simply a table, so a 2 dimensional array.
If you store something under the same x and the same y (same parent, same child), then it would overwrite it... if you use different values for either or both, then you are storing them under different slots.
 
Level 13
Joined
Jan 2, 2016
Messages
978
2) Well, it loads nulls / 0's. It's kind a odd, tho. On one map, when I was trying to load a boolean from an empty table - it was giving me neither true, neither false (in an if, with the boolean as a condition). However, lately I've been getting 'false' when loading booleans from empty table, so I'm kind a confused.
Ofc when I wasn't getting neither true, neither false, I was worse than I am now at script writing, so it's possible that I've had some 'other' mistake, but then, when I started setting the boolean to false before loading it - the function was runing normally...

EDIT:
JASS:
function RecTimer takes timer t returns nothing
    local integer i
    if not LoadBoolean(udg_Table, GetHandleId(t), 0 ) then
        set i = LoadInteger(udg_Table, 0 , 0 ) + 1
        call SaveTimerHandle(udg_Table, 0 , i , t )
        call SaveInteger(udg_Table, 0 , 0 , i)
        call SaveBoolean(udg_Table, GetHandleId(t), 0 , true)
    endif
    set t = null
endfunction

function GetFreeTimer takes nothing returns timer
    local integer i = LoadInteger(udg_Table, 0 , 0 )
    if i > 0 then
        call SaveInteger(udg_Table, 0 , 0 , i-1)
        call SaveBoolean(udg_Table, GetHandleId(LoadTimerHandle(udg_Table, 0 , i)), 0 , false)
        return LoadTimerHandle(udg_Table, 0 , i )
    else
        return CreateTimer()
    endif
endfunction
How's that version of it?

EDIT 2:
Another question: Is there a way to detect an event "A unit is 'removed' " without having to set a real to 1 and then to 0 every time I remove a unit with a trigger.
 
Last edited:
Level 13
Joined
Jan 2, 2016
Messages
978
JASS:
function GroupCheck takes unit u, integer i returns boolean
    local integer looop = 1
    set udg_Temp_Unit = u
    set u = null
    loop
        exitwhen looop > 9
        if IsUnitInGroup(udg_Temp_Unit, udg_Mag_Cluster_Group[(12*looop)+i]) then 
            return true
        endif
        set looop = looop + 1
    endloop
    return false
endfunction

Will the loop continiue if any of the values is true, or will it stop looping?

I actually found a better way to do it, that wouldn't break the game for sure, but I'm still wondering how would the 1-st function react :p
JASS:
function MC_GroupAdd takes unit u, integer i returns nothing
    local integer looop = 1
    local boolean b = false
    loop
        exitwhen looop > 9 or b == true
        if IsUnitInGroup(u, udg_Mag_Cluster_Group[(12*looop)+i]) then
            set b = true
        endif
        set looop = looop + 1
    endloop
    if not b then
        call GroupAddUnit(udg_Mag_Cluster_Group[12+i], u)
    endif
    set u = null
endfunction
 
Level 24
Joined
Aug 1, 2013
Messages
4,658
Returning in a function will cause that function to stop at once.
All actions placed after a return will not be called.
(In some languages, you have a "finally"(Java) block that would allow you to run some code even if there is something returned... dunno why Java needs something like that though :D)

"set u = null"
That is not necessary.
Variables that are passed in as parameters do not necessarily have to be nulled.
So that also means you dont need the global unit variable.

"looop" should be "i"
"i" is often used as iterator in a loop.
So for simplicity, readability reasons, you should be changing the name to "i"
"integer i" in the parameters on the other hand tells you nothing about what it is.
I see it is the offset in "udg_Mag_Cluster_Group"'s index, so the name should be representing something more to that group.

The difference between these is that one of them is only a local variable that is created and used within the actual function. The other is a variable name given to a parameter which would be used by other parts of the code.
 
Level 24
Joined
Aug 1, 2013
Messages
4,658
I dont understand your first question.
I guess you cant because it already happens.

Player selection is unfortunately done locally so has to be synced to do it properly.
But yes, there is a function that fills a group with the selection of a certain player.
Then checking if the unit is inside that group would do what you need.
Be aware that this will have a slight delay in the script and causes it to run asynchroneously.
 
Level 13
Joined
Jan 2, 2016
Messages
978
About my 1-st question:
I re-worked my sliding system to use timers - I'm starting a timer, and saving the unit, angle, and distance into it, instead of saving speed, angle, and time remaining into the unit's hashtable, and putting the unit into a unit group.
Anyways.. for my new system to work - I need to put the timer's function into the Map's Custom Scripts, (so I wouldn't have to put them into every trigger that is going to use sliding).
But I started putting more functions into the Map's Custom Script, and it started becoming a bit messy, so I wanted to organise things a bit, and take out the functions from there, and put them into "normal" triggers (I think I mean "tigger blocks", but not sure if that's the right term).

And about my 2-nd question:
I want to re-add a unit to the player's selection, after it's revived ONLY if the player had it selected before that.
Can ya write the functions that I need to use for that?
 
Level 24
Joined
Aug 1, 2013
Messages
4,658
There is no such thing as "Map's Custom Scripts".
I think you mean the header script.
In that case, you can just create a normal trigger and convert it to custom text.
Then you can use that one instead.
GUI triggers are not really JASS friendly though.

You would have to use a DDS that can check when a unit is going to die...
Aka the moment BEFORE "A unit dies" runs.
On that event, you can check if that unit is in the player's selection.
You can store that and read it out when that unit revives.
 
Level 13
Joined
Jan 2, 2016
Messages
978
Naah, it works without a DDS too:
I have "A unit dies" as event and:
local boolean b = IsUnitSelected(u,p)
and later on when I have:
if b then
call SelectUnitAddForPlayer( u, p )
endif

it works just as its supposed to :)

EDIT: Another question: What is "SuspendTimeOfDay()" returning? I know it returns a boolean, but what is the MEANING of this boolean?
Is it "true = Day and false = Night", or something like that?
If it does mean that - Does it change when a player uses an item, which turns day to night, and does it change back its value when this effect is over?
Else - Is there any way to check if it's day or night?
 
Last edited:
Level 13
Joined
Jan 2, 2016
Messages
978
Hmm... what do I need to write as string when I use GroupEnumUnitsByType(group, string, filterFunc). I tried to write the unit's name, but didn't work...

Also, how can I detect when day changes into night, without having a periodic check? I figured that bj_dncIsDaytime gives me if it's day or night, but I don't know how to detect it changing (without periodic timer). Note that I also want to detect when a player uses an item/ability that changes day to night with the same trigger.
 
Level 12
Joined
May 22, 2015
Messages
1,051
Hmm... what do I need to write as string when I use GroupEnumUnitsByType(group, string, filterFunc). I tried to write the unit's name, but didn't work...

Also, how can I detect when day changes into night, without having a periodic check? I figured that bj_dncIsDaytime gives me if it's day or night, but I don't know how to detect it changing (without periodic timer). Note that I also want to detect when a player uses an item/ability that changes day to night with the same trigger.

Not sure exactly how that function works, but unit type comparison is usually done with the unit type ID - an integer that is written like 'h001'. You can see it by doing ctrl + d in the object editor and it will appear beside the unit's name.

Not sure how to do the day / night thing, but the timing would be consistent, wouldn't it? The only time it would not be exactly matching on a periodic timer is if you use the eclipse spell (whatever the night elf item thing is) or if you manually stop it.
 
Level 13
Joined
Jan 2, 2016
Messages
978
JASS:
function UpdateEachStockBuilding takes itemtype iType, integer iLevel returns nothing
    local group g

    set bj_stockPickedItemType = iType
    set bj_stockPickedItemLevel = iLevel

    set g = CreateGroup()
    call GroupEnumUnitsOfType(g, "marketplace", null)
    call ForGroup(g, function UpdateEachStockBuildingEnum)
    call DestroyGroup(g)
endfunction
This is a blizzard.j function that uses GroupEnumUnitsofType, so I guess it's not the UnitTypeId that I should be using.
 
Level 12
Joined
May 22, 2015
Messages
1,051
JASS:
function UpdateEachStockBuilding takes itemtype iType, integer iLevel returns nothing
    local group g

    set bj_stockPickedItemType = iType
    set bj_stockPickedItemLevel = iLevel

    set g = CreateGroup()
    call GroupEnumUnitsOfType(g, "marketplace", null)
    call ForGroup(g, function UpdateEachStockBuildingEnum)
    call DestroyGroup(g)
endfunction
This is a blizzard.j function that uses GroupEnumUnitsofType, so I guess it's not the UnitTypeId that I should be using.

That is so weird. I've never used that function before. Since it is all lower case, though, it leads me to believe that it might be similar to order strings. Maybe there is some field that holds that somewhere.
 
Level 24
Joined
Aug 1, 2013
Messages
4,658
It kind of works as classifications.
JASS:
function Trig_Test_Actions takes nothing returns nothing
    local group g = CreateGroup()
    local unit FoG
    local integer i = 0
    local string unitname = "footman"
    
    call GroupEnumUnitsOfType(g, unitname, null)
    loop
        set FoG = FirstOfGroup(g)
        exitwhen FoG == null
        call GroupRemoveUnit(g, FoG)
        
        call UnitApplyTimedLife(FoG, 0, 0.01)
    endloop
    
    call DestroyGroup(g)
    set g = null
endfunction

//===========================================================================
function InitTrig_Test takes nothing returns nothing
    set gg_trg_Test = CreateTrigger(  )
    call TriggerAddAction( gg_trg_Test, function Trig_Test_Actions )
endfunction
Place a few footman (normal ones) on the map and watch them die.
However, if you change the name of those footman... they still die.

On the other hand, creating a custom unit based on the footman, without modified fields, will not die...
So I guess the names are linked to their object type ids... kinda.
At least it is done in reverse path than normal classifications, so it is pretty useless.

It may actually have multiple unit types based on the same string or have some serious stuff about custom units, then it gets interesting.
However, I prefer to have things of which I know what they do.
 
Level 20
Joined
Jul 14, 2011
Messages
877
Correct me if I am wrong but didnt GroupEnumUnitsOfType leak?

Also, according to this post, all unit's names are the defaults in lower case, and those of the custom ones are "custom_" + rawcode.
Apparently UnitId2String doesnt work after a save game is loaded which sucks (next post, same thread).
 
Level 24
Joined
Aug 1, 2013
Messages
4,658
Correct me if I am wrong but didnt GroupEnumUnitsOfType leak?

Not exactly.
There are a few threads about it but I can see why you are thinking it actually leaks.
Im happy to tell you... I literally have no idea... sort of.

What I can say that leaks is this:
  • Unit Group - Pick every unit in (Units of type Rifleman) and do (Actions)
The difference is that this function is actually this:
JASS:
function GetUnitsOfTypeIdAll takes integer unitid returns group
    local group   result = CreateGroup()
    local group   g      = CreateGroup()
    local integer index

    set index = 0
    loop
        set bj_groupEnumTypeId = unitid
        call GroupClear(g)
        call GroupEnumUnitsOfPlayer(g, Player(index), filterGetUnitsOfTypeIdAll)
        call GroupAddGroup(g, result)

        set index = index + 1
        exitwhen index == bj_MAX_PLAYER_SLOTS
    endloop
    call DestroyGroup(g)

    return result
endfunction
And for those who cannot see the leak or are unfamiliar with it.
Agents that are pointed to by a variable cannot be completely removed.
So all pointers to it have to be set to something else (null is also something else) before it is really removed.
That is why in some cases (maybe not this one), this may still work:
  • Actions
    • Set Unit = (Triggering unit)
    • Unit - Remove Unit from the game
    • Set Location = (Position of Unit)
Some data is not removed, some is, so it is a bad habit to do so.
However, that also means that a function with a local agent variable that is not nulled, will leak because the agent can never be removed...
Most triggers wont care about it... players are agents, but you dont remove those either (there isnt even a function that does that... which is reasonable), but groups for example are created/destroyed all over the place.

In this script, both "result" and "g" are not nulled and thus will leak 2 group handles.
Kind of a pain yes.

However, that does not mean GroupEnumUnitsOfType() doesnt leak.
For example, there has been a bit of a fuss about KillUnit() and according to all tests... it leaks.
Most dont know why and dont know how to check it, but we do know it leaks... this may also be for other functions... even though I doubt many will even make a difference.
 
Level 20
Joined
Jul 14, 2011
Messages
877
Yeah, I was reffering to the native. I know about local pointer leaks but Blizzard.j is pretty much full of them.
I also remember that there was a third "Pick units in..." function in GUI specifically about the unit type, that isnt there anymore.
Maybe I am imagining things but I am pretty sure it existed at some point. Might be one of those Deja Vu moments :p
 
Level 13
Joined
Jan 2, 2016
Messages
978
Hmm, is there a way to declare my own "bj_" variables?
Actually I don't really need them to be "bj_", but I don't want to see them in my global variables list, and I want them to work like global variables, but not to be called "udg_..."

EDIT: And hmm.. Would it be too stupid to restart a timer manually every time it expires? (instead of setting the boolean "repeats" to true)?
I am considering to do that, cuz the time of the timer depends on a global variable, that can change its value (only in test mode tho). And I wanna test different modes, without having to restart the map all the time.
So I'm just wondering if it's bad to manually restart the timer every 0,05 - 0,21 seconds.
 
Last edited:
Level 19
Joined
Mar 18, 2012
Messages
1,716
Hmm, is there a way to declare my own "bj_" variables?
The prefix bj_ refers to the Blizzard.j

Actually I don't really need them to be "bj_", but I don't want to see them in my global variables list, and I want them to work like global variables, but not to be called "udg_..."
You can make a seperate library the variables can have any name you want, but only in vJass, Zinc or Wurst.
In vanilla JASS you have to live with the udg_ and the variable list.
 
Level 24
Joined
Aug 1, 2013
Messages
4,658
JASS:
globals // <<< for normal JASS scripts, scopes and libraries
    
    integer a = 12345678 // <<< a variable with a default value
    
    integer MY_GLOBAL_INT // <<< FULL upper case for constants or globals that imitate 
        // constants
    constant integer A_REAL_CONSTANT // <<< this one is a real constant that you cant 
        // change. I thought they were a good habit to use.
        // These variables always need a default value.
    
    string array textMessages // <<< non constants ussually Camel Case (first word with 
        // lower case letters, all consecutive words with a capital letter.)
    boolean array myBooleans // <<< arrays are also fun :D
    
    private integer myPrivateInteger // <<< inside scopes, libraries and also structs, 
        // you can define your variables as private so only they can read it and a prefix 
        // will be automatically added... making you able to use the same global names in 
        // other scopes, libraries and structs.
    
endglobals

Structs are a bit different but you will just have to check the documentation or uploaded scripts of it.
 
Level 13
Joined
Jan 2, 2016
Messages
978
Hmm, what's "call SyncSelections()" doing?
blizzard.j function using it:
JASS:
function GetUnitsSelectedAll takes player whichPlayer returns group
    local group g = CreateGroup()
    call SyncSelections()
    call GroupEnumUnitsSelected(g, whichPlayer, null)
    return g
endfunction
But when I tried to do this:
JASS:
function CmdKill takes nothing returns nothing
    local player p = GetTriggerPlayer()
    local group g = CreateGroup()
    local unit u
    //call SyncSelections()
    call GroupEnumUnitsSelected(g, p, null)
    loop
        set u = FirstOfGroup(g)
        exitwhen u == null
        call KillUnit(u)
        call GroupRemoveUnit(g, u)
    endloop
    call DestroyGroup(g)
    set g = null
    set p = null
endfunction
it doesn't work when "SyncSelections()" is active.

And by the way:
Is there a way to get "i" without this loop:
JASS:
function GetI takes unit u returns integer
    local integer i = 1
    loop
        exitwhen i > udg_count
        if u == udg_unit[i] then
            return i
        endif
        set i = i + 1
    endloop
    return 0
endfunction
 
Last edited:
Level 24
Joined
Aug 1, 2013
Messages
4,658
Getting i is simple, you just store i in an array.
The index that you use is the UnitUserData.
So return udg_I_List[GetUnitUserData(u)] would be the content of the "GetI" function.

SyncSelections is something I dont understand either.
I suppose it requires a trigger action to properly work.
However, because without it, it also runs properly, I dont see a reason to use it.
 
Level 13
Joined
Jan 2, 2016
Messages
978
Say, what are the differences between JASS and vJASS.
Wietlol already revealed the "Globals declaring". What else? :p
Are there any different/extra functions?
Is the syntax any different (even if partly)?

And can anyone explain structs, libraries, and other stuff like that (which are in vJASS)
~I'm kind a thinking to try it out... and if the syntax it the same as in JASS, I might do just that~
 
Level 7
Joined
Oct 19, 2015
Messages
286
I see no good reason why anyone would want to use JASS instead of vJass. If you are using JASS, you should stop reading this and go switch to vJass right now.

The syntax is the same. vJass is still JASS, it just adds some stuff on top.

Libraries are awesome. They allow you to organize your code into multiple triggers and the preprocessor will make sure that they get added to the map script in the right order. With libraries you no longer have to put all your systems into the map header. This also makes it easier to share code, so you can more easily make use of libraries written by others instead of having to write everything yourself.

Structs are awesome. They are basically data (and code) containers that can be dynamically created. They allow you to easily write multi-instanceable code. I can't imagine going back to writing code without structs.
 
Status
Not open for further replies.
Top