Group Filter Function?

BlueMirage

Trust, but doubt.
Reaction score
39
I'm trying to make a function that will make it easier to sort out units of a group that I don't want, so I'm making a function that will do so.

It looks something like this at the moment:

JASS:
function FilterGroup takes group g, boolexpr b returns group
    local group g2 = CreateGroup()
    local boolean = Condition(
    local unit u
    loop
        set u = FirstOfGroup(g)
        exitwhen u == null
        if b == TRUE then
            call GroupAddUnit(g2, u)
        endif
        call GroupRemoveUnit(g, u)
    endloop
    return g2
endfunction


The problem that I have is that if the function takes a boolean, I think that the boolean is set to true or false when I input it in the "takes" part. So, I think I have to use a boolean expression instead. I'm not sure if that's the solution, but my guess is that an expression does not have a true or false value as a variable, but will rather give one when used. Problem is, I don't know how to, as I can't compare "b" with TRUE.

Any ideas on how to create this?

I'm quite sure that it leaks, since it uses a unit group that is not cleaned up.
 

saw792

Is known to say things. That is all.
Reaction score
280
This is already done for you. It's called a GroupEnum...() function, and it takes a boolexpr to use as a filter for the group. A few variants: [ljass]GroupEnumUnitsInRange(), GroupEnumUnitsOfPlayer(), GroupEnumUnitsInRect()...[/ljass]
 

BlueMirage

Trust, but doubt.
Reaction score
39
The problem is that all of those functions takes range, a player or a region, and I feel clunky if I take that into account when I don't need to.

I thought it would be faster if I created a custom function, but maybe it isn't?
 

Darthfett

Aerospace/Cybersecurity Software Engineer
Reaction score
615
Generally, saw792 is right. You should do filtering when you select the units for the group. However, there are cases when you want to create multiple groups from one set, and it's not as efficient to GroupEnum for the units multiple times.

I don't know if you're using vJass, but you could try using a function interface if you are:

JASS:
globals
    private group tempGroup
    private UnitFilter tempUF
endglobals

function interface UnitFilter takes unit u returns boolean

private function FilterGroupCallback takes nothing returns nothing
    if tempUF(GetEnumUnit()) then
        call GroupAddUnit(tempGroup,GetEnumUnit())
    endif
endfunction

function FilterGroup takes group g, UnitFilter UF returns group
    set tempGroup = CreateGroup()
    call ForGroup(g,function FilterGroupCallback
    return tempGroup
endfunction

//Usage:
function GetAllUnitsFilter takes unit u returns boolean
    return true
endfunction

    call FilterGroup(someGroup,UnitFilter.GetAllUnitsFilter)
//endUsage
 

BlueMirage

Trust, but doubt.
Reaction score
39
Nope, I don't know vJASS, nor am I really trying to learn it. If you could explain how to make it normal JASS, I'd be glad. Until then, I'll just study your code in order to understand atleast some parts of it.
 

Darthfett

Aerospace/Cybersecurity Software Engineer
Reaction score
615
Nope, I don't know vJASS, nor am I really trying to learn it. If you could explain how to make it normal JASS, I'd be glad.

Any specific reason why? vJass is extremely useful.

Essentially, the snippet I wrote just does a ForGroup with the original group, and inside the Callback function, it checks to see if the unit matches the set conditions. If it does, it adds it to the new group.

I wouldn't recommend using a FirstOfGroup loop (what you wrote originally), as it means it will mess with the units in the passed group (not good coding practice, and could cause problems if the user of the function doesn't understand this), or it will need to parse through all the units to add them to a new group ([ljass]GroupAddGroup[/ljass]), and then parse through them again to see if they match the filter (You never want to have to parse through something twice, if you can avoid it).

However, using a ForGroup will require the New group for the units to be added to, to be put into a global variable (As you can see in my example). Since you're not using vJass, you won't be able to pass functions very easily. For this, you will need to create a function for each type of filtering you want to do.

Example code:

JASS:
globals
    group udg_tempGroup
endglobals

function CopyGroupCallback takes nothing returns nothing
    call GroupAddUnit(udg_tempGroup,GetEnumUnit())
endfunction

function CopyGroup takes group g returns group
    set udg_tempGroup = CreateGroup()
    call ForGroup(g,function CopyGroupCallback)
    return udg_tempGroup
endfunction


The problem with this method, is that if you want to add more filters, you have to add TWO additional functions:

JASS:
globals
    player udg_tempPlayer
endglobals

function GetPlayersUnitsCallback takes nothing returns nothing
    if GetOwningPlayer(GetEnumUnit()) == udg_tempPlayer then
        call GroupAddUnit(udg_tempGroup,GetEnumUnit())
    endif
endfunction

function GetPlayersUnits takes group g, player p returns group
    set udg_tempGroup = CreateGroup()
    set udg_tempPlayer = p
    call ForGroup(g,function GetPlayersUnitsCallback)
    return udg_tempGroup
endfunction


Whereas with the vJass version, all you have to do is create a function that takes a unit, returns a boolean, and simply determines whether the passed unit should be included in the group. One additional function for each additional filter.
 

Jesus4Lyf

Good Idea™
Reaction score
397
This is fun. Vanilla JASS! :D
JASS:
function FilterGroupEnum takes nothing returns nothing
    if TriggerEvaluate(bj_cineSceneBeingSkipped) then
        call GroupAddUnit(bj_groupAddGroupDest,GetEnumUnit())
    endif
endfunction
function FilterGroup takes group g, boolexpr b returns group
    local trigger skip=bj_cineSceneBeingSkipped // sets back later
    set bj_cineSceneBeingSkipped=CreateTrigger()
    call TriggerAddCondition(bj_cineSceneBeingSkipped,b)
    set bj_groupAddGroupDest=CreateGroup()
    call ForGroup(g,function FilterGroupEnum)
    call DestroyTrigger(bj_cineSceneBeingSkipped)
    set bj_cineSceneBeingSkipped=skip
    set skip=null
    return bj_groupAddGroupDest
endfunction

Leak free lag free blah blah just use it.

Example filter:
JASS:
function AliveFilter takes nothing returns boolean
    return GetWidgetLife(GetEnumUnit())>0.405
endfunction

Note that you must use [LJASS]GetEnumUnit()[/LJASS] in the filter instead of [LJASS]GetFilterUnit()[/LJASS]. :)

So [LJASS]FilterGroup(myGroup, Filter(function AliveFilter))[/LJASS] would return a new group with all alive units in myGroup. :thup:
 

BlueMirage

Trust, but doubt.
Reaction score
39
I don't really want to learn vJASS since I feel that while it may be useful, it does nothing but convert vJASS code into JASS code and thus learning simple JASS would logically make me learn more about how it works.

I can sort of understand Jesus' code, so I guess I'll try and use that.
+ rep for both though for helping.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top