• 🏆 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!

[System] Damage Reduction

Level 23
Joined
Apr 16, 2012
Messages
4,041
JASS:
library DamageReduction uses DamageEvent, Table
/*
    Made by: edo494
    Version: 1.1
   
    Requires:
        DamageEvent - [url]http://www.hiveworkshop.com/forums/jass-resources-412/system-physical-damage-detection-228456/[/url]
        Table(Bribe) - [url]http://www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/[/url]
   
    This library allows you to manipuate damage received by
    any unit on the map depending on the unit type, the
    unit, its abilities, item types of wearing items as well
    as items weared by the unit.
    This library manipulates the damage of all 3 types(Physical,
    Spell and Code).
   
    Primary reason of existance of this resource is because of the
    problem that people use Runed Bracers for spell damage reduction,
    even tho the DDS will not work if they do so.
   
    Disadvantage of this resource is that every reduction
    is scaled additively, which means that if unit
    has 10% + 15% reduction, it will have 25% total
    reduction.
   
    If reduction reaches >100%, it is automatically adjusted to
    100% meaning that you will always take 0 damage as long as you
    have it on you
   
    API:
   
    NOTE!!! Abilities do not work unless you call one of the following:
        function UnitRegisterAbility takes unit u, integer abil returns nothing
        function UnitTypeRegisterAbility takes integer uType, integer abil returns nothing
        function UnitAddAbilityEx takes unit whichUnit, integer abilId returns boolean
           
        More about those function below Struct API
           
    NOTE!!! Methods set are called reset, because set is reserved keyword and cannot be
            a name for method
           
    Legend: integer a - always refers to amplifyType, the type we want
                        the function to modify
                        Example: Reduction.SPELL, Reduction.CODE
                       
            real pRd  - always refers to percentual reduction
                        Example: 0.16(which represents 16%)
                       
            integer ut - always refers to unit type, that we
                         want to modify values for
                         
            unit u - always refers to unit we want to modify
                     values for
                     
            integer it - always refers to item type we want
                         to modify values for
                         
            item i - always refers to item we want to modify
                     values for
                     
            integer ab - always refers to ability(via rawcode)
                         that we want to modify values for
                         
            integer lv - always refers to the level of ability
                         we are modifying
                         
           
    globals:
        Visit configuration block below this documentation
       
    struct Reduction extends array
        static integer PHYSICAL = REDUCTION_PHYSICAL
        static integer SPELL = REDUCTION_SPELL
        static integer CODE = REDUCTION_CODE
            - those 3 integers define the reduction types
              you are applying
             
             
    //--- UNIT TYPE REDUCTIONS API ---//
    static Reduction.UnitType.reset takes takes integer ut, integer a, real pRd returns nothing
        - sets the reduction for UnitType "ut" of type "a" to "pRd"
       
    static Reduction.UnitType.add takes integer ut, integer a, real pRd returns nothing
        - adds/increases the reduction for UnitType "ut" of type "a" to "pRd"
       
    static Reduction.UnitType.substract takes integer ut, integer a, real pRd returns nothing
        - substracts/decreases the reduction for UnitType "ut" of type "a" to "pRd"
        - equivalent to call: Reduction.UnitType.add(ut, a, -pRd)
       
    static Reduction.UnitType.get takes integer ut, integer a returns real
        - returns the amount of reduction for UnitType "ut" of type "a"
       
       
    //--- UNIT REDUCTION API ---//
    static Reduction.Unit.reset takes takes unit u, integer a, real pRd returns nothing
        - sets the reduction for unit "u" of type "a" to "pRd"
       
    static Reduction.Unit.add takes unit u, integer a, real pRd returns nothing
        - adds/increases the reduction for unit "u" of type "a" to "pRd"
       
    static Reduction.Unit.substract takes unit u, integer a, real pRd returns nothing
        - substracts/decreases the reduction for unit "u" of type "a" to "pRd"
        - equivalent to call: Reduction.Unit.add(ut, a, -pRd)
       
    static Reduction.Unit.get takes unit u, integer a returns real
        - returns the reduction for unit "u" of type "a"
       
       
    //--- ITEM TYPE REDUCTION API ---//
    static Reduction.ItemType.reset takes takes integer it, integer a, real pRd returns nothing
        - sets the reduction for item type "it" of type "a" to "pRd"
       
    static Reduction.ItemType.add takes integer it, integer a, real pRd returns nothing
        - adds/increases the reduction for item type "it" of type "a" to "pRd"
       
    static Reduction.ItemType.substract takes integer it, integer a, real pRd returns nothing
        - substracts/decreases the reduction for item type "it" of type "a" to "pRd"
        - equivalent to call: Reduction.ItemType.add(it, a, -pRd)
       
    static Reduction.ItemType.get takes integer it, integer a returns real
        - returns the reduction for item type "it" of type "a"
       
       
    //--- ITEM REDUCTION API ---//
    static Reduction.Item.reset takes takes item i, integer a, real pRd returns nothing
        - sets the reduction for item "i" of type "a" to "pRd"
       
    static Reduction.Item.add takes item i, integer a, real pRd returns nothing
        - adds/increases the reduction for item "i" of type "a" to "pRd"
       
    static Reduction.Item.substract takes item i, integer a, real pRd returns nothing
        - substracts/decreases the reduction for item "i" of type "a" to "pRd"
        - equivalent to call: Reduction.Item.add(ut, a, -pRd)
       
    static Reduction.Item.get takes item i, integer a returns real
        - returns the reduction for item "i" of type "a"
    
    
    //--- ON CAST REDUCTION API ---//
    static Reduction.OnCast.setTime takes integer ab, integer lv, real howLong returns nothing
        Sets a time for given ability on given level for how long the bonus should be applied.
    
    static Reduction.OnCast.getTime takes integer ab, integer lv returns real
        Returns for how long will given ability on given level apply its reduction for.
    
    static Reduction.OnCast.useMultiLevel takes integer ab, boolean use returns nothing
        Marks whether the ability uses multiple level bonuses or not.
        If it does, it will use each individual level for ability as differnet.
        If doesnt, it will always apply level == 1 to the effect(time, amount).
   
    static Reduction.OnCast.usesMultiLevel takes integer ab returns boolean
        Returns whether ability uses multiple level bonuses or not.
    
    static Reduction.OnCast.reset takes integer ab, integer lv, integer a, real pRd returns nothing
        Equivalent to: substract(get(...)) followed by add(...)
   
    static Reduction.OnCast.add takes integer ab, integer lv, integer a, real pRd returns nothing
        Increases Reduction for given ability when it is cast of given type("a") by pRd.
   
    static Reduction.OnCast.substract takes integer ab, integer lv, integer a, real pRd returns nothing
        Reduces Reduction for given ability when it is cast of given type("a") by pRd.
   
    static Reduction.OnCast.get takes integer ab, integer lv, integer a returns real
        Returns how much reduction of given type will be applied when ability is cast with given level.
   
   
    //--- ABILITY REDUCTION API ---//
    static Reduction.Ability.useMultiLevel takes integer ab, boolean use returns nothing
        - sets whether given ability uses multi level bonuses or not
        - if true is passed, each level for ability "ab" will have different
          reduction values(for all types)
   
    static Reduction.Ability.usesMultiLevel takes integer ab returns boolean
        - gets whether the ability "ab" uses multi level bonuses or not
   
    static Reduction.Ability.reset takes integer ab, integer lv, integer a, real pRd returns nothing
        - sets the reduction for ability "ab" of type "a" to "pRd" for given level "lv"
        - if ability doesnt use mutli level bonuses, returns the same value for any "lv" passed
   
    static Reduction.Ability.add takes integer ab, integer lv, integer a, real pRd returns nothing
        - adds/increases the reduction for ability "ab" of type "a" to "pRd" for given level "lv"
        - if ability doesnt use mutli level bonuses, returns the same value for any "lv" passed
   
    static Reduction.Ability.substract takes integer ab, integer lv, integer a, real pRd returns nothing
        - substracts/reduces the reduction for ability "ab" of type "a" to "pRd" for given level "lv"
        - if ability doesnt use mutli level bonuses, returns the same value for any "lv" passed
        - equivalent to call: Reduction.Ability.add(ab, lv, a, -pRd)
   
    static Reduction.Ability.get takes integer ab, integer lv, integer a returns real
        - gets the reduction for ability "ab" of type "a" for given level "lv"
        - if ability doesnt use mutli level bonuses, returns the same value for any "lv" passed
       
       
    Functional API
   
    function UnitRegisterAbility takes unit u, integer abil returns nothing
        - registers ability with rawcode "abil" into unit "u"
        - Reduction from this ability will only be considered if the unit
          has this ability
   
    function UnitUnregisterAbility takes unit u, integer abil returns nothing
        - unregisters ability with rawcode "abil" from unit "u"
        - Reduction from this ability will no longer be accounted when unit "u"
        - takes damage even if he has this ability learened
   
    function UnitTypeRegisterAbility takes integer uType, integer abil returns nothing
        - registers ability with rawcode "abil" for unit type "uType"
        - whenever unit of type "uType" takes damage, and has this ability
          (>0 level in it), the Reduction will be applied to the damage
   
    function UnitTypeUnregisterAbility takes integer uType, integer abil returns nothing
        - unregisters ability with rawcode "abil" for unit type "uType"
   
    function UnitAddAbilityEx takes unit whichUnit, integer abilId returns boolean
        - first adds ability "abilId" into unit "whichUnit"
        - if it was added successfully, it also calls
          UnitRegisterAbility(whichUnit, abilId)
        - returns the return value of UnitAddAbility
   
    function UnitRemoveAbilityEx takes unit whichUnit, integer abilId returns boolean
        - first removes "abilId" from "whichUnit"
        - if it was successful, it also calls
          UnitUnregisterAbility(whichUnit, abilId)
        - returns the return value of UnitRemoveAbility
   
    NOTE: - Yes, I know the names are very potentionally
            conflicting, Im up for better name suggestions
          - Keep in mind that the functions should have
            considerably short name
   
*/
    /***********************************/
    /********   Configuration   ********/
    /***********************************/
    globals        
        //when you remove all abilities from list of one unit, it will
        //automatically recycle given instance
        //also applies to unit-type specific list
        private constant boolean DESTROY_EMPTY_STRUCTS = false
       
        //if you want the list of registered unit abilities inside the list
        //to be in strict order(so they are always in the order of insertation), make it true
        private constant boolean UNIT_ABIL_LIST_STRICT_ORDER = false
       
        //set this to true if you dont want the list of unit's abilities
        //to contain duplicates
        private constant boolean LIST_SECURE_DOUBLE_ADD = false
       
        //if this is set, every time unit takes damage the
        //output the damage before and after modification
        //as well as the modification factor
        private constant boolean DEBUG_PRINT_ON_HIT_DMG = false
		
		//how often should onCast values be updated(if you take inverse of this value
		//you will find out how many times per second will this system update onCast time)
		private constant real TICK_TIME = 1.0/8
        
        //how many different REDUCTION_XXX there are
        private constant integer DAMAGE_TYPES = 3
    endglobals
    /***************************************/
    /********   End Configuration   ********/
    /***************************************/
   
   
    globals
        //first value must be 0, and they should increment by 1
        constant integer REDUCTION_PHYSICAL = 0
        constant integer REDUCTION_SPELL = 1
        constant integer REDUCTION_CODE = 2
    endglobals
   
    globals
        private Table amplifiedPhys
        private Table amplifiedMag
        private Table amplifiedCode
       
        //to dispatch in O(1) the types without if block
        private Table array ampDispatch
       
        private Table abilDatIndicies
       
        private Table unitListIndicies
    endglobals
	
	private struct OnCastDat
		unit caster
        Table amounts
        real time
        
        static thistype head
        thistype next
        thistype prev
        
        static method create takes unit caster returns thistype
            local thistype this = allocate()
            set this.caster = caster
            set amounts = Table.create()
            
            set this.next = head.next
            set this.prev = head
            set head.next = this
            
            return this
        endmethod
        
        method destroy takes nothing returns nothing
            call amounts.destroy()
            
            set this.next.prev = this.prev
            set this.prev.next = this.next
            
            set this.prev = 0
            set this.next = 0

            call deallocate()
        endmethod
        
        static method allocated takes nothing returns boolean
            return head.next != 0
        endmethod
        
        private static method onInit takes nothing returns nothing
            set head = create(null)
        endmethod
	endstruct
	
    private struct AbilDat
		TableArray levels
        boolean multiLevel
		
		//for onCast
		Table overallTime
		//end for onCast
		
        static method create takes nothing returns thistype
            local thistype this = allocate()
			set overallTime = Table.create()
            set levels = TableArray[DAMAGE_TYPES]
		   
            set multiLevel = true
           
            return this
        endmethod
       
        method dispatch takes integer i returns Table
			return levels[i]
        endmethod
       
        method destroy takes nothing returns nothing
			call levels.destroy()
			call overallTime.destroy()
        endmethod
    endstruct
   
    private struct UnitAbilList
        private Table list
        private unit stored
        static method create takes unit toStore returns thistype
            local thistype this = allocate()
            set list = Table.create()
            set list[0] = 0
            set stored = toStore
            return this
        endmethod
       
        method size takes nothing returns integer
            return list[0]
        endmethod
       
        static if DEBUG_MODE then
            private method isInside takes integer abilId returns boolean
                return list[abilId] != 0
            endmethod
        elseif LIST_SECURE_DOUBLE_ADD then
            private method isInside takes integer abilId returns boolean
                return list[abilId] != 0
            endmethod
        endif
       
        method add takes integer abilId returns nothing
            //cSize now points one beyond the last element
            local integer cSize = list[0] + 1
           
            static if DEBUG_MODE then
                if isInside(abilId) then
                    return
                endif
            elseif LIST_SERCURE_DOUBLE_ADD then
                if isInside(abilId) then
                    return
                endif
            endif
           
            set list[0] = cSize
            set list[cSize] = abilId
           
            //make it point to itself for O(1) removal
            set list[abilId] = cSize
        endmethod
       
        method sumOfBonus takes integer modifType returns real
            local AbilDat aDat = 0
            local integer curr = 1
            local integer cSize = list[0]
            local integer abilLvl = 0
            local integer abilId = 0
            local real result = 0
            loop
                set abilId = list[curr]
                set aDat = abilDatIndicies[abilId]
               
                if aDat != 0 then
                    set abilLvl = GetUnitAbilityLevel(stored, abilId)
                   
                    if not aDat.multiLevel and abilLvl != 0 then
                        set abilLvl = 1
                    endif
                    set result = result + aDat.dispatch(modifType).real[abilLvl]
                endif
               
                exitwhen curr >= cSize
                set curr = curr + 1
            endloop
            return result
        endmethod
       
        method sumOfBonusEx takes unit forUnit, integer modifType returns real
            local unit u = stored
            local real r = 0
            if stored == forUnit then
                return sumOfBonus(modifType)
            endif
           
            set stored = forUnit
            set r = sumOfBonus(modifType)
            set stored = u
            return r
        endmethod
       
        private method popBack takes nothing returns nothing
            //get the size
            local integer cSize = list[0]
            //shrink it by one
            set list[0] = cSize - 1
            //make the pointer inside list[abilId] point to nothing
            set list[list[cSize]] = 0
            //make the last element store no ability
            set list[cSize] = 0
        endmethod
       
        static if UNIT_ABIL_LIST_STRICT_ORDER then
            private method removeStrict takes integer size, integer pos returns nothing
                //pos is the current position, size is the size of the list
                local integer iter = pos
                local integer abilId = list[pos]
               
                //loop over [pos, end]
                loop
                    exitwhen iter == size
                    set list[iter] = list[iter + 1]
                endloop
               
                //make the current ability point to nothing
                set list[abilId] = 0
               
                //pop from back, cause that ability is inside twice now
                call popBack()
            endmethod
        endif
       
        method remove takes integer abilId returns nothing
            local integer pos = list[abilId]
            //points into the last element of the list
            local integer cSize = list[0]
           
            //if it isnt inside the list
            //or the list is empty
            if pos == 0 or cSize == 0 then
                return
            endif
           
            //if strict order
            static if UNIT_ABIL_LIST_STRICT_ORDER then
                call removeStrict(cSize, pos)
            else
                //move whatever you want
               
                //if it isnt the last element
                if pos != cSize then
                    //replace ours with last
                    set list[pos] = list[cSize]
                endif
               
                //make the ability pointer point to nothing
                set list[abilId] = 0
               
                //pop last element
                //call to popBack will shrink the size automatically
                //it will also remove the pointer of list[abilId] = position
                call popBack()
            endif
        endmethod
       
        method destroy takes nothing returns nothing
            call list.destroy()
        endmethod
    endstruct
   
    //for Reduction.UnitType.XXX syntax
    private struct UnitTypeImpl extends array
        static method reset takes integer unitType, integer amplifType, real percentReduction returns nothing
            set ampDispatch[amplifType].real[unitType] = percentReduction
        endmethod
       
        static method add takes integer unitType, integer amplifType, real percentReduction returns nothing
            local real cA = ampDispatch[amplifType].real[unitType] + percentReduction
            set ampDispatch[amplifType].real[unitType] = cA
        endmethod
       
        static method substract takes integer unitType, integer amplifType, real percentReduction returns nothing
            call add(unitType, amplifType, -percentReduction)
        endmethod
       
        static method get takes integer unitType, integer amplifType returns real
            return ampDispatch[amplifType].real[unitType]
        endmethod
    endstruct
   
    //for Reduction.Unit.XXX syntax
    private struct UnitImpl extends array
        static method reset takes unit u, integer amplifType, real percentReduction returns nothing
            set ampDispatch[amplifType].real[GetHandleId(u)] = percentReduction
        endmethod
       
        static method add takes unit u, integer amplifType, real percentReduction returns nothing
            local integer hId = GetHandleId(u)
            local real cA = ampDispatch[amplifType].real[hId] + percentReduction
            set ampDispatch[amplifType].real[hId] = cA
        endmethod
       
        static method substract takes unit u, integer amplifType, real percentReduction returns nothing
            call add(u, amplifType, -percentReduction)
        endmethod
       
        static method get takes unit u, integer amplifType returns real
            return ampDispatch[amplifType].real[GetHandleId(u)]
        endmethod
    endstruct
   
    //for Reduction.ItemType.XXX syntax
    private struct ItemTypeImpl extends array
        static method reset takes integer itemType, integer amplifType, real percentReduction returns nothing
            set ampDispatch[amplifType].real[itemType] = percentReduction
        endmethod
       
        static method add takes integer itemType, integer amplifType, real percentReduction returns nothing
            local real cA = ampDispatch[amplifType].real[itemType] + percentReduction
            set ampDispatch[amplifType].real[itemType] = cA
        endmethod
       
        static method substract takes integer itemType, integer amplifType, real percentReduction returns nothing
            call add(itemType, amplifType, -percentReduction)
        endmethod
       
        static method get takes integer itemType, integer amplifType returns real
            return ampDispatch[amplifType].real[itemType]
        endmethod
    endstruct
   
    //for Reduction.Item.XXX syntax
    private struct ItemImpl extends array
        static method reset takes item it, integer amplifType, real percentReduction returns nothing
            set ampDispatch[amplifType].real[GetHandleId(it)] = percentReduction
        endmethod
       
        static method add takes item it, integer amplifType, real percentReduction returns nothing
            local integer hId = GetHandleId(it)
            local real cA = ampDispatch[amplifType].real[hId] + percentReduction
            set ampDispatch[amplifType].real[hId] = cA
        endmethod
       
        static method substract takes item it, integer amplifType, real percentReduction returns nothing
            call add(it, amplifType, -percentReduction)
        endmethod
       
        static method get takes item it, integer amplifType returns real
            return ampDispatch[amplifType].real[GetHandleId(it)]
        endmethod
    endstruct
	
	//for Reduction.OnCast.XX
	private struct OnCastImpl extends array
		static method setTime takes integer abil, integer level, real howLong returns nothing
            local AbilDat dat = abilDatIndicies[-abil]
            if level == 0 then
                set level = 1
            endif
            
            if dat == 0 then
                set dat = AbilDat.create()
                set abilDatIndicies[-abil] = dat
            endif
            
			if not dat.multiLevel then
				set level = 1
			endif
			
			set dat.overallTime.real[level] = howLong
		endmethod
		
		static method getTime takes integer abil, integer level returns real
			local AbilDat dat = abilDatIndicies[-abil]
			return dat.overallTime.real[level]
		endmethod
		
        static method useMultiLevel takes integer abil, boolean use returns nothing
            local AbilDat dat = abilDatIndicies[-abil]
            if dat == 0 then
                set dat = AbilDat.create()
                set abilDatIndicies[-abil] = dat
            endif
           
            set dat.multiLevel = use
        endmethod
       
        static method usesMultiLevel takes integer abil returns boolean
            local AbilDat dat = abilDatIndicies[-abil]
            return dat != 0 and dat.multiLevel
        endmethod
		
        static method reset takes integer abil, integer level, integer amplifType, real percentReduction returns nothing
            local AbilDat dat = abilDatIndicies[-abil]
            if dat == 0 then
                set dat = AbilDat.create()
                set abilDatIndicies[-abil] = dat
            endif
           
            if not dat.multiLevel then
                set level = 1
            endif
           
            set dat.dispatch(amplifType).real[level] = percentReduction
        endmethod
       
        static method add takes integer abil, integer level, integer amplifType, real percentReduction returns nothing
            local AbilDat dat = abilDatIndicies[-abil]
            local real cA = 0
            if dat == 0 then
                set dat = AbilDat.create()
                set abilDatIndicies[-abil] = dat
            endif
           
            if not dat.multiLevel then
                set level = 1
            endif
           
            set cA = dat.dispatch(amplifType).real[level] + percentReduction
                       
            set dat.dispatch(amplifType).real[level] = cA
        endmethod
       
        static method substract takes integer abil, integer level, integer amplifType, real percentReduction returns nothing
            call add(abil, level, amplifType, -percentReduction)
        endmethod
       
        static method get takes integer abil, integer level, integer amplifType returns real
            local AbilDat dat = abilDatIndicies[-abil]
            if dat == 0 then
                return 0.
            endif
           
            if not dat.multiLevel then
                set level = 1
            endif
           
            return dat.dispatch(amplifType).real[level]
        endmethod
	endstruct
   
    //for Reduction.Ability.XXX syntax
    private struct AbilityImpl extends array
        static method useMultiLevel takes integer abil, boolean use returns nothing
            local AbilDat dat = abilDatIndicies[abil]
            if dat == 0 then
                set dat = AbilDat.create()
                set abilDatIndicies[abil] = dat
            endif
           
            set dat.multiLevel = use
        endmethod
       
        static method usesMultiLevel takes integer abil returns boolean
            local AbilDat dat = abilDatIndicies[abil]
            return dat != 0 and dat.multiLevel
        endmethod
       
        static method reset takes integer abil, integer level, integer amplifType, real percentReduction returns nothing
            local AbilDat dat = abilDatIndicies[abil]
            if dat == 0 then
                set dat = AbilDat.create()
                set abilDatIndicies[abil] = dat
            endif
           
            if not dat.multiLevel then
                set level = 1
            endif
           
            set dat.dispatch(amplifType).real[level] = percentReduction
        endmethod
       
        static method add takes integer abil, integer level, integer amplifType, real percentReduction returns nothing
            local AbilDat dat = abilDatIndicies[abil]
            local real cA = 0
            if dat == 0 then
                set dat = AbilDat.create()
                set abilDatIndicies[abil] = dat
            endif
           
            if not dat.multiLevel then
                set level = 1
            endif
           
            set cA = dat.dispatch(amplifType).real[level] + percentReduction
                       
            set dat.dispatch(amplifType).real[level] = cA
        endmethod
       
        static method substract takes integer abil, integer level, integer amplifType, real percentReduction returns nothing
            call add(abil, level, amplifType, -percentReduction)
        endmethod
       
        static method get takes integer abil, integer level, integer amplifType returns real
            local AbilDat dat = abilDatIndicies[abil]
            if dat == 0 then
                return 0.
            endif
           
            if not dat.multiLevel then
                set level = 1
            endif
           
            return dat.dispatch(amplifType).real[level]
        endmethod
    endstruct
   
    /********************************/
    /********   Struct API   ********/
    /********************************/
    struct Reduction extends array
        readonly static integer PHYSICAL = REDUCTION_PHYSICAL
        readonly static integer SPELL = REDUCTION_SPELL
        readonly static integer CODE = REDUCTION_CODE
       
        readonly static AbilityImpl Ability = 1
        readonly static UnitImpl Unit = 1
        readonly static UnitTypeImpl UnitType = 1
        readonly static ItemImpl Item = 1
        readonly static ItemTypeImpl ItemType = 1
		readonly static OnCastImpl OnCast = 1
    endstruct
   
    function UnitRegisterAbility takes unit u, integer abil returns nothing
        local integer hId = GetHandleId(u)
        local UnitAbilList list = unitListIndicies[hId]
       
        if list == 0 then
            set list = UnitAbilList.create(u)
            set unitListIndicies[hId] = list
        endif
       
        call list.add(abil)
    endfunction
   
    function UnitUnregisterAbility takes unit u, integer abil returns nothing
        local integer hId = GetHandleId(u)
        local UnitAbilList list = unitListIndicies[hId]
       
        if list != 0 then
            call list.remove(abil)
           
            static if DESTROY_EMPTY_STRUCTS then
                if list.size() == 0 then
                    set unitListIndicies[hId] = 0
                    call list.destroy()
                endif
            endif
        endif
    endfunction
   
    function UnitTypeRegisterAbility takes integer uType, integer abil returns nothing
        local UnitAbilList list = unitListIndicies[uType]
       
        if list == 0 then
            set list = UnitAbilList.create(null)
            set unitListIndicies[uType] = list
        endif
       
        call list.add(abil)
    endfunction
   
    function UnitTypeUnregisterAbility takes integer uType, integer abil returns nothing
        local UnitAbilList list = unitListIndicies[uType]
       
        if list != 0 then
            call list.remove(abil)
           
            static if DESTROY_EMPTY_STRUCTS then
                if list.size() == 0 then
                    set unitListIndicies[uType] = 0
                    call list.destroy()
                endif
            endif
        endif
    endfunction
   
    function UnitAddAbilityEx takes unit whichUnit, integer abilId returns boolean
        local boolean b = UnitAddAbility(whichUnit, abilId)
        if b then
            call UnitRegisterAbility(whichUnit, abilId)
        endif
        return b
    endfunction
   
    function UnitRemoveAbilityEx takes unit whichUnit, integer abilId returns boolean
        local boolean b = UnitRemoveAbility(whichUnit, abilId)
        if b then
            call UnitUnregisterAbility(whichUnit, abilId)
        endif
        return b
    endfunction
   
    private function accumulateForItems takes unit ofUnit, integer ofType returns real
        local item it = null
        local integer itType = 0
        local integer looper = 0
        local integer max = bj_MAX_INVENTORY
        local real r = 0
        
        loop
            exitwhen max == looper
            
            set it = UnitItemInSlot(ofUnit, looper)
            set itType = GetItemTypeId(it)
           
            set r = r + Reduction.Item.get(it, ofType)
            set r = r + Reduction.ItemType.get(itType, ofType)

            set looper = looper + 1
        endloop
        set it = null
       
        return r
    endfunction
   
   
    private function dmgHandler takes nothing returns nothing
        local real reductionPh = 0
        local real reductionSp = 0
        local real reductionCo = 0
        local unit u = PDDS.target
        local integer uId = GetHandleId(u)
        local integer dmgType = PDDS.damageType
        local UnitAbilList uList = unitListIndicies[uId]
        local real redFull = 0
        local UnitAbilList uTypeList = unitListIndicies[GetUnitTypeId(u)]
        local real amount = PDDS.amount
		
        static if DEBUG_PRINT_ON_HIT_DMG then
            local string dOutput = "Before: " + R2S(amount)
        endif
       
        if uList != 0 then
            set redFull = redFull + uList.sumOfBonus(dmgType)
        endif
       
        if uTypeList != 0 then
            set redFull = redFull + uTypeList.sumOfBonusEx(u, dmgType)
        endif
       
        set redFull = redFull + Reduction.UnitType.get(GetUnitTypeId(u), dmgType)
        set redFull = redFull + Reduction.Unit.get(u, dmgType)
        set redFull = redFull + accumulateForItems(u, dmgType)
       
        if redFull > 1 then
            set amount = 0
        else
            set amount = amount * (1 - redFull)
        endif
       
        static if DEBUG_PRINT_ON_HIT_DMG then
            set dOutput = dOutput + " After: " + R2S(amount) + " factor: " + R2S(redFull)
            call BJDebugMsg(dOutput)
        endif
		
		set PDDS.amount = amount
       
        set u = null
    endfunction
	
    globals
        private timer CastLooper = CreateTimer()
    endglobals
    
    private function CopyAbilToCastInstance takes OnCastDat cDat,/*
                                                */AbilDat aDat, integer abilLvl returns OnCastDat
        local integer looper = 1
        local integer mLooper = 0
        
        if not aDat.multiLevel then
            set abilLvl = 1
        endif
        
        loop
            set cDat.amounts.real[mLooper] = aDat.dispatch(mLooper).real[abilLvl]
            exitwhen mLooper == DAMAGE_TYPES - 1
            set mLooper = mLooper + 1
        endloop
        
        set cDat.time = aDat.overallTime.real[abilLvl]
        return cDat
    endfunction
    
	private function onCastLooper takes nothing returns nothing
        local OnCastDat looper = OnCastDat.head
        local boolean alloc = OnCastDat.allocated()
        local integer looperT = 0
		loop
            set looper.time = looper.time - TICK_TIME
            
            if (looper.time <= 0.) then
                //go through all possible reductions
                loop
                    call Reduction.Unit.substract(looper.caster, looperT, looper.amounts.real[looperT])
                    exitwhen looperT == DAMAGE_TYPES - 1
                    set looperT = looperT + 1
                endloop
                
                call looper.destroy()
            endif
                
            exitwhen looper == 0
            set looper = OnCastDat.head.next
        endloop
        
        if alloc and not OnCastDat.allocated() then
            call PauseTimer(CastLooper)
        endif
	endfunction
	
	private function onCastHandler takes nothing returns boolean
		local unit caster = GetTriggerUnit()
		local integer abil = GetSpellAbilityId()
		local AbilDat dat = abilDatIndicies[-abil]
        local boolean was = OnCastDat.allocated()
        local integer abilityLevel = GetUnitAbilityLevel(caster, abil)
		local OnCastDat onCDat = 0
        
		if dat == 0 then
			return false
		endif
		
        set onCDat = CopyAbilToCastInstance(OnCastDat.create(caster), dat, abilityLevel)
        
        if OnCastDat.allocated() and not was then
            call TimerStart(CastLooper, TICK_TIME, true, function onCastLooper)
        endif
		
        //use as loop now
        set abil = 0
        //loop through all possible reductions
        loop
            call Reduction.Unit.add(caster, abil, onCDat.amounts.real[abil])
            exitwhen abil == DAMAGE_TYPES - 1
            set abil = abil + 1
        endloop
        
		set caster = null
		return false
	endfunction
   
    private module m
        private static method onInit takes nothing returns nothing
            local trigger t = CreateTrigger()
			call AddDamageHandler(function dmgHandler)
           
            set amplifiedPhys = Table.create()
            set amplifiedMag = Table.create()
            set amplifiedCode = Table.create()
            set ampDispatch[0] = amplifiedPhys
            set ampDispatch[1] = amplifiedMag
            set ampDispatch[2] = amplifiedCode
           
            set abilDatIndicies = Table.create()
            set unitListIndicies = Table.create()
			
			call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
			call TriggerAddCondition(t, Filter(function onCastHandler))
			set t = null
        endmethod
    endmodule
   
    private struct s extends array
        implement m
    endstruct
   
endlibrary

Example:

JASS:
scope s initializer init
    private function f takes nothing returns nothing
        //destroy timer, preventing leaks
        call DestroyTimer(GetExpiredTimer())
        
        //decrease damage reduction of Physical damage for
        //Boots of speed by 16.6%
        call Reduction.ItemType.substract('bspd', Reduction.PHYSICAL, 0.166)
    endfunction
    
    private function init takes nothing returns nothing
        //create footman for enemy player
        local unit u = CreateUnit(Player(1), 'hfoo', 0, 0, 0)
        
        //create paladin for us
        local unit h = CreateUnit(Player(0), 'Hmkg', 0, -380, 0)
        
        //set damage reduction of spell damage for all footmans on map
        //to -0.15
        call Reduction.UnitType.add(GetUnitTypeId(u), Reduction.SPELL, -0.15)
        
        //set damage reduction of spell damage for specific footman
        //we created to -0.15
        call Reduction.Unit.add(u, Reduction.SPELL, -0.15)
        
        //in here, footman will take 30% more damage from spells
        
        //say to the system that Mountain King is using Storm Bolt
        call UnitTypeRegisterAbility('Hmkg', 'AHtb')
        
        //Set Multiple level bonus for Storm Bolt to false
        //Basically this means that every level of Storm Bolt
        //uses the same bonuses
        call Reduction.Ability.useMultiLevel('AHtb', false)
        
        //after that set physical damage reduction for Storm Bolt
        //at level 0(doesnt matter because of false in useMultiLevel)
        //to 36.7% reduced damage
        call Reduction.Ability.add('AHtb', 0, Reduction.PHYSICAL, 0.367)
        
        //At this point, as long as any Mountain King has
        //Storm Bolt learned(level is >0), he will receive
        //the reduction
        
        //set reduction for Boots of Speed of type Physical to 16.6%
        call Reduction.ItemType.add('bspd', Reduction.PHYSICAL, 0.166)
        
        //at this point, if any unit that receives damage is carrying
        //Boots of Speed, he will receive the reduction
        
        //start timer to remove reduction from Boots of Speed
        call TimerStart(CreateTimer(), 5., false, function f)
        
        //give the spawned hero Boots of Speed
        call UnitAddItemById(h, 'bspd')
        
        //set time of day to 12 pm, so we can see nice and far
        call SetFloatGameState(GAME_STATE_TIME_OF_DAY, 12)
    endfunction
endscope



  • added OnCast
  • fixed PDDS incompatibility
  • fixed UnitAbilDat.isInside returns nothing despite returning boolean
  • modified dispatch method inside AbilDat, so that it does simple array subscript now(on TableArray, should still be faster than possibly 3 if block evaluations)
  • added new configurable: TICK_TIME
  • Removed functions from API(code would be unmanageably big + I would have to update 2 interfaces every time)
  • Code now supports arbitrary number of Reduction types, besides the hardcoded 3 ones, but it has strong requirement: All damage types must be set to incrementing value starting at 0. There is afaik no support for this currently in LFH's DDS, so may not be really usable, but it is there.


  • library DamageAmplifier -> library DamageReduction


  • Initial Release on Hive
  • Full API Rework


 

Attachments

  • DamageAmplifier.png
    DamageAmplifier.png
    1.4 MB · Views: 347
Last edited:
Level 25
Joined
Jun 5, 2008
Messages
2,572
Sorry to post something not really related but:

Primary reason of existance of this resource is because of the
problem that people use Runed Bracers for spell damage reduction,
even tho the DDS will not work if they do so.

Is this for real? Having a runed bracer spell damage reduction ability on a unit/item breaks DDS? It's the first time i heard of it.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
You can, but only one type. This is specific to DDS systems that can distinguish between spell and physical damage. With this resource however, you can stack the reduction simulating the reduction from runed bracers
 
Level 15
Joined
Aug 7, 2013
Messages
1,337
There may be a typo in the documentation:

JASS:
Disadvantage of this resource is that every reduction
    is scaled addictively

I believe the word is additively?
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
You can, but only one type. This is specific to DDS systems that can distinguish between spell and physical damage. With this resource however, you can stack the reduction simulating the reduction from runed bracers
So this system can simulates the damage reduction from the runed bracer's ability? Pretty neat.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
There may be a typo in the documentation:

JASS:
Disadvantage of this resource is that every reduction
    is scaled addictively

I believe the word is additively?

yea :D

fixed

Chobibo: Yes, because with DDS you can only have 1 runed bracer ability, so its not really easy to create spell damage reduction. Physical(and possibly code) damage reductions are kind of easy to do
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
well yea, it is meant to amplify the damage, and it does so, even tho it is kind of ambiguous name, because when I was writing it I had idea of reducing magical damage in mind, since LFH's DDS doesnt allow you to use stacking runed bracers so you have to do it with code. This still allows you to increase damage taken, but in "awkward" name. I will think about the naming
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
I think the name should be changed to Damage Reduction.

Damage Amplification makes more sense overall, because you can both increase or decrease spell/attack/code damage, but calling Amplification.Unit.add(...) seems weird, just as much as Amplify.Unit.add(...). This also requires a bit less drastic changes, because the other option would include radical API change(heh who am I kidding, I bet this got downloaded 0 times for real use :D)

Change:

  • library DamageAmplifier -> library DamageReduction
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
bump(I think after 8 months, it cant even be considered double post or against rules), this is functioning, has been updated(see post above).

Edit: I thought of some optimizations, namely for dispatch inside AbilDat struct, as well as providing users a simple way to change the additive stacking of bonuses(basic for the time being)
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
The jass section follows the global site rules, but with some exceptions.
Double posting just applies for two posts in a row within 48 hours,
but in the Jass section you are allow to do so, if you wish to raise attention
on current changes you made. :)

Will soon look into it. Actually I just didn't do so yet, because looking_for_help
is a greater expert in everything connected to damage modifying systems than me.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
Update to version 1.1.0!


  • added OnCast
  • fixed PDDS incompatibility
  • fixed UnitAbilDat.isInside returns nothing despite returning boolean
  • modified dispatch method inside AbilDat, so that it does simple array subscript now(on TableArray, should still be faster than possibly 3 if block evaluations)
  • added new configurable: TICK_TIME
  • Removed functions from API(code would be unmanageably big + I would have to update 2 interfaces every time)
  • Code now supports arbitrary number of Reduction types, besides the hardcoded 3 ones, but it has strong requirement: All damage types must be set to incrementing value starting at 0. There is afaik no support for this currently in LFH's DDS, so may not be really usable, but it is there.


Other changes: API is no longer listed in thread, because its HUUUGE and Im not updating that every time.

Brief description of onCast functionality:

You can, just like with Ability, set whether you want multi ability bonuses or not, and also get that information.(If you set to true, each level will have different reduction values, if you set it to false, it will use level 1 all the time).

Just like with others, it features add, reset, substract, get functionality.
Arguments go in following order: AbilityId, Level, Modification type, Reduction value(in absolute value, so 0.4 == 40%).

The last function in onCast is setTime and getTime.

setTime will set for how long the reduction for given ability with given level should be applied for, and getTime returns it. Therefore, each level can have different time it applies its reduction for. I considered doing it for different types of reductions too(physical would be applied for different time than code for instance), but that would require design change, and I considered it to not be worth it, not by effort side, but it would most likely be very heavy.

The onCasts stack additivelly(when you cast storm bolt 2 times and the reduction is applied for longer than the cooldown, and storm bolt gives you 15% reduction for 15 seconds, then for certain time you will have 30% reduction).

The data itself uses linked list, whcih requires static head by my design, so it can store up to 8190 simultaneous cast instances.

There is currently no way to read how much time on given instance is remaining(the information is there, but no API for it).

This design allows for single timer being used with switching on/off, depending if there is some running instance or not.

Note: If unit casts ability that does not have any information on it, the system will not even add it to the list of checking, so it should not lag on casts so much.
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
Other changes: API is no longer listed in thread, because its HUUUGE and Im not updating that every time.
Somewhere it should be. Don't expect users to read and understand the whole code.
However it seems to be included in the header. Is it incomplete?

Currently I don't have so much time, but I will try to get to this asap. ( or maybe lfh does )
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
the header is complete, I even updated it with the OnCast API, but the thing is, the external header had lots of [icode=jass] blocks, and so it would be very hard to keep up with(rather, time consuming).

Well considering how long it took me to update it, Im in no rush to be honest :D
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
Will take a look at this soon.

Btw, either a small test map or some "unproblematic" x/y values for the unit creation in the demo script would be nice. Because in a standard sized map, the units are created out of map bounds (first thought its the fault of the system but then I realized its just the demo script).
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
UnitAddAbilityEx/UnitRemoveAbilityEx are "acceptable" for the naming convention (imo every function which is library specific should always be obvious which library it's coming from). UnitTypeUnregisterAbility/ UnitRegisterAbility in particular don't make sense that they apply specifically to your library.

Naming convention of structs:

StructName
memberName

I see quite a few places where it's spaghetti code.

There are like 6,000 structs in your map, I am having a hard time grasping why that much complexity is needed. Let's expand on the purpose of this resource:

- This resource allows you to modify spell damage using unit types/units/units' abilities/items.

After scanning through the code and your descriptions, I can see that the user must manually assign each ability for it to be detected by the system.

Since I haven't played WarCraft 3 since they discovered the physical damage detection, please excuse any ignorance which may follow (or if it is not ignorant, please consider it as it is good in theory imo):

- When a unit casts an ability, hash the ability ID to the unit's handle ID.
- When the unit is damaged by a spell, reference that previously-stored value to retrieve the ability it was damaged by.

Maybe it won't work for damage-over time spells where the caster had the ability to cast something else in the meanwhile? That could be remedied by having a dummy unit owned by the player to cast the ability instead. In fact, all abilities could be cast by dummies who are indexed to the original caster if you wanted to pick up on any specific ability which was cast. It avoids the need to register offensive abilities, does it not?
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
yea, I actually thought of catching, and before you wrote this post I would be quite convinced that it is implemented :D I could also make the functions private and hook UnitAddAbility, but I wasnt sure about that one either(and it wouldnt catch pre-placed abilities, so it would still need the automatic updating), and my ability to name stuff is not the best, so I gave it rather easy function names :D

It has so many structs because they are kind of like pimpl structs, you cant even allocate them(they all extend array) and they are made for convenient syntax, so you can say Reduction.Item.add(...), instead of something like Reduction.addForItem(...).

I think everything except the members Item, Unit etc(the forwarders in Reduction itself) follows StructName memberName, and these dont follow it, because I really dont like having variables called the same way as native types(like static unit unit), it seems confusing.
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
yes, but I dont like naming any kind of member the same way as predefined types. In table it makes sense tho

I agree on that. Unfortunatly vJass allows this, but IMO it should be avoided whenever possible.

Speaking about the API, is there an argument about something like

JASS:
local Reduction r = Reduction.createOnUnit(u, Reduction.SPELL, 2.0) // Create
set r.value = 1.5 // Change reduction amount
set r.reductionType = Reduction.PHYSICAL // Change reduction type

That would also make the methods get/reset/add/substract unnecessary, which are a bit redundant anyway and can't cover every change anyway (multiplication, division, etc) ... Just let the user manipulate the value himself.

I think those things could simplify this resource a bit (not in terms of functionality), because at the moment its quite massiv.
 
Level 11
Joined
Dec 3, 2011
Messages
366
I agree on that. Unfortunatly vJass allows this, but IMO it should be avoided whenever possible.

Speaking about the API, is there an argument about something like

JASS:
local Reduction r = Reduction.createOnUnit(u, Reduction.SPELL, 2.0) // Create
set r.value = 1.5 // Change reduction amount
set r.reductionType = Reduction.PHYSICAL // Change reduction type

That would also make the methods get/reset/add/substract unnecessary, which are a bit redundant anyway and can't cover every change anyway (multiplication, division, etc) ... Just let the user manipulate the value himself.

I think those things could simplify this resource a bit (not in terms of functionality), because at the moment its quite massiv.

Use operator method instead of get/reset/add/subtract ... :ogre_love:
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
I'm revisiting the philosophy of this resource to try to assess if it meets the criteria for a new standard.

Something really important:

A DDS exists so that users can decide how to respond to damage. Sometimes we're talking about nullifying the damage or reducing it by a percentage. Other times, the user might want to reflect the damage or amplify it.

To make a resource this specific work (changing damage based on unit, unit type or item), it involves mountains of registration code to make those units and items recognized by the system. At this point, I would spend as much time learning the nuances of this system as I would just coding the various scenarios myself.

I don't see this being a required resource by anything, but maybe you could expand the utility of this resource via splitting it into several components. One component would be the base where damage is modified. Another component registers abilities, another registers unit types, etc. This way, instead of one paramount resource, you would have several lightweight, learn-at-a-glance resources. The API is huge and adds a lot of code that maybe most people don't need. By splitting it into sections, maybe the user only needs ability registration.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
After developing version 3 of Damage Engine, I can definitely see a use for a system like this. Instead of being a system that supplies a myriad of functions to access the library, this resource should be a template for the end-user to put in their map. Damage reduction based on item/unit/unittype/itemtype but with the user deciding how much - if at all - they want to fatten those functions up. Perhaps they want stacking spell resistance with multiple items, for example. Maybe they want to use a logarithmic approach so that additional magic resistance has diminishing returns like with armor.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
I know what you mean. You have a lot of good content here. Let me try to be more productive:

  1. You have damage types in there, like differentiating between physical, code and spell damage when those things should just be part of the standard DDS that you extend from.
  2. The only thing you should reference for DDS types is a boolean to determine if the damage was caused physically or by a spell. Custom damage types should be set by the user so that damage can be caused by both a spell and by a certain damage type. Discriminating against spell damage caused by code is not good, because maybe the user wants that damage to be spell damage but also be "fire type".
  3. Speaking of different types, that could be what your system does, to give it a more specific role. Support different armor types and damage types that can be assigned to an ability, unittype, itemtype, unit, item or manually set by the user before triggering damage.

The concept of the system I have in mind would support something like "unit is carrying item X which enhances its basic attacks with fire damage" and "unit type is grass and is susceptible to fire damage". Or "unit is carrying water shield item which enhances its armor against fire damage". Stuff like that would be more open-ended to the user and even get this resource moved up to a point where spells in the spell section would want to extend off of it.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
the fire attack thing I actually tried before and failed :D and I think that could be doable now(as in, by me).

The intention of this system was to make items and whatnot that can actually work with spell resistance, because runed bracers are already taken by the DDS. But then I thought, why not all types? :D

I think you can already do the 2. as in, the user can already say "DDS.damageType = 15 /* lets say, this is fire */" and then fire the dds, which my system also supports, if you pass into the functions 15 as damagetype argument.

The problem I see in 3. is that there is no easy way to get unit's armor type, no real way to get attack type(unless you make the unit hit some dummies with different armors 8 times pretty much) and pretty much no way to get the % values from the tables.

For the 1., they already are part of DDS, but what if user wants to say "Oh, this damage will reduce only physical damage done to you for 10 seconds", well then you already need to differentiate between the damage types in the system.

I will try to think of a good and lightweight solution for the "fire, water" etc thing because that seems more perspective, but I would still like to support at least spell dmg enhancing because currently it is very cumbersome to make it with the DDS(unless I dont know of something), because as I said and we know, the bracers are already taken by the system
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
I would like the honor of coding that part I'm referring to if that's ok. Basically, have a struct which is called DamageType and another called ArmorType. By default (as in, the user doesn't register an interaction between types) everything behaves as normal. However, the user can say damagetype fire deals 10% more damage to armortype grass, and associate the 2 struct members to each other using a Table or TableArray. To associate damagetypes to an ability/unit/etc. use a static TableArray for the entire struct. Do the same with armor. I would love to code that.

Edit: it may be a good idea for this system to use logarithmic magic resist, working similarly to armor. I think percentage/additive resistance is too easy to code to merit its own resource as the user simply has to modify DamageEventAmount x .67 for the effect of runed bracers for example (and this is also doesn't worry about hitting 100% with too much MR unless that's what the user truly wants).
 
When the user also uses DDS events it might become a bit chaotic, or?

User can regitser item/abilities/unit types and define certain DamageReductions for each of them, that's fine.
But finaly it might be probably very useful for compatibility with user's other damage event triggers if there was a function to retuen an overall damage reduction of Physic/Code/Spell for the unit.
Like it would check the unit's inventory and potential abilities, the unit type, and the unit itself, and then calculates and returns the overall DamageReduction for the unit.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
Well my initial idea was that it would be automated, and that you would have to make sure you call your addDamageHandler after I did in my onInit, having query functions is also doable tho(unit.getTotalReduction et. al.), there in fact is one to sum the bonus of all abilities registered to unit already, also for items, but they are currently private
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
Nice! ;D Will the API also change overall? I mean you just because of:

Its reference to this:

I agree on that. Unfortunatly vJass allows this, but IMO it should be avoided whenever possible.

Speaking about the API, is there an argument about something like

JASS:
local Reduction r = Reduction.createOnUnit(u, Reduction.SPELL, 2.0) // Create
set r.value = 1.5 // Change reduction amount
set r.reductionType = Reduction.PHYSICAL // Change reduction type

That would also make the methods get/reset/add/substract unnecessary, which are a bit redundant anyway and can't cover every change anyway (multiplication, division, etc) ... Just let the user manipulate the value himself.

I think those things could simplify this resource a bit (not in terms of functionality), because at the moment its quite massiv.

which is much better idea, and I will most definitely do it(also doesnt require heavy code change)
 
Top