Permalink
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
181 lines (150 sloc) 5.69 KB
package ClosureForGroups
public interface ForGroupCallback
function callback(unit u)
/** This is used as dummy in the GroupEnum calls and should not be used */
constant DUMMY_GROUP = CreateGroup()
// ====Callback stack for nested usage====
ForGroupCallback array tempCallbacks
var tempCallbacksCount = 0
var maxCount = INT_MAX
var iterCount = 0
constant filter = Filter(() -> filterCallback(GetFilterUnit()))
function filterCallback(unit filter)
if iterCount < maxCount
currentCallback().callback(filter)
iterCount++
function pushCallback(ForGroupCallback c)
tempCallbacks[tempCallbacksCount] = c
tempCallbacksCount++
iterCount = 0
maxCount = INT_MAX
function popCallback()
DUMMY_GROUP.clear()
tempCallbacksCount--
destroy tempCallbacks[tempCallbacksCount]
function currentCallback() returns ForGroupCallback
return tempCallbacks[tempCallbacksCount - 1]
// ====Stack end====
/** Executes the given closure for every unit in this group,
removing the units from the group as processed */
public function group.forEachFrom(ForGroupCallback cb)
for u from this
cb.callback(u)
destroy cb
/** Executes the given closure for every unit in this group,
keeping all units in the group */
public function group.forEachIn(ForGroupCallback cb)
for u in this
cb.callback(u)
destroy cb
/** Executes the given closure for every unit of the given type.
Remember that names of custom units are "custom_[typeId]" */
public function forUnitsOfType(string unitname, ForGroupCallback c)
pushCallback(c)
GroupEnumUnitsOfType(DUMMY_GROUP, unitname, filter)
popCallback()
/** Executes the given closure for every unit of the given player.
Cancels itself after *count* iterations */
public function forUnitsOfTypeCounted(string unitname, int count, ForGroupCallback c)
pushCallback(c)
maxCount = count
GroupEnumUnitsOfType(DUMMY_GROUP, unitname, filter)
popCallback()
/** Executes the given closure for every unit of the given player */
public function forUnitsOfPlayer(player p, ForGroupCallback c)
pushCallback(c)
GroupEnumUnitsOfPlayer(DUMMY_GROUP, p, filter)
popCallback()
/** Executes the given closure for every existing unit */
public function forUnitsAll(ForGroupCallback c)
for i = 0 to bj_MAX_PLAYER_SLOTS - 1
pushCallback(c)
GroupEnumUnitsOfPlayer(DUMMY_GROUP, players[i], filter)
DUMMY_GROUP.clear()
tempCallbacksCount--
destroy c
/** Executes the given closure for every unit in the given rect */
public function forUnitsInRect(rect r, ForGroupCallback c)
pushCallback(c)
GroupEnumUnitsInRect(DUMMY_GROUP, r, filter)
popCallback()
/** Executes the given closure for every unit in the given rect.
Cancels itself after *count* iterations */
public function forUnitsInRectCounted(rect r, int count, ForGroupCallback c)
pushCallback(c)
maxCount = count
GroupEnumUnitsInRect(DUMMY_GROUP, r, filter)
popCallback()
/** Executes the given closure for every unit in range of the given position */
public function forUnitsInRange(vec2 pos, real radius, ForGroupCallback c)
pushCallback(c)
GroupEnumUnitsInRange(DUMMY_GROUP, pos.x, pos.y, radius, filter)
popCallback()
/** Executes the given closure for every unit in range of the given position
Cancels itself after *count* iterations */
public function forUnitsInRangeCounted(vec2 pos, real radius, int count, ForGroupCallback c)
pushCallback(c)
maxCount = count
GroupEnumUnitsInRange(DUMMY_GROUP, pos.x, pos.y, radius, filter)
popCallback()
/** Executes the given closure for every unit selected by the given player */
public function forUnitsSelected(player p, ForGroupCallback c)
pushCallback(c)
GroupEnumUnitsSelected(DUMMY_GROUP, p, filter)
popCallback()
/** Executes the given closure for the closest unit inside the given range of the given position,
matching the provided filter. If there is no unit in range, the closure will be run with "null" */
public function forNearestUnit(vec2 pos, real range, filterfunc filter, ForGroupCallback c)
pushCallback(c)
GroupEnumUnitsInRange(ENUM_GROUP, pos.x, pos.y, range, filter)
unit nearest = null
var bestDist = REAL_MAX
for u from ENUM_GROUP
let distSq = pos.distanceToSq(u.getPos())
if distSq < bestDist
nearest = u
bestDist = distSq
c.callback(nearest)
popCallback()
// Destructables
// ====Callback stack for nested usage====
public interface ForGroupCallbackD
function callback(destructable d)
function filterD() returns boolean
currentCallbackD().callback(GetEnumDestructable())
return false
ForGroupCallbackD array tempCallbacksD
int tempCallbacksDCount = 0
function pushCallbackD(ForGroupCallbackD c)
tempCallbacksD[tempCallbacksDCount] = c
tempCallbacksDCount++
function popCallbackD()
tempCallbacksDCount--
destroy tempCallbacksD[tempCallbacksDCount]
function currentCallbackD() returns ForGroupCallbackD
return tempCallbacksD[tempCallbacksDCount - 1]
// ====Stack end====
/** Executes the given closure for all destructables in the given rect */
public function forDestructablesInRect(rect r, ForGroupCallbackD cb)
pushCallbackD(cb)
EnumDestructablesInRect(r, null, () -> filterD())
popCallbackD()
// Nearest Destructable helpers
destructable nearestD = null
real nearestDDist = REAL_MAX
vec2 gpos = ZERO2
/** Executes the given closure for the closes destructable in the given rect.
If there is no destructable in range, the closure will be run with "null" */
public function forNearestDestructable(vec2 pos, real range, ForGroupCallbackD c)
pushCallbackD(c)
gpos = pos
nearestDDist = range.squared()
nearestD = null
let r = pos.withRadiusRect(range)
EnumDestructablesInRect(r, filterEnumDestructablesInCircleBJ) ->
let dist = gpos.distanceToSq(GetFilterDestructable().getPos())
if dist < nearestDDist
nearestD = GetFilterDestructable()
nearestDDist = dist
c.callback(nearestD)
popCallbackD()