HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Looping Through a Unit Group without Leaks

08-09-2006, 03:17 AM#1
TheEpigoni
I'm trying to figure out a way to build a unit group without leaks, but I'm stuck at the point of having to use a filter function and I'm not exactly sure how to go about it since there's no passing of variables to a filter function and hence no way of giving the filter function the unit I'm testing without assigning a global which seems a bit messy to me.

Collapse JASS:
function AssignAll takes nothing returns nothing
  local group ugroup = CreateGroup()
  local unit u

  call GroupEnumUnitsOfType(ugroup,"hmtt",null)

  loop
    set u = FirstOfGroup(ugroup)
    exitwhen u == null
    call AssignIndex(u)
    //DEBUG
    call DisplayTextToForce( GetPlayersAll(), "Assigning Index to: " + GetUnitName(u) )
    //DEBUG
    call GroupRemoveUnit(ugroup, u)
  endloop

  call DestroyGroup(ugroup)
  set ugroup = null
endfunction

In the above code I tried to use GroupEnumUnitsOfType but apparantly the "Type" that their referring to is not unittype but something a bit broader, I'm curious if it's referring to unit types like "giant" or "ethereal".

Finally, is there a standard way of doing this nowadays?
08-09-2006, 03:22 AM#2
DioD
Collapse JASS:
local boolean B = IsUnitType(SomeLocalUnit,Unit_Type_Giant) == true
or
local boolexpr X = Condition(function some)
DestroyBoolexpr(X)

First is boolean with arguments
second can be done from first by some funny way
Collapse JASS:
local boolexpr Z = And(null,X)

this will parse arguments inside any function.
08-09-2006, 03:42 AM#3
TheEpigoni
DioD, can you please explain your answer a little clearer and make sure you understood my question correctly.

I'm completely unsure of what you're referring to in your answer or what it accomplishes.

Essentially my question is such...

1) How do I create a group of units containing every unit on the map of a certain unittype?

2) Can GroupEnumUnitsOfType be used to accomplish this, or is the type string that it recieves different from unittype?

3) If using either GroupEnumUnitsOfPlayer or GroupEnumUnitsInRect how do I use the filter boolexpr that it takes to check the type of the unit? Does this require a global to "pass" the unit I'm currently checking to the function?
08-09-2006, 04:02 AM#4
DioD
Functions used
Collapse JASS:
constant native GetUnitTypeId       takes unit whichUnit returns integer

constant native GetOwningPlayer     takes unit whichUnit returns player

native GroupEnumUnitsInRect                 takes group whichGroup, rect r, boolexpr filter returns nothing

Trigger

Collapse JASS:

function FilterMain takes nothing returns boolean
    if GetUnitTypeId(GetFilterUnit()) == 'hpea' then
        if GetOwningPlayer(GetFilterUnit()) == Player(0) then
            return true
        endif
    endif
    return false
endfunction

call GroupEnumUnitsInRect(udg_Group,bj_mapInitialPlayableArea,Condition(function Filtermain))


it will be much more longer with local boolexpr.
08-09-2006, 04:03 AM#5
The_AwaKening
This will grab all footman units in the map.
Collapse JASS:
function GroupActions takes nothing returns nothing
 local group g=CreateGroup()
 local boolean b=GetUnitTypeId(GetFilterUnit())=='hfoo'
    call GroupEnumUnitsInRect(g,GetPlayableMapRect(),b)
    // Then the rest of your stuff
endfunction
As for your 3rd question, you would use GetFilterUnit() just as I have shown above. If calling a ForGroup, it is GetEnumUnit(). There is no other way to pass units between functions.

Boolean Express way.
Collapse JASS:
function GroupBool takes nothing returns nothing
    return GetUnitTypeId(GetFilterUnit())=='hfoo'
endfunction

function GroupActions takes nothing returns nothing
 local group g=CreateGroup
 local boolexpr b=Condition(function GroupBool)
 local unit u
    call GroupEnumUnitsInRect(g,GetPlayableMapRect(),b)
    loop
        set u=FirstOfGroup(g)
        exitwhen u==null
        // Your actions
        call GroupRemoveUnit(g,u)
    endloop
    call DestroyGroup(g)
    call DestroyBoolExpr(b)
 set g=null
 set u=null
 set b=null
endfunction
Or you could use a ForGroup call instead of the loop, but you would just Use GetEnumUnit() instead of u

On another note, I have a question of my own about a leak with the boolean. If I were to do this without using a local, would it leak?
Collapse JASS:
    call GroupEnumUnitsInRect(g,GetPlayableMapRect(),Condition(function whatever))
If so, then wouldn't using a local boolean also leak since it points to a condition that you aren't able to destroy?
08-09-2006, 04:17 AM#6
TheEpigoni
Thanks both of you. I didn't initially realize the connection between GetFilterUnit() and GroupEnum and wanted to avoid using it at first. I suppose there's not much other choice.
08-09-2006, 04:18 AM#7
DioD
Data parsed to functions do not leak. (only strings cause it always leak)
08-09-2006, 10:46 AM#8
PitzerMike
The string for the unittype of GroupEnumUnitsOfType can be found in UnitUI.slk or UnitData.slk. Example:

Collapse JASS:
call GroupEnumUnitsOfType(ugroup,"waterelemental",null)

... adds all water elementals to the group.
08-09-2006, 02:31 PM#9
TheEpigoni
Quote:
Originally Posted by PitzerMike
The string for the unittype of GroupEnumUnitsOfType can be found in UnitUI.slk or UnitData.slk. Example:

Collapse JASS:
call GroupEnumUnitsOfType(ugroup,"waterelemental",null)

... adds all water elementals to the group.

If this is true then I should definatly be using GroupEnumUnitsOfType instead of:

call GroupEnumUnitsInRect(g,GetPlayableMapRect(),b)

But I do have a question, how would custom units be determined in this way? Do they not have a unit name at all, or do they use the unit name of their base unit?

It also seems kindof weird that it would use a descriptive string name to filter by, especially since in the SLK that column is marked "comment(s)" implying it to be more of a descriptive field rather than a data field.
08-09-2006, 03:30 PM#10
Vexorian
Strings don't leak...
08-09-2006, 10:04 PM#11
PitzerMike
It is not the comment(s) column. It's the name column in UnitUI.slk
For customs you'd have to add that field to the unit editor to be able to change it.
I think by default it inherits the value from the base unit.
08-09-2006, 10:44 PM#12
TheEpigoni
Quote:
Originally Posted by PitzerMike
It is not the comment(s) column. It's the name column in UnitUI.slk
For customs you'd have to add that field to the unit editor to be able to change it.
I think by default it inherits the value from the base unit.

So am I right in thinking it would be more effecient than using the filter function?
08-09-2006, 11:32 PM#13
The_AwaKening
It would definitely be cleaner, but not really more efficient. You are still choosing units conditionally either way. BTW, you have to use a boolean express instead of a boolean. I made a bad post earlier in showing a way to use a local boolean. Just do the express way.
08-10-2006, 11:55 AM#14
PitzerMike
Quote:
Originally Posted by TheEpigoni
So am I right in thinking it would be more effecient than using the filter function?

Yes. It will still go through all units on the map but checking for the unit type is definitely faster than checking the in-rect-condition + a callback.
08-10-2006, 01:20 PM#15
DioD
Quote:
Originally Posted by Vexorian
Strings don't leak...

I will return bug string, and string "waterelemental" will be returned from its ID.

I have demo map for string leaks, it will kill any PC in few seconds.
I will post it if some one need...