• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • ✅ Time to vote for the top 3 models! The POLL for Hive's 6th HD Modeling Contest: Mechanical is now open! 📅 Poll close on July 16, 2024! 🔗 Cast your vote now!
  • ✅ The POLL for Hive's Texturing Contest #33 is OPEN! Vote for the TOP 3 SKINS! 🔗Click here to cast your vote!

TasUnitBonus

This bundle is marked as pending. It has not been reviewed by a staff member yet.

Introduction


TasUnitBonus is a unit Stat Lua system for Warcraft 3 V1.31 or higher.
It gives an one way api to inc/dec unit stats, the types of stats is "easy" expandable. Includes addons to handle bonus over Buffs, Items, LevelUps, Learning Skills & Skill-Fields.

To increase a stat of an unit using TasUnitBonus you would run TasUnitBonus(unit, key, value) key is one of the supported keys of TasUnitBonus. As said before you can add own custom keys/stats pretty easy, checkout the examples at the bottom.

The main System contains prebuilt warcraft 3 stats, the stats prebuilt only use code no ability-features -> no object Editor setup required.
Life
Mana
Armor
Attack
AttackSpeed
AttackRange (Not V1.31.1)
AttackRangeR (Not V1.31.1)
LifeReg
ManaReg
Agi
Str
Int
Primary
CastPoint
CastBackswing
TurnSpeed
UnitLevel
Ability
AbilityInc
Tech
Add 10 Primary Hero Stat (white numbers) TasUnitBonus(unit, "Primary", 10)
Bonus Strenght is an ability feature for such is the TasUnitBonusSkill addon, can require custom abilities and object Editor setup.

How to install


Requiers Warcraft 3 1.31+ or higher
  • Copy the TasUnitBonus Script/Folder (trigger Editor).
  • Or Copy the TasUnitBonus code from this post in your map, probably the addons aswell.
  • Without Total Init run InitTasUnitBonusHero() & InitTasUnitBonusItem() & InitTasUnitBonusLearn() inside a mapInit/function main action to create events.
  • Check the data in TasUnitBonusSkill, make sure that the skills used work for your map and are of expected base behaviour.
  • Installed

Code


Lua:
if Debug then Debug.beginFile "TasUnitBonus" end
do
   --[[ TasUnitBonus 1.5 by Tasyen
       A system to provide various bonuses to Units over one way. This only defines Types and what to do for them.

       Apply a bonus: TasUnitBonus(unit, key, value)
           TasUnitBonus(udg_Unit, "Life", 100) -- add 100 HP to udg_Unit
           TasUnitBonus(udg_Unit, "Ability", FourCC'AHbz') -- add Blizzard
           TasUnitBonus(udg_Unit, "AttackSpeed", -0.1) -- improve base ATK cooldown by 0.1

       TasUnitBonus.UnitAdd(object, unit, add)
           apply many bonuses with one call, expects {key = x, key2 = y, key3 = z ,...}
           object is affecting unit by add Times (add needs to be an integer). Use -1 to remove bonus. 1 to add bonus

       TasUnitBonus.NewType(key, function(unit, value, key) end)
           Adds a new supported bonus reached by key, key should be unique. 
           The function runs when calling TasUnitBonus with that key, and it needs to do the wanted effect, in most cases increase some unit stat; newValue = oldValue + value.
           instead of a function you can give an already existing key to make keyB do the same as keyA, for TasUnitBonus.UnitAdd keyA and keyB are 2 serperate stats.

       TasUnitBonus.AddSimpleType(key)
           add a new supported type meant for an global array in env _G.
           Which would result into key[unit] = key[unit] + bonus
           TasUnitBonus.AddSimpleType("udg_Unit_Super_Power")

       this.AddSimpleTypeBatch = function(...)
           add many AddSimpleType as once
           AddSimpleTypeBatch("MagicPower", "WeaponPower",...)
   ]]
   local this = {}
   TasUnitBonus = this
   this.IgnoreUnsupported = {Aktiv = true} -- do not throw erros for these unsupported keys encountered in TasUnitBonus.UnitAdd; expects Key = true, Key2 = true
   
    this.AddSimpleType = function(key) this.Types[key] =  this.Types.SimpleBonusType end
    this.NewType = function(key, action)
        if type(action) == "function" then
            this.Types[key] =  action
        elseif type(action) == "string" then
            this.Types[key] = this.Types[action]
        end
    end
    this.AddSimpleTypeBatch = function(...) for _, k in ipairs({...}) do this.AddSimpleType(k) end end

    -- object is affecting unit by add Times. Use -1 to remove bonus. 1 to add bonus
    this.UnitAdd =  function (object, unit, add)
        if not unit then return end
        if GetUnitTypeId(unit) == 0 then return end -- this might be smart to do when you only use units
        -- loop the object and apply any key that is in TasUnitBonus.Types
        for key, value in pairs(object) do
            if this.IgnoreUnsupported[key] or type(key) == "number" then
            elseif this.Types[key] then
                -- supported Type call it
                if key == "Ability" then
                    -- Ability only support +1/-1 for add
                    this.Types[key](unit, value*ISignBJ(add), key)
                else
                    this.Types[key](unit, value*add, key)
                end
            -- try TasUnitBonusSkill when it exists
            -- elseif TasUnitBonusSkill and TasUnitBonusSkill.Data[key] then
            --   TasUnitBonusSkill.Add(unit, key, value*add)
            else print("TasUnitBonus.UnitAdd - Unsuported Key", key)
            end
        end
    end
    setmetatable(this, {__call = function(table, unit, key, value)
        if not unit then return end
        --if string.find(tostring(unit), "unit:") and GetUnitTypeId(unit) == 0 then print("TasUnitBonus - no Unit: ",key, value) return end
        if GetUnitTypeId(unit) == 0 then print("TasUnitBonus - no Unit: ",key, value) return end
        if this.Types[key] then
            this.Types[key](unit, value, key)
    --  elseif TasUnitBonusSkill and TasUnitBonusSkill.Data[key] then
    --      TasUnitBonusSkill.Add(unit, key, value)
        else
            print("TasUnitBonus - Unsupported Key: ",Key)
        end
    end})

   -- supported Types and what to do for them. the functions should work for -value and +value
   this.Types = {
       Life = function(unit, value) BlzSetUnitMaxHP(unit, BlzGetUnitMaxHP(unit) + value) if value > 0 then SetWidgetLife(unit, GetWidgetLife(unit) + value) end end
       ,Mana = function(unit, value) BlzSetUnitMaxMana(unit, BlzGetUnitMaxMana(unit) + value) if value > 0 then SetUnitState(unit, UNIT_STATE_MANA, GetUnitState(unit, UNIT_STATE_MANA) + value) end end
       ,Armor = function(unit, value) BlzSetUnitArmor(unit, BlzGetUnitArmor(unit) + value) end
       ,Attack = function(unit, value) BlzSetUnitBaseDamage(unit, BlzGetUnitBaseDamage(unit, 0) + value, 0) end
       ,AttackSpeed = function(unit, value) BlzSetUnitAttackCooldown(unit, BlzGetUnitAttackCooldown(unit, 0) + value, 0)  end

       -- AttackRange does not work in warcraft 3 v1.31
       ,AttackRange = function(unit, value) BlzSetUnitWeaponRealField(unit, UNIT_WEAPON_RF_ATTACK_RANGE, 1, value + BlzGetUnitWeaponRealField(unit, UNIT_WEAPON_RF_ATTACK_RANGE, 1)) end
       ,AttackRangeR = function(unit, value) if IsUnitIdType(GetUnitTypeId(unit), UNIT_TYPE_RANGED_ATTACKER) then this.Types.AttackRange(unit, value) end end
       ,LifeReg = function(unit, value) BlzSetUnitRealField(unit, UNIT_RF_HIT_POINTS_REGENERATION_RATE, BlzGetUnitRealField(unit, UNIT_RF_HIT_POINTS_REGENERATION_RATE) + value) end
       ,ManaReg = function(unit, value) BlzSetUnitRealField(unit, UNIT_RF_MANA_REGENERATION, BlzGetUnitRealField(unit, UNIT_RF_MANA_REGENERATION) + value) end
       ,Agi = function(unit, value) SetHeroAgi(unit, GetHeroAgi(unit, false) + value, true) end
       ,Str = function(unit, value) SetHeroStr(unit, GetHeroStr(unit, false) + value, true) end
       ,Int = function(unit, value) SetHeroInt(unit, GetHeroInt(unit, false) + value, true) end
       ,Primary = function(unit, value)
           local stat = BlzGetUnitIntegerField(unit, UNIT_IF_PRIMARY_ATTRIBUTE)
           if stat == GetHandleId(HERO_ATTRIBUTE_STR) then
               this.Types.Str(unit, value)
           elseif stat == GetHandleId(HERO_ATTRIBUTE_AGI) then
               this.Types.Agi(unit, value)
           elseif stat == GetHandleId(HERO_ATTRIBUTE_INT) then
               this.Types.Int(unit, value)
           end
       end
       -- CastPoint CastBackswing don't affect abilities the unit already has. One would have to lose and regain all to make it work.
       ,CastPoint = function(unit, value) BlzSetUnitRealField(unit, UNIT_RF_CAST_POINT, BlzGetUnitRealField(unit, UNIT_RF_CAST_POINT) + value) end
       ,CastBackswing = function(unit, value) BlzSetUnitRealField(unit, UNIT_RF_CAST_BACK_SWING, BlzGetUnitRealField(unit, UNIT_RF_CAST_BACK_SWING) + value) end
       ,TurnSpeed = function(unit, value) SetUnitTurnSpeed(unit, GetUnitTurnSpeed(unit) + value) end
       ,UnitLevel = function(unit, value)
           if not IsUnitType(unit, UNIT_TYPE_HERO) and not IsHeroUnitId(GetUnitTypeId(unit)) then
               BlzSetUnitIntegerField(unit, UNIT_IF_LEVEL, BlzGetUnitIntegerField(unit, UNIT_IF_LEVEL) + value)
           end
       end

       -- example of a custom variable setting, MagicDef should bedefined to catch nilpointers with __jarray(0)
       --,MagicDef = function(unit, value) MagicDef[unit] = MagicDef[unit] + value end
      
      ,Ability = function(unit, value)
           if value >= 0 then
               UnitMakeAbilityPermanent(unit, true, value)
               UnitAddAbility(unit, value)
           else
               UnitRemoveAbility(unit, -value)
           end
       end
       ,AbilityInc = function(unit, value)
            if value >= 0 then IncUnitAbilityLevel(unit, value)
            else DecUnitAbilityLevel(unit, -value) end
       end
       ,Tech = function(unit, value)
            if value >= 0 then
                AddPlayerTechResearched(GetOwningPlayer(unit), value, 1)
            else
                BlzDecPlayerTechResearched(GetOwningPlayer(unit), -value, 1)
            end
        end

       ,SimpleBonusType = function(unit, value, key) _G[key][unit] = _G[key][unit] + value end
       -- Key+ uses skills to provide non base bonus
       -- You need to provide abilities and update the references inside TasUnitBonusSkill
       -- the "+" key iself should not be used it is the base for all TasUnitBonusSkill
       ,["+"] = function(unit, value, key) TasUnitBonusSkill.Add(unit, key, value) end
   }
   -- setup equals
    TasUnitBonus.NewType("ATK", "Attack") -- now TasUnitBonus(unit, "ATK", 22) & TasUnitBonus(unit, "Attack", 22) do the same

   -- custom ones
   --this.AddSimpleTypeBatch("TasCasterLevel","WeaponPower","WeaponDef","MagicPower", "MagicDefAstral","MagicDef")
end

if Debug then Debug.endFile() end

The Addons:
TasUnitBonusSkill handles & adds TasUnitBonus-Keys that require abilities to be given like bonus str, bonus def, bonus attack, evasion, default crit and such in the default all Keys of this Section end with + like "STR+".
TasUnitBonusItem gives TasUnitBonus on pick/drop items has unit-events. You can define data-Lua-tables for specific items and of items with a given rawCode.
TasUnitBonusHero give TasUnitBonus on Levelups for any hero, that hero and Heroes of class x, Has unit-events.
TasUnitBonusBuff attach a TasUnitBonus to a Warcraft 3 BuffCode. You need to tell the types of bonuses once and then when the buff is gained by an unit tell how much of each stat.
TasUnitBonusLearn give TasUnitBonus when Learning a Skill over warcraft 3 Hero Learn ui, can be called from the outside in case you heroes gain skills in a other way, Has unit-events.
TasUnitBonusItemTooltip addon for TasUnitBonusItem update tooltips to display TasUnitBonus gained by items.

Lua:
--[[
TasUnitBonusSkill 1.2 by Tasyen
Addon for TasUnitBonus handles bonus provided over an ability (green +)
needs custom map setup, make sure the Abilities in the data setup is okay in your map.
Scroll down upto System functions. thisData["STR+"] are data setups.
   when a skill provides more than one thing make sure the base in object Editor don't conflicts with your goal
    ^^ for abilities with multiple fields you should make a custom version with default values good for your purposes like hero stat skill 0 0 0.
   the abilities should not be used otherwise

======
function TasUnitBonusSkill.Remove(unit, whichType)
    removes the ability providing the bonus
function TasUnitBonusSkill.Set(unit, whichType, amount)
    add the ability and set the bonus provided
function TasUnitBonusSkill.Get(unit, whichType)
function TasUnitBonusSkill.Add(unit, whichType, amount)
    adds amount to the current bonus
======
--]]
if Debug then Debug.beginFile "TasUnitBonusSkill" end
do
   TasUnitBonusSkill = {Data = {}}
   local this = TasUnitBonusSkill
   this.HideSkills = true -- hide the skills gained by this system with BlzUnitHideAbility?
   local this = TasUnitBonusSkill
   local thisData = TasUnitBonusSkill.Data

   -- enforce update functions
   local function UpdateLevel(unit, data)
       IncUnitAbilityLevel(unit, data.Skill)
       DecUnitAbilityLevel(unit, data.Skill)
   end
   local function UpdateInt(unit, data)
       SetHeroInt(unit, GetHeroInt(unit, false)+1, true)
       SetHeroInt(unit, GetHeroInt(unit, false)-1, true)
   end
   local function UpdateStr(unit, data)
       SetHeroStr(unit, GetHeroStr(unit, false)+1, true)
       SetHeroStr(unit, GetHeroStr(unit, false)-1, true)
   end
   
   -- shortcuts
   local iGet = BlzGetAbilityIntegerLevelField
   local iSet = BlzSetAbilityIntegerLevelField
   local rGet = BlzGetAbilityRealLevelField
   local rSet = BlzSetAbilityRealLevelField

--[[
   define abilities providing the bonuses and which field is update using which function for Get and Set
   Skill = FourCC(abiliCode)
   Field = field to read/write
   Get = function used to read
   Set = function used to write
   Update = call a function to apply changes, needed for some values.
   
]]
--======
   -- Data Setup
--======
   --ability clone of 'Aamk' Hero Attributes
   thisData["STR+"] = {Skill = FourCC('TU00'), Field = ABILITY_ILF_STRENGTH_BONUS_ISTR, Get = iGet, Set = iSet, Update = UpdateLevel}
   thisData["AGI+"] = {Skill = FourCC('TU00'), Field = ABILITY_ILF_AGILITY_BONUS, Get = iGet, Set = iSet, Update = UpdateLevel}
   thisData["INT+"] = {Skill = FourCC('TU00'), Field = ABILITY_ILF_INTELLIGENCE_BONUS, Get = iGet, Set = iSet, Update = UpdateLevel}

   --claw of attack
   thisData["ATK+"] = {Skill = FourCC('AItg'), Field = ABILITY_ILF_ATTACK_BONUS, Get = iGet, Set = iSet, Update = UpdateLevel}
   thisData["DMG+"] = thisData["ATK+"] -- one can also use "DMG+" for attack damage
   --gloves
   thisData["ATKSP+"] = {Skill = FourCC('AIsx'), Field = ABILITY_RLF_ATTACK_SPEED_INCREASE_ISX1, Get = rGet, Set = rSet, Update = UpdateLevel}
   --armor item
   thisData["DEF+"] = {Skill = FourCC('AId1'), Field = ABILITY_ILF_DEFENSE_BONUS_IDEF, Get = iGet, Set = iSet, Update = UpdateLevel}

   --based on 'ACev'
    thisData["EVADE+"] = {Skill = FourCC('AIev'), Field = ABILITY_RLF_CHANCE_TO_EVADE_EEV1, Get = rGet, Set = rSet}
    --trunken fighter or orc crit
    thisData["KRIT_CHANCE+"] = {Skill = FourCC('AIcs'), Field = ABILITY_RLF_CHANCE_TO_CRITICAL_STRIKE, Get = rGet, Set = rSet}
    thisData["KRIT_FACTOR+"] = {Skill = FourCC('AIcs'), Field = ABILITY_RLF_DAMAGE_MULTIPLIER_OCR2, Get = rGet, Set = rSet}
    thisData["KRIT_DAMAGE+"] = {Skill = FourCC('AIcs'), Field = ABILITY_RLF_DAMAGE_BONUS_OCR3, Get = rGet, Set = rSet}
    thisData["KRIT_EVADE+"] = {Skill = FourCC('AIcs'), Field = ABILITY_RLF_CHANCE_TO_EVADE_OCR4, Get = rGet, Set = rSet}
    thisData["KRIT_TRUE_STRIKE+"] = {Skill = FourCC('AIcs'), Field = ABILITY_ILF_SUMMONED_UNIT_COUNT_NPA5, Get = iGet, Set = iSet}
    thisData["KRIT_BONUS+"] = {Skill = FourCC('AIcs'), Field = ABILITY_ILF_WAVE_COUNT_NHS6, Get = iGet, Set = iSet}

   --boots of speed skill, they don't stack anyway
    thisData["MOVE+"] = {Skill = FourCC('AIms'), Field = ABILITY_ILF_MOVEMENT_SPEED_BONUS, Get = iGet, Set = iSet, Update = UpdateLevel}

   --elunes grace 'Aegr'
    thisData["MAGIC_RES+"] = {Skill = FourCC('AIdd'), Field = ABILITY_RLF_MAGIC_DAMAGE_REDUCTION_DEF5, Get = rGet, Set = rSet}
    thisData["PIERCE_RES+"] = {Skill = FourCC('AIdd'), Field = ABILITY_RLF_DAMAGE_TAKEN_PERCENT_DEF1, Get = rGet, Set = rSet}
   -- Deflect has to be enabled inside Game constants
    thisData["DEFLECT_CHANCE+"] = {Skill = FourCC('AIdd'), Field = ABILITY_RLF_CHANCE_TO_DEFLECT, Get = rGet, Set = rSet}
    thisData["DEFLECT_DAMAGE_MAGIC+"] = {Skill = FourCC('AIdd'), Field = ABILITY_RLF_DEFLECT_DAMAGE_TAKEN_SPELLS, Get = rGet, Set = rSet}
    thisData["DEFLECT_DAMAGE_PIERCE+"] = {Skill = FourCC('AIdd'), Field = ABILITY_RLF_DEFLECT_DAMAGE_TAKEN_PIERCING, Get = rGet, Set = rSet}
    -- multiplies basic attack without UI-Feedback
    thisData["DAMAGE_FACTOR+"] = {Skill = FourCC('AIdd'), Field = ABILITY_RLF_DAMAGE_DEALT_PERCENT_DEF2, Get = rGet, Set = rSet}

    -- spell ress brace item skill
    -- beaware this can break the the Aegr magic res feature for this unit
    thisData["SPELL_RES+"] = {Skill = FourCC('AIsr'), Field = ABILITY_RLF_DAMAGE_REDUCTION_ISR2, Get = rGet, Set = rSet, Update = UpdateLevel}    

   --based on 'Ansk'
   thisData["BLOCK_AMOUNT+"] = {Skill = FourCC('Ansk'), Field = ABILITY_RLF_IGNORED_DAMAGE, Get = rGet, Set = rSet}
   thisData["BLOCK_MIN+"] = {Skill = FourCC('Ansk'), Field = ABILITY_RLF_MINIMUM_DAMAGE, Get = rGet, Set = rSet}
   thisData["BLOCK_CHANCE+"] = {Skill = FourCC('Ansk'), Field = ABILITY_RLF_CHANCE_TO_REDUCE_DAMAGE_PERCENT, Get = rGet, Set = rSet}

   --'ACce' MeleeCleave
   thisData["CLEAVE_DAMAGE+"] = {Skill = FourCC('ACce'), Field = ABILITY_RLF_DISTRIBUTED_DAMAGE_FACTOR_NCA1, Get = rGet, Set = rSet}
   thisData["CLEAVE_AOE+"] = {Skill = FourCC('ACce'), Field = ABILITY_RLF_AREA_OF_EFFECT, Get = rGet, Set = rSet}

   --'ACpv'
    thisData["PULV_CHANCE+"] = {Skill = FourCC('ACpv'), Field = ABILITY_RLF_CHANCE_TO_STOMP_PERCENT, Get = rGet, Set = rSet}
    thisData["PULV_DAMAGE+"] = {Skill = FourCC('ACpv'), Field = ABILITY_RLF_DAMAGE_DEALT_WAR2, Get = rGet, Set = rSet}
    thisData["PULV_AOE+"] = {Skill = FourCC('ACpv'), Field = ABILITY_RLF_FULL_DAMAGE_RADIUS_WAR3, Get = rGet, Set = rSet}
    thisData["PULV_AOE_HALF+"] = {Skill = FourCC('ACpv'), Field = ABILITY_RLF_HALF_DAMAGE_RADIUS_WAR4, Get = rGet, Set = rSet}
    thisData["PULV_SFX+"] = {Skill = FourCC('ACpv'), Field = ABILITY_SLF_SPECIAL, Get = BlzGetAbilityStringLevelField, Set = BlzSetAbilityStringLevelField}

   --'Afbk'
    thisData["FEEDBACK_MANA+"] = {Skill = FourCC('Afbb'), Field = ABILITY_RLF_MAX_MANA_DRAINED_UNITS, Get = rGet, Set = rSet}
    thisData["FEEDBACK_MANA_HERO+"] = {Skill = FourCC('Afbb'), Field = ABILITY_RLF_MAX_MANA_DRAINED_HEROS, Get = rGet, Set = rSet}
    thisData["FEEDBACK_DAMAGE+"] = {Skill = FourCC('Afbb'), Field = ABILITY_RLF_DAMAGE_RATIO_UNITS_PERCENT, Get = rGet, Set = rSet}
    thisData["FEEDBACK_DAMAGE_HERO+"] = {Skill = FourCC('Afbb'), Field = ABILITY_RLF_DAMAGE_RATIO_HEROS_PERCENT, Get = rGet, Set = rSet}
    thisData["FEEDBACK_DAMAGE_SUMMON+"] = {Skill = FourCC('Afbb'), Field = ABILITY_RLF_SUMMONED_DAMAGE, Get = rGet, Set = rSet}

   --'Apxf'
    thisData["AUTO_SHOT_DAMAGE+"] = {Skill = FourCC('Apxf'), Field = ABILITY_RLF_INITIAL_DAMAGE_PXF1, Get = rGet, Set = rSet, Update = UpdateLevel}
    thisData["AUTO_SHOT_DPS+"] = {Skill = FourCC('Apxf'), Field = ABILITY_RLF_DAMAGE_PER_SECOND_PXF2, Get = rGet, Set = rSet, Update = UpdateLevel}
    thisData["AUTO_SHOT_DUR+"] = {Skill = FourCC('Apxf'), Field = ABILITY_RLF_DURATION_NORMAL, Get = rGet, Set = rSet, Update = UpdateLevel}
    thisData["AUTO_SHOT_DUR_HERO+"] = {Skill = FourCC('Apxf'), Field = ABILITY_RLF_DURATION_HERO, Get = rGet, Set = rSet, Update = UpdateLevel}
    thisData["AUTO_SHOT_AOE+"] = {Skill = FourCC('Apxf'), Field = ABILITY_RLF_AREA_OF_EFFECT, Get = rGet, Set = rSet, Update = UpdateLevel}
    thisData["AUTO_SHOT_TIME+"] = {Skill = FourCC('Apxf'), Field = ABILITY_RLF_COOLDOWN, Get = rGet, Set = rSet, Update = UpdateLevel}

   --'ANss'
    thisData["SPELL_SHIELD+"] = {Skill = FourCC('ANss'), Field = ABILITY_RLF_COOLDOWN, Get = rGet, Set = rSet}

   --'ACrn'
    thisData["REINCARNATION_COOLDOWN+"] = {Skill = FourCC('ACrn'), Field = ABILITY_RLF_COOLDOWN, Get = rGet, Set = rSet}
    thisData["REINCARNATION_DUR+"] = {Skill = FourCC('ACrn'), Field = ABILITY_RLF_REINCARNATION_DELAY, Get = rGet, Set = rSet}

   --Bash
   thisData["BASH_CHANCE+"] = {Skill = FourCC('AIbx'), Field = ABILITY_RLF_CHANCE_TO_BASH, Get = rGet, Set = rSet}
   thisData["BASH_DAMAGE+"] = {Skill = FourCC('AIbx'), Field = ABILITY_RLF_DAMAGE_BONUS_HBH3, Get = rGet, Set = rSet}
   thisData["BASH_DUR+"] = {Skill = FourCC('AIbx'), Field = ABILITY_RLF_DURATION_NORMAL, Get = rGet, Set = rSet}
   thisData["BASH_DURHERO+"] = {Skill = FourCC('AIbx'), Field = ABILITY_RLF_DURATION_HERO, Get = rGet, Set = rSet}
   thisData["BASH_TRUE_STRIKE+"] = {Skill = FourCC('AIbx'), Field = ABILITY_ILF_SUMMONED_UNIT_COUNT_NPA5, Get = iGet, Set = iSet}

   -- Item Lifesteal skill 'AIva'
   thisData["LIFE_STEAL+"] = {Skill = FourCC('AIva'), Field = ABILITY_RLF_DAMAGE_DEALT_ESF1, Get = rGet, Set = rSet, Update = UpdateLevel}   

   --Poison Buff Placer 'ACvs'
    thisData["POISON_DPS+"] = {Skill = FourCC('ACvs'), Field = ABILITY_RLF_DAMAGE_PER_SECOND_POI1, Get = rGet, Set = rSet}
    thisData["POISON_SLOW_ATK+"] = {Skill = FourCC('ACvs'), Field = ABILITY_RLF_ATTACK_SPEED_FACTOR_POI2, Get = rGet, Set = rSet}
    thisData["POISON_SLOW_MOVE+"] = {Skill = FourCC('ACvs'), Field = ABILITY_RLF_MOVEMENT_SPEED_FACTOR_POI3, Get = rGet, Set = rSet}
    thisData["POISON_TYPE+"] = {Skill = FourCC('ACvs'), Field = ABILITY_ILF_STACKING_TYPE_POI4, Get = iGet, Set = iSet}
    thisData["POISON_DUR+"] = {Skill = FourCC('ACvs'), Field = ABILITY_RLF_DURATION_NORMAL, Get = rGet, Set = rSet}
    thisData["POISON_DUR_HERO+"] = {Skill = FourCC('ACvs'), Field = ABILITY_RLF_DURATION_HERO, Get = rGet, Set = rSet}

    TasUnitBonus.NewType("PRIMARY+", function(unit, value, key)
        local stat = BlzGetUnitIntegerField(unit, UNIT_IF_PRIMARY_ATTRIBUTE)
        if stat == GetHandleId(HERO_ATTRIBUTE_STR) then
            this.Add(unit, "STR+", value)
        elseif stat == GetHandleId(HERO_ATTRIBUTE_AGI) then
            this.Add(unit, "AGI+", value)
        elseif stat == GetHandleId(HERO_ATTRIBUTE_INT) then
            this.Add(unit, "INT+", value)
        end
     end)
--======
-- System functions
--======
   setmetatable(thisData, {__index = function(table, key)
       print("TasUnitBonusSkill - Error - invalid Key", key)
       return nil
   end})

   function this.Set(unit, whichType, amount)
       local data = thisData[whichType]
       
       --if not BlzGetUnitAbility(unit, data.Skill) then UnitAddAbility(unit, data.Skill) end
       UnitAddAbility(unit, data.Skill)
       UnitMakeAbilityPermanent(unit, true, data.Skill)
       if this.HideSkills then BlzUnitHideAbility(unit, data.Skill, true) end
       data.Set(BlzGetUnitAbility(unit, data.Skill), data.Field, 0, amount)
       if data.Update then
           data.Update(unit, data)
       end
   end

   function this.Get(unit, whichType)
       local spell = BlzGetUnitAbility(unit, thisData[whichType].Skill)
       if not spell then
           return 0
       else
           return thisData[whichType].Get(spell, thisData[whichType].Field, 0)
       end    
   end
   function this.Remove(unit, whichType)
       UnitRemoveAbility(unit, thisData[whichType].Skill)
   end

   function this.Add(unit, whichType, amount)
       this.Set(unit, whichType, this.Get(unit, whichType) + amount)
   end

    -- add all they keys from TasUnitBonusSkill to to TasUnitBonus   
    -- they all use the same function
    for key in pairs(this.Data) do
        TasUnitBonus.NewType(key,"+")
    end
end
if Debug then Debug.endFile() end

--[[
TasUnitBonusBuff V1b
by Tasyen

Addon for TasUnitBonus; Give bonuses as long an unit has an Ability/Buff. Has to be evoked when an unit gains the buff.


function TasUnitBonusBuff.add(unit, buffCode, ...)
    as long unit has buffCode it benefits from the given amount
    Overwrites the current boni which first is lost
    TasUnitBonusBuff.add(unit, 'Binf', 200, 5) -- Gives 200 of the first Key in TasUnitBonusBuff.DefineKeys and 5 for the second
    
function TasUnitBonusBuff.DefineKeys(buffCode, ...)
    Which keys are used By buffCode (keys are from TasUnitBonus). This will generate Tables for it, only do this once at map init before using any buff placer.
    TasUnitBonusBuff.DefineKeys('Binf', "Life", "Str")
--]]
do
if Debug then Debug.beginFile "TasUnitBonusBuff" end
TasUnitBonusBuff = {
   -- current Buffs
   Unit = {}
   ,BuffCode = {}
   ,Count = 0

   -- BuffCode Data
   ,Data = {}
   -- to interpret the given Data
   ,Keys = {}
   -- KeysWaitingForRgister
   ,Delayed = {}
}
local this = TasUnitBonusBuff

function this.DefineKeys(buffCode, ...)
   if not buffCode then print("TasUnitBonusBuff.DefineKeys - Invalid buffCode", buffCode) return end
   if type(buffCode) == "string" then buffCode = FourCC(buffCode) end
   if this.Keys[buffCode] then if DEBUG then print("TasUnitBonusBuff.DefineKeys - Twice ", buffCode, string.pack(">I4", buffCode)) end return end
   this.Data[buffCode] = {}
   this.Keys[buffCode] = {}
   -- make for the buffCode one table for each Key
   -- unitspecific data is stored at --this.Data[buffCode][Key][unit]
   -- that way after each buffCode has define keys no Table has to be created anymore
   for i, key in ipairs({...}) do
       this.Data[buffCode][key] = {}
       this.Keys[buffCode][i] = key -- this is required to call the TasUnitBonus
   end
   -- has unit Buff & Time Buff Gained
   this.Data[buffCode][0] = {}
end

function this.StoreKey(...)
   if this.Delayed then
       table.insert(this.Delayed, {...})
   else
       this.DefineKeys({...})
   end
end
function this.ApplyStoredKeys()
   for _, v in ipairs(this.Delayed) do this.DefineKeys(table.unpack(v)) end
   this.Delayed = nil
end

function this.add(unit, buffCode, ...)
   if type(buffCode) == "string" then buffCode = FourCC(buffCode) end
if not unit then print("TasUnitBonusBuff.add No Unit") return end
   if not this.Timer then this.Timer = CreateTimer() end
   if not this.Data[buffCode] then 
       print("TasUnitBonusBuff.add - Not Registered BuffCode", buffCode, string.pack(">I4", buffCode))
       return
   end

   -- new buff?
   if not this.Data[buffCode][0][unit] then
       -- the Time buff gained
       this.Data[buffCode][0][unit] = 5

       this.Count = this.Count + 1
       this.Unit[this.Count] = unit
       this.BuffCode[this.Count] = buffCode

       -- apply bonus
       local key
       for i, value in ipairs({...}) do
           key = this.Keys[buffCode][i]            
           this.Data[buffCode][key][unit] = value
           TasUnitBonus(unit, key, value)
       end

       if this.Count == 1 then TimerStart(this.Timer, 0.1, true, this.TimerAction) end
   else
       -- rebuff
       local dif
       for i, value in ipairs({...}) do
           key = this.Keys[buffCode][i]
           dif = value - this.Data[buffCode][key][unit]
           this.Data[buffCode][key][unit] = value
           TasUnitBonus(unit, key, dif)
       end
   end

end

function this.TimerAction()
   local buffCode, unit, unitCode
--    print(this.Count)
   for index = this.Count, 1, -1 do
       -- Have buff Lost? And atleast 0.5 seconds expired
       buffCode = this.BuffCode[index]
       unit = this.Unit[index]
       unitCode = GetUnitTypeId(unit)
       --print(buffCode, GetFourCC(buffCode))
       if unitCode == 0 or ( not BlzGetUnitAbility(unit, buffCode)
           and (this.Data[buffCode][0][unit] <= 0)
       ) then
              -- print("expired",buffCode, GetFourCC(buffCode), TimerGetElapsed(udg_SpielZeit), TasUnitBonusBuff.Data[buffCode][0][unit])
           -- revert bonus
           for _, key in ipairs(this.Keys[buffCode]) do
               if unitCode > 0 then TasUnitBonus(unit, key, -this.Data[buffCode][key][unit]) end
               this.Data[buffCode][key][unit] = nil
           end
           -- unmark having TasUnitBonusBuff
           this.Data[buffCode][0][unit] = nil

           -- reindex
           this.Unit[index] = this.Unit[this.Count]
           this.BuffCode[index] = this.BuffCode[this.Count]

           this.Unit[this.Count] = nil
           this.Count = this.Count - 1

           
           if this.Count  <= 0 then PauseTimer(this.Timer) end
         elseif this.Data[buffCode][0][unit] > 0 then 
            this.Data[buffCode][0][unit] = this.Data[buffCode][0][unit] - 1
       end
   end
   buffCode = nil
   unit =  nil
end
end
if Debug then Debug.endFile() end
if Debug then Debug.beginFile "TasUnitBonusItem" end
do
   --[[ TasUnitBonusItem 1.4b by Tasyen
       Code driven Bonus for items. Also can be used for powerups.

       requires TasUnitBonus 
       can use FourCCTable & Total Initialization
       without Total Initialization you need to run InitTasUnitBonusItem() to create the events

       example; the keys used need to be suported by TasUnitBonus, before such an item is picked Up/Droped
       TasUnitBonusItem['I000'] = {
           Attack = 20 --add 20 ATK
           ,Mana = 100
           ,Life = 30
           ,Armor = 1.5 -- + 1.5 Armor
           ,LifeReg = 2.2
           ,ManaReg = 1.0 -- +1.0 Mana/s
           ,Agi = 1
           ,Str = 3
           ,Int = 5
       }

        one can set a bonus for an specific item, both  TasUnitBonusItem[GetItemTypeId] & TasUnitBonusItem[item] are gained/lost.
        TasUnitBonusItem[udg_Item] = { Attack = 20 }
   ]]
   if CreateFourCCTable then TasUnitBonusItem = CreateFourCCTable()
   else TasUnitBonusItem = {} end   
   local this = TasUnitBonusItem
   
   local function Action(unit, item, itemCode, add)      
       if IsUnitType(unit, UNIT_TYPE_HERO) then
           if this[itemCode] then TasUnitBonus.UnitAdd(this[itemCode], unit, add) end
           if this[item] then TasUnitBonus.UnitAdd(this[item], unit, add) end
       end
   end

   function InitTasUnitBonusItem()
      InitTasUnitBonusItem = DoNothing
      local trig = CreateTrigger()
      TriggerAddAction(trig, function()
         local unit, item, itemCode = GetManipulatingUnit(), GetManipulatedItem(), GetItemTypeId(GetManipulatedItem())
       -- heroes only
       if not IsUnitType(unit, UNIT_TYPE_HERO) then return end
       -- skip the drop part for powerups, to have a permanent boni :)
       if not IsItemPowerup(item) then
           Action(unit, item, itemCode, -1)
       end
      end)
      TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_DROP_ITEM)

      trig = CreateTrigger()
      TriggerAddAction(trig, function()
         local unit, item, itemCode = GetManipulatingUnit(), GetManipulatedItem(), GetItemTypeId(GetManipulatedItem())
         -- heroes only
         if not IsUnitType(unit, UNIT_TYPE_HERO) then return end
         Action(unit, item, itemCode, 1)
      end)
      TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_PICKUP_ITEM)
   end
   if OnInit then OnInit.trig(InitTasUnitBonusItem) end
end
if Debug then Debug.endFile() end

--[[
TasUnitBonusItemTooltip by Tasyen
Addon for TasUnitBonusItem rewrites the tooltips with stats given by an item. 
Only does something when called onto an item. to use this is an item needs to have the placeholders inside its default extended tooltip.
$ replaces all tooltip
$item inser the StatList here
TasUnitBonusItemTooltip(item)
]]
if Debug then Debug.beginFile "TasUnitBonusItemTooltip" end
TasUnitBonusItemTooltip = {}
do
   
   local this = TasUnitBonusItemTooltip
   PercentChar = "\x25"
   this.DisplayMulti = {
      -- multi the value for display purposes
      -- for given keys
      ["ATKSP+"] = 100
      ,ATKSP = 100
   }
   this.DisplayFormat = {
      -- rounding rules for display purposes
      ["ATKSP+"] = PercentChar..".0f"
      ,ATKSP = PercentChar..".0f"
   }
   this.Strings = {
      -- strings used in the tooltip gen
      -- the values are thrown into GetLocalizedString
      Str = "STRENGTH"
      ,Agi = "AGILITY"
      ,Int = "INTELLECT"
      ,STR = "STRENGTH"
      ,AGI = "AGILITY"
      ,INT = "INTELLECT"
   }
   setmetatable(this.Strings, {__index = function(table, key)
       return key end -- default fallback
   } )
   setmetatable(this, {__call = function(table, item) this.Apply(item) end } )

 function this.Formater(key, value)
    if this.DisplayFormat[key] then return string.format(this.DisplayFormat[key], value) end
    return value
 end
 function this.AddStat(obj, key, value)
   -- + not allowed In StringList, therefore drop it
   local keyString = key
   if string.sub(keyString, - 1) == "+" then keyString = string.sub(keyString, 1 , -2) end
   if (type(value) == "number") then 
      if not obj[keyString] then obj[keyString] = value
      else obj[keyString] = obj[keyString] + value
      end
   end
end
 
 function this.Apply(item)
     local itemCode = GetItemTypeId(item)
     if not TasUnitBonusItem[itemCode] and not TasUnitBonusItem[item] then return end

     --local text = BlzGetItemExtendedTooltip(item)
     local text = BlzGetAbilityExtendedTooltip(itemCode, 0)

     local temp = {}     
     if TasUnitBonusItem[itemCode] then for key, value in pairs(TasUnitBonusItem[itemCode]) do  this.AddStat(temp ,key, value) end end
     if TasUnitBonusItem[item] then for key, value in pairs(TasUnitBonusItem[item]) do  this.AddStat(temp ,key, value) end end
     local addText = ""
     for key, value in pairs(temp) do  
      addText = addText .. this.Formater(key, value*(this.DisplayMulti[key] or 1)) .." ".. GetLocalizedString(this.Strings[key]).."|n"
     end
     -- all dynamic
     if (text == "$") then
         BlzSetItemExtendedTooltip(item, addText)
         BlzSetItemDescription(item, addText)
     -- add all itemstats here
     elseif string.find(text, "$item") then
         local oldText = text
         text = string.gsub(oldText, "$item", addText)
         BlzSetItemExtendedTooltip(item, text)
         BlzSetItemDescription(item, text)
     end 
 end
end
if Debug then Debug.endFile() end

if Debug then Debug.beginFile "TasUnitBonusHero" end
do
   --[[ TasUnitBonusHero 1.1a by Tasyen
       Code driven Stat Bonus for HeroLevels.

       requires TasUnitBonus 
       can use FourCCTable & Total Initialization
       without Total Initialization you need to run InitTasUnitBonusHero() to create the events

       example, the keys need to be supported by TasUnitBonus
       TasUnitBonusHero[FourCC'Hpal'] = {
        Str = 1
        ,["DMG+"] = 5 -- gain 5 Bonus ATK every LevelUp
        ,[2] = { Ability = FourCC'AHbz'} -- at level 2 add Blizzard
        ,[4] = {["STR+"] = 12} -- Level 4 gain 12 bonus Str
        }

        TasUnitBonusHero[0] = { -- hero levelup bonus for all heroes
        Primary = 1
        ,Str = 1
        ,Agi = 1
        ,Int = 1
        }

        TasUnitBonusHero[udg_Unit] = { Primary = 2} -- specific levelup bonus

        Level [1] can not give a bonus.
        A Hero benefits from TasUnitBonusHero[0], TasUnitBonusHero[GetUnitTypeId] & TasUnitBonusHero[unit] at once.
   ]]
   local lastLevel = __jarray(1)
   if CreateFourCCTable then TasUnitBonusHero = CreateFourCCTable()
   else TasUnitBonusHero = {} end
   local this = TasUnitBonusHero
   
   local function apply(data, unit, newLevel, levelUps)
    if not data then return end
    TasUnitBonus.UnitAdd(data, unit, levelUps)
    for i = lastLevel[unit] + 1, newLevel do if data[i] then TasUnitBonus.UnitAdd(data[i], unit, 1) end end
   end

   function InitTasUnitBonusHero()
    InitTasUnitBonusHero = DoNothing
      local trig = CreateTrigger()
      TriggerAddAction(trig, function()
        local unit = GetTriggerUnit()
        local level = GetHeroLevel(unit)
        local levelUps = level - lastLevel[unit]
        local unitCode = GetUnitTypeId(unit)
        apply(this[unit], unit, level, levelUps) -- hero specific bonus
        apply(this[0], unit, level, levelUps)  -- any hero-class bonus
        apply(this[unitCode], unit, level, levelUps) -- this hero-class bonus
        lastLevel[unit] = level
      end)
      TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_HERO_LEVEL)
   end
   if OnInit then OnInit.trig(InitTasUnitBonusHero) end
end
if Debug then Debug.endFile() end

if Debug then Debug.beginFile "TasUnitBonusLearn" end
do
   --[[ TasUnitBonusLearn by Tasyen
       Code driven Stat Bonus for Heroes Learning Skills.

       requires TasUnitBonus 
       can use FourCCTable & Total Initialization
       without Total Initialization you need to run InitTasUnitBonusLearn() to create the events

       you can give a bonus with TasUnitBonusLearnAction(unit, spellCode, learnedLevel). 
       You could do this when a skill is not learned over the default warcraft 3 learn ui.

       example, the keys need to be suported by TasUnitBonus
       TasUnitBonusLearn[FourCC'AHhb'] = {
        ["DMG+"] = 5 -- gain 5 Bonus ATK every time Skilled
        ,[2] = { Str = 10} -- Skilling level 2 10 base Str
        }
   ]]
   if CreateFourCCTable then TasUnitBonusLearn = CreateFourCCTable()
   else TasUnitBonusLearn = {} end
   local this = TasUnitBonusLearn
   
   function TasUnitBonusLearnAction(unit, spellCode, learnedLevel)
    local data = TasUnitBonusLearn[spellCode]
    if not data then return end
    TasUnitBonus.UnitAdd(data, unit, 1)
    if data[learnedLevel] then TasUnitBonus.UnitAdd(data[learnedLevel], unit, 1) end
   end

   function InitTasUnitBonusLearn()
    InitTasUnitBonusLearn = DoNothing
      local trig = CreateTrigger()
      TriggerAddAction(trig, function() TasUnitBonusLearnAction(GetTriggerUnit(), GetLearnedSkill(), GetLearnedSkillLevel()) end)
      TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_HERO_SKILL)
   end
   if OnInit then OnInit.trig(InitTasUnitBonusLearn) end
end
if Debug then Debug.endFile() end

example: TasUnitBonusItem Simple Items
Lua:
--[[
 example use of TasUnitBonusItem
 setup what each items of RawCode gives while carried by a hero
--]]
do
    itemPower = TasUnitBonusItem -- need to write less text
    itemPower[FourCC'I000'] = {Armor = 3} -- 3 base armor
    itemPower[FourCC'I001'] = {["STR+"] = 3} -- +3 bonus str
    itemPower[FourCC'I002'] = {["MOVE+"] = 50} 
    itemPower[FourCC'I003'] = {Int = 6} -- + 6 base int
    itemPower[FourCC'I004'] = {Attack = 9} -- + 9 base dmg
    itemPower[FourCC'I005'] = {["INT+"] = 4, ["AGI+"] = 4} -- gives 4 bonus agi and int
    itemPower[FourCC'I006'] = {["DMG+"] = 6} -- + 6 bonus dmg    
end

example: TasUnitBonusLearn
Lua:
TasUnitBonusLearn[FourCC'AHhb'] = { -- HolyLight
  ["DMG+"] = 3 -- 3 Bonus ATK every time Skilled
 ,[2] = { Str = 10} -- Skilling level 2 10 base Str
}

example: TasUnitBonusItem MaskOfDeath
Lua:
-- MaskOfDeath is an example for item specific TasUnitBonus combined with itemCode bonus.
--+20 ATK|n+5 for each last hit done while holding this item, upto 100 additional ATK.

MaskOfDeathCode = FourCC'I008'
function MaskOfDeath()
    TasUnitBonusItem[MaskOfDeathCode] = {["DMG+"] = 20} -- + 20 bonus dmg

    local trig = CreateTrigger()
    TriggerAddAction(trig, function()
        local killer = GetKillingUnit()
        if not IsUnitType(killer, UNIT_TYPE_HERO) then return end

        for i = 0, bj_MAX_INVENTORY -1 do
            local item = UnitItemInSlot(killer, i)
            if GetItemTypeId(item) == MaskOfDeathCode then

                -- create item speicifc table when not existing yet
                if not TasUnitBonusItem[item] then TasUnitBonusItem[item] = {["DMG+"] = 0} end
                if TasUnitBonusItem[item]["DMG+"] < 100 then 
                    TasUnitBonusItem[item]["DMG+"] = TasUnitBonusItem[item]["DMG+"] + 5
                    
                    -- give the bonus now, because TasUnitBonusItem is only given and taken on PIckUP/drop events
                    TasUnitBonus(killer, "DMG+", 5)
                    
                    -- update item name & tooltip
                    TasUnitBonusItemTooltip(item)
                    BlzSetItemName(item, GetObjectName(MaskOfDeathCode) .. "(+".. TasUnitBonusItem[item]["DMG+"] ..")")
                end
            end
        end

    end)
    TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_DEATH)
end

example: CustomStat UndeadSlayer & Backstab
Lua:
--example of 2 custom types backstab and UndeadSlayer
-- backstab gives Bonus ATK when hitting into the back
-- UndeadSlayer gives Bonus ATK when attacking units with the UNDEAD-Class


-- needed for backstab
function AngleW2W(source, target)
    return bj_RADTODEG * Atan2(GetWidgetY(target) - GetWidgetY(source), GetWidgetX(target) - GetWidgetX(source))
end
do -- 
    function CustomStats()
        udg_BackStab = __jarray(0)
        udg_UndeadSlayer = __jarray(0)
        TasUnitBonus.AddSimpleType("udg_BackStab")
        TasUnitBonus.AddSimpleType("udg_UndeadSlayer")

        itemPower[FourCC'I009'] = {udg_UndeadSlayer = 27}
        itemPower[FourCC'I00A'] = {udg_BackStab = 35}

-- current Bonus used for reset
        local oldBackStab = __jarray(0)
        local oldUndeadSlayer = __jarray(0)
        local trig = CreateTrigger()
        TriggerAddAction(trig, function()
            local unit, attacker = GetTriggerUnit(), GetAttacker()
            local newValue = udg_BackStab[attacker]
            if oldBackStab[attacker] ~= 0 or newValue ~= 0 then
                if CosBJ(AngleW2W(attacker, unit) - GetUnitFacing(unit)) < 0 then newValue = 0 end
                TasUnitBonus(attacker, "ATK+", newValue - oldBackStab[attacker])
                oldBackStab[attacker] = newValue
            end

            newValue = udg_UndeadSlayer[attacker]
            if oldUndeadSlayer[attacker] ~= 0 or newValue ~= 0 then
                if not IsUnitType(unit, UNIT_TYPE_UNDEAD) then newValue = 0 end
                TasUnitBonus(attacker, "ATK+", newValue - oldUndeadSlayer[attacker])
                oldUndeadSlayer[attacker] = newValue
            end
        end)
        TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_ATTACKED)
    end
end

Examples for Buffing
Lua:
-- example for TasUnitBonusBuff

function InitDemoSpellCast()
    -- define once what bonus keys buffs give
    TasUnitBonusBuff.DefineKeys('Binv', "MOVE+")
    TasUnitBonusBuff.DefineKeys('Binf', "STR+")
    TasUnitBonusBuff.DefineKeys('Bblo', "Ability")

-- do not run this again
    InitDemoSpellCast = nil
end

function DemoSpellCast()
    if InitDemoSpellCast then InitDemoSpellCast() end

    -- the spellcasts tell TasUnitBonusBuff how much to add for a given buffCode

--Invis buff gives 500 movespeed
    if GetSpellAbilityId() == FourCC'Aivs' then TasUnitBonusBuff.add(GetSpellTargetUnit(), 'Binv', 500) end

-- inner fire gives hero str
-- first cast adds 15 recast give 5 more 15 20 25 30
    local buffCode = FourCC'Binf'
    if GetSpellAbilityId() == FourCC'Ainf' then
        local value = TasUnitBonusBuff.Data[buffCode]["STR+"][GetSpellTargetUnit()] or 0
 	if value  < 15 then value  = 15 else value  = value + 5 end
        TasUnitBonusBuff.add(GetSpellTargetUnit(), buffCode, value ) end

-- bloodlust gives an endurance aura
    local skill = FourCC'AIae'
    if GetSpellAbilityId() == FourCC'ACbb' then TasUnitBonusBuff.add(GetSpellTargetUnit(), 'Bblo', skill) end    
end

ChangeLog


1.5) improve comments, ability survives morphs, seperated TasUnitBonusSkill more from TasUnitBonus, Added Key Tech inc/dec Reserach by 1
1.4) fix key AttackRange
1.3x) Added TasUnitBonusLearn
1.3) Added TasUnitBonusItemTooltip & 4 stats
1.2c) Fixed TasUnitBonusHero
1.2b) added TasUnitBonusHero
1.2a) replaced HealUnit(Mana) with native aviable functions


Tags: RPG, Hero, Stats, Unit Bonus, Str, Agi, Int, ATK​
Contents

TasUnitBonus (Map)

Reviews
Antares
I don't know what that means. Please use an AI assistant like ChatGPT to help you with the translation or have someone help you with the documentation. I'm sure there are a lot of people who would be happy to. The description in the OP is fine, but...
Level 5
Joined
Oct 31, 2011
Messages
85
Another one of Tasyen's subscription systems, I wish Blizzard had the same dedication to Warcraft as you and the community here at Hivework Shop.

Apparently it adds a skill that has a bonus that it will increase to the Hero, but how does it increase CastPoint and CastBackswing?

And another thing, will there be a Jass version?
 
And another thing, will there be a Jass version?
I will not make a vjass version of this. vjass cant do this dynamic function mapping which is a core feature.

but how does it increase CastPoint and CastBackswing?
castpoint and castbackswing are unit stats when an ability is gained the ability copies the unit's current castpoint & castbackswing values.
To make already owned abilities be cast faster you would change the unit castpoint then lose the castable spells from the unit and readd them.

Edit: would be easier when one would have the ability_RealFields for castpoint but sadly no, so only doable by readding spells.
 
Updated to V1.2b)
Added the addon TasUnitBonusHero, I forgot to port it from my map.
TasUnitBonus.UnitAdd does not use numbers as key anymore. "1" is still allowed 1 not.
TasUnitBonusHero manages TasUnitBonuses on level ups for any hero [0] and [unit] and [RawCode].
Lua:
TasUnitBonusHero[FourCC'Hpal'] = { -- paladin levelup Bonus
 Str = 1
 ,["DMG+"] = 5 -- gain 5 Bonus ATK every LevelUp
 ,[2] = { Ability = FourCC'AHbz'} -- at level 2 add Blizzard
 ,[4] = {["STR+"] = 12}
}

Edit:
V1.2c)
fixed serious bugs of TasUnitBonusHero.
 
Last edited:
Level 5
Joined
Mar 7, 2024
Messages
79
You're so talented, I also wish I knew how to make an off-screen interface like that, but this is way beyond my level, like the photo I posted, you can do for those positions is add a container Hero's items?
HOI4.PNG
 
You're so talented,
I trained many years. in gui, then java and some other none warcraft 3 stuff, after that jass, then i trained Lua and warcraft 3 custom UI (was quite bad at some point in that subject). But y, I guess have talent for some parts of math/order.
TasUnitBonus is the result of systems, I wrote before, some not public released and only for my map or as a experiment. In that systems I encountered the problem that I needed to give unit stats and so I came to this idea. My Talent system is one of these concept-ancestors it has a stat systems by Lua tables.

One can create many types of ui but warcraft 3 frames are based on rectangles -> images are easier than models. One can create a custom ui with buttons to contain: items like a bag, yes. I made such and some others did as well. Making more default item/command/hero buttons is not doable with the ui-frame api. In such a case one would need to recreate the whole feature.




The image shows TasCheatbox, if one wonders, i added that as demo to have some tester super powers like dispel buffs and such.
normaly the 3 & 4 page would create items & units but in this map the were replaced with "cheats" using TasUnitBonus.
 
Updated to V1.3)
added 4 prebuilt stats

2 over skills
"PRIMARY+"
"LIFE_STEAL+" item lifesteal

2 but they dont work in V1.31.1 cause they use Unit Weaponfields.
AttackRange
AttackRangeR

AttackRangeR is AttackRange but wont do anthing if the unit is not ranged.

improved AbilityInc
now should be able to decrease current level like key Ability with a -value.

What common important stat is missing?

Ported another addon TasUnitBonusItemTooltip. Updates item tooltips to include the stats given by that item + itemCode. Items only use this feature when you call it onto it.
TasUnitBonusItemTooltip(item)

TasUnitBonusItemTooltip replaces a placeholder: There are 2 options.
$ replaces all tooltip
$item inser the StatList here keep the rest as it is.

I think all addons for TasUnitBonus are now ported.
 
Last edited:
I think all addons for TasUnitBonus are now ported.
I was wrong. Still got one that gives TasUnitBonus when a hero learns a skill. But I cant port the version from my map, it has weird featues and was constructed for 1 level skills only that give another bonus after dozens of levels and maybe (also/only) affecting other units.

Could make an simpler version that works kinda like TasUnitBonusHero. Would then be called TasUnitBonusLearn.

Edit:
Updated, includes now the addon TasUnitBonusLearn, should be suited for the normal warcraft 3 Learning system.
TasUnitBonusLearn uses the same format as TasUnitBonusHero it does not have the any key with 0 and instead of hero level, skill levels matter, it also can be called from the outside.
TasUnitBonusLearnAction(unit, spellCode, learnedLevel)

Lua:
TasUnitBonusLearn[FourCC'AHhb'] = { -- HolyLight
  ["DMG+"] = 3 -- 3 Bonus ATK every time Skilled
 ,[2] = { Str = 10} -- Skilling level 2 10 base Str
}
 
Last edited:
Adds a new supported type by key the function runs when a request to add to this key.
The function needs to do the inc.
instead of a function you can give an already existing key to make key do the same.
I don't know what that means.

Please use an AI assistant like ChatGPT to help you with the translation or have someone help you with the documentation. I'm sure there are a lot of people who would be happy to.

The description in the OP is fine, but for the comments in the code, I just don't know what it's trying to tell me.

It doesn't help that the formatting is all messed up. It looks like the scope in TasUnitBonus is closed on line 34. Please fix the indentation and add some empty lines.

I'm sure the code itself is superb as always, but we're trying to be more stringent when it comes to documentation, as to increase the accessibility of this section.

Awaiting Update
 
Updated to V1.5)
improved api comments
key Ability; ability survives morphs
seperated TasUnitBonusSkill more from TasUnitBonus
Added Key Tech, it increases/decreases a Research by 1.

TasUnitBonusHero mentions that a Hero benefits from upto 3 tabels at once [0] [GetUnitTypeId] & [unit]
TasUnitBonusItem mentions that an item supports boh at the same time [GetItemTypeId] & [item]
 
Last edited:
Top