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

[Snippet] GroupIterator

Level 10
Joined
Sep 19, 2011
Messages
527
i wasn't going to post this, because i thought that it was too simple. turns out that is quite helpful (at least to me). maybe helps someone too.

JASS:
library GroupIterator
    struct GroupIterator
        readonly unit unit
        integer unitTypeId
        boolean onlyIllusions
        boolean onlyHeroes
        player onlyEnemiesOfPlayer
        player onlyAlliesOfPlayer
        player onlyOwnerByPlayer
        real lifeGreaterThan
        real lifeLowerThan
        real lifeEqualTo
        integer max
        private group group
        
        method destroy takes nothing returns nothing
            if ( this.group != bj_lastCreatedGroup ) then
                call DestroyGroup(this.group)
            endif
            
            set this.unit = null
            set this.unitTypeId = 0
            set this.onlyIllusions = false
            set this.onlyHeroes = false
            set this.onlyEnemiesOfPlayer = null
            set this.onlyAlliesOfPlayer = null
            set this.onlyOwnerByPlayer = null
            set this.lifeGreaterThan = -1
            set this.lifeLowerThan = -1
            set this.lifeEqualTo = -1
            set this.max = -1
            set this.group = null
            
            call this.deallocate()
        endmethod
        
        method save takes group whichGroup returns nothing
            call GroupAddUnit(whichGroup, this.unit)
        endmethod
        
        method operator next takes nothing returns thistype
            local real life
        
            set this.unit = FirstOfGroup(this.group)
            
            if ( this.unit == null or this.max == 0 ) then
                call this.destroy()
                return 0
            else
                call GroupRemoveUnit(this.group, this.unit)
            endif
            
            if ( this.unitTypeId != 0 and GetUnitTypeId(this.unit) != this.unitTypeId ) then
                return this.next
            endif
            
            if ( this.onlyIllusions and IsUnitIllusion(this.unit) == false ) then
                return this.next
            endif
            
            if ( this.onlyHeroes and IsUnitType(this.unit, UNIT_TYPE_HERO) == false ) then
                return this.next
            endif
            
            if ( this.onlyEnemiesOfPlayer != null and IsUnitEnemy(this.unit, this.onlyEnemiesOfPlayer) == false ) then
                return this.next
            endif
            
            if ( this.onlyAlliesOfPlayer != null and IsUnitAlly(this.unit, this.onlyAlliesOfPlayer) == false ) then
                return this.next
            endif
            
            if ( this.onlyOwnerByPlayer != null and IsUnitOwnedByPlayer(this.unit, this.onlyOwnerByPlayer) == false ) then
                return this.next
            endif
            
            if ( this.lifeGreaterThan != -1 or this.lifeLowerThan != -1 or this.lifeEqualTo != -1 ) then
                set life = GetWidgetLife(this.unit)
                
                if ( this.lifeGreaterThan != -1 and life > this.lifeGreaterThan ) then
                    return this.next
                endif
                
                if ( this.lifeLowerThan != -1 and life < this.lifeLowerThan ) then
                    return this.next
                endif
                
                if ( this.lifeEqualTo != -1 and life != this.lifeEqualTo ) then
                    return this.next
                endif
            endif
            
            if ( this.max != -1 ) then
                set this.max = this.max - 1
            endif
        
            return this
        endmethod
    
        static method create takes group whichGroup returns thistype
            local thistype this = thistype.allocate()
            
            set this.unit = null
            set this.unitTypeId = 0
            set this.onlyIllusions = false
            set this.onlyHeroes = false
            set this.onlyEnemiesOfPlayer = null
            set this.onlyAlliesOfPlayer = null
            set this.onlyOwnerByPlayer = null
            set this.lifeGreaterThan = -1
            set this.lifeLowerThan = -1
            set this.lifeEqualTo = -1
            set this.max = -1
            set this.group = whichGroup
            
            return this
        endmethod
        
        static method createFromUnitsOfPlayer takes player whichPlayer returns thistype
            call GroupEnumUnitsOfPlayer(bj_lastCreatedGroup, whichPlayer, null)
            return thistype.create(bj_lastCreatedGroup)
        endmethod
        
        static method createFromCoords takes real x, real y, real radius returns thistype
            call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, radius, null)
            return thistype.create(bj_lastCreatedGroup)
        endmethod
        
        static method createFromLoc takes location loc, real radius returns thistype
            return thistype.createFromCoords(GetLocationX(loc), GetLocationY(loc), radius)
        endmethod
    endstruct
endlibrary
examples

JASS:
local group oldGroup = CreateGroup()
local group newGroup = CreateGroup()
local GroupIterator iterator = GroupIterator.create(oldGroup)

call CreateUnit(Player(0), 'Hpal', 0, 0, 0)
call CreateUnit(Player(0), 'hfoo', 0, 0, 0)

call GroupEnumUnitsInRange(oldGroup, 0, 0, 300, null)

loop
    set iterator = iterator.next
    exitwhen iterator == 0
    
    // saving the paladin in the new group
    if ( GetUnitTypeId(iterator.unit) == 'Hpal' ) then
        call iterator.save(newGroup)
    endif
    
    call BJDebugMsg(GetUnitName(iterator.unit))
endloop
JASS:
local GroupIterator iterator

call CreateUnit(Player(0), 'Hpal', 0, 0, 0)
call CreateUnit(Player(0), 'Hpal', 0, 0, 0)
call CreateUnit(Player(0), 'hfoo', 0, 0, 0)

set iterator = GroupIterator.createFromCoords(0, 0, 999999) // all units from Loc(0, 0) in a 999... radius
set iterator.unitTypeId = 'Hpal' // only paladin

loop
    set iterator = iterator.next
    exitwhen iterator == 0
    
    call BJDebugMsg(GetUnitName(iterator.unit))
endloop
 
I think a group iterator may be too simple, unless they include some features I haven't thought of.

I also don't see the point of all the struct's members and the massifblocks. Shouldn't people simply make those checks themselves since that would support everything and be more efficient?

A simple wrapper for FirstOfGroup+GroupRemoveUnit may be too simple, although maybe not.
 
Top