• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[General] Nes DDS Installation

Status
Not open for further replies.
Level 7
Joined
Feb 9, 2021
Messages
301
I am still trying to install Nes DDS into my map. One of the thing that I had to change is to use [System] UnitDex - Unit Indexer instead of Nes UnitIndexer (nestharus/JASS). However, I get an error for some reason, which does not make sense to me. I put Nes code in the comments. GetUnitById should return unit not integer, as shown in the error.

JASS:
library DamageEventArchetype /* v1.0.2.0
*************************************************************************************
*
*   Damage Event Archetype plugin for DDS
*
*
*   Notes
*   --------------
*
*       -   Must invert Damage Return Factor for Locust Swarm based abilities
*
*       -   Must invert healing portion of Life Drain based abilities
*
*************************************************************************************
*
*   */uses/*
*
*       */ DDS                      /*      hiveworkshop.com/forums/spells-569/framework-dds-damage-detection-system-231238/
*       */ DamageEventModification  /*      hiveworkshop.com/forums/jass-resources-412/dds-plugin-damage-event-modification-231176/
        */ UnitDex                  /*
*
************************************************************************************
*
*   SETTINGS
*/
globals
    /*************************************************************************************
    *
    *   Configure to spell reduction ability type id
    *
    *************************************************************************************/
    constant integer DAMAGE_EVENT_ARCHETYPE_PLUGIN_ABILITY = 'A002'
endglobals
/*
*************************************************************************************
*
*   API
*
*       static constant integer Archetype.SPELL
*       static constant integer Archetype.PHYSICAL
*       static constant integer Archetype.CODE
*
*       readonly static integer archetype
*           -   type of damage source damage came from: SPELL, PHYSICAL, CODE
*
*       static UnitIndex damageCode
*           -   set this to the unit that will be damaged with code
*
*       seals (can no longer be overwritten)
*
*           boolean enabled (from DDS Framework)
*
*************************************************************************************/
    //! textmacro DAMAGE_EVENT_ARCHETYPE_CODE
    globals
        private constant boolean ENABLED_EXISTS = true
  
        private real scale
    endglobals

    scope Archetype
        private struct DamageEventArchtype extends array
            static constant integer SPELL = 0
            static constant integer PHYSICAL = 1
            static constant integer CODE = 2
        endstruct

        /*
        *   DDS API
        *
        *       DDS.Archetype.SPELL
        *       DDS.Archetype.PHYSICAL
        *       DDS.Archetype.CODE
        *       DDS.archetype
        *       DDS.damageCode
        * 
        */
            private keyword archetype_p
            private keyword damageEventArchetypeInit
            private keyword damageCode_p
            module DAMAGE_EVENT_ARCHETYPE_API
                readonly static DamageEventArchtype Archetype = 0
                static integer archetype_p = 0
                static UnitIndex damageCode_p = 0
          
                static method operator damageCode= takes UnitIndex u returns nothing
                    set damageCode_p = u
                endmethod
                static method operator damageCode takes nothing returns UnitIndex
                    return damageCode_p
                endmethod
          
                static method operator archetype takes nothing returns integer
                    return archetype_p
                endmethod
          
                private static method onIndex takes nothing returns boolean
                    call UnitAddAbility(UnitIndexer.eventUnit, DAMAGE_EVENT_ARCHETYPE_PLUGIN_ABILITY)
                    call UnitMakeAbilityPermanent(UnitIndexer.eventUnit, true, DAMAGE_EVENT_ARCHETYPE_PLUGIN_ABILITY)
              
                    return false
                endmethod
          
                static method damageEventArchetypeInit takes nothing returns nothing
                    local integer playerId
      
                    set playerId = 15
                    loop
                        call SetPlayerAbilityAvailable(Player(playerId), DAMAGE_EVENT_ARCHETYPE_PLUGIN_ABILITY, false)
                  
                        exitwhen 0 == playerId
                        set playerId = playerId - 1
                    endloop
                    call RegisterUnitIndexEvent(Filter(function thistype.onIndex)  , EVENT_UNIT_INDEX)
                    //call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onIndex))
                endmethod
            endmodule
            module DAMAGE_EVENT_ENABLE
                method operator enabled= takes boolean b returns nothing
                    if (b) then
                        call EnableTrigger(RefreshTrigger(this).parent.trigger)
                        call UnitAddAbility(GetUnitById(this), DAMAGE_EVENT_ARCHETYPE_PLUGIN_ABILITY)
                        call UnitMakeAbilityPermanent(GetUnitById(this), true, DAMAGE_EVENT_ARCHETYPE_PLUGIN_ABILITY)
                        //call UnitAddAbility(UnitIndex(this).unit, DAMAGE_EVENT_ARCHETYPE_PLUGIN_ABILITY)
                        //call UnitMakeAbilityPermanent(UnitIndex(this).unit, true, DAMAGE_EVENT_ARCHETYPE_PLUGIN_ABILITY)
                    else
                        call DisableTrigger(RefreshTrigger(this).parent.trigger)
                        call UnitRemoveAbility(GetUnitById(this), DAMAGE_EVENT_ARCHETYPE_PLUGIN_ABILITY)
                        //call UnitRemoveAbility(UnitIndex(this).unit, DAMAGE_EVENT_ARCHETYPE_PLUGIN_ABILITY)
                    endif
                endmethod
            endmodule
            module DAMAGE_EVENT_ARCHETYPE_INIT
                call DDS.damageEventArchetypeInit()
            endmodule

        /*
        *   DDS Interface
        */
        module DAMAGE_EVENT_ARCHETYPE_INTERFACE
      
        endmodule

        /*
        *   DDS Event Handling
        */
module DAMAGE_EVENT_ARCHETYPE_RESPONSE_LOCALS
                local integer prevArchetype = archetype_p
endmodule
module DAMAGE_EVENT_ARCHETYPE_RESPONSE_BEFORE
                if (damage_p < 0) then
                    set archetype_p = Archetype.SPELL
              
                    /*
                    *   Calculate spell resistance
                    */
                    call DisableTrigger(RefreshTrigger(targetId_p).parent.trigger)
              
                        set life = GetWidgetLife(u)
                        set scale = GetUnitState(u, UNIT_STATE_MAX_LIFE)
                        call SetWidgetLife(u, scale)
                        call UnitDamageTarget(killUnit, u, -scale/2, false, false, null, DAMAGE_TYPE_UNIVERSAL, null)
                        set scale = 2*(scale - GetWidgetLife(u))/scale
                        if (scale > 1) then
                            set damageOriginal = -damageOriginal*scale
                        else
                            set damageOriginal = -damageOriginal
                        endif
                        call SetWidgetLife(u, life)
              
                    call EnableTrigger(RefreshTrigger(targetId_p).parent.trigger)
              
                    set damage_p = damageOriginal
                else
                    set archetype_p = Archetype.PHYSICAL
                endif

                if (damageCode_p != 0) then
                    set archetype_p = Archetype.CODE
                    set damageCode_p = 0
                endif
endmodule
module DAMAGE_EVENT_ARCHETYPE_RESPONSE
          
endmodule
module DAMAGE_EVENT_ARCHETYPE_RESPONSE_AFTER
          
endmodule
module DAMAGE_EVENT_ARCHETYPE_RESPONSE_CLEANUP
                set archetype_p = prevArchetype
endmodule
    endscope
    //! endtextmacro
endlibrary

1621169328192.png

I also get another error when my hero start to attack neutral units:
1621172494787.png

JASS:
library Trigger /* v1.1.0.1
************************************************************************************
*
*   */ uses /*
*   
*       */ ErrorMessage         /*
*       */ BooleanExpression    /*
*       */ NxListT              /*
*        */ UniqueNxListT        /*
*       */ Init                 /*
*
************************************************************************************
*
*   struct Trigger extends array
*           
*       Fields
*       -------------------------
*
*           readonly trigger trigger
*               -   use to register events, nothing else
*               -   keep in mind that triggers referencing this trigger won't fire when events fire
*               -   this trigger will fire when triggers referencing this trigger are fired
*
*           boolean enabled
*
*       Methods
*       -------------------------
*
*           static method create takes boolean reversed returns Trigger
*                -    when reverse is true, the entire expression is run in reverse
*
*           method destroy takes nothing returns nothing
*
*           method register takes boolexpr expression returns TriggerCondition
*
*           method reference takes Trigger trig returns TriggerReference
*               -   like register, but for triggers instead
*
*           method fire takes nothing returns nothing
*
*           method clear takes nothing returns nothing
*               -   clears expressions
*           method clearReferences takes nothing returns nothing
*               -   clears trigger references
*           method clearBackReferences takes nothing returns nothing
*               -   removes references for all triggers referencing this trigger
*           method clearEvents takes nothing returns nothing
*               -   clears events
*
*           debug static method calculateMemoryUsage takes nothing returns integer
*           debug static method getAllocatedMemoryAsString takes nothing returns string
*
************************************************************************************
*
*   struct TriggerReference extends array
*           
*       Methods
*       -------------------------
*
*           method destroy takes nothing returns nothing
*
*           method replace takes Trigger trigger returns nothing
*
************************************************************************************
*
*   struct TriggerCondition extends array
*
*       Methods
*       -------------------------
*
*           method destroy takes nothing returns nothing
*
*           method replace takes boolexpr expr returns nothing
*
************************************************************************************/
    private struct TriggerMemory extends array
        //! runtextmacro CREATE_TABLE_FIELD("public", "trigger", "trig", "trigger")
        //! runtextmacro CREATE_TABLE_FIELD("public", "triggercondition", "tc", "triggercondition")
        
        //! runtextmacro CREATE_TABLE_FIELD("public", "integer", "expression", "BooleanExpression")                 //the trigger's expression
        
        //! runtextmacro CREATE_TABLE_FIELD("public", "boolean", "enabled", "boolean")
        
        method updateTrigger takes nothing returns nothing
            if (tc != null) then
                call TriggerRemoveCondition(trig, tc)
            endif
        
            if (enabled and expression.expression != null) then
                set tc = TriggerAddCondition(trig, expression.expression)
            else
                call tc_clear()
            endif
        endmethod
        
        private static method init takes nothing returns nothing
            //! runtextmacro INITIALIZE_TABLE_FIELD("trig")
            //! runtextmacro INITIALIZE_TABLE_FIELD("tc")
            
            //! runtextmacro INITIALIZE_TABLE_FIELD("expression")
            
            //! runtextmacro INITIALIZE_TABLE_FIELD("enabled")
        endmethod
        
        implement Init
    endstruct

    private struct TriggerAllocator extends array
        implement AllocT
    endstruct
    
    private keyword TriggerReferencedList
    
    private struct TriggerReferenceListData extends array
        //! runtextmacro CREATE_TABLE_FIELD("public", "integer", "trig", "TriggerMemory")           //the referenced trigger
        //! runtextmacro CREATE_TABLE_FIELD("public", "integer", "ref", "TriggerReferencedList")    //the TriggerReferencedList data for that trigger (relationship in 2 places)
        //! runtextmacro CREATE_TABLE_FIELD("public", "integer", "expr", "BooleanExpression")
    
        implement NxListT
        
        private static method init takes nothing returns nothing
            //! runtextmacro INITIALIZE_TABLE_FIELD("trig")
            //! runtextmacro INITIALIZE_TABLE_FIELD("ref")
            //! runtextmacro INITIALIZE_TABLE_FIELD("expr")
        endmethod
        
        implement Init
    endstruct

    /*
    *   List of triggers referencing current trigger
    */
    private struct TriggerReferencedList extends array
        //! runtextmacro CREATE_TABLE_FIELD("public", "integer", "trig", "TriggerMemory")               //the trigger referencing this trigger
        //! runtextmacro CREATE_TABLE_FIELD("public", "integer", "ref", "TriggerReferenceListData")     //the ref 
    
        implement NxListT
        
        method updateExpression takes nothing returns nothing
            local thistype node
            local boolexpr expr
            
            /*
            *   Retrieve the expression of the referenced trigger
            */
            if (TriggerMemory(this).enabled) then
                set expr = TriggerMemory(this).expression.expression
            else
                set expr = null
            endif
            
            /*
            *   Iterate over all triggers referencing this trigger
            */
            set node = first
            loop
                exitwhen node == 0
                
                /*
                *   Replace expression and then update the target trigger
                */
                call node.ref.expr.replace(expr)
                call node.trig.updateTrigger()
                call TriggerReferencedList(node.trig).updateExpression()
                
                set node = node.next
            endloop
            
            set expr = null
        endmethod
        
        method purge takes nothing returns nothing
            local thistype node = first
            
            loop
                exitwhen node == 0
                
                /*
                *   Unregister the expression from the referencing trigger
                *   Update that trigger
                */
                call node.ref.expr.unregister()
                call node.trig.updateTrigger()
                call node.ref.remove()
                call TriggerReferencedList(node.trig).updateExpression()
                
                set node = node.next
            endloop
            
            call destroy()
        endmethod
        
        method clearReferences takes nothing returns nothing
            local thistype node = first
            
            loop
                exitwhen node == 0
                
                /*
                *   Unregister the expression from the referencing trigger
                *   Update that trigger
                */
                call node.ref.expr.unregister()
                call node.trig.updateTrigger()
                call node.ref.remove()
                call TriggerReferencedList(node.trig).updateExpression()
                
                set node = node.next
            endloop
            
            call clear()
        endmethod
        
        private static method init takes nothing returns nothing
            //! runtextmacro INITIALIZE_TABLE_FIELD("trig")
            //! runtextmacro INITIALIZE_TABLE_FIELD("ref")
        endmethod
        
        implement Init
    endstruct
    
    /*
    *   List of triggers current trigger references
    */
    private struct TriggerReferenceList extends array
        method add takes TriggerReferencedList trig returns thistype
            local TriggerReferenceListData node = TriggerReferenceListData(this).enqueue()
            
            /*
            *   Register the trigger as a reference
            */
            set node.trig = trig
            set node.ref = TriggerReferencedList(trig).enqueue()
            set node.ref.trig = this
            set node.ref.ref = node
            
            /*
            *   Add the reference's expression
            *
            *   Add even if null to ensure correct order
            */
            if (TriggerMemory(trig).enabled) then
                set node.expr = TriggerMemory(this).expression.register(TriggerMemory(trig).expression.expression)
            else
                set node.expr = TriggerMemory(this).expression.register(null)
            endif
            
            call TriggerMemory(this).updateTrigger()
            
            /*
            *   Update the expressions of triggers referencing this trigger
            */
            call TriggerReferencedList(this).updateExpression()
            
            /*
            *   Return the reference
            */
            return node
        endmethod
        
        method erase takes nothing returns nothing
            local TriggerReferenceListData node = this          //the node
            set this = node.ref.trig                            //this trigger        
            
            call node.expr.unregister()
            call TriggerMemory(this).updateTrigger()
            call TriggerReferencedList(this).updateExpression()
            
            call node.ref.remove()
            call node.remove()
        endmethod
        
        method replace takes TriggerMemory trig returns nothing
            local TriggerReferenceListData node = this
            set this = node.list
            
            call node.ref.remove()
            
            set node.trig = trig
            set node.ref = TriggerReferencedList(trig).enqueue()
            set node.ref.trig = this
            set node.ref.ref = node
            
            if (trig.enabled) then
                call node.expr.replace(trig.expression.expression)
            else
                call node.expr.replace(null)
            endif
            
            call TriggerMemory(this).updateTrigger()
            
            call TriggerReferencedList(this).updateExpression()
        endmethod
        
        /*
        *   Purges all references
        */
        method purge takes nothing returns nothing
            local TriggerReferenceListData node = TriggerReferenceListData(this).first
            
            loop
                exitwhen node == 0
                
                /*
                *   Removes the reference from the referenced list
                *   (triggers no longer referenced by this)
                */
                call node.ref.remove()
                
                set node = node.next
            endloop
            
            /*
            *   Destroy all references by triggers referencing this
            */
            call TriggerReferencedList(this).purge()
            
            call TriggerReferenceListData(this).destroy()
        endmethod
        
        method clearReferences takes nothing returns nothing
            local TriggerReferenceListData node = TriggerReferenceListData(this).first
            
            loop
                exitwhen node == 0
                
                /*
                *   Removes the reference from the referenced list
                *   (triggers no longer referenced by this)
                */
                call node.ref.remove()
                
                /*
                *    unregisters code
                */
                call node.expr.unregister()
                
                set node = node.next
            endloop
            
            call TriggerReferenceListData(this).clear()
        endmethod
    endstruct
    
    private struct TriggerReferenceData extends array
        static if DEBUG_MODE then
            //! runtextmacro CREATE_TABLE_FIELD("private", "boolean", "isTriggerReference", "boolean")
        endif
        
        static method create takes TriggerReferenceList origin, TriggerMemory ref returns thistype
            local thistype this = origin.add(ref)
            
            debug set isTriggerReference = true
            
            return this
        endmethod
        
        method destroy takes nothing returns nothing
            debug call ThrowError(this == 0,                "Trigger", "destroy", "TriggerReferenceData", this, "Attempted To Destroy Null TriggerReferenceData.")
            debug call ThrowError(not isTriggerReference,   "Trigger", "destroy", "TriggerReferenceData", this, "Attempted To Destroy Invalid TriggerReferenceData.")
            
            debug set isTriggerReference = false
            
            call TriggerReferenceList(this).erase()
        endmethod
        
        method replace takes Trigger trig returns nothing
            debug call ThrowError(this == 0,                "Trigger", "destroy", "TriggerReferenceData", this, "Attempted To Destroy Null TriggerReferenceData.")
            debug call ThrowError(not isTriggerReference,   "Trigger", "destroy", "TriggerReferenceData", this, "Attempted To Destroy Invalid TriggerReferenceData.")
            
            call TriggerReferenceList(this).replace(trig)
        endmethod
        
        private static method init takes nothing returns nothing
            static if DEBUG_MODE then
                //! runtextmacro INITIALIZE_TABLE_FIELD("isTriggerReference")
            endif
        endmethod
        
        implement Init
    endstruct
    
    private struct TriggerConditionDataCollection extends array
        implement UniqueNxListT
    endstruct
    
    private struct TriggerConditionData extends array
        static if DEBUG_MODE then
            //! runtextmacro CREATE_TABLE_FIELD("private", "boolean", "isCondition", "boolean")
        endif
        
        //! runtextmacro CREATE_TABLE_FIELD("private", "integer", "trig", "TriggerMemory")
        
        private static method updateTrigger takes TriggerMemory trig returns nothing
            call trig.updateTrigger()
            call TriggerReferencedList(trig).updateExpression()
        endmethod
    
        static method create takes TriggerMemory trig, boolexpr expression returns thistype
            local thistype this = trig.expression.register(expression)
            
            set this.trig = trig
            
            debug set isCondition = true
            
            call TriggerConditionDataCollection(trig).enqueue(this)
            
            call updateTrigger(trig)
            
            return this
        endmethod
        
        method destroy takes nothing returns nothing
            debug call ThrowError(this == 0,        "Trigger", "destroy", "TriggerConditionData", this, "Attempted To Destroy Null TriggerConditionData.")
            debug call ThrowError(not isCondition,  "Trigger", "destroy", "TriggerConditionData", this, "Attempted To Destroy Invalid TriggerConditionData.")
            
            call BooleanExpression(this).unregister()
            
            call TriggerConditionDataCollection(this).remove()
            
            debug set isCondition = false
            
            /*
            *   Update the expression
            */
            call updateTrigger(trig)
        endmethod
        
        method replace takes boolexpr expr returns nothing
            debug call ThrowError(this == 0,        "Trigger", "destroy", "TriggerConditionData", this, "Attempted To Destroy Null TriggerConditionData.")
            debug call ThrowError(not isCondition,  "Trigger", "destroy", "TriggerConditionData", this, "Attempted To Destroy Invalid TriggerConditionData.")
            
            call BooleanExpression(this).replace(expr)
            
            call updateTrigger(trig)
        endmethod
        
        private static method init takes nothing returns nothing
            static if DEBUG_MODE then
                //! runtextmacro INITIALIZE_TABLE_FIELD("isCondition")
            endif
            
            //! runtextmacro INITIALIZE_TABLE_FIELD("trig")
        endmethod
        
        implement Init
    endstruct
    
    struct TriggerReference extends array
        method destroy takes nothing returns nothing
            call TriggerReferenceData(this).destroy()
        endmethod
        method replace takes Trigger trig returns nothing
            call TriggerReferenceData(this).replace(trig)
        endmethod
    endstruct
    
    struct TriggerCondition extends array
        method destroy takes nothing returns nothing
            call TriggerConditionData(this).destroy()
        endmethod
        method replace takes boolexpr expr returns nothing
            call TriggerConditionData(this).replace(expr)
        endmethod
    endstruct
    
    struct Trigger extends array
        static if DEBUG_MODE then
            //! runtextmacro CREATE_TABLE_FIELD("private", "boolean", "isTrigger", "boolean")
        endif
    
        static method create takes boolean reversed returns thistype
            local thistype this = TriggerAllocator.allocate()
            
            debug set isTrigger = true
            
            set TriggerMemory(this).enabled = true
            
            call TriggerReferencedList(this).clear()
            call TriggerReferenceListData(this).clear()
            call TriggerConditionDataCollection(this).clear()
            
            set TriggerMemory(this).expression = BooleanExpression.create(reversed)
            
            set TriggerMemory(this).trig = CreateTrigger()
            
            return this
        endmethod
        
        static if DEBUG_MODE then
            method destroy takes nothing returns nothing
                call destroy_p()
            endmethod
        
            private method destroy_p takes nothing returns nothing
                debug call ThrowError(this == 0,        "Trigger", "destroy", "Trigger", this, "Attempted To Destroy Null Trigger.")
                debug call ThrowError(not isTrigger,    "Trigger", "destroy", "Trigger", this, "Attempted To Destroy Invalid Trigger.")
                
                debug set isTrigger = false
            
                call TriggerReferenceList(this).purge()
                call TriggerConditionDataCollection(this).destroy()
                
                if (TriggerMemory(this).tc != null) then
                    call TriggerRemoveCondition(TriggerMemory(this).trig, TriggerMemory(this).tc)
                endif
                call TriggerMemory(this).tc_clear()
                call DestroyTrigger(TriggerMemory(this).trig)
                call TriggerMemory(this).trig_clear()
                
                call TriggerMemory(this).expression.destroy()
                
                call TriggerAllocator(this).deallocate()
            endmethod
        else
            method destroy takes nothing returns nothing
                debug call ThrowError(this == 0,        "Trigger", "destroy", "Trigger", this, "Attempted To Destroy Null Trigger.")
                debug call ThrowError(not isTrigger,    "Trigger", "destroy", "Trigger", this, "Attempted To Destroy Invalid Trigger.")
                
                debug set isTrigger = false
            
                call TriggerReferenceList(this).purge()
                call TriggerConditionDataCollection(this).destroy()
                
                if (TriggerMemory(this).tc != null) then
                    call TriggerRemoveCondition(TriggerMemory(this).trig, TriggerMemory(this).tc)
                endif
                call TriggerMemory(this).tc_clear()
                call DestroyTrigger(TriggerMemory(this).trig)
                call TriggerMemory(this).trig_clear()
                
                call TriggerMemory(this).expression.destroy()
                
                call TriggerAllocator(this).deallocate()
            endmethod
        endif

        static if DEBUG_MODE then
            method register takes boolexpr expression returns TriggerCondition
                return register_p(expression)
            endmethod
            private method register_p takes boolexpr expression returns TriggerCondition
                debug call ThrowError(this == 0,            "Trigger", "register", "Trigger", this, "Attempted To Register To Null Trigger.")
                debug call ThrowError(not isTrigger,        "Trigger", "register", "Trigger", this, "Attempted To Register To Invalid Trigger.")
            
                /*
                *   Register the expression
                */
                return TriggerConditionData.create(this, expression)
            endmethod
        else
            method register takes boolexpr expression returns TriggerCondition
                debug call ThrowError(this == 0,            "Trigger", "register", "Trigger", this, "Attempted To Register To Null Trigger.")
                debug call ThrowError(not isTrigger,        "Trigger", "register", "Trigger", this, "Attempted To Register To Invalid Trigger.")
            
                /*
                *   Register the expression
                */
                return TriggerConditionData.create(this, expression)
            endmethod
        endif
        
        static if DEBUG_MODE then
            method clear takes nothing returns nothing
                call clear_p()
            endmethod
            private method clear_p takes nothing returns nothing
                local TriggerConditionDataCollection node = TriggerConditionDataCollection(this).first
            
                debug call ThrowError(this == 0,        "Trigger", "clear", "Trigger", this, "Attempted To Clear Null Trigger.")
                debug call ThrowError(not isTrigger,    "Trigger", "clear", "Trigger", this, "Attempted To Clear Invalid Trigger.")
                
                loop
                    exitwhen node == 0
                    
                    call BooleanExpression(node).unregister()
                    
                    set node = node.next
                endloop
                
                call TriggerConditionDataCollection(this).clear()
                
                call TriggerMemory(this).updateTrigger()
                call TriggerReferencedList(this).updateExpression()
            endmethod
        else
            method clear takes nothing returns nothing
                local TriggerConditionDataCollection node = TriggerConditionDataCollection(this).first
            
                debug call ThrowError(this == 0,        "Trigger", "clear", "Trigger", this, "Attempted To Clear Null Trigger.")
                debug call ThrowError(not isTrigger,    "Trigger", "clear", "Trigger", this, "Attempted To Clear Invalid Trigger.")
                
                loop
                    exitwhen node == 0
                    
                    call BooleanExpression(node).unregister()
                    
                    set node = node.next
                endloop
                
                call TriggerConditionDataCollection(this).clear()
                
                call TriggerMemory(this).updateTrigger()
                call TriggerReferencedList(this).updateExpression()
            endmethod
        endif
        
        static if DEBUG_MODE then
            method clearReferences takes nothing returns nothing
                call clearReferences_p()
            endmethod
            private method clearReferences_p takes nothing returns nothing
                debug call ThrowError(this == 0,        "Trigger", "clearReferences", "Trigger", this, "Attempted To Clear References Of Null Trigger.")
                debug call ThrowError(not isTrigger,    "Trigger", "clearReferences", "Trigger", this, "Attempted To Clear References Of Invalid Trigger.")
                
                call TriggerReferenceList(this).clearReferences()
                
                call TriggerMemory(this).updateTrigger()
                call TriggerReferencedList(this).updateExpression()
            endmethod
        else
            method clearReferences takes nothing returns nothing
                debug call ThrowError(this == 0,        "Trigger", "clearReferences", "Trigger", this, "Attempted To Clear References Of Null Trigger.")
                debug call ThrowError(not isTrigger,    "Trigger", "clearReferences", "Trigger", this, "Attempted To Clear References Of Invalid Trigger.")
                
                call TriggerReferenceList(this).clearReferences()
                
                call TriggerMemory(this).updateTrigger()
                call TriggerReferencedList(this).updateExpression()
            endmethod
        endif
        
        static if DEBUG_MODE then
            method clearBackReferences takes nothing returns nothing
                call clearBackReferences_p()
            endmethod
            
            private method clearBackReferences_p takes nothing returns nothing
                debug call ThrowError(this == 0,        "Trigger", "clearReferences", "Trigger", this, "Attempted To Clear Back References Of Null Trigger.")
                debug call ThrowError(not isTrigger,    "Trigger", "clearReferences", "Trigger", this, "Attempted To Clear Back References Of Invalid Trigger.")
                
                call TriggerReferencedList(this).clearReferences()
            endmethod
        else
            method clearBackReferences takes nothing returns nothing
                debug call ThrowError(this == 0,        "Trigger", "clearReferences", "Trigger", this, "Attempted To Clear Back References Of Null Trigger.")
                debug call ThrowError(not isTrigger,    "Trigger", "clearReferences", "Trigger", this, "Attempted To Clear Back References Of Invalid Trigger.")
                
                call TriggerReferencedList(this).clearReferences()
            endmethod
        endif
        
        static if DEBUG_MODE then
            method reference takes thistype trig returns TriggerReference
                return reference_p(trig)
            endmethod
            
            private method reference_p takes thistype trig returns TriggerReference
                debug call ThrowError(this == 0,            "Trigger", "reference", "Trigger", this, "Attempted To Make Null Trigger Reference Trigger.")
                debug call ThrowError(not isTrigger,        "Trigger", "reference", "Trigger", this, "Attempted To Make Invalid Trigger Reference Trigger.")
                debug call ThrowError(trig == 0,            "Trigger", "reference", "Trigger", this, "Attempted To Reference Null Trigger (" + I2S(trig) + ").")
                debug call ThrowError(not trig.isTrigger,   "Trigger", "reference", "Trigger", this, "Attempted To Reference Invalid Trigger (" + I2S(trig) + ").")
                
                return TriggerReferenceData.create(this, trig)
            endmethod
        else
            method reference takes thistype trig returns TriggerReference
                debug call ThrowError(this == 0,            "Trigger", "reference", "Trigger", this, "Attempted To Make Null Trigger Reference Trigger.")
                debug call ThrowError(not isTrigger,        "Trigger", "reference", "Trigger", this, "Attempted To Make Invalid Trigger Reference Trigger.")
                debug call ThrowError(trig == 0,            "Trigger", "reference", "Trigger", this, "Attempted To Reference Null Trigger (" + I2S(trig) + ").")
                debug call ThrowError(not trig.isTrigger,   "Trigger", "reference", "Trigger", this, "Attempted To Reference Invalid Trigger (" + I2S(trig) + ").")
                
                return TriggerReferenceData.create(this, trig)
            endmethod
        endif
        
        static if DEBUG_MODE then
            method clearEvents takes nothing returns nothing
                call clearEvents_p()
            endmethod
            
            private method clearEvents_p takes nothing returns nothing
                debug call ThrowError(this == 0,        "Trigger", "clearEvents", "Trigger", this, "Attempted To Clear Events Of Null Trigger.")
                debug call ThrowError(not isTrigger,    "Trigger", "clearEvents", "Trigger", this, "Attempted To Clear Events Of Invalid Trigger.")
            
                if (TriggerMemory(this).tc != null) then
                    call TriggerRemoveCondition(TriggerMemory(this).trig, TriggerMemory(this).tc)
                endif
                call DestroyTrigger(TriggerMemory(this).trig)
                
                set TriggerMemory(this).trig = CreateTrigger()
                if (TriggerMemory(this).enabled) then
                    set TriggerMemory(this).tc = TriggerAddCondition(TriggerMemory(this).trig, TriggerMemory(this).expression.expression)
                else
                    call TriggerMemory(this).tc_clear()
                endif
            endmethod
        else
            method clearEvents takes nothing returns nothing
                debug call ThrowError(this == 0,        "Trigger", "clearEvents", "Trigger", this, "Attempted To Clear Events Of Null Trigger.")
                debug call ThrowError(not isTrigger,    "Trigger", "clearEvents", "Trigger", this, "Attempted To Clear Events Of Invalid Trigger.")
            
                if (TriggerMemory(this).tc != null) then
                    call TriggerRemoveCondition(TriggerMemory(this).trig, TriggerMemory(this).tc)
                endif
                call DestroyTrigger(TriggerMemory(this).trig)
                
                set TriggerMemory(this).trig = CreateTrigger()
                if (TriggerMemory(this).enabled) then
                    set TriggerMemory(this).tc = TriggerAddCondition(TriggerMemory(this).trig, TriggerMemory(this).expression.expression)
                else
                    call TriggerMemory(this).tc_clear()
                endif
            endmethod
        endif
        
        method fire takes nothing returns nothing
            debug call ThrowError(this == 0,        "Trigger", "fire", "Trigger", this, "Attempted To Fire Null Trigger.")
            debug call ThrowError(not isTrigger,    "Trigger", "fire", "Trigger", this, "Attempted To Fire Invalid Trigger.")
        
            call TriggerEvaluate(TriggerMemory(this).trig)
        endmethod
        
        method operator trigger takes nothing returns trigger
            debug call ThrowError(this == 0,        "Trigger", "trigger", "Trigger", this, "Attempted To Read Null Trigger.")
            debug call ThrowError(not isTrigger,    "Trigger", "trigger", "Trigger", this, "Attempted To Read Invalid Trigger.")
        
            return TriggerMemory(this).trig
        endmethod
        
        method operator enabled takes nothing returns boolean
            debug call ThrowError(this == 0,                                "Trigger", "enabled", "Trigger", this, "Attempted To Read Null Trigger.")
            debug call ThrowError(not isTrigger,                            "Trigger", "enabled", "Trigger", this, "Attempted To Read Invalid Trigger.")
            
            return TriggerMemory(this).enabled
        endmethod
        
        static if DEBUG_MODE then
            method operator enabled= takes boolean enable returns nothing
                set enabled_p = enable
            endmethod
            private method operator enabled_p= takes boolean enable returns nothing
                debug call ThrowError(this == 0,                                "Trigger", "enabled=", "Trigger", this, "Attempted To Set Null Trigger.")
                debug call ThrowError(not isTrigger,                            "Trigger", "enabled=", "Trigger", this, "Attempted To Set Invalid Trigger.")
                debug call ThrowWarning(TriggerMemory(this).enabled == enable,  "Trigger", "enabled=", "Trigger", this, "Setting Enabled To Its Value.")
            
                set TriggerMemory(this).enabled = enable
                
                call TriggerMemory(this).updateTrigger()
                call TriggerReferencedList(this).updateExpression()
            endmethod
        else
            method operator enabled= takes boolean enable returns nothing
                debug call ThrowError(this == 0,                                "Trigger", "enabled=", "Trigger", this, "Attempted To Set Null Trigger.")
                debug call ThrowError(not isTrigger,                            "Trigger", "enabled=", "Trigger", this, "Attempted To Set Invalid Trigger.")
                debug call ThrowWarning(TriggerMemory(this).enabled == enable,  "Trigger", "enabled=", "Trigger", this, "Setting Enabled To Its Value.")
            
                set TriggerMemory(this).enabled = enable
                
                call TriggerMemory(this).updateTrigger()
                call TriggerReferencedList(this).updateExpression()
            endmethod
        endif
        
        static if DEBUG_MODE then
            static method calculateMemoryUsage takes nothing returns integer
                return /*
                */    TriggerAllocator.calculateMemoryUsage() + /*
                */    TriggerConditionDataCollection.calculateMemoryUsage() + /*
                */    TriggerReferenceListData.calculateMemoryUsage() + /*
                */    TriggerReferencedList.calculateMemoryUsage() + /*
                */    BooleanExpression.calculateMemoryUsage()
            endmethod
            
            static method getAllocatedMemoryAsString takes nothing returns string
                return /*
                */    "(Trigger)[" + TriggerAllocator.getAllocatedMemoryAsString() + "], " + /*
                */    "(Trigger TriggerConditionDataCollection)[" + TriggerConditionDataCollection.getAllocatedMemoryAsString() + "], " + /*
                */    "(Trigger Reference)[" + TriggerReferenceListData.getAllocatedMemoryAsString() + "], " + /*
                */    "(Trigger Reference Back)[" + TriggerReferencedList.getAllocatedMemoryAsString() + "], " + /*
                */    "(Boolean Expression (all))[" + BooleanExpression.getAllocatedMemoryAsString() + "]"
            endmethod
        endif
        
        private static method init takes nothing returns nothing
            static if DEBUG_MODE then
                //! runtextmacro INITIALIZE_TABLE_FIELD("isTrigger")
            endif
        endmethod
        
        implement Init
    endstruct
endlibrary
 
Last edited:
+1 to that recommendation^. To fix your issue, it looks like UnitIndexer.eventIndex is the issue--that's a variable in Nestharus' system that represents the index of the unit--but you'd want to convert that index to a unit before trying to add an ability to it.

In TriggerHappy's system, you get the indexed unit a bit differently. You should update your method to use GetIndexedUnit():
JASS:
                private static method onIndex takes nothing returns boolean
                    call UnitAddAbility(GetIndexedUnit(), DAMAGE_EVENT_ARCHETYPE_PLUGIN_ABILITY)
                    call UnitMakeAbilityPermanent(GetIndexedUnit(), true, DAMAGE_EVENT_ARCHETYPE_PLUGIN_ABILITY)
              
                    return false
                endmethod

For the second error--that's just a warning that appears when you're debugging the map. If you want to find the root cause, you'll want to search your map for fire() calls and add debug messages to track down where exactly it's being called with a null trigger.
 
Level 7
Joined
Feb 9, 2021
Messages
301
While this doesn't solve your issue, you could consider a switch to using Bribe's Damage Engine, as I think it is the most well maintained DDS. It also doesn't need a Unit Indexing system and is available for GUI, Lua, and Jass.
+1 to that recommendation^. To fix your issue, it looks like UnitIndexer.eventIndex is the issue--that's a variable in Nestharus' system that represents the index of the unit--but you'd want to convert that index to a unit before trying to add an ability to it.

In TriggerHappy's system, you get the indexed unit a bit differently. You should update your method to use GetIndexedUnit():
JASS:
                private static method onIndex takes nothing returns boolean
                    call UnitAddAbility(GetIndexedUnit(), DAMAGE_EVENT_ARCHETYPE_PLUGIN_ABILITY)
                    call UnitMakeAbilityPermanent(GetIndexedUnit(), true, DAMAGE_EVENT_ARCHETYPE_PLUGIN_ABILITY)
         
                    return false
                endmethod

For the second error--that's just a warning that appears when you're debugging the map. If you want to find the root cause, you'll want to search your map for fire() calls and add debug messages to track down where exactly it's being called with a null trigger.
Thank you for your recommendation. I used Bribe Damage Engine before, but I decided to switch to Nes's engine because it has better functionality. In fact, it seems like the best DDS for vJass users on 1.26.

@PurgeandFire thank you for your advice on UnitIndexer.

Regarding the second error, it is definitely coming from Nes DDS, as I didn't have it before the installation. I assume it happens because I didn't upgrade to UniDex correctly. Since otherwise, Nes DDS should work just fine.

Here is my Updated API for Nes UnitIndexer

JASS:
library UnitIndexer requires UnitDex

    struct UnitIndexer
        readonly static integer INDEX   = EVENT_UNIT_INDEX
        readonly static integer DEINDEX = EVENT_UNIT_DEINDEX
  
        static method operator enabled= takes boolean b returns nothing
            set UnitDex.Enabled=b
        endmethod
  
        static method operator enabled takes nothing returns boolean
            return UnitDex.Enabled
        endmethod
    
        static method eventIndex takes nothing returns integer
            return GetIndexedUnitId()
        endmethod
    
        static method eventUnit takes nothing returns unit
            return GetIndexedUnit()
        endmethod
    endstruct

    module UnitIndexStructMethods
        static method operator [] takes unit u returns thistype
            return GetUnitUserData(u)
        endmethod
  
        method operator unit takes nothing returns unit
            return UnitDex.Unit[this]
        endmethod
    endmodule

    module UnitIndexStruct
        implement UnitIndexStructMethods
  
        method operator allocated takes nothing returns boolean
            return this==GetUnitUserData(UnitDex.Unit[this])
        endmethod
    endmodule

    function IsUnitDeindexing takes unit u returns boolean
        return IsUnitIndexed(u) and 0==GetUnitAbilityLevel(u, UnitDex.DETECT_LEAVE_ABILITY)
    endfunction

    struct UnitIndex extends array
        method lock takes nothing returns nothing
        endmethod
  
        method unlock takes nothing returns nothing
        endmethod
  
        method operator unit takes nothing returns unit
            return UnitDex.Unit[this]
        endmethod
  
        static method operator [] takes unit whichUnit returns thistype
            return GetUnitUserData(whichUnit)
        endmethod
    endstruct

endlibrary

These are only two triggers in which I made changes (change for UnitIndexer). I commented out Nes functions and added mine. Therefore, it should be easy to compare and see if I did something wrong. :

JASS:
library TriggerRefresh /* v1.0.3.0
*************************************************************************************
*
*   Optimal trigger refreshing for unit events. Used in such things as Damage Detection
*   Systems.
*
*   Events are never destroyed. When a unit event is registered to a trigger and that
*   unit no longer exists, the event remains. The trigger has to be recreated in order
*   to clean the leak. This resource recreates triggers in the most optimal manner possible.
*
*   Used in DamageEvent and recommended for all Damage Detection Systems.
*
*   Place the macros in order at the bottom of the DDS Library.
*
*************************************************************************************
*
*   */uses/*
*
*       */ UnitIndexer      /*      hiveworkshop.com/forums/jass-functions-413/unit-indexer-172090/
*       All Requirements of Unit Indexer are not needed as they are included with RefreshTrigger Refresh
*
*************************************************************************************
*
*   //! textmacro TRIGGER_REFRESH takes TRIGGER_SIZE, TRIGGER_EVENT, CODE
*
*       This macro creates the refreshing trigger.
*
*           TRIGGER_SIZE
*               How many units to register to a given trigger. More units = less refreshes, but
*               more fps spikes. A value of 80 is recommended.
*
*           TRIGGER_EVENT
*               The event to register to the trigger. Example: EVENT_UNIT_DAMAGED.
*
*           CODE
*               Registers code to the trigger. Only 1 function may be registered to the trigger.
*
*   private keyword RefreshTrigger
*   RefreshTrigger(UnitIndex).parent.trigger
*       -   enable/disable trigger for specific unit
*
*************************************************************************************
*
*   //quick and dirty DDS
*   library MyDDS
*       private function Core takes nothing returns nothing
*           //will display whenever a unit is damaged
*           call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,R2S(GetEventDamage()))
*       endfunction
*
*       //! runtextmacro TRIGGER_REFRESH("80", "EVENT_UNIT_DAMAGED", "function Core")
*   endlibrary
*
*************************************************************************************/
endlibrary

//! textmacro TRIGGER_REFRESH takes TRIGGER_SIZE, TRIGGER_EVENT, CODE
    scope TriggerRefresh
        globals
            private boolexpr condition
        endglobals
    
        struct RefreshTrigger extends array
            private static integer instanceCount = 0
    
            private thistype first
            private thistype next
            private thistype prev
            readonly thistype parent
        
            private integer inactiveUnits
            readonly integer activeUnits
        
            readonly trigger trigger
        
            private method registerUnit takes UnitIndex whichUnit returns boolean
                if (activeUnits < $TRIGGER_SIZE$) then
                    call TriggerRegisterUnitEvent(trigger, whichUnit.unit, $TRIGGER_EVENT$)
                    set activeUnits = activeUnits + 1
                
                    return true
                endif
            
                return false
            endmethod
            private method unregisterUnit takes nothing returns nothing
                set inactiveUnits = inactiveUnits + 1
                set activeUnits = activeUnits - 1
            endmethod
        
            private method createTrigger takes nothing returns nothing
                set trigger = CreateTrigger()
                call TriggerAddCondition(trigger, condition)
            endmethod
            private method remakeTrigger takes nothing returns nothing
                call DestroyTrigger(trigger)
                call createTrigger()
            endmethod
            private method rebuildTrigger takes nothing returns nothing
                local thistype current = first
            
                call remakeTrigger()
            
                /*
                *   Iterate over all units registered to the trigger and reregister them
                */
                set current.prev.next = 0
                loop
                    exitwhen 0 == current
                    call TriggerRegisterUnitEvent(trigger, UnitIndex(current).unit, $TRIGGER_EVENT$)
                    set current = current.next
                endloop
                set first.prev.next = current
            endmethod
        
            private method remake takes nothing returns nothing
                if (inactiveUnits == $TRIGGER_SIZE$) then
                    set inactiveUnits = 0
                    call rebuildTrigger()
                endif
            endmethod
        
            private method addToList takes thistype whichUnit returns nothing
                set whichUnit.parent = this
        
                if (0 == first) then
                    set first = whichUnit
                    set whichUnit.next = whichUnit
                    set whichUnit.prev = whichUnit
                else
                    set this = first
                
                    set whichUnit.prev = prev
                    set whichUnit.next = this
                    set prev.next = whichUnit
                    set prev = whichUnit
                endif
            endmethod
            method add takes thistype whichUnit returns boolean
                if (0 == this) then
                    return false
                endif
        
                if (registerUnit(whichUnit)) then
                    call addToList(whichUnit)
                
                    return true
                endif
            
                return false
            endmethod
        
            private method removeFromList takes thistype whichUnit returns nothing
                set whichUnit.parent = 0
        
                set whichUnit.prev.next = whichUnit.next
                set whichUnit.next.prev = whichUnit.prev
            
                if (first == whichUnit) then
                    set first = whichUnit.next
                    if (first == whichUnit) then
                        set first = 0
                    endif
                endif
            endmethod
            static method remove takes thistype whichUnit returns nothing
                local thistype this = whichUnit.parent
        
                call removeFromList(whichUnit)
                call unregisterUnit()
                call remake()
            endmethod
        
            private static method allocate takes nothing returns thistype
                set instanceCount = instanceCount + 1
                return instanceCount
            endmethod
            static method create takes nothing returns thistype
                local thistype this = allocate()
            
                call createTrigger()
            
                return this
            endmethod
        endstruct
    
        private struct TriggerHeapInner extends array
            readonly static integer size = 0
            readonly thistype node
            readonly thistype heap
        
            public method bubbleUp takes nothing returns nothing
                local integer activeUnits = RefreshTrigger(this).activeUnits
                local thistype heapPosition = heap
            
                local thistype parent
            
                /*
                *   Bubble node up
                */
                loop
                    set parent = heapPosition/2
                
                    if (integer(parent) != 0 and activeUnits < RefreshTrigger(parent.node).activeUnits) then
                        set heapPosition.node = parent.node
                        set heapPosition.node.heap = heapPosition
                    else
                        exitwhen true
                    endif
                
                    set heapPosition = parent
                endloop
            
                /*
                *   Update pointers
                */
                set heapPosition.node = this
                set heap = heapPosition
            endmethod
            public method bubbleDown takes nothing returns nothing
                local integer activeUnits = RefreshTrigger(this).activeUnits
                local thistype heapPosition = heap
            
                local thistype left
                local thistype right
            
                /*
                *   Bubble node down
                */
                loop
                    set left = heapPosition*2
                    set right = left + 1
                
                    if (RefreshTrigger(left.node).activeUnits < activeUnits and RefreshTrigger(left.node).activeUnits < RefreshTrigger(right.node).activeUnits) then
                        /*
                        *   Go left
                        */
                        set heapPosition.node = left.node
                        set heapPosition.node.heap = heapPosition
                        set heapPosition = left
                    elseif (RefreshTrigger(right.node).activeUnits < activeUnits) then
                        /*
                        *   Go right
                        */
                        set heapPosition.node = right.node
                        set heapPosition.node.heap = heapPosition
                        set heapPosition = right
                    else
                        exitwhen true
                    endif
                endloop
            
                /*
                *   Update pointers
                */
                set heapPosition.node = this
                set heap = heapPosition
            endmethod
        
            static method insert takes thistype this returns nothing
                /*
                *   Increase heap size
                */
                set size = size + 1
            
                /*
                *   Store node in last heap position
                */
                set thistype(size).node = this
                set heap = size
            
                /*
                *   Bubble node into correct position
                */
                call bubbleUp()
            endmethod
        endstruct
    
        private struct TriggerHeap extends array
            static method add takes UnitIndex whichUnit returns nothing
                local RefreshTrigger trig = TriggerHeapInner(1).node
            
                if (not trig.add(whichUnit)) then
                    set trig = RefreshTrigger.create()
                    call trig .add(whichUnit)
                    call TriggerHeapInner.insert(trig)
                else
                    call TriggerHeapInner(trig).bubbleDown()
                endif
            endmethod
            static method remove takes UnitIndex whichUnit returns nothing
                local RefreshTrigger trig = RefreshTrigger(whichUnit).parent
                call RefreshTrigger.remove(whichUnit)
                call TriggerHeapInner(trig).bubbleUp()
            endmethod
        endstruct
    
        private module TriggerRefreshInitModule
            private static method onInit takes nothing returns nothing
                call init($CODE$)
            endmethod
        endmodule
    
        private struct TriggerRefreshInit extends array
            private static method onIndex takes nothing returns boolean
                call TriggerHeap.add(UnitIndexer.eventIndex)
            
                return false
            endmethod
        
            private static method onDeindex takes nothing returns boolean
                call TriggerHeap.remove(UnitIndexer.eventIndex)
        
                return false
            endmethod
    
            private static method init takes code c returns nothing
                set condition = Condition(c)
            
                call RegisterUnitIndexEvent(Filter(function thistype.onIndex)  , EVENT_UNIT_INDEX)
                call RegisterUnitIndexEvent(Filter(function thistype.onDeindex)  , EVENT_UNIT_DEINDEX)
                //call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onIndex))
                //call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onDeindex))
            endmethod
        
            implement TriggerRefreshInitModule
        endstruct
    endscope
//! endtextmacro

JASS:
library DamageEvent /* v2.0.0.0
*************************************************************************************
*
*   Damage Event plugin for DDS
*
*************************************************************************************
*
*   */uses/*
*
*       */ DDS                      /*
*        */ Trigger                    /*
*
************************************************************************************
*
*   SETTINGS
*/
globals
    /*************************************************************************************
    *
    *   Enabling four phases, which splits ON_DAMAGE into ON_DAMAGE and ON_DAMAGE_OUTGOING
    *
    *    This adds a little overhead, but gives more functionality. Only enable these extra
    *    phases if you need them.
    *
    *************************************************************************************/
    public constant boolean FOUR_PHASE = true
endglobals
/*
*************************************************************************************
*
*   API
*
*       readonly static Trigger DDS.GlobalDamageEvent.ON_DAMAGE_BEFORE
*            -    runs first whenever any unit is damaged (setup)
*
*        readonly static Trigger DDS.GlobalDamageEvent.ON_DAMAGE_AFTER
*            -    runs last and in reverse whenever any unit is damaged (cleanup)
*
*        readonly Trigger DDS.ON_DAMAGE
*            -    runs when a specific unit is damaged
*
*        method fireLocal takes nothing returns nothing
*            -    fires ON_DAMAGE followed by ON_DAMAGE_AFTER correctly
*
*            -    this is used for custom combat systems, meaning that the DDS data for
*                damage, target, etc will no longer be accurate
*
*            -    it is expected that damage data is created (similarly to ON_DAMAGE_BEFORE)
*
*       readony static real damage
*           -   amount of damage dealt
*
*       readonly static unit target
*       readonly static UnitIndex targetId
*           -   damaged unit
*
*       readonly static unit source
*       readonly static UnitIndex sourceId
*           -   unit that dealt damage
*
*       readonly static player sourcePlayer
*           -   owner of source
*
*        readonly static player targetPlayer
*            -    owner of target
*
*
*        MUST BE DECLARED -        onDamageBefore
*        ------------------------------------------
*
*            readonly static Trigger ON_DAMAGE_BEFORE
*                -    allows a user to run through the struct rather than DDS
*
*
*        MUST BE DECLARED -        onDamageAfter
*        ------------------------------------------
*
*            readonly static Trigger ON_DAMAGE_AFTER
*                -    allows a user to run through the struct rather than DDS
*
*
*        MUST BE DECLARED -        onDamage
*        ------------------------------------------
*
*            readonly Trigger ON_DAMAGE
*                -    allows a user to run through the struct rather than DDS
*
*            method enableDamageEventLocal takes nothing returns boolean
*                -    will enable the local event for a given unit index
*                    after the first enable, it will just increase a counter
*
*                -    returns true when actually enabling
*                    returns false when just increasing the counter
*
*                    Examples:    local MyStruct modifier = someUnitIndex //on item pickup
*                                call modifier.enableDamageEventLocal()
*                                set modifier.physicalDamageReduction = modifier.physicalDamageReduction + item.physicalDamageReduction
*
*            method disableDamageEventLocal takes nothing returns boolean
*                -    will disable the local event for a given unit index
*                    decreases a counter until that counter reaches 0, at which point
*                    the thing is actuall disabled
*
*                -    returns true when actually disabling
*                    returns false when just decreasing the counter
*
*                    Examples:    local MyStruct modifier = someUnitIndex //on item drop
*                                call modifier.disableDamageEventLocal()
*                                set modifier.physicalDamageReduction = modifier.physicalDamageReduction - item.physicalDamageReduction
*
*    FOUR_PHASE ONLY SECTION
*
*        readonly Trigger DDS.ON_DAMAGE_OUTGOING
*            -    runs when a specific unit deals damage
*
*        MUST BE DECLARED -        onDamageOutgoing
*        ------------------------------------------
*
*            readonly Trigger ON_DAMAGE_OUTGOING
*                -    allows a user to run through the struct rather than DDS
*
*            method enableDamageEventLocalOutgoing takes nothing returns boolean
*                -    will enable the local event for a given unit index
*                    after the first enable, it will just increase a counter
*
*                -    returns true when actually enabling
*                    returns false when just increasing the counter
*
*                    Examples:    local MyStruct modifier = someUnitIndex //on item pickup
*                                call modifier.enableDamageEventLocalOutgoing()
*                                set modifier.attackIncrease = modifier.attackIncrease + item.attackIncrease
*
*            method disableDamageEventLocalOutgoing takes nothing returns boolean
*                -    will disable the local event for a given unit index
*                    decreases a counter until that counter reaches 0, at which point
*                    the thing is actuall disabled
*
*                -    returns true when actually disabling
*                    returns false when just decreasing the counter
*
*                    Examples:    local MyStruct modifier = someUnitIndex //on item drop
*                                call modifier.disableDamageEventLocalOutgoing()
*                                set modifier.attackIncrease = modifier.attackIncrease - item.attackIncrease
*
*************************************************************************************
*
*   Interface
*
*       (optional) private static method onDamageBefore takes nothing returns nothing
*           -   is run first whenever a unit is damaged
*       (optional) private static method onDamageAfter takes nothing returns nothing
*           -   is run last whenever a unit is damaged
*
*       (optional) private method onDamage takes nothing returns nothing
*           -   is run when a specific unit is damaged
*
*            -    this == index of unit taking damage
*
*    FOUR_PHASE ONLY SECTION
*
*       (optional) private method onDamageOutgoing takes nothing returns nothing
*           -   is run when a specific unit deals damage
*
*            -    this == index of unit dealing damage
*
*************************************************************************************
*
*   Plugin Information (can only be used by other plugins)
*
*       static UnitIndex targetId_p
*       static UnitIndex sourceId_p
*
*       static real damage_p
*
*       static player sourcePlayer_p
*       static player targetPlayer_p
*
*************************************************************************************/
    //! textmacro DAMAGE_EVENT_CODE

    private keyword damage_p
    private keyword targetId_p
    private keyword sourceId_p
    private keyword sourcePlayer_p
    private keyword targetPlayer_p

    scope DamageEvent
        private keyword init
        private keyword ON_DAMAGE_MAIN
        private keyword ON_DAMAGE_MAIN_2
    
        private struct GlobalDamageEvent extends array
            readonly static Trigger ON_DAMAGE_BEFORE
            readonly static Trigger ON_DAMAGE_AFTER
        
            static method init takes nothing returns nothing
                set ON_DAMAGE_BEFORE = Trigger.create(false)
                set ON_DAMAGE_AFTER = Trigger.create(true)
            endmethod
        endstruct
        struct LocalDamageEvent extends array
            readonly Trigger ON_DAMAGE_MAIN                //BEFORE, OUTGOING
            readonly Trigger ON_DAMAGE_MAIN_2            //INCOMING, AFTER
            readonly Trigger ON_DAMAGE
        
            method fireLocal takes nothing returns nothing
                call ON_DAMAGE_MAIN_2.fire()
            endmethod
    
            static if DamageEvent_FOUR_PHASE then
                readonly Trigger ON_DAMAGE_OUTGOING
            
                private static method onUnitIndex takes nothing returns boolean
                    local thistype this = UnitIndexer.eventIndex
                
                    set ON_DAMAGE_MAIN = Trigger.create(false)
                    set ON_DAMAGE_MAIN_2 = Trigger.create(false)
                    set ON_DAMAGE = Trigger.create(false)
                    set ON_DAMAGE_OUTGOING = Trigger.create(false)
                
                    call ON_DAMAGE_MAIN.reference(GlobalDamageEvent.ON_DAMAGE_BEFORE)
                    call ON_DAMAGE_MAIN.reference(ON_DAMAGE_OUTGOING)
                    call ON_DAMAGE_MAIN_2.reference(ON_DAMAGE)
                    call ON_DAMAGE_MAIN_2.reference(GlobalDamageEvent.ON_DAMAGE_AFTER)
        
                    return false
                endmethod
            
                private static method onUnitDeindex takes nothing returns boolean
                    local thistype this = UnitIndexer.eventIndex
                
                    call ON_DAMAGE_MAIN.destroy()
                    call ON_DAMAGE_MAIN_2.destroy()
                    call ON_DAMAGE.destroy()
                    call ON_DAMAGE_OUTGOING.destroy()
            
                    return false
                endmethod
            else
                private static method onUnitIndex takes nothing returns boolean
                    local thistype this = UnitIndexer.eventIndex
                
                    set ON_DAMAGE_MAIN = Trigger.create(false)
                    set ON_DAMAGE_MAIN_2 = Trigger.create(false)
                    set ON_DAMAGE = Trigger.create(false)
                
                    call ON_DAMAGE_MAIN.reference(GlobalDamageEvent.ON_DAMAGE_BEFORE)
                    call ON_DAMAGE_MAIN.reference(ON_DAMAGE_MAIN_2)
                    call ON_DAMAGE_MAIN_2.reference(ON_DAMAGE)
                    call ON_DAMAGE_MAIN_2.reference(GlobalDamageEvent.ON_DAMAGE_AFTER)
        
                    return false
                endmethod
            
                private static method onUnitDeindex takes nothing returns boolean
                    local thistype this = UnitIndexer.eventIndex
                
                    call ON_DAMAGE_MAIN.destroy()
                    call ON_DAMAGE_MAIN_2.destroy()
                    call ON_DAMAGE.destroy()
            
                    return false
                endmethod
            endif
        
            static method init takes nothing returns nothing
        
                call RegisterUnitIndexEvent(Filter(function thistype.onUnitIndex)  , EVENT_UNIT_INDEX)
                call RegisterUnitIndexEvent(Filter(function thistype.onUnitDeindex)  , EVENT_UNIT_DEINDEX)
        
                //call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onUnitIndex))
                //call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onUnitDeindex))
            endmethod
        endstruct
    
        /*
        *   DDS API
        *
        *       DDS.GlobalEvent.ON_DAMAGE_BEFORE
        *       DDS.GlobalEvent.ON_DAMAGE_AFTER
        *        DDS.Event.ON_DAMAGE
        *
        *       DDS.target
        *        DDS.targetId
        *       DDS.source
        *        DDS.sourceId
        *        DDS.sourcePlayer
        *       DDS.damage
        *
        */
        private keyword damageEventInit
    
        module DAMAGE_EVENT_API
            static method operator GlobalEvent takes nothing returns GlobalDamageEvent
                return 0
            endmethod
            method operator Event takes nothing returns LocalDamageEvent
                return this
            endmethod
    
            static UnitIndex targetId_p = 0
            static UnitIndex sourceId_p = 0
            static real damage_p = 0
            static player sourcePlayer_p = null
            static player targetPlayer_p = null
        
            static method operator targetId takes nothing returns UnitIndex
                return targetId_p
            endmethod
            static method operator target takes nothing returns unit
                return targetId.unit
            endmethod
        
            static method operator sourceId takes nothing returns UnitIndex
                return sourceId_p
            endmethod
            static method operator source takes nothing returns unit
                return sourceId.unit
            endmethod
        
            static method operator damage takes nothing returns real
                return damage_p
            endmethod
        
            static method operator sourcePlayer takes nothing returns player
                return sourcePlayer_p
            endmethod
        
            static method operator targetPlayer takes nothing returns player
                return targetPlayer_p
            endmethod
        
            static method damageEventInit takes nothing returns nothing
                call GlobalDamageEvent.init()
                call LocalDamageEvent.init()
            endmethod
        endmodule
    
        module DAMAGE_EVENT_INIT
            call DDS.damageEventInit()
        endmodule

        /*
        *   DDS Interface
        *
        *       interface private static method onDamage takes nothing returns nothing
        *
        *   
        */
        module DAMAGE_EVENT_INTERFACE
            /*
            *    private static method getCondition takes code c returns boolexpr
            */
            static if thistype.onDamageBefore.exists then
                private static method getCondition takes code c returns boolexpr
                    return Condition(c)
                    return null
                endmethod
            elseif thistype.onDamageAfter.exists then
                private static method getCondition takes code c returns boolexpr
                    return Condition(c)
                    return null
                endmethod
            endif
        
            static if thistype.onDamageBefore.exists then
                readonly static Trigger ON_DAMAGE_BEFORE
            endif
            static if thistype.onDamageAfter.exists then
                readonly static Trigger ON_DAMAGE_AFTER
            endif
        
            static if thistype.onDamage.exists then
                readonly Trigger ON_DAMAGE
                private static boolexpr onDamageExpr
                private TriggerReference ON_DAMAGE_REF
            
                private static method onDamageFunc takes nothing returns boolean
                    call thistype(targetId).onDamage()
                    return false
                endmethod
            
                private integer count
            
                method enableDamageEventLocal takes nothing returns boolean
                    set count = count + 1
            
                    if (count == 1) then
                        set ON_DAMAGE_REF = LocalDamageEvent(this).ON_DAMAGE.reference(ON_DAMAGE)
                    
                        return true
                    endif
                
                    return false
                endmethod
            
                method disableDamageEventLocal takes nothing returns boolean
                    if (count == 0) then
                        return false
                    endif
            
                    set count = count - 1
            
                    if (count == 0) then
                        call ON_DAMAGE_REF.destroy()
                    
                        return true
                    endif
                
                    return false
                endmethod
            endif
    
            static if DamageEvent_FOUR_PHASE then
                static if thistype.onDamageOutgoing.exists then
                    readonly Trigger ON_DAMAGE_OUTGOING
                    private static boolexpr onDamageOutgoingExpr
                    private TriggerReference ON_DAMAGE_OUTGOING_REF
                
                    private static method onDamageOutgoingFunc takes nothing returns boolean
                        call thistype(sourceId).onDamageOutgoing()
                        return false
                    endmethod
                
                    private integer countOutgoing
                
                    method enableDamageEventLocalOutgoing takes nothing returns boolean
                        set countOutgoing = countOutgoing + 1
                
                        if (countOutgoing == 1) then
                            set ON_DAMAGE_OUTGOING_REF = LocalDamageEvent(this).ON_DAMAGE_OUTGOING.reference(ON_DAMAGE_OUTGOING)
                        
                            return true
                        endif
                    
                        return false
                    endmethod
                
                    method disableDamageEventLocalOutgoing takes nothing returns boolean
                        if (countOutgoing == 0) then
                            return false
                        endif
                
                        set countOutgoing = countOutgoing - 1
                
                        if (countOutgoing == 0) then
                            call ON_DAMAGE_OUTGOING_REF.destroy()
                        
                            return true
                        endif
                    
                        return false
                    endmethod
                endif
            
                static if thistype.onDamageOutgoing.exists then
                    private static method onUnitIndex takes nothing returns boolean
                        local thistype this = UnitIndexer.eventIndex
                
                        static if thistype.onDamage.exists then
                            set ON_DAMAGE = Trigger.create(false)
                            call ON_DAMAGE.register(onDamageExpr)
                        endif
                    
                        static if thistype.onDamageOutgoing.exists then
                            set ON_DAMAGE_OUTGOING = Trigger.create(false)
                            call ON_DAMAGE_OUTGOING.register(onDamageOutgoingExpr)
                        endif
                    
                        return false
                    endmethod
                
                    private static method onUnitDeindex takes nothing returns boolean
                        local thistype this = UnitIndexer.eventIndex
                    
                        static if thistype.onDamage.exists then
                            call ON_DAMAGE.destroy()
                        
                            set count = 0
                        endif
                    
                        static if thistype.onDamageOutgoing.exists then
                            call ON_DAMAGE_OUTGOING.destroy()
                        
                            set countOutgoing = 0
                        endif
                    
                        return false
                    endmethod
                elseif thistype.onDamage.exists then
                    private static method onUnitIndex takes nothing returns boolean
                        local thistype this = UnitIndexer.eventIndex
                
                        static if thistype.onDamage.exists then
                            set ON_DAMAGE = Trigger.create(false)
                            call ON_DAMAGE.register(onDamageExpr)
                        endif
                    
                        static if thistype.onDamageOutgoing.exists then
                            set ON_DAMAGE_OUTGOING = Trigger.create(false)
                            call ON_DAMAGE_OUTGOING.register(onDamageOutgoingExpr)
                        endif
                    
                        return false
                    endmethod
                
                    private static method onUnitDeindex takes nothing returns boolean
                        local thistype this = UnitIndexer.eventIndex
                    
                        static if thistype.onDamage.exists then
                            call ON_DAMAGE.destroy()
                        
                            set count = 0
                        endif
                    
                        static if thistype.onDamageOutgoing.exists then
                            call ON_DAMAGE_OUTGOING.destroy()
                        
                            set countOutgoing = 0
                        endif
                    
                        return false
                    endmethod
                endif
            
                static if thistype.onDamageBefore.exists then
                    private static method onInit takes nothing returns nothing
                        static if thistype.onDamage.exists then
                            set onDamageExpr = Condition(function thistype.onDamageFunc)
                        endif
                    
                        static if thistype.onDamageOutgoing.exists then
                            set onDamageOutgoingExpr = Condition(function thistype.onDamageOutgoingFunc)
                        endif
                    
                        static if thistype.onDamage.exists then
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitIndex)  , EVENT_UNIT_INDEX)
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitDeindex)  , EVENT_UNIT_DEINDEX)
                    
                            //call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onUnitIndex))
                            //call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onUnitDeindex))
                        elseif thistype.onDamageOutgoing.exists then
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitIndex)  , EVENT_UNIT_INDEX)
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitDeindex)  , EVENT_UNIT_DEINDEX)
                    
                    
                            //call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onUnitIndex))
                            //call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onUnitDeindex))
                        endif
                    
                        static if thistype.onDamageBefore.exists then
                            set ON_DAMAGE_BEFORE = Trigger.create(false)
                            call ON_DAMAGE_BEFORE.register(getCondition(function thistype.onDamageBefore))
                            call GlobalDamageEvent.ON_DAMAGE_BEFORE.reference(ON_DAMAGE_BEFORE)
                        endif
                    
                        static if thistype.onDamageAfter.exists then
                            set ON_DAMAGE_AFTER = Trigger.create(true)
                            call ON_DAMAGE_AFTER.register(getCondition(function thistype.onDamageAfter))
                            call GlobalDamageEvent.ON_DAMAGE_AFTER.reference(ON_DAMAGE_AFTER)
                        endif
                    endmethod
                elseif thistype.onDamageAfter.exists then
                    private static method onInit takes nothing returns nothing
                        static if thistype.onDamage.exists then
                            set onDamageExpr = Condition(function thistype.onDamageFunc)
                        endif
                    
                        static if thistype.onDamageOutgoing.exists then
                            set onDamageOutgoingExpr = Condition(function thistype.onDamageOutgoingFunc)
                        endif
                    
                        static if thistype.onDamage.exists then
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitIndex)  , EVENT_UNIT_INDEX)
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitDeindex)  , EVENT_UNIT_DEINDEX)
                    
                            //call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onUnitIndex))
                            //call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onUnitDeindex))
                        elseif thistype.onDamageOutgoing.exists then
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitIndex)  , EVENT_UNIT_INDEX)
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitDeindex)  , EVENT_UNIT_DEINDEX)
                    
                            //call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onUnitIndex))
                            //call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onUnitDeindex))
                        endif
                    
                        static if thistype.onDamageBefore.exists then
                            set ON_DAMAGE_BEFORE = Trigger.create(false)
                            call ON_DAMAGE_BEFORE.register(getCondition(function thistype.onDamageBefore))
                            call GlobalDamageEvent.ON_DAMAGE_BEFORE.reference(ON_DAMAGE_BEFORE)
                        endif
                    
                        static if thistype.onDamageAfter.exists then
                            set ON_DAMAGE_AFTER = Trigger.create(true)
                            call ON_DAMAGE_AFTER.register(getCondition(function thistype.onDamageAfter))
                            call GlobalDamageEvent.ON_DAMAGE_AFTER.reference(ON_DAMAGE_AFTER)
                        endif
                    endmethod
                elseif thistype.onDamage.exists then
                    private static method onInit takes nothing returns nothing
                        static if thistype.onDamage.exists then
                            set onDamageExpr = Condition(function thistype.onDamageFunc)
                        endif
                    
                        static if thistype.onDamageOutgoing.exists then
                            set onDamageOutgoingExpr = Condition(function thistype.onDamageOutgoingFunc)
                        endif
                    
                        static if thistype.onDamage.exists then
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitIndex)  , EVENT_UNIT_INDEX)
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitDeindex)  , EVENT_UNIT_DEINDEX)
                    
                            //call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onUnitIndex))
                            //call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onUnitDeindex))
                        elseif thistype.onDamageOutgoing.exists then
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitIndex)  , EVENT_UNIT_INDEX)
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitDeindex)  , EVENT_UNIT_DEINDEX)
                    
                            //call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onUnitIndex))
                            //call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onUnitDeindex))
                        endif
                    
                        static if thistype.onDamageBefore.exists then
                            set ON_DAMAGE_BEFORE = Trigger.create(false)
                            call ON_DAMAGE_BEFORE.register(getCondition(function thistype.onDamageBefore))
                            call GlobalDamageEvent.ON_DAMAGE_BEFORE.reference(ON_DAMAGE_BEFORE)
                        endif
                    
                        static if thistype.onDamageAfter.exists then
                            set ON_DAMAGE_AFTER = Trigger.create(true)
                            call ON_DAMAGE_AFTER.register(getCondition(function thistype.onDamageAfter))
                            call GlobalDamageEvent.ON_DAMAGE_AFTER.reference(ON_DAMAGE_AFTER)
                        endif
                    endmethod
                elseif thistype.onDamageOutgoing.exists then
                    private static method onInit takes nothing returns nothing
                        static if thistype.onDamage.exists then
                            set onDamageExpr = Condition(function thistype.onDamageFunc)
                        endif
                    
                        static if thistype.onDamageOutgoing.exists then
                            set onDamageOutgoingExpr = Condition(function thistype.onDamageOutgoingFunc)
                        endif
                    
                        static if thistype.onDamage.exists then
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitIndex)  , EVENT_UNIT_INDEX)
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitDeindex)  , EVENT_UNIT_DEINDEX)
                    
                    
                            //call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onUnitIndex))
                            //call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onUnitDeindex))
                        elseif thistype.onDamageOutgoing.exists then
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitIndex)  , EVENT_UNIT_INDEX)
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitDeindex)  , EVENT_UNIT_DEINDEX)
                    
                            //call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onUnitIndex))
                            //call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onUnitDeindex))
                        endif
                    
                        static if thistype.onDamageBefore.exists then
                            set ON_DAMAGE_BEFORE = Trigger.create(false)
                            call ON_DAMAGE_BEFORE.register(getCondition(function thistype.onDamageBefore))
                            call GlobalDamageEvent.ON_DAMAGE_BEFORE.reference(ON_DAMAGE_BEFORE)
                        endif
                    
                        static if thistype.onDamageAfter.exists then
                            set ON_DAMAGE_AFTER = Trigger.create(true)
                            call ON_DAMAGE_AFTER.register(getCondition(function thistype.onDamageAfter))
                            call GlobalDamageEvent.ON_DAMAGE_AFTER.reference(ON_DAMAGE_AFTER)
                        endif
                    endmethod
                endif
            else
                static if thistype.onDamage.exists then
                    private static method onUnitIndex takes nothing returns boolean
                        local thistype this = UnitIndexer.eventIndex
                
                        set ON_DAMAGE = Trigger.create(false)
                        call ON_DAMAGE.register(onDamageExpr)
                
                        return false
                    endmethod
                
                    private static method onUnitDeindex takes nothing returns boolean
                        local thistype this = UnitIndexer.eventIndex
                
                        call ON_DAMAGE.destroy()
                    
                        set count = 0
                    
                        return false
                    endmethod
                endif
            
                static if thistype.onDamageBefore.exists then
                    private static method onInit takes nothing returns nothing
                        static if thistype.onDamage.exists then
                            set onDamageExpr = Condition(function thistype.onDamageFunc)
                        
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitIndex)  , EVENT_UNIT_INDEX)
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitDeindex)  , EVENT_UNIT_DEINDEX)
                            //call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onUnitIndex))
                            //call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onUnitDeindex))
                        endif
                
                        static if thistype.onDamageBefore.exists then
                            set ON_DAMAGE_BEFORE = Trigger.create(false)
                            call ON_DAMAGE_BEFORE.register(getCondition(function thistype.onDamageBefore))
                            call GlobalDamageEvent.ON_DAMAGE_BEFORE.reference(ON_DAMAGE_BEFORE)
                        endif
                    
                        static if thistype.onDamageAfter.exists then
                            set ON_DAMAGE_AFTER = Trigger.create(true)
                            call ON_DAMAGE_AFTER.register(getCondition(function thistype.onDamageAfter))
                            call GlobalDamageEvent.ON_DAMAGE_AFTER.reference(ON_DAMAGE_AFTER)
                        endif
                    endmethod
                elseif thistype.onDamageAfter.exists then
                    private static method onInit takes nothing returns nothing
                        static if thistype.onDamage.exists then
                            set onDamageExpr = Condition(function thistype.onDamageFunc)
                        
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitIndex)  , EVENT_UNIT_INDEX)
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitDeindex)  , EVENT_UNIT_DEINDEX)
                        
                            //call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onUnitIndex))
                            //call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onUnitDeindex))
                        endif
                
                        static if thistype.onDamageBefore.exists then
                            set ON_DAMAGE_BEFORE = Trigger.create(false)
                            call ON_DAMAGE_BEFORE.register(getCondition(function thistype.onDamageBefore))
                            call GlobalDamageEvent.ON_DAMAGE_BEFORE.reference(ON_DAMAGE_BEFORE)
                        endif
                    
                        static if thistype.onDamageAfter.exists then
                            set ON_DAMAGE_AFTER = Trigger.create(true)
                            call ON_DAMAGE_AFTER.register(getCondition(function thistype.onDamageAfter))
                            call GlobalDamageEvent.ON_DAMAGE_AFTER.reference(ON_DAMAGE_AFTER)
                        endif
                    endmethod
                elseif thistype.onDamage.exists then
                    private static method onInit takes nothing returns nothing
                        static if thistype.onDamage.exists then
                            set onDamageExpr = Condition(function thistype.onDamageFunc)
                        
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitIndex)  , EVENT_UNIT_INDEX)
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitDeindex)  , EVENT_UNIT_DEINDEX)
                        
                            //call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onUnitIndex))
                            //call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onUnitDeindex))
                        endif
                
                        static if thistype.onDamageBefore.exists then
                            set ON_DAMAGE_BEFORE = Trigger.create(false)
                            call ON_DAMAGE_BEFORE.register(getCondition(function thistype.onDamageBefore))
                            call GlobalDamageEvent.ON_DAMAGE_BEFORE.reference(ON_DAMAGE_BEFORE)
                        endif
                    
                        static if thistype.onDamageAfter.exists then
                            set ON_DAMAGE_AFTER = Trigger.create(true)
                            call ON_DAMAGE_AFTER.register(getCondition(function thistype.onDamageAfter))
                            call GlobalDamageEvent.ON_DAMAGE_AFTER.reference(ON_DAMAGE_AFTER)
                        endif
                    endmethod
                endif
            endif
        endmodule

        /*
        *   DDS Event Handling
        */
module DAMAGE_EVENT_RESPONSE_LOCALS
                local UnitIndex prevTarget = targetId_p
                local UnitIndex prevSource = sourceId_p
            
                local real prevDamage = damage_p
endmodule
module DAMAGE_EVENT_RESPONSE_BEFORE
                if (0 == GetEventDamage()) then
                    return
                endif
            
                set targetId_p = GetUnitUserData(GetTriggerUnit())
                set sourceId_p = GetUnitUserData(GetEventDamageSource())
                set damage_p = GetEventDamage()
                set sourcePlayer_p = GetOwningPlayer(sourceId_p.unit)
                set targetPlayer_p = GetOwningPlayer(targetId_p.unit)
endmodule
module DAMAGE_EVENT_RESPONSE
                static if DamageEvent_FOUR_PHASE then
                    call LocalDamageEvent(sourceId_p).ON_DAMAGE_MAIN.fire()
                    call LocalDamageEvent(targetId_p).ON_DAMAGE_MAIN_2.fire()
                else
                    call LocalDamageEvent(targetId_p).ON_DAMAGE_MAIN.fire()
                endif
endmodule
module DAMAGE_EVENT_RESPONSE_AFTER
            
endmodule
module DAMAGE_EVENT_RESPONSE_CLEANUP
                set targetId_p = prevTarget
                set sourceId_p = prevSource
                set damage_p = prevDamage
            
                if (sourceId_p == 0) then
                    set sourcePlayer_p = null
                else
                    set targetPlayer_p = GetOwningPlayer(sourceId_p.unit)
                endif
            
                if (targetId_p == 0) then
                    set sourcePlayer_p = null
                else
                    set targetPlayer_p = GetOwningPlayer(targetId_p.unit)
                endif
endmodule
    endscope
    //! endtextmacro
endlibrary

EDIT: Actually, to make it easier, there are two main changes for TriggerRefresh and DamageEvent:


JASS:
call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onUnitIndex))
call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onUnitDeindex))

was replaced with

JASS:
call RegisterUnitIndexEvent(Filter(function thistype.onUnitIndex)  , EVENT_UNIT_INDEX)
call RegisterUnitIndexEvent(Filter(function thistype.onUnitDeindex)  , EVENT_UNIT_DEINDEX)

and

JASS:
call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onIndex))
call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onDeindex))

was replaced with

JASS:
call RegisterUnitIndexEvent(Filter(function thistype.onIndex)  , EVENT_UNIT_INDEX)
call RegisterUnitIndexEvent(Filter(function thistype.onDeindex)  , EVENT_UNIT_DEINDEX)

EDIT2: It seems like my API is wrong, based on what you said?
 
Last edited:
You're replacing the events correctly, but I believe you just need to update the callbacks for each event.

For example, anywhere you have something like this:
JASS:
call RegisterUnitIndexEvent(Filter(function thistype.onIndex)  , EVENT_UNIT_INDEX)
call RegisterUnitIndexEvent(Filter(function thistype.onDeindex)  , EVENT_UNIT_DEINDEX)

You'll want to look for the callback (function thistype.onIndex and function thistype.onDeindex) and check that it is using the correct values. For example, this code here:
JASS:
                private static method onUnitIndex takes nothing returns boolean
                    local thistype this = UnitIndexer.eventIndex // USING WRONG INDEXER API
                
                    set ON_DAMAGE_MAIN = Trigger.create(false)
                    set ON_DAMAGE_MAIN_2 = Trigger.create(false)
                    set ON_DAMAGE = Trigger.create(false)
                
                    call ON_DAMAGE_MAIN.reference(GlobalDamageEvent.ON_DAMAGE_BEFORE)
                    call ON_DAMAGE_MAIN.reference(ON_DAMAGE_MAIN_2)
                    call ON_DAMAGE_MAIN_2.reference(ON_DAMAGE)
                    call ON_DAMAGE_MAIN_2.reference(GlobalDamageEvent.ON_DAMAGE_AFTER)
        
                    return false
                endmethod
            
                private static method onUnitDeindex takes nothing returns boolean
                    local thistype this = UnitIndexer.eventIndex // USING WRONG INDEXER API
                
                    call ON_DAMAGE_MAIN.destroy()
                    call ON_DAMAGE_MAIN_2.destroy()
                    call ON_DAMAGE.destroy()
            
                    return false
                endmethod

... would need to be updated like so:
JASS:
                private static method onUnitIndex takes nothing returns boolean
                    local thistype this = GetIndexedUnitId() // GOOD NOW
                
                    set ON_DAMAGE_MAIN = Trigger.create(false)
                    set ON_DAMAGE_MAIN_2 = Trigger.create(false)
                    set ON_DAMAGE = Trigger.create(false)
                
                    call ON_DAMAGE_MAIN.reference(GlobalDamageEvent.ON_DAMAGE_BEFORE)
                    call ON_DAMAGE_MAIN.reference(ON_DAMAGE_MAIN_2)
                    call ON_DAMAGE_MAIN_2.reference(ON_DAMAGE)
                    call ON_DAMAGE_MAIN_2.reference(GlobalDamageEvent.ON_DAMAGE_AFTER)
        
                    return false
                endmethod
            
                private static method onUnitDeindex takes nothing returns boolean
                    local thistype this = GetIndexedUnitId() // GOOD NOW
                
                    call ON_DAMAGE_MAIN.destroy()
                    call ON_DAMAGE_MAIN_2.destroy()
                    call ON_DAMAGE.destroy()
            
                    return false
                endmethod
 
Level 7
Joined
Feb 9, 2021
Messages
301
You're replacing the events correctly, but I believe you just need to update the callbacks for each event.

For example, anywhere you have something like this:
JASS:
call RegisterUnitIndexEvent(Filter(function thistype.onIndex)  , EVENT_UNIT_INDEX)
call RegisterUnitIndexEvent(Filter(function thistype.onDeindex)  , EVENT_UNIT_DEINDEX)

You'll want to look for the callback (function thistype.onIndex and function thistype.onDeindex) and check that it is using the correct values. For example, this code here:
JASS:
                private static method onUnitIndex takes nothing returns boolean
                    local thistype this = UnitIndexer.eventIndex // USING WRONG INDEXER API
             
                    set ON_DAMAGE_MAIN = Trigger.create(false)
                    set ON_DAMAGE_MAIN_2 = Trigger.create(false)
                    set ON_DAMAGE = Trigger.create(false)
             
                    call ON_DAMAGE_MAIN.reference(GlobalDamageEvent.ON_DAMAGE_BEFORE)
                    call ON_DAMAGE_MAIN.reference(ON_DAMAGE_MAIN_2)
                    call ON_DAMAGE_MAIN_2.reference(ON_DAMAGE)
                    call ON_DAMAGE_MAIN_2.reference(GlobalDamageEvent.ON_DAMAGE_AFTER)
     
                    return false
                endmethod
         
                private static method onUnitDeindex takes nothing returns boolean
                    local thistype this = UnitIndexer.eventIndex // USING WRONG INDEXER API
             
                    call ON_DAMAGE_MAIN.destroy()
                    call ON_DAMAGE_MAIN_2.destroy()
                    call ON_DAMAGE.destroy()
         
                    return false
                endmethod

... would need to be updated like so:
JASS:
                private static method onUnitIndex takes nothing returns boolean
                    local thistype this = GetIndexedUnitId() // GOOD NOW
             
                    set ON_DAMAGE_MAIN = Trigger.create(false)
                    set ON_DAMAGE_MAIN_2 = Trigger.create(false)
                    set ON_DAMAGE = Trigger.create(false)
             
                    call ON_DAMAGE_MAIN.reference(GlobalDamageEvent.ON_DAMAGE_BEFORE)
                    call ON_DAMAGE_MAIN.reference(ON_DAMAGE_MAIN_2)
                    call ON_DAMAGE_MAIN_2.reference(ON_DAMAGE)
                    call ON_DAMAGE_MAIN_2.reference(GlobalDamageEvent.ON_DAMAGE_AFTER)
     
                    return false
                endmethod
         
                private static method onUnitDeindex takes nothing returns boolean
                    local thistype this = GetIndexedUnitId() // GOOD NOW
             
                    call ON_DAMAGE_MAIN.destroy()
                    call ON_DAMAGE_MAIN_2.destroy()
                    call ON_DAMAGE.destroy()
         
                    return false
                endmethod
Unfortunately, this did not help. I get an error when the first attack on the map happens. The system should work 100%, so the problem is most likely with the unit indexer.

API
JASS:
library UnitIndexer requires UnitDex
 
    struct UnitIndexer
        readonly static integer INDEX   = EVENT_UNIT_INDEX
        readonly static integer DEINDEX = EVENT_UNIT_DEINDEX
     
        static method operator enabled= takes boolean b returns nothing
            set UnitDex.Enabled=b
        endmethod
     
        static method operator enabled takes nothing returns boolean
            return UnitDex.Enabled
        endmethod
       
        static method eventIndex takes nothing returns integer
            return GetIndexedUnitId()
        endmethod
       
        static method eventUnit takes nothing returns unit
            return GetIndexedUnit()
        endmethod
    endstruct
 
    module UnitIndexStructMethods
        static method operator [] takes unit u returns thistype
            return GetUnitUserData(u)
        endmethod
     
        method operator unit takes nothing returns unit
            return UnitDex.Unit[this]
        endmethod
    endmodule
 
    module UnitIndexStruct
        implement UnitIndexStructMethods
     
        method operator allocated takes nothing returns boolean
            return this==GetUnitUserData(UnitDex.Unit[this])
        endmethod
    endmodule

    function IsUnitDeindexing takes unit u returns boolean
        return IsUnitIndexed(u) and 0==GetUnitAbilityLevel(u, UnitDex.DETECT_LEAVE_ABILITY)
    endfunction
 
    struct UnitIndex extends array
        method lock takes nothing returns nothing
        endmethod
     
        method unlock takes nothing returns nothing
        endmethod
     
        method operator unit takes nothing returns unit
            return UnitDex.Unit[this]
        endmethod
     
        static method operator [] takes unit whichUnit returns thistype
            return GetUnitUserData(whichUnit)
        endmethod
    endstruct
 
endlibrary

TriggerRefresh
JASS:
library TriggerRefresh /* v1.0.3.0
*************************************************************************************
*
*   Optimal trigger refreshing for unit events. Used in such things as Damage Detection
*   Systems.
*
*   Events are never destroyed. When a unit event is registered to a trigger and that
*   unit no longer exists, the event remains. The trigger has to be recreated in order
*   to clean the leak. This resource recreates triggers in the most optimal manner possible.
*
*   Used in DamageEvent and recommended for all Damage Detection Systems.
*
*   Place the macros in order at the bottom of the DDS Library.
*
*************************************************************************************
*
*   */uses/*
*
*       */ UnitIndexer      /*      hiveworkshop.com/forums/jass-functions-413/unit-indexer-172090/
        */ UnitDex          /*
*       All Requirements of Unit Indexer are not needed as they are included with RefreshTrigger Refresh
*
*************************************************************************************
*
*   //! textmacro TRIGGER_REFRESH takes TRIGGER_SIZE, TRIGGER_EVENT, CODE
*
*       This macro creates the refreshing trigger.
*
*           TRIGGER_SIZE
*               How many units to register to a given trigger. More units = less refreshes, but
*               more fps spikes. A value of 80 is recommended.
*
*           TRIGGER_EVENT
*               The event to register to the trigger. Example: EVENT_UNIT_DAMAGED.
*
*           CODE
*               Registers code to the trigger. Only 1 function may be registered to the trigger.
*
*   private keyword RefreshTrigger
*   RefreshTrigger(UnitIndex).parent.trigger
*       -   enable/disable trigger for specific unit
*
*************************************************************************************
*
*   //quick and dirty DDS
*   library MyDDS
*       private function Core takes nothing returns nothing
*           //will display whenever a unit is damaged
*           call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,10,R2S(GetEventDamage()))
*       endfunction
*
*       //! runtextmacro TRIGGER_REFRESH("80", "EVENT_UNIT_DAMAGED", "function Core")
*   endlibrary
*
*************************************************************************************/
endlibrary

//! textmacro TRIGGER_REFRESH takes TRIGGER_SIZE, TRIGGER_EVENT, CODE
    scope TriggerRefresh
        globals
            private boolexpr condition
        endglobals
       
        struct RefreshTrigger extends array
            private static integer instanceCount = 0
       
            private thistype first
            private thistype next
            private thistype prev
            readonly thistype parent
           
            private integer inactiveUnits
            readonly integer activeUnits
           
            readonly trigger trigger
           
            private method registerUnit takes UnitIndex whichUnit returns boolean
                if (activeUnits < $TRIGGER_SIZE$) then
                    call TriggerRegisterUnitEvent(trigger, whichUnit.unit, $TRIGGER_EVENT$)
                    set activeUnits = activeUnits + 1
                   
                    return true
                endif
               
                return false
            endmethod
            private method unregisterUnit takes nothing returns nothing
                set inactiveUnits = inactiveUnits + 1
                set activeUnits = activeUnits - 1
            endmethod
           
            private method createTrigger takes nothing returns nothing
                set trigger = CreateTrigger()
                call TriggerAddCondition(trigger, condition)
            endmethod
            private method remakeTrigger takes nothing returns nothing
                call DestroyTrigger(trigger)
                call createTrigger()
            endmethod
            private method rebuildTrigger takes nothing returns nothing
                local thistype current = first
               
                call remakeTrigger()
               
                /*
                *   Iterate over all units registered to the trigger and reregister them
                */
                set current.prev.next = 0
                loop
                    exitwhen 0 == current
                    call TriggerRegisterUnitEvent(trigger, UnitIndex(current).unit, $TRIGGER_EVENT$)
                    set current = current.next
                endloop
                set first.prev.next = current
            endmethod
           
            private method remake takes nothing returns nothing
                if (inactiveUnits == $TRIGGER_SIZE$) then
                    set inactiveUnits = 0
                    call rebuildTrigger()
                endif
            endmethod
           
            private method addToList takes thistype whichUnit returns nothing
                set whichUnit.parent = this
           
                if (0 == first) then
                    set first = whichUnit
                    set whichUnit.next = whichUnit
                    set whichUnit.prev = whichUnit
                else
                    set this = first
                   
                    set whichUnit.prev = prev
                    set whichUnit.next = this
                    set prev.next = whichUnit
                    set prev = whichUnit
                endif
            endmethod
            method add takes thistype whichUnit returns boolean
                if (0 == this) then
                    return false
                endif
           
                if (registerUnit(whichUnit)) then
                    call addToList(whichUnit)
                   
                    return true
                endif
               
                return false
            endmethod
           
            private method removeFromList takes thistype whichUnit returns nothing
                set whichUnit.parent = 0
           
                set whichUnit.prev.next = whichUnit.next
                set whichUnit.next.prev = whichUnit.prev
               
                if (first == whichUnit) then
                    set first = whichUnit.next
                    if (first == whichUnit) then
                        set first = 0
                    endif
                endif
            endmethod
            static method remove takes thistype whichUnit returns nothing
                local thistype this = whichUnit.parent
           
                call removeFromList(whichUnit)
                call unregisterUnit()
                call remake()
            endmethod
           
            private static method allocate takes nothing returns thistype
                set instanceCount = instanceCount + 1
                return instanceCount
            endmethod
            static method create takes nothing returns thistype
                local thistype this = allocate()
               
                call createTrigger()
               
                return this
            endmethod
        endstruct
       
        private struct TriggerHeapInner extends array
            readonly static integer size = 0
            readonly thistype node
            readonly thistype heap
           
            public method bubbleUp takes nothing returns nothing
                local integer activeUnits = RefreshTrigger(this).activeUnits
                local thistype heapPosition = heap
               
                local thistype parent
               
                /*
                *   Bubble node up
                */
                loop
                    set parent = heapPosition/2
                   
                    if (integer(parent) != 0 and activeUnits < RefreshTrigger(parent.node).activeUnits) then
                        set heapPosition.node = parent.node
                        set heapPosition.node.heap = heapPosition
                    else
                        exitwhen true
                    endif
                   
                    set heapPosition = parent
                endloop
               
                /*
                *   Update pointers
                */
                set heapPosition.node = this
                set heap = heapPosition
            endmethod
            public method bubbleDown takes nothing returns nothing
                local integer activeUnits = RefreshTrigger(this).activeUnits
                local thistype heapPosition = heap
               
                local thistype left
                local thistype right
               
                /*
                *   Bubble node down
                */
                loop
                    set left = heapPosition*2
                    set right = left + 1
                   
                    if (RefreshTrigger(left.node).activeUnits < activeUnits and RefreshTrigger(left.node).activeUnits < RefreshTrigger(right.node).activeUnits) then
                        /*
                        *   Go left
                        */
                        set heapPosition.node = left.node
                        set heapPosition.node.heap = heapPosition
                        set heapPosition = left
                    elseif (RefreshTrigger(right.node).activeUnits < activeUnits) then
                        /*
                        *   Go right
                        */
                        set heapPosition.node = right.node
                        set heapPosition.node.heap = heapPosition
                        set heapPosition = right
                    else
                        exitwhen true
                    endif
                endloop
               
                /*
                *   Update pointers
                */
                set heapPosition.node = this
                set heap = heapPosition
            endmethod
           
            static method insert takes thistype this returns nothing
                /*
                *   Increase heap size
                */
                set size = size + 1
               
                /*
                *   Store node in last heap position
                */
                set thistype(size).node = this
                set heap = size
               
                /*
                *   Bubble node into correct position
                */
                call bubbleUp()
            endmethod
        endstruct
       
        private struct TriggerHeap extends array
            static method add takes UnitIndex whichUnit returns nothing
                local RefreshTrigger trig = TriggerHeapInner(1).node
               
                if (not trig.add(whichUnit)) then
                    set trig = RefreshTrigger.create()
                    call trig .add(whichUnit)
                    call TriggerHeapInner.insert(trig)
                else
                    call TriggerHeapInner(trig).bubbleDown()
                endif
            endmethod
            static method remove takes UnitIndex whichUnit returns nothing
                local RefreshTrigger trig = RefreshTrigger(whichUnit).parent
                call RefreshTrigger.remove(whichUnit)
                call TriggerHeapInner(trig).bubbleUp()
            endmethod
        endstruct
       
        private module TriggerRefreshInitModule
            private static method onInit takes nothing returns nothing
                call init($CODE$)
            endmethod
        endmodule
       
        private struct TriggerRefreshInit extends array
            private static method onIndex takes nothing returns boolean
                call TriggerHeap.add(GetIndexedUnitId())
               
                return false
            endmethod
           
            private static method onDeindex takes nothing returns boolean
                call TriggerHeap.remove(GetIndexedUnitId())
           
                return false
            endmethod
       
            private static method init takes code c returns nothing
                set condition = Condition(c)
               
                call RegisterUnitIndexEvent(Filter(function thistype.onIndex)  , EVENT_UNIT_INDEX)
                call RegisterUnitIndexEvent(Filter(function thistype.onDeindex)  , EVENT_UNIT_DEINDEX)
                //call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onIndex))
                //call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onDeindex))
            endmethod
           
            implement TriggerRefreshInitModule
        endstruct
    endscope
//! endtextmacro

DamageEvent
JASS:
library DamageEvent /* v2.0.0.0
*************************************************************************************
*
*   Damage Event plugin for DDS
*
*************************************************************************************
*
*   */uses/*
*
*       */ DDS                      /*
*        */ Trigger                    /*
*
************************************************************************************
*
*   SETTINGS
*/
globals
    /*************************************************************************************
    *
    *   Enabling four phases, which splits ON_DAMAGE into ON_DAMAGE and ON_DAMAGE_OUTGOING
    *
    *    This adds a little overhead, but gives more functionality. Only enable these extra
    *    phases if you need them.
    *
    *************************************************************************************/
    public constant boolean FOUR_PHASE = true
endglobals
/*
*************************************************************************************
*
*   API
*
*       readonly static Trigger DDS.GlobalDamageEvent.ON_DAMAGE_BEFORE
*            -    runs first whenever any unit is damaged (setup)
*
*        readonly static Trigger DDS.GlobalDamageEvent.ON_DAMAGE_AFTER
*            -    runs last and in reverse whenever any unit is damaged (cleanup)
*
*        readonly Trigger DDS.ON_DAMAGE
*            -    runs when a specific unit is damaged
*
*        method fireLocal takes nothing returns nothing
*            -    fires ON_DAMAGE followed by ON_DAMAGE_AFTER correctly
*
*            -    this is used for custom combat systems, meaning that the DDS data for
*                damage, target, etc will no longer be accurate
*
*            -    it is expected that damage data is created (similarly to ON_DAMAGE_BEFORE)
*
*       readony static real damage
*           -   amount of damage dealt
*
*       readonly static unit target
*       readonly static UnitIndex targetId
*           -   damaged unit
*
*       readonly static unit source
*       readonly static UnitIndex sourceId
*           -   unit that dealt damage
*
*       readonly static player sourcePlayer
*           -   owner of source
*
*        readonly static player targetPlayer
*            -    owner of target
*
*
*        MUST BE DECLARED -        onDamageBefore
*        ------------------------------------------
*
*            readonly static Trigger ON_DAMAGE_BEFORE
*                -    allows a user to run through the struct rather than DDS
*
*
*        MUST BE DECLARED -        onDamageAfter
*        ------------------------------------------
*
*            readonly static Trigger ON_DAMAGE_AFTER
*                -    allows a user to run through the struct rather than DDS
*
*
*        MUST BE DECLARED -        onDamage
*        ------------------------------------------
*
*            readonly Trigger ON_DAMAGE
*                -    allows a user to run through the struct rather than DDS
*
*            method enableDamageEventLocal takes nothing returns boolean
*                -    will enable the local event for a given unit index
*                    after the first enable, it will just increase a counter
*
*                -    returns true when actually enabling
*                    returns false when just increasing the counter
*
*                    Examples:    local MyStruct modifier = someUnitIndex //on item pickup
*                                call modifier.enableDamageEventLocal()
*                                set modifier.physicalDamageReduction = modifier.physicalDamageReduction + item.physicalDamageReduction
*
*            method disableDamageEventLocal takes nothing returns boolean
*                -    will disable the local event for a given unit index
*                    decreases a counter until that counter reaches 0, at which point
*                    the thing is actuall disabled
*
*                -    returns true when actually disabling
*                    returns false when just decreasing the counter
*
*                    Examples:    local MyStruct modifier = someUnitIndex //on item drop
*                                call modifier.disableDamageEventLocal()
*                                set modifier.physicalDamageReduction = modifier.physicalDamageReduction - item.physicalDamageReduction
*
*    FOUR_PHASE ONLY SECTION
*
*        readonly Trigger DDS.ON_DAMAGE_OUTGOING
*            -    runs when a specific unit deals damage
*
*        MUST BE DECLARED -        onDamageOutgoing
*        ------------------------------------------
*
*            readonly Trigger ON_DAMAGE_OUTGOING
*                -    allows a user to run through the struct rather than DDS
*
*            method enableDamageEventLocalOutgoing takes nothing returns boolean
*                -    will enable the local event for a given unit index
*                    after the first enable, it will just increase a counter
*
*                -    returns true when actually enabling
*                    returns false when just increasing the counter
*
*                    Examples:    local MyStruct modifier = someUnitIndex //on item pickup
*                                call modifier.enableDamageEventLocalOutgoing()
*                                set modifier.attackIncrease = modifier.attackIncrease + item.attackIncrease
*
*            method disableDamageEventLocalOutgoing takes nothing returns boolean
*                -    will disable the local event for a given unit index
*                    decreases a counter until that counter reaches 0, at which point
*                    the thing is actuall disabled
*
*                -    returns true when actually disabling
*                    returns false when just decreasing the counter
*
*                    Examples:    local MyStruct modifier = someUnitIndex //on item drop
*                                call modifier.disableDamageEventLocalOutgoing()
*                                set modifier.attackIncrease = modifier.attackIncrease - item.attackIncrease
*
*************************************************************************************
*
*   Interface
*
*       (optional) private static method onDamageBefore takes nothing returns nothing
*           -   is run first whenever a unit is damaged
*       (optional) private static method onDamageAfter takes nothing returns nothing
*           -   is run last whenever a unit is damaged
*
*       (optional) private method onDamage takes nothing returns nothing
*           -   is run when a specific unit is damaged
*
*            -    this == index of unit taking damage
*
*    FOUR_PHASE ONLY SECTION
*
*       (optional) private method onDamageOutgoing takes nothing returns nothing
*           -   is run when a specific unit deals damage
*
*            -    this == index of unit dealing damage
*
*************************************************************************************
*
*   Plugin Information (can only be used by other plugins)
*
*       static UnitIndex targetId_p
*       static UnitIndex sourceId_p
*
*       static real damage_p
*
*       static player sourcePlayer_p
*       static player targetPlayer_p
*
*************************************************************************************/
    //! textmacro DAMAGE_EVENT_CODE
   
    private keyword damage_p
    private keyword targetId_p
    private keyword sourceId_p
    private keyword sourcePlayer_p
    private keyword targetPlayer_p
   
    scope DamageEvent
        private keyword init
        private keyword ON_DAMAGE_MAIN
        private keyword ON_DAMAGE_MAIN_2
       
        private struct GlobalDamageEvent extends array
            readonly static Trigger ON_DAMAGE_BEFORE
            readonly static Trigger ON_DAMAGE_AFTER
           
            static method init takes nothing returns nothing
                set ON_DAMAGE_BEFORE = Trigger.create(false)
                set ON_DAMAGE_AFTER = Trigger.create(true)
            endmethod
        endstruct
        struct LocalDamageEvent extends array
            readonly Trigger ON_DAMAGE_MAIN                //BEFORE, OUTGOING
            readonly Trigger ON_DAMAGE_MAIN_2            //INCOMING, AFTER
            readonly Trigger ON_DAMAGE
           
            method fireLocal takes nothing returns nothing
                call ON_DAMAGE_MAIN_2.fire()
            endmethod
       
            static if DamageEvent_FOUR_PHASE then
                readonly Trigger ON_DAMAGE_OUTGOING
               
                private static method onUnitIndex takes nothing returns boolean
                    local thistype this = GetIndexedUnitId()
                   
                    set ON_DAMAGE_MAIN = Trigger.create(false)
                    set ON_DAMAGE_MAIN_2 = Trigger.create(false)
                    set ON_DAMAGE = Trigger.create(false)
                    set ON_DAMAGE_OUTGOING = Trigger.create(false)
                   
                    call ON_DAMAGE_MAIN.reference(GlobalDamageEvent.ON_DAMAGE_BEFORE)
                    call ON_DAMAGE_MAIN.reference(ON_DAMAGE_OUTGOING)
                    call ON_DAMAGE_MAIN_2.reference(ON_DAMAGE)
                    call ON_DAMAGE_MAIN_2.reference(GlobalDamageEvent.ON_DAMAGE_AFTER)
           
                    return false
                endmethod
               
                private static method onUnitDeindex takes nothing returns boolean
                    local thistype this = GetIndexedUnitId()
                   
                    call ON_DAMAGE_MAIN.destroy()
                    call ON_DAMAGE_MAIN_2.destroy()
                    call ON_DAMAGE.destroy()
                    call ON_DAMAGE_OUTGOING.destroy()
               
                    return false
                endmethod
            else
                private static method onUnitIndex takes nothing returns boolean
                    local thistype this = GetIndexedUnitId()
                   
                    set ON_DAMAGE_MAIN = Trigger.create(false)
                    set ON_DAMAGE_MAIN_2 = Trigger.create(false)
                    set ON_DAMAGE = Trigger.create(false)
                   
                    call ON_DAMAGE_MAIN.reference(GlobalDamageEvent.ON_DAMAGE_BEFORE)
                    call ON_DAMAGE_MAIN.reference(ON_DAMAGE_MAIN_2)
                    call ON_DAMAGE_MAIN_2.reference(ON_DAMAGE)
                    call ON_DAMAGE_MAIN_2.reference(GlobalDamageEvent.ON_DAMAGE_AFTER)
           
                    return false
                endmethod
               
                private static method onUnitDeindex takes nothing returns boolean
                    local thistype this = GetIndexedUnitId()
                   
                    call ON_DAMAGE_MAIN.destroy()
                    call ON_DAMAGE_MAIN_2.destroy()
                    call ON_DAMAGE.destroy()
               
                    return false
                endmethod
            endif
           
            static method init takes nothing returns nothing
           
                call RegisterUnitIndexEvent(Filter(function thistype.onUnitIndex)  , EVENT_UNIT_INDEX)
                call RegisterUnitIndexEvent(Filter(function thistype.onUnitDeindex)  , EVENT_UNIT_DEINDEX)
           
                //call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onUnitIndex))
                //call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onUnitDeindex))
            endmethod
        endstruct
       
        /*
        *   DDS API
        *
        *       DDS.GlobalEvent.ON_DAMAGE_BEFORE
        *       DDS.GlobalEvent.ON_DAMAGE_AFTER
        *        DDS.Event.ON_DAMAGE
        *
        *       DDS.target
        *        DDS.targetId
        *       DDS.source
        *        DDS.sourceId
        *        DDS.sourcePlayer
        *       DDS.damage
        *
        */
        private keyword damageEventInit
       
        module DAMAGE_EVENT_API
            static method operator GlobalEvent takes nothing returns GlobalDamageEvent
                return 0
            endmethod
            method operator Event takes nothing returns LocalDamageEvent
                return this
            endmethod
       
            static UnitIndex targetId_p = 0
            static UnitIndex sourceId_p = 0
            static real damage_p = 0
            static player sourcePlayer_p = null
            static player targetPlayer_p = null
           
            static method operator targetId takes nothing returns UnitIndex
                return targetId_p
            endmethod
            static method operator target takes nothing returns unit
                return targetId.unit
            endmethod
           
            static method operator sourceId takes nothing returns UnitIndex
                return sourceId_p
            endmethod
            static method operator source takes nothing returns unit
                return sourceId.unit
            endmethod
           
            static method operator damage takes nothing returns real
                return damage_p
            endmethod
           
            static method operator sourcePlayer takes nothing returns player
                return sourcePlayer_p
            endmethod
           
            static method operator targetPlayer takes nothing returns player
                return targetPlayer_p
            endmethod
           
            static method damageEventInit takes nothing returns nothing
                call GlobalDamageEvent.init()
                call LocalDamageEvent.init()
            endmethod
        endmodule
       
        module DAMAGE_EVENT_INIT
            call DDS.damageEventInit()
        endmodule

        /*
        *   DDS Interface
        *
        *       interface private static method onDamage takes nothing returns nothing
        *
        *      
        */
        module DAMAGE_EVENT_INTERFACE
            /*
            *    private static method getCondition takes code c returns boolexpr
            */
            static if thistype.onDamageBefore.exists then
                private static method getCondition takes code c returns boolexpr
                    return Condition(c)
                    return null
                endmethod
            elseif thistype.onDamageAfter.exists then
                private static method getCondition takes code c returns boolexpr
                    return Condition(c)
                    return null
                endmethod
            endif
           
            static if thistype.onDamageBefore.exists then
                readonly static Trigger ON_DAMAGE_BEFORE
            endif
            static if thistype.onDamageAfter.exists then
                readonly static Trigger ON_DAMAGE_AFTER
            endif
           
            static if thistype.onDamage.exists then
                readonly Trigger ON_DAMAGE
                private static boolexpr onDamageExpr
                private TriggerReference ON_DAMAGE_REF
               
                private static method onDamageFunc takes nothing returns boolean
                    call thistype(targetId).onDamage()
                    return false
                endmethod
               
                private integer count
               
                method enableDamageEventLocal takes nothing returns boolean
                    set count = count + 1
               
                    if (count == 1) then
                        set ON_DAMAGE_REF = LocalDamageEvent(this).ON_DAMAGE.reference(ON_DAMAGE)
                       
                        return true
                    endif
                   
                    return false
                endmethod
               
                method disableDamageEventLocal takes nothing returns boolean
                    if (count == 0) then
                        return false
                    endif
               
                    set count = count - 1
               
                    if (count == 0) then
                        call ON_DAMAGE_REF.destroy()
                       
                        return true
                    endif
                   
                    return false
                endmethod
            endif
       
            static if DamageEvent_FOUR_PHASE then
                static if thistype.onDamageOutgoing.exists then
                    readonly Trigger ON_DAMAGE_OUTGOING
                    private static boolexpr onDamageOutgoingExpr
                    private TriggerReference ON_DAMAGE_OUTGOING_REF
                   
                    private static method onDamageOutgoingFunc takes nothing returns boolean
                        call thistype(sourceId).onDamageOutgoing()
                        return false
                    endmethod
                   
                    private integer countOutgoing
                   
                    method enableDamageEventLocalOutgoing takes nothing returns boolean
                        set countOutgoing = countOutgoing + 1
                   
                        if (countOutgoing == 1) then
                            set ON_DAMAGE_OUTGOING_REF = LocalDamageEvent(this).ON_DAMAGE_OUTGOING.reference(ON_DAMAGE_OUTGOING)
                           
                            return true
                        endif
                       
                        return false
                    endmethod
                   
                    method disableDamageEventLocalOutgoing takes nothing returns boolean
                        if (countOutgoing == 0) then
                            return false
                        endif
                   
                        set countOutgoing = countOutgoing - 1
                   
                        if (countOutgoing == 0) then
                            call ON_DAMAGE_OUTGOING_REF.destroy()
                           
                            return true
                        endif
                       
                        return false
                    endmethod
                endif
               
                static if thistype.onDamageOutgoing.exists then
                    private static method onUnitIndex takes nothing returns boolean
                        local thistype this = GetIndexedUnitId()
                   
                        static if thistype.onDamage.exists then
                            set ON_DAMAGE = Trigger.create(false)
                            call ON_DAMAGE.register(onDamageExpr)
                        endif
                       
                        static if thistype.onDamageOutgoing.exists then
                            set ON_DAMAGE_OUTGOING = Trigger.create(false)
                            call ON_DAMAGE_OUTGOING.register(onDamageOutgoingExpr)
                        endif
                       
                        return false
                    endmethod
                   
                    private static method onUnitDeindex takes nothing returns boolean
                        local thistype this = GetIndexedUnitId()
                       
                        static if thistype.onDamage.exists then
                            call ON_DAMAGE.destroy()
                           
                            set count = 0
                        endif
                       
                        static if thistype.onDamageOutgoing.exists then
                            call ON_DAMAGE_OUTGOING.destroy()
                           
                            set countOutgoing = 0
                        endif
                       
                        return false
                    endmethod
                elseif thistype.onDamage.exists then
                    private static method onUnitIndex takes nothing returns boolean
                        local thistype this = GetIndexedUnitId()
                   
                        static if thistype.onDamage.exists then
                            set ON_DAMAGE = Trigger.create(false)
                            call ON_DAMAGE.register(onDamageExpr)
                        endif
                       
                        static if thistype.onDamageOutgoing.exists then
                            set ON_DAMAGE_OUTGOING = Trigger.create(false)
                            call ON_DAMAGE_OUTGOING.register(onDamageOutgoingExpr)
                        endif
                       
                        return false
                    endmethod
                   
                    private static method onUnitDeindex takes nothing returns boolean
                        local thistype this = GetIndexedUnitId()
                       
                        static if thistype.onDamage.exists then
                            call ON_DAMAGE.destroy()
                           
                            set count = 0
                        endif
                       
                        static if thistype.onDamageOutgoing.exists then
                            call ON_DAMAGE_OUTGOING.destroy()
                           
                            set countOutgoing = 0
                        endif
                       
                        return false
                    endmethod
                endif
               
                static if thistype.onDamageBefore.exists then
                    private static method onInit takes nothing returns nothing
                        static if thistype.onDamage.exists then
                            set onDamageExpr = Condition(function thistype.onDamageFunc)
                        endif
                       
                        static if thistype.onDamageOutgoing.exists then
                            set onDamageOutgoingExpr = Condition(function thistype.onDamageOutgoingFunc)
                        endif
                       
                        static if thistype.onDamage.exists then
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitIndex)  , EVENT_UNIT_INDEX)
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitDeindex)  , EVENT_UNIT_DEINDEX)
                       
                            //call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onUnitIndex))
                            //call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onUnitDeindex))
                        elseif thistype.onDamageOutgoing.exists then
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitIndex)  , EVENT_UNIT_INDEX)
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitDeindex)  , EVENT_UNIT_DEINDEX)
                       
                       
                            //call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onUnitIndex))
                            //call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onUnitDeindex))
                        endif
                       
                        static if thistype.onDamageBefore.exists then
                            set ON_DAMAGE_BEFORE = Trigger.create(false)
                            call ON_DAMAGE_BEFORE.register(getCondition(function thistype.onDamageBefore))
                            call GlobalDamageEvent.ON_DAMAGE_BEFORE.reference(ON_DAMAGE_BEFORE)
                        endif
                       
                        static if thistype.onDamageAfter.exists then
                            set ON_DAMAGE_AFTER = Trigger.create(true)
                            call ON_DAMAGE_AFTER.register(getCondition(function thistype.onDamageAfter))
                            call GlobalDamageEvent.ON_DAMAGE_AFTER.reference(ON_DAMAGE_AFTER)
                        endif
                    endmethod
                elseif thistype.onDamageAfter.exists then
                    private static method onInit takes nothing returns nothing
                        static if thistype.onDamage.exists then
                            set onDamageExpr = Condition(function thistype.onDamageFunc)
                        endif
                       
                        static if thistype.onDamageOutgoing.exists then
                            set onDamageOutgoingExpr = Condition(function thistype.onDamageOutgoingFunc)
                        endif
                       
                        static if thistype.onDamage.exists then
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitIndex)  , EVENT_UNIT_INDEX)
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitDeindex)  , EVENT_UNIT_DEINDEX)
                       
                            //call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onUnitIndex))
                            //call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onUnitDeindex))
                        elseif thistype.onDamageOutgoing.exists then
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitIndex)  , EVENT_UNIT_INDEX)
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitDeindex)  , EVENT_UNIT_DEINDEX)
                       
                            //call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onUnitIndex))
                            //call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onUnitDeindex))
                        endif
                       
                        static if thistype.onDamageBefore.exists then
                            set ON_DAMAGE_BEFORE = Trigger.create(false)
                            call ON_DAMAGE_BEFORE.register(getCondition(function thistype.onDamageBefore))
                            call GlobalDamageEvent.ON_DAMAGE_BEFORE.reference(ON_DAMAGE_BEFORE)
                        endif
                       
                        static if thistype.onDamageAfter.exists then
                            set ON_DAMAGE_AFTER = Trigger.create(true)
                            call ON_DAMAGE_AFTER.register(getCondition(function thistype.onDamageAfter))
                            call GlobalDamageEvent.ON_DAMAGE_AFTER.reference(ON_DAMAGE_AFTER)
                        endif
                    endmethod
                elseif thistype.onDamage.exists then
                    private static method onInit takes nothing returns nothing
                        static if thistype.onDamage.exists then
                            set onDamageExpr = Condition(function thistype.onDamageFunc)
                        endif
                       
                        static if thistype.onDamageOutgoing.exists then
                            set onDamageOutgoingExpr = Condition(function thistype.onDamageOutgoingFunc)
                        endif
                       
                        static if thistype.onDamage.exists then
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitIndex)  , EVENT_UNIT_INDEX)
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitDeindex)  , EVENT_UNIT_DEINDEX)
                       
                            //call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onUnitIndex))
                            //call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onUnitDeindex))
                        elseif thistype.onDamageOutgoing.exists then
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitIndex)  , EVENT_UNIT_INDEX)
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitDeindex)  , EVENT_UNIT_DEINDEX)
                       
                            //call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onUnitIndex))
                            //call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onUnitDeindex))
                        endif
                       
                        static if thistype.onDamageBefore.exists then
                            set ON_DAMAGE_BEFORE = Trigger.create(false)
                            call ON_DAMAGE_BEFORE.register(getCondition(function thistype.onDamageBefore))
                            call GlobalDamageEvent.ON_DAMAGE_BEFORE.reference(ON_DAMAGE_BEFORE)
                        endif
                       
                        static if thistype.onDamageAfter.exists then
                            set ON_DAMAGE_AFTER = Trigger.create(true)
                            call ON_DAMAGE_AFTER.register(getCondition(function thistype.onDamageAfter))
                            call GlobalDamageEvent.ON_DAMAGE_AFTER.reference(ON_DAMAGE_AFTER)
                        endif
                    endmethod
                elseif thistype.onDamageOutgoing.exists then
                    private static method onInit takes nothing returns nothing
                        static if thistype.onDamage.exists then
                            set onDamageExpr = Condition(function thistype.onDamageFunc)
                        endif
                       
                        static if thistype.onDamageOutgoing.exists then
                            set onDamageOutgoingExpr = Condition(function thistype.onDamageOutgoingFunc)
                        endif
                       
                        static if thistype.onDamage.exists then
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitIndex)  , EVENT_UNIT_INDEX)
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitDeindex)  , EVENT_UNIT_DEINDEX)
                       
                       
                            //call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onUnitIndex))
                            //call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onUnitDeindex))
                        elseif thistype.onDamageOutgoing.exists then
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitIndex)  , EVENT_UNIT_INDEX)
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitDeindex)  , EVENT_UNIT_DEINDEX)
                       
                            //call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onUnitIndex))
                            //call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onUnitDeindex))
                        endif
                       
                        static if thistype.onDamageBefore.exists then
                            set ON_DAMAGE_BEFORE = Trigger.create(false)
                            call ON_DAMAGE_BEFORE.register(getCondition(function thistype.onDamageBefore))
                            call GlobalDamageEvent.ON_DAMAGE_BEFORE.reference(ON_DAMAGE_BEFORE)
                        endif
                       
                        static if thistype.onDamageAfter.exists then
                            set ON_DAMAGE_AFTER = Trigger.create(true)
                            call ON_DAMAGE_AFTER.register(getCondition(function thistype.onDamageAfter))
                            call GlobalDamageEvent.ON_DAMAGE_AFTER.reference(ON_DAMAGE_AFTER)
                        endif
                    endmethod
                endif
            else
                static if thistype.onDamage.exists then
                    private static method onUnitIndex takes nothing returns boolean
                        local thistype this = GetIndexedUnitId()
                   
                        set ON_DAMAGE = Trigger.create(false)
                        call ON_DAMAGE.register(onDamageExpr)
                   
                        return false
                    endmethod
                   
                    private static method onUnitDeindex takes nothing returns boolean
                        local thistype this = GetIndexedUnitId()
                   
                        call ON_DAMAGE.destroy()
                       
                        set count = 0
                       
                        return false
                    endmethod
                endif
               
                static if thistype.onDamageBefore.exists then
                    private static method onInit takes nothing returns nothing
                        static if thistype.onDamage.exists then
                            set onDamageExpr = Condition(function thistype.onDamageFunc)
                           
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitIndex)  , EVENT_UNIT_INDEX)
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitDeindex)  , EVENT_UNIT_DEINDEX)
                            //call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onUnitIndex))
                            //call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onUnitDeindex))
                        endif
                   
                        static if thistype.onDamageBefore.exists then
                            set ON_DAMAGE_BEFORE = Trigger.create(false)
                            call ON_DAMAGE_BEFORE.register(getCondition(function thistype.onDamageBefore))
                            call GlobalDamageEvent.ON_DAMAGE_BEFORE.reference(ON_DAMAGE_BEFORE)
                        endif
                       
                        static if thistype.onDamageAfter.exists then
                            set ON_DAMAGE_AFTER = Trigger.create(true)
                            call ON_DAMAGE_AFTER.register(getCondition(function thistype.onDamageAfter))
                            call GlobalDamageEvent.ON_DAMAGE_AFTER.reference(ON_DAMAGE_AFTER)
                        endif
                    endmethod
                elseif thistype.onDamageAfter.exists then
                    private static method onInit takes nothing returns nothing
                        static if thistype.onDamage.exists then
                            set onDamageExpr = Condition(function thistype.onDamageFunc)
                           
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitIndex)  , EVENT_UNIT_INDEX)
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitDeindex)  , EVENT_UNIT_DEINDEX)
                           
                            //call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onUnitIndex))
                            //call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onUnitDeindex))
                        endif
                   
                        static if thistype.onDamageBefore.exists then
                            set ON_DAMAGE_BEFORE = Trigger.create(false)
                            call ON_DAMAGE_BEFORE.register(getCondition(function thistype.onDamageBefore))
                            call GlobalDamageEvent.ON_DAMAGE_BEFORE.reference(ON_DAMAGE_BEFORE)
                        endif
                       
                        static if thistype.onDamageAfter.exists then
                            set ON_DAMAGE_AFTER = Trigger.create(true)
                            call ON_DAMAGE_AFTER.register(getCondition(function thistype.onDamageAfter))
                            call GlobalDamageEvent.ON_DAMAGE_AFTER.reference(ON_DAMAGE_AFTER)
                        endif
                    endmethod
                elseif thistype.onDamage.exists then
                    private static method onInit takes nothing returns nothing
                        static if thistype.onDamage.exists then
                            set onDamageExpr = Condition(function thistype.onDamageFunc)
                           
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitIndex)  , EVENT_UNIT_INDEX)
                            call RegisterUnitIndexEvent(Filter(function thistype.onUnitDeindex)  , EVENT_UNIT_DEINDEX)
                           
                            //call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onUnitIndex))
                            //call UnitIndexer.GlobalEvent.ON_DEINDEX.register(Condition(function thistype.onUnitDeindex))
                        endif
                   
                        static if thistype.onDamageBefore.exists then
                            set ON_DAMAGE_BEFORE = Trigger.create(false)
                            call ON_DAMAGE_BEFORE.register(getCondition(function thistype.onDamageBefore))
                            call GlobalDamageEvent.ON_DAMAGE_BEFORE.reference(ON_DAMAGE_BEFORE)
                        endif
                       
                        static if thistype.onDamageAfter.exists then
                            set ON_DAMAGE_AFTER = Trigger.create(true)
                            call ON_DAMAGE_AFTER.register(getCondition(function thistype.onDamageAfter))
                            call GlobalDamageEvent.ON_DAMAGE_AFTER.reference(ON_DAMAGE_AFTER)
                        endif
                    endmethod
                endif
            endif
        endmodule

        /*
        *   DDS Event Handling
        */
module DAMAGE_EVENT_RESPONSE_LOCALS
                local UnitIndex prevTarget = targetId_p
                local UnitIndex prevSource = sourceId_p
               
                local real prevDamage = damage_p
endmodule
module DAMAGE_EVENT_RESPONSE_BEFORE
                if (0 == GetEventDamage()) then
                    return
                endif
               
                set targetId_p = GetUnitUserData(GetTriggerUnit())
                set sourceId_p = GetUnitUserData(GetEventDamageSource())
                set damage_p = GetEventDamage()
                set sourcePlayer_p = GetOwningPlayer(sourceId_p.unit)
                set targetPlayer_p = GetOwningPlayer(targetId_p.unit)
endmodule
module DAMAGE_EVENT_RESPONSE
                static if DamageEvent_FOUR_PHASE then
                    call LocalDamageEvent(sourceId_p).ON_DAMAGE_MAIN.fire()
                    call LocalDamageEvent(targetId_p).ON_DAMAGE_MAIN_2.fire()
                else
                    call LocalDamageEvent(targetId_p).ON_DAMAGE_MAIN.fire()
                endif
endmodule
module DAMAGE_EVENT_RESPONSE_AFTER
               
endmodule
module DAMAGE_EVENT_RESPONSE_CLEANUP
                set targetId_p = prevTarget
                set sourceId_p = prevSource
                set damage_p = prevDamage
               
                if (sourceId_p == 0) then
                    set sourcePlayer_p = null
                else
                    set targetPlayer_p = GetOwningPlayer(sourceId_p.unit)
                endif
               
                if (targetId_p == 0) then
                    set sourcePlayer_p = null
                else
                    set targetPlayer_p = GetOwningPlayer(targetId_p.unit)
                endif
endmodule
    endscope
    //! endtextmacro
endlibrary
DamageEventArchetype

JASS:
library DamageEventArchetype /* v1.0.2.0
*************************************************************************************
*
*   Damage Event Archetype plugin for DDS
*
*
*   Notes
*   --------------
*
*       -   Must invert Damage Return Factor for Locust Swarm based abilities
*
*       -   Must invert healing portion of Life Drain based abilities
*
*************************************************************************************
*
*   */uses/*
*
*       */ DDS                      /*      hiveworkshop.com/forums/spells-569/framework-dds-damage-detection-system-231238/
*       */ DamageEventModification  /*      hiveworkshop.com/forums/jass-resources-412/dds-plugin-damage-event-modification-231176/
        */ UnitDex                  /*
        */ UnitIndexer              /*
*
************************************************************************************
*
*   SETTINGS
*/
globals
    /*************************************************************************************
    *
    *   Configure to spell reduction ability type id
    *
    *************************************************************************************/
    constant integer DAMAGE_EVENT_ARCHETYPE_PLUGIN_ABILITY = 'A002'
endglobals
/*
*************************************************************************************
*
*   API
*
*       static constant integer Archetype.SPELL
*       static constant integer Archetype.PHYSICAL
*       static constant integer Archetype.CODE
*
*       readonly static integer archetype
*           -   type of damage source damage came from: SPELL, PHYSICAL, CODE
*
*       static UnitIndex damageCode
*           -   set this to the unit that will be damaged with code
*
*       seals (can no longer be overwritten)
*
*           boolean enabled (from DDS Framework)
*
*************************************************************************************/
    //! textmacro DAMAGE_EVENT_ARCHETYPE_CODE
    globals
        private constant boolean ENABLED_EXISTS = true
       
        private real scale
    endglobals
   
    scope Archetype
        private struct DamageEventArchtype extends array
            static constant integer SPELL = 0
            static constant integer PHYSICAL = 1
            static constant integer CODE = 2
        endstruct
   
        /*
        *   DDS API
        *
        *       DDS.Archetype.SPELL
        *       DDS.Archetype.PHYSICAL
        *       DDS.Archetype.CODE
        *       DDS.archetype
        *       DDS.damageCode
        *      
        */
            private keyword archetype_p
            private keyword damageEventArchetypeInit
            private keyword damageCode_p
            module DAMAGE_EVENT_ARCHETYPE_API
                readonly static DamageEventArchtype Archetype = 0
                static integer archetype_p = 0
                static UnitIndex damageCode_p = 0
               
                static method operator damageCode= takes UnitIndex u returns nothing
                    set damageCode_p = u
                endmethod
                static method operator damageCode takes nothing returns UnitIndex
                    return damageCode_p
                endmethod
               
                static method operator archetype takes nothing returns integer
                    return archetype_p
                endmethod
               
                private static method onIndex takes nothing returns boolean
                    call UnitAddAbility(GetIndexedUnit(), DAMAGE_EVENT_ARCHETYPE_PLUGIN_ABILITY)
                    call UnitMakeAbilityPermanent(GetIndexedUnit(), true, DAMAGE_EVENT_ARCHETYPE_PLUGIN_ABILITY)
                   
                    return false
                endmethod
               
                static method damageEventArchetypeInit takes nothing returns nothing
                    local integer playerId
           
                    set playerId = 15
                    loop
                        call SetPlayerAbilityAvailable(Player(playerId), DAMAGE_EVENT_ARCHETYPE_PLUGIN_ABILITY, false)
                       
                        exitwhen 0 == playerId
                        set playerId = playerId - 1
                    endloop
                    call RegisterUnitIndexEvent(Filter(function thistype.onIndex)  , EVENT_UNIT_INDEX)
                    //call UnitIndexer.GlobalEvent.ON_INDEX.register(Condition(function thistype.onIndex))
                endmethod
            endmodule
            module DAMAGE_EVENT_ENABLE
                method operator enabled= takes boolean b returns nothing
                    if (b) then
                        call EnableTrigger(RefreshTrigger(this).parent.trigger)
                        call UnitAddAbility(UnitIndex(this).unit, DAMAGE_EVENT_ARCHETYPE_PLUGIN_ABILITY)
                        call UnitMakeAbilityPermanent(UnitIndex(this).unit, true, DAMAGE_EVENT_ARCHETYPE_PLUGIN_ABILITY)
                    else
                        call DisableTrigger(RefreshTrigger(this).parent.trigger)
                        call UnitRemoveAbility(UnitIndex(this).unit, DAMAGE_EVENT_ARCHETYPE_PLUGIN_ABILITY)
                    endif
                endmethod
            endmodule
            module DAMAGE_EVENT_ARCHETYPE_INIT
                call DDS.damageEventArchetypeInit()
            endmodule

        /*
        *   DDS Interface
        */
        module DAMAGE_EVENT_ARCHETYPE_INTERFACE
           
        endmodule

        /*
        *   DDS Event Handling
        */
module DAMAGE_EVENT_ARCHETYPE_RESPONSE_LOCALS
                local integer prevArchetype = archetype_p
endmodule
module DAMAGE_EVENT_ARCHETYPE_RESPONSE_BEFORE
                if (damage_p < 0) then
                    set archetype_p = Archetype.SPELL
                   
                    /*
                    *   Calculate spell resistance
                    */
                    call DisableTrigger(RefreshTrigger(targetId_p).parent.trigger)
                   
                        set life = GetWidgetLife(u)
                        set scale = GetUnitState(u, UNIT_STATE_MAX_LIFE)
                        call SetWidgetLife(u, scale)
                        call UnitDamageTarget(killUnit, u, -scale/2, false, false, null, DAMAGE_TYPE_UNIVERSAL, null)
                        set scale = 2*(scale - GetWidgetLife(u))/scale
                        if (scale > 1) then
                            set damageOriginal = -damageOriginal*scale
                        else
                            set damageOriginal = -damageOriginal
                        endif
                        call SetWidgetLife(u, life)
                   
                    call EnableTrigger(RefreshTrigger(targetId_p).parent.trigger)
                   
                    set damage_p = damageOriginal
                else
                    set archetype_p = Archetype.PHYSICAL
                endif

                if (damageCode_p != 0) then
                    set archetype_p = Archetype.CODE
                    set damageCode_p = 0
                endif
endmodule
module DAMAGE_EVENT_ARCHETYPE_RESPONSE
               
endmodule
module DAMAGE_EVENT_ARCHETYPE_RESPONSE_AFTER
               
endmodule
module DAMAGE_EVENT_ARCHETYPE_RESPONSE_CLEANUP
                set archetype_p = prevArchetype
endmodule
    endscope
    //! endtextmacro
endlibrary
 
Last edited:
Status
Not open for further replies.
Top