//* API: //* boolean ADD_ALL_UNITS: If enabled, a trigger turns on which automatically //* registers all units in the map. //* integer BUCKET_SIZE: How many units to add to each 'bucket' - a larger //* bucket will have their trigger refresh less frequently but will be //* more computationally expensive. A good starting value is about 20. //* real PER_CLEANUP_TIMEOUT: How many seconds to wait in between each //* scan for empty buckets. This value should be lower if units die often //* in your map. A good starting value is about 60. //* static method addHandler: Registers a callback function to the generic //* unit damage event. Example: StructuredDD.addHandler(function h) //* static method add: Adds a unit to a bucket. If ADD_ALL_UNITS is enabled, //* this method need not be used. library StructuredDD initializer ini //<< BEGIN SETTINGS SECTION //* Set this to true if you want all units in your map to be //* automatically added to StructuredDD. Otherwise you will have to //* manually add them with StructuredDD.add(u). public constant boolean ADD_ALL_UNITS = true //* This is the amount of units that exist in each trigger bucket. //* This number should be something between 5 and 30. A good starting //* value will be an estimate of your map's average count of units, //* divided by 10. When in doubt, just use 20. constant integer BUCKET_SIZE = 5 //* This is how often StructuredDD will search for empty buckets. If //* your map has units being created and dying often, a lower value //* is better. Anything between 10 and 180 is good. When in doubt, //* just use 60. constant real PER_CLEANUP_TIMEOUT = 60. //>> END SETTINGS SECTION //* Our bucket struct which contains a trigger and its associated contents. struct Bucket integer bucketIndex = 0 trigger trig = CreateTrigger() unit array members[BUCKET_SIZE] end //* Our wrapper struct. We never intend to actually instanciate "a //* StructuredDD", we just use this for a pretty, java-like API :3 public struct StructuredDD private static boolexpr array conditions private static Bucket array bucketDB private static integer conditionsIndex = -1 private static integer dbIndex = -1 private static integer maxDBIndex = -1 //* This method gets a readily available bucket for a unit to be added. //* If the "current" bucket is full, it returns a new one, otherwise //* it just returns the current bucket. private static method getBucket takes nothing returns integer integer index = 0 Bucket tempDat if dbIndex != -1 and bucketDB[dbIndex].bucketIndex < BUCKET_SIZE then return dbIndex else maxDBIndex++ dbIndex = maxDBIndex tempDat = new Bucket() bucketDB[maxDBIndex] = tempDat loop exitwhen index > conditionsIndex TriggerAddCondition(tempDat.trig, conditions[index]) index++ end return dbIndex end end static method disable takes nothing returns nothing integer index = 0 Bucket b loop exitwhen index > maxDBIndex b = bucketDB[index] DisableTrigger(b.trig) index++ end end static method enable takes nothing returns nothing integer index = 0 Bucket b loop exitwhen index > maxDBIndex b = bucketDB[index] EnableTrigger(b.trig) index++ end end //* This method is for adding a handler to the system. Whenever a //* handler is added, damage detection will immediately trigger that //* handler. There is no way to deallocate a handler, so don't try to //* do this dynamically (!) Support for handler deallocation is //* feasible (please contact me) static method addHandler takes code func returns nothing Bucket tempDat integer index = 0 conditionsIndex++ conditions[conditionsIndex] = Condition(func) loop exitwhen index > maxDBIndex tempDat = bucketDB[index] TriggerAddCondition(tempDat.trig, conditions[conditionsIndex]) index++ end end //* This method adds a unit to the damage detection system. If //* ADD_ALL_UNITS is enabled, this method need not be used. static method add takes unit member returns nothing Bucket tempDat integer whichBucket = getBucket() tempDat = bucketDB[whichBucket] tempDat.members[tempDat.bucketIndex] = member tempDat.bucketIndex++ TriggerRegisterUnitEvent(tempDat.trig, member, EVENT_UNIT_DAMAGED) end //* This is just an auxillary function for ADD_ALL_UNITS' implementation static method autoAddC takes nothing returns boolean add(GetTriggerUnit()) return false end //* This method is used to check if a given bucket is empty (and thus //* can be deallocated) - this is an auxillary reoutine for the //* periodic cleanup system. private static method bucketIsEmpty takes integer which returns boolean Bucket tempDat = bucketDB[which] integer index = 0 loop exitwhen index == BUCKET_SIZE //GetUnitTypeId(unit) == 0 means that the unit has been removed. if GetUnitTypeId(tempDat.members[index]) != 0 then return false end index++ end return true end //* This method cleans up any empty buckets periodically by checking //* if it has been fully allocated and then checking if all its //* members no longer exist. static method perCleanup takes nothing returns nothing integer index = 0 loop exitwhen index > maxDBIndex if index != dbIndex and bucketIsEmpty(index) then DestroyTrigger(bucketDB[index].trig) destroy bucketDB[index] bucketDB[index] = bucketDB[maxDBIndex] maxDBIndex-- if maxDBIndex == dbIndex then dbIndex = index end index-- end index++ end end end //* This is a initialization function necessary for the setup of //* StructuredDD. function ini takes nothing returns nothing group grp region reg trigger autoAddUnits timer perCleanup unit iter if ADD_ALL_UNITS then //Add starting units grp = CreateGroup() GroupEnumUnitsInRect(grp, bj_mapInitialPlayableArea, null) loop iter = FirstOfGroup(grp) exitwhen iter == null StructuredDD.add(iter) GroupRemoveUnit(grp, iter) end //Add entering units autoAddUnits = CreateTrigger() reg = CreateRegion() RegionAddRect(reg, bj_mapInitialPlayableArea) TriggerRegisterEnterRegion(autoAddUnits, reg, null) TriggerAddCondition(autoAddUnits, Condition(function StructuredDD.autoAddC)) end //enable periodic cleanup: perCleanup = CreateTimer() TimerStart(perCleanup, PER_CLEANUP_TIMEOUT, true, function StructuredDD.perCleanup) end endlibrary