1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  3. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still haven't received your rank award? Then please contact the administration.
    Dismiss Notice
  4. Let your favorite entries duke it out in the 15th Techtree Contest Poll.
    Dismiss Notice
  5. Weave light to take you to your highest hopes - the 6th Special Effect Contest is here!
    Dismiss Notice
  6. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

New Bonus v2.0

Submitted by chopinski
This bundle is marked as approved. It works and satisfies the submission rules.
Intro
Hello, this is my first submission in the spell section, so apologies in advance for any mistake. I present to you the New Bonus System. Since Object Merger stopped working and we still have no ways to edit the bonus values of a unit natively, I decided to create this light weight system to manage that and give everyone a simpler way to work with bonus values than the Bonus Mod.
How it works?
By using the new Object API introduced to Warcraft, we can now modify an unit ability field value, so when giving an unit a bonus, we add a specific ability to that unit that gives such bonus, if it do not have it already, and change that ability field bonus value to the desired value. Retrieving the amount is also trivial, by just reading that field value.

How to Import?
Importing New Bonus is really simple. Just copy the 9 abilities with the prefix "NewBonus" from the Object Editor into your map [Raw Codes Z001 to Z009 in demo map] and match their new raw code to the bonus types in the global block of the library. You can also define their raw code when pasting to be Z001 to Z009, that's why I created them with this raw codes. Then create a trigger called NewBonus, convert it to custom text, delete all text in it and paste the Library code there. That's it, you are done!
Requirements
NewBonus requires patch 1.31+ and RegisterPlayerUnitEvent Library. NewBonus Expanded also Requires DamageInterface librarys and CooldownReduction
JASS API
Bonus Types:
  • BONUS_DAMAGE
  • BONUS_ARMOR
  • BONUS_AGILITY
  • BONUS_STRENGTH
  • BONUS_INTELLIGENCE
  • BONUS_HEALTH
  • BONUS_MANA
  • BONUS_MOVEMENT_SPEED
  • BONUS_SIGHT_RANGE
  • BONUS_HEALTH_REGEN (Real value)
  • BONUS_MANA_REGEN (Real value)
  • BONUS_ATTACK_SPEED (Real value)
  • BONUS_MAGIC_RESISTANCE (Real value)
  • Expanded Bonus only (Real Values)
  • BONUS_EVASION_CHANCE
  • BONUS_MISS_CHANCE
  • BONUS_CRITICAL_CHANCE
  • BONUS_CRITICAL_DAMAGE
  • BONUS_SPELL_POWER_FLAT
  • BONUS_SPELL_POWER_PERCENT
  • BONUS_LIFE_STEAL
  • BONUS_SPELL_VAMP
  • BONUS_COOLDOWN_REDUCTION
  • BONUS_COOLDOWN_REDUCTION_FLAT
  • BONUS_COOLDOWN_OFFSET

Code (vJASS):

    function GetUnitBonus takes unit u, integer bonus_type returns integer
        -> Returns the specified bonus amount for the unit
        -> Example: set amount = GetUnitBonus(GetTriggerUnit(), BONUS_AGILITY)

    function SetUnitBonus takes unit u, integer bonus_type, integer amount returns integer
        -> Set the specified bonus type to amount for the unit
        -> Example: call SetUnitBonus(GetTriggerUnit(), BONUS_DAMAGE, 100)
 
    function RemoveUnitBonus takes unit u, integer bonus_type returns nothing
        -> Removes the Specified bonus type from unit
        -> Example: call RemoveUnitBonus(GetTriggerUnit(), BONUS_AGILITY)
 
    function AddUnitBonus takes unit u, integer bonus_type, integer amount returns integer
        -> Add the specified amount for the specified bonus tyte for unit
        -> Example: call AddUnitBonus(GetTriggerUnit(), BONUS_DAMAGE, 100)

    function GetUnitBonusReal takes unit u, integer bonus_type returns real
        -> Returns the specified bonus amount for the unit
        -> Example: set amount = GetUnitBonusReal(GetTriggerUnit(), BONUS_HEALTH_REGEN)

    function SetUnitBonusReal takes unit u, integer bonus_type, real amount returns nothing
        -> Set the specified bonus type to amount for the unit
        -> Example: call SetUnitBonusReal(GetTriggerUnit(), BONUS_ATTACK_SPEED, 0.15)

    function RemoveUnitBonusReal takes unit u, real bonus_type returns nothing
        -> Removes the Specified bonus type from unit
        -> Example: call RemoveUnitBonusReal(GetTriggerUnit(), BONUS_MANA_REGEN)

    function AddUnitBonusReal takes unit u, integer bonus_type, real amount returns real
        -> Add the specified amount for the specified bonus tyte for unit
        -> Example: call AddUnitBonusReal(GetTriggerUnit(), BONUS_LIFE_STEAL, 0.33)
 

Code (vJASS):

        function AddUnitBonusTimed takes unit u, integer bonus_type, real amount, real duration returns nothing
            -> Add the specified amount for the specified bonus type for unit for a duration
            -> Example: call AddUnitBonusTimed(GetTriggerUnit(), BONUS_ARMOR, 13, 10.5)

        function LinkBonusToBuff takes unit u, integer bonus_type, real amount, integer buffId returns nothing
            -> Links the bonus amount specified to a buff or ability. As long as the unit has the buff or
            -> the ability represented by the parameter buffId the bonus is not removed.
            -> Example: call LinkBonusToBuff(GetTriggerUnit(), BONUS_ARMOR, 10, 'B000')
        function LinkBonusToItem takes unit u, integer bonus_type, real amount, item i returns nothing
            -> Links the bonus amount specified to an item. As long as the unit has that item the bonus is not removed.
            -> Note that it will work for items with the same id, because it takes as parameter the item object.
            -> Example: call LinkBonusToItem(GetManipulatingUnit(), BONUS_ARMOR, 10, GetManipulatedItem())

        function UnitCopyBonuses takes unit source, unit target returns nothing
            -> Copy the source unit bonuses using the Add functionality to the target unit
            -> Example: call UnitCopyBonuses(GetTriggerUnit(), GetSummonedUnit())

        function UnitMirrorBonuses takes unit source, unit target returns nothing
            -> Copy the source unit bonuses using the Set functionality to the target unit
            -> Example: call UnitMirrorBonuses(GetTriggerUnit(), GetSummonedUnit())
 
Code
Code (vJASS):

library NewBonus
    /* ----------------------- NewBonus v1.9 by Chopinski ----------------------- */
    //! novjass
        Since ObjectMerger is broken and we still have no means to edit
        bonus values (green values) i decided to create a light weight
        Bonus library that works in the same way that the original Bonus Mod
        by Earth Fury did. NewBonus requires patch 1.30+.
 
        How it works?
        By using the new Object API recently introduced to warcraft, we can now
        modify an ability field, so when giving an unit a bonus, we add a specific
        ability to that unit, if it do not have it already, and change that ability
        bonus value to the desired value. Retrieving the amount is also trivial, by
        just reading that field value.
 
        How to Import?
        Importing bonus mod is really simple. Just copy the 9 abilities with the
        prefix "NewBonus" from the Object Editor into your map and match their new raw
        code to the bonus types in the global block below. Then create a trigger called
        NewBonus, convert it to custom text and paste this code there. You done!
 
        API:
        function GetUnitBonus takes unit u, integer bonus_type returns integer
            -> Returns the specified bonus amount for the unit
            -> Example: set amount = GetUnitBonus(GetTriggerUnit(), BONUS_AGILITY)

        function SetUnitBonus takes unit u, integer bonus_type, integer amount returns integer
            -> Set the specified bonus type to amount for the unit
            -> Example: call SetUnitBonus(GetTriggerUnit(), BONUS_DAMAGE, 100)
        function RemoveUnitBonus takes unit u, integer bonus_type returns nothing
            -> Removes the Specified bonus type from unit
            -> Example: call RemoveUnitBonus(GetTriggerUnit(), BONUS_AGILITY)
        function AddUnitBonus takes unit u, integer bonus_type, integer amount returns integer
            -> Add the specified amount for the specified bonus tyte for unit
            -> Example: call AddUnitBonus(GetTriggerUnit(), BONUS_DAMAGE, 100)

        function GetUnitBonusReal takes unit u, integer bonus_type returns real
            -> Returns the specified bonus amount for the unit
            -> Example: set amount = GetUnitBonusReal(GetTriggerUnit(), BONUS_HEALTH_REGEN)

        function SetUnitBonusReal takes unit u, integer bonus_type, real amount returns nothing
            -> Set the specified bonus type to amount for the unit
            -> Example: call SetUnitBonusReal(GetTriggerUnit(), BONUS_ATTACK_SPEED, 0.15)

        function RemoveUnitBonusReal takes unit u, real bonus_type returns nothing
            -> Removes the Specified bonus type from unit
            -> Example: call RemoveUnitBonusReal(GetTriggerUnit(), BONUS_MANA_REGEN)

        function AddUnitBonusReal takes unit u, integer bonus_type, real amount returns real
            -> Add the specified amount for the specified bonus tyte for unit
            -> Example: call AddUnitBonusReal(GetTriggerUnit(), BONUS_LIFE_STEAL, 0.33)
 
        Added in version 1.5:
            Upper and Lower limit to max bonus amount set to 2147483647 and -2147483648
            to avoid over/under flowing the integer fields. AddUnitBonus()
            now returns the amount of bonus that was actually setted. In case of no over/under flow,
            it returns the amount passed, in case of over/under flow it returns the amount that
            was allowed to be setted. It is still up to the user to call the functions without
            passing integers that already over/under flown.
     
        Added in version 1.7
            - Fixed a bug when Adding Health/Mana bonus not keeping the unit Health/Mana Percentage
            - Added the funcitons: They manipuilate real bonuses values correctly.
                - GetUnitBonusReal()
                - SetUnitBonusReal()
                - RemoveUnitBonusReal()
                - AddUnitBonusReal()
            - Refactored the LinkBonusToItem() to use the On Drop event instead of a periodic timer to check the link
            - Included an Expanded version of NewBonus and NewBonusUtils that take advangtage of the Damage Inteface System and Cooldown Reduction System
            - Renamed 4 bonus types for better readability.
            - Removed the "Ex" from the end of the API functions
 
        Credits to Earth Fury for the original Bonus idea
    //! endnovjass
    /* ----------------------------------- END ---------------------------------- */
     
    globals
        //The bonus types
        constant integer BONUS_DAMAGE                  = 1
        constant integer BONUS_ARMOR                   = 2
        constant integer BONUS_AGILITY                 = 3
        constant integer BONUS_STRENGTH                = 4
        constant integer BONUS_INTELLIGENCE            = 5
        constant integer BONUS_HEALTH                  = 6
        constant integer BONUS_MANA                    = 7
        constant integer BONUS_MOVEMENT_SPEED          = 8
        constant integer BONUS_SIGHT_RANGE             = 9
        constant integer BONUS_HEALTH_REGEN            = 10
        constant integer BONUS_MANA_REGEN              = 11
        constant integer BONUS_ATTACK_SPEED            = 12
        constant integer BONUS_MAGIC_RESISTANCE        = 13
 
        //The abilities codes for each bonus
        //When pasting the abilities over to your map
        //their raw code should match the bonus here
        private constant integer DAMAGE_ABILITY           = 'Z001'
        private constant integer ARMOR_ABILITY            = 'Z002'
        private constant integer STATS_ABILITY            = 'Z003'
        private constant integer HEALTH_ABILITY           = 'Z004'
        private constant integer MANA_ABILITY             = 'Z005'
        private constant integer HEALTHREGEN_ABILITY      = 'Z006'
        private constant integer MANAREGEN_ABILITY        = 'Z007'
        private constant integer ATTACKSPEED_ABILITY      = 'Z008'
        private constant integer MOVEMENTSPEED_ABILITY    = 'Z009'
        private constant integer SIGHT_RANGE_ABILITY      = 'Z00A'
        private constant integer MAGIC_RESISTANCE_ABILITY = 'Z00B'
 
        //The abilities fields that are modified. For the sake of readability
        private constant abilityintegerlevelfield DAMAGE_FIELD           = ABILITY_ILF_ATTACK_BONUS
        private constant abilityintegerlevelfield ARMOR_FIELD            = ABILITY_ILF_DEFENSE_BONUS_IDEF
        private constant abilityintegerlevelfield AGILITY_FIELD          = ABILITY_ILF_AGILITY_BONUS
        private constant abilityintegerlevelfield STRENGTH_FIELD         = ABILITY_ILF_STRENGTH_BONUS_ISTR
        private constant abilityintegerlevelfield INTELLIGENCE_FIELD     = ABILITY_ILF_INTELLIGENCE_BONUS
        private constant abilityintegerlevelfield HEALTH_FIELD           = ABILITY_ILF_MAX_LIFE_GAINED
        private constant abilityintegerlevelfield MANA_FIELD             = ABILITY_ILF_MAX_MANA_GAINED
        private constant abilityintegerlevelfield MOVEMENTSPEED_FIELD    = ABILITY_ILF_MOVEMENT_SPEED_BONUS
        private constant abilityintegerlevelfield SIGHT_RANGE_FIELD      = ABILITY_ILF_SIGHT_RANGE_BONUS
        private constant abilityreallevelfield    HEALTHREGEN_FIELD      = ABILITY_RLF_AMOUNT_OF_HIT_POINTS_REGENERATED
        private constant abilityreallevelfield    MANAREGEN_FIELD        = ABILITY_RLF_AMOUNT_REGENERATED
        private constant abilityreallevelfield    ATTACKSPEED_FIELD      = ABILITY_RLF_ATTACK_SPEED_INCREASE_ISX1
        private constant abilityreallevelfield    MAGIC_RESISTANCE_FIELD = ABILITY_RLF_DAMAGE_REDUCTION_ISR2
    endglobals
 
    struct NewBonus
        //SetUnitAbilityBonusI() and SetUnitAbilityBonusR are necessary to manage abilities that have integer fields and real fields
        //but the return is normalized to reals
        static method SetUnitAbilityBonusI takes unit u, integer abilCode, abilityintegerlevelfield field, integer amount returns integer
            if GetUnitAbilityLevel(u, abilCode) == 0 then
                call UnitAddAbility(u, abilCode)
                call UnitMakeAbilityPermanent(u, true, abilCode)
            endif
     
            //Increasing and Decreasing is necessary since the abilities do not get updated just by changing
            //it's fields values. In the future, if Blizzard decides to patch it, it could be removed.
            if BlzSetAbilityIntegerLevelField(BlzGetUnitAbility(u, abilCode), field, 0, amount) then
                call IncUnitAbilityLevel(u, abilCode)
                call DecUnitAbilityLevel(u, abilCode)
            endif
     
            return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(u, abilCode), field, 0)
        endmethod

        static method SetUnitAbilityBonusR takes unit u, integer abilCode, abilityreallevelfield field, real amount returns real
            if GetUnitAbilityLevel(u, abilCode) == 0 then
                call UnitAddAbility(u, abilCode)
                call UnitMakeAbilityPermanent(u, true, abilCode)
            endif
     
            if BlzSetAbilityRealLevelField(BlzGetUnitAbility(u, abilCode), field, 0, amount) then
                call IncUnitAbilityLevel(u, abilCode)
                call DecUnitAbilityLevel(u, abilCode)
            endif
     
            return BlzGetAbilityRealLevelField(BlzGetUnitAbility(u, abilCode), field, 0)
        endmethod

        static method GetUnitBonus takes unit u, integer bonus_type returns integer
            if bonus_type == BONUS_DAMAGE then
                return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(u, DAMAGE_ABILITY), DAMAGE_FIELD, 0)
            elseif bonus_type == BONUS_ARMOR then
                return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(u, ARMOR_ABILITY), ARMOR_FIELD, 0)
            elseif bonus_type == BONUS_HEALTH then
                return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(u, HEALTH_ABILITY), HEALTH_FIELD, 0)
            elseif bonus_type == BONUS_MANA then
                return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(u, MANA_ABILITY), MANA_FIELD, 0)
            elseif bonus_type == BONUS_AGILITY then
                return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(u, STATS_ABILITY), AGILITY_FIELD, 0)
            elseif bonus_type == BONUS_STRENGTH then
                return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(u, STATS_ABILITY), STRENGTH_FIELD, 0)
            elseif bonus_type == BONUS_INTELLIGENCE then
                return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(u, STATS_ABILITY), INTELLIGENCE_FIELD, 0)
            elseif bonus_type == BONUS_MOVEMENT_SPEED then
                return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(u, MOVEMENTSPEED_ABILITY), MOVEMENTSPEED_FIELD, 0)
            elseif bonus_type == BONUS_SIGHT_RANGE then
                return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(u, SIGHT_RANGE_ABILITY), SIGHT_RANGE_FIELD, 0)
            else
                call DisplayTimedTextToPlayer(Player(0), 0, 0, 10, "Invalid Bonus Type")
            endif
         
            return -1
        endmethod

        static method SetUnitBonus takes unit u, integer bonus_type, integer amount returns integer
            local real p

            if bonus_type == BONUS_DAMAGE then
                return SetUnitAbilityBonusI(u, DAMAGE_ABILITY, DAMAGE_FIELD, amount)
            elseif bonus_type == BONUS_ARMOR then
                return SetUnitAbilityBonusI(u, ARMOR_ABILITY, ARMOR_FIELD, amount)
            elseif bonus_type == BONUS_HEALTH then
                set p = GetUnitLifePercent(u)
                call BlzSetUnitMaxHP(u, (BlzGetUnitMaxHP(u) + amount - GetUnitBonus(u, bonus_type)))
                call SetUnitLifePercentBJ(u, p)
                return SetUnitAbilityBonusI(u, HEALTH_ABILITY, HEALTH_FIELD, amount)
            elseif bonus_type == BONUS_MANA then
                set p = GetUnitManaPercent(u)
                call BlzSetUnitMaxMana(u, (BlzGetUnitMaxMana(u) + amount - GetUnitBonus(u, bonus_type)))
                call SetUnitManaPercentBJ(u, p)
                return SetUnitAbilityBonusI(u, MANA_ABILITY, MANA_FIELD, amount)
            elseif bonus_type == BONUS_AGILITY then
                return SetUnitAbilityBonusI(u, STATS_ABILITY, AGILITY_FIELD, amount)
            elseif bonus_type == BONUS_STRENGTH then
                return SetUnitAbilityBonusI(u, STATS_ABILITY, STRENGTH_FIELD, amount)
            elseif bonus_type == BONUS_INTELLIGENCE then
                return SetUnitAbilityBonusI(u, STATS_ABILITY, INTELLIGENCE_FIELD, amount)
            elseif bonus_type == BONUS_MOVEMENT_SPEED then
                return SetUnitAbilityBonusI(u, MOVEMENTSPEED_ABILITY, MOVEMENTSPEED_FIELD, amount)
            elseif bonus_type == BONUS_SIGHT_RANGE then
                call BlzSetUnitRealField(u, UNIT_RF_SIGHT_RADIUS, (BlzGetUnitRealField(u, UNIT_RF_SIGHT_RADIUS) + amount - GetUnitBonus(u, bonus_type)))
                return SetUnitAbilityBonusI(u, SIGHT_RANGE_ABILITY, SIGHT_RANGE_FIELD, amount)
            else
                call DisplayTimedTextToPlayer(Player(0), 0, 0, 10, "Invalid Bonus Type")
            endif

            return -1
        endmethod

        static method AddUnitBonus takes unit u, integer bonus_type, integer amount returns integer
            local integer current_amount = GetUnitBonus(u, bonus_type)

            // Added in version 1.5 to avoid overflow/underflow of the field value
            if amount > 0 and current_amount > 2147483647 - amount then //Overflow
                set amount = 2147483647 - current_amount
            elseif amount < 0 and current_amount < -2147483648 - amount then //Underflow
                set amount = -2147483648 - current_amount
            endif

            call SetUnitBonus(u, bonus_type, (current_amount + amount))

            return amount
        endmethod

        // Funtions that handle the real bonus types

        static method GetUnitBonusR takes unit u, integer bonus_type returns real
            if bonus_type == BONUS_HEALTH_REGEN then
                return BlzGetAbilityRealLevelField(BlzGetUnitAbility(u, HEALTHREGEN_ABILITY), HEALTHREGEN_FIELD, 0)
            elseif bonus_type == BONUS_MANA_REGEN then
                return BlzGetAbilityRealLevelField(BlzGetUnitAbility(u, MANAREGEN_ABILITY), MANAREGEN_FIELD, 0)
            elseif bonus_type == BONUS_ATTACK_SPEED then
                return BlzGetAbilityRealLevelField(BlzGetUnitAbility(u, ATTACKSPEED_ABILITY), ATTACKSPEED_FIELD, 0)
            elseif bonus_type == BONUS_MAGIC_RESISTANCE then
                return BlzGetAbilityRealLevelField(BlzGetUnitAbility(u, MAGIC_RESISTANCE_ABILITY), MAGIC_RESISTANCE_FIELD, 0)
            else
                call DisplayTimedTextToPlayer(Player(0), 0, 0, 10, "Invalid Bonus Type")
            endif
         
            return -1.0
        endmethod

        static method SetUnitBonusR takes unit u, integer bonus_type, real amount returns nothing
            if bonus_type == BONUS_HEALTH_REGEN then
                call SetUnitAbilityBonusR(u, HEALTHREGEN_ABILITY, HEALTHREGEN_FIELD, amount)
            elseif bonus_type == BONUS_MANA_REGEN then
                call SetUnitAbilityBonusR(u, MANAREGEN_ABILITY, MANAREGEN_FIELD, amount)
            elseif bonus_type == BONUS_ATTACK_SPEED then
                call SetUnitAbilityBonusR(u, ATTACKSPEED_ABILITY, ATTACKSPEED_FIELD, amount)
            elseif bonus_type == BONUS_MAGIC_RESISTANCE then
                call SetUnitAbilityBonusR(u, MAGIC_RESISTANCE_ABILITY, MAGIC_RESISTANCE_FIELD, amount)
            else
                call DisplayTimedTextToPlayer(Player(0), 0, 0, 10, "Invalid Bonus Type")
            endif
        endmethod

        static method AddUnitBonusR takes unit u, integer bonus_type, real amount returns nothing
            if bonus_type == BONUS_HEALTH_REGEN then
                call SetUnitBonusR(u, bonus_type, GetUnitBonusR(u, bonus_type) + amount)
            elseif bonus_type == BONUS_MANA_REGEN then
                call SetUnitBonusR(u, bonus_type, GetUnitBonusR(u, bonus_type) + amount)
            elseif bonus_type == BONUS_ATTACK_SPEED then
                call SetUnitBonusR(u, bonus_type, GetUnitBonusR(u, bonus_type) + amount)
            elseif bonus_type == BONUS_MAGIC_RESISTANCE then
                call SetUnitBonusR(u, bonus_type, GetUnitBonusR(u, bonus_type) + amount)
            else
                call DisplayTimedTextToPlayer(Player(0), 0, 0, 10, "Invalid Bonus Type")
            endif
        endmethod
    endstruct
 
    /* -------------------------------------------------------------------------- */
    /*                               JASS Public API                              */
    /* -------------------------------------------------------------------------- */
 
    function GetUnitBonus takes unit u, integer bonus_type returns integer
        return NewBonus.GetUnitBonus(u, bonus_type)
    endfunction

    function SetUnitBonus takes unit u, integer bonus_type, integer amount returns integer
        return NewBonus.SetUnitBonus(u, bonus_type, amount)
    endfunction
 
    function RemoveUnitBonus takes unit u, integer bonus_type returns nothing
        call NewBonus.SetUnitBonus(u, bonus_type, 0)
    endfunction
 
    function AddUnitBonus takes unit u, integer bonus_type, integer amount returns integer
        return NewBonus.AddUnitBonus(u, bonus_type, amount)
    endfunction

    // functions for manipulating the real bonus types

    function GetUnitBonusReal takes unit u, integer bonus_type returns real
        return NewBonus.GetUnitBonusR(u, bonus_type)
    endfunction

    function SetUnitBonusReal takes unit u, integer bonus_type, real amount returns nothing
        call NewBonus.SetUnitBonusR(u, bonus_type, amount)
    endfunction
 
    function RemoveUnitBonusReal takes unit u, integer bonus_type returns nothing
        call NewBonus.SetUnitBonusR(u, bonus_type, 0)
    endfunction
 
    function AddUnitBonusReal takes unit u, integer bonus_type, real amount returns real
        call NewBonus.AddUnitBonusR(u, bonus_type, amount)
        return amount
    endfunction
endlibrary
 

Code (vJASS):

library NewBonusUtils requires NewBonus, RegisterPlayerUnitEvent
    /* ----------------------- NewBonusUtils v1.9 by Chopinski ----------------------- */
    //! novjass
   Required Library: RegisterPlayerUnitEvent -> www.hiveworkshop.com/threads/snippet-registerplayerunitevent.203338/

        API:
        function AddUnitBonusTimed takes unit u, integer bonus_type, real amount, real duration returns nothing
            -> Add the specified amount for the specified bonus type for unit for a duration
            -> Example: call AddUnitBonusTimed(GetTriggerUnit(), BONUS_ARMOR, 13, 10.5)

        function LinkBonusToBuff takes unit u, integer bonus_type, real amount, integer buffId returns nothing
            -> Links the bonus amount specified to a buff or ability. As long as the unit has the buff or
            -> the ability represented by the parameter buffId the bonus is not removed.
            -> Example: call LinkBonusToBuff(GetTriggerUnit(), BONUS_ARMOR, 10, 'B000')
        function LinkBonusToItem takes unit u, integer bonus_type, real amount, item i returns nothing
            -> Links the bonus amount specified to an item. As long as the unit has that item the bonus is not removed.
            -> Note that it will work for items with the same id, because it takes as parameter the item object.
            -> Example: call LinkBonusToItem(GetManipulatingUnit(), BONUS_ARMOR, 10, GetManipulatedItem())

        function UnitCopyBonuses takes unit source, unit target returns nothing
            -> Copy the source unit bonuses using the Add functionality to the target unit
            -> Example: call UnitCopyBonuses(GetTriggerUnit(), GetSummonedUnit())

        function UnitMirrorBonuses takes unit source, unit target returns nothing
            -> Copy the source unit bonuses using the Set functionality to the target unit
            -> Example: call UnitMirrorBonuses(GetTriggerUnit(), GetSummonedUnit())
    //! endnovjass
    /* ----------------------------------- END ---------------------------------- */
    private struct NewBonusUtils extends NewBonus
        static timer t = CreateTimer()

        //Dynamic Indexing for buff and timed
        static integer didx = -1
        static thistype array data

        //Dynamic Indexing for items
        static integer ditem = -1
        static thistype array items

        unit    u
        item    i
        real    ticks
        integer bonus_type
        integer buffId // Works for abilities too.
        integer int_amount
        real    real_amount
        boolean link //true -> Timed bonus / false -> Linked to a buff

        method destroyInstance takes integer i, boolean isItem returns integer
            if this.bonus_type < 10 then
                call AddUnitBonus(this.u, this.bonus_type, -this.int_amount)
            else
                call AddUnitBonusReal(this.u, this.bonus_type, -this.real_amount)
            endif

            if isItem then
                set  items[i] = items[ditem]
                set  ditem     = ditem - 1
            else
                set  data[i] = data[didx]
                set  didx    = didx - 1

                if didx == -1 then
                    call PauseTimer(t)
                endif
            endif

            set  this.u = null
            set  this.i = null
            call this.deallocate()

            return i - 1
        endmethod

        static method OnDrop takes nothing returns nothing
            local item     itm = GetManipulatedItem()
            local integer  i = 0
            local thistype this

            loop
                exitwhen i > ditem
                    set this = items[i]

                    if this.i == itm then
                        set i = this.destroyInstance(i, true)
                    endif
                set i = i + 1
            endloop
        endmethod
     
        static method OnPeriod takes nothing returns nothing
            local integer  i = 0
            local thistype this

            loop
                exitwhen i > didx
                    set this = data[i]

                    if this.link then // Timed link
                        set this.ticks = this.ticks - 1

                        if this.ticks <= 0 then
                            set i = this.destroyInstance(i, false)
                        endif
                    else // Buff Link
                        if GetUnitAbilityLevel(this.u, this.buffId) == 0 then
                            set i = this.destroyInstance(i, false)
                        endif
                    endif
                set i = i + 1
            endloop
        endmethod

        static method TimeLink takes unit u, integer bonus_type, real amount, real duration, boolean link returns nothing
            local thistype this = thistype.allocate()

            set this.u          = u
            set this.bonus_type = bonus_type
            set this.ticks      = duration/0.03125000
            set this.link       = link
            set didx            = didx + 1
            set data[didx]      = this

            if bonus_type < 10 then
                set this.int_amount = AddUnitBonus(u, bonus_type, R2I(amount))
            else
                set this.real_amount = AddUnitBonusReal(u, bonus_type, amount)
            endif
         
            if didx == 0 then
                call TimerStart(t, 0.03125000, true, function thistype.OnPeriod)
            endif
        endmethod

        static method BuffLink takes unit u, integer bonus_type, real amount, integer buffId, boolean link returns nothing
            local thistype this = thistype.allocate()

            set this.u          = u
            set this.bonus_type = bonus_type
            set this.buffId     = buffId
            set this.link       = link
            set didx            = didx + 1
            set data[didx]      = this

            if bonus_type < 10 then
                set this.int_amount = AddUnitBonus(u, bonus_type, R2I(amount))
            else
                set this.real_amount = AddUnitBonusReal(u, bonus_type, amount)
            endif
         
            if didx == 0 then
                call TimerStart(t, 0.03125000, true, function thistype.OnPeriod)
            endif
        endmethod

        static method ItemLink takes unit u, integer bonus_type, real amount, item i returns nothing
            local thistype this = thistype.allocate()

            set this.u          = u
            set this.i          = i
            set this.bonus_type = bonus_type
            set ditem           = ditem + 1
            set items[ditem]    = this
         
            if bonus_type < 10 then
                set this.int_amount = AddUnitBonus(u, bonus_type, R2I(amount))
            else
                set this.real_amount = AddUnitBonusReal(u, bonus_type, amount)
            endif
        endmethod

        static method CopyBonuses takes unit source, unit target returns nothing
            local integer i = 1

            loop
                exitwhen i > 13
                    if i < 10 then
                        if GetUnitBonus(source, i) != 0 then
                            call AddUnitBonus(target, i, GetUnitBonus(source, i))
                        endif
                    else
                        if GetUnitBonusReal(source, i) != 0 then
                            call AddUnitBonusReal(target, i, GetUnitBonusReal(source, i))
                        endif
                    endif
                set i = i + 1
            endloop
        endmethod

        static method MirrorBonuses takes unit source, unit target returns nothing
            local integer i = 1

            loop
                exitwhen i > 13
                    if i < 10 then
                        call SetUnitBonus(target, i, GetUnitBonus(source, i))
                    else
                        call SetUnitBonusReal(target, i, GetUnitBonusReal(source, i))
                    endif
                set i = i + 1
            endloop
        endmethod

        static method onInit takes nothing returns nothing
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DROP_ITEM, function thistype.OnDrop)
        endmethod
    endstruct

    /* -------------------------------------------------------------------------- */
    /*                               JASS Public API                              */
    /* -------------------------------------------------------------------------- */

    function AddUnitBonusTimed takes unit u, integer bonus_type, real amount, real duration returns nothing
        call NewBonusUtils.TimeLink(u, bonus_type, amount, duration, true)
    endfunction

    function LinkBonusToBuff takes unit u, integer bonus_type, real amount, integer buffId returns nothing
        call NewBonusUtils.BuffLink(u, bonus_type, amount, buffId, false)
    endfunction

    function LinkBonusToItem takes unit u, integer bonus_type, real amount, item i returns nothing
        call NewBonusUtils.ItemLink(u, bonus_type, amount, i)
    endfunction

    function UnitCopyBonuses takes unit source, unit target returns nothing
        call NewBonusUtils.CopyBonuses(source, target)
    endfunction

    function UnitMirrorBonuses takes unit source, unit target returns nothing
        call NewBonusUtils.MirrorBonuses(source, target)
    endfunction
endlibrary
 

Code (vJASS):

library NewBonus requires DamageInterface, Evasion, CriticalStrike, SpellPower, LifeSteal, SpellVamp, CooldownReduction
    /* ----------------------- NewBonus Expanded v1.9 by Chopinski ----------------------- */
    //! novjass
        Since ObjectMerger is broken and we still have no means to edit
        bonus values (green values) i decided to create a light weight
        Bonus library that works in the same way that the original Bonus Mod
        by Earth Fury did. NewBonus requires patch 1.31+.
 
        How it works?
        By using the new Object API recently introduced to warcraft, we can now
        modify an ability field, so when giving an unit a bonus, we add a specific
        ability to that unit, if it do not have it already, and change that ability
        bonus value to the desired value. Retrieving the amount is also trivial, by
        just reading that field value.
 
        How to Import?
        Importing bonus mod is really simple. Just copy the 9 abilities with the
        prefix "NewBonus" from the Object Editor into your map and match their new raw
        code to the bonus types in the global block below. Then create a trigger called
        NewBonus, convert it to custom text and paste this code there. You done!
 
        API:
        function GetUnitBonus takes unit u, integer bonus_type returns integer
            -> Returns the specified bonus amount for the unit
            -> Example: set amount = GetUnitBonus(GetTriggerUnit(), BONUS_AGILITY)

        function SetUnitBonus takes unit u, integer bonus_type, integer amount returns integer
            -> Set the specified bonus type to amount for the unit
            -> Example: call SetUnitBonus(GetTriggerUnit(), BONUS_DAMAGE, 100)
        function RemoveUnitBonus takes unit u, integer bonus_type returns nothing
            -> Removes the Specified bonus type from unit
            -> Example: call RemoveUnitBonus(GetTriggerUnit(), BONUS_AGILITY)
        function AddUnitBonus takes unit u, integer bonus_type, integer amount returns integer
            -> Add the specified amount for the specified bonus tyte for unit
            -> Example: call AddUnitBonus(GetTriggerUnit(), BONUS_DAMAGE, 100)

        function GetUnitBonusReal takes unit u, integer bonus_type returns real
            -> Returns the specified bonus amount for the unit
            -> Example: set amount = GetUnitBonusReal(GetTriggerUnit(), BONUS_HEALTH_REGEN)

        function SetUnitBonusReal takes unit u, integer bonus_type, real amount returns nothing
            -> Set the specified bonus type to amount for the unit
            -> Example: call SetUnitBonusReal(GetTriggerUnit(), BONUS_ATTACK_SPEED, 0.15)

        function RemoveUnitBonusReal takes unit u, real bonus_type returns nothing
            -> Removes the Specified bonus type from unit
            -> Example: call RemoveUnitBonusReal(GetTriggerUnit(), BONUS_MANA_REGEN)

        function AddUnitBonusReal takes unit u, integer bonus_type, real amount returns real
            -> Add the specified amount for the specified bonus tyte for unit
            -> Example: call AddUnitBonusReal(GetTriggerUnit(), BONUS_LIFE_STEAL, 0.33)
 
        Added in version 1.5:
            Upper and Lower limit to max bonus amount set to 2147483647 and -2147483648
            to avoid over/under flowing the integer fields. AddUnitBonus()
            now returns the amount of bonus that was actually setted. In case of no over/under flow,
            it returns the amount passed, in case of over/under flow it returns the amount that
            was allowed to be setted. It is still up to the user to call the functions without
            passing integers that already over/under flown.
     
        Added in version 1.7
            - Fixed a bug when Adding Health/Mana bonus not keeping the unit Health/Mana Percentage
            - Added the funcitons: They manipuilate real bonuses values correctly.
                - GetUnitBonusReal()
                - SetUnitBonusReal()
                - RemoveUnitBonusReal()
                - AddUnitBonusReal()
            - Refactored the LinkBonusToItem() to use the On Drop event instead of a periodic timer to check the link
            - Included an Expanded version of NewBonus and NewBonusUtils that take advangtage of the Damage Inteface System and Cooldown Reduction System
            - Renamed 4 bonus types for better readability.
            - Removed the "Ex" from the end of the API functions
 
        Credits to Earth Fury for the original Bonus idea
    //! endnovjass
    /* ----------------------------------- END ---------------------------------- */
     
        globals
            //The bonus types
            constant integer BONUS_DAMAGE                  = 1
            constant integer BONUS_ARMOR                   = 2
            constant integer BONUS_AGILITY                 = 3
            constant integer BONUS_STRENGTH                = 4
            constant integer BONUS_INTELLIGENCE            = 5
            constant integer BONUS_HEALTH                  = 6
            constant integer BONUS_MANA                    = 7
            constant integer BONUS_MOVEMENT_SPEED          = 8
            constant integer BONUS_SIGHT_RANGE             = 9
            constant integer BONUS_HEALTH_REGEN            = 10
            constant integer BONUS_MANA_REGEN              = 11
            constant integer BONUS_ATTACK_SPEED            = 12
            constant integer BONUS_MAGIC_RESISTANCE        = 13
            //expanded bonus types not linked to abilities
            constant integer BONUS_EVASION_CHANCE          = 14
            constant integer BONUS_MISS_CHANCE             = 15
            constant integer BONUS_CRITICAL_CHANCE         = 16
            constant integer BONUS_CRITICAL_DAMAGE         = 17
            constant integer BONUS_SPELL_POWER_FLAT        = 18
            constant integer BONUS_SPELL_POWER_PERCENT     = 19
            constant integer BONUS_LIFE_STEAL              = 20
            constant integer BONUS_SPELL_VAMP              = 21
            constant integer BONUS_COOLDOWN_REDUCTION      = 22
            constant integer BONUS_COOLDOWN_REDUCTION_FLAT = 23
            constant integer BONUS_COOLDOWN_OFFSET         = 24
     
            //The abilities codes for each bonus
            //When pasting the abilities over to your map
            //their raw code should match the bonus here
            private constant integer DAMAGE_ABILITY           = 'Z001'
            private constant integer ARMOR_ABILITY            = 'Z002'
            private constant integer STATS_ABILITY            = 'Z003'
            private constant integer HEALTH_ABILITY           = 'Z004'
            private constant integer MANA_ABILITY             = 'Z005'
            private constant integer HEALTHREGEN_ABILITY      = 'Z006'
            private constant integer MANAREGEN_ABILITY        = 'Z007'
            private constant integer ATTACKSPEED_ABILITY      = 'Z008'
            private constant integer MOVEMENTSPEED_ABILITY    = 'Z009'
            private constant integer SIGHT_RANGE_ABILITY      = 'Z00A'
            private constant integer MAGIC_RESISTANCE_ABILITY = 'Z00B'
     
            //The abilities fields that are modified. For the sake of readability
            private constant abilityintegerlevelfield DAMAGE_FIELD           = ABILITY_ILF_ATTACK_BONUS
            private constant abilityintegerlevelfield ARMOR_FIELD            = ABILITY_ILF_DEFENSE_BONUS_IDEF
            private constant abilityintegerlevelfield AGILITY_FIELD          = ABILITY_ILF_AGILITY_BONUS
            private constant abilityintegerlevelfield STRENGTH_FIELD         = ABILITY_ILF_STRENGTH_BONUS_ISTR
            private constant abilityintegerlevelfield INTELLIGENCE_FIELD     = ABILITY_ILF_INTELLIGENCE_BONUS
            private constant abilityintegerlevelfield HEALTH_FIELD           = ABILITY_ILF_MAX_LIFE_GAINED
            private constant abilityintegerlevelfield MANA_FIELD             = ABILITY_ILF_MAX_MANA_GAINED
            private constant abilityintegerlevelfield MOVEMENTSPEED_FIELD    = ABILITY_ILF_MOVEMENT_SPEED_BONUS
            private constant abilityintegerlevelfield SIGHT_RANGE_FIELD      = ABILITY_ILF_SIGHT_RANGE_BONUS
            private constant abilityreallevelfield    HEALTHREGEN_FIELD      = ABILITY_RLF_AMOUNT_OF_HIT_POINTS_REGENERATED
            private constant abilityreallevelfield    MANAREGEN_FIELD        = ABILITY_RLF_AMOUNT_REGENERATED
            private constant abilityreallevelfield    ATTACKSPEED_FIELD      = ABILITY_RLF_ATTACK_SPEED_INCREASE_ISX1
            private constant abilityreallevelfield    MAGIC_RESISTANCE_FIELD = ABILITY_RLF_DAMAGE_REDUCTION_ISR2
        endglobals
     
        struct NewBonus
            //SetUnitAbilityBonusI() and SetUnitAbilityBonusR are necessary to manage abilities that have integer fields and real fields
            //but the return is normalized to reals
            static method SetUnitAbilityBonusI takes unit u, integer abilCode, abilityintegerlevelfield field, integer amount returns integer
                if GetUnitAbilityLevel(u, abilCode) == 0 then
                    call UnitAddAbility(u, abilCode)
                    call UnitMakeAbilityPermanent(u, true, abilCode)
                endif
         
                //Increasing and Decreasing is necessary since the abilities do not get updated just by changing
                //it's fields values. In the future, if Blizzard decides to patch it, it could be removed.
                if BlzSetAbilityIntegerLevelField(BlzGetUnitAbility(u, abilCode), field, 0, amount) then
                    call IncUnitAbilityLevel(u, abilCode)
                    call DecUnitAbilityLevel(u, abilCode)
                endif
         
                return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(u, abilCode), field, 0)
            endmethod
 
            static method SetUnitAbilityBonusR takes unit u, integer abilCode, abilityreallevelfield field, real amount returns real
                if GetUnitAbilityLevel(u, abilCode) == 0 then
                    call UnitAddAbility(u, abilCode)
                    call UnitMakeAbilityPermanent(u, true, abilCode)
                endif
         
                if BlzSetAbilityRealLevelField(BlzGetUnitAbility(u, abilCode), field, 0, amount) then
                    call IncUnitAbilityLevel(u, abilCode)
                    call DecUnitAbilityLevel(u, abilCode)
                endif
         
                return BlzGetAbilityRealLevelField(BlzGetUnitAbility(u, abilCode), field, 0)
            endmethod
 
            static method GetUnitBonus takes unit u, integer bonus_type returns integer
                if bonus_type == BONUS_DAMAGE then
                    return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(u, DAMAGE_ABILITY), DAMAGE_FIELD, 0)
                elseif bonus_type == BONUS_ARMOR then
                    return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(u, ARMOR_ABILITY), ARMOR_FIELD, 0)
                elseif bonus_type == BONUS_HEALTH then
                    return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(u, HEALTH_ABILITY), HEALTH_FIELD, 0)
                elseif bonus_type == BONUS_MANA then
                    return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(u, MANA_ABILITY), MANA_FIELD, 0)
                elseif bonus_type == BONUS_AGILITY then
                    return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(u, STATS_ABILITY), AGILITY_FIELD, 0)
                elseif bonus_type == BONUS_STRENGTH then
                    return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(u, STATS_ABILITY), STRENGTH_FIELD, 0)
                elseif bonus_type == BONUS_INTELLIGENCE then
                    return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(u, STATS_ABILITY), INTELLIGENCE_FIELD, 0)
                elseif bonus_type == BONUS_MOVEMENT_SPEED then
                    return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(u, MOVEMENTSPEED_ABILITY), MOVEMENTSPEED_FIELD, 0)
                elseif bonus_type == BONUS_SIGHT_RANGE then
                    return BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(u, SIGHT_RANGE_ABILITY), SIGHT_RANGE_FIELD, 0)
                else
                    call DisplayTimedTextToPlayer(Player(0), 0, 0, 10, "Invalid Bonus Type")
                endif
             
                return -1
            endmethod
 
            static method SetUnitBonus takes unit u, integer bonus_type, integer amount returns integer
                local real p

                if bonus_type == BONUS_DAMAGE then
                    return SetUnitAbilityBonusI(u, DAMAGE_ABILITY, DAMAGE_FIELD, amount)
                elseif bonus_type == BONUS_ARMOR then
                    return SetUnitAbilityBonusI(u, ARMOR_ABILITY, ARMOR_FIELD, amount)
                elseif bonus_type == BONUS_HEALTH then
                    set p = GetUnitLifePercent(u)
                    call BlzSetUnitMaxHP(u, (BlzGetUnitMaxHP(u) + amount - GetUnitBonus(u, bonus_type)))
                    call SetUnitLifePercentBJ(u, p)
                    return SetUnitAbilityBonusI(u, HEALTH_ABILITY, HEALTH_FIELD, amount)
                elseif bonus_type == BONUS_MANA then
                    set p = GetUnitManaPercent(u)
                    call BlzSetUnitMaxMana(u, (BlzGetUnitMaxMana(u) + amount - GetUnitBonus(u, bonus_type)))
                    call SetUnitManaPercentBJ(u, p)
                    return SetUnitAbilityBonusI(u, MANA_ABILITY, MANA_FIELD, amount)
                elseif bonus_type == BONUS_AGILITY then
                    return SetUnitAbilityBonusI(u, STATS_ABILITY, AGILITY_FIELD, amount)
                elseif bonus_type == BONUS_STRENGTH then
                    return SetUnitAbilityBonusI(u, STATS_ABILITY, STRENGTH_FIELD, amount)
                elseif bonus_type == BONUS_INTELLIGENCE then
                    return SetUnitAbilityBonusI(u, STATS_ABILITY, INTELLIGENCE_FIELD, amount)
                elseif bonus_type == BONUS_MOVEMENT_SPEED then
                    return SetUnitAbilityBonusI(u, MOVEMENTSPEED_ABILITY, MOVEMENTSPEED_FIELD, amount)
                elseif bonus_type == BONUS_SIGHT_RANGE then
                    call BlzSetUnitRealField(u, UNIT_RF_SIGHT_RADIUS, (BlzGetUnitRealField(u, UNIT_RF_SIGHT_RADIUS) + amount - GetUnitBonus(u, bonus_type)))
                    return SetUnitAbilityBonusI(u, SIGHT_RANGE_ABILITY, SIGHT_RANGE_FIELD, amount)
                else
                    call DisplayTimedTextToPlayer(Player(0), 0, 0, 10, "Invalid Bonus Type")
                endif
 
                return -1
            endmethod
 
            static method AddUnitBonus takes unit u, integer bonus_type, integer amount returns integer
                local integer current_amount = GetUnitBonus(u, bonus_type)

                // Added in version 1.5 to avoid overflow/underflow of the field value
                if amount > 0 and current_amount > 2147483647 - amount then //Overflow
                    set amount = 2147483647 - current_amount
                elseif amount < 0 and current_amount < -2147483648 - amount then //Underflow
                    set amount = -2147483648 - current_amount
                endif
 
                call SetUnitBonus(u, bonus_type, (current_amount + amount))
 
                return amount
            endmethod

            // Funtions that handle the real bonus types

            static method GetUnitBonusR takes unit u, integer bonus_type returns real
                if bonus_type == BONUS_HEALTH_REGEN then
                    return BlzGetAbilityRealLevelField(BlzGetUnitAbility(u, HEALTHREGEN_ABILITY), HEALTHREGEN_FIELD, 0)
                elseif bonus_type == BONUS_MANA_REGEN then
                    return BlzGetAbilityRealLevelField(BlzGetUnitAbility(u, MANAREGEN_ABILITY), MANAREGEN_FIELD, 0)
                elseif bonus_type == BONUS_ATTACK_SPEED then
                    return BlzGetAbilityRealLevelField(BlzGetUnitAbility(u, ATTACKSPEED_ABILITY), ATTACKSPEED_FIELD, 0)
                elseif bonus_type == BONUS_MAGIC_RESISTANCE then
                    return BlzGetAbilityRealLevelField(BlzGetUnitAbility(u, MAGIC_RESISTANCE_ABILITY), MAGIC_RESISTANCE_FIELD, 0)
                elseif bonus_type == BONUS_EVASION_CHANCE then
                    return GetUnitEvasionChance(u)
                elseif bonus_type == BONUS_MISS_CHANCE then
                    return GetUnitMissChance(u)
                elseif bonus_type == BONUS_CRITICAL_CHANCE then
                    return GetUnitCriticalChance(u)
                elseif bonus_type == BONUS_CRITICAL_DAMAGE then
                    return GetUnitCriticalMultiplier(u)
                elseif bonus_type == BONUS_SPELL_POWER_FLAT then
                    return GetUnitSpellPowerFlat(u)
                elseif bonus_type == BONUS_SPELL_POWER_PERCENT then
                    return GetUnitSpellPowerPercent(u)
                elseif bonus_type == BONUS_LIFE_STEAL then
                    return GetUnitLifeSteal(u)
                elseif bonus_type == BONUS_SPELL_VAMP then
                    return GetUnitSpellVamp(u)
                elseif bonus_type == BONUS_COOLDOWN_REDUCTION then
                    return GetUnitCooldownReduction(u)
                elseif bonus_type == BONUS_COOLDOWN_REDUCTION_FLAT then
                    return GetUnitCooldownReductionFlat(u)
                elseif bonus_type == BONUS_COOLDOWN_OFFSET then
                    return GetUnitCooldownOffset(u)
                else
                    call DisplayTimedTextToPlayer(Player(0), 0, 0, 10, "Invalid Bonus Type")
                endif
             
                return -1.0
            endmethod
 
            static method SetUnitBonusR takes unit u, integer bonus_type, real amount returns nothing
                if bonus_type == BONUS_HEALTH_REGEN then
                    call SetUnitAbilityBonusR(u, HEALTHREGEN_ABILITY, HEALTHREGEN_FIELD, amount)
                elseif bonus_type == BONUS_MANA_REGEN then
                    call SetUnitAbilityBonusR(u, MANAREGEN_ABILITY, MANAREGEN_FIELD, amount)
                elseif bonus_type == BONUS_ATTACK_SPEED then
                    call SetUnitAbilityBonusR(u, ATTACKSPEED_ABILITY, ATTACKSPEED_FIELD, amount)
                elseif bonus_type == BONUS_MAGIC_RESISTANCE then
                    call SetUnitAbilityBonusR(u, MAGIC_RESISTANCE_ABILITY, MAGIC_RESISTANCE_FIELD, amount)
                elseif bonus_type == BONUS_EVASION_CHANCE then
                    call SetUnitEvasionChance(u, amount)
                elseif bonus_type == BONUS_MISS_CHANCE then
                    call SetUnitMissChance(u, amount)
                elseif bonus_type == BONUS_CRITICAL_CHANCE then
                    call SetUnitCriticalChance(u, amount)
                elseif bonus_type == BONUS_CRITICAL_DAMAGE then
                    call SetUnitCriticalMultiplier(u, amount)
                elseif bonus_type == BONUS_SPELL_POWER_FLAT then
                    call SetUnitSpellPowerFlat(u, amount)
                elseif bonus_type == BONUS_SPELL_POWER_PERCENT then
                    call SetUnitSpellPowerPercent(u, amount)
                elseif bonus_type == BONUS_LIFE_STEAL then
                    call SetUnitLifeSteal(u, amount)
                elseif bonus_type == BONUS_SPELL_VAMP then
                    call SetUnitSpellVamp(u, amount)
                elseif bonus_type == BONUS_COOLDOWN_REDUCTION then
                    call SetUnitCooldownReduction(u, amount)
                elseif bonus_type == BONUS_COOLDOWN_REDUCTION_FLAT then
                    call SetUnitCooldownReductionFlat(u, amount)
                elseif bonus_type == BONUS_COOLDOWN_OFFSET then
                    call SetUnitCooldownOffset(u, amount)
                else
                    call DisplayTimedTextToPlayer(Player(0), 0, 0, 10, "Invalid Bonus Type")
                endif
            endmethod
 
            static method AddUnitBonusR takes unit u, integer bonus_type, real amount returns nothing
                if bonus_type == BONUS_HEALTH_REGEN then
                    call SetUnitBonusR(u, bonus_type, GetUnitBonusR(u, bonus_type) + amount)
                elseif bonus_type == BONUS_MANA_REGEN then
                    call SetUnitBonusR(u, bonus_type, GetUnitBonusR(u, bonus_type) + amount)
                elseif bonus_type == BONUS_ATTACK_SPEED then
                    call SetUnitBonusR(u, bonus_type, GetUnitBonusR(u, bonus_type) + amount)
                elseif bonus_type == BONUS_MAGIC_RESISTANCE then
                    call SetUnitBonusR(u, bonus_type, GetUnitBonusR(u, bonus_type) + amount)
                elseif bonus_type == BONUS_EVASION_CHANCE then
                    call UnitAddEvasionChance(u, amount)
                elseif bonus_type == BONUS_MISS_CHANCE then
                    call UnitAddMissChance(u, amount)
                elseif bonus_type == BONUS_CRITICAL_CHANCE then
                    call UnitAddCriticalStrike(u, amount, 0)
                elseif bonus_type == BONUS_CRITICAL_DAMAGE then
                    call UnitAddCriticalStrike(u, 0, amount)
                elseif bonus_type == BONUS_SPELL_POWER_FLAT then
                    call UnitAddSpellPowerFlat(u, amount)
                elseif bonus_type == BONUS_SPELL_POWER_PERCENT then
                    call UnitAddSpellPowerPercent(u, amount)
                elseif bonus_type == BONUS_LIFE_STEAL then
                    call UnitAddLifeSteal(u, amount)
                elseif bonus_type == BONUS_SPELL_VAMP then
                    call UnitAddSpellVamp(u, amount)
                elseif bonus_type == BONUS_COOLDOWN_REDUCTION then
                    call UnitAddCooldownReduction(u, amount)
                elseif bonus_type == BONUS_COOLDOWN_REDUCTION_FLAT then
                    call UnitAddCooldownReductionFlat(u, amount)
                elseif bonus_type == BONUS_COOLDOWN_OFFSET then
                    call UnitAddCooldownOffset(u, amount)
                else
                    call DisplayTimedTextToPlayer(Player(0), 0, 0, 10, "Invalid Bonus Type")
                endif
            endmethod
        endstruct
     
        /* -------------------------------------------------------------------------- */
        /*                               JASS Public API                              */
        /* -------------------------------------------------------------------------- */
     
        function GetUnitBonus takes unit u, integer bonus_type returns integer
            return NewBonus.GetUnitBonus(u, bonus_type)
        endfunction
 
        function SetUnitBonus takes unit u, integer bonus_type, integer amount returns integer
            return NewBonus.SetUnitBonus(u, bonus_type, amount)
        endfunction
     
        function RemoveUnitBonus takes unit u, integer bonus_type returns nothing
            call NewBonus.SetUnitBonus(u, bonus_type, 0)
        endfunction
     
        function AddUnitBonus takes unit u, integer bonus_type, integer amount returns integer
            return NewBonus.AddUnitBonus(u, bonus_type, amount)
        endfunction

        // Extra functions for manipulating the real bonus types

        function GetUnitBonusReal takes unit u, integer bonus_type returns real
            return NewBonus.GetUnitBonusR(u, bonus_type)
        endfunction
 
        function SetUnitBonusReal takes unit u, integer bonus_type, real amount returns nothing
            call NewBonus.SetUnitBonusR(u, bonus_type, amount)
        endfunction
     
        function RemoveUnitBonusReal takes unit u, integer bonus_type returns nothing
            call NewBonus.SetUnitBonusR(u, bonus_type, 0)
        endfunction
     
        function AddUnitBonusReal takes unit u, integer bonus_type, real amount returns real
            call NewBonus.AddUnitBonusR(u, bonus_type, amount)
            return amount
        endfunction
    endlibrary
 

Code (vJASS):

library NewBonusUtils requires NewBonus, RegisterPlayerUnitEvent
    /* ----------------------- NewBonusUtils Expanded v1.9 by Chopinski ----------------------- */
    //! novjass
   Required Library: RegisterPlayerUnitEvent -> https://www.hiveworkshop.com/threads/snippet-registerplayerunitevent.203338/

        API:
        function AddUnitBonusTimed takes unit u, integer bonus_type, real amount, real duration returns nothing
            -> Add the specified amount for the specified bonus type for unit for a duration
            -> Example: call AddUnitBonusTimed(GetTriggerUnit(), BONUS_ARMOR, 13, 10.5)

        function LinkBonusToBuff takes unit u, integer bonus_type, real amount, integer buffId returns nothing
            -> Links the bonus amount specified to a buff or ability. As long as the unit has the buff or
            -> the ability represented by the parameter buffId the bonus is not removed.
            -> Example: call LinkBonusToBuff(GetTriggerUnit(), BONUS_ARMOR, 10, 'B000')
        function LinkBonusToItem takes unit u, integer bonus_type, real amount, item i returns nothing
            -> Links the bonus amount specified to an item. As long as the unit has that item the bonus is not removed.
            -> Note that it will work for items with the same id, because it takes as parameter the item object.
            -> Example: call LinkBonusToItem(GetManipulatingUnit(), BONUS_ARMOR, 10, GetManipulatedItem())

        function UnitCopyBonuses takes unit source, unit target returns nothing
            -> Copy the source unit bonuses using the Add functionality to the target unit
            -> Example: call UnitCopyBonuses(GetTriggerUnit(), GetSummonedUnit())

        function UnitMirrorBonuses takes unit source, unit target returns nothing
            -> Copy the source unit bonuses using the Set functionality to the target unit
            -> Example: call UnitMirrorBonuses(GetTriggerUnit(), GetSummonedUnit())
    //! endnovjass
    /* ----------------------------------- END ---------------------------------- */
    private struct NewBonusUtils extends NewBonus
        static timer t = CreateTimer()

        //Dynamic Indexing for buff and timed
        static integer didx = -1
        static thistype array data

        //Dynamic Indexing for items
        static integer ditem = -1
        static thistype array items

        unit    u
        item    i
        real    ticks
        integer bonus_type
        integer buffId // Works for abilities too.
        integer int_amount
        real    real_amount
        boolean link //true -> Timed bonus / false -> Linked to a buff

        method destroyInstance takes integer i, boolean isItem returns integer
            if this.bonus_type < 10 then
                call AddUnitBonus(this.u, this.bonus_type, -this.int_amount)
            else
                if this.bonus_type == BONUS_COOLDOWN_REDUCTION then
                    call UnitRemoveCooldownReduction(this.u, this.real_amount)
                else
                    call AddUnitBonusReal(this.u, this.bonus_type, -this.real_amount)
                endif
            endif

            if isItem then
                set  items[i] = items[ditem]
                set  ditem     = ditem - 1
            else
                set  data[i] = data[didx]
                set  didx    = didx - 1

                if didx == -1 then
                    call PauseTimer(t)
                endif
            endif

            set  this.u = null
            set  this.i = null
            call this.deallocate()

            return i - 1
        endmethod

        static method OnDrop takes nothing returns nothing
            local item     itm = GetManipulatedItem()
            local integer  i = 0
            local thistype this

            loop
                exitwhen i > ditem
                    set this = items[i]

                    if this.i == itm then
                        set i = this.destroyInstance(i, true)
                    endif
                set i = i + 1
            endloop
        endmethod
   
        static method OnPeriod takes nothing returns nothing
            local integer  i = 0
            local thistype this

            loop
                exitwhen i > didx
                    set this = data[i]

                    if this.link then // Timed link
                        set this.ticks = this.ticks - 1

                        if this.ticks <= 0 then
                            set i = this.destroyInstance(i, false)
                        endif
                    else // Buff Link
                        if GetUnitAbilityLevel(this.u, this.buffId) == 0 then
                            set i = this.destroyInstance(i, false)
                        endif
                    endif
                set i = i + 1
            endloop
        endmethod

        static method TimeLink takes unit u, integer bonus_type, real amount, real duration, boolean link returns nothing
            local thistype this = thistype.allocate()

            set this.u          = u
            set this.bonus_type = bonus_type
            set this.ticks      = duration/0.03125000
            set this.link       = link
            set didx            = didx + 1
            set data[didx]      = this

            if bonus_type < 10 then
                set this.int_amount = AddUnitBonus(u, bonus_type, R2I(amount))
            else
                set this.real_amount = AddUnitBonusReal(u, bonus_type, amount)
            endif
       
            if didx == 0 then
                call TimerStart(t, 0.03125000, true, function thistype.OnPeriod)
            endif
        endmethod

        static method BuffLink takes unit u, integer bonus_type, real amount, integer buffId, boolean link returns nothing
            local thistype this = thistype.allocate()

            set this.u          = u
            set this.bonus_type = bonus_type
            set this.buffId     = buffId
            set this.link       = link
            set didx            = didx + 1
            set data[didx]      = this

            if bonus_type < 10 then
                set this.int_amount = AddUnitBonus(u, bonus_type, R2I(amount))
            else
                set this.real_amount = AddUnitBonusReal(u, bonus_type, amount)
            endif
       
            if didx == 0 then
                call TimerStart(t, 0.03125000, true, function thistype.OnPeriod)
            endif
        endmethod

        static method ItemLink takes unit u, integer bonus_type, real amount, item i returns nothing
            local thistype this = thistype.allocate()

            set this.u          = u
            set this.i          = i
            set this.bonus_type = bonus_type
            set ditem           = ditem + 1
            set items[ditem]    = this
       
            if bonus_type < 10 then
                set this.int_amount = AddUnitBonus(u, bonus_type, R2I(amount))
            else
                set this.real_amount = AddUnitBonusReal(u, bonus_type, amount)
            endif
        endmethod

        static method CopyBonuses takes unit source, unit target returns nothing
            local integer i = 1

            loop
                exitwhen i > 24
                    if i < 10 then
                        if GetUnitBonus(source, i) != 0 then
                            call AddUnitBonus(target, i, GetUnitBonus(source, i))
                        endif
                    else
                        if GetUnitBonusReal(source, i) != 0 then
                            call AddUnitBonusReal(target, i, GetUnitBonusReal(source, i))
                        endif
                    endif
                set i = i + 1
            endloop
        endmethod

        static method MirrorBonuses takes unit source, unit target returns nothing
            local integer i = 1

            loop
                exitwhen i > 24
                    if i < 10 then
                        call SetUnitBonus(target, i, GetUnitBonus(source, i))
                    else
                        call SetUnitBonusReal(target, i, GetUnitBonusReal(source, i))
                    endif
                set i = i + 1
            endloop
        endmethod

        static method onInit takes nothing returns nothing
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DROP_ITEM, function thistype.OnDrop)
        endmethod
    endstruct

    /* -------------------------------------------------------------------------- */
    /*                               JASS Public API                              */
    /* -------------------------------------------------------------------------- */

    function AddUnitBonusTimed takes unit u, integer bonus_type, real amount, real duration returns nothing
        call NewBonusUtils.TimeLink(u, bonus_type, amount, duration, true)
    endfunction

    function LinkBonusToBuff takes unit u, integer bonus_type, real amount, integer buffId returns nothing
        call NewBonusUtils.BuffLink(u, bonus_type, amount, buffId, false)
    endfunction

    function LinkBonusToItem takes unit u, integer bonus_type, real amount, item i returns nothing
        call NewBonusUtils.ItemLink(u, bonus_type, amount, i)
    endfunction

    function UnitCopyBonuses takes unit source, unit target returns nothing
        call NewBonusUtils.CopyBonuses(source, target)
    endfunction

    function UnitMirrorBonuses takes unit source, unit target returns nothing
        call NewBonusUtils.MirrorBonuses(source, target)
    endfunction
endlibrary

 
Important*
Bonus Health and Bonus Mana are not working currently. This is not the system fault, but the health abilities present in Warcraft instead. This is because changing the abilities health and mana values and updating it via Inc and Dec Ability Level is not making the unit get the bonusses. This is probably a bug in the Object API, so I'll leave both bonusses implemented, and if Blizzard ever decides to fix it then they will work properly.

Changelog
(v1.0)
  • Submission
(v1.1)
  • Updated the code to use BlzSetUnitMaxHP() and BlzSetUnitMaxMana() in order to make Bonus_Health and Bonus_Mana work properly.
(v1.2)
  • Implemented the ability to link a bonus amount to a buff or ability as per requested by @The_Silent . Refactored the code and added a new example of this new functionality in the test map.
(v1.3)
  • FIxed a bug on AddUnitBonusExTimed()
(v1.4)
  • Normalized the AMOUNT input parameter to Integer instead of real to fix a type conversion problem when converting real to integer for abilities which field value is a integer value.
(v1.5)
  • Updated the system to respect integer fields bounds when adding to existing bonus (max 2147483647 and min -2147483648).
  • It's still the users job to pass the correct amount, the system will only handle addtions and subtractions that overflow/underflow.
(v1.6)
  • Split NewBonus into 2 libraries
    • NewBonus contains the core system to set / remove / add bonus types
    • NewBonusUtils contains extra functionalities such as timed and linked bonuses
  • Redesigned timed and linked bonuses to improve performance.
  • New utility functions AddUnitBonusTimed(), LinkBonusToBuff(), LinkBonusToItem()
  • Renamed Constans to upper case to be more visible.
  • Updated test map: included examples for the 3 new utility functions.
(v1.7)
  • Fixed a bug when Adding Health/Mana bonus not keeping the unit Health/Mana Percentage
  • Added the funcitons: They manipuilate real bonuses values correctly.
    • GetUnitBonusReal()
    • SetUnitBonusReal()
    • RemoveUnitBonusReal()
    • AddUnitBonusReal()
  • Refactored the LinkBonusToItem() to use the On Drop event instead of a periodic timer to check the link
  • Included an Expanded version of NewBonus and NewBonusUtils that take advangtage of the Damage Inteface System and Cooldown Reduction System
  • Renamed 4 bonus types for better readability.
  • Removed the "Ex" from the end of the API functions
(v1.8)
  • 2 new bonus types:
    • Sight Range
    • Magic Resistence (real)
  • 2 new functionalities in the NewBonusUtils (See API for usage): Thx to SinisterLuffy for the idea
    • function UnitCopyBonuses takes unit source, unit target returns nothing
    • function UnitMirrorBonuses takes unit source, unit target returns nothing
(v1.9)
  • Correction of a minor spelling error.
(v2.0)
  • Fixed a minor syntax error for the non extended Utils library

For those with problems to open the map because of Reforged 1.32 patch, please see this
Contents

New Bonus v2.0 (Map)

Reviews
MyPad
[spoiler] [spoiler] Considering the test map alone, I would approve this system. However, certain things addressed in the Code section of the review would need to be resolved before approval. Hence, this has been moved to Awaiting Update.
  1. SinisterLuffy

    SinisterLuffy

    Joined:
    Apr 8, 2020
    Messages:
    35
    Resources:
    0
    Resources:
    0
    For bonus health and mana, you could use the new natives that manipulate max health and mana instead of using abilities.

    Which patch did you work on? My 1.31.1 world editor cannot open the test map. Level info missing comes up as an error.
     
  2. chopinski

    chopinski

    Joined:
    May 16, 2012
    Messages:
    379
    Resources:
    3
    Spells:
    3
    Resources:
    3
    I know about the new natives, and i think there is no point into using them in the system, it would create more code just to keep track of the amount, and jassers can use the natives directly. I'm still thinking on using it, just so the the system is complete. I'm on the latest reforged patch and created the map using the new editor. The file format is w3m. I'll try to save it as w3x.

    Edit 1: Map format updated.
    Edit 2: 2 more lines of code to make Health and Mana works as intended.
     
    Last edited: Apr 16, 2020
  3. SinisterLuffy

    SinisterLuffy

    Joined:
    Apr 8, 2020
    Messages:
    35
    Resources:
    0
    Resources:
    0
    Copying nine abilities is still a bit cumbersome, especially for maps already in development. If only it were possible to copy multiple objects at once, then it would be less tedious of a process.

    I find JNGP Lua Edition still operable even in Reforged because the findpath.lua file has been modified to be simpler. Replacing that file in any version of JNGP of your choice with the one in Lua Edition's makes that JNGP usable. The Object Merger can then be utilized to make installing this system smoother.
     
  4. disruptive_

    disruptive_

    Joined:
    Mar 19, 2017
    Messages:
    211
    Resources:
    0
    Resources:
    0
    A potential good system, but i'm pretty sure the ability field modifiers don't work with item abilities (ej. item damage bonus ability that maybe you are using for bonus damage effect) at least in 1.31. This was my experience trying to code a bonus system and failing because of that.
    Maybe such functionality works in 1.32+?
     
  5. chopinski

    chopinski

    Joined:
    May 16, 2012
    Messages:
    379
    Resources:
    3
    Spells:
    3
    Resources:
    3
    I tested all the bonusses, they work fine, and quite a few of them are from item abilities. I think what you experienced is indeed a bug that occurs when you change the field value of an ability and dont increase and decrease its level to update it.. You can download the map and see for yourself.
     
  6. The_Silent

    The_Silent

    Joined:
    Feb 4, 2008
    Messages:
    3,037
    Resources:
    164
    Models:
    53
    Icons:
    90
    Packs:
    8
    Skins:
    12
    Maps:
    1
    Resources:
    164
    Looks great.

    This might not be worth the effort, but would you consider adding a version of
    AddUnitBonus
    that is tied to a buff integer code. So it lasts as long as the unit has that specific buff? Would be extremely useful for spells.
     
  7. chopinski

    chopinski

    Joined:
    May 16, 2012
    Messages:
    379
    Resources:
    3
    Spells:
    3
    Resources:
    3
    I will try, but can you give me an example, because there is multiple ways i could interpret that. I mean give the parameters that you were thinking and i will work from it.

    Edit 1: Request Implemented.
     
    Last edited: Apr 18, 2020
  8. The_Silent

    The_Silent

    Joined:
    Feb 4, 2008
    Messages:
    3,037
    Resources:
    164
    Models:
    53
    Icons:
    90
    Packs:
    8
    Skins:
    12
    Maps:
    1
    Resources:
    164
    Say the function looks like this:
    call AddUnitBonusExBuff(unit whichUnit, integer bonus_type, real amount, integer buffid)

    And it checks evey 0.04 second if the unit still has the buff. If it does not, the bonus ends.

    Say you want the Frenzy ability to give a +10 agility bonus.

    • Untitled Trigger 001
      • Events
        • Unit - A unit Starts the effect of an ability
      • Conditions
        • (Ability being cast) Equal to Frenzy
      • Actions
        • Custom script: call AddUnitBonusExBuff(GetTriggerUnit(), Bonus_Agility, 10, 'Bfzy')


    So it just automatically handles removing the bonus again once the buff have expired or been dispelled. Dispelled is probably the most important aspect here, since
    AddUnitBonusExTimed
    would work otherwise. (Or it might be a channeled spell, etc.)
     
  9. chopinski

    chopinski

    Joined:
    May 16, 2012
    Messages:
    379
    Resources:
    3
    Spells:
    3
    Resources:
    3
    Ok, i'm on it!
     
  10. IcemanBo

    IcemanBo

    Joined:
    Sep 6, 2013
    Messages:
    6,515
    Resources:
    22
    Maps:
    3
    Spells:
    11
    Template:
    1
    Tutorials:
    4
    JASS:
    3
    Resources:
    22
    Such functionality that only bases on the system should probably be be a new library, like a helper or tools library. Because otherwise it might bloat the core system. Some other user might want to use not only buffs, but maybe also items, too, when a unit owns/drops one item of one type... and so forth.
     
  11. chopinski

    chopinski

    Joined:
    May 16, 2012
    Messages:
    379
    Resources:
    3
    Spells:
    3
    Resources:
    3
    For items the events of on pickup and drop could be used with the normal functions. For buffs and abilities only one new function is enough since both are checked using GetUnitAbilityLevel > 0
     
  12. MyPad

    MyPad

    Spell Reviewer

    Joined:
    May 9, 2014
    Messages:
    1,465
    Resources:
    8
    Models:
    1
    Icons:
    2
    Maps:
    1
    Spells:
    3
    JASS:
    1
    Resources:
    8
    The code is easily understandable, as well as being well-documented, and exceptionally clean. The only drawback is the inclusion of functions that are best suited in another library (something like BonusHelper). The functions in question are the following:

    Code (vJASS):

    function AddUnitBonusExTimed
    function AddUnitBonusLinked
     


    A minor gripe with this is how the constants are cased. They should be capitalized to help the user identify them as constants.

    The test map best demonstrates the capabilities of this system. With the ability to print out information at will, as well as manipulate the bonuses easily at run-time, this will leave no doubt of the system's performance to the end-user.

    Considering the test map alone, I would approve this system. However, certain things addressed in the Code section of the review would need to be resolved before approval. Hence, this has been moved to Awaiting Update.
     
  13. chopinski

    chopinski

    Joined:
    May 16, 2012
    Messages:
    379
    Resources:
    3
    Spells:
    3
    Resources:
    3
    System Updated as required.
     
  14. JAKEZINC

    JAKEZINC

    Joined:
    Aug 13, 2013
    Messages:
    1,592
    Resources:
    9
    Spells:
    9
    Resources:
    9
    Just a minor thing, update its patch requirement. This only works on 1.31+, 1.30 don't have that kind of runtime natives :)
     
  15. chopinski

    chopinski

    Joined:
    May 16, 2012
    Messages:
    379
    Resources:
    3
    Spells:
    3
    Resources:
    3
    Ok, Thx!

    Done.
     
  16. Uncle

    Uncle

    Joined:
    Aug 10, 2018
    Messages:
    1,832
    Resources:
    0
    Resources:
    0
    Great system, good work. But how does one go about adding Real values? Such as adding 0.25 HP Regen or something.
     
  17. The_Silent

    The_Silent

    Joined:
    Feb 4, 2008
    Messages:
    3,037
    Resources:
    164
    Models:
    53
    Icons:
    90
    Packs:
    8
    Skins:
    12
    Maps:
    1
    Resources:
    164
    Yeah, I have the same issue, want to give a unit a +15% attack rate bonus (0.15).
     
  18. chopinski

    chopinski

    Joined:
    May 16, 2012
    Messages:
    379
    Resources:
    3
    Spells:
    3
    Resources:
    3
    Initially the amount parameter was a real, but i had to change that in version 1.4 because of a issue with converting reals to integers. I noticed that the conversion back and forth was returning different values, resulting in differences in a bonus operation.

    You still can do that @The_Silent you just need to call UnitAddBonusEx(u, BONUS_ATTACKSPEED, 15). If you see the code, internally for attack speed bonus it multiply the amount by 0.01 to be passed as parameter for the functions that manipulates the ability field and multiply by 100 when returning it. Attack Speed bonus take that advantage.

    I will try to think of a solution for the real parameter case, but for now I'll keep the more stable version on.
     
  19. Uncle

    Uncle

    Joined:
    Aug 10, 2018
    Messages:
    1,832
    Resources:
    0
    Resources:
    0
    Found an issue, when adding Health to a unit, it's maximum health is increased but it's current health stays the same value. It's not updating the percentage of health.

    In other words, a unit with 100 hp that is given +50 health goes from 100/100 hp to 100/150 hp.