• Check out the results of the Techtree Contest #19!
  • Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.
  • Create a void inspired texture for Warcraft 3 and enter Hive's 34th Texturing Contest: Void! Click here to enter!
  • The Hive's 22nd Icon Contest: Creep Abilities is now concluded, time to vote for your favourite set of icons! Click here to vote!

ExtendableBonusSystem

This bundle is marked as pending. It has not been reviewed by a staff member yet.
What is this system?
Inspired by chopinski New Bonus system, I wanted a system that you can add your own bonuses using a simple coding interface. Hopefully the interface will be simple so it is easy to implement but also this means that the core can upgrade without impacting the extensions! (hopefully)

Inspired by: chopinski New Bonus system
(Warning: this "clashes" with New Bonus System!, this was designed for my map that previously used it!)

Adding your own custom stat (such as "Armor Penetration", or "Drop health globes from Diablo 3") can be done without modifying internals of the system.
You need to write a small amount of code to register it to the system, and then of course trigger "what should happen", using said stat.

Comes with basic stats (Damage, Armor, Attack Speed, etc.)

Used in The Defence of The Castle since 2022-04-06 and been tested since.

That map uses for basics, spell haste (LoL style), Spell Power, Life on Hit, Armor Penetration ("flat amount" and %), Health Globes on monster kill drop chance along with many other things.
Since many of them are map specific and added as you go, it's good to have an extendable system!

How to import:
  • Requirements (included in RequiredLibraries in the test map)
  • Copy-paste folder from ExtendableBonusSystem in test map or the code from below.
  • (Optional!) Copy-paste (or setup manually) abilities for the basic bonuses
    • This is just used by the "ExtendableBonusSystemBasicStats", just a collection of "plugins" for this system to handle basic stats
    • Copy paste abilities in Abilities -> Custom Abilities -> Neutral Hostile -> Items
      • Note that their ids must match what's in the code found in: ExtendableBonusSystemBasicStats-file
    • Use them!
  • (Optional!) Do same for ExtendableBonusAdditional
    • Copy-paste relevant abilities with correct IDs, or setup abilities manually and set their ids in the code, similar to the basics.
  • (Optional!) Setup you own stats! See "HandleCustomStats". You can add "Life-on-hit", "Spell vamp", etc. as bonuses, and then make a trigger that uses the values. See example of 2 stats being added, one backed by an array accessed directly and one backed by table accessed by the systems functions.

Without bonuses (plugins) this system does nothing except for clashing with chopiniskis new bonus system!

Release Notes:
2021-10-23 - Version 0.1:
2025-07-18 - Version 0.1.1:
  • Published as a system.
  • Trackes values as data in tables for heroes, making it behave as expected if dying with timed bonuses, or bonuses bound by buffs.
    • If you died with temporary bonus, said bonus would not be "cleared" when revived.
  • Now keeps an internal table for bonuses.
  • "Set"-function no longer returns real
2025-09-21 - Updated "Test map"
  • No change to the system
  • Imported DamageEngine and a few more systems to make better demo
  • Added my "Life on Hit" system and a few of my "Utils".
  • Added items that have unique effects and differences between melee and ranged heroes

This manages it all, stores values etc.
JASS:
library ExtendableBonusSystem requires Table
    /* ----------------------- ExtendableBonusSystem v0.1.1 by ThompZon ----------------------- */
    //! novjass
        Inspired by chopinski New Bonus system, I wanted a system that you can add your own bonuses
        using a simple interface. Hopefully the interface will be simple so it is easy to implement
        but also this means that the core can upgrade without impacting the extensions!
        Inspired by: chopinski New Bonus system
        https://www.hiveworkshop.com/threads/new-bonus-vjass-lua.324058/
        Requires: Table
        https://www.hiveworkshop.com/threads/lua-vjass-new-table.188084/
        jassApi
    //! endnovjass
    /* -------------------------------------------------------------------------- */
    /*                                   System                                   */
    /* --------------------------------------------------------------------------
    */
    globals
        //This stores ability-backed bonuses for heroes and
        Table bonusTable
    endglobals
    public interface ExtendableBonusPlugin
        method IsIntegerBonus takes nothing returns boolean defaults false
        method Get takes unit u returns real
        method Set takes unit u, real value returns nothing
    endinterface
  
    //Simple bonuses that just want to store a value can be stored here!
    struct TableBonus extends ExtendableBonusPlugin
        method Set takes unit u, real value returns nothing
            call bonusTable.link(GetUnitUserData(u)).real.save(getType(), value)
        endmethod
        method Get takes unit u returns real
            local integer index = GetUnitUserData(u)
            if bonusTable.has(index) then
                return bonusTable[index].real[getType()]
            endif
            return 0.0
        endmethod
    endstruct
    struct RealAbilityBonus extends ExtendableBonusPlugin
        stub method AbilityCode takes nothing returns integer
            call BJDebugMsg("RealAbilityBonus missing AbilityCode!")
            return -1
        endmethod
        stub method Field takes nothing returns abilityreallevelfield
            call BJDebugMsg("RealAbilityBonus missing Field!")
            return null
        endmethod
        method Set takes unit u, real value returns nothing
            local integer abilCode = AbilityCode()
            if GetUnitAbilityLevel(u, abilCode) == 0 then
                call UnitAddAbility(u, abilCode)
                call UnitMakeAbilityPermanent(u, true, abilCode)
                if IsUnitType(u, UNIT_TYPE_HERO) then
                    call bonusTable.link(GetUnitUserData(u)).real.save(getType(), value)
                endif
            endif
            if IsUnitType(u, UNIT_TYPE_HERO) then
                call bonusTable[GetUnitUserData(u)].real.save(getType(), value)
                call BlzSetAbilityRealLevelField(BlzGetUnitAbility(u, abilCode), Field(), 0, value)
            else
                call BlzSetAbilityRealLevelField(BlzGetUnitAbility(u, abilCode), Field(), 0, value)
            endif
            call IncUnitAbilityLevel(u, abilCode)
            call DecUnitAbilityLevel(u, abilCode)
        endmethod
        method Get takes unit u returns real
            local integer index = GetUnitUserData(u)
            if IsUnitType(u, UNIT_TYPE_HERO) then
                if bonusTable.has(index) then
                    return bonusTable[index].real[getType()]
                endif
                return 0.0
            endif
            return BlzGetAbilityRealLevelField(BlzGetUnitAbility(u, AbilityCode()), Field(), 0)
        endmethod
    endstruct
    struct IntegerAbilityBonus extends ExtendableBonusPlugin
        stub method AbilityCode takes nothing returns integer
            call BJDebugMsg("IntegerAbilityBonus missing AbilityCode!")
            return -1
        endmethod
        stub method Field takes nothing returns abilityintegerlevelfield
            call BJDebugMsg("IntegerAbilityBonus missing Field!")
            return null
        endmethod
        method Set takes unit u, real value returns nothing
            local integer abilCode = AbilityCode()
            if GetUnitAbilityLevel(u, abilCode) == 0 then
                call UnitAddAbility(u, abilCode)
                call UnitMakeAbilityPermanent(u, true, abilCode)
                if IsUnitType(u, UNIT_TYPE_HERO) then
                    call bonusTable.link(GetUnitUserData(u)).integer.save(getType(), R2I(value))
                endif
            endif
            if IsUnitType(u, UNIT_TYPE_HERO) then
                call bonusTable[GetUnitUserData(u)].integer.save(getType(), R2I(value))
                call BlzSetAbilityIntegerLevelField(BlzGetUnitAbility(u, abilCode), Field(), 0, R2I(value))
            else
                call BlzSetAbilityIntegerLevelField(BlzGetUnitAbility(u, abilCode), Field(), 0, R2I(value))
            endif
            call IncUnitAbilityLevel(u, abilCode)
            call DecUnitAbilityLevel(u, abilCode)
        endmethod
        method Get takes unit u returns real
            local integer index = GetUnitUserData(u)
            if IsUnitType(u, UNIT_TYPE_HERO) then
                if bonusTable.has(index) then
                    return I2R(bonusTable[index].integer[getType()])
                endif
                return 0.0
            endif
            return I2R(BlzGetAbilityIntegerLevelField(BlzGetUnitAbility(u, AbilityCode()), Field(), 0))
        endmethod
        method IsIntegerBonus takes nothing returns boolean
            return true
        endmethod
    endstruct
    struct ExtendableBonus
        private static ExtendableBonusPlugin array registeredBonuses
        //private static integer maxTypeId = -1
        static method Register takes ExtendableBonusPlugin bonus returns integer
            set registeredBonuses[bonus.getType()] = bonus
            //set maxTypeId = IMaxBJ(maxTypeId, bonus.getType())
            //call BJDebugMsg("registedTypeId=" + I2S(bonus.getType()) + ", bonus=" + I2S(bonus))
            return bonus.getType()
        endmethod
        static method GetBonus takes integer typeId returns ExtendableBonusPlugin
            return registeredBonuses[typeId]
        endmethod
        static method Get takes unit u, integer typeId returns real
            if (registeredBonuses[typeId] == 0) then
                call BJDebugMsg("type is not registered! id=" + I2S(typeId))
                return -1.0
            else
                return registeredBonuses[typeId].Get(u)
            endif
        endmethod
        static method Set takes unit u, integer typeId, real value returns nothing
            if (registeredBonuses[typeId] == 0) then
                call BJDebugMsg("type is not registered! id=" + I2S(typeId))
            else
                //call BJDebugMsg("Setting type=" + I2S(typeId) + " to " + R2S(value))
                call registeredBonuses[typeId].Set(u, value)
            endif
        endmethod
        static method Add takes unit u, integer typeId, real value returns nothing
            local ExtendableBonusPlugin currentBonus = GetBonus(typeId)
            local real addedValue
            if currentBonus.IsIntegerBonus() then
                set addedValue = R2I(value)
            else
                set addedValue = value
            endif
            call Set(u, typeId, currentBonus.Get(u) + addedValue)
        endmethod
        static method onInit takes nothing returns nothing
            //You are not supposed to do this, but I want to allow struct on-init to use the BonusTable to set themselves up (it's easier than having 1 "centralized")
            set bonusTable = Table.create()
        endmethod
    endstruct
    function GetUnitBonus takes unit u, integer typeId returns real
        return ExtendableBonus.Get(u, typeId)
    endfunction
    function SetUnitBonus takes unit u, integer typeId, real value returns nothing
        call ExtendableBonus.Set(u, typeId, value)
    endfunction
    function AddUnitBonus takes unit u, integer typeId, real value returns nothing
        call ExtendableBonus.Add(u, typeId, value)
    endfunction
    function RemoveUnitBonus takes unit u, integer typeId returns nothing
        call ExtendableBonus.Set(u, typeId, 0)
    endfunction
    function PurgeAllUnitBonus takes unit u returns nothing
        //TODO - remove bonuses from bonusTable
    endfunction
endlibrary

Utils to bind bonuses to timer, item, buff, etc. This system can be used without this component!
JASS:
library NewBonusUtils requires ExtendableBonusSystem, RegisterPlayerUnitEvent
    /* ------------------- ExtendableBonusUtils v0.1.1 by ThompZon ------------------- */
    /* ----------------------- NewBonusUtils v2.2 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 ---------------------------------- */
  
    /* -------------------------------------------------------------------------- */
    /*                                   System                                   */
    /* --------------------------------------------------------------------------
    */
    private struct NewBonusUtils
        static timer timer = CreateTimer()
        static integer key = -1
        static thistype array array
      
        static integer k = -1
        static thistype array items
        unit    unit
        item    item
        real    ticks
        integer type
        integer buff
        real    amount
        boolean link
        method remove takes integer i, boolean isItem returns integer
            call AddUnitBonus(unit, type, -amount)
            if isItem then
                set items[i] = items[k]
                set k = k - 1
            else
                set array[i] = array[key]
                set key = key - 1
                if key == -1 then
                    call PauseTimer(timer)
                endif
            endif
            set unit = null
            set item = null
          
            call deallocate()
            return i - 1
        endmethod
        static method removeBonusTypeForItem takes item itm, integer bonusToRemove returns nothing
            local integer i = 0
            local thistype this
            loop
                exitwhen i > k
                    set this = items[i]
                    if item == itm and type == bonusToRemove then
                        set i = remove(i, true)
                    endif
                set i = i + 1
            endloop
        endmethod
        static method onDrop takes nothing returns nothing
            local item itm = GetManipulatedItem()
            local integer i = 0
            local thistype this
            loop
                exitwhen i > k
                    set this = items[i]
                    if item == itm then
                        set i = remove(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 > key
                    set this = array[i]
                    if link then
                        set ticks = ticks - 1
                        if ticks <= 0 then
                            set i = remove(i, false)
                        endif
                    else
                        if GetUnitAbilityLevel(unit, buff) == 0 then
                            set i = remove(i, false)
                        endif
                    endif
                set i = i + 1
            endloop
        endmethod
        static method linkTimed takes unit u, integer bonus_type, real amount, real duration, boolean link returns nothing
            local thistype this = thistype.allocate()
            set this.unit = u
            set this.type = bonus_type
            set this.ticks = duration/0.03125000
            set this.link = link
            set this.amount = amount
            call AddUnitBonus(u, bonus_type, this.amount)
            set key = key + 1
            set array[key] = this
       
            if key == 0 then
                call TimerStart(timer, 0.03125000, true, function thistype.onPeriod)
            endif
        endmethod
        static method linkBuff takes unit u, integer bonus_type, real amount, integer buffId, boolean link returns nothing
            local thistype this = thistype.allocate()
            set this.unit = u
            set this.type = bonus_type
            set this.buff = buffId
            set this.link = link
            set this.amount = amount
            call AddUnitBonus(u, bonus_type, this.amount)
            set key = key + 1
            set array[key] = this
       
            if key == 0 then
                call TimerStart(timer, 0.03125000, true, function thistype.onPeriod)
            endif
        endmethod
        static method linkItem takes unit u, integer bonus_type, real amount, item i returns nothing
            local thistype this = thistype.allocate()
            set this.unit = u
            set this.item = i
            set this.type = bonus_type
            set this.amount = amount
            call AddUnitBonus(u, bonus_type, this.amount)
            set k = k + 1
            set items[k] = this
        endmethod
        static method copy takes unit source, unit target returns nothing
            local integer i = 1
            loop
                exitwhen i > 17
                    if GetUnitBonus(source, i) != 0 then
                        call AddUnitBonus(target, i, GetUnitBonus(source, i))
                    endif
                set i = i + 1
            endloop
        endmethod
        static method mirror takes unit source, unit target returns nothing
            local integer i = 1
            loop
                exitwhen i > 17
                    call SetUnitBonus(target, i, GetUnitBonus(source, i))
                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 API                                  */
    /* --------------------------------------------------------------------------
    */
    function AddUnitBonusTimed takes unit u, integer bonus_type, real amount, real duration returns nothing
        call NewBonusUtils.linkTimed(u, bonus_type, amount, duration, true)
    endfunction
    function LinkBonusToBuff takes unit u, integer bonus_type, real amount, integer buffId returns nothing
        call NewBonusUtils.linkBuff(u, bonus_type, amount, buffId, false)
    endfunction
    function LinkBonusToItem takes unit u, integer bonus_type, real amount, item i returns nothing
        call NewBonusUtils.linkItem(u, bonus_type, amount, i)
    endfunction
    function RemoveSpecificBonusFromItem takes item i, integer bonus_type returns nothing
        call NewBonusUtils.removeBonusTypeForItem(i, bonus_type)
    endfunction
    function UnitCopyBonuses takes unit source, unit target returns nothing
        call NewBonusUtils.copy(source, target)
    endfunction
    function UnitMirrorBonuses takes unit source, unit target returns nothing
        call NewBonusUtils.mirror(source, target)
    endfunction
endlibrary

JASS:
library ExtendableBonusesCustom requires ExtendableBonusSystem, Table
    struct BonusCustomStatArrayBacked extends ExtendableBonusSystem_ExtendableBonusPlugin
        method Get takes unit u returns real
            return udg_CustomStat[GetUnitUserData(u)]
        endmethod
        method Set takes unit u, real value returns nothing
            set udg_CustomStat[GetUnitUserData(u)] = value
        endmethod
        static method onInit takes nothing returns nothing
            call ExtendableBonus.Register(thistype.allocate())
        endmethod
    endstruct
  
    struct BonusCustomStatTableBacked extends ExtendableBonusSystem_ExtendableBonusPlugin
        method Get takes unit u returns real
            return bonusTable[GetUnitUserData(u)].real[thistype.typeid]
        endmethod
        method Set takes unit u, real value returns nothing
            call bonusTable.link(GetUnitUserData(u)).real.save(thistype.typeid, value)
        endmethod
        static method onInit takes nothing returns nothing
            local integer a = ExtendableBonus.Register(thistype.allocate())
        endmethod
    endstruct
endlibrary
  • UseCustomStat
    • Events
      • Unit - A unit enters GainCustomStat <gen>
    • Conditions
    • Actions
      • Set CustomStat[(Custom value of (Triggering unit))] = (CustomStat[(Custom value of (Triggering unit))] + 1.00)
      • Custom script: call AddUnitBonus(GetTriggerUnit(), BonusCustomStatTableBacked.typeid, 1)
      • Custom script: set udg_temp_real = GetUnitBonus(GetTriggerUnit(), BonusCustomStatTableBacked.typeid)
      • Game - Display to (All players) the text: ((Unit: + (Name of (Triggering unit))) + ( has following custom stat: + (((String(CustomStat[(Custom value of (Triggering unit))])) + , ) + (String(temp_real)))))

If you are as insane as me, you can define item bonuses using this system (because some stats must be tracked by a system in order to keep accurate values).
This is how it can look like for: my map (DTC)
JASS:
scope ItemsDefinitions
    globals
        boolean writeBonusesToItemText = false
        boolean isRefreshAction = false
        //BASIC ITEMS (Permanent):
        constant integer AXE_OF_ATTACK = 'I00Q'
        constant integer SWORD_OF_ATTACK = 'I00R'
        constant integer LEATHER_PANTS = 'I00P'
        constant integer SCALE_ARMOR = 'I00M'
        constant integer STRANGE_AMULET = 'I02S'
        constant integer SLIGHTLY_MAGICAL_WAND = 'I02R'
        constant integer BOOTS_OF_SPEED = 'I00H'
        constant integer DAGGER = 'I00G'
        constant integer SHIV_OF_CRITICAL_STABBING = 'I02F'
        constant integer GEM_OF_LIFE = 'I00U'
        constant integer GEM_OF_MANA = 'I00S'
        constant integer REGENERATING_BRANCH = 'I00I'
        constant integer MANA_POACH = 'I00F'
        //Stats
        constant integer TABI_OF_AGILITY = 'I005'
        constant integer CLOAK_OF_AGILITY = 'I00C'
        constant integer CLUB_OF_STRENGTH = 'I004'
        constant integer HAMMER_OF_STRENGTH = 'I00D'
        constant integer WIZARD_HAT_OF_INTELLIGENCE = 'I009'
        constant integer STAFF_OF_INTELLIGENCE = 'I00E'
        constant integer DIADEM_OF_NOBILITY = 'I00A'
        //Consumables (Charged):
        constant integer HEALING_POTION = 'I047'
        constant integer HEALING_SALVE = 'I01Y'
        constant integer MANA_POTION = 'I046'
        constant integer MOON_ORCHID = 'I048'
        constant integer REJUVENATION_POTION = 'I049'
        constant integer STONE_SKIN_POTION = 'I04A'
        //POWER UP
        constant integer EXTRA_LIFE = 'I00K'
        constant integer MEDKIT = 'I01E'
        //ARTIFACTS
        constant integer AMULET_OF_AMPLIFICATION = 'I04Q'
        constant integer AMULET_OF_FIRE = 'I03M'
        constant integer ARCANE_ARMOR_OF_BLASTING = 'I03C'
        constant integer ARCANE_RING_OF_AMILIFICATION = 'I006'
        constant integer ARCANE_RING_OF_AMILIFICATION_OFF = 'I007'
        constant integer ARCANE_STAFF_OF_ENERGY = 'I01A'
        constant integer AXE_OF_THE_BRUTE = 'I04Y'
        constant integer BLACK_NAVAJA = 'I02B'
        constant integer BLOOD_TOOTH = 'I03N'
        constant integer BOOTS_OF_OCCASIONAL_FULMINATION = 'I03K'
        constant integer BOOTS_OF_OCCASIONAL_LIGHTNING = 'I03I'
        constant integer BROOCH_OF_AGILE_SWIFTNESS = 'I026'
        constant integer BROOCH_OF_FORCEFUL_SWIFTNESS = 'I025'
        constant integer BROOCH_OF_INSIGHTFUL_SWIFTNESS = 'I027'
        constant integer BROOCH_OF_SWIFTNESS = 'I01Q'
        constant integer CLEAVING_AXE = 'I00N'
        constant integer CRITICAL_DEATH_MASK = 'I02N'
        constant integer CRITICAL_SLICER = 'I02L'
        constant integer CUP_OF_BLOOD = 'I03E'
        constant integer DAGGER_OF_FAST_STABBING = 'I014'
        constant integer DARK_BLADE_OF_SOUL_REAPING = 'I042'
        constant integer DEATH_DEALER = 'I018'
        constant integer DEATH_DIRK_OF_BLOOD = 'I03U'
        constant integer DRAGON_STAFF_OF_FLAMES = 'I03Y'
        constant integer ENT_BARK_SHIELD = 'I01H'
        constant integer ENDLESS_ELIXIR_HEALING = 'I00J'
        constant integer ENDLESS_ELIXIR_MANA = 'I02D'
        constant integer FLAMING_PAULDRONS_OF_RADIANT_HEAT = 'I016'
        constant integer FROZEN_SKULL_OF_NOVA = 'I038'
        constant integer GNARLT_STINGER_OF_ACUTE_TOXICITY = 'I04B'
        constant integer GOBLET_OF_FIRE = 'I01U'
        constant integer GOLDEN_GOBLET_OF_GORE = 'I03G'
        constant integer GOLDEN_SHIELD_OF_AEGIS = 'I03W'
        constant integer HEAVY_PLATE_ARMOR = 'I00X'
        constant integer HEAVY_SHIELD_OF_STRENGTH = 'I015'
        constant integer INCONVENIENTLY_HEAVY_SHIELD = 'I02X'
        constant integer INFINITE_VIAL_HEALING = 'I00B'
        constant integer INFINITE_VIAL_MANA = 'I01V'
        constant integer LIFE_STAFF = 'I03Q'
        constant integer MANA_STEEL_SWORD = 'I04H'
        constant integer MAGE_ARMOR = 'I03A'
        constant integer MAGE_BLADE = 'I01P'
        constant integer MAGE_BLADE_OFF = 'I01Z'
        constant integer MAGI_SWORD = 'I020'
        constant integer MAGI_SWORD_OFF = 'I01W'
        constant integer MAGICAL_AMULET = 'I030'
        constant integer MAGICAL_DAGGER = 'I03Z'
        constant integer MANAFLOWIFICATOR = 'I032'
        constant integer MAUL_OF_FORCEFUL_IMPACT = 'I011'
        constant integer MAUL_OF_TREMENDOUS_IMPACT = 'I022'
        constant integer MERCURIAL_SCIMITAR_OF_INFINITE_SHARPNESS = 'I044'
        constant integer MIGHTY_SKULL_OF_INSIGHT = 'I000'
        constant integer MECHANICAL_DEVICE_OF_CONVINSING_CLONING = 'I04T'
        constant integer OBSERVING_STAFF_OF_THE_GREAT_EYE = 'I04P'
        constant integer OMNI_GEM = 'I04V'
        constant integer PHOENIX_AXE = 'I00L'
        constant integer POWER_HAMMER_OF_FABRICATION = 'I04N'      
        constant integer REACTIVE_ARMOR_OF_ARCANE_REPULSION = 'I04D'
        constant integer RING_OF_LIFE = 'I01M'
        constant integer RING_OF_MANA = 'I01L'
        constant integer RING_OF_POWER = 'I01O'
        constant integer SMALL_SHIELD = 'I02P'
        constant integer SPIKED_PLATE_OF_VENGEANCE = 'I03S'
        constant integer SPIKED_SMASHER_OF_ARMOR_DESTRUCTION = 'I04X'
        constant integer STAFF_OF_INSIGHT = 'I00Z'
        constant integer STAFF_OF_SUPREME_INSIGHT = 'I028'
        constant integer SUPREME_DAGGER_OF_SWIFT_STABBING = 'I02V'
        constant integer SWIFT_BLADE_OF_QUICKENING = 'I04F'
        constant integer SOUL_SIPHONING_SWORD_OF_SLAUGHTER = 'I04K'
        constant integer THUNDER_CLAWS = 'I02J'
        constant integer THUNDER_DEATH_BLADE = 'I02T'
        constant integer WAND_OF_BLASTING = 'I034'
    endglobals

    private struct ItemsDefinitions
        static method IsBootsMSNotBlockedBy takes unit u, integer newBoots, integer itemToCheckFor returns boolean
            return (newBoots == itemToCheckFor and CountItemsOfType(u, newBoots) == 1) or (newBoots != itemToCheckFor and CountItemsOfType(u, itemToCheckFor) == 0)
        endmethod
        static method BootsMovementSpeedAllowed takes unit u, integer newBoots returns boolean
            local boolean checkedBoS = IsBootsMSNotBlockedBy(u, newBoots, BOOTS_OF_SPEED)
            local boolean checkedBrooches = IsBootsMSNotBlockedBy(u, newBoots, BROOCH_OF_SWIFTNESS) and IsBootsMSNotBlockedBy(u, newBoots, BROOCH_OF_AGILE_SWIFTNESS)
            local boolean checkedBrooches2 = IsBootsMSNotBlockedBy(u, newBoots, BROOCH_OF_FORCEFUL_SWIFTNESS) and IsBootsMSNotBlockedBy(u, newBoots, BROOCH_OF_INSIGHTFUL_SWIFTNESS)
            local boolean checkedLightningBoots = IsBootsMSNotBlockedBy(u, newBoots, BOOTS_OF_OCCASIONAL_LIGHTNING) and IsBootsMSNotBlockedBy(u, newBoots, BOOTS_OF_OCCASIONAL_FULMINATION)
            return checkedBoS and checkedBrooches and checkedBrooches2 and checkedLightningBoots
        endmethod
        static method RefreshItem takes unit u, item i returns nothing
            local integer itemTypeId = GetItemTypeId(i)
            if IsUnitType(u, UNIT_TYPE_STRUCTURE) then
                return
            endif
            if itemTypeId == CUP_OF_BLOOD then
                call RemoveSpecificBonusFromItem(i, BonusSpellPower.typeid)
                call LinkBonusToItem(u, BonusSpellPower.typeid, 5 + 0.1 * GetItemCharges(i), i)
            elseif itemTypeId == GOLDEN_GOBLET_OF_GORE then
                call RemoveSpecificBonusFromItem(i, BonusSpellPower.typeid)
                call RemoveSpecificBonusFromItem(i, BonusSpellHaste.typeid)
                call LinkBonusToItem(u, BonusSpellPower.typeid, 40 + 0.1 * GetItemCharges(i), i)
                call LinkBonusToItem(u, BonusSpellHaste.typeid, 0.04 * GetItemCharges(i), i)
            elseif itemTypeId == MAGE_BLADE then
                call RemoveSpecificBonusFromItem(i, BonusDamage.typeid)
                if GetUnitStateSwap(UNIT_STATE_MANA, u) > 0.2 * MaxMana(u) then
                    call LinkBonusToItem(u, BonusDamage.typeid, 25 + 0.02 * MaxMana(u), i)
                else
                    call LinkBonusToItem(u, BonusDamage.typeid, 25, i)
                endif
            elseif itemTypeId == MAGI_SWORD then
                call RemoveSpecificBonusFromItem(i, BonusDamage.typeid)
                if GetUnitStateSwap(UNIT_STATE_MANA, u) > 0.2 * MaxMana(u) then
                    call LinkBonusToItem(u, BonusDamage.typeid, 45 + 0.04 * MaxMana(u), i)
                else
                    call LinkBonusToItem(u, BonusDamage.typeid, 45, i)
                endif
            elseif itemTypeId == MAUL_OF_TREMENDOUS_IMPACT then
                call RemoveSpecificBonusFromItem(i, BonusDamage.typeid)
                call LinkBonusToItem(u, BonusDamage.typeid, 0.0175 * MaxHp(u), i)
            elseif itemTypeId == MERCURIAL_SCIMITAR_OF_INFINITE_SHARPNESS then
                call RemoveSpecificBonusFromItem(i, BonusDamage.typeid)
                call RemoveSpecificBonusFromItem(i, BonusCriticalDamage.typeid)
                call LinkBonusToItem(u, BonusDamage.typeid, 35 + 4 * GetItemCharges(i), i)
                call LinkBonusToItem(u, BonusCriticalDamage.typeid, 0.01 * GetItemCharges(i), i)
            elseif itemTypeId == STAFF_OF_SUPREME_INSIGHT then
                if CountItemsOfType(u, STAFF_OF_SUPREME_INSIGHT) == 1 then
                    call RemoveSpecificBonusFromItem(i, BonusSpellPower.typeid)
                    call LinkBonusToItem(u, BonusSpellPower.typeid, 0.024 * MaxMana(u), i)
                endif
            elseif itemTypeId == SUPREME_DAGGER_OF_SWIFT_STABBING then
                if CountItemsOfType(u, SUPREME_DAGGER_OF_SWIFT_STABBING) == 1 then
                    call RemoveSpecificBonusFromItem(i, BonusDamage.typeid)
                    call LinkBonusToItem(u, BonusDamage.typeid, 1.5 * GetHeroBonusAgi(u), i)
                endif
            endif
        endmethod
        static method OnDropItem takes nothing returns nothing
            local unit u = GetManipulatingUnit()
            local item i = GetManipulatedItem()
            local integer itemTypeId = GetItemTypeId(i)
            local group g
          
            if not isRefreshAction and not IsUnitType(u, UNIT_TYPE_STRUCTURE) and CountItemsOfType(u, itemTypeId) == 1 then
                if itemTypeId == RING_OF_POWER then
                    set g = LoadGroupHandle(udg_item_hash, StringHash("Ring of Power wearers"), 0)
                    call GroupRemoveUnit(g, u)
                    if BlzGroupGetSize(g) == 0 then
                        call DisableTrigger(gg_trg_RingOfPowerEvent)
                    endif
                elseif itemTypeId == BLACK_NAVAJA then
                    call RemoveCustomOnHit(u, BlackNavaja.typeid)
                elseif itemTypeId == DARK_BLADE_OF_SOUL_REAPING then
                    call RemoveCustomOnHit(u, DarkBladeOfSoulReaping.typeid)
                elseif itemTypeId == DEATH_DIRK_OF_BLOOD then
                    call RemoveCustomOnHit(u, DeathDirkOfBlood.typeid)
                elseif itemTypeId == AXE_OF_THE_BRUTE then
                    call RemoveCustomOnHit(u, AxeOfTheBruteOnHit.typeid)
                elseif itemTypeId == SPIKED_SMASHER_OF_ARMOR_DESTRUCTION then
                    call RemoveCustomOnHit(u, SpikedSmasherOfArmorDestructionOnHit.typeid)
                endif
            endif
            set u = null
            set i = null
            set g = null
        endmethod
        static method OnPickUp takes nothing returns nothing
            local unit u = GetManipulatingUnit()
            local item i = GetManipulatedItem()
            local boolean isMelee = IsUnitType(u, UNIT_TYPE_MELEE_ATTACKER)
            local integer itemTypeId = GetItemTypeId(i)
            if IsUnitType(u, UNIT_TYPE_STRUCTURE) then
                set u = null
                set i = null
                return
            endif
//call BJDebugMsg("Pick up")
            //----- PERMANENT ITEMS ------
            if itemTypeId == AXE_OF_ATTACK then
                call LinkBonusToItem(u, BonusDamage.typeid, 8, i)
            elseif itemTypeId == SWORD_OF_ATTACK then
                call LinkBonusToItem(u, BonusDamage.typeid, 20, i)
            elseif itemTypeId == LEATHER_PANTS then
                call LinkBonusToItem(u, BonusArmor.typeid, 8, i)
            elseif itemTypeId == SCALE_ARMOR then
                call LinkBonusToItem(u, BonusArmor.typeid, 20, i)
            elseif itemTypeId == STRANGE_AMULET then
                call LinkBonusToItem(u, BonusSpellPower.typeid, 8, i)
            elseif itemTypeId == SLIGHTLY_MAGICAL_WAND then
                call LinkBonusToItem(u, BonusSpellPower.typeid, 30, i)
            elseif itemTypeId == BOOTS_OF_SPEED then
                if BootsMovementSpeedAllowed(u, BOOTS_OF_SPEED) then
                    call LinkBonusToItem(u, BONUS_MOVEMENT_SPEED, 40, i)
                endif
            elseif itemTypeId == DAGGER then
                call LinkBonusToItem(u, BonusAttackSpeed.typeid, 0.10, i)
            elseif itemTypeId == SHIV_OF_CRITICAL_STABBING then
                call LinkBonusToItem(u, BonusCriticalChance.typeid, 0.03, i)
            elseif itemTypeId == GEM_OF_LIFE then
                call LinkBonusToItem(u, BonusHealth.typeid, 125, i)
            elseif itemTypeId == GEM_OF_MANA then
                call LinkBonusToItem(u, BonusMana.typeid, 150, i)
            elseif itemTypeId == REGENERATING_BRANCH then
                call LinkBonusToItem(u, BonusHealthRegen.typeid, 0.75, i)
            elseif itemTypeId == MANA_POACH then
                call LinkBonusToItem(u, BonusManaRegen.typeid, 0.5, i)
            elseif itemTypeId == TABI_OF_AGILITY then
                call LinkBonusToItem(u, BonusAgility.typeid, 3, i)
            elseif itemTypeId == CLOAK_OF_AGILITY then
                call LinkBonusToItem(u, BonusAgility.typeid, 10, i)
            elseif itemTypeId == CLUB_OF_STRENGTH then
                call LinkBonusToItem(u, BonusStrength.typeid, 3, i)
            elseif itemTypeId == HAMMER_OF_STRENGTH then
                call LinkBonusToItem(u, BonusStrength.typeid, 10, i)
            elseif itemTypeId == WIZARD_HAT_OF_INTELLIGENCE then
                call LinkBonusToItem(u, BonusIntelligence.typeid, 3, i)
            elseif itemTypeId == STAFF_OF_INTELLIGENCE then
                call LinkBonusToItem(u, BonusIntelligence.typeid, 10, i)
            elseif itemTypeId == DIADEM_OF_NOBILITY then
                call LinkBonusToItem(u, BonusStrength.typeid, 2, i)
                call LinkBonusToItem(u, BonusAgility.typeid, 2, i)
                call LinkBonusToItem(u, BonusIntelligence.typeid, 2, i)
            //----- ARTIFACT ITEMS ------
            elseif itemTypeId == AMULET_OF_AMPLIFICATION then
                call LinkBonusToItem(u, BonusSpellPower.typeid, 40, i)
                call LinkBonusToItem(u, BonusSpellPowerMultiplier.typeid, 0.07, i)
            elseif itemTypeId == AMULET_OF_FIRE then
                call LinkBonusToItem(u, BonusHealth.typeid, 200, i)
                call LinkBonusToItem(u, BonusSpellPower.typeid, 15, i)
            elseif itemTypeId == ARCANE_ARMOR_OF_BLASTING then
                call LinkBonusToItem(u, BonusArmor.typeid, 45, i)
                call LinkBonusToItem(u, BonusSpellPower.typeid, 65, i)
                call LinkBonusToItem(u, BonusIntelligence.typeid, 18, i)
                call LinkBonusToItem(u, BonusSpellHaste.typeid, 15, i)
            elseif itemTypeId == ARCANE_STAFF_OF_ENERGY then
                call LinkBonusToItem(u, BonusMana.typeid, 350, i)
                call LinkBonusToItem(u, BonusSpellPower.typeid, 100, i)
                call LinkBonusToItem(u, BonusSpellPowerMultiplier.typeid, 0.25, i)
            elseif itemTypeId == ARCANE_RING_OF_AMILIFICATION then
                call LinkBonusToItem(u, BonusMana.typeid, 450, i)
                call LinkBonusToItem(u, BonusSpellPower.typeid, 50, i)
                call LinkBonusToItem(u, BonusSpellPowerMultiplier.typeid, 0.5, i)
            elseif itemTypeId == ARCANE_RING_OF_AMILIFICATION_OFF then
                call LinkBonusToItem(u, BonusMana.typeid, 450, i)
                call LinkBonusToItem(u, BonusSpellPower.typeid, 50, i)
            elseif itemTypeId == AXE_OF_THE_BRUTE then
                    call LinkBonusToItem(u, BonusDamage.typeid, 15, i)
                call LinkBonusToItem(u, BonusHealth.typeid, 150, i)
                call AddUniqueOnHitOrDestroy(u, AxeOfTheBruteOnHit.create())
            elseif itemTypeId == BROOCH_OF_SWIFTNESS then
                call LinkBonusToItem(u, BonusAttackSpeed.typeid, 0.2, i)
                if BootsMovementSpeedAllowed(u, BROOCH_OF_SWIFTNESS) then
                    call LinkBonusToItem(u, BONUS_MOVEMENT_SPEED, 60, i)
                endif
            elseif itemTypeId == BROOCH_OF_AGILE_SWIFTNESS then
                call LinkBonusToItem(u, BonusAgility.typeid, 25, i)
                call LinkBonusToItem(u, BonusAttackSpeed.typeid, 0.35, i)
                if BootsMovementSpeedAllowed(u, BROOCH_OF_AGILE_SWIFTNESS) then
                    call LinkBonusToItem(u, BONUS_MOVEMENT_SPEED, 80, i)
                endif
            elseif itemTypeId == BROOCH_OF_FORCEFUL_SWIFTNESS then
                call LinkBonusToItem(u, BonusStrength.typeid, 25, i)
                call LinkBonusToItem(u, BonusAttackSpeed.typeid, 0.35, i)
                if BootsMovementSpeedAllowed(u, BROOCH_OF_FORCEFUL_SWIFTNESS) then
                    call LinkBonusToItem(u, BONUS_MOVEMENT_SPEED, 80, i)
                endif
            elseif itemTypeId == BROOCH_OF_INSIGHTFUL_SWIFTNESS then
                call LinkBonusToItem(u, BonusIntelligence.typeid, 25, i)
                call LinkBonusToItem(u, BonusAttackSpeed.typeid, 0.35, i)
                if BootsMovementSpeedAllowed(u, BROOCH_OF_INSIGHTFUL_SWIFTNESS) then
                    call LinkBonusToItem(u, BONUS_MOVEMENT_SPEED, 80., i)
                endif
            elseif itemTypeId == BLACK_NAVAJA then
                call LinkBonusToItem(u, BonusDamage.typeid, 22., i)
                call LinkBonusToItem(u, BonusAgility.typeid, 5., i)
                call LinkBonusToItem(u, BonusHealthRegen.typeid, 1.4, i)
                call AddUniqueOnHitOrDestroy(u, BlackNavaja.create())
            elseif itemTypeId == BLOOD_TOOTH then
                call LinkBonusToItem(u, BonusDamage.typeid, 20., i)
                call LinkBonusToItem(u, BonusHealthRegen.typeid, 1.1, i)
                if isMelee then
                    call LinkBonusToItem(u, BonusLifeOnHit.typeid, 4.5, i)
                else
                    call LinkBonusToItem(u, BonusLifeOnHit.typeid, 3.5, i)
                endif
            elseif itemTypeId == BOOTS_OF_OCCASIONAL_LIGHTNING then
                call LinkBonusToItem(u, BonusSpellPower.typeid, 25, i)
                if BootsMovementSpeedAllowed(u, BOOTS_OF_OCCASIONAL_LIGHTNING) then
                    call LinkBonusToItem(u, BONUS_MOVEMENT_SPEED, 60, i)
                endif
            elseif itemTypeId == BOOTS_OF_OCCASIONAL_FULMINATION then
                call LinkBonusToItem(u, BonusSpellPower.typeid, 65, i)
                if BootsMovementSpeedAllowed(u, BOOTS_OF_OCCASIONAL_FULMINATION) then
                    call LinkBonusToItem(u, BONUS_MOVEMENT_SPEED, 80, i)
                endif
            elseif itemTypeId == CLEAVING_AXE then
                call LinkBonusToItem(u, BonusDamage.typeid, 15, i)
                call LinkBonusToItem(u, BonusSpellHaste.typeid, 10, i)
            elseif itemTypeId == CRITICAL_DEATH_MASK then
                call LinkBonusToItem(u, BonusDamage.typeid, 50, i)
                call LinkBonusToItem(u, BonusCriticalChance.typeid, 0.10, i)
                call LinkBonusToItem(u, BonusCriticalDamage.typeid, 0.35, i)
            elseif itemTypeId == CRITICAL_SLICER then
                call LinkBonusToItem(u, BonusCriticalChance.typeid, 0.03, i)
                call LinkBonusToItem(u, BonusCriticalDamage.typeid, 0.12, i)
            elseif itemTypeId == CUP_OF_BLOOD then
                call LinkBonusToItem(u, BonusHealth.typeid, 225, i)
                if GetItemCharges(i) < 100 then
                    call SetItemCharges(i, 100) //Initial charge-count
                endif
                call LinkBonusToItem(u, BonusSpellPower.typeid, 5 + 0.1 * GetItemCharges(i), i)
            elseif itemTypeId == DAGGER_OF_FAST_STABBING then
                call LinkBonusToItem(u, BonusAgility.typeid, 6, i)
                call LinkBonusToItem(u, BonusAttackSpeed.typeid, 0.18, i)
                call LinkBonusToItem(u, BonusDamage.typeid, 18, i)
                call LinkBonusToItem(u, BonusSpellHaste.typeid, 8, i)
                call EnableTrigger( gg_trg_DaggerOfFastStabbing_onhit )
            elseif itemTypeId == DARK_BLADE_OF_SOUL_REAPING then
                call LinkBonusToItem(u, BonusDamage.typeid, 35., i)
                call LinkBonusToItem(u, BonusAgility.typeid, 18., i)
                call LinkBonusToItem(u, BonusHealthRegen.typeid, 1.8, i)
                call LinkBonusToItem(u, BonusSpellHaste.typeid, 10., i)
                call AddUniqueOnHitOrDestroy(u, DarkBladeOfSoulReaping.create())
            elseif itemTypeId == DEATH_DEALER then
                call LinkBonusToItem(u, BonusDamage.typeid, 25, i)
                call LinkBonusToItem(u, BonusCriticalChance.typeid, 0.05, i)
            elseif itemTypeId == DEATH_DIRK_OF_BLOOD then
                call LinkBonusToItem(u, BonusDamage.typeid, 55, i)
                call LinkBonusToItem(u, BonusHealthRegen.typeid, 2.0, i)
                call LinkBonusToItem(u, BonusCriticalChance.typeid, 0.08, i)
                call LinkBonusToItem(u, BonusCriticalDamage.typeid, 0.25, i)
                call AddUniqueOnHitOrDestroy(u, DeathDirkOfBlood.create())
            elseif itemTypeId == DRAGON_STAFF_OF_FLAMES then
                call LinkBonusToItem(u, BonusDamage.typeid, 35, i)
                call LinkBonusToItem(u, BonusHealth.typeid, 350, i)
                call LinkBonusToItem(u, BonusSpellPower.typeid, 45, i)
                call LinkBonusToItem(u, BonusSpellHaste.typeid, 10, i)
            elseif itemTypeId == ENT_BARK_SHIELD then
                call LinkBonusToItem(u, BonusHealth.typeid, 500, i)
                call LinkBonusToItem(u, BonusHealthRegen.typeid, 2.0, i)
                call LinkBonusToItem(u, BonusArmor.typeid, 25, i)
                call LinkBonusToItem(u, BonusHealthStone.typeid, 0.0125, i)
            elseif itemTypeId == ENDLESS_ELIXIR_HEALING then
                call LinkBonusToItem(u, BonusAgility.typeid, 14, i)
                call LinkBonusToItem(u, BonusStrength.typeid, 14, i)
                call LinkBonusToItem(u, BonusIntelligence.typeid, 14, i)
                call LinkBonusToItem(u, BonusHealth.typeid, 400, i)
                call LinkBonusToItem(u, BonusSpellPower.typeid, 40, i)
            elseif itemTypeId == ENDLESS_ELIXIR_MANA then
                call LinkBonusToItem(u, BonusAgility.typeid, 14, i)
                call LinkBonusToItem(u, BonusStrength.typeid, 14, i)
                call LinkBonusToItem(u, BonusIntelligence.typeid, 14, i)
                call LinkBonusToItem(u, BonusMana.typeid, 400, i)
                call LinkBonusToItem(u, BonusSpellPower.typeid, 40, i)
            elseif itemTypeId == FLAMING_PAULDRONS_OF_RADIANT_HEAT then
                call LinkBonusToItem(u, BonusArmor.typeid, 45, i)
                call LinkBonusToItem(u, BonusHealth.typeid, 450, i)
                call LinkBonusToItem(u, BonusSpellPower.typeid, 50, i)
            elseif itemTypeId == FROZEN_SKULL_OF_NOVA then
                call LinkBonusToItem(u, BonusStrength.typeid, 15, i)
                call LinkBonusToItem(u, BonusMana.typeid, 400, i)
                call LinkBonusToItem(u, BonusManaRegen.typeid, 2.0, i)
                call LinkBonusToItem(u, BonusSpellPower.typeid, 50, i)
                call LinkBonusToItem(u, BonusSpellHaste.typeid, 20, i)
            elseif itemTypeId == GNARLT_STINGER_OF_ACUTE_TOXICITY then
                call LinkBonusToItem(u, BonusDamage.typeid, 30, i)
                call LinkBonusToItem(u, BonusAttackSpeed.typeid, 0.35, i)
                call LinkBonusToItem(u, BonusCriticalChance.typeid, 0.12, i)
                call LinkBonusToItem(u, BonusSpellHaste.typeid, 10, i)
            elseif itemTypeId == GOBLET_OF_FIRE then
                call LinkBonusToItem(u, BonusHealth.typeid, 400, i)
                call LinkBonusToItem(u, BonusMana.typeid, 350, i)
                call LinkBonusToItem(u, BonusSpellPower.typeid, 75, i)
                call LinkBonusToItem(u, BonusSpellHaste.typeid, 20, i)
            elseif itemTypeId == GOLDEN_GOBLET_OF_GORE then
                if GetItemCharges(i) < 250 then
                    call SetItemCharges(i, 250) //Initial charge-count
                endif
                call LinkBonusToItem(u, BonusSpellPower.typeid, 40 + 0.1 * GetItemCharges(i), i)
                call LinkBonusToItem(u, BonusSpellHaste.typeid, 0.04 * GetItemCharges(i), i)
                call LinkBonusToItem(u, BonusHealth.typeid, 650, i)
                call LinkBonusToItem(u, BonusLifeOnKillFlat.typeid, 1.0, i)
                call LinkBonusToItem(u, BonusLifeOnKillMissing.typeid, 0.003, i)
            elseif itemTypeId == GOLDEN_SHIELD_OF_AEGIS then
                call LinkBonusToItem(u, BonusArmor.typeid, 30, i)
                call LinkBonusToItem(u, BonusHealth.typeid, 375, i)
                call LinkBonusToItem(u, BonusSpellHaste.typeid, 20, i)
            elseif itemTypeId == HEAVY_PLATE_ARMOR then
                call LinkBonusToItem(u, BonusArmor.typeid, 35, i)
            elseif itemTypeId == HEAVY_SHIELD_OF_STRENGTH then
                call LinkBonusToItem(u, BonusHealth.typeid, 225, i)
                call LinkBonusToItem(u, BonusStrength.typeid, 5, i)
                call LinkBonusToItem(u, BonusArmor.typeid, 20, i)
            elseif itemTypeId == INCONVENIENTLY_HEAVY_SHIELD then
                call LinkBonusToItem(u, BonusHealth.typeid, 500, i)
                call LinkBonusToItem(u, BonusStrength.typeid, 18, i)
                call LinkBonusToItem(u, BonusArmor.typeid, 35, i)
            elseif itemTypeId == INFINITE_VIAL_HEALING then
                call LinkBonusToItem(u, BonusAgility.typeid, 5, i)
                call LinkBonusToItem(u, BonusStrength.typeid, 5, i)
                call LinkBonusToItem(u, BonusIntelligence.typeid, 5, i)
            elseif itemTypeId == INFINITE_VIAL_MANA then
                call LinkBonusToItem(u, BonusAgility.typeid, 5, i)
                call LinkBonusToItem(u, BonusStrength.typeid, 5, i)
                call LinkBonusToItem(u, BonusIntelligence.typeid, 5, i)
            elseif itemTypeId == LIFE_STAFF then
                call LinkBonusToItem(u, BonusDamage.typeid, 30, i)
                call LinkBonusToItem(u, BonusHealth.typeid, 400, i)
                call LinkBonusToItem(u, BonusSpellPower.typeid, 40, i)
                call LinkBonusToItem(u, BonusSpellHaste.typeid, 15, i)
            elseif itemTypeId == MANA_STEEL_SWORD then
                call LinkBonusToItem(u, BonusDamage.typeid, 25, i)
                call LinkBonusToItem(u, BonusMana.typeid, 250, i)
                call LinkBonusToItem(u, BonusSpellHaste.typeid, 12, i)
            elseif itemTypeId == MAGE_ARMOR then
                call LinkBonusToItem(u, BonusIntelligence.typeid, 5, i)
                call LinkBonusToItem(u, BonusArmor.typeid, 25, i)
                call LinkBonusToItem(u, BonusSpellPower.typeid, 12, i)
                call LinkBonusToItem(u, BonusSpellHaste.typeid, 10, i)
            elseif itemTypeId == MAGE_BLADE then
                call LinkBonusToItem(u, BonusIntelligence.typeid, 6, i)
                call LinkBonusToItem(u, BonusMana.typeid, 400, i)
                call LinkBonusToItem(u, BonusSpellHaste.typeid, 12, i)
                if GetUnitStateSwap(UNIT_STATE_MANA, u) > 0.2 * MaxMana(u) then
                    call LinkBonusToItem(u, BonusDamage.typeid, 25 + 0.02 * MaxMana(u), i)
                else
                    call LinkBonusToItem(u, BonusDamage.typeid, 25, i)
                endif
                call EnableTrigger( gg_trg_MageBlade_onhit )
            elseif itemTypeId == MAGE_BLADE_OFF then
                call LinkBonusToItem(u, BonusIntelligence.typeid, 6, i)
                call LinkBonusToItem(u, BonusMana.typeid, 400, i)
                call LinkBonusToItem(u, BonusDamage.typeid, 25, i)
                call LinkBonusToItem(u, BonusSpellHaste.typeid, 12, i)
            elseif itemTypeId == MAGI_SWORD then
                call LinkBonusToItem(u, BonusIntelligence.typeid, 15, i)
                call LinkBonusToItem(u, BonusMana.typeid, 600, i)
                call LinkBonusToItem(u, BonusSpellHaste.typeid, 12, i)
                call LinkBonusToItem(u, BonusCriticalChance.typeid, 0.07, i)
                if GetUnitStateSwap(UNIT_STATE_MANA, u) > 0.2 * MaxMana(u) then
                    call LinkBonusToItem(u, BonusDamage.typeid, 45 + 0.04 * MaxMana(u), i)
                else
                    call LinkBonusToItem(u, BonusDamage.typeid, 45, i)
                endif
                call EnableTrigger( gg_trg_MagiSword_onhit )
            elseif itemTypeId == MAGI_SWORD_OFF then
                call LinkBonusToItem(u, BonusIntelligence.typeid, 15, i)
                call LinkBonusToItem(u, BonusMana.typeid, 600, i)
                call LinkBonusToItem(u, BonusSpellHaste.typeid, 12, i)
                call LinkBonusToItem(u, BonusCriticalChance.typeid, 0.07, i)
                call LinkBonusToItem(u, BonusDamage.typeid, 45, i)
            elseif itemTypeId == MAGICAL_AMULET then
                call LinkBonusToItem(u, BonusMana.typeid, 200, i)
                call LinkBonusToItem(u, BonusSpellPower.typeid, 15, i)
            elseif itemTypeId == MAGICAL_DAGGER then
                call LinkBonusToItem(u, BonusDamage.typeid, 15, i)
                call LinkBonusToItem(u, BonusAttackSpeed.typeid, 0.15, i)
                call LinkBonusToItem(u, BonusSpellHaste.typeid, 5, i)
            elseif itemTypeId == MANAFLOWIFICATOR then
                call LinkBonusToItem(u, BonusMana.typeid, 800, i)
                call LinkBonusToItem(u, BonusManaStone.typeid, 0.01, i)
                call LinkBonusToItem(u, BonusSpellPower.typeid, 25, i)
            elseif itemTypeId == MAUL_OF_FORCEFUL_IMPACT then
                call LinkBonusToItem(u, BonusStrength.typeid, 7., i)
                call LinkBonusToItem(u, BonusHealthRegen.typeid, 1.5, i)
                call LinkBonusToItem(u, BonusDamage.typeid, 15., i)
            elseif itemTypeId == MAUL_OF_TREMENDOUS_IMPACT then
                call LinkBonusToItem(u, BonusStrength.typeid, 25, i)
                call LinkBonusToItem(u, BonusHealthRegen.typeid, 2.5, i)
                call LinkBonusToItem(u, BonusDamage.typeid, 0.0175 * MaxHp(u), i)
            elseif itemTypeId == MERCURIAL_SCIMITAR_OF_INFINITE_SHARPNESS then
                call LinkBonusToItem(u, BonusDamage.typeid, 35 + 4 * GetItemCharges(i), i)
                call LinkBonusToItem(u, BonusCriticalDamage.typeid, 0.01 * GetItemCharges(i), i)
                call LinkBonusToItem(u, BonusAttackSpeed.typeid, 0.35, i)
                call LinkBonusToItem(u, BonusCriticalChance.typeid, 0.08, i)
                call EnableTrigger( gg_trg_Mercurial_Scimitar_of_Infinite_Sharpness_onhit )
            elseif itemTypeId == MIGHTY_SKULL_OF_INSIGHT then
                call LinkBonusToItem(u, BonusStrength.typeid, 5, i)
                call LinkBonusToItem(u, BonusManaRegen.typeid, 1.0, i)
                call LinkBonusToItem(u, BonusSpellHaste.typeid, 12, i)
            elseif itemTypeId == MECHANICAL_DEVICE_OF_CONVINSING_CLONING then
                call LinkBonusToItem(u, BonusHealth.typeid, 350, i)
                call LinkBonusToItem(u, BonusMana.typeid, 400, i)
                call LinkBonusToItem(u, BonusArmor.typeid, 40, i)
                call LinkBonusToItem(u, BonusSpellPower.typeid, 35, i)
            elseif itemTypeId == OBSERVING_STAFF_OF_THE_GREAT_EYE then
                call LinkBonusToItem(u, BonusSpellPower.typeid, 60, i)
                call LinkBonusToItem(u, BonusSpellPowerMultiplier.typeid, 0.15, i)
                call LinkBonusToItem(u, BonusSpellHaste.typeid, 30, i)
                call LinkBonusToItem(u, BonusArmor.typeid, 35, i)
            elseif itemTypeId == OMNI_GEM then
                call LinkBonusToItem(u, BonusHealth.typeid, 175, i)
                call LinkBonusToItem(u, BonusMana.typeid, 175, i)
                call LinkBonusToItem(u, BonusSpellPower.typeid, 17, i)
            elseif itemTypeId == PHOENIX_AXE then
                call LinkBonusToItem(u, BonusDamage.typeid, 40, i)
                call LinkBonusToItem(u, BonusHealth.typeid, 400, i)
                call LinkBonusToItem(u, BonusSpellPower.typeid, 25, i)
                call LinkBonusToItem(u, BonusSpellHaste.typeid, 18, i)
                if not HaveSavedInteger(udg_item_hash, GetHandleId(u), StringHash("phoenixaxe")) then
                    call SaveInteger(udg_item_hash, GetHandleId(u), StringHash("phoenixaxe"), 0)
                    call EnableTrigger( gg_trg_PhoenixAxeOnHit )
                endif
            elseif itemTypeId == POWER_HAMMER_OF_FABRICATION then
                call LinkBonusToItem(u, BonusDamage.typeid, 45, i)
                call LinkBonusToItem(u, BonusMana.typeid, 500, i)
                call LinkBonusToItem(u, BonusSpellPower.typeid, 45, i)
                call LinkBonusToItem(u, BonusSpellHaste.typeid, 15, i)
            elseif itemTypeId == REACTIVE_ARMOR_OF_ARCANE_REPULSION then
                call LinkBonusToItem(u, BonusHealth.typeid, 400, i)
                call LinkBonusToItem(u, BonusArmor.typeid, 40, i)
                call LinkBonusToItem(u, BonusSpellPower.typeid, 30, i)
                call LinkBonusToItem(u, BonusSpellHaste.typeid, 20, i)
            elseif itemTypeId == RING_OF_LIFE then
                call LinkBonusToItem(u, BonusHealth.typeid, 200, i)
                call LinkBonusToItem(u, BonusHealthStone.typeid, 0.0075, i)
                call LinkBonusToItem(u, BonusHealthRegen.typeid, 1.0, i)
            elseif itemTypeId == RING_OF_MANA then
                call LinkBonusToItem(u, BonusMana.typeid, 250, i)
                call LinkBonusToItem(u, BonusManaStone.typeid, 0.0075, i)
                call LinkBonusToItem(u, BonusManaRegen.typeid, 1.0, i)
            elseif itemTypeId == RING_OF_POWER then
                call LinkBonusToItem(u, BonusHealth.typeid, 750, i)
                call LinkBonusToItem(u, BonusMana.typeid, 750, i)
                call LinkBonusToItem(u, BonusManaStone.typeid, 0.0125, i)
                call LinkBonusToItem(u, BonusHealthStone.typeid, 0.0125, i)
                call GroupAddUnit(LoadGroupHandle(udg_item_hash, StringHash("Ring of Power wearers"), 0), u)
                call EnableTrigger( gg_trg_RingOfPowerEvent )
            elseif itemTypeId == SMALL_SHIELD then
                call LinkBonusToItem(u, BonusArmor.typeid, 12, i)
                call LinkBonusToItem(u, BonusHealth.typeid, 200, i)
            elseif itemTypeId == SPIKED_PLATE_OF_VENGEANCE then
                call LinkBonusToItem(u, BonusArmor.typeid, 70, i)
                call LinkBonusToItem(u, BonusHealth.typeid, 350, i)
            elseif itemTypeId == STAFF_OF_INSIGHT then
                call LinkBonusToItem(u, BonusIntelligence.typeid, 7, i)
                call LinkBonusToItem(u, BonusMana.typeid, 240, i)
                call LinkBonusToItem(u, BonusManaRegen.typeid, 1.25, i)
                call LinkBonusToItem(u, BonusSpellPower.typeid, 12, i)
            elseif itemTypeId == STAFF_OF_SUPREME_INSIGHT then
                call LinkBonusToItem(u, BonusIntelligence.typeid, 24, i)
                call LinkBonusToItem(u, BonusMana.typeid, 360, i)
                call LinkBonusToItem(u, BonusManaRegen.typeid, 2.0, i)
                if CountItemsOfType(u, STAFF_OF_SUPREME_INSIGHT) == 1 then
                    call LinkBonusToItem(u, BonusSpellPower.typeid, 0.024 * MaxMana(u), i)
                endif
            elseif itemTypeId == SUPREME_DAGGER_OF_SWIFT_STABBING then
                call LinkBonusToItem(u, BonusAgility.typeid, 24, i)
                call LinkBonusToItem(u, BonusAttackSpeed.typeid, 0.35, i)
                call LinkBonusToItem(u, BonusSpellHaste.typeid, 12, i)
                if CountItemsOfType(u, SUPREME_DAGGER_OF_SWIFT_STABBING) == 1 then
                    call LinkBonusToItem(u, BonusDamage.typeid, 1.5 * GetHeroBonusAgi(u), i)
                endif
                call EnableTrigger( gg_trg_SupremeDaggerOfSwiftStabbing_onhit )
            elseif itemTypeId == SWIFT_BLADE_OF_QUICKENING then
                call LinkBonusToItem(u, BonusDamage.typeid, 30, i)
                call LinkBonusToItem(u, BonusAttackSpeed.typeid, 0.3, i)
                call LinkBonusToItem(u, BonusCriticalChance.typeid, 0.05, i)
                call LinkBonusToItem(u, BonusSpellHaste.typeid, 15, i)
                call EnableTrigger( gg_trg_Swift_Blade_of_Quickening_OnHit )
            elseif itemTypeId == SOUL_SIPHONING_SWORD_OF_SLAUGHTER then
                call LinkBonusToItem(u, BonusDamage.typeid, 70, i)
                call LinkBonusToItem(u, BonusSpellHaste.typeid, 20, i)
                call LinkBonusToItem(u, BonusMana.typeid, 600, i)
                call LinkBonusToItem(u, BonusManaStone.typeid, 0.01, i)
            elseif itemTypeId == SPIKED_SMASHER_OF_ARMOR_DESTRUCTION then
                call LinkBonusToItem(u, BonusDamage.typeid, 40, i)
                call LinkBonusToItem(u, BonusHealth.typeid, 275, i)
                call LinkBonusToItem(u, BonusArmorPenetrationPercent.typeid, 0.20, i)
                call LinkBonusToItem(u, BonusCriticalChance.typeid, 0.06, i)
                call AddUniqueOnHitOrDestroy(u, SpikedSmasherOfArmorDestructionOnHit.create())
            elseif itemTypeId == THUNDER_CLAWS then
                call LinkBonusToItem(u, BonusAgility.typeid, 5, i)
                call LinkBonusToItem(u, BonusManaRegen.typeid, 1.0, i)
                call LinkBonusToItem(u, BonusCriticalChance.typeid, 0.05, i)
                call LinkBonusToItem(u, BonusCriticalDamage.typeid, 0.15, i)
            elseif itemTypeId == THUNDER_DEATH_BLADE then
                call LinkBonusToItem(u, BonusAgility.typeid, 16, i)
                call LinkBonusToItem(u, BonusDamage.typeid, 30, i)
                call LinkBonusToItem(u, BonusManaRegen.typeid, 2.0, i)
                call LinkBonusToItem(u, BonusCriticalChance.typeid, 0.10, i)
                call LinkBonusToItem(u, BonusCriticalDamage.typeid, 0.24, i)
            elseif itemTypeId == WAND_OF_BLASTING then
                call LinkBonusToItem(u, BonusSpellPower.typeid, 40, i)
            endif
            set i = null
            set u = null
        endmethod
        static method onInit takes nothing returns nothing
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_PICKUP_ITEM, function thistype.OnPickUp)
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DROP_ITEM, function thistype.OnDropItem)
        endmethod 
    endstruct
  
    function RefreshItem takes unit u, item i returns nothing
        call ItemsDefinitions.RefreshItem(u, i)
    endfunction
endscope
Contents

ExtendableBonusSystem (Map)

I've updated test map with item definitions for 3 custom items, with unique effects and effects depending if hero is melee or ranged.
Also imported a few supporting systems to make Demo better (DamageEngine, TimerUtils, etc. but they are not part of this system).
Also added more text in test-map and some comments in demo-triggers

Edit: I added another circle of power for life on hit a few minutes after first uploading this updated demo-map. So 2 updates within a few minutes.
 
Last edited:
Back
Top