System AuraStruct

Nestharus

o-o
Reaction score
84
This is not compatible with Warcraft 3 Standard Aura Abilities. If you use any aura abilities at all, this will break.
You may only use auras that have None as the valid unit targets (no valid targets), which is what I use in the Demo Map.

Warcraft 3 auras break UnitInRangeEvent

Units that aren't indexed and units with locust will not fire.

JASS:

library AuraStruct /* v2.1.3.0
*************************************************************************************
*
*   An efficient and easy to use module for fully custom aura design.
*
*************************************************************************************
*
*   */uses/*
*
*       */ UnitEvent /*                 hiveworkshop.com/forums/jass-functions-413/extension-unit-event-172365/
*       */ UnitInRangeEvent /*          hiveworkshop.com/forums/submissions-414/unitinrangeevent-205036/
*       */ Tt /*                        hiveworkshop.com/forums/jass-functions-413/system-timer-tools-201165/
*       */ RegisterPlayerUnitEvent /*   hiveworkshop.com/forums/jass-functions-413/snippet-registerplayerunitevent-203338/
*
************************************************************************************
*
*   static method getActiveAuraCount takes UnitIndex unitId returns integer
*   static method getAuraCount takes UnitIndex unitId returns integer
*   static method getUnitsUnderAura takes UnitIndex sourceId returns integer
*   static method getUnitsUnderActiveAura takes UnitIndex sourceId returns integer
*
*   static method createAura takes UnitIndex sourceId returns nothing
*       -   Call this when the unit initially gets the aura. This can also be
*       -   called whenever the aura's level changes for an instant update.
*
*   Interface
*
*       private static constant boolean ANIMATED_BESTOW_AURA
*           (required) -   Determine whether animated units bestow auras or not
*
*       private static constant real TIMEOUT
*           (required) -   How often the aura effect runs
*
*       private static constant boolean STACKS
*           (required) -   Does the aura stack?
*
*       private static method getLevel takes UnitIndex sourceId returns integer
*           (required) -    Returns the level of the aura on the unit
*
*       private static method onLevel takes UnitIndex source, integer level returns nothing
*           (optional) -    Runs when aura levels up
*
*       private static method getRange takes UnitIndex source, integer level returns real
*           (required) -    Should return the range of the aura
*
*       private method onEndEffect takes UnitIndex source, UnitIndex affected, integer level returns nothing
*           (optional) -    Runs when the aura effect ends (aura no longer on unit)
*
*       private method onEffect takes UnitIndex source, UnitIndex affected, integer level returns nothing
*           (optional) -    Runs when aura effect starts (aura just went on to unit)
*
*       private method onPeriodicEffect takes UnitIndex source, UnitIndex affected, integer level returns nothing
*           (optional) -    Runs every period of the aura. First run is right after onEffect
*
*       private static method absFilter takes UnitIndex source, UnitIndex entering returns boolean
*           (optional) -    Runs when the unit initially enters in the range of the aura. If this returns false, the
*                      -    unit is ignored as if it doesn't exist and it will never be able to get the aura
*
*       private method filter takes UnitIndex source, UnitIndex affected, integer level returns boolean
*           (optional) -    Runs whenever the aura cycles (every TIMEOUT seconds). This helps determine if the
*                      -    aura is active or not for the unit.
*
*       (it is either both of these at once or neither of them)
*       private static method removeBuff takes unit whichUnit, integer level returns nothing
*           (optional) -    Runs when the buff icon should be removed from the unit
*
*       private static method addBuff takes unit whichUnit, integer level returns nothing
*           (optional) -    Runs when the buff icon should be added to the unit
*
************************************************************************************/
    globals
        private integer array affectedLevel
        private boolean array active
        private UnitIndex array source
        private UnitIndex array affected
    endglobals
    
    private function InitModule takes code index, code deindex, code death, code revive, boolean animatedBestow returns nothing
        call RegisterUnitIndexEvent(Condition(index), UnitIndexer.INDEX)
        call RegisterUnitIndexEvent(Condition(deindex), UnitIndexer.DEINDEX)
        
        call UnitEvent.START_REINCARNATE.register(Condition(death))
        call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, Condition(death))
        
        call UnitEvent.REINCARNATE.register(Condition(revive))
        call UnitEvent.RESURRECT.register(Condition(revive))
        
        if (animatedBestow) then
            call UnitEvent.ANIMATE.register(Condition(revive))
        endif
    endfunction
    
    module AuraStruct
        private static integer array buffCount
        private static integer array auraCount
        private static integer array auraInstance
        private static integer array activeAura
        private static integer array onEnterT
        private static integer array onEnterT2
        private static integer array auraLevel
        private static integer array level
        private static thistype array next
        private static thistype array prev
        private static Table array affecting
        private static real array range
        private static integer array sourceAffected
        
        static method getActiveAuraCount takes UnitIndex affectedId returns integer
            return buffCount[affectedId]
        endmethod
        
        static method getAuraCount takes UnitIndex affectedId returns integer
            return auraCount[affectedId]
        endmethod
        
        static method getUnitsUnderAura takes UnitIndex sourceId returns integer
            return auraInstance[sourceId]
        endmethod
        
        static method getUnitsUnderActiveAura takes UnitIndex sourceId returns integer
            return activeAura[sourceId]
        endmethod
        
        private method isActive takes integer af, integer so returns boolean
            static if not thistype.STACKS then
                static if thistype.filter.exists then
                    return filter(so, af, level[so]) and (level[so] > auraLevel[af] or sourceAffected[af] == this)
                else
                    return level[so] > auraLevel[af] or sourceAffected[af] == this
                endif
            else
                static if thistype.filter.exists then
                    return filter(so, af, level[so])
                else
                    return true
                endif
            endif
        endmethod
        
        private static method removeCheck takes UnitIndex sourceId returns nothing
            set next[prev[sourceId]]=next[sourceId]
            set prev[next[sourceId]]=prev[sourceId]
            
            call sourceId.unlock()
        endmethod
        
        private static integer array ho
        private static boolean array wa
        private static integer array ht
        private static integer array htc
        
        implement CTM
            local boolean wasActive
            local UnitIndex so
            local UnitIndex af
            local integer lev
            local integer array l
            local integer hc = 0
        implement CTMExpire
            set so = source[this]
            set af = affected[this]
            set lev = level[so]
            
            if (/*
                    */0 == lev or /*
                    */not IsUnitInRange(GetUnitById(so), GetUnitById(af), range[so]) /*
            */) then
                set auraCount[af] = auraCount[af] - 1
                set auraInstance[so] = auraInstance[so] - 1
                
                if (active[this]) then
                    set buffCount[af] = buffCount[af] - 1
                    set activeAura[so] = activeAura[so] - 1
                    
                    static if thistype.addBuff.exists then
                        if (0 == buffCount[af]) then
                            call removeBuff(GetUnitById(af), auraLevel[af])
                        endif
                    endif
                    
                    if (sourceAffected[af] == this) then
                        set auraLevel[af] = 0
                        set sourceAffected[af] = 0
                    endif
                    
                    static if thistype.onEndEffect.exists then
                        call onEndEffect(so, af, affectedLevel[this])
                    endif
                endif
                
                call destroy()
                
                if (0 != affecting[so]) then
                    call affecting[so].remove(af)
                endif
                
                call so.unlock()
                call af.unlock()
            elseif (affectedLevel[this] == level[so]) then
                set wasActive = active[this]
                set active[this] = isActive(af, so)
                
                if (active[this]) then
                    if (lev > auraLevel[af]) then
                        if (lev > l[af]) then
                            set l[af] = lev
                            if (0 == ht[af]) then
                                set ht[af] = hc
                                set htc[hc] = af
                                set ho[hc] = this
                                set wa[hc] = wasActive
                                set hc = hc + 1
                            else
                                set hc = ht[af]
                                set ho[hc] = this
                                set wa[hc] = wasActive
                            endif
                        endif
                        
                        static if thistype.STACKS then
                            static if thistype.onPeriodicEffect.exists then
                                call onPeriodicEffect(so, af, lev)
                            endif
                        endif
                    else
                        static if thistype.onPeriodicEffect.exists then
                            call onPeriodicEffect(so, af, lev)
                        endif
                    endif
                elseif (wasActive) then
                    set buffCount[af] = buffCount[af] - 1
                    set activeAura[so] = activeAura[so] - 1
                    
                    static if thistype.addBuff.exists then
                        if (0 == buffCount[af]) then
                            call removeBuff(GetUnitById(af), auraLevel[af])
                        endif
                    endif
                    
                    if (sourceAffected[af] == this) then
                        set auraLevel[af] = 0
                        set sourceAffected[af] = 0
                    endif
                    
                    static if thistype.onEndEffect.exists then
                        call onEndEffect(so, af, affectedLevel[this])
                    endif
                endif
            endif
        implement CTMNull
            loop
                exitwhen 0 == hc
                set hc = hc - 1
                set ht[htc[hc]] = 0
                set this = ho[hc]
                
                set so = source[this]
                set af = affected[this]
                set lev = level[so]
                
                static if not thistype.STACKS then
                    set wasActive = wa[hc]
                    
                    if (not wasActive) then
                        set buffCount[af] = buffCount[af] + 1
                        set activeAura[so] = activeAura[so] + 1
                    endif
                endif
                
                static if thistype.addBuff.exists then
                    if (0 < buffCount[af]) then
                        call removeBuff(GetUnitById(af), auraLevel[af])
                    endif
                endif
                
                static if not thistype.STACKS then
                    static if thistype.onEndEffect.exists then
                        if (wasActive) then
                            call onEndEffect(so, af, affectedLevel[this])
                        else
                            if (0 != sourceAffected[af]) then
                                set active[sourceAffected[af]] = false
                                call thistype(sourceAffected[af]).onEndEffect(source[sourceAffected[af]], af, auraLevel[af])
                            endif
                        endif
                    endif
                    
                    set sourceAffected[af] = this
                    set auraLevel[af] = lev
                endif
                
                static if thistype.addBuff.exists then
                    call addBuff(GetUnitById(af), lev)
                endif
                
                static if not thistype.STACKS then
                    static if thistype.onEffect.exists then
                        call onEffect(so, af, lev)
                    endif
                endif
            endloop
        implement CTMEnd
        
        private static method doEnter takes UnitIndex sourceId, UnitIndex entering returns nothing
            local thistype time = affecting[sourceId][entering]
            
            local boolean canEnter
            local boolean wasActive
            
            local integer buffs
            
            local integer lev
            
            static if thistype.absFilter.exists then
                set canEnter = absFilter(sourceId, entering)
            else
                set canEnter = true
            endif
            
            if (0 != entering and GetUnitUserData(GetUnitById(entering)) == entering and canEnter and (0 == time or affectedLevel[time] != level[sourceId])) then
                if (0 == time) then
                    call entering.lock()
                    call sourceId.lock()
                    
                    set time = create(TIMEOUT)
                    
                    set source[time] = sourceId
                    set affected[time] = entering
                    
                    set affectedLevel[time] = 0
                    
                    set affecting[sourceId][entering] = time
                    
                    set auraCount[entering] = auraCount[entering] + 1
                    set auraInstance[sourceId] = auraInstance[sourceId] + 1
                    
                    set wasActive = false
                else
                    set wasActive = active[time]
                endif
                
                set lev = level[sourceId]
                set active[time] = time.isActive(entering, sourceId)
                
                if (active[time]) then
                    if (auraLevel[entering] < lev) then
                        static if thistype.addBuff.exists then
                            if (0 < buffCount[entering]) then
                                call removeBuff(GetUnitById(entering), auraLevel[entering])
                            endif
                        endif
                        
                        static if thistype.addBuff.exists then
                            call addBuff(GetUnitById(entering), lev)
                        endif
                    endif
                    
                    if (not wasActive) then
                        set buffCount[entering] = buffCount[entering] + 1
                        set activeAura[sourceId] = activeAura[sourceId] + 1
                    endif
                    
                    static if thistype.onEndEffect.exists then
                        if (wasActive) then
                            call time.onEndEffect(sourceId, entering, affectedLevel[time])
                        else
                            static if not thistype.STACKS then
                                if (0 != sourceAffected[entering]) then
                                    set buffCount[entering] = buffCount[entering] - 1
                                    set activeAura[source[sourceAffected[entering]]] = activeAura[source[sourceAffected[entering]]] - 1
                                    set active[sourceAffected[entering]] = false
                                    call thistype(sourceAffected[entering]).onEndEffect(source[sourceAffected[entering]], entering, auraLevel[entering])
                                endif
                            endif
                        endif
                    endif
                    
                    set auraLevel[entering] = lev
                    
                    set sourceAffected[entering] = time
                    static if thistype.onEffect.exists then
                        call time.onEffect(sourceId, entering, lev)
                    endif
                elseif (wasActive) then
                    if (sourceAffected[entering] == time) then
                        set auraLevel[entering] = 0
                        set sourceAffected[entering] = 0
                    endif
                    
                    set buffCount[entering] = buffCount[entering] - 1
                    set activeAura[sourceId] = activeAura[sourceId] - 1
                    
                    static if thistype.addBuff.exists then
                        if (0 == buffCount[entering]) then
                            call removeBuff(GetUnitById(entering), auraLevel[entering])
                        endif
                    endif
                    static if thistype.onEndEffect.exists then
                        call time.onEndEffect(sourceId, entering, affectedLevel[time])
                    endif
                endif
                
                set affectedLevel[time] = lev
            endif
        endmethod
        
        private static method onEnter takes nothing returns boolean
            call doEnter(GetEventSourceUnitId(), GetUnitUserData(GetTriggerUnit()))
            return false
        endmethod
        private static method registerRange takes integer sourceId, unit sourceUnit, real range returns nothing
            set onEnterT[sourceId] = RegisterUnitInRangeEvent(function thistype.onEnter, sourceUnit, range)
        endmethod
        private static method checkLevel takes nothing returns boolean
            local thistype sourceId = next[0]
            local integer newLevel
            
            loop
                exitwhen 0 == sourceId
                
                set newLevel = getLevel(sourceId)
                
                if (newLevel != level[sourceId]) then
                    if (0 != range[sourceId]) then
                        call UnregisterUnitInRangeEvent(onEnterT[sourceId])
                    endif
                    
                    set level[sourceId] = newLevel
                    
                    if (0 == newLevel) then
                        set range[sourceId] = 0
                    else
                        set range[sourceId] = getRange(sourceId, newLevel)
                    endif
                    
                    static if thistype.onLevel.exists then
                        call onLevel(sourceId, level[sourceId])
                    endif
                    
                    if (0 != newLevel) then
                        call doEnter(sourceId, sourceId)
                    endif
                    
                    if (0 != range[sourceId]) then
                        call registerRange(sourceId, GetUnitById(sourceId), range[sourceId])
                    endif
                endif
                
                set sourceId = next[sourceId]
            endloop
            
            return false
        endmethod
        private static method addCheck takes UnitIndex sourceId returns nothing
            call sourceId.lock()
            
            set prev[sourceId]=prev[0]
            set next[sourceId]=0
            set next[prev[0]]=sourceId
            set prev[0]=sourceId
        endmethod
        
        static method createAura takes UnitIndex sourceId returns boolean
            local integer newLevel = getLevel(sourceId)
            local unit sourceUnit = GetUnitById(sourceId)
            
            if (not (IsUnitDead(sourceId) or IsUnitReincarnating(sourceId)) and 0 != GetUnitTypeId(sourceUnit) and GetUnitUserData(sourceUnit) == sourceId) then
                call addCheck(sourceId)
                if (0 == newLevel) then
                    set range[sourceId] = 0
                else
                    set range[sourceId] = getRange(sourceId, newLevel)
                endif
                if (newLevel != level[sourceId]) then
                    static if thistype.onLevel.exists then
                        call onLevel(sourceId, newLevel)
                    endif
                    if (0 != newLevel) then
                        call doEnter(sourceId, sourceId)
                    endif
                    if (0 != range[sourceId]) then
                        call registerRange(sourceId, sourceUnit, range[sourceId])
                    endif
                endif
                
                set level[sourceId] = newLevel
            endif
            
            set sourceUnit = null
            
            return false
        endmethod
        
        private static method onIndex takes nothing returns boolean
            set affecting[GetIndexedUnitId()] = Table.create()
            set level[GetIndexedUnitId()] = 0
            set range[GetIndexedUnitId()] = 0
            set onEnterT[GetIndexedUnitId()] = 0
            set sourceAffected[GetIndexedUnitId()] = 0
            return false
        endmethod
        
        private static method onDeath takes nothing returns boolean
            local integer id = GetUnitUserData(GetTriggerUnit())
            if (0 != level[id]) then
                if (0 != range[id]) then
                    call UnregisterUnitInRangeEvent(onEnterT[id])
                endif
                call removeCheck(id)
                set level[id] = 0
            endif
            
            return false
        endmethod
        
        private static method onRevive takes nothing returns boolean
            set level[GetEventUnitId()] = getLevel(GetEventUnitId())
            if (0 != level[GetEventUnitId()]) then
                set range[GetEventUnitId()] = getRange(GetEventUnitId(), level[GetEventUnitId()])
                call addCheck(GetEventUnitId())
                call doEnter(GetEventUnitId(), GetEventUnitId())
                if (0 != range[GetEventUnitId()]) then
                    call registerRange(GetEventUnitId(), GetEventUnit(), getRange(GetEventUnitId(), level[GetEventUnitId()]))
                endif
            endif
            
            return false
        endmethod
        
        private static method onDeindex takes nothing returns boolean
            if (0 != level[GetIndexedUnitId()]) then
                set level[GetIndexedUnitId()] = 0
                call removeCheck(GetIndexedUnitId())
                call affecting[GetIndexedUnitId()].destroy()
                set affecting[GetIndexedUnitId()] = 0
            endif
            return false
        endmethod
        
        private static method onInit takes nothing returns nothing
            call Timer[TIMEOUT].list.register(Condition(function thistype.checkLevel))
            
            static if thistype.ANIMATED_BESTOW_AURA then
                call InitModule(function thistype.onIndex, function thistype.onDeindex, function thistype.onDeath, function thistype.onRevive, true)
            else
                call InitModule(function thistype.onIndex, function thistype.onDeindex, function thistype.onDeath, function thistype.onRevive, false)
            endif
        endmethod
    endmodule
endlibrary


Demo
JASS:

struct tester extends array
    //required
    private static constant real TIMEOUT = .3
    private static constant boolean ANIMATED_BESTOW_AURA = true
    private static constant boolean STACKS = false
    
    private static method getLevel takes UnitIndex sourceId returns integer
    endmethod
    
    private static method getRange takes UnitIndex source, integer level returns real
    endmethod
    
    //optional
    private static method removeBuff takes unit whichUnit, integer level returns nothing
        call UnitRemoveAbility(whichUnit, BUFF_ID) //for level?
    endmethod
    
    private static method addBuff takes unit whichUnit, integer level returns nothing
        call DummyCaster[ABILITY_BUFF_ORDER].castTarget(...)
    endmethod
    
    private static method onLevel takes UnitIndex source, integer level returns nothing
    endmethod
    
    private method onEndEffect takes UnitIndex source, UnitIndex affected, integer level returns nothing
    endmethod
    
    private method onEffect takes UnitIndex source, UnitIndex affected, integer level returns nothing
    endmethod
    
    private method onPeriodicEffect takes UnitIndex source, UnitIndex affected, integer level returns nothing
    endmethod
    
    private static method absFilter takes UnitIndex source, UnitIndex entering returns boolean
    endmethod
    
    private method filter takes UnitIndex source, UnitIndex affected, integer level returns boolean
    endmethod
    
    //required
    implement AuraStruct
    
    //code

    private static method onInit takes nothing returns nothing
        //event registration
    endmethod
endstruct
 

Attachments

  • AuraStruct.w3x
    52 KB · Views: 367
General chit-chat
Help Users
  • No one is chatting at the moment.
  • Varine Varine:
    How can you tell the difference between real traffic and indexing or AI generation bots?
  • The Helper The Helper:
    The bots will show up as users online in the forum software but they do not show up in my stats tracking. I am sure there are bots in the stats but the way alot of the bots treat the site do not show up on the stats
  • Varine Varine:
    I want to build a filtration system for my 3d printer, and that shit is so much more complicated than I thought it would be
  • Varine Varine:
    Apparently ABS emits styrene particulates which can be like .2 micrometers, which idk if the VOC detectors I have can even catch that
  • Varine Varine:
    Anyway I need to get some of those sensors and two air pressure sensors installed before an after the filters, which I need to figure out how to calculate the necessary pressure for and I have yet to find anything that tells me how to actually do that, just the cfm ratings
  • Varine Varine:
    And then I have to set up an arduino board to read those sensors, which I also don't know very much about but I have a whole bunch of crash course things for that
  • Varine Varine:
    These sensors are also a lot more than I thought they would be. Like 5 to 10 each, idk why but I assumed they would be like 2 dollars
  • Varine Varine:
    Another issue I'm learning is that a lot of the air quality sensors don't work at very high ambient temperatures. I'm planning on heating this enclosure to like 60C or so, and that's the upper limit of their functionality
  • Varine Varine:
    Although I don't know if I need to actually actively heat it or just let the plate and hotend bring the ambient temp to whatever it will, but even then I need to figure out an exfiltration for hot air. I think I kind of know what to do but it's still fucking confusing
  • The Helper The Helper:
    Maybe you could find some of that information from AC tech - like how they detect freon and such
  • Varine Varine:
    That's mostly what I've been looking at
  • Varine Varine:
    I don't think I'm dealing with quite the same pressures though, at the very least its a significantly smaller system. For the time being I'm just going to put together a quick scrubby box though and hope it works good enough to not make my house toxic
  • Varine Varine:
    I mean I don't use this enough to pose any significant danger I don't think, but I would still rather not be throwing styrene all over the air
  • The Helper The Helper:
    New dessert added to recipes Southern Pecan Praline Cake https://www.thehelper.net/threads/recipe-southern-pecan-praline-cake.193555/
  • The Helper The Helper:
    Another bot invasion 493 members online most of them bots that do not show up on stats
  • Varine Varine:
    I'm looking at a solid 378 guests, but 3 members. Of which two are me and VSNES. The third is unlisted, which makes me think its a ghost.
    +1
  • The Helper The Helper:
    Some members choose invisibility mode
    +1
  • The Helper The Helper:
    I bitch about Xenforo sometimes but it really is full featured you just have to really know what you are doing to get the most out of it.
  • The Helper The Helper:
    It is just not easy to fix styles and customize but it definitely can be done
  • The Helper The Helper:
    I do know this - xenforo dropped the ball by not keeping the vbulletin reputation comments as a feature. The loss of the Reputation comments data when we switched to Xenforo really was the death knell for the site when it came to all the users that left. I know I missed it so much and I got way less interested in the site when that feature was gone and I run the site.
  • Blackveiled Blackveiled:
    People love rep, lol
    +1
  • The Helper The Helper:
    The recipe today is Sloppy Joe Casserole - one of my faves LOL https://www.thehelper.net/threads/sloppy-joe-casserole-with-manwich.193585/
  • The Helper The Helper:
    Decided to put up a healthier type recipe to mix it up - Honey Garlic Shrimp Stir-Fry https://www.thehelper.net/threads/recipe-honey-garlic-shrimp-stir-fry.193595/

      The Helper Discord

      Staff online

      • Ghan
        Administrator - Servers are fun

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top