Group API

From WarCraft3

Jump to: navigation, search

The Group API lets you manage collection of units, the handle to a collection of units is called a group. IsUnitInGroup checks if a unit is in the group, but isn't part of the Group API according to blizzard.

Contents

Code

common.j

//============================================================================
// Group API
//
native CreateGroup                          takes nothing returns group
native DestroyGroup                         takes group whichGroup returns nothing
native GroupAddUnit                         takes group whichGroup, unit whichUnit returns nothing
native GroupRemoveUnit                      takes group whichGroup, unit whichUnit returns nothing
native GroupClear                           takes group whichGroup returns nothing
native GroupEnumUnitsOfType                 takes group whichGroup, string unitname, boolexpr filter returns nothing
native GroupEnumUnitsOfPlayer               takes group whichGroup, player whichPlayer, boolexpr filter returns nothing
native GroupEnumUnitsOfTypeCounted          takes group whichGroup, string unitname, boolexpr filter, integer countLimit returns nothing
native GroupEnumUnitsInRect                 takes group whichGroup, rect r, boolexpr filter returns nothing
native GroupEnumUnitsInRectCounted          takes group whichGroup, rect r, boolexpr filter, integer countLimit returns nothing
native GroupEnumUnitsInRange                takes group whichGroup, real x, real y, real radius, boolexpr filter returns nothing
native GroupEnumUnitsInRangeOfLoc           takes group whichGroup, location whichLocation, real radius, boolexpr filter returns nothing
native GroupEnumUnitsInRangeCounted         takes group whichGroup, real x, real y, real radius, boolexpr filter, integer countLimit returns nothing
native GroupEnumUnitsInRangeOfLocCounted    takes group whichGroup, location whichLocation, real radius, boolexpr filter, integer countLimit returns nothing
native GroupEnumUnitsSelected               takes group whichGroup, player whichPlayer, boolexpr filter returns nothing

native GroupImmediateOrder                  takes group whichGroup, string order returns boolean
native GroupImmediateOrderById              takes group whichGroup, integer order returns boolean
native GroupPointOrder                      takes group whichGroup, string order, real x, real y returns boolean
native GroupPointOrderLoc                   takes group whichGroup, string order, location whichLocation returns boolean
native GroupPointOrderById                  takes group whichGroup, integer order, real x, real y returns boolean
native GroupPointOrderByIdLoc               takes group whichGroup, integer order, location whichLocation returns boolean
native GroupTargetOrder                     takes group whichGroup, string order, widget targetWidget returns boolean
native GroupTargetOrderById                 takes group whichGroup, integer order, widget targetWidget returns boolean

// This will be difficult to support with potentially disjoint, cell-based regions
// as it would involve enumerating all the cells that are covered by a particularregion
// a better implementation would be a trigger that adds relevant units as they enter
// and removes them if they leave...
native ForGroup                 takes group whichGroup, code callback returns nothing
native FirstOfGroup             takes group whichGroup returns unit
Confused? Jass help forum!

Adding units

Units can be added to a group one by one with GroupAddUnit or many at the same time with one of the GroupEnumUnits natives. All GroupEnumUnits natives takes a boolexpr arguments that is the condition specifying if the unit will be added to the group or not. Inside the boolexpr you use GetFilterUnit to get the unit that is currently considered.

Example

// Filters out all units who have more than 100 life
function IsWeak takes nothing returns boolean
    return GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) <= 100
endfunction
//...
call GroupEnumUnitsOfPlayer(someGroup, Player(0), Filter(function IsWeak))

Enumerating

There are two different ways to enumerate the units in a group, the first one is to use ForGroup, the second one is to use FirstOfGroup. There is also a third way to enumerate units, without storing them in a group.

FirstOfGroup

local unit current
loop
   set current = FirstOfGroup(someGroup)
   exitwhen current == null
   // do stuff with current
   call GroupRemoveUnit(someGroup, current)
endloop

Pros

  • Can use local variables declared in the current function
  • Easy to break out of the loop before all units are processed

Cons

  • Easier to get wrong, forgetting the GroupRemoveUnit is a common source of errors.
  • A lower level construct than ForGroup, meaning more syntax and less intent.
  • Empties the group.

ForGroup

function DoStuff takes nothing returns nothing
   local unit current = GetEnumUnit()
   // do stuff with current
endfunction

//...
call ForGroup(someGroup, function DoStuff)

Pros

  • Hard to get wrong
  • Easier to introduce explaining functions

Cons

  • Passing parameters to the callback requires using globals
  • No easy way to break out prematurely

boolexpr as callback

This type of enumeration works well when we have code like this:

function EnumCondition takes nothing returns boolean
    return someCondition(GetFilterUnit())
endfunction

function EnumAction takes nothing returns nothing
   local unit u = GetEnumUnit()
   // do something with the unit
endfunction

function Actions takes nothing returns nothing
    local group g = CreateGroup()
    call GroupEnumUnits*(g, ..., Condition(function EnumCondition))
    call ForGroup(g, function EnumAction)
    call DestroyGroup(g)
    set g = null
endfunction

As you can see, we are creating a group just to destroy it after we've enumerated it. We can use a dummy group together with with a "condition" that makes the actions on the filter unit to remove the need of creating/destroying a group all the time.

function EnumAction takes nothing returns boolean
    local unit u = GetFilterUnit()
    if someCondition(u) then
        // do something with the unit
    endif
    return false
endfunction

function Actions takes nothing returns nothing
    call GroupEnumUnits*(DUMMYGROUP, ..., Condition(function EnumAction))
endfunction

Note that the condition always returns false so the dummy group will always be empty.

Pros

  • Faster than ForGroup
  • Almost as easy to get right as ForGroup

Cons

  • Only works when the enumeration happens at the same place as the selection
  • Can't use combined boolexprs
Personal tools